[gnome-builder] libide/tweaks: use visitor pattern for item->model conversion



commit b066bf118dcc1d0887bfcfedc668e5f7c65b573b
Author: Christian Hergert <chergert redhat com>
Date:   Tue Aug 2 18:19:17 2022 -0700

    libide/tweaks: use visitor pattern for item->model conversion
    
    This makes it a bit easier to control if we need to recurse through an
    intermediate node (such as a section) without being so type based. We still
    keep special handling for factories though.

 src/libide/tweaks/ide-tweaks-model-private.h |  18 +++-
 src/libide/tweaks/ide-tweaks-model.c         | 120 ++++++++++++++++-----------
 src/libide/tweaks/ide-tweaks-panel-list.c    |  30 ++++++-
 3 files changed, 115 insertions(+), 53 deletions(-)
---
diff --git a/src/libide/tweaks/ide-tweaks-model-private.h b/src/libide/tweaks/ide-tweaks-model-private.h
index 5dd6bc032..6db7c9487 100644
--- a/src/libide/tweaks/ide-tweaks-model-private.h
+++ b/src/libide/tweaks/ide-tweaks-model-private.h
@@ -27,11 +27,23 @@ G_BEGIN_DECLS
 
 #define IDE_TYPE_TWEAKS_MODEL (ide_tweaks_model_get_type())
 
+typedef enum
+{
+  IDE_TWEAKS_ITEM_VISIT_STOP = 0,
+  IDE_TWEAKS_ITEM_VISIT_SKIP,
+  IDE_TWEAKS_ITEM_VISIT_ACCEPT,
+  IDE_TWEAKS_ITEM_VISIT_RECURSE,
+} IdeTweaksItemVisitResult;
+
+typedef IdeTweaksItemVisitResult (*IdeTweaksItemVisitor) (IdeTweaksItem *item,
+                                                          gpointer       user_data);
+
 G_DECLARE_FINAL_TYPE (IdeTweaksModel, ide_tweaks_model, IDE, TWEAKS_MODEL, GObject)
 
-IdeTweaksModel *ide_tweaks_model_new      (IdeTweaksItem  *item,
-                                           const GType    *allowed_types,
-                                           guint           n_allowed_types);
+IdeTweaksModel *ide_tweaks_model_new      (IdeTweaksItem        *item,
+                                           IdeTweaksItemVisitor  visitor,
+                                           gpointer              visitor_data,
+                                           GDestroyNotify        visitor_data_destroy);
 IdeTweaksItem  *ide_tweaks_model_get_item (IdeTweaksModel *self);
 
 G_END_DECLS
diff --git a/src/libide/tweaks/ide-tweaks-model.c b/src/libide/tweaks/ide-tweaks-model.c
index 2a4ca9f97..1e0a7bc15 100644
--- a/src/libide/tweaks/ide-tweaks-model.c
+++ b/src/libide/tweaks/ide-tweaks-model.c
@@ -28,11 +28,17 @@
 
 struct _IdeTweaksModel
 {
-  GObject        parent_instance;
-  IdeTweaksItem *item;
-  GPtrArray     *items;
+  GObject               parent_instance;
+  IdeTweaksItem        *item;
+  GPtrArray            *items;
+  IdeTweaksItemVisitor  visitor;
+  gpointer              visitor_data;
+  GDestroyNotify        visitor_data_destroy;
 };
 
