Don't crash when inserting variables into an empty 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,
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   dict_unref (d->dict);
292
293   G_OBJECT_CLASS (parent_class)->dispose (object);
294 }
295
296 /* Pass on callbacks from src/data/dictionary, as
297    signals in the Gtk library */
298 static void
299 addcb (struct dictionary *d, int idx, void *pd)
300 {
301   PsppireDict *dict = PSPPIRE_DICT (pd);
302
303   if ( ! dict->disable_insert_signal)
304     {
305       g_signal_emit (dict, signals [VARIABLE_INSERTED], 0, idx);
306       g_signal_emit_by_name (dict, "items-changed", idx, 1, 1);
307     }
308 }
309
310 static void
311 delcb (struct dictionary *d, const struct variable *var,
312        int dict_idx, int case_idx, void *pd)
313 {
314   g_signal_emit (pd, signals [VARIABLE_DELETED], 0,
315                  var, dict_idx, case_idx);
316   g_signal_emit_by_name (pd, "items-changed",  dict_idx, 1, 0);
317 }
318
319 static void
320 mutcb (struct dictionary *d, int idx, unsigned int what, const struct variable *oldvar, void *pd)
321 {
322   g_signal_emit (pd, signals [VARIABLE_CHANGED], 0, idx, what, oldvar);
323   g_signal_emit_by_name (pd, "items-changed", idx, 1, 1);
324 }
325
326 static void
327 weight_changed_callback (struct dictionary *d, int idx, void *pd)
328 {
329   g_signal_emit (pd, signals [WEIGHT_CHANGED], 0, idx);
330 }
331
332 static void
333 filter_changed_callback (struct dictionary *d, int idx, void *pd)
334 {
335   g_signal_emit (pd, signals [FILTER_CHANGED], 0, idx);
336 }
337
338 static void
339 split_changed_callback (struct dictionary *d, void *pd)
340 {
341   g_signal_emit (pd, signals [SPLIT_CHANGED], 0);
342 }
343
344 static const struct dict_callbacks gui_callbacks =
345   {
346     addcb,
347     delcb,
348     mutcb,
349     weight_changed_callback,
350     filter_changed_callback,
351     split_changed_callback
352   };
353
354 static void
355 psppire_dict_init (PsppireDict *psppire_dict)
356 {
357   psppire_dict->stamp = g_random_int ();
358   psppire_dict->disable_insert_signal = FALSE;
359 }
360
361 /**
362  * psppire_dict_new_from_dict:
363  * @returns: a new #PsppireDict object
364  *
365  * Creates a new #PsppireDict.
366  */
367 PsppireDict*
368 psppire_dict_new_from_dict (struct dictionary *d)
369 {
370   PsppireDict *new_dict = g_object_new (PSPPIRE_TYPE_DICT, NULL);
371   new_dict->dict = dict_ref (d);
372
373   dict_set_callbacks (new_dict->dict, &gui_callbacks, new_dict);
374
375   return new_dict;
376 }
377
378
379 void
380 psppire_dict_replace_dictionary (PsppireDict *dict, struct dictionary *d)
381 {
382   struct variable *var =  dict_get_weight (d);
383
384   struct dictionary *old_dict = dict->dict;
385
386   guint old_n = dict_get_var_cnt (dict->dict);
387   guint new_n = dict_get_var_cnt (d);
388
389   dict->dict = dict_ref (d);
390   dict_unref (old_dict);
391
392   weight_changed_callback (d, var ? var_get_dict_index (var) : -1, dict);
393
394   var = dict_get_filter (d);
395   filter_changed_callback (d, var ? var_get_dict_index (var) : -1, dict);
396
397   split_changed_callback (d, dict);
398
399   dict_set_callbacks (dict->dict, &gui_callbacks, dict);
400
401   g_signal_emit_by_name (dict, "items-changed", 0, old_n, new_n);
402 }
403
404
405 /* Stores a valid name for a new variable in DICT into the SIZE bytes in NAME.
406    Returns true if successful, false if SIZE is insufficient. */
407 bool
408 psppire_dict_generate_name (const PsppireDict *dict, char *name, size_t size)
409 {
410   gint d;
411
412   for (d = 1; ; d++)
413     {
414       int len;
415
416       /* TRANSLATORS: This string must be a valid variable name.  That means:
417          - The string must be at most 64 bytes (not characters) long.
418          - The string may not contain whitespace.
419          - The first character may not be '$'
420          - The first character may not be a digit
421          - The final character may not be '.' or '_'
422       */
423       len = snprintf (name, size, _("Var%04d"), d);
424       if (len + 1 >= size)
425         return false;
426
427       if (psppire_dict_lookup_var (dict, name) == NULL)
428         return true;
429     }
430
431   return name;
432 }
433
434 /* Insert a new variable at posn IDX, with the name NAME, and return the
435    new variable.
436    IDX may take the special value -1, which will be treated the same as
437    zero.   If NAME is null, then a name will be automatically assigned.
438 */
439 struct variable *
440 psppire_dict_insert_variable (PsppireDict *d, gint idx, const gchar *name)
441 {
442   struct variable *var;
443   char tmpname[64];
444
445   if (idx == -1)    /* Note bug #56392. */
446     idx = 0;
447   g_return_val_if_fail (d, NULL);
448   g_return_val_if_fail (PSPPIRE_IS_DICT (d), NULL);
449
450   if (name == NULL)
451     {
452       if (!psppire_dict_generate_name (d, tmpname, sizeof tmpname))
453         g_return_val_if_reached (NULL);
454
455       name = tmpname;
456     }
457
458   d->disable_insert_signal = TRUE;
459
460   var = dict_create_var (d->dict, name, 0);
461
462   dict_reorder_var (d->dict, var, idx);
463
464   d->disable_insert_signal = FALSE;
465
466   g_signal_emit (d, signals[VARIABLE_INSERTED], 0, idx);
467   g_signal_emit_by_name (d, "items-changed", idx, 0, 1);
468
469   return var;
470 }
471
472 /* Delete N variables beginning at FIRST */
473 void
474 psppire_dict_delete_variables (PsppireDict *d, gint first, gint n)
475 {
476   gint idx;
477   g_return_if_fail (d);
478   g_return_if_fail (d->dict);
479   g_return_if_fail (PSPPIRE_IS_DICT (d));
480
481   for (idx = 0 ; idx < n ; ++idx )
482     {
483       struct variable *var;
484
485       /* Do nothing if it's out of bounds */
486       if ( first >= dict_get_var_cnt (d->dict))
487         break;
488
489       var = dict_get_var (d->dict, first);
490       dict_delete_var (d->dict, var);
491     }
492 }
493
494
495 gboolean
496 psppire_dict_set_name (PsppireDict* d, gint idx, const gchar *name)
497 {
498   struct variable *var;
499   g_assert (d);
500   g_assert (PSPPIRE_IS_DICT (d));
501
502   if ( ! dict_id_is_valid (d->dict, name, false))
503     return FALSE;
504
505   if ( idx < dict_get_var_cnt (d->dict))
506     {
507       /* This is an existing variable? */
508       var = dict_get_var (d->dict, idx);
509       dict_rename_var (d->dict, var, name);
510     }
511   else
512     {
513       /* new variable */
514       dict_create_var (d->dict, name, 0);
515     }
516
517   return TRUE;
518 }
519
520
521
522 /* Return the IDXth variable.
523    Will return NULL if IDX  exceeds the number of variables in the dictionary.
524  */
525 struct variable *
526 psppire_dict_get_variable (const PsppireDict *d, gint idx)
527 {
528   g_return_val_if_fail (d, NULL);
529   g_return_val_if_fail (d->dict, NULL);
530
531   if ( dict_get_var_cnt (d->dict) <= idx )
532     return NULL;
533
534   return dict_get_var (d->dict, idx);
535 }
536
537
538 /* Return the number of variables in the dictionary */
539 gint
540 psppire_dict_get_var_cnt (const PsppireDict *d)
541 {
542   g_return_val_if_fail (d, -1);
543   g_return_val_if_fail (d->dict, -1);
544
545   return dict_get_var_cnt (d->dict);
546 }
547
548
549 /* Return the number of `union value's in the dictionary */
550 size_t
551 psppire_dict_get_value_cnt (const PsppireDict *d)
552 {
553   g_return_val_if_fail (d, -1);
554   g_return_val_if_fail (d->dict, -1);
555
556   return dict_get_next_value_idx (d->dict);
557 }
558
559
560 /* Returns the prototype for the cases that match the dictionary */
561 const struct caseproto *
562 psppire_dict_get_proto (const PsppireDict *d)
563 {
564   g_return_val_if_fail (d, NULL);
565   g_return_val_if_fail (d->dict, NULL);
566
567   return dict_get_proto (d->dict);
568 }
569
570
571 /* Return a variable by name.
572    Return NULL if it doesn't exist
573 */
574 struct variable *
575 psppire_dict_lookup_var (const PsppireDict *d, const gchar *name)
576 {
577   g_return_val_if_fail (d, NULL);
578   g_return_val_if_fail (d->dict, NULL);
579
580   return dict_lookup_var (d->dict, name);
581 }
582
583 /* Clears the contents of D */
584 void
585 psppire_dict_clear (PsppireDict *d)
586 {
587   g_return_if_fail (d);
588   g_return_if_fail (d->dict);
589
590   {
591     dict_clear (d->dict);
592   }
593 }
594
595
596 /* Return true if NAME would be a valid name of a variable to add to the
597    dictionary.  False otherwise.
598    If REPORT is true, then invalid names will be reported as such as errors
599 */
600 gboolean
601 psppire_dict_check_name (const PsppireDict *dict,
602                          const gchar *name, gboolean report)
603 {
604   if ( ! dict_id_is_valid (dict->dict, name, report ) )
605     return FALSE;
606
607   if (psppire_dict_lookup_var (dict, name))
608     {
609       if ( report )
610         msg (ME, _("Duplicate variable name."));
611       return FALSE;
612     }
613
614   return TRUE;
615 }
616
617
618 gint
619 psppire_dict_get_next_value_idx (const PsppireDict *dict)
620 {
621   return dict_get_next_value_idx (dict->dict);
622 }
623
624
625 /* Tree Model Stuff */
626
627 static GtkTreeModelFlags tree_model_get_flags (GtkTreeModel *model);
628
629 static gint tree_model_n_columns (GtkTreeModel *model);
630
631 static GType tree_model_column_type (GtkTreeModel *model, gint index);
632
633 static gboolean tree_model_get_iter (GtkTreeModel *model, GtkTreeIter *iter,
634                                      GtkTreePath *path);
635
636 static gboolean tree_model_iter_next (GtkTreeModel *model, GtkTreeIter *iter);
637
638 static GtkTreePath * tree_model_get_path (GtkTreeModel *model,
639                                           GtkTreeIter *iter);
640
641 static void tree_model_get_value (GtkTreeModel *model, GtkTreeIter *iter,
642                                   gint column, GValue *value);
643
644 static gboolean tree_model_nth_child (GtkTreeModel *model, GtkTreeIter *iter,
645                                       GtkTreeIter *parent, gint n);
646
647 static gint tree_model_n_children (GtkTreeModel *tree_model,
648                                    GtkTreeIter  *iter);
649
650 static gboolean tree_model_iter_children (GtkTreeModel *,
651                                           GtkTreeIter *,
652                                           GtkTreeIter *);
653
654 static gboolean tree_model_iter_parent (GtkTreeModel *tree_model,
655                                         GtkTreeIter *iter,
656                                         GtkTreeIter *child);
657
658 static gboolean tree_model_iter_has_child  (GtkTreeModel *tree_model,
659                                             GtkTreeIter  *iter);
660
661 static void
662 dictionary_tree_model_init (GtkTreeModelIface *iface)
663 {
664   iface->get_flags = tree_model_get_flags;
665   iface->get_n_columns = tree_model_n_columns;
666   iface->get_column_type = tree_model_column_type;
667   iface->get_iter = tree_model_get_iter;
668   iface->iter_next = tree_model_iter_next;
669   iface->get_path = tree_model_get_path;
670   iface->get_value = tree_model_get_value;
671
672   iface->iter_children = tree_model_iter_children ;
673   iface->iter_has_child = tree_model_iter_has_child ;
674   iface->iter_n_children = tree_model_n_children ;
675   iface->iter_nth_child = tree_model_nth_child ;
676   iface->iter_parent = tree_model_iter_parent ;
677 }
678
679 static gboolean
680 tree_model_iter_has_child  (GtkTreeModel *tree_model,
681                             GtkTreeIter  *iter)
682 {
683   return FALSE;
684 }
685
686 static gboolean
687 tree_model_iter_parent (GtkTreeModel *tree_model,
688                         GtkTreeIter *iter,
689                         GtkTreeIter *child)
690 {
691   return TRUE;
692 }
693
694 static GtkTreeModelFlags
695 tree_model_get_flags (GtkTreeModel *model)
696 {
697   g_return_val_if_fail (PSPPIRE_IS_DICT (model), (GtkTreeModelFlags) 0);
698
699   return GTK_TREE_MODEL_LIST_ONLY;
700 }
701
702
703 static gint
704 tree_model_n_columns (GtkTreeModel *model)
705 {
706   return n_DICT_COLS;
707 }
708
709 static GType
710 tree_model_column_type (GtkTreeModel *model, gint index)
711 {
712   g_return_val_if_fail (PSPPIRE_IS_DICT (model), (GType) 0);
713
714   GType t = 0;
715
716   switch (index)
717     {
718     case DICT_TVM_COL_NAME:
719     case DICT_TVM_COL_LABEL:
720       t = G_TYPE_STRING;
721       break;
722     case DICT_TVM_COL_DECIMAL:
723     case DICT_TVM_COL_WIDTH:
724     case DICT_TVM_COL_COLUMNS:
725       t = G_TYPE_INT;
726       break;
727     case DICT_TVM_COL_VAR:
728       t = PSPPIRE_VAR_PTR_TYPE;
729       break;
730     case DICT_TVM_COL_ALIGNMENT:
731       t = align_enum_type;
732       break;
733     case DICT_TVM_COL_MEASURE:
734       t = measure_enum_type;
735       break;
736     case DICT_TVM_COL_ROLE:
737       t = role_enum_type;
738       break;
739     }
740
741   return t;
742 }
743
744 static gboolean
745 tree_model_get_iter (GtkTreeModel *model, GtkTreeIter *iter, GtkTreePath *path)
746 {
747   gint *indices, depth;
748   gint n;
749   struct variable *var;
750
751   PsppireDict *dict = PSPPIRE_DICT (model);
752
753   g_return_val_if_fail (path, FALSE);
754
755   indices = gtk_tree_path_get_indices (path);
756   depth = gtk_tree_path_get_depth (path);
757
758   g_return_val_if_fail (depth == 1, FALSE);
759
760   n = indices [0];
761
762   if ( n < 0 || n >= psppire_dict_get_var_cnt (dict))
763     {
764       iter->stamp = 0;
765       iter->user_data = NULL;
766       return FALSE;
767     }
768
769   var = psppire_dict_get_variable (dict, n);
770
771   g_assert (var_get_dict_index (var) == n);
772
773   iter->stamp = dict->stamp;
774   iter->user_data = var;
775
776   return TRUE;
777 }
778
779
780 static gboolean
781 tree_model_iter_next (GtkTreeModel *model, GtkTreeIter *iter)
782 {
783   PsppireDict *dict = PSPPIRE_DICT (model);
784   struct variable *var;
785   gint idx;
786
787   if ( iter == NULL || iter->user_data == NULL)
788     return FALSE;
789
790   g_return_val_if_fail (iter->stamp == dict->stamp, FALSE);
791
792   var = iter->user_data;
793
794   idx = var_get_dict_index (var);
795
796   if ( idx + 1 >= psppire_dict_get_var_cnt (dict))
797     {
798       iter->user_data = NULL;
799       iter->stamp = 0;
800       return FALSE;
801     }
802
803   var = psppire_dict_get_variable (dict, idx + 1);
804
805   g_assert (var_get_dict_index (var) == idx + 1);
806
807   iter->user_data = var;
808
809   return TRUE;
810 }
811
812 static GtkTreePath *
813 tree_model_get_path (GtkTreeModel *model, GtkTreeIter *iter)
814 {
815   GtkTreePath *path;
816   struct variable *var;
817   PsppireDict *dict = PSPPIRE_DICT (model);
818
819   g_return_val_if_fail (iter->stamp == dict->stamp, FALSE);
820
821   var = iter->user_data;
822
823   path = gtk_tree_path_new ();
824   gtk_tree_path_append_index (path, var_get_dict_index (var));
825
826   return path;
827 }
828
829 const struct fmt_spec *var_get_write_format (const struct variable *);
830
831 static void
832 tree_model_get_value (GtkTreeModel *model, GtkTreeIter *iter,
833                       gint column, GValue *value)
834 {
835   struct variable *var;
836   PsppireDict *dict = PSPPIRE_DICT (model);
837
838   g_return_if_fail (iter->stamp == dict->stamp);
839
840   var = iter->user_data;
841
842   const struct fmt_spec *fs = var_get_write_format (var);
843
844   switch (column)
845     {
846     case DICT_TVM_COL_NAME:
847       g_value_init (value, G_TYPE_STRING);
848       g_value_set_string (value, var_get_name (var));
849       break;
850     case DICT_TVM_COL_WIDTH:
851       g_value_init (value, G_TYPE_INT);
852       g_value_set_int (value, fs->w);
853       break;
854     case DICT_TVM_COL_DECIMAL:
855       g_value_init (value, G_TYPE_INT);
856       g_value_set_int (value, fs->d);
857       break;
858     case DICT_TVM_COL_LABEL:
859       g_value_init (value, G_TYPE_STRING);
860       g_value_set_string (value, var_get_label (var));
861       break;
862     case DICT_TVM_COL_COLUMNS:
863       g_value_init (value, G_TYPE_INT);
864       g_value_set_int (value, var_get_display_width (var));
865       break;
866     case DICT_TVM_COL_ALIGNMENT:
867       g_value_init (value, align_enum_type);
868       g_value_set_enum (value, var_get_alignment (var));
869       break;
870     case DICT_TVM_COL_MEASURE:
871       g_value_init (value, measure_enum_type);
872       g_value_set_enum (value, var_get_measure (var));
873       break;
874     case DICT_TVM_COL_ROLE:
875       g_value_init (value, role_enum_type);
876       g_value_set_enum (value, var_get_role (var));
877       break;
878     case DICT_TVM_COL_VAR:
879       g_value_init (value, PSPPIRE_VAR_PTR_TYPE);
880       g_value_set_boxed (value, var);
881       break;
882     default:
883       g_value_init (value, G_TYPE_STRING);
884       g_value_set_string (value, "????");
885       break;
886     }
887 }
888
889 static gboolean
890 tree_model_iter_children (GtkTreeModel *tree_model,
891                           GtkTreeIter *iter,
892                           GtkTreeIter *parent)
893 {
894   return FALSE;
895 }
896
897 static gint
898 tree_model_n_children (GtkTreeModel *model,
899                        GtkTreeIter  *iter)
900 {
901   PsppireDict *dict = PSPPIRE_DICT (model);
902
903   if (iter == NULL)
904     return psppire_dict_get_var_cnt (dict);
905
906   return 0;
907 }
908
909 static gboolean
910 tree_model_nth_child (GtkTreeModel *model, GtkTreeIter *iter,
911                       GtkTreeIter *parent, gint n)
912 {
913   PsppireDict *dict;
914
915   g_return_val_if_fail (PSPPIRE_IS_DICT (model), FALSE);
916
917   dict = PSPPIRE_DICT (model);
918
919   if ( parent )
920     return FALSE;
921
922   if ( n >= psppire_dict_get_var_cnt (dict) )
923     return FALSE;
924
925   iter->stamp = dict->stamp;
926   iter->user_data = psppire_dict_get_variable (dict, n);
927
928   if ( !iter->user_data)
929     return FALSE;
930
931   return TRUE;
932 }
933
934
935 gboolean
936 psppire_dict_rename_var (PsppireDict *dict, struct variable *v,
937                          const gchar *name)
938 {
939   if ( ! dict_id_is_valid (dict->dict, name, false))
940     return FALSE;
941
942   /* Make sure no other variable has this name */
943   if ( NULL != psppire_dict_lookup_var (dict, name))
944     return FALSE;
945
946   dict_rename_var (dict->dict, v, name);
947
948   return TRUE;
949 }
950
951
952 struct variable *
953 psppire_dict_get_weight_variable (const PsppireDict *dict)
954 {
955   return dict_get_weight (dict->dict);
956 }
957
958
959
960 #if DEBUGGING
961 void
962 psppire_dict_dump (const PsppireDict *dict)
963 {
964   gint i;
965   const struct dictionary *d = dict->dict;
966
967   for (i = 0; i < dict_get_var_cnt (d); ++i)
968     {
969       const struct variable *v = psppire_dict_get_variable (dict, i);
970       int di = var_get_dict_index (v);
971       g_print ("`%s' idx=%d, fv=%d\n",
972                var_get_name(v),
973                di,
974                var_get_case_index(v));
975
976     }
977 }
978 #endif
979
980
981 const gchar *
982 psppire_dict_encoding (const PsppireDict *dict)
983 {
984   return dict_get_encoding (dict->dict);
985 }