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