[gnome-builder] navigation: jump between edit points with global navigation.



commit 7543f6b1eb23021c5e3663c1e4cfe5df9263a507
Author: Christian Hergert <christian hergert me>
Date:   Wed Sep 24 17:54:37 2014 -0700

    navigation: jump between edit points with global navigation.
    
    Lots of plumbing had to go in here that I'm not happy about with regards
    to circular references. We used weak references for them, of course, but
    the part that bothers me is that the define had to go in workbench instead
    of in navigation-list.
    
    Anywho, its a good start. We need to make this open existing files if the
    tab has been closed, though.

 src/editor/gb-editor-commands.c        |    3 +
 src/editor/gb-editor-navigation-item.c |   33 ++++++++++++-
 src/editor/gb-editor-tab.c             |   18 ++++++-
 src/editor/gb-editor-tab.h             |    2 +
 src/navigation/gb-navigation-item.c    |   84 +++++++++++++++++++++++++++----
 src/navigation/gb-navigation-item.h    |    6 ++-
 src/navigation/gb-navigation-list.c    |   78 +++++++++++++++++++++++++++++-
 src/navigation/gb-navigation-list.h    |    1 -
 src/workbench/gb-workbench.c           |   50 +++++++++++++++++--
 src/workbench/gb-workbench.h           |    2 +
 tests/test-navigation-list.c           |    2 +-
 11 files changed, 255 insertions(+), 24 deletions(-)
---
diff --git a/src/editor/gb-editor-commands.c b/src/editor/gb-editor-commands.c
index d778bcc..f529080 100644
--- a/src/editor/gb-editor-commands.c
+++ b/src/editor/gb-editor-commands.c
@@ -471,6 +471,7 @@ gb_editor_tab_do_save (GbEditorTab *tab)
    */
   {
     GbWorkbench *workbench;
+    GbWorkspace *workspace;
     GbNavigationItem *item;
     GbNavigationList *list = NULL;
     GtkTextMark *insert;
@@ -479,6 +480,7 @@ gb_editor_tab_do_save (GbEditorTab *tab)
     guint line_offset;
 
     workbench = GB_WORKBENCH (gtk_widget_get_toplevel (GTK_WIDGET (priv->source_view)));
+    workspace = gb_workbench_get_workspace (workbench, GB_TYPE_EDITOR_WORKSPACE);
     list = gb_workbench_get_navigation_list (workbench);
 
     insert = gtk_text_buffer_get_insert (GTK_TEXT_BUFFER (priv->document));
@@ -491,6 +493,7 @@ gb_editor_tab_do_save (GbEditorTab *tab)
                          "line", line,
                          "line-offset", line_offset,
                          "tab", tab,
+                         "workspace", workspace,
                          NULL);
     gb_navigation_list_append (list, item);
   }
diff --git a/src/editor/gb-editor-navigation-item.c b/src/editor/gb-editor-navigation-item.c
index 3449d0b..1323b90 100644
--- a/src/editor/gb-editor-navigation-item.c
+++ b/src/editor/gb-editor-navigation-item.c
@@ -19,6 +19,9 @@
 #include <glib/gi18n.h>
 
 #include "gb-editor-navigation-item.h"
