fixed goto case dialog
[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   const 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   size_t varcnt = dict_get_var_cnt (d->dict);
481   g_return_if_fail (first < varcnt);
482   g_return_if_fail (first >= 0);
483   g_return_if_fail (n > 0);
484   g_return_if_fail (first + n <= varcnt);
485
486   dict_delete_consecutive_vars (d->dict, first, n);
487 }
488
489
490 gboolean
491 psppire_dict_set_name (PsppireDict* d, gint idx, const gchar *name)
492 {
493   struct variable *var;
494   g_assert (d);
495   g_assert (PSPPIRE_IS_DICT (d));
496
497   if ( ! dict_id_is_valid (d->dict, name, false))
498     return FALSE;
499
500   if ( idx < dict_get_var_cnt (d->dict))
501     {
502       /* This is an existing variable? */
503       var = dict_get_var (d->dict, idx);
504       dict_rename_var (d->dict, var, name);
505     }
506   else
507     {
508       /* new variable */
509       dict_create_var (d->dict, name, 0);
510     }
511
512   return TRUE;
513 }
514
515
516
517 /* Return the IDXth variable.
518    Will return NULL if IDX  exceeds the number of variables in the dictionary.
519  */
520 struct variable *
521 psppire_dict_get_variable (const PsppireDict *d, gint idx)
522 {
523   g_return_val_if_fail (d, NULL);
524   g_return_val_if_fail (d->dict, NULL);
525
526   if ( dict_get_var_cnt (d->dict) <= idx )
527     return NULL;
528
529   return dict_get_var (d->dict, idx);
530 }
531
532
533 /* Return the number of variables in the dictionary */
534 gint
535 psppire_dict_get_var_cnt (const PsppireDict *d)
536 {
537   g_return_val_if_fail (d, -1);
538   g_return_val_if_fail (d->dict, -1);
539
540   return dict_get_var_cnt (d->dict);
541 }
542
543
544 /* Return the number of `union value's in the dictionary */
545 size_t
546 psppire_dict_get_value_cnt (const PsppireDict *d)
547 {
548   g_return_val_if_fail (d, -1);
549   g_return_val_if_fail (d->dict, -1);
550
551   return dict_get_next_value_idx (d->dict);
552 }
553
554
555 /* Returns the prototype for the cases that match the dictionary */
556 const struct caseproto *
557 psppire_dict_get_proto (const PsppireDict *d)
558 {
559   g_return_val_if_fail (d, NULL);
560   g_return_val_if_fail (d->dict, NULL);
561
562   return dict_get_proto (d->dict);
563 }
564
565
566 /* Return a variable by name.
567    Return NULL if it doesn't exist
568 */
569 struct variable *
570 psppire_dict_lookup_var (const PsppireDict *d, const gchar *name)
571 {
572   g_return_val_if_fail (d, NULL);
573   g_return_val_if_fail (d->dict, NULL);
574
575   return dict_lookup_var (d->dict, name);
576 }
577
578 /* Clears the contents of D */
579 void
580 psppire_dict_clear (PsppireDict *d)
581 {
582   g_return_if_fail (d);
583   g_return_if_fail (d->dict);
584
585   {
586     dict_clear (d->dict);
587   }
588 }
589
590
591 /* Return true if NAME would be a valid name of a variable to add to the
592    dictionary.  False otherwise.
593    If REPORT is true, then invalid names will be reported as such as errors
594 */
595 gboolean
596 psppire_dict_check_name (const PsppireDict *dict,
597                          const gchar *name, gboolean report)
598 {
599   if ( ! dict_id_is_valid (dict->dict, name, report ) )
600     return FALSE;
601
602   if (psppire_dict_lookup_var (dict, name))
603     {
604       if ( report )
605         msg (ME, _("Duplicate variable name."));
606       return FALSE;
607     }
608
609   return TRUE;
610 }
611
612
613 gint
614 psppire_dict_get_next_value_idx (const PsppireDict *dict)
615 {
616   return dict_get_next_value_idx (dict->dict);
617 }
618
619
620 /* Tree Model Stuff */
621
622 static GtkTreeModelFlags tree_model_get_flags (GtkTreeModel *model);
623
624 static gint tree_model_n_columns (GtkTreeModel *model);
625
626 static GType tree_model_column_type (GtkTreeModel *model, gint index);
627
628 static gboolean tree_model_get_iter (GtkTreeModel *model, GtkTreeIter *iter,
629                                      GtkTreePath *path);
630
631 static gboolean tree_model_iter_next (GtkTreeModel *model, GtkTreeIter *iter);
632
633 static GtkTreePath * tree_model_get_path (GtkTreeModel *model,
634                                           GtkTreeIter *iter);
635
636 static void tree_model_get_value (GtkTreeModel *model, GtkTreeIter *iter,
637                                   gint column, GValue *value);
638
639 static gboolean tree_model_nth_child (GtkTreeModel *model, GtkTreeIter *iter,
640                                       GtkTreeIter *parent, gint n);
641
642 static gint tree_model_n_children (GtkTreeModel *tree_model,
643                                    GtkTreeIter  *iter);
644
645 static gboolean tree_model_iter_children (GtkTreeModel *,
646                                           GtkTreeIter *,
647                                           GtkTreeIter *);
648
649 static gboolean tree_model_iter_parent (GtkTreeModel *tree_model,
650                                         GtkTreeIter *iter,
651                                         GtkTreeIter *child);
652
653 static gboolean tree_model_iter_has_child  (GtkTreeModel *tree_model,
654                                             GtkTreeIter  *iter);
655
656 static void
657 dictionary_tree_model_init (GtkTreeModelIface *iface)
658 {
659   iface->get_flags = tree_model_get_flags;
660   iface->get_n_columns = tree_model_n_columns;
661   iface->get_column_type = tree_model_column_type;
662   iface->get_iter = tree_model_get_iter;
663   iface->iter_next = tree_model_iter_next;
664   iface->get_path = tree_model_get_path;
665   iface->get_value = tree_model_get_value;
666
667   iface->iter_children = tree_model_iter_children ;
668   iface->iter_has_child = tree_model_iter_has_child ;
669   iface->iter_n_children = tree_model_n_children ;
670   iface->iter_nth_child = tree_model_nth_child ;
671   iface->iter_parent = tree_model_iter_parent ;
672 }
673
674 static gboolean
675 tree_model_iter_has_child  (GtkTreeModel *tree_model,
676                             GtkTreeIter  *iter)
677 {
678   return FALSE;
679 }
680
681 static gboolean
682 tree_model_iter_parent (GtkTreeModel *tree_model,
683                         GtkTreeIter *iter,
684                         GtkTreeIter *child)
685 {
686   return TRUE;
687 }
688
689 static GtkTreeModelFlags
690 tree_model_get_flags (GtkTreeModel *model)
691 {
692   g_return_val_if_fail (PSPPIRE_IS_DICT (model), (GtkTreeModelFlags) 0);
693
694   return GTK_TREE_MODEL_LIST_ONLY;
695 }
696
697
698 static gint
699 tree_model_n_columns (GtkTreeModel *model)
700 {
701   return n_DICT_COLS;
702 }
703
704 static GType
705 tree_model_column_type (GtkTreeModel *model, gint index)
706 {
707   g_return_val_if_fail (PSPPIRE_IS_DICT (model), (GType) 0);
708
709   GType t = 0;
710
711   switch (index)
712     {
713     case DICT_TVM_COL_NAME:
714     case DICT_TVM_COL_LABEL:
715       t = G_TYPE_STRING;
716       break;
717     case DICT_TVM_COL_DECIMAL:
718     case DICT_TVM_COL_WIDTH:
719     case DICT_TVM_COL_COLUMNS:
720       t = G_TYPE_INT;
721       break;
722     case DICT_TVM_COL_VAR:
723       t = PSPPIRE_VAR_PTR_TYPE;
724       break;
725     case DICT_TVM_COL_ALIGNMENT:
726       t = align_enum_type;
727       break;
728     case DICT_TVM_COL_MEASURE:
729       t = measure_enum_type;
730       break;
731     case DICT_TVM_COL_ROLE:
732       t = role_enum_type;
733       break;
734     }
735
736   return t;
737 }
738
739 static gboolean
740 tree_model_get_iter (GtkTreeModel *model, GtkTreeIter *iter, GtkTreePath *path)
741 {
742   gint *indices, depth;
743   gint n;
744   struct variable *var;
745
746   PsppireDict *dict = PSPPIRE_DICT (model);
747
748   g_return_val_if_fail (path, FALSE);
749
750   indices = gtk_tree_path_get_indices (path);
751   depth = gtk_tree_path_get_depth (path);
752
753   g_return_val_if_fail (depth == 1, FALSE);
754
755   n = indices [0];
756
757   if ( n < 0 || n >= psppire_dict_get_var_cnt (dict))
758     {
759       iter->stamp = 0;
760       iter->user_data = NULL;
761       return FALSE;
762     }
763
764   var = psppire_dict_get_variable (dict, n);
765
766   g_assert (var_get_dict_index (var) == n);
767
768   iter->stamp = dict->stamp;
769   iter->user_data = var;
770
771   return TRUE;
772 }
773
774
775 static gboolean
776 tree_model_iter_next (GtkTreeModel *model, GtkTreeIter *iter)
777 {
778   PsppireDict *dict = PSPPIRE_DICT (model);
779   struct variable *var;
780   gint idx;
781
782   if ( iter == NULL || iter->user_data == NULL)
783     return FALSE;
784
785   g_return_val_if_fail (iter->stamp == dict->stamp, FALSE);
786
787   var = iter->user_data;
788
789   idx = var_get_dict_index (var);
790
791   if ( idx + 1 >= psppire_dict_get_var_cnt (dict))
792     {
793       iter->user_data = NULL;
794       iter->stamp = 0;
795       return FALSE;
796     }
797
798   var = psppire_dict_get_variable (dict, idx + 1);
799
800   g_assert (var_get_dict_index (var) == idx + 1);
801
802   iter->user_data = var;
803
804   return TRUE;
805 }
806
807 static GtkTreePath *
808 tree_model_get_path (GtkTreeModel *model, GtkTreeIter *iter)
809 {
810   GtkTreePath *path;
811   struct variable *var;
812   PsppireDict *dict = PSPPIRE_DICT (model);
813
814   g_return_val_if_fail (iter->stamp == dict->stamp, FALSE);
815
816   var = iter->user_data;
817
818   path = gtk_tree_path_new ();
819   gtk_tree_path_append_index (path, var_get_dict_index (var));
820
821   return path;
822 }
823
824 const struct fmt_spec *var_get_write_format (const struct variable *);
825
826 static void
827 tree_model_get_value (GtkTreeModel *model, GtkTreeIter *iter,
828                       gint column, GValue *value)
829 {
830   struct variable *var;
831   PsppireDict *dict = PSPPIRE_DICT (model);
832
833   g_return_if_fail (iter->stamp == dict->stamp);
834
835   var = iter->user_data;
836
837   const struct fmt_spec *fs = var_get_write_format (var);
838
839   switch (column)
840     {
841     case DICT_TVM_COL_NAME:
842       g_value_init (value, G_TYPE_STRING);
843       g_value_set_string (value, var_get_name (var));
844       break;
845     case DICT_TVM_COL_WIDTH:
846       g_value_init (value, G_TYPE_INT);
847       g_value_set_int (value, fs->w);
848       break;
849     case DICT_TVM_COL_DECIMAL:
850       g_value_init (value, G_TYPE_INT);
851       g_value_set_int (value, fs->d);
852       break;
853     case DICT_TVM_COL_LABEL:
854       g_value_init (value, G_TYPE_STRING);
855       g_value_set_string (value, var_get_label (var));
856       break;
857     case DICT_TVM_COL_COLUMNS:
858       g_value_init (value, G_TYPE_INT);
859       g_value_set_int (value, var_get_display_width (var));
860       break;
861     case DICT_TVM_COL_ALIGNMENT:
862       g_value_init (value, align_enum_type);
863       g_value_set_enum (value, var_get_alignment (var));
864       break;
865     case DICT_TVM_COL_MEASURE:
866       g_value_init (value, measure_enum_type);
867       g_value_set_enum (value, var_get_measure (var));
868       break;
869     case DICT_TVM_COL_ROLE:
870       g_value_init (value, role_enum_type);
871       g_value_set_enum (value, var_get_role (var));
872       break;
873     case DICT_TVM_COL_VAR:
874       g_value_init (value, PSPPIRE_VAR_PTR_TYPE);
875       g_value_set_boxed (value, var);
876       break;
877     default:
878       g_value_init (value, G_TYPE_STRING);
879       g_value_set_string (value, "????");
880       break;
881     }
882 }
883
884 static gboolean
885 tree_model_iter_children (GtkTreeModel *tree_model,
886                           GtkTreeIter *iter,
887                           GtkTreeIter *parent)
888 {
889   return FALSE;
890 }
891
892 static gint
893 tree_model_n_children (GtkTreeModel *model,
894                        GtkTreeIter  *iter)
895 {
896   PsppireDict *dict = PSPPIRE_DICT (model);
897
898   if (iter == NULL)
899     return psppire_dict_get_var_cnt (dict);
900
901   return 0;
902 }
903
904 static gboolean
905 tree_model_nth_child (GtkTreeModel *model, GtkTreeIter *iter,
906                       GtkTreeIter *parent, gint n)
907 {
908   PsppireDict *dict;
909
910   g_return_val_if_fail (PSPPIRE_IS_DICT (model), FALSE);
911
912   dict = PSPPIRE_DICT (model);
913
914   if ( parent )
915     return FALSE;
916
917   if ( n >= psppire_dict_get_var_cnt (dict) )
918     return FALSE;
919
920   iter->stamp = dict->stamp;
921   iter->user_data = psppire_dict_get_variable (dict, n);
922
923   if ( !iter->user_data)
924     return FALSE;
925
926   return TRUE;
927 }
928
929
930 gboolean
931 psppire_dict_rename_var (PsppireDict *dict, struct variable *v,
932                          const gchar *name)
933 {
934   if ( ! dict_id_is_valid (dict->dict, name, false))
935     return FALSE;
936
937   /* Make sure no other variable has this name */
938   if ( NULL != psppire_dict_lookup_var (dict, name))
939     return FALSE;
940
941   dict_rename_var (dict->dict, v, name);
942
943   return TRUE;
944 }
945
946
947 struct variable *
948 psppire_dict_get_weight_variable (const PsppireDict *dict)
949 {
950   return dict_get_weight (dict->dict);
951 }
952
953
954
955 #if DEBUGGING
956 void
957 psppire_dict_dump (const PsppireDict *dict)
958 {
959   gint i;
960   const struct dictionary *d = dict->dict;
961
962   for (i = 0; i < dict_get_var_cnt (d); ++i)
963     {
964       const struct variable *v = psppire_dict_get_variable (dict, i);
965       int di = var_get_dict_index (v);
966       g_print ("`%s' idx=%d, fv=%d\n",
967                var_get_name(v),
968                di,
969                var_get_case_index(v));
970
971     }
972 }
973 #endif
974
975
976 const gchar *
977 psppire_dict_encoding (const PsppireDict *dict)
978 {
979   return dict_get_encoding (dict->dict);
980 }