Added static qualifier
[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 #if AXIS_TRANSITION
303   g_sheet_model_columns_deleted (G_SHEET_MODEL (store), dict_index, 1);
304
305   g_sheet_column_columns_changed (G_SHEET_COLUMN (store),
306                                    dict_index, -1);
307 #endif
308 }
309
310
311
312 static void
313 variable_changed_callback (GObject *obj, gint var_num, gpointer data)
314 {
315   PsppireDataStore *store  = PSPPIRE_DATA_STORE (data);
316
317 #if AXIS_TRANSITION
318   g_sheet_column_columns_changed (G_SHEET_COLUMN (store),
319                                   var_num, 1);
320
321
322   g_sheet_model_range_changed (G_SHEET_MODEL (store),
323                                -1, var_num,
324                                -1, var_num);
325 #endif
326 }
327
328 static void
329 insert_variable_callback (GObject *obj, gint var_num, gpointer data)
330 {
331   PsppireDataStore *store;
332   gint posn;
333
334   g_return_if_fail (data);
335
336   store  = PSPPIRE_DATA_STORE (data);
337
338   if ( var_num > 0 )
339     {
340       struct variable *variable =
341         psppire_dict_get_variable (store->dict, var_num);
342
343       g_assert (variable != NULL);
344
345       posn = var_get_case_index (variable);
346     }
347   else
348     {
349       posn = 0;
350     }
351
352   psppire_data_store_insert_values (store, 1, posn);
353
354 #if AXIS_TRANSITION
355   g_sheet_column_columns_changed (G_SHEET_COLUMN (store),
356                                   var_num, 1);
357 #endif
358
359   g_sheet_model_columns_inserted (G_SHEET_MODEL (store), var_num, 1);
360 }
361
362
363 static void
364 dict_size_change_callback (GObject *obj,
365                           gint posn, gint adjustment, gpointer data)
366 {
367   PsppireDataStore *store  = PSPPIRE_DATA_STORE (data);
368
369   const struct variable *v = psppire_dict_get_variable (store->dict, posn);
370
371   const gint new_val_width = value_cnt_from_width (var_get_width (v));
372
373   if ( adjustment > 0 )
374     psppire_data_store_insert_values (store, adjustment,
375                                      new_val_width - adjustment +
376                                      var_get_case_index(v));
377 }
378
379
380
381 /**
382  * psppire_data_store_new:
383  * @dict: The dictionary for this data_store.
384  *
385  *
386  * Return value: a new #PsppireDataStore
387  **/
388 PsppireDataStore *
389 psppire_data_store_new (PsppireDict *dict)
390 {
391   PsppireDataStore *retval;
392
393   retval = g_object_new (GTK_TYPE_DATA_STORE, NULL);
394
395   psppire_data_store_set_dictionary (retval, dict);
396
397   return retval;
398 }
399
400 void
401 psppire_data_store_set_reader (PsppireDataStore *ds,
402                                struct casereader *reader)
403 {
404   gint i;
405
406   if ( ds->datasheet)
407     datasheet_destroy (ds->datasheet);
408
409   ds->datasheet = datasheet_create (reader);
410
411   g_sheet_model_range_changed (G_SHEET_MODEL (ds),
412                                -1, -1, -1, -1);
413
414   if ( ds->dict )
415     for (i = 0 ; i < n_dict_signals; ++i )
416       {
417         if ( ds->dict_handler_id [i] > 0)
418           {
419             g_signal_handler_unblock (ds->dict,
420                                       ds->dict_handler_id[i]);
421           }
422       }
423
424   g_signal_emit (ds, signals[BACKEND_CHANGED], 0);
425 }
426
427
428 /**
429  * psppire_data_store_replace_set_dictionary:
430  * @data_store: The variable store
431  * @dict: The dictionary to set
432  *
433  * If a dictionary is already associated with the data-store, then it will be
434  * destroyed.
435  **/
436 void
437 psppire_data_store_set_dictionary (PsppireDataStore *data_store, PsppireDict *dict)
438 {
439   int i;
440
441   /* Disconnect any existing handlers */
442   if ( data_store->dict )
443     for (i = 0 ; i < n_dict_signals; ++i )
444       {
445         g_signal_handler_disconnect (data_store->dict,
446                                      data_store->dict_handler_id[i]);
447       }
448
449   data_store->dict = dict;
450
451   if ( dict != NULL)
452     {
453
454       data_store->dict_handler_id [VARIABLE_INSERTED] =
455         g_signal_connect (dict, "variable-inserted",
456                           G_CALLBACK (insert_variable_callback),
457                           data_store);
458
459       data_store->dict_handler_id [VARIABLE_DELETED] =
460         g_signal_connect (dict, "variable-deleted",
461                           G_CALLBACK (delete_variable_callback),
462                           data_store);
463
464       data_store->dict_handler_id [VARIABLE_CHANGED] =
465         g_signal_connect (dict, "variable-changed",
466                           G_CALLBACK (variable_changed_callback),
467                           data_store);
468
469       data_store->dict_handler_id [SIZE_CHANGED] =
470         g_signal_connect (dict, "dict-size-changed",
471                           G_CALLBACK (dict_size_change_callback),
472                           data_store);
473     }
474
475
476
477   /* The entire model has changed */
478   g_sheet_model_range_changed (G_SHEET_MODEL (data_store), -1, -1, -1, -1);
479
480 #if AXIS_TRANSITION
481   g_sheet_column_columns_changed (G_SHEET_COLUMN (data_store), 0, -1);
482 #endif
483
484   if ( data_store->dict )
485     for (i = 0 ; i < n_dict_signals; ++i )
486       {
487         if ( data_store->dict_handler_id [i] > 0)
488           {
489             g_signal_handler_block (data_store->dict,
490                                     data_store->dict_handler_id[i]);
491           }
492       }
493 }
494
495 static void
496 psppire_data_store_finalize (GObject *object)
497 {
498
499   /* must chain up */
500   (* parent_class->finalize) (object);
501 }
502
503
504 static void
505 psppire_data_store_dispose (GObject *object)
506 {
507   PsppireDataStore *ds = PSPPIRE_DATA_STORE (object);
508
509   if (ds->dispose_has_run)
510     return;
511
512   if (ds->datasheet)
513     {
514       datasheet_destroy (ds->datasheet);
515       ds->datasheet = NULL;
516     }
517
518   /* must chain up */
519   (* parent_class->dispose) (object);
520
521   ds->dispose_has_run = TRUE;
522 }
523
524
525
526 /* Insert a blank case before POSN */
527 gboolean
528 psppire_data_store_insert_new_case (PsppireDataStore *ds, casenumber posn)
529 {
530   gboolean result;
531   gint val_cnt, v;
532   struct ccase cc;
533   g_return_val_if_fail (ds, FALSE);
534
535   val_cnt = datasheet_get_column_cnt (ds->datasheet) ;
536
537   g_return_val_if_fail (val_cnt > 0, FALSE);
538
539   g_return_val_if_fail (posn <= psppire_data_store_get_case_count (ds), FALSE);
540
541   case_create (&cc, val_cnt);
542
543   memset ( case_data_rw_idx (&cc, 0), 0, val_cnt * MAX_SHORT_STRING);
544
545   for (v = 0 ; v < psppire_dict_get_var_cnt (ds->dict) ; ++v)
546     {
547       const struct variable *pv = psppire_dict_get_variable (ds->dict, v);
548       if ( var_is_alpha (pv))
549         continue;
550
551       case_data_rw (&cc, pv)->f = SYSMIS;
552     }
553
554   result = psppire_data_store_insert_case (ds, &cc, posn);
555
556   case_destroy (&cc);
557
558   return result;
559 }
560
561
562 gchar *
563 psppire_data_store_get_string (PsppireDataStore *store, glong row, glong column)
564 {
565   gint idx;
566   char *text;
567   const struct fmt_spec *fp ;
568   const struct variable *pv ;
569   union value *v ;
570   GString *s;
571
572   g_return_val_if_fail (store->dict, NULL);
573   g_return_val_if_fail (store->datasheet, NULL);
574
575   if (column >= psppire_dict_get_var_cnt (store->dict))
576     return NULL;
577
578   if ( row >= psppire_data_store_get_case_count (store))
579     return NULL;
580
581   pv = psppire_dict_get_variable (store->dict, column);
582
583   g_assert (pv);
584
585   idx = var_get_case_index (pv);
586
587   g_assert (idx >= 0);
588
589   v = psppire_data_store_get_value (store, row, idx, NULL,
590                                    var_get_width (pv));
591
592   g_return_val_if_fail (v, NULL);
593
594   if ( store->show_labels)
595     {
596       const gchar *label = var_lookup_value_label (pv, v);
597       if (label)
598         {
599           free (v);
600           return pspp_locale_to_utf8 (label, -1, 0);
601         }
602     }
603
604   fp = var_get_write_format (pv);
605
606   s = g_string_sized_new (fp->w + 1);
607   g_string_set_size (s, fp->w);
608
609   memset (s->str, 0, fp->w);
610
611   g_assert (fp->w == s->len);
612
613   /* Converts binary value V into printable form in the exactly
614      FP->W character in buffer S according to format specification
615      FP.  No null terminator is appended to the buffer.  */
616   data_out (v, fp, s->str);
617
618   text = pspp_locale_to_utf8 (s->str, fp->w, 0);
619   g_string_free (s, TRUE);
620
621   g_strchomp (text);
622
623   free (v);
624   return text;
625 }
626
627
628 static gboolean
629 psppire_data_store_clear_datum (GSheetModel *model,
630                                           glong row, glong col)
631 {
632   PsppireDataStore *store = PSPPIRE_DATA_STORE (model);
633
634   union value v;
635   const struct variable *pv = psppire_dict_get_variable (store->dict, col);
636
637   const gint index = var_get_case_index (pv) ;
638
639   if ( var_is_numeric (pv))
640     v.f = SYSMIS;
641   else
642     memcpy (v.s, "", MAX_SHORT_STRING);
643
644   psppire_data_store_set_value (store, row, index, &v,
645                                 var_get_width (pv));
646
647   return TRUE;
648 }
649
650
651 /* Attempts to update that part of the variable store which corresponds
652    to ROW, COL with  the value TEXT.
653    Returns true if anything was updated, false otherwise.
654 */
655 gboolean
656 psppire_data_store_set_string (PsppireDataStore *store,
657                                const gchar *text, glong row, glong col)
658 {
659   glong n_cases;
660   const struct variable *pv = psppire_dict_get_variable (store->dict, col);
661   g_return_val_if_fail (pv, FALSE);
662
663   n_cases = psppire_data_store_get_case_count (store);
664
665   if ( row > n_cases)
666     return FALSE;
667
668   if (row == n_cases)
669     psppire_data_store_insert_new_case (store, row);
670
671   psppire_data_store_data_in (store, row,
672                               var_get_case_index (pv), ss_cstr (text),
673                               var_get_write_format (pv));
674
675   return TRUE;
676 }
677
678
679
680 void
681 psppire_data_store_show_labels (PsppireDataStore *store, gboolean show_labels)
682 {
683   g_return_if_fail (store);
684   g_return_if_fail (PSPPIRE_IS_DATA_STORE (store));
685
686   store->show_labels = show_labels;
687
688   g_sheet_model_range_changed (G_SHEET_MODEL (store),
689                                  -1, -1, -1, -1);
690 }
691
692
693 void
694 psppire_data_store_clear (PsppireDataStore *ds)
695 {
696   datasheet_destroy (ds->datasheet);
697   ds->datasheet = NULL;
698
699   psppire_dict_clear (ds->dict);
700
701   g_signal_emit (ds, signals [CASES_DELETED], 0, 0, -1);
702 }
703
704
705
706 /* Return a casereader made from this datastore */
707 struct casereader *
708 psppire_data_store_get_reader (PsppireDataStore *ds)
709 {
710   int i;
711   struct casereader *reader ;
712
713   if ( ds->dict )
714     for (i = 0 ; i < n_dict_signals; ++i )
715       {
716         g_signal_handler_block (ds->dict,
717                                 ds->dict_handler_id[i]);
718       }
719
720   reader = datasheet_make_reader (ds->datasheet);
721
722   /* We must not reference this again */
723   ds->datasheet = NULL;
724
725   return reader;
726 }
727
728
729
730 /* Column related funcs */
731
732
733 static const gchar null_var_name[]=N_("var");
734
735 \f
736
737 /* Row related funcs */
738
739 static gchar *
740 get_row_button_label (const GSheetModel *model, gint unit)
741 {
742   gchar *s = g_strdup_printf (_("%d"), unit + FIRST_CASE_NUMBER);
743
744   gchar *text =  pspp_locale_to_utf8 (s, -1, 0);
745
746   g_free (s);
747
748   return text;
749 }
750
751
752 static gboolean
753 get_row_sensitivity (const GSheetModel *model, gint unit)
754 {
755   PsppireDataStore *ds = PSPPIRE_DATA_STORE (model);
756
757   return (unit < psppire_data_store_get_case_count (ds));
758 }
759
760
761 \f
762
763 /* Column related stuff */
764
765 static gchar *
766 get_column_subtitle (const GSheetModel *model, gint col)
767 {
768   gchar *text;
769   const struct variable *v ;
770   PsppireDataStore *ds = PSPPIRE_DATA_STORE (model);
771
772   if ( col >= psppire_dict_get_var_cnt (ds->dict) )
773     return NULL;
774
775   v = psppire_dict_get_variable (ds->dict, col);
776
777   if ( ! var_has_label (v))
778     return NULL;
779
780   text =  pspp_locale_to_utf8 (var_get_label (v), -1, 0);
781
782   return text;
783 }
784
785 static gchar *
786 get_column_button_label (const GSheetModel *model, gint col)
787 {
788   gchar *text;
789   struct variable *pv ;
790   PsppireDataStore *ds = PSPPIRE_DATA_STORE (model);
791
792   if ( col >= psppire_dict_get_var_cnt (ds->dict) )
793     return g_locale_to_utf8 (null_var_name, -1, 0, 0, 0);
794
795   pv = psppire_dict_get_variable (ds->dict, col);
796
797   text =  pspp_locale_to_utf8 (var_get_name (pv), -1, 0);
798
799   return text;
800 }
801
802 static gboolean
803 get_column_sensitivity (const GSheetModel *model, gint col)
804 {
805   PsppireDataStore *ds = PSPPIRE_DATA_STORE (model);
806
807   return (col < psppire_dict_get_var_cnt (ds->dict));
808 }
809
810
811
812 static GtkJustification
813 get_column_justification (const GSheetModel *model, gint col)
814 {
815   PsppireDataStore *ds = PSPPIRE_DATA_STORE (model);
816   const struct variable *pv ;
817
818   if ( col >= psppire_dict_get_var_cnt (ds->dict) )
819     return GTK_JUSTIFY_LEFT;
820
821   pv = psppire_dict_get_variable (ds->dict, col);
822
823   return (var_get_alignment (pv) == ALIGN_LEFT ? GTK_JUSTIFY_LEFT
824           : var_get_alignment (pv) == ALIGN_RIGHT ? GTK_JUSTIFY_RIGHT
825           : GTK_JUSTIFY_CENTER);
826 }
827
828
829
830 \f
831
832
833 /* Fills C with the CASENUMth case.
834    Returns true on success, false otherwise.
835  */
836 gboolean
837 psppire_data_store_get_case (const PsppireDataStore *ds,
838                              casenumber casenum,
839                              struct ccase *c)
840 {
841   g_return_val_if_fail (ds, FALSE);
842   g_return_val_if_fail (ds->datasheet, FALSE);
843
844   return datasheet_get_row (ds->datasheet, casenum, c);
845 }
846
847
848 gboolean
849 psppire_data_store_delete_cases (PsppireDataStore *ds, casenumber first,
850                                  casenumber n_cases)
851 {
852   g_return_val_if_fail (ds, FALSE);
853   g_return_val_if_fail (ds->datasheet, FALSE);
854
855   g_return_val_if_fail (first + n_cases <=
856                         psppire_data_store_get_case_count (ds), FALSE);
857
858
859   datasheet_delete_rows (ds->datasheet, first, n_cases);
860
861   g_signal_emit (ds, signals [CASES_DELETED], 0, first, n_cases);
862
863   return TRUE;
864 }
865
866
867
868 /* Insert case CC into the case file before POSN */
869 static gboolean
870 psppire_data_store_insert_case (PsppireDataStore *ds,
871                                 struct ccase *cc,
872                                 casenumber posn)
873 {
874   struct ccase tmp;
875   bool result ;
876
877   g_return_val_if_fail (ds, FALSE);
878   g_return_val_if_fail (ds->datasheet, FALSE);
879
880   case_clone (&tmp, cc);
881   result = datasheet_insert_rows (ds->datasheet, posn, &tmp, 1);
882
883   if ( result )
884     g_signal_emit (ds, signals [CASE_INSERTED], 0, posn);
885   else
886     g_warning ("Cannot insert case at position %ld\n", posn);
887
888   return result;
889 }
890
891
892 /* Copies the IDXth value from case CASENUM into VALUE.
893    If VALUE is null, then memory is allocated is allocated with
894    malloc.  Returns the value if successful, NULL on failure. */
895 static union value *
896 psppire_data_store_get_value (const PsppireDataStore *ds,
897                               casenumber casenum, size_t idx,
898                               union value *value, int width)
899 {
900   bool allocated;
901
902   g_return_val_if_fail (ds, false);
903   g_return_val_if_fail (ds->datasheet, false);
904
905   g_return_val_if_fail (idx < datasheet_get_column_cnt (ds->datasheet), false);
906
907   if (value == NULL)
908     {
909       value = xnmalloc (value_cnt_from_width (width), sizeof *value);
910       allocated = true;
911     }
912   else
913     allocated = false;
914   if (!datasheet_get_value (ds->datasheet, casenum, idx, value, width))
915     {
916       if (allocated)
917         free (value);
918       value = NULL;
919     }
920   return value;
921 }
922
923
924
925 /* Set the IDXth value of case C to V.
926    Returns true if successful, false on I/O error. */
927 static gboolean
928 psppire_data_store_set_value (PsppireDataStore *ds, casenumber casenum,
929                               gint idx, union value *v, gint width)
930 {
931   bool ok;
932
933   g_return_val_if_fail (ds, FALSE);
934   g_return_val_if_fail (ds->datasheet, FALSE);
935
936   g_return_val_if_fail (idx < datasheet_get_column_cnt (ds->datasheet), FALSE);
937
938   ok = datasheet_put_value (ds->datasheet, casenum, idx, v, width);
939   if (ok)
940     g_signal_emit (ds, signals [CASE_CHANGED], 0, casenum);
941   return ok;
942 }
943
944
945
946
947 /* Set the IDXth value of case C using D_IN */
948 static gboolean
949 psppire_data_store_data_in (PsppireDataStore *ds, casenumber casenum, gint idx,
950                             struct substring input, const struct fmt_spec *fmt)
951 {
952   union value *value = NULL;
953   int width;
954   bool ok;
955
956   g_return_val_if_fail (ds, FALSE);
957   g_return_val_if_fail (ds->datasheet, FALSE);
958
959   g_return_val_if_fail (idx < datasheet_get_column_cnt (ds->datasheet), FALSE);
960
961   width = fmt_var_width (fmt);
962   value = xmalloca (value_cnt_from_width (width) * sizeof *value);
963   ok = (datasheet_get_value (ds->datasheet, casenum, idx, value, width)
964         && data_in (input, LEGACY_NATIVE, fmt->type, 0, 0, 0, value, width)
965         && datasheet_put_value (ds->datasheet, casenum, idx, value, width));
966
967   if (ok)
968     g_signal_emit (ds, signals [CASE_CHANGED], 0, casenum);
969
970   freea (value);
971
972   return TRUE;
973 }
974
975 /* Resize the cases in the casefile, by inserting N_VALUES into every
976    one of them at the position immediately preceeding WHERE.
977 */
978 static gboolean
979 psppire_data_store_insert_values (PsppireDataStore *ds,
980                                   gint n_values, gint where)
981 {
982   g_return_val_if_fail (ds, FALSE);
983
984   if ( n_values == 0 )
985     return FALSE;
986
987   g_assert (n_values > 0);
988
989   if ( ! ds->datasheet )
990     ds->datasheet = datasheet_create (NULL);
991
992   {
993     union value *values = xcalloc (n_values, sizeof *values);
994     datasheet_insert_columns (ds->datasheet, values, n_values, where);
995     free (values);
996   }
997
998   return TRUE;
999 }