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