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