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