From 731df357f8b7064c82c264b899ce784bf19320bf Mon Sep 17 00:00:00 2001 From: Ben Pfaff Date: Wed, 24 Oct 2012 23:24:25 -0700 Subject: [PATCH] gui: Make Tab, Shift+Tab skip row head and new-var columns in data sheet. Before this commit, Tab and Shift+Tab acted just like Left and Right in the data sheet, that is, they visit every column except the row head column and always stay on the same row. After this commit, Tab and Shift+Tab skip the row head and new-variable columns. Also, Tab at the end of a row goes to the beginning of the next row, and Shift+Tab at the beginning of a row goes to the end of the previous row. Suggested by John Darrington. --- src/ui/gui/pspp-sheet-view-column.c | 60 +++++++++++- src/ui/gui/pspp-sheet-view-column.h | 6 +- src/ui/gui/pspp-sheet-view.c | 137 ++++++++++++++++++++++++++-- src/ui/gui/psppire-data-sheet.c | 2 + 4 files changed, 195 insertions(+), 10 deletions(-) diff --git a/src/ui/gui/pspp-sheet-view-column.c b/src/ui/gui/pspp-sheet-view-column.c index c586a4bdae..a8d9f48918 100644 --- a/src/ui/gui/pspp-sheet-view-column.c +++ b/src/ui/gui/pspp-sheet-view-column.c @@ -72,7 +72,8 @@ enum PROP_QUICK_EDIT, PROP_SELECTED, PROP_SELECTABLE, - PROP_ROW_HEAD + PROP_ROW_HEAD, + PROP_TABBABLE }; enum @@ -426,6 +427,14 @@ pspp_sheet_view_column_class_init (PsppSheetViewColumnClass *class) P_("If true, this column is a \"row head\", equivalent to a column head. If rectangular selection is enabled, then shift+click and control+click in the column select row ranges and toggle row selection, respectively. The column should ordinarily include a button cell; clicking on the button will select the row (and deselect all other rows)."), FALSE, GTK_PARAM_READWRITE)); + + g_object_class_install_property (object_class, + PROP_TABBABLE, + g_param_spec_boolean ("tabbable", + P_("Tabbable"), + P_("If true, Tab and Shift+Tab visit this column. If false, Tab and Shift+Tab skip this column."), + TRUE, + GTK_PARAM_READWRITE)); } static void @@ -468,6 +477,7 @@ pspp_sheet_view_column_init (PsppSheetViewColumn *tree_column) tree_column->selected = FALSE; tree_column->selectable = TRUE; tree_column->row_head = FALSE; + tree_column->tabbable = TRUE; tree_column->sort_order = GTK_SORT_ASCENDING; tree_column->show_sort_indicator = FALSE; tree_column->property_changed_signal = 0; @@ -621,6 +631,11 @@ pspp_sheet_view_column_set_property (GObject *object, g_value_get_boolean (value)); break; + case PROP_TABBABLE: + pspp_sheet_view_column_set_tabbable (tree_column, + g_value_get_boolean (value)); + break; + default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; @@ -739,6 +754,11 @@ pspp_sheet_view_column_get_property (GObject *object, pspp_sheet_view_column_get_row_head (tree_column)); break; + case PROP_TABBABLE: + g_value_set_boolean (value, + pspp_sheet_view_column_get_tabbable (tree_column)); + break; + default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; @@ -2741,6 +2761,44 @@ pspp_sheet_view_column_get_row_head (PsppSheetViewColumn *tree_column) } +/** + * pspp_sheet_view_column_set_tabbable: + * @tree_column: A #PsppSheetViewColumn + * @tabbable: If true, the column is "tabbable", meaning that Tab and Shift+Tab + * in the sheet visit this column. If false, Tab and Shift+Tab skip this + * column. + **/ +void +pspp_sheet_view_column_set_tabbable (PsppSheetViewColumn *tree_column, + gboolean tabbable) +{ + g_return_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (tree_column)); + + tabbable = !!tabbable; + if (tree_column->tabbable != tabbable) + { + tree_column->tabbable = tabbable; + g_object_notify (G_OBJECT (tree_column), "tabbable"); + } +} + +/** + * pspp_sheet_view_column_get_tabbable: + * @tree_column: A #PsppSheetViewColumn + * + * Returns %TRUE if the column is tabbable. + * + * Return value: %TRUE if the column is tabbable. + **/ +gboolean +pspp_sheet_view_column_get_tabbable (PsppSheetViewColumn *tree_column) +{ + g_return_val_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (tree_column), FALSE); + + return tree_column->tabbable; +} + + /** * pspp_sheet_view_column_set_sort_column_id: * @tree_column: a #PsppSheetViewColumn diff --git a/src/ui/gui/pspp-sheet-view-column.h b/src/ui/gui/pspp-sheet-view-column.h index 743440f682..f18fee1d10 100644 --- a/src/ui/gui/pspp-sheet-view-column.h +++ b/src/ui/gui/pspp-sheet-view-column.h @@ -1,5 +1,5 @@ /* PSPPIRE - a graphical user interface for PSPP. - Copyright (C) 2011 Free Software Foundation, Inc. + Copyright (C) 2011, 2012 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 @@ -110,6 +110,7 @@ struct _PsppSheetViewColumn guint GSEAL (selected) : 1; guint GSEAL (selectable) : 1; guint GSEAL (row_head) : 1; + guint GSEAL (tabbable) : 1; guint GSEAL (need_button) : 1; }; @@ -214,6 +215,9 @@ gboolean pspp_sheet_view_column_get_selectable (PsppSheetView void pspp_sheet_view_column_set_row_head (PsppSheetViewColumn *tree_column, gboolean row_head); gboolean pspp_sheet_view_column_get_row_head (PsppSheetViewColumn *tree_column); +void pspp_sheet_view_column_set_tabbable (PsppSheetViewColumn *tree_column, + gboolean tabbable); +gboolean pspp_sheet_view_column_get_tabbable (PsppSheetViewColumn *tree_column); diff --git a/src/ui/gui/pspp-sheet-view.c b/src/ui/gui/pspp-sheet-view.c index 32627beffd..c06abeb2a6 100644 --- a/src/ui/gui/pspp-sheet-view.c +++ b/src/ui/gui/pspp-sheet-view.c @@ -315,12 +315,14 @@ 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, +static gboolean pspp_sheet_view_move_cursor_up_down (PsppSheetView *tree_view, gint count); static void pspp_sheet_view_move_cursor_page_up_down (PsppSheetView *tree_view, gint count); static void pspp_sheet_view_move_cursor_left_right (PsppSheetView *tree_view, gint count); +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); static void pspp_sheet_view_real_set_cursor (PsppSheetView *tree_view, @@ -921,6 +923,14 @@ pspp_sheet_view_class_init (PsppSheetViewClass *class) 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_VISUAL_POSITIONS, G_TYPE_INT, 1); @@ -6976,8 +6986,9 @@ pspp_sheet_view_real_move_cursor (PsppSheetView *tree_view, 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); break; @@ -7794,7 +7805,7 @@ 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) { @@ -7805,19 +7816,19 @@ 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); @@ -7909,6 +7920,8 @@ 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 @@ -8097,6 +8110,113 @@ pspp_sheet_view_move_cursor_left_right (PsppSheetView *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) + && pspp_sheet_view_move_cursor_up_down (tree_view, count) + && !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) @@ -12181,9 +12301,10 @@ pspp_sheet_view_event (GtkWidget *widget, keyval = GDK_Down; break; - case GDK_Tab: + case GDK_Tab: case GDK_KP_Tab: case GDK_ISO_Left_Tab: - keyval = event->state & GDK_SHIFT_MASK ? GDK_Left : GDK_Right; + keyval = GDK_Tab; + state |= event->state & GDK_SHIFT_MASK; break; default: diff --git a/src/ui/gui/psppire-data-sheet.c b/src/ui/gui/psppire-data-sheet.c index 0ff5974d3d..6714bfb90e 100644 --- a/src/ui/gui/psppire-data-sheet.c +++ b/src/ui/gui/psppire-data-sheet.c @@ -228,6 +228,7 @@ make_row_number_column (PsppireDataSheet *data_sheet, renderer, NULL); pspp_sheet_view_column_set_selectable (column, TRUE); pspp_sheet_view_column_set_row_head (column, TRUE); + pspp_sheet_view_column_set_tabbable (column, FALSE); pspp_sheet_view_column_set_clickable (column, TRUE); pspp_sheet_view_column_set_cell_data_func ( column, renderer, render_row_number_cell, ds, NULL); @@ -757,6 +758,7 @@ make_new_variable_column (PsppireDataSheet *data_sheet, width = display_width_to_pixel_width (data_sheet, 8, base_width, incr_width); pspp_sheet_view_column_set_min_width (column, 10); pspp_sheet_view_column_set_fixed_width (column, width); + pspp_sheet_view_column_set_tabbable (column, FALSE); g_object_set_data (G_OBJECT (cell), "data-sheet", data_sheet); g_signal_connect (column, "button-press-event", -- 2.30.2