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);
137 datasheet_destroy (cf->datasheet);
139 G_OBJECT_CLASS (parent_class)->finalize (object);
143 psppire_case_file_init (PsppireCaseFile *cf)
145 cf->datasheet = NULL;
146 cf->accessible = FALSE;
151 * psppire_case_file_new:
152 * @returns: a new #PsppireCaseFile object
154 * Creates a new #PsppireCaseFile.
157 psppire_case_file_new (struct casereader *reader)
159 PsppireCaseFile *cf = g_object_new (G_TYPE_PSPPIRE_CASE_FILE, NULL);
161 cf->datasheet = datasheet_create (reader);
162 cf->accessible = TRUE;
169 psppire_case_file_delete_cases (PsppireCaseFile *cf, gint n_cases, gint first)
171 g_return_val_if_fail (cf, FALSE);
172 g_return_val_if_fail (cf->datasheet, FALSE);
174 datasheet_delete_rows (cf->datasheet, first, n_cases);
176 g_signal_emit (cf, signals [CASES_DELETED], 0, n_cases, first);
181 /* Insert case CC into the case file before POSN */
183 psppire_case_file_insert_case (PsppireCaseFile *cf,
190 g_return_val_if_fail (cf, FALSE);
191 g_return_val_if_fail (cf->datasheet, FALSE);
193 case_clone (&tmp, cc);
194 result = datasheet_insert_rows (cf->datasheet, posn, &tmp, 1);
197 g_signal_emit (cf, signals [CASE_INSERTED], 0, posn);
199 g_warning ("Cannot insert case at position %d\n", posn);
205 /* Append a case to the case file */
207 psppire_case_file_append_case (PsppireCaseFile *cf,
214 g_return_val_if_fail (cf, FALSE);
215 g_return_val_if_fail (cf->datasheet, FALSE);
217 posn = datasheet_get_row_cnt (cf->datasheet);
219 case_clone (&tmp, c);
220 result = datasheet_insert_rows (cf->datasheet, posn, &tmp, 1);
222 g_signal_emit (cf, signals [CASE_INSERTED], 0, posn);
229 psppire_case_file_get_case_count (const PsppireCaseFile *cf)
231 g_return_val_if_fail (cf, FALSE);
232 g_return_val_if_fail (cf->accessible, FALSE);
234 if ( ! cf->datasheet)
237 return datasheet_get_row_cnt (cf->datasheet);
240 /* Copies the IDXth value from case CASENUM into VALUE.
241 If VALUE is null, then memory is allocated is allocated with
242 malloc. Returns the value if successful, NULL on failure. */
244 psppire_case_file_get_value (const PsppireCaseFile *cf,
245 casenumber casenum, size_t idx,
246 union value *value, int width)
250 g_return_val_if_fail (cf, false);
251 g_return_val_if_fail (cf->datasheet, false);
253 g_return_val_if_fail (idx < datasheet_get_column_cnt (cf->datasheet), false);
257 value = xnmalloc (value_cnt_from_width (width), sizeof *value);
262 if (!datasheet_get_value (cf->datasheet, casenum, idx, value, width))
272 psppire_case_file_clear (PsppireCaseFile *cf)
274 datasheet_destroy (cf->datasheet);
275 cf->datasheet = NULL;
276 g_signal_emit (cf, signals [CASES_DELETED], 0, 0, -1);
279 /* Set the IDXth value of case C to V.
280 Returns true if successful, false on I/O error. */
282 psppire_case_file_set_value (PsppireCaseFile *cf, gint casenum, gint idx,
283 union value *v, gint width)
287 g_return_val_if_fail (cf, FALSE);
288 g_return_val_if_fail (cf->datasheet, FALSE);
290 g_return_val_if_fail (idx < datasheet_get_column_cnt (cf->datasheet), FALSE);
292 ok = datasheet_put_value (cf->datasheet, casenum, idx, v, width);
294 g_signal_emit (cf, signals [CASE_CHANGED], 0, casenum);
300 /* Set the IDXth value of case C using D_IN */
302 psppire_case_file_data_in (PsppireCaseFile *cf, gint casenum, gint idx,
303 struct substring input, const struct fmt_spec *fmt)
309 g_return_val_if_fail (cf, FALSE);
310 g_return_val_if_fail (cf->datasheet, FALSE);
312 g_return_val_if_fail (idx < datasheet_get_column_cnt (cf->datasheet), FALSE);
314 width = fmt_var_width (fmt);
315 value = xmalloca (value_cnt_from_width (width) * sizeof *value);
316 ok = (datasheet_get_value (cf->datasheet, casenum, idx, value, width)
317 && data_in (input, fmt->type, 0, 0, value, width)
318 && datasheet_put_value (cf->datasheet, casenum, idx, value, width));
321 g_signal_emit (cf, signals [CASE_CHANGED], 0, casenum);
330 psppire_case_file_sort (PsppireCaseFile *cf, struct case_ordering *ordering)
332 struct casereader *sorted_data;
335 sorted_data = sort_execute (datasheet_make_reader (cf->datasheet), ordering);
336 cf->datasheet = datasheet_create (sorted_data);
338 /* FIXME: Need to have a signal to change a range of cases, instead of
339 calling a signal many times */
340 for ( c = 0 ; c < datasheet_get_row_cnt (cf->datasheet) ; ++c )
341 g_signal_emit (cf, signals [CASE_CHANGED], 0, c);
345 /* Resize the cases in the casefile, by inserting N_VALUES into every
348 psppire_case_file_insert_values (PsppireCaseFile *cf,
349 gint n_values, gint before)
352 g_return_val_if_fail (cf, FALSE);
353 g_return_val_if_fail (cf->accessible, FALSE);
355 if ( ! cf->datasheet )
356 cf->datasheet = datasheet_create (NULL);
358 values = xcalloc (n_values, sizeof *values);
359 datasheet_insert_columns (cf->datasheet, values, n_values, before);
365 /* Fills C with the CASENUMth case.
366 Returns true on success, false otherwise.
369 psppire_case_file_get_case (const PsppireCaseFile *cf, gint casenum,
372 g_return_val_if_fail (cf, FALSE);
373 g_return_val_if_fail (cf->datasheet, FALSE);
375 return datasheet_get_row (cf->datasheet, casenum, c);
381 psppire_case_file_make_reader (PsppireCaseFile *cf)
383 struct casereader *r = datasheet_make_reader (cf->datasheet);
384 cf->accessible = FALSE;