psppire-data-store: Don't try to parse strings as custom currency formats.
[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   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
546
547 /* Column related funcs */
548
549
550 static const gchar null_var_name[]=N_("var");
551
552
553 \f
554
555
556 /* Returns the CASENUMth case, or a null pointer on failure.
557  */
558 struct ccase *
559 psppire_data_store_get_case (const PsppireDataStore *ds,
560                              casenumber casenum)
561 {
562   g_return_val_if_fail (ds, FALSE);
563   g_return_val_if_fail (ds->datasheet, FALSE);
564
565   return datasheet_get_row (ds->datasheet, casenum);
566 }
567
568
569 gboolean
570 psppire_data_store_delete_cases (PsppireDataStore *ds, casenumber first,
571                                  casenumber n_cases)
572 {
573   g_return_val_if_fail (ds, FALSE);
574   g_return_val_if_fail (ds->datasheet, FALSE);
575
576   g_return_val_if_fail (first + n_cases <=
577                         psppire_data_store_get_case_count (ds), FALSE);
578
579
580   datasheet_delete_rows (ds->datasheet, first, n_cases);
581
582   g_signal_emit (ds, signals [CASES_DELETED], 0, first, n_cases);
583
584   return TRUE;
585 }
586
587
588
589 /* Insert case CC into the case file before POSN */
590 static gboolean
591 psppire_data_store_insert_case (PsppireDataStore *ds,
592                                 struct ccase *cc,
593                                 casenumber posn)
594 {
595   bool result ;
596
597   g_return_val_if_fail (ds, FALSE);
598   g_return_val_if_fail (ds->datasheet, FALSE);
599
600   cc = case_ref (cc);
601   result = datasheet_insert_rows (ds->datasheet, posn, &cc, 1);
602
603   if ( result )
604     g_signal_emit (ds, signals [CASE_INSERTED], 0, posn);
605   else
606     g_warning ("Cannot insert case at position %ld\n", posn);
607
608   return result;
609 }
610
611
612 /* Set the value of VAR in case CASENUM to V.
613    V must be the correct width for IDX.
614    Returns true if successful, false on I/O error. */
615 gboolean
616 psppire_data_store_set_value (PsppireDataStore *ds, casenumber casenum,
617                               const struct variable *var, const union value *v)
618 {
619   glong n_cases;
620   bool ok;
621
622   g_return_val_if_fail (ds, FALSE);
623   g_return_val_if_fail (ds->datasheet, FALSE);
624
625   n_cases = psppire_data_store_get_case_count (ds);
626   if ( casenum > n_cases)
627     return FALSE;
628
629   if (casenum == n_cases)
630     psppire_data_store_insert_new_case (ds, casenum);
631
632   ok = datasheet_put_value (ds->datasheet, casenum, var_get_case_index (var),
633                             v);
634   if (ok)
635     g_signal_emit (ds, signals [CASE_CHANGED], 0, casenum);
636
637   return ok;
638 }
639
640
641
642
643 /* Set the IDXth value of case C using D_IN */
644 static gboolean
645 psppire_data_store_data_in (PsppireDataStore *ds, casenumber casenum, gint idx,
646                             struct substring input, const struct fmt_spec *fmt)
647 {
648   union value value;
649   int width;
650   bool ok;
651
652   PsppireDict *dict;
653
654   g_return_val_if_fail (ds, FALSE);
655   g_return_val_if_fail (ds->datasheet, FALSE);
656
657   g_return_val_if_fail (idx < datasheet_get_n_columns (ds->datasheet), FALSE);
658
659   dict = ds->dict;
660
661   width = fmt_var_width (fmt);
662   g_return_val_if_fail (caseproto_get_width (
663                           datasheet_get_proto (ds->datasheet), idx) == width,
664                         FALSE);
665   value_init (&value, width);
666   ok = (datasheet_get_value (ds->datasheet, casenum, idx, &value)
667         && data_in_msg (input, UTF8, fmt->type, &value, width,
668                         dict_get_encoding (dict->dict))
669         && datasheet_put_value (ds->datasheet, casenum, idx, &value));
670   value_destroy (&value, width);
671
672   return ok;
673 }
674
675 /* Resize the cases in the casefile, by inserting a value of the
676    given WIDTH into every one of them at the position immediately
677    preceding WHERE.
678 */
679 static gboolean
680 psppire_data_store_insert_value (PsppireDataStore *ds,
681                                  gint width, gint where)
682 {
683   union value value;
684
685   g_return_val_if_fail (ds, FALSE);
686
687   g_assert (width >= 0);
688
689   if ( ! ds->datasheet )
690     ds->datasheet = datasheet_create (NULL);
691
692   value_init (&value, width);
693   value_set_missing (&value, width);
694
695   datasheet_insert_column (ds->datasheet, &value, width, where);
696   value_destroy (&value, width);
697
698   return TRUE;
699 }
700
701 gboolean
702 psppire_data_store_filtered (PsppireDataStore *ds,
703                              glong row)
704 {
705   union value val;
706
707   const struct dictionary *dict;
708   const struct variable *filter;
709
710   if ( row < 0 || row >= datasheet_get_n_rows (ds->datasheet))
711     return FALSE;
712
713   dict = ds->dict->dict;
714   g_return_val_if_fail (dict, FALSE);
715   filter = dict_get_filter (dict);
716   if ( ! filter)
717     return FALSE;
718
719   g_return_val_if_fail (var_is_numeric (filter), FALSE);
720   value_init (&val, 0);
721   if ( ! datasheet_get_value (ds->datasheet, row,
722                               var_get_case_index (filter),
723                               &val) )
724     return FALSE;
725
726   return (val.f == 0.0);
727 }