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