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/format.h>
26 #include <data/case.h>
27 #include <data/data-in.h>
28 #include <data/datasheet.h>
29 #include <data/casereader.h>
30 #include <math/sort.h>
31 #include <libpspp/misc.h>
36 /* --- prototypes --- */
37 static void psppire_case_file_class_init (PsppireCaseFileClass *class);
38 static void psppire_case_file_init (PsppireCaseFile *case_file);
39 static void psppire_case_file_finalize (GObject *object);
42 /* --- variables --- */
43 static GObjectClass *parent_class = NULL;
50 static guint signals [n_SIGNALS];
53 /* --- functions --- */
55 * psppire_case_file_get_type:
56 * @returns: the type ID for accelerator groups.
59 psppire_case_file_get_type (void)
61 static GType object_type = 0;
65 static const GTypeInfo object_info = {
66 sizeof (PsppireCaseFileClass),
68 (GBaseFinalizeFunc) NULL,
69 (GClassInitFunc) psppire_case_file_class_init,
70 NULL, /* class_finalize */
71 NULL, /* class_data */
72 sizeof (PsppireCaseFile),
74 (GInstanceInitFunc) psppire_case_file_init,
77 object_type = g_type_register_static (G_TYPE_OBJECT, "PsppireCaseFile",
96 psppire_case_file_set_property (GObject *object,
102 PsppireCaseFile *cf = PSPPIRE_CASE_FILE (object);
107 cf->datasheet = datasheet_create (g_value_get_pointer (value));
108 cf->accessible = TRUE;
111 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
117 psppire_case_file_get_property (GObject *object,
122 PsppireCaseFile *cf = PSPPIRE_CASE_FILE (object);
127 g_value_set_pointer (value, cf->datasheet);
130 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
137 psppire_case_file_class_init (PsppireCaseFileClass *class)
139 GObjectClass *object_class = G_OBJECT_CLASS (class);
140 GParamSpec *datasheet_spec ;
141 GParamSpec *reader_spec ;
143 parent_class = g_type_class_peek_parent (class);
145 object_class->finalize = psppire_case_file_finalize;
148 g_param_spec_pointer ("datasheet",
150 "A pointer to the datasheet belonging to this object",
153 g_param_spec_pointer ("casereader",
155 "A pointer to the case reader from which this object is constructed",
156 G_PARAM_CONSTRUCT_ONLY | G_PARAM_WRITABLE );
158 object_class->set_property = psppire_case_file_set_property;
159 object_class->get_property = psppire_case_file_get_property;
161 g_object_class_install_property (object_class,
165 g_object_class_install_property (object_class,
169 signals [CASE_CHANGED] =
170 g_signal_new ("case-changed",
171 G_TYPE_FROM_CLASS (class),
175 g_cclosure_marshal_VOID__INT,
181 signals [CASE_INSERTED] =
182 g_signal_new ("case-inserted",
183 G_TYPE_FROM_CLASS (class),
187 g_cclosure_marshal_VOID__INT,
193 signals [CASES_DELETED] =
194 g_signal_new ("cases-deleted",
195 G_TYPE_FROM_CLASS (class),
199 gtkextra_VOID__INT_INT,
202 G_TYPE_INT, G_TYPE_INT);
206 psppire_case_file_finalize (GObject *object)
208 PsppireCaseFile *cf = PSPPIRE_CASE_FILE (object);
211 datasheet_destroy (cf->datasheet);
213 G_OBJECT_CLASS (parent_class)->finalize (object);
217 psppire_case_file_init (PsppireCaseFile *cf)
219 cf->datasheet = NULL;
220 cf->accessible = FALSE;
225 * psppire_case_file_new:
226 * @returns: a new #PsppireCaseFile object
228 * Creates a new #PsppireCaseFile.
231 psppire_case_file_new (struct casereader *reader)
233 return g_object_new (G_TYPE_PSPPIRE_CASE_FILE,
234 "casereader", reader,
240 psppire_case_file_delete_cases (PsppireCaseFile *cf, casenumber n_cases, casenumber first)
242 g_return_val_if_fail (cf, FALSE);
243 g_return_val_if_fail (cf->datasheet, FALSE);
244 g_return_val_if_fail (cf->accessible, FALSE);
246 g_return_val_if_fail (first + n_cases <=
247 psppire_case_file_get_case_count (cf), FALSE);
249 datasheet_delete_rows (cf->datasheet, first, n_cases);
251 g_signal_emit (cf, signals [CASES_DELETED], 0, first, n_cases);
256 /* Insert case CC into the case file before POSN */
258 psppire_case_file_insert_case (PsppireCaseFile *cf,
265 g_return_val_if_fail (cf, FALSE);
266 g_return_val_if_fail (cf->datasheet, FALSE);
267 g_return_val_if_fail (cf->accessible, FALSE);
269 case_clone (&tmp, cc);
270 result = datasheet_insert_rows (cf->datasheet, posn, &tmp, 1);
273 g_signal_emit (cf, signals [CASE_INSERTED], 0, posn);
275 g_warning ("Cannot insert case at position %ld\n", posn);
282 psppire_case_file_get_case_count (const PsppireCaseFile *cf)
284 g_return_val_if_fail (cf, FALSE);
285 g_return_val_if_fail (cf->accessible, FALSE);
287 if ( ! cf->datasheet)
290 return datasheet_get_row_cnt (cf->datasheet);
293 /* Copies the IDXth value from case CASENUM into VALUE.
294 If VALUE is null, then memory is allocated is allocated with
295 malloc. Returns the value if successful, NULL on failure. */
297 psppire_case_file_get_value (const PsppireCaseFile *cf,
298 casenumber casenum, size_t idx,
299 union value *value, int width)
303 g_return_val_if_fail (cf, false);
304 g_return_val_if_fail (cf->datasheet, false);
306 g_return_val_if_fail (idx < datasheet_get_column_cnt (cf->datasheet), false);
310 value = xnmalloc (value_cnt_from_width (width), sizeof *value);
315 if (!datasheet_get_value (cf->datasheet, casenum, idx, value, width))
325 psppire_case_file_clear (PsppireCaseFile *cf)
327 datasheet_destroy (cf->datasheet);
328 cf->datasheet = NULL;
329 g_signal_emit (cf, signals [CASES_DELETED], 0, 0, -1);
332 /* Set the IDXth value of case C to V.
333 Returns true if successful, false on I/O error. */
335 psppire_case_file_set_value (PsppireCaseFile *cf, casenumber casenum, gint idx,
336 union value *v, gint width)
340 g_return_val_if_fail (cf, FALSE);
341 g_return_val_if_fail (cf->datasheet, FALSE);
343 g_return_val_if_fail (idx < datasheet_get_column_cnt (cf->datasheet), FALSE);
345 ok = datasheet_put_value (cf->datasheet, casenum, idx, v, width);
347 g_signal_emit (cf, signals [CASE_CHANGED], 0, casenum);
353 /* Set the IDXth value of case C using D_IN */
355 psppire_case_file_data_in (PsppireCaseFile *cf, casenumber casenum, gint idx,
356 struct substring input, const struct fmt_spec *fmt)
358 union value *value = NULL;
362 g_return_val_if_fail (cf, FALSE);
363 g_return_val_if_fail (cf->datasheet, FALSE);
365 g_return_val_if_fail (idx < datasheet_get_column_cnt (cf->datasheet), FALSE);
367 width = fmt_var_width (fmt);
368 value = xmalloca (value_cnt_from_width (width) * sizeof *value);
369 ok = (datasheet_get_value (cf->datasheet, casenum, idx, value, width)
370 && data_in (input, LEGACY_NATIVE, fmt->type, 0, 0, 0, value, width)
371 && datasheet_put_value (cf->datasheet, casenum, idx, value, width));
374 g_signal_emit (cf, signals [CASE_CHANGED], 0, casenum);
383 psppire_case_file_sort (PsppireCaseFile *cf, struct case_ordering *ordering)
385 struct casereader *sorted_data;
388 sorted_data = sort_execute (datasheet_make_reader (cf->datasheet), ordering);
389 cf->datasheet = datasheet_create (sorted_data);
391 /* FIXME: Need to have a signal to change a range of cases, instead of
392 calling a signal many times */
393 for ( c = 0 ; c < datasheet_get_row_cnt (cf->datasheet) ; ++c )
394 g_signal_emit (cf, signals [CASE_CHANGED], 0, c);
398 /* Resize the cases in the casefile, by inserting N_VALUES into every
399 one of them at the position immediately preceeding WHERE.
402 psppire_case_file_insert_values (PsppireCaseFile *cf,
403 gint n_values, gint where)
405 g_return_val_if_fail (cf, FALSE);
406 g_return_val_if_fail (cf->accessible, FALSE);
411 g_assert (n_values > 0);
413 if ( ! cf->datasheet )
414 cf->datasheet = datasheet_create (NULL);
417 union value *values = xcalloc (n_values, sizeof *values);
418 datasheet_insert_columns (cf->datasheet, values, n_values, where);
426 /* Fills C with the CASENUMth case.
427 Returns true on success, false otherwise.
430 psppire_case_file_get_case (const PsppireCaseFile *cf, casenumber casenum,
433 g_return_val_if_fail (cf, FALSE);
434 g_return_val_if_fail (cf->datasheet, FALSE);
436 return datasheet_get_row (cf->datasheet, casenum, c);
442 psppire_case_file_make_reader (PsppireCaseFile *cf)
444 struct casereader *r = datasheet_make_reader (cf->datasheet);
445 cf->accessible = FALSE;