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