[network-manager-applet] editor: improve navigation in address/route treeview (rh #1201412)



commit b988a2e1c65c05e4b4ce9ae8b71a78609f7f06b5
Author: Jiří Klimeš <jklimes redhat com>
Date:   Tue Mar 17 17:56:41 2015 +0100

    editor: improve navigation in address/route treeview (rh #1201412)
    
    The commit makes these changes:
    * Shift-Tab allows moving backwards (instead of messing up the cells)
    * Up arrow key moves backwards as well
    * Pressing Enter key in the last cell closes the row without cycling to
      the first column
    
    https://bugzilla.redhat.com/show_bug.cgi?id=1201412

 src/connection-editor/ip4-routes-dialog.c |   60 ++++++++++++++++++----------
 src/connection-editor/ip6-routes-dialog.c |   59 ++++++++++++++++++---------
 src/connection-editor/page-ip4.c          |   61 +++++++++++++++++++---------
 src/connection-editor/page-ip6.c          |   61 +++++++++++++++++++---------
 src/utils/utils.c                         |   17 ++++++++
 src/utils/utils.h                         |    2 +
 6 files changed, 179 insertions(+), 81 deletions(-)
---
diff --git a/src/connection-editor/ip4-routes-dialog.c b/src/connection-editor/ip4-routes-dialog.c
index 1d1f271..42e3a6a 100644
--- a/src/connection-editor/ip4-routes-dialog.c
+++ b/src/connection-editor/ip4-routes-dialog.c
@@ -328,6 +328,9 @@ cell_editing_canceled (GtkCellRenderer *renderer, gpointer user_data)
        validate (GTK_WIDGET (gtk_builder_get_object (builder, "ip4_routes_dialog")));
 }
 
+#define DO_NOT_CYCLE_TAG "do-not-cycle"
+#define DIRECTION_TAG    "direction"
+
 static void
 cell_edited (GtkCellRendererText *cell,
              const gchar *path_string,
@@ -342,6 +345,8 @@ cell_edited (GtkCellRendererText *cell,
        guint32 column;
        GtkTreeViewColumn *next_col;
        GtkCellRenderer *next_cell;
+       gboolean can_cycle;
+       int direction, tmp;
 
        /* Free auxiliary stuff */
        g_free (last_edited);
@@ -358,12 +363,22 @@ cell_edited (GtkCellRendererText *cell,
        gtk_tree_model_get_iter (GTK_TREE_MODEL (store), &iter, path);
        gtk_list_store_set (store, &iter, column, new_text, -1);
 
-       /* Move focus to the next column */
-       column = (column >= COL_LAST) ? 0 : column + 1;
+       /* Move focus to the next/previous column */
+       can_cycle = g_object_get_data (G_OBJECT (cell), DO_NOT_CYCLE_TAG) == NULL;
+       direction = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (cell), DIRECTION_TAG));
+       g_object_set_data (G_OBJECT (cell), DIRECTION_TAG, NULL);
+       g_object_set_data (G_OBJECT (cell), DO_NOT_CYCLE_TAG, NULL);
+       if (direction == 0)  /* Move forward by default */
+               direction = 1;
+
+       tmp = column + direction;
+       if (can_cycle)
+               column = tmp < 0 ? COL_LAST : tmp > COL_LAST ? 0 : tmp;
+       else
+               column = tmp;
        next_col = gtk_tree_view_get_column (GTK_TREE_VIEW (widget), column);
        dialog = GTK_WIDGET (gtk_builder_get_object (builder, "ip4_routes_dialog"));
        next_cell = g_slist_nth_data (g_object_get_data (G_OBJECT (dialog), "renderers"), column);
-
        gtk_tree_view_set_cursor_on_cell (GTK_TREE_VIEW (widget), path, next_col, next_cell, TRUE);
 
        gtk_tree_path_free (path);
@@ -481,12 +496,12 @@ cell_changed_cb (GtkEditable *editable,
 }
 
 static gboolean
-key_pressed_cb (GtkWidget *widget,
-                GdkEvent *event,
-                gpointer user_data)
+key_pressed_cb (GtkWidget *widget, GdkEventKey *event, gpointer user_data)
 {
-       GdkKeymapKey *keys = NULL;
-       gint n_keys;
+       GdkModifierType modifiers;
+       GtkCellRenderer *cell = (GtkCellRenderer *) user_data;
+
+       modifiers = event->state & gtk_accelerator_get_default_mod_mask ();
 
        /*
         * Tab should behave the same way as Enter (cycling on cells).
@@ -496,17 +511,20 @@ key_pressed_cb (GtkWidget *widget,
         * But unfortunately, it showed up crash occurred with XIM input (GTK_IM_MODULE=xim).
         * https://bugzilla.redhat.com/show_bug.cgi?id=747368
         */
-       if (event->type == GDK_KEY_PRESS && event->key.keyval == GDK_KEY_Tab) {
-               /* Get hardware keycode for GDK_KEY_Return */
-               if (gdk_keymap_get_entries_for_keyval (gdk_keymap_get_default (), GDK_KEY_Return, &keys, 
&n_keys)) {
-                       /* Change 'Tab' to 'Enter' key */
-                       event->key.keyval = GDK_KEY_Return;
-                       event->key.hardware_keycode = keys[0].keycode;
-               }
-               g_free (keys);
-       }
-
-       return FALSE;
+       if (event->keyval == GDK_KEY_Tab && modifiers == 0) {
+               /* Tab */
+               g_object_set_data (G_OBJECT (cell), DIRECTION_TAG, GINT_TO_POINTER (1));
+               utils_fake_return_key (event);
+       } else if (event->keyval == GDK_KEY_ISO_Left_Tab && modifiers == GDK_SHIFT_MASK) {
+               /* Shift-Tab */
+               g_object_set_data (G_OBJECT (cell), DIRECTION_TAG, GINT_TO_POINTER (-1));
+               utils_fake_return_key (event);
+       } else if (event->keyval == GDK_KEY_Up)
+               g_object_set_data (G_OBJECT (cell), DIRECTION_TAG, GINT_TO_POINTER (-1));
+       else if (event->keyval == GDK_KEY_Return || event->keyval == GDK_KEY_ISO_Enter)
+               g_object_set_data (G_OBJECT (cell), DO_NOT_CYCLE_TAG, GUINT_TO_POINTER (TRUE));
+
+       return FALSE; /* Allow default handler to be called */
 }
 
 static void
@@ -544,7 +562,7 @@ ip4_cell_editing_started (GtkCellRenderer *cell,
        /* Set up key pressed handler - need to handle Tab key */
        g_signal_connect (G_OBJECT (editable), "key-press-event",
                          (GCallback) key_pressed_cb,
-                         user_data);
+                         cell);
 }
 
 static void
@@ -609,7 +627,7 @@ uint_cell_editing_started (GtkCellRenderer *cell,
        /* Set up key pressed handler - need to handle Tab key */
        g_signal_connect (G_OBJECT (editable), "key-press-event",
                          (GCallback) key_pressed_cb,
-                         user_data);
+                         cell);
 }
 
 static gboolean
