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