Merge commit 'origin/stable'
[pspp-builds.git] / src / ui / gui / psppire-data-store.c
1 /* PSPPIRE - a graphical user interface for PSPP.
2    Copyright (C) 2006, 2008, 2009  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 <ui/gui/sheet/psppire-sheetmodel.h>
29 #include <ui/gui/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 (PsppireSheetModelIface *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 (PsppireSheetModel *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                                    PSPPIRE_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 PsppireSheetModel *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 PsppireSheetModel *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 PsppireSheetModel *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 (PsppireSheetModel *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 PsppireSheetModel *model, gint col);
260 static gchar * get_column_button_label (const PsppireSheetModel *model, gint col);
261 static gboolean get_column_sensitivity (const PsppireSheetModel *model, gint col);
262 static GtkJustification get_column_justification (const PsppireSheetModel *model, gint col);
263
264 static gchar * get_row_button_label (const PsppireSheetModel *model, gint row);
265 static gboolean get_row_sensitivity (const PsppireSheetModel *model, gint row);
266
267
268 static void
269 psppire_data_store_sheet_model_init (PsppireSheetModelIface *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   psppire_sheet_model_columns_deleted (PSPPIRE_SHEET_MODEL (store), dict_index, 1);
303 #if AXIS_TRANSITION
304
305
306   psppire_sheet_column_columns_changed (PSPPIRE_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   psppire_sheet_column_columns_changed (PSPPIRE_SHEET_COLUMN (store),
320                                   var_num, 1);
321
322
323   psppire_sheet_model_range_changed (PSPPIRE_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   psppire_sheet_column_columns_changed (PSPPIRE_SHEET_COLUMN (store),
358                                   var_num, 1);
359 #endif
360
361   psppire_sheet_model_columns_inserted (PSPPIRE_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   psppire_sheet_model_range_changed (PSPPIRE_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   psppire_sheet_model_range_changed (PSPPIRE_SHEET_MODEL (data_store), -1, -1, -1, -1);
481
482 #if AXIS_TRANSITION
483   psppire_sheet_column_columns_changed (PSPPIRE_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   cc = case_create (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_unref (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 (PsppireSheetModel *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   psppire_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   psppire_sheet_model_range_changed (PSPPIRE_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   psppire_sheet_model_range_changed (PSPPIRE_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 PsppireSheetModel *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 PsppireSheetModel *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 PsppireSheetModel *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 PsppireSheetModel *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 PsppireSheetModel *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 PsppireSheetModel *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 /* Returns the CASENUMth case, or a null pointer on failure.
841  */
842 struct ccase *
843 psppire_data_store_get_case (const PsppireDataStore *ds,
844                              casenumber casenum)
845 {
846   g_return_val_if_fail (ds, FALSE);
847   g_return_val_if_fail (ds->datasheet, FALSE);
848
849   return datasheet_get_row (ds->datasheet, casenum);
850 }
851
852
853 gboolean
854 psppire_data_store_delete_cases (PsppireDataStore *ds, casenumber first,
855                                  casenumber n_cases)
856 {
857   g_return_val_if_fail (ds, FALSE);
858   g_return_val_if_fail (ds->datasheet, FALSE);
859
860   g_return_val_if_fail (first + n_cases <=
861                         psppire_data_store_get_case_count (ds), FALSE);
862
863
864   datasheet_delete_rows (ds->datasheet, first, n_cases);
865
866   g_signal_emit (ds, signals [CASES_DELETED], 0, first, n_cases);
867   psppire_sheet_model_rows_deleted (PSPPIRE_SHEET_MODEL (ds), first, n_cases);
868
869   return TRUE;
870 }
871
872
873
874 /* Insert case CC into the case file before POSN */
875 static gboolean
876 psppire_data_store_insert_case (PsppireDataStore *ds,
877                                 struct ccase *cc,
878                                 casenumber posn)
879 {
880   bool result ;
881
882   g_return_val_if_fail (ds, FALSE);
883   g_return_val_if_fail (ds->datasheet, FALSE);
884
885   case_ref (cc);
886   result = datasheet_insert_rows (ds->datasheet, posn, &cc, 1);
887
888   if ( result )
889     {
890       g_signal_emit (ds, signals [CASE_INSERTED], 0, posn);
891       psppire_sheet_model_rows_inserted (PSPPIRE_SHEET_MODEL (ds), posn, 1);
892     }
893   else
894     g_warning ("Cannot insert case at position %ld\n", posn);
895
896   return result;
897 }
898
899
900 /* Copies the IDXth value from case CASENUM into VALUE.
901    If VALUE is null, then memory is allocated is allocated with
902    malloc.  Returns the value if successful, NULL on failure. */
903 static union value *
904 psppire_data_store_get_value (const PsppireDataStore *ds,
905                               casenumber casenum, size_t idx,
906                               union value *value, int width)
907 {
908   bool allocated;
909
910   g_return_val_if_fail (ds, false);
911   g_return_val_if_fail (ds->datasheet, false);
912
913   g_return_val_if_fail (idx < datasheet_get_column_cnt (ds->datasheet), false);
914
915   if (value == NULL)
916     {
917       value = xnmalloc (value_cnt_from_width (width), sizeof *value);
918       allocated = true;
919     }
920   else
921     allocated = false;
922   if (!datasheet_get_value (ds->datasheet, casenum, idx, value, width))
923     {
924       if (allocated)
925         free (value);
926       value = NULL;
927     }
928   return value;
929 }
930
931
932
933 /* Set the IDXth value of case C to V.
934    Returns true if successful, false on I/O error. */
935 static gboolean
936 psppire_data_store_set_value (PsppireDataStore *ds, casenumber casenum,
937                               gint idx, union value *v, gint width)
938 {
939   bool ok;
940
941   g_return_val_if_fail (ds, FALSE);
942   g_return_val_if_fail (ds->datasheet, FALSE);
943
944   g_return_val_if_fail (idx < datasheet_get_column_cnt (ds->datasheet), FALSE);
945
946   ok = datasheet_put_value (ds->datasheet, casenum, idx, v, width);
947   if (ok)
948     g_signal_emit (ds, signals [CASE_CHANGED], 0, casenum);
949
950   return ok;
951 }
952
953
954
955
956 /* Set the IDXth value of case C using D_IN */
957 static gboolean
958 psppire_data_store_data_in (PsppireDataStore *ds, casenumber casenum, gint idx,
959                             struct substring input, const struct fmt_spec *fmt)
960 {
961   union value *value = NULL;
962   int width;
963   bool ok;
964
965   g_return_val_if_fail (ds, FALSE);
966   g_return_val_if_fail (ds->datasheet, FALSE);
967
968   g_return_val_if_fail (idx < datasheet_get_column_cnt (ds->datasheet), FALSE);
969
970   width = fmt_var_width (fmt);
971   value = xmalloca (value_cnt_from_width (width) * sizeof *value);
972   ok = (datasheet_get_value (ds->datasheet, casenum, idx, value, width)
973         && data_in (input, LEGACY_NATIVE, fmt->type, 0, 0, 0, value, width)
974         && datasheet_put_value (ds->datasheet, casenum, idx, value, width));
975
976   freea (value);
977
978   if (ok)
979     g_signal_emit (ds, signals [CASE_CHANGED], 0, casenum);
980
981   return ok;
982 }
983
984 /* Resize the cases in the casefile, by inserting N_VALUES into every
985    one of them at the position immediately preceeding WHERE.
986 */
987 static gboolean
988 psppire_data_store_insert_values (PsppireDataStore *ds,
989                                   gint n_values, gint where)
990 {
991   g_return_val_if_fail (ds, FALSE);
992
993   if ( n_values == 0 )
994     return FALSE;
995
996   g_assert (n_values > 0);
997
998   if ( ! ds->datasheet )
999     ds->datasheet = datasheet_create (NULL);
1000
1001   {
1002     union value *values = xcalloc (n_values, sizeof *values);
1003     datasheet_insert_columns (ds->datasheet, values, n_values, where);
1004     free (values);
1005   }
1006
1007   return TRUE;
1008 }