X-Git-Url: https://pintos-os.org/cgi-bin/gitweb.cgi?a=blobdiff_plain;f=src%2Fui%2Fgui%2Fpspp-sheet-view.c;h=cd4999301f6539a13d95dc21d5c32e050108b503;hb=900a7a094b23778368271ed77a95b331748e4aec;hp=5ddef9d821ed4de39ea16b56a780413d5c62e59b;hpb=d9c6597d5b7a0fb3211d5ba0696b0c9681c776c0;p=pspp diff --git a/src/ui/gui/pspp-sheet-view.c b/src/ui/gui/pspp-sheet-view.c index 5ddef9d821..cd4999301f 100644 --- a/src/ui/gui/pspp-sheet-view.c +++ b/src/ui/gui/pspp-sheet-view.c @@ -1,5 +1,5 @@ /* PSPPIRE - a graphical user interface for PSPP. - Copyright (C) 2011, 2012 Free Software Foundation, Inc. + Copyright (C) 2011, 2012, 2013 Free Software Foundation, Inc. This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -144,7 +144,9 @@ enum { PROP_RUBBER_BANDING, PROP_ENABLE_GRID_LINES, PROP_TOOLTIP_COLUMN, - PROP_SPECIAL_CELLS + PROP_SPECIAL_CELLS, + PROP_FIXED_HEIGHT, + PROP_FIXED_HEIGHT_SET }; /* object signals */ @@ -158,8 +160,7 @@ static void pspp_sheet_view_get_property (GObject *object, GValue *value, GParamSpec *pspec); -/* gtkobject signals */ -static void pspp_sheet_view_destroy (GtkObject *object); +static void pspp_sheet_view_dispose (GObject *object); /* gtkwidget signals */ static void pspp_sheet_view_realize (GtkWidget *widget); @@ -255,7 +256,8 @@ static gboolean pspp_sheet_view_real_move_cursor (PsppSheetView * static gboolean pspp_sheet_view_real_select_all (PsppSheetView *tree_view); static gboolean pspp_sheet_view_real_unselect_all (PsppSheetView *tree_view); static gboolean pspp_sheet_view_real_select_cursor_row (PsppSheetView *tree_view, - gboolean start_editing); + gboolean start_editing, + PsppSheetSelectMode mode); static gboolean pspp_sheet_view_real_toggle_cursor_row (PsppSheetView *tree_view); static void pspp_sheet_view_row_changed (GtkTreeModel *model, GtkTreePath *path, @@ -314,18 +316,28 @@ static void pspp_sheet_view_clamp_column_visible (PsppSheetView static gboolean pspp_sheet_view_maybe_begin_dragging_row (PsppSheetView *tree_view, GdkEventMotion *event); static void pspp_sheet_view_focus_to_cursor (PsppSheetView *tree_view); -static void pspp_sheet_view_move_cursor_up_down (PsppSheetView *tree_view, - gint count); +static gboolean pspp_sheet_view_move_cursor_up_down (PsppSheetView *tree_view, + gint count, + PsppSheetSelectMode mode); static void pspp_sheet_view_move_cursor_page_up_down (PsppSheetView *tree_view, - gint count); + gint count, + PsppSheetSelectMode mode); static void pspp_sheet_view_move_cursor_left_right (PsppSheetView *tree_view, + gint count, + PsppSheetSelectMode mode); +static void pspp_sheet_view_move_cursor_line_start_end (PsppSheetView *tree_view, + gint count, + PsppSheetSelectMode mode); +static void pspp_sheet_view_move_cursor_tab (PsppSheetView *tree_view, gint count); static void pspp_sheet_view_move_cursor_start_end (PsppSheetView *tree_view, - gint count); + gint count, + PsppSheetSelectMode mode); static void pspp_sheet_view_real_set_cursor (PsppSheetView *tree_view, GtkTreePath *path, gboolean clear_and_select, - gboolean clamp_node); + gboolean clamp_node, + PsppSheetSelectMode mode); static gboolean pspp_sheet_view_has_special_cell (PsppSheetView *tree_view); static void pspp_sheet_view_stop_rubber_band (PsppSheetView *tree_view); static void update_prelight (PsppSheetView *tree_view, @@ -427,6 +439,8 @@ static void remove_scroll_timeout (PsppSheetView *tree_view); static guint tree_view_signals [LAST_SIGNAL] = { 0 }; +static GtkBindingSet *edit_bindings; + /* GType Methods @@ -440,15 +454,17 @@ static void pspp_sheet_view_class_init (PsppSheetViewClass *class) { GObjectClass *o_class; - GtkObjectClass *object_class; GtkWidgetClass *widget_class; GtkContainerClass *container_class; - GtkBindingSet *binding_set; + GtkBindingSet *binding_set[2]; + int i; - binding_set = gtk_binding_set_by_class (class); + binding_set[0] = gtk_binding_set_by_class (class); + + binding_set[1] = gtk_binding_set_new ("PsppSheetViewEditing"); + edit_bindings = binding_set[1]; o_class = (GObjectClass *) class; - object_class = (GtkObjectClass *) class; widget_class = (GtkWidgetClass *) class; container_class = (GtkContainerClass *) class; @@ -456,9 +472,7 @@ pspp_sheet_view_class_init (PsppSheetViewClass *class) o_class->set_property = pspp_sheet_view_set_property; o_class->get_property = pspp_sheet_view_get_property; o_class->finalize = pspp_sheet_view_finalize; - - /* GtkObject signals */ - object_class->destroy = pspp_sheet_view_destroy; + o_class->dispose = pspp_sheet_view_dispose; /* GtkWidget signals */ widget_class->map = pspp_sheet_view_map; @@ -637,6 +651,24 @@ pspp_sheet_view_class_init (PsppSheetViewClass *class) PSPP_SHEET_VIEW_SPECIAL_CELLS_DETECT, GTK_PARAM_READWRITE)); + g_object_class_install_property (o_class, + PROP_FIXED_HEIGHT, + g_param_spec_int ("fixed-height", + P_("Fixed Height"), + P_("Height of a single row. Normally the height of a row is determined automatically. Writing this property sets fixed-height-set to true, preventing this property's value from changing."), + -1, + G_MAXINT, + -1, + GTK_PARAM_READWRITE)); + + g_object_class_install_property (o_class, + PROP_FIXED_HEIGHT_SET, + g_param_spec_boolean ("fixed-height-set", + P_("Fixed Height Set"), + P_("Whether fixed-height was set externally."), + FALSE, + GTK_PARAM_READWRITE)); + /* Style properties */ #define _TREE_VIEW_EXPANDER_SIZE 12 #define _TREE_VIEW_VERTICAL_SEPARATOR 2 @@ -797,7 +829,7 @@ pspp_sheet_view_class_init (PsppSheetViewClass *class) tree_view_signals[MOVE_CURSOR] = g_signal_new ("move-cursor", - G_TYPE_FROM_CLASS (object_class), + G_TYPE_FROM_CLASS (o_class), G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION, G_STRUCT_OFFSET (PsppSheetViewClass, move_cursor), NULL, NULL, @@ -808,7 +840,7 @@ pspp_sheet_view_class_init (PsppSheetViewClass *class) tree_view_signals[SELECT_ALL] = g_signal_new ("select-all", - G_TYPE_FROM_CLASS (object_class), + G_TYPE_FROM_CLASS (o_class), G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION, G_STRUCT_OFFSET (PsppSheetViewClass, select_all), NULL, NULL, @@ -817,7 +849,7 @@ pspp_sheet_view_class_init (PsppSheetViewClass *class) tree_view_signals[UNSELECT_ALL] = g_signal_new ("unselect-all", - G_TYPE_FROM_CLASS (object_class), + G_TYPE_FROM_CLASS (o_class), G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION, G_STRUCT_OFFSET (PsppSheetViewClass, unselect_all), NULL, NULL, @@ -826,17 +858,17 @@ pspp_sheet_view_class_init (PsppSheetViewClass *class) tree_view_signals[SELECT_CURSOR_ROW] = g_signal_new ("select-cursor-row", - G_TYPE_FROM_CLASS (object_class), + G_TYPE_FROM_CLASS (o_class), G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION, G_STRUCT_OFFSET (PsppSheetViewClass, select_cursor_row), NULL, NULL, psppire_marshal_BOOLEAN__BOOLEAN, - G_TYPE_BOOLEAN, 1, - G_TYPE_BOOLEAN); + G_TYPE_BOOLEAN, 2, + G_TYPE_BOOLEAN, G_TYPE_INT); tree_view_signals[TOGGLE_CURSOR_ROW] = g_signal_new ("toggle-cursor-row", - G_TYPE_FROM_CLASS (object_class), + G_TYPE_FROM_CLASS (o_class), G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION, G_STRUCT_OFFSET (PsppSheetViewClass, toggle_cursor_row), NULL, NULL, @@ -845,7 +877,7 @@ pspp_sheet_view_class_init (PsppSheetViewClass *class) tree_view_signals[START_INTERACTIVE_SEARCH] = g_signal_new ("start-interactive-search", - G_TYPE_FROM_CLASS (object_class), + G_TYPE_FROM_CLASS (o_class), G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION, G_STRUCT_OFFSET (PsppSheetViewClass, start_interactive_search), NULL, NULL, @@ -853,110 +885,136 @@ pspp_sheet_view_class_init (PsppSheetViewClass *class) G_TYPE_BOOLEAN, 0); /* Key bindings */ - pspp_sheet_view_add_move_binding (binding_set, GDK_Up, 0, TRUE, - GTK_MOVEMENT_DISPLAY_LINES, -1); - pspp_sheet_view_add_move_binding (binding_set, GDK_KP_Up, 0, TRUE, - GTK_MOVEMENT_DISPLAY_LINES, -1); - - pspp_sheet_view_add_move_binding (binding_set, GDK_Down, 0, TRUE, - GTK_MOVEMENT_DISPLAY_LINES, 1); - pspp_sheet_view_add_move_binding (binding_set, GDK_KP_Down, 0, TRUE, - GTK_MOVEMENT_DISPLAY_LINES, 1); - - pspp_sheet_view_add_move_binding (binding_set, GDK_p, GDK_CONTROL_MASK, FALSE, - GTK_MOVEMENT_DISPLAY_LINES, -1); - - pspp_sheet_view_add_move_binding (binding_set, GDK_n, GDK_CONTROL_MASK, FALSE, - GTK_MOVEMENT_DISPLAY_LINES, 1); - - pspp_sheet_view_add_move_binding (binding_set, GDK_Home, 0, TRUE, - GTK_MOVEMENT_BUFFER_ENDS, -1); - pspp_sheet_view_add_move_binding (binding_set, GDK_KP_Home, 0, TRUE, - GTK_MOVEMENT_BUFFER_ENDS, -1); - - pspp_sheet_view_add_move_binding (binding_set, GDK_End, 0, TRUE, - GTK_MOVEMENT_BUFFER_ENDS, 1); - pspp_sheet_view_add_move_binding (binding_set, GDK_KP_End, 0, TRUE, - GTK_MOVEMENT_BUFFER_ENDS, 1); - - pspp_sheet_view_add_move_binding (binding_set, GDK_Page_Up, 0, TRUE, - GTK_MOVEMENT_PAGES, -1); - pspp_sheet_view_add_move_binding (binding_set, GDK_KP_Page_Up, 0, TRUE, - GTK_MOVEMENT_PAGES, -1); - - pspp_sheet_view_add_move_binding (binding_set, GDK_Page_Down, 0, TRUE, - GTK_MOVEMENT_PAGES, 1); - pspp_sheet_view_add_move_binding (binding_set, GDK_KP_Page_Down, 0, TRUE, - GTK_MOVEMENT_PAGES, 1); - - - gtk_binding_entry_add_signal (binding_set, GDK_Right, 0, "move-cursor", 2, - G_TYPE_ENUM, GTK_MOVEMENT_VISUAL_POSITIONS, - G_TYPE_INT, 1); - - gtk_binding_entry_add_signal (binding_set, GDK_Left, 0, "move-cursor", 2, - G_TYPE_ENUM, GTK_MOVEMENT_VISUAL_POSITIONS, - G_TYPE_INT, -1); - - gtk_binding_entry_add_signal (binding_set, GDK_KP_Right, 0, "move-cursor", 2, - G_TYPE_ENUM, GTK_MOVEMENT_VISUAL_POSITIONS, - G_TYPE_INT, 1); - - gtk_binding_entry_add_signal (binding_set, GDK_KP_Left, 0, "move-cursor", 2, - G_TYPE_ENUM, GTK_MOVEMENT_VISUAL_POSITIONS, - G_TYPE_INT, -1); - - gtk_binding_entry_add_signal (binding_set, GDK_Right, GDK_CONTROL_MASK, - "move-cursor", 2, - G_TYPE_ENUM, GTK_MOVEMENT_VISUAL_POSITIONS, - G_TYPE_INT, 1); - - gtk_binding_entry_add_signal (binding_set, GDK_Left, GDK_CONTROL_MASK, - "move-cursor", 2, - G_TYPE_ENUM, GTK_MOVEMENT_VISUAL_POSITIONS, - G_TYPE_INT, -1); - - gtk_binding_entry_add_signal (binding_set, GDK_KP_Right, GDK_CONTROL_MASK, - "move-cursor", 2, - G_TYPE_ENUM, GTK_MOVEMENT_VISUAL_POSITIONS, - G_TYPE_INT, 1); - - gtk_binding_entry_add_signal (binding_set, GDK_KP_Left, GDK_CONTROL_MASK, - "move-cursor", 2, - G_TYPE_ENUM, GTK_MOVEMENT_VISUAL_POSITIONS, - G_TYPE_INT, -1); - - gtk_binding_entry_add_signal (binding_set, GDK_space, GDK_CONTROL_MASK, "toggle-cursor-row", 0); - gtk_binding_entry_add_signal (binding_set, GDK_KP_Space, GDK_CONTROL_MASK, "toggle-cursor-row", 0); - - gtk_binding_entry_add_signal (binding_set, GDK_a, GDK_CONTROL_MASK, "select-all", 0); - gtk_binding_entry_add_signal (binding_set, GDK_slash, GDK_CONTROL_MASK, "select-all", 0); - - gtk_binding_entry_add_signal (binding_set, GDK_A, GDK_CONTROL_MASK | GDK_SHIFT_MASK, "unselect-all", 0); - gtk_binding_entry_add_signal (binding_set, GDK_backslash, GDK_CONTROL_MASK, "unselect-all", 0); - - gtk_binding_entry_add_signal (binding_set, GDK_space, GDK_SHIFT_MASK, "select-cursor-row", 1, - G_TYPE_BOOLEAN, TRUE); - gtk_binding_entry_add_signal (binding_set, GDK_KP_Space, GDK_SHIFT_MASK, "select-cursor-row", 1, - G_TYPE_BOOLEAN, TRUE); + for (i = 0; i < 2; i++) + { + pspp_sheet_view_add_move_binding (binding_set[i], GDK_Up, 0, TRUE, + GTK_MOVEMENT_DISPLAY_LINES, -1); + pspp_sheet_view_add_move_binding (binding_set[i], GDK_KP_Up, 0, TRUE, + GTK_MOVEMENT_DISPLAY_LINES, -1); - gtk_binding_entry_add_signal (binding_set, GDK_space, 0, "select-cursor-row", 1, - G_TYPE_BOOLEAN, TRUE); - gtk_binding_entry_add_signal (binding_set, GDK_KP_Space, 0, "select-cursor-row", 1, - G_TYPE_BOOLEAN, TRUE); - gtk_binding_entry_add_signal (binding_set, GDK_Return, 0, "select-cursor-row", 1, - G_TYPE_BOOLEAN, TRUE); - gtk_binding_entry_add_signal (binding_set, GDK_ISO_Enter, 0, "select-cursor-row", 1, - G_TYPE_BOOLEAN, TRUE); - gtk_binding_entry_add_signal (binding_set, GDK_KP_Enter, 0, "select-cursor-row", 1, - G_TYPE_BOOLEAN, TRUE); + pspp_sheet_view_add_move_binding (binding_set[i], GDK_Down, 0, TRUE, + GTK_MOVEMENT_DISPLAY_LINES, 1); + pspp_sheet_view_add_move_binding (binding_set[i], GDK_KP_Down, 0, TRUE, + GTK_MOVEMENT_DISPLAY_LINES, 1); - gtk_binding_entry_add_signal (binding_set, GDK_BackSpace, 0, "select-cursor-parent", 0); - gtk_binding_entry_add_signal (binding_set, GDK_BackSpace, GDK_CONTROL_MASK, "select-cursor-parent", 0); + pspp_sheet_view_add_move_binding (binding_set[i], GDK_p, GDK_CONTROL_MASK, FALSE, + GTK_MOVEMENT_DISPLAY_LINES, -1); - gtk_binding_entry_add_signal (binding_set, GDK_f, GDK_CONTROL_MASK, "start-interactive-search", 0); + pspp_sheet_view_add_move_binding (binding_set[i], GDK_n, GDK_CONTROL_MASK, FALSE, + GTK_MOVEMENT_DISPLAY_LINES, 1); - gtk_binding_entry_add_signal (binding_set, GDK_F, GDK_CONTROL_MASK, "start-interactive-search", 0); + pspp_sheet_view_add_move_binding (binding_set[i], GDK_Home, 0, TRUE, + GTK_MOVEMENT_DISPLAY_LINE_ENDS, -1); + pspp_sheet_view_add_move_binding (binding_set[i], GDK_KP_Home, 0, TRUE, + GTK_MOVEMENT_DISPLAY_LINE_ENDS, -1); + + pspp_sheet_view_add_move_binding (binding_set[i], GDK_End, 0, TRUE, + GTK_MOVEMENT_DISPLAY_LINE_ENDS, 1); + pspp_sheet_view_add_move_binding (binding_set[i], GDK_KP_End, 0, TRUE, + GTK_MOVEMENT_DISPLAY_LINE_ENDS, 1); + + pspp_sheet_view_add_move_binding (binding_set[i], GDK_Page_Up, 0, TRUE, + GTK_MOVEMENT_PAGES, -1); + pspp_sheet_view_add_move_binding (binding_set[i], GDK_KP_Page_Up, 0, TRUE, + GTK_MOVEMENT_PAGES, -1); + + pspp_sheet_view_add_move_binding (binding_set[i], GDK_Page_Down, 0, TRUE, + GTK_MOVEMENT_PAGES, 1); + pspp_sheet_view_add_move_binding (binding_set[i], GDK_KP_Page_Down, 0, TRUE, + GTK_MOVEMENT_PAGES, 1); + + + gtk_binding_entry_add_signal (binding_set[i], GDK_Up, GDK_CONTROL_MASK, "move-cursor", 2, + G_TYPE_ENUM, GTK_MOVEMENT_BUFFER_ENDS, + G_TYPE_INT, -1); + + gtk_binding_entry_add_signal (binding_set[i], GDK_Down, GDK_CONTROL_MASK, "move-cursor", 2, + G_TYPE_ENUM, GTK_MOVEMENT_BUFFER_ENDS, + G_TYPE_INT, 1); + + gtk_binding_entry_add_signal (binding_set[i], GDK_Right, 0, "move-cursor", 2, + G_TYPE_ENUM, GTK_MOVEMENT_VISUAL_POSITIONS, + G_TYPE_INT, 1); + + gtk_binding_entry_add_signal (binding_set[i], GDK_Left, 0, "move-cursor", 2, + G_TYPE_ENUM, GTK_MOVEMENT_VISUAL_POSITIONS, + G_TYPE_INT, -1); + + gtk_binding_entry_add_signal (binding_set[i], GDK_Tab, 0, "move-cursor", 2, + G_TYPE_ENUM, GTK_MOVEMENT_LOGICAL_POSITIONS, + G_TYPE_INT, 1); + + gtk_binding_entry_add_signal (binding_set[i], GDK_Tab, GDK_SHIFT_MASK, "move-cursor", 2, + G_TYPE_ENUM, GTK_MOVEMENT_LOGICAL_POSITIONS, + G_TYPE_INT, -1); + + gtk_binding_entry_add_signal (binding_set[i], GDK_KP_Right, 0, "move-cursor", 2, + G_TYPE_ENUM, GTK_MOVEMENT_DISPLAY_LINE_ENDS, + G_TYPE_INT, 1); + + gtk_binding_entry_add_signal (binding_set[i], GDK_KP_Left, 0, "move-cursor", 2, + G_TYPE_ENUM, GTK_MOVEMENT_DISPLAY_LINE_ENDS, + G_TYPE_INT, -1); + + gtk_binding_entry_add_signal (binding_set[i], GDK_Right, GDK_CONTROL_MASK, + "move-cursor", 2, + G_TYPE_ENUM, GTK_MOVEMENT_DISPLAY_LINE_ENDS, + G_TYPE_INT, 1); + + gtk_binding_entry_add_signal (binding_set[i], GDK_Left, GDK_CONTROL_MASK, + "move-cursor", 2, + G_TYPE_ENUM, GTK_MOVEMENT_DISPLAY_LINE_ENDS, + G_TYPE_INT, -1); + + gtk_binding_entry_add_signal (binding_set[i], GDK_KP_Right, GDK_CONTROL_MASK, + "move-cursor", 2, + G_TYPE_ENUM, GTK_MOVEMENT_VISUAL_POSITIONS, + G_TYPE_INT, 1); + + gtk_binding_entry_add_signal (binding_set[i], GDK_KP_Left, GDK_CONTROL_MASK, + "move-cursor", 2, + G_TYPE_ENUM, GTK_MOVEMENT_VISUAL_POSITIONS, + G_TYPE_INT, -1); + + gtk_binding_entry_add_signal (binding_set[i], GDK_f, GDK_CONTROL_MASK, "start-interactive-search", 0); + + gtk_binding_entry_add_signal (binding_set[i], GDK_F, GDK_CONTROL_MASK, "start-interactive-search", 0); + } + + gtk_binding_entry_add_signal (binding_set[0], GDK_space, GDK_CONTROL_MASK, "toggle-cursor-row", 0); + gtk_binding_entry_add_signal (binding_set[0], GDK_KP_Space, GDK_CONTROL_MASK, "toggle-cursor-row", 0); + + gtk_binding_entry_add_signal (binding_set[0], GDK_a, GDK_CONTROL_MASK, "select-all", 0); + gtk_binding_entry_add_signal (binding_set[0], GDK_slash, GDK_CONTROL_MASK, "select-all", 0); + + gtk_binding_entry_add_signal (binding_set[0], GDK_A, GDK_CONTROL_MASK | GDK_SHIFT_MASK, "unselect-all", 0); + gtk_binding_entry_add_signal (binding_set[0], GDK_backslash, GDK_CONTROL_MASK, "unselect-all", 0); + + gtk_binding_entry_add_signal (binding_set[0], GDK_space, GDK_SHIFT_MASK, "select-cursor-row", 1, + G_TYPE_BOOLEAN, TRUE, + G_TYPE_INT, PSPP_SHEET_SELECT_MODE_EXTEND); + gtk_binding_entry_add_signal (binding_set[0], GDK_KP_Space, GDK_SHIFT_MASK, "select-cursor-row", 1, + G_TYPE_BOOLEAN, TRUE, + G_TYPE_INT, PSPP_SHEET_SELECT_MODE_EXTEND); + + gtk_binding_entry_add_signal (binding_set[0], GDK_space, 0, "select-cursor-row", 1, + G_TYPE_BOOLEAN, TRUE, + G_TYPE_INT, 0); + gtk_binding_entry_add_signal (binding_set[0], GDK_KP_Space, 0, "select-cursor-row", 1, + G_TYPE_BOOLEAN, TRUE, + G_TYPE_INT, 0); + gtk_binding_entry_add_signal (binding_set[0], GDK_Return, 0, "select-cursor-row", 1, + G_TYPE_BOOLEAN, TRUE, + G_TYPE_INT, 0); + gtk_binding_entry_add_signal (binding_set[0], GDK_ISO_Enter, 0, "select-cursor-row", 1, + G_TYPE_BOOLEAN, TRUE, + G_TYPE_INT, 0); + gtk_binding_entry_add_signal (binding_set[0], GDK_KP_Enter, 0, "select-cursor-row", 1, + G_TYPE_BOOLEAN, TRUE, + G_TYPE_INT, 0); + + gtk_binding_entry_add_signal (binding_set[0], GDK_BackSpace, 0, "select-cursor-parent", 0); + gtk_binding_entry_add_signal (binding_set[0], GDK_BackSpace, GDK_CONTROL_MASK, "select-cursor-parent", 0); g_type_class_add_private (o_class, sizeof (PsppSheetViewPrivate)); } @@ -994,6 +1052,7 @@ pspp_sheet_view_init (PsppSheetView *tree_view) tree_view->priv->presize_handler_timer = 0; tree_view->priv->scroll_sync_timer = 0; tree_view->priv->fixed_height = -1; + tree_view->priv->fixed_height_set = FALSE; pspp_sheet_view_set_adjustments (tree_view, NULL, NULL); tree_view->priv->selection = _pspp_sheet_selection_new_with_tree_view (tree_view); tree_view->priv->enable_search = TRUE; @@ -1030,6 +1089,8 @@ pspp_sheet_view_init (PsppSheetView *tree_view) tree_view->priv->anchor_column = NULL; tree_view->priv->button_style = NULL; + + tree_view->dispose_has_run = FALSE; } @@ -1091,6 +1152,29 @@ pspp_sheet_view_set_property (GObject *object, case PROP_SPECIAL_CELLS: pspp_sheet_view_set_special_cells (tree_view, g_value_get_enum (value)); break; + case PROP_FIXED_HEIGHT: + pspp_sheet_view_set_fixed_height (tree_view, g_value_get_int (value)); + break; + case PROP_FIXED_HEIGHT_SET: + if (g_value_get_boolean (value)) + { + if (!tree_view->priv->fixed_height_set + && tree_view->priv->fixed_height >= 0) + { + tree_view->priv->fixed_height_set = true; + g_object_notify (G_OBJECT (tree_view), "fixed-height-set"); + } + } + else + { + if (tree_view->priv->fixed_height_set) + { + tree_view->priv->fixed_height_set = false; + g_object_notify (G_OBJECT (tree_view), "fixed-height-set"); + install_presize_handler (tree_view); + } + } + break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; @@ -1151,6 +1235,12 @@ pspp_sheet_view_get_property (GObject *object, case PROP_SPECIAL_CELLS: g_value_set_enum (value, tree_view->priv->special_cells); break; + case PROP_FIXED_HEIGHT: + g_value_set_int (value, pspp_sheet_view_get_fixed_height (tree_view)); + break; + case PROP_FIXED_HEIGHT_SET: + g_value_set_boolean (value, tree_view->priv->fixed_height_set); + break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; @@ -1158,9 +1248,41 @@ pspp_sheet_view_get_property (GObject *object, } static void -pspp_sheet_view_finalize (GObject *object) +pspp_sheet_view_dispose (GObject *object) { - G_OBJECT_CLASS (pspp_sheet_view_parent_class)->finalize (object); + PsppSheetView *tree_view = PSPP_SHEET_VIEW (object); + + if (tree_view->dispose_has_run) + return; + + tree_view->dispose_has_run = TRUE; + + if (tree_view->priv->selection != NULL) + { + _pspp_sheet_selection_set_tree_view (tree_view->priv->selection, NULL); + g_object_unref (tree_view->priv->selection); + tree_view->priv->selection = NULL; + } + + if (tree_view->priv->hadjustment) + { + g_object_unref (tree_view->priv->hadjustment); + tree_view->priv->hadjustment = NULL; + } + if (tree_view->priv->vadjustment) + { + g_object_unref (tree_view->priv->vadjustment); + tree_view->priv->vadjustment = NULL; + } + + if (tree_view->priv->button_style) + { + g_object_unref (tree_view->priv->button_style); + tree_view->priv->button_style = NULL; + } + + + G_OBJECT_CLASS (pspp_sheet_view_parent_class)->dispose (object); } @@ -1174,14 +1296,10 @@ pspp_sheet_view_buildable_add_child (GtkBuildable *tree_view, pspp_sheet_view_append_column (PSPP_SHEET_VIEW (tree_view), PSPP_SHEET_VIEW_COLUMN (child)); } -/* GtkObject Methods - */ - static void -pspp_sheet_view_destroy (GtkObject *object) +pspp_sheet_view_finalize (GObject *object) { PsppSheetView *tree_view = PSPP_SHEET_VIEW (object); - GList *list; pspp_sheet_view_stop_editing (tree_view, TRUE); @@ -1191,27 +1309,9 @@ pspp_sheet_view_destroy (GtkObject *object) tree_view->priv->selected = NULL; } - if (tree_view->priv->columns != NULL) - { - list = tree_view->priv->columns; - while (list) - { - PsppSheetViewColumn *column; - column = PSPP_SHEET_VIEW_COLUMN (list->data); - list = list->next; - pspp_sheet_view_remove_column (tree_view, column); - } - tree_view->priv->columns = NULL; - } tree_view->priv->prelight_node = -1; - if (tree_view->priv->selection != NULL) - { - _pspp_sheet_selection_set_tree_view (tree_view->priv->selection, NULL); - g_object_unref (tree_view->priv->selection); - tree_view->priv->selection = NULL; - } if (tree_view->priv->scroll_to_path != NULL) { @@ -1278,24 +1378,8 @@ pspp_sheet_view_destroy (GtkObject *object) pspp_sheet_view_set_model (tree_view, NULL); - if (tree_view->priv->hadjustment) - { - g_object_unref (tree_view->priv->hadjustment); - tree_view->priv->hadjustment = NULL; - } - if (tree_view->priv->vadjustment) - { - g_object_unref (tree_view->priv->vadjustment); - tree_view->priv->vadjustment = NULL; - } - if (tree_view->priv->button_style) - { - g_object_unref (tree_view->priv->button_style); - tree_view->priv->button_style = NULL; - } - - GTK_OBJECT_CLASS (pspp_sheet_view_parent_class)->destroy (object); + G_OBJECT_CLASS (pspp_sheet_view_parent_class)->finalize (object); } @@ -1370,6 +1454,7 @@ pspp_sheet_view_map (GtkWidget *widget) static void pspp_sheet_view_realize (GtkWidget *widget) { + gint i; PsppSheetView *tree_view = PSPP_SHEET_VIEW (widget); GList *tmp_list; GdkWindowAttr attributes; @@ -1451,15 +1536,24 @@ pspp_sheet_view_realize (GtkWidget *widget) pspp_sheet_view_set_grid_lines (tree_view, tree_view->priv->grid_lines); install_presize_handler (tree_view); + + for (i = 0; i < 5; ++i) + { + tree_view->priv->grid_line_gc[i] = gdk_gc_new (widget->window); + gdk_gc_copy (tree_view->priv->grid_line_gc[i], widget->style->text_aa_gc[i]); + } } static void pspp_sheet_view_unrealize (GtkWidget *widget) { + gint x; PsppSheetView *tree_view = PSPP_SHEET_VIEW (widget); PsppSheetViewPrivate *priv = tree_view->priv; GList *list; + GTK_WIDGET_CLASS (pspp_sheet_view_parent_class)->unrealize (widget); + if (priv->scroll_timeout != 0) { g_source_remove (priv->scroll_timeout); @@ -1521,13 +1615,21 @@ pspp_sheet_view_unrealize (GtkWidget *widget) priv->drag_highlight_window = NULL; } - if (priv->grid_line_gc) + for (x = 0 ; x < 5 ; ++x) + g_object_unref (priv->grid_line_gc[x]); + + if (tree_view->priv->columns != NULL) { - g_object_unref (priv->grid_line_gc); - priv->grid_line_gc = NULL; + list = tree_view->priv->columns; + while (list) + { + PsppSheetViewColumn *column; + column = PSPP_SHEET_VIEW_COLUMN (list->data); + list = list->next; + pspp_sheet_view_remove_column (tree_view, column); + } + tree_view->priv->columns = NULL; } - - GTK_WIDGET_CLASS (pspp_sheet_view_parent_class)->unrealize (widget); } /* GtkWidget::size_request helper */ @@ -2253,7 +2355,6 @@ pspp_sheet_view_button_press (GtkWidget *widget, PsppSheetViewColumn *column = NULL; GtkCellRenderer *focus_cell = NULL; gboolean row_double_click = FALSE; - gboolean node_selected; /* Empty tree? */ if (tree_view->priv->row_count == 0) @@ -2275,7 +2376,6 @@ pspp_sheet_view_button_press (GtkWidget *widget, return TRUE; /* select */ - node_selected = pspp_sheet_view_node_is_selected (tree_view, node); pre_val = tree_view->priv->vadjustment->value; path = _pspp_sheet_view_find_path (tree_view, node); @@ -2284,10 +2384,12 @@ pspp_sheet_view_button_press (GtkWidget *widget, */ if (event->type == GDK_BUTTON_PRESS) { + PsppSheetSelectionMode mode = 0; + if ((event->state & GDK_CONTROL_MASK) == GDK_CONTROL_MASK) - tree_view->priv->ctrl_pressed = TRUE; + mode |= PSPP_SHEET_SELECT_MODE_TOGGLE; if ((event->state & GDK_SHIFT_MASK) == GDK_SHIFT_MASK) - tree_view->priv->shift_pressed = TRUE; + mode |= PSPP_SHEET_SELECT_MODE_EXTEND; focus_cell = _pspp_sheet_view_column_get_cell_at_pos (column, event->x - background_area.x); if (focus_cell) @@ -2295,17 +2397,17 @@ pspp_sheet_view_button_press (GtkWidget *widget, if (event->state & GDK_CONTROL_MASK) { - pspp_sheet_view_real_set_cursor (tree_view, path, FALSE, TRUE); + pspp_sheet_view_real_set_cursor (tree_view, path, FALSE, TRUE, mode); pspp_sheet_view_real_toggle_cursor_row (tree_view); } else if (event->state & GDK_SHIFT_MASK) { - pspp_sheet_view_real_set_cursor (tree_view, path, TRUE, TRUE); - pspp_sheet_view_real_select_cursor_row (tree_view, FALSE); + pspp_sheet_view_real_set_cursor (tree_view, path, TRUE, TRUE, mode); + pspp_sheet_view_real_select_cursor_row (tree_view, FALSE, mode); } else { - pspp_sheet_view_real_set_cursor (tree_view, path, TRUE, TRUE); + pspp_sheet_view_real_set_cursor (tree_view, path, TRUE, TRUE, 0); } if (tree_view->priv->anchor_column == NULL || @@ -2315,9 +2417,6 @@ pspp_sheet_view_button_press (GtkWidget *widget, pspp_sheet_selection_select_column_range (tree_view->priv->selection, tree_view->priv->anchor_column, column); - - tree_view->priv->ctrl_pressed = FALSE; - tree_view->priv->shift_pressed = FALSE; } /* the treeview may have been scrolled because of _set_cursor, @@ -2341,7 +2440,6 @@ pspp_sheet_view_button_press (GtkWidget *widget, tree_view->priv->press_start_node = node; if (tree_view->priv->rubber_banding_enable - //&& !node_selected && (tree_view->priv->selection->type == PSPP_SHEET_SELECTION_MULTIPLE || tree_view->priv->selection->type == PSPP_SHEET_SELECTION_RECTANGLE)) { @@ -2570,6 +2668,10 @@ pspp_sheet_view_button_release_edit (PsppSheetView *tree_view, if (event->window != tree_view->priv->bin_window) return FALSE; + /* Ignore a released button, if that button wasn't depressed */ + if (tree_view->priv->pressed_button != event->button) + return FALSE; + if (!find_click (tree_view, event->x, event->y, &node, &column, &background_area, &cell_area)) return FALSE; @@ -2604,7 +2706,7 @@ pspp_sheet_view_button_release_edit (PsppSheetView *tree_view, return FALSE; pspp_sheet_view_real_set_cursor (tree_view, path, - TRUE, TRUE); + TRUE, TRUE, 0); /* XXX mode? */ gtk_widget_queue_draw (GTK_WIDGET (tree_view)); area = cell_area; @@ -2722,7 +2824,7 @@ prelight_or_select (PsppSheetView *tree_view, if (pspp_sheet_view_node_is_selected (tree_view, node)) { PSPP_SHEET_VIEW_UNSET_FLAG (tree_view, PSPP_SHEET_VIEW_DRAW_KEYFOCUS); - pspp_sheet_view_real_set_cursor (tree_view, path, FALSE, FALSE); + pspp_sheet_view_real_set_cursor (tree_view, path, FALSE, FALSE, 0); /* XXX mode? */ } gtk_tree_path_free (path); } @@ -3214,7 +3316,7 @@ pspp_sheet_view_stop_rubber_band (PsppSheetView *tree_view) /* ... and the cursor to the end path */ tmp_path = _pspp_sheet_view_find_path (tree_view, tree_view->priv->rubber_band_end_node); - pspp_sheet_view_real_set_cursor (PSPP_SHEET_VIEW (tree_view), tmp_path, FALSE, FALSE); + pspp_sheet_view_real_set_cursor (PSPP_SHEET_VIEW (tree_view), tmp_path, FALSE, FALSE, 0); /* XXX mode? */ gtk_tree_path_free (tmp_path); _pspp_sheet_selection_emit_changed (tree_view->priv->selection); @@ -3664,22 +3766,25 @@ pspp_sheet_view_draw_grid_lines (PsppSheetView *tree_view, for (list = tree_view->priv->columns; list; list = list->next, i++) { PsppSheetViewColumn *column = list->data; - - /* We don't want a line for the last column */ - if (i == n_visible_columns - 1) - break; + gint x; if (! column->visible) continue; current_x += column->width; - if (current_x - 1 >= event->area.x - && current_x - 1 < event->area.x + event->area.width) + /* Generally the grid lines should fit within the column, but for the + last visible column we put it just past the end of the column. + (Otherwise horizontal grid lines sometimes stick out by one pixel.) */ + x = current_x; + if (i != n_visible_columns - 1) + x--; + + if (x >= event->area.x && x < event->area.x + event->area.width) gdk_draw_line (event->window, - tree_view->priv->grid_line_gc, - current_x - 1, min_y, - current_x - 1, max_y - min_y); + tree_view->priv->grid_line_gc[GTK_WIDGET(tree_view)->state], + x, min_y, + x, max_y - min_y); } } @@ -3703,7 +3808,6 @@ pspp_sheet_view_bin_expose (GtkWidget *widget, gint new_y; gint y_offset, cell_offset; gint max_height; - gint depth; GdkRectangle background_area; GdkRectangle cell_area; guint flags; @@ -3776,7 +3880,6 @@ pspp_sheet_view_bin_expose (GtkWidget *widget, gtk_tree_model_get_iter (tree_view->priv->model, &iter, path); - depth = gtk_tree_path_get_depth (path); gtk_tree_path_free (path); cursor_path = NULL; @@ -4060,14 +4163,14 @@ pspp_sheet_view_bin_expose (GtkWidget *widget, { if (background_area.y > 0) gdk_draw_line (event->window, - tree_view->priv->grid_line_gc, + tree_view->priv->grid_line_gc[widget->state], background_area.x, background_area.y, background_area.x + background_area.width, background_area.y); - if (y_offset + max_height >= event->area.height) + if (y_offset + max_height <= event->area.height) gdk_draw_line (event->window, - tree_view->priv->grid_line_gc, + tree_view->priv->grid_line_gc[widget->state], background_area.x, background_area.y + max_height, background_area.x + background_area.width, background_area.y + max_height); @@ -4953,7 +5056,6 @@ validate_row (PsppSheetView *tree_view, gint horizontal_separator; gint vertical_separator; gint focus_line_width; - gboolean retval = FALSE; gboolean draw_vgrid_lines, draw_hgrid_lines; gint focus_pad; gint grid_line_width; @@ -5016,10 +5118,7 @@ validate_row (PsppSheetView *tree_view, } if (tmp_width > column->requested_width) - { - retval = TRUE; - column->requested_width = tmp_width; - } + column->requested_width = tmp_width; } if (draw_hgrid_lines) @@ -5244,6 +5343,9 @@ initialize_fixed_height_mode (PsppSheetView *tree_view) if (!tree_view->priv->row_count) return; + if (tree_view->priv->fixed_height_set) + return; + if (tree_view->priv->fixed_height < 0) { GtkTreeIter iter; @@ -5257,6 +5359,8 @@ initialize_fixed_height_mode (PsppSheetView *tree_view) tree_view->priv->fixed_height = validate_row (tree_view, node, &iter, path); gtk_tree_path_free (path); + + g_object_notify (G_OBJECT (tree_view), "fixed-height"); } } @@ -5287,6 +5391,9 @@ do_presize_handler (PsppSheetView *tree_view) validate_visible_area (tree_view); tree_view->priv->presize_handler_timer = 0; + if (! gtk_widget_get_realized (GTK_WIDGET (tree_view))) + return FALSE; + gtk_widget_size_request (GTK_WIDGET (tree_view), &requisition); tree_view->priv->hadjustment->upper = MAX (tree_view->priv->hadjustment->upper, (gfloat)requisition.width); @@ -6502,7 +6609,9 @@ pspp_sheet_view_focus_column (PsppSheetView *tree_view, if (!focus_column->button) { pspp_sheet_view_column_set_need_button (focus_column, TRUE); - g_return_if_fail (focus_column->button != NULL); + // g_return_if_fail (focus_column->button != NULL); + if (focus_column->button == NULL) + return; } if (GTK_CONTAINER (tree_view)->focus_child != focus_column->button) @@ -6631,13 +6740,16 @@ pspp_sheet_view_header_focus (PsppSheetView *tree_view, break; } column = tmp_list->data; - if (column->button && - column->visible && + if (column->visible && pspp_sheet_view_column_can_focus (column)) - { - pspp_sheet_view_focus_column (tree_view, column, - clamp_column_visible); - return TRUE; + { + pspp_sheet_view_column_set_need_button (column, TRUE); + if (column->button) + { + pspp_sheet_view_focus_column (tree_view, column, + clamp_column_visible); + return TRUE; + } } } return FALSE; @@ -6751,9 +6863,18 @@ pspp_sheet_view_style_set (GtkWidget *widget, if (gtk_widget_get_realized (widget)) { + gint i; + PsppSheetViewPrivate *priv = PSPP_SHEET_VIEW (widget)->priv; + gdk_window_set_back_pixmap (widget->window, NULL, FALSE); gdk_window_set_background (tree_view->priv->bin_window, &widget->style->base[widget->state]); gtk_style_set_background (widget->style, tree_view->priv->header_window, GTK_STATE_NORMAL); + for (i = 0; i < 5 ; ++i) + { + g_object_unref (priv->grid_line_gc[i]); + priv->grid_line_gc[i] = gdk_gc_new (widget->window); + gdk_gc_copy (priv->grid_line_gc[i], widget->style->text_aa_gc[i]); + } pspp_sheet_view_set_grid_lines (tree_view, tree_view->priv->grid_lines); } @@ -6867,6 +6988,7 @@ pspp_sheet_view_real_move_cursor (PsppSheetView *tree_view, GtkMovementStep step, gint count) { + PsppSheetSelectMode mode; GdkModifierType state; g_return_val_if_fail (PSPP_IS_SHEET_VIEW (tree_view), FALSE); @@ -6874,7 +6996,8 @@ pspp_sheet_view_real_move_cursor (PsppSheetView *tree_view, step == GTK_MOVEMENT_VISUAL_POSITIONS || step == GTK_MOVEMENT_DISPLAY_LINES || step == GTK_MOVEMENT_PAGES || - step == GTK_MOVEMENT_BUFFER_ENDS, FALSE); + step == GTK_MOVEMENT_BUFFER_ENDS || + step == GTK_MOVEMENT_DISPLAY_LINE_ENDS, FALSE); if (tree_view->priv->row_count == 0) return FALSE; @@ -6885,38 +7008,40 @@ pspp_sheet_view_real_move_cursor (PsppSheetView *tree_view, PSPP_SHEET_VIEW_SET_FLAG (tree_view, PSPP_SHEET_VIEW_DRAW_KEYFOCUS); gtk_widget_grab_focus (GTK_WIDGET (tree_view)); + mode = 0; if (gtk_get_current_event_state (&state)) { if ((state & GDK_CONTROL_MASK) == GDK_CONTROL_MASK) - tree_view->priv->ctrl_pressed = TRUE; + mode |= PSPP_SHEET_SELECT_MODE_TOGGLE; if ((state & GDK_SHIFT_MASK) == GDK_SHIFT_MASK) - tree_view->priv->shift_pressed = TRUE; + mode |= PSPP_SHEET_SELECT_MODE_EXTEND; } /* else we assume not pressed */ switch (step) { - /* currently we make no distinction. When we go bi-di, we need to */ case GTK_MOVEMENT_LOGICAL_POSITIONS: + pspp_sheet_view_move_cursor_tab (tree_view, count); + break; case GTK_MOVEMENT_VISUAL_POSITIONS: - pspp_sheet_view_move_cursor_left_right (tree_view, count); + pspp_sheet_view_move_cursor_left_right (tree_view, count, mode); break; case GTK_MOVEMENT_DISPLAY_LINES: - pspp_sheet_view_move_cursor_up_down (tree_view, count); + pspp_sheet_view_move_cursor_up_down (tree_view, count, mode); break; case GTK_MOVEMENT_PAGES: - pspp_sheet_view_move_cursor_page_up_down (tree_view, count); + pspp_sheet_view_move_cursor_page_up_down (tree_view, count, mode); break; case GTK_MOVEMENT_BUFFER_ENDS: - pspp_sheet_view_move_cursor_start_end (tree_view, count); + pspp_sheet_view_move_cursor_start_end (tree_view, count, mode); + break; + case GTK_MOVEMENT_DISPLAY_LINE_ENDS: + pspp_sheet_view_move_cursor_line_start_end (tree_view, count, mode); break; default: g_assert_not_reached (); } - tree_view->priv->ctrl_pressed = FALSE; - tree_view->priv->shift_pressed = FALSE; - return TRUE; } @@ -7682,9 +7807,9 @@ pspp_sheet_view_focus_to_cursor (PsppSheetView *tree_view) { if (tree_view->priv->selection->type == PSPP_SHEET_SELECTION_MULTIPLE || tree_view->priv->selection->type == PSPP_SHEET_SELECTION_RECTANGLE) - pspp_sheet_view_real_set_cursor (tree_view, cursor_path, FALSE, FALSE); + pspp_sheet_view_real_set_cursor (tree_view, cursor_path, FALSE, FALSE, 0); else - pspp_sheet_view_real_set_cursor (tree_view, cursor_path, TRUE, FALSE); + pspp_sheet_view_real_set_cursor (tree_view, cursor_path, TRUE, FALSE, 0); } } @@ -7714,9 +7839,10 @@ pspp_sheet_view_focus_to_cursor (PsppSheetView *tree_view) } } -static void +static gboolean pspp_sheet_view_move_cursor_up_down (PsppSheetView *tree_view, - gint count) + gint count, + PsppSheetSelectMode mode) { gint selection_count; int cursor_node = -1; @@ -7725,25 +7851,25 @@ pspp_sheet_view_move_cursor_up_down (PsppSheetView *tree_view, gboolean grab_focus = TRUE; if (! gtk_widget_has_focus (GTK_WIDGET (tree_view))) - return; + return FALSE; cursor_path = NULL; if (!gtk_tree_row_reference_valid (tree_view->priv->cursor)) /* FIXME: we lost the cursor; should we get the first? */ - return; + return FALSE; cursor_path = gtk_tree_row_reference_get_path (tree_view->priv->cursor); _pspp_sheet_view_find_node (tree_view, cursor_path, &cursor_node); if (cursor_node < 0) /* FIXME: we lost the cursor; should we get the first? */ - return; + return FALSE; selection_count = pspp_sheet_selection_count_selected_rows (tree_view->priv->selection); if (selection_count == 0 && tree_view->priv->selection->type != PSPP_SHEET_SELECTION_NONE - && !tree_view->priv->ctrl_pressed) + && !(mode & PSPP_SHEET_SELECT_MODE_TOGGLE)) { /* Don't move the cursor, but just select the current node */ new_cursor_node = cursor_node; @@ -7797,14 +7923,14 @@ pspp_sheet_view_move_cursor_up_down (PsppSheetView *tree_view, if (new_cursor_node >= 0) { cursor_path = _pspp_sheet_view_find_path (tree_view, new_cursor_node); - pspp_sheet_view_real_set_cursor (tree_view, cursor_path, TRUE, TRUE); + pspp_sheet_view_real_set_cursor (tree_view, cursor_path, TRUE, TRUE, mode); gtk_tree_path_free (cursor_path); } else { pspp_sheet_view_clamp_node_visible (tree_view, cursor_node); - if (!tree_view->priv->shift_pressed) + if (!(mode & PSPP_SHEET_SELECT_MODE_EXTEND)) { if (! gtk_widget_keynav_failed (GTK_WIDGET (tree_view), count < 0 ? @@ -7829,11 +7955,14 @@ pspp_sheet_view_move_cursor_up_down (PsppSheetView *tree_view, if (grab_focus) gtk_widget_grab_focus (GTK_WIDGET (tree_view)); + + return new_cursor_node >= 0; } static void pspp_sheet_view_move_cursor_page_up_down (PsppSheetView *tree_view, - gint count) + gint count, + PsppSheetSelectMode mode) { int cursor_node = -1; GtkTreePath *old_cursor_path = NULL; @@ -7907,7 +8036,7 @@ pspp_sheet_view_move_cursor_page_up_down (PsppSheetView *tree_view, /* update y */ y = pspp_sheet_view_node_find_offset (tree_view, cursor_node); - pspp_sheet_view_real_set_cursor (tree_view, cursor_path, TRUE, FALSE); + pspp_sheet_view_real_set_cursor (tree_view, cursor_path, TRUE, FALSE, mode); y -= window_y; pspp_sheet_view_scroll_to_point (tree_view, -1, y); @@ -7926,7 +8055,8 @@ cleanup: static void pspp_sheet_view_move_cursor_left_right (PsppSheetView *tree_view, - gint count) + gint count, + PsppSheetSelectMode mode) { int cursor_node = -1; GtkTreePath *cursor_path = NULL; @@ -7971,7 +8101,7 @@ pspp_sheet_view_move_cursor_left_right (PsppSheetView *tree_view, gboolean left, right; column = list->data; - if (column->visible == FALSE) + if (column->visible == FALSE || column->row_head) goto loop_end; pspp_sheet_view_column_cell_set_cell_data (column, @@ -8017,9 +8147,209 @@ pspp_sheet_view_move_cursor_left_right (PsppSheetView *tree_view, tree_view->priv->focus_column, TRUE); } +static void +pspp_sheet_view_move_cursor_line_start_end (PsppSheetView *tree_view, + gint count, + PsppSheetSelectMode mode) +{ + int cursor_node = -1; + GtkTreePath *cursor_path = NULL; + PsppSheetViewColumn *column; + PsppSheetViewColumn *found_column; + GtkTreeIter iter; + GList *list; + gboolean rtl; + + rtl = (gtk_widget_get_direction (GTK_WIDGET (tree_view)) == GTK_TEXT_DIR_RTL); + + if (!gtk_widget_has_focus (GTK_WIDGET (tree_view))) + return; + + if (gtk_tree_row_reference_valid (tree_view->priv->cursor)) + cursor_path = gtk_tree_row_reference_get_path (tree_view->priv->cursor); + else + return; + + _pspp_sheet_view_find_node (tree_view, cursor_path, &cursor_node); + if (cursor_node < 0) + return; + if (gtk_tree_model_get_iter (tree_view->priv->model, &iter, cursor_path) == FALSE) + { + gtk_tree_path_free (cursor_path); + return; + } + gtk_tree_path_free (cursor_path); + + list = rtl ? g_list_last (tree_view->priv->columns) : g_list_first (tree_view->priv->columns); + if (tree_view->priv->focus_column) + { + for (; list; list = (rtl ? list->prev : list->next)) + { + if (list->data == tree_view->priv->focus_column) + break; + } + } + + found_column = NULL; + while (list) + { + gboolean left, right; + + column = list->data; + if (column->visible == FALSE || column->row_head) + goto loop_end; + + pspp_sheet_view_column_cell_set_cell_data (column, + tree_view->priv->model, + &iter); + + if (rtl) + { + right = list->prev ? TRUE : FALSE; + left = list->next ? TRUE : FALSE; + } + else + { + left = list->prev ? TRUE : FALSE; + right = list->next ? TRUE : FALSE; + } + + if (column->tabbable + && _pspp_sheet_view_column_cell_focus (column, count, left, right)) + found_column = column; + + loop_end: + if (count == 1) + list = rtl ? list->prev : list->next; + else + list = rtl ? list->next : list->prev; + } + + if (found_column) + { + tree_view->priv->focus_column = found_column; + _pspp_sheet_view_queue_draw_node (tree_view, cursor_node, NULL); + g_signal_emit (tree_view, tree_view_signals[CURSOR_CHANGED], 0); + gtk_widget_grab_focus (GTK_WIDGET (tree_view)); + } + + pspp_sheet_view_clamp_column_visible (tree_view, + tree_view->priv->focus_column, TRUE); +} + +static gboolean +try_move_cursor_tab (PsppSheetView *tree_view, + gboolean start_at_focus_column, + gint count) +{ + PsppSheetViewColumn *column; + GtkTreeIter iter; + int cursor_node = -1; + GtkTreePath *cursor_path = NULL; + gboolean rtl; + GList *list; + + if (gtk_tree_row_reference_valid (tree_view->priv->cursor)) + cursor_path = gtk_tree_row_reference_get_path (tree_view->priv->cursor); + else + return TRUE; + + _pspp_sheet_view_find_node (tree_view, cursor_path, &cursor_node); + if (cursor_node < 0) + return TRUE; + if (gtk_tree_model_get_iter (tree_view->priv->model, &iter, cursor_path) == FALSE) + { + gtk_tree_path_free (cursor_path); + return TRUE; + } + gtk_tree_path_free (cursor_path); + + rtl = gtk_widget_get_direction (GTK_WIDGET (tree_view)) == GTK_TEXT_DIR_RTL; + if (start_at_focus_column) + { + list = (rtl + ? g_list_last (tree_view->priv->columns) + : g_list_first (tree_view->priv->columns)); + if (tree_view->priv->focus_column) + { + for (; list; list = (rtl ? list->prev : list->next)) + { + if (list->data == tree_view->priv->focus_column) + break; + } + } + } + else + { + list = (rtl ^ (count == 1) + ? g_list_first (tree_view->priv->columns) + : g_list_last (tree_view->priv->columns)); + } + + while (list) + { + gboolean left, right; + + column = list->data; + if (column->visible == FALSE || !column->tabbable) + goto loop_end; + + pspp_sheet_view_column_cell_set_cell_data (column, + tree_view->priv->model, + &iter); + + if (rtl) + { + right = list->prev ? TRUE : FALSE; + left = list->next ? TRUE : FALSE; + } + else + { + left = list->prev ? TRUE : FALSE; + right = list->next ? TRUE : FALSE; + } + + if (column->tabbable + && _pspp_sheet_view_column_cell_focus (column, count, left, right)) + { + tree_view->priv->focus_column = column; + _pspp_sheet_view_queue_draw_node (tree_view, cursor_node, NULL); + g_signal_emit (tree_view, tree_view_signals[CURSOR_CHANGED], 0); + gtk_widget_grab_focus (GTK_WIDGET (tree_view)); + return TRUE; + } + loop_end: + if (count == 1) + list = rtl ? list->prev : list->next; + else + list = rtl ? list->next : list->prev; + } + + return FALSE; +} + +static void +pspp_sheet_view_move_cursor_tab (PsppSheetView *tree_view, + gint count) +{ + if (!gtk_widget_has_focus (GTK_WIDGET (tree_view))) + return; + + if (!try_move_cursor_tab (tree_view, TRUE, count)) + { + if (pspp_sheet_view_move_cursor_up_down (tree_view, count, 0) + && !try_move_cursor_tab (tree_view, FALSE, count)) + gtk_widget_error_bell (GTK_WIDGET (tree_view)); + } + + pspp_sheet_view_clamp_column_visible (tree_view, + tree_view->priv->focus_column, TRUE); +} + static void pspp_sheet_view_move_cursor_start_end (PsppSheetView *tree_view, - gint count) + gint count, + PsppSheetSelectMode mode) { int cursor_node; GtkTreePath *path; @@ -8052,7 +8382,7 @@ pspp_sheet_view_move_cursor_start_end (PsppSheetView *tree_view, if (gtk_tree_path_compare (old_path, path)) { - pspp_sheet_view_real_set_cursor (tree_view, path, TRUE, TRUE); + pspp_sheet_view_real_set_cursor (tree_view, path, TRUE, TRUE, mode); gtk_widget_grab_focus (GTK_WIDGET (tree_view)); } else @@ -8097,12 +8427,12 @@ pspp_sheet_view_real_unselect_all (PsppSheetView *tree_view) static gboolean pspp_sheet_view_real_select_cursor_row (PsppSheetView *tree_view, - gboolean start_editing) + gboolean start_editing, + PsppSheetSelectMode mode) { int new_node = -1; int cursor_node = -1; GtkTreePath *cursor_path = NULL; - GtkTreeSelectMode mode = 0; if (!gtk_widget_has_focus (GTK_WIDGET (tree_view))) return FALSE; @@ -8122,7 +8452,7 @@ pspp_sheet_view_real_select_cursor_row (PsppSheetView *tree_view, return FALSE; } - if (!tree_view->priv->shift_pressed && start_editing && + if (!(mode & PSPP_SHEET_SELECT_MODE_EXTEND) && start_editing && tree_view->priv->focus_column) { if (pspp_sheet_view_start_editing (tree_view, cursor_path)) @@ -8132,11 +8462,6 @@ pspp_sheet_view_real_select_cursor_row (PsppSheetView *tree_view, } } - if (tree_view->priv->ctrl_pressed) - mode |= GTK_TREE_SELECT_MODE_TOGGLE; - if (tree_view->priv->shift_pressed) - mode |= GTK_TREE_SELECT_MODE_EXTEND; - _pspp_sheet_selection_internal_select_node (tree_view->priv->selection, cursor_node, cursor_path, @@ -8157,7 +8482,7 @@ pspp_sheet_view_real_select_cursor_row (PsppSheetView *tree_view, gtk_widget_grab_focus (GTK_WIDGET (tree_view)); _pspp_sheet_view_queue_draw_node (tree_view, cursor_node, NULL); - if (!tree_view->priv->shift_pressed) + if (!(mode & PSPP_SHEET_SELECT_MODE_EXTEND)) pspp_sheet_view_row_activated (tree_view, cursor_path, tree_view->priv->focus_column); @@ -8193,7 +8518,7 @@ pspp_sheet_view_real_toggle_cursor_row (PsppSheetView *tree_view) _pspp_sheet_selection_internal_select_node (tree_view->priv->selection, cursor_node, cursor_path, - GTK_TREE_SELECT_MODE_TOGGLE, + PSPP_SHEET_SELECT_MODE_TOGGLE, FALSE); /* We bail out if the original (tree, node) don't exist anymore after @@ -8233,9 +8558,9 @@ send_focus_change (GtkWidget *widget, g_object_ref (widget); if (in) - GTK_WIDGET_SET_FLAGS (widget, GTK_HAS_FOCUS); - else - GTK_WIDGET_UNSET_FLAGS (widget, GTK_HAS_FOCUS); + GTK_WIDGET_SET_FLAGS (widget, GTK_HAS_FOCUS); + else + GTK_WIDGET_UNSET_FLAGS (widget, GTK_HAS_FOCUS); fevent->focus_change.type = GDK_FOCUS_CHANGE; fevent->focus_change.window = g_object_ref (widget->window); @@ -8727,7 +9052,6 @@ pspp_sheet_view_set_model (PsppSheetView *tree_view, if (tree_view->priv->model) { gint i; - GtkTreeModelFlags flags; if (tree_view->priv->search_column == -1) { @@ -8761,8 +9085,6 @@ pspp_sheet_view_set_model (PsppSheetView *tree_view, G_CALLBACK (pspp_sheet_view_rows_reordered), tree_view); - flags = gtk_tree_model_get_flags (tree_view->priv->model); - tree_view->priv->row_count = gtk_tree_model_iter_n_children (tree_view->priv->model, NULL); /* FIXME: do I need to do this? pspp_sheet_view_create_buttons (tree_view); */ @@ -9151,7 +9473,8 @@ pspp_sheet_view_remove_column (PsppSheetView *tree_view, } if (tree_view->priv->n_columns == 0 && - pspp_sheet_view_get_headers_visible (tree_view)) + pspp_sheet_view_get_headers_visible (tree_view) && + tree_view->priv->header_window) gdk_window_hide (tree_view->priv->header_window); gtk_widget_queue_resize (GTK_WIDGET (tree_view)); @@ -9697,7 +10020,8 @@ static void pspp_sheet_view_real_set_cursor (PsppSheetView *tree_view, GtkTreePath *path, gboolean clear_and_select, - gboolean clamp_node) + gboolean clamp_node, + PsppSheetSelectMode mode) { int node = -1; @@ -9722,19 +10046,10 @@ pspp_sheet_view_real_set_cursor (PsppSheetView *tree_view, { int new_node = -1; - if (clear_and_select && !tree_view->priv->ctrl_pressed) - { - GtkTreeSelectMode mode = 0; - - if (tree_view->priv->ctrl_pressed) - mode |= GTK_TREE_SELECT_MODE_TOGGLE; - if (tree_view->priv->shift_pressed) - mode |= GTK_TREE_SELECT_MODE_EXTEND; - - _pspp_sheet_selection_internal_select_node (tree_view->priv->selection, + if (clear_and_select && !(mode & PSPP_SHEET_SELECT_MODE_TOGGLE)) + _pspp_sheet_selection_internal_select_node (tree_view->priv->selection, node, path, mode, FALSE); - } /* We have to re-find tree and node here again, somebody might have * cleared the node or the whole tree in the PsppSheetSelection::changed @@ -9868,7 +10183,7 @@ pspp_sheet_view_set_cursor_on_cell (PsppSheetView *tree_view, tree_view->priv->edited_column->editable_widget) pspp_sheet_view_stop_editing (tree_view, TRUE); - pspp_sheet_view_real_set_cursor (tree_view, path, TRUE, TRUE); + pspp_sheet_view_real_set_cursor (tree_view, path, TRUE, TRUE, 0); if (focus_column && focus_column->visible) { @@ -10966,7 +11281,6 @@ pspp_sheet_view_create_row_drag_icon (PsppSheetView *tree_view, GdkRectangle background_area; GdkRectangle expose_area; GtkWidget *widget; - gint depth; /* start drawing inside the black outline */ gint x = 1, y = 1; GdkDrawable *drawable; @@ -10981,8 +11295,6 @@ pspp_sheet_view_create_row_drag_icon (PsppSheetView *tree_view, if (!gtk_widget_get_realized (widget)) return NULL; - depth = gtk_tree_path_get_depth (path); - _pspp_sheet_view_find_node (tree_view, path, &node); @@ -11791,7 +12103,7 @@ pspp_sheet_view_search_iter (GtkTreeModel *model, pspp_sheet_view_scroll_to_cell (tree_view, path, NULL, TRUE, 0.5, 0.0); pspp_sheet_selection_select_iter (selection, iter); - pspp_sheet_view_real_set_cursor (tree_view, path, FALSE, TRUE); + pspp_sheet_view_real_set_cursor (tree_view, path, FALSE, TRUE, 0); if (path) gtk_tree_path_free (path); @@ -12005,6 +12317,185 @@ pspp_sheet_view_editable_clicked (GtkButton *button, sheet_view); } +static gboolean +is_all_selected (GtkWidget *widget) +{ + GtkEntryBuffer *buffer; + gint start_pos, end_pos; + + if (!GTK_IS_ENTRY (widget)) + return FALSE; + + buffer = gtk_entry_get_buffer (GTK_ENTRY (widget)); + return (gtk_editable_get_selection_bounds (GTK_EDITABLE (widget), + &start_pos, &end_pos) + && start_pos == 0 + && end_pos == gtk_entry_buffer_get_length (buffer)); +} + +static gboolean +is_at_left (GtkWidget *widget) +{ + return (GTK_IS_ENTRY (widget) + && gtk_editable_get_position (GTK_EDITABLE (widget)) == 0); +} + +static gboolean +is_at_right (GtkWidget *widget) +{ + GtkEntryBuffer *buffer; + gint length; + + if (!GTK_IS_ENTRY (widget)) + return FALSE; + + buffer = gtk_entry_get_buffer (GTK_ENTRY (widget)); + length = gtk_entry_buffer_get_length (buffer); + return gtk_editable_get_position (GTK_EDITABLE (widget)) == length; +} + +static gboolean +pspp_sheet_view_event (GtkWidget *widget, + GdkEventKey *event, + PsppSheetView *tree_view) +{ + PsppSheetViewColumn *column; + GtkTreePath *path; + gboolean handled; + gboolean cancel; + guint keyval; + gint row; + + /* Intercept only key press events. + It would make sense to use "key-press-event" instead of "event", but + GtkEntry attaches its own signal handler to "key-press-event" that runs + before ours and overrides our desired behavior for GDK_Up and GDK_Down. + */ + if (event->type != GDK_KEY_PRESS) + return FALSE; + + keyval = event->keyval; + cancel = FALSE; + switch (event->state & (GDK_CONTROL_MASK | GDK_SHIFT_MASK | GDK_MOD1_MASK)) + { + case 0: + switch (event->keyval) + { + case GDK_Left: case GDK_KP_Left: + case GDK_Home: case GDK_KP_Home: + if (!is_all_selected (widget) && !is_at_left (widget)) + return FALSE; + break; + + case GDK_Right: case GDK_KP_Right: + case GDK_End: case GDK_KP_End: + if (!is_all_selected (widget) && !is_at_right (widget)) + return FALSE; + break; + + case GDK_Up: case GDK_KP_Up: + case GDK_Down: case GDK_KP_Down: + break; + + case GDK_Page_Up: case GDK_KP_Page_Up: + case GDK_Page_Down: case GDK_KP_Page_Down: + break; + + case GDK_Escape: + cancel = TRUE; + break; + + case GDK_Return: + keyval = GDK_Down; + break; + + case GDK_Tab: case GDK_KP_Tab: + case GDK_ISO_Left_Tab: + keyval = GDK_Tab; + break; + + default: + return FALSE; + } + break; + + case GDK_SHIFT_MASK: + switch (event->keyval) + { + case GDK_Tab: + case GDK_ISO_Left_Tab: + keyval = GDK_Tab; + break; + + default: + return FALSE; + } + break; + + case GDK_CONTROL_MASK: + switch (event->keyval) + { + case GDK_Left: case GDK_KP_Left: + if (!is_all_selected (widget) && !is_at_left (widget)) + return FALSE; + break; + + case GDK_Right: case GDK_KP_Right: + if (!is_all_selected (widget) && !is_at_right (widget)) + return FALSE; + break; + + case GDK_Up: case GDK_KP_Up: + case GDK_Down: case GDK_KP_Down: + break; + + default: + return FALSE; + } + break; + + default: + return FALSE; + } + + row = tree_view->priv->edited_row; + column = tree_view->priv->edited_column; + path = gtk_tree_path_new_from_indices (row, -1); + + pspp_sheet_view_stop_editing (tree_view, cancel); + gtk_widget_grab_focus (GTK_WIDGET (tree_view)); + + pspp_sheet_view_set_cursor (tree_view, path, column, FALSE); + gtk_tree_path_free (path); + + handled = gtk_binding_set_activate (edit_bindings, keyval, event->state, + GTK_OBJECT (tree_view)); + if (handled) + g_signal_stop_emission_by_name (widget, "event"); + + pspp_sheet_view_get_cursor (tree_view, &path, NULL); + pspp_sheet_view_start_editing (tree_view, path); + gtk_tree_path_free (path); + + return handled; +} + +static void +pspp_sheet_view_override_cell_keypresses (GtkWidget *widget, + gpointer data) +{ + PsppSheetView *sheet_view = data; + + g_signal_connect (widget, "event", + G_CALLBACK (pspp_sheet_view_event), + sheet_view); + + if (GTK_IS_CONTAINER (widget)) + gtk_container_foreach (GTK_CONTAINER (widget), + pspp_sheet_view_override_cell_keypresses, + data); +} + static void pspp_sheet_view_real_start_editing (PsppSheetView *tree_view, PsppSheetViewColumn *column, @@ -12017,11 +12508,16 @@ pspp_sheet_view_real_start_editing (PsppSheetView *tree_view, PsppSheetSelectionMode mode = pspp_sheet_selection_get_mode (tree_view->priv->selection); gint pre_val = tree_view->priv->vadjustment->value; GtkRequisition requisition; + gint row; + + g_return_if_fail (gtk_tree_path_get_depth (path) == 1); tree_view->priv->edited_column = column; _pspp_sheet_view_column_start_editing (column, GTK_CELL_EDITABLE (cell_editable)); - pspp_sheet_view_real_set_cursor (tree_view, path, FALSE, TRUE); + row = gtk_tree_path_get_indices (path)[0]; + tree_view->priv->edited_row = row; + pspp_sheet_view_real_set_cursor (tree_view, path, FALSE, TRUE, 0); cell_area->y += pre_val - (int)tree_view->priv->vadjustment->value; pspp_sheet_selection_unselect_all_columns (tree_view->priv->selection); @@ -12061,11 +12557,14 @@ pspp_sheet_view_real_start_editing (PsppSheetView *tree_view, G_CALLBACK (pspp_sheet_view_editable_button_press_event), tree_view); g_object_set_data (G_OBJECT (cell_editable), "pspp-sheet-view-node", - GINT_TO_POINTER (gtk_tree_path_get_indices (path)[0])); + GINT_TO_POINTER (row)); g_signal_connect (cell_editable, "clicked", G_CALLBACK (pspp_sheet_view_editable_clicked), tree_view); } + + pspp_sheet_view_override_cell_keypresses (GTK_WIDGET (cell_editable), + tree_view); } void @@ -12279,40 +12778,15 @@ pspp_sheet_view_set_grid_lines (PsppSheetView *tree_view, PsppSheetViewGridLines grid_lines) { PsppSheetViewPrivate *priv; - GtkWidget *widget; PsppSheetViewGridLines old_grid_lines; g_return_if_fail (PSPP_IS_SHEET_VIEW (tree_view)); priv = tree_view->priv; - widget = GTK_WIDGET (tree_view); old_grid_lines = priv->grid_lines; priv->grid_lines = grid_lines; - if (gtk_widget_get_realized (widget)) - { - if (grid_lines == PSPP_SHEET_VIEW_GRID_LINES_NONE && - priv->grid_line_gc) - { - g_object_unref (priv->grid_line_gc); - priv->grid_line_gc = NULL; - } - - if (grid_lines != PSPP_SHEET_VIEW_GRID_LINES_NONE && - !priv->grid_line_gc) - { - gint line_width; - - gtk_widget_style_get (widget, - "grid-line-width", &line_width, - NULL); - - priv->grid_line_gc = gdk_gc_new (widget->window); - gdk_gc_copy (priv->grid_line_gc, widget->style->black_gc); - } - } - if (old_grid_lines != grid_lines) { gtk_widget_queue_draw (GTK_WIDGET (tree_view)); @@ -12352,12 +12826,10 @@ pspp_sheet_view_set_special_cells (PsppSheetView *tree_view, PsppSheetViewSpecialCells special_cells) { PsppSheetViewPrivate *priv; - GtkWidget *widget; g_return_if_fail (PSPP_IS_SHEET_VIEW (tree_view)); priv = tree_view->priv; - widget = GTK_WIDGET (tree_view); if (priv->special_cells != special_cells) { @@ -12367,6 +12839,31 @@ pspp_sheet_view_set_special_cells (PsppSheetView *tree_view, } } +int +pspp_sheet_view_get_fixed_height (const PsppSheetView *tree_view) +{ + /* XXX (re)calculate fixed_height if necessary */ + return tree_view->priv->fixed_height; +} + +void +pspp_sheet_view_set_fixed_height (PsppSheetView *tree_view, + int fixed_height) +{ + g_return_if_fail (fixed_height > 0); + + if (tree_view->priv->fixed_height != fixed_height) + { + tree_view->priv->fixed_height = fixed_height; + g_object_notify (G_OBJECT (tree_view), "fixed-height"); + } + if (!tree_view->priv->fixed_height_set) + { + tree_view->priv->fixed_height_set = TRUE; + g_object_notify (G_OBJECT (tree_view), "fixed-height-set"); + } +} + /** * pspp_sheet_view_set_tooltip_row: * @tree_view: a #PsppSheetView