[gnome-builder] symbol-tree: track current scope when cursor moves



commit 4a43db86b01bc1597f586333f6ca21f490921065
Author: Christian Hergert <chergert redhat com>
Date:   Mon Jul 3 16:08:06 2017 -0700

    symbol-tree: track current scope when cursor moves
    
    This uses a ½ second delay when the cursor moves to update the
    name of the scope in the Document Symbols stack header.
    
    Currently there are no implementations of this IdeSymbolResolver
    interface feature, but those will come shortly.
    
    Signed-off-by: Christian Hergert <chergert redhat com>

 .../symbol-tree/gbp-symbol-layout-stack-addin.c    |   91 +++++++++++++++++++-
 plugins/symbol-tree/gbp-symbol-menu-button.c       |   35 +++++++-
 plugins/symbol-tree/gbp-symbol-menu-button.h       |    2 +
 plugins/symbol-tree/gbp-symbol-menu-button.ui      |   19 ++++-
 4 files changed, 144 insertions(+), 3 deletions(-)
---
diff --git a/plugins/symbol-tree/gbp-symbol-layout-stack-addin.c 
b/plugins/symbol-tree/gbp-symbol-layout-stack-addin.c
index f9015ba..f03362d 100644
--- a/plugins/symbol-tree/gbp-symbol-layout-stack-addin.c
+++ b/plugins/symbol-tree/gbp-symbol-layout-stack-addin.c
@@ -23,24 +23,107 @@
 #include "gbp-symbol-layout-stack-addin.h"
 #include "gbp-symbol-menu-button.h"
 
+#define CURSOR_MOVED_DELAY_MSEC 500
+
 struct _GbpSymbolLayoutStackAddin {
   GObject              parent_instance;
 
   GbpSymbolMenuButton *button;
   GCancellable        *cancellable;
+  GCancellable        *scope_cancellable;
   DzlSignalGroup      *buffer_signals;
+
+  guint                cursor_moved_handler;
 };
 
 static void
+gbp_symbol_layout_stack_addin_find_scope_cb (GObject      *object,
+                                             GAsyncResult *result,
+                                             gpointer      user_data)
+{
+  IdeSymbolResolver *symbol_resolver = (IdeSymbolResolver *)object;
+  g_autoptr(GbpSymbolLayoutStackAddin) self = user_data;
+  g_autoptr(IdeSymbol) symbol = NULL;
+  g_autoptr(GError) error = NULL;
+
+  g_assert (IDE_IS_SYMBOL_RESOLVER (symbol_resolver));
+  g_assert (G_IS_ASYNC_RESULT (result));
+  g_assert (GBP_IS_SYMBOL_LAYOUT_STACK_ADDIN (self));
+
+  symbol = ide_symbol_resolver_find_nearest_scope_finish (symbol_resolver, result, &error);
+
+  if (error != NULL &&
+      !(g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED) ||
+        g_error_matches (error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED)))
+    g_warning ("Failed to find nearest scope: %s", error->message);
+
+  if (self->button != NULL)
+    gbp_symbol_menu_button_set_symbol (self->button, symbol);
+}
+
+static gboolean
+gbp_symbol_layout_stack_addin_cursor_moved_cb (gpointer user_data)
+{
+  GbpSymbolLayoutStackAddin *self = user_data;
+  IdeBuffer *buffer;
+
+  g_assert (GBP_IS_SYMBOL_LAYOUT_STACK_ADDIN (self));
+
+  g_cancellable_cancel (self->scope_cancellable);
+  g_clear_object (&self->scope_cancellable);
+
+  buffer = dzl_signal_group_get_target (self->buffer_signals);
+
+  if (buffer != NULL)
+    {
+      IdeSymbolResolver *symbol_resolver = ide_buffer_get_symbol_resolver (buffer);
+
+      if (symbol_resolver != NULL)
+        {
+          g_autoptr(IdeSourceLocation) location = ide_buffer_get_insert_location (buffer);
+
+          self->scope_cancellable = g_cancellable_new ();
+
+          ide_symbol_resolver_find_nearest_scope_async (symbol_resolver,
+                                                        location,
+                                                        self->scope_cancellable,
+                                                        gbp_symbol_layout_stack_addin_find_scope_cb,
+                                                        g_object_ref (self));
+        }
+    }
+
+  self->cursor_moved_handler = 0;
+
+  return G_SOURCE_REMOVE;
+}
+
+static void
 gbp_symbol_layout_stack_addin_cursor_moved (GbpSymbolLayoutStackAddin *self,
                                             const GtkTextIter         *location,
                                             IdeBuffer                 *buffer)
 {
+  GSource *source;
+  gint64 ready_time;
+
   g_assert (GBP_IS_SYMBOL_LAYOUT_STACK_ADDIN (self));
   g_assert (location != NULL);
   g_assert (IDE_IS_BUFFER (buffer));
 
-  /* TODO: Delay a bit so we aren't super active */
+  if (self->cursor_moved_handler == 0)
+    {
+      self->cursor_moved_handler =
+        gdk_threads_add_timeout_full (G_PRIORITY_LOW,
+                                      CURSOR_MOVED_DELAY_MSEC,
+                                      gbp_symbol_layout_stack_addin_cursor_moved_cb,
+                                      g_object_ref (self),
+                                      g_object_unref);
+      return;
+    }
+
+  /* Try to reuse our existing GSource if we can */
+  ready_time = g_get_monotonic_time () + (CURSOR_MOVED_DELAY_MSEC * 1000);
+  source = g_main_context_find_source_by_id (NULL, self->cursor_moved_handler);
+  g_source_set_ready_time (source, ready_time);
 }
 
 static void
