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