First step in making struct variable opaque: the boring mechanical
[pspp-builds.git] / src / ui / gui / psppire-dict.c
1 /* 
2     PSPPIRE --- A Graphical User Interface for PSPP
3     Copyright (C) 2004, 2006  Free Software Foundation
4     Written by John Darrington
5
6     This program is free software; you can redistribute it and/or modify
7     it under the terms of the GNU General Public License as published by
8     the Free Software Foundation; either version 2 of the License, or
9     (at your option) any later version.
10
11     This program is distributed in the hope that it will be useful,
12     but WITHOUT ANY WARRANTY; without even the implied warranty of
13     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14     GNU General Public License for more details.
15
16     You should have received a copy of the GNU General Public License
17     along with this program; if not, write to the Free Software
18     Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
19     02110-1301, USA. */
20
21
22 #include <string.h>
23 #include <stdlib.h>
24
25 #include <gtk/gtk.h>
26 #include <gtksheet/gtkextra-marshal.h>
27
28 #include "psppire-object.h"
29 #include "psppire-dict.h"
30 #include <data/format.h>
31 #include <data/dictionary.h>
32 #include <data/missing-values.h>
33 #include <data/value-labels.h>
34
35
36 #include "message-dialog.h"
37 #include "psppire-variable.h"
38
39 /* --- prototypes --- */
40 static void psppire_dict_class_init     (PsppireDictClass       *class);
41 static void psppire_dict_init   (PsppireDict            *dict);
42 static void psppire_dict_finalize       (GObject                *object);
43
44 static void dictionary_tree_model_init(GtkTreeModelIface *iface);
45
46
47 /* --- variables --- */
48 static GObjectClass     *parent_class = NULL;
49
50 enum  {VARIABLE_CHANGED, 
51        VARIABLE_RESIZED,
52        VARIABLE_INSERTED,
53        VARIABLES_DELETED, 
54        n_SIGNALS};
55
56 static guint signal[n_SIGNALS];
57
58 #define CACHE_CHUNK 5
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_PSPPIRE_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   signal[VARIABLE_CHANGED] =
114     g_signal_new ("variable_changed",
115                   G_TYPE_FROM_CLASS(class),
116                   G_SIGNAL_RUN_FIRST,
117                   0,
118                   NULL, NULL,
119                   g_cclosure_marshal_VOID__INT,
120                   G_TYPE_NONE, 
121                   1,
122                   G_TYPE_INT);
123
124
125
126   signal[VARIABLE_INSERTED] =
127     g_signal_new ("variable_inserted",
128                   G_TYPE_FROM_CLASS(class),
129                   G_SIGNAL_RUN_FIRST,
130                   0,
131                   NULL, NULL,
132                   g_cclosure_marshal_VOID__INT,
133                   G_TYPE_NONE, 
134                   1,
135                   G_TYPE_INT);
136
137
138   signal[VARIABLES_DELETED] =
139     g_signal_new ("variables_deleted",
140                   G_TYPE_FROM_CLASS(class),
141                   G_SIGNAL_RUN_FIRST,
142                   0,
143                   NULL, NULL,
144                   gtkextra_VOID__INT_INT,
145                   G_TYPE_NONE, 
146                   2,
147                   G_TYPE_INT,
148                   G_TYPE_INT);
149
150
151   signal[VARIABLE_RESIZED] =
152     g_signal_new ("dict-size-changed",
153                   G_TYPE_FROM_CLASS(class),
154                   G_SIGNAL_RUN_FIRST,
155                   0,
156                   NULL, NULL,
157                   gtkextra_VOID__INT_INT,
158                   G_TYPE_NONE, 
159                   2,
160                   G_TYPE_INT,
161                   G_TYPE_INT);
162
163 }
164
165 static void
166 psppire_dict_finalize (GObject *object)
167 {
168   gint v;
169   PsppireDict *d = PSPPIRE_DICT (object);
170   
171   for (v = 0 ; v < psppire_dict_get_var_cnt(d) ; ++v ) 
172     g_free(d->variables[v]);
173
174   g_free(d->variables);
175   d->cache_size = 0;
176
177   dict_destroy(d->dict);
178
179   G_OBJECT_CLASS (parent_class)->finalize (object);
180 }
181
182 static void
183 psppire_dict_init (PsppireDict *psppire_dict)
184 {
185   psppire_dict->dict = dict_create();
186
187   psppire_dict->variables = 0; 
188   psppire_dict->cache_size = 0;
189
190   psppire_dict->stamp = g_random_int();
191 }
192
193 /**
194  * psppire_dict_new:
195  * @returns: a new #PsppireDict object
196  * 
197  * Creates a new #PsppireDict. 
198  */
199 PsppireDict*
200 psppire_dict_new (void)
201 {
202   return g_object_new (G_TYPE_PSPPIRE_DICT, NULL);
203 }
204
205
206 /**
207  * psppire_dict_new_from_dict:
208  * @returns: a new #PsppireDict object
209  * 
210  * Creates a new #PsppireDict. 
211  */
212 PsppireDict*
213 psppire_dict_new_from_dict (struct dictionary *d)
214 {
215   PsppireDict *new_dict = g_object_new (G_TYPE_PSPPIRE_DICT, NULL);
216   new_dict->dict = d;
217   new_dict->cache_size = dict_get_var_cnt(d);
218   new_dict->variables = g_malloc0(sizeof(struct PsppireVariable *) * 
219                                   new_dict->cache_size);
220
221
222   return new_dict;
223 }
224
225
226 /* Returns a valid name for a new variable in DICT.
227    The return value is statically allocated */
228 static gchar * 
229 auto_generate_var_name(PsppireDict *dict)
230 {
231   gint d = 0;
232   static gchar name[10];
233
234
235   while (g_snprintf(name, 10, "VAR%05d",d++),
236          psppire_dict_lookup_var(dict, name))
237     ;
238
239   return name;
240 }
241
242 /* Insert a new variable at posn IDX, with the name NAME.
243    If NAME is null, then a name will be automatically assigned.
244  */
245 void
246 psppire_dict_insert_variable(PsppireDict *d, gint idx, const gchar *name)
247 {
248   struct variable *var ;
249   gint i;
250   g_return_if_fail(d);
251   g_return_if_fail(G_IS_PSPPIRE_DICT(d));
252
253
254   /* Invalidate the cache from IDX onwards */
255   for ( i = idx ; i < d->cache_size ; ++i ) 
256     {
257       g_free(d->variables[i]);
258       d->variables[i] = 0;
259     }
260
261   /* Ensure that the cache is large enough */
262   if ( dict_get_var_cnt(d->dict) >= d->cache_size ) 
263     {
264       d->variables = g_realloc(d->variables, sizeof(struct PsppireVariable*) * 
265                                (d->cache_size + CACHE_CHUNK));
266       d->cache_size += CACHE_CHUNK;
267     }
268
269   /* Zero the new pointers */
270   for ( ; i < d->cache_size ; ++i ) 
271     {
272       d->variables[i] = 0;
273     }
274
275   if ( ! name ) 
276     name = auto_generate_var_name(d);
277   
278   var = dict_create_var(d->dict, name, 0);
279
280   dict_reorder_var(d->dict, var, idx);
281
282   d->variables[idx] = g_malloc(sizeof (struct PsppireVariable));
283   d->variables[idx]->v = var;
284   d->variables[idx]->dict = d;
285
286   g_signal_emit(d, signal[VARIABLE_INSERTED], 0, idx );  
287 }
288
289 /* Delete N variables beginning at FIRST */
290 void
291 psppire_dict_delete_variables(PsppireDict *d, gint first, gint n)
292 {
293   gint idx;
294   g_return_if_fail(d);
295   g_return_if_fail(d->dict);
296   g_return_if_fail(G_IS_PSPPIRE_DICT(d));
297
298   /* Invalidate all pvs from FIRST onwards */
299   for ( idx = first ; idx < d->cache_size ; ++idx ) 
300     {
301       g_free(d->variables[idx]);
302       d->variables[idx] = 0;
303     }
304
305   for (idx = 0 ; idx < n ; ++idx ) 
306     {
307       struct variable *var;
308
309       /* Do nothing if it's out of bounds */
310       if ( first >= dict_get_var_cnt (d->dict))
311         break; 
312
313       var = dict_get_var(d->dict, first);
314       dict_delete_var (d->dict, var);
315     }
316   dict_compact_values(d->dict);
317
318   g_signal_emit(d, signal[VARIABLES_DELETED], 0, first, idx );  
319 }
320
321
322 void
323 psppire_dict_set_name(PsppireDict* d, gint idx, const gchar *name)
324 {
325   struct variable *var;
326   g_assert(d);
327   g_assert(G_IS_PSPPIRE_DICT(d));
328
329
330   if ( idx < dict_get_var_cnt(d->dict))
331     {
332       /* This is an existing variable? */
333       var = dict_get_var(d->dict, idx);
334       dict_rename_var(d->dict, var, name);
335       g_signal_emit(d, signal[VARIABLE_CHANGED], 0, idx);
336     }
337   else
338     {
339       /* new variable */
340       dict_create_var(d->dict, name, 0);
341       g_signal_emit(d, signal[VARIABLE_INSERTED], 0, idx);
342     }
343 }
344
345
346
347 /* Return the IDXth variable */
348 struct PsppireVariable *
349 psppire_dict_get_variable(PsppireDict *d, gint idx)
350 {
351   struct PsppireVariable *var ;
352   g_return_val_if_fail(d, NULL);
353   g_return_val_if_fail(d->dict, NULL);
354
355   if ( ! d->variables) 
356     return NULL;
357   
358   if (idx < 0 || idx >= psppire_dict_get_var_cnt(d))
359     return NULL;
360
361   var = d->variables[idx] ; 
362
363   if (! var ) 
364     {
365       var = g_malloc(sizeof (*var));
366       var->dict = d;
367       var->v = dict_get_var(d->dict, idx);
368       d->variables[idx] = var;
369     }
370     
371   return var;
372 }
373
374
375 /* Return the number of variables in the dictionary */
376 gint 
377 psppire_dict_get_var_cnt(const PsppireDict *d)
378 {
379   g_return_val_if_fail(d, -1);
380   g_return_val_if_fail(d->dict, -1);
381   
382
383   return dict_get_var_cnt(d->dict);
384 }
385
386
387 /* Return a variable by name.
388    Return NULL if it doesn't exist
389 */
390 struct variable *
391 psppire_dict_lookup_var (const PsppireDict *d, const gchar *name)
392 {
393   g_return_val_if_fail(d, NULL);
394   g_return_val_if_fail(d->dict, NULL);
395
396   return dict_lookup_var(d->dict, name);
397 }
398
399
400 void
401 psppire_dict_var_changed(PsppireDict *d, gint idx)
402 {
403   g_return_if_fail(d);
404
405   g_signal_emit(d, signal[VARIABLE_CHANGED], 0, idx);
406 }
407
408
409 /* Clears the contents of D */
410 void 
411 psppire_dict_clear(PsppireDict *d)
412 {
413   g_return_if_fail(d);
414   g_return_if_fail(d->dict);
415
416   {
417     const gint n_vars = dict_get_var_cnt(d->dict);
418     gint i;
419   
420     dict_clear(d->dict);
421
422     /* Invalidate the entire cache */
423     for ( i = 0 ; i < d->cache_size ; ++i ) 
424       {
425         g_free(d->variables[i]);
426         d->variables[i] = 0;
427       }
428
429     g_signal_emit(d, signal[VARIABLES_DELETED], 0, 0, n_vars );  
430   }
431 }
432
433
434
435 /* Return true is NAME would be a valid name of a variable to add to the 
436    dictionary.  False otherwise. 
437    If REPORT is true, then invalid names will be reported as such as errors
438 */
439 gboolean
440 psppire_dict_check_name(const PsppireDict *dict, 
441                      const gchar *name, gboolean report)
442 {
443   if ( ! var_is_valid_name(name, report ) )
444       return FALSE;
445
446   if (psppire_dict_lookup_var(dict, name))
447     {
448       if ( report ) 
449         msg(ME,"Duplicate variable name.");
450       return FALSE;
451     }
452
453   return TRUE;
454 }
455
456
457 inline gint 
458 psppire_dict_get_next_value_idx (const PsppireDict *dict)
459 {
460   return dict_get_next_value_idx(dict->dict);
461 }
462
463
464 void 
465 psppire_dict_resize_variable(PsppireDict *d, const struct PsppireVariable *pv,
466                              gint old_size, gint new_size)
467 {
468   gint fv;
469   g_return_if_fail (d);
470   g_return_if_fail (d->dict);
471   
472   if ( old_size == new_size ) 
473     return ;
474
475   dict_compact_values(d->dict);
476
477   fv = psppire_variable_get_fv(pv);
478
479   g_signal_emit(d, signal[VARIABLE_RESIZED], 0, 
480                 fv + old_size, 
481                 new_size - old_size );  
482 }
483
484
485
486
487
488 /* Tree Model Stuff */
489
490 static GtkTreeModelFlags tree_model_get_flags(GtkTreeModel *model);
491
492 static gint tree_model_n_columns(GtkTreeModel *model);
493
494 static GType tree_model_column_type(GtkTreeModel *model, gint index);
495
496 static gboolean tree_model_get_iter(GtkTreeModel *model, GtkTreeIter *iter, 
497                                     GtkTreePath *path);
498
499 static gboolean tree_model_iter_next(GtkTreeModel *model, GtkTreeIter *iter);
500
501 static GtkTreePath * tree_model_get_path(GtkTreeModel *model, 
502                                          GtkTreeIter *iter);
503
504 static void tree_model_get_value(GtkTreeModel *model, GtkTreeIter *iter,
505                                  gint column, GValue *value);
506
507 static gboolean tree_model_nth_child(GtkTreeModel *model, GtkTreeIter *iter, 
508                                      GtkTreeIter *parent, gint n);
509
510
511 static void
512 dictionary_tree_model_init(GtkTreeModelIface *iface)
513 {
514   iface->get_flags = tree_model_get_flags;
515   iface->get_n_columns = tree_model_n_columns;
516   iface->get_column_type = tree_model_column_type;
517   iface->get_iter = tree_model_get_iter;
518   iface->iter_next = tree_model_iter_next;
519   iface->get_path = tree_model_get_path;
520   iface->get_value = tree_model_get_value;
521
522   iface->iter_children = 0;
523   iface->iter_has_child =0;
524   iface->iter_n_children =0;
525   iface->iter_nth_child = tree_model_nth_child ;
526   iface->iter_parent =0;
527 }
528
529 static GtkTreeModelFlags
530 tree_model_get_flags(GtkTreeModel *model)
531 {
532   g_return_val_if_fail(G_IS_PSPPIRE_DICT(model), (GtkTreeModelFlags) 0);
533
534   return GTK_TREE_MODEL_LIST_ONLY;
535 }
536
537
538 static gint
539 tree_model_n_columns(GtkTreeModel *model)
540 {
541   return n_DICT_COLS;
542 }
543
544 static GType
545 tree_model_column_type(GtkTreeModel *model, gint index)
546 {
547  g_return_val_if_fail(G_IS_PSPPIRE_DICT(model), (GType) 0);
548
549  switch(index) 
550    {
551    case DICT_TVM_COL_NAME:
552      return G_TYPE_STRING;
553      break;
554    case DICT_TVM_COL_VAR:
555      return G_TYPE_POINTER;
556      break;
557    default:
558      g_return_val_if_reached((GType)0);
559      break;
560    }
561
562  g_assert_not_reached();
563  return ((GType)0);
564 }
565
566 static gboolean
567 tree_model_get_iter(GtkTreeModel *model, GtkTreeIter *iter, GtkTreePath *path)
568 {
569   gint *indices, depth;
570   gint n;
571   struct PsppireVariable *variable;
572
573   PsppireDict *dict = PSPPIRE_DICT (model);
574
575   g_return_val_if_fail(path, FALSE);
576
577   indices = gtk_tree_path_get_indices(path);
578   depth = gtk_tree_path_get_depth(path);
579
580   g_return_val_if_fail(depth == 1, FALSE);
581
582   n = indices[0];
583
584   if ( n < 0 || n >= psppire_dict_get_var_cnt(dict)) 
585     return FALSE;
586
587   variable = psppire_dict_get_variable(dict, n);
588
589   g_assert(psppire_variable_get_index(variable) == n);
590
591   iter->stamp = dict->stamp;
592   iter->user_data = variable; 
593
594   return TRUE;
595 }
596
597
598 static gboolean
599 tree_model_iter_next(GtkTreeModel *model, GtkTreeIter *iter)
600 {
601   PsppireDict *dict = PSPPIRE_DICT (model);
602   struct PsppireVariable *variable;
603   gint idx;
604
605   g_return_val_if_fail(iter->stamp == dict->stamp, FALSE);
606
607   if ( iter == NULL || iter->user_data == NULL)
608     return FALSE;
609
610   variable = (struct PsppireVariable *) iter->user_data;
611
612   idx = psppire_variable_get_index(variable);
613   
614   if ( idx + 1 >= psppire_dict_get_var_cnt(dict))
615     return FALSE;
616
617   variable = psppire_dict_get_variable(dict, idx + 1);
618
619   g_assert(psppire_variable_get_index(variable) == idx + 1);
620   
621   iter->user_data = variable;
622
623   return TRUE;
624 }
625
626 static GtkTreePath *
627 tree_model_get_path(GtkTreeModel *model, GtkTreeIter *iter)
628 {
629   GtkTreePath *path;
630   struct PsppireVariable *variable;
631   PsppireDict *dict = PSPPIRE_DICT (model);
632
633   g_return_val_if_fail(iter->stamp == dict->stamp, FALSE);
634
635   variable = (struct PsppireVariable *) iter->user_data;
636
637   path = gtk_tree_path_new();
638   gtk_tree_path_append_index(path, psppire_variable_get_index(variable));
639
640   return path;
641 }
642
643
644 static void
645 tree_model_get_value(GtkTreeModel *model, GtkTreeIter *iter,
646                      gint column, GValue *value)
647 {
648   struct PsppireVariable *variable;
649   PsppireDict *dict = PSPPIRE_DICT (model);
650
651   g_return_if_fail(iter->stamp == dict->stamp);
652
653   variable = (struct PsppireVariable *) iter->user_data;
654
655   switch(column)
656     {
657     case DICT_TVM_COL_NAME:
658       g_value_init(value, G_TYPE_STRING);
659       g_value_set_string(value, psppire_variable_get_name(variable));
660       break;
661     case DICT_TVM_COL_VAR:
662       g_value_init(value, G_TYPE_POINTER);
663       g_value_set_pointer(value, variable);
664       break;
665     default:
666       g_return_if_reached();
667       break;
668     }
669 }
670
671
672 static gboolean
673 tree_model_nth_child(GtkTreeModel *model, GtkTreeIter *iter, 
674                      GtkTreeIter *parent, gint n)
675 {
676   PsppireDict *dict;
677   g_return_val_if_fail(G_IS_PSPPIRE_DICT(model), FALSE);
678
679   dict = PSPPIRE_DICT(model);
680
681   if ( parent ) 
682     return FALSE;
683
684   if ( n >= psppire_dict_get_var_cnt(dict) ) 
685     return FALSE;
686
687   iter->stamp = dict->stamp;
688   iter->user_data = psppire_dict_get_variable(dict, n);
689
690   if ( !iter->user_data) 
691     return FALSE;
692   
693   
694   return TRUE;
695 }