diff --git a/src/connection-editor/ip6-routes-dialog.c b/src/connection-editor/ip6-routes-dialog.c
index 1a3242f..3cfdb74 100644
--- a/src/connection-editor/ip6-routes-dialog.c
+++ b/src/connection-editor/ip6-routes-dialog.c
@@ -282,6 +282,9 @@ cell_editing_canceled (GtkCellRenderer *renderer, gpointer user_data)
        validate (GTK_WIDGET (gtk_builder_get_object (builder, "ip6_routes_dialog")));
 }
 
+#define DO_NOT_CYCLE_TAG "do-not-cycle"
+#define DIRECTION_TAG    "direction"
+
 static void
 cell_edited (GtkCellRendererText *cell,
              const gchar *path_string,
@@ -296,6 +299,8 @@ cell_edited (GtkCellRendererText *cell,
        guint32 column;
        GtkTreeViewColumn *next_col;
        GtkCellRenderer *next_cell;
+       gboolean can_cycle;
+       int direction, tmp;
 
        /* Free auxiliary stuff */
        g_free (last_edited);
@@ -312,8 +317,19 @@ cell_edited (GtkCellRendererText *cell,
        gtk_tree_model_get_iter (GTK_TREE_MODEL (store), &iter, path);
        gtk_list_store_set (store, &iter, column, new_text, -1);
 
-       /* Move focus to the next column */
-       column = (column >= COL_LAST) ? 0 : column + 1;
+       /* Move focus to the next/previous column */
+       can_cycle = g_object_get_data (G_OBJECT (cell), DO_NOT_CYCLE_TAG) == NULL;
+       direction = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (cell), DIRECTION_TAG));
+       g_object_set_data (G_OBJECT (cell), DIRECTION_TAG, NULL);
+       g_object_set_data (G_OBJECT (cell), DO_NOT_CYCLE_TAG, NULL);
+       if (direction == 0)  /* Move forward by default */
+               direction = 1;
+
+       tmp = column + direction;
+       if (can_cycle)
+               column = tmp < 0 ? COL_LAST : tmp > COL_LAST ? 0 : tmp;
+       else
+               column = tmp;
        next_col = gtk_tree_view_get_column (GTK_TREE_VIEW (widget), column);
        dialog = GTK_WIDGET (gtk_builder_get_object (builder, "ip6_routes_dialog"));
        next_cell = g_slist_nth_data (g_object_get_data (G_OBJECT (dialog), "renderers"), column);
@@ -425,12 +441,12 @@ cell_changed_cb (GtkEditable *editable,
 }
 
 static gboolean
-key_pressed_cb (GtkWidget *widget,
-                GdkEvent *event,
-                gpointer user_data)
+key_pressed_cb (GtkWidget *widget, GdkEventKey *event, gpointer user_data)
 {
-       GdkKeymapKey *keys = NULL;
-       gint n_keys;
+       GdkModifierType modifiers;
+       GtkCellRenderer *cell = (GtkCellRenderer *) user_data;
+
+       modifiers = event->state & gtk_accelerator_get_default_mod_mask ();
 
        /*
         * Tab should behave the same way as Enter (cycling on cells).
@@ -440,17 +456,20 @@ key_pressed_cb (GtkWidget *widget,
         * But unfortunately, it showed up crash occurred with XIM input (GTK_IM_MODULE=xim).
         * https://bugzilla.redhat.com/show_bug.cgi?id=747368
         */
-       if (event->type == GDK_KEY_PRESS && event->key.keyval == GDK_KEY_Tab) {
-               /* Get hardware keycode for GDK_KEY_Return */
-               if (gdk_keymap_get_entries_for_keyval (gdk_keymap_get_default (), GDK_KEY_Return, &keys, 
&n_keys)) {
-                       /* Change 'Tab' to 'Enter' key */
-                       event->key.keyval = GDK_KEY_Return;
-                       event->key.hardware_keycode = keys[0].keycode;
-               }
-               g_free (keys);
-       }
-
-       return FALSE;
+       if (event->keyval == GDK_KEY_Tab && modifiers == 0) {
+               /* Tab */
+               g_object_set_data (G_OBJECT (cell), DIRECTION_TAG, GINT_TO_POINTER (1));
+               utils_fake_return_key (event);
+       } else if (event->keyval == GDK_KEY_ISO_Left_Tab && modifiers == GDK_SHIFT_MASK) {
+               /* Shift-Tab */
+               g_object_set_data (G_OBJECT (cell), DIRECTION_TAG, GINT_TO_POINTER (-1));
+               utils_fake_return_key (event);
+       } else if (event->keyval == GDK_KEY_Up)
+               g_object_set_data (G_OBJECT (cell), DIRECTION_TAG, GINT_TO_POINTER (-1));
+       else if (event->keyval == GDK_KEY_Return || event->keyval == GDK_KEY_ISO_Enter)
+               g_object_set_data (G_OBJECT (cell), DO_NOT_CYCLE_TAG, GUINT_TO_POINTER (TRUE));
+
+       return FALSE; /* Allow default handler to be called */
 }
 
 static void
@@ -488,7 +507,7 @@ ip6_cell_editing_started (GtkCellRenderer *cell,
        /* Set up key pressed handler - need to handle Tab key */
        g_signal_connect (G_OBJECT (editable), "key-press-event",
                          (GCallback) key_pressed_cb,
-                         user_data);
+                         cell);
 }
 
 static void
