Merge remote-tracking branch 'origin/master' into gtk3
[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  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
209   datasheet_delete_columns (store->datasheet, case_index, 1);
210   datasheet_insert_column (store->datasheet, NULL, -1, case_index);
211 }
212
213 struct resize_datum_aux
214   {
215     const struct dictionary *dict;
216     const struct variable *new_variable;
217     const struct variable *old_variable;
218   };
219
220 static void
221 resize_datum (const union value *old, union value *new, const void *aux_)
222 {
223   const struct resize_datum_aux *aux = aux_;
224   int new_width = var_get_width (aux->new_variable);
225   const char *enc = dict_get_encoding (aux->dict);
226   const struct fmt_spec *newfmt = var_get_print_format (aux->new_variable);
227   char *s = data_out (old, enc, var_get_print_format (aux->old_variable));
228   free (data_in (ss_cstr (s), enc, newfmt->type, new, new_width, enc));
229   free (s);
230 }
231
232 static void
233 variable_changed_callback (GObject *obj, gint var_num, guint what, const struct variable *oldvar,
234                            gpointer data)
235 {
236   PsppireDataStore *store  = PSPPIRE_DATA_STORE (data);
237   struct variable *variable = psppire_dict_get_variable (store->dict, var_num);
238
239   if (what & VAR_TRAIT_WIDTH)
240     {
241       int posn = var_get_case_index (variable);
242       struct resize_datum_aux aux;
243       aux.old_variable = oldvar;
244       aux.new_variable = variable;
245       aux.dict = store->dict->dict;
246       datasheet_resize_column (store->datasheet, posn, var_get_width (variable),
247                                resize_datum, &aux);
248     }
249 }
250
251 static void
252 insert_variable_callback (GObject *obj, gint var_num, gpointer data)
253 {
254   struct variable *variable;
255   PsppireDataStore *store;
256   gint posn;
257
258   g_return_if_fail (data);
259
260   store  = PSPPIRE_DATA_STORE (data);
261
262   variable = psppire_dict_get_variable (store->dict, var_num);
263   posn = var_get_case_index (variable);
264   psppire_data_store_insert_value (store, var_get_width (variable), posn);
265 }
266
267 /**
268  * psppire_data_store_new:
269  * @dict: The dictionary for this data_store.
270  *
271  *
272  * Return value: a new #PsppireDataStore
273  **/
274 PsppireDataStore *
275 psppire_data_store_new (PsppireDict *dict)
276 {
277   PsppireDataStore *retval;
278
279   retval = g_object_new (PSPPIRE_TYPE_DATA_STORE, NULL);
280
281   psppire_data_store_set_dictionary (retval, dict);
282
283   return retval;
284 }
285
286 void
287 psppire_data_store_set_reader (PsppireDataStore *ds,
288                                struct casereader *reader)
289 {
290   gint i;
291
292   if ( ds->datasheet)
293     datasheet_destroy (ds->datasheet);
294
295   ds->datasheet = datasheet_create (reader);
296
297   if ( ds->dict )
298     for (i = 0 ; i < n_dict_signals; ++i )
299       {
300         if ( ds->dict_handler_id [i] > 0)
301           {
302             g_signal_handler_unblock (ds->dict,
303                                       ds->dict_handler_id[i]);
304           }
305       }
306
307   g_signal_emit (ds, signals[BACKEND_CHANGED], 0);
308 }
309
310
311 /**
312  * psppire_data_store_replace_set_dictionary:
313  * @data_store: The variable store
314  * @dict: The dictionary to set
315  *
316  * If a dictionary is already associated with the data-store, then it will be
317  * destroyed.
318  **/
319 void
320 psppire_data_store_set_dictionary (PsppireDataStore *data_store, PsppireDict *dict)
321 {
322   int i;
323
324   /* Disconnect any existing handlers */
325   if ( data_store->dict )
326     for (i = 0 ; i < n_dict_signals; ++i )
327       {
328         g_signal_handler_disconnect (data_store->dict,
329                                      data_store->dict_handler_id[i]);
330       }
331
332   data_store->dict = dict;
333
334   if ( dict != NULL)
335     {
336
337       data_store->dict_handler_id [VARIABLE_INSERTED] =
338         g_signal_connect (dict, "variable-inserted",
339                           G_CALLBACK (insert_variable_callback),
340                           data_store);
341
342       data_store->dict_handler_id [VARIABLE_DELETED] =
343         g_signal_connect (dict, "variable-deleted",
344                           G_CALLBACK (delete_variable_callback),
345                           data_store);
346
347       data_store->dict_handler_id [VARIABLE_CHANGED] =
348         g_signal_connect (dict, "variable-changed",
349                           G_CALLBACK (variable_changed_callback),
350                           data_store);
351     }
352
353
354
355   /* The entire model has changed */
356
357   if ( data_store->dict )
358     for (i = 0 ; i < n_dict_signals; ++i )
359       {
360         if ( data_store->dict_handler_id [i] > 0)
361           {
362             g_signal_handler_block (data_store->dict,
363                                     data_store->dict_handler_id[i]);
364           }
365       }
366 }
367
368 static void
369 psppire_data_store_finalize (GObject *object)
370 {
371   PsppireDataStore *ds = PSPPIRE_DATA_STORE (object);
372
373   if (ds->datasheet)
374     {
375       datasheet_destroy (ds->datasheet);
376       ds->datasheet = NULL;
377     }
378
379   /* must chain up */
380   (* parent_class->finalize) (object);
381 }
382
383
384 static void
385 psppire_data_store_dispose (GObject *object)
386 {
387   PsppireDataStore *ds = PSPPIRE_DATA_STORE (object);
388
389   if (ds->dispose_has_run)
390     return;
391
392
393   /* must chain up */
394   (* parent_class->dispose) (object);
395
396   ds->dispose_has_run = TRUE;
397 }
398
399
400
401 /* Insert a blank case before POSN */
402 gboolean
403 psppire_data_store_insert_new_case (PsppireDataStore *ds, casenumber posn)
404 {
405   gboolean result;
406   const struct caseproto *proto;
407   struct ccase *cc;
408   g_return_val_if_fail (ds, FALSE);
409
410   proto = datasheet_get_proto (ds->datasheet);
411   g_return_val_if_fail (caseproto_get_n_widths (proto) > 0, FALSE);
412   g_return_val_if_fail (posn <= psppire_data_store_get_case_count (ds), FALSE);
413
414   cc = case_create (proto);
415   case_set_missing (cc);
416
417   result = psppire_data_store_insert_case (ds, cc, posn);
418
419   case_unref (cc);
420
421   return result;
422 }
423
424 gchar *
425 psppire_data_store_get_string (PsppireDataStore *store,
426                                glong row, const struct variable *var,
427                                bool use_value_label)
428 {
429   gchar *string;
430   union value v;
431   int width;
432
433   g_return_val_if_fail (store != NULL, NULL);
434   g_return_val_if_fail (var != NULL, NULL);
435
436   if (row < 0 || row >= datasheet_get_n_rows (store->datasheet))
437     return NULL;
438
439   width = var_get_width (var);
440   value_init (&v, width);
441   datasheet_get_value (store->datasheet, row, var_get_case_index (var), &v);
442
443   string = NULL;
444   if (use_value_label)
445     {
446       const char *label = var_lookup_value_label (var, &v);
447       if (label != NULL)
448         string = g_strdup (label);
449     }
450   if (string == NULL)
451     string = value_to_text (v, var);
452
453   value_destroy (&v, width);
454
455   return string;
456 }
457
458
459 /* Attempts to update that part of the variable store which corresponds to VAR
460    within ROW with the value TEXT.
461
462    If USE_VALUE_LABEL is true, and TEXT is a value label for the column's
463    variable, then stores the value from that value label instead of the literal
464    TEXT.
465
466    Returns true if anything was updated, false otherwise.  */
467 gboolean
468 psppire_data_store_set_string (PsppireDataStore *store,
469                                const gchar *text,
470                                glong row, const struct variable *var,
471                                gboolean use_value_label)
472 {
473   gint case_index;
474   glong n_cases;
475   gboolean ok;
476
477   n_cases = psppire_data_store_get_case_count (store);
478   if (row > n_cases)
479     return FALSE;
480   if (row == n_cases)
481     psppire_data_store_insert_new_case (store, row);
482
483   case_index = var_get_case_index (var);
484   if (use_value_label)
485     {
486       const struct val_labs *vls = var_get_value_labels (var);
487       const union value *value = vls ? val_labs_find_value (vls, text) : NULL;
488       if (value)
489         ok = datasheet_put_value (store->datasheet, row, case_index, value);
490       else
491         ok = FALSE;
492     }
493   else
494     ok = psppire_data_store_data_in (store, row, case_index, ss_cstr (text),
495                                      var_get_print_format (var));
496
497   if (ok)
498     g_signal_emit (store, signals [CASE_CHANGED], 0, row);
499   return ok;
500 }
501
502
503
504 void
505 psppire_data_store_clear (PsppireDataStore *ds)
506 {
507   datasheet_destroy (ds->datasheet);
508   ds->datasheet = NULL;
509
510   psppire_dict_clear (ds->dict);
511
512   g_signal_emit (ds, signals [CASES_DELETED], 0, 0, -1);
513 }
514
515
516
517 /* Return a casereader made from this datastore */
518 struct casereader *
519 psppire_data_store_get_reader (PsppireDataStore *ds)
520 {
521   int i;
522   struct casereader *reader ;
523
524   if ( ds->dict )
525     for (i = 0 ; i < n_dict_signals; ++i )
526       {
527         g_signal_handler_block (ds->dict,
528                                 ds->dict_handler_id[i]);
529       }
530
531   reader = datasheet_make_reader (ds->datasheet);
532
533   /* We must not reference this again */
534   ds->datasheet = NULL;
535
536   return reader;
537 }
538
539
540
541 /* Column related funcs */
542
543
544 static const gchar null_var_name[]=N_("var");
545
546
547 \f
548
549
550 /* Returns the CASENUMth case, or a null pointer on failure.
551  */
552 struct ccase *
553 psppire_data_store_get_case (const PsppireDataStore *ds,
554                              casenumber casenum)
555 {
556   g_return_val_if_fail (ds, FALSE);
557   g_return_val_if_fail (ds->datasheet, FALSE);
558
559   return datasheet_get_row (ds->datasheet, casenum);
560 }
561
562
563 gboolean
564 psppire_data_store_delete_cases (PsppireDataStore *ds, casenumber first,
565                                  casenumber n_cases)
566 {
567   g_return_val_if_fail (ds, FALSE);
568   g_return_val_if_fail (ds->datasheet, FALSE);
569
570   g_return_val_if_fail (first + n_cases <=
571                         psppire_data_store_get_case_count (ds), FALSE);
572
573
574   datasheet_delete_rows (ds->datasheet, first, n_cases);
575
576   g_signal_emit (ds, signals [CASES_DELETED], 0, first, n_cases);
577
578   return TRUE;
579 }
580
581
582
583 /* Insert case CC into the case file before POSN */
584 static gboolean
585 psppire_data_store_insert_case (PsppireDataStore *ds,
586                                 struct ccase *cc,
587                                 casenumber posn)
588 {
589   bool result ;
590
591   g_return_val_if_fail (ds, FALSE);
592   g_return_val_if_fail (ds->datasheet, FALSE);
593
594   cc = case_ref (cc);
595   result = datasheet_insert_rows (ds->datasheet, posn, &cc, 1);
596
597   if ( result )
598     g_signal_emit (ds, signals [CASE_INSERTED], 0, posn);
599   else
600     g_warning ("Cannot insert case at position %ld\n", posn);
601
602   return result;
603 }
604
605
606 /* Set the value of VAR in case CASENUM to V.
607    V must be the correct width for IDX.
608    Returns true if successful, false on I/O error. */
609 gboolean
610 psppire_data_store_set_value (PsppireDataStore *ds, casenumber casenum,
611                               const struct variable *var, const union value *v)
612 {
613   glong n_cases;
614   bool ok;
615
616   g_return_val_if_fail (ds, FALSE);
617   g_return_val_if_fail (ds->datasheet, FALSE);
618
619   n_cases = psppire_data_store_get_case_count (ds);
620   if ( casenum > n_cases)
621     return FALSE;
622
623   if (casenum == n_cases)
624     psppire_data_store_insert_new_case (ds, casenum);
625
626   ok = datasheet_put_value (ds->datasheet, casenum, var_get_case_index (var),
627                             v);
628   if (ok)
629     g_signal_emit (ds, signals [CASE_CHANGED], 0, casenum);
630
631   return ok;
632 }
633
634
635
636
637 /* Set the IDXth value of case C using D_IN */
638 static gboolean
639 psppire_data_store_data_in (PsppireDataStore *ds, casenumber casenum, gint idx,
640                             struct substring input, const struct fmt_spec *fmt)
641 {
642   union value value;
643   int width;
644   bool ok;
645
646   PsppireDict *dict;
647
648   g_return_val_if_fail (ds, FALSE);
649   g_return_val_if_fail (ds->datasheet, FALSE);
650
651   g_return_val_if_fail (idx < datasheet_get_n_columns (ds->datasheet), FALSE);
652
653   dict = ds->dict;
654
655   width = fmt_var_width (fmt);
656   g_return_val_if_fail (caseproto_get_width (
657                           datasheet_get_proto (ds->datasheet), idx) == width,
658                         FALSE);
659   value_init (&value, width);
660   ok = (datasheet_get_value (ds->datasheet, casenum, idx, &value)
661         && data_in_msg (input, UTF8, fmt->type, &value, width,
662                         dict_get_encoding (dict->dict))
663         && datasheet_put_value (ds->datasheet, casenum, idx, &value));
664   value_destroy (&value, width);
665
666   return ok;
667 }
668
669 /* Resize the cases in the casefile, by inserting a value of the
670    given WIDTH into every one of them at the position immediately
671    preceding WHERE.
672 */
673 static gboolean
674 psppire_data_store_insert_value (PsppireDataStore *ds,
675                                  gint width, gint where)
676 {
677   union value value;
678
679   g_return_val_if_fail (ds, FALSE);
680
681   g_assert (width >= 0);
682
683   if ( ! ds->datasheet )
684     ds->datasheet = datasheet_create (NULL);
685
686   value_init (&value, width);
687   value_set_missing (&value, width);
688
689   datasheet_insert_column (ds->datasheet, &value, width, where);
690   value_destroy (&value, width);
691
692   return TRUE;
693 }
694
695 gboolean
696 psppire_data_store_filtered (PsppireDataStore *ds,
697                              glong row)
698 {
699   union value val;
700
701   const struct dictionary *dict;
702   const struct variable *filter;
703
704   if ( row < 0 || row >= datasheet_get_n_rows (ds->datasheet))
705     return FALSE;
706
707   dict = ds->dict->dict;
708   g_return_val_if_fail (dict, FALSE);
709   filter = dict_get_filter (dict);
710   if ( ! filter)
711     return FALSE;
712
713   g_return_val_if_fail (var_is_numeric (filter), FALSE);
714   value_init (&val, 0);
715   if ( ! datasheet_get_value (ds->datasheet, row,
716                               var_get_case_index (filter),
717                               &val) )
718     return FALSE;
719
720   return (val.f == 0.0);
721 }