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