@@ -553,7 +572,7 @@ uint_cell_editing_started (GtkCellRenderer *cell,
        /* Set up key pressed handler - need to handle Tab key */
        g_signal_connect (G_OBJECT (editable), "key-press-event",
                          (GCallback) key_pressed_cb,
-                         user_data);
+                         cell);
 }
 
 static gboolean
diff --git a/src/connection-editor/page-ip4.c b/src/connection-editor/page-ip4.c
index 07d4eac..f2cbb02 100644
--- a/src/connection-editor/page-ip4.c
+++ b/src/connection-editor/page-ip4.c
@@ -542,6 +542,9 @@ cell_editing_canceled (GtkCellRenderer *renderer, gpointer user_data)
        priv->last_column = -1;
 }
 
+#define DO_NOT_CYCLE_TAG "do-not-cycle"
+#define DIRECTION_TAG    "direction"
+
 static void
 cell_edited (GtkCellRendererText *cell,
              const gchar *path_string,
@@ -555,6 +558,9 @@ cell_edited (GtkCellRendererText *cell,
        GtkTreeIter iter;
        guint32 column;
        GtkTreeViewColumn *next_col;
+       GtkCellRenderer *next_cell;
+       gboolean can_cycle;
+       int direction, tmp;
 
        /* Free auxiliary stuff */
        g_free (priv->last_edited);
@@ -588,10 +594,22 @@ cell_edited (GtkCellRendererText *cell,
                g_free (prefix);
        }
 
-       /* Move focus to the next column */
-       column = (column >= COL_LAST) ? 0 : column + 1;
+       /* Move focus to the next/previous column */
+       can_cycle = g_object_get_data (G_OBJECT (cell), DO_NOT_CYCLE_TAG) == NULL;
+       direction = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (cell), DIRECTION_TAG));
+       g_object_set_data (G_OBJECT (cell), DIRECTION_TAG, NULL);
+       g_object_set_data (G_OBJECT (cell), DO_NOT_CYCLE_TAG, NULL);
+       if (direction == 0)  /* Move forward by default */
+               direction = 1;
+
+       tmp = column + direction;
+       if (can_cycle)
+               column = tmp < 0 ? COL_LAST : tmp > COL_LAST ? 0 : tmp;
+       else
+               column = tmp;
        next_col = gtk_tree_view_get_column (priv->addr_list, column);
