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