[libdazzle] tree-store: add DnD store backend for DzlTree
- From: Christian Hergert <chergert src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [libdazzle] tree-store: add DnD store backend for DzlTree
- Date: Tue, 5 Dec 2017 10:23:17 +0000 (UTC)
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]