+static gboolean ide_tweaks_model_populate (IdeTweaksModel *self,
+                                           IdeTweaksItem  *item);
+
 static GType
 list_model_get_item_type (GListModel *model)
 {
@@ -76,81 +82,92 @@ enum {
 
 static GParamSpec *properties [N_PROPS];
 
-static inline gboolean
-descendant_is_allowed (IdeTweaksItem *item,
-                       const GType   *allowed_types,
-                       guint          n_allowed_types)
+static gboolean
+ide_tweaks_model_visit (IdeTweaksModel *self,
+                        IdeTweaksItem  *item)
 {
-  GType item_type = G_OBJECT_TYPE (item);
+  IdeTweaksItemVisitResult res;
+
+  g_assert (IDE_IS_TWEAKS_MODEL (self));
+  g_assert (IDE_IS_TWEAKS_ITEM (item));
 
-  for (guint i = 0; i < n_allowed_types; i++)
+  res = self->visitor (item, self->visitor_data);
+
+  switch (res)
     {
-      if (g_type_is_a (item_type, allowed_types[i]))
-        return TRUE;
+    case IDE_TWEAKS_ITEM_VISIT_STOP:
+      return TRUE;
+
+    case IDE_TWEAKS_ITEM_VISIT_SKIP:
+      return FALSE;
+
+    case IDE_TWEAKS_ITEM_VISIT_ACCEPT:
+      g_ptr_array_add (self->items, g_object_ref (item));
+      return FALSE;
+
+    case IDE_TWEAKS_ITEM_VISIT_RECURSE:
+      return ide_tweaks_model_populate (self, item);
+
+    default:
+      break;
     }
 
-  return FALSE;
+  g_assert_not_reached ();
 }
 
-static void
+static gboolean
 ide_tweaks_model_populate (IdeTweaksModel *self,
-                           const GType    *allowed_types,
-                           guint           n_allowed_types)
+                           IdeTweaksItem  *item)
 {
   g_assert (IDE_IS_TWEAKS_MODEL (self));
-  g_assert (IDE_IS_TWEAKS_ITEM (self->item));
   g_assert (self->items != NULL);
-  g_assert (self->items->len == 0);
-  g_assert (allowed_types != NULL);
-  g_assert (n_allowed_types > 0);
+  g_assert (self->visitor != NULL);
 
-  for (IdeTweaksItem *child = ide_tweaks_item_get_first_child (self->item);
-       child != NULL;
-       child = ide_tweaks_item_get_next_sibling (child))
+  if (IDE_IS_TWEAKS_FACTORY (item))
     {
-      if (descendant_is_allowed (child, allowed_types, n_allowed_types))
-        {
-          g_ptr_array_add (self->items, g_object_ref (child));
-          continue;
-        }
+      g_autoptr(GPtrArray) factory_items = _ide_tweaks_factory_inflate (IDE_TWEAKS_FACTORY (item));
 
-      /* Now check if this is a factory, we might need to create
-       * items based on the factory.
-       */
-      if (IDE_IS_TWEAKS_FACTORY (child) &&
-          _ide_tweaks_factory_is_one_of (IDE_TWEAKS_FACTORY (child),
-                                         allowed_types,
-                                         n_allowed_types))
+      for (guint i = 0; i < factory_items->len; i++)
         {
-          g_autoptr(GPtrArray) factory_items = _ide_tweaks_factory_inflate (IDE_TWEAKS_FACTORY (child));
-
-          for (guint i = 0; i < factory_items->len; i++)
-            {
-              IdeTweaksItem *factory_item = g_ptr_array_index (factory_items, i);
+          IdeTweaksItem *factory_item = g_ptr_array_index (factory_items, i);
 
-              if (descendant_is_allowed (factory_item, allowed_types, n_allowed_types))
-                g_ptr_array_add (self->items, g_object_ref (factory_item));
-            }
+          if (ide_tweaks_model_visit (self, factory_item))
+            return TRUE;
+        }
+    }
+  else
+    {
+      for (IdeTweaksItem *child = ide_tweaks_item_get_first_child (item);
+           child != NULL;
+           child = ide_tweaks_item_get_next_sibling (child))
+        {
+          if (ide_tweaks_model_visit (self, child))
+            return TRUE;
         }
     }
+
+  return FALSE;
 }
 
 IdeTweaksModel *
-ide_tweaks_model_new (IdeTweaksItem *item,
-                      const GType   *allowed_types,
-                      guint          n_allowed_types)
+ide_tweaks_model_new (IdeTweaksItem        *item,
+                      IdeTweaksItemVisitor  visitor,
+                      gpointer              visitor_data,
+                      GDestroyNotify        visitor_data_destroy)
 {
   IdeTweaksModel *self;
 
   g_return_val_if_fail (IDE_IS_TWEAKS_ITEM (item), NULL);
-  g_return_val_if_fail (allowed_types != NULL, NULL);
-  g_return_val_if_fail (n_allowed_types > 0, NULL);
+  g_return_val_if_fail (visitor != NULL, NULL);
 
   self = g_object_new (IDE_TYPE_TWEAKS_MODEL, NULL);
   self->items = g_ptr_array_new_with_free_func (g_object_unref);
+  self->visitor = visitor;
+  self->visitor_data = visitor_data;
+  self->visitor_data_destroy = visitor_data_destroy;
 
   if (g_set_object (&self->item, item))
-    ide_tweaks_model_populate (self, allowed_types, n_allowed_types);
+    ide_tweaks_model_populate (self, item);
 
   return self;
 }
@@ -162,6 +179,13 @@ ide_tweaks_model_dispose (GObject *object)
 
   g_clear_object (&self->item);
 
+  if (self->visitor_data_destroy)
+    {
+      GDestroyNotify notify = g_steal_pointer (&self->visitor_data_destroy);
+      self->visitor = NULL;
+      g_clear_pointer (&self->visitor_data, notify);
+    }
+
   G_OBJECT_CLASS (ide_tweaks_model_parent_class)->dispose (object);
 }
 
