gui: Avoid referencing freed data upon closing data window.
[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  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   psppire_data_store_set_dictionary (ds, NULL);
394
395   /* must chain up */
396   (* parent_class->dispose) (object);
397
398   ds->dispose_has_run = TRUE;
399 }
400
401
402
403 /* Insert a blank case before POSN */
404 gboolean
405 psppire_data_store_insert_new_case (PsppireDataStore *ds, casenumber posn)
406 {
407   gboolean result;
408   const struct caseproto *proto;
409   struct ccase *cc;
410   g_return_val_if_fail (ds, FALSE);
411
412   proto = datasheet_get_proto (ds->datasheet);
413   g_return_val_if_fail (caseproto_get_n_widths (proto) > 0, FALSE);
414   g_return_val_if_fail (posn <= psppire_data_store_get_case_count (ds), FALSE);
415
416   cc = case_create (proto);
417   case_set_missing (cc);
418
419   result = psppire_data_store_insert_case (ds, cc, posn);
420
421   case_unref (cc);
422
423   return result;
424 }
425
426 gchar *
427 psppire_data_store_get_string (PsppireDataStore *store,
428                                glong row, const struct variable *var,
429                                bool use_value_label)
430 {
431   gchar *string;
432   union value v;
433   int width;
434
435   g_return_val_if_fail (store != NULL, NULL);
436   g_return_val_if_fail (store->datasheet != NULL, NULL);
437   g_return_val_if_fail (var != NULL, NULL);
438
439   if (row < 0 || row >= datasheet_get_n_rows (store->datasheet))
440     return NULL;
441
442   width = var_get_width (var);
443   value_init (&v, width);
444   datasheet_get_value (store->datasheet, row, var_get_case_index (var), &v);
445
446   string = NULL;
447   if (use_value_label)
448     {
449       const char *label = var_lookup_value_label (var, &v);
450       if (label != NULL)
451         string = g_strdup (label);
452     }
453   if (string == NULL)
454     string = value_to_text (v, var);
455
456   value_destroy (&v, width);
457
458   return string;
459 }
460
461
462 /* Attempts to update that part of the variable store which corresponds to VAR
463    within ROW with the value TEXT.
464
465    If USE_VALUE_LABEL is true, and TEXT is a value label for the column's
466    variable, then stores the value from that value label instead of the literal
467    TEXT.
468
469    Returns true if anything was updated, false otherwise.  */
470 gboolean
471 psppire_data_store_set_string (PsppireDataStore *store,
472                                const gchar *text,
473                                glong row, const struct variable *var,
474                                gboolean use_value_label)
475 {
476   gint case_index;
477   glong n_cases;
478   gboolean ok;
479
480   n_cases = psppire_data_store_get_case_count (store);
481   if (row > n_cases)
482     return FALSE;
483   if (row == n_cases)
484     psppire_data_store_insert_new_case (store, row);
485
486   case_index = var_get_case_index (var);
487   if (use_value_label)
488     {
489       const struct val_labs *vls = var_get_value_labels (var);
490       const union value *value = vls ? val_labs_find_value (vls, text) : NULL;
491       if (value)
492         ok = datasheet_put_value (store->datasheet, row, case_index, value);
493       else
494         ok = FALSE;
495     }
496   else
497     ok = psppire_data_store_data_in (store, row, case_index, ss_cstr (text),
498                                      var_get_print_format (var));
499
500   if (ok)
501     g_signal_emit (store, signals [CASE_CHANGED], 0, row);
502   return ok;
503 }
504
505
506
507 void
508 psppire_data_store_clear (PsppireDataStore *ds)
509 {
510   datasheet_destroy (ds->datasheet);
511   ds->datasheet = NULL;
512
513   psppire_dict_clear (ds->dict);
514
515   g_signal_emit (ds, signals [CASES_DELETED], 0, 0, -1);
516 }
517
518
519
520 /* Return a casereader made from this datastore */
521 struct casereader *
522 psppire_data_store_get_reader (PsppireDataStore *ds)
523 {
524   int i;
525   struct casereader *reader ;
526
527   if ( ds->dict )
528     for (i = 0 ; i < n_dict_signals; ++i )
529       {
530         g_signal_handler_block (ds->dict,
531                                 ds->dict_handler_id[i]);
532       }
533
534   reader = datasheet_make_reader (ds->datasheet);
535
536   /* We must not reference this again */
537   ds->datasheet = NULL;
538
539   return reader;
540 }
541
542
543
544 /* Column related funcs */
545
546
547 static const gchar null_var_name[]=N_("var");
548
549
550 \f
551
552
553 /* Returns the CASENUMth case, or a null pointer on failure.
554  */
555 struct ccase *
556 psppire_data_store_get_case (const PsppireDataStore *ds,
557                              casenumber casenum)
558 {
559   g_return_val_if_fail (ds, FALSE);
560   g_return_val_if_fail (ds->datasheet, FALSE);
561
562   return datasheet_get_row (ds->datasheet, casenum);
563 }
564
565
566 gboolean
567 psppire_data_store_delete_cases (PsppireDataStore *ds, casenumber first,
568                                  casenumber n_cases)
569 {
570   g_return_val_if_fail (ds, FALSE);
571   g_return_val_if_fail (ds->datasheet, FALSE);
572
573   g_return_val_if_fail (first + n_cases <=
574                         psppire_data_store_get_case_count (ds), FALSE);
575
576
577   datasheet_delete_rows (ds->datasheet, first, n_cases);
578
579   g_signal_emit (ds, signals [CASES_DELETED], 0, first, n_cases);
580
581   return TRUE;
582 }
583
584
585
586 /* Insert case CC into the case file before POSN */
587 static gboolean
588 psppire_data_store_insert_case (PsppireDataStore *ds,
589                                 struct ccase *cc,
590                                 casenumber posn)
591 {
592   bool result ;
593
594   g_return_val_if_fail (ds, FALSE);
595   g_return_val_if_fail (ds->datasheet, FALSE);
596
597   cc = case_ref (cc);
598   result = datasheet_insert_rows (ds->datasheet, posn, &cc, 1);
599
600   if ( result )
601     g_signal_emit (ds, signals [CASE_INSERTED], 0, posn);
602   else
603     g_warning ("Cannot insert case at position %ld\n", posn);
604
605   return result;
606 }
607
608
609 /* Set the value of VAR in case CASENUM to V.
610    V must be the correct width for IDX.
611    Returns true if successful, false on I/O error. */
612 gboolean
613 psppire_data_store_set_value (PsppireDataStore *ds, casenumber casenum,
614                               const struct variable *var, const union value *v)
615 {
616   glong n_cases;
617   bool ok;
618
619   g_return_val_if_fail (ds, FALSE);
620   g_return_val_if_fail (ds->datasheet, FALSE);
621
622   n_cases = psppire_data_store_get_case_count (ds);
623   if ( casenum > n_cases)
624     return FALSE;
625
626   if (casenum == n_cases)
627     psppire_data_store_insert_new_case (ds, casenum);
628
629   ok = datasheet_put_value (ds->datasheet, casenum, var_get_case_index (var),
630                             v);
631   if (ok)
632     g_signal_emit (ds, signals [CASE_CHANGED], 0, casenum);
633
634   return ok;
635 }
636
637
638
639
640 /* Set the IDXth value of case C using D_IN */
641 static gboolean
642 psppire_data_store_data_in (PsppireDataStore *ds, casenumber casenum, gint idx,
643                             struct substring input, const struct fmt_spec *fmt)
644 {
645   union value value;
646   int width;
647   bool ok;
648
649   PsppireDict *dict;
650
651   g_return_val_if_fail (ds, FALSE);
652   g_return_val_if_fail (ds->datasheet, FALSE);
653
654   g_return_val_if_fail (idx < datasheet_get_n_columns (ds->datasheet), FALSE);
655
656   dict = ds->dict;
657
658   width = fmt_var_width (fmt);
659   g_return_val_if_fail (caseproto_get_width (
660                           datasheet_get_proto (ds->datasheet), idx) == width,
661                         FALSE);
662   value_init (&value, width);
663   ok = (datasheet_get_value (ds->datasheet, casenum, idx, &value)
664         && data_in_msg (input, UTF8, fmt->type, &value, width,
665                         dict_get_encoding (dict->dict))
666         && datasheet_put_value (ds->datasheet, casenum, idx, &value));
667   value_destroy (&value, width);
668
669   return ok;
670 }
671
672 /* Resize the cases in the casefile, by inserting a value of the
673    given WIDTH into every one of them at the position immediately
674    preceding WHERE.
675 */
676 static gboolean
677 psppire_data_store_insert_value (PsppireDataStore *ds,
678                                  gint width, gint where)
679 {
680   union value value;
681
682   g_return_val_if_fail (ds, FALSE);
683
684   g_assert (width >= 0);
685
686   if ( ! ds->datasheet )
687     ds->datasheet = datasheet_create (NULL);
688
689   value_init (&value, width);
690   value_set_missing (&value, width);
691
692   datasheet_insert_column (ds->datasheet, &value, width, where);
693   value_destroy (&value, width);
694
695   return TRUE;
696 }
697
698 gboolean
699 psppire_data_store_filtered (PsppireDataStore *ds,
700                              glong row)
701 {
702   union value val;
703
704   const struct dictionary *dict;
705   const struct variable *filter;
706
707   if ( row < 0 || row >= datasheet_get_n_rows (ds->datasheet))
708     return FALSE;
709
710   dict = ds->dict->dict;
711   g_return_val_if_fail (dict, FALSE);
712   filter = dict_get_filter (dict);
713   if ( ! filter)
714     return FALSE;
715
716   g_return_val_if_fail (var_is_numeric (filter), FALSE);
717   value_init (&val, 0);
718   if ( ! datasheet_get_value (ds->datasheet, row,
719                               var_get_case_index (filter),
720                               &val) )
721     return FALSE;
722
723   return (val.f == 0.0);
724 }