[libdazzle] tree-store: add DnD store backend for DzlTree



commit 2ee304767ea4391a9e39e6d5add68e719f18bc48
Author: Christian Hergert <chergert redhat com>
Date:   Tue Dec 5 02:16:29 2017 -0800

    tree-store: add DnD store backend for DzlTree
    
    This allows us to plumb in some common DnD operations into the
    tree builders using the GtkTreeDragDest/Source interfaces. We
    override common operations and bridge them to the builders.
    
    Some API prefers using the DzlTreeNode directly to simplify how
    the builders manage their DnD state.

 src/tree/dzl-tree-private.h |    1 +
 src/tree/dzl-tree-store.c   |  296 +++++++++++++++++++++++++++++++++++++++++++
 src/tree/dzl-tree-store.h   |   29 ++++
 src/tree/dzl-tree.c         |    3 +-
 src/tree/meson.build        |    1 +
 5 files changed, 329 insertions(+), 1 deletions(-)
---
diff --git a/src/tree/dzl-tree-private.h b/src/tree/dzl-tree-private.h
index f7a5b4e..35f2c29 100644
--- a/src/tree/dzl-tree-private.h
+++ b/src/tree/dzl-tree-private.h
@@ -98,6 +98,7 @@ gboolean      _dzl_tree_builder_node_draggable          (DzlTreeBuilder
 gboolean      _dzl_tree_builder_node_droppable          (DzlTreeBuilder         *builder,
                                                          DzlTreeNode            *node,
                                                          GtkSelectionData       *data);
+GtkTreeStore *_dzl_tree_store_new                       (DzlTree                *tree);
 
 G_END_DECLS
 
diff --git a/src/tree/dzl-tree-store.c b/src/tree/dzl-tree-store.c
new file mode 100644
index 0000000..602f6ee
--- /dev/null
+++ b/src/tree/dzl-tree-store.c
@@ -0,0 +1,296 @@
+/* dzl-tree-store.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-tree-store"
+
+#include "tree/dzl-tree-builder.h"
+#include "tree/dzl-tree-node.h"
+#include "tree/dzl-tree-private.h"
+#include "tree/dzl-tree-store.h"
+#include "util/dzl-macros.h"
+
+struct _DzlTreeStore
+{
+  GtkTreeStore  parent_instance;
+
+  /* Weak references */
+  DzlTree      *tree;
+};
+
+static void dest_iface_init   (GtkTreeDragDestIface   *iface);
+static void source_iface_init (GtkTreeDragSourceIface *iface);
+
+G_DEFINE_TYPE_WITH_CODE (DzlTreeStore, dzl_tree_store, GTK_TYPE_TREE_STORE,
+                         G_IMPLEMENT_INTERFACE (GTK_TYPE_TREE_DRAG_DEST, dest_iface_init)
+                         G_IMPLEMENT_INTERFACE (GTK_TYPE_TREE_DRAG_SOURCE, source_iface_init))
+
+static void
+dzl_tree_store_dispose (GObject *object)
+{
+  DzlTreeStore *self = (DzlTreeStore *)object;
+
+  dzl_clear_weak_pointer (&self->tree);
+
+  G_OBJECT_CLASS (dzl_tree_store_parent_class)->dispose (object);
+}
+
+static void
+dzl_tree_store_class_init (DzlTreeStoreClass *klass)
+{
+  GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+  object_class->dispose = dzl_tree_store_dispose;
+}
+
+static void
+dzl_tree_store_init (DzlTreeStore *self)
+{
+  GType types[] = { DZL_TYPE_TREE_NODE };
+
+  gtk_tree_store_set_column_types (GTK_TREE_STORE (self), 1, types);
+}
+
+static gboolean
+dzl_tree_store_row_draggable (GtkTreeDragSource *source,
+                              GtkTreePath       *path)
+{
+  GtkTreeIter iter;
+
+  g_assert (GTK_IS_TREE_DRAG_SOURCE (source));
+  g_assert (path != NULL);
+
+  if (gtk_tree_model_get_iter (GTK_TREE_MODEL (source), &iter, path))
+    {
+      g_autoptr(DzlTreeNode) node = NULL;
+      GPtrArray *builders;
+      DzlTree *tree;
+
+      gtk_tree_model_get (GTK_TREE_MODEL (source), &iter, 0, &node, -1);
+      g_assert (DZL_IS_TREE_NODE (node));
+
+      tree = dzl_tree_node_get_tree (node);
+      g_assert (DZL_IS_TREE (tree));
+
+      builders = _dzl_tree_get_builders (tree);
+      g_assert (builders != NULL);
+
+      if (dzl_tree_node_is_root (node) || _dzl_tree_node_is_dummy (node))
+        return FALSE;
+
+      for (guint i = 0; i < builders->len; i++)
+        {
+          DzlTreeBuilder *builder = g_ptr_array_index (builders, i);
+
+          if (_dzl_tree_builder_node_draggable (builder, node))
+            return TRUE;
+        }
+    }
+
+  return FALSE;
+}
+
+static gboolean
+dzl_tree_store_drag_data_get (GtkTreeDragSource *source,
+                              GtkTreePath       *path,
+                              GtkSelectionData  *data)
+{
+  GtkTreeIter iter;
+
+  g_assert (DZL_IS_TREE_STORE (source));
+  g_assert (path != NULL);
+  g_assert (data != NULL);
+
+  if (gtk_tree_model_get_iter (GTK_TREE_MODEL (source), &iter, path))
+    {
+      g_autoptr(DzlTreeNode) node = NULL;
+      GPtrArray *builders;
+      DzlTree *tree;
+
+      gtk_tree_model_get (GTK_TREE_MODEL (source), &iter, 0, &node, -1);
+      g_assert (DZL_IS_TREE_NODE (node));
+
+      tree = dzl_tree_node_get_tree (node);
+      builders = _dzl_tree_get_builders (tree);
+
+      for (guint i = 0; i < builders->len; i++)
+        {
+          DzlTreeBuilder *builder = g_ptr_array_index (builders, i);
+
+          if (_dzl_tree_builder_drag_data_get (builder, node, data))
+            return TRUE;
+        }
+    }
+
+  return FALSE;
+}
+
+static gboolean
+dzl_tree_store_row_drop_possible (GtkTreeDragDest  *dest,
+                                  GtkTreePath      *path,
+                                  GtkSelectionData *data)
+{
+  GtkTreeIter iter;
+
+  g_assert (GTK_IS_TREE_DRAG_DEST (dest));
+  g_assert (path != NULL);
+  g_assert (data != NULL);
+
+  if (gtk_tree_model_get_iter (GTK_TREE_MODEL (dest), &iter, path))
+    {
+      g_autoptr(DzlTreeNode) node = NULL;
+      DzlTreeNode *effective;
+      GPtrArray *builders;
+      DzlTree *tree;
+
+      gtk_tree_model_get (GTK_TREE_MODEL (dest), &iter, 0, &node, -1);
+      g_assert (DZL_IS_TREE_NODE (node));
+
+      tree = dzl_tree_node_get_tree (node);
+      g_assert (DZL_IS_TREE (tree));
+
+      builders = _dzl_tree_get_builders (tree);
+      g_assert (builders != NULL);
+
+      if (dzl_tree_node_is_root (node))
+        return FALSE;
+
+      effective = _dzl_tree_node_is_dummy (node)
+                ?  dzl_tree_node_get_parent (node)
+                : node;
+
+      if (effective == NULL || dzl_tree_node_is_root (effective))
+        return FALSE;
+
+      g_assert (effective != NULL);
+      g_assert (!_dzl_tree_node_is_dummy (effective));
+      g_assert (!dzl_tree_node_is_root (effective));
+
+      for (guint i = 0; i < builders->len; i++)
+        {
+          DzlTreeBuilder *builder = g_ptr_array_index (builders, i);
+
+          if (_dzl_tree_builder_node_droppable (builder, effective, data))
+            return TRUE;
+        }
+    }
+
+  return FALSE;
+}
+
+static gboolean
+dzl_tree_store_drag_data_received (GtkTreeDragDest  *dest,
+                                   GtkTreePath      *path,
+                                   GtkSelectionData *data)
+{
+  DzlTreeStore *self = (DzlTreeStore *)dest;
+  g_autoptr(DzlTreeNode) drop_node = NULL;
+  GPtrArray *builders;
+  DzlTreeDropPosition pos = 0;
+
+  g_assert (GTK_IS_TREE_DRAG_DEST (self));
+  g_assert (self->tree != NULL);
+  g_assert (path != NULL);
+  g_assert (data != NULL);
+
+  builders = _dzl_tree_get_builders (self->tree);
+  drop_node = _dzl_tree_get_drop_node (self->tree, &pos);
+
+  /*
+   * If we have a drag/drop of a node onto/adjacent another node, then
+   * use the simplified drag_node_received API for the builders instead
+   * of making them extract the node information themselves.
+   */
+  if (gtk_selection_data_get_target (data) == gdk_atom_intern_static_string ("GTK_TREE_MODEL_ROW"))
+    {
+      g_autoptr(GtkTreePath) src_path = NULL;
+      GtkTreeModel *model = NULL;
+
+      if (gtk_tree_get_row_drag_data (data, &model, &src_path))
+        {
+          GtkTreeIter iter;
+
+          if (gtk_tree_model_get_iter (model, &iter, src_path))
+            {
+              g_autoptr(DzlTreeNode) drag_node = NULL;
+
+              gtk_tree_model_get (model, &iter, 0, &drag_node, -1);
+              g_assert (DZL_IS_TREE_NODE (drag_node));
+
+              for (guint i = 0; i < builders->len; i++)
+                {
+                  DzlTreeBuilder *builder = g_ptr_array_index (builders, i);
+
+                  g_assert (DZL_IS_TREE_BUILDER (builder));
+
+                  if (_dzl_tree_builder_drag_node_received (builder, drag_node, drop_node, pos, data))
+                    return TRUE;
+                }
+            }
+        }
+    }
+
+  for (guint i = 0; i < builders->len; i++)
+    {
+      DzlTreeBuilder *builder = g_ptr_array_index (builders, i);
+
+      g_assert (DZL_IS_TREE_BUILDER (builder));
+
+      if (_dzl_tree_builder_drag_data_received (builder, drop_node, pos, data))
+        return TRUE;
+    }
+
+  return FALSE;
+}
+
+static gboolean
+dzl_tree_store_drag_data_delete (GtkTreeDragSource *source,
+                                 GtkTreePath       *path)
+{
+  g_assert (GTK_IS_TREE_DRAG_SOURCE (source));
+  g_assert (path != NULL);
+
+  /* XXX: Handle drag data delete */
+
+  return FALSE;
+}
+
+static void
+dest_iface_init (GtkTreeDragDestIface *iface)
+{
+  iface->row_drop_possible = dzl_tree_store_row_drop_possible;
+  iface->drag_data_received = dzl_tree_store_drag_data_received;
+}
+
+static void
+source_iface_init (GtkTreeDragSourceIface *iface)
+{
+  iface->row_draggable = dzl_tree_store_row_draggable;
+  iface->drag_data_get = dzl_tree_store_drag_data_get;
+  iface->drag_data_delete = dzl_tree_store_drag_data_delete;
+}
+
+GtkTreeStore *
+_dzl_tree_store_new (DzlTree *tree)
+{
+  DzlTreeStore *self;
+
+  self = g_object_new (DZL_TYPE_TREE_STORE, NULL);
+  dzl_set_weak_pointer (&self->tree, tree);
+
+  return GTK_TREE_STORE (self);
+}
diff --git a/src/tree/dzl-tree-store.h b/src/tree/dzl-tree-store.h
new file mode 100644
index 0000000..e8d5c80
--- /dev/null
+++ b/src/tree/dzl-tree-store.h
@@ -0,0 +1,29 @@
+/* dzl-tree-store.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/>.
+ */
+
+#pragma once
+
+#include <gtk/gtk.h>
+
+G_BEGIN_DECLS
+
+#define DZL_TYPE_TREE_STORE (dzl_tree_store_get_type())
+
+G_DECLARE_FINAL_TYPE (DzlTreeStore, dzl_tree_store, DZL, TREE_STORE, GtkTreeStore)
+
+G_END_DECLS
diff --git a/src/tree/dzl-tree.c b/src/tree/dzl-tree.c
index d33bc99..e09d9fd 100644
--- a/src/tree/dzl-tree.c
+++ b/src/tree/dzl-tree.c
@@ -23,6 +23,7 @@
 #include "tree/dzl-tree.h"
 #include "tree/dzl-tree-node.h"
 #include "tree/dzl-tree-private.h"
+#include "tree/dzl-tree-store.h"
 #include "util/dzl-util-private.h"
 
 typedef struct
@@ -1174,7 +1175,7 @@ dzl_tree_init (DzlTree *self)
 
   priv->builders = g_ptr_array_new ();
   g_ptr_array_set_free_func (priv->builders, g_object_unref);
-  priv->store = gtk_tree_store_new (1, DZL_TYPE_TREE_NODE);
+  priv->store = _dzl_tree_store_new (self);
 
   selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (self));
   g_signal_connect_object (selection, "changed",
diff --git a/src/tree/meson.build b/src/tree/meson.build
index 5a03a47..222eca8 100644
--- a/src/tree/meson.build
+++ b/src/tree/meson.build
@@ -10,6 +10,7 @@ tree_sources = [
   'dzl-tree-builder.c',
   'dzl-tree.c',
   'dzl-tree-node.c',
+  'dzl-tree-store.c',
   'dzl-list-store-adapter.c',
 ]
 


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