From a6644b75fc122fc2e10cfae3c0ee7fad84d9bacb Mon Sep 17 00:00:00 2001 From: Chris Shoemaker Date: Tue, 25 Apr 2006 04:18:45 +0000 Subject: [PATCH] Implement a keynav policy for the budget page. Addresses bug #339515. git-svn-id: svn+ssh://svn.gnucash.org/repo/gnucash/trunk@13847 57a11ea4-9604-0410-9ed3-97b8803252fd --- src/gnome-utils/gnc-tree-view.c | 95 ++++++++++++++++++++++++++++++ src/gnome-utils/gnc-tree-view.h | 13 ++++ src/gnome/gnc-plugin-page-budget.c | 70 ++++++++++++++-------- 3 files changed, 155 insertions(+), 23 deletions(-) diff --git a/src/gnome-utils/gnc-tree-view.c b/src/gnome-utils/gnc-tree-view.c index e60bfeaf62..01129e4d58 100644 --- a/src/gnome-utils/gnc-tree-view.c +++ b/src/gnome-utils/gnc-tree-view.c @@ -35,6 +35,7 @@ #include #include +#include #include #include "gnc-tree-view.h" @@ -2084,4 +2085,98 @@ gnc_tree_view_append_column (GncTreeView *view, return gtk_tree_view_insert_column (GTK_TREE_VIEW(view), column, n); } +static gboolean +get_column_next_to(GtkTreeView *tv, GtkTreeViewColumn **col, gboolean backward) +{ + GList *cols, *node; + GtkTreeViewColumn *c = NULL; + gint seen = 0; + gboolean wrapped = FALSE; + + cols = gtk_tree_view_get_columns(tv); + g_return_val_if_fail(g_list_length(cols) > 0, FALSE); + + node = g_list_find(cols, *col); + g_return_val_if_fail(node, FALSE); + do { + node = backward ? node->prev : node->next; + if (!node) { + wrapped = TRUE; + node = backward ? g_list_last(cols) : cols; + } + c = GTK_TREE_VIEW_COLUMN(node->data); + if (c && gtk_tree_view_column_get_visible(c)) + seen++; + if (c == *col) break; + } while (!seen); + + g_list_free(cols); + *col = c; + return wrapped; +} + +gboolean +gnc_tree_view_path_is_valid(GncTreeView *view, GtkTreePath *path) +{ + GtkTreeView *tv = GTK_TREE_VIEW(view); + GtkTreeModel *s_model; + GtkTreeIter iter; + + s_model = gtk_tree_view_get_model(tv); + return gtk_tree_model_get_iter(s_model, &iter, path); +} + +void +gnc_tree_view_keynav(GncTreeView *view, GtkTreeViewColumn **col, + GtkTreePath *path, GdkEventKey *event) +{ + GtkTreeView *tv = GTK_TREE_VIEW(view); + gint depth; + gboolean shifted; + + if (event->type != GDK_KEY_PRESS) return; + + switch (event->keyval) { + case GDK_Tab: + case GDK_ISO_Left_Tab: + case GDK_KP_Tab: + shifted = event->state & GDK_SHIFT_MASK; + if (get_column_next_to(tv, col, shifted)) { + /* This is the end (or beginning) of the line, buddy. */ + depth = gtk_tree_path_get_depth(path); + if (shifted) { + if (!gtk_tree_path_prev(path) && depth > 1) { + gtk_tree_path_up(path); + } + } else if (gtk_tree_view_row_expanded(tv, path)) { + gtk_tree_path_down(path); + } else { + gtk_tree_path_next(path); + if (!gnc_tree_view_path_is_valid(view, path) && depth > 1) { + gtk_tree_path_prev(path); + gtk_tree_path_up(path); + gtk_tree_path_next(path); + } + } + } + break; + + case GDK_Return: + case GDK_KP_Enter: + if (gtk_tree_view_row_expanded(tv, path)) { + gtk_tree_path_down(path); + } else { + gtk_tree_path_next(path); + if (!gnc_tree_view_path_is_valid(view, path) && depth > 1) { + gtk_tree_path_prev(path); + gtk_tree_path_up(path); + gtk_tree_path_next(path); + } + } + break; + } + return; +} + + /** @} */ diff --git a/src/gnome-utils/gnc-tree-view.h b/src/gnome-utils/gnc-tree-view.h index cef568ce00..b5124c893b 100644 --- a/src/gnome-utils/gnc-tree-view.h +++ b/src/gnome-utils/gnc-tree-view.h @@ -369,6 +369,19 @@ gnc_tree_view_get_show_column_menu (GncTreeView *view); GtkCellRenderer * gnc_tree_view_column_get_renderer(GtkTreeViewColumn *column); + +/* Takes a GdkEventKey and the current path and column for the + * treeview. Interprets the event as something that might move the + * cursor. Returns the new column and the possibly changed (if + * navigation wrapped a row) path. */ +void +gnc_tree_view_keynav(GncTreeView *view, GtkTreeViewColumn **col, + GtkTreePath *path, GdkEventKey *event); + +/* Returns TRUE if path is a vaid path for the treeview */ +gboolean +gnc_tree_view_path_is_valid(GncTreeView *view, GtkTreePath *path); + /** @} */ /** @} */ diff --git a/src/gnome/gnc-plugin-page-budget.c b/src/gnome/gnc-plugin-page-budget.c index cbf4076374..18d436ba90 100644 --- a/src/gnome/gnc-plugin-page-budget.c +++ b/src/gnome/gnc-plugin-page-budget.c @@ -95,12 +95,14 @@ static GncPluginPage *gnc_plugin_page_budget_recreate_page ( GtkWidget *window, GKeyFile *file, const gchar *group); -static gboolean gnc_plugin_page_budget_button_press_cb( +static gboolean gppb_button_press_cb( GtkWidget *widget, GdkEventButton *event, GncPluginPage *page); -static void gnc_plugin_page_budget_double_click_cb( +static gboolean gppb_key_press_cb( + GtkWidget *treeview, GdkEventKey *event, gpointer userdata); +static void gppb_double_click_cb( GtkTreeView *treeview, GtkTreePath *path, GtkTreeViewColumn *col, GncPluginPageBudget *page); -static void gnc_plugin_page_budget_selection_changed_cb( +static void gppb_selection_changed_cb( GtkTreeSelection *selection, GncPluginPageBudget *page); static void gnc_plugin_page_budget_view_refresh (GncPluginPageBudget *page); @@ -394,17 +396,16 @@ gnc_plugin_page_budget_create_widget (GncPluginPage *plugin_page) selection = gtk_tree_view_get_selection(tree_view); gtk_tree_selection_set_mode(selection, GTK_SELECTION_MULTIPLE); - g_signal_connect (G_OBJECT (selection), "changed", - G_CALLBACK (gnc_plugin_page_budget_selection_changed_cb), - plugin_page); - g_signal_connect (G_OBJECT (tree_view), "button-press-event", - G_CALLBACK (gnc_plugin_page_budget_button_press_cb), - plugin_page); - g_signal_connect (G_OBJECT (tree_view), "row-activated", - G_CALLBACK (gnc_plugin_page_budget_double_click_cb), - page); + g_signal_connect(G_OBJECT(selection), "changed", + G_CALLBACK(gppb_selection_changed_cb), plugin_page); + g_signal_connect(G_OBJECT(tree_view), "button-press-event", + G_CALLBACK(gppb_button_press_cb), plugin_page); + g_signal_connect(G_OBJECT(tree_view), "row-activated", + G_CALLBACK(gppb_double_click_cb), page); + g_signal_connect_after(G_OBJECT(tree_view), "key-press-event", + G_CALLBACK(gppb_key_press_cb), NULL); - gnc_plugin_page_budget_selection_changed_cb (NULL, page); + gppb_selection_changed_cb (NULL, page); gtk_tree_view_set_headers_visible(tree_view, TRUE); gtk_widget_show (GTK_WIDGET (tree_view)); gtk_container_add (GTK_CONTAINER (scrolled_window), @@ -564,9 +565,8 @@ gnc_plugin_page_budget_recreate_page (GtkWidget *window, GKeyFile *key_file, * Button presses on all other pages are caught by the signal * registered in gnc-main-window.c. */ static gboolean -gnc_plugin_page_budget_button_press_cb (GtkWidget *widget, - GdkEventButton *event, - GncPluginPage *page) +gppb_button_press_cb(GtkWidget *widget, GdkEventButton *event, + GncPluginPage *page) { gboolean result; @@ -578,11 +578,36 @@ gnc_plugin_page_budget_button_press_cb (GtkWidget *widget, return result; } +static gboolean +gppb_key_press_cb(GtkWidget *treeview, GdkEventKey *event, gpointer userdata) +{ + GtkTreeView *tv = GTK_TREE_VIEW(treeview); + GtkTreeViewColumn *col; + GtkTreePath *path = NULL; + + if (event->type != GDK_KEY_PRESS) return TRUE; + + switch (event->keyval) { + case GDK_Tab: + case GDK_ISO_Left_Tab: + case GDK_KP_Tab: + case GDK_Return: + case GDK_KP_Enter: + gtk_tree_view_get_cursor(tv, &path, &col); + if (!path) return TRUE; + //finish_edit(col); + break; + } + gnc_tree_view_keynav(GNC_TREE_VIEW(tv), &col, path, event); + + if (path && gnc_tree_view_path_is_valid(GNC_TREE_VIEW(tv), path)) + gtk_tree_view_set_cursor(tv, path, col, TRUE); + return TRUE; +} + static void -gnc_plugin_page_budget_double_click_cb (GtkTreeView *treeview, - GtkTreePath *path, - GtkTreeViewColumn *col, - GncPluginPageBudget *page) +gppb_double_click_cb(GtkTreeView *treeview, GtkTreePath *path, + GtkTreeViewColumn *col, GncPluginPageBudget *page) { GtkWidget *window; GncPluginPage *new_page; @@ -600,8 +625,8 @@ gnc_plugin_page_budget_double_click_cb (GtkTreeView *treeview, } static void -gnc_plugin_page_budget_selection_changed_cb (GtkTreeSelection *selection, - GncPluginPageBudget *page) +gppb_selection_changed_cb(GtkTreeSelection *selection, + GncPluginPageBudget *page) { GtkActionGroup *action_group; GtkTreeView *view; @@ -627,7 +652,6 @@ gnc_plugin_page_budget_selection_changed_cb (GtkTreeSelection *selection, gnc_plugin_update_actions (action_group, actions_requiring_account, "sensitive", sensitive); } - /* Command callbacks */