1 /* PSPPIRE - a graphical user interface for PSPP.
2 Copyright (C) 2006, 2009, 2010, 2011, 2012 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 #define _(msgid) gettext (msgid)
22 #define N_(msgid) msgid
24 #include <libpspp/i18n.h>
26 #include <gobject/gvaluecollector.h>
28 #include <ui/gui/sheet/psppire-sheetmodel.h>
30 #include "psppire-var-store.h"
33 #include <data/dictionary.h>
34 #include <data/variable.h>
35 #include <data/format.h>
36 #include <data/missing-values.h>
38 #include "val-labs-dialog.h"
39 #include "missing-val-dialog.h"
40 #include <data/value-labels.h>
42 #include "var-display.h"
45 var_change_callback (GtkWidget *w, gint n, gpointer data)
47 PsppireSheetModel *model = PSPPIRE_SHEET_MODEL (data);
49 psppire_sheet_model_range_changed (model,
50 n, 0, n, PSPPIRE_VAR_STORE_n_COLS);
55 var_delete_callback (GtkWidget *w, const struct variable *var UNUSED,
56 gint dict_idx, gint case_idx UNUSED, gpointer data)
58 PsppireSheetModel *model = PSPPIRE_SHEET_MODEL (data);
60 psppire_sheet_model_rows_deleted (model, dict_idx, 1);
66 var_insert_callback (GtkWidget *w, glong row, gpointer data)
68 PsppireSheetModel *model = PSPPIRE_SHEET_MODEL (data);
70 psppire_sheet_model_rows_inserted (model, row, 1);
74 refresh (PsppireDict *d, gpointer data)
76 PsppireVarStore *vs = data;
78 psppire_sheet_model_range_changed (PSPPIRE_SHEET_MODEL (vs), -1, -1, -1, -1);
84 PSPPIRE_VAR_STORE_FORMAT_TYPE,
85 PSPPIRE_VAR_STORE_DICT
88 static void psppire_var_store_init (PsppireVarStore *var_store);
89 static void psppire_var_store_class_init (PsppireVarStoreClass *class);
90 static void psppire_var_store_sheet_model_init (PsppireSheetModelIface *iface);
91 static void psppire_var_store_finalize (GObject *object);
92 static void psppire_var_store_dispose (GObject *object);
95 static gchar *psppire_var_store_get_string (const PsppireSheetModel *sheet_model, glong row, glong column);
97 static gboolean psppire_var_store_clear (PsppireSheetModel *model, glong row, glong col);
100 static gboolean psppire_var_store_set_string (PsppireSheetModel *model,
101 const gchar *text, glong row, glong column);
103 static glong psppire_var_store_get_row_count (const PsppireSheetModel * model);
104 static glong psppire_var_store_get_column_count (const PsppireSheetModel * model);
106 static gchar *text_for_column (PsppireVarStore *vs, const struct variable *pv,
107 gint c, GError **err);
110 static GObjectClass *parent_class = NULL;
113 psppire_var_store_format_type_get_type (void)
115 static GType etype = 0;
118 static const GEnumValue values[] =
120 { PSPPIRE_VAR_STORE_INPUT_FORMATS,
121 "PSPPIRE_VAR_STORE_INPUT_FORMATS",
123 { PSPPIRE_VAR_STORE_OUTPUT_FORMATS,
124 "PSPPIRE_VAR_STORE_OUTPUT_FORMATS",
129 etype = g_enum_register_static
130 (g_intern_static_string ("PsppireVarStoreFormatType"), values);
137 psppire_var_store_get_type (void)
139 static GType var_store_type = 0;
143 static const GTypeInfo var_store_info =
145 sizeof (PsppireVarStoreClass),
146 NULL, /* base_init */
147 NULL, /* base_finalize */
148 (GClassInitFunc) psppire_var_store_class_init,
149 NULL, /* class_finalize */
150 NULL, /* class_data */
151 sizeof (PsppireVarStore),
153 (GInstanceInitFunc) psppire_var_store_init,
156 static const GInterfaceInfo sheet_model_info =
158 (GInterfaceInitFunc) psppire_var_store_sheet_model_init,
163 var_store_type = g_type_register_static (G_TYPE_OBJECT, "PsppireVarStore", &var_store_info, 0);
165 g_type_add_interface_static (var_store_type,
166 PSPPIRE_TYPE_SHEET_MODEL,
170 return var_store_type;
174 psppire_var_store_set_property (GObject *object,
179 PsppireVarStore *self = (PsppireVarStore *) object;
183 case PSPPIRE_VAR_STORE_FORMAT_TYPE:
184 self->format_type = g_value_get_enum (value);
187 case PSPPIRE_VAR_STORE_DICT:
188 if ( self->dictionary)
189 g_object_unref (self->dictionary);
190 self->dictionary = g_value_dup_object (value);
191 g_signal_connect (self->dictionary, "variable-changed", G_CALLBACK (var_change_callback),
194 g_signal_connect (self->dictionary, "variable-deleted", G_CALLBACK (var_delete_callback),
197 g_signal_connect (self->dictionary, "variable-inserted",
198 G_CALLBACK (var_insert_callback), self);
200 g_signal_connect (self->dictionary, "backend-changed", G_CALLBACK (refresh),
203 /* The entire model has changed */
204 psppire_sheet_model_range_changed (PSPPIRE_SHEET_MODEL (self), -1, -1, -1, -1);
209 G_OBJECT_WARN_INVALID_PROPERTY_ID(object, property_id, pspec);
215 psppire_var_store_get_property (GObject *object,
220 PsppireVarStore *self = (PsppireVarStore *) object;
224 case PSPPIRE_VAR_STORE_FORMAT_TYPE:
225 g_value_set_enum (value, self->format_type);
228 case PSPPIRE_VAR_STORE_DICT:
229 g_value_take_object (value, self->dictionary);
233 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
240 psppire_var_store_class_init (PsppireVarStoreClass *class)
242 GObjectClass *object_class;
243 GParamSpec *format_pspec;
244 GParamSpec *dict_pspec;
246 parent_class = g_type_class_peek_parent (class);
247 object_class = (GObjectClass*) class;
249 object_class->finalize = psppire_var_store_finalize;
250 object_class->dispose = psppire_var_store_dispose;
251 object_class->set_property = psppire_var_store_set_property;
252 object_class->get_property = psppire_var_store_get_property;
254 format_pspec = g_param_spec_enum ("format-type",
255 "Variable format type",
256 ("Whether variables have input or output "
258 PSPPIRE_TYPE_VAR_STORE_FORMAT_TYPE,
259 PSPPIRE_VAR_STORE_OUTPUT_FORMATS,
262 g_object_class_install_property (object_class,
263 PSPPIRE_VAR_STORE_FORMAT_TYPE,
266 dict_pspec = g_param_spec_object ("dictionary",
268 "The PsppireDict represented by this var store",
270 G_PARAM_READWRITE | G_PARAM_CONSTRUCT);
272 g_object_class_install_property (object_class,
273 PSPPIRE_VAR_STORE_DICT,
277 #define DISABLED_COLOR "gray"
280 psppire_var_store_init (PsppireVarStore *var_store)
282 if ( ! gdk_color_parse (DISABLED_COLOR, &var_store->disabled))
283 g_critical ("Could not parse color `%s'", DISABLED_COLOR);
285 var_store->dictionary = NULL;
286 var_store->format_type = PSPPIRE_VAR_STORE_OUTPUT_FORMATS;
290 psppire_var_store_item_editable (PsppireVarStore *var_store, glong row, glong column)
292 const struct fmt_spec *write_spec ;
294 struct variable *pv = psppire_var_store_get_var (var_store, row);
299 if ( var_is_alpha (pv) && column == PSPPIRE_VAR_STORE_COL_DECIMALS )
302 write_spec = var_get_print_format (pv);
304 switch ( write_spec->type )
319 if ( column == PSPPIRE_VAR_STORE_COL_DECIMALS || column == PSPPIRE_VAR_STORE_COL_WIDTH)
331 psppire_var_store_get_var (PsppireVarStore *store, glong row)
333 return psppire_dict_get_variable (store->dictionary, row);
337 psppire_var_store_is_editable (const PsppireSheetModel *model, glong row, glong column)
339 PsppireVarStore *store = PSPPIRE_VAR_STORE (model);
340 return psppire_var_store_item_editable (store, row, column);
345 psppire_var_store_get_foreground (const PsppireSheetModel *model, glong row, glong column)
347 PsppireVarStore *store = PSPPIRE_VAR_STORE (model);
349 if ( ! psppire_var_store_item_editable (store, row, column) )
350 return &store->disabled;
356 static gchar *get_column_title (const PsppireSheetModel *model, gint col);
357 static gchar *get_row_title (const PsppireSheetModel *model, gint row);
358 static gboolean get_row_sensitivity (const PsppireSheetModel *model, gint row);
361 psppire_var_store_sheet_model_init (PsppireSheetModelIface *iface)
363 iface->get_row_count = psppire_var_store_get_row_count;
364 iface->get_column_count = psppire_var_store_get_column_count;
365 iface->free_strings = TRUE;
366 iface->get_string = psppire_var_store_get_string;
367 iface->set_string = psppire_var_store_set_string;
368 iface->clear_datum = psppire_var_store_clear;
369 iface->is_editable = psppire_var_store_is_editable;
370 iface->get_foreground = psppire_var_store_get_foreground;
371 iface->get_background = NULL;
372 iface->get_justification = NULL;
374 iface->get_column_title = get_column_title;
376 iface->get_row_title = get_row_title;
377 iface->get_row_sensitivity = get_row_sensitivity;
379 iface->get_row_overstrike = NULL;
383 * psppire_var_store_new:
384 * @dict: The dictionary for this var_store.
387 * Return value: a new #PsppireVarStore
390 psppire_var_store_new (PsppireDict *dict)
392 PsppireVarStore *retval;
394 retval = g_object_new (GTK_TYPE_VAR_STORE, "dictionary", dict, NULL);
396 // psppire_var_store_set_dictionary (retval, dict);
403 * psppire_var_store_replace_set_dictionary:
404 * @var_store: The variable store
405 * @dict: The dictionary to set
407 * If a dictionary is already associated with the var-store, then it will be
411 psppire_var_store_set_dictionary (PsppireVarStore *var_store, PsppireDict *dict)
413 if ( var_store->dict ) g_object_unref (var_store->dict);
415 var_store->dict = dict;
417 g_signal_connect (dict, "variable-changed", G_CALLBACK (var_change_callback),
420 g_signal_connect (dict, "variable-deleted", G_CALLBACK (var_delete_callback),
423 g_signal_connect (dict, "variable-inserted",
424 G_CALLBACK (var_insert_callback), var_store);
426 g_signal_connect (dict, "backend-changed", G_CALLBACK (refresh),
429 /* The entire model has changed */
430 psppire_sheet_model_range_changed (PSPPIRE_SHEET_MODEL (var_store), -1, -1, -1, -1);
435 psppire_var_store_finalize (GObject *object)
438 (* parent_class->finalize) (object);
442 psppire_var_store_dispose (GObject *object)
444 PsppireVarStore *self = PSPPIRE_VAR_STORE (object);
446 if (self->dictionary)
447 g_object_unref (self->dictionary);
450 (* parent_class->finalize) (object);
455 psppire_var_store_get_string (const PsppireSheetModel *model,
456 glong row, glong column)
458 PsppireVarStore *store = PSPPIRE_VAR_STORE (model);
462 if ( row >= psppire_dict_get_var_cnt (store->dictionary))
465 pv = psppire_dict_get_variable (store->dictionary, row);
467 return text_for_column (store, pv, column, 0);
471 /* Clears that part of the variable store, if possible, which corresponds
473 Returns true if anything was updated, false otherwise.
476 psppire_var_store_clear (PsppireSheetModel *model, glong row, glong col)
478 struct variable *pv ;
480 PsppireVarStore *var_store = PSPPIRE_VAR_STORE (model);
482 if ( row >= psppire_dict_get_var_cnt (var_store->dictionary))
485 pv = psppire_var_store_get_var (var_store, row);
492 case PSPPIRE_VAR_STORE_COL_LABEL:
493 var_clear_label (pv);
501 /* Attempts to update that part of the variable store which corresponds
502 to ROW, COL with the value TEXT.
503 Returns true if anything was updated, false otherwise.
506 psppire_var_store_set_string (PsppireSheetModel *model,
507 const gchar *text, glong row, glong col)
509 struct variable *pv ;
511 PsppireVarStore *var_store = PSPPIRE_VAR_STORE (model);
513 if ( row >= psppire_dict_get_var_cnt (var_store->dictionary))
516 pv = psppire_var_store_get_var (var_store, row);
523 case PSPPIRE_VAR_STORE_COL_NAME:
526 ok = psppire_dict_rename_var (var_store->dictionary, pv, text);
529 case PSPPIRE_VAR_STORE_COL_COLUMNS:
530 if ( ! text) return FALSE;
531 var_set_display_width (pv, atoi (text));
534 case PSPPIRE_VAR_STORE_COL_WIDTH:
536 const int width = atoi (text);
543 if ( var_is_alpha (pv))
545 if ( width > MAX_STRING )
547 var_set_width (pv, width);
552 = var_store->format_type == PSPPIRE_VAR_STORE_INPUT_FORMATS;
553 struct fmt_spec fmt ;
554 fmt = *var_get_print_format (pv);
555 if ( width < fmt_min_width (fmt.type, for_input)
557 width > fmt_max_width (fmt.type, for_input))
561 fmt.d = MIN (fmt_max_decimals (fmt.type, width, for_input), fmt.d);
563 var_set_both_formats (pv, &fmt);
569 case PSPPIRE_VAR_STORE_COL_DECIMALS:
572 = var_store->format_type == PSPPIRE_VAR_STORE_INPUT_FORMATS;
575 if ( ! text) return FALSE;
576 decimals = atoi (text);
577 fmt = *var_get_print_format (pv);
579 fmt_max_decimals (fmt.type,
586 var_set_both_formats (pv, &fmt);
590 case PSPPIRE_VAR_STORE_COL_LABEL:
592 var_set_label (pv, text, true);
596 case PSPPIRE_VAR_STORE_COL_TYPE:
597 case PSPPIRE_VAR_STORE_COL_VALUES:
598 case PSPPIRE_VAR_STORE_COL_MISSING:
599 case PSPPIRE_VAR_STORE_COL_ALIGN:
600 case PSPPIRE_VAR_STORE_COL_MEASURE:
601 /* These can be modified only by their respective dialog boxes */
605 g_assert_not_reached ();
613 static const gchar none[] = N_("None");
616 text_for_column (PsppireVarStore *vs,
617 const struct variable *pv, gint c, GError **err)
619 PsppireDict *dict = vs->dictionary;
621 const struct fmt_spec *format = var_get_print_format (pv);
625 case PSPPIRE_VAR_STORE_COL_NAME:
626 return xstrdup (var_get_name (pv));
628 case PSPPIRE_VAR_STORE_COL_TYPE:
629 return xstrdup (fmt_gui_name (format->type));
631 case PSPPIRE_VAR_STORE_COL_WIDTH:
634 GString *gstr = g_string_sized_new (10);
635 g_string_printf (gstr, _("%d"), format->w);
636 s = g_locale_to_utf8 (gstr->str, gstr->len, 0, 0, err);
637 g_string_free (gstr, TRUE);
641 case PSPPIRE_VAR_STORE_COL_DECIMALS:
644 GString *gstr = g_string_sized_new (10);
645 g_string_printf (gstr, _("%d"), format->d);
646 s = g_locale_to_utf8 (gstr->str, gstr->len, 0, 0, err);
647 g_string_free (gstr, TRUE);
651 case PSPPIRE_VAR_STORE_COL_COLUMNS:
654 GString *gstr = g_string_sized_new (10);
655 g_string_printf (gstr, _("%d"), var_get_display_width (pv));
656 s = g_locale_to_utf8 (gstr->str, gstr->len, 0, 0, err);
657 g_string_free (gstr, TRUE);
661 case PSPPIRE_VAR_STORE_COL_LABEL:
663 const char *label = var_get_label (pv);
665 return xstrdup (label);
670 case PSPPIRE_VAR_STORE_COL_MISSING:
672 return missing_values_to_string (dict, pv, err);
675 case PSPPIRE_VAR_STORE_COL_VALUES:
677 if ( ! var_has_value_labels (pv))
678 return xstrdup (gettext (none));
681 const struct val_labs *vls = var_get_value_labels (pv);
682 const struct val_lab **labels = val_labs_sorted (vls);
683 const struct val_lab *vl = labels[0];
689 gchar *const vstr = value_to_text (vl->value, pv);
691 return g_strdup_printf (_("{%s,`%s'}_"), vstr,
692 val_lab_get_escaped_label (vl));
697 case PSPPIRE_VAR_STORE_COL_ALIGN:
699 const gint align = var_get_alignment (pv);
701 g_assert (align < n_ALIGNMENTS);
702 return xstrdup (alignment_to_string (align));
705 case PSPPIRE_VAR_STORE_COL_MEASURE:
707 return xstrdup (measure_to_string (var_get_measure (pv)));
716 /* Return the number of variables */
718 psppire_var_store_get_var_cnt (PsppireVarStore *store)
720 return psppire_dict_get_var_cnt (store->dictionary);
725 psppire_var_store_get_row_count (const PsppireSheetModel * model)
728 PsppireVarStore *vs = PSPPIRE_VAR_STORE (model);
731 rows = psppire_dict_get_var_cnt (vs->dictionary);
737 psppire_var_store_get_column_count (const PsppireSheetModel * model)
739 return PSPPIRE_VAR_STORE_n_COLS ;
744 /* Row related funcs */
748 get_row_sensitivity (const PsppireSheetModel *model, gint row)
750 PsppireVarStore *vs = PSPPIRE_VAR_STORE (model);
752 if ( ! vs->dictionary)
755 return row < psppire_dict_get_var_cnt (vs->dictionary);
760 get_row_title (const PsppireSheetModel *model, gint unit)
762 return g_strdup_printf (_("%d"), unit + 1);
768 static const gchar *column_titles[] = {
783 get_column_title (const PsppireSheetModel *model, gint col)
787 return g_strdup (gettext (column_titles[col]));