45fa82488b4e19dabbdf991bae83681fe2e93075
[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 <libpspp/i18n.h>
35 #include "helper.h"
36
37 #include <data/dictionary.h>
38 #include <data/missing-values.h>
39 #include <data/value-labels.h>
40 #include <data/data-in.h>
41 #include <data/format.h>
42
43 #include <math/sort.h>
44
45 #include "xalloc.h"
46 #include "xmalloca.h"
47
48
49
50 static void psppire_data_store_init            (PsppireDataStore      *data_store);
51 static void psppire_data_store_class_init      (PsppireDataStoreClass *class);
52 static void psppire_data_store_sheet_model_init (PsppireSheetModelIface *iface);
53
54 static void psppire_data_store_finalize        (GObject           *object);
55 static void psppire_data_store_dispose        (GObject           *object);
56
57 static gboolean psppire_data_store_clear_datum (PsppireSheetModel *model,
58                                           glong row, glong column);
59
60
61 static gboolean psppire_data_store_insert_case (PsppireDataStore *ds,
62                                                 struct ccase *cc,
63                                                 casenumber posn);
64
65
66 static gboolean psppire_data_store_data_in (PsppireDataStore *ds,
67                                             casenumber casenum, gint idx,
68                                             struct substring input,
69                                             const struct fmt_spec *fmt);
70
71
72
73 static GObjectClass *parent_class = NULL;
74
75
76 enum
77   {
78     BACKEND_CHANGED,
79     CASES_DELETED,
80     CASE_INSERTED,
81     CASE_CHANGED,
82     n_SIGNALS
83   };
84
85 static guint signals [n_SIGNALS];
86
87
88 GType
89 psppire_data_store_get_type (void)
90 {
91   static GType data_store_type = 0;
92
93   if (!data_store_type)
94     {
95       static const GTypeInfo data_store_info =
96       {
97         sizeof (PsppireDataStoreClass),
98         NULL,           /* base_init */
99         NULL,           /* base_finalize */
100         (GClassInitFunc) psppire_data_store_class_init,
101         NULL,           /* class_finalize */
102         NULL,           /* class_data */
103         sizeof (PsppireDataStore),
104         0,
105         (GInstanceInitFunc) psppire_data_store_init,
106       };
107
108       static const GInterfaceInfo sheet_model_info =
109       {
110         (GInterfaceInitFunc) psppire_data_store_sheet_model_init,
111         NULL,
112         NULL
113       };
114
115
116       data_store_type = g_type_register_static (G_TYPE_OBJECT,
117                                                 "PsppireDataStore",
118                                                 &data_store_info, 0);
119
120       g_type_add_interface_static (data_store_type,
121                                    PSPPIRE_TYPE_SHEET_MODEL,
122                                    &sheet_model_info);
123
124     }
125
126   return data_store_type;
127 }
128
129
130 static void
131 psppire_data_store_class_init (PsppireDataStoreClass *class)
132 {
133   GObjectClass *object_class;
134
135   parent_class = g_type_class_peek_parent (class);
136   object_class = (GObjectClass*) class;
137
138   object_class->finalize = psppire_data_store_finalize;
139   object_class->dispose = psppire_data_store_dispose;
140
141   signals [BACKEND_CHANGED] =
142     g_signal_new ("backend-changed",
143                   G_TYPE_FROM_CLASS (class),
144                   G_SIGNAL_RUN_FIRST,
145                   0,
146                   NULL, NULL,
147                   g_cclosure_marshal_VOID__VOID,
148                   G_TYPE_NONE,
149                   0);
150
151   signals [CASE_INSERTED] =
152     g_signal_new ("case-inserted",
153                   G_TYPE_FROM_CLASS (class),
154                   G_SIGNAL_RUN_FIRST,
155                   0,
156                   NULL, NULL,
157                   g_cclosure_marshal_VOID__INT,
158                   G_TYPE_NONE,
159                   1,
160                   G_TYPE_INT);
161
162
163   signals [CASE_CHANGED] =
164     g_signal_new ("case-changed",
165                   G_TYPE_FROM_CLASS (class),
166                   G_SIGNAL_RUN_FIRST,
167                   0,
168                   NULL, NULL,
169                   g_cclosure_marshal_VOID__INT,
170                   G_TYPE_NONE,
171                   1,
172                   G_TYPE_INT);
173
174   signals [CASES_DELETED] =
175     g_signal_new ("cases-deleted",
176                   G_TYPE_FROM_CLASS (class),
177                   G_SIGNAL_RUN_FIRST,
178                   0,
179                   NULL, NULL,
180                   psppire_marshal_VOID__INT_INT,
181                   G_TYPE_NONE,
182                   2,
183                   G_TYPE_INT,
184                   G_TYPE_INT);
185 }
186
187
188
189 static gboolean
190 psppire_data_store_insert_values (PsppireDataStore *ds,
191                                   gint n_values, gint where);
192
193 static union value *
194 psppire_data_store_get_value (const PsppireDataStore *ds,
195                               casenumber casenum, size_t idx,
196                               union value *value, int width);
197
198
199 static gboolean
200 psppire_data_store_set_value (PsppireDataStore *ds, casenumber casenum,
201                               gint idx, union value *v, gint width);
202
203
204
205
206 static glong
207 psppire_data_store_get_var_count (const PsppireSheetModel *model)
208 {
209   const PsppireDataStore *store = PSPPIRE_DATA_STORE (model);
210
211   return psppire_dict_get_var_cnt (store->dict);
212 }
213
214 casenumber
215 psppire_data_store_get_case_count (const PsppireDataStore *store)
216 {
217   return datasheet_get_row_cnt (store->datasheet);
218 }
219
220 size_t
221 psppire_data_store_get_value_count (const PsppireDataStore *store)
222 {
223   return psppire_dict_get_value_cnt (store->dict);
224 }
225
226 static casenumber
227 psppire_data_store_get_case_count_wrapper (const PsppireSheetModel *model)
228 {
229   const PsppireDataStore *store = PSPPIRE_DATA_STORE (model);
230   return psppire_data_store_get_case_count (store);
231 }
232
233 static void
234 psppire_data_store_init (PsppireDataStore *data_store)
235 {
236   data_store->dict = 0;
237   data_store->datasheet = NULL;
238   data_store->dispose_has_run = FALSE;
239 }
240
241 static inline gchar *
242 psppire_data_store_get_string_wrapper (const PsppireSheetModel *model, glong row,
243                                        glong column)
244 {
245   return psppire_data_store_get_string (PSPPIRE_DATA_STORE (model), row, column);
246 }
247
248
249 static inline gboolean
250 psppire_data_store_set_string_wrapper (PsppireSheetModel *model,
251                                        const gchar *text,
252                                        glong row, glong column)
253 {
254   return psppire_data_store_set_string (PSPPIRE_DATA_STORE (model), text,
255                                         row, column);
256 }
257
258
259
260 static gchar * get_column_subtitle (const PsppireSheetModel *model, gint col);
261 static gchar * get_column_button_label (const PsppireSheetModel *model, gint col);
262 static gboolean get_column_sensitivity (const PsppireSheetModel *model, gint col);
263 static GtkJustification get_column_justification (const PsppireSheetModel *model, gint col);
264
265 static gchar * get_row_button_label (const PsppireSheetModel *model, gint row);
266 static gboolean get_row_sensitivity (const PsppireSheetModel *model, gint row);
267 static gboolean get_row_overstrike (const PsppireSheetModel *model, gint row);
268
269
270 static void
271 psppire_data_store_sheet_model_init (PsppireSheetModelIface *iface)
272 {
273   iface->free_strings = TRUE;
274   iface->get_string = psppire_data_store_get_string_wrapper;
275   iface->set_string = psppire_data_store_set_string_wrapper;
276   iface->clear_datum = psppire_data_store_clear_datum;
277   iface->is_editable = NULL;
278   iface->get_foreground = NULL;
279   iface->get_background = NULL;
280   iface->get_column_count = psppire_data_store_get_var_count;
281   iface->get_row_count = psppire_data_store_get_case_count_wrapper;
282
283   iface->get_column_subtitle = get_column_subtitle;
284   iface->get_column_title = get_column_button_label;
285   iface->get_column_sensitivity = get_column_sensitivity;
286   iface->get_column_justification = get_column_justification;
287
288   iface->get_row_title = get_row_button_label;
289   iface->get_row_sensitivity = get_row_sensitivity;
290   iface->get_row_overstrike = get_row_overstrike;
291 }
292
293
294 /*
295    A callback which occurs after a variable has been deleted.
296  */
297 static void
298 delete_variable_callback (GObject *obj, gint dict_index,
299                           gint case_index, gint val_cnt,
300                           gpointer data)
301 {
302   PsppireDataStore *store  = PSPPIRE_DATA_STORE (data);
303
304
305   psppire_sheet_model_columns_deleted (PSPPIRE_SHEET_MODEL (store), dict_index, 1);
306 #if AXIS_TRANSITION
307
308
309   psppire_sheet_column_columns_changed (PSPPIRE_SHEET_COLUMN (store),
310                                    dict_index, -1);
311 #endif
312 }
313
314 static void
315 variable_changed_callback (GObject *obj, gint var_num, gpointer data)
316 {
317 #if AXIS_TRANSITION
318   PsppireDataStore *store  = PSPPIRE_DATA_STORE (data);
319
320   psppire_sheet_column_columns_changed (PSPPIRE_SHEET_COLUMN (store),
321                                   var_num, 1);
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 recode_string (UTF8, psppire_dict_encoding (store->dict),
603                                 label, -1);
604         }
605     }
606
607   fp = var_get_write_format (pv);
608
609   s = g_string_sized_new (fp->w + 1);
610   g_string_set_size (s, fp->w);
611
612   memset (s->str, 0, fp->w);
613
614   g_assert (fp->w == s->len);
615
616   /* Converts binary value V into printable form in the exactly
617      FP->W character in buffer S according to format specification
618      FP.  No null terminator is appended to the buffer.  */
619   data_out (v, fp, s->str);
620
621   text = recode_string (UTF8, psppire_dict_encoding (store->dict),
622                         s->str, fp->w);
623   g_string_free (s, TRUE);
624
625   g_strchomp (text);
626
627   free (v);
628   return text;
629 }
630
631
632 static gboolean
633 psppire_data_store_clear_datum (PsppireSheetModel *model,
634                                           glong row, glong col)
635 {
636   PsppireDataStore *store = PSPPIRE_DATA_STORE (model);
637
638   union value v;
639   const struct variable *pv = psppire_dict_get_variable (store->dict, col);
640
641   const gint index = var_get_case_index (pv) ;
642
643   if ( var_is_numeric (pv))
644     v.f = SYSMIS;
645   else
646     memcpy (v.s, "", MAX_SHORT_STRING);
647
648   psppire_data_store_set_value (store, row, index, &v,
649                                 var_get_width (pv));
650
651   psppire_sheet_model_range_changed (model, row, col, row, col);
652
653   return TRUE;
654 }
655
656
657 /* Attempts to update that part of the variable store which corresponds
658    to ROW, COL with  the value TEXT.
659    Returns true if anything was updated, false otherwise.
660 */
661 gboolean
662 psppire_data_store_set_string (PsppireDataStore *store,
663                                const gchar *text, glong row, glong col)
664 {
665   gchar *s;
666   glong n_cases;
667   const struct variable *pv = psppire_dict_get_variable (store->dict, col);
668   if ( NULL == pv)
669     return FALSE;
670
671   n_cases = psppire_data_store_get_case_count (store);
672
673   if ( row > n_cases)
674     return FALSE;
675
676   if (row == n_cases)
677     psppire_data_store_insert_new_case (store, row);
678
679   s = recode_string (psppire_dict_encoding (store->dict), UTF8, text, -1);
680
681   psppire_data_store_data_in (store, row,
682                               var_get_case_index (pv), ss_cstr (s),
683                               var_get_write_format (pv));
684   free (s);
685
686   psppire_sheet_model_range_changed (PSPPIRE_SHEET_MODEL (store), row, col, row, col);
687
688   return TRUE;
689 }
690
691
692
693 void
694 psppire_data_store_show_labels (PsppireDataStore *store, gboolean show_labels)
695 {
696   g_return_if_fail (store);
697   g_return_if_fail (PSPPIRE_IS_DATA_STORE (store));
698
699   store->show_labels = show_labels;
700
701   psppire_sheet_model_range_changed (PSPPIRE_SHEET_MODEL (store),
702                                  -1, -1, -1, -1);
703 }
704
705
706 void
707 psppire_data_store_clear (PsppireDataStore *ds)
708 {
709   datasheet_destroy (ds->datasheet);
710   ds->datasheet = NULL;
711
712   psppire_dict_clear (ds->dict);
713
714   g_signal_emit (ds, signals [CASES_DELETED], 0, 0, -1);
715 }
716
717
718
719 /* Return a casereader made from this datastore */
720 struct casereader *
721 psppire_data_store_get_reader (PsppireDataStore *ds)
722 {
723   int i;
724   struct casereader *reader ;
725
726   if ( ds->dict )
727     for (i = 0 ; i < n_dict_signals; ++i )
728       {
729         g_signal_handler_block (ds->dict,
730                                 ds->dict_handler_id[i]);
731       }
732
733   reader = datasheet_make_reader (ds->datasheet);
734
735   /* We must not reference this again */
736   ds->datasheet = NULL;
737
738   return reader;
739 }
740
741
742
743 /* Column related funcs */
744
745
746 static const gchar null_var_name[]=N_("var");
747
748 \f
749
750 /* Row related funcs */
751
752 static gchar *
753 get_row_button_label (const PsppireSheetModel *model, gint unit)
754 {
755   PsppireDataStore *ds = PSPPIRE_DATA_STORE (model);
756   gchar *s = g_strdup_printf (_("%d"), unit + FIRST_CASE_NUMBER);
757
758   gchar *text =  recode_string (UTF8, psppire_dict_encoding (ds->dict),
759                                 s, -1);
760
761   g_free (s);
762
763   return text;
764 }
765
766
767 static gboolean
768 get_row_sensitivity (const PsppireSheetModel *model, gint unit)
769 {
770   PsppireDataStore *ds = PSPPIRE_DATA_STORE (model);
771
772   return (unit < psppire_data_store_get_case_count (ds));
773 }
774
775
776 \f
777
778 /* Column related stuff */
779
780 static gchar *
781 get_column_subtitle (const PsppireSheetModel *model, gint col)
782 {
783   gchar *text;
784   const struct variable *v ;
785   PsppireDataStore *ds = PSPPIRE_DATA_STORE (model);
786
787   if ( col >= psppire_dict_get_var_cnt (ds->dict) )
788     return NULL;
789
790   v = psppire_dict_get_variable (ds->dict, col);
791
792   if ( ! var_has_label (v))
793     return NULL;
794
795   text =  recode_string (UTF8, psppire_dict_encoding (ds->dict),
796                          var_get_label (v), -1);
797
798   return text;
799 }
800
801 static gchar *
802 get_column_button_label (const PsppireSheetModel *model, gint col)
803 {
804   gchar *text;
805   struct variable *pv ;
806   PsppireDataStore *ds = PSPPIRE_DATA_STORE (model);
807
808   if ( col >= psppire_dict_get_var_cnt (ds->dict) )
809     return g_locale_to_utf8 (null_var_name, -1, 0, 0, 0);
810
811   pv = psppire_dict_get_variable (ds->dict, col);
812
813   text = recode_string (UTF8, psppire_dict_encoding (ds->dict),
814                         var_get_name (pv), -1);
815
816   return text;
817 }
818
819 static gboolean
820 get_column_sensitivity (const PsppireSheetModel *model, gint col)
821 {
822   PsppireDataStore *ds = PSPPIRE_DATA_STORE (model);
823
824   return (col < psppire_dict_get_var_cnt (ds->dict));
825 }
826
827
828
829 static GtkJustification
830 get_column_justification (const PsppireSheetModel *model, gint col)
831 {
832   PsppireDataStore *ds = PSPPIRE_DATA_STORE (model);
833   const struct variable *pv ;
834
835   if ( col >= psppire_dict_get_var_cnt (ds->dict) )
836     return GTK_JUSTIFY_LEFT;
837
838   pv = psppire_dict_get_variable (ds->dict, col);
839
840   return (var_get_alignment (pv) == ALIGN_LEFT ? GTK_JUSTIFY_LEFT
841           : var_get_alignment (pv) == ALIGN_RIGHT ? GTK_JUSTIFY_RIGHT
842           : GTK_JUSTIFY_CENTER);
843 }
844
845
846
847 \f
848
849
850 /* Returns the CASENUMth case, or a null pointer on failure.
851  */
852 struct ccase *
853 psppire_data_store_get_case (const PsppireDataStore *ds,
854                              casenumber casenum)
855 {
856   g_return_val_if_fail (ds, FALSE);
857   g_return_val_if_fail (ds->datasheet, FALSE);
858
859   return datasheet_get_row (ds->datasheet, casenum);
860 }
861
862
863 gboolean
864 psppire_data_store_delete_cases (PsppireDataStore *ds, casenumber first,
865                                  casenumber n_cases)
866 {
867   g_return_val_if_fail (ds, FALSE);
868   g_return_val_if_fail (ds->datasheet, FALSE);
869
870   g_return_val_if_fail (first + n_cases <=
871                         psppire_data_store_get_case_count (ds), FALSE);
872
873
874   datasheet_delete_rows (ds->datasheet, first, n_cases);
875
876   g_signal_emit (ds, signals [CASES_DELETED], 0, first, n_cases);
877   psppire_sheet_model_rows_deleted (PSPPIRE_SHEET_MODEL (ds), first, n_cases);
878
879   return TRUE;
880 }
881
882
883
884 /* Insert case CC into the case file before POSN */
885 static gboolean
886 psppire_data_store_insert_case (PsppireDataStore *ds,
887                                 struct ccase *cc,
888                                 casenumber posn)
889 {
890   bool result ;
891
892   g_return_val_if_fail (ds, FALSE);
893   g_return_val_if_fail (ds->datasheet, FALSE);
894
895   case_ref (cc);
896   result = datasheet_insert_rows (ds->datasheet, posn, &cc, 1);
897
898   if ( result )
899     {
900       g_signal_emit (ds, signals [CASE_INSERTED], 0, posn);
901       psppire_sheet_model_rows_inserted (PSPPIRE_SHEET_MODEL (ds), posn, 1);
902     }
903   else
904     g_warning ("Cannot insert case at position %ld\n", posn);
905
906   return result;
907 }
908
909
910 /* Copies the IDXth value from case CASENUM into VALUE.
911    If VALUE is null, then memory is allocated is allocated with
912    malloc.  Returns the value if successful, NULL on failure. */
913 static union value *
914 psppire_data_store_get_value (const PsppireDataStore *ds,
915                               casenumber casenum, size_t idx,
916                               union value *value, int width)
917 {
918   bool allocated;
919
920   g_return_val_if_fail (ds, false);
921   g_return_val_if_fail (ds->datasheet, false);
922
923   g_return_val_if_fail (idx < datasheet_get_column_cnt (ds->datasheet), false);
924
925   if (value == NULL)
926     {
927       value = xnmalloc (value_cnt_from_width (width), sizeof *value);
928       allocated = true;
929     }
930   else
931     allocated = false;
932   if (!datasheet_get_value (ds->datasheet, casenum, idx, value, width))
933     {
934       if (allocated)
935         free (value);
936       value = NULL;
937     }
938   return value;
939 }
940
941
942
943 /* Set the IDXth value of case C to V.
944    Returns true if successful, false on I/O error. */
945 static gboolean
946 psppire_data_store_set_value (PsppireDataStore *ds, casenumber casenum,
947                               gint idx, union value *v, gint width)
948 {
949   bool ok;
950
951   g_return_val_if_fail (ds, FALSE);
952   g_return_val_if_fail (ds->datasheet, FALSE);
953
954   g_return_val_if_fail (idx < datasheet_get_column_cnt (ds->datasheet), FALSE);
955
956   ok = datasheet_put_value (ds->datasheet, casenum, idx, v, width);
957   if (ok)
958     g_signal_emit (ds, signals [CASE_CHANGED], 0, casenum);
959
960   return ok;
961 }
962
963
964
965
966 /* Set the IDXth value of case C using D_IN */
967 static gboolean
968 psppire_data_store_data_in (PsppireDataStore *ds, casenumber casenum, gint idx,
969                             struct substring input, const struct fmt_spec *fmt)
970 {
971   union value *value = NULL;
972   int width;
973   bool ok;
974
975   g_return_val_if_fail (ds, FALSE);
976   g_return_val_if_fail (ds->datasheet, FALSE);
977
978   g_return_val_if_fail (idx < datasheet_get_column_cnt (ds->datasheet), FALSE);
979
980   width = fmt_var_width (fmt);
981   value = xmalloca (value_cnt_from_width (width) * sizeof *value);
982   ok = (datasheet_get_value (ds->datasheet, casenum, idx, value, width)
983         && data_in (input, LEGACY_NATIVE, fmt->type, 0, 0, 0, value, width)
984         && datasheet_put_value (ds->datasheet, casenum, idx, value, width));
985
986   freea (value);
987
988   if (ok)
989     g_signal_emit (ds, signals [CASE_CHANGED], 0, casenum);
990
991   return ok;
992 }
993
994 /* Resize the cases in the casefile, by inserting N_VALUES into every
995    one of them at the position immediately preceeding WHERE.
996 */
997 static gboolean
998 psppire_data_store_insert_values (PsppireDataStore *ds,
999                                   gint n_values, gint where)
1000 {
1001   g_return_val_if_fail (ds, FALSE);
1002
1003   if ( n_values == 0 )
1004     return FALSE;
1005
1006   g_assert (n_values > 0);
1007
1008   if ( ! ds->datasheet )
1009     ds->datasheet = datasheet_create (NULL);
1010
1011   {
1012     union value *values = xcalloc (n_values, sizeof *values);
1013     datasheet_insert_columns (ds->datasheet, values, n_values, where);
1014     free (values);
1015   }
1016
1017   return TRUE;
1018 }
1019
1020 static gboolean
1021 get_row_overstrike (const PsppireSheetModel *model, gint row)
1022 {
1023   union value val;
1024   PsppireDataStore *ds = PSPPIRE_DATA_STORE (model);
1025
1026   const struct dictionary *dict = ds->dict->dict;
1027
1028   const struct variable *filter = dict_get_filter (dict);
1029
1030   if ( row < 0 || row >= datasheet_get_row_cnt (ds->datasheet))
1031     return FALSE;
1032
1033   if ( ! filter)
1034     return FALSE;
1035
1036   g_assert (var_is_numeric (filter));
1037
1038   if ( ! datasheet_get_value (ds->datasheet, row,
1039                               var_get_case_index (filter),
1040                               &val, 0) )
1041     return FALSE;
1042
1043
1044   return (val.f == 0.0);
1045 }