gui: Remove unused static variables.
[pspp] / src / ui / gui / psppire-data-store.c
1 /* PSPPIRE - a graphical user interface for PSPP.
2    Copyright (C) 2006, 2008, 2009, 2010, 2011, 2012, 2013, 2016  Free Software Foundation
3
4    This program is free software: you can redistribute it and/or modify
5    it under the terms of the GNU General Public License as published by
6    the Free Software Foundation, either version 3 of the License, or
7    (at your option) any later version.
8
9    This program is distributed in the hope that it will be useful,
10    but WITHOUT ANY WARRANTY; without even the implied warranty of
11    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12    GNU General Public License for more details.
13
14    You should have received a copy of the GNU General Public License
15    along with this program.  If not, see <http://www.gnu.org/licenses/>. */
16
17 #include <config.h>
18 #include <string.h>
19 #include <stdlib.h>
20 #include <gettext.h>
21 #define _(msgid) gettext (msgid)
22 #define N_(msgid) msgid
23
24 #include <data/datasheet.h>
25 #include <data/data-out.h>
26 #include <data/variable.h>
27
28 #include <ui/gui/psppire-marshal.h>
29
30 #include <pango/pango-context.h>
31
32 #include "psppire-data-store.h"
33 #include <libpspp/i18n.h>
34 #include "helper.h"
35
36 #include <data/dictionary.h>
37 #include <data/missing-values.h>
38 #include <data/value-labels.h>
39 #include <data/data-in.h>
40 #include <data/format.h>
41
42 #include <math/sort.h>
43
44 #include "xalloc.h"
45 #include "xmalloca.h"
46
47
48
49 static void psppire_data_store_init            (PsppireDataStore      *data_store);
50 static void psppire_data_store_class_init      (PsppireDataStoreClass *class);
51
52 static void psppire_data_store_finalize        (GObject           *object);
53 static void psppire_data_store_dispose        (GObject           *object);
54
55 static gboolean psppire_data_store_insert_case (PsppireDataStore *ds,
56                                                 struct ccase *cc,
57                                                 casenumber posn);
58
59
60 static gboolean psppire_data_store_data_in (PsppireDataStore *ds,
61                                             casenumber casenum, gint idx,
62                                             struct substring input,
63                                             const struct fmt_spec *fmt);
64
65 static GObjectClass *parent_class = NULL;
66
67
68 enum
69   {
70     BACKEND_CHANGED,
71     CASES_DELETED,
72     CASE_INSERTED,
73     CASE_CHANGED,
74     n_SIGNALS
75   };
76
77 static guint signals [n_SIGNALS];
78
79
80 GType
81 psppire_data_store_get_type (void)
82 {
83   static GType data_store_type = 0;
84
85   if (!data_store_type)
86     {
87       static const GTypeInfo data_store_info =
88       {
89         sizeof (PsppireDataStoreClass),
90         NULL,           /* base_init */
91         NULL,           /* base_finalize */
92         (GClassInitFunc) psppire_data_store_class_init,
93         NULL,           /* class_finalize */
94         NULL,           /* class_data */
95         sizeof (PsppireDataStore),
96         0,
97         (GInstanceInitFunc) psppire_data_store_init,
98       };
99
100       data_store_type = g_type_register_static (G_TYPE_OBJECT,
101                                                 "PsppireDataStore",
102                                                 &data_store_info, 0);
103     }
104
105   return data_store_type;
106 }
107
108
109 static void
110 psppire_data_store_class_init (PsppireDataStoreClass *class)
111 {
112   GObjectClass *object_class;
113
114   parent_class = g_type_class_peek_parent (class);
115   object_class = (GObjectClass*) class;
116
117   object_class->finalize = psppire_data_store_finalize;
118   object_class->dispose = psppire_data_store_dispose;
119
120   signals [BACKEND_CHANGED] =
121     g_signal_new ("backend-changed",
122                   G_TYPE_FROM_CLASS (class),
123                   G_SIGNAL_RUN_FIRST,
124                   0,
125                   NULL, NULL,
126                   g_cclosure_marshal_VOID__VOID,
127                   G_TYPE_NONE,
128                   0);
129
130   signals [CASE_INSERTED] =
131     g_signal_new ("case-inserted",
132                   G_TYPE_FROM_CLASS (class),
133                   G_SIGNAL_RUN_FIRST,
134                   0,
135                   NULL, NULL,
136                   g_cclosure_marshal_VOID__INT,
137                   G_TYPE_NONE,
138                   1,
139                   G_TYPE_INT);
140
141
142   signals [CASE_CHANGED] =
143     g_signal_new ("case-changed",
144                   G_TYPE_FROM_CLASS (class),
145                   G_SIGNAL_RUN_FIRST,
146                   0,
147                   NULL, NULL,
148                   g_cclosure_marshal_VOID__INT,
149                   G_TYPE_NONE,
150                   1,
151                   G_TYPE_INT);
152
153   signals [CASES_DELETED] =
154     g_signal_new ("cases-deleted",
155                   G_TYPE_FROM_CLASS (class),
156                   G_SIGNAL_RUN_FIRST,
157                   0,
158                   NULL, NULL,
159                   psppire_marshal_VOID__INT_INT,
160                   G_TYPE_NONE,
161                   2,
162                   G_TYPE_INT,
163                   G_TYPE_INT);
164 }
165
166
167
168 static gboolean
169 psppire_data_store_insert_value (PsppireDataStore *ds,
170                                   gint width, gint where);
171
172 casenumber
173 psppire_data_store_get_case_count (const PsppireDataStore *store)
174 {
175   return datasheet_get_n_rows (store->datasheet);
176 }
177
178 size_t
179 psppire_data_store_get_value_count (const PsppireDataStore *store)
180 {
181   return psppire_dict_get_value_cnt (store->dict);
182 }
183
184 const struct caseproto *
185 psppire_data_store_get_proto (const PsppireDataStore *store)
186 {
187   return psppire_dict_get_proto (store->dict);
188 }
189
190 static void
191 psppire_data_store_init (PsppireDataStore *data_store)
192 {
193   data_store->dict = NULL;
194   data_store->datasheet = NULL;
195   data_store->dispose_has_run = FALSE;
196 }
197
198 /*
199    A callback which occurs after a variable has been deleted.
200  */
201 static void
202 delete_variable_callback (GObject *obj, const struct variable *var UNUSED,
203                           gint dict_index, gint case_index,
204                           gpointer data)
205 {
206   PsppireDataStore *store  = PSPPIRE_DATA_STORE (data);
207
208   g_return_if_fail (store->datasheet);
209
210   datasheet_delete_columns (store->datasheet, case_index, 1);
211   datasheet_insert_column (store->datasheet, NULL, -1, case_index);
212 }
213
214 struct resize_datum_aux
215   {
216     const struct dictionary *dict;
217     const struct variable *new_variable;
218     const struct variable *old_variable;
219   };
220
221 static void
222 resize_datum (const union value *old, union value *new, const void *aux_)
223 {
224   const struct resize_datum_aux *aux = aux_;
225   int new_width = var_get_width (aux->new_variable);
226   const char *enc = dict_get_encoding (aux->dict);
227   const struct fmt_spec *newfmt = var_get_print_format (aux->new_variable);
228   char *s = data_out (old, enc, var_get_print_format (aux->old_variable));
229   enum fmt_type type = (fmt_usable_for_input (newfmt->type)
230                         ? newfmt->type
231                         : FMT_DOLLAR);
232   free (data_in (ss_cstr (s), enc, type, new, new_width, enc));
233   free (s);
234 }
235
236 static void
237 variable_changed_callback (GObject *obj, gint var_num, guint what, const struct variable *oldvar,
238                            gpointer data)
239 {
240   PsppireDataStore *store  = PSPPIRE_DATA_STORE (data);
241   struct variable *variable = psppire_dict_get_variable (store->dict, var_num);
242
243   if (what & VAR_TRAIT_WIDTH)
244     {
245       int posn = var_get_case_index (variable);
246       struct resize_datum_aux aux;
247       aux.old_variable = oldvar;
248       aux.new_variable = variable;
249       aux.dict = store->dict->dict;
250       datasheet_resize_column (store->datasheet, posn, var_get_width (variable),
251                                resize_datum, &aux);
252     }
253 }
254
255 static void
256 insert_variable_callback (GObject *obj, gint var_num, gpointer data)
257 {
258   struct variable *variable;
259   PsppireDataStore *store;
260   gint posn;
261
262   g_return_if_fail (data);
263
264   store  = PSPPIRE_DATA_STORE (data);
265
266   variable = psppire_dict_get_variable (store->dict, var_num);
267   posn = var_get_case_index (variable);
268   psppire_data_store_insert_value (store, var_get_width (variable), posn);
269 }
270
271 /**
272  * psppire_data_store_new:
273  * @dict: The dictionary for this data_store.
274  *
275  *
276  * Return value: a new #PsppireDataStore
277  **/
278 PsppireDataStore *
279 psppire_data_store_new (PsppireDict *dict)
280 {
281   PsppireDataStore *retval;
282
283   retval = g_object_new (PSPPIRE_TYPE_DATA_STORE, NULL);
284
285   psppire_data_store_set_dictionary (retval, dict);
286
287   return retval;
288 }
289
290 void
291 psppire_data_store_set_reader (PsppireDataStore *ds,
292                                struct casereader *reader)
293 {
294   gint i;
295
296   if ( ds->datasheet)
297     datasheet_destroy (ds->datasheet);
298
299   ds->datasheet = datasheet_create (reader);
300
301   if ( ds->dict )
302     for (i = 0 ; i < n_dict_signals; ++i )
303       {
304         if ( ds->dict_handler_id [i] > 0)
305           {
306             g_signal_handler_unblock (ds->dict,
307                                       ds->dict_handler_id[i]);
308           }
309       }
310
311   g_signal_emit (ds, signals[BACKEND_CHANGED], 0);
312 }
313
314
315 /**
316  * psppire_data_store_replace_set_dictionary:
317  * @data_store: The variable store
318  * @dict: The dictionary to set
319  *
320  * If a dictionary is already associated with the data-store, then it will be
321  * destroyed.
322  **/
323 void
324 psppire_data_store_set_dictionary (PsppireDataStore *data_store, PsppireDict *dict)
325 {
326   int i;
327
328   /* Disconnect any existing handlers */
329   if ( data_store->dict )
330     for (i = 0 ; i < n_dict_signals; ++i )
331       {
332         g_signal_handler_disconnect (data_store->dict,
333                                      data_store->dict_handler_id[i]);
334       }
335
336   data_store->dict = dict;
337
338   if ( dict != NULL)
339     {
340
341       data_store->dict_handler_id [VARIABLE_INSERTED] =
342         g_signal_connect (dict, "variable-inserted",
343                           G_CALLBACK (insert_variable_callback),
344                           data_store);
345
346       data_store->dict_handler_id [VARIABLE_DELETED] =
347         g_signal_connect (dict, "variable-deleted",
348                           G_CALLBACK (delete_variable_callback),
349                           data_store);
350
351       data_store->dict_handler_id [VARIABLE_CHANGED] =
352         g_signal_connect (dict, "variable-changed",
353                           G_CALLBACK (variable_changed_callback),
354                           data_store);
355     }
356
357
358
359   /* The entire model has changed */
360
361   if ( data_store->dict )
362     for (i = 0 ; i < n_dict_signals; ++i )
363       {
364         if ( data_store->dict_handler_id [i] > 0)
365           {
366             g_signal_handler_block (data_store->dict,
367                                     data_store->dict_handler_id[i]);
368           }
369       }
370 }
371
372 static void
373 psppire_data_store_finalize (GObject *object)
374 {
375   PsppireDataStore *ds = PSPPIRE_DATA_STORE (object);
376
377   if (ds->datasheet)
378     {
379       datasheet_destroy (ds->datasheet);
380       ds->datasheet = NULL;
381     }
382
383   /* must chain up */
384   (* parent_class->finalize) (object);
385 }
386
387
388 static void
389 psppire_data_store_dispose (GObject *object)
390 {
391   PsppireDataStore *ds = PSPPIRE_DATA_STORE (object);
392
393   if (ds->dispose_has_run)
394     return;
395
396   psppire_data_store_set_dictionary (ds, NULL);
397
398   /* must chain up */
399   (* parent_class->dispose) (object);
400
401   ds->dispose_has_run = TRUE;
402 }
403
404
405
406 /* Insert a blank case before POSN */
407 gboolean
408 psppire_data_store_insert_new_case (PsppireDataStore *ds, casenumber posn)
409 {
410   gboolean result;
411   const struct caseproto *proto;
412   struct ccase *cc;
413   g_return_val_if_fail (ds, FALSE);
414
415   proto = datasheet_get_proto (ds->datasheet);
416   g_return_val_if_fail (caseproto_get_n_widths (proto) > 0, FALSE);
417   g_return_val_if_fail (posn <= psppire_data_store_get_case_count (ds), FALSE);
418
419   cc = case_create (proto);
420   case_set_missing (cc);
421
422   result = psppire_data_store_insert_case (ds, cc, posn);
423
424   case_unref (cc);
425
426   return result;
427 }
428
429 gchar *
430 psppire_data_store_get_string (PsppireDataStore *store,
431                                glong row, const struct variable *var,
432                                bool use_value_label)
433 {
434   gchar *string;
435   union value v;
436   int width;
437
438   g_return_val_if_fail (store != NULL, NULL);
439   g_return_val_if_fail (store->datasheet != NULL, NULL);
440   g_return_val_if_fail (var != NULL, NULL);
441
442   if (row < 0 || row >= datasheet_get_n_rows (store->datasheet))
443     return NULL;
444
445   width = var_get_width (var);
446   value_init (&v, width);
447   datasheet_get_value (store->datasheet, row, var_get_case_index (var), &v);
448
449   string = NULL;
450   if (use_value_label)
451     {
452       const char *label = var_lookup_value_label (var, &v);
453       if (label != NULL)
454         string = g_strdup (label);
455     }
456   if (string == NULL)
457     string = value_to_text (v, var);
458
459   value_destroy (&v, width);
460
461   return string;
462 }
463
464
465 /* Attempts to update that part of the variable store which corresponds to VAR
466    within ROW with the value TEXT.
467
468    If USE_VALUE_LABEL is true, and TEXT is a value label for the column's
469    variable, then stores the value from that value label instead of the literal
470    TEXT.
471
472    Returns true if anything was updated, false otherwise.  */
473 gboolean
474 psppire_data_store_set_string (PsppireDataStore *store,
475                                const gchar *text,
476                                glong row, const struct variable *var,
477                                gboolean use_value_label)
478 {
479   gint case_index;
480   glong n_cases;
481   gboolean ok;
482
483   n_cases = psppire_data_store_get_case_count (store);
484   if (row > n_cases)
485     return FALSE;
486   if (row == n_cases)
487     psppire_data_store_insert_new_case (store, row);
488
489   case_index = var_get_case_index (var);
490   if (use_value_label)
491     {
492       const struct val_labs *vls = var_get_value_labels (var);
493       const union value *value = vls ? val_labs_find_value (vls, text) : NULL;
494       if (value)
495         ok = datasheet_put_value (store->datasheet, row, case_index, value);
496       else
497         ok = FALSE;
498     }
499   else
500     ok = psppire_data_store_data_in (store, row, case_index, ss_cstr (text),
501                                      var_get_print_format (var));
502
503   if (ok)
504     g_signal_emit (store, signals [CASE_CHANGED], 0, row);
505   return ok;
506 }
507
508
509
510 void
511 psppire_data_store_clear (PsppireDataStore *ds)
512 {
513   datasheet_destroy (ds->datasheet);
514   ds->datasheet = NULL;
515
516   psppire_dict_clear (ds->dict);
517
518   g_signal_emit (ds, signals [CASES_DELETED], 0, 0, -1);
519 }
520
521
522
523 /* Return a casereader made from this datastore */
524 struct casereader *
525 psppire_data_store_get_reader (PsppireDataStore *ds)
526 {
527   int i;
528   struct casereader *reader ;
529
530   if ( ds->dict )
531     for (i = 0 ; i < n_dict_signals; ++i )
532       {
533         g_signal_handler_block (ds->dict,
534                                 ds->dict_handler_id[i]);
535       }
536
537   reader = datasheet_make_reader (ds->datasheet);
538
539   /* We must not reference this again */
540   ds->datasheet = NULL;
541
542   return reader;
543 }
544
545 /* Returns the CASENUMth case, or a null pointer on failure.
546  */
547 struct ccase *
548 psppire_data_store_get_case (const PsppireDataStore *ds,
549                              casenumber casenum)
550 {
551   g_return_val_if_fail (ds, FALSE);
552   g_return_val_if_fail (ds->datasheet, FALSE);
553
554   return datasheet_get_row (ds->datasheet, casenum);
555 }
556
557
558 gboolean
559 psppire_data_store_delete_cases (PsppireDataStore *ds, casenumber first,
560                                  casenumber n_cases)
561 {
562   g_return_val_if_fail (ds, FALSE);
563   g_return_val_if_fail (ds->datasheet, FALSE);
564
565   g_return_val_if_fail (first + n_cases <=
566                         psppire_data_store_get_case_count (ds), FALSE);
567
568
569   datasheet_delete_rows (ds->datasheet, first, n_cases);
570
571   g_signal_emit (ds, signals [CASES_DELETED], 0, first, n_cases);
572
573   return TRUE;
574 }
575
576
577
578 /* Insert case CC into the case file before POSN */
579 static gboolean
580 psppire_data_store_insert_case (PsppireDataStore *ds,
581                                 struct ccase *cc,
582                                 casenumber posn)
583 {
584   bool result ;
585
586   g_return_val_if_fail (ds, FALSE);
587   g_return_val_if_fail (ds->datasheet, FALSE);
588
589   cc = case_ref (cc);
590   result = datasheet_insert_rows (ds->datasheet, posn, &cc, 1);
591
592   if ( result )
593     g_signal_emit (ds, signals [CASE_INSERTED], 0, posn);
594   else
595     g_warning ("Cannot insert case at position %ld\n", posn);
596
597   return result;
598 }
599
600
601 /* Set the value of VAR in case CASENUM to V.
602    V must be the correct width for IDX.
603    Returns true if successful, false on I/O error. */
604 gboolean
605 psppire_data_store_set_value (PsppireDataStore *ds, casenumber casenum,
606                               const struct variable *var, const union value *v)
607 {
608   glong n_cases;
609   bool ok;
610
611   g_return_val_if_fail (ds, FALSE);
612   g_return_val_if_fail (ds->datasheet, FALSE);
613
614   n_cases = psppire_data_store_get_case_count (ds);
615   if ( casenum > n_cases)
616     return FALSE;
617
618   if (casenum == n_cases)
619     psppire_data_store_insert_new_case (ds, casenum);
620
621   ok = datasheet_put_value (ds->datasheet, casenum, var_get_case_index (var),
622                             v);
623   if (ok)
624     g_signal_emit (ds, signals [CASE_CHANGED], 0, casenum);
625
626   return ok;
627 }
628
629
630
631
632 /* Set the IDXth value of case C using D_IN */
633 static gboolean
634 psppire_data_store_data_in (PsppireDataStore *ds, casenumber casenum, gint idx,
635                             struct substring input, const struct fmt_spec *fmt)
636 {
637   union value value;
638   int width;
639   bool ok;
640
641   PsppireDict *dict;
642
643   g_return_val_if_fail (ds, FALSE);
644   g_return_val_if_fail (ds->datasheet, FALSE);
645
646   g_return_val_if_fail (idx < datasheet_get_n_columns (ds->datasheet), FALSE);
647
648   dict = ds->dict;
649
650   width = fmt_var_width (fmt);
651   g_return_val_if_fail (caseproto_get_width (
652                           datasheet_get_proto (ds->datasheet), idx) == width,
653                         FALSE);
654   value_init (&value, width);
655   ok = (datasheet_get_value (ds->datasheet, casenum, idx, &value)
656         && data_in_msg (input, UTF8, fmt->type, &value, width,
657                         dict_get_encoding (dict->dict))
658         && datasheet_put_value (ds->datasheet, casenum, idx, &value));
659   value_destroy (&value, width);
660
661   return ok;
662 }
663
664 /* Resize the cases in the casefile, by inserting a value of the
665    given WIDTH into every one of them at the position immediately
666    preceding WHERE.
667 */
668 static gboolean
669 psppire_data_store_insert_value (PsppireDataStore *ds,
670                                  gint width, gint where)
671 {
672   union value value;
673
674   g_return_val_if_fail (ds, FALSE);
675
676   g_assert (width >= 0);
677
678   if ( ! ds->datasheet )
679     ds->datasheet = datasheet_create (NULL);
680
681   value_init (&value, width);
682   value_set_missing (&value, width);
683
684   datasheet_insert_column (ds->datasheet, &value, width, where);
685   value_destroy (&value, width);
686
687   return TRUE;
688 }
689
690 gboolean
691 psppire_data_store_filtered (PsppireDataStore *ds,
692                              glong row)
693 {
694   union value val;
695
696   const struct dictionary *dict;
697   const struct variable *filter;
698
699   if ( row < 0 || row >= datasheet_get_n_rows (ds->datasheet))
700     return FALSE;
701
702   dict = ds->dict->dict;
703   g_return_val_if_fail (dict, FALSE);
704   filter = dict_get_filter (dict);
705   if ( ! filter)
706     return FALSE;
707
708   g_return_val_if_fail (var_is_numeric (filter), FALSE);
709   value_init (&val, 0);
710   if ( ! datasheet_get_value (ds->datasheet, row,
711                               var_get_case_index (filter),
712                               &val) )
713     return FALSE;
714
715   return (val.f == 0.0);
716 }