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