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