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