Remove the gsheet-row-* modules and replaced with psppire-axis-*
[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 "psppire-case-file.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
43 static void psppire_data_store_init            (PsppireDataStore      *data_store);
44 static void psppire_data_store_class_init      (PsppireDataStoreClass *class);
45 static void psppire_data_store_sheet_model_init (GSheetModelIface *iface);
46
47 static void psppire_data_store_finalize        (GObject           *object);
48 static void psppire_data_store_dispose        (GObject           *object);
49
50 static gboolean psppire_data_store_clear_datum (GSheetModel *model,
51                                           glong row, glong column);
52
53
54 static GObjectClass *parent_class = NULL;
55
56
57 enum  {FONT_CHANGED,
58        BACKEND_CHANGED,
59        n_SIGNALS};
60
61 static guint signals [n_SIGNALS];
62
63
64 GType
65 psppire_data_store_get_type (void)
66 {
67   static GType data_store_type = 0;
68
69   if (!data_store_type)
70     {
71       static const GTypeInfo data_store_info =
72       {
73         sizeof (PsppireDataStoreClass),
74         NULL,           /* base_init */
75         NULL,           /* base_finalize */
76         (GClassInitFunc) psppire_data_store_class_init,
77         NULL,           /* class_finalize */
78         NULL,           /* class_data */
79         sizeof (PsppireDataStore),
80         0,
81         (GInstanceInitFunc) psppire_data_store_init,
82       };
83
84       static const GInterfaceInfo sheet_model_info =
85       {
86         (GInterfaceInitFunc) psppire_data_store_sheet_model_init,
87         NULL,
88         NULL
89       };
90
91
92       data_store_type = g_type_register_static (G_TYPE_OBJECT, "PsppireDataStore",
93                                                 &data_store_info, 0);
94
95       g_type_add_interface_static (data_store_type,
96                                    G_TYPE_SHEET_MODEL,
97                                    &sheet_model_info);
98
99     }
100
101   return data_store_type;
102 }
103
104
105 static void
106 psppire_data_store_class_init (PsppireDataStoreClass *class)
107 {
108   GObjectClass *object_class;
109
110   parent_class = g_type_class_peek_parent (class);
111   object_class = (GObjectClass*) class;
112
113   object_class->finalize = psppire_data_store_finalize;
114   object_class->dispose = psppire_data_store_dispose;
115
116   signals [FONT_CHANGED] =
117     g_signal_new ("font_changed",
118                   G_TYPE_FROM_CLASS (class),
119                   G_SIGNAL_RUN_FIRST,
120                   0,
121                   NULL, NULL,
122                   g_cclosure_marshal_VOID__VOID,
123                   G_TYPE_NONE,
124                   0);
125
126
127   signals [BACKEND_CHANGED] =
128     g_signal_new ("backend-changed",
129                   G_TYPE_FROM_CLASS (class),
130                   G_SIGNAL_RUN_FIRST,
131                   0,
132                   NULL, NULL,
133                   g_cclosure_marshal_VOID__VOID,
134                   G_TYPE_NONE,
135                   0);
136 }
137
138
139
140 static glong
141 psppire_data_store_get_var_count (const GSheetModel *model)
142 {
143   const PsppireDataStore *store = PSPPIRE_DATA_STORE (model);
144
145   return psppire_dict_get_var_cnt (store->dict);
146 }
147
148 casenumber
149 psppire_data_store_get_case_count (const PsppireDataStore *store)
150 {
151   return psppire_case_file_get_case_count (store->case_file);
152 }
153
154 size_t
155 psppire_data_store_get_value_count (const PsppireDataStore *store)
156 {
157   return psppire_dict_get_value_cnt (store->dict);
158 }
159
160 casenumber
161 psppire_data_store_get_case_count_wrapper (const GSheetModel *model)
162 {
163   const PsppireDataStore *store = PSPPIRE_DATA_STORE (model);
164   return psppire_data_store_get_case_count (store);
165 }
166
167 static void
168 psppire_data_store_init (PsppireDataStore *data_store)
169 {
170   data_store->dict = 0;
171   data_store->case_file = NULL;
172   data_store->width_of_m = 10;
173   data_store->dispose_has_run = FALSE;
174 }
175
176 const PangoFontDescription *
177 psppire_data_store_get_font_desc (const GSheetModel *model,
178                               glong row, glong column)
179 {
180   PsppireDataStore *store = PSPPIRE_DATA_STORE (model);
181
182   return store->font_desc;
183 }
184
185 static inline gchar *
186 psppire_data_store_get_string_wrapper (const GSheetModel *model, glong row,
187                                        glong column)
188 {
189   return psppire_data_store_get_string (PSPPIRE_DATA_STORE (model), row, column);
190 }
191
192
193 static inline gboolean
194 psppire_data_store_set_string_wrapper (GSheetModel *model,
195                                        const gchar *text,
196                                        glong row, glong column)
197 {
198   return psppire_data_store_set_string (PSPPIRE_DATA_STORE (model), text,
199                                         row, column);
200 }
201
202
203
204 static gchar * get_column_subtitle (const GSheetModel *model, gint col);
205 static gchar * get_column_button_label (const GSheetModel *model, gint col);
206 static gboolean get_column_sensitivity (const GSheetModel *model, gint col);
207 static GtkJustification get_column_justification (const GSheetModel *model, gint col);
208
209 static gchar * get_row_button_label (const GSheetModel *model, gint row);
210 static gboolean get_row_sensitivity (const GSheetModel *model, gint row);
211
212
213 static void
214 psppire_data_store_sheet_model_init (GSheetModelIface *iface)
215 {
216   iface->free_strings = TRUE;
217   iface->get_string = psppire_data_store_get_string_wrapper;
218   iface->set_string = psppire_data_store_set_string_wrapper;
219   iface->clear_datum = psppire_data_store_clear_datum;
220   iface->is_editable = NULL;
221   iface->is_visible = NULL;
222   iface->get_foreground = NULL;
223   iface->get_background = NULL;
224   iface->get_font_desc = psppire_data_store_get_font_desc;
225   iface->get_cell_border = NULL;
226   iface->get_column_count = psppire_data_store_get_var_count;
227   iface->get_row_count = psppire_data_store_get_case_count_wrapper;
228
229   iface->get_column_subtitle = get_column_subtitle;
230   iface->get_column_title = get_column_button_label;
231   iface->get_column_sensitivity = get_column_sensitivity;
232   iface->get_column_justification = get_column_justification;
233
234   iface->get_row_title = get_row_button_label;
235   iface->get_row_sensitivity = get_row_sensitivity;
236 }
237
238 static void
239 delete_cases_callback (GtkWidget *w,
240          casenumber first, casenumber n_cases, gpointer data)
241 {
242   PsppireDataStore *store  ;
243
244   g_return_if_fail (data);
245
246   store  = PSPPIRE_DATA_STORE (data);
247
248   g_assert (first >= 0);
249
250   g_sheet_model_rows_deleted (G_SHEET_MODEL (store), first, n_cases);
251 }
252
253
254 static void
255 insert_case_callback (GtkWidget *w, casenumber casenum, gpointer data)
256 {
257   PsppireDataStore *store  = PSPPIRE_DATA_STORE (data);
258
259   g_return_if_fail (data);
260
261   g_print ("%s\n", __FUNCTION__);
262
263   g_sheet_model_range_changed (G_SHEET_MODEL (store),
264                                casenum, -1,
265                                psppire_case_file_get_case_count (store->case_file),
266                                -1);
267
268   g_sheet_model_rows_inserted (G_SHEET_MODEL (store), casenum, 1);
269 }
270
271
272 static void
273 changed_case_callback (GtkWidget *w, gint casenum, gpointer data)
274 {
275   PsppireDataStore *store  ;
276   g_return_if_fail (data);
277
278   store  = PSPPIRE_DATA_STORE (data);
279
280   g_sheet_model_range_changed (G_SHEET_MODEL (store),
281                                  casenum, -1,
282                                  casenum, -1);
283 }
284
285
286 /*
287    A callback which occurs after a variable has been deleted.
288  */
289 static void
290 delete_variable_callback (GObject *obj, gint dict_index,
291                           gint case_index, gint val_cnt,
292                           gpointer data)
293 {
294   PsppireDataStore *store  = PSPPIRE_DATA_STORE (data);
295
296 #if AXIS_TRANSITION
297   g_sheet_model_columns_deleted (G_SHEET_MODEL (store), dict_index, 1);
298
299   g_sheet_column_columns_changed (G_SHEET_COLUMN (store),
300                                    dict_index, -1);
301 #endif
302 }
303
304
305 static void
306 variable_changed_callback (GObject *obj, gint var_num, gpointer data)
307 {
308   PsppireDataStore *store  = PSPPIRE_DATA_STORE (data);
309
310 #if AXIS_TRANSITION
311   g_sheet_column_columns_changed (G_SHEET_COLUMN (store),
312                                   var_num, 1);
313
314
315   g_sheet_model_range_changed (G_SHEET_MODEL (store),
316                                -1, var_num,
317                                -1, var_num);
318 #endif
319 }
320
321 static void
322 insert_variable_callback (GObject *obj, gint var_num, gpointer data)
323 {
324   PsppireDataStore *store;
325   gint posn;
326
327   g_return_if_fail (data);
328
329   store  = PSPPIRE_DATA_STORE (data);
330
331   if ( var_num > 0 )
332     {
333       struct variable *variable =
334         psppire_dict_get_variable (store->dict, var_num);
335
336       g_assert (variable != NULL);
337
338       posn = var_get_case_index (variable);
339     }
340   else
341     {
342       posn = 0;
343     }
344
345   psppire_case_file_insert_values (store->case_file, 1, posn);
346
347 #if AXIS_TRANSITION
348   g_sheet_column_columns_changed (G_SHEET_COLUMN (store),
349                                   var_num, 1);
350 #endif
351
352   g_sheet_model_columns_inserted (G_SHEET_MODEL (store), var_num, 1);
353 }
354
355
356 static void
357 dict_size_change_callback (GObject *obj,
358                           gint posn, gint adjustment, gpointer data)
359 {
360   PsppireDataStore *store  = PSPPIRE_DATA_STORE (data);
361
362   const struct variable *v = psppire_dict_get_variable (store->dict, posn);
363
364   const gint new_val_width = value_cnt_from_width (var_get_width (v));
365
366   if ( adjustment > 0 )
367     psppire_case_file_insert_values (store->case_file, adjustment,
368                                      new_val_width - adjustment +
369                                      var_get_case_index(v));
370 }
371
372
373
374 /**
375  * psppire_data_store_new:
376  * @dict: The dictionary for this data_store.
377  *
378  *
379  * Return value: a new #PsppireDataStore
380  **/
381 PsppireDataStore *
382 psppire_data_store_new (PsppireDict *dict)
383 {
384   PsppireDataStore *retval;
385
386   retval = g_object_new (GTK_TYPE_DATA_STORE, NULL);
387
388   psppire_data_store_set_dictionary (retval, dict);
389
390   return retval;
391 }
392
393
394 void
395 psppire_data_store_set_case_file (PsppireDataStore *ds,
396                                   PsppireCaseFile *cf)
397 {
398   gint i;
399   if ( ds->case_file)  g_object_unref (ds->case_file);
400   ds->case_file = cf;
401
402   g_sheet_model_range_changed (G_SHEET_MODEL (ds),
403                                -1, -1, -1, -1);
404
405   for (i = 0 ; i < n_cf_signals ; ++i )
406     {
407       if ( ds->cf_handler_id [i] > 0 )
408         g_signal_handler_disconnect (ds->case_file,
409                                      ds->cf_handler_id[i]);
410     }
411
412
413   if ( ds->dict )
414     for (i = 0 ; i < n_dict_signals; ++i )
415       {
416         if ( ds->dict_handler_id [i] > 0)
417           {
418             g_signal_handler_unblock (ds->dict,
419                                       ds->dict_handler_id[i]);
420           }
421       }
422
423   ds->cf_handler_id [CASES_DELETED] =
424     g_signal_connect (ds->case_file, "cases-deleted",
425                       G_CALLBACK (delete_cases_callback),
426                       ds);
427
428   ds->cf_handler_id [CASE_INSERTED] =
429     g_signal_connect (ds->case_file, "case-inserted",
430                       G_CALLBACK (insert_case_callback),
431                       ds);
432
433   ds->cf_handler_id [CASE_CHANGED] =
434     g_signal_connect (ds->case_file, "case-changed",
435                       G_CALLBACK (changed_case_callback),
436                       ds);
437
438   g_signal_emit (ds, signals[BACKEND_CHANGED], 0);
439 }
440
441
442 /**
443  * psppire_data_store_replace_set_dictionary:
444  * @data_store: The variable store
445  * @dict: The dictionary to set
446  *
447  * If a dictionary is already associated with the data-store, then it will be
448  * destroyed.
449  **/
450 void
451 psppire_data_store_set_dictionary (PsppireDataStore *data_store, PsppireDict *dict)
452 {
453   int i;
454
455   /* Disconnect any existing handlers */
456   if ( data_store->dict )
457     for (i = 0 ; i < n_dict_signals; ++i )
458       {
459         g_signal_handler_disconnect (data_store->dict,
460                                      data_store->dict_handler_id[i]);
461       }
462
463   data_store->dict = dict;
464
465   if ( dict != NULL)
466     {
467
468       data_store->dict_handler_id [VARIABLE_INSERTED] =
469         g_signal_connect (dict, "variable-inserted",
470                           G_CALLBACK (insert_variable_callback),
471                           data_store);
472
473       data_store->dict_handler_id [VARIABLE_DELETED] =
474         g_signal_connect (dict, "variable-deleted",
475                           G_CALLBACK (delete_variable_callback),
476                           data_store);
477
478       data_store->dict_handler_id [VARIABLE_CHANGED] =
479         g_signal_connect (dict, "variable-changed",
480                           G_CALLBACK (variable_changed_callback),
481                           data_store);
482
483       data_store->dict_handler_id [SIZE_CHANGED] =
484         g_signal_connect (dict, "dict-size-changed",
485                           G_CALLBACK (dict_size_change_callback),
486                           data_store);
487     }
488
489
490
491   /* The entire model has changed */
492   g_sheet_model_range_changed (G_SHEET_MODEL (data_store), -1, -1, -1, -1);
493
494 #if AXIS_TRANSITION
495   g_sheet_column_columns_changed (G_SHEET_COLUMN (data_store), 0, -1);
496 #endif
497
498   if ( data_store->dict )
499     for (i = 0 ; i < n_dict_signals; ++i )
500       {
501         if ( data_store->dict_handler_id [i] > 0)
502           {
503             g_signal_handler_block (data_store->dict,
504                                     data_store->dict_handler_id[i]);
505           }
506       }
507 }
508
509 static void
510 psppire_data_store_finalize (GObject *object)
511 {
512
513   /* must chain up */
514   (* parent_class->finalize) (object);
515 }
516
517
518 static void
519 psppire_data_store_dispose (GObject *object)
520 {
521   PsppireDataStore *ds = PSPPIRE_DATA_STORE (object);
522
523   if (ds->dispose_has_run)
524     return;
525
526   if (ds->case_file) g_object_unref (ds->case_file);
527
528   /* must chain up */
529   (* parent_class->dispose) (object);
530
531   ds->dispose_has_run = TRUE;
532 }
533
534
535 gboolean
536 psppire_data_store_delete_cases (PsppireDataStore *ds,
537                                  casenumber first, casenumber count)
538 {
539   g_return_val_if_fail (ds, FALSE);
540
541   return psppire_case_file_delete_cases (ds->case_file, count, first);
542 }
543
544
545
546 /* Insert a blank case before POSN */
547 gboolean
548 psppire_data_store_insert_new_case (PsppireDataStore *ds, casenumber posn)
549 {
550   gboolean result;
551   gint val_cnt, v;
552   struct ccase cc;
553   g_return_val_if_fail (ds, FALSE);
554
555   val_cnt = datasheet_get_column_cnt (ds->case_file->datasheet) ;
556
557   g_return_val_if_fail (val_cnt > 0, FALSE);
558
559   g_return_val_if_fail (posn <= psppire_data_store_get_case_count (ds), FALSE);
560
561   case_create (&cc, val_cnt);
562
563   memset ( case_data_rw_idx (&cc, 0), 0, val_cnt * MAX_SHORT_STRING);
564
565   for (v = 0 ; v < psppire_dict_get_var_cnt (ds->dict) ; ++v)
566     {
567       const struct variable *pv = psppire_dict_get_variable (ds->dict, v);
568       if ( var_is_alpha (pv))
569         continue;
570
571       case_data_rw (&cc, pv)->f = SYSMIS;
572     }
573
574   result = psppire_case_file_insert_case (ds->case_file, &cc, posn);
575
576   case_destroy (&cc);
577
578   return result;
579 }
580
581
582 gchar *
583 psppire_data_store_get_string (PsppireDataStore *store, glong row, glong column)
584 {
585   gint idx;
586   char *text;
587   const struct fmt_spec *fp ;
588   const struct variable *pv ;
589   union value *v ;
590   GString *s;
591
592   g_return_val_if_fail (store->dict, NULL);
593   g_return_val_if_fail (store->case_file, NULL);
594
595   if (column >= psppire_dict_get_var_cnt (store->dict))
596     return NULL;
597
598   if ( row >= psppire_case_file_get_case_count (store->case_file))
599     return NULL;
600
601   pv = psppire_dict_get_variable (store->dict, column);
602
603   g_assert (pv);
604
605   idx = var_get_case_index (pv);
606
607   g_assert (idx >= 0);
608
609   v = psppire_case_file_get_value (store->case_file, row, idx, NULL,
610                                    var_get_width (pv));
611
612   g_return_val_if_fail (v, NULL);
613
614   if ( store->show_labels)
615     {
616       const gchar *label = var_lookup_value_label (pv, v);
617       if (label)
618         {
619           free (v);
620           return pspp_locale_to_utf8 (label, -1, 0);
621         }
622     }
623
624   fp = var_get_write_format (pv);
625
626   s = g_string_sized_new (fp->w + 1);
627   g_string_set_size (s, fp->w);
628
629   memset (s->str, 0, fp->w);
630
631   g_assert (fp->w == s->len);
632
633   /* Converts binary value V into printable form in the exactly
634      FP->W character in buffer S according to format specification
635      FP.  No null terminator is appended to the buffer.  */
636   data_out (v, fp, s->str);
637
638   text = pspp_locale_to_utf8 (s->str, fp->w, 0);
639   g_string_free (s, TRUE);
640
641   g_strchomp (text);
642
643   free (v);
644   return text;
645 }
646
647
648 static gboolean
649 psppire_data_store_clear_datum (GSheetModel *model,
650                                           glong row, glong col)
651 {
652   PsppireDataStore *store = PSPPIRE_DATA_STORE (model);
653
654   union value v;
655   const struct variable *pv = psppire_dict_get_variable (store->dict, col);
656
657   const gint index = var_get_case_index (pv) ;
658
659   if ( var_is_numeric (pv))
660     v.f = SYSMIS;
661   else
662     memcpy (v.s, "", MAX_SHORT_STRING);
663
664   psppire_case_file_set_value (store->case_file, row, index, &v,
665                               var_get_width (pv));
666
667   return TRUE;
668 }
669
670
671 /* Attempts to update that part of the variable store which corresponds
672    to ROW, COL with  the value TEXT.
673    Returns true if anything was updated, false otherwise.
674 */
675 gboolean
676 psppire_data_store_set_string (PsppireDataStore *store,
677                                const gchar *text, glong row, glong col)
678 {
679   glong n_cases;
680   const struct variable *pv = psppire_dict_get_variable (store->dict, col);
681   g_return_val_if_fail (pv, FALSE);
682
683   n_cases = psppire_data_store_get_case_count (store);
684
685   if ( row > n_cases)
686     return FALSE;
687
688   if (row == n_cases)
689     psppire_data_store_insert_new_case (store, row);
690
691   psppire_case_file_data_in (store->case_file, row,
692                              var_get_case_index (pv), ss_cstr (text),
693                              var_get_write_format (pv));
694
695   return TRUE;
696 }
697
698
699 void
700 psppire_data_store_set_font (PsppireDataStore *store,
701                             const PangoFontDescription *fd)
702 {
703   g_return_if_fail (store);
704   g_return_if_fail (PSPPIRE_IS_DATA_STORE (store));
705
706   store->font_desc = fd;
707 #if 0
708   store->width_of_m = calc_m_width (fd);
709 #endif
710   g_signal_emit (store, signals [FONT_CHANGED], 0);
711
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_show_labels (PsppireDataStore *store, gboolean show_labels)
720 {
721   g_return_if_fail (store);
722   g_return_if_fail (PSPPIRE_IS_DATA_STORE (store));
723
724   store->show_labels = show_labels;
725
726   g_sheet_model_range_changed (G_SHEET_MODEL (store),
727                                  -1, -1, -1, -1);
728 }
729
730
731 void
732 psppire_data_store_clear (PsppireDataStore *data_store)
733 {
734   psppire_case_file_clear (data_store->case_file);
735
736   psppire_dict_clear (data_store->dict);
737 }
738
739
740
741 /* Return a casereader made from this datastore */
742 struct casereader *
743 psppire_data_store_get_reader (PsppireDataStore *ds)
744 {
745   int i;
746   struct casereader *reader ;
747
748   for (i = 0 ; i < n_cf_signals ; ++i )
749     {
750       g_signal_handler_disconnect (ds->case_file, ds->cf_handler_id[i]);
751       ds->cf_handler_id[i] = 0 ;
752     }
753
754   if ( ds->dict )
755     for (i = 0 ; i < n_dict_signals; ++i )
756       {
757         g_signal_handler_block (ds->dict,
758                                 ds->dict_handler_id[i]);
759       }
760
761   reader = psppire_case_file_make_reader (ds->case_file);
762
763   return reader;
764 }
765
766
767
768 /* Column related funcs */
769
770
771 static const gchar null_var_name[]=N_("var");
772
773 \f
774
775 /* Row related funcs */
776
777 static gchar *
778 get_row_button_label (const GSheetModel *model, gint unit)
779 {
780   gchar *text;
781   gchar *s;
782   PsppireDataStore *ds = PSPPIRE_DATA_STORE (model);
783
784   s = g_strdup_printf (_("%d"), unit + 1);
785
786   text =  pspp_locale_to_utf8 (s, -1, 0);
787
788   g_free (s);
789
790   return text;
791 }
792
793
794 static gboolean
795 get_row_sensitivity (const GSheetModel *model, gint unit)
796 {
797   PsppireDataStore *ds = PSPPIRE_DATA_STORE (model);
798
799   return (unit < psppire_case_file_get_case_count (ds->case_file));
800 }
801
802
803 \f
804
805 /* Column related stuff */
806
807 static gchar *
808 get_column_subtitle (const GSheetModel *model, gint col)
809 {
810   gchar *text;
811   const struct variable *v ;
812   PsppireDataStore *ds = PSPPIRE_DATA_STORE (model);
813
814   if ( col >= psppire_dict_get_var_cnt (ds->dict) )
815     return NULL;
816
817   v = psppire_dict_get_variable (ds->dict, col);
818
819   if ( ! var_has_label (v))
820     return NULL;
821
822   text =  pspp_locale_to_utf8 (var_get_label (v), -1, 0);
823
824   return text;
825 }
826
827 static gchar *
828 get_column_button_label (const GSheetModel *model, gint col)
829 {
830   gchar *text;
831   struct variable *pv ;
832   PsppireDataStore *ds = PSPPIRE_DATA_STORE (model);
833
834   if ( col >= psppire_dict_get_var_cnt (ds->dict) )
835     return g_locale_to_utf8 (null_var_name, -1, 0, 0, 0);
836
837   pv = psppire_dict_get_variable (ds->dict, col);
838
839   text =  pspp_locale_to_utf8 (var_get_name (pv), -1, 0);
840
841   return text;
842 }
843
844 static gboolean
845 get_column_sensitivity (const GSheetModel *model, gint col)
846 {
847   PsppireDataStore *ds = PSPPIRE_DATA_STORE (model);
848
849   return (col < psppire_dict_get_var_cnt (ds->dict));
850 }
851
852
853
854 static GtkJustification
855 get_column_justification (const GSheetModel *model, gint col)
856 {
857   PsppireDataStore *ds = PSPPIRE_DATA_STORE (model);
858   const struct variable *pv ;
859
860   if ( col >= psppire_dict_get_var_cnt (ds->dict) )
861     return GTK_JUSTIFY_LEFT;
862
863   pv = psppire_dict_get_variable (ds->dict, col);
864
865   return (var_get_alignment (pv) == ALIGN_LEFT ? GTK_JUSTIFY_LEFT
866           : var_get_alignment (pv) == ALIGN_RIGHT ? GTK_JUSTIFY_RIGHT
867           : GTK_JUSTIFY_CENTER);
868 }
869
870