+#include "gb-log.h"
+#include "gb-notebook.h"
+#include "gb-workbench.h"
 
 struct _GbEditorNavigationItemPrivate
 {
@@ -156,9 +159,37 @@ gb_editor_navigation_item_activate (GbNavigationItem *item)
 {
   GbEditorNavigationItem *self = (GbEditorNavigationItem *)item;
 
+  ENTRY;
+
   g_return_if_fail (GB_IS_EDITOR_NAVIGATION_ITEM (self));
 
-  g_print ("Activate item\n");
+  if (self->priv->tab)
+    {
+      GtkWidget *parent;
+      guint page;
+
+      parent = gtk_widget_get_parent (GTK_WIDGET (self->priv->tab));
+
+      if (GB_IS_NOTEBOOK (parent))
+        {
+          gtk_container_child_get (GTK_CONTAINER (parent),
+                                   GTK_WIDGET (self->priv->tab),
+                                   "position", &page,
+                                   NULL);
+          gtk_notebook_set_current_page (GTK_NOTEBOOK (parent), page);
+          gb_editor_tab_scroll_to_line (self->priv->tab, self->priv->line);
+          gtk_widget_grab_focus (GTK_WIDGET (self->priv->tab));
+        }
+    }
+  else
+    {
+      /*
+       * TODO: We will need to implement this once we handle closing files
+       *       properly as well as saving state between application loads.
+       */
+    }
+
+  EXIT;
 }
 
 static void
diff --git a/src/editor/gb-editor-tab.c b/src/editor/gb-editor-tab.c
index 100193c..16d9e0e 100644
--- a/src/editor/gb-editor-tab.c
+++ b/src/editor/gb-editor-tab.c
@@ -852,6 +852,22 @@ on_source_view_push_snippet (GbSourceView           *source_view,
     }
 }
 
+void
+gb_editor_tab_scroll_to_line (GbEditorTab *tab,
+                              guint        line)
+{
+  GtkTextIter iter;
+
+  g_return_if_fail (GB_IS_EDITOR_TAB (tab));
+
+  gtk_text_buffer_get_iter_at_line (GTK_TEXT_BUFFER (tab->priv->document),
+                                    &iter, line);
+  gtk_text_buffer_select_range (GTK_TEXT_BUFFER (tab->priv->document),
+                                &iter, &iter);
+  gtk_text_view_scroll_to_iter (GTK_TEXT_VIEW (tab->priv->source_view), &iter,
+                                0.0, FALSE, 0.0, 0.5);
+}
+
 static gboolean
 transform_file_to_language (GBinding     *binding,
                             const GValue *src_value,
@@ -1243,7 +1259,7 @@ gb_editor_tab_class_init (GbEditorTabClass *klass)
                                                 search_highlighter);
   gtk_widget_class_bind_template_child_private (widget_class, GbEditorTab,
                                                 search_settings);
