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, 2013  Free Software Foundation
3
4    This program is free software: you can redistribute it and/or modify
5    it under the terms of the GNU General Public License as published by
6    the Free Software Foundation, either version 3 of the License, or
7    (at your option) any later version.
8
9    This program is distributed in the hope that it will be useful,
10    but WITHOUT ANY WARRANTY; without even the implied warranty of
11    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12    GNU General Public License for more details.
13
14    You should have received a copy of the GNU General Public License
15    along with this program.  If not, see <http://www.gnu.org/licenses/>. */
16
17 #include <config.h>
18 #include <string.h>
19 #include <stdlib.h>
20 #include <gettext.h>
21 #define _(msgid) gettext (msgid)
22 #define N_(msgid) msgid
23
24 #include <data/datasheet.h>
25 #include <data/data-out.h>
26 #include <data/variable.h>
27
28 #include <ui/gui/psppire-marshal.h>
29
30 #include <pango/pango-context.h>
31
32 #include "psppire-data-store.h"
33 #include <libpspp/i18n.h>
34 #include "helper.h"
35
36 #include <data/dictionary.h>
37 #include <data/missing-values.h>
38 #include <data/value-labels.h>
39 #include <data/data-in.h>
40 #include <data/format.h>
41
42 #include <math/sort.h>
43
44 #include "xalloc.h"
45 #include "xmalloca.h"
46
47
48
49 static void psppire_data_store_init            (PsppireDataStore      *data_store);
50 static void psppire_data_store_class_init      (PsppireDataStoreClass *class);
51
52 static void psppire_data_store_finalize        (GObject           *object);
53 static void psppire_data_store_dispose        (GObject           *object);
54
55 static gboolean psppire_data_store_insert_case (PsppireDataStore *ds,
56                                                 struct ccase *cc,
57                                                 casenumber posn);
58
59
60 static gboolean psppire_data_store_data_in (PsppireDataStore *ds,
61                                             casenumber casenum, gint idx,
62                                             struct substring input,
63                                             const struct fmt_spec *fmt);
64
65 static GObjectClass *parent_class = NULL;
66
67
68 enum
69   {
70     ITEMS_CHANGED,
71     CASES_DELETED,
72     CASE_INSERTED,
73     CASE_CHANGED,
74     n_SIGNALS
75   };
76
77 static guint signals [n_SIGNALS];
78
79 static gint
80 __tree_model_iter_n_children (GtkTreeModel *tree_model,
81                              GtkTreeIter *iter)
82 {
83   PsppireDataStore *store  = PSPPIRE_DATA_STORE (tree_model);
84
85   gint n =  datasheet_get_n_rows (store->datasheet);
86
87   return n;
88 }
89
90 static GtkTreeModelFlags
91 __tree_model_get_flags (GtkTreeModel *model)
92 {
93   g_return_val_if_fail (PSPPIRE_IS_DATA_STORE (model), (GtkTreeModelFlags) 0);
94
95   return GTK_TREE_MODEL_LIST_ONLY;
96 }
97
98 static gint
99 __tree_model_get_n_columns (GtkTreeModel *tree_model)
100 {
101   PsppireDataStore *store  = PSPPIRE_DATA_STORE (tree_model);
102
103   return psppire_dict_get_value_cnt (store->dict);
104 }
105
106
107 static gboolean
108 __iter_nth_child (GtkTreeModel *tree_model,
109                   GtkTreeIter *iter,
110                   GtkTreeIter *parent,
111                   gint n)
112 {
113   PsppireDataStore *store  = PSPPIRE_DATA_STORE (tree_model);
114   
115   g_assert (parent == NULL);
116
117   g_return_val_if_fail (store, FALSE);
118   g_return_val_if_fail (store->datasheet, FALSE);
119
120   if (n >= datasheet_get_n_rows (store->datasheet))
121     {
122       iter->stamp = -1;
123       iter->user_data = NULL;
124       return FALSE;
125     }
126   
127   iter->user_data = GINT_TO_POINTER (n);
128   iter->stamp = store->stamp;
129   
130   return TRUE;
131 }
132
133
134
135 static void
136 __get_value (GtkTreeModel *tree_model,
137              GtkTreeIter *iter,
138              gint column,
139              GValue *value)
140 {
141   PsppireDataStore *store  = PSPPIRE_DATA_STORE (tree_model);
142
143   g_return_if_fail (iter->stamp == store->stamp);
144   
145   const struct variable *variable = psppire_dict_get_variable (store->dict, column);
146   if (NULL == variable)
147     return;
148
149   if (var_is_numeric (variable))
150     g_value_init (value, G_TYPE_DOUBLE);
151   else
152     g_value_init (value, G_TYPE_STRING);
153
154   gint row = GPOINTER_TO_INT (iter->user_data);
155
156   struct ccase *cc = datasheet_get_row (store->datasheet, row);
157   
158   if (var_is_numeric (variable))
159     g_value_set_double (value, case_data_idx (cc, column)->f);
160   else
161     {
162       const gchar *ss = value_str (case_data_idx (cc, column),
163                              var_get_width (variable));
164       g_value_set_string (value, ss);
165     }
166   case_unref (cc);
167 }
168
169
170 static GType
171 __get_type (GtkTreeModel *tree_model,   gint idx)
172 {
173   PsppireDataStore *store  = PSPPIRE_DATA_STORE (tree_model);
174
175   const struct variable *variable = psppire_dict_get_variable (store->dict, idx);
176
177   if (NULL == variable)
178     return 0;
179
180   if (var_is_numeric (variable))
181     return G_TYPE_DOUBLE;
182
183   return G_TYPE_STRING;
184 }
185
186 static void
187 __tree_model_init (GtkTreeModelIface *iface)
188 {
189   iface->get_flags       = __tree_model_get_flags;
190   iface->get_n_columns   = __tree_model_get_n_columns ;
191   iface->get_column_type = __get_type;
192   iface->get_iter        = NULL; 
193   iface->iter_next       = NULL; 
194   iface->get_path        = NULL; 
195   iface->get_value       = __get_value;
196
197   iface->iter_children   = NULL; 
198   iface->iter_has_child  = NULL; 
199   iface->iter_n_children = __tree_model_iter_n_children;
200   iface->iter_nth_child  = __iter_nth_child;
201   iface->iter_parent     = NULL; 
202 }
203
204
205 GType
206 psppire_data_store_get_type (void)
207 {
208   static GType data_store_type = 0;
209
210   if (!data_store_type)
211     {
212       static const GTypeInfo data_store_info =
213       {
214         sizeof (PsppireDataStoreClass),
215         NULL,           /* base_init */
216         NULL,           /* base_finalize */
217         (GClassInitFunc) psppire_data_store_class_init,
218         NULL,           /* class_finalize */
219         NULL,           /* class_data */
220         sizeof (PsppireDataStore),
221         0,
222         (GInstanceInitFunc) psppire_data_store_init,
223       };
224
225       static const GInterfaceInfo tree_model_info = {
226         (GInterfaceInitFunc) __tree_model_init,
227         NULL,
228         NULL
229       };
230
231       data_store_type = g_type_register_static (G_TYPE_OBJECT,
232                                                 "PsppireDataStore",
233                                                 &data_store_info, 0);
234
235       g_type_add_interface_static (data_store_type, GTK_TYPE_TREE_MODEL,
236                                    &tree_model_info);
237     }
238
239   return data_store_type;
240 }
241
242
243 static void
244 psppire_data_store_class_init (PsppireDataStoreClass *class)
245 {
246   GObjectClass *object_class;
247
248   parent_class = g_type_class_peek_parent (class);
249   object_class = (GObjectClass*) class;
250
251   object_class->finalize = psppire_data_store_finalize;
252   object_class->dispose = psppire_data_store_dispose;
253
254     signals [ITEMS_CHANGED] =
255     g_signal_new ("changed",
256                   G_TYPE_FROM_CLASS (class),
257                   G_SIGNAL_RUN_FIRST,
258                   0,
259                   NULL, NULL,
260                   psppire_marshal_VOID__UINT_UINT_UINT,
261                   G_TYPE_NONE,
262                   3,
263                   G_TYPE_UINT,
264                   G_TYPE_UINT,
265                   G_TYPE_UINT);
266
267   signals [CASE_INSERTED] =
268     g_signal_new ("case-inserted",
269                   G_TYPE_FROM_CLASS (class),
270                   G_SIGNAL_RUN_FIRST,
271                   0,
272                   NULL, NULL,
273                   g_cclosure_marshal_VOID__INT,
274                   G_TYPE_NONE,
275                   1,
276                   G_TYPE_INT);
277
278
279   signals [CASE_CHANGED] =
280     g_signal_new ("case-changed",
281                   G_TYPE_FROM_CLASS (class),
282                   G_SIGNAL_RUN_FIRST,
283                   0,
284                   NULL, NULL,
285                   g_cclosure_marshal_VOID__INT,
286                   G_TYPE_NONE,
287                   1,
288                   G_TYPE_INT);
289
290   signals [CASES_DELETED] =
291     g_signal_new ("cases-deleted",
292                   G_TYPE_FROM_CLASS (class),
293                   G_SIGNAL_RUN_FIRST,
294                   0,
295                   NULL, NULL,
296                   psppire_marshal_VOID__INT_INT,
297                   G_TYPE_NONE,
298                   2,
299                   G_TYPE_INT,
300                   G_TYPE_INT);
301 }
302
303
304
305 static gboolean
306 psppire_data_store_insert_value (PsppireDataStore *ds,
307                                   gint width, gint where);
308
309 casenumber
310 psppire_data_store_get_case_count (const PsppireDataStore *store)
311 {
312   return datasheet_get_n_rows (store->datasheet);
313 }
314
315 size_t
316 psppire_data_store_get_value_count (const PsppireDataStore *store)
317 {
318   return psppire_dict_get_value_cnt (store->dict);
319 }
320
321 const struct caseproto *
322 psppire_data_store_get_proto (const PsppireDataStore *store)
323 {
324   return psppire_dict_get_proto (store->dict);
325 }
326
327 static void
328 psppire_data_store_init (PsppireDataStore *data_store)
329 {
330   data_store->dict = NULL;
331   data_store->datasheet = NULL;
332   data_store->dispose_has_run = FALSE;
333   data_store->stamp = g_random_int ();
334 }
335
336 /*
337    A callback which occurs after a variable has been deleted.
338  */
339 static void
340 delete_variable_callback (GObject *obj, const struct variable *var UNUSED,
341                           gint dict_index, gint case_index,
342                           gpointer data)
343 {
344   PsppireDataStore *store  = PSPPIRE_DATA_STORE (data);
345
346   g_return_if_fail (store->datasheet);
347
348   datasheet_delete_columns (store->datasheet, case_index, 1);
349   datasheet_insert_column (store->datasheet, NULL, -1, 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 gchar *
573 psppire_data_store_get_string (PsppireDataStore *store,
574                                glong row, const struct variable *var,
575                                bool use_value_label)
576 {
577   gchar *string;
578   union value v;
579   int width;
580
581   g_return_val_if_fail (store != NULL, NULL);
582   g_return_val_if_fail (store->datasheet != NULL, NULL);
583   g_return_val_if_fail (var != NULL, NULL);
584
585   if (row < 0 || row >= datasheet_get_n_rows (store->datasheet))
586     return NULL;
587
588   width = var_get_width (var);
589   value_init (&v, width);
590   datasheet_get_value (store->datasheet, row, var_get_case_index (var), &v);
591
592   string = NULL;
593   if (use_value_label)
594     {
595       const char *label = var_lookup_value_label (var, &v);
596       if (label != NULL)
597         string = g_strdup (label);
598     }
599   if (string == NULL)
600     string = value_to_text (v, var);
601
602   value_destroy (&v, width);
603
604   return string;
605 }
606
607
608 /* Attempts to update that part of the variable store which corresponds to VAR
609    within ROW with the value TEXT.
610
611    If USE_VALUE_LABEL is true, and TEXT is a value label for the column's
612    variable, then stores the value from that value label instead of the literal
613    TEXT.
614
615    Returns true if anything was updated, false otherwise.  */
616 gboolean
617 psppire_data_store_set_string (PsppireDataStore *store,
618                                const gchar *text,
619                                glong row, const struct variable *var,
620                                gboolean use_value_label)
621 {
622   gint case_index;
623   glong n_cases;
624   gboolean ok;
625
626   n_cases = psppire_data_store_get_case_count (store);
627   if (row > n_cases)
628     return FALSE;
629   if (row == n_cases)
630     psppire_data_store_insert_new_case (store, row);
631
632   case_index = var_get_case_index (var);
633   if (use_value_label)
634     {
635       const struct val_labs *vls = var_get_value_labels (var);
636       const union value *value = vls ? val_labs_find_value (vls, text) : NULL;
637       if (value)
638         ok = datasheet_put_value (store->datasheet, row, case_index, value);
639       else
640         ok = FALSE;
641     }
642   else
643     ok = psppire_data_store_data_in (store, row, case_index, ss_cstr (text),
644                                      var_get_print_format (var));
645
646   if (ok)
647     g_signal_emit (store, signals [CASE_CHANGED], 0, row);
648   return ok;
649 }
650
651
652
653 void
654 psppire_data_store_clear (PsppireDataStore *ds)
655 {
656   datasheet_destroy (ds->datasheet);
657   ds->datasheet = NULL;
658
659   psppire_dict_clear (ds->dict);
660
661   g_signal_emit (ds, signals [CASES_DELETED], 0, 0, -1);
662 }
663
664
665
666 /* Return a casereader made from this datastore */
667 struct casereader *
668 psppire_data_store_get_reader (PsppireDataStore *ds)
669 {
670   int i;
671   struct casereader *reader ;
672
673   if ( ds->dict )
674     for (i = 0 ; i < n_dict_signals; ++i )
675       {
676         g_signal_handler_block (ds->dict,
677                                 ds->dict_handler_id[i]);
678       }
679
680   reader = datasheet_make_reader (ds->datasheet);
681
682   /* We must not reference this again */
683   ds->datasheet = NULL;
684
685   return reader;
686 }
687
688
689
690 /* Column related funcs */
691
692
693 static const gchar null_var_name[]=N_("var");
694
695
696 \f
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 [CASES_DELETED], 0, first, n_cases);
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     g_signal_emit (ds, signals [CASE_INSERTED], 0, posn);
748   else
749     g_warning ("Cannot insert case at position %ld\n", posn);
750
751   return result;
752 }
753
754
755 /* Set the value of VAR in case CASENUM to V.
756    V must be the correct width for IDX.
757    Returns true if successful, false on I/O error. */
758 gboolean
759 psppire_data_store_set_value (PsppireDataStore *ds, casenumber casenum,
760                               const struct variable *var, const union value *v)
761 {
762   glong n_cases;
763   bool ok;
764
765   g_return_val_if_fail (ds, FALSE);
766   g_return_val_if_fail (ds->datasheet, FALSE);
767
768   n_cases = psppire_data_store_get_case_count (ds);
769   if ( casenum > n_cases)
770     return FALSE;
771
772   if (casenum == n_cases)
773     psppire_data_store_insert_new_case (ds, casenum);
774
775   ok = datasheet_put_value (ds->datasheet, casenum, var_get_case_index (var),
776                             v);
777   if (ok)
778     g_signal_emit (ds, signals [CASE_CHANGED], 0, casenum);
779
780   return ok;
781 }
782
783
784
785
786 /* Set the IDXth value of case C using D_IN */
787 static gboolean
788 psppire_data_store_data_in (PsppireDataStore *ds, casenumber casenum, gint idx,
789                             struct substring input, const struct fmt_spec *fmt)
790 {
791   union value value;
792   int width;
793   bool ok;
794
795   PsppireDict *dict;
796
797   g_return_val_if_fail (ds, FALSE);
798   g_return_val_if_fail (ds->datasheet, FALSE);
799
800   g_return_val_if_fail (idx < datasheet_get_n_columns (ds->datasheet), FALSE);
801
802   dict = ds->dict;
803
804   width = fmt_var_width (fmt);
805   g_return_val_if_fail (caseproto_get_width (
806                           datasheet_get_proto (ds->datasheet), idx) == width,
807                         FALSE);
808   value_init (&value, width);
809   ok = (datasheet_get_value (ds->datasheet, casenum, idx, &value)
810         && data_in_msg (input, UTF8, fmt->type, &value, width,
811                         dict_get_encoding (dict->dict))
812         && datasheet_put_value (ds->datasheet, casenum, idx, &value));
813   value_destroy (&value, width);
814
815   return ok;
816 }
817
818 /* Resize the cases in the casefile, by inserting a value of the
819    given WIDTH into every one of them at the position immediately
820    preceding WHERE.
821 */
822 static gboolean
823 psppire_data_store_insert_value (PsppireDataStore *ds,
824                                  gint width, gint where)
825 {
826   union value value;
827
828   g_return_val_if_fail (ds, FALSE);
829
830   g_assert (width >= 0);
831
832   if ( ! ds->datasheet )
833     ds->datasheet = datasheet_create (NULL);
834
835   value_init (&value, width);
836   value_set_missing (&value, width);
837
838   datasheet_insert_column (ds->datasheet, &value, width, where);
839   value_destroy (&value, width);
840
841   return TRUE;
842 }
843
844 gboolean
845 psppire_data_store_filtered (PsppireDataStore *ds,
846                              glong row)
847 {
848   union value val;
849
850   const struct dictionary *dict;
851   const struct variable *filter;
852
853   if ( row < 0 || row >= datasheet_get_n_rows (ds->datasheet))
854     return FALSE;
855
856   dict = ds->dict->dict;
857   g_return_val_if_fail (dict, FALSE);
858   filter = dict_get_filter (dict);
859   if ( ! filter)
860     return FALSE;
861
862   g_return_val_if_fail (var_is_numeric (filter), FALSE);
863   value_init (&val, 0);
864   if ( ! datasheet_get_value (ds->datasheet, row,
865                               var_get_case_index (filter),
866                               &val) )
867     return FALSE;
868
869   return (val.f == 0.0);
870 }