Update model on inserting/deleting cases
[pspp-builds.git] / src / ui / gui / psppire-data-store.c
1 /* PSPPIRE - a graphical user interface for PSPP.
2    Copyright (C) 2006, 2008  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 <gtksheet/gsheetmodel.h>
29 #include <gtksheet/psppire-marshal.h>
30
31 #include <pango/pango-context.h>
32
33 #include "psppire-data-store.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 static void psppire_data_store_sheet_model_init (GSheetModelIface *iface);
52
53 static void psppire_data_store_finalize        (GObject           *object);
54 static void psppire_data_store_dispose        (GObject           *object);
55
56 static gboolean psppire_data_store_clear_datum (GSheetModel *model,
57                                           glong row, glong column);
58
59
60 static gboolean psppire_data_store_insert_case (PsppireDataStore *ds,
61                                                 struct ccase *cc,
62                                                 casenumber posn);
63
64
65 static gboolean psppire_data_store_data_in (PsppireDataStore *ds,
66                                             casenumber casenum, gint idx,
67                                             struct substring input,
68                                             const struct fmt_spec *fmt);
69
70
71
72 static GObjectClass *parent_class = NULL;
73
74
75 enum
76   {
77     BACKEND_CHANGED,
78     CASES_DELETED,
79     CASE_INSERTED,
80     CASE_CHANGED,
81     n_SIGNALS
82   };
83
84 static guint signals [n_SIGNALS];
85
86
87 GType
88 psppire_data_store_get_type (void)
89 {
90   static GType data_store_type = 0;
91
92   if (!data_store_type)
93     {
94       static const GTypeInfo data_store_info =
95       {
96         sizeof (PsppireDataStoreClass),
97         NULL,           /* base_init */
98         NULL,           /* base_finalize */
99         (GClassInitFunc) psppire_data_store_class_init,
100         NULL,           /* class_finalize */
101         NULL,           /* class_data */
102         sizeof (PsppireDataStore),
103         0,
104         (GInstanceInitFunc) psppire_data_store_init,
105       };
106
107       static const GInterfaceInfo sheet_model_info =
108       {
109         (GInterfaceInitFunc) psppire_data_store_sheet_model_init,
110         NULL,
111         NULL
112       };
113
114
115       data_store_type = g_type_register_static (G_TYPE_OBJECT,
116                                                 "PsppireDataStore",
117                                                 &data_store_info, 0);
118
119       g_type_add_interface_static (data_store_type,
120                                    G_TYPE_SHEET_MODEL,
121                                    &sheet_model_info);
122
123     }
124
125   return data_store_type;
126 }
127
128
129 static void
130 psppire_data_store_class_init (PsppireDataStoreClass *class)
131 {
132   GObjectClass *object_class;
133
134   parent_class = g_type_class_peek_parent (class);
135   object_class = (GObjectClass*) class;
136
137   object_class->finalize = psppire_data_store_finalize;
138   object_class->dispose = psppire_data_store_dispose;
139
140   signals [BACKEND_CHANGED] =
141     g_signal_new ("backend-changed",
142                   G_TYPE_FROM_CLASS (class),
143                   G_SIGNAL_RUN_FIRST,
144                   0,
145                   NULL, NULL,
146                   g_cclosure_marshal_VOID__VOID,
147                   G_TYPE_NONE,
148                   0);
149
150   signals [CASE_INSERTED] =
151     g_signal_new ("case-inserted",
152                   G_TYPE_FROM_CLASS (class),
153                   G_SIGNAL_RUN_FIRST,
154                   0,
155                   NULL, NULL,
156                   g_cclosure_marshal_VOID__INT,
157                   G_TYPE_NONE,
158                   1,
159                   G_TYPE_INT);
160
161
162   signals [CASE_CHANGED] =
163     g_signal_new ("case-changed",
164                   G_TYPE_FROM_CLASS (class),
165                   G_SIGNAL_RUN_FIRST,
166                   0,
167                   NULL, NULL,
168                   g_cclosure_marshal_VOID__INT,
169                   G_TYPE_NONE,
170                   1,
171                   G_TYPE_INT);
172
173   signals [CASES_DELETED] =
174     g_signal_new ("cases-deleted",
175                   G_TYPE_FROM_CLASS (class),
176                   G_SIGNAL_RUN_FIRST,
177                   0,
178                   NULL, NULL,
179                   psppire_marshal_VOID__INT_INT,
180                   G_TYPE_NONE,
181                   2,
182                   G_TYPE_INT,
183                   G_TYPE_INT);
184 }
185
186
187
188 static gboolean
189 psppire_data_store_insert_values (PsppireDataStore *ds,
190                                   gint n_values, gint where);
191
192 static union value *
193 psppire_data_store_get_value (const PsppireDataStore *ds,
194                               casenumber casenum, size_t idx,
195                               union value *value, int width);
196
197
198 static gboolean
199 psppire_data_store_set_value (PsppireDataStore *ds, casenumber casenum,
200                               gint idx, union value *v, gint width);
201
202
203
204
205 static glong
206 psppire_data_store_get_var_count (const GSheetModel *model)
207 {
208   const PsppireDataStore *store = PSPPIRE_DATA_STORE (model);
209
210   return psppire_dict_get_var_cnt (store->dict);
211 }
212
213 casenumber
214 psppire_data_store_get_case_count (const PsppireDataStore *store)
215 {
216   return datasheet_get_row_cnt (store->datasheet);
217 }
218
219 size_t
220 psppire_data_store_get_value_count (const PsppireDataStore *store)
221 {
222   return psppire_dict_get_value_cnt (store->dict);
223 }
224
225 static casenumber
226 psppire_data_store_get_case_count_wrapper (const GSheetModel *model)
227 {
228   const PsppireDataStore *store = PSPPIRE_DATA_STORE (model);
229   return psppire_data_store_get_case_count (store);
230 }
231
232 static void
233 psppire_data_store_init (PsppireDataStore *data_store)
234 {
235   data_store->dict = 0;
236   data_store->datasheet = NULL;
237   data_store->dispose_has_run = FALSE;
238 }
239
240 static inline gchar *
241 psppire_data_store_get_string_wrapper (const GSheetModel *model, glong row,
242                                        glong column)
243 {
244   return psppire_data_store_get_string (PSPPIRE_DATA_STORE (model), row, column);
245 }
246
247
248 static inline gboolean
249 psppire_data_store_set_string_wrapper (GSheetModel *model,
250                                        const gchar *text,
251                                        glong row, glong column)
252 {
253   return psppire_data_store_set_string (PSPPIRE_DATA_STORE (model), text,
254                                         row, column);
255 }
256
257
258
259 static gchar * get_column_subtitle (const GSheetModel *model, gint col);
260 static gchar * get_column_button_label (const GSheetModel *model, gint col);
261 static gboolean get_column_sensitivity (const GSheetModel *model, gint col);
262 static GtkJustification get_column_justification (const GSheetModel *model, gint col);
263
264 static gchar * get_row_button_label (const GSheetModel *model, gint row);
265 static gboolean get_row_sensitivity (const GSheetModel *model, gint row);
266
267
268 static void
269 psppire_data_store_sheet_model_init (GSheetModelIface *iface)
270 {
271   iface->free_strings = TRUE;
272   iface->get_string = psppire_data_store_get_string_wrapper;
273   iface->set_string = psppire_data_store_set_string_wrapper;
274   iface->clear_datum = psppire_data_store_clear_datum;
275   iface->is_editable = NULL;
276   iface->get_foreground = NULL;
277   iface->get_background = NULL;
278   iface->get_cell_border = NULL;
279   iface->get_column_count = psppire_data_store_get_var_count;
280   iface->get_row_count = psppire_data_store_get_case_count_wrapper;
281
282   iface->get_column_subtitle = get_column_subtitle;
283   iface->get_column_title = get_column_button_label;
284   iface->get_column_sensitivity = get_column_sensitivity;
285   iface->get_column_justification = get_column_justification;
286
287   iface->get_row_title = get_row_button_label;
288   iface->get_row_sensitivity = get_row_sensitivity;
289 }
290
291
292 /*
293    A callback which occurs after a variable has been deleted.
294  */
295 static void
296 delete_variable_callback (GObject *obj, gint dict_index,
297                           gint case_index, gint val_cnt,
298                           gpointer data)
299 {
300   PsppireDataStore *store  = PSPPIRE_DATA_STORE (data);
301
302
303   g_sheet_model_columns_deleted (G_SHEET_MODEL (store), dict_index, 1);
304 #if AXIS_TRANSITION
305
306
307   g_sheet_column_columns_changed (G_SHEET_COLUMN (store),
308                                    dict_index, -1);
309 #endif
310 }
311
312
313
314 static void
315 variable_changed_callback (GObject *obj, gint var_num, gpointer data)
316 {
317   PsppireDataStore *store  = PSPPIRE_DATA_STORE (data);
318
319 #if AXIS_TRANSITION
320   g_sheet_column_columns_changed (G_SHEET_COLUMN (store),
321                                   var_num, 1);
322
323
324   g_sheet_model_range_changed (G_SHEET_MODEL (store),
325                                -1, var_num,
326                                -1, var_num);
327 #endif
328 }
329
330 static void
331 insert_variable_callback (GObject *obj, gint var_num, gpointer data)
332 {
333   PsppireDataStore *store;
334   gint posn;
335
336   g_return_if_fail (data);
337
338   store  = PSPPIRE_DATA_STORE (data);
339
340   if ( var_num > 0 )
341     {
342       struct variable *variable =
343         psppire_dict_get_variable (store->dict, var_num);
344
345       g_assert (variable != NULL);
346
347       posn = var_get_case_index (variable);
348     }
349   else
350     {
351       posn = 0;
352     }
353
354   psppire_data_store_insert_values (store, 1, posn);
355
356 #if AXIS_TRANSITION
357
358   g_sheet_column_columns_changed (G_SHEET_COLUMN (store),
359                                   var_num, 1);
360 #endif
361
362   g_sheet_model_columns_inserted (G_SHEET_MODEL (store), var_num, 1);
363 }
364
365
366 static void
367 dict_size_change_callback (GObject *obj,
368                           gint posn, gint adjustment, gpointer data)
369 {
370   PsppireDataStore *store  = PSPPIRE_DATA_STORE (data);
371
372   const struct variable *v = psppire_dict_get_variable (store->dict, posn);
373
374   const gint new_val_width = value_cnt_from_width (var_get_width (v));
375
376   if ( adjustment > 0 )
377     psppire_data_store_insert_values (store, adjustment,
378                                      new_val_width - adjustment +
379                                      var_get_case_index(v));
380 }
381
382
383
384 /**
385  * psppire_data_store_new:
386  * @dict: The dictionary for this data_store.
387  *
388  *
389  * Return value: a new #PsppireDataStore
390  **/
391 PsppireDataStore *
392 psppire_data_store_new (PsppireDict *dict)
393 {
394   PsppireDataStore *retval;
395
396   retval = g_object_new (GTK_TYPE_DATA_STORE, NULL);
397
398   psppire_data_store_set_dictionary (retval, dict);
399
400   return retval;
401 }
402
403 void
404 psppire_data_store_set_reader (PsppireDataStore *ds,
405                                struct casereader *reader)
406 {
407   gint i;
408
409   if ( ds->datasheet)
410     datasheet_destroy (ds->datasheet);
411
412   ds->datasheet = datasheet_create (reader);
413
414   g_sheet_model_range_changed (G_SHEET_MODEL (ds),
415                                -1, -1, -1, -1);
416
417   if ( ds->dict )
418     for (i = 0 ; i < n_dict_signals; ++i )
419       {
420         if ( ds->dict_handler_id [i] > 0)
421           {
422             g_signal_handler_unblock (ds->dict,
423                                       ds->dict_handler_id[i]);
424           }
425       }
426
427   g_signal_emit (ds, signals[BACKEND_CHANGED], 0);
428 }
429
430
431 /**
432  * psppire_data_store_replace_set_dictionary:
433  * @data_store: The variable store
434  * @dict: The dictionary to set
435  *
436  * If a dictionary is already associated with the data-store, then it will be
437  * destroyed.
438  **/
439 void
440 psppire_data_store_set_dictionary (PsppireDataStore *data_store, PsppireDict *dict)
441 {
442   int i;
443
444   /* Disconnect any existing handlers */
445   if ( data_store->dict )
446     for (i = 0 ; i < n_dict_signals; ++i )
447       {
448         g_signal_handler_disconnect (data_store->dict,
449                                      data_store->dict_handler_id[i]);
450       }
451
452   data_store->dict = dict;
453
454   if ( dict != NULL)
455     {
456
457       data_store->dict_handler_id [VARIABLE_INSERTED] =
458         g_signal_connect (dict, "variable-inserted",
459                           G_CALLBACK (insert_variable_callback),
460                           data_store);
461
462       data_store->dict_handler_id [VARIABLE_DELETED] =
463         g_signal_connect (dict, "variable-deleted",
464                           G_CALLBACK (delete_variable_callback),
465                           data_store);
466
467       data_store->dict_handler_id [VARIABLE_CHANGED] =
468         g_signal_connect (dict, "variable-changed",
469                           G_CALLBACK (variable_changed_callback),
470                           data_store);
471
472       data_store->dict_handler_id [SIZE_CHANGED] =
473         g_signal_connect (dict, "dict-size-changed",
474                           G_CALLBACK (dict_size_change_callback),
475                           data_store);
476     }
477
478
479
480   /* The entire model has changed */
481   g_sheet_model_range_changed (G_SHEET_MODEL (data_store), -1, -1, -1, -1);
482
483 #if AXIS_TRANSITION
484   g_sheet_column_columns_changed (G_SHEET_COLUMN (data_store), 0, -1);
485 #endif
486
487   if ( data_store->dict )
488     for (i = 0 ; i < n_dict_signals; ++i )
489       {
490         if ( data_store->dict_handler_id [i] > 0)
491           {
492             g_signal_handler_block (data_store->dict,
493                                     data_store->dict_handler_id[i]);
494           }
495       }
496 }
497
498 static void
499 psppire_data_store_finalize (GObject *object)
500 {
501
502   /* must chain up */
503   (* parent_class->finalize) (object);
504 }
505
506
507 static void
508 psppire_data_store_dispose (GObject *object)
509 {
510   PsppireDataStore *ds = PSPPIRE_DATA_STORE (object);
511
512   if (ds->dispose_has_run)
513     return;
514
515   if (ds->datasheet)
516     {
517       datasheet_destroy (ds->datasheet);
518       ds->datasheet = NULL;
519     }
520
521   /* must chain up */
522   (* parent_class->dispose) (object);
523
524   ds->dispose_has_run = TRUE;
525 }
526
527
528
529 /* Insert a blank case before POSN */
530 gboolean
531 psppire_data_store_insert_new_case (PsppireDataStore *ds, casenumber posn)
532 {
533   gboolean result;
534   gint val_cnt, v;
535   struct ccase cc;
536   g_return_val_if_fail (ds, FALSE);
537
538   val_cnt = datasheet_get_column_cnt (ds->datasheet) ;
539
540   g_return_val_if_fail (val_cnt > 0, FALSE);
541
542   g_return_val_if_fail (posn <= psppire_data_store_get_case_count (ds), FALSE);
543
544   case_create (&cc, val_cnt);
545
546   memset ( case_data_rw_idx (&cc, 0), 0, val_cnt * MAX_SHORT_STRING);
547
548   for (v = 0 ; v < psppire_dict_get_var_cnt (ds->dict) ; ++v)
549     {
550       const struct variable *pv = psppire_dict_get_variable (ds->dict, v);
551       if ( var_is_alpha (pv))
552         continue;
553
554       case_data_rw (&cc, pv)->f = SYSMIS;
555     }
556
557   result = psppire_data_store_insert_case (ds, &cc, posn);
558
559   case_destroy (&cc);
560
561   return result;
562 }
563
564
565 gchar *
566 psppire_data_store_get_string (PsppireDataStore *store, glong row, glong column)
567 {
568   gint idx;
569   char *text;
570   const struct fmt_spec *fp ;
571   const struct variable *pv ;
572   union value *v ;
573   GString *s;
574
575   g_return_val_if_fail (store->dict, NULL);
576   g_return_val_if_fail (store->datasheet, NULL);
577
578   if (column >= psppire_dict_get_var_cnt (store->dict))
579     return NULL;
580
581   if ( row >= psppire_data_store_get_case_count (store))
582     return NULL;
583
584   pv = psppire_dict_get_variable (store->dict, column);
585
586   g_assert (pv);
587
588   idx = var_get_case_index (pv);
589
590   g_assert (idx >= 0);
591
592   v = psppire_data_store_get_value (store, row, idx, NULL,
593                                    var_get_width (pv));
594
595   g_return_val_if_fail (v, NULL);
596
597   if ( store->show_labels)
598     {
599       const gchar *label = var_lookup_value_label (pv, v);
600       if (label)
601         {
602           free (v);
603           return pspp_locale_to_utf8 (label, -1, 0);
604         }
605     }
606
607   fp = var_get_write_format (pv);
608
609   s = g_string_sized_new (fp->w + 1);
610   g_string_set_size (s, fp->w);
611
612   memset (s->str, 0, fp->w);
613
614   g_assert (fp->w == s->len);
615
616   /* Converts binary value V into printable form in the exactly
617      FP->W character in buffer S according to format specification
618      FP.  No null terminator is appended to the buffer.  */
619   data_out (v, fp, s->str);
620
621   text = pspp_locale_to_utf8 (s->str, fp->w, 0);
622   g_string_free (s, TRUE);
623
624   g_strchomp (text);
625
626   free (v);
627   return text;
628 }
629
630
631 static gboolean
632 psppire_data_store_clear_datum (GSheetModel *model,
633                                           glong row, glong col)
634 {
635   PsppireDataStore *store = PSPPIRE_DATA_STORE (model);
636
637   union value v;
638   const struct variable *pv = psppire_dict_get_variable (store->dict, col);
639
640   const gint index = var_get_case_index (pv) ;
641
642   if ( var_is_numeric (pv))
643     v.f = SYSMIS;
644   else
645     memcpy (v.s, "", MAX_SHORT_STRING);
646
647   psppire_data_store_set_value (store, row, index, &v,
648                                 var_get_width (pv));
649
650   return TRUE;
651 }
652
653
654 /* Attempts to update that part of the variable store which corresponds
655    to ROW, COL with  the value TEXT.
656    Returns true if anything was updated, false otherwise.
657 */
658 gboolean
659 psppire_data_store_set_string (PsppireDataStore *store,
660                                const gchar *text, glong row, glong col)
661 {
662   glong n_cases;
663   const struct variable *pv = psppire_dict_get_variable (store->dict, col);
664   g_return_val_if_fail (pv, FALSE);
665
666   n_cases = psppire_data_store_get_case_count (store);
667
668   if ( row > n_cases)
669     return FALSE;
670
671   if (row == n_cases)
672     psppire_data_store_insert_new_case (store, row);
673
674   psppire_data_store_data_in (store, row,
675                               var_get_case_index (pv), ss_cstr (text),
676                               var_get_write_format (pv));
677
678   return TRUE;
679 }
680
681
682
683 void
684 psppire_data_store_show_labels (PsppireDataStore *store, gboolean show_labels)
685 {
686   g_return_if_fail (store);
687   g_return_if_fail (PSPPIRE_IS_DATA_STORE (store));
688
689   store->show_labels = show_labels;
690
691   g_sheet_model_range_changed (G_SHEET_MODEL (store),
692                                  -1, -1, -1, -1);
693 }
694
695
696 void
697 psppire_data_store_clear (PsppireDataStore *ds)
698 {
699   datasheet_destroy (ds->datasheet);
700   ds->datasheet = NULL;
701
702   psppire_dict_clear (ds->dict);
703
704   g_signal_emit (ds, signals [CASES_DELETED], 0, 0, -1);
705 }
706
707
708
709 /* Return a casereader made from this datastore */
710 struct casereader *
711 psppire_data_store_get_reader (PsppireDataStore *ds)
712 {
713   int i;
714   struct casereader *reader ;
715
716   if ( ds->dict )
717     for (i = 0 ; i < n_dict_signals; ++i )
718       {
719         g_signal_handler_block (ds->dict,
720                                 ds->dict_handler_id[i]);
721       }
722
723   reader = datasheet_make_reader (ds->datasheet);
724
725   /* We must not reference this again */
726   ds->datasheet = NULL;
727
728   return reader;
729 }
730
731
732
733 /* Column related funcs */
734
735
736 static const gchar null_var_name[]=N_("var");
737
738 \f
739
740 /* Row related funcs */
741
742 static gchar *
743 get_row_button_label (const GSheetModel *model, gint unit)
744 {
745   gchar *s = g_strdup_printf (_("%d"), unit + FIRST_CASE_NUMBER);
746
747   gchar *text =  pspp_locale_to_utf8 (s, -1, 0);
748
749   g_free (s);
750
751   return text;
752 }
753
754
755 static gboolean
756 get_row_sensitivity (const GSheetModel *model, gint unit)
757 {
758   PsppireDataStore *ds = PSPPIRE_DATA_STORE (model);
759
760   return (unit < psppire_data_store_get_case_count (ds));
761 }
762
763
764 \f
765
766 /* Column related stuff */
767
768 static gchar *
769 get_column_subtitle (const GSheetModel *model, gint col)
770 {
771   gchar *text;
772   const struct variable *v ;
773   PsppireDataStore *ds = PSPPIRE_DATA_STORE (model);
774
775   if ( col >= psppire_dict_get_var_cnt (ds->dict) )
776     return NULL;
777
778   v = psppire_dict_get_variable (ds->dict, col);
779
780   if ( ! var_has_label (v))
781     return NULL;
782
783   text =  pspp_locale_to_utf8 (var_get_label (v), -1, 0);
784
785   return text;
786 }
787
788 static gchar *
789 get_column_button_label (const GSheetModel *model, gint col)
790 {
791   gchar *text;
792   struct variable *pv ;
793   PsppireDataStore *ds = PSPPIRE_DATA_STORE (model);
794
795   if ( col >= psppire_dict_get_var_cnt (ds->dict) )
796     return g_locale_to_utf8 (null_var_name, -1, 0, 0, 0);
797
798   pv = psppire_dict_get_variable (ds->dict, col);
799
800   text =  pspp_locale_to_utf8 (var_get_name (pv), -1, 0);
801
802   return text;
803 }
804
805 static gboolean
806 get_column_sensitivity (const GSheetModel *model, gint col)
807 {
808   PsppireDataStore *ds = PSPPIRE_DATA_STORE (model);
809
810   return (col < psppire_dict_get_var_cnt (ds->dict));
811 }
812
813
814
815 static GtkJustification
816 get_column_justification (const GSheetModel *model, gint col)
817 {
818   PsppireDataStore *ds = PSPPIRE_DATA_STORE (model);
819   const struct variable *pv ;
820
821   if ( col >= psppire_dict_get_var_cnt (ds->dict) )
822     return GTK_JUSTIFY_LEFT;
823
824   pv = psppire_dict_get_variable (ds->dict, col);
825
826   return (var_get_alignment (pv) == ALIGN_LEFT ? GTK_JUSTIFY_LEFT
827           : var_get_alignment (pv) == ALIGN_RIGHT ? GTK_JUSTIFY_RIGHT
828           : GTK_JUSTIFY_CENTER);
829 }
830
831
832
833 \f
834
835
836 /* Fills C with the CASENUMth case.
837    Returns true on success, false otherwise.
838  */
839 gboolean
840 psppire_data_store_get_case (const PsppireDataStore *ds,
841                              casenumber casenum,
842                              struct ccase *c)
843 {
844   g_return_val_if_fail (ds, FALSE);
845   g_return_val_if_fail (ds->datasheet, FALSE);
846
847   return datasheet_get_row (ds->datasheet, casenum, c);
848 }
849
850
851 gboolean
852 psppire_data_store_delete_cases (PsppireDataStore *ds, casenumber first,
853                                  casenumber n_cases)
854 {
855   g_return_val_if_fail (ds, FALSE);
856   g_return_val_if_fail (ds->datasheet, FALSE);
857
858   g_return_val_if_fail (first + n_cases <=
859                         psppire_data_store_get_case_count (ds), FALSE);
860
861
862   datasheet_delete_rows (ds->datasheet, first, n_cases);
863
864   g_signal_emit (ds, signals [CASES_DELETED], 0, first, n_cases);
865   g_sheet_model_rows_deleted (G_SHEET_MODEL (ds), first, n_cases);
866
867   return TRUE;
868 }
869
870
871
872 /* Insert case CC into the case file before POSN */
873 static gboolean
874 psppire_data_store_insert_case (PsppireDataStore *ds,
875                                 struct ccase *cc,
876                                 casenumber posn)
877 {
878   struct ccase tmp;
879   bool result ;
880
881   g_return_val_if_fail (ds, FALSE);
882   g_return_val_if_fail (ds->datasheet, FALSE);
883
884   case_clone (&tmp, cc);
885   result = datasheet_insert_rows (ds->datasheet, posn, &tmp, 1);
886
887   if ( result )
888     {
889       g_signal_emit (ds, signals [CASE_INSERTED], 0, posn);
890       g_sheet_model_rows_inserted (G_SHEET_MODEL (ds), posn, 1);
891     }
892   else
893     g_warning ("Cannot insert case at position %ld\n", posn);
894
895   return result;
896 }
897
898
899 /* Copies the IDXth value from case CASENUM into VALUE.
900    If VALUE is null, then memory is allocated is allocated with
901    malloc.  Returns the value if successful, NULL on failure. */
902 static union value *
903 psppire_data_store_get_value (const PsppireDataStore *ds,
904                               casenumber casenum, size_t idx,
905                               union value *value, int width)
906 {
907   bool allocated;
908
909   g_return_val_if_fail (ds, false);
910   g_return_val_if_fail (ds->datasheet, false);
911
912   g_return_val_if_fail (idx < datasheet_get_column_cnt (ds->datasheet), false);
913
914   if (value == NULL)
915     {
916       value = xnmalloc (value_cnt_from_width (width), sizeof *value);
917       allocated = true;
918     }
919   else
920     allocated = false;
921   if (!datasheet_get_value (ds->datasheet, casenum, idx, value, width))
922     {
923       if (allocated)
924         free (value);
925       value = NULL;
926     }
927   return value;
928 }
929
930
931
932 /* Set the IDXth value of case C to V.
933    Returns true if successful, false on I/O error. */
934 static gboolean
935 psppire_data_store_set_value (PsppireDataStore *ds, casenumber casenum,
936                               gint idx, union value *v, gint width)
937 {
938   bool ok;
939
940   g_return_val_if_fail (ds, FALSE);
941   g_return_val_if_fail (ds->datasheet, FALSE);
942
943   g_return_val_if_fail (idx < datasheet_get_column_cnt (ds->datasheet), FALSE);
944
945   ok = datasheet_put_value (ds->datasheet, casenum, idx, v, width);
946   if (ok)
947     g_signal_emit (ds, signals [CASE_CHANGED], 0, casenum);
948   return ok;
949 }
950
951
952
953
954 /* Set the IDXth value of case C using D_IN */
955 static gboolean
956 psppire_data_store_data_in (PsppireDataStore *ds, casenumber casenum, gint idx,
957                             struct substring input, const struct fmt_spec *fmt)
958 {
959   union value *value = NULL;
960   int width;
961   bool ok;
962
963   g_return_val_if_fail (ds, FALSE);
964   g_return_val_if_fail (ds->datasheet, FALSE);
965
966   g_return_val_if_fail (idx < datasheet_get_column_cnt (ds->datasheet), FALSE);
967
968   width = fmt_var_width (fmt);
969   value = xmalloca (value_cnt_from_width (width) * sizeof *value);
970   ok = (datasheet_get_value (ds->datasheet, casenum, idx, value, width)
971         && data_in (input, LEGACY_NATIVE, fmt->type, 0, 0, 0, value, width)
972         && datasheet_put_value (ds->datasheet, casenum, idx, value, width));
973
974   if (ok)
975     g_signal_emit (ds, signals [CASE_CHANGED], 0, casenum);
976
977   freea (value);
978
979   return TRUE;
980 }
981
982 /* Resize the cases in the casefile, by inserting N_VALUES into every
983    one of them at the position immediately preceeding WHERE.
984 */
985 static gboolean
986 psppire_data_store_insert_values (PsppireDataStore *ds,
987                                   gint n_values, gint where)
988 {
989   g_return_val_if_fail (ds, FALSE);
990
991   if ( n_values == 0 )
992     return FALSE;
993
994   g_assert (n_values > 0);
995
996   if ( ! ds->datasheet )
997     ds->datasheet = datasheet_create (NULL);
998
999   {
1000     union value *values = xcalloc (n_values, sizeof *values);
1001     datasheet_insert_columns (ds->datasheet, values, n_values, where);
1002     free (values);
1003   }
1004
1005   return TRUE;
1006 }