1 /* PSPPIRE - a graphical user interface for PSPP.
2 Copyright (C) 2008, 2009, 2010, 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/>. */
19 #include "ui/gui/psppire-data-editor.h"
22 #include <gtk-contrib/gtkxpaned.h>
24 #include "data/datasheet.h"
25 #include "data/value-labels.h"
26 #include "libpspp/range-set.h"
27 #include "ui/gui/helper.h"
28 #include "ui/gui/pspp-sheet-selection.h"
29 #include "ui/gui/psppire-data-sheet.h"
30 #include "ui/gui/psppire-data-store.h"
31 #include "ui/gui/psppire-value-entry.h"
32 #include "ui/gui/psppire-var-sheet.h"
33 #include "ui/gui/psppire.h"
36 #define _(msgid) gettext (msgid)
38 #define FOR_EACH_DATA_SHEET(DATA_SHEET, IDX, DATA_EDITOR) \
41 && ((DATA_SHEET) = PSPPIRE_DATA_SHEET ( \
42 (DATA_EDITOR)->data_sheets[IDX])) != NULL; \
45 static void psppire_data_editor_class_init (PsppireDataEditorClass *klass);
46 static void psppire_data_editor_init (PsppireDataEditor *de);
48 static void disconnect_data_sheets (PsppireDataEditor *);
49 static void refresh_entry (PsppireDataEditor *);
50 static void psppire_data_editor_update_ui_manager (PsppireDataEditor *);
53 psppire_data_editor_get_type (void)
55 static GType de_type = 0;
59 static const GTypeInfo de_info =
61 sizeof (PsppireDataEditorClass),
63 NULL, /* base_finalize */
64 (GClassInitFunc) psppire_data_editor_class_init,
65 NULL, /* class_finalize */
66 NULL, /* class_data */
67 sizeof (PsppireDataEditor),
69 (GInstanceInitFunc) psppire_data_editor_init,
72 de_type = g_type_register_static (GTK_TYPE_NOTEBOOK, "PsppireDataEditor",
79 static GObjectClass * parent_class = NULL;
82 psppire_data_editor_dispose (GObject *obj)
84 PsppireDataEditor *de = (PsppireDataEditor *) obj;
86 disconnect_data_sheets (de);
90 g_object_unref (de->data_store);
91 de->data_store = NULL;
96 g_object_unref (de->dict);
100 if (de->font != NULL)
102 pango_font_description_free (de->font);
108 g_object_unref (de->ui_manager);
109 de->ui_manager = NULL;
112 /* Chain up to the parent class */
113 G_OBJECT_CLASS (parent_class)->dispose (obj);
127 psppire_data_editor_refresh_model (PsppireDataEditor *de)
129 PsppireVarSheet *var_sheet = PSPPIRE_VAR_SHEET (de->var_sheet);
130 PsppireDataSheet *data_sheet;
133 FOR_EACH_DATA_SHEET (data_sheet, i, de)
134 psppire_data_sheet_set_data_store (data_sheet, de->data_store);
135 psppire_var_sheet_set_dictionary (var_sheet, de->dict);
139 psppire_data_editor_set_property (GObject *object,
144 PsppireDataEditor *de = PSPPIRE_DATA_EDITOR (object);
145 PsppireDataSheet *data_sheet;
150 case PROP_SPLIT_WINDOW:
151 psppire_data_editor_split_window (de, g_value_get_boolean (value));
153 case PROP_DATA_STORE:
156 g_signal_handlers_disconnect_by_func (de->data_store,
157 G_CALLBACK (refresh_entry),
159 g_object_unref (de->data_store);
162 de->data_store = g_value_get_pointer (value);
163 g_object_ref (de->data_store);
164 psppire_data_editor_refresh_model (de);
166 g_signal_connect_swapped (de->data_store, "case-changed",
167 G_CALLBACK (refresh_entry), de);
170 case PROP_DICTIONARY:
172 g_object_unref (de->dict);
173 de->dict = g_value_get_pointer (value);
174 g_object_ref (de->dict);
176 psppire_var_sheet_set_dictionary (PSPPIRE_VAR_SHEET (de->var_sheet),
179 case PROP_VALUE_LABELS:
180 FOR_EACH_DATA_SHEET (data_sheet, i, de)
181 psppire_data_sheet_set_value_labels (data_sheet,
182 g_value_get_boolean (value));
184 case PROP_UI_MANAGER:
186 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
192 psppire_data_editor_get_property (GObject *object,
197 PsppireDataEditor *de = PSPPIRE_DATA_EDITOR (object);
201 case PROP_SPLIT_WINDOW:
202 g_value_set_boolean (value, de->split);
204 case PROP_DATA_STORE:
205 g_value_set_pointer (value, de->data_store);
207 case PROP_DICTIONARY:
208 g_value_set_pointer (value, de->dict);
210 case PROP_VALUE_LABELS:
211 g_value_set_boolean (value,
212 psppire_data_sheet_get_value_labels (
213 PSPPIRE_DATA_SHEET (de->data_sheets[0])));
215 case PROP_UI_MANAGER:
216 g_value_set_object (value, psppire_data_editor_get_ui_manager (de));
219 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
225 psppire_data_editor_switch_page (GtkNotebook *notebook,
226 GtkNotebookPage *page,
229 GTK_NOTEBOOK_CLASS (parent_class)->switch_page (notebook, page, page_num);
230 psppire_data_editor_update_ui_manager (PSPPIRE_DATA_EDITOR (notebook));
234 psppire_data_editor_set_focus_child (GtkContainer *container,
237 GTK_CONTAINER_CLASS (parent_class)->set_focus_child (container, widget);
238 psppire_data_editor_update_ui_manager (PSPPIRE_DATA_EDITOR (container));
242 psppire_data_editor_class_init (PsppireDataEditorClass *klass)
244 GParamSpec *data_store_spec ;
245 GParamSpec *dict_spec ;
246 GParamSpec *value_labels_spec;
247 GParamSpec *split_window_spec;
248 GParamSpec *ui_manager_spec;
249 GObjectClass *object_class = G_OBJECT_CLASS (klass);
250 GtkContainerClass *container_class = GTK_CONTAINER_CLASS (klass);
251 GtkNotebookClass *notebook_class = GTK_NOTEBOOK_CLASS (klass);
253 parent_class = g_type_class_peek_parent (klass);
255 object_class->dispose = psppire_data_editor_dispose;
256 object_class->set_property = psppire_data_editor_set_property;
257 object_class->get_property = psppire_data_editor_get_property;
259 container_class->set_focus_child = psppire_data_editor_set_focus_child;
261 notebook_class->switch_page = psppire_data_editor_switch_page;
264 g_param_spec_pointer ("data-store",
266 "A pointer to the data store associated with this editor",
267 G_PARAM_CONSTRUCT_ONLY | G_PARAM_WRITABLE | G_PARAM_READABLE );
269 g_object_class_install_property (object_class,
274 g_param_spec_pointer ("dictionary",
276 "A pointer to the dictionary associated with this editor",
277 G_PARAM_CONSTRUCT_ONLY | G_PARAM_WRITABLE | G_PARAM_READABLE );
279 g_object_class_install_property (object_class,
284 g_param_spec_boolean ("value-labels",
286 "Whether or not the data sheet should display labels instead of values",
288 G_PARAM_WRITABLE | G_PARAM_READABLE);
290 g_object_class_install_property (object_class,
296 g_param_spec_boolean ("split",
298 "True iff the data sheet is split",
300 G_PARAM_READABLE | G_PARAM_WRITABLE);
302 g_object_class_install_property (object_class,
307 g_param_spec_object ("ui-manager",
309 "UI manager for the active notebook tab. The client should merge this UI manager with the active UI manager to obtain menu items and tool bar items specific to the active notebook tab.",
312 g_object_class_install_property (object_class,
318 on_data_sheet_var_double_clicked (PsppireDataSheet *data_sheet,
320 PsppireDataEditor *de)
322 gtk_notebook_set_current_page (GTK_NOTEBOOK (de),
323 PSPPIRE_DATA_EDITOR_VARIABLE_VIEW);
325 psppire_var_sheet_goto_variable (PSPPIRE_VAR_SHEET (de->var_sheet),
332 on_var_sheet_var_double_clicked (PsppireVarSheet *var_sheet, gint dict_index,
333 PsppireDataEditor *de)
335 PsppireDataSheet *data_sheet;
337 gtk_notebook_set_current_page (GTK_NOTEBOOK (de),
338 PSPPIRE_DATA_EDITOR_DATA_VIEW);
340 data_sheet = psppire_data_editor_get_active_data_sheet (de);
341 psppire_data_sheet_show_variable (data_sheet, dict_index);
346 /* Refreshes 'de->cell_ref_label' and 'de->datum_entry' from the currently
347 active cell or cells. */
349 refresh_entry (PsppireDataEditor *de)
351 PsppireDataSheet *data_sheet = psppire_data_editor_get_active_data_sheet (de);
352 PsppSheetView *sheet_view = PSPP_SHEET_VIEW (data_sheet);
353 PsppSheetSelection *selection = pspp_sheet_view_get_selection (sheet_view);
355 gchar *ref_cell_text;
356 GList *selected_columns, *iter;
357 struct variable *var;
361 selected_columns = pspp_sheet_selection_get_selected_columns (selection);
364 for (iter = selected_columns; iter != NULL; iter = iter->next)
366 PsppSheetViewColumn *column = iter->data;
367 struct variable *v = g_object_get_data (G_OBJECT (column), "variable");
374 g_list_free (selected_columns);
376 n_cases = pspp_sheet_selection_count_selected_rows (selection);
379 /* The final row is selectable but it isn't a case (it's just used to add
380 more cases), so don't count it. */
384 case_count = psppire_data_store_get_case_count (de->data_store);
385 path = gtk_tree_path_new_from_indices (case_count, -1);
386 if (pspp_sheet_selection_path_is_selected (selection, path))
388 gtk_tree_path_free (path);
391 ref_cell_text = NULL;
392 if (n_cases == 1 && n_vars == 1)
394 PsppireValueEntry *value_entry = PSPPIRE_VALUE_ENTRY (de->datum_entry);
395 struct range_set *selected_rows;
396 gboolean show_value_labels;
401 selected_rows = pspp_sheet_selection_get_range_set (selection);
402 row = range_set_scan (selected_rows, 0);
403 range_set_destroy (selected_rows);
405 ref_cell_text = g_strdup_printf ("%d : %s", row + 1, var_get_name (var));
407 show_value_labels = psppire_data_sheet_get_value_labels (data_sheet);
409 psppire_value_entry_set_variable (value_entry, var);
410 psppire_value_entry_set_show_value_label (value_entry,
413 width = var_get_width (var);
414 value_init (&value, width);
415 datasheet_get_value (de->data_store->datasheet,
416 row, var_get_case_index (var), &value);
417 psppire_value_entry_set_value (value_entry, &value, width);
418 value_destroy (&value, width);
420 gtk_widget_set_sensitive (de->datum_entry, TRUE);
424 if (n_cases == 0 || n_vars == 0)
426 ref_cell_text = NULL;
432 string = g_string_sized_new (25);
433 g_string_append_printf (string,
434 ngettext ("%'d case", "%'d cases", n_cases),
436 g_string_append_c (string, ' ');
437 g_string_append_unichar (string, 0xd7); /* U+00D7 MULTIPLICATION SIGN */
438 g_string_append_c (string, ' ');
439 g_string_append_printf (string,
440 ngettext ("%'d variable", "%'d variables",
443 ref_cell_text = string->str;
444 g_string_free (string, FALSE);
447 psppire_value_entry_set_variable (PSPPIRE_VALUE_ENTRY (de->datum_entry),
450 GTK_ENTRY (gtk_bin_get_child (GTK_BIN (de->datum_entry))), "");
451 gtk_widget_set_sensitive (de->datum_entry, FALSE);
454 gtk_label_set_label (GTK_LABEL (de->cell_ref_label),
455 ref_cell_text ? ref_cell_text : "");
456 g_free (ref_cell_text);
460 on_datum_entry_activate (PsppireValueEntry *entry, PsppireDataEditor *de)
462 PsppireDataSheet *data_sheet = psppire_data_editor_get_active_data_sheet (de);
463 struct variable *var;
468 row = psppire_data_sheet_get_current_case (data_sheet);
469 var = psppire_data_sheet_get_current_variable (data_sheet);
473 width = var_get_width (var);
474 value_init (&value, width);
475 if (psppire_value_entry_get_value (PSPPIRE_VALUE_ENTRY (de->datum_entry),
477 psppire_data_store_set_value (de->data_store, row, var, &value);
478 value_destroy (&value, width);
482 on_data_sheet_selection_changed (PsppSheetSelection *selection,
483 PsppireDataEditor *de)
485 /* In a split view, ensure that only a single data sheet has a nonempty
488 && pspp_sheet_selection_count_selected_rows (selection)
489 && pspp_sheet_selection_count_selected_columns (selection))
491 PsppireDataSheet *ds;
494 FOR_EACH_DATA_SHEET (ds, i, de)
496 PsppSheetSelection *s;
498 s = pspp_sheet_view_get_selection (PSPP_SHEET_VIEW (ds));
500 pspp_sheet_selection_unselect_all (s);
507 /* Ensures that rows in the right-hand panes in the split view have the same
508 row height as the left-hand panes. Otherwise, the rows in the right-hand
509 pane tend to be smaller, because the right-hand pane doesn't have buttons
512 on_data_sheet_fixed_height_notify (PsppireDataSheet *ds,
514 PsppireDataEditor *de)
518 TL = GTK_XPANED_TOP_LEFT,
519 TR = GTK_XPANED_TOP_RIGHT,
520 BL = GTK_XPANED_BOTTOM_LEFT,
521 BR = GTK_XPANED_BOTTOM_RIGHT
524 int fixed_height = pspp_sheet_view_get_fixed_height (PSPP_SHEET_VIEW (ds));
526 pspp_sheet_view_set_fixed_height (PSPP_SHEET_VIEW (de->data_sheets[TR]),
528 pspp_sheet_view_set_fixed_height (PSPP_SHEET_VIEW (de->data_sheets[BR]),
533 disconnect_data_sheets (PsppireDataEditor *de)
535 PsppireDataSheet *ds;
538 FOR_EACH_DATA_SHEET (ds, i, de)
540 PsppSheetSelection *selection;
544 /* This can only happen if 'dispose' runs more than once. */
548 if (i == GTK_XPANED_TOP_LEFT)
549 g_signal_handlers_disconnect_by_func (
550 ds, G_CALLBACK (on_data_sheet_fixed_height_notify), de);
552 g_signal_handlers_disconnect_by_func (
553 ds, G_CALLBACK (refresh_entry), de);
554 g_signal_handlers_disconnect_by_func (
555 ds, G_CALLBACK (on_data_sheet_var_double_clicked), de);
557 selection = pspp_sheet_view_get_selection (PSPP_SHEET_VIEW (ds));
558 g_signal_handlers_disconnect_by_func (
559 selection, G_CALLBACK (on_data_sheet_selection_changed), de);
561 de->data_sheets[i] = NULL;
566 make_data_sheet (PsppireDataEditor *de, GtkTreeViewGridLines grid_lines)
568 PsppSheetSelection *selection;
571 ds = psppire_data_sheet_new ();
572 pspp_sheet_view_set_grid_lines (PSPP_SHEET_VIEW (ds), grid_lines);
574 g_signal_connect_swapped (ds, "notify::value-labels",
575 G_CALLBACK (refresh_entry), de);
576 g_signal_connect (ds, "var-double-clicked",
577 G_CALLBACK (on_data_sheet_var_double_clicked), de);
579 selection = pspp_sheet_view_get_selection (PSPP_SHEET_VIEW (ds));
580 g_signal_connect (selection, "changed",
581 G_CALLBACK (on_data_sheet_selection_changed), de);
587 make_single_datasheet (PsppireDataEditor *de, GtkTreeViewGridLines grid_lines)
589 GtkWidget *data_sheet_scroller;
591 de->data_sheets[0] = make_data_sheet (de, grid_lines);
592 de->data_sheets[1] = de->data_sheets[2] = de->data_sheets[3] = NULL;
594 /* Put data sheet in scroller. */
595 data_sheet_scroller = gtk_scrolled_window_new (NULL, NULL);
596 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (data_sheet_scroller),
597 GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
598 gtk_container_add (GTK_CONTAINER (data_sheet_scroller), de->data_sheets[0]);
600 return data_sheet_scroller;
604 make_split_datasheet (PsppireDataEditor *de, GtkTreeViewGridLines grid_lines)
606 /* Panes, in the order in which we want to create them. */
611 BL, /* bottom left */
612 BR /* bottom right */
615 PsppSheetView *ds[4];
619 xpaned = GTK_XPANED (gtk_xpaned_new ());
621 for (i = 0; i < 4; i++)
623 GtkAdjustment *hadjust, *vadjust;
624 GtkPolicyType hpolicy, vpolicy;
627 de->data_sheets[i] = make_data_sheet (de, grid_lines);
628 ds[i] = PSPP_SHEET_VIEW (de->data_sheets[i]);
631 hadjust = pspp_sheet_view_get_hadjustment (ds[TL]);
633 hadjust = pspp_sheet_view_get_hadjustment (ds[TR]);
638 vadjust = pspp_sheet_view_get_vadjustment (ds[TL]);
640 vadjust = pspp_sheet_view_get_vadjustment (ds[BL]);
644 scroller = gtk_scrolled_window_new (hadjust, vadjust);
645 gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (scroller),
646 GTK_SHADOW_ETCHED_IN);
647 hpolicy = i == TL || i == TR ? GTK_POLICY_NEVER : GTK_POLICY_ALWAYS;
648 vpolicy = i == TL || i == BL ? GTK_POLICY_NEVER : GTK_POLICY_ALWAYS;
649 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scroller),
651 gtk_container_add (GTK_CONTAINER (scroller), GTK_WIDGET (ds[i]));
656 gtk_xpaned_pack_top_left (xpaned, scroller, TRUE, TRUE);
660 gtk_xpaned_pack_top_right (xpaned, scroller, TRUE, TRUE);
664 gtk_xpaned_pack_bottom_left (xpaned, scroller, TRUE, TRUE);
668 gtk_xpaned_pack_bottom_right (xpaned, scroller, TRUE, TRUE);
672 g_warn_if_reached ();
676 /* Bottom sheets don't display variable names. */
677 pspp_sheet_view_set_headers_visible (ds[BL], FALSE);
678 pspp_sheet_view_set_headers_visible (ds[BR], FALSE);
680 /* Right sheets don't display case numbers. */
681 psppire_data_sheet_set_case_numbers (PSPPIRE_DATA_SHEET (ds[TR]), FALSE);
682 psppire_data_sheet_set_case_numbers (PSPPIRE_DATA_SHEET (ds[BR]), FALSE);
684 g_signal_connect (ds[TL], "notify::fixed-height",
685 G_CALLBACK (on_data_sheet_fixed_height_notify), de);
687 return GTK_WIDGET (xpaned);
691 psppire_data_editor_init (PsppireDataEditor *de)
693 GtkWidget *var_sheet_scroller;
697 de->ui_manager = NULL;
699 g_object_set (de, "tab-pos", GTK_POS_BOTTOM, NULL);
701 de->cell_ref_label = gtk_label_new ("");
702 gtk_label_set_width_chars (GTK_LABEL (de->cell_ref_label), 25);
703 gtk_misc_set_alignment (GTK_MISC (de->cell_ref_label), 0.0, 0.5);
705 de->datum_entry = psppire_value_entry_new ();
706 g_signal_connect (GTK_ENTRY (gtk_bin_get_child (GTK_BIN (de->datum_entry))),
707 "activate", G_CALLBACK (on_datum_entry_activate), de);
709 hbox = gtk_hbox_new (FALSE, 0);
710 gtk_box_pack_start (GTK_BOX (hbox), de->cell_ref_label, FALSE, FALSE, 0);
711 gtk_box_pack_start (GTK_BOX (hbox), de->datum_entry, TRUE, TRUE, 0);
714 de->datasheet_vbox_widget
715 = make_single_datasheet (de, GTK_TREE_VIEW_GRID_LINES_BOTH);
717 de->vbox = gtk_vbox_new (FALSE, 0);
718 gtk_box_pack_start (GTK_BOX (de->vbox), hbox, FALSE, FALSE, 0);
719 gtk_box_pack_start (GTK_BOX (de->vbox), de->datasheet_vbox_widget,
722 gtk_notebook_append_page (GTK_NOTEBOOK (de), de->vbox,
723 gtk_label_new_with_mnemonic (_("Data View")));
725 gtk_widget_show_all (de->vbox);
727 de->var_sheet = GTK_WIDGET (psppire_var_sheet_new ());
728 pspp_sheet_view_set_grid_lines (PSPP_SHEET_VIEW (de->var_sheet),
729 GTK_TREE_VIEW_GRID_LINES_BOTH);
730 var_sheet_scroller = gtk_scrolled_window_new (NULL, NULL);
731 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (var_sheet_scroller),
732 GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
733 gtk_container_add (GTK_CONTAINER (var_sheet_scroller), de->var_sheet);
734 gtk_widget_show_all (var_sheet_scroller);
735 gtk_notebook_append_page (GTK_NOTEBOOK (de), var_sheet_scroller,
736 gtk_label_new_with_mnemonic (_("Variable View")));
738 g_signal_connect (de->var_sheet, "var-double-clicked",
739 G_CALLBACK (on_var_sheet_var_double_clicked), de);
741 g_object_set (de, "can-focus", FALSE, NULL);
743 psppire_data_editor_update_ui_manager (de);
747 psppire_data_editor_new (PsppireDict *dict,
748 PsppireDataStore *data_store)
750 return g_object_new (PSPPIRE_DATA_EDITOR_TYPE,
752 "data-store", data_store,
756 /* Turns the visible grid on or off, according to GRID_VISIBLE, for DE's data
757 sheet(s) and variable sheet. */
759 psppire_data_editor_show_grid (PsppireDataEditor *de, gboolean grid_visible)
761 GtkTreeViewGridLines grid;
762 PsppireDataSheet *data_sheet;
766 ? GTK_TREE_VIEW_GRID_LINES_BOTH
767 : GTK_TREE_VIEW_GRID_LINES_NONE);
769 FOR_EACH_DATA_SHEET (data_sheet, i, de)
770 pspp_sheet_view_set_grid_lines (PSPP_SHEET_VIEW (data_sheet), grid);
771 pspp_sheet_view_set_grid_lines (PSPP_SHEET_VIEW (de->var_sheet), grid);
776 set_font_recursively (GtkWidget *w, gpointer data)
778 PangoFontDescription *font_desc = data;
779 GtkRcStyle *style = gtk_widget_get_modifier_style (w);
781 pango_font_description_free (style->font_desc);
782 style->font_desc = pango_font_description_copy (font_desc);
784 gtk_widget_modify_style (w, style);
786 if ( GTK_IS_CONTAINER (w))
787 gtk_container_foreach (GTK_CONTAINER (w), set_font_recursively, font_desc);
790 /* Sets FONT_DESC as the font used by the data sheet(s) and variable sheet. */
792 psppire_data_editor_set_font (PsppireDataEditor *de, PangoFontDescription *font_desc)
794 set_font_recursively (GTK_WIDGET (de), font_desc);
797 pango_font_description_free (de->font);
798 de->font = pango_font_description_copy (font_desc);
801 /* If SPLIT is TRUE, splits DE's data sheet into four panes.
802 If SPLIT is FALSE, un-splits it into a single pane. */
804 psppire_data_editor_split_window (PsppireDataEditor *de, gboolean split)
806 GtkTreeViewGridLines grid_lines;
808 if (split == de->split)
812 grid_lines = pspp_sheet_view_get_grid_lines (
813 PSPP_SHEET_VIEW (de->data_sheets[0]));
815 disconnect_data_sheets (de);
816 gtk_widget_destroy (de->datasheet_vbox_widget);
819 de->datasheet_vbox_widget = make_split_datasheet (de, grid_lines);
821 de->datasheet_vbox_widget = make_single_datasheet (de, grid_lines);
822 psppire_data_editor_refresh_model (de);
824 gtk_box_pack_start (GTK_BOX (de->vbox), de->datasheet_vbox_widget,
826 gtk_widget_show_all (de->vbox);
829 set_font_recursively (GTK_WIDGET (de), de->font);
832 g_object_notify (G_OBJECT (de), "split");
833 psppire_data_editor_update_ui_manager (de);
836 /* Makes the variable with dictionary index DICT_INDEX in DE's dictionary
837 visible and selected in the active view in DE. */
839 psppire_data_editor_goto_variable (PsppireDataEditor *de, gint dict_index)
841 PsppireDataSheet *data_sheet;
843 switch (gtk_notebook_get_current_page (GTK_NOTEBOOK (de)))
845 case PSPPIRE_DATA_EDITOR_DATA_VIEW:
846 data_sheet = psppire_data_editor_get_active_data_sheet (de);
847 psppire_data_sheet_show_variable (data_sheet, dict_index);
850 case PSPPIRE_DATA_EDITOR_VARIABLE_VIEW:
851 psppire_var_sheet_goto_variable (PSPPIRE_VAR_SHEET (de->var_sheet),
857 /* Returns the "active" data sheet in DE. If DE is in single-paned mode, this
858 is the only data sheet. If DE is in split mode (showing four data sheets),
859 this is the focused data sheet or, if none is focused, the data sheet with
860 selected cells or, if none has selected cells, the upper-left data sheet. */
862 psppire_data_editor_get_active_data_sheet (PsppireDataEditor *de)
866 PsppireDataSheet *data_sheet;
870 /* If one of the datasheet's scrollers is focused, choose that one. */
871 scroller = gtk_container_get_focus_child (
872 GTK_CONTAINER (de->datasheet_vbox_widget));
873 if (scroller != NULL)
874 return PSPPIRE_DATA_SHEET (gtk_bin_get_child (GTK_BIN (scroller)));
876 /* Otherwise if there's a nonempty selection in some data sheet, choose
878 FOR_EACH_DATA_SHEET (data_sheet, i, de)
880 PsppSheetSelection *selection;
882 selection = pspp_sheet_view_get_selection (
883 PSPP_SHEET_VIEW (data_sheet));
884 if (pspp_sheet_selection_count_selected_rows (selection)
885 && pspp_sheet_selection_count_selected_columns (selection))
890 return PSPPIRE_DATA_SHEET (de->data_sheets[0]);
893 /* Returns the UI manager that should be merged into DE's toplevel widget's UI
894 manager to display menu items and toolbar items specific to DE's current
897 DE's toplevel widget can watch for changes by connecting to DE's
898 notify::ui-manager signal. */
900 psppire_data_editor_get_ui_manager (PsppireDataEditor *de)
902 psppire_data_editor_update_ui_manager (de);
903 return de->ui_manager;
907 psppire_data_editor_update_ui_manager (PsppireDataEditor *de)
909 PsppireDataSheet *data_sheet;
910 GtkUIManager *ui_manager;
914 switch (gtk_notebook_get_current_page (GTK_NOTEBOOK (de)))
916 case PSPPIRE_DATA_EDITOR_DATA_VIEW:
917 data_sheet = psppire_data_editor_get_active_data_sheet (de);
918 if (data_sheet != NULL)
919 ui_manager = psppire_data_sheet_get_ui_manager (data_sheet);
922 /* This happens transiently in psppire_data_editor_split_window(). */
926 case PSPPIRE_DATA_EDITOR_VARIABLE_VIEW:
927 ui_manager = psppire_var_sheet_get_ui_manager (
928 PSPPIRE_VAR_SHEET (de->var_sheet));
932 /* This happens transiently in psppire_data_editor_init(). */
936 if (ui_manager != de->ui_manager)
939 g_object_unref (de->ui_manager);
941 g_object_ref (ui_manager);
942 de->ui_manager = ui_manager;
944 g_object_notify (G_OBJECT (de), "ui-manager");