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