Improve the conversion to and from cell values
[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 #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 gchar *
596 psppire_data_store_get_string (PsppireDataStore *store,
597                                glong row, const struct variable *var,
598                                bool use_value_label)
599 {
600   gchar *string;
601   union value v;
602   int width;
603
604   g_return_val_if_fail (store != NULL, NULL);
605   g_return_val_if_fail (store->datasheet != NULL, NULL);
606   g_return_val_if_fail (var != NULL, NULL);
607
608   if (row < 0 || row >= datasheet_get_n_rows (store->datasheet))
609     return NULL;
610
611   width = var_get_width (var);
612   value_init (&v, width);
613   datasheet_get_value (store->datasheet, row, var_get_case_index (var), &v);
614
615   string = NULL;
616   if (use_value_label)
617     {
618       const char *label = var_lookup_value_label (var, &v);
619       if (label != NULL)
620         string = g_strdup (label);
621     }
622   if (string == NULL)
623     string = value_to_text (v, var);
624
625   value_destroy (&v, width);
626
627   return string;
628 }
629
630
631 /* Attempts to update that part of the variable store which corresponds to VAR
632    within ROW with the value TEXT.
633
634    If USE_VALUE_LABEL is true, and TEXT is a value label for the column's
635    variable, then stores the value from that value label instead of the literal
636    TEXT.
637
638    Returns true if anything was updated, false otherwise.  */
639 gboolean
640 psppire_data_store_set_string (PsppireDataStore *store,
641                                const gchar *text,
642                                glong row, const struct variable *var,
643                                gboolean use_value_label)
644 {
645   gint case_index;
646   glong n_cases;
647   gboolean ok;
648
649   n_cases = psppire_data_store_get_case_count (store);
650   if (row > n_cases)
651     return FALSE;
652   if (row == n_cases)
653     psppire_data_store_insert_new_case (store, row);
654
655   case_index = var_get_case_index (var);
656   if (use_value_label)
657     {
658       const struct val_labs *vls = var_get_value_labels (var);
659       const union value *value = vls ? val_labs_find_value (vls, text) : NULL;
660       if (value)
661         ok = datasheet_put_value (store->datasheet, row, case_index, value);
662       else
663         ok = FALSE;
664     }
665   else
666     ok = psppire_data_store_data_in (store, row, case_index, ss_cstr (text),
667                                      var_get_print_format (var));
668
669   if (ok)
670     g_signal_emit (store, signals [CASE_CHANGED], 0, row);
671   return ok;
672 }
673
674
675
676 void
677 psppire_data_store_clear (PsppireDataStore *ds)
678 {
679   datasheet_destroy (ds->datasheet);
680   ds->datasheet = NULL;
681
682   psppire_dict_clear (ds->dict);
683
684   g_signal_emit (ds, signals [CASES_DELETED], 0, 0, -1);
685 }
686
687
688
689 /* Return a casereader made from this datastore */
690 struct casereader *
691 psppire_data_store_get_reader (PsppireDataStore *ds)
692 {
693   int i;
694   struct casereader *reader ;
695
696   if ( ds->dict )
697     for (i = 0 ; i < n_dict_signals; ++i )
698       {
699         g_signal_handler_block (ds->dict,
700                                 ds->dict_handler_id[i]);
701       }
702
703   reader = datasheet_make_reader (ds->datasheet);
704
705   /* We must not reference this again */
706   ds->datasheet = NULL;
707
708   return reader;
709 }
710
711
712
713 /* Column related funcs */
714
715
716 static const gchar null_var_name[]=N_("var");
717
718
719 \f
720
721
722 /* Returns the CASENUMth case, or a null pointer on failure.
723  */
724 struct ccase *
725 psppire_data_store_get_case (const PsppireDataStore *ds,
726                              casenumber casenum)
727 {
728   g_return_val_if_fail (ds, FALSE);
729   g_return_val_if_fail (ds->datasheet, FALSE);
730
731   return datasheet_get_row (ds->datasheet, casenum);
732 }
733
734
735 gboolean
736 psppire_data_store_delete_cases (PsppireDataStore *ds, casenumber first,
737                                  casenumber n_cases)
738 {
739   g_return_val_if_fail (ds, FALSE);
740   g_return_val_if_fail (ds->datasheet, FALSE);
741
742   g_return_val_if_fail (first + n_cases <=
743                         psppire_data_store_get_case_count (ds), FALSE);
744
745
746   datasheet_delete_rows (ds->datasheet, first, n_cases);
747
748   g_signal_emit (ds, signals [CASES_DELETED], 0, first, n_cases);
749
750   return TRUE;
751 }
752
753
754
755 /* Insert case CC into the case file before POSN */
756 static gboolean
757 psppire_data_store_insert_case (PsppireDataStore *ds,
758                                 struct ccase *cc,
759                                 casenumber posn)
760 {
761   bool result ;
762
763   g_return_val_if_fail (ds, FALSE);
764   g_return_val_if_fail (ds->datasheet, FALSE);
765
766   cc = case_ref (cc);
767   result = datasheet_insert_rows (ds->datasheet, posn, &cc, 1);
768
769   if ( result )
770     g_signal_emit (ds, signals [CASE_INSERTED], 0, posn);
771   else
772     g_warning ("Cannot insert case at position %ld\n", posn);
773
774   return result;
775 }
776
777
778 /* Set the value of VAR in case CASENUM to V.
779    V must be the correct width for IDX.
780    Returns true if successful, false on I/O error. */
781 gboolean
782 psppire_data_store_set_value (PsppireDataStore *ds, casenumber casenum,
783                               const struct variable *var, const union value *v)
784 {
785   glong n_cases;
786   bool ok;
787
788   g_return_val_if_fail (ds, FALSE);
789   g_return_val_if_fail (ds->datasheet, FALSE);
790
791   n_cases = psppire_data_store_get_case_count (ds);
792   if ( casenum > n_cases)
793     return FALSE;
794
795   if (casenum == n_cases)
796     psppire_data_store_insert_new_case (ds, casenum);
797
798   ok = datasheet_put_value (ds->datasheet, casenum, var_get_case_index (var),
799                             v);
800   if (ok)
801     g_signal_emit (ds, signals [CASE_CHANGED], 0, casenum);
802
803   return ok;
804 }
805
806
807
808
809 /* Set the IDXth value of case C using D_IN */
810 static gboolean
811 psppire_data_store_data_in (PsppireDataStore *ds, casenumber casenum, gint idx,
812                             struct substring input, const struct fmt_spec *fmt)
813 {
814   union value value;
815   int width;
816   bool ok;
817
818   PsppireDict *dict;
819
820   g_return_val_if_fail (ds, FALSE);
821   g_return_val_if_fail (ds->datasheet, FALSE);
822
823   g_return_val_if_fail (idx < datasheet_get_n_columns (ds->datasheet), FALSE);
824
825   dict = ds->dict;
826
827   width = fmt_var_width (fmt);
828   g_return_val_if_fail (caseproto_get_width (
829                           datasheet_get_proto (ds->datasheet), idx) == width,
830                         FALSE);
831   value_init (&value, width);
832   ok = (datasheet_get_value (ds->datasheet, casenum, idx, &value)
833         && data_in_msg (input, UTF8, fmt->type, &value, width,
834                         dict_get_encoding (dict->dict))
835         && datasheet_put_value (ds->datasheet, casenum, idx, &value));
836   value_destroy (&value, width);
837
838   return ok;
839 }
840
841 /* Resize the cases in the casefile, by inserting a value of the
842    given WIDTH into every one of them at the position immediately
843    preceding WHERE.
844 */
845 static gboolean
846 psppire_data_store_insert_value (PsppireDataStore *ds,
847                                  gint width, gint where)
848 {
849   union value value;
850
851   g_return_val_if_fail (ds, FALSE);
852
853   g_assert (width >= 0);
854
855   if ( ! ds->datasheet )
856     ds->datasheet = datasheet_create (NULL);
857
858   value_init (&value, width);
859   value_set_missing (&value, width);
860
861   datasheet_insert_column (ds->datasheet, &value, width, where);
862   value_destroy (&value, width);
863
864   return TRUE;
865 }
866
867 gboolean
868 psppire_data_store_filtered (PsppireDataStore *ds,
869                              glong row)
870 {
871   union value val;
872
873   const struct dictionary *dict;
874   const struct variable *filter;
875
876   if ( row < 0 || row >= datasheet_get_n_rows (ds->datasheet))
877     return FALSE;
878
879   dict = ds->dict->dict;
880   g_return_val_if_fail (dict, FALSE);
881   filter = dict_get_filter (dict);
882   if ( ! filter)
883     return FALSE;
884
885   g_return_val_if_fail (var_is_numeric (filter), FALSE);
886   value_init (&val, 0);
887   if ( ! datasheet_get_value (ds->datasheet, row,
888                               var_get_case_index (filter),
889                               &val) )
890     return FALSE;
891
892   return (val.f == 0.0);
893 }