@@ -163,8 +246,14 @@ gbp_symbol_layout_stack_addin_unbind (GbpSymbolLayoutStackAddin *self,
   g_assert (GBP_IS_SYMBOL_LAYOUT_STACK_ADDIN (self));
   g_assert (DZL_IS_SIGNAL_GROUP (buffer_signals));
 
+  ide_clear_source (&self->cursor_moved_handler);
+
   g_cancellable_cancel (self->cancellable);
   g_clear_object (&self->cancellable);
+
+  g_cancellable_cancel (self->scope_cancellable);
+  g_clear_object (&self->scope_cancellable);
+
   gtk_widget_hide (GTK_WIDGET (self->button));
 }
 
diff --git a/plugins/symbol-tree/gbp-symbol-menu-button.c b/plugins/symbol-tree/gbp-symbol-menu-button.c
index 9cb0e9e..b30fc33 100644
--- a/plugins/symbol-tree/gbp-symbol-menu-button.c
+++ b/plugins/symbol-tree/gbp-symbol-menu-button.c
@@ -16,7 +16,9 @@
  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
  */
 
-#define G_LOG_DOMAIN "gbp-symbol-menu-button.h"
+#define G_LOG_DOMAIN "gbp-symbol-menu-button"
+
+#include <glib/gi18n.h>
 
 #include "gbp-symbol-menu-button.h"
 #include "gbp-symbol-tree-builder.h"
@@ -33,6 +35,8 @@ struct _GbpSymbolMenuButton
   DzlTreeBuilder *tree_builder;
   GtkPopover     *popover;
   GtkSearchEntry *search_entry;
