Revert "Fixed a use after free error when manipulating datasets."
[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,
3    2013, 2016, 2017  Free Software Foundation
4
5    This program is free software: you can redistribute it and/or modify
6    it under the terms of the GNU General Public License as published by
7    the Free Software Foundation, either version 3 of the License, or
8    (at your option) any later version.
9
10    This program is distributed in the hope that it will be useful,
11    but WITHOUT ANY WARRANTY; without even the implied warranty of
12    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13    GNU General Public License for more details.
14
15    You should have received a copy of the GNU General Public License
16    along with this program.  If not, see <http://www.gnu.org/licenses/>. */
17
18 #include <config.h>
19 #include <string.h>
20 #include <stdlib.h>
21 #include <gettext.h>
22 #define _(msgid) gettext (msgid)
23 #define P_(msgid) msgid
24
25 #include <data/datasheet.h>
26 #include <data/data-out.h>
27 #include <data/variable.h>
28
29 #include <ui/gui/psppire-marshal.h>
30
31 #include <pango/pango-context.h>
32
33 #include "psppire-data-store.h"
34 #include <libpspp/i18n.h>
35 #include "helper.h"
36
37 #include <data/dictionary.h>
38 #include <data/missing-values.h>
39 #include <data/value-labels.h>
40 #include <data/data-in.h>
41 #include <data/format.h>
42
43 #include <math/sort.h>
44
45 #include "xmalloca.h"
46
47 #include "value-variant.h"
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     ITEMS_CHANGED,
71     CASE_CHANGED,
72     n_SIGNALS
73   };
74
75 static guint signals [n_SIGNALS];
76
77 static gint
78 __tree_model_iter_n_children (GtkTreeModel *tree_model,
79                              GtkTreeIter *iter)
80 {
81   PsppireDataStore *store  = PSPPIRE_DATA_STORE (tree_model);
82
83   if (store->datasheet == NULL)
84     return 0;
85
86   gint n =  datasheet_get_n_rows (store->datasheet);
87
88   return n;
89 }
90
91 static GtkTreeModelFlags
92 __tree_model_get_flags (GtkTreeModel *model)
93 {
94   g_return_val_if_fail (PSPPIRE_IS_DATA_STORE (model), (GtkTreeModelFlags) 0);
95
96   return GTK_TREE_MODEL_LIST_ONLY;
97 }
98
99 static gint
100 __tree_model_get_n_columns (GtkTreeModel *tree_model)
101 {
102   PsppireDataStore *store  = PSPPIRE_DATA_STORE (tree_model);
103
104   return psppire_dict_get_var_cnt (store->dict);
105 }
106
107
108 static gboolean
109 __iter_nth_child (GtkTreeModel *tree_model,
110                   GtkTreeIter *iter,
111                   GtkTreeIter *parent,
112                   gint n)
113 {
114   PsppireDataStore *store  = PSPPIRE_DATA_STORE (tree_model);
115
116   g_assert (parent == NULL);
117   g_return_val_if_fail (store, FALSE);
118
119   if (!store->datasheet || n >= datasheet_get_n_rows (store->datasheet))
120     {
121       iter->stamp = -1;
122       iter->user_data = NULL;
123       return FALSE;
124     }
125
126   iter->user_data = GINT_TO_POINTER (n);
127   iter->stamp = store->stamp;
128
129   return TRUE;
130 }
131
132 /* Set the contents of OUT to reflect the information provided by IN, COL, and
133    ROW, for MODEL.  Returns TRUE if successful. */
134 gboolean
135 psppire_data_store_string_to_value (GtkTreeModel *model, gint col, gint row,
136                                     const gchar *in, GValue *out)
137 {
138   PsppireDataStore *store = PSPPIRE_DATA_STORE (model);
139
140   while (col >= psppire_dict_get_var_cnt (store->dict))
141     {
142       const struct variable *var =
143         psppire_dict_insert_variable (store->dict,
144                                       psppire_dict_get_var_cnt (store->dict),
145                                       NULL);
146       g_return_val_if_fail (var, FALSE);
147     }
148
149   const struct variable *variable = psppire_dict_get_variable (store->dict, col);
150   g_return_val_if_fail (variable, FALSE);
151
152   const struct fmt_spec *fmt = var_get_print_format (variable);
153
154   int width = var_get_width (variable);
155
156   union value val;
157   value_init (&val, width);
158   char *xx =
159     data_in (ss_cstr (in), psppire_dict_encoding (store->dict),
160              fmt->type, &val, width, "UTF-8");
161
162   GVariant *vrnt = value_variant_new (&val, width);
163   value_destroy (&val, width);
164
165   g_value_init (out, G_TYPE_VARIANT);
166   g_value_set_variant (out, vrnt);
167   free (xx);
168   return TRUE;
169 }
170
171 static char *
172 unlabeled_value (PsppireDataStore *store, const struct variable *variable, const union value *val)
173 {
174   const struct fmt_spec *fmt = var_get_print_format (variable);
175   return data_out (val, psppire_dict_encoding (store->dict),  fmt);
176 }
177
178 gchar *
179 psppire_data_store_value_to_string (gpointer unused, PsppireDataStore *store, gint col, gint row, const GValue *v)
180 {
181   const struct variable *variable = psppire_dict_get_variable (store->dict, col);
182   g_return_val_if_fail (variable, g_strdup ("???"));
183
184   GVariant *vrnt = g_value_get_variant (v);
185   g_return_val_if_fail (vrnt, g_strdup ("???"));
186
187   union value val;
188   value_variant_get (&val, vrnt);
189
190   char *out = unlabeled_value (store, variable, &val);
191
192   value_destroy_from_variant (&val, vrnt);
193
194   return out;
195 }
196
197 gchar *
198 psppire_data_store_value_to_string_with_labels (gpointer unused, PsppireDataStore *store, gint col, gint row, const GValue *v)
199 {
200   const struct variable *variable = psppire_dict_get_variable (store->dict, col);
201   g_return_val_if_fail (variable, g_strdup ("???"));
202
203   GVariant *vrnt = g_value_get_variant (v);
204   union value val;
205   value_variant_get (&val, vrnt);
206
207   char *out = NULL;
208
209   const struct val_labs *vls = var_get_value_labels (variable);
210   struct val_lab *vl = val_labs_lookup (vls, &val);
211   if (vl != NULL)
212     out = strdup (val_lab_get_label (vl));
213   else
214     out = unlabeled_value (store, variable, &val);
215
216   value_destroy_from_variant (&val, vrnt);
217
218   return out;
219 }
220
221 static void
222 __get_value (GtkTreeModel *tree_model,
223              GtkTreeIter *iter,
224              gint column,
225              GValue *value)
226 {
227   PsppireDataStore *store  = PSPPIRE_DATA_STORE (tree_model);
228
229   g_return_if_fail (iter->stamp == store->stamp);
230
231   const struct variable *variable = psppire_dict_get_variable (store->dict, column);
232   if (NULL == variable)
233     return;
234
235   gint row = GPOINTER_TO_INT (iter->user_data);
236
237   struct ccase *cc = datasheet_get_row (store->datasheet, row);
238
239   g_return_if_fail (cc);
240
241   g_value_init (value, G_TYPE_VARIANT);
242
243   const union value *val = case_data_idx (cc, var_get_case_index (variable));
244
245   GVariant *vv = value_variant_new (val, var_get_width (variable));
246
247   g_value_set_variant (value, vv);
248
249   case_unref (cc);
250 }
251
252
253 static void
254 __tree_model_init (GtkTreeModelIface *iface)
255 {
256   iface->get_flags       = __tree_model_get_flags;
257   iface->get_n_columns   = __tree_model_get_n_columns ;
258   iface->get_column_type = NULL;
259   iface->get_iter        = NULL;
260   iface->iter_next       = NULL;
261   iface->get_path        = NULL;
262   iface->get_value       = __get_value;
263
264   iface->iter_children   = NULL;
265   iface->iter_has_child  = NULL;
266   iface->iter_n_children = __tree_model_iter_n_children;
267   iface->iter_nth_child  = __iter_nth_child;
268   iface->iter_parent     = NULL;
269 }
270
271
272 GType
273 psppire_data_store_get_type (void)
274 {
275   static GType data_store_type = 0;
276
277   if (!data_store_type)
278     {
279       static const GTypeInfo data_store_info =
280       {
281         sizeof (PsppireDataStoreClass),
282         NULL,           /* base_init */
283         NULL,           /* base_finalize */
284         (GClassInitFunc) psppire_data_store_class_init,
285         NULL,           /* class_finalize */
286         NULL,           /* class_data */
287         sizeof (PsppireDataStore),
288         0,
289         (GInstanceInitFunc) psppire_data_store_init,
290       };
291
292       static const GInterfaceInfo tree_model_info = {
293         (GInterfaceInitFunc) __tree_model_init,
294         NULL,
295         NULL
296       };
297
298       data_store_type = g_type_register_static (G_TYPE_OBJECT,
299                                                 "PsppireDataStore",
300                                                 &data_store_info, 0);
301
302       g_type_add_interface_static (data_store_type, GTK_TYPE_TREE_MODEL,
303                                    &tree_model_info);
304     }
305
306   return data_store_type;
307 }
308
309
310 static void
311 psppire_data_store_class_init (PsppireDataStoreClass *class)
312 {
313   GObjectClass *object_class;
314
315   parent_class = g_type_class_peek_parent (class);
316   object_class = (GObjectClass*) class;
317
318   object_class->finalize = psppire_data_store_finalize;
319   object_class->dispose = psppire_data_store_dispose;
320
321   signals [ITEMS_CHANGED] =
322     g_signal_new ("items-changed",
323                   G_TYPE_FROM_CLASS (class),
324                   G_SIGNAL_RUN_FIRST,
325                   0,
326                   NULL, NULL,
327                   psppire_marshal_VOID__UINT_UINT_UINT,
328                   G_TYPE_NONE,
329                   3,
330                   G_TYPE_UINT,  /* Index of the start of the change */
331                   G_TYPE_UINT,  /* The number of items deleted */
332                   G_TYPE_UINT); /* The number of items inserted */
333
334   signals [CASE_CHANGED] =
335     g_signal_new ("case-changed",
336                   G_TYPE_FROM_CLASS (class),
337                   G_SIGNAL_RUN_FIRST,
338                   0,
339                   NULL, NULL,
340                   g_cclosure_marshal_VOID__INT,
341                   G_TYPE_NONE,
342                   1,
343                   G_TYPE_INT);
344 }
345
346
347
348 casenumber
349 psppire_data_store_get_case_count (const PsppireDataStore *store)
350 {
351   return datasheet_get_n_rows (store->datasheet);
352 }
353
354 size_t
355 psppire_data_store_get_value_count (const PsppireDataStore *store)
356 {
357   return psppire_dict_get_value_cnt (store->dict);
358 }
359
360 const struct caseproto *
361 psppire_data_store_get_proto (const PsppireDataStore *store)
362 {
363   return psppire_dict_get_proto (store->dict);
364 }
365
366 static void
367 psppire_data_store_init (PsppireDataStore *data_store)
368 {
369   data_store->dict = NULL;
370   data_store->datasheet = NULL;
371   data_store->dispose_has_run = FALSE;
372   data_store->stamp = g_random_int ();
373 }
374
375
376 static void
377 psppire_data_store_delete_value (PsppireDataStore *store, gint case_index)
378 {
379   g_return_if_fail (store->datasheet);
380   datasheet_delete_columns (store->datasheet, case_index, 1);
381   datasheet_insert_column (store->datasheet, NULL, -1, case_index);
382 }
383
384
385 /*
386    A callback which occurs after a variable has been deleted.
387  */
388 static void
389 delete_variable_callback (GObject *obj, const struct variable *var UNUSED,
390                           gint dict_index, gint case_index,
391                           gpointer data)
392 {
393   PsppireDataStore *store  = PSPPIRE_DATA_STORE (data);
394
395   psppire_data_store_delete_value (store, case_index);
396 }
397
398 struct resize_datum_aux
399   {
400     const struct dictionary *dict;
401     const struct variable *new_variable;
402     const struct variable *old_variable;
403   };
404
405 static void
406 resize_datum (const union value *old, union value *new, const void *aux_)
407 {
408   const struct resize_datum_aux *aux = aux_;
409   int new_width = var_get_width (aux->new_variable);
410   const char *enc = dict_get_encoding (aux->dict);
411   const struct fmt_spec *newfmt = var_get_print_format (aux->new_variable);
412   char *s = data_out (old, enc, var_get_print_format (aux->old_variable));
413   enum fmt_type type = (fmt_usable_for_input (newfmt->type)
414                         ? newfmt->type
415                         : FMT_DOLLAR);
416   free (data_in (ss_cstr (s), enc, type, new, new_width, enc));
417   free (s);
418 }
419
420 static void
421 variable_changed_callback (GObject *obj, gint var_num, guint what, const struct variable *oldvar,
422                            gpointer data)
423 {
424   PsppireDataStore *store  = PSPPIRE_DATA_STORE (data);
425   struct variable *variable = psppire_dict_get_variable (store->dict, var_num);
426
427   if (what & VAR_TRAIT_WIDTH)
428     {
429       int posn = var_get_case_index (variable);
430       struct resize_datum_aux aux;
431       aux.old_variable = oldvar;
432       aux.new_variable = variable;
433       aux.dict = store->dict->dict;
434       datasheet_resize_column (store->datasheet, posn, var_get_width (variable),
435                                resize_datum, &aux);
436     }
437 }
438
439 static void
440 insert_variable_callback (GObject *obj, gint var_num, gpointer data)
441 {
442   struct variable *variable;
443   PsppireDataStore *store;
444   gint posn;
445
446   g_return_if_fail (data);
447
448   store  = PSPPIRE_DATA_STORE (data);
449
450   variable = psppire_dict_get_variable (store->dict, var_num);
451   posn = var_get_case_index (variable);
452   psppire_data_store_insert_value (store, var_get_width (variable), posn);
453 }
454
455 /**
456  * psppire_data_store_new:
457  * @dict: The dictionary for this data_store.
458  *
459  *
460  * Return value: a new #PsppireDataStore
461  **/
462 PsppireDataStore *
463 psppire_data_store_new (PsppireDict *dict)
464 {
465   PsppireDataStore *retval;
466
467   retval = g_object_new (PSPPIRE_TYPE_DATA_STORE, NULL);
468
469   psppire_data_store_set_dictionary (retval, dict);
470
471   return retval;
472 }
473
474 void
475 psppire_data_store_set_reader (PsppireDataStore *ds,
476                                struct casereader *reader)
477 {
478   gint i;
479   gint old_n = 0;
480   if (ds->datasheet)
481     {
482       old_n = datasheet_get_n_rows (ds->datasheet);
483       datasheet_destroy (ds->datasheet);
484     }
485
486   ds->datasheet = datasheet_create (reader);
487
488   gint new_n = datasheet_get_n_rows (ds->datasheet);
489
490   if (ds->dict)
491     for (i = 0 ; i < n_dict_signals; ++i)
492       {
493         if (ds->dict_handler_id [i] > 0)
494           {
495             g_signal_handler_unblock (ds->dict,
496                                       ds->dict_handler_id[i]);
497           }
498       }
499
500   g_signal_emit (ds, signals[ITEMS_CHANGED], 0, 0, old_n, new_n);
501 }
502
503
504 /**
505  * psppire_data_store_replace_set_dictionary:
506  * @data_store: The variable store
507  * @dict: The dictionary to set
508  *
509  * If a dictionary is already associated with the data-store, then it will be
510  * destroyed.
511  **/
512 void
513 psppire_data_store_set_dictionary (PsppireDataStore *data_store, PsppireDict *dict)
514 {
515   int i;
516
517   /* Disconnect any existing handlers */
518   if (data_store->dict)
519     for (i = 0 ; i < n_dict_signals; ++i)
520       {
521         g_signal_handler_disconnect (data_store->dict,
522                                      data_store->dict_handler_id[i]);
523       }
524
525   data_store->dict = dict;
526
527   if (dict != NULL)
528     {
529
530       data_store->dict_handler_id [VARIABLE_INSERTED] =
531         g_signal_connect (dict, "variable-inserted",
532                           G_CALLBACK (insert_variable_callback),
533                           data_store);
534
535       data_store->dict_handler_id [VARIABLE_DELETED] =
536         g_signal_connect (dict, "variable-deleted",
537                           G_CALLBACK (delete_variable_callback),
538                           data_store);
539
540       data_store->dict_handler_id [VARIABLE_CHANGED] =
541         g_signal_connect (dict, "variable-changed",
542                           G_CALLBACK (variable_changed_callback),
543                           data_store);
544     }
545
546
547
548   /* The entire model has changed */
549
550   if (data_store->dict)
551     for (i = 0 ; i < n_dict_signals; ++i)
552       {
553         if (data_store->dict_handler_id [i] > 0)
554           {
555             g_signal_handler_block (data_store->dict,
556                                     data_store->dict_handler_id[i]);
557           }
558       }
559 }
560
561 static void
562 psppire_data_store_finalize (GObject *object)
563 {
564   PsppireDataStore *ds = PSPPIRE_DATA_STORE (object);
565
566   if (ds->datasheet)
567     {
568       datasheet_destroy (ds->datasheet);
569       ds->datasheet = NULL;
570     }
571
572   /* must chain up */
573   (* parent_class->finalize) (object);
574 }
575
576
577 static void
578 psppire_data_store_dispose (GObject *object)
579 {
580   PsppireDataStore *ds = PSPPIRE_DATA_STORE (object);
581
582   if (ds->dispose_has_run)
583     return;
584
585   psppire_data_store_set_dictionary (ds, NULL);
586
587   /* must chain up */
588   (* parent_class->dispose) (object);
589
590   ds->dispose_has_run = TRUE;
591 }
592
593
594
595 /* Insert a blank case before POSN */
596 gboolean
597 psppire_data_store_insert_new_case (PsppireDataStore *ds, casenumber posn)
598 {
599   gboolean result;
600   const struct caseproto *proto;
601   struct ccase *cc;
602   g_return_val_if_fail (ds, FALSE);
603
604   proto = datasheet_get_proto (ds->datasheet);
605   g_return_val_if_fail (caseproto_get_n_widths (proto) > 0, FALSE);
606   g_return_val_if_fail (posn <= psppire_data_store_get_case_count (ds), FALSE);
607
608   cc = case_create (proto);
609   case_set_missing (cc);
610
611   result = psppire_data_store_insert_case (ds, cc, posn);
612
613   case_unref (cc);
614
615   return result;
616 }
617
618 gboolean
619 psppire_data_store_get_value (PsppireDataStore *store,
620                               glong row, const struct variable *var,
621                               union value *val)
622 {
623   g_return_val_if_fail (store != NULL, FALSE);
624   g_return_val_if_fail (store->datasheet != NULL, FALSE);
625   g_return_val_if_fail (var != NULL, FALSE);
626
627   if (row < 0 || row >= datasheet_get_n_rows (store->datasheet))
628     return FALSE;
629
630   int width = var_get_width (var);
631   value_init (val, width);
632   datasheet_get_value (store->datasheet, row, var_get_case_index (var), val);
633
634   return TRUE;
635 }
636
637
638
639 gchar *
640 psppire_data_store_get_string (PsppireDataStore *store,
641                                glong row, const struct variable *var,
642                                bool use_value_label)
643 {
644   gchar *string;
645   union value v;
646   int width = var_get_width (var);
647   if (! psppire_data_store_get_value (store, row, var, &v))
648     return NULL;
649
650   string = NULL;
651   if (use_value_label)
652     {
653       const char *label = var_lookup_value_label (var, &v);
654       if (label != NULL)
655         string = g_strdup (label);
656     }
657   if (string == NULL)
658     string = value_to_text (v, var);
659
660   value_destroy (&v, width);
661
662   return string;
663 }
664
665
666 /* Attempts to update that part of the variable store which corresponds to VAR
667    within ROW with the value TEXT.
668
669    If USE_VALUE_LABEL is true, and TEXT is a value label for the column's
670    variable, then stores the value from that value label instead of the literal
671    TEXT.
672
673    Returns true if anything was updated, false otherwise.  */
674 gboolean
675 psppire_data_store_set_string (PsppireDataStore *store,
676                                const gchar *text,
677                                glong row, const struct variable *var,
678                                gboolean use_value_label)
679 {
680   gint case_index;
681   glong n_cases;
682   gboolean ok;
683
684   n_cases = psppire_data_store_get_case_count (store);
685   if (row > n_cases)
686     return FALSE;
687   if (row == n_cases)
688     psppire_data_store_insert_new_case (store, row);
689
690   case_index = var_get_case_index (var);
691   if (use_value_label)
692     {
693       const struct val_labs *vls = var_get_value_labels (var);
694       const union value *value = vls ? val_labs_find_value (vls, text) : NULL;
695       if (value)
696         ok = datasheet_put_value (store->datasheet, row, case_index, value);
697       else
698         ok = FALSE;
699     }
700   else
701     ok = psppire_data_store_data_in (store, row, case_index, ss_cstr (text),
702                                      var_get_print_format (var));
703
704   if (ok)
705     g_signal_emit (store, signals [CASE_CHANGED], 0, row);
706   return ok;
707 }
708
709
710
711 void
712 psppire_data_store_clear (PsppireDataStore *ds)
713 {
714   datasheet_destroy (ds->datasheet);
715   ds->datasheet = NULL;
716
717   psppire_dict_clear (ds->dict);
718
719   g_signal_emit (ds, signals [ITEMS_CHANGED], 0, 0, -1, 0);
720 }
721
722
723
724 /* Return a casereader made from this datastore */
725 struct casereader *
726 psppire_data_store_get_reader (PsppireDataStore *ds)
727 {
728   int i;
729   struct casereader *reader ;
730
731   if (ds->dict)
732     for (i = 0 ; i < n_dict_signals; ++i)
733       {
734         g_signal_handler_block (ds->dict,
735                                 ds->dict_handler_id[i]);
736       }
737
738   reader = datasheet_make_reader (ds->datasheet);
739
740   /* We must not reference this again */
741   ds->datasheet = NULL;
742
743   return reader;
744 }
745
746 /* Returns the CASENUMth case, or a null pointer on failure.
747  */
748 struct ccase *
749 psppire_data_store_get_case (const PsppireDataStore *ds,
750                              casenumber casenum)
751 {
752   g_return_val_if_fail (ds, FALSE);
753   g_return_val_if_fail (ds->datasheet, FALSE);
754
755   return datasheet_get_row (ds->datasheet, casenum);
756 }
757
758
759 gboolean
760 psppire_data_store_delete_cases (PsppireDataStore *ds, casenumber first,
761                                  casenumber n_cases)
762 {
763   g_return_val_if_fail (ds, FALSE);
764   g_return_val_if_fail (ds->datasheet, FALSE);
765
766   g_return_val_if_fail (first + n_cases <=
767                         psppire_data_store_get_case_count (ds), FALSE);
768
769
770   datasheet_delete_rows (ds->datasheet, first, n_cases);
771
772   g_signal_emit (ds, signals[ITEMS_CHANGED], 0, first, n_cases, 0);
773
774   return TRUE;
775 }
776
777
778
779 /* Insert case CC into the case file before POSN */
780 static gboolean
781 psppire_data_store_insert_case (PsppireDataStore *ds,
782                                 struct ccase *cc,
783                                 casenumber posn)
784 {
785   bool result ;
786
787   g_return_val_if_fail (ds, FALSE);
788   g_return_val_if_fail (ds->datasheet, FALSE);
789
790   cc = case_ref (cc);
791   result = datasheet_insert_rows (ds->datasheet, posn, &cc, 1);
792
793   if (result)
794     {
795       g_signal_emit (ds, signals[ITEMS_CHANGED], 0, posn, 0, 1);
796     }
797   else
798     g_warning ("Cannot insert case at position %ld\n", posn);
799
800   return result;
801 }
802
803
804 /* Set the value of VAR in case CASENUM to V.
805    V must be the correct width for IDX.
806    Returns true if successful, false on I/O error. */
807 gboolean
808 psppire_data_store_set_value (PsppireDataStore *ds, casenumber casenum,
809                               const struct variable *var, const union value *v)
810 {
811   glong n_cases;
812   bool ok;
813
814   g_return_val_if_fail (ds, FALSE);
815   g_return_val_if_fail (ds->datasheet, FALSE);
816
817   n_cases = psppire_data_store_get_case_count (ds);
818   if (casenum > n_cases)
819     return FALSE;
820
821   if (casenum == n_cases)
822     psppire_data_store_insert_new_case (ds, casenum);
823
824   ok = datasheet_put_value (ds->datasheet, casenum, var_get_case_index (var),
825                             v);
826   if (ok)
827     {
828       g_signal_emit (ds, signals [CASE_CHANGED], 0, casenum);
829       g_signal_emit (ds, signals [ITEMS_CHANGED], 0, casenum, 1, 1);
830     }
831
832   return ok;
833 }
834
835
836
837
838 /* Set the IDXth value of case C using D_IN */
839 static gboolean
840 psppire_data_store_data_in (PsppireDataStore *ds, casenumber casenum, gint idx,
841                             struct substring input, const struct fmt_spec *fmt)
842 {
843   union value value;
844   int width;
845   bool ok;
846
847   PsppireDict *dict;
848
849   g_return_val_if_fail (ds, FALSE);
850   g_return_val_if_fail (ds->datasheet, FALSE);
851
852   g_return_val_if_fail (idx < datasheet_get_n_columns (ds->datasheet), FALSE);
853
854   dict = ds->dict;
855
856   width = fmt_var_width (fmt);
857   g_return_val_if_fail (caseproto_get_width (
858                           datasheet_get_proto (ds->datasheet), idx) == width,
859                         FALSE);
860   value_init (&value, width);
861   ok = (datasheet_get_value (ds->datasheet, casenum, idx, &value)
862         && data_in_msg (input, UTF8, fmt->type, &value, width,
863                         dict_get_encoding (dict->dict))
864         && datasheet_put_value (ds->datasheet, casenum, idx, &value));
865   value_destroy (&value, width);
866
867   return ok;
868 }
869
870 /* Resize the cases in the casefile, by inserting a value of the
871    given WIDTH into every one of them at the position immediately
872    preceding WHERE.
873 */
874 gboolean
875 psppire_data_store_insert_value (PsppireDataStore *ds,
876                                  gint width, gint where)
877 {
878   union value value;
879
880   g_return_val_if_fail (ds, FALSE);
881
882   g_assert (width >= 0);
883
884   if (! ds->datasheet)
885     ds->datasheet = datasheet_create (NULL);
886
887   value_init (&value, width);
888   value_set_missing (&value, width);
889
890   datasheet_insert_column (ds->datasheet, &value, width, where);
891   value_destroy (&value, width);
892
893   return TRUE;
894 }
895
896 gboolean
897 psppire_data_store_filtered (PsppireDataStore *ds,
898                              glong row)
899 {
900   union value val;
901
902   const struct dictionary *dict;
903   const struct variable *filter;
904
905   if (row < 0 || row >= datasheet_get_n_rows (ds->datasheet))
906     return FALSE;
907
908   dict = ds->dict->dict;
909   g_return_val_if_fail (dict, FALSE);
910   filter = dict_get_filter (dict);
911   if (! filter)
912     return FALSE;
913
914   g_return_val_if_fail (var_is_numeric (filter), FALSE);
915   value_init (&val, 0);
916   if (! datasheet_get_value (ds->datasheet, row,
917                               var_get_case_index (filter),
918                               &val))
919     return FALSE;
920
921   return (val.f == 0.0);
922 }