-  gtk_widget_class_bind_template_child_private (widget_class, GbEditorTab, 
+  gtk_widget_class_bind_template_child_private (widget_class, GbEditorTab,
                                                 snippets_provider);
   gtk_widget_class_bind_template_child_private (widget_class, GbEditorTab,
                                                 source_view);
diff --git a/src/editor/gb-editor-tab.h b/src/editor/gb-editor-tab.h
index 1c76a94..2db26b3 100644
--- a/src/editor/gb-editor-tab.h
+++ b/src/editor/gb-editor-tab.h
@@ -60,6 +60,8 @@ void              gb_editor_tab_set_settings   (GbEditorTab                *tab,
 void              gb_editor_tab_set_font_desc  (GbEditorTab                *tab,
                                                 const PangoFontDescription *font_desc);
 gboolean          gb_editor_tab_get_is_default (GbEditorTab                *tab);
+void              gb_editor_tab_scroll_to_line (GbEditorTab                *tab,
+                                                guint                       line);
 
 G_END_DECLS
 
diff --git a/src/navigation/gb-navigation-item.c b/src/navigation/gb-navigation-item.c
index cc35900..b4a092d 100644
--- a/src/navigation/gb-navigation-item.c
+++ b/src/navigation/gb-navigation-item.c
@@ -22,7 +22,8 @@
 
 struct _GbNavigationItemPrivate
 {
-  gchar *label;
+  gchar       *label;
+  GbWorkspace *workspace;
 };
 
 G_DEFINE_TYPE_WITH_PRIVATE (GbNavigationItem, gb_navigation_item,
@@ -31,6 +32,7 @@ G_DEFINE_TYPE_WITH_PRIVATE (GbNavigationItem, gb_navigation_item,
 enum {
   PROP_0,
   PROP_LABEL,
+  PROP_WORKSPACE,
   LAST_PROP
 };
 
@@ -54,7 +56,7 @@ const gchar *
 gb_navigation_item_get_label (GbNavigationItem *item)
 {
   g_return_val_if_fail (GB_IS_NAVIGATION_ITEM (item), NULL);
-  
+
   return item->priv->label;
 }
 
@@ -63,17 +65,51 @@ gb_navigation_item_set_label (GbNavigationItem *item,
                               const gchar      *label)
 {
   g_return_if_fail (GB_IS_NAVIGATION_ITEM (item));
-  
+
   g_free (item->priv->label);
   item->priv->label = g_strdup (label);
   g_object_notify_by_pspec (G_OBJECT (item), gParamSpecs [PROP_LABEL]);
 }
 
+GbWorkspace *
+gb_navigation_item_get_workspace (GbNavigationItem *item)
+{
+  g_return_val_if_fail (GB_IS_NAVIGATION_ITEM (item), NULL);
+
+  return item->priv->workspace;
+}
+
+static void
+gb_navigation_item_set_workspace (GbNavigationItem *item,
+                                  GbWorkspace      *workspace)
+{
+  g_return_if_fail (GB_IS_NAVIGATION_ITEM (item));
+  g_return_if_fail (!workspace || GB_IS_WORKSPACE (workspace));
+
+  if (item->priv->workspace)
+    {
+      g_object_remove_weak_pointer (G_OBJECT (item),
+                                    (gpointer *)&item->priv->workspace);
+      item->priv->workspace = NULL;
+    }
+
+  if (workspace)
+    {
+      item->priv->workspace = workspace;
+      g_object_add_weak_pointer (G_OBJECT (workspace),
+                                 (gpointer *)&item->priv->workspace);
+    }
+
+  g_object_notify_by_pspec (G_OBJECT (item), gParamSpecs [PROP_WORKSPACE]);
+}
+
+
+
 void
 gb_navigation_item_emit_activate (GbNavigationItem *item)
 {
   g_return_if_fail (GB_IS_NAVIGATION_ITEM (item));
-  
+
   g_signal_emit (item, gSignals [ACTIVATE], 0);
 }
 
@@ -81,9 +117,16 @@ static void
 gb_navigation_item_finalize (GObject *object)
 {
   GbNavigationItemPrivate *priv = GB_NAVIGATION_ITEM (object)->priv;
-  
+
   g_clear_pointer (&priv->label, g_free);
 
+  if (priv->workspace)
+    {
+      g_object_remove_weak_pointer (G_OBJECT (priv->workspace),
+                                    (gpointer *)&priv->workspace);
+      priv->workspace = NULL;
+    }
+
   G_OBJECT_CLASS (gb_navigation_item_parent_class)->finalize (object);
 }
 
@@ -100,7 +143,11 @@ gb_navigation_item_get_property (GObject    *object,
     case PROP_LABEL:
       g_value_set_string (value, gb_navigation_item_get_label (self));
       break;
-      
+
+    case PROP_WORKSPACE:
+      g_value_set_object (value, gb_navigation_item_get_workspace (self));
+      break;
+
     default:
       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
     }
@@ -119,7 +166,11 @@ gb_navigation_item_set_property (GObject      *object,
     case PROP_LABEL:
       gb_navigation_item_set_label (self, g_value_get_string (value));
       break;
-      
+
+    case PROP_WORKSPACE:
+      gb_navigation_item_set_workspace (self, g_value_get_object (value));
+      break;
+
     default:
       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
     }
@@ -133,10 +184,10 @@ gb_navigation_item_class_init (GbNavigationItemClass *klass)
   object_class->finalize = gb_navigation_item_finalize;
   object_class->get_property = gb_navigation_item_get_property;
   object_class->set_property = gb_navigation_item_set_property;
-  
+
   /**
    * GbNavigationItem:label:
-   * 
+   *
    * The "label" for the item within the navigation list.
    */
   gParamSpecs [PROP_LABEL] =
@@ -147,10 +198,21 @@ gb_navigation_item_class_init (GbNavigationItemClass *klass)
                          (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
   g_object_class_install_property (object_class, PROP_LABEL,
                                    gParamSpecs [PROP_LABEL]);
-  
+
+  gParamSpecs [PROP_WORKSPACE] =
+    g_param_spec_object ("workspace",
+                         _("Workspace"),
+                         _("The workspace to ensure is focused."),
+                         GB_TYPE_WORKSPACE,
+                         (G_PARAM_READWRITE |
+                          G_PARAM_CONSTRUCT_ONLY |
+                          G_PARAM_STATIC_STRINGS));
+  g_object_class_install_property (object_class, PROP_WORKSPACE,
+                                   gParamSpecs [PROP_WORKSPACE]);
+
   /**
    * GbNavigationItem::activate:
-   * 
+   *
    * This signal is emitted when the navigation item should be navigated
    * to. The subscriber should change to their respective workspace and focus
    * anything necessary to view the represented state.
diff --git a/src/navigation/gb-navigation-item.h b/src/navigation/gb-navigation-item.h
index b467f06..335e6ff 100644
--- a/src/navigation/gb-navigation-item.h
+++ b/src/navigation/gb-navigation-item.h
@@ -21,6 +21,8 @@
 
 #include <glib-object.h>
 
+#include "gb-workspace.h"
+
 G_BEGIN_DECLS
 
 #define GB_TYPE_NAVIGATION_ITEM            (gb_navigation_item_get_type())
@@ -46,7 +48,7 @@ struct _GbNavigationItem
 struct _GbNavigationItemClass
 {
   GInitiallyUnownedClass parent;
-  
+
   void (*activate) (GbNavigationItem *item);
 };
 
@@ -56,7 +58,7 @@ void              gb_navigation_item_emit_activate (GbNavigationItem *item);
 const gchar      *gb_navigation_item_get_label     (GbNavigationItem *item);
 void              gb_navigation_item_set_label     (GbNavigationItem *item,
                                                     const gchar      *label);
-
+GbWorkspace      *gb_navigation_item_get_workspace (GbNavigationItem *item);
 
 G_END_DECLS
 
diff --git a/src/navigation/gb-navigation-list.c b/src/navigation/gb-navigation-list.c
index 15c4002..838993e 100644
--- a/src/navigation/gb-navigation-list.c
+++ b/src/navigation/gb-navigation-list.c
@@ -21,13 +21,15 @@
 #include <glib/gi18n.h>
 
 #include "gb-navigation-list.h"
+#include "gb-workbench.h"
 
 #define NAVIGATION_MAX_ITEMS 32
 
 struct _GbNavigationListPrivate
 {
-  GPtrArray *items;
-  gint       current;
+  GbWorkbench *workbench;
+  GPtrArray   *items;
+  gint         current;
 };
 
 G_DEFINE_TYPE_WITH_PRIVATE (GbNavigationList, gb_navigation_list, G_TYPE_OBJECT)
@@ -38,6 +40,7 @@ enum {
   PROP_CAN_GO_FORWARD,
   PROP_CURRENT_ITEM,
   PROP_DEPTH,
+  PROP_WORKBENCH,
   LAST_PROP
 };
 
@@ -49,6 +52,42 @@ gb_navigation_list_new (void)
   return g_object_new (GB_TYPE_NAVIGATION_LIST, NULL);
 }
 
+GbWorkbench *
+gb_navigation_list_get_workbench (GbNavigationList *list)
+{
+  g_return_val_if_fail (GB_IS_NAVIGATION_LIST (list), NULL);
+
+  return list->priv->workbench;
+}
+
+static void
+gb_navigation_list_set_workbench (GbNavigationList *list,
+                                  GbWorkbench      *workbench)
+{
+  GbNavigationListPrivate *priv;
+
+  g_return_if_fail (GB_IS_NAVIGATION_LIST (list));
+  g_return_if_fail (!workbench || GB_IS_WORKBENCH (workbench));
+
+  priv = list->priv;
+
+  if (priv->workbench)
+    {
+      g_object_remove_weak_pointer (G_OBJECT (priv->workbench),
+                                    (gpointer *)&priv->workbench);
+      priv->workbench = NULL;
+    }
+
+  if (workbench)
+    {
+      priv->workbench = workbench;
+      g_object_add_weak_pointer (G_OBJECT (priv->workbench),
+                                 (gpointer *)&priv->workbench);
+    }
+
+  g_object_notify_by_pspec (G_OBJECT (list), gParamSpecs [PROP_WORKBENCH]);
+}
+
 guint
 gb_navigation_list_get_depth (GbNavigationList *list)
 {
@@ -187,18 +226,42 @@ gb_navigation_list_get_property (GObject    *object,
       g_value_set_object (value, gb_navigation_list_get_current_item (self));
       break;
 
+    case PROP_WORKBENCH:
+      g_value_set_object (value, gb_navigation_list_get_workbench (self));
+      break;
+
     default:
       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
     }
 }
 
 static void
+gb_navigation_list_set_property (GObject      *object,
+                                 guint         prop_id,
+                                 const GValue *value,
+                                 GParamSpec   *pspec)
+{
+  GbNavigationList *list = GB_NAVIGATION_LIST(object);
+
+  switch (prop_id)
+    {
+    case PROP_WORKBENCH:
+      gb_navigation_list_set_workbench (list, g_value_get_object (value));
+      break;
+
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
+    }
+}
+
+static void
 gb_navigation_list_class_init (GbNavigationListClass *klass)
 {
   GObjectClass *object_class = G_OBJECT_CLASS (klass);
 
   object_class->finalize = gb_navigation_list_finalize;
   object_class->get_property = gb_navigation_list_get_property;
+  object_class->set_property = gb_navigation_list_set_property;
 
   gParamSpecs [PROP_CAN_GO_BACKWARD] =
     g_param_spec_boolean ("can-go-backward",
@@ -229,6 +292,17 @@ gb_navigation_list_class_init (GbNavigationListClass *klass)
                           G_PARAM_STATIC_STRINGS));
   g_object_class_install_property (object_class, PROP_CURRENT_ITEM,
                                    gParamSpecs [PROP_CURRENT_ITEM]);
+
+  gParamSpecs [PROP_WORKBENCH] =
+    g_param_spec_object ("workbench",
+                         _("Workbench"),
+                         _("The workbench the navigation list is for."),
+                         GB_TYPE_WORKBENCH,
+                         (G_PARAM_READWRITE |
+                          G_PARAM_CONSTRUCT_ONLY |
+                          G_PARAM_STATIC_STRINGS));
+  g_object_class_install_property (object_class, PROP_WORKBENCH,
+                                   gParamSpecs [PROP_WORKBENCH]);
 }
 
 static void
diff --git a/src/navigation/gb-navigation-list.h b/src/navigation/gb-navigation-list.h
index 68c6284..34762c7 100644
--- a/src/navigation/gb-navigation-list.h
+++ b/src/navigation/gb-navigation-list.h
@@ -51,7 +51,6 @@ struct _GbNavigationListClass
 };
 
 GType                 gb_navigation_list_get_type            (void) G_GNUC_CONST;
-GbNavigationList     *gb_navigation_list_new                 (void);
 gboolean              gb_navigation_list_get_can_go_backward (GbNavigationList *list);
 gboolean              gb_navigation_list_get_can_go_forward  (GbNavigationList *list);
 GbNavigationItem     *gb_navigation_list_get_current_item    (GbNavigationList *list);
diff --git a/src/workbench/gb-workbench.c b/src/workbench/gb-workbench.c
index eafa928..7fc06ec 100644
--- a/src/workbench/gb-workbench.c
+++ b/src/workbench/gb-workbench.c
@@ -215,12 +215,15 @@ on_go_forward_activate (GSimpleAction *action,
                         GVariant      *variant,
                         gpointer       user_data)
 {
+  GbWorkbenchPrivate *priv;
   GbWorkbench *workbench = user_data;
 
   g_return_if_fail (GB_IS_WORKBENCH (workbench));
 
-  if (gb_navigation_list_get_can_go_forward (workbench->priv->navigation_list))
-    gb_navigation_list_go_forward (workbench->priv->navigation_list);
+  priv = workbench->priv;
+
+  if (gb_navigation_list_get_can_go_forward (priv->navigation_list))
+    gb_navigation_list_go_forward (priv->navigation_list);
 }
 
 static void
@@ -228,12 +231,41 @@ on_go_backward_activate (GSimpleAction *action,
                          GVariant      *variant,
                          gpointer       user_data)
 {
+  GbWorkbenchPrivate *priv;
   GbWorkbench *workbench = user_data;
 
   g_return_if_fail (GB_IS_WORKBENCH (workbench));
 
-  if (gb_navigation_list_get_can_go_backward (workbench->priv->navigation_list))
-    gb_navigation_list_go_backward (workbench->priv->navigation_list);
+  priv = workbench->priv;
+
+  if (gb_navigation_list_get_can_go_backward (priv->navigation_list))
+    gb_navigation_list_go_backward (priv->navigation_list);
+}
+
+static void
+gb_workbench_navigation_changed (GbWorkbench      *workbench,
+                                 GParamSpec       *pspec,
+                                 GbNavigationList *list)
+{
+  GbWorkbenchPrivate *priv;
+  GbNavigationItem *item;
+  GbWorkspace *workspace;
+
+  g_return_if_fail (GB_IS_WORKBENCH (workbench));
+  g_return_if_fail (GB_IS_NAVIGATION_LIST (list));
+
+  priv = workbench->priv;
+
+  item = gb_navigation_list_get_current_item (list);
+
+  if (item)
+    {
+      workspace = gb_navigation_item_get_workspace (item);
+      if (workspace)
+        gtk_stack_set_visible_child (priv->stack, GTK_WIDGET (workspace));
+
+      gb_navigation_item_emit_activate (item);
+    }
 }
 
 static void
@@ -276,6 +308,12 @@ gb_workbench_constructed (GObject *object)
   g_action_map_add_action_entries (G_ACTION_MAP (workbench), actions,
                                    G_N_ELEMENTS (actions), workbench);
 
+  g_signal_connect_object (priv->navigation_list,
+                           "notify::current-item",
+                           G_CALLBACK (gb_workbench_navigation_changed),
+                           workbench,
+                           G_CONNECT_SWAPPED);
+
   action = g_action_map_lookup_action (G_ACTION_MAP (workbench), "go-backward");
   g_object_bind_property (priv->navigation_list, "can-go-backward",
                           action, "enabled", G_BINDING_SYNC_CREATE);
@@ -405,7 +443,9 @@ gb_workbench_init (GbWorkbench *workbench)
 
   gtk_widget_init_template (GTK_WIDGET (workbench));
 
-  workbench->priv->navigation_list = gb_navigation_list_new ();
+  workbench->priv->navigation_list = g_object_new (GB_TYPE_NAVIGATION_LIST,
+                                                   "workbench", workbench,
+                                                   NULL);
   workbench->priv->actions = gb_workbench_actions_new (workbench);
   gtk_widget_insert_action_group (GTK_WIDGET (workbench),
                                   "workbench",
diff --git a/src/workbench/gb-workbench.h b/src/workbench/gb-workbench.h
index 368081a..2d58810 100644
--- a/src/workbench/gb-workbench.h
+++ b/src/workbench/gb-workbench.h
@@ -60,6 +60,8 @@ GbWorkspace      *gb_workbench_get_active_workspace (GbWorkbench *workbench);
 GbWorkspace      *gb_workbench_get_workspace        (GbWorkbench *workbench,
                                                      GType        type);
 
+GbWorkbench      *gb_navigation_list_get_workbench  (GbNavigationList *list);
+
 G_END_DECLS
 
 #endif /* GB_WORKBENCH_H */
diff --git a/tests/test-navigation-list.c b/tests/test-navigation-list.c
index 922a742..536c086 100644
--- a/tests/test-navigation-list.c
+++ b/tests/test-navigation-list.c
@@ -8,7 +8,7 @@ test_navigation_list_basic (void)
   GbNavigationItem *item;
   guint i;
 
-  list = gb_navigation_list_new ();
+  list = g_object_new (GB_TYPE_NAVIGATION_LIST, NULL);
 
   g_assert_cmpint (0, ==, gb_navigation_list_get_depth (list));
 


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