+  GtkImage       *symbol_icon;
+  GtkLabel       *symbol_title;
 };
 
 enum {
@@ -173,6 +177,8 @@ gbp_symbol_menu_button_class_init (GbpSymbolMenuButtonClass *klass)
   gtk_widget_class_set_template_from_resource (widget_class, 
"/org/gnome/builder/plugins/symbol-tree-plugin/gbp-symbol-menu-button.ui");
   gtk_widget_class_bind_template_child (widget_class, GbpSymbolMenuButton, popover);
   gtk_widget_class_bind_template_child (widget_class, GbpSymbolMenuButton, search_entry);
+  gtk_widget_class_bind_template_child (widget_class, GbpSymbolMenuButton, symbol_icon);
+  gtk_widget_class_bind_template_child (widget_class, GbpSymbolMenuButton, symbol_title);
   gtk_widget_class_bind_template_child (widget_class, GbpSymbolMenuButton, tree);
   gtk_widget_class_bind_template_child (widget_class, GbpSymbolMenuButton, tree_builder);
 
@@ -248,3 +254,30 @@ gbp_symbol_menu_button_set_symbol_tree (GbpSymbolMenuButton *self,
       g_object_notify_by_pspec (G_OBJECT (self), properties [PROP_SYMBOL_TREE]);
     }
 }
+
+void
+gbp_symbol_menu_button_set_symbol (GbpSymbolMenuButton *self,
+                                   IdeSymbol           *symbol)
+{
+  const gchar *title = _("Document Outline");
+  const gchar *icon_name = NULL;
+
+  g_assert (GBP_IS_SYMBOL_MENU_BUTTON (self));
+
+  if (symbol != NULL)
+    {
+      IdeSymbolKind kind = ide_symbol_get_kind (symbol);
+
+      icon_name = ide_symbol_kind_get_icon_name (kind);
+    }
+
+  g_object_set (self->symbol_icon,
+                "icon-name", icon_name,
+                "visible", (symbol != NULL),
+                NULL);
+
+  g_object_set (self->symbol_title,
+                "label", title,
+                "visible", (symbol != NULL),
+                NULL);
+}
diff --git a/plugins/symbol-tree/gbp-symbol-menu-button.h b/plugins/symbol-tree/gbp-symbol-menu-button.h
index 9a11c2b..5f1a4a0 100644
--- a/plugins/symbol-tree/gbp-symbol-menu-button.h
+++ b/plugins/symbol-tree/gbp-symbol-menu-button.h
@@ -26,6 +26,8 @@ G_BEGIN_DECLS
 
 G_DECLARE_FINAL_TYPE (GbpSymbolMenuButton, gbp_symbol_menu_button, GBP, SYMBOL_MENU_BUTTON, GtkMenuButton)
 
+void           gbp_symbol_menu_button_set_symbol      (GbpSymbolMenuButton *self,
+                                                       IdeSymbol           *symbol);
 IdeSymbolTree *gbp_symbol_menu_button_get_symbol_tree (GbpSymbolMenuButton *self);
 void           gbp_symbol_menu_button_set_symbol_tree (GbpSymbolMenuButton *self,
                                                        IdeSymbolTree       *symbol_tree);
diff --git a/plugins/symbol-tree/gbp-symbol-menu-button.ui b/plugins/symbol-tree/gbp-symbol-menu-button.ui
index e71133f..be96ba7 100644
--- a/plugins/symbol-tree/gbp-symbol-menu-button.ui
+++ b/plugins/symbol-tree/gbp-symbol-menu-button.ui
@@ -54,7 +54,24 @@
     </child>
   </object>
   <template class="GbpSymbolMenuButton" parent="GtkMenuButton">
-    <property name="label" translatable="yes">Document Outline</property>
     <property name="popover">popover</property>
+    <child>
+      <object class="GtkBox">
+        <property name="hexpand">true</property>
+        <property name="visible">true</property>
+        <child>
+          <object class="GtkImage" id="symbol_icon">
+            <property name="hexpand">true</property>
+            <property name="halign">end</property>
+          </object>
+        </child>
+        <child type="center">
+          <object class="GtkLabel" id="symbol_title">
+            <property name="label" translatable="yes">Document Outline</property>
+            <property name="visible">true</property>
+          </object>
+        </child>
+      </object>
+    </child>
   </template>
 </interface>


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