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 <math/sort.h>
32 #include <libpspp/misc.h>
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);
43 /* --- variables --- */
44 static GObjectClass *parent_class = NULL;
51 static guint signals [n_SIGNALS];
54 /* --- functions --- */
56 * psppire_case_file_get_type:
57 * @returns: the type ID for accelerator groups.
60 psppire_case_file_get_type (void)
62 static GType object_type = 0;
66 static const GTypeInfo object_info = {
67 sizeof (PsppireCaseFileClass),
69 (GBaseFinalizeFunc) NULL,
70 (GClassInitFunc) psppire_case_file_class_init,
71 NULL, /* class_finalize */
72 NULL, /* class_data */
73 sizeof (PsppireCaseFile),
75 (GInstanceInitFunc) psppire_case_file_init,
78 object_type = g_type_register_static (G_TYPE_OBJECT, "PsppireCaseFile",
87 psppire_case_file_class_init (PsppireCaseFileClass *class)
89 GObjectClass *object_class = G_OBJECT_CLASS (class);
91 parent_class = g_type_class_peek_parent (class);
93 object_class->finalize = psppire_case_file_finalize;
95 signals [CASE_CHANGED] =
96 g_signal_new ("case_changed",
97 G_TYPE_FROM_CLASS (class),
101 g_cclosure_marshal_VOID__INT,
107 signals [CASE_INSERTED] =
108 g_signal_new ("case_inserted",
109 G_TYPE_FROM_CLASS (class),
113 g_cclosure_marshal_VOID__INT,
119 signals [CASES_DELETED] =
120 g_signal_new ("cases_deleted",
121 G_TYPE_FROM_CLASS (class),
125 gtkextra_VOID__INT_INT,
128 G_TYPE_INT, G_TYPE_INT);
132 psppire_case_file_finalize (GObject *object)
134 PsppireCaseFile *cf = PSPPIRE_CASE_FILE (object);
136 datasheet_destroy (cf->datasheet);
138 G_OBJECT_CLASS (parent_class)->finalize (object);
142 psppire_case_file_init (PsppireCaseFile *cf)
144 cf->datasheet = NULL;
149 * psppire_case_file_new:
150 * @returns: a new #PsppireCaseFile object
152 * Creates a new #PsppireCaseFile.
155 psppire_case_file_new (void)
157 PsppireCaseFile *cf = g_object_new (G_TYPE_PSPPIRE_CASE_FILE, NULL);
159 cf->datasheet = datasheet_create (NULL);
166 psppire_case_file_replace_datasheet (PsppireCaseFile *cf, struct datasheet *ds)
174 psppire_case_file_delete_cases (PsppireCaseFile *cf, gint n_cases, gint first)
176 g_return_val_if_fail (cf, FALSE);
177 g_return_val_if_fail (cf->datasheet, FALSE);
179 datasheet_delete_rows (cf->datasheet, first, n_cases);
181 g_signal_emit (cf, signals [CASES_DELETED], 0, n_cases, first);
186 /* Insert case CC into the case file before POSN */
188 psppire_case_file_insert_case (PsppireCaseFile *cf,
195 g_return_val_if_fail (cf, FALSE);
196 g_return_val_if_fail (cf->datasheet, FALSE);
198 case_clone (&tmp, cc);
199 result = datasheet_insert_rows (cf->datasheet, posn, &tmp, 1);
202 g_signal_emit (cf, signals [CASE_INSERTED], 0, posn);
204 g_warning ("Cannot insert case at position %d\n", posn);
210 /* Append a case to the case file */
212 psppire_case_file_append_case (PsppireCaseFile *cf,
219 g_return_val_if_fail (cf, FALSE);
220 g_return_val_if_fail (cf->datasheet, FALSE);
222 posn = datasheet_get_row_cnt (cf->datasheet);
224 case_clone (&tmp, c);
225 result = datasheet_insert_rows (cf->datasheet, posn, &tmp, 1);
227 g_signal_emit (cf, signals [CASE_INSERTED], 0, posn);
234 psppire_case_file_get_case_count (const PsppireCaseFile *cf)
236 g_return_val_if_fail (cf, FALSE);
238 if ( ! cf->datasheet)
241 return datasheet_get_row_cnt (cf->datasheet);
244 /* Copies the IDXth value from case CASENUM into VALUE.
245 If VALUE is null, then memory is allocated is allocated with
246 malloc. Returns the value if successful, NULL on failure. */
248 psppire_case_file_get_value (const PsppireCaseFile *cf,
249 casenumber casenum, size_t idx,
250 union value *value, int width)
254 g_return_val_if_fail (cf, false);
255 g_return_val_if_fail (cf->datasheet, false);
257 g_return_val_if_fail (idx < datasheet_get_column_cnt (cf->datasheet), false);
261 value = xnmalloc (value_cnt_from_width (width), sizeof *value);
266 if (!datasheet_get_value (cf->datasheet, casenum, idx, value, width))
276 psppire_case_file_clear (PsppireCaseFile *cf)
278 datasheet_destroy (cf->datasheet);
279 cf->datasheet = NULL;
280 g_signal_emit (cf, signals [CASES_DELETED], 0, 0, -1);
283 /* Set the IDXth value of case C to V.
284 Returns true if successful, false on I/O error. */
286 psppire_case_file_set_value (PsppireCaseFile *cf, gint casenum, gint idx,
287 union value *v, gint width)
291 g_return_val_if_fail (cf, FALSE);
292 g_return_val_if_fail (cf->datasheet, FALSE);
294 g_return_val_if_fail (idx < datasheet_get_column_cnt (cf->datasheet), FALSE);
296 ok = datasheet_put_value (cf->datasheet, casenum, idx, v, width);
298 g_signal_emit (cf, signals [CASE_CHANGED], 0, casenum);
304 /* Set the IDXth value of case C using D_IN */
306 psppire_case_file_data_in (PsppireCaseFile *cf, gint casenum, gint idx,
307 struct substring input, const struct fmt_spec *fmt)
313 g_return_val_if_fail (cf, FALSE);
314 g_return_val_if_fail (cf->datasheet, FALSE);
316 g_return_val_if_fail (idx < datasheet_get_column_cnt (cf->datasheet), FALSE);
318 width = fmt_var_width (fmt);
319 value = xallocsa (value_cnt_from_width (width) * sizeof *value);
320 ok = (datasheet_get_value (cf->datasheet, casenum, idx, value, width)
321 && data_in (input, fmt->type, 0, 0, value, width)
322 && datasheet_put_value (cf->datasheet, casenum, idx, value, width));
325 g_signal_emit (cf, signals [CASE_CHANGED], 0, casenum);
334 psppire_case_file_sort (PsppireCaseFile *cf, struct case_ordering *ordering)
336 struct casereader *sorted_data;
339 sorted_data = sort_execute (datasheet_make_reader (cf->datasheet), ordering);
340 cf->datasheet = datasheet_create (sorted_data);
342 /* FIXME: Need to have a signal to change a range of cases, instead of
343 calling a signal many times */
344 for ( c = 0 ; c < datasheet_get_row_cnt (cf->datasheet) ; ++c )
345 g_signal_emit (cf, signals [CASE_CHANGED], 0, c);
349 /* Resize the cases in the casefile, by inserting N_VALUES into every
352 psppire_case_file_insert_values (PsppireCaseFile *cf,
353 gint n_values, gint before)
356 g_return_val_if_fail (cf, FALSE);
358 if ( ! cf->datasheet )
359 cf->datasheet = datasheet_create (NULL);
361 values = xcalloc (n_values, sizeof *values);
362 datasheet_insert_columns (cf->datasheet, values, n_values, before);
368 /* Fills C with the CASENUMth case.
369 Returns true on success, false otherwise.
372 psppire_case_file_get_case (const PsppireCaseFile *cf, gint casenum,
375 g_return_val_if_fail (cf, FALSE);
376 g_return_val_if_fail (cf->datasheet, FALSE);
378 return datasheet_get_row (cf->datasheet, casenum, c);