Fixed a multitude of C89 compatibility warnings.
[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 <gtksheet/gtkextra-marshal.c>
26
27 #include "psppire-object.h"
28 #include "psppire-dict.h"
29 #include <data/format.h>
30 #include <data/dictionary.h>
31 #include <data/missing-values.h>
32 #include <data/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   struct variable *var ;
232   gint i;
233   g_return_if_fail(d);
234   g_return_if_fail(G_IS_PSPPIRE_DICT(d));
235
236
237   /* Invalidate the cache from IDX onwards */
238   for ( i = idx ; i < d->cache_size ; ++i ) 
239     {
240       g_free(d->variables[i]);
241       d->variables[i] = 0;
242     }
243
244   /* Ensure that the cache is large enough */
245   if ( dict_get_var_cnt(d->dict) >= d->cache_size ) 
246     {
247       d->variables = g_realloc(d->variables, sizeof(struct PsppireVariable*) * 
248                                (d->cache_size + CACHE_CHUNK));
249       d->cache_size += CACHE_CHUNK;
250     }
251
252   /* Zero the new pointers */
253   for ( ; i < d->cache_size ; ++i ) 
254     {
255       d->variables[i] = 0;
256     }
257
258   if ( ! name ) 
259     name = auto_generate_var_name(d);
260   
261   var = dict_create_var(d->dict, name, 0);
262
263   dict_reorder_var(d->dict, var, idx);
264
265   d->variables[idx] = g_malloc(sizeof (struct PsppireVariable));
266   d->variables[idx]->v = var;
267   d->variables[idx]->dict = d;
268
269   g_signal_emit(d, signal[VARIABLE_INSERTED], 0, idx );  
270 }
271
272 /* Delete N variables beginning at FIRST */
273 void
274 psppire_dict_delete_variables(PsppireDict *d, gint first, gint n)
275 {
276   gint idx;
277   g_return_if_fail(d);
278   g_return_if_fail(d->dict);
279   g_return_if_fail(G_IS_PSPPIRE_DICT(d));
280
281   /* Invalidate all pvs from FIRST onwards */
282   for ( idx = first ; idx < d->cache_size ; ++idx ) 
283     {
284       g_free(d->variables[idx]);
285       d->variables[idx] = 0;
286     }
287
288   for (idx = 0 ; idx < n ; ++idx ) 
289     {
290       struct variable *var;
291
292       /* Do nothing if it's out of bounds */
293       if ( first >= dict_get_var_cnt (d->dict))
294         break; 
295
296       var = dict_get_var(d->dict, first);
297       dict_delete_var (d->dict, var);
298     }
299
300   g_signal_emit(d, signal[VARIABLES_DELETED], 0, first, idx );  
301 }
302
303
304 void
305 psppire_dict_set_name(PsppireDict* d, gint idx, const gchar *name)
306 {
307   struct variable *var;
308   g_assert(d);
309   g_assert(G_IS_PSPPIRE_DICT(d));
310
311
312   if ( idx < dict_get_var_cnt(d->dict))
313     {
314       /* This is an existing variable? */
315       var = dict_get_var(d->dict, idx);
316       dict_rename_var(d->dict, var, name);
317       g_signal_emit(d, signal[VARIABLE_CHANGED], 0, idx);
318     }
319   else
320     {
321       /* new variable */
322       dict_create_var(d->dict, name, 0);
323       g_print("Emitting variable-inserted signal\n");
324       g_signal_emit(d, signal[VARIABLE_INSERTED], 0, idx);
325     }
326 }
327
328
329
330 /* Return the IDXth variable */
331 struct PsppireVariable *
332 psppire_dict_get_variable(PsppireDict *d, gint idx)
333 {
334   struct PsppireVariable *var ;
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   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   {
398     const gint n_vars = dict_get_var_cnt(d->dict);
399     gint i;
400   
401     dict_clear(d->dict);
402
403     /* Invalidate the entire cache */
404     for ( i = 0 ; i < d->cache_size ; ++i ) 
405       {
406         g_free(d->variables[i]);
407         d->variables[i] = 0;
408       }
409
410     g_signal_emit(d, signal[VARIABLES_DELETED], 0, 0, n_vars );  
411   }
412 }
413
414
415
416 /* Return true is NAME would be a valid name of a variable to add to the 
417    dictionary.  False otherwise. 
418    If REPORT is true, then invalid names will be reported as such as errors
419 */
420 gboolean
421 psppire_dict_check_name(const PsppireDict *dict, 
422                      const gchar *name, gboolean report)
423 {
424   if ( ! var_is_valid_name(name, report ) )
425       return FALSE;
426
427   if (psppire_dict_lookup_var(dict, name))
428     {
429       if ( report ) 
430         msg(ME,"Duplicate variable name.");
431       return FALSE;
432     }
433
434   return TRUE;
435 }