2 PSPPIRE --- A Graphical User Interface for PSPP
3 Copyright (C) 2006 Free Software Foundation
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.
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.
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
24 #include "psppire-case-file.h"
26 #include <gtksheet/gtkextra-marshal.h>
28 #include <data/case.h>
29 #include <data/data-in.h>
30 #include <data/datasheet.h>
31 #include <data/casereader.h>
32 #include <math/sort.h>
33 #include <libpspp/misc.h>
38 /* --- prototypes --- */
39 static void psppire_case_file_class_init (PsppireCaseFileClass *class);
40 static void psppire_case_file_init (PsppireCaseFile *case_file);
41 static void psppire_case_file_finalize (GObject *object);
44 /* --- variables --- */
45 static GObjectClass *parent_class = NULL;
52 static guint signals [n_SIGNALS];
55 /* --- functions --- */
57 * psppire_case_file_get_type:
58 * @returns: the type ID for accelerator groups.
61 psppire_case_file_get_type (void)
63 static GType object_type = 0;
67 static const GTypeInfo object_info = {
68 sizeof (PsppireCaseFileClass),
70 (GBaseFinalizeFunc) NULL,
71 (GClassInitFunc) psppire_case_file_class_init,
72 NULL, /* class_finalize */
73 NULL, /* class_data */
74 sizeof (PsppireCaseFile),
76 (GInstanceInitFunc) psppire_case_file_init,
79 object_type = g_type_register_static (G_TYPE_OBJECT, "PsppireCaseFile",
88 psppire_case_file_class_init (PsppireCaseFileClass *class)
90 GObjectClass *object_class = G_OBJECT_CLASS (class);
92 parent_class = g_type_class_peek_parent (class);
94 object_class->finalize = psppire_case_file_finalize;
96 signals [CASE_CHANGED] =
97 g_signal_new ("case-changed",
98 G_TYPE_FROM_CLASS (class),
102 g_cclosure_marshal_VOID__INT,
108 signals [CASE_INSERTED] =
109 g_signal_new ("case-inserted",
110 G_TYPE_FROM_CLASS (class),
114 g_cclosure_marshal_VOID__INT,
120 signals [CASES_DELETED] =
121 g_signal_new ("cases-deleted",
122 G_TYPE_FROM_CLASS (class),
126 gtkextra_VOID__INT_INT,
129 G_TYPE_INT, G_TYPE_INT);
133 psppire_case_file_finalize (GObject *object)
135 PsppireCaseFile *cf = PSPPIRE_CASE_FILE (object);
138 datasheet_destroy (cf->datasheet);
140 G_OBJECT_CLASS (parent_class)->finalize (object);
144 psppire_case_file_init (PsppireCaseFile *cf)
146 cf->datasheet = NULL;
147 cf->accessible = FALSE;
152 * psppire_case_file_new:
153 * @returns: a new #PsppireCaseFile object
155 * Creates a new #PsppireCaseFile.
158 psppire_case_file_new (const struct casereader *reader)
160 PsppireCaseFile *cf = g_object_new (G_TYPE_PSPPIRE_CASE_FILE, NULL);
162 cf->datasheet = datasheet_create (casereader_clone (reader));
163 cf->accessible = TRUE;
170 psppire_case_file_delete_cases (PsppireCaseFile *cf, gint n_cases, gint first)
172 g_return_val_if_fail (cf, FALSE);
173 g_return_val_if_fail (cf->datasheet, FALSE);
175 datasheet_delete_rows (cf->datasheet, first, n_cases);
177 g_signal_emit (cf, signals [CASES_DELETED], 0, n_cases, first);
182 /* Insert case CC into the case file before POSN */
184 psppire_case_file_insert_case (PsppireCaseFile *cf,
191 g_return_val_if_fail (cf, FALSE);
192 g_return_val_if_fail (cf->datasheet, FALSE);
194 case_clone (&tmp, cc);
195 result = datasheet_insert_rows (cf->datasheet, posn, &tmp, 1);
198 g_signal_emit (cf, signals [CASE_INSERTED], 0, posn);
200 g_warning ("Cannot insert case at position %d\n", posn);
206 /* Append a case to the case file */
208 psppire_case_file_append_case (PsppireCaseFile *cf,
215 g_return_val_if_fail (cf, FALSE);
216 g_return_val_if_fail (cf->datasheet, FALSE);
218 posn = datasheet_get_row_cnt (cf->datasheet);
220 case_clone (&tmp, c);
221 result = datasheet_insert_rows (cf->datasheet, posn, &tmp, 1);
223 g_signal_emit (cf, signals [CASE_INSERTED], 0, posn);
230 psppire_case_file_get_case_count (const PsppireCaseFile *cf)
232 g_return_val_if_fail (cf, FALSE);
233 g_return_val_if_fail (cf->accessible, FALSE);
235 if ( ! cf->datasheet)
238 return datasheet_get_row_cnt (cf->datasheet);
241 /* Copies the IDXth value from case CASENUM into VALUE.
242 If VALUE is null, then memory is allocated is allocated with
243 malloc. Returns the value if successful, NULL on failure. */
245 psppire_case_file_get_value (const PsppireCaseFile *cf,
246 casenumber casenum, size_t idx,
247 union value *value, int width)
251 g_return_val_if_fail (cf, false);
252 g_return_val_if_fail (cf->datasheet, false);
254 g_return_val_if_fail (idx < datasheet_get_column_cnt (cf->datasheet), false);
258 value = xnmalloc (value_cnt_from_width (width), sizeof *value);
263 if (!datasheet_get_value (cf->datasheet, casenum, idx, value, width))
273 psppire_case_file_clear (PsppireCaseFile *cf)
275 datasheet_destroy (cf->datasheet);
276 cf->datasheet = NULL;
277 g_signal_emit (cf, signals [CASES_DELETED], 0, 0, -1);
280 /* Set the IDXth value of case C to V.
281 Returns true if successful, false on I/O error. */
283 psppire_case_file_set_value (PsppireCaseFile *cf, gint casenum, gint idx,
284 union value *v, gint width)
288 g_return_val_if_fail (cf, FALSE);
289 g_return_val_if_fail (cf->datasheet, FALSE);
291 g_return_val_if_fail (idx < datasheet_get_column_cnt (cf->datasheet), FALSE);
293 ok = datasheet_put_value (cf->datasheet, casenum, idx, v, width);
295 g_signal_emit (cf, signals [CASE_CHANGED], 0, casenum);
301 /* Set the IDXth value of case C using D_IN */
303 psppire_case_file_data_in (PsppireCaseFile *cf, gint casenum, gint idx,
304 struct substring input, const struct fmt_spec *fmt)
310 g_return_val_if_fail (cf, FALSE);
311 g_return_val_if_fail (cf->datasheet, FALSE);
313 g_return_val_if_fail (idx < datasheet_get_column_cnt (cf->datasheet), FALSE);
315 width = fmt_var_width (fmt);
316 value = xmalloca (value_cnt_from_width (width) * sizeof *value);
317 ok = (datasheet_get_value (cf->datasheet, casenum, idx, value, width)
318 && data_in (input, fmt->type, 0, 0, value, width)
319 && datasheet_put_value (cf->datasheet, casenum, idx, value, width));
322 g_signal_emit (cf, signals [CASE_CHANGED], 0, casenum);
331 psppire_case_file_sort (PsppireCaseFile *cf, struct case_ordering *ordering)
333 struct casereader *sorted_data;
336 sorted_data = sort_execute (datasheet_make_reader (cf->datasheet), ordering);
337 cf->datasheet = datasheet_create (sorted_data);
339 /* FIXME: Need to have a signal to change a range of cases, instead of
340 calling a signal many times */
341 for ( c = 0 ; c < datasheet_get_row_cnt (cf->datasheet) ; ++c )
342 g_signal_emit (cf, signals [CASE_CHANGED], 0, c);
346 /* Resize the cases in the casefile, by inserting N_VALUES into every
349 psppire_case_file_insert_values (PsppireCaseFile *cf,
350 gint n_values, gint before)
353 g_return_val_if_fail (cf, FALSE);
354 g_return_val_if_fail (cf->accessible, FALSE);
356 if ( ! cf->datasheet )
357 cf->datasheet = datasheet_create (NULL);
359 values = xcalloc (n_values, sizeof *values);
360 datasheet_insert_columns (cf->datasheet, values, n_values, before);
366 /* Fills C with the CASENUMth case.
367 Returns true on success, false otherwise.
370 psppire_case_file_get_case (const PsppireCaseFile *cf, gint casenum,
373 g_return_val_if_fail (cf, FALSE);
374 g_return_val_if_fail (cf->datasheet, FALSE);
376 return datasheet_get_row (cf->datasheet, casenum, c);
382 psppire_case_file_make_reader (PsppireCaseFile *cf)
384 struct casereader *r = datasheet_make_reader (cf->datasheet);
385 cf->accessible = FALSE;