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