-       gtk_tree_view_set_cursor_on_cell (priv->addr_list, path, next_col, priv->addr_cells[column], TRUE);
+       next_cell = column <= COL_LAST ? priv->addr_cells[column] : NULL;
+       gtk_tree_view_set_cursor_on_cell (priv->addr_list, path, next_col, next_cell, TRUE);
 
        gtk_tree_path_free (path);
        ce_page_changed (CE_PAGE (self));
@@ -721,12 +739,12 @@ cell_changed_cb (GtkEditable *editable,
 }
 
 static gboolean
-key_pressed_cb (GtkWidget *widget,
-                GdkEvent *event,
-                gpointer user_data)
+key_pressed_cb (GtkWidget *widget, GdkEventKey *event, gpointer user_data)
 {
-       GdkKeymapKey *keys = NULL;
-       gint n_keys;
+       GdkModifierType modifiers;
+       GtkCellRenderer *cell = (GtkCellRenderer *) user_data;
+
+       modifiers = event->state & gtk_accelerator_get_default_mod_mask ();
 
        /*
         * Tab should behave the same way as Enter (cycling on cells).
@@ -736,17 +754,20 @@ key_pressed_cb (GtkWidget *widget,
         * But unfortunately, it showed up crash occurred with XIM input (GTK_IM_MODULE=xim).
         * https://bugzilla.redhat.com/show_bug.cgi?id=747368
         */
-       if (event->type == GDK_KEY_PRESS && event->key.keyval == GDK_KEY_Tab) {
-               /* Get hardware keycode for GDK_KEY_Return */
-               if (gdk_keymap_get_entries_for_keyval (gdk_keymap_get_default (), GDK_KEY_Return, &keys, 
&n_keys)) {
-                       /* Change 'Tab' to 'Enter' key */
-                       event->key.keyval = GDK_KEY_Return;
-                       event->key.hardware_keycode = keys[0].keycode;
-               }
-               g_free (keys);
-       }
-
-       return FALSE;
+       if (event->keyval == GDK_KEY_Tab && modifiers == 0) {
+               /* Tab */
+               g_object_set_data (G_OBJECT (cell), DIRECTION_TAG, GINT_TO_POINTER (1));
+               utils_fake_return_key (event);
+       } else if (event->keyval == GDK_KEY_ISO_Left_Tab && modifiers == GDK_SHIFT_MASK) {
+               /* Shift-Tab */
+               g_object_set_data (G_OBJECT (cell), DIRECTION_TAG, GINT_TO_POINTER (-1));
+               utils_fake_return_key (event);
+       } else if (event->keyval == GDK_KEY_Up)
+               g_object_set_data (G_OBJECT (cell), DIRECTION_TAG, GINT_TO_POINTER (-1));
+       else if (event->keyval == GDK_KEY_Return || event->keyval == GDK_KEY_ISO_Enter)
+               g_object_set_data (G_OBJECT (cell), DO_NOT_CYCLE_TAG, GUINT_TO_POINTER (TRUE));
+
+       return FALSE; /* Allow default handler to be called */
 }
 
 static void
