1 /* PSPPIRE - a graphical user interface for PSPP.
2 Copyright (C) 2006 Free Software Foundation
4 This program is free software: you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation, either version 3 of the License, or
7 (at your option) any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with this program. If not, see <http://www.gnu.org/licenses/>. */
21 #include "psppire-case-file.h"
23 #include <gtksheet/gtkextra-marshal.h>
25 #include <data/case.h>
26 #include <data/data-in.h>
27 #include <data/datasheet.h>
28 #include <data/casereader.h>
29 #include <math/sort.h>
30 #include <libpspp/misc.h>
35 /* --- prototypes --- */
36 static void psppire_case_file_class_init (PsppireCaseFileClass *class);
37 static void psppire_case_file_init (PsppireCaseFile *case_file);
38 static void psppire_case_file_finalize (GObject *object);
41 /* --- variables --- */
42 static GObjectClass *parent_class = NULL;
49 static guint signals [n_SIGNALS];
52 /* --- functions --- */
54 * psppire_case_file_get_type:
55 * @returns: the type ID for accelerator groups.
58 psppire_case_file_get_type (void)
60 static GType object_type = 0;
64 static const GTypeInfo object_info = {
65 sizeof (PsppireCaseFileClass),
67 (GBaseFinalizeFunc) NULL,
68 (GClassInitFunc) psppire_case_file_class_init,
69 NULL, /* class_finalize */
70 NULL, /* class_data */
71 sizeof (PsppireCaseFile),
73 (GInstanceInitFunc) psppire_case_file_init,
76 object_type = g_type_register_static (G_TYPE_OBJECT, "PsppireCaseFile",
95 psppire_case_file_set_property (GObject *object,
101 PsppireCaseFile *cf = PSPPIRE_CASE_FILE (object);
106 cf->datasheet = datasheet_create (g_value_get_pointer (value));
107 cf->accessible = TRUE;
110 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
116 psppire_case_file_get_property (GObject *object,
121 PsppireCaseFile *cf = PSPPIRE_CASE_FILE (object);
126 g_value_set_pointer (value, cf->datasheet);
129 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
136 psppire_case_file_class_init (PsppireCaseFileClass *class)
138 GObjectClass *object_class = G_OBJECT_CLASS (class);
139 GParamSpec *datasheet_spec ;
140 GParamSpec *reader_spec ;
142 parent_class = g_type_class_peek_parent (class);
144 object_class->finalize = psppire_case_file_finalize;
147 g_param_spec_pointer ("datasheet",
149 "A pointer to the datasheet belonging to this object",
152 g_param_spec_pointer ("casereader",
154 "A pointer to the case reader from which this object is constructed",
155 G_PARAM_CONSTRUCT_ONLY | G_PARAM_WRITABLE );
157 object_class->set_property = psppire_case_file_set_property;
158 object_class->get_property = psppire_case_file_get_property;
160 g_object_class_install_property (object_class,
164 g_object_class_install_property (object_class,
168 signals [CASE_CHANGED] =
169 g_signal_new ("case-changed",
170 G_TYPE_FROM_CLASS (class),
174 g_cclosure_marshal_VOID__INT,
180 signals [CASE_INSERTED] =
181 g_signal_new ("case-inserted",
182 G_TYPE_FROM_CLASS (class),
186 g_cclosure_marshal_VOID__INT,
192 signals [CASES_DELETED] =
193 g_signal_new ("cases-deleted",
194 G_TYPE_FROM_CLASS (class),
198 gtkextra_VOID__INT_INT,
201 G_TYPE_INT, G_TYPE_INT);
205 psppire_case_file_finalize (GObject *object)
207 PsppireCaseFile *cf = PSPPIRE_CASE_FILE (object);
210 datasheet_destroy (cf->datasheet);
212 G_OBJECT_CLASS (parent_class)->finalize (object);
216 psppire_case_file_init (PsppireCaseFile *cf)
218 cf->datasheet = NULL;
219 cf->accessible = FALSE;
224 * psppire_case_file_new:
225 * @returns: a new #PsppireCaseFile object
227 * Creates a new #PsppireCaseFile.
230 psppire_case_file_new (struct casereader *reader)
232 return g_object_new (G_TYPE_PSPPIRE_CASE_FILE,
233 "casereader", reader,
239 psppire_case_file_delete_cases (PsppireCaseFile *cf, casenumber n_cases, casenumber first)
241 g_return_val_if_fail (cf, FALSE);
242 g_return_val_if_fail (cf->datasheet, FALSE);
243 g_return_val_if_fail (cf->accessible, FALSE);
245 g_return_val_if_fail (first + n_cases <=
246 psppire_case_file_get_case_count (cf), FALSE);
248 datasheet_delete_rows (cf->datasheet, first, n_cases);
250 g_signal_emit (cf, signals [CASES_DELETED], 0, first, n_cases);
255 /* Insert case CC into the case file before POSN */
257 psppire_case_file_insert_case (PsppireCaseFile *cf,
264 g_return_val_if_fail (cf, FALSE);
265 g_return_val_if_fail (cf->datasheet, FALSE);
266 g_return_val_if_fail (cf->accessible, FALSE);
268 case_clone (&tmp, cc);
269 result = datasheet_insert_rows (cf->datasheet, posn, &tmp, 1);
272 g_signal_emit (cf, signals [CASE_INSERTED], 0, posn);
274 g_warning ("Cannot insert case at position %ld\n", posn);
281 psppire_case_file_get_case_count (const PsppireCaseFile *cf)
283 g_return_val_if_fail (cf, FALSE);
284 g_return_val_if_fail (cf->accessible, FALSE);
286 if ( ! cf->datasheet)
289 return datasheet_get_row_cnt (cf->datasheet);
292 /* Copies the IDXth value from case CASENUM into VALUE.
293 If VALUE is null, then memory is allocated is allocated with
294 malloc. Returns the value if successful, NULL on failure. */
296 psppire_case_file_get_value (const PsppireCaseFile *cf,
297 casenumber casenum, size_t idx,
298 union value *value, int width)
302 g_return_val_if_fail (cf, false);
303 g_return_val_if_fail (cf->datasheet, false);
305 g_return_val_if_fail (idx < datasheet_get_column_cnt (cf->datasheet), false);
309 value = xnmalloc (value_cnt_from_width (width), sizeof *value);
314 if (!datasheet_get_value (cf->datasheet, casenum, idx, value, width))
324 psppire_case_file_clear (PsppireCaseFile *cf)
326 datasheet_destroy (cf->datasheet);
327 cf->datasheet = NULL;
328 g_signal_emit (cf, signals [CASES_DELETED], 0, 0, -1);
331 /* Set the IDXth value of case C to V.
332 Returns true if successful, false on I/O error. */
334 psppire_case_file_set_value (PsppireCaseFile *cf, casenumber casenum, gint idx,
335 union value *v, gint width)
339 g_return_val_if_fail (cf, FALSE);
340 g_return_val_if_fail (cf->datasheet, FALSE);
342 g_return_val_if_fail (idx < datasheet_get_column_cnt (cf->datasheet), FALSE);
344 ok = datasheet_put_value (cf->datasheet, casenum, idx, v, width);
346 g_signal_emit (cf, signals [CASE_CHANGED], 0, casenum);
352 /* Set the IDXth value of case C using D_IN */
354 psppire_case_file_data_in (PsppireCaseFile *cf, casenumber casenum, gint idx,
355 struct substring input, const struct fmt_spec *fmt)
357 union value *value = NULL;
361 g_return_val_if_fail (cf, FALSE);
362 g_return_val_if_fail (cf->datasheet, FALSE);
364 g_return_val_if_fail (idx < datasheet_get_column_cnt (cf->datasheet), FALSE);
366 width = fmt_var_width (fmt);
367 value = xmalloca (value_cnt_from_width (width) * sizeof *value);
368 ok = (datasheet_get_value (cf->datasheet, casenum, idx, value, width)
369 && data_in (input, LEGACY_NATIVE, fmt->type, 0, 0, 0, value, width)
370 && datasheet_put_value (cf->datasheet, casenum, idx, value, width));
373 g_signal_emit (cf, signals [CASE_CHANGED], 0, casenum);
382 psppire_case_file_sort (PsppireCaseFile *cf, struct case_ordering *ordering)
384 struct casereader *sorted_data;
387 sorted_data = sort_execute (datasheet_make_reader (cf->datasheet), ordering);
388 cf->datasheet = datasheet_create (sorted_data);
390 /* FIXME: Need to have a signal to change a range of cases, instead of
391 calling a signal many times */
392 for ( c = 0 ; c < datasheet_get_row_cnt (cf->datasheet) ; ++c )
393 g_signal_emit (cf, signals [CASE_CHANGED], 0, c);
397 /* Resize the cases in the casefile, by inserting N_VALUES into every
398 one of them at the position immediately preceeding WHERE.
401 psppire_case_file_insert_values (PsppireCaseFile *cf,
402 gint n_values, gint where)
404 g_return_val_if_fail (cf, FALSE);
405 g_return_val_if_fail (cf->accessible, FALSE);
410 g_assert (n_values > 0);
412 if ( ! cf->datasheet )
413 cf->datasheet = datasheet_create (NULL);
416 union value *values = xcalloc (n_values, sizeof *values);
417 datasheet_insert_columns (cf->datasheet, values, n_values, where);
425 /* Fills C with the CASENUMth case.
426 Returns true on success, false otherwise.
429 psppire_case_file_get_case (const PsppireCaseFile *cf, casenumber casenum,
432 g_return_val_if_fail (cf, FALSE);
433 g_return_val_if_fail (cf->datasheet, FALSE);
435 return datasheet_get_row (cf->datasheet, casenum, c);
441 psppire_case_file_make_reader (PsppireCaseFile *cf)
443 struct casereader *r = datasheet_make_reader (cf->datasheet);
444 cf->accessible = FALSE;