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