Removed unsed is_visible from sheetmodel
[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->get_foreground = NULL;
222   iface->get_background = NULL;
223   iface->get_font_desc = psppire_data_store_get_font_desc;
224   iface->get_cell_border = NULL;
225   iface->get_column_count = psppire_data_store_get_var_count;
226   iface->get_row_count = psppire_data_store_get_case_count_wrapper;
227
228   iface->get_column_subtitle = get_column_subtitle;
229   iface->get_column_title = get_column_button_label;
230   iface->get_column_sensitivity = get_column_sensitivity;
231   iface->get_column_justification = get_column_justification;
232
233   iface->get_row_title = get_row_button_label;
234   iface->get_row_sensitivity = get_row_sensitivity;
235 }
236
237 static void
238 delete_cases_callback (GtkWidget *w,
239          casenumber first, casenumber n_cases, gpointer data)
240 {
241   PsppireDataStore *store  ;
242
243   g_return_if_fail (data);
244
245   store  = PSPPIRE_DATA_STORE (data);
246
247   g_assert (first >= 0);
248
249   g_sheet_model_rows_deleted (G_SHEET_MODEL (store), first, n_cases);
250 }
251
252
253 static void
254 insert_case_callback (GtkWidget *w, casenumber casenum, gpointer data)
255 {
256   PsppireDataStore *store  = PSPPIRE_DATA_STORE (data);
257
258   g_return_if_fail (data);
259
260   g_print ("%s\n", __FUNCTION__);
261
262   g_sheet_model_range_changed (G_SHEET_MODEL (store),
263                                casenum, -1,
264                                psppire_case_file_get_case_count (store->case_file),
265                                -1);
266
267   g_sheet_model_rows_inserted (G_SHEET_MODEL (store), casenum, 1);
268 }
269
270
271 static void
272 changed_case_callback (GtkWidget *w, gint casenum, gpointer data)
273 {
274   PsppireDataStore *store  ;
275   g_return_if_fail (data);
276
277   store  = PSPPIRE_DATA_STORE (data);
278
279   g_sheet_model_range_changed (G_SHEET_MODEL (store),
280                                  casenum, -1,
281                                  casenum, -1);
282 }
283
284
285 /*
286    A callback which occurs after a variable has been deleted.
287  */
288 static void
289 delete_variable_callback (GObject *obj, gint dict_index,
290                           gint case_index, gint val_cnt,
291                           gpointer data)
292 {
293   PsppireDataStore *store  = PSPPIRE_DATA_STORE (data);
294
295 #if AXIS_TRANSITION
296   g_sheet_model_columns_deleted (G_SHEET_MODEL (store), dict_index, 1);
297
298   g_sheet_column_columns_changed (G_SHEET_COLUMN (store),
299                                    dict_index, -1);
300 #endif
301 }
302
303
304 static void
305 variable_changed_callback (GObject *obj, gint var_num, gpointer data)
306 {
307   PsppireDataStore *store  = PSPPIRE_DATA_STORE (data);
308
309 #if AXIS_TRANSITION
310   g_sheet_column_columns_changed (G_SHEET_COLUMN (store),
311                                   var_num, 1);
312
313
314   g_sheet_model_range_changed (G_SHEET_MODEL (store),
315                                -1, var_num,
316                                -1, var_num);
317 #endif
318 }
319
320 static void
321 insert_variable_callback (GObject *obj, gint var_num, gpointer data)
322 {
323   PsppireDataStore *store;
324   gint posn;
325
326   g_return_if_fail (data);
327
328   store  = PSPPIRE_DATA_STORE (data);
329
330   if ( var_num > 0 )
331     {
332       struct variable *variable =
333         psppire_dict_get_variable (store->dict, var_num);
334
335       g_assert (variable != NULL);
336
337       posn = var_get_case_index (variable);
338     }
339   else
340     {
341       posn = 0;
342     }
343
344   psppire_case_file_insert_values (store->case_file, 1, posn);
345
346 #if AXIS_TRANSITION
347   g_sheet_column_columns_changed (G_SHEET_COLUMN (store),
348                                   var_num, 1);
349 #endif
350
351   g_sheet_model_columns_inserted (G_SHEET_MODEL (store), var_num, 1);
352 }
353
354
355 static void
356 dict_size_change_callback (GObject *obj,
357                           gint posn, gint adjustment, gpointer data)
358 {
359   PsppireDataStore *store  = PSPPIRE_DATA_STORE (data);
360
361   const struct variable *v = psppire_dict_get_variable (store->dict, posn);
362
363   const gint new_val_width = value_cnt_from_width (var_get_width (v));
364
365   if ( adjustment > 0 )
366     psppire_case_file_insert_values (store->case_file, adjustment,
367                                      new_val_width - adjustment +
368                                      var_get_case_index(v));
369 }
370
371
372
373 /**
374  * psppire_data_store_new:
375  * @dict: The dictionary for this data_store.
376  *
377  *
378  * Return value: a new #PsppireDataStore
379  **/
380 PsppireDataStore *
381 psppire_data_store_new (PsppireDict *dict)
382 {
383   PsppireDataStore *retval;
384
385   retval = g_object_new (GTK_TYPE_DATA_STORE, NULL);
386
387   psppire_data_store_set_dictionary (retval, dict);
388
389   return retval;
390 }
391
392
393 void
394 psppire_data_store_set_case_file (PsppireDataStore *ds,
395                                   PsppireCaseFile *cf)
396 {
397   gint i;
398   if ( ds->case_file)  g_object_unref (ds->case_file);
399   ds->case_file = cf;
400
401   g_sheet_model_range_changed (G_SHEET_MODEL (ds),
402                                -1, -1, -1, -1);
403
404   for (i = 0 ; i < n_cf_signals ; ++i )
405     {
406       if ( ds->cf_handler_id [i] > 0 )
407         g_signal_handler_disconnect (ds->case_file,
408                                      ds->cf_handler_id[i]);
409     }
410
411
412   if ( ds->dict )
413     for (i = 0 ; i < n_dict_signals; ++i )
414       {
415         if ( ds->dict_handler_id [i] > 0)
416           {
417             g_signal_handler_unblock (ds->dict,
418                                       ds->dict_handler_id[i]);
419           }
420       }
421
422   ds->cf_handler_id [CASES_DELETED] =
423     g_signal_connect (ds->case_file, "cases-deleted",
424                       G_CALLBACK (delete_cases_callback),
425                       ds);
426
427   ds->cf_handler_id [CASE_INSERTED] =
428     g_signal_connect (ds->case_file, "case-inserted",
429                       G_CALLBACK (insert_case_callback),
430                       ds);
431
432   ds->cf_handler_id [CASE_CHANGED] =
433     g_signal_connect (ds->case_file, "case-changed",
434                       G_CALLBACK (changed_case_callback),
435                       ds);
436
437   g_signal_emit (ds, signals[BACKEND_CHANGED], 0);
438 }
439
440
441 /**
442  * psppire_data_store_replace_set_dictionary:
443  * @data_store: The variable store
444  * @dict: The dictionary to set
445  *
446  * If a dictionary is already associated with the data-store, then it will be
447  * destroyed.
448  **/
449 void
450 psppire_data_store_set_dictionary (PsppireDataStore *data_store, PsppireDict *dict)
451 {
452   int i;
453
454   /* Disconnect any existing handlers */
455   if ( data_store->dict )
456     for (i = 0 ; i < n_dict_signals; ++i )
457       {
458         g_signal_handler_disconnect (data_store->dict,
459                                      data_store->dict_handler_id[i]);
460       }
461
462   data_store->dict = dict;
463
464   if ( dict != NULL)
465     {
466
467       data_store->dict_handler_id [VARIABLE_INSERTED] =
468         g_signal_connect (dict, "variable-inserted",
469                           G_CALLBACK (insert_variable_callback),
470                           data_store);
471
472       data_store->dict_handler_id [VARIABLE_DELETED] =
473         g_signal_connect (dict, "variable-deleted",
474                           G_CALLBACK (delete_variable_callback),
475                           data_store);
476
477       data_store->dict_handler_id [VARIABLE_CHANGED] =
478         g_signal_connect (dict, "variable-changed",
479                           G_CALLBACK (variable_changed_callback),
480                           data_store);
481
482       data_store->dict_handler_id [SIZE_CHANGED] =
483         g_signal_connect (dict, "dict-size-changed",
484                           G_CALLBACK (dict_size_change_callback),
485                           data_store);
486     }
487
488
489
490   /* The entire model has changed */
491   g_sheet_model_range_changed (G_SHEET_MODEL (data_store), -1, -1, -1, -1);
492
493 #if AXIS_TRANSITION
494   g_sheet_column_columns_changed (G_SHEET_COLUMN (data_store), 0, -1);
495 #endif
496
497   if ( data_store->dict )
498     for (i = 0 ; i < n_dict_signals; ++i )
499       {
500         if ( data_store->dict_handler_id [i] > 0)
501           {
502             g_signal_handler_block (data_store->dict,
503                                     data_store->dict_handler_id[i]);
504           }
505       }
506 }
507
508 static void
509 psppire_data_store_finalize (GObject *object)
510 {
511
512   /* must chain up */
513   (* parent_class->finalize) (object);
514 }
515
516
517 static void
518 psppire_data_store_dispose (GObject *object)
519 {
520   PsppireDataStore *ds = PSPPIRE_DATA_STORE (object);
521
522   if (ds->dispose_has_run)
523     return;
524
525   if (ds->case_file) g_object_unref (ds->case_file);
526
527   /* must chain up */
528   (* parent_class->dispose) (object);
529
530   ds->dispose_has_run = TRUE;
531 }
532
533
534 gboolean
535 psppire_data_store_delete_cases (PsppireDataStore *ds,
536                                  casenumber first, casenumber count)
537 {
538   g_return_val_if_fail (ds, FALSE);
539
540   return psppire_case_file_delete_cases (ds->case_file, count, first);
541 }
542
543
544
545 /* Insert a blank case before POSN */
546 gboolean
547 psppire_data_store_insert_new_case (PsppireDataStore *ds, casenumber posn)
548 {
549   gboolean result;
550   gint val_cnt, v;
551   struct ccase cc;
552   g_return_val_if_fail (ds, FALSE);
553
554   val_cnt = datasheet_get_column_cnt (ds->case_file->datasheet) ;
555
556   g_return_val_if_fail (val_cnt > 0, FALSE);
557
558   g_return_val_if_fail (posn <= psppire_data_store_get_case_count (ds), FALSE);
559
560   case_create (&cc, val_cnt);
561
562   memset ( case_data_rw_idx (&cc, 0), 0, val_cnt * MAX_SHORT_STRING);
563
564   for (v = 0 ; v < psppire_dict_get_var_cnt (ds->dict) ; ++v)
565     {
566       const struct variable *pv = psppire_dict_get_variable (ds->dict, v);
567       if ( var_is_alpha (pv))
568         continue;
569
570       case_data_rw (&cc, pv)->f = SYSMIS;
571     }
572
573   result = psppire_case_file_insert_case (ds->case_file, &cc, posn);
574
575   case_destroy (&cc);
576
577   return result;
578 }
579
580
581 gchar *
582 psppire_data_store_get_string (PsppireDataStore *store, glong row, glong column)
583 {
584   gint idx;
585   char *text;
586   const struct fmt_spec *fp ;
587   const struct variable *pv ;
588   union value *v ;
589   GString *s;
590
591   g_return_val_if_fail (store->dict, NULL);
592   g_return_val_if_fail (store->case_file, NULL);
593
594   if (column >= psppire_dict_get_var_cnt (store->dict))
595     return NULL;
596
597   if ( row >= psppire_case_file_get_case_count (store->case_file))
598     return NULL;
599
600   pv = psppire_dict_get_variable (store->dict, column);
601
602   g_assert (pv);
603
604   idx = var_get_case_index (pv);
605
606   g_assert (idx >= 0);
607
608   v = psppire_case_file_get_value (store->case_file, row, idx, NULL,
609                                    var_get_width (pv));
610
611   g_return_val_if_fail (v, NULL);
612
613   if ( store->show_labels)
614     {
615       const gchar *label = var_lookup_value_label (pv, v);
616       if (label)
617         {
618           free (v);
619           return pspp_locale_to_utf8 (label, -1, 0);
620         }
621     }
622
623   fp = var_get_write_format (pv);
624
625   s = g_string_sized_new (fp->w + 1);
626   g_string_set_size (s, fp->w);
627
628   memset (s->str, 0, fp->w);
629
630   g_assert (fp->w == s->len);
631
632   /* Converts binary value V into printable form in the exactly
633      FP->W character in buffer S according to format specification
634      FP.  No null terminator is appended to the buffer.  */
635   data_out (v, fp, s->str);
636
637   text = pspp_locale_to_utf8 (s->str, fp->w, 0);
638   g_string_free (s, TRUE);
639
640   g_strchomp (text);
641
642   free (v);
643   return text;
644 }
645
646
647 static gboolean
648 psppire_data_store_clear_datum (GSheetModel *model,
649                                           glong row, glong col)
650 {
651   PsppireDataStore *store = PSPPIRE_DATA_STORE (model);
652
653   union value v;
654   const struct variable *pv = psppire_dict_get_variable (store->dict, col);
655
656   const gint index = var_get_case_index (pv) ;
657
658   if ( var_is_numeric (pv))
659     v.f = SYSMIS;
660   else
661     memcpy (v.s, "", MAX_SHORT_STRING);
662
663   psppire_case_file_set_value (store->case_file, row, index, &v,
664                               var_get_width (pv));
665
666   return TRUE;
667 }
668
669
670 /* Attempts to update that part of the variable store which corresponds
671    to ROW, COL with  the value TEXT.
672    Returns true if anything was updated, false otherwise.
673 */
674 gboolean
675 psppire_data_store_set_string (PsppireDataStore *store,
676                                const gchar *text, glong row, glong col)
677 {
678   glong n_cases;
679   const struct variable *pv = psppire_dict_get_variable (store->dict, col);
680   g_return_val_if_fail (pv, FALSE);
681
682   n_cases = psppire_data_store_get_case_count (store);
683
684   if ( row > n_cases)
685     return FALSE;
686
687   if (row == n_cases)
688     psppire_data_store_insert_new_case (store, row);
689
690   psppire_case_file_data_in (store->case_file, row,
691                              var_get_case_index (pv), ss_cstr (text),
692                              var_get_write_format (pv));
693
694   return TRUE;
695 }
696
697
698 void
699 psppire_data_store_set_font (PsppireDataStore *store,
700                             const PangoFontDescription *fd)
701 {
702   g_return_if_fail (store);
703   g_return_if_fail (PSPPIRE_IS_DATA_STORE (store));
704
705   store->font_desc = fd;
706 #if 0
707   store->width_of_m = calc_m_width (fd);
708 #endif
709   g_signal_emit (store, signals [FONT_CHANGED], 0);
710
711
712   g_sheet_model_range_changed (G_SHEET_MODEL (store),
713                                  -1, -1, -1, -1);
714 }
715
716
717 void
718 psppire_data_store_show_labels (PsppireDataStore *store, gboolean show_labels)
719 {
720   g_return_if_fail (store);
721   g_return_if_fail (PSPPIRE_IS_DATA_STORE (store));
722
723   store->show_labels = show_labels;
724
725   g_sheet_model_range_changed (G_SHEET_MODEL (store),
726                                  -1, -1, -1, -1);
727 }
728
729
730 void
731 psppire_data_store_clear (PsppireDataStore *data_store)
732 {
733   psppire_case_file_clear (data_store->case_file);
734
735   psppire_dict_clear (data_store->dict);
736 }
737
738
739
740 /* Return a casereader made from this datastore */
741 struct casereader *
742 psppire_data_store_get_reader (PsppireDataStore *ds)
743 {
744   int i;
745   struct casereader *reader ;
746
747   for (i = 0 ; i < n_cf_signals ; ++i )
748     {
749       g_signal_handler_disconnect (ds->case_file, ds->cf_handler_id[i]);
750       ds->cf_handler_id[i] = 0 ;
751     }
752
753   if ( ds->dict )
754     for (i = 0 ; i < n_dict_signals; ++i )
755       {
756         g_signal_handler_block (ds->dict,
757                                 ds->dict_handler_id[i]);
758       }
759
760   reader = psppire_case_file_make_reader (ds->case_file);
761
762   return reader;
763 }
764
765
766
767 /* Column related funcs */
768
769
770 static const gchar null_var_name[]=N_("var");
771
772 \f
773
774 /* Row related funcs */
775
776 static gchar *
777 get_row_button_label (const GSheetModel *model, gint unit)
778 {
779   gchar *text;
780   gchar *s;
781   PsppireDataStore *ds = PSPPIRE_DATA_STORE (model);
782
783   s = g_strdup_printf (_("%d"), unit + 1);
784
785   text =  pspp_locale_to_utf8 (s, -1, 0);
786
787   g_free (s);
788
789   return text;
790 }
791
792
793 static gboolean
794 get_row_sensitivity (const GSheetModel *model, gint unit)
795 {
796   PsppireDataStore *ds = PSPPIRE_DATA_STORE (model);
797
798   return (unit < psppire_case_file_get_case_count (ds->case_file));
799 }
800
801
802 \f
803
804 /* Column related stuff */
805
806 static gchar *
807 get_column_subtitle (const GSheetModel *model, gint col)
808 {
809   gchar *text;
810   const struct variable *v ;
811   PsppireDataStore *ds = PSPPIRE_DATA_STORE (model);
812
813   if ( col >= psppire_dict_get_var_cnt (ds->dict) )
814     return NULL;
815
816   v = psppire_dict_get_variable (ds->dict, col);
817
818   if ( ! var_has_label (v))
819     return NULL;
820
821   text =  pspp_locale_to_utf8 (var_get_label (v), -1, 0);
822
823   return text;
824 }
825
826 static gchar *
827 get_column_button_label (const GSheetModel *model, gint col)
828 {
829   gchar *text;
830   struct variable *pv ;
831   PsppireDataStore *ds = PSPPIRE_DATA_STORE (model);
832
833   if ( col >= psppire_dict_get_var_cnt (ds->dict) )
834     return g_locale_to_utf8 (null_var_name, -1, 0, 0, 0);
835
836   pv = psppire_dict_get_variable (ds->dict, col);
837
838   text =  pspp_locale_to_utf8 (var_get_name (pv), -1, 0);
839
840   return text;
841 }
842
843 static gboolean
844 get_column_sensitivity (const GSheetModel *model, gint col)
845 {
846   PsppireDataStore *ds = PSPPIRE_DATA_STORE (model);
847
848   return (col < psppire_dict_get_var_cnt (ds->dict));
849 }
850
851
852
853 static GtkJustification
854 get_column_justification (const GSheetModel *model, gint col)
855 {
856   PsppireDataStore *ds = PSPPIRE_DATA_STORE (model);
857   const struct variable *pv ;
858
859   if ( col >= psppire_dict_get_var_cnt (ds->dict) )
860     return GTK_JUSTIFY_LEFT;
861
862   pv = psppire_dict_get_variable (ds->dict, col);
863
864   return (var_get_alignment (pv) == ALIGN_LEFT ? GTK_JUSTIFY_LEFT
865           : var_get_alignment (pv) == ALIGN_RIGHT ? GTK_JUSTIFY_RIGHT
866           : GTK_JUSTIFY_CENTER);
867 }
868
869