Add range_changed callbacks as appropriate
[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   g_sheet_model_range_changed (model, row, col, row, col);
651
652   return TRUE;
653 }
654
655
656 /* Attempts to update that part of the variable store which corresponds
657    to ROW, COL with  the value TEXT.
658    Returns true if anything was updated, false otherwise.
659 */
660 gboolean
661 psppire_data_store_set_string (PsppireDataStore *store,
662                                const gchar *text, glong row, glong col)
663 {
664   glong n_cases;
665   const struct variable *pv = psppire_dict_get_variable (store->dict, col);
666   g_return_val_if_fail (pv, FALSE);
667
668   n_cases = psppire_data_store_get_case_count (store);
669
670   if ( row > n_cases)
671     return FALSE;
672
673   if (row == n_cases)
674     psppire_data_store_insert_new_case (store, row);
675
676   psppire_data_store_data_in (store, row,
677                               var_get_case_index (pv), ss_cstr (text),
678                               var_get_write_format (pv));
679
680   g_sheet_model_range_changed (G_SHEET_MODEL (store), row, col, row, col);
681
682   return TRUE;
683 }
684
685
686
687 void
688 psppire_data_store_show_labels (PsppireDataStore *store, gboolean show_labels)
689 {
690   g_return_if_fail (store);
691   g_return_if_fail (PSPPIRE_IS_DATA_STORE (store));
692
693   store->show_labels = show_labels;
694
695   g_sheet_model_range_changed (G_SHEET_MODEL (store),
696                                  -1, -1, -1, -1);
697 }
698
699
700 void
701 psppire_data_store_clear (PsppireDataStore *ds)
702 {
703   datasheet_destroy (ds->datasheet);
704   ds->datasheet = NULL;
705
706   psppire_dict_clear (ds->dict);
707
708   g_signal_emit (ds, signals [CASES_DELETED], 0, 0, -1);
709 }
710
711
712
713 /* Return a casereader made from this datastore */
714 struct casereader *
715 psppire_data_store_get_reader (PsppireDataStore *ds)
716 {
717   int i;
718   struct casereader *reader ;
719
720   if ( ds->dict )
721     for (i = 0 ; i < n_dict_signals; ++i )
722       {
723         g_signal_handler_block (ds->dict,
724                                 ds->dict_handler_id[i]);
725       }
726
727   reader = datasheet_make_reader (ds->datasheet);
728
729   /* We must not reference this again */
730   ds->datasheet = NULL;
731
732   return reader;
733 }
734
735
736
737 /* Column related funcs */
738
739
740 static const gchar null_var_name[]=N_("var");
741
742 \f
743
744 /* Row related funcs */
745
746 static gchar *
747 get_row_button_label (const GSheetModel *model, gint unit)
748 {
749   gchar *s = g_strdup_printf (_("%d"), unit + FIRST_CASE_NUMBER);
750
751   gchar *text =  pspp_locale_to_utf8 (s, -1, 0);
752
753   g_free (s);
754
755   return text;
756 }
757
758
759 static gboolean
760 get_row_sensitivity (const GSheetModel *model, gint unit)
761 {
762   PsppireDataStore *ds = PSPPIRE_DATA_STORE (model);
763
764   return (unit < psppire_data_store_get_case_count (ds));
765 }
766
767
768 \f
769
770 /* Column related stuff */
771
772 static gchar *
773 get_column_subtitle (const GSheetModel *model, gint col)
774 {
775   gchar *text;
776   const struct variable *v ;
777   PsppireDataStore *ds = PSPPIRE_DATA_STORE (model);
778
779   if ( col >= psppire_dict_get_var_cnt (ds->dict) )
780     return NULL;
781
782   v = psppire_dict_get_variable (ds->dict, col);
783
784   if ( ! var_has_label (v))
785     return NULL;
786
787   text =  pspp_locale_to_utf8 (var_get_label (v), -1, 0);
788
789   return text;
790 }
791
792 static gchar *
793 get_column_button_label (const GSheetModel *model, gint col)
794 {
795   gchar *text;
796   struct variable *pv ;
797   PsppireDataStore *ds = PSPPIRE_DATA_STORE (model);
798
799   if ( col >= psppire_dict_get_var_cnt (ds->dict) )
800     return g_locale_to_utf8 (null_var_name, -1, 0, 0, 0);
801
802   pv = psppire_dict_get_variable (ds->dict, col);
803
804   text =  pspp_locale_to_utf8 (var_get_name (pv), -1, 0);
805
806   return text;
807 }
808
809 static gboolean
810 get_column_sensitivity (const GSheetModel *model, gint col)
811 {
812   PsppireDataStore *ds = PSPPIRE_DATA_STORE (model);
813
814   return (col < psppire_dict_get_var_cnt (ds->dict));
815 }
816
817
818
819 static GtkJustification
820 get_column_justification (const GSheetModel *model, gint col)
821 {
822   PsppireDataStore *ds = PSPPIRE_DATA_STORE (model);
823   const struct variable *pv ;
824
825   if ( col >= psppire_dict_get_var_cnt (ds->dict) )
826     return GTK_JUSTIFY_LEFT;
827
828   pv = psppire_dict_get_variable (ds->dict, col);
829
830   return (var_get_alignment (pv) == ALIGN_LEFT ? GTK_JUSTIFY_LEFT
831           : var_get_alignment (pv) == ALIGN_RIGHT ? GTK_JUSTIFY_RIGHT
832           : GTK_JUSTIFY_CENTER);
833 }
834
835
836
837 \f
838
839
840 /* Fills C with the CASENUMth case.
841    Returns true on success, false otherwise.
842  */
843 gboolean
844 psppire_data_store_get_case (const PsppireDataStore *ds,
845                              casenumber casenum,
846                              struct ccase *c)
847 {
848   g_return_val_if_fail (ds, FALSE);
849   g_return_val_if_fail (ds->datasheet, FALSE);
850
851   return datasheet_get_row (ds->datasheet, casenum, c);
852 }
853
854
855 gboolean
856 psppire_data_store_delete_cases (PsppireDataStore *ds, casenumber first,
857                                  casenumber n_cases)
858 {
859   g_return_val_if_fail (ds, FALSE);
860   g_return_val_if_fail (ds->datasheet, FALSE);
861
862   g_return_val_if_fail (first + n_cases <=
863                         psppire_data_store_get_case_count (ds), FALSE);
864
865
866   datasheet_delete_rows (ds->datasheet, first, n_cases);
867
868   g_signal_emit (ds, signals [CASES_DELETED], 0, first, n_cases);
869   g_sheet_model_rows_deleted (G_SHEET_MODEL (ds), first, n_cases);
870
871   return TRUE;
872 }
873
874
875
876 /* Insert case CC into the case file before POSN */
877 static gboolean
878 psppire_data_store_insert_case (PsppireDataStore *ds,
879                                 struct ccase *cc,
880                                 casenumber posn)
881 {
882   struct ccase tmp;
883   bool result ;
884
885   g_return_val_if_fail (ds, FALSE);
886   g_return_val_if_fail (ds->datasheet, FALSE);
887
888   case_clone (&tmp, cc);
889   result = datasheet_insert_rows (ds->datasheet, posn, &tmp, 1);
890
891   if ( result )
892     {
893       g_signal_emit (ds, signals [CASE_INSERTED], 0, posn);
894       g_sheet_model_rows_inserted (G_SHEET_MODEL (ds), posn, 1);
895     }
896   else
897     g_warning ("Cannot insert case at position %ld\n", posn);
898
899   return result;
900 }
901
902
903 /* Copies the IDXth value from case CASENUM into VALUE.
904    If VALUE is null, then memory is allocated is allocated with
905    malloc.  Returns the value if successful, NULL on failure. */
906 static union value *
907 psppire_data_store_get_value (const PsppireDataStore *ds,
908                               casenumber casenum, size_t idx,
909                               union value *value, int width)
910 {
911   bool allocated;
912
913   g_return_val_if_fail (ds, false);
914   g_return_val_if_fail (ds->datasheet, false);
915
916   g_return_val_if_fail (idx < datasheet_get_column_cnt (ds->datasheet), false);
917
918   if (value == NULL)
919     {
920       value = xnmalloc (value_cnt_from_width (width), sizeof *value);
921       allocated = true;
922     }
923   else
924     allocated = false;
925   if (!datasheet_get_value (ds->datasheet, casenum, idx, value, width))
926     {
927       if (allocated)
928         free (value);
929       value = NULL;
930     }
931   return value;
932 }
933
934
935
936 /* Set the IDXth value of case C to V.
937    Returns true if successful, false on I/O error. */
938 static gboolean
939 psppire_data_store_set_value (PsppireDataStore *ds, casenumber casenum,
940                               gint idx, union value *v, gint width)
941 {
942   bool ok;
943
944   g_return_val_if_fail (ds, FALSE);
945   g_return_val_if_fail (ds->datasheet, FALSE);
946
947   g_return_val_if_fail (idx < datasheet_get_column_cnt (ds->datasheet), FALSE);
948
949   ok = datasheet_put_value (ds->datasheet, casenum, idx, v, width);
950   if (ok)
951     g_signal_emit (ds, signals [CASE_CHANGED], 0, casenum);
952
953   return ok;
954 }
955
956
957
958
959 /* Set the IDXth value of case C using D_IN */
960 static gboolean
961 psppire_data_store_data_in (PsppireDataStore *ds, casenumber casenum, gint idx,
962                             struct substring input, const struct fmt_spec *fmt)
963 {
964   union value *value = NULL;
965   int width;
966   bool ok;
967
968   g_return_val_if_fail (ds, FALSE);
969   g_return_val_if_fail (ds->datasheet, FALSE);
970
971   g_return_val_if_fail (idx < datasheet_get_column_cnt (ds->datasheet), FALSE);
972
973   width = fmt_var_width (fmt);
974   value = xmalloca (value_cnt_from_width (width) * sizeof *value);
975   ok = (datasheet_get_value (ds->datasheet, casenum, idx, value, width)
976         && data_in (input, LEGACY_NATIVE, fmt->type, 0, 0, 0, value, width)
977         && datasheet_put_value (ds->datasheet, casenum, idx, value, width));
978
979   freea (value);
980
981   if (ok)
982     g_signal_emit (ds, signals [CASE_CHANGED], 0, casenum);
983
984   return ok;
985 }
986
987 /* Resize the cases in the casefile, by inserting N_VALUES into every
988    one of them at the position immediately preceeding WHERE.
989 */
990 static gboolean
991 psppire_data_store_insert_values (PsppireDataStore *ds,
992                                   gint n_values, gint where)
993 {
994   g_return_val_if_fail (ds, FALSE);
995
996   if ( n_values == 0 )
997     return FALSE;
998
999   g_assert (n_values > 0);
1000
1001   if ( ! ds->datasheet )
1002     ds->datasheet = datasheet_create (NULL);
1003
1004   {
1005     union value *values = xcalloc (n_values, sizeof *values);
1006     datasheet_insert_columns (ds->datasheet, values, n_values, where);
1007     free (values);
1008   }
1009
1010   return TRUE;
1011 }