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