1 /* PSPPIRE - a graphical user interface for PSPP.
2 Copyright (C) 2008, 2009, 2011, 2012, 2013 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/>. */
19 #include "ui/gui/psppire-var-sheet.h"
21 #include "data/format.h"
22 #include "data/value-labels.h"
23 #include "libpspp/range-set.h"
24 #include "ui/gui/builder-wrapper.h"
25 #include "ui/gui/helper.h"
26 #include "ui/gui/missing-val-dialog.h"
27 #include "ui/gui/pspp-sheet-selection.h"
28 #include "ui/gui/psppire-cell-renderer-button.h"
29 #include "ui/gui/psppire-data-editor.h"
30 #include "ui/gui/psppire-data-window.h"
31 #include "ui/gui/psppire-dialog-action-var-info.h"
32 #include "ui/gui/psppire-dictview.h"
33 #include "ui/gui/psppire-empty-list-store.h"
34 #include "ui/gui/psppire-marshal.h"
35 #include "ui/gui/val-labs-dialog.h"
36 #include "ui/gui/var-type-dialog.h"
37 #include "ui/gui/var-display.h"
38 #include "ui/gui/var-type-dialog.h"
40 #include "gl/intprops.h"
43 #define _(msgid) gettext (msgid)
44 #define N_(msgid) msgid
60 G_DEFINE_TYPE (PsppireVarSheet, psppire_var_sheet, PSPP_TYPE_SHEET_VIEW);
63 set_spin_cell (GtkCellRenderer *cell, int value, int min, int max, int step)
65 char text[INT_BUFSIZE_BOUND (int)];
66 GtkAdjustment *adjust;
69 adjust = GTK_ADJUSTMENT (gtk_adjustment_new (value, min, max,
74 sprintf (text, "%d", value);
83 error_dialog (GtkWindow *w, gchar *primary_text, gchar *secondary_text)
86 gtk_message_dialog_new (w,
87 GTK_DIALOG_DESTROY_WITH_PARENT,
89 GTK_BUTTONS_CLOSE, "%s", primary_text);
91 g_object_set (dialog, "icon-name", "psppicon", NULL);
93 gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG (dialog),
94 "%s", secondary_text);
96 gtk_dialog_run (GTK_DIALOG (dialog));
98 gtk_widget_destroy (dialog);
102 on_name_column_editing_started (GtkCellRenderer *cell,
103 GtkCellEditable *editable,
107 PsppireVarSheet *var_sheet = g_object_get_data (G_OBJECT (cell), "var-sheet");
108 PsppireDict *dict = psppire_var_sheet_get_dictionary (var_sheet);
110 g_return_if_fail (var_sheet);
111 g_return_if_fail (dict);
113 if (GTK_IS_ENTRY (editable))
115 GtkEntry *entry = GTK_ENTRY (editable);
116 if (gtk_entry_get_text (entry)[0] == '\0')
119 if (psppire_dict_generate_name (dict, name, sizeof name))
120 gtk_entry_set_text (entry, name);
126 scroll_to_bottom (GtkWidget *widget,
127 GtkRequisition *requisition,
128 gpointer unused UNUSED)
130 PsppireVarSheet *var_sheet = PSPPIRE_VAR_SHEET (widget);
131 PsppSheetView *sheet_view = PSPP_SHEET_VIEW (widget);
132 GtkAdjustment *vadjust;
134 vadjust = pspp_sheet_view_get_vadjustment (sheet_view);
135 gtk_adjustment_set_value (vadjust, gtk_adjustment_get_upper (vadjust));
137 if (var_sheet->scroll_to_bottom_signal)
139 g_signal_handler_disconnect (var_sheet,
140 var_sheet->scroll_to_bottom_signal);
141 var_sheet->scroll_to_bottom_signal = 0;
146 on_var_column_edited (GtkCellRendererText *cell,
151 PsppireVarSheet *var_sheet = user_data;
152 GtkWindow *window = GTK_WINDOW (gtk_widget_get_toplevel (GTK_WIDGET (var_sheet)));
153 struct dictionary *dict = var_sheet->dict->dict;
154 enum vs_column column_id;
155 struct variable *var;
160 path = gtk_tree_path_new_from_string (path_string);
161 row = gtk_tree_path_get_indices (path)[0];
162 gtk_tree_path_free (path);
164 column_id = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (cell),
167 var = psppire_dict_get_variable (var_sheet->dict, row);
170 g_return_if_fail (column_id == VS_NAME);
172 if (!dict_id_is_valid (dict, new_text, false))
173 error_dialog (window,
174 g_strdup (_("Cannot create variable.")),
175 g_strdup_printf (_("\"%s\" is not a valid variable "
176 "name."), new_text));
177 else if (dict_lookup_var (dict, new_text) != NULL)
178 error_dialog (window,
179 g_strdup (_("Cannot create variable.")),
180 g_strdup_printf (_("This dictionary already contains "
181 "a variable named \"%s\"."),
185 dict_create_var (var_sheet->dict->dict, new_text, 0);
186 if (!var_sheet->scroll_to_bottom_signal)
188 gtk_widget_queue_resize (GTK_WIDGET (var_sheet));
189 var_sheet->scroll_to_bottom_signal =
190 g_signal_connect (var_sheet, "size-request",
191 G_CALLBACK (scroll_to_bottom), NULL);
201 if (!dict_id_is_valid (dict, new_text, false))
202 error_dialog (window,
203 g_strdup (_("Cannot rename variable.")),
204 g_strdup_printf (_("\"%s\" is not a valid variable "
205 "name."), new_text));
206 else if (dict_lookup_var (dict, new_text) != NULL
207 && dict_lookup_var (dict, new_text) != var)
208 error_dialog (window,
209 g_strdup (_("Cannot rename variable.")),
210 g_strdup_printf (_("This dictionary already contains "
211 "a variable named \"%s\"."),
214 dict_rename_var (dict, var, new_text);
222 width = atoi (new_text);
225 struct fmt_spec format;
227 format = *var_get_print_format (var);
228 fmt_change_width (&format, width, var_sheet->format_use);
229 var_set_width (var, fmt_var_width (&format));
230 var_set_both_formats (var, &format);
235 decimals = atoi (new_text);
238 struct fmt_spec format;
240 format = *var_get_print_format (var);
241 fmt_change_decimals (&format, decimals, var_sheet->format_use);
242 var_set_print_format (var, &format);
247 var_set_label (var, new_text, false);
255 width = atoi (new_text);
256 if (width > 0 && width < 2 * MAX_STRING)
257 var_set_display_width (var, width);
261 if (!strcmp (new_text, alignment_to_string (ALIGN_LEFT)))
262 var_set_alignment (var, ALIGN_LEFT);
263 else if (!strcmp (new_text, alignment_to_string (ALIGN_CENTRE)))
264 var_set_alignment (var, ALIGN_CENTRE);
265 else if (!strcmp (new_text, alignment_to_string (ALIGN_RIGHT)))
266 var_set_alignment (var, ALIGN_RIGHT);
270 if (!strcmp (new_text, measure_to_string (MEASURE_NOMINAL)))
271 var_set_measure (var, MEASURE_NOMINAL);
272 else if (!strcmp (new_text, measure_to_string (MEASURE_ORDINAL)))
273 var_set_measure (var, MEASURE_ORDINAL);
274 else if (!strcmp (new_text, measure_to_string (MEASURE_SCALE)))
275 var_set_measure (var, MEASURE_SCALE);
281 render_popup_cell (PsppSheetViewColumn *tree_column,
282 GtkCellRenderer *cell,
287 PsppireVarSheet *var_sheet = user_data;
290 row = GPOINTER_TO_INT (iter->user_data);
292 "editable", row < psppire_dict_get_var_cnt (var_sheet->dict),
297 render_var_cell (PsppSheetViewColumn *tree_column,
298 GtkCellRenderer *cell,
303 PsppireVarSheet *var_sheet = user_data;
304 const struct fmt_spec *print;
305 enum vs_column column_id;
306 struct variable *var;
309 column_id = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (tree_column),
310 "column-number")) - 1;
311 row = GPOINTER_TO_INT (iter->user_data);
313 if (row >= psppire_dict_get_var_cnt (var_sheet->dict))
315 if (GTK_IS_CELL_RENDERER_TEXT (cell))
319 "editable", column_id == VS_NAME,
321 if (column_id == VS_WIDTH
322 || column_id == VS_DECIMALS
323 || column_id == VS_COLUMNS)
324 g_object_set (cell, "adjustment", NULL, NULL);
327 g_object_set (cell, "stock-id", "", NULL);
331 var = psppire_dict_get_variable (var_sheet->dict, row);
333 print = var_get_print_format (var);
338 "text", var_get_name (var),
345 "text", fmt_gui_name (print->type),
351 set_spin_cell (cell, print->w,
352 fmt_min_width (print->type, var_sheet->format_use),
353 fmt_max_width (print->type, var_sheet->format_use),
354 fmt_step_width (print->type));
358 if (fmt_takes_decimals (print->type))
360 int max_w = fmt_max_width (print->type, var_sheet->format_use);
361 int max_d = fmt_max_decimals (print->type, max_w,
362 var_sheet->format_use);
363 set_spin_cell (cell, print->d, 0, max_d, 1);
375 "text", var_has_label (var) ? var_get_label (var) : "",
381 g_object_set (cell, "editable", FALSE, NULL);
382 if ( ! var_has_value_labels (var))
383 g_object_set (cell, "text", _("None"), NULL);
386 const struct val_labs *vls = var_get_value_labels (var);
387 const struct val_lab **labels = val_labs_sorted (vls);
388 const struct val_lab *vl = labels[0];
389 gchar *vstr = value_to_text (vl->value, var);
390 char *text = xasprintf (_("{%s, %s}..."), vstr,
391 val_lab_get_escaped_label (vl));
394 g_object_set (cell, "text", text, NULL);
402 char *text = missing_values_to_string (var_sheet->dict, var, NULL);
412 set_spin_cell (cell, var_get_display_width (var), 1, 2 * MAX_STRING, 1);
417 "text", alignment_to_string (var_get_alignment (var)),
423 if (GTK_IS_CELL_RENDERER_TEXT (cell))
425 "text", measure_to_string (var_get_measure (var)),
429 g_object_set (cell, "stock-id",
430 psppire_dict_view_get_var_measurement_stock_id (var),
436 static struct variable *
437 path_string_to_variable (PsppireVarSheet *var_sheet, gchar *path_string)
443 path = gtk_tree_path_new_from_string (path_string);
444 row = gtk_tree_path_get_indices (path)[0];
445 gtk_tree_path_free (path);
447 dict = psppire_var_sheet_get_dictionary (var_sheet);
448 g_return_val_if_fail (dict != NULL, NULL);
450 return psppire_dict_get_variable (dict, row);
454 on_type_click (PsppireCellRendererButton *cell,
456 PsppireVarSheet *var_sheet)
458 GtkWidget *toplevel = gtk_widget_get_toplevel (GTK_WIDGET (var_sheet));
459 struct fmt_spec format;
460 struct variable *var;
462 var = path_string_to_variable (var_sheet, path);
463 g_return_if_fail (var != NULL);
465 format = *var_get_print_format (var);
466 psppire_var_type_dialog_run (GTK_WINDOW (toplevel), &format);
468 var_set_width_and_formats (var, fmt_var_width (&format), &format, &format);
472 on_value_labels_click (PsppireCellRendererButton *cell,
474 PsppireVarSheet *var_sheet)
476 GtkWidget *toplevel = gtk_widget_get_toplevel (GTK_WIDGET (var_sheet));
477 struct val_labs *labels;
478 struct variable *var;
480 var = path_string_to_variable (var_sheet, path);
481 g_return_if_fail (var != NULL);
483 labels = psppire_val_labs_dialog_run (GTK_WINDOW (toplevel), var);
486 var_set_value_labels (var, labels);
487 val_labs_destroy (labels);
492 on_missing_values_click (PsppireCellRendererButton *cell,
494 PsppireVarSheet *var_sheet)
496 GtkWidget *toplevel = gtk_widget_get_toplevel (GTK_WIDGET (var_sheet));
497 struct missing_values mv;
498 struct variable *var;
500 var = path_string_to_variable (var_sheet, path);
501 g_return_if_fail (var != NULL);
503 psppire_missing_val_dialog_run (GTK_WINDOW (toplevel), var, &mv);
504 var_set_missing_values (var, &mv);
509 get_string_width (PsppSheetView *treeview, GtkCellRenderer *renderer,
513 g_object_set (G_OBJECT (renderer),
514 PSPPIRE_IS_CELL_RENDERER_BUTTON (renderer) ? "label" : "text",
515 string, (void *) NULL);
516 gtk_cell_renderer_get_size (renderer, GTK_WIDGET (treeview),
517 NULL, NULL, NULL, &width, NULL);
522 get_monospace_width (PsppSheetView *treeview, GtkCellRenderer *renderer,
529 ds_put_byte_multiple (&s, '0', char_cnt);
530 ds_put_byte (&s, ' ');
531 width = get_string_width (treeview, renderer, ds_cstr (&s));
537 static PsppSheetViewColumn *
538 add_var_sheet_column (PsppireVarSheet *var_sheet, GtkCellRenderer *renderer,
539 enum vs_column column_id,
540 const char *title, int width)
542 PsppSheetView *sheet_view = PSPP_SHEET_VIEW (var_sheet);
543 int title_width, content_width;
544 PsppSheetViewColumn *column;
546 column = pspp_sheet_view_column_new_with_attributes (title, renderer, NULL);
547 g_object_set_data (G_OBJECT (column), "column-number",
548 GINT_TO_POINTER (column_id) + 1);
550 pspp_sheet_view_column_set_cell_data_func (
551 column, renderer, render_var_cell, var_sheet, NULL);
553 title_width = get_string_width (sheet_view, renderer, title);
554 content_width = get_monospace_width (sheet_view, renderer, width);
555 g_object_set_data (G_OBJECT (column), "content-width",
556 GINT_TO_POINTER (content_width));
558 pspp_sheet_view_column_set_fixed_width (column,
559 MAX (title_width, content_width));
560 pspp_sheet_view_column_set_resizable (column, TRUE);
562 pspp_sheet_view_append_column (sheet_view, column);
564 g_signal_connect (renderer, "edited",
565 G_CALLBACK (on_var_column_edited),
567 g_object_set_data (G_OBJECT (renderer), "column-id",
568 GINT_TO_POINTER (column_id));
569 g_object_set_data (G_OBJECT (renderer), "var-sheet", var_sheet);
574 static PsppSheetViewColumn *
575 add_text_column (PsppireVarSheet *var_sheet, enum vs_column column_id,
576 const char *title, int width)
578 return add_var_sheet_column (var_sheet, gtk_cell_renderer_text_new (),
579 column_id, title, width);
582 static PsppSheetViewColumn *
583 add_spin_column (PsppireVarSheet *var_sheet, enum vs_column column_id,
584 const char *title, int width)
586 return add_var_sheet_column (var_sheet, gtk_cell_renderer_spin_new (),
587 column_id, title, width);
590 static PsppSheetViewColumn *
591 add_combo_column (PsppireVarSheet *var_sheet, enum vs_column column_id,
592 const char *title, int width,
595 GtkCellRenderer *cell;
600 store = gtk_list_store_new (2, G_TYPE_INT, G_TYPE_STRING);
601 va_start (args, width);
602 while ((name = va_arg (args, const char *)) != NULL)
604 int value = va_arg (args, int);
605 gtk_list_store_insert_with_values (store, NULL, G_MAXINT,
612 cell = gtk_cell_renderer_combo_new ();
615 "model", GTK_TREE_MODEL (store),
619 return add_var_sheet_column (var_sheet, cell, column_id, title, width);
624 add_popup_menu (PsppireVarSheet *var_sheet,
625 PsppSheetViewColumn *column,
626 void (*on_click) (PsppireCellRendererButton *,
628 PsppireVarSheet *var_sheet))
630 PsppSheetView *sheet_view = PSPP_SHEET_VIEW (var_sheet);
631 const char *button_label = "...";
632 GtkCellRenderer *button_renderer;
635 button_renderer = psppire_cell_renderer_button_new ();
636 g_object_set (button_renderer,
637 "label", button_label,
640 g_signal_connect (button_renderer, "clicked", G_CALLBACK (on_click),
642 pspp_sheet_view_column_pack_start (column, button_renderer, FALSE);
643 pspp_sheet_view_column_set_cell_data_func (
644 column, button_renderer, render_popup_cell, var_sheet, NULL);
646 content_width = GPOINTER_TO_INT (g_object_get_data (
647 G_OBJECT (column), "content-width"));
648 content_width += get_string_width (sheet_view, button_renderer,
650 if (content_width > pspp_sheet_view_column_get_fixed_width (column))
651 pspp_sheet_view_column_set_fixed_width (column, content_width);
655 get_tooltip_location (GtkWidget *widget, GtkTooltip *tooltip,
656 gint wx, gint wy, size_t *row, size_t *column)
658 PsppSheetView *tree_view = PSPP_SHEET_VIEW (widget);
662 PsppSheetViewColumn *tree_column;
663 GtkTreeModel *tree_model;
667 /* Check that WIDGET is really visible on the screen before we
668 do anything else. This is a bug fix for a sticky situation:
669 when text_data_import_assistant() returns, it frees the data
670 necessary to compose the tool tip message, but there may be
671 a tool tip under preparation at that point (even if there is
672 no visible tool tip) that will call back into us a little
673 bit later. Perhaps the correct solution to this problem is
674 to make the data related to the tool tips part of a GObject
675 that only gets destroyed when all references are released,
676 but this solution appears to be effective too. */
677 if (!gtk_widget_get_mapped (widget))
680 pspp_sheet_view_convert_widget_to_bin_window_coords (tree_view,
682 if (!pspp_sheet_view_get_path_at_pos (tree_view, bx, by,
683 &path, &tree_column, NULL, NULL))
686 column_ptr = g_object_get_data (G_OBJECT (tree_column), "column-number");
687 if (column_ptr == NULL)
689 *column = GPOINTER_TO_INT (column_ptr) - 1;
691 pspp_sheet_view_set_tooltip_cell (tree_view, tooltip, path, tree_column,
694 tree_model = pspp_sheet_view_get_model (tree_view);
695 ok = gtk_tree_model_get_iter (tree_model, &iter, path);
696 gtk_tree_path_free (path);
700 *row = GPOINTER_TO_INT (iter.user_data);
705 on_query_var_tooltip (GtkWidget *widget, gint wx, gint wy,
706 gboolean keyboard_mode UNUSED,
707 GtkTooltip *tooltip, gpointer *user_data UNUSED)
709 PsppireVarSheet *var_sheet = PSPPIRE_VAR_SHEET (widget);
711 struct variable *var;
714 if (!get_tooltip_location (widget, tooltip, wx, wy, &row, &column))
717 dict = psppire_var_sheet_get_dictionary (var_sheet);
718 g_return_val_if_fail (dict != NULL, FALSE);
720 if (row >= psppire_dict_get_var_cnt (dict))
722 gtk_tooltip_set_text (tooltip, _("Enter a variable name to add a "
727 var = psppire_dict_get_variable (dict, row);
728 g_return_val_if_fail (var != NULL, FALSE);
734 char text[FMT_STRING_LEN_MAX + 1];
736 fmt_to_string (var_get_print_format (var), text);
737 gtk_tooltip_set_text (tooltip, text);
742 if (var_has_value_labels (var))
744 const struct val_labs *vls = var_get_value_labels (var);
745 const struct val_lab **labels = val_labs_sorted (vls);
750 for (i = 0; i < val_labs_count (vls); i++)
752 const struct val_lab *vl = labels[i];
755 if (i >= 10 || ds_length (&s) > 500)
757 ds_put_cstr (&s, "...");
761 vstr = value_to_text (vl->value, var);
762 ds_put_format (&s, _("{%s, %s}\n"), vstr,
763 val_lab_get_escaped_label (vl));
767 ds_chomp_byte (&s, '\n');
769 gtk_tooltip_set_text (tooltip, ds_cstr (&s));
781 do_popup_menu (GtkWidget *widget, guint button, guint32 time)
783 PsppireVarSheet *var_sheet = PSPPIRE_VAR_SHEET (widget);
786 menu = get_widget_assert (var_sheet->builder, "varsheet-variable-popup");
787 gtk_menu_popup (GTK_MENU (menu), NULL, NULL, NULL, NULL, button, time);
791 on_popup_menu (GtkWidget *widget, gpointer user_data UNUSED)
793 do_popup_menu (widget, 0, gtk_get_current_event_time ());
797 on_button_pressed (GtkWidget *widget, GdkEventButton *event,
798 gpointer user_data UNUSED)
800 PsppSheetView *sheet_view = PSPP_SHEET_VIEW (widget);
802 if (event->type == GDK_BUTTON_PRESS && event->button == 3)
804 PsppSheetSelection *selection;
806 selection = pspp_sheet_view_get_selection (sheet_view);
807 if (pspp_sheet_selection_count_selected_rows (selection) <= 1)
811 if (pspp_sheet_view_get_path_at_pos (sheet_view, event->x, event->y,
812 &path, NULL, NULL, NULL))
814 pspp_sheet_selection_unselect_all (selection);
815 pspp_sheet_selection_select_path (selection, path);
816 gtk_tree_path_free (path);
820 do_popup_menu (widget, event->button, event->time);
828 psppire_fmt_use_get_type (void)
830 static GType etype = 0;
833 static const GEnumValue values[] =
835 { FMT_FOR_INPUT, "FMT_FOR_INPUT", "input" },
836 { FMT_FOR_OUTPUT, "FMT_FOR_OUTPUT", "output" },
840 etype = g_enum_register_static
841 (g_intern_static_string ("PsppireFmtUse"), values);
850 PROP_MAY_CREATE_VARS,
851 PROP_MAY_DELETE_VARS,
857 psppire_var_sheet_set_property (GObject *object,
862 PsppireVarSheet *obj = PSPPIRE_VAR_SHEET (object);
866 case PROP_DICTIONARY:
867 psppire_var_sheet_set_dictionary (obj,
868 PSPPIRE_DICT (g_value_get_object (
872 case PROP_MAY_CREATE_VARS:
873 psppire_var_sheet_set_may_create_vars (obj,
874 g_value_get_boolean (value));
877 case PROP_MAY_DELETE_VARS:
878 psppire_var_sheet_set_may_delete_vars (obj,
879 g_value_get_boolean (value));
882 case PROP_FORMAT_TYPE:
883 obj->format_use = g_value_get_enum (value);
886 case PROP_UI_MANAGER:
888 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
894 psppire_var_sheet_get_property (GObject *object,
899 PsppireVarSheet *obj = PSPPIRE_VAR_SHEET (object);
903 case PROP_DICTIONARY:
904 g_value_set_object (value,
905 G_OBJECT (psppire_var_sheet_get_dictionary (obj)));
908 case PROP_MAY_CREATE_VARS:
909 g_value_set_boolean (value, obj->may_create_vars);
912 case PROP_MAY_DELETE_VARS:
913 g_value_set_boolean (value, obj->may_delete_vars);
916 case PROP_FORMAT_TYPE:
917 g_value_set_enum (value, obj->format_use);
920 case PROP_UI_MANAGER:
921 g_value_set_object (value, psppire_var_sheet_get_ui_manager (obj));
925 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
931 psppire_var_sheet_dispose (GObject *obj)
933 PsppireVarSheet *var_sheet = PSPPIRE_VAR_SHEET (obj);
936 if (var_sheet->dispose_has_run)
939 var_sheet->dispose_has_run = TRUE;
941 for (i = 0; i < PSPPIRE_VAR_SHEET_N_SIGNALS; i++)
942 if ( var_sheet->dict_signals[i])
943 g_signal_handler_disconnect (var_sheet->dict,
944 var_sheet->dict_signals[i]);
947 g_object_unref (var_sheet->dict);
950 g_object_unref (var_sheet->uim);
952 /* These dialogs are not GObjects (although they should be!)
953 But for now, unreffing them only causes a GCritical Error
954 so comment them out for now. (and accept the memory leakage)
956 g_object_unref (var_sheet->val_labs_dialog);
957 g_object_unref (var_sheet->missing_val_dialog);
958 g_object_unref (var_sheet->var_type_dialog);
961 G_OBJECT_CLASS (psppire_var_sheet_parent_class)->dispose (obj);
965 psppire_var_sheet_class_init (PsppireVarSheetClass *class)
967 GObjectClass *gobject_class = G_OBJECT_CLASS (class);
970 gobject_class->set_property = psppire_var_sheet_set_property;
971 gobject_class->get_property = psppire_var_sheet_get_property;
972 gobject_class->dispose = psppire_var_sheet_dispose;
974 g_signal_new ("var-double-clicked",
975 G_OBJECT_CLASS_TYPE (gobject_class),
978 g_signal_accumulator_true_handled, NULL,
979 psppire_marshal_BOOLEAN__INT,
980 G_TYPE_BOOLEAN, 1, G_TYPE_INT);
982 pspec = g_param_spec_object ("dictionary",
983 "Dictionary displayed by the sheet",
984 "The PsppireDict that the sheet displays "
985 "may allow the user to edit",
988 g_object_class_install_property (gobject_class, PROP_DICTIONARY, pspec);
990 pspec = g_param_spec_boolean ("may-create-vars",
991 "May create variables",
992 "Whether the user may create more variables",
995 g_object_class_install_property (gobject_class, PROP_MAY_CREATE_VARS, pspec);
997 pspec = g_param_spec_boolean ("may-delete-vars",
998 "May delete variables",
999 "Whether the user may delete variables",
1002 g_object_class_install_property (gobject_class, PROP_MAY_DELETE_VARS, pspec);
1004 pspec = g_param_spec_enum ("format-use",
1005 "Use of variable format",
1006 ("Whether variables have input or output "
1008 PSPPIRE_TYPE_FMT_USE,
1011 g_object_class_install_property (gobject_class, PROP_FORMAT_TYPE, pspec);
1013 pspec = g_param_spec_object ("ui-manager",
1015 "UI manager for the variable sheet. The client should merge this UI manager with the active UI manager to obtain variable sheet specific menu items and tool bar items.",
1016 GTK_TYPE_UI_MANAGER,
1018 g_object_class_install_property (gobject_class, PROP_UI_MANAGER, pspec);
1022 render_row_number_cell (PsppSheetViewColumn *tree_column,
1023 GtkCellRenderer *cell,
1024 GtkTreeModel *model,
1028 PsppireVarSheet *var_sheet = user_data;
1029 GValue gvalue = { 0, };
1032 row = GPOINTER_TO_INT (iter->user_data);
1034 g_value_init (&gvalue, G_TYPE_INT);
1035 g_value_set_int (&gvalue, row + 1);
1036 g_object_set_property (G_OBJECT (cell), "label", &gvalue);
1037 g_value_unset (&gvalue);
1039 if (!var_sheet->dict || row < psppire_dict_get_var_cnt (var_sheet->dict))
1040 g_object_set (cell, "editable", TRUE, NULL);
1042 g_object_set (cell, "editable", FALSE, NULL);
1046 psppire_var_sheet_row_number_double_clicked (PsppireCellRendererButton *button,
1048 PsppireVarSheet *var_sheet)
1052 g_return_if_fail (var_sheet->dict != NULL);
1054 path = gtk_tree_path_new_from_string (path_string);
1055 if (gtk_tree_path_get_depth (path) == 1)
1057 gint *indices = gtk_tree_path_get_indices (path);
1058 if (indices[0] < psppire_dict_get_var_cnt (var_sheet->dict))
1061 g_signal_emit_by_name (var_sheet, "var-double-clicked",
1062 indices[0], &handled);
1065 gtk_tree_path_free (path);
1069 psppire_var_sheet_variables_column_clicked (PsppSheetViewColumn *column,
1070 PsppireVarSheet *var_sheet)
1072 PsppSheetView *sheet_view = PSPP_SHEET_VIEW (var_sheet);
1073 PsppSheetSelection *selection = pspp_sheet_view_get_selection (sheet_view);
1075 pspp_sheet_selection_select_all (selection);
1078 static PsppSheetViewColumn *
1079 make_row_number_column (PsppireVarSheet *var_sheet)
1081 PsppSheetViewColumn *column;
1082 GtkCellRenderer *renderer;
1084 renderer = psppire_cell_renderer_button_new ();
1085 g_object_set (renderer, "xalign", 1.0, NULL);
1086 g_signal_connect (renderer, "double-clicked",
1087 G_CALLBACK (psppire_var_sheet_row_number_double_clicked),
1090 column = pspp_sheet_view_column_new_with_attributes (_("Variable"),
1092 pspp_sheet_view_column_set_clickable (column, TRUE);
1093 pspp_sheet_view_column_set_cell_data_func (
1094 column, renderer, render_row_number_cell, var_sheet, NULL);
1095 pspp_sheet_view_column_set_fixed_width (column, 50);
1096 g_signal_connect (column, "clicked",
1097 G_CALLBACK (psppire_var_sheet_variables_column_clicked),
1104 on_edit_clear_variables (GtkAction *action, PsppireVarSheet *var_sheet)
1106 PsppSheetView *sheet_view = PSPP_SHEET_VIEW (var_sheet);
1107 PsppSheetSelection *selection = pspp_sheet_view_get_selection (sheet_view);
1108 PsppireDict *dict = var_sheet->dict;
1109 const struct range_set_node *node;
1110 struct range_set *selected;
1112 selected = pspp_sheet_selection_get_range_set (selection);
1113 for (node = range_set_last (selected); node != NULL;
1114 node = range_set_prev (selected, node))
1118 for (i = 1; i <= range_set_node_get_width (node); i++)
1120 unsigned long row = range_set_node_get_end (node) - i;
1121 if (row >= 0 && row < psppire_dict_get_var_cnt (dict))
1122 psppire_dict_delete_variables (dict, row, 1);
1125 range_set_destroy (selected);
1129 on_selection_changed (PsppSheetSelection *selection,
1130 gpointer user_data UNUSED)
1132 PsppSheetView *sheet_view = pspp_sheet_selection_get_tree_view (selection);
1133 PsppireVarSheet *var_sheet = PSPPIRE_VAR_SHEET (sheet_view);
1134 gint n_selected_rows;
1135 gboolean may_delete;
1139 n_selected_rows = pspp_sheet_selection_count_selected_rows (selection);
1141 action = get_action_assert (var_sheet->builder, "edit_insert-variable");
1142 gtk_action_set_sensitive (action, (var_sheet->may_create_vars
1143 && n_selected_rows > 0));
1145 switch (n_selected_rows)
1152 /* The row used for inserting new variables cannot be deleted. */
1153 path = gtk_tree_path_new_from_indices (
1154 psppire_dict_get_var_cnt (var_sheet->dict), -1);
1155 may_delete = !pspp_sheet_selection_path_is_selected (selection, path);
1156 gtk_tree_path_free (path);
1163 action = get_action_assert (var_sheet->builder, "edit_clear-variables");
1164 gtk_action_set_sensitive (action, var_sheet->may_delete_vars && may_delete);
1168 on_edit_insert_variable (GtkAction *action, PsppireVarSheet *var_sheet)
1170 PsppSheetView *sheet_view = PSPP_SHEET_VIEW (var_sheet);
1171 PsppSheetSelection *selection = pspp_sheet_view_get_selection (sheet_view);
1172 PsppireDict *dict = var_sheet->dict;
1173 struct range_set *selected;
1176 selected = pspp_sheet_selection_get_range_set (selection);
1177 row = range_set_scan (selected, 0);
1178 range_set_destroy (selected);
1180 if (row <= psppire_dict_get_var_cnt (dict))
1183 if (psppire_dict_generate_name (dict, name, sizeof name))
1184 psppire_dict_insert_variable (dict, row, name);
1189 psppire_var_sheet_init (PsppireVarSheet *obj)
1191 PsppSheetView *sheet_view = PSPP_SHEET_VIEW (obj);
1192 PsppSheetViewColumn *column;
1193 GtkCellRenderer *cell;
1198 obj->format_use = FMT_FOR_OUTPUT;
1199 obj->may_create_vars = TRUE;
1200 obj->may_delete_vars = TRUE;
1202 obj->scroll_to_bottom_signal = 0;
1204 obj->container = NULL;
1205 obj->dispose_has_run = FALSE;
1208 pspp_sheet_view_append_column (sheet_view, make_row_number_column (obj));
1210 column = add_text_column (obj, VS_NAME, _("Name"), 12);
1211 list = gtk_cell_layout_get_cells (GTK_CELL_LAYOUT (column));
1212 g_signal_connect (list->data, "editing-started",
1213 G_CALLBACK (on_name_column_editing_started), NULL);
1216 column = add_text_column (obj, VS_TYPE, _("Type"), 8);
1217 add_popup_menu (obj, column, on_type_click);
1219 add_spin_column (obj, VS_WIDTH, _("Width"), 5);
1221 add_spin_column (obj, VS_DECIMALS, _("Decimals"), 2);
1223 add_text_column (obj, VS_LABEL, _("Label"), 20);
1225 column = add_text_column (obj, VS_VALUES, _("Value Labels"), 20);
1226 add_popup_menu (obj, column, on_value_labels_click);
1228 column = add_text_column (obj, VS_MISSING, _("Missing Values"), 20);
1229 add_popup_menu (obj, column, on_missing_values_click);
1231 add_spin_column (obj, VS_COLUMNS, _("Columns"), 3);
1233 add_combo_column (obj, VS_ALIGN, _("Align"), 6,
1234 alignment_to_string (ALIGN_LEFT), ALIGN_LEFT,
1235 alignment_to_string (ALIGN_CENTRE), ALIGN_CENTRE,
1236 alignment_to_string (ALIGN_RIGHT), ALIGN_RIGHT,
1240 = add_combo_column (obj, VS_MEASURE, _("Measure"), 12,
1241 measure_to_string (MEASURE_NOMINAL), MEASURE_NOMINAL,
1242 measure_to_string (MEASURE_ORDINAL), MEASURE_ORDINAL,
1243 measure_to_string (MEASURE_SCALE), MEASURE_SCALE,
1245 cell = gtk_cell_renderer_pixbuf_new ();
1246 pspp_sheet_view_column_pack_end (column, cell, FALSE);
1247 pspp_sheet_view_column_set_cell_data_func (
1248 column, cell, render_var_cell, obj, NULL);
1250 pspp_sheet_view_set_rubber_banding (sheet_view, TRUE);
1251 pspp_sheet_selection_set_mode (pspp_sheet_view_get_selection (sheet_view),
1252 PSPP_SHEET_SELECTION_MULTIPLE);
1254 g_object_set (G_OBJECT (obj), "has-tooltip", TRUE, NULL);
1255 g_signal_connect (obj, "query-tooltip",
1256 G_CALLBACK (on_query_var_tooltip), NULL);
1257 g_signal_connect (obj, "button-press-event",
1258 G_CALLBACK (on_button_pressed), NULL);
1259 g_signal_connect (obj, "popup-menu", G_CALLBACK (on_popup_menu), NULL);
1261 obj->builder = builder_new ("var-sheet.ui");
1263 action = get_action_assert (obj->builder, "edit_clear-variables");
1264 g_signal_connect (action, "activate", G_CALLBACK (on_edit_clear_variables),
1266 gtk_action_set_sensitive (action, FALSE);
1267 g_signal_connect (pspp_sheet_view_get_selection (sheet_view),
1268 "changed", G_CALLBACK (on_selection_changed), NULL);
1270 action = get_action_assert (obj->builder, "edit_insert-variable");
1271 gtk_action_set_sensitive (action, FALSE);
1272 g_signal_connect (action, "activate", G_CALLBACK (on_edit_insert_variable),
1277 psppire_var_sheet_new (void)
1279 return g_object_new (PSPPIRE_VAR_SHEET_TYPE, NULL);
1283 psppire_var_sheet_get_dictionary (PsppireVarSheet *var_sheet)
1285 return var_sheet->dict;
1289 refresh_model (PsppireVarSheet *var_sheet)
1291 pspp_sheet_view_set_model (PSPP_SHEET_VIEW (var_sheet), NULL);
1293 if (var_sheet->dict != NULL)
1295 PsppireEmptyListStore *store;
1298 n_rows = (psppire_dict_get_var_cnt (var_sheet->dict)
1299 + var_sheet->may_create_vars);
1300 store = psppire_empty_list_store_new (n_rows);
1301 pspp_sheet_view_set_model (PSPP_SHEET_VIEW (var_sheet),
1302 GTK_TREE_MODEL (store));
1303 g_object_unref (store);
1308 on_var_changed (PsppireDict *dict, glong row,
1309 guint what, const struct variable *oldvar,
1310 PsppireVarSheet *var_sheet)
1312 PsppireEmptyListStore *store;
1314 g_return_if_fail (dict == var_sheet->dict);
1316 store = PSPPIRE_EMPTY_LIST_STORE (pspp_sheet_view_get_model (
1317 PSPP_SHEET_VIEW (var_sheet)));
1318 g_return_if_fail (store != NULL);
1320 psppire_empty_list_store_row_changed (store, row);
1324 on_var_inserted (PsppireDict *dict, glong row, PsppireVarSheet *var_sheet)
1326 PsppireEmptyListStore *store;
1329 g_return_if_fail (dict == var_sheet->dict);
1331 store = PSPPIRE_EMPTY_LIST_STORE (pspp_sheet_view_get_model (
1332 PSPP_SHEET_VIEW (var_sheet)));
1333 g_return_if_fail (store != NULL);
1335 n_rows = (psppire_dict_get_var_cnt (var_sheet->dict)
1336 + var_sheet->may_create_vars);
1337 psppire_empty_list_store_set_n_rows (store, n_rows);
1338 psppire_empty_list_store_row_inserted (store, row);
1342 on_var_deleted (PsppireDict *dict,
1343 const struct variable *var, int dict_idx, int case_idx,
1344 PsppireVarSheet *var_sheet)
1346 PsppireEmptyListStore *store;
1349 g_return_if_fail (dict == var_sheet->dict);
1351 store = PSPPIRE_EMPTY_LIST_STORE (pspp_sheet_view_get_model (
1352 PSPP_SHEET_VIEW (var_sheet)));
1353 g_return_if_fail (store != NULL);
1355 n_rows = (psppire_dict_get_var_cnt (var_sheet->dict)
1356 + var_sheet->may_create_vars);
1357 psppire_empty_list_store_set_n_rows (store, n_rows);
1358 psppire_empty_list_store_row_deleted (store, dict_idx);
1362 on_backend_changed (PsppireDict *dict, PsppireVarSheet *var_sheet)
1364 g_return_if_fail (dict == var_sheet->dict);
1365 refresh_model (var_sheet);
1369 psppire_var_sheet_set_dictionary (PsppireVarSheet *var_sheet,
1372 if (var_sheet->dict != NULL)
1376 for (i = 0; i < PSPPIRE_VAR_SHEET_N_SIGNALS; i++)
1378 if (var_sheet->dict_signals[i])
1379 g_signal_handler_disconnect (var_sheet->dict,
1380 var_sheet->dict_signals[i]);
1382 var_sheet->dict_signals[i] = 0;
1385 g_object_unref (var_sheet->dict);
1388 var_sheet->dict = dict;
1392 g_object_ref (dict);
1394 var_sheet->dict_signals[PSPPIRE_VAR_SHEET_BACKEND_CHANGED]
1395 = g_signal_connect (dict, "backend-changed",
1396 G_CALLBACK (on_backend_changed), var_sheet);
1398 var_sheet->dict_signals[PSPPIRE_VAR_SHEET_VARIABLE_CHANGED]
1399 = g_signal_connect (dict, "variable-changed",
1400 G_CALLBACK (on_var_changed), var_sheet);
1402 var_sheet->dict_signals[PSPPIRE_VAR_SHEET_VARIABLE_DELETED]
1403 = g_signal_connect (dict, "variable-inserted",
1404 G_CALLBACK (on_var_inserted), var_sheet);
1406 var_sheet->dict_signals[PSPPIRE_VAR_SHEET_VARIABLE_INSERTED]
1407 = g_signal_connect (dict, "variable-deleted",
1408 G_CALLBACK (on_var_deleted), var_sheet);
1411 refresh_model (var_sheet);
1415 psppire_var_sheet_get_may_create_vars (PsppireVarSheet *var_sheet)
1417 return var_sheet->may_create_vars;
1421 psppire_var_sheet_set_may_create_vars (PsppireVarSheet *var_sheet,
1422 gboolean may_create_vars)
1424 if (var_sheet->may_create_vars != may_create_vars)
1426 PsppireEmptyListStore *store;
1429 var_sheet->may_create_vars = may_create_vars;
1431 store = PSPPIRE_EMPTY_LIST_STORE (pspp_sheet_view_get_model (
1432 PSPP_SHEET_VIEW (var_sheet)));
1433 g_return_if_fail (store != NULL);
1435 n_rows = (psppire_dict_get_var_cnt (var_sheet->dict)
1436 + var_sheet->may_create_vars);
1437 psppire_empty_list_store_set_n_rows (store, n_rows);
1439 if (may_create_vars)
1440 psppire_empty_list_store_row_inserted (store, n_rows - 1);
1442 psppire_empty_list_store_row_deleted (store, n_rows);
1444 on_selection_changed (pspp_sheet_view_get_selection (
1445 PSPP_SHEET_VIEW (var_sheet)), NULL);
1450 psppire_var_sheet_get_may_delete_vars (PsppireVarSheet *var_sheet)
1452 return var_sheet->may_delete_vars;
1456 psppire_var_sheet_set_may_delete_vars (PsppireVarSheet *var_sheet,
1457 gboolean may_delete_vars)
1459 if (var_sheet->may_delete_vars != may_delete_vars)
1461 var_sheet->may_delete_vars = may_delete_vars;
1462 on_selection_changed (pspp_sheet_view_get_selection (
1463 PSPP_SHEET_VIEW (var_sheet)), NULL);
1468 psppire_var_sheet_goto_variable (PsppireVarSheet *var_sheet, int dict_index)
1470 PsppSheetView *sheet_view = PSPP_SHEET_VIEW (var_sheet);
1473 path = gtk_tree_path_new_from_indices (dict_index, -1);
1474 pspp_sheet_view_scroll_to_cell (sheet_view, path, NULL, FALSE, 0.0, 0.0);
1475 pspp_sheet_view_set_cursor (sheet_view, path, NULL, FALSE);
1476 gtk_tree_path_free (path);
1480 psppire_var_sheet_get_ui_manager (PsppireVarSheet *var_sheet)
1482 if (var_sheet->uim == NULL)
1484 var_sheet->uim = GTK_UI_MANAGER (get_object_assert (var_sheet->builder,
1486 GTK_TYPE_UI_MANAGER));
1487 g_object_ref (var_sheet->uim);
1490 return var_sheet->uim;