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