@@ -787,7 +808,7 @@ cell_editing_started (GtkCellRenderer *cell,
        /* Set up key pressed handler - need to handle Tab key */
        g_signal_connect (G_OBJECT (editable), "key-press-event",
                          (GCallback) key_pressed_cb,
-                         user_data);
+                         cell);
 }
 
 static void
diff --git a/src/connection-editor/page-ip6.c b/src/connection-editor/page-ip6.c
index 4e71712..cfa09ff 100644
--- a/src/connection-editor/page-ip6.c
+++ b/src/connection-editor/page-ip6.c
@@ -585,6 +585,9 @@ cell_editing_canceled (GtkCellRenderer *renderer, gpointer user_data)
        priv->last_column = -1;
 }
 
+#define DO_NOT_CYCLE_TAG "do-not-cycle"
+#define DIRECTION_TAG    "direction"
+
 static void
 cell_edited (GtkCellRendererText *cell,
              const gchar *path_string,
@@ -598,6 +601,9 @@ cell_edited (GtkCellRendererText *cell,
        GtkTreeIter iter;
        guint32 column;
        GtkTreeViewColumn *next_col;
+       GtkCellRenderer *next_cell;
+       gboolean can_cycle;
+       int direction, tmp;
 
        /* Free auxiliary stuff */
        g_free (priv->last_edited);
@@ -610,10 +616,22 @@ cell_edited (GtkCellRendererText *cell,
        gtk_tree_model_get_iter (GTK_TREE_MODEL (store), &iter, path);
        gtk_list_store_set (store, &iter, column, new_text, -1);
 
-       /* Move focus to the next column */
-       column = (column >= COL_LAST) ? 0 : column + 1;
+       /* Move focus to the next/previous column */
+       can_cycle = g_object_get_data (G_OBJECT (cell), DO_NOT_CYCLE_TAG) == NULL;
+       direction = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (cell), DIRECTION_TAG));
+       g_object_set_data (G_OBJECT (cell), DIRECTION_TAG, NULL);
+       g_object_set_data (G_OBJECT (cell), DO_NOT_CYCLE_TAG, NULL);
+       if (direction == 0)  /* Move forward by default */
+               direction = 1;
+
+       tmp = column + direction;
+       if (can_cycle)
+               column = tmp < 0 ? COL_LAST : tmp > COL_LAST ? 0 : tmp;
+       else
+               column = tmp;
        next_col = gtk_tree_view_get_column (priv->addr_list, column);
-       gtk_tree_view_set_cursor_on_cell (priv->addr_list, path, next_col, priv->addr_cells[column], TRUE);
+       next_cell = column <= COL_LAST ? priv->addr_cells[column] : NULL;
+       gtk_tree_view_set_cursor_on_cell (priv->addr_list, path, next_col, next_cell, TRUE);
 
        gtk_tree_path_free (path);
        ce_page_changed (CE_PAGE (self));
@@ -717,12 +735,12 @@ cell_changed_cb (GtkEditable *editable,
 }
 
 static gboolean
-key_pressed_cb (GtkWidget *widget,
-                GdkEvent *event,
-                gpointer user_data)
+key_pressed_cb (GtkWidget *widget, GdkEventKey *event, gpointer user_data)
 {
-       GdkKeymapKey *keys = NULL;
-       gint n_keys;
+       GdkModifierType modifiers;
+       GtkCellRenderer *cell = (GtkCellRenderer *) user_data;
+
+       modifiers = event->state & gtk_accelerator_get_default_mod_mask ();
 
        /*
         * Tab should behave the same way as Enter (cycling on cells).
@@ -732,17 +750,20 @@ key_pressed_cb (GtkWidget *widget,
         * But unfortunately, it showed up crash occurred with XIM input (GTK_IM_MODULE=xim).
         * https://bugzilla.redhat.com/show_bug.cgi?id=747368
         */
-       if (event->type == GDK_KEY_PRESS && event->key.keyval == GDK_KEY_Tab) {
-               /* Get hardware keycode for GDK_KEY_Return */
-               if (gdk_keymap_get_entries_for_keyval (gdk_keymap_get_default (), GDK_KEY_Return, &keys, 
&n_keys)) {
-                       /* Change 'Tab' to 'Enter' key */
-                       event->key.keyval = GDK_KEY_Return;
-                       event->key.hardware_keycode = keys[0].keycode;
-               }
-               g_free (keys);
-       }
-
-       return FALSE;
+       if (event->keyval == GDK_KEY_Tab && modifiers == 0) {
+               /* Tab */
+               g_object_set_data (G_OBJECT (cell), DIRECTION_TAG, GINT_TO_POINTER (1));
+               utils_fake_return_key (event);
+       } else if (event->keyval == GDK_KEY_ISO_Left_Tab && modifiers == GDK_SHIFT_MASK) {
+               /* Shift-Tab */
+               g_object_set_data (G_OBJECT (cell), DIRECTION_TAG, GINT_TO_POINTER (-1));
+               utils_fake_return_key (event);
+       } else if (event->keyval == GDK_KEY_Up)
+               g_object_set_data (G_OBJECT (cell), DIRECTION_TAG, GINT_TO_POINTER (-1));
+       else if (event->keyval == GDK_KEY_Return || event->keyval == GDK_KEY_ISO_Enter)
+               g_object_set_data (G_OBJECT (cell), DO_NOT_CYCLE_TAG, GUINT_TO_POINTER (TRUE));
+
+       return FALSE; /* Allow default handler to be called */
 }
 
 static void
@@ -788,7 +809,7 @@ cell_editing_started (GtkCellRenderer *cell,
        /* Set up key pressed handler - need to handle Tab key */
        g_signal_connect (G_OBJECT (editable), "key-press-event",
                          (GCallback) key_pressed_cb,
-                         user_data);
+                         cell);
 }
 
 static void
