Removed my authorship lines.
[pspp] / src / ui / gui / psppire-case-file.c
1 /* 
2     PSPPIRE --- A Graphical User Interface for PSPP
3     Copyright (C) 2006  Free Software Foundation
4
5     This program is free software; you can redistribute it and/or modify
6     it under the terms of the GNU General Public License as published by
7     the Free Software Foundation; either version 2 of the License, or
8     (at your option) any later version.
9
10     This program is distributed in the hope that it will be useful,
11     but WITHOUT ANY WARRANTY; without even the implied warranty of
12     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13     GNU General Public License for more details.
14
15     You should have received a copy of the GNU General Public License
16     along with this program; if not, write to the Free Software
17     Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
18     02110-1301, USA. */
19
20 #include <config.h>
21 #include <string.h>
22 #include <stdlib.h>
23
24 #include "psppire-object.h"
25 #include "psppire-case-file.h"
26
27 #include <gtksheet/gtkextra-marshal.h>
28
29 #include <data/case.h>
30 #include <ui/flexifile.h>
31 #include <data/casefile.h>
32 #include <data/data-in.h>
33 #include <math/sort.h>
34 #include <libpspp/misc.h>
35
36 /* --- prototypes --- */
37 static void psppire_case_file_class_init        (PsppireCaseFileClass   *class);
38 static void psppire_case_file_init      (PsppireCaseFile        *case_file);
39 static void psppire_case_file_finalize  (GObject                *object);
40
41
42 /* --- variables --- */
43 static GObjectClass     *parent_class = NULL;
44
45 enum  {CASE_CHANGED, 
46        CASE_INSERTED,
47        CASES_DELETED,
48        n_SIGNALS};
49
50 static guint signal[n_SIGNALS];
51
52
53 /* --- functions --- */
54 /**
55  * psppire_case_file_get_type:
56  * @returns: the type ID for accelerator groups.
57  */
58 GType
59 psppire_case_file_get_type (void)
60 {
61   static GType object_type = 0;
62
63   if (!object_type)
64     {
65       static const GTypeInfo object_info = {
66         sizeof (PsppireCaseFileClass),
67         (GBaseInitFunc) NULL,
68         (GBaseFinalizeFunc) NULL,
69         (GClassInitFunc) psppire_case_file_class_init,
70         NULL,   /* class_finalize */
71         NULL,   /* class_data */
72         sizeof (PsppireCaseFile),
73         0,      /* n_preallocs */
74         (GInstanceInitFunc) psppire_case_file_init,
75       };
76
77       object_type = g_type_register_static (G_TYPE_PSPPIRE_OBJECT, "PsppireCaseFile",
78                                             &object_info, 0);
79     }
80
81   return object_type;
82 }
83
84
85 static void
86 psppire_case_file_class_init (PsppireCaseFileClass *class)
87 {
88   GObjectClass *object_class = G_OBJECT_CLASS (class);
89
90   parent_class = g_type_class_peek_parent (class);
91
92   object_class->finalize = psppire_case_file_finalize;
93
94   signal[CASE_CHANGED] =
95     g_signal_new ("case_changed",
96                   G_TYPE_FROM_CLASS(class),
97                   G_SIGNAL_RUN_FIRST,
98                   0,
99                   NULL, NULL,
100                   g_cclosure_marshal_VOID__INT,
101                   G_TYPE_NONE, 
102                   1,
103                   G_TYPE_INT);
104
105
106   signal[CASE_INSERTED] =
107     g_signal_new ("case_inserted",
108                   G_TYPE_FROM_CLASS(class),
109                   G_SIGNAL_RUN_FIRST,
110                   0,
111                   NULL, NULL,
112                   g_cclosure_marshal_VOID__INT,
113                   G_TYPE_NONE, 
114                   1,
115                   G_TYPE_INT);
116
117
118   signal[CASES_DELETED] =
119     g_signal_new ("cases_deleted",
120                   G_TYPE_FROM_CLASS(class),
121                   G_SIGNAL_RUN_FIRST,
122                   0,
123                   NULL, NULL,
124                   gtkextra_VOID__INT_INT,
125                   G_TYPE_NONE, 
126                   2,
127                   G_TYPE_INT, G_TYPE_INT);
128 }
129
130 static void
131 psppire_case_file_finalize (GObject *object)
132 {
133   PsppireCaseFile *cf = PSPPIRE_CASE_FILE (object);
134   
135   if ( cf->flexifile) 
136     casefile_destroy(cf->flexifile);
137
138   G_OBJECT_CLASS (parent_class)->finalize (object);
139 }
140
141 static void
142 psppire_case_file_init (PsppireCaseFile *cf)
143 {
144   cf->flexifile = 0;
145 }
146
147 /**
148  * psppire_case_file_new:
149  * @returns: a new #PsppireCaseFile object
150  * 
151  * Creates a new #PsppireCaseFile. 
152  */
153 PsppireCaseFile*
154 psppire_case_file_new (gint val_cnt)
155 {
156   PsppireCaseFile *cf = g_object_new (G_TYPE_PSPPIRE_CASE_FILE, NULL);
157
158   cf->flexifile = flexifile_create (val_cnt);
159
160   return cf;
161 }
162
163
164 gboolean
165 psppire_case_file_delete_cases(PsppireCaseFile *cf, gint n_cases, gint first)
166 {
167   int result;
168
169   g_return_val_if_fail(cf, FALSE);
170   g_return_val_if_fail(cf->flexifile, FALSE);
171
172   result =  flexifile_delete_cases(FLEXIFILE(cf->flexifile), n_cases,  first);
173
174   g_signal_emit(cf, signal[CASES_DELETED], 0, n_cases, first);
175
176   return result;
177 }
178
179 /* Insert case CC into the case file before POSN */
180 gboolean
181 psppire_case_file_insert_case(PsppireCaseFile *cf, 
182                               struct ccase *cc,
183                               gint posn)
184 {
185   bool result ;
186
187   g_return_val_if_fail(cf, FALSE);
188   g_return_val_if_fail(cf->flexifile, FALSE);
189
190   result = flexifile_insert_case(FLEXIFILE(cf->flexifile), cc, posn);
191   
192   if ( result ) 
193     g_signal_emit(cf, signal[CASE_INSERTED], 0, posn);
194   else
195     g_warning("Cannot insert case at position %d\n", posn);
196                 
197   return result;
198 }
199
200
201 /* Append a case to the case file */
202 gboolean
203 psppire_case_file_append_case(PsppireCaseFile *cf, 
204                               struct ccase *c)
205 {
206   bool result ;
207   gint posn ;
208
209   g_return_val_if_fail(cf, FALSE);
210   g_return_val_if_fail(cf->flexifile, FALSE);
211
212   posn = casefile_get_case_cnt(cf->flexifile);
213
214   result = casefile_append(cf->flexifile, c);
215   
216   g_signal_emit(cf, signal[CASE_INSERTED], 0, posn);
217                 
218   return result;
219 }
220
221
222 inline gint
223 psppire_case_file_get_case_count(const PsppireCaseFile *cf)
224 {
225   g_return_val_if_fail(cf, FALSE);
226   
227   if ( ! cf->flexifile) 
228     return 0;
229
230   return casefile_get_case_cnt(cf->flexifile);
231 }
232
233 /* Return the IDXth value from case CASENUM.
234    The return value must not be freed or written to
235  */
236 const union value *
237 psppire_case_file_get_value(const PsppireCaseFile *cf, gint casenum, gint idx)
238 {
239   const union value *v; 
240   struct ccase c;
241
242   g_return_val_if_fail(cf, NULL);
243   g_return_val_if_fail(cf->flexifile, NULL);
244
245   g_return_val_if_fail(idx < casefile_get_value_cnt(cf->flexifile), NULL);
246
247   flexifile_get_case(FLEXIFILE(cf->flexifile), casenum, &c);
248
249   v = case_data_idx(&c, idx);
250
251   case_destroy(&c);
252
253   return v;
254 }
255
256 void
257 psppire_case_file_clear(PsppireCaseFile *cf)
258 {
259   casefile_destroy(cf->flexifile);
260   cf->flexifile = 0;
261   g_signal_emit(cf, signal[CASES_DELETED], 0, 0, -1);
262 }
263
264 /* Set the IDXth value of case C to SYSMIS/EMPTY */
265 gboolean
266 psppire_case_file_set_value(PsppireCaseFile *cf, gint casenum, gint idx,
267                             union value *v, gint width)
268 {
269   struct ccase cc ;
270   int bytes;
271
272   g_return_val_if_fail(cf, FALSE);
273   g_return_val_if_fail(cf->flexifile, FALSE);
274
275   g_return_val_if_fail(idx < casefile_get_value_cnt(cf->flexifile), FALSE);
276
277   if ( ! flexifile_get_case(FLEXIFILE(cf->flexifile), casenum, &cc) )
278     return FALSE;
279
280   if ( width == 0 ) 
281     bytes = MAX_SHORT_STRING;
282   else
283     bytes = DIV_RND_UP(width, MAX_SHORT_STRING) * MAX_SHORT_STRING ;
284
285   /* Cast away const in flagrant abuse of the casefile */
286   memcpy((union value *)case_data_idx(&cc, idx), v, bytes);
287
288   g_signal_emit(cf, signal[CASE_CHANGED], 0, casenum);
289
290   return TRUE;
291 }
292
293
294
295 /* Set the IDXth value of case C using D_IN */
296 gboolean
297 psppire_case_file_data_in(PsppireCaseFile *cf, gint casenum, gint idx,
298                           struct substring input, const struct fmt_spec *fmt)
299 {
300   struct ccase cc ;
301
302   g_return_val_if_fail(cf, FALSE);
303   g_return_val_if_fail(cf->flexifile, FALSE);
304
305   g_return_val_if_fail(idx < casefile_get_value_cnt(cf->flexifile), FALSE);
306
307   if ( ! flexifile_get_case(FLEXIFILE(cf->flexifile), casenum, &cc) )
308     return FALSE;
309
310   /* Cast away const in flagrant abuse of the casefile */
311   if (!data_in (input, fmt->type, 0, 0,
312                 (union value *) case_data_idx(&cc, idx), fmt_var_width (fmt)))
313     g_warning("Cant set value\n");
314
315   g_signal_emit(cf, signal[CASE_CHANGED], 0, casenum);
316
317   return TRUE;
318 }
319
320
321 void
322 psppire_case_file_sort(PsppireCaseFile *cf, const struct sort_criteria *sc)
323 {
324   struct ccase cc;
325   gint c;
326   struct casefile *cfile;
327   struct casereader *reader = casefile_get_reader (cf->flexifile, NULL);
328   const int value_cnt = casefile_get_value_cnt(cf->flexifile);
329
330   cfile = sort_execute(reader, sc);
331
332   casefile_destroy(cf->flexifile);
333
334   /* Copy casefile into flexifile */
335
336   reader = casefile_get_destructive_reader(cfile);
337   cf->flexifile = flexifile_create(value_cnt);
338   while(casereader_read(reader, &cc))
339       casefile_append(cf->flexifile, &cc);
340   
341
342   /* FIXME: Need to have a signal to change a range of cases, instead of
343      calling a signal many times */
344   for ( c = 0 ; c < casefile_get_case_cnt(cf->flexifile) ; ++c ) 
345     g_signal_emit(cf, signal[CASE_CHANGED], 0, c);
346 }
347
348
349 /* Resize the cases in the casefile, by inserting N_VALUES into every 
350    one of them. */
351 gboolean 
352 psppire_case_file_insert_values (PsppireCaseFile *cf, 
353                                  gint n_values, gint before)
354 {
355   g_return_val_if_fail(cf, FALSE);
356
357   if ( ! cf->flexifile ) 
358     {
359       cf->flexifile = flexifile_create(n_values);
360       return TRUE;
361     }
362
363   return flexifile_resize (FLEXIFILE(cf->flexifile), n_values, before);
364 }
365
366 /* Fills C with the CASENUMth case.
367    Returns true on success, false otherwise.
368  */
369 gboolean
370 psppire_case_file_get_case (const PsppireCaseFile *cf, gint casenum, 
371                            struct ccase *c)
372 {
373   g_return_val_if_fail (cf, FALSE);
374   g_return_val_if_fail (cf->flexifile, FALSE);
375
376   return flexifile_get_case (FLEXIFILE(cf->flexifile), casenum, c);
377 }