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",
85 psppire_case_file_class_init (PsppireCaseFileClass *class)
87 GObjectClass *object_class = G_OBJECT_CLASS (class);
89 parent_class = g_type_class_peek_parent (class);
91 object_class->finalize = psppire_case_file_finalize;
93 signals [CASE_CHANGED] =
94 g_signal_new ("case-changed",
95 G_TYPE_FROM_CLASS (class),
99 g_cclosure_marshal_VOID__INT,
105 signals [CASE_INSERTED] =
106 g_signal_new ("case-inserted",
107 G_TYPE_FROM_CLASS (class),
111 g_cclosure_marshal_VOID__INT,
117 signals [CASES_DELETED] =
118 g_signal_new ("cases-deleted",
119 G_TYPE_FROM_CLASS (class),
123 gtkextra_VOID__INT_INT,
126 G_TYPE_INT, G_TYPE_INT);
130 psppire_case_file_finalize (GObject *object)
132 PsppireCaseFile *cf = PSPPIRE_CASE_FILE (object);
135 datasheet_destroy (cf->datasheet);
137 G_OBJECT_CLASS (parent_class)->finalize (object);
141 psppire_case_file_init (PsppireCaseFile *cf)
143 cf->datasheet = NULL;
144 cf->accessible = FALSE;
149 * psppire_case_file_new:
150 * @returns: a new #PsppireCaseFile object
152 * Creates a new #PsppireCaseFile.
155 psppire_case_file_new (const struct casereader *reader)
157 PsppireCaseFile *cf = g_object_new (G_TYPE_PSPPIRE_CASE_FILE, NULL);
159 cf->datasheet = datasheet_create (casereader_clone (reader));
160 cf->accessible = TRUE;
167 psppire_case_file_delete_cases (PsppireCaseFile *cf, casenumber n_cases, casenumber first)
169 g_return_val_if_fail (cf, FALSE);
170 g_return_val_if_fail (cf->datasheet, FALSE);
172 datasheet_delete_rows (cf->datasheet, first, n_cases);
174 g_signal_emit (cf, signals [CASES_DELETED], 0, n_cases, first);
179 /* Insert case CC into the case file before POSN */
181 psppire_case_file_insert_case (PsppireCaseFile *cf,
188 g_return_val_if_fail (cf, FALSE);
189 g_return_val_if_fail (cf->datasheet, FALSE);
191 case_clone (&tmp, cc);
192 result = datasheet_insert_rows (cf->datasheet, posn, &tmp, 1);
195 g_signal_emit (cf, signals [CASE_INSERTED], 0, posn);
197 g_warning ("Cannot insert case at position %ld\n", posn);
203 /* Append a case to the case file */
205 psppire_case_file_append_case (PsppireCaseFile *cf,
212 g_return_val_if_fail (cf, FALSE);
213 g_return_val_if_fail (cf->datasheet, FALSE);
215 posn = datasheet_get_row_cnt (cf->datasheet);
217 case_clone (&tmp, c);
218 result = datasheet_insert_rows (cf->datasheet, posn, &tmp, 1);
220 g_signal_emit (cf, signals [CASE_INSERTED], 0, posn);
227 psppire_case_file_get_case_count (const PsppireCaseFile *cf)
229 g_return_val_if_fail (cf, FALSE);
230 g_return_val_if_fail (cf->accessible, FALSE);
232 if ( ! cf->datasheet)
235 return datasheet_get_row_cnt (cf->datasheet);
238 /* Copies the IDXth value from case CASENUM into VALUE.
239 If VALUE is null, then memory is allocated is allocated with
240 malloc. Returns the value if successful, NULL on failure. */
242 psppire_case_file_get_value (const PsppireCaseFile *cf,
243 casenumber casenum, size_t idx,
244 union value *value, int width)
248 g_return_val_if_fail (cf, false);
249 g_return_val_if_fail (cf->datasheet, false);
251 g_return_val_if_fail (idx < datasheet_get_column_cnt (cf->datasheet), false);
255 value = xnmalloc (value_cnt_from_width (width), sizeof *value);
260 if (!datasheet_get_value (cf->datasheet, casenum, idx, value, width))
270 psppire_case_file_clear (PsppireCaseFile *cf)
272 datasheet_destroy (cf->datasheet);
273 cf->datasheet = NULL;
274 g_signal_emit (cf, signals [CASES_DELETED], 0, 0, -1);
277 /* Set the IDXth value of case C to V.
278 Returns true if successful, false on I/O error. */
280 psppire_case_file_set_value (PsppireCaseFile *cf, casenumber casenum, gint idx,
281 union value *v, gint width)
285 g_return_val_if_fail (cf, FALSE);
286 g_return_val_if_fail (cf->datasheet, FALSE);
288 g_return_val_if_fail (idx < datasheet_get_column_cnt (cf->datasheet), FALSE);
290 ok = datasheet_put_value (cf->datasheet, casenum, idx, v, width);
292 g_signal_emit (cf, signals [CASE_CHANGED], 0, casenum);
298 /* Set the IDXth value of case C using D_IN */
300 psppire_case_file_data_in (PsppireCaseFile *cf, casenumber casenum, gint idx,
301 struct substring input, const struct fmt_spec *fmt)
307 g_return_val_if_fail (cf, FALSE);
308 g_return_val_if_fail (cf->datasheet, FALSE);
310 g_return_val_if_fail (idx < datasheet_get_column_cnt (cf->datasheet), FALSE);
312 width = fmt_var_width (fmt);
313 value = xmalloca (value_cnt_from_width (width) * sizeof *value);
314 ok = (datasheet_get_value (cf->datasheet, casenum, idx, value, width)
315 && data_in (input, fmt->type, 0, 0, value, width)
316 && datasheet_put_value (cf->datasheet, casenum, idx, value, width));
319 g_signal_emit (cf, signals [CASE_CHANGED], 0, casenum);
328 psppire_case_file_sort (PsppireCaseFile *cf, struct case_ordering *ordering)
330 struct casereader *sorted_data;
333 sorted_data = sort_execute (datasheet_make_reader (cf->datasheet), ordering);
334 cf->datasheet = datasheet_create (sorted_data);
336 /* FIXME: Need to have a signal to change a range of cases, instead of
337 calling a signal many times */
338 for ( c = 0 ; c < datasheet_get_row_cnt (cf->datasheet) ; ++c )
339 g_signal_emit (cf, signals [CASE_CHANGED], 0, c);
343 /* Resize the cases in the casefile, by inserting N_VALUES into every
346 psppire_case_file_insert_values (PsppireCaseFile *cf,
347 gint n_values, gint before)
350 g_return_val_if_fail (cf, FALSE);
351 g_return_val_if_fail (cf->accessible, FALSE);
353 if ( ! cf->datasheet )
354 cf->datasheet = datasheet_create (NULL);
356 values = xcalloc (n_values, sizeof *values);
357 datasheet_insert_columns (cf->datasheet, values, n_values, before);
363 /* Fills C with the CASENUMth case.
364 Returns true on success, false otherwise.
367 psppire_case_file_get_case (const PsppireCaseFile *cf, casenumber casenum,
370 g_return_val_if_fail (cf, FALSE);
371 g_return_val_if_fail (cf->datasheet, FALSE);
373 return datasheet_get_row (cf->datasheet, casenum, c);
379 psppire_case_file_make_reader (PsppireCaseFile *cf)
381 struct casereader *r = datasheet_make_reader (cf->datasheet);
382 cf->accessible = FALSE;