diff --git a/src/utils/utils.c b/src/utils/utils.c
index 64ceee8..f4b2ce7 100644
--- a/src/utils/utils.c
+++ b/src/utils/utils.c
@@ -539,3 +539,20 @@ utils_set_cell_background (GtkCellRenderer *cell,
        } else
                g_object_set (G_OBJECT (cell), "cell-background-set", FALSE, NULL);
 }
+
+/* Change key in @event to 'Enter' key. */
+void
+utils_fake_return_key (GdkEventKey *event)
+{
+       GdkKeymapKey *keys = NULL;
+       gint n_keys;
+
+       /* Get hardware keycode for GDK_KEY_Return */
+       if (gdk_keymap_get_entries_for_keyval (gdk_keymap_get_default (), GDK_KEY_Return, &keys, &n_keys)) {
+               event->keyval = GDK_KEY_Return;
+               event->hardware_keycode = keys[0].keycode;
+               event->state = 0;
+       }
+       g_free (keys);
+}
+
diff --git a/src/utils/utils.h b/src/utils/utils.h
index 6d4147f..b005dcc 100644
--- a/src/utils/utils.h
+++ b/src/utils/utils.h
@@ -105,5 +105,7 @@ void utils_set_cell_background (GtkCellRenderer *cell,
                                 const char *color,
                                 const char *value);
 
+void utils_fake_return_key (GdkEventKey *event);
+
 #endif /* UTILS_H */
 


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]