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