Added new files resulting from directory restructuring.
[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 "gtkextra-marshal.c"
26
27 #include "psppire-object.h"
28 #include "psppire-dict.h"
29 #include "format.h"
30 #include "dictionary.h"
31 #include "missing-values.h"
32 #include "value-labels.h"
33
34
35 #include "message-dialog.h"
36 #include "psppire-variable.h"
37
38 /* --- prototypes --- */
39 static void psppire_dict_class_init     (PsppireDictClass       *class);
40 static void psppire_dict_init   (PsppireDict            *dict);
41 static void psppire_dict_finalize       (GObject                *object);
42
43
44 /* --- variables --- */
45 static GObjectClass     *parent_class = NULL;
46
47 enum  {VARIABLE_CHANGED, 
48        VARIABLE_INSERTED,
49        VARIABLE_DELETED, 
50        VARIABLES_DELETED, 
51        n_SIGNALS};
52
53 static guint signal[n_SIGNALS];
54
55 #define CACHE_CHUNK 5
56
57 /* --- functions --- */
58 /**
59  * psppire_dict_get_type:
60  * @returns: the type ID for accelerator groups.
61  */
62 GType
63 psppire_dict_get_type (void)
64 {
65   static GType object_type = 0;
66
67   if (!object_type)
68     {
69       static const GTypeInfo object_info = {
70         sizeof (PsppireDictClass),
71         (GBaseInitFunc) NULL,
72         (GBaseFinalizeFunc) NULL,
73         (GClassInitFunc) psppire_dict_class_init,
74         NULL,   /* class_finalize */
75         NULL,   /* class_data */
76         sizeof (PsppireDict),
77         0,      /* n_preallocs */
78         (GInstanceInitFunc) psppire_dict_init,
79       };
80
81       object_type = g_type_register_static (G_TYPE_PSPPIRE_OBJECT, "PsppireDict",
82                                             &object_info, 0);
83     }
84
85   return object_type;
86 }
87
88
89 static void
90 psppire_dict_class_init (PsppireDictClass *class)
91 {
92   GObjectClass *object_class = G_OBJECT_CLASS (class);
93
94   parent_class = g_type_class_peek_parent (class);
95
96   object_class->finalize = psppire_dict_finalize;
97
98   signal[VARIABLE_CHANGED] =
99     g_signal_new ("variable_changed",
100                   G_TYPE_FROM_CLASS(class),
101                   G_SIGNAL_RUN_FIRST,
102                   0,
103                   NULL, NULL,
104                   g_cclosure_marshal_VOID__INT,
105                   G_TYPE_NONE, 
106                   1,
107                   G_TYPE_INT);
108
109
110
111   signal[VARIABLE_INSERTED] =
112     g_signal_new ("variable_inserted",
113                   G_TYPE_FROM_CLASS(class),
114                   G_SIGNAL_RUN_FIRST,
115                   0,
116                   NULL, NULL,
117                   g_cclosure_marshal_VOID__INT,
118                   G_TYPE_NONE, 
119                   1,
120                   G_TYPE_INT);
121
122   signal[VARIABLE_DELETED] =
123     g_signal_new ("variable_deleted",
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   signal[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
148 static void
149 psppire_dict_finalize (GObject *object)
150 {
151   gint v;
152   PsppireDict *d = PSPPIRE_DICT (object);
153   
154
155
156   for (v = 0 ; v < psppire_dict_get_var_cnt(d) ; ++v ) 
157     g_free(d->variables[v]);
158
159   g_free(d->variables);
160   d->cache_size = 0;
161
162   dict_destroy(d->dict);
163
164   G_OBJECT_CLASS (parent_class)->finalize (object);
165 }
166
167 static void
168 psppire_dict_init (PsppireDict *psppire_dict)
169 {
170   psppire_dict->dict = dict_create();
171
172   psppire_dict->variables = 0; 
173   psppire_dict->cache_size = 0;
174 }
175
176 /**
177  * psppire_dict_new:
178  * @returns: a new #PsppireDict object
179  * 
180  * Creates a new #PsppireDict. 
181  */
182 PsppireDict*
183 psppire_dict_new (void)
184 {
185   return g_object_new (G_TYPE_PSPPIRE_DICT, NULL);
186 }
187
188
189 /**
190  * psppire_dict_new_from_dict:
191  * @returns: a new #PsppireDict object
192  * 
193  * Creates a new #PsppireDict. 
194  */
195 PsppireDict*
196 psppire_dict_new_from_dict (struct dictionary *d)
197 {
198   PsppireDict *new_dict = g_object_new (G_TYPE_PSPPIRE_DICT, NULL);
199   new_dict->dict = d;
200   new_dict->cache_size = dict_get_var_cnt(d);
201   new_dict->variables = g_malloc0(sizeof(struct PsppireVariable *) * 
202                                   new_dict->cache_size);
203
204
205   return new_dict;
206 }
207
208
209 /* Returns a valid name for a new variable in DICT.
210    The return value is statically allocated */
211 static gchar * 
212 auto_generate_var_name(PsppireDict *dict)
213 {
214   gint d = 0;
215   static gchar name[255];
216
217
218   while (g_snprintf(name, 255, "VAR%05d",d++),
219          psppire_dict_lookup_var(dict, name))
220     ;
221
222   return name;
223 }
224
225 /* Insert a new variable at posn IDX, with the name NAME.
226    If NAME is null, then a name will be automatically assigned.
227  */
228 void
229 psppire_dict_insert_variable(PsppireDict *d, gint idx, const gchar *name)
230 {
231   gint i;
232   g_return_if_fail(d);
233   g_return_if_fail(G_IS_PSPPIRE_DICT(d));
234
235
236   /* Invalidate the cache from IDX onwards */
237   for ( i = idx ; i < d->cache_size ; ++i ) 
238     {
239       g_free(d->variables[i]);
240       d->variables[i] = 0;
241     }
242
243   /* Ensure that the cache is large enough */
244   if ( dict_get_var_cnt(d->dict) >= d->cache_size ) 
245     {
246       d->variables = g_realloc(d->variables, sizeof(struct PsppireVariable*) * 
247                                (d->cache_size + CACHE_CHUNK));
248       d->cache_size += CACHE_CHUNK;
249     }
250
251   /* Zero the new pointers */
252   for ( ; i < d->cache_size ; ++i ) 
253     {
254       d->variables[i] = 0;
255     }
256
257   if ( ! name ) 
258     name = auto_generate_var_name(d);
259   
260   struct variable *var = 
261     dict_create_var(d->dict, name, 0);
262
263   dict_reorder_var(d->dict, var, idx);
264
265
266   d->variables[idx] = g_malloc(sizeof (struct PsppireVariable));
267   d->variables[idx]->v = var;
268   d->variables[idx]->dict = d;
269
270   g_signal_emit(d, signal[VARIABLE_INSERTED], 0, idx );  
271 }
272
273 /* Delete N variables beginning at FIRST */
274 void
275 psppire_dict_delete_variables(PsppireDict *d, gint first, gint n)
276 {
277   gint idx;
278   g_return_if_fail(d);
279   g_return_if_fail(d->dict);
280   g_return_if_fail(G_IS_PSPPIRE_DICT(d));
281
282   /* Invalidate all pvs from FIRST onwards */
283   for ( idx = first ; idx < d->cache_size ; ++idx ) 
284     {
285       g_free(d->variables[idx]);
286       d->variables[idx] = 0;
287     }
288
289   for (idx = 0 ; idx < n ; ++idx ) 
290     {
291       struct variable *var;
292
293       /* Do nothing if it's out of bounds */
294       if ( first >= dict_get_var_cnt (d->dict))
295         break; 
296
297       var = dict_get_var(d->dict, first);
298       dict_delete_var (d->dict, var);
299     }
300
301   g_signal_emit(d, signal[VARIABLES_DELETED], 0, first, idx );  
302 }
303
304
305 void
306 psppire_dict_set_name(PsppireDict* d, gint idx, const gchar *name)
307 {
308   struct variable *var;
309   g_assert(d);
310   g_assert(G_IS_PSPPIRE_DICT(d));
311
312
313   if ( idx < dict_get_var_cnt(d->dict))
314     {
315       /* This is an existing variable? */
316       var = dict_get_var(d->dict, idx);
317       dict_rename_var(d->dict, var, name);
318       g_signal_emit(d, signal[VARIABLE_CHANGED], 0, idx);
319     }
320   else
321     {
322       /* new variable */
323       dict_create_var(d->dict, name, 0);
324       g_print("Emitting variable-inserted signal\n");
325       g_signal_emit(d, signal[VARIABLE_INSERTED], 0, idx);
326     }
327 }
328
329
330
331 /* Return the IDXth variable */
332 struct PsppireVariable *
333 psppire_dict_get_variable(PsppireDict *d, gint idx)
334 {
335   g_return_val_if_fail(d, NULL);
336   g_return_val_if_fail(d->dict, NULL);
337   g_return_val_if_fail(d->variables, NULL);
338   
339   if (idx < 0 || idx >= psppire_dict_get_var_cnt(d))
340     return NULL;
341
342   struct PsppireVariable *var = d->variables[idx] ; 
343
344   if (! var ) 
345     {
346       var = g_malloc(sizeof (*var));
347       var->dict = d;
348       var->v = dict_get_var(d->dict, idx);
349       d->variables[idx] = var;
350     }
351     
352   return var;
353 }
354
355
356 /* Return the number of variables in the dictionary */
357 gint 
358 psppire_dict_get_var_cnt(const PsppireDict *d)
359 {
360   g_return_val_if_fail(d, -1);
361   g_return_val_if_fail(d->dict, -1);
362   
363
364   return dict_get_var_cnt(d->dict);
365 }
366
367
368 /* Return a variable by name.
369    Return NULL if it doesn't exist
370 */
371 struct variable *
372 psppire_dict_lookup_var (const PsppireDict *d, const gchar *name)
373 {
374   g_return_val_if_fail(d, NULL);
375   g_return_val_if_fail(d->dict, NULL);
376
377   return dict_lookup_var(d->dict, name);
378 }
379
380
381 void
382 psppire_dict_var_changed(PsppireDict *d, gint idx)
383 {
384   g_return_if_fail(d);
385
386   g_signal_emit(d, signal[VARIABLE_CHANGED], 0, idx);
387 }
388
389
390 /* Clears the contents of D */
391 void 
392 psppire_dict_clear(PsppireDict *d)
393 {
394   g_return_if_fail(d);
395   g_return_if_fail(d->dict);
396
397   const gint n_vars = dict_get_var_cnt(d->dict);
398   gint i;
399   
400   dict_clear(d->dict);
401
402   /* Invalidate the entire cache */
403   for ( i = 0 ; i < d->cache_size ; ++i ) 
404     {
405       g_free(d->variables[i]);
406       d->variables[i] = 0;
407     }
408
409   g_signal_emit(d, signal[VARIABLES_DELETED], 0, 0, n_vars );  
410 }
411
412
413
414 /* Return true is NAME would be a valid name of a variable to add to the 
415    dictionary.  False otherwise. 
416    If REPORT is true, then invalid names will be reported as such as errors
417 */
418 gboolean
419 psppire_dict_check_name(const PsppireDict *dict, 
420                      const gchar *name, gboolean report)
421 {
422   if ( ! var_is_valid_name(name, report ) )
423       return FALSE;
424
425   if (psppire_dict_lookup_var(dict, name))
426     {
427       if ( report ) 
428         msg(ME,"Duplicate variable name.");
429       return FALSE;
430     }
431
432   return TRUE;
433 }