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