When inserting new cases into the data sheet, initialise them with blank/SYSMIS
[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   for (v = 0 ; v < psppire_dict_get_var_cnt(d) ; ++v ) 
155     g_free(d->variables[v]);
156
157   g_free(d->variables);
158   d->cache_size = 0;
159
160   dict_destroy(d->dict);
161
162   G_OBJECT_CLASS (parent_class)->finalize (object);
163 }
164
165 static void
166 psppire_dict_init (PsppireDict *psppire_dict)
167 {
168   psppire_dict->dict = dict_create();
169
170   psppire_dict->variables = 0; 
171   psppire_dict->cache_size = 0;
172 }
173
174 /**
175  * psppire_dict_new:
176  * @returns: a new #PsppireDict object
177  * 
178  * Creates a new #PsppireDict. 
179  */
180 PsppireDict*
181 psppire_dict_new (void)
182 {
183   return g_object_new (G_TYPE_PSPPIRE_DICT, NULL);
184 }
185
186
187 /**
188  * psppire_dict_new_from_dict:
189  * @returns: a new #PsppireDict object
190  * 
191  * Creates a new #PsppireDict. 
192  */
193 PsppireDict*
194 psppire_dict_new_from_dict (struct dictionary *d)
195 {
196   PsppireDict *new_dict = g_object_new (G_TYPE_PSPPIRE_DICT, NULL);
197   new_dict->dict = d;
198   new_dict->cache_size = dict_get_var_cnt(d);
199   new_dict->variables = g_malloc0(sizeof(struct PsppireVariable *) * 
200                                   new_dict->cache_size);
201
202
203   return new_dict;
204 }
205
206
207 /* Returns a valid name for a new variable in DICT.
208    The return value is statically allocated */
209 static gchar * 
210 auto_generate_var_name(PsppireDict *dict)
211 {
212   gint d = 0;
213   static gchar name[10];
214
215
216   while (g_snprintf(name, 10, "VAR%05d",d++),
217          psppire_dict_lookup_var(dict, name))
218     ;
219
220   return name;
221 }
222
223 /* Insert a new variable at posn IDX, with the name NAME.
224    If NAME is null, then a name will be automatically assigned.
225  */
226 void
227 psppire_dict_insert_variable(PsppireDict *d, gint idx, const gchar *name)
228 {
229   struct variable *var ;
230   gint i;
231   g_return_if_fail(d);
232   g_return_if_fail(G_IS_PSPPIRE_DICT(d));
233
234
235   /* Invalidate the cache from IDX onwards */
236   for ( i = idx ; i < d->cache_size ; ++i ) 
237     {
238       g_free(d->variables[i]);
239       d->variables[i] = 0;
240     }
241
242   /* Ensure that the cache is large enough */
243   if ( dict_get_var_cnt(d->dict) >= d->cache_size ) 
244     {
245       d->variables = g_realloc(d->variables, sizeof(struct PsppireVariable*) * 
246                                (d->cache_size + CACHE_CHUNK));
247       d->cache_size += CACHE_CHUNK;
248     }
249
250   /* Zero the new pointers */
251   for ( ; i < d->cache_size ; ++i ) 
252     {
253       d->variables[i] = 0;
254     }
255
256   if ( ! name ) 
257     name = auto_generate_var_name(d);
258   
259   var = dict_create_var(d->dict, name, 0);
260
261   dict_reorder_var(d->dict, var, idx);
262
263   d->variables[idx] = g_malloc(sizeof (struct PsppireVariable));
264   d->variables[idx]->v = var;
265   d->variables[idx]->dict = d;
266
267   g_signal_emit(d, signal[VARIABLE_INSERTED], 0, idx );  
268 }
269
270 /* Delete N variables beginning at FIRST */
271 void
272 psppire_dict_delete_variables(PsppireDict *d, gint first, gint n)
273 {
274   gint idx;
275   g_return_if_fail(d);
276   g_return_if_fail(d->dict);
277   g_return_if_fail(G_IS_PSPPIRE_DICT(d));
278
279   /* Invalidate all pvs from FIRST onwards */
280   for ( idx = first ; idx < d->cache_size ; ++idx ) 
281     {
282       g_free(d->variables[idx]);
283       d->variables[idx] = 0;
284     }
285
286   for (idx = 0 ; idx < n ; ++idx ) 
287     {
288       struct variable *var;
289
290       /* Do nothing if it's out of bounds */
291       if ( first >= dict_get_var_cnt (d->dict))
292         break; 
293
294       var = dict_get_var(d->dict, first);
295       dict_delete_var (d->dict, var);
296     }
297
298   g_signal_emit(d, signal[VARIABLES_DELETED], 0, first, idx );  
299 }
300
301
302 void
303 psppire_dict_set_name(PsppireDict* d, gint idx, const gchar *name)
304 {
305   struct variable *var;
306   g_assert(d);
307   g_assert(G_IS_PSPPIRE_DICT(d));
308
309
310   if ( idx < dict_get_var_cnt(d->dict))
311     {
312       /* This is an existing variable? */
313       var = dict_get_var(d->dict, idx);
314       dict_rename_var(d->dict, var, name);
315       g_signal_emit(d, signal[VARIABLE_CHANGED], 0, idx);
316     }
317   else
318     {
319       /* new variable */
320       dict_create_var(d->dict, name, 0);
321       g_print("Emitting variable-inserted signal\n");
322       g_signal_emit(d, signal[VARIABLE_INSERTED], 0, idx);
323     }
324 }
325
326
327
328 /* Return the IDXth variable */
329 struct PsppireVariable *
330 psppire_dict_get_variable(PsppireDict *d, gint idx)
331 {
332   struct PsppireVariable *var ;
333   g_return_val_if_fail(d, NULL);
334   g_return_val_if_fail(d->dict, NULL);
335   g_return_val_if_fail(d->variables, NULL);
336   
337   if (idx < 0 || idx >= psppire_dict_get_var_cnt(d))
338     return NULL;
339
340   var = d->variables[idx] ; 
341
342   if (! var ) 
343     {
344       var = g_malloc(sizeof (*var));
345       var->dict = d;
346       var->v = dict_get_var(d->dict, idx);
347       d->variables[idx] = var;
348     }
349     
350   return var;
351 }
352
353
354 /* Return the number of variables in the dictionary */
355 gint 
356 psppire_dict_get_var_cnt(const PsppireDict *d)
357 {
358   g_return_val_if_fail(d, -1);
359   g_return_val_if_fail(d->dict, -1);
360   
361
362   return dict_get_var_cnt(d->dict);
363 }
364
365
366 /* Return a variable by name.
367    Return NULL if it doesn't exist
368 */
369 struct variable *
370 psppire_dict_lookup_var (const PsppireDict *d, const gchar *name)
371 {
372   g_return_val_if_fail(d, NULL);
373   g_return_val_if_fail(d->dict, NULL);
374
375   return dict_lookup_var(d->dict, name);
376 }
377
378
379 void
380 psppire_dict_var_changed(PsppireDict *d, gint idx)
381 {
382   g_return_if_fail(d);
383
384   g_signal_emit(d, signal[VARIABLE_CHANGED], 0, idx);
385 }
386
387
388 /* Clears the contents of D */
389 void 
390 psppire_dict_clear(PsppireDict *d)
391 {
392   g_return_if_fail(d);
393   g_return_if_fail(d->dict);
394
395   {
396     const gint n_vars = dict_get_var_cnt(d->dict);
397     gint i;
398   
399     dict_clear(d->dict);
400
401     /* Invalidate the entire cache */
402     for ( i = 0 ; i < d->cache_size ; ++i ) 
403       {
404         g_free(d->variables[i]);
405         d->variables[i] = 0;
406       }
407
408     g_signal_emit(d, signal[VARIABLES_DELETED], 0, 0, n_vars );  
409   }
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 }