[libdazzle] joinedmenu: add DzlJoinedMenu



commit e5a4bd2aa45f7811fc0116a93ad0e1d7bdab0e75
Author: Christian Hergert <chergert redhat com>
Date:   Wed Jun 21 01:27:33 2017 -0700

    joinedmenu: add DzlJoinedMenu
    
    The DzlJoinedMenu GMenuModel implementation is a menu model that lets you
    join multiple GMenuModels together sequentially. This is handy when you
    have multiple menus, each with their own sections and you want them
    flattened into one level.

 src/dazzle.h                |    1 +
 src/menus/dzl-joined-menu.c |  323 +++++++++++++++++++++++++++++++++++++++++++
 src/menus/dzl-joined-menu.h |   43 ++++++
 src/meson.build             |    2 +
 4 files changed, 369 insertions(+), 0 deletions(-)
---
diff --git a/src/dazzle.h b/src/dazzle.h
index 6fe97c5..7ec51b0 100644
--- a/src/dazzle.h
+++ b/src/dazzle.h
@@ -51,6 +51,7 @@ G_BEGIN_DECLS
 #include "graphing/dzl-graph-model.h"
 #include "graphing/dzl-graph-renderer.h"
 #include "graphing/dzl-graph-view.h"
+#include "menus/dzl-joined-menu.h"
 #include "menus/dzl-menu-manager.h"
 #include "panel/dzl-dock-bin-edge.h"
 #include "panel/dzl-dock-bin.h"
