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