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