Deleted psppire-case-file.[ch]
[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 <gtksheet/gsheetmodel.h>
29
30 #include <pango/pango-context.h>
31
32 #include "psppire-data-store.h"
33 #include "helper.h"
34
35 #include <data/dictionary.h>
36 #include <data/missing-values.h>
37 #include <data/value-labels.h>
38 #include <data/data-in.h>
39 #include <data/format.h>
40
41 #include <math/sort.h>
42
43 #include "xalloc.h"
44 #include "xmalloca.h"
45
46 static void psppire_data_store_init            (PsppireDataStore      *data_store);
47 static void psppire_data_store_class_init      (PsppireDataStoreClass *class);
48 static void psppire_data_store_sheet_model_init (GSheetModelIface *iface);
49
50 static void psppire_data_store_finalize        (GObject           *object);
51 static void psppire_data_store_dispose        (GObject           *object);
52
53 static gboolean psppire_data_store_clear_datum (GSheetModel *model,
54                                           glong row, glong column);
55
56
57 static gboolean psppire_data_store_insert_case (PsppireDataStore *ds,
58                                                 struct ccase *cc,
59                                                 casenumber posn);
60
61
62 static gboolean psppire_data_store_data_in (PsppireDataStore *ds,
63                                             casenumber casenum, gint idx,
64                                             struct substring input,
65                                             const struct fmt_spec *fmt);
66
67
68
69 static GObjectClass *parent_class = NULL;
70
71
72 enum  {
73        BACKEND_CHANGED,
74        n_SIGNALS};
75
76 static guint signals [n_SIGNALS];
77
78
79 GType
80 psppire_data_store_get_type (void)
81 {
82   static GType data_store_type = 0;
83
84   if (!data_store_type)
85     {
86       static const GTypeInfo data_store_info =
87       {
88         sizeof (PsppireDataStoreClass),
89         NULL,           /* base_init */
90         NULL,           /* base_finalize */
91         (GClassInitFunc) psppire_data_store_class_init,
92         NULL,           /* class_finalize */
93         NULL,           /* class_data */
94         sizeof (PsppireDataStore),
95         0,
96         (GInstanceInitFunc) psppire_data_store_init,
97       };
98
99       static const GInterfaceInfo sheet_model_info =
100       {
101         (GInterfaceInitFunc) psppire_data_store_sheet_model_init,
102         NULL,
103         NULL
104       };
105
106
107       data_store_type = g_type_register_static (G_TYPE_OBJECT, "PsppireDataStore",
108                                                 &data_store_info, 0);
109
110       g_type_add_interface_static (data_store_type,
111                                    G_TYPE_SHEET_MODEL,
112                                    &sheet_model_info);
113
114     }
115
116   return data_store_type;
117 }
118
119
120 static void
121 psppire_data_store_class_init (PsppireDataStoreClass *class)
122 {
123   GObjectClass *object_class;
124
125   parent_class = g_type_class_peek_parent (class);
126   object_class = (GObjectClass*) class;
127
128   object_class->finalize = psppire_data_store_finalize;
129   object_class->dispose = psppire_data_store_dispose;
130
131   signals [BACKEND_CHANGED] =
132     g_signal_new ("backend-changed",
133                   G_TYPE_FROM_CLASS (class),
134                   G_SIGNAL_RUN_FIRST,
135                   0,
136                   NULL, NULL,
137                   g_cclosure_marshal_VOID__VOID,
138                   G_TYPE_NONE,
139                   0);
140 }
141
142
143
144 static gboolean
145 psppire_data_store_insert_values (PsppireDataStore *ds,
146                                   gint n_values, gint where);
147
148 static union value *
149 psppire_data_store_get_value (const PsppireDataStore *ds,
150                               casenumber casenum, size_t idx,
151                               union value *value, int width);
152
153
154 static gboolean
155 psppire_data_store_set_value (PsppireDataStore *ds, casenumber casenum,
156                               gint idx, union value *v, gint width);
157
158
159
160
161 static glong
162 psppire_data_store_get_var_count (const GSheetModel *model)
163 {
164   const PsppireDataStore *store = PSPPIRE_DATA_STORE (model);
165
166   return psppire_dict_get_var_cnt (store->dict);
167 }
168
169 casenumber
170 psppire_data_store_get_case_count (const PsppireDataStore *store)
171 {
172   return datasheet_get_row_cnt (store->datasheet);
173 }
174
175 size_t
176 psppire_data_store_get_value_count (const PsppireDataStore *store)
177 {
178   return psppire_dict_get_value_cnt (store->dict);
179 }
180
181 casenumber
182 psppire_data_store_get_case_count_wrapper (const GSheetModel *model)
183 {
184   const PsppireDataStore *store = PSPPIRE_DATA_STORE (model);
185   return psppire_data_store_get_case_count (store);
186 }
187
188 static void
189 psppire_data_store_init (PsppireDataStore *data_store)
190 {
191   data_store->dict = 0;
192   data_store->datasheet = NULL;
193   data_store->dispose_has_run = FALSE;
194 }
195
196 static inline gchar *
197 psppire_data_store_get_string_wrapper (const GSheetModel *model, glong row,
198                                        glong column)
199 {
200   return psppire_data_store_get_string (PSPPIRE_DATA_STORE (model), row, column);
201 }
202
203
204 static inline gboolean
205 psppire_data_store_set_string_wrapper (GSheetModel *model,
206                                        const gchar *text,
207                                        glong row, glong column)
208 {
209   return psppire_data_store_set_string (PSPPIRE_DATA_STORE (model), text,
210                                         row, column);
211 }
212
213
214
215 static gchar * get_column_subtitle (const GSheetModel *model, gint col);
216 static gchar * get_column_button_label (const GSheetModel *model, gint col);
217 static gboolean get_column_sensitivity (const GSheetModel *model, gint col);
218 static GtkJustification get_column_justification (const GSheetModel *model, gint col);
219
220 static gchar * get_row_button_label (const GSheetModel *model, gint row);
221 static gboolean get_row_sensitivity (const GSheetModel *model, gint row);
222
223
224 static void
225 psppire_data_store_sheet_model_init (GSheetModelIface *iface)
226 {
227   iface->free_strings = TRUE;
228   iface->get_string = psppire_data_store_get_string_wrapper;
229   iface->set_string = psppire_data_store_set_string_wrapper;
230   iface->clear_datum = psppire_data_store_clear_datum;
231   iface->is_editable = NULL;
232   iface->get_foreground = NULL;
233   iface->get_background = NULL;
234   iface->get_cell_border = NULL;
235   iface->get_column_count = psppire_data_store_get_var_count;
236   iface->get_row_count = psppire_data_store_get_case_count_wrapper;
237
238   iface->get_column_subtitle = get_column_subtitle;
239   iface->get_column_title = get_column_button_label;
240   iface->get_column_sensitivity = get_column_sensitivity;
241   iface->get_column_justification = get_column_justification;
242
243   iface->get_row_title = get_row_button_label;
244   iface->get_row_sensitivity = get_row_sensitivity;
245 }
246
247 static void
248 delete_cases_callback (GtkWidget *w,
249          casenumber first, casenumber n_cases, gpointer data)
250 {
251   PsppireDataStore *store  ;
252
253   g_return_if_fail (data);
254
255   store  = PSPPIRE_DATA_STORE (data);
256
257   g_assert (first >= 0);
258
259   g_sheet_model_rows_deleted (G_SHEET_MODEL (store), first, n_cases);
260 }
261
262
263 static void
264 insert_case_callback (GtkWidget *w, casenumber casenum, gpointer data)
265 {
266   PsppireDataStore *store  = PSPPIRE_DATA_STORE (data);
267
268   g_return_if_fail (data);
269
270   g_print ("%s\n", __FUNCTION__);
271
272   g_sheet_model_range_changed (G_SHEET_MODEL (store),
273                                casenum, -1,
274                                psppire_data_store_get_case_count (store),
275                                -1);
276
277   g_sheet_model_rows_inserted (G_SHEET_MODEL (store), casenum, 1);
278 }
279
280
281 static void
282 changed_case_callback (GtkWidget *w, gint casenum, gpointer data)
283 {
284   PsppireDataStore *store  ;
285   g_return_if_fail (data);
286
287   store  = PSPPIRE_DATA_STORE (data);
288
289   g_sheet_model_range_changed (G_SHEET_MODEL (store),
290                                  casenum, -1,
291                                  casenum, -1);
292 }
293
294
295 /*
296    A callback which occurs after a variable has been deleted.
297  */
298 static void
299 delete_variable_callback (GObject *obj, gint dict_index,
300                           gint case_index, gint val_cnt,
301                           gpointer data)
302 {
303   PsppireDataStore *store  = PSPPIRE_DATA_STORE (data);
304
305 #if AXIS_TRANSITION
306   g_sheet_model_columns_deleted (G_SHEET_MODEL (store), dict_index, 1);
307
308   g_sheet_column_columns_changed (G_SHEET_COLUMN (store),
309                                    dict_index, -1);
310 #endif
311 }
312
313
314 static void
315 variable_changed_callback (GObject *obj, gint var_num, gpointer data)
316 {
317   PsppireDataStore *store  = PSPPIRE_DATA_STORE (data);
318
319 #if AXIS_TRANSITION
320   g_sheet_column_columns_changed (G_SHEET_COLUMN (store),
321                                   var_num, 1);
322
323
324   g_sheet_model_range_changed (G_SHEET_MODEL (store),
325                                -1, var_num,
326                                -1, var_num);
327 #endif
328 }
329
330 static void
331 insert_variable_callback (GObject *obj, gint var_num, gpointer data)
332 {
333   PsppireDataStore *store;
334   gint posn;
335
336   g_return_if_fail (data);
337
338   store  = PSPPIRE_DATA_STORE (data);
339
340   if ( var_num > 0 )
341     {
342       struct variable *variable =
343         psppire_dict_get_variable (store->dict, var_num);
344
345       g_assert (variable != NULL);
346
347       posn = var_get_case_index (variable);
348     }
349   else
350     {
351       posn = 0;
352     }
353
354   psppire_data_store_insert_values (store, 1, posn);
355
356 #if AXIS_TRANSITION
357   g_sheet_column_columns_changed (G_SHEET_COLUMN (store),
358                                   var_num, 1);
359 #endif
360
361   g_sheet_model_columns_inserted (G_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   ds->datasheet = datasheet_create (reader);
409
410   g_sheet_model_range_changed (G_SHEET_MODEL (ds),
411                                -1, -1, -1, -1);
412
413 #if 0
414   for (i = 0 ; i < n_cf_signals ; ++i )
415     {
416       if ( ds->cf_handler_id [i] > 0 )
417         g_signal_handler_disconnect (ds->case_file,
418                                      ds->cf_handler_id[i]);
419     }
420 #endif
421
422   if ( ds->dict )
423     for (i = 0 ; i < n_dict_signals; ++i )
424       {
425         if ( ds->dict_handler_id [i] > 0)
426           {
427             g_signal_handler_unblock (ds->dict,
428                                       ds->dict_handler_id[i]);
429           }
430       }
431
432 #if 0
433   ds->cf_handler_id [CASES_DELETED] =
434     g_signal_connect (ds->case_file, "cases-deleted",
435                       G_CALLBACK (delete_cases_callback),
436                       ds);
437
438   ds->cf_handler_id [CASE_INSERTED] =
439     g_signal_connect (ds->case_file, "case-inserted",
440                       G_CALLBACK (insert_case_callback),
441                       ds);
442
443   ds->cf_handler_id [CASE_CHANGED] =
444     g_signal_connect (ds->case_file, "case-changed",
445                       G_CALLBACK (changed_case_callback),
446                       ds);
447 #endif
448
449   g_signal_emit (ds, signals[BACKEND_CHANGED], 0);
450 }
451
452
453 /**
454  * psppire_data_store_replace_set_dictionary:
455  * @data_store: The variable store
456  * @dict: The dictionary to set
457  *
458  * If a dictionary is already associated with the data-store, then it will be
459  * destroyed.
460  **/
461 void
462 psppire_data_store_set_dictionary (PsppireDataStore *data_store, PsppireDict *dict)
463 {
464   int i;
465
466   /* Disconnect any existing handlers */
467   if ( data_store->dict )
468     for (i = 0 ; i < n_dict_signals; ++i )
469       {
470         g_signal_handler_disconnect (data_store->dict,
471                                      data_store->dict_handler_id[i]);
472       }
473
474   data_store->dict = dict;
475
476   if ( dict != NULL)
477     {
478
479       data_store->dict_handler_id [VARIABLE_INSERTED] =
480         g_signal_connect (dict, "variable-inserted",
481                           G_CALLBACK (insert_variable_callback),
482                           data_store);
483
484       data_store->dict_handler_id [VARIABLE_DELETED] =
485         g_signal_connect (dict, "variable-deleted",
486                           G_CALLBACK (delete_variable_callback),
487                           data_store);
488
489       data_store->dict_handler_id [VARIABLE_CHANGED] =
490         g_signal_connect (dict, "variable-changed",
491                           G_CALLBACK (variable_changed_callback),
492                           data_store);
493
494       data_store->dict_handler_id [SIZE_CHANGED] =
495         g_signal_connect (dict, "dict-size-changed",
496                           G_CALLBACK (dict_size_change_callback),
497                           data_store);
498     }
499
500
501
502   /* The entire model has changed */
503   g_sheet_model_range_changed (G_SHEET_MODEL (data_store), -1, -1, -1, -1);
504
505 #if AXIS_TRANSITION
506   g_sheet_column_columns_changed (G_SHEET_COLUMN (data_store), 0, -1);
507 #endif
508
509   if ( data_store->dict )
510     for (i = 0 ; i < n_dict_signals; ++i )
511       {
512         if ( data_store->dict_handler_id [i] > 0)
513           {
514             g_signal_handler_block (data_store->dict,
515                                     data_store->dict_handler_id[i]);
516           }
517       }
518 }
519
520 static void
521 psppire_data_store_finalize (GObject *object)
522 {
523
524   /* must chain up */
525   (* parent_class->finalize) (object);
526 }
527
528
529 static void
530 psppire_data_store_dispose (GObject *object)
531 {
532   PsppireDataStore *ds = PSPPIRE_DATA_STORE (object);
533
534   if (ds->dispose_has_run)
535     return;
536
537   if (ds->datasheet)
538     {
539       datasheet_destroy (ds->datasheet);
540       ds->datasheet = NULL;
541     }
542
543   /* must chain up */
544   (* parent_class->dispose) (object);
545
546   ds->dispose_has_run = TRUE;
547 }
548
549
550
551 /* Insert a blank case before POSN */
552 gboolean
553 psppire_data_store_insert_new_case (PsppireDataStore *ds, casenumber posn)
554 {
555   gboolean result;
556   gint val_cnt, v;
557   struct ccase cc;
558   g_return_val_if_fail (ds, FALSE);
559
560   val_cnt = datasheet_get_column_cnt (ds->datasheet) ;
561
562   g_return_val_if_fail (val_cnt > 0, FALSE);
563
564   g_return_val_if_fail (posn <= psppire_data_store_get_case_count (ds), FALSE);
565
566   case_create (&cc, val_cnt);
567
568   memset ( case_data_rw_idx (&cc, 0), 0, val_cnt * MAX_SHORT_STRING);
569
570   for (v = 0 ; v < psppire_dict_get_var_cnt (ds->dict) ; ++v)
571     {
572       const struct variable *pv = psppire_dict_get_variable (ds->dict, v);
573       if ( var_is_alpha (pv))
574         continue;
575
576       case_data_rw (&cc, pv)->f = SYSMIS;
577     }
578
579   result = psppire_data_store_insert_case (ds, &cc, posn);
580
581   case_destroy (&cc);
582
583   return result;
584 }
585
586
587 gchar *
588 psppire_data_store_get_string (PsppireDataStore *store, glong row, glong column)
589 {
590   gint idx;
591   char *text;
592   const struct fmt_spec *fp ;
593   const struct variable *pv ;
594   union value *v ;
595   GString *s;
596
597   g_return_val_if_fail (store->dict, NULL);
598   g_return_val_if_fail (store->datasheet, NULL);
599
600   if (column >= psppire_dict_get_var_cnt (store->dict))
601     return NULL;
602
603   if ( row >= psppire_data_store_get_case_count (store))
604     return NULL;
605
606   pv = psppire_dict_get_variable (store->dict, column);
607
608   g_assert (pv);
609
610   idx = var_get_case_index (pv);
611
612   g_assert (idx >= 0);
613
614   v = psppire_data_store_get_value (store, row, idx, NULL,
615                                    var_get_width (pv));
616
617   g_return_val_if_fail (v, NULL);
618
619   if ( store->show_labels)
620     {
621       const gchar *label = var_lookup_value_label (pv, v);
622       if (label)
623         {
624           free (v);
625           return pspp_locale_to_utf8 (label, -1, 0);
626         }
627     }
628
629   fp = var_get_write_format (pv);
630
631   s = g_string_sized_new (fp->w + 1);
632   g_string_set_size (s, fp->w);
633
634   memset (s->str, 0, fp->w);
635
636   g_assert (fp->w == s->len);
637
638   /* Converts binary value V into printable form in the exactly
639      FP->W character in buffer S according to format specification
640      FP.  No null terminator is appended to the buffer.  */
641   data_out (v, fp, s->str);
642
643   text = pspp_locale_to_utf8 (s->str, fp->w, 0);
644   g_string_free (s, TRUE);
645
646   g_strchomp (text);
647
648   free (v);
649   return text;
650 }
651
652
653 static gboolean
654 psppire_data_store_clear_datum (GSheetModel *model,
655                                           glong row, glong col)
656 {
657   PsppireDataStore *store = PSPPIRE_DATA_STORE (model);
658
659   union value v;
660   const struct variable *pv = psppire_dict_get_variable (store->dict, col);
661
662   const gint index = var_get_case_index (pv) ;
663
664   if ( var_is_numeric (pv))
665     v.f = SYSMIS;
666   else
667     memcpy (v.s, "", MAX_SHORT_STRING);
668
669   psppire_data_store_set_value (store, row, index, &v,
670                                 var_get_width (pv));
671
672   return TRUE;
673 }
674
675
676 /* Attempts to update that part of the variable store which corresponds
677    to ROW, COL with  the value TEXT.
678    Returns true if anything was updated, false otherwise.
679 */
680 gboolean
681 psppire_data_store_set_string (PsppireDataStore *store,
682                                const gchar *text, glong row, glong col)
683 {
684   glong n_cases;
685   const struct variable *pv = psppire_dict_get_variable (store->dict, col);
686   g_return_val_if_fail (pv, FALSE);
687
688   n_cases = psppire_data_store_get_case_count (store);
689
690   if ( row > n_cases)
691     return FALSE;
692
693   if (row == n_cases)
694     psppire_data_store_insert_new_case (store, row);
695
696   psppire_data_store_data_in (store, row,
697                               var_get_case_index (pv), ss_cstr (text),
698                               var_get_write_format (pv));
699
700   return TRUE;
701 }
702
703
704
705 void
706 psppire_data_store_show_labels (PsppireDataStore *store, gboolean show_labels)
707 {
708   g_return_if_fail (store);
709   g_return_if_fail (PSPPIRE_IS_DATA_STORE (store));
710
711   store->show_labels = show_labels;
712
713   g_sheet_model_range_changed (G_SHEET_MODEL (store),
714                                  -1, -1, -1, -1);
715 }
716
717
718 void
719 psppire_data_store_clear (PsppireDataStore *ds)
720 {
721   datasheet_destroy (ds->datasheet);
722   ds->datasheet = NULL;
723
724   psppire_dict_clear (ds->dict);
725
726   g_signal_emit (ds, signals [CASES_DELETED], 0, 0, -1);
727 }
728
729
730
731 /* Return a casereader made from this datastore */
732 struct casereader *
733 psppire_data_store_get_reader (PsppireDataStore *ds)
734 {
735   int i;
736   struct casereader *reader ;
737
738 #if 0
739   for (i = 0 ; i < n_cf_signals ; ++i )
740     {
741       g_signal_handler_disconnect (ds->case_file, ds->cf_handler_id[i]);
742       ds->cf_handler_id[i] = 0 ;
743     }
744 #endif
745
746   if ( ds->dict )
747     for (i = 0 ; i < n_dict_signals; ++i )
748       {
749         g_signal_handler_block (ds->dict,
750                                 ds->dict_handler_id[i]);
751       }
752
753   return  datasheet_make_reader (ds->datasheet);
754 }
755
756
757
758 /* Column related funcs */
759
760
761 static const gchar null_var_name[]=N_("var");
762
763 \f
764
765 /* Row related funcs */
766
767 static gchar *
768 get_row_button_label (const GSheetModel *model, gint unit)
769 {
770   gchar *s = g_strdup_printf (_("%d"), unit + FIRST_CASE_NUMBER);
771
772   gchar *text =  pspp_locale_to_utf8 (s, -1, 0);
773
774   g_free (s);
775
776   return text;
777 }
778
779
780 static gboolean
781 get_row_sensitivity (const GSheetModel *model, gint unit)
782 {
783   PsppireDataStore *ds = PSPPIRE_DATA_STORE (model);
784
785   return (unit < psppire_data_store_get_case_count (ds));
786 }
787
788
789 \f
790
791 /* Column related stuff */
792
793 static gchar *
794 get_column_subtitle (const GSheetModel *model, gint col)
795 {
796   gchar *text;
797   const struct variable *v ;
798   PsppireDataStore *ds = PSPPIRE_DATA_STORE (model);
799
800   if ( col >= psppire_dict_get_var_cnt (ds->dict) )
801     return NULL;
802
803   v = psppire_dict_get_variable (ds->dict, col);
804
805   if ( ! var_has_label (v))
806     return NULL;
807
808   text =  pspp_locale_to_utf8 (var_get_label (v), -1, 0);
809
810   return text;
811 }
812
813 static gchar *
814 get_column_button_label (const GSheetModel *model, gint col)
815 {
816   gchar *text;
817   struct variable *pv ;
818   PsppireDataStore *ds = PSPPIRE_DATA_STORE (model);
819
820   if ( col >= psppire_dict_get_var_cnt (ds->dict) )
821     return g_locale_to_utf8 (null_var_name, -1, 0, 0, 0);
822
823   pv = psppire_dict_get_variable (ds->dict, col);
824
825   text =  pspp_locale_to_utf8 (var_get_name (pv), -1, 0);
826
827   return text;
828 }
829
830 static gboolean
831 get_column_sensitivity (const GSheetModel *model, gint col)
832 {
833   PsppireDataStore *ds = PSPPIRE_DATA_STORE (model);
834
835   return (col < psppire_dict_get_var_cnt (ds->dict));
836 }
837
838
839
840 static GtkJustification
841 get_column_justification (const GSheetModel *model, gint col)
842 {
843   PsppireDataStore *ds = PSPPIRE_DATA_STORE (model);
844   const struct variable *pv ;
845
846   if ( col >= psppire_dict_get_var_cnt (ds->dict) )
847     return GTK_JUSTIFY_LEFT;
848
849   pv = psppire_dict_get_variable (ds->dict, col);
850
851   return (var_get_alignment (pv) == ALIGN_LEFT ? GTK_JUSTIFY_LEFT
852           : var_get_alignment (pv) == ALIGN_RIGHT ? GTK_JUSTIFY_RIGHT
853           : GTK_JUSTIFY_CENTER);
854 }
855
856
857
858 \f
859
860
861 /* Fills C with the CASENUMth case.
862    Returns true on success, false otherwise.
863  */
864 gboolean
865 psppire_data_store_get_case (const PsppireDataStore *ds,
866                              casenumber casenum,
867                              struct ccase *c)
868 {
869   g_return_val_if_fail (ds, FALSE);
870   g_return_val_if_fail (ds->datasheet, FALSE);
871
872   return datasheet_get_row (ds->datasheet, casenum, c);
873 }
874
875
876 gboolean
877 psppire_data_store_delete_cases (PsppireDataStore *ds, casenumber n_cases,
878                                  casenumber first)
879 {
880   g_return_val_if_fail (ds, FALSE);
881   g_return_val_if_fail (ds->datasheet, FALSE);
882
883   g_return_val_if_fail (first + n_cases <=
884                         psppire_data_store_get_case_count (ds), FALSE);
885
886   datasheet_delete_rows (ds->datasheet, first, n_cases);
887
888   g_signal_emit (ds, signals [CASES_DELETED], 0, first, n_cases);
889
890   return TRUE;
891 }
892
893
894
895 /* Insert case CC into the case file before POSN */
896 static gboolean
897 psppire_data_store_insert_case (PsppireDataStore *ds,
898                                 struct ccase *cc,
899                                 casenumber posn)
900 {
901   struct ccase tmp;
902   bool result ;
903
904   g_return_val_if_fail (ds, FALSE);
905   g_return_val_if_fail (ds->datasheet, FALSE);
906
907   case_clone (&tmp, cc);
908   result = datasheet_insert_rows (ds->datasheet, posn, &tmp, 1);
909
910   if ( result )
911     g_signal_emit (ds, signals [CASE_INSERTED], 0, posn);
912   else
913     g_warning ("Cannot insert case at position %ld\n", posn);
914
915   return result;
916 }
917
918
919 /* Copies the IDXth value from case CASENUM into VALUE.
920    If VALUE is null, then memory is allocated is allocated with
921    malloc.  Returns the value if successful, NULL on failure. */
922 static union value *
923 psppire_data_store_get_value (const PsppireDataStore *ds,
924                               casenumber casenum, size_t idx,
925                               union value *value, int width)
926 {
927   bool allocated;
928
929   g_return_val_if_fail (ds, false);
930   g_return_val_if_fail (ds->datasheet, false);
931
932   g_return_val_if_fail (idx < datasheet_get_column_cnt (ds->datasheet), false);
933
934   if (value == NULL)
935     {
936       value = xnmalloc (value_cnt_from_width (width), sizeof *value);
937       allocated = true;
938     }
939   else
940     allocated = false;
941   if (!datasheet_get_value (ds->datasheet, casenum, idx, value, width))
942     {
943       if (allocated)
944         free (value);
945       value = NULL;
946     }
947   return value;
948 }
949
950
951
952 /* Set the IDXth value of case C to V.
953    Returns true if successful, false on I/O error. */
954 static gboolean
955 psppire_data_store_set_value (PsppireDataStore *ds, casenumber casenum,
956                               gint idx, union value *v, gint width)
957 {
958   bool ok;
959
960   g_return_val_if_fail (ds, FALSE);
961   g_return_val_if_fail (ds->datasheet, FALSE);
962
963   g_return_val_if_fail (idx < datasheet_get_column_cnt (ds->datasheet), FALSE);
964
965   ok = datasheet_put_value (ds->datasheet, casenum, idx, v, width);
966   if (ok)
967     g_signal_emit (ds, signals [CASE_CHANGED], 0, casenum);
968   return ok;
969 }
970
971
972
973
974 /* Set the IDXth value of case C using D_IN */
975 static gboolean
976 psppire_data_store_data_in (PsppireDataStore *ds, casenumber casenum, gint idx,
977                             struct substring input, const struct fmt_spec *fmt)
978 {
979   union value *value = NULL;
980   int width;
981   bool ok;
982
983   g_return_val_if_fail (ds, FALSE);
984   g_return_val_if_fail (ds->datasheet, FALSE);
985
986   g_return_val_if_fail (idx < datasheet_get_column_cnt (ds->datasheet), FALSE);
987
988   width = fmt_var_width (fmt);
989   value = xmalloca (value_cnt_from_width (width) * sizeof *value);
990   ok = (datasheet_get_value (ds->datasheet, casenum, idx, value, width)
991         && data_in (input, LEGACY_NATIVE, fmt->type, 0, 0, 0, value, width)
992         && datasheet_put_value (ds->datasheet, casenum, idx, value, width));
993
994   if (ok)
995     g_signal_emit (ds, signals [CASE_CHANGED], 0, casenum);
996
997   freea (value);
998
999   return TRUE;
1000 }
1001
1002 /* Resize the cases in the casefile, by inserting N_VALUES into every
1003    one of them at the position immediately preceeding WHERE.
1004 */
1005 static gboolean
1006 psppire_data_store_insert_values (PsppireDataStore *ds,
1007                                   gint n_values, gint where)
1008 {
1009   g_return_val_if_fail (ds, FALSE);
1010
1011   if ( n_values == 0 )
1012     return FALSE;
1013
1014   g_assert (n_values > 0);
1015
1016   if ( ! ds->datasheet )
1017     ds->datasheet = datasheet_create (NULL);
1018
1019   {
1020     union value *values = xcalloc (n_values, sizeof *values);
1021     datasheet_insert_columns (ds->datasheet, values, n_values, where);
1022     free (values);
1023   }
1024
1025   return TRUE;
1026 }