fda121605a467dee5c5089c2a302780857554a6f
[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 signals [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   signals [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   signals [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   signals [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   cf->flexifile = flexifile_create (0);
161
162   return cf;
163 }
164
165
166 void
167 psppire_case_file_replace_flexifile (PsppireCaseFile *cf, struct flexifile *ff)
168 {
169   cf->flexifile = (struct casefile *) ff;
170 }
171
172
173
174 gboolean
175 psppire_case_file_delete_cases (PsppireCaseFile *cf, gint n_cases, gint first)
176 {
177   int result;
178
179   g_return_val_if_fail (cf, FALSE);
180   g_return_val_if_fail (cf->flexifile, FALSE);
181
182   result =  flexifile_delete_cases (FLEXIFILE (cf->flexifile), n_cases,  first);
183
184   g_signal_emit (cf, signals [CASES_DELETED], 0, n_cases, first);
185
186   return result;
187 }
188
189 /* Insert case CC into the case file before POSN */
190 gboolean
191 psppire_case_file_insert_case (PsppireCaseFile *cf,
192                               struct ccase *cc,
193                               gint posn)
194 {
195   bool result ;
196
197   g_return_val_if_fail (cf, FALSE);
198   g_return_val_if_fail (cf->flexifile, FALSE);
199
200   result = flexifile_insert_case (FLEXIFILE (cf->flexifile), cc, posn);
201
202   if ( result )
203     g_signal_emit (cf, signals [CASE_INSERTED], 0, posn);
204   else
205     g_warning ("Cannot insert case at position %d\n", posn);
206
207   return result;
208 }
209
210
211 /* Append a case to the case file */
212 gboolean
213 psppire_case_file_append_case (PsppireCaseFile *cf,
214                               struct ccase *c)
215 {
216   bool result ;
217   gint posn ;
218
219   g_return_val_if_fail (cf, FALSE);
220   g_return_val_if_fail (cf->flexifile, FALSE);
221
222   posn = casefile_get_case_cnt (cf->flexifile);
223
224   result = casefile_append (cf->flexifile, c);
225
226   g_signal_emit (cf, signals [CASE_INSERTED], 0, posn);
227
228   return result;
229 }
230
231
232 inline gint
233 psppire_case_file_get_case_count (const PsppireCaseFile *cf)
234 {
235   g_return_val_if_fail (cf, FALSE);
236
237   if ( ! cf->flexifile)
238     return 0;
239
240   return casefile_get_case_cnt (cf->flexifile);
241 }
242
243 /* Return the IDXth value from case CASENUM.
244    The return value must not be freed or written to
245  */
246 const union value *
247 psppire_case_file_get_value (const PsppireCaseFile *cf, gint casenum, gint idx)
248 {
249   const union value *v;
250   struct ccase c;
251
252   g_return_val_if_fail (cf, NULL);
253   g_return_val_if_fail (cf->flexifile, NULL);
254
255   g_return_val_if_fail (idx < casefile_get_value_cnt (cf->flexifile), NULL);
256
257   flexifile_get_case (FLEXIFILE (cf->flexifile), casenum, &c);
258
259   v = case_data_idx (&c, idx);
260   case_destroy (&c);
261
262   return v;
263 }
264
265 void
266 psppire_case_file_clear (PsppireCaseFile *cf)
267 {
268   casefile_destroy (cf->flexifile);
269   cf->flexifile = 0;
270   g_signal_emit (cf, signals [CASES_DELETED], 0, 0, -1);
271 }
272
273 /* Set the IDXth value of case C to SYSMIS/EMPTY */
274 gboolean
275 psppire_case_file_set_value (PsppireCaseFile *cf, gint casenum, gint idx,
276                             union value *v, gint width)
277 {
278   struct ccase cc ;
279   int bytes;
280
281   g_return_val_if_fail (cf, FALSE);
282   g_return_val_if_fail (cf->flexifile, FALSE);
283
284   g_return_val_if_fail (idx < casefile_get_value_cnt (cf->flexifile), FALSE);
285
286   if ( ! flexifile_get_case (FLEXIFILE (cf->flexifile), casenum, &cc) )
287     return FALSE;
288
289   if ( width == 0 )
290     bytes = MAX_SHORT_STRING;
291   else
292     bytes = DIV_RND_UP (width, MAX_SHORT_STRING) * MAX_SHORT_STRING ;
293
294   /* Cast away const in flagrant abuse of the casefile */
295   memcpy ((union value *)case_data_idx (&cc, idx), v, bytes);
296
297   g_signal_emit (cf, signals [CASE_CHANGED], 0, casenum);
298
299   return TRUE;
300 }
301
302
303
304 /* Set the IDXth value of case C using D_IN */
305 gboolean
306 psppire_case_file_data_in (PsppireCaseFile *cf, gint casenum, gint idx,
307                           struct substring input, const struct fmt_spec *fmt)
308 {
309   struct ccase cc ;
310
311   g_return_val_if_fail (cf, FALSE);
312   g_return_val_if_fail (cf->flexifile, FALSE);
313
314   g_return_val_if_fail (idx < casefile_get_value_cnt (cf->flexifile), FALSE);
315
316   if ( ! flexifile_get_case (FLEXIFILE (cf->flexifile), casenum, &cc) )
317     return FALSE;
318
319   /* Cast away const in flagrant abuse of the casefile */
320   if (!data_in (input, fmt->type, 0, 0,
321                 (union value *) case_data_idx (&cc, idx), fmt_var_width (fmt)))
322     g_warning ("Cant set value\n");
323
324   g_signal_emit (cf, signals [CASE_CHANGED], 0, casenum);
325
326   return TRUE;
327 }
328
329
330 void
331 psppire_case_file_sort (PsppireCaseFile *cf, const struct sort_criteria *sc)
332 {
333   gint c;
334
335   struct casereader *reader = casefile_get_reader (cf->flexifile, NULL);
336   struct casefile *cfile;
337
338   struct casefile_factory *factory  = flexifile_factory_create ();
339
340   cfile = sort_execute (reader, sc, factory);
341
342   casefile_destroy (cf->flexifile);
343
344   cf->flexifile = cfile;
345
346   /* FIXME: Need to have a signal to change a range of cases, instead of
347      calling a signal many times */
348   for ( c = 0 ; c < casefile_get_case_cnt (cf->flexifile) ; ++c )
349     g_signal_emit (cf, signals [CASE_CHANGED], 0, c);
350
351   flexifile_factory_destroy (factory);
352 }
353
354
355 /* Resize the cases in the casefile, by inserting N_VALUES into every
356    one of them. */
357 gboolean
358 psppire_case_file_insert_values (PsppireCaseFile *cf,
359                                  gint n_values, gint before)
360 {
361   g_return_val_if_fail (cf, FALSE);
362
363   if ( ! cf->flexifile )
364     {
365       cf->flexifile = flexifile_create (n_values);
366
367       return TRUE;
368     }
369
370   return flexifile_resize (FLEXIFILE (cf->flexifile), n_values, before);
371 }
372
373 /* Fills C with the CASENUMth case.
374    Returns true on success, false otherwise.
375  */
376 gboolean
377 psppire_case_file_get_case (const PsppireCaseFile *cf, gint casenum,
378                            struct ccase *c)
379 {
380   g_return_val_if_fail (cf, FALSE);
381   g_return_val_if_fail (cf->flexifile, FALSE);
382
383   return flexifile_get_case (FLEXIFILE (cf->flexifile), casenum, c);
384 }