More runtime warnings fixed
[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_column_count = psppire_data_store_get_var_count;
279   iface->get_row_count = psppire_data_store_get_case_count_wrapper;
280
281   iface->get_column_subtitle = get_column_subtitle;
282   iface->get_column_title = get_column_button_label;
283   iface->get_column_sensitivity = get_column_sensitivity;
284   iface->get_column_justification = get_column_justification;
285
286   iface->get_row_title = get_row_button_label;
287   iface->get_row_sensitivity = get_row_sensitivity;
288 }
289
290
291 /*
292    A callback which occurs after a variable has been deleted.
293  */
294 static void
295 delete_variable_callback (GObject *obj, gint dict_index,
296                           gint case_index, gint val_cnt,
297                           gpointer data)
298 {
299   PsppireDataStore *store  = PSPPIRE_DATA_STORE (data);
300
301
302   g_sheet_model_columns_deleted (G_SHEET_MODEL (store), dict_index, 1);
303 #if AXIS_TRANSITION
304
305
306   g_sheet_column_columns_changed (G_SHEET_COLUMN (store),
307                                    dict_index, -1);
308 #endif
309 }
310
311
312
313 static void
314 variable_changed_callback (GObject *obj, gint var_num, gpointer data)
315 {
316   PsppireDataStore *store  = PSPPIRE_DATA_STORE (data);
317
318 #if AXIS_TRANSITION
319   g_sheet_column_columns_changed (G_SHEET_COLUMN (store),
320                                   var_num, 1);
321
322
323   g_sheet_model_range_changed (G_SHEET_MODEL (store),
324                                -1, var_num,
325                                -1, var_num);
326 #endif
327 }
328
329 static void
330 insert_variable_callback (GObject *obj, gint var_num, gpointer data)
331 {
332   PsppireDataStore *store;
333   gint posn;
334
335   g_return_if_fail (data);
336
337   store  = PSPPIRE_DATA_STORE (data);
338
339   if ( var_num > 0 )
340     {
341       struct variable *variable =
342         psppire_dict_get_variable (store->dict, var_num);
343
344       g_assert (variable != NULL);
345
346       posn = var_get_case_index (variable);
347     }
348   else
349     {
350       posn = 0;
351     }
352
353   psppire_data_store_insert_values (store, 1, posn);
354
355 #if AXIS_TRANSITION
356
357   g_sheet_column_columns_changed (G_SHEET_COLUMN (store),
358                                   var_num, 1);
359 #endif
360
361   g_sheet_model_columns_inserted (G_SHEET_MODEL (store), var_num, 1);
362 }
363
364
365 static void
366 dict_size_change_callback (GObject *obj,
367                           gint posn, gint adjustment, gpointer data)
368 {
369   PsppireDataStore *store  = PSPPIRE_DATA_STORE (data);
370
371   const struct variable *v = psppire_dict_get_variable (store->dict, posn);
372
373   const gint new_val_width = value_cnt_from_width (var_get_width (v));
374
375   if ( adjustment > 0 )
376     psppire_data_store_insert_values (store, adjustment,
377                                      new_val_width - adjustment +
378                                      var_get_case_index(v));
379 }
380
381
382
383 /**
384  * psppire_data_store_new:
385  * @dict: The dictionary for this data_store.
386  *
387  *
388  * Return value: a new #PsppireDataStore
389  **/
390 PsppireDataStore *
391 psppire_data_store_new (PsppireDict *dict)
392 {
393   PsppireDataStore *retval;
394
395   retval = g_object_new (GTK_TYPE_DATA_STORE, NULL);
396
397   psppire_data_store_set_dictionary (retval, dict);
398
399   return retval;
400 }
401
402 void
403 psppire_data_store_set_reader (PsppireDataStore *ds,
404                                struct casereader *reader)
405 {
406   gint i;
407
408   if ( ds->datasheet)
409     datasheet_destroy (ds->datasheet);
410
411   ds->datasheet = datasheet_create (reader);
412
413   g_sheet_model_range_changed (G_SHEET_MODEL (ds),
414                                -1, -1, -1, -1);
415
416   if ( ds->dict )
417     for (i = 0 ; i < n_dict_signals; ++i )
418       {
419         if ( ds->dict_handler_id [i] > 0)
420           {
421             g_signal_handler_unblock (ds->dict,
422                                       ds->dict_handler_id[i]);
423           }
424       }
425
426   g_signal_emit (ds, signals[BACKEND_CHANGED], 0);
427 }
428
429
430 /**
431  * psppire_data_store_replace_set_dictionary:
432  * @data_store: The variable store
433  * @dict: The dictionary to set
434  *
435  * If a dictionary is already associated with the data-store, then it will be
436  * destroyed.
437  **/
438 void
439 psppire_data_store_set_dictionary (PsppireDataStore *data_store, PsppireDict *dict)
440 {
441   int i;
442
443   /* Disconnect any existing handlers */
444   if ( data_store->dict )
445     for (i = 0 ; i < n_dict_signals; ++i )
446       {
447         g_signal_handler_disconnect (data_store->dict,
448                                      data_store->dict_handler_id[i]);
449       }
450
451   data_store->dict = dict;
452
453   if ( dict != NULL)
454     {
455
456       data_store->dict_handler_id [VARIABLE_INSERTED] =
457         g_signal_connect (dict, "variable-inserted",
458                           G_CALLBACK (insert_variable_callback),
459                           data_store);
460
461       data_store->dict_handler_id [VARIABLE_DELETED] =
462         g_signal_connect (dict, "variable-deleted",
463                           G_CALLBACK (delete_variable_callback),
464                           data_store);
465
466       data_store->dict_handler_id [VARIABLE_CHANGED] =
467         g_signal_connect (dict, "variable-changed",
468                           G_CALLBACK (variable_changed_callback),
469                           data_store);
470
471       data_store->dict_handler_id [SIZE_CHANGED] =
472         g_signal_connect (dict, "dict-size-changed",
473                           G_CALLBACK (dict_size_change_callback),
474                           data_store);
475     }
476
477
478
479   /* The entire model has changed */
480   g_sheet_model_range_changed (G_SHEET_MODEL (data_store), -1, -1, -1, -1);
481
482 #if AXIS_TRANSITION
483   g_sheet_column_columns_changed (G_SHEET_COLUMN (data_store), 0, -1);
484 #endif
485
486   if ( data_store->dict )
487     for (i = 0 ; i < n_dict_signals; ++i )
488       {
489         if ( data_store->dict_handler_id [i] > 0)
490           {
491             g_signal_handler_block (data_store->dict,
492                                     data_store->dict_handler_id[i]);
493           }
494       }
495 }
496
497 static void
498 psppire_data_store_finalize (GObject *object)
499 {
500
501   /* must chain up */
502   (* parent_class->finalize) (object);
503 }
504
505
506 static void
507 psppire_data_store_dispose (GObject *object)
508 {
509   PsppireDataStore *ds = PSPPIRE_DATA_STORE (object);
510
511   if (ds->dispose_has_run)
512     return;
513
514   if (ds->datasheet)
515     {
516       datasheet_destroy (ds->datasheet);
517       ds->datasheet = NULL;
518     }
519
520   /* must chain up */
521   (* parent_class->dispose) (object);
522
523   ds->dispose_has_run = TRUE;
524 }
525
526
527
528 /* Insert a blank case before POSN */
529 gboolean
530 psppire_data_store_insert_new_case (PsppireDataStore *ds, casenumber posn)
531 {
532   gboolean result;
533   gint val_cnt, v;
534   struct ccase cc;
535   g_return_val_if_fail (ds, FALSE);
536
537   val_cnt = datasheet_get_column_cnt (ds->datasheet) ;
538
539   g_return_val_if_fail (val_cnt > 0, FALSE);
540
541   g_return_val_if_fail (posn <= psppire_data_store_get_case_count (ds), FALSE);
542
543   case_create (&cc, val_cnt);
544
545   memset ( case_data_rw_idx (&cc, 0), 0, val_cnt * MAX_SHORT_STRING);
546
547   for (v = 0 ; v < psppire_dict_get_var_cnt (ds->dict) ; ++v)
548     {
549       const struct variable *pv = psppire_dict_get_variable (ds->dict, v);
550       if ( var_is_alpha (pv))
551         continue;
552
553       case_data_rw (&cc, pv)->f = SYSMIS;
554     }
555
556   result = psppire_data_store_insert_case (ds, &cc, posn);
557
558   case_destroy (&cc);
559
560   return result;
561 }
562
563
564 gchar *
565 psppire_data_store_get_string (PsppireDataStore *store, glong row, glong column)
566 {
567   gint idx;
568   char *text;
569   const struct fmt_spec *fp ;
570   const struct variable *pv ;
571   union value *v ;
572   GString *s;
573
574   g_return_val_if_fail (store->dict, NULL);
575   g_return_val_if_fail (store->datasheet, NULL);
576
577   if (column >= psppire_dict_get_var_cnt (store->dict))
578     return NULL;
579
580   if ( row >= psppire_data_store_get_case_count (store))
581     return NULL;
582
583   pv = psppire_dict_get_variable (store->dict, column);
584
585   g_assert (pv);
586
587   idx = var_get_case_index (pv);
588
589   g_assert (idx >= 0);
590
591   v = psppire_data_store_get_value (store, row, idx, NULL,
592                                    var_get_width (pv));
593
594   g_return_val_if_fail (v, NULL);
595
596   if ( store->show_labels)
597     {
598       const gchar *label = var_lookup_value_label (pv, v);
599       if (label)
600         {
601           free (v);
602           return pspp_locale_to_utf8 (label, -1, 0);
603         }
604     }
605
606   fp = var_get_write_format (pv);
607
608   s = g_string_sized_new (fp->w + 1);
609   g_string_set_size (s, fp->w);
610
611   memset (s->str, 0, fp->w);
612
613   g_assert (fp->w == s->len);
614
615   /* Converts binary value V into printable form in the exactly
616      FP->W character in buffer S according to format specification
617      FP.  No null terminator is appended to the buffer.  */
618   data_out (v, fp, s->str);
619
620   text = pspp_locale_to_utf8 (s->str, fp->w, 0);
621   g_string_free (s, TRUE);
622
623   g_strchomp (text);
624
625   free (v);
626   return text;
627 }
628
629
630 static gboolean
631 psppire_data_store_clear_datum (GSheetModel *model,
632                                           glong row, glong col)
633 {
634   PsppireDataStore *store = PSPPIRE_DATA_STORE (model);
635
636   union value v;
637   const struct variable *pv = psppire_dict_get_variable (store->dict, col);
638
639   const gint index = var_get_case_index (pv) ;
640
641   if ( var_is_numeric (pv))
642     v.f = SYSMIS;
643   else
644     memcpy (v.s, "", MAX_SHORT_STRING);
645
646   psppire_data_store_set_value (store, row, index, &v,
647                                 var_get_width (pv));
648
649   g_sheet_model_range_changed (model, row, col, row, col);
650
651   return TRUE;
652 }
653
654
655 /* Attempts to update that part of the variable store which corresponds
656    to ROW, COL with  the value TEXT.
657    Returns true if anything was updated, false otherwise.
658 */
659 gboolean
660 psppire_data_store_set_string (PsppireDataStore *store,
661                                const gchar *text, glong row, glong col)
662 {
663   glong n_cases;
664   const struct variable *pv = psppire_dict_get_variable (store->dict, col);
665   if ( NULL == pv)
666     return 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 }