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