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