Allow adding new variables in the var sheet
[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_var_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, var_get_case_index (variable));
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 casenumber
304 psppire_data_store_get_case_count (const PsppireDataStore *store)
305 {
306   return datasheet_get_n_rows (store->datasheet);
307 }
308
309 size_t
310 psppire_data_store_get_value_count (const PsppireDataStore *store)
311 {
312   return psppire_dict_get_value_cnt (store->dict);
313 }
314
315 const struct caseproto *
316 psppire_data_store_get_proto (const PsppireDataStore *store)
317 {
318   return psppire_dict_get_proto (store->dict);
319 }
320
321 static void
322 psppire_data_store_init (PsppireDataStore *data_store)
323 {
324   data_store->dict = NULL;
325   data_store->datasheet = NULL;
326   data_store->dispose_has_run = FALSE;
327   data_store->stamp = g_random_int ();
328 }
329
330
331 static void
332 psppire_data_store_delete_value (PsppireDataStore *store, gint case_index)
333 {
334   g_return_if_fail (store->datasheet);
335   datasheet_delete_columns (store->datasheet, case_index, 1);
336   datasheet_insert_column (store->datasheet, NULL, -1, case_index);
337 }
338
339
340 /*
341    A callback which occurs after a variable has been deleted.
342  */
343 static void
344 delete_variable_callback (GObject *obj, const struct variable *var UNUSED,
345                           gint dict_index, gint case_index,
346                           gpointer data)
347 {
348   PsppireDataStore *store  = PSPPIRE_DATA_STORE (data);
349
350   psppire_data_store_delete_value (store, case_index);
351 }
352
353 struct resize_datum_aux
354   {
355     const struct dictionary *dict;
356     const struct variable *new_variable;
357     const struct variable *old_variable;
358   };
359
360 static void
361 resize_datum (const union value *old, union value *new, const void *aux_)
362 {
363   const struct resize_datum_aux *aux = aux_;
364   int new_width = var_get_width (aux->new_variable);
365   const char *enc = dict_get_encoding (aux->dict);
366   const struct fmt_spec *newfmt = var_get_print_format (aux->new_variable);
367   char *s = data_out (old, enc, var_get_print_format (aux->old_variable));
368   enum fmt_type type = (fmt_usable_for_input (newfmt->type)
369                         ? newfmt->type
370                         : FMT_DOLLAR);
371   free (data_in (ss_cstr (s), enc, type, new, new_width, enc));
372   free (s);
373 }
374
375 static void
376 variable_changed_callback (GObject *obj, gint var_num, guint what, const struct variable *oldvar,
377                            gpointer data)
378 {
379   PsppireDataStore *store  = PSPPIRE_DATA_STORE (data);
380   struct variable *variable = psppire_dict_get_variable (store->dict, var_num);
381
382   if (what & VAR_TRAIT_WIDTH)
383     {
384       int posn = var_get_case_index (variable);
385       struct resize_datum_aux aux;
386       aux.old_variable = oldvar;
387       aux.new_variable = variable;
388       aux.dict = store->dict->dict;
389       datasheet_resize_column (store->datasheet, posn, var_get_width (variable),
390                                resize_datum, &aux);
391     }
392 }
393
394 static void
395 insert_variable_callback (GObject *obj, gint var_num, gpointer data)
396 {
397   struct variable *variable;
398   PsppireDataStore *store;
399   gint posn;
400
401   g_return_if_fail (data);
402
403   store  = PSPPIRE_DATA_STORE (data);
404
405   variable = psppire_dict_get_variable (store->dict, var_num);
406   posn = var_get_case_index (variable);
407   psppire_data_store_insert_value (store, var_get_width (variable), posn);
408 }
409
410 /**
411  * psppire_data_store_new:
412  * @dict: The dictionary for this data_store.
413  *
414  *
415  * Return value: a new #PsppireDataStore
416  **/
417 PsppireDataStore *
418 psppire_data_store_new (PsppireDict *dict)
419 {
420   PsppireDataStore *retval;
421
422   retval = g_object_new (PSPPIRE_TYPE_DATA_STORE, NULL);
423
424   psppire_data_store_set_dictionary (retval, dict);
425
426   return retval;
427 }
428
429 void
430 psppire_data_store_set_reader (PsppireDataStore *ds,
431                                struct casereader *reader)
432 {
433   gint i;
434   gint old_n = 0;
435   if ( ds->datasheet)
436     {
437       old_n = datasheet_get_n_rows (ds->datasheet);
438       datasheet_destroy (ds->datasheet);
439     }
440
441   ds->datasheet = datasheet_create (reader);
442
443   gint new_n = datasheet_get_n_rows (ds->datasheet);
444   
445   if ( ds->dict )
446     for (i = 0 ; i < n_dict_signals; ++i )
447       {
448         if ( ds->dict_handler_id [i] > 0)
449           {
450             g_signal_handler_unblock (ds->dict,
451                                       ds->dict_handler_id[i]);
452           }
453       }
454
455   g_signal_emit (ds, signals[ITEMS_CHANGED], 0, 0, old_n, new_n);
456 }
457
458
459 /**
460  * psppire_data_store_replace_set_dictionary:
461  * @data_store: The variable store
462  * @dict: The dictionary to set
463  *
464  * If a dictionary is already associated with the data-store, then it will be
465  * destroyed.
466  **/
467 void
468 psppire_data_store_set_dictionary (PsppireDataStore *data_store, PsppireDict *dict)
469 {
470   int i;
471
472   /* Disconnect any existing handlers */
473   if ( data_store->dict )
474     for (i = 0 ; i < n_dict_signals; ++i )
475       {
476         g_signal_handler_disconnect (data_store->dict,
477                                      data_store->dict_handler_id[i]);
478       }
479
480   data_store->dict = dict;
481
482   if ( dict != NULL)
483     {
484
485       data_store->dict_handler_id [VARIABLE_INSERTED] =
486         g_signal_connect (dict, "variable-inserted",
487                           G_CALLBACK (insert_variable_callback),
488                           data_store);
489
490       data_store->dict_handler_id [VARIABLE_DELETED] =
491         g_signal_connect (dict, "variable-deleted",
492                           G_CALLBACK (delete_variable_callback),
493                           data_store);
494
495       data_store->dict_handler_id [VARIABLE_CHANGED] =
496         g_signal_connect (dict, "variable-changed",
497                           G_CALLBACK (variable_changed_callback),
498                           data_store);
499     }
500
501
502
503   /* The entire model has changed */
504
505   if ( data_store->dict )
506     for (i = 0 ; i < n_dict_signals; ++i )
507       {
508         if ( data_store->dict_handler_id [i] > 0)
509           {
510             g_signal_handler_block (data_store->dict,
511                                     data_store->dict_handler_id[i]);
512           }
513       }
514 }
515
516 static void
517 psppire_data_store_finalize (GObject *object)
518 {
519   PsppireDataStore *ds = PSPPIRE_DATA_STORE (object);
520
521   if (ds->datasheet)
522     {
523       datasheet_destroy (ds->datasheet);
524       ds->datasheet = NULL;
525     }
526
527   /* must chain up */
528   (* parent_class->finalize) (object);
529 }
530
531
532 static void
533 psppire_data_store_dispose (GObject *object)
534 {
535   PsppireDataStore *ds = PSPPIRE_DATA_STORE (object);
536
537   if (ds->dispose_has_run)
538     return;
539
540   psppire_data_store_set_dictionary (ds, NULL);
541
542   /* must chain up */
543   (* parent_class->dispose) (object);
544
545   ds->dispose_has_run = TRUE;
546 }
547
548
549
550 /* Insert a blank case before POSN */
551 gboolean
552 psppire_data_store_insert_new_case (PsppireDataStore *ds, casenumber posn)
553 {
554   gboolean result;
555   const struct caseproto *proto;
556   struct ccase *cc;
557   g_return_val_if_fail (ds, FALSE);
558
559   proto = datasheet_get_proto (ds->datasheet);
560   g_return_val_if_fail (caseproto_get_n_widths (proto) > 0, FALSE);
561   g_return_val_if_fail (posn <= psppire_data_store_get_case_count (ds), FALSE);
562
563   cc = case_create (proto);
564   case_set_missing (cc);
565
566   result = psppire_data_store_insert_case (ds, cc, posn);
567
568   case_unref (cc);
569
570   return result;
571 }
572
573 gboolean
574 psppire_data_store_get_value (PsppireDataStore *store,
575                               glong row, const struct variable *var,
576                               union value *val)
577 {
578   g_return_val_if_fail (store != NULL, FALSE);
579   g_return_val_if_fail (store->datasheet != NULL, FALSE);
580   g_return_val_if_fail (var != NULL, FALSE);
581
582   if (row < 0 || row >= datasheet_get_n_rows (store->datasheet))
583     return FALSE;
584
585   int width = var_get_width (var);
586   value_init (val, width);
587   datasheet_get_value (store->datasheet, row, var_get_case_index (var), val);
588
589   return TRUE;
590 }
591
592   
593
594 gchar *
595 psppire_data_store_get_string (PsppireDataStore *store,
596                                glong row, const struct variable *var,
597                                bool use_value_label)
598 {
599   gchar *string;
600   union value v;
601   int width = var_get_width (var);
602   if (! psppire_data_store_get_value (store, row, var, &v))
603     return NULL;
604   
605   string = NULL;
606   if (use_value_label)
607     {
608       const char *label = var_lookup_value_label (var, &v);
609       if (label != NULL)
610         string = g_strdup (label);
611     }
612   if (string == NULL)
613     string = value_to_text (v, var);
614
615   value_destroy (&v, width);
616
617   return string;
618 }
619
620
621 /* Attempts to update that part of the variable store which corresponds to VAR
622    within ROW with the value TEXT.
623
624    If USE_VALUE_LABEL is true, and TEXT is a value label for the column's
625    variable, then stores the value from that value label instead of the literal
626    TEXT.
627
628    Returns true if anything was updated, false otherwise.  */
629 gboolean
630 psppire_data_store_set_string (PsppireDataStore *store,
631                                const gchar *text,
632                                glong row, const struct variable *var,
633                                gboolean use_value_label)
634 {
635   gint case_index;
636   glong n_cases;
637   gboolean ok;
638
639   n_cases = psppire_data_store_get_case_count (store);
640   if (row > n_cases)
641     return FALSE;
642   if (row == n_cases)
643     psppire_data_store_insert_new_case (store, row);
644
645   case_index = var_get_case_index (var);
646   if (use_value_label)
647     {
648       const struct val_labs *vls = var_get_value_labels (var);
649       const union value *value = vls ? val_labs_find_value (vls, text) : NULL;
650       if (value)
651         ok = datasheet_put_value (store->datasheet, row, case_index, value);
652       else
653         ok = FALSE;
654     }
655   else
656     ok = psppire_data_store_data_in (store, row, case_index, ss_cstr (text),
657                                      var_get_print_format (var));
658
659   if (ok)
660     g_signal_emit (store, signals [CASE_CHANGED], 0, row);
661   return ok;
662 }
663
664
665
666 void
667 psppire_data_store_clear (PsppireDataStore *ds)
668 {
669   datasheet_destroy (ds->datasheet);
670   ds->datasheet = NULL;
671
672   psppire_dict_clear (ds->dict);
673
674   g_signal_emit (ds, signals [ITEMS_CHANGED], 0, 0, -1, 0);
675 }
676
677
678
679 /* Return a casereader made from this datastore */
680 struct casereader *
681 psppire_data_store_get_reader (PsppireDataStore *ds)
682 {
683   int i;
684   struct casereader *reader ;
685
686   if ( ds->dict )
687     for (i = 0 ; i < n_dict_signals; ++i )
688       {
689         g_signal_handler_block (ds->dict,
690                                 ds->dict_handler_id[i]);
691       }
692
693   reader = datasheet_make_reader (ds->datasheet);
694
695   /* We must not reference this again */
696   ds->datasheet = NULL;
697
698   return reader;
699 }
700
701 /* Returns the CASENUMth case, or a null pointer on failure.
702  */
703 struct ccase *
704 psppire_data_store_get_case (const PsppireDataStore *ds,
705                              casenumber casenum)
706 {
707   g_return_val_if_fail (ds, FALSE);
708   g_return_val_if_fail (ds->datasheet, FALSE);
709
710   return datasheet_get_row (ds->datasheet, casenum);
711 }
712
713
714 gboolean
715 psppire_data_store_delete_cases (PsppireDataStore *ds, casenumber first,
716                                  casenumber n_cases)
717 {
718   g_return_val_if_fail (ds, FALSE);
719   g_return_val_if_fail (ds->datasheet, FALSE);
720
721   g_return_val_if_fail (first + n_cases <=
722                         psppire_data_store_get_case_count (ds), FALSE);
723
724
725   datasheet_delete_rows (ds->datasheet, first, n_cases);
726
727   g_signal_emit (ds, signals[ITEMS_CHANGED], 0, first, n_cases, 0);
728
729   return TRUE;
730 }
731
732
733
734 /* Insert case CC into the case file before POSN */
735 static gboolean
736 psppire_data_store_insert_case (PsppireDataStore *ds,
737                                 struct ccase *cc,
738                                 casenumber posn)
739 {
740   bool result ;
741
742   g_return_val_if_fail (ds, FALSE);
743   g_return_val_if_fail (ds->datasheet, FALSE);
744
745   cc = case_ref (cc);
746   result = datasheet_insert_rows (ds->datasheet, posn, &cc, 1);
747
748   if ( result )
749     {
750       g_signal_emit (ds, signals[ITEMS_CHANGED], 0, posn, 0, 1);
751     }
752   else
753     g_warning ("Cannot insert case at position %ld\n", posn);
754
755   return result;
756 }
757
758
759 /* Set the value of VAR in case CASENUM to V.
760    V must be the correct width for IDX.
761    Returns true if successful, false on I/O error. */
762 gboolean
763 psppire_data_store_set_value (PsppireDataStore *ds, casenumber casenum,
764                               const struct variable *var, const union value *v)
765 {
766   glong n_cases;
767   bool ok;
768
769   g_return_val_if_fail (ds, FALSE);
770   g_return_val_if_fail (ds->datasheet, FALSE);
771
772   n_cases = psppire_data_store_get_case_count (ds);
773   if ( casenum > n_cases)
774     return FALSE;
775
776   if (casenum == n_cases)
777     psppire_data_store_insert_new_case (ds, casenum);
778
779   ok = datasheet_put_value (ds->datasheet, casenum, var_get_case_index (var),
780                             v);
781   if (ok)
782     g_signal_emit (ds, signals [CASE_CHANGED], 0, casenum);
783
784   return ok;
785 }
786
787
788
789
790 /* Set the IDXth value of case C using D_IN */
791 static gboolean
792 psppire_data_store_data_in (PsppireDataStore *ds, casenumber casenum, gint idx,
793                             struct substring input, const struct fmt_spec *fmt)
794 {
795   union value value;
796   int width;
797   bool ok;
798
799   PsppireDict *dict;
800
801   g_return_val_if_fail (ds, FALSE);
802   g_return_val_if_fail (ds->datasheet, FALSE);
803
804   g_return_val_if_fail (idx < datasheet_get_n_columns (ds->datasheet), FALSE);
805
806   dict = ds->dict;
807
808   width = fmt_var_width (fmt);
809   g_return_val_if_fail (caseproto_get_width (
810                           datasheet_get_proto (ds->datasheet), idx) == width,
811                         FALSE);
812   value_init (&value, width);
813   ok = (datasheet_get_value (ds->datasheet, casenum, idx, &value)
814         && data_in_msg (input, UTF8, fmt->type, &value, width,
815                         dict_get_encoding (dict->dict))
816         && datasheet_put_value (ds->datasheet, casenum, idx, &value));
817   value_destroy (&value, width);
818
819   return ok;
820 }
821
822 /* Resize the cases in the casefile, by inserting a value of the
823    given WIDTH into every one of them at the position immediately
824    preceding WHERE.
825 */
826 gboolean
827 psppire_data_store_insert_value (PsppireDataStore *ds,
828                                  gint width, gint where)
829 {
830   union value value;
831
832   g_return_val_if_fail (ds, FALSE);
833
834   g_assert (width >= 0);
835
836   if ( ! ds->datasheet )
837     ds->datasheet = datasheet_create (NULL);
838
839   value_init (&value, width);
840   value_set_missing (&value, width);
841
842   datasheet_insert_column (ds->datasheet, &value, width, where);
843   value_destroy (&value, width);
844
845   return TRUE;
846 }
847
848 gboolean
849 psppire_data_store_filtered (PsppireDataStore *ds,
850                              glong row)
851 {
852   union value val;
853
854   const struct dictionary *dict;
855   const struct variable *filter;
856
857   if ( row < 0 || row >= datasheet_get_n_rows (ds->datasheet))
858     return FALSE;
859
860   dict = ds->dict->dict;
861   g_return_val_if_fail (dict, FALSE);
862   filter = dict_get_filter (dict);
863   if ( ! filter)
864     return FALSE;
865
866   g_return_val_if_fail (var_is_numeric (filter), FALSE);
867   value_init (&val, 0);
868   if ( ! datasheet_get_value (ds->datasheet, row,
869                               var_get_case_index (filter),
870                               &val) )
871     return FALSE;
872
873   return (val.f == 0.0);
874 }