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