Fix bug #20910.
[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 the number of `union value's in the dictionary */
415 size_t
416 psppire_dict_get_value_cnt (const PsppireDict *d)
417 {
418   g_return_val_if_fail (d, -1);
419   g_return_val_if_fail (d->dict, -1);
420
421   return dict_get_next_value_idx (d->dict);
422 }
423
424
425 /* Return a variable by name.
426    Return NULL if it doesn't exist
427 */
428 struct variable *
429 psppire_dict_lookup_var (const PsppireDict *d, const gchar *name)
430 {
431   g_return_val_if_fail (d, NULL);
432   g_return_val_if_fail (d->dict, NULL);
433
434   return dict_lookup_var (d->dict, name);
435 }
436
437 /* Clears the contents of D */
438 void
439 psppire_dict_clear (PsppireDict *d)
440 {
441   g_return_if_fail (d);
442   g_return_if_fail (d->dict);
443
444   {
445     dict_clear (d->dict);
446   }
447 }
448
449
450 /* Return true is NAME would be a valid name of a variable to add to the
451    dictionary.  False otherwise.
452    If REPORT is true, then invalid names will be reported as such as errors
453 */
454 gboolean
455 psppire_dict_check_name (const PsppireDict *dict,
456                          const gchar *name, gboolean report)
457 {
458   if ( ! var_is_valid_name (name, report ) )
459     return FALSE;
460
461   if (psppire_dict_lookup_var (dict, name))
462     {
463       if ( report )
464         msg (ME,"Duplicate variable name.");
465       return FALSE;
466     }
467
468   return TRUE;
469 }
470
471
472 inline gint
473 psppire_dict_get_next_value_idx (const PsppireDict *dict)
474 {
475   return dict_get_next_value_idx (dict->dict);
476 }
477
478
479 void
480 psppire_dict_resize_variable (PsppireDict *d, const struct variable *pv,
481                               gint old_size, gint new_size)
482 {
483   gint fv;
484   g_return_if_fail (d);
485   g_return_if_fail (d->dict);
486
487   if ( old_size == new_size )
488     return ;
489
490   fv = var_get_case_index (pv);
491
492   g_signal_emit (d, signals [VARIABLE_RESIZED], 0,
493                  fv + old_size,
494                  new_size - old_size );
495 }
496
497
498 /* Tree Model Stuff */
499
500 static GtkTreeModelFlags tree_model_get_flags (GtkTreeModel *model);
501
502 static gint tree_model_n_columns (GtkTreeModel *model);
503
504 static GType tree_model_column_type (GtkTreeModel *model, gint index);
505
506 static gboolean tree_model_get_iter (GtkTreeModel *model, GtkTreeIter *iter,
507                                      GtkTreePath *path);
508
509 static gboolean tree_model_iter_next (GtkTreeModel *model, GtkTreeIter *iter);
510
511 static GtkTreePath * tree_model_get_path (GtkTreeModel *model,
512                                           GtkTreeIter *iter);
513
514 static void tree_model_get_value (GtkTreeModel *model, GtkTreeIter *iter,
515                                   gint column, GValue *value);
516
517 static gboolean tree_model_nth_child (GtkTreeModel *model, GtkTreeIter *iter,
518                                       GtkTreeIter *parent, gint n);
519
520 static gint tree_model_n_children (GtkTreeModel *tree_model,
521                                    GtkTreeIter  *iter);
522
523 static gboolean tree_model_iter_children (GtkTreeModel *,
524                                           GtkTreeIter *,
525                                           GtkTreeIter *);
526
527 static gboolean tree_model_iter_parent (GtkTreeModel *tree_model,
528                                         GtkTreeIter *iter,
529                                         GtkTreeIter *child);
530
531 static gboolean tree_model_iter_has_child  (GtkTreeModel *tree_model,
532                                             GtkTreeIter  *iter);
533
534 static void
535 dictionary_tree_model_init (GtkTreeModelIface *iface)
536 {
537   iface->get_flags = tree_model_get_flags;
538   iface->get_n_columns = tree_model_n_columns;
539   iface->get_column_type = tree_model_column_type;
540   iface->get_iter = tree_model_get_iter;
541   iface->iter_next = tree_model_iter_next;
542   iface->get_path = tree_model_get_path;
543   iface->get_value = tree_model_get_value;
544
545   iface->iter_children = tree_model_iter_children ;
546   iface->iter_has_child = tree_model_iter_has_child ;
547   iface->iter_n_children = tree_model_n_children ;
548   iface->iter_nth_child = tree_model_nth_child ;
549   iface->iter_parent = tree_model_iter_parent ;
550 }
551
552 static gboolean
553 tree_model_iter_has_child  (GtkTreeModel *tree_model,
554                             GtkTreeIter  *iter)
555 {
556   return FALSE;
557 }
558
559 static gboolean
560 tree_model_iter_parent (GtkTreeModel *tree_model,
561                         GtkTreeIter *iter,
562                         GtkTreeIter *child)
563 {
564   return TRUE;
565 }
566
567 static GtkTreeModelFlags
568 tree_model_get_flags (GtkTreeModel *model)
569 {
570   g_return_val_if_fail (PSPPIRE_IS_DICT (model), (GtkTreeModelFlags) 0);
571
572   return GTK_TREE_MODEL_LIST_ONLY;
573 }
574
575
576 static gint
577 tree_model_n_columns (GtkTreeModel *model)
578 {
579   return n_DICT_COLS;
580 }
581
582 static GType
583 tree_model_column_type (GtkTreeModel *model, gint index)
584 {
585   g_return_val_if_fail (PSPPIRE_IS_DICT (model), (GType) 0);
586
587   switch (index)
588     {
589     case DICT_TVM_COL_NAME:
590       return G_TYPE_STRING;
591       break;
592     case DICT_TVM_COL_VAR:
593       return G_TYPE_POINTER;
594       break;
595     default:
596       g_return_val_if_reached ((GType)0);
597       break;
598     }
599
600   g_assert_not_reached ();
601   return ((GType)0);
602 }
603
604 static gboolean
605 tree_model_get_iter (GtkTreeModel *model, GtkTreeIter *iter, GtkTreePath *path)
606 {
607   gint *indices, depth;
608   gint n;
609   struct variable *var;
610
611   PsppireDict *dict = PSPPIRE_DICT (model);
612
613   g_return_val_if_fail (path, FALSE);
614
615   indices = gtk_tree_path_get_indices (path);
616   depth = gtk_tree_path_get_depth (path);
617
618   g_return_val_if_fail (depth == 1, FALSE);
619
620   n = indices [0];
621
622   if ( n < 0 || n >= psppire_dict_get_var_cnt (dict))
623     {
624       iter->stamp = 0;
625       iter->user_data = NULL;
626       return FALSE;
627     }
628
629   var = psppire_dict_get_variable (dict, n);
630
631   g_assert (var_get_dict_index (var) == n);
632
633   iter->stamp = dict->stamp;
634   iter->user_data = var;
635
636   return TRUE;
637 }
638
639
640 static gboolean
641 tree_model_iter_next (GtkTreeModel *model, GtkTreeIter *iter)
642 {
643   PsppireDict *dict = PSPPIRE_DICT (model);
644   struct variable *var;
645   gint idx;
646
647   g_return_val_if_fail (iter->stamp == dict->stamp, FALSE);
648
649   if ( iter == NULL || iter->user_data == NULL)
650     return FALSE;
651
652   var = iter->user_data;
653
654   idx = var_get_dict_index (var);
655
656   if ( idx + 1 >= psppire_dict_get_var_cnt (dict))
657     {
658       iter->user_data = NULL;
659       iter->stamp = 0;
660       return FALSE;
661     }
662
663   var = psppire_dict_get_variable (dict, idx + 1);
664
665   g_assert (var_get_dict_index (var) == idx + 1);
666
667   iter->user_data = var;
668
669   return TRUE;
670 }
671
672 static GtkTreePath *
673 tree_model_get_path (GtkTreeModel *model, GtkTreeIter *iter)
674 {
675   GtkTreePath *path;
676   struct variable *var;
677   PsppireDict *dict = PSPPIRE_DICT (model);
678
679   g_return_val_if_fail (iter->stamp == dict->stamp, FALSE);
680
681   var = iter->user_data;
682
683   path = gtk_tree_path_new ();
684   gtk_tree_path_append_index (path, var_get_dict_index (var));
685
686   return path;
687 }
688
689
690 static void
691 tree_model_get_value (GtkTreeModel *model, GtkTreeIter *iter,
692                       gint column, GValue *value)
693 {
694   struct variable *var;
695   PsppireDict *dict = PSPPIRE_DICT (model);
696
697   g_return_if_fail (iter->stamp == dict->stamp);
698
699   var =  iter->user_data;
700
701   switch (column)
702     {
703     case DICT_TVM_COL_NAME:
704       {
705       gchar *name = pspp_locale_to_utf8(var_get_name (var), -1, NULL);
706       g_value_init (value, G_TYPE_STRING);
707       g_value_set_string (value, name);
708       g_free (name);
709       }
710       break;
711     case DICT_TVM_COL_VAR:
712       g_value_init (value, G_TYPE_POINTER);
713       g_value_set_pointer (value, var);
714       break;
715     default:
716       g_return_if_reached ();
717       break;
718     }
719 }
720
721 static gboolean
722 tree_model_iter_children (GtkTreeModel *tree_model,
723                           GtkTreeIter *iter,
724                           GtkTreeIter *parent)
725 {
726   return FALSE;
727 }
728
729 static gint
730 tree_model_n_children (GtkTreeModel *model,
731                        GtkTreeIter  *iter)
732 {
733   PsppireDict *dict = PSPPIRE_DICT (model);
734
735   if ( iter == NULL )
736     return psppire_dict_get_var_cnt (dict);
737
738   return 0;
739 }
740
741 static gboolean
742 tree_model_nth_child (GtkTreeModel *model, GtkTreeIter *iter,
743                       GtkTreeIter *parent, gint n)
744 {
745   PsppireDict *dict;
746
747   g_return_val_if_fail (PSPPIRE_IS_DICT (model), FALSE);
748
749   dict = PSPPIRE_DICT (model);
750
751   if ( parent )
752     return FALSE;
753
754   if ( n >= psppire_dict_get_var_cnt (dict) )
755     return FALSE;
756
757   iter->stamp = dict->stamp;
758   iter->user_data = psppire_dict_get_variable (dict, n);
759
760   if ( !iter->user_data)
761     return FALSE;
762
763   return TRUE;
764 }
765
766
767 gboolean
768 psppire_dict_rename_var (PsppireDict *dict, struct variable *v,
769                          const gchar *name)
770 {
771   if ( ! var_is_valid_name (name, false))
772     return FALSE;
773
774   dict_rename_var (dict->dict, v, name);
775
776   return TRUE;
777 }
778
779
780 struct variable *
781 psppire_dict_get_weight_variable (const PsppireDict *dict)
782 {
783   return dict_get_weight (dict->dict);
784 }
785
786
787
788 #if DEBUGGING
789 void
790 psppire_dict_dump (const PsppireDict *dict)
791 {
792   gint i;
793   const struct dictionary *d = dict->dict;
794
795   for (i = 0; i < dict_get_var_cnt (d); ++i)
796     {
797       const struct variable *v = psppire_dict_get_variable (dict, i);
798       int di = var_get_dict_index (v);
799       g_print ("\"%s\" idx=%d, fv=%d, size=%d\n",
800                var_get_name(v),
801                di,
802                var_get_case_index(v),
803                value_cnt_from_width(var_get_width(v)));
804
805     }
806 }
807 #endif