diff --git a/src/libide/tweaks/ide-tweaks-panel-list.c b/src/libide/tweaks/ide-tweaks-panel-list.c
index fa41e16ab..4a0b0a369 100644
--- a/src/libide/tweaks/ide-tweaks-panel-list.c
+++ b/src/libide/tweaks/ide-tweaks-panel-list.c
@@ -22,9 +22,11 @@
 
 #include "config.h"
 
+#include "ide-tweaks-factory-private.h"
 #include "ide-tweaks-model-private.h"
 #include "ide-tweaks-page.h"
 #include "ide-tweaks-panel-list-private.h"
+#include "ide-tweaks-section.h"
 #include "ide-tweaks-subpage.h"
 
 struct _IdeTweaksPanelList
@@ -148,6 +150,28 @@ ide_tweaks_panel_list_create_row_cb (gpointer item,
   return g_object_new (GTK_TYPE_LABEL, "label", "TODO: ", NULL);
 }
 
+static IdeTweaksItemVisitResult
+panel_list_visitor (IdeTweaksItem *item,
+                    gpointer       user_data)
+{
+  static GType page_type;
+
+  if (!page_type)
+    page_type = IDE_TYPE_TWEAKS_PAGE;
+
+  if (IDE_IS_TWEAKS_SECTION (item))
+    return IDE_TWEAKS_ITEM_VISIT_RECURSE;
+
+  if (IDE_IS_TWEAKS_PAGE (item))
+    return IDE_TWEAKS_ITEM_VISIT_ACCEPT;
+
+  if (IDE_IS_TWEAKS_FACTORY (item) &&
+      _ide_tweaks_factory_is_one_of (IDE_TWEAKS_FACTORY (item), &page_type, 1))
+    return IDE_TWEAKS_ITEM_VISIT_ACCEPT;
+
+  return IDE_TWEAKS_ITEM_VISIT_SKIP;
+}
+
 void
 ide_tweaks_panel_list_set_item (IdeTweaksPanelList *self,
                                 IdeTweaksItem      *item)
@@ -161,9 +185,11 @@ ide_tweaks_panel_list_set_item (IdeTweaksPanelList *self,
 
       if (item != NULL)
         {
-          const GType allowed_types[] = { IDE_TYPE_TWEAKS_PAGE, IDE_TYPE_TWEAKS_SUBPAGE };
+          model = ide_tweaks_model_new (item, panel_list_visitor, NULL, NULL);
+
+          g_print ("Setting model: %p %d items\n",
+                   model, g_list_model_get_n_items (G_LIST_MODEL (model)));
 
-          model = ide_tweaks_model_new (item, allowed_types, G_N_ELEMENTS (allowed_types));
           gtk_list_box_bind_model (self->list_box,
                                    G_LIST_MODEL (model),
                                    ide_tweaks_panel_list_create_row_cb,


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