1 /* PSPPIRE - a graphical user interface for PSPP.
2 Copyright (C) 2008, 2009, 2011, 2012 Free Software Foundation, Inc.
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/>. */
18 #include "psppire-var-sheet.h"
19 #include <ui/gui/sheet/psppire-axis.h>
21 #include "builder-wrapper.h"
24 #include "customentry.h"
25 #include <data/variable.h>
26 #include "data/value-labels.h"
27 #include "psppire-var-store.h"
28 #include "ui/gui/val-labs-dialog.h"
29 #include "ui/gui/var-type-dialog.h"
32 #define _(msgid) gettext (msgid)
33 #define N_(msgid) msgid
36 static void psppire_var_sheet_class_init (PsppireVarSheetClass *klass);
37 static void psppire_var_sheet_init (PsppireVarSheet *vs);
42 PSPPIRE_VAR_SHEET_MAY_CREATE_VARS = 1
46 psppire_var_sheet_get_type (void)
48 static GType vs_type = 0;
52 static const GTypeInfo vs_info =
54 sizeof (PsppireVarSheetClass),
56 NULL, /* base_finalize */
57 (GClassInitFunc) psppire_var_sheet_class_init,
58 NULL, /* class_finalize */
59 NULL, /* class_data */
60 sizeof (PsppireVarSheet),
62 (GInstanceInitFunc) psppire_var_sheet_init,
65 vs_type = g_type_register_static (PSPPIRE_TYPE_SHEET, "PsppireVarSheet",
72 static GObjectClass * parent_class = NULL;
75 psppire_var_sheet_dispose (GObject *obj)
77 PsppireVarSheet *vs = (PsppireVarSheet *)obj;
79 if (vs->dispose_has_run)
82 /* Make sure dispose does not run twice. */
83 vs->dispose_has_run = TRUE;
85 /* Chain up to the parent class */
86 G_OBJECT_CLASS (parent_class)->dispose (obj);
90 psppire_var_sheet_finalize (GObject *obj)
92 /* Chain up to the parent class */
93 G_OBJECT_CLASS (parent_class)->finalize (obj);
97 struct column_parameters
103 #define n_ALIGNMENTS 3
105 const gchar *const alignments[n_ALIGNMENTS + 1]={
112 const gchar *const measures[n_MEASURES + 1]={
121 /* Create a list store from an array of strings */
122 static GtkListStore *
123 create_label_list (const gchar *const *labels)
129 GtkListStore *list_store = gtk_list_store_new (1, G_TYPE_STRING);
131 while ( (s = labels[i++]))
133 gtk_list_store_append (list_store, &iter);
134 gtk_list_store_set (list_store, &iter,
144 psppire_var_sheet_set_property (GObject *object,
149 PsppireVarSheet *self = (PsppireVarSheet *) object;
153 case PSPPIRE_VAR_SHEET_MAY_CREATE_VARS:
154 self->may_create_vars = g_value_get_boolean (value);
158 G_OBJECT_WARN_INVALID_PROPERTY_ID(object, property_id, pspec);
164 psppire_var_sheet_get_property (GObject *object,
169 PsppireVarSheet *self = (PsppireVarSheet *) object;
173 case PSPPIRE_VAR_SHEET_MAY_CREATE_VARS:
174 g_value_set_boolean (value, self->may_create_vars);
178 G_OBJECT_WARN_INVALID_PROPERTY_ID(object, property_id, pspec);
185 psppire_var_sheet_class_init (PsppireVarSheetClass *klass)
187 GObjectClass *object_class = G_OBJECT_CLASS (klass);
190 parent_class = g_type_class_peek_parent (klass);
192 object_class->dispose = psppire_var_sheet_dispose;
193 object_class->finalize = psppire_var_sheet_finalize;
194 object_class->set_property = psppire_var_sheet_set_property;
195 object_class->get_property = psppire_var_sheet_get_property;
197 pspec = g_param_spec_boolean ("may-create-vars",
198 "May create variables",
199 "Whether the user may create more variables",
202 g_object_class_install_property (object_class,
203 PSPPIRE_VAR_SHEET_MAY_CREATE_VARS,
206 klass->measure_list = create_label_list (measures);
207 klass->alignment_list = create_label_list (alignments);
212 /* Callback for when the alignment combo box
215 change_alignment (GtkComboBox *cb,
216 struct variable *var)
218 gint active_item = gtk_combo_box_get_active (cb);
220 if ( active_item < 0 ) return ;
222 var_set_alignment (var, active_item);
227 /* Callback for when the measure combo box
230 change_measure (GtkComboBox *cb,
231 struct variable *var)
233 gint active_item = gtk_combo_box_get_active (cb);
235 if ( active_item < 0 ) return ;
237 var_set_measure (var, active_item);
241 /* Moves the focus to a new cell.
242 Returns TRUE iff the move should be disallowed */
244 traverse_cell_callback (PsppireSheet *sheet,
245 const PsppireSheetCell *existing_cell,
246 PsppireSheetCell *new_cell)
248 PsppireVarSheet *var_sheet = PSPPIRE_VAR_SHEET (sheet);
249 PsppireVarStore *var_store = PSPPIRE_VAR_STORE (psppire_sheet_get_model (sheet));
251 gint n_vars = psppire_var_store_get_var_cnt (var_store);
253 if (new_cell->col >= PSPPIRE_VAR_STORE_n_COLS)
256 if (new_cell->row >= n_vars && !var_sheet->may_create_vars)
259 if ( existing_cell->row == n_vars && new_cell->row >= n_vars)
261 GtkEntry *entry = psppire_sheet_get_entry (sheet);
263 const gchar *name = gtk_entry_get_text (entry);
265 if (! psppire_dict_check_name (var_store->dictionary, name, TRUE))
268 psppire_dict_insert_variable (var_store->dictionary, existing_cell->row, name);
274 /* If the destination cell is outside the current variables, then
275 automatically create variables for the new rows.
277 if ( ((new_cell->row > n_vars) ||
278 (new_cell->row == n_vars &&
279 new_cell->col != PSPPIRE_VAR_STORE_COL_NAME)) )
282 for ( i = n_vars ; i <= new_cell->row; ++i )
283 psppire_dict_insert_variable (var_store->dictionary, i, NULL);
290 var_sheet_show_var_type_dialog (PsppireVarSheet *vs)
292 PsppireVarStore *var_store;
293 struct fmt_spec format;
294 struct variable *var;
297 var_store = PSPPIRE_VAR_STORE (psppire_sheet_get_model (PSPPIRE_SHEET (vs)));
299 psppire_sheet_get_active_cell (PSPPIRE_SHEET (vs), &row, NULL);
300 var = psppire_var_store_get_var (var_store, row);
301 g_return_if_fail (var != NULL);
303 format = *var_get_print_format (var);
304 psppire_var_type_dialog_run (GTK_WINDOW (gtk_widget_get_toplevel (
305 GTK_WIDGET (vs))), &format);
306 var_set_width (var, fmt_var_width (&format));
307 var_set_both_formats (var, &format);
311 var_sheet_show_val_labs_dialog (PsppireVarSheet *vs)
313 PsppireVarStore *var_store;
314 struct val_labs *labels;
315 struct variable *var;
318 var_store = PSPPIRE_VAR_STORE (psppire_sheet_get_model (PSPPIRE_SHEET (vs)));
320 psppire_sheet_get_active_cell (PSPPIRE_SHEET (vs), &row, NULL);
321 var = psppire_var_store_get_var (var_store, row);
322 g_return_if_fail (var != NULL);
324 labels = psppire_val_labs_dialog_run (GTK_WINDOW (gtk_widget_get_toplevel (
325 GTK_WIDGET (vs))), var);
328 var_set_value_labels (var, labels);
329 val_labs_destroy (labels);
334 var_sheet_show_miss_vals_dialog (PsppireVarSheet *vs)
336 PsppireVarStore *var_store;
337 struct missing_values mv;
338 struct variable *var;
341 var_store = PSPPIRE_VAR_STORE (psppire_sheet_get_model (PSPPIRE_SHEET (vs)));
343 psppire_sheet_get_active_cell (PSPPIRE_SHEET (vs), &row, NULL);
344 var = psppire_var_store_get_var (var_store, row);
345 g_return_if_fail (var != NULL);
347 psppire_missing_val_dialog_run (GTK_WINDOW (gtk_widget_get_toplevel (
348 GTK_WIDGET (vs))), var, &mv);
349 var_set_missing_values (var, &mv);
354 Callback whenever the active cell changes on the var sheet.
357 var_sheet_change_active_cell (PsppireVarSheet *vs,
358 gint row, gint column,
359 gint oldrow, gint oldcolumn,
362 PsppireVarStore *var_store;
363 PsppireVarSheetClass *vs_class =
364 PSPPIRE_VAR_SHEET_CLASS(G_OBJECT_GET_CLASS (vs));
366 struct variable *var ;
367 PsppireSheet *sheet = PSPPIRE_SHEET (vs);
369 g_return_if_fail (sheet != NULL);
371 var_store = PSPPIRE_VAR_STORE (psppire_sheet_get_model (sheet));
373 g_assert (var_store);
375 g_return_if_fail (oldcolumn == PSPPIRE_VAR_STORE_COL_NAME ||
376 row < psppire_var_store_get_var_cnt (var_store));
378 var = psppire_var_store_get_var (var_store, row);
382 case PSPPIRE_VAR_STORE_COL_ALIGN:
385 static GtkListStore *list_store = NULL;
386 GtkComboBoxEntry *cbe;
387 psppire_sheet_change_entry (sheet, GTK_TYPE_COMBO_BOX_ENTRY);
388 entry = psppire_sheet_get_entry (sheet);
389 cbe = GTK_COMBO_BOX_ENTRY (GTK_WIDGET (entry)->parent);
391 if ( ! list_store) list_store = create_label_list (alignments);
393 gtk_combo_box_set_model (GTK_COMBO_BOX (cbe),
394 GTK_TREE_MODEL (vs_class->alignment_list));
396 gtk_combo_box_entry_set_text_column (cbe, 0);
398 g_signal_connect (cbe, "changed",
399 G_CALLBACK (change_alignment), var);
403 case PSPPIRE_VAR_STORE_COL_MEASURE:
406 GtkComboBoxEntry *cbe;
407 psppire_sheet_change_entry (sheet, GTK_TYPE_COMBO_BOX_ENTRY);
408 entry = psppire_sheet_get_entry (sheet);
409 cbe = GTK_COMBO_BOX_ENTRY (GTK_WIDGET (entry)->parent);
411 gtk_combo_box_set_model (GTK_COMBO_BOX (cbe),
412 GTK_TREE_MODEL (vs_class->measure_list));
414 gtk_combo_box_entry_set_text_column (cbe, 0);
416 g_signal_connect (cbe, "changed",
417 G_CALLBACK (change_measure), var);
421 case PSPPIRE_VAR_STORE_COL_VALUES:
423 PsppireCustomEntry *customEntry;
425 psppire_sheet_change_entry (sheet, PSPPIRE_CUSTOM_ENTRY_TYPE);
428 PSPPIRE_CUSTOM_ENTRY (psppire_sheet_get_entry (sheet));
430 g_signal_connect_swapped (customEntry,
432 G_CALLBACK (var_sheet_show_val_labs_dialog),
437 case PSPPIRE_VAR_STORE_COL_MISSING:
439 PsppireCustomEntry *customEntry;
441 psppire_sheet_change_entry (sheet, PSPPIRE_CUSTOM_ENTRY_TYPE);
444 PSPPIRE_CUSTOM_ENTRY (psppire_sheet_get_entry (sheet));
446 g_signal_connect_swapped (customEntry,
448 G_CALLBACK (var_sheet_show_miss_vals_dialog),
453 case PSPPIRE_VAR_STORE_COL_TYPE:
455 PsppireCustomEntry *customEntry;
457 psppire_sheet_change_entry (sheet, PSPPIRE_CUSTOM_ENTRY_TYPE);
460 PSPPIRE_CUSTOM_ENTRY (psppire_sheet_get_entry (sheet));
462 g_signal_connect_swapped (customEntry,
464 G_CALLBACK (var_sheet_show_var_type_dialog),
469 case PSPPIRE_VAR_STORE_COL_WIDTH:
470 case PSPPIRE_VAR_STORE_COL_DECIMALS:
471 case PSPPIRE_VAR_STORE_COL_COLUMNS:
473 if ( psppire_sheet_model_is_editable (PSPPIRE_SHEET_MODEL(var_store),
478 const gchar *s = psppire_sheet_cell_get_text (sheet, row, column);
482 GtkSpinButton *spinButton ;
483 const gint current_value = g_strtod (s, NULL);
486 const struct fmt_spec *fmt = var_get_print_format (var);
489 case PSPPIRE_VAR_STORE_COL_WIDTH:
490 r_min = MAX (fmt->d + 1, fmt_min_output_width (fmt->type));
491 r_max = fmt_max_output_width (fmt->type);
493 case PSPPIRE_VAR_STORE_COL_DECIMALS:
495 r_max = fmt_max_output_decimals (fmt->type, fmt->w);
497 case PSPPIRE_VAR_STORE_COL_COLUMNS:
499 r_max = 255 ; /* Is this a sensible value ? */
502 g_assert_not_reached ();
505 adj = gtk_adjustment_new (current_value,
507 1.0, 1.0, /* steps */
510 psppire_sheet_change_entry (sheet, GTK_TYPE_SPIN_BUTTON);
513 GTK_SPIN_BUTTON (psppire_sheet_get_entry (sheet));
515 gtk_spin_button_set_adjustment (spinButton, GTK_ADJUSTMENT (adj));
516 gtk_spin_button_set_digits (spinButton, 0);
523 psppire_sheet_change_entry (sheet, GTK_TYPE_ENTRY);
530 psppire_var_sheet_init (PsppireVarSheet *vs)
532 GtkBuilder *builder = builder_new ("data-editor.ui");
534 connect_help (builder);
536 g_object_unref (builder);
538 vs->dispose_has_run = FALSE;
539 vs->may_create_vars = TRUE;
541 g_signal_connect (vs, "activate",
542 G_CALLBACK (var_sheet_change_active_cell),
545 g_signal_connect (vs, "traverse",
546 G_CALLBACK (traverse_cell_callback), NULL);
550 static const struct column_parameters column_def[] = {
554 { N_("Decimals"),91},
556 { N_("Values"), 103},
557 { N_("Missing"), 95},
558 { N_("Columns"), 80},
560 { N_("Measure"), 99},
564 psppire_var_sheet_new (void)
567 PsppireAxis *ha = psppire_axis_new ();
568 PsppireAxis *va = psppire_axis_new ();
570 GtkWidget *w = g_object_new (psppire_var_sheet_get_type (), NULL);
572 for (i = 0 ; i < 10 ; ++i)
573 psppire_axis_append (ha, column_def[i].width);
579 g_object_set (ha, "minimum-extent", 0,
583 "horizontal-axis", ha,