diff --git a/src/menus/dzl-joined-menu.c b/src/menus/dzl-joined-menu.c
new file mode 100644
index 0000000..2b465d6
--- /dev/null
+++ b/src/menus/dzl-joined-menu.c
@@ -0,0 +1,323 @@
+/* dzl-joined-menu.c
+ *
+ * Copyright (C) 2017 Christian Hergert <chergert redhat com>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#define G_LOG_DOMAIN "dzl-joined-menu"
+
+#include "dzl-joined-menu.h"
+
+typedef struct
+{
+  GMenuModel *model;
+  gulong      items_changed_handler;
+} Menu;
+
+struct _DzlJoinedMenu
+{
+  GMenuModel  parent_instance;
+  GArray     *menus;
+};
+
+G_DEFINE_TYPE (DzlJoinedMenu, dzl_joined_menu, G_TYPE_MENU_MODEL)
+
+static void
+clear_menu (gpointer data)
+{
+  Menu *menu = data;
+
+  g_signal_handler_disconnect (menu->model, menu->items_changed_handler);
+  menu->items_changed_handler = 0;
+  g_clear_object (&menu->model);
+}
+
+static gint
+dzl_joined_menu_get_offset_at_index (DzlJoinedMenu *self,
+                                     gint           index)
+{
+  gint offset = 0;
+
+  for (guint i = 0; i < index; i++)
+    offset += g_menu_model_get_n_items (g_array_index (self->menus, Menu, i).model);
+
+  return offset;
+}
+
+static gint
+dzl_joined_menu_get_offset_at_model (DzlJoinedMenu *self,
+                                     GMenuModel    *model)
+{
+  gint offset = 0;
+
+  for (guint i = 0; i < self->menus->len; i++)
+    {
+      const Menu *menu = &g_array_index (self->menus, Menu, i);
+
+      if (menu->model == model)
+        break;
+
+      offset += g_menu_model_get_n_items (menu->model);
+    }
+
+  return offset;
+}
+
+static gboolean
+dzl_joined_menu_is_mutable (GMenuModel *model)
+{
+  return TRUE;
+}
+
+static gint
+dzl_joined_menu_get_n_items (GMenuModel *model)
+{
+  DzlJoinedMenu *self = (DzlJoinedMenu *)model;
+
+  if (self->menus->len == 0)
+    return 0;
+
+  return dzl_joined_menu_get_offset_at_index (self, self->menus->len);
+}
+
+static const Menu *
+dzl_joined_menu_get_item (DzlJoinedMenu *self,
+                          gint          *item_index)
+{
+  g_assert (DZL_IS_JOINED_MENU (self));
+
+  for (guint i = 0; i < self->menus->len; i++)
+    {
+      const Menu *menu = &g_array_index (self->menus, Menu, i);
+      gint n_items = g_menu_model_get_n_items (menu->model);
+
+      if (n_items > *item_index)
+        return menu;
+
+      (*item_index) -= n_items;
+    }
+
+  g_assert_not_reached ();
+
+  return NULL;
+}
+
+static void
+dzl_joined_menu_get_item_attributes (GMenuModel  *model,
+                                     gint         item_index,
+                                     GHashTable **attributes)
+{
+  const Menu *menu = dzl_joined_menu_get_item (DZL_JOINED_MENU (model), &item_index);
+  G_MENU_MODEL_GET_CLASS (menu->model)->get_item_attributes (menu->model, item_index, attributes);
+}
+
+static GMenuAttributeIter *
+dzl_joined_menu_iterate_item_attributes (GMenuModel *model,
+                                         gint        item_index)
+{
+  const Menu *menu = dzl_joined_menu_get_item (DZL_JOINED_MENU (model), &item_index);
+  return G_MENU_MODEL_GET_CLASS (menu->model)->iterate_item_attributes (menu->model, item_index);
+}
+
+static GVariant *
+dzl_joined_menu_get_item_attribute_value (GMenuModel         *model,
+                                          gint                item_index,
+                                          const gchar        *attribute,
+                                          const GVariantType *expected_type)
+{
+  const Menu *menu = dzl_joined_menu_get_item (DZL_JOINED_MENU (model), &item_index);
+  return G_MENU_MODEL_GET_CLASS (menu->model)->get_item_attribute_value (menu->model, item_index, attribute, 
expected_type);
+}
+
+static void
+dzl_joined_menu_get_item_links (GMenuModel  *model,
+                                gint         item_index,
+                                GHashTable **links)
+{
+  const Menu *menu = dzl_joined_menu_get_item (DZL_JOINED_MENU (model), &item_index);
+  G_MENU_MODEL_GET_CLASS (menu->model)->get_item_links (menu->model, item_index, links);
+}
+
+static GMenuLinkIter *
+dzl_joined_menu_iterate_item_links (GMenuModel *model,
+                                    gint        item_index)
+{
+  const Menu *menu = dzl_joined_menu_get_item (DZL_JOINED_MENU (model), &item_index);
+  return G_MENU_MODEL_GET_CLASS (menu->model)->iterate_item_links (menu->model, item_index);
+}
+
+static GMenuModel *
+dzl_joined_menu_get_item_link (GMenuModel  *model,
+                               gint         item_index,
+                               const gchar *link)
+{
+  const Menu *menu = dzl_joined_menu_get_item (DZL_JOINED_MENU (model), &item_index);
+  return G_MENU_MODEL_GET_CLASS (menu->model)->get_item_link (menu->model, item_index, link);
+}
+
+static void
+dzl_joined_menu_finalize (GObject *object)
+{
+  DzlJoinedMenu *self = (DzlJoinedMenu *)object;
+
+  g_clear_pointer (&self->menus, g_array_unref);
+
+  G_OBJECT_CLASS (dzl_joined_menu_parent_class)->finalize (object);
+}
+
+static void
+dzl_joined_menu_class_init (DzlJoinedMenuClass *klass)
+{
+  GObjectClass *object_class = G_OBJECT_CLASS (klass);
+  GMenuModelClass *menu_model_class = G_MENU_MODEL_CLASS (klass);
+
+  object_class->finalize = dzl_joined_menu_finalize;
+
+  menu_model_class->is_mutable = dzl_joined_menu_is_mutable;
+  menu_model_class->get_n_items = dzl_joined_menu_get_n_items;
+  menu_model_class->get_item_attributes = dzl_joined_menu_get_item_attributes;
+  menu_model_class->iterate_item_attributes = dzl_joined_menu_iterate_item_attributes;
+  menu_model_class->get_item_attribute_value = dzl_joined_menu_get_item_attribute_value;
+  menu_model_class->get_item_links = dzl_joined_menu_get_item_links;
+  menu_model_class->iterate_item_links = dzl_joined_menu_iterate_item_links;
+  menu_model_class->get_item_link = dzl_joined_menu_get_item_link;
+}
+
+static void
+dzl_joined_menu_init (DzlJoinedMenu *self)
+{
+  self->menus = g_array_new (FALSE, FALSE, sizeof (Menu));
+  g_array_set_clear_func (self->menus, clear_menu);
+}
+
+static void
+dzl_joined_menu_on_items_changed (DzlJoinedMenu *self,
+                                  guint          offset,
+                                  guint          removed,
+                                  guint          added,
+                                  GMenuModel    *model)
+{
+  g_assert (DZL_IS_JOINED_MENU (self));
+  g_assert (G_IS_MENU_MODEL (model));
+
+  offset += dzl_joined_menu_get_offset_at_model (self, model);
+  g_menu_model_items_changed (G_MENU_MODEL (self), offset, removed, added);
+}
+
+DzlJoinedMenu *
+dzl_joined_menu_new (void)
+{
+  return g_object_new (DZL_TYPE_JOINED_MENU, NULL);
+}
+
+static void
+dzl_joined_menu_insert (DzlJoinedMenu *self,
+                        GMenuModel    *model,
+                        gint           index)
+{
+  Menu menu = { 0 };
+  gint offset;
+  gint n_items;
+
+  g_assert (DZL_IS_JOINED_MENU (self));
+  g_assert (G_IS_MENU_MODEL (model));
+  g_assert (index >= 0);
+  g_assert (index <= self->menus->len);
+
+  menu.model = g_object_ref (model);
+  menu.items_changed_handler =
+    g_signal_connect_swapped (menu.model,
+                              "items-changed",
+                              G_CALLBACK (dzl_joined_menu_on_items_changed),
+                              self);
+  g_array_insert_val (self->menus, index, menu);
+
+  n_items = g_menu_model_get_n_items (model);
+  offset = dzl_joined_menu_get_offset_at_index (self, index);
+  g_menu_model_items_changed (G_MENU_MODEL (self), offset, 0, n_items);
+}
+
+void
+dzl_joined_menu_append_menu (DzlJoinedMenu *self,
+                             GMenuModel    *model)
+{
+
+  g_return_if_fail (DZL_IS_JOINED_MENU (self));
+  g_return_if_fail (G_MENU_MODEL (model));
+
+  dzl_joined_menu_insert (self, model, self->menus->len);
+}
+
+void
+dzl_joined_menu_prepend_menu (DzlJoinedMenu *self,
+                              GMenuModel    *model)
+{
+  g_return_if_fail (DZL_IS_JOINED_MENU (self));
+  g_return_if_fail (G_MENU_MODEL (model));
+
+  dzl_joined_menu_insert (self, model, 0);
+}
+
+void
+dzl_joined_menu_remove_index (DzlJoinedMenu *self,
+                              guint          index)
+{
+  const Menu *menu;
+  gint n_items;
+  gint offset;
+
+  g_return_if_fail (DZL_IS_JOINED_MENU (self));
+  g_return_if_fail (index < self->menus->len);
+
+  menu = &g_array_index (self->menus, Menu, index);
+
+  offset = dzl_joined_menu_get_offset_at_index (self, index);
+  n_items = g_menu_model_get_n_items (menu->model);
+
+  g_array_remove_index (self->menus, index);
+
+  g_menu_model_items_changed (G_MENU_MODEL (self), offset, n_items, 0);
+}
+
+void
+dzl_joined_menu_remove_menu (DzlJoinedMenu *self,
+                             GMenuModel    *model)
+{
+  g_return_if_fail (DZL_IS_JOINED_MENU (self));
+  g_return_if_fail (G_IS_MENU_MODEL (model));
+
+  for (guint i = 0; i < self->menus->len; i++)
+    {
+      if (g_array_index (self->menus, Menu, i).model == model)
+        {
+          dzl_joined_menu_remove_index (self, i);
+          break;
+        }
+    }
+}
+
+/**
+ * dzl_joined_menu_get_n_joined:
+ * @self: a #DzlJoinedMenu
+ *
+ * Gets the number of joined menus.
+ */
+guint
+dzl_joined_menu_get_n_joined (DzlJoinedMenu *self)
+{
+  g_return_val_if_fail (DZL_IS_JOINED_MENU (self), 0);
+
+  return self->menus->len;
+}
diff --git a/src/menus/dzl-joined-menu.h b/src/menus/dzl-joined-menu.h
new file mode 100644
index 0000000..8550f70
--- /dev/null
+++ b/src/menus/dzl-joined-menu.h
@@ -0,0 +1,43 @@
+/* dzl-joined-menu.h
+ *
+ * Copyright (C) 2017 Christian Hergert <chergert redhat com>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef DZL_JOINED_MENU_H
+#define DZL_JOINED_MENU_H
+
+#include <gio/gio.h>
+
+G_BEGIN_DECLS
+
+#define DZL_TYPE_JOINED_MENU (dzl_joined_menu_get_type())
+
+G_DECLARE_FINAL_TYPE (DzlJoinedMenu, dzl_joined_menu, DZL, JOINED_MENU, GMenuModel)
+
+DzlJoinedMenu *dzl_joined_menu_new          (void);
+guint          dzl_joined_menu_get_n_joined (DzlJoinedMenu *self);
+void           dzl_joined_menu_append_menu  (DzlJoinedMenu *self,
+                                             GMenuModel    *model);
+void           dzl_joined_menu_prepend_menu (DzlJoinedMenu *self,
+                                             GMenuModel    *model);
+void           dzl_joined_menu_remove_menu  (DzlJoinedMenu *self,
+                                             GMenuModel    *model);
+void           dzl_joined_menu_remove_index (DzlJoinedMenu *self,
+                                             guint          index);
+
+G_END_DECLS
+
+#endif /* DZL_JOINED_MENU_H */
diff --git a/src/meson.build b/src/meson.build
index 34d0d58..10ae140 100644
--- a/src/meson.build
+++ b/src/meson.build
@@ -67,6 +67,7 @@ libdazzle_public_headers = [
   'graphing/dzl-graph-renderer.h',
   'graphing/dzl-graph-view.h',
 
+  'menus/dzl-joined-menu.h',
   'menus/dzl-menu-manager.h',
 
   'panel/dzl-dock-bin-edge.h',
@@ -211,6 +212,7 @@ libdazzle_public_sources = [
   'graphing/dzl-graph-renderer.c',
   'graphing/dzl-graph-view.c',
 
+  'menus/dzl-joined-menu.c',
   'menus/dzl-menu-manager.c',
 
   'panel/dzl-dock-bin-edge.c',


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