Use new sheet in var-sheet
[pspp] / src / ui / gui / psppire-dict.c
1 /* PSPPIRE - a graphical user interface for PSPP.
2    Copyright (C) 2004, 2006, 2007, 2009, 2010, 2011, 2012  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
19 #include "ui/gui/psppire-dict.h"
20
21 #include <string.h>
22 #include <stdlib.h>
23 #include <gtk/gtk.h>
24
25 #include "data/dictionary.h"
26 #include "data/identifier.h"
27 #include "data/missing-values.h"
28 #include "data/value-labels.h"
29 #include "data/variable.h"
30 #include "libpspp/i18n.h"
31 #include "libpspp/message.h"
32 #include "ui/gui/helper.h"
33 #include "ui/gui/psppire-marshal.h"
34 #include "ui/gui/psppire-var-ptr.h"
35
36 #include "ui/gui/efficient-sheet/jmd-datum.h"
37
38
39 #include <gettext.h>
40 #define _(msgid) gettext (msgid)
41 #define N_(msgid) msgid
42
43 enum  {
44   BACKEND_CHANGED,
45
46   VARIABLE_CHANGED,
47   VARIABLE_INSERTED,
48   VARIABLE_DELETED,
49
50   WEIGHT_CHANGED,
51   FILTER_CHANGED,
52   SPLIT_CHANGED,
53   n_SIGNALS
54 };
55
56
57 /* --- prototypes --- */
58 static void psppire_dict_class_init     (PsppireDictClass       *class);
59 static void psppire_dict_init   (PsppireDict            *dict);
60 static void psppire_dict_dispose        (GObject                *object);
61
62 static void dictionary_tree_model_init (GtkTreeModelIface *iface);
63
64
65
66 static guint
67 gni (GListModel *list)
68 {
69   PsppireDict *dict = PSPPIRE_DICT (list);
70
71   return psppire_dict_get_var_cnt (dict);
72 }
73
74 static GType
75 git (GListModel *list)
76 {
77   return JMD_TYPE_DATUM;
78 }
79
80 static gpointer
81 gi (GListModel *list, guint id)
82 {
83   JmdDatum *gd = JMD_DATUM (g_object_new (JMD_TYPE_DATUM, NULL));
84
85   PsppireDict *dict = PSPPIRE_DICT (list);
86   
87   if (id >= psppire_dict_get_var_cnt (dict))
88     {
89       gd->text = g_strdup (_("Var"));
90     }
91   else
92     {
93       const struct variable *v =  psppire_dict_get_variable (dict, id);
94
95       gd->text = g_strdup (var_get_name (v));
96       gd->label = g_strdup (var_get_label (v));
97     }
98
99   return gd;
100 }
101
102
103 static void
104 jmd_init_iface (GListModelInterface *iface)
105 {
106   iface->get_n_items = gni;
107   iface->get_item = gi;
108   iface->get_item_type = git;
109 }
110
111
112 /* --- variables --- */
113 static GObjectClass     *parent_class = NULL;
114
115 static guint signals [n_SIGNALS];
116
117 /* --- functions --- */
118 /**
119  * psppire_dict_get_type:
120  * @returns: the type ID for accelerator groups.
121  */
122 GType
123 psppire_dict_get_type (void)
124 {
125   static GType object_type = 0;
126
127   if (!object_type)
128     {
129       static const GTypeInfo object_info = {
130         sizeof (PsppireDictClass),
131         (GBaseInitFunc) NULL,
132         (GBaseFinalizeFunc) NULL,
133         (GClassInitFunc) psppire_dict_class_init,
134         NULL,   /* class_finalize */
135         NULL,   /* class_data */
136         sizeof (PsppireDict),
137         0,      /* n_preallocs */
138         (GInstanceInitFunc) psppire_dict_init,
139       };
140
141       static const GInterfaceInfo tree_model_info = {
142         (GInterfaceInitFunc) dictionary_tree_model_init,
143         NULL,
144         NULL
145       };
146
147       static const GInterfaceInfo list_model_info = {
148         (GInterfaceInitFunc) jmd_init_iface,
149         NULL,
150         NULL
151       };
152
153       object_type = g_type_register_static (G_TYPE_OBJECT,
154                                             "PsppireDict",
155                                             &object_info, 0);
156       
157       g_type_add_interface_static (object_type, GTK_TYPE_TREE_MODEL,
158                                    &tree_model_info);
159
160       g_type_add_interface_static (object_type, G_TYPE_LIST_MODEL,
161                                    &list_model_info);
162     }
163
164   return object_type;
165 }
166
167
168 static void
169 psppire_dict_class_init (PsppireDictClass *class)
170 {
171   GObjectClass *object_class = G_OBJECT_CLASS (class);
172
173   parent_class = g_type_class_peek_parent (class);
174
175   object_class->dispose = psppire_dict_dispose;
176
177   signals [BACKEND_CHANGED] =
178     g_signal_new ("backend-changed",
179                   G_TYPE_FROM_CLASS (class),
180                   G_SIGNAL_RUN_FIRST,
181                   0,
182                   NULL, NULL,
183                   g_cclosure_marshal_VOID__VOID,
184                   G_TYPE_NONE,
185                   0);
186
187
188   signals [VARIABLE_CHANGED] =
189     g_signal_new ("variable-changed",
190                   G_TYPE_FROM_CLASS (class),
191                   G_SIGNAL_RUN_FIRST,
192                   0,
193                   NULL, NULL,
194                   psppire_marshal_VOID__INT_UINT_POINTER,
195                   G_TYPE_NONE,
196                   3,
197                   G_TYPE_INT,
198                   G_TYPE_UINT,
199                   G_TYPE_POINTER
200                   );
201
202
203
204   signals [VARIABLE_INSERTED] =
205     g_signal_new ("variable-inserted",
206                   G_TYPE_FROM_CLASS (class),
207                   G_SIGNAL_RUN_FIRST,
208                   0,
209                   NULL, NULL,
210                   g_cclosure_marshal_VOID__INT,
211                   G_TYPE_NONE,
212                   1,
213                   G_TYPE_INT);
214
215
216   signals [VARIABLE_DELETED] =
217     g_signal_new ("variable-deleted",
218                   G_TYPE_FROM_CLASS (class),
219                   G_SIGNAL_RUN_FIRST,
220                   0,
221                   NULL, NULL,
222                   psppire_marshal_VOID__POINTER_INT_INT,
223                   G_TYPE_NONE,
224                   3,
225                   G_TYPE_POINTER,
226                   G_TYPE_INT,
227                   G_TYPE_INT);
228
229
230   signals [WEIGHT_CHANGED] =
231     g_signal_new ("weight-changed",
232                   G_TYPE_FROM_CLASS (class),
233                   G_SIGNAL_RUN_FIRST,
234                   0,
235                   NULL, NULL,
236                   g_cclosure_marshal_VOID__INT,
237                   G_TYPE_NONE,
238                   1,
239                   G_TYPE_INT);
240
241
242   signals [FILTER_CHANGED] =
243     g_signal_new ("filter-changed",
244                   G_TYPE_FROM_CLASS (class),
245                   G_SIGNAL_RUN_FIRST,
246                   0,
247                   NULL, NULL,
248                   g_cclosure_marshal_VOID__INT,
249                   G_TYPE_NONE,
250                   1,
251                   G_TYPE_INT);
252
253
254   signals [SPLIT_CHANGED] =
255     g_signal_new ("split-changed",
256                   G_TYPE_FROM_CLASS (class),
257                   G_SIGNAL_RUN_FIRST,
258                   0,
259                   NULL, NULL,
260                   g_cclosure_marshal_VOID__VOID,
261                   G_TYPE_NONE,
262                   0);
263 }
264
265 static void
266 psppire_dict_dispose (GObject *object)
267 {
268   PsppireDict *d = PSPPIRE_DICT (object);
269
270   dict_set_callbacks (d->dict, NULL, NULL);
271
272   G_OBJECT_CLASS (parent_class)->dispose (object);
273 }
274
275 /* Pass on callbacks from src/data/dictionary, as
276    signals in the Gtk library */
277 static void
278 addcb (struct dictionary *d, int idx, void *pd)
279 {
280   PsppireDict *dict = PSPPIRE_DICT (pd);
281
282   if ( ! dict->disable_insert_signal)
283     g_signal_emit (dict, signals [VARIABLE_INSERTED], 0, idx);
284 }
285
286 static void
287 delcb (struct dictionary *d, const struct variable *var,
288        int dict_idx, int case_idx, void *pd)
289 {
290   g_signal_emit (pd, signals [VARIABLE_DELETED], 0,
291                  var, dict_idx, case_idx);
292 }
293
294 static void
295 mutcb (struct dictionary *d, int idx, unsigned int what, const struct variable *oldvar, void *pd)
296 {
297   g_signal_emit (pd, signals [VARIABLE_CHANGED], 0, idx, what, oldvar);
298 }
299
300 static void
301 weight_changed_callback (struct dictionary *d, int idx, void *pd)
302 {
303   g_signal_emit (pd, signals [WEIGHT_CHANGED], 0, idx);
304 }
305
306 static void
307 filter_changed_callback (struct dictionary *d, int idx, void *pd)
308 {
309   g_signal_emit (pd, signals [FILTER_CHANGED], 0, idx);
310 }
311
312 static void
313 split_changed_callback (struct dictionary *d, void *pd)
314 {
315   g_signal_emit (pd, signals [SPLIT_CHANGED], 0);
316 }
317
318 static const struct dict_callbacks gui_callbacks =
319   {
320     addcb,
321     delcb,
322     mutcb,
323     weight_changed_callback,
324     filter_changed_callback,
325     split_changed_callback
326   };
327
328 static void
329 psppire_dict_init (PsppireDict *psppire_dict)
330 {
331   psppire_dict->stamp = g_random_int ();
332   psppire_dict->disable_insert_signal = FALSE;
333 }
334
335 /**
336  * psppire_dict_new_from_dict:
337  * @returns: a new #PsppireDict object
338  *
339  * Creates a new #PsppireDict.
340  */
341 PsppireDict*
342 psppire_dict_new_from_dict (struct dictionary *d)
343 {
344   PsppireDict *new_dict = g_object_new (PSPPIRE_TYPE_DICT, NULL);
345   new_dict->dict = d;
346
347   dict_set_callbacks (new_dict->dict, &gui_callbacks, new_dict);
348
349   return new_dict;
350 }
351
352
353 void
354 psppire_dict_replace_dictionary (PsppireDict *dict, struct dictionary *d)
355 {
356   struct variable *var =  dict_get_weight (d);
357
358   dict->dict = d;
359
360   weight_changed_callback (d, var ? var_get_dict_index (var) : -1, dict);
361
362   var = dict_get_filter (d);
363   filter_changed_callback (d, var ? var_get_dict_index (var) : -1, dict);
364
365   split_changed_callback (d, dict);
366
367   dict_set_callbacks (dict->dict, &gui_callbacks, dict);
368
369   g_signal_emit (dict, signals [BACKEND_CHANGED], 0);
370 }
371
372
373 /* Stores a valid name for a new variable in DICT into the SIZE bytes in NAME.
374    Returns true if successful, false if SIZE is insufficient. */
375 bool
376 psppire_dict_generate_name (const PsppireDict *dict, char *name, size_t size)
377 {
378   gint d;
379
380   for (d = 1; ; d++)
381     {
382       int len;
383
384       /* TRANSLATORS: This string must be a valid variable name.  That means:
385          - The string must be at most 64 bytes (not characters) long.
386          - The string may not contain whitespace.
387          - The first character may not be '$'
388          - The first character may not be a digit
389          - The final charactor may not be '.' or '_'
390       */
391       len = snprintf (name, size, _("Var%04d"), d);
392       if (len + 1 >= size)
393         return false;
394
395       if (psppire_dict_lookup_var (dict, name) == NULL)
396         return true;
397     }
398
399   return name;
400 }
401
402 /* Insert a new variable at posn IDX, with the name NAME, and return the
403    new variable.
404    If NAME is null, then a name will be automatically assigned.
405 */
406 struct variable *
407 psppire_dict_insert_variable (PsppireDict *d, gint idx, const gchar *name)
408 {
409   struct variable *var;
410   char tmpname[64];
411
412   g_return_val_if_fail (idx >= 0, NULL);
413   g_return_val_if_fail (d, NULL);
414   g_return_val_if_fail (PSPPIRE_IS_DICT (d), NULL);
415
416   if (name == NULL)
417     {
418       if (!psppire_dict_generate_name (d, tmpname, sizeof tmpname))
419         g_return_val_if_reached (NULL);
420
421       name = tmpname;
422     }
423
424   d->disable_insert_signal = TRUE;
425
426   var = dict_create_var (d->dict, name, 0);
427
428   dict_reorder_var (d->dict, var, idx);
429
430   d->disable_insert_signal = FALSE;
431
432   g_signal_emit (d, signals[VARIABLE_INSERTED], 0, idx);
433
434   return var;
435 }
436
437 /* Delete N variables beginning at FIRST */
438 void
439 psppire_dict_delete_variables (PsppireDict *d, gint first, gint n)
440 {
441   gint idx;
442   g_return_if_fail (d);
443   g_return_if_fail (d->dict);
444   g_return_if_fail (PSPPIRE_IS_DICT (d));
445
446   for (idx = 0 ; idx < n ; ++idx )
447     {
448       struct variable *var;
449
450       /* Do nothing if it's out of bounds */
451       if ( first >= dict_get_var_cnt (d->dict))
452         break;
453
454       var = dict_get_var (d->dict, first);
455       dict_delete_var (d->dict, var);
456     }
457 }
458
459
460 gboolean
461 psppire_dict_set_name (PsppireDict* d, gint idx, const gchar *name)
462 {
463   struct variable *var;
464   g_assert (d);
465   g_assert (PSPPIRE_IS_DICT (d));
466
467   if ( ! dict_id_is_valid (d->dict, name, false))
468     return FALSE;
469
470   if ( idx < dict_get_var_cnt (d->dict))
471     {
472       /* This is an existing variable? */
473       var = dict_get_var (d->dict, idx);
474       dict_rename_var (d->dict, var, name);
475     }
476   else
477     {
478       /* new variable */
479       dict_create_var (d->dict, name, 0);
480     }
481
482   return TRUE;
483 }
484
485
486
487 /* Return the IDXth variable.
488    Will return NULL if IDX  exceeds the number of variables in the dictionary.
489  */
490 struct variable *
491 psppire_dict_get_variable (const PsppireDict *d, gint idx)
492 {
493   g_return_val_if_fail (d, NULL);
494   g_return_val_if_fail (d->dict, NULL);
495
496   if ( dict_get_var_cnt (d->dict) <= idx )
497     return NULL;
498
499   return dict_get_var (d->dict, idx);
500 }
501
502
503 /* Return the number of variables in the dictionary */
504 gint
505 psppire_dict_get_var_cnt (const PsppireDict *d)
506 {
507   g_return_val_if_fail (d, -1);
508   g_return_val_if_fail (d->dict, -1);
509
510   return dict_get_var_cnt (d->dict);
511 }
512
513
514 /* Return the number of `union value's in the dictionary */
515 size_t
516 psppire_dict_get_value_cnt (const PsppireDict *d)
517 {
518   g_return_val_if_fail (d, -1);
519   g_return_val_if_fail (d->dict, -1);
520
521   return dict_get_next_value_idx (d->dict);
522 }
523
524
525 /* Returns the prototype for the cases that match the dictionary */
526 const struct caseproto *
527 psppire_dict_get_proto (const PsppireDict *d)
528 {
529   g_return_val_if_fail (d, NULL);
530   g_return_val_if_fail (d->dict, NULL);
531
532   return dict_get_proto (d->dict);
533 }
534
535
536 /* Return a variable by name.
537    Return NULL if it doesn't exist
538 */
539 struct variable *
540 psppire_dict_lookup_var (const PsppireDict *d, const gchar *name)
541 {
542   g_return_val_if_fail (d, NULL);
543   g_return_val_if_fail (d->dict, NULL);
544
545   return dict_lookup_var (d->dict, name);
546 }
547
548 /* Clears the contents of D */
549 void
550 psppire_dict_clear (PsppireDict *d)
551 {
552   g_return_if_fail (d);
553   g_return_if_fail (d->dict);
554
555   {
556     dict_clear (d->dict);
557   }
558 }
559
560
561 /* Return true is NAME would be a valid name of a variable to add to the
562    dictionary.  False otherwise.
563    If REPORT is true, then invalid names will be reported as such as errors
564 */
565 gboolean
566 psppire_dict_check_name (const PsppireDict *dict,
567                          const gchar *name, gboolean report)
568 {
569   if ( ! dict_id_is_valid (dict->dict, name, report ) )
570     return FALSE;
571
572   if (psppire_dict_lookup_var (dict, name))
573     {
574       if ( report )
575         msg (ME, _("Duplicate variable name."));
576       return FALSE;
577     }
578
579   return TRUE;
580 }
581
582
583 gint
584 psppire_dict_get_next_value_idx (const PsppireDict *dict)
585 {
586   return dict_get_next_value_idx (dict->dict);
587 }
588
589
590 /* Tree Model Stuff */
591
592 static GtkTreeModelFlags tree_model_get_flags (GtkTreeModel *model);
593
594 static gint tree_model_n_columns (GtkTreeModel *model);
595
596 static GType tree_model_column_type (GtkTreeModel *model, gint index);
597
598 static gboolean tree_model_get_iter (GtkTreeModel *model, GtkTreeIter *iter,
599                                      GtkTreePath *path);
600
601 static gboolean tree_model_iter_next (GtkTreeModel *model, GtkTreeIter *iter);
602
603 static GtkTreePath * tree_model_get_path (GtkTreeModel *model,
604                                           GtkTreeIter *iter);
605
606 static void tree_model_get_value (GtkTreeModel *model, GtkTreeIter *iter,
607                                   gint column, GValue *value);
608
609 static gboolean tree_model_nth_child (GtkTreeModel *model, GtkTreeIter *iter,
610                                       GtkTreeIter *parent, gint n);
611
612 static gint tree_model_n_children (GtkTreeModel *tree_model,
613                                    GtkTreeIter  *iter);
614
615 static gboolean tree_model_iter_children (GtkTreeModel *,
616                                           GtkTreeIter *,
617                                           GtkTreeIter *);
618
619 static gboolean tree_model_iter_parent (GtkTreeModel *tree_model,
620                                         GtkTreeIter *iter,
621                                         GtkTreeIter *child);
622
623 static gboolean tree_model_iter_has_child  (GtkTreeModel *tree_model,
624                                             GtkTreeIter  *iter);
625
626 static void
627 dictionary_tree_model_init (GtkTreeModelIface *iface)
628 {
629   iface->get_flags = tree_model_get_flags;
630   iface->get_n_columns = tree_model_n_columns;
631   iface->get_column_type = tree_model_column_type;
632   iface->get_iter = tree_model_get_iter;
633   iface->iter_next = tree_model_iter_next;
634   iface->get_path = tree_model_get_path;
635   iface->get_value = tree_model_get_value;
636
637   iface->iter_children = tree_model_iter_children ;
638   iface->iter_has_child = tree_model_iter_has_child ;
639   iface->iter_n_children = tree_model_n_children ;
640   iface->iter_nth_child = tree_model_nth_child ;
641   iface->iter_parent = tree_model_iter_parent ;
642 }
643
644 static gboolean
645 tree_model_iter_has_child  (GtkTreeModel *tree_model,
646                             GtkTreeIter  *iter)
647 {
648   return FALSE;
649 }
650
651 static gboolean
652 tree_model_iter_parent (GtkTreeModel *tree_model,
653                         GtkTreeIter *iter,
654                         GtkTreeIter *child)
655 {
656   return TRUE;
657 }
658
659 static GtkTreeModelFlags
660 tree_model_get_flags (GtkTreeModel *model)
661 {
662   g_return_val_if_fail (PSPPIRE_IS_DICT (model), (GtkTreeModelFlags) 0);
663
664   return GTK_TREE_MODEL_LIST_ONLY;
665 }
666
667
668 static gint
669 tree_model_n_columns (GtkTreeModel *model)
670 {
671   return n_DICT_COLS;
672 }
673
674 static GType
675 tree_model_column_type (GtkTreeModel *model, gint index)
676 {
677   g_return_val_if_fail (PSPPIRE_IS_DICT (model), (GType) 0);
678
679   switch (index)
680     {
681     case DICT_TVM_COL_NAME:
682       return G_TYPE_STRING;
683       break;
684     case DICT_TVM_COL_VAR:
685       return PSPPIRE_VAR_PTR_TYPE;
686       break;
687     case DICT_TVM_COL_LABEL:
688       return G_TYPE_STRING;
689       break;
690     default:
691       g_return_val_if_reached ((GType)0);
692       break;
693     }
694
695   g_assert_not_reached ();
696   return ((GType)0);
697 }
698
699 static gboolean
700 tree_model_get_iter (GtkTreeModel *model, GtkTreeIter *iter, GtkTreePath *path)
701 {
702   gint *indices, depth;
703   gint n;
704   struct variable *var;
705
706   PsppireDict *dict = PSPPIRE_DICT (model);
707
708   g_return_val_if_fail (path, FALSE);
709
710   indices = gtk_tree_path_get_indices (path);
711   depth = gtk_tree_path_get_depth (path);
712
713   g_return_val_if_fail (depth == 1, FALSE);
714
715   n = indices [0];
716
717   if ( n < 0 || n >= psppire_dict_get_var_cnt (dict))
718     {
719       iter->stamp = 0;
720       iter->user_data = NULL;
721       return FALSE;
722     }
723
724   var = psppire_dict_get_variable (dict, n);
725
726   g_assert (var_get_dict_index (var) == n);
727
728   iter->stamp = dict->stamp;
729   iter->user_data = var;
730
731   return TRUE;
732 }
733
734
735 static gboolean
736 tree_model_iter_next (GtkTreeModel *model, GtkTreeIter *iter)
737 {
738   PsppireDict *dict = PSPPIRE_DICT (model);
739   struct variable *var;
740   gint idx;
741
742   g_return_val_if_fail (iter->stamp == dict->stamp, FALSE);
743
744   if ( iter == NULL || iter->user_data == NULL)
745     return FALSE;
746
747   var = iter->user_data;
748
749   idx = var_get_dict_index (var);
750
751   if ( idx + 1 >= psppire_dict_get_var_cnt (dict))
752     {
753       iter->user_data = NULL;
754       iter->stamp = 0;
755       return FALSE;
756     }
757
758   var = psppire_dict_get_variable (dict, idx + 1);
759
760   g_assert (var_get_dict_index (var) == idx + 1);
761
762   iter->user_data = var;
763
764   return TRUE;
765 }
766
767 static GtkTreePath *
768 tree_model_get_path (GtkTreeModel *model, GtkTreeIter *iter)
769 {
770   GtkTreePath *path;
771   struct variable *var;
772   PsppireDict *dict = PSPPIRE_DICT (model);
773
774   g_return_val_if_fail (iter->stamp == dict->stamp, FALSE);
775
776   var = iter->user_data;
777
778   path = gtk_tree_path_new ();
779   gtk_tree_path_append_index (path, var_get_dict_index (var));
780
781   return path;
782 }
783
784 const struct fmt_spec *var_get_write_format (const struct variable *);
785
786 static void
787 tree_model_get_value (GtkTreeModel *model, GtkTreeIter *iter,
788                       gint column, GValue *value)
789 {
790   struct variable *var;
791   PsppireDict *dict = PSPPIRE_DICT (model);
792
793   g_return_if_fail (iter->stamp == dict->stamp);
794
795   var = iter->user_data;
796
797   const struct fmt_spec *fs = var_get_write_format (var);
798   
799   switch (column)
800     {
801     case DICT_TVM_COL_NAME:
802       g_value_init (value, G_TYPE_STRING);
803       g_value_set_string (value, var_get_name (var));
804       break;
805     case DICT_TVM_COL_WIDTH:
806       g_value_init (value, G_TYPE_INT);
807       g_value_set_int (value, fs->w);
808       break;
809     case DICT_TVM_COL_DECIMAL:
810       g_value_init (value, G_TYPE_INT);
811       g_value_set_int (value, fs->d);
812       break;
813     case DICT_TVM_COL_LABEL:
814       g_value_init (value, G_TYPE_STRING);
815       g_value_set_string (value, var_get_label (var));
816       break;
817     case DICT_TVM_COL_COLUMNS:
818       g_value_init (value, G_TYPE_INT);
819       g_value_set_int (value, var_get_display_width (var));
820       break;
821     case DICT_TVM_COL_ALIGNMENT:
822       g_value_init (value, G_TYPE_INT);
823       g_value_set_int (value, var_get_alignment (var));
824       break;
825     case DICT_TVM_COL_MEASURE:
826       g_value_init (value, G_TYPE_INT);
827       g_value_set_int (value, var_get_measure (var));
828       break;
829     case DICT_TVM_COL_ROLE:
830       g_value_init (value, G_TYPE_INT);
831       g_value_set_int (value, var_get_role (var));
832       break;
833     case DICT_TVM_COL_VAR:
834       g_value_init (value, PSPPIRE_VAR_PTR_TYPE);
835       g_value_set_boxed (value, var);
836       break;
837     default:
838       g_value_init (value, G_TYPE_STRING);
839       g_value_set_string (value, "????");
840       break;
841     }
842 }
843
844 static gboolean
845 tree_model_iter_children (GtkTreeModel *tree_model,
846                           GtkTreeIter *iter,
847                           GtkTreeIter *parent)
848 {
849   return FALSE;
850 }
851
852 static gint
853 tree_model_n_children (GtkTreeModel *model,
854                        GtkTreeIter  *iter)
855 {
856   PsppireDict *dict = PSPPIRE_DICT (model);
857
858   if ( iter == NULL )
859     return psppire_dict_get_var_cnt (dict);
860
861   return 0;
862 }
863
864 static gboolean
865 tree_model_nth_child (GtkTreeModel *model, GtkTreeIter *iter,
866                       GtkTreeIter *parent, gint n)
867 {
868   PsppireDict *dict;
869
870   g_return_val_if_fail (PSPPIRE_IS_DICT (model), FALSE);
871
872   dict = PSPPIRE_DICT (model);
873
874   if ( parent )
875     return FALSE;
876
877   if ( n >= psppire_dict_get_var_cnt (dict) )
878     return FALSE;
879
880   iter->stamp = dict->stamp;
881   iter->user_data = psppire_dict_get_variable (dict, n);
882
883   if ( !iter->user_data)
884     return FALSE;
885
886   return TRUE;
887 }
888
889
890 gboolean
891 psppire_dict_rename_var (PsppireDict *dict, struct variable *v,
892                          const gchar *name)
893 {
894   if ( ! dict_id_is_valid (dict->dict, name, false))
895     return FALSE;
896
897   /* Make sure no other variable has this name */
898   if ( NULL != psppire_dict_lookup_var (dict, name))
899     return FALSE;
900
901   dict_rename_var (dict->dict, v, name);
902
903   return TRUE;
904 }
905
906
907 struct variable *
908 psppire_dict_get_weight_variable (const PsppireDict *dict)
909 {
910   return dict_get_weight (dict->dict);
911 }
912
913
914
915 #if DEBUGGING
916 void
917 psppire_dict_dump (const PsppireDict *dict)
918 {
919   gint i;
920   const struct dictionary *d = dict->dict;
921
922   for (i = 0; i < dict_get_var_cnt (d); ++i)
923     {
924       const struct variable *v = psppire_dict_get_variable (dict, i);
925       int di = var_get_dict_index (v);
926       g_print ("`%s' idx=%d, fv=%d\n",
927                var_get_name(v),
928                di,
929                var_get_case_index(v));
930
931     }
932 }
933 #endif
934
935
936
937
938 const gchar *
939 psppire_dict_encoding (const PsppireDict *dict)
940 {
941   return dict_get_encoding (dict->dict);
942 }