[gnome-builder/wip/chergert/perspective] prefs: implement preferences search



commit 22dd897f1518aa6c9fda7663e262d27bbd64d60b
Author: Christian Hergert <christian hergert me>
Date:   Tue Nov 10 19:52:37 2015 -0800

    prefs: implement preferences search

 data/ui/ide-preferences-perspective.ui             |   30 +++++++---
 libide/preferences/ide-preferences-bin-private.h   |    6 +-
 libide/preferences/ide-preferences-bin.c           |   26 +++++++++
 libide/preferences/ide-preferences-bin.h           |   12 +++-
 libide/preferences/ide-preferences-entry.c         |   25 ++++++++
 libide/preferences/ide-preferences-font-button.c   |   22 +++++++
 libide/preferences/ide-preferences-group-private.h |    7 ++-
 libide/preferences/ide-preferences-group.c         |   57 +++++++++++++++++++
 libide/preferences/ide-preferences-page-private.h  |    7 ++-
 libide/preferences/ide-preferences-page.c          |   16 +++++
 libide/preferences/ide-preferences-perspective.c   |   59 ++++++++++++++++++++
 libide/preferences/ide-preferences-spin-button.c   |   25 ++++++++
 libide/preferences/ide-preferences-switch.c        |   25 ++++++++
 13 files changed, 298 insertions(+), 19 deletions(-)
---
diff --git a/data/ui/ide-preferences-perspective.ui b/data/ui/ide-preferences-perspective.ui
index 2dd065c..52513b4 100644
--- a/data/ui/ide-preferences-perspective.ui
+++ b/data/ui/ide-preferences-perspective.ui
@@ -40,15 +40,27 @@
   <object class="IdeWorkbenchHeaderBar" id="titlebar">
     <property name="visible">true</property>
     <child>
-                       <object class="GtkButton" id="back_button">
-                               <property name="action-name">perspective.go-back</property>
-                               <child>
-                                       <object class="GtkImage">
-                                               <property name="icon-name">go-previous-symbolic</property>
-                                               <property name="visible">true</property>
-                                       </object>
-                               </child>
-                       </object>
+      <object class="GtkButton" id="back_button">
+        <property name="action-name">perspective.go-back</property>
+        <style>
+          <class name="image-button"/>
+        </style>
+        <child>
+          <object class="GtkImage">
+            <property name="icon-name">go-previous-symbolic</property>
+            <property name="visible">true</property>
+          </object>
+        </child>
+      </object>
+    </child>
+    <child type="title">
+      <object class="GtkSearchEntry" id="search_entry">
+        <property name="hexpand">true</property>
+        <property name="margin-end">6</property>
+        <property name="margin-start">6</property>
+        <property name="max-width-chars">50</property>
+        <property name="visible">true</property>
+      </object>
     </child>
   </object>
 </interface>
diff --git a/libide/preferences/ide-preferences-bin-private.h 
b/libide/preferences/ide-preferences-bin-private.h
index a005bfd..d748a00 100644
--- a/libide/preferences/ide-preferences-bin-private.h
+++ b/libide/preferences/ide-preferences-bin-private.h
@@ -23,8 +23,10 @@
 
 G_BEGIN_DECLS
 
-void _ide_preferences_bin_set_map (IdePreferencesBin *self,
-                                   GHashTable        *map);
+void     _ide_preferences_bin_set_map (IdePreferencesBin *self,
+                                       GHashTable        *map);
+gboolean _ide_preferences_bin_matches (IdePreferencesBin *self,
+                                       IdePatternSpec    *spec);
 
 G_END_DECLS
 
diff --git a/libide/preferences/ide-preferences-bin.c b/libide/preferences/ide-preferences-bin.c
index 98615ee..64a7246 100644
--- a/libide/preferences/ide-preferences-bin.c
+++ b/libide/preferences/ide-preferences-bin.c
@@ -393,3 +393,29 @@ _ide_preferences_bin_set_map (IdePreferencesBin *self,
       ide_preferences_bin_reload (self);
     }
 }
+
+gboolean
+_ide_preferences_bin_matches (IdePreferencesBin *self,
+                              IdePatternSpec    *spec)
+{
+  IdePreferencesBinPrivate *priv = ide_preferences_bin_get_instance_private (self);
+
+  g_return_val_if_fail (IDE_IS_PREFERENCES_BIN (self), FALSE);
+
+  if (spec == NULL)
+    return TRUE;
+
+  if (priv->keywords && ide_pattern_spec_match (spec, priv->keywords))
+    return TRUE;
+
+  if (priv->schema_id && ide_pattern_spec_match (spec, priv->schema_id))
+    return TRUE;
+
+  if (priv->path && ide_pattern_spec_match (spec, priv->path))
+    return TRUE;
+
+  if (IDE_PREFERENCES_BIN_GET_CLASS (self)->matches)
+    return IDE_PREFERENCES_BIN_GET_CLASS (self)->matches (self, spec);
+
+  return FALSE;
+}
diff --git a/libide/preferences/ide-preferences-bin.h b/libide/preferences/ide-preferences-bin.h
index bab0725..c014817 100644
--- a/libide/preferences/ide-preferences-bin.h
+++ b/libide/preferences/ide-preferences-bin.h
@@ -21,6 +21,8 @@
 
 #include <gtk/gtk.h>
 
+#include "ide-pattern-spec.h"
+
 G_BEGIN_DECLS
 
 #define IDE_TYPE_PREFERENCES_BIN (ide_preferences_bin_get_type())
@@ -31,10 +33,12 @@ struct _IdePreferencesBinClass
 {
   GtkBinClass parent_class;
 
-  void (*connect)    (IdePreferencesBin *self,
-                      GSettings         *settings);
-  void (*disconnect) (IdePreferencesBin *self,
-                      GSettings         *settings);
+  void     (*connect)    (IdePreferencesBin *self,
+                          GSettings         *settings);
+  void     (*disconnect) (IdePreferencesBin *self,
+                          GSettings         *settings);
+  gboolean (*matches)    (IdePreferencesBin *self,
+                          IdePatternSpec    *spec);
 };
 
 G_END_DECLS
diff --git a/libide/preferences/ide-preferences-entry.c b/libide/preferences/ide-preferences-entry.c
index 6f4755b..ba1d1ca 100644
--- a/libide/preferences/ide-preferences-entry.c
+++ b/libide/preferences/ide-preferences-entry.c
@@ -115,15 +115,40 @@ ide_preferences_entry_changed (IdePreferencesEntry *self,
   g_signal_emit (self, signals [CHANGED], 0, text);
 }
 
+static gboolean
+ide_preferences_entry_matches (IdePreferencesBin *bin,
+                               IdePatternSpec    *spec)
+{
+  IdePreferencesEntry *self = (IdePreferencesEntry *)bin;
+  IdePreferencesEntryPrivate *priv = ide_preferences_entry_get_instance_private (self);
+  const gchar *tmp;
+
+  g_assert (IDE_IS_PREFERENCES_ENTRY (self));
+  g_assert (spec != NULL);
+
+  tmp = gtk_label_get_label (priv->title);
+  if (tmp && ide_pattern_spec_match (spec, tmp))
+    return TRUE;
+
+  tmp = gtk_entry_get_text (GTK_ENTRY (priv->entry));
+  if (tmp && ide_pattern_spec_match (spec, tmp))
+    return TRUE;
+
+  return FALSE;
+}
+
 static void
 ide_preferences_entry_class_init (IdePreferencesEntryClass *klass)
 {
   GObjectClass *object_class = G_OBJECT_CLASS (klass);
   GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
+  IdePreferencesBinClass *bin_class = IDE_PREFERENCES_BIN_CLASS (klass);
 
   object_class->get_property = ide_preferences_entry_get_property;
   object_class->set_property = ide_preferences_entry_set_property;
 
+  bin_class->matches = ide_preferences_entry_matches;
+
   signals [ACTIVATE] =
     g_signal_new_class_handler ("activate",
                                 G_TYPE_FROM_CLASS (klass),
diff --git a/libide/preferences/ide-preferences-font-button.c 
b/libide/preferences/ide-preferences-font-button.c
index 3396b9b..adeb90f 100644
--- a/libide/preferences/ide-preferences-font-button.c
+++ b/libide/preferences/ide-preferences-font-button.c
@@ -139,6 +139,27 @@ ide_preferences_font_button_disconnect (IdePreferencesBin *bin,
   self->handler = 0;
 }
 
+static gboolean
+ide_preferences_font_button_matches (IdePreferencesBin *bin,
+                                     IdePatternSpec    *spec)
+{
+  IdePreferencesFontButton *self = (IdePreferencesFontButton *)bin;
+  const gchar *tmp;
+
+  g_assert (IDE_IS_PREFERENCES_FONT_BUTTON (self));
+  g_assert (spec != NULL);
+
+  tmp = gtk_label_get_label (self->title);
+  if (tmp && ide_pattern_spec_match (spec, tmp))
+    return TRUE;
+
+  tmp = gtk_label_get_label (self->font_family);
+  if (tmp && ide_pattern_spec_match (spec, tmp))
+    return TRUE;
+
+  return FALSE;
+}
+
 static void
 ide_preferences_font_button_finalize (GObject *object)
 {
@@ -209,6 +230,7 @@ ide_preferences_font_button_class_init (IdePreferencesFontButtonClass *klass)
 
   bin_class->connect = ide_preferences_font_button_connect;
   bin_class->disconnect = ide_preferences_font_button_disconnect;
+  bin_class->matches = ide_preferences_font_button_matches;
 
   signals [ACTIVATE] =
     g_signal_new_class_handler ("activate",
diff --git a/libide/preferences/ide-preferences-group-private.h 
b/libide/preferences/ide-preferences-group-private.h
index cf7c277..50d2c4d 100644
--- a/libide/preferences/ide-preferences-group-private.h
+++ b/libide/preferences/ide-preferences-group-private.h
@@ -19,12 +19,15 @@
 #ifndef IDE_PREFERENCES_GROUP_PRIVATE_H
 #define IDE_PREFERENCES_GROUP_PRIVATE_H
 
+#include "ide-pattern-spec.h"
 #include "ide-preferences-group.h"
 
 G_BEGIN_DECLS
 
-void _ide_preferences_group_set_map (IdePreferencesGroup *self,
-                                     GHashTable          *map);
+void  _ide_preferences_group_set_map  (IdePreferencesGroup *self,
+                                       GHashTable          *map);
+guint _ide_preferences_group_refilter (IdePreferencesGroup *self,
+                                       IdePatternSpec      *spec);
 
 G_END_DECLS
 
diff --git a/libide/preferences/ide-preferences-group.c b/libide/preferences/ide-preferences-group.c
index c82d0d8..d826d17 100644
--- a/libide/preferences/ide-preferences-group.c
+++ b/libide/preferences/ide-preferences-group.c
@@ -19,6 +19,7 @@
 #include "ide-preferences-bin.h"
 #include "ide-preferences-bin-private.h"
 #include "ide-preferences-group.h"
+#include "ide-preferences-group-private.h"
 
 struct _IdePreferencesGroup
 {
@@ -251,3 +252,59 @@ _ide_preferences_group_set_map (IdePreferencesGroup *self,
         _ide_preferences_bin_set_map (IDE_PREFERENCES_BIN (widget), map);
     }
 }
+
+static void
+ide_preferences_group_refilter_cb (GtkWidget *widget,
+                                   gpointer   user_data)
+{
+  IdePreferencesBin *bin = NULL;
+  struct {
+    IdePatternSpec *spec;
+    guint matches;
+  } *lookup = user_data;
+  gboolean matches;
+
+  if (IDE_IS_PREFERENCES_BIN (widget))
+    bin = IDE_PREFERENCES_BIN (widget);
+  else if (GTK_IS_BIN (widget) && IDE_IS_PREFERENCES_BIN (gtk_bin_get_child (GTK_BIN (widget))))
+    bin = IDE_PREFERENCES_BIN (gtk_bin_get_child (GTK_BIN (widget)));
+  else
+    return;
+
+  if (lookup->spec == NULL)
+    matches = TRUE;
+  else
+    matches = _ide_preferences_bin_matches (bin, lookup->spec);
+
+  gtk_widget_set_visible (widget, matches);
+
+  lookup->matches += matches;
+}
+
+guint
+_ide_preferences_group_refilter (IdePreferencesGroup *self,
+                                 IdePatternSpec      *spec)
+{
+  struct {
+    IdePatternSpec *spec;
+    guint matches;
+  } lookup = { spec, 0 };
+  const gchar *tmp;
+
+  g_return_val_if_fail (IDE_IS_PREFERENCES_GROUP (self), 0);
+
+  tmp = gtk_label_get_label (self->title);
+  if (spec && tmp && ide_pattern_spec_match (spec, tmp))
+    lookup.spec = NULL;
+
+  gtk_container_foreach (GTK_CONTAINER (self->list_box),
+                         ide_preferences_group_refilter_cb,
+                         &lookup);
+  gtk_container_foreach (GTK_CONTAINER (self->box),
+                         ide_preferences_group_refilter_cb,
+                         &lookup);
+
+  gtk_widget_set_visible (GTK_WIDGET (self), lookup.matches > 0);
+
+  return lookup.matches;
+}
diff --git a/libide/preferences/ide-preferences-page-private.h 
b/libide/preferences/ide-preferences-page-private.h
index df52ae3..50bfbf1 100644
--- a/libide/preferences/ide-preferences-page-private.h
+++ b/libide/preferences/ide-preferences-page-private.h
@@ -19,12 +19,15 @@
 #ifndef IDE_PREFERENCES_PAGE_PRIVATE_H
 #define IDE_PREFERENCES_PAGE_PRIVATE_H
 
+#include "ide-pattern-spec.h"
 #include "ide-preferences-page.h"
 
 G_BEGIN_DECLS
 
-void _ide_preferences_page_set_map (IdePreferencesPage *self,
-                                    GHashTable         *map);
+void _ide_preferences_page_set_map  (IdePreferencesPage *self,
+                                     GHashTable         *map);
+void _ide_preferences_page_refilter (IdePreferencesPage *self,
+                                     IdePatternSpec     *spec);
 
 G_END_DECLS
 
diff --git a/libide/preferences/ide-preferences-page.c b/libide/preferences/ide-preferences-page.c
index c241759..c2cf64e 100644
--- a/libide/preferences/ide-preferences-page.c
+++ b/libide/preferences/ide-preferences-page.c
@@ -173,3 +173,19 @@ _ide_preferences_page_set_map (IdePreferencesPage *self,
   while (g_hash_table_iter_next (&iter, NULL, (gpointer *)&group))
     _ide_preferences_group_set_map (group, map);
 }
+
+void
+_ide_preferences_page_refilter (IdePreferencesPage *self,
+                                IdePatternSpec     *spec)
+{
+  IdePreferencesGroup *group;
+  GHashTableIter iter;
+  guint count = 0;
+
+  g_return_if_fail (IDE_IS_PREFERENCES_PAGE (self));
+
+  g_hash_table_iter_init (&iter, self->groups_by_name);
+  while (g_hash_table_iter_next (&iter, NULL, (gpointer *)&group))
+    count += _ide_preferences_group_refilter (group, spec);
+  gtk_widget_set_visible (GTK_WIDGET (self), count > 0);
+}
diff --git a/libide/preferences/ide-preferences-perspective.c 
b/libide/preferences/ide-preferences-perspective.c
index da83684..a3fe059 100644
--- a/libide/preferences/ide-preferences-perspective.c
+++ b/libide/preferences/ide-preferences-perspective.c
@@ -21,6 +21,8 @@
 #include <glib/gi18n.h>
 #include <libpeas/peas.h>
 
+#include "ide-macros.h"
+#include "ide-pattern-spec.h"
 #include "ide-perspective.h"
 #include "ide-preferences.h"
 #include "ide-preferences-addin.h"
@@ -48,6 +50,7 @@ struct _IdePreferencesPerspective
   GtkButton             *back_button;
   GtkStack              *page_stack;
   GtkStackSwitcher      *page_stack_sidebar;
+  GtkSearchEntry        *search_entry;
   GtkStack              *subpage_stack;
   GtkStack              *top_stack;
   IdeWorkbenchHeaderBar *titlebar;
@@ -60,6 +63,39 @@ G_DEFINE_TYPE_EXTENDED (IdePreferencesPerspective, ide_preferences_perspective,
                         G_IMPLEMENT_INTERFACE (IDE_TYPE_PREFERENCES, ide_preferences_iface_init)
                         G_IMPLEMENT_INTERFACE (IDE_TYPE_PERSPECTIVE, ide_perspective_iface_init))
 
+static void
+ide_preferences_perspective_refilter_cb (GtkWidget *widget,
+                                         gpointer   user_data)
+{
+  IdePreferencesPage *page = (IdePreferencesPage *)widget;
+  IdePatternSpec *spec = user_data;
+
+  g_assert (IDE_IS_PREFERENCES_PAGE (page));
+
+  _ide_preferences_page_refilter (page, spec);
+}
+
+static void
+ide_preferences_perspective_refilter (IdePreferencesPerspective *self,
+                                      const gchar               *search_text)
+{
+  IdePatternSpec *spec = NULL;
+
+  g_assert (IDE_IS_PREFERENCES_PERSPECTIVE (self));
+
+  if (search_text != NULL)
+    spec = ide_pattern_spec_new (search_text);
+
+  gtk_container_foreach (GTK_CONTAINER (self->page_stack),
+                         ide_preferences_perspective_refilter_cb,
+                         spec);
+  gtk_container_foreach (GTK_CONTAINER (self->subpage_stack),
+                         ide_preferences_perspective_refilter_cb,
+                         spec);
+
+  g_clear_pointer (&spec, ide_pattern_spec_unref);
+}
+
 static gint
 sort_by_priority (gconstpointer a,
                   gconstpointer b,
@@ -160,6 +196,7 @@ ide_preferences_perspective_class_init (IdePreferencesPerspectiveClass *klass)
   gtk_widget_class_bind_template_child (widget_class, IdePreferencesPerspective, back_button);
   gtk_widget_class_bind_template_child (widget_class, IdePreferencesPerspective, page_stack_sidebar);
   gtk_widget_class_bind_template_child (widget_class, IdePreferencesPerspective, page_stack);
+  gtk_widget_class_bind_template_child (widget_class, IdePreferencesPerspective, search_entry);
   gtk_widget_class_bind_template_child (widget_class, IdePreferencesPerspective, subpage_stack);
   gtk_widget_class_bind_template_child (widget_class, IdePreferencesPerspective, titlebar);
   gtk_widget_class_bind_template_child (widget_class, IdePreferencesPerspective, top_stack);
@@ -179,6 +216,22 @@ go_back_activate (GSimpleAction *action,
 }
 
 static void
+ide_preferences_perspective_search_entry_changed (IdePreferencesPerspective *self,
+                                                  GtkSearchEntry            *search_entry)
+{
+  const gchar *text;
+
+  g_assert (IDE_IS_PREFERENCES_PERSPECTIVE (self));
+  g_assert (GTK_IS_SEARCH_ENTRY (search_entry));
+
+  text = gtk_entry_get_text (GTK_ENTRY (search_entry));
+  if (ide_str_empty0 (text))
+    text = NULL;
+
+  ide_preferences_perspective_refilter (self, text);
+}
+
+static void
 ide_preferences_perspective_init (IdePreferencesPerspective *self)
 {
   static const GActionEntry entries[] = {
@@ -187,6 +240,12 @@ ide_preferences_perspective_init (IdePreferencesPerspective *self)
 
   gtk_widget_init_template (GTK_WIDGET (self));
 
+  g_signal_connect_object (self->search_entry,
+                           "changed",
+                           G_CALLBACK (ide_preferences_perspective_search_entry_changed),
+                           self,
+                           G_CONNECT_SWAPPED);
+
   g_signal_connect_object (self->page_stack,
                            "notify::visible-child",
                            G_CALLBACK (ide_preferences_perspective_notify_visible_child),
diff --git a/libide/preferences/ide-preferences-spin-button.c 
b/libide/preferences/ide-preferences-spin-button.c
index 5f7af7c..0f42ed4 100644
--- a/libide/preferences/ide-preferences-spin-button.c
+++ b/libide/preferences/ide-preferences-spin-button.c
@@ -240,6 +240,30 @@ ide_preferences_spin_button_disconnect (IdePreferencesBin *bin,
   self->handler = 0;
 }
 
+static gboolean
+ide_preferences_spin_button_matches (IdePreferencesBin *bin,
+                                     IdePatternSpec    *spec)
+{
+  IdePreferencesSpinButton *self = (IdePreferencesSpinButton *)bin;
+  const gchar *tmp;
+
+  g_assert (IDE_IS_PREFERENCES_SPIN_BUTTON (self));
+  g_assert (spec != NULL);
+
+  tmp = gtk_label_get_label (self->title);
+  if (tmp && ide_pattern_spec_match (spec, tmp))
+    return TRUE;
+
+  tmp = gtk_label_get_label (self->subtitle);
+  if (tmp && ide_pattern_spec_match (spec, tmp))
+    return TRUE;
+
+  if (self->key && ide_pattern_spec_match (spec, self->key))
+    return TRUE;
+
+  return FALSE;
+}
+
 static void
 ide_preferences_spin_button_finalize (GObject *object)
 {
@@ -318,6 +342,7 @@ ide_preferences_spin_button_class_init (IdePreferencesSpinButtonClass *klass)
 
   bin_class->connect = ide_preferences_spin_button_connect;
   bin_class->disconnect = ide_preferences_spin_button_disconnect;
+  bin_class->matches = ide_preferences_spin_button_matches;
 
   signals [ACTIVATE] =
     g_signal_new_class_handler ("activate",
diff --git a/libide/preferences/ide-preferences-switch.c b/libide/preferences/ide-preferences-switch.c
index 04d8c6c..cabac74 100644
--- a/libide/preferences/ide-preferences-switch.c
+++ b/libide/preferences/ide-preferences-switch.c
@@ -242,6 +242,30 @@ ide_preferences_switch_activate (IdePreferencesSwitch *self)
 
 }
 
+static gboolean
+ide_preferences_switch_matches (IdePreferencesBin *bin,
+                                IdePatternSpec    *spec)
+{
+  IdePreferencesSwitch *self = (IdePreferencesSwitch *)bin;
+  const gchar *tmp;
+
+  g_assert (IDE_IS_PREFERENCES_SWITCH (self));
+  g_assert (spec != NULL);
+
+  tmp = gtk_label_get_label (self->title);
+  if (tmp && ide_pattern_spec_match (spec, tmp))
+    return TRUE;
+
+  tmp = gtk_label_get_label (self->subtitle);
+  if (tmp && ide_pattern_spec_match (spec, tmp))
+    return TRUE;
+
+  if (self->key && ide_pattern_spec_match (spec, self->key))
+    return TRUE;
+
+  return FALSE;
+}
+
 static void
 ide_preferences_switch_finalize (GObject *object)
 {
@@ -342,6 +366,7 @@ ide_preferences_switch_class_init (IdePreferencesSwitchClass *klass)
 
   bin_class->connect = ide_preferences_switch_connect;
   bin_class->disconnect = ide_preferences_switch_disconnect;
+  bin_class->matches = ide_preferences_switch_matches;
 
   signals [ACTIVATED] =
     g_signal_new_class_handler ("activated",


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