summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--ChangeLog55
-rw-r--r--ChangeLog.pre-2-055
-rw-r--r--ChangeLog.pre-2-1055
-rw-r--r--ChangeLog.pre-2-255
-rw-r--r--ChangeLog.pre-2-455
-rw-r--r--ChangeLog.pre-2-655
-rw-r--r--ChangeLog.pre-2-855
-rw-r--r--gtk/gtkliststore.c172
-rw-r--r--gtk/gtkliststore.h1
-rw-r--r--gtk/gtktreedatalist.c8
-rw-r--r--gtk/gtktreednd.c32
-rw-r--r--gtk/gtktreednd.h16
-rw-r--r--gtk/gtktreemodel.c169
-rw-r--r--gtk/gtktreemodel.h5
-rw-r--r--gtk/gtktreestore.c490
-rw-r--r--gtk/gtktreeview.c240
-rw-r--r--gtk/gtktreeview.h6
17 files changed, 1336 insertions, 188 deletions
diff --git a/ChangeLog b/ChangeLog
index 3d676d25e3..6f11860751 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,58 @@
+2001-01-30 Havoc Pennington <hp@redhat.com>
+
+ * gtk/gtkliststore.c (gtk_list_store_insert_before): fix bug in
+ here where prev pointer was set to the wrong thing
+
+ * gtk/gtktreemodel.c (gtk_tree_path_is_ancestor): new function
+ (gtk_tree_path_is_descendant): new function
+
+ * gtk/gtkliststore.c (gtk_list_store_iter_n_children): return
+ cached length
+ (gtk_list_store_get_iter): don't modify iter if we can't get the
+ path.
+
+ * gtk/gtkliststore.h (struct _GtkListStore): cache the length
+
+ * gtk/gtktreednd.h: add virtual function row_drop_possible() to
+ GtkTreeDragDest
+
+ * gtk/gtktreestore.c (copy_node_data): fix varargs type error that
+ was causing segfault
+
+ * gtk/gtktreedatalist.c (_gtk_tree_data_list_node_copy): set next
+ pointer to NULL
+
+ * gtk/gtktreestore.c (gtk_tree_store_append): fix memleak
+
+ * gtk/gtkliststore.c (gtk_list_store_iter_next): don't modify iter
+ on returning FALSE
+ (gtk_list_store_iter_children): ditto
+ (gtk_list_store_iter_nth_child): ditto
+ (gtk_list_store_iter_nth_child): ditto
+ (gtk_list_store_iter_parent): ditto
+
+ * gtk/gtktreestore.c (gtk_tree_store_get_path): g_return_if_fail
+ on iter->user_data != NULL instead of silently accepting it.
+ (gtk_tree_store_iter_next): ditto. Also, don't modify iter unless
+ we are returning TRUE.
+ (gtk_tree_store_iter_children): ditto
+ (gtk_tree_store_iter_nth_child): ditto
+ (gtk_tree_store_iter_parent): ditto
+ (gtk_tree_store_insert): remove handling of parent->user_data ==
+ NULL, replace with parent == NULL
+
+ * gtk/gtktreemodel.c (inserted_callback): put some fixes in here,
+ and a comment explaining things
+
+ * gtk/gtktreestore.c: add GtkTreeDragSource/GtkTreeDragDest
+ interface support to GtkTreeStore.
+
+ * gtk/gtktreemodel.c (gtk_tree_path_prev): didn't properly return
+ FALSE if no prev, fix
+
+ * gtk/gtktreeview.c (set_source_row): use a row reference
+ (set_dest_row): use a row reference
+
Sat Jan 27 15:52:02 2001 Jonathan Blandford <jrb@redhat.com>
* gtk/gtktreeselection.c (gtk_tree_selection_unselect_iter): Fix
diff --git a/ChangeLog.pre-2-0 b/ChangeLog.pre-2-0
index 3d676d25e3..6f11860751 100644
--- a/ChangeLog.pre-2-0
+++ b/ChangeLog.pre-2-0
@@ -1,3 +1,58 @@
+2001-01-30 Havoc Pennington <hp@redhat.com>
+
+ * gtk/gtkliststore.c (gtk_list_store_insert_before): fix bug in
+ here where prev pointer was set to the wrong thing
+
+ * gtk/gtktreemodel.c (gtk_tree_path_is_ancestor): new function
+ (gtk_tree_path_is_descendant): new function
+
+ * gtk/gtkliststore.c (gtk_list_store_iter_n_children): return
+ cached length
+ (gtk_list_store_get_iter): don't modify iter if we can't get the
+ path.
+
+ * gtk/gtkliststore.h (struct _GtkListStore): cache the length
+
+ * gtk/gtktreednd.h: add virtual function row_drop_possible() to
+ GtkTreeDragDest
+
+ * gtk/gtktreestore.c (copy_node_data): fix varargs type error that
+ was causing segfault
+
+ * gtk/gtktreedatalist.c (_gtk_tree_data_list_node_copy): set next
+ pointer to NULL
+
+ * gtk/gtktreestore.c (gtk_tree_store_append): fix memleak
+
+ * gtk/gtkliststore.c (gtk_list_store_iter_next): don't modify iter
+ on returning FALSE
+ (gtk_list_store_iter_children): ditto
+ (gtk_list_store_iter_nth_child): ditto
+ (gtk_list_store_iter_nth_child): ditto
+ (gtk_list_store_iter_parent): ditto
+
+ * gtk/gtktreestore.c (gtk_tree_store_get_path): g_return_if_fail
+ on iter->user_data != NULL instead of silently accepting it.
+ (gtk_tree_store_iter_next): ditto. Also, don't modify iter unless
+ we are returning TRUE.
+ (gtk_tree_store_iter_children): ditto
+ (gtk_tree_store_iter_nth_child): ditto
+ (gtk_tree_store_iter_parent): ditto
+ (gtk_tree_store_insert): remove handling of parent->user_data ==
+ NULL, replace with parent == NULL
+
+ * gtk/gtktreemodel.c (inserted_callback): put some fixes in here,
+ and a comment explaining things
+
+ * gtk/gtktreestore.c: add GtkTreeDragSource/GtkTreeDragDest
+ interface support to GtkTreeStore.
+
+ * gtk/gtktreemodel.c (gtk_tree_path_prev): didn't properly return
+ FALSE if no prev, fix
+
+ * gtk/gtktreeview.c (set_source_row): use a row reference
+ (set_dest_row): use a row reference
+
Sat Jan 27 15:52:02 2001 Jonathan Blandford <jrb@redhat.com>
* gtk/gtktreeselection.c (gtk_tree_selection_unselect_iter): Fix
diff --git a/ChangeLog.pre-2-10 b/ChangeLog.pre-2-10
index 3d676d25e3..6f11860751 100644
--- a/ChangeLog.pre-2-10
+++ b/ChangeLog.pre-2-10
@@ -1,3 +1,58 @@
+2001-01-30 Havoc Pennington <hp@redhat.com>
+
+ * gtk/gtkliststore.c (gtk_list_store_insert_before): fix bug in
+ here where prev pointer was set to the wrong thing
+
+ * gtk/gtktreemodel.c (gtk_tree_path_is_ancestor): new function
+ (gtk_tree_path_is_descendant): new function
+
+ * gtk/gtkliststore.c (gtk_list_store_iter_n_children): return
+ cached length
+ (gtk_list_store_get_iter): don't modify iter if we can't get the
+ path.
+
+ * gtk/gtkliststore.h (struct _GtkListStore): cache the length
+
+ * gtk/gtktreednd.h: add virtual function row_drop_possible() to
+ GtkTreeDragDest
+
+ * gtk/gtktreestore.c (copy_node_data): fix varargs type error that
+ was causing segfault
+
+ * gtk/gtktreedatalist.c (_gtk_tree_data_list_node_copy): set next
+ pointer to NULL
+
+ * gtk/gtktreestore.c (gtk_tree_store_append): fix memleak
+
+ * gtk/gtkliststore.c (gtk_list_store_iter_next): don't modify iter
+ on returning FALSE
+ (gtk_list_store_iter_children): ditto
+ (gtk_list_store_iter_nth_child): ditto
+ (gtk_list_store_iter_nth_child): ditto
+ (gtk_list_store_iter_parent): ditto
+
+ * gtk/gtktreestore.c (gtk_tree_store_get_path): g_return_if_fail
+ on iter->user_data != NULL instead of silently accepting it.
+ (gtk_tree_store_iter_next): ditto. Also, don't modify iter unless
+ we are returning TRUE.
+ (gtk_tree_store_iter_children): ditto
+ (gtk_tree_store_iter_nth_child): ditto
+ (gtk_tree_store_iter_parent): ditto
+ (gtk_tree_store_insert): remove handling of parent->user_data ==
+ NULL, replace with parent == NULL
+
+ * gtk/gtktreemodel.c (inserted_callback): put some fixes in here,
+ and a comment explaining things
+
+ * gtk/gtktreestore.c: add GtkTreeDragSource/GtkTreeDragDest
+ interface support to GtkTreeStore.
+
+ * gtk/gtktreemodel.c (gtk_tree_path_prev): didn't properly return
+ FALSE if no prev, fix
+
+ * gtk/gtktreeview.c (set_source_row): use a row reference
+ (set_dest_row): use a row reference
+
Sat Jan 27 15:52:02 2001 Jonathan Blandford <jrb@redhat.com>
* gtk/gtktreeselection.c (gtk_tree_selection_unselect_iter): Fix
diff --git a/ChangeLog.pre-2-2 b/ChangeLog.pre-2-2
index 3d676d25e3..6f11860751 100644
--- a/ChangeLog.pre-2-2
+++ b/ChangeLog.pre-2-2
@@ -1,3 +1,58 @@
+2001-01-30 Havoc Pennington <hp@redhat.com>
+
+ * gtk/gtkliststore.c (gtk_list_store_insert_before): fix bug in
+ here where prev pointer was set to the wrong thing
+
+ * gtk/gtktreemodel.c (gtk_tree_path_is_ancestor): new function
+ (gtk_tree_path_is_descendant): new function
+
+ * gtk/gtkliststore.c (gtk_list_store_iter_n_children): return
+ cached length
+ (gtk_list_store_get_iter): don't modify iter if we can't get the
+ path.
+
+ * gtk/gtkliststore.h (struct _GtkListStore): cache the length
+
+ * gtk/gtktreednd.h: add virtual function row_drop_possible() to
+ GtkTreeDragDest
+
+ * gtk/gtktreestore.c (copy_node_data): fix varargs type error that
+ was causing segfault
+
+ * gtk/gtktreedatalist.c (_gtk_tree_data_list_node_copy): set next
+ pointer to NULL
+
+ * gtk/gtktreestore.c (gtk_tree_store_append): fix memleak
+
+ * gtk/gtkliststore.c (gtk_list_store_iter_next): don't modify iter
+ on returning FALSE
+ (gtk_list_store_iter_children): ditto
+ (gtk_list_store_iter_nth_child): ditto
+ (gtk_list_store_iter_nth_child): ditto
+ (gtk_list_store_iter_parent): ditto
+
+ * gtk/gtktreestore.c (gtk_tree_store_get_path): g_return_if_fail
+ on iter->user_data != NULL instead of silently accepting it.
+ (gtk_tree_store_iter_next): ditto. Also, don't modify iter unless
+ we are returning TRUE.
+ (gtk_tree_store_iter_children): ditto
+ (gtk_tree_store_iter_nth_child): ditto
+ (gtk_tree_store_iter_parent): ditto
+ (gtk_tree_store_insert): remove handling of parent->user_data ==
+ NULL, replace with parent == NULL
+
+ * gtk/gtktreemodel.c (inserted_callback): put some fixes in here,
+ and a comment explaining things
+
+ * gtk/gtktreestore.c: add GtkTreeDragSource/GtkTreeDragDest
+ interface support to GtkTreeStore.
+
+ * gtk/gtktreemodel.c (gtk_tree_path_prev): didn't properly return
+ FALSE if no prev, fix
+
+ * gtk/gtktreeview.c (set_source_row): use a row reference
+ (set_dest_row): use a row reference
+
Sat Jan 27 15:52:02 2001 Jonathan Blandford <jrb@redhat.com>
* gtk/gtktreeselection.c (gtk_tree_selection_unselect_iter): Fix
diff --git a/ChangeLog.pre-2-4 b/ChangeLog.pre-2-4
index 3d676d25e3..6f11860751 100644
--- a/ChangeLog.pre-2-4
+++ b/ChangeLog.pre-2-4
@@ -1,3 +1,58 @@
+2001-01-30 Havoc Pennington <hp@redhat.com>
+
+ * gtk/gtkliststore.c (gtk_list_store_insert_before): fix bug in
+ here where prev pointer was set to the wrong thing
+
+ * gtk/gtktreemodel.c (gtk_tree_path_is_ancestor): new function
+ (gtk_tree_path_is_descendant): new function
+
+ * gtk/gtkliststore.c (gtk_list_store_iter_n_children): return
+ cached length
+ (gtk_list_store_get_iter): don't modify iter if we can't get the
+ path.
+
+ * gtk/gtkliststore.h (struct _GtkListStore): cache the length
+
+ * gtk/gtktreednd.h: add virtual function row_drop_possible() to
+ GtkTreeDragDest
+
+ * gtk/gtktreestore.c (copy_node_data): fix varargs type error that
+ was causing segfault
+
+ * gtk/gtktreedatalist.c (_gtk_tree_data_list_node_copy): set next
+ pointer to NULL
+
+ * gtk/gtktreestore.c (gtk_tree_store_append): fix memleak
+
+ * gtk/gtkliststore.c (gtk_list_store_iter_next): don't modify iter
+ on returning FALSE
+ (gtk_list_store_iter_children): ditto
+ (gtk_list_store_iter_nth_child): ditto
+ (gtk_list_store_iter_nth_child): ditto
+ (gtk_list_store_iter_parent): ditto
+
+ * gtk/gtktreestore.c (gtk_tree_store_get_path): g_return_if_fail
+ on iter->user_data != NULL instead of silently accepting it.
+ (gtk_tree_store_iter_next): ditto. Also, don't modify iter unless
+ we are returning TRUE.
+ (gtk_tree_store_iter_children): ditto
+ (gtk_tree_store_iter_nth_child): ditto
+ (gtk_tree_store_iter_parent): ditto
+ (gtk_tree_store_insert): remove handling of parent->user_data ==
+ NULL, replace with parent == NULL
+
+ * gtk/gtktreemodel.c (inserted_callback): put some fixes in here,
+ and a comment explaining things
+
+ * gtk/gtktreestore.c: add GtkTreeDragSource/GtkTreeDragDest
+ interface support to GtkTreeStore.
+
+ * gtk/gtktreemodel.c (gtk_tree_path_prev): didn't properly return
+ FALSE if no prev, fix
+
+ * gtk/gtktreeview.c (set_source_row): use a row reference
+ (set_dest_row): use a row reference
+
Sat Jan 27 15:52:02 2001 Jonathan Blandford <jrb@redhat.com>
* gtk/gtktreeselection.c (gtk_tree_selection_unselect_iter): Fix
diff --git a/ChangeLog.pre-2-6 b/ChangeLog.pre-2-6
index 3d676d25e3..6f11860751 100644
--- a/ChangeLog.pre-2-6
+++ b/ChangeLog.pre-2-6
@@ -1,3 +1,58 @@
+2001-01-30 Havoc Pennington <hp@redhat.com>
+
+ * gtk/gtkliststore.c (gtk_list_store_insert_before): fix bug in
+ here where prev pointer was set to the wrong thing
+
+ * gtk/gtktreemodel.c (gtk_tree_path_is_ancestor): new function
+ (gtk_tree_path_is_descendant): new function
+
+ * gtk/gtkliststore.c (gtk_list_store_iter_n_children): return
+ cached length
+ (gtk_list_store_get_iter): don't modify iter if we can't get the
+ path.
+
+ * gtk/gtkliststore.h (struct _GtkListStore): cache the length
+
+ * gtk/gtktreednd.h: add virtual function row_drop_possible() to
+ GtkTreeDragDest
+
+ * gtk/gtktreestore.c (copy_node_data): fix varargs type error that
+ was causing segfault
+
+ * gtk/gtktreedatalist.c (_gtk_tree_data_list_node_copy): set next
+ pointer to NULL
+
+ * gtk/gtktreestore.c (gtk_tree_store_append): fix memleak
+
+ * gtk/gtkliststore.c (gtk_list_store_iter_next): don't modify iter
+ on returning FALSE
+ (gtk_list_store_iter_children): ditto
+ (gtk_list_store_iter_nth_child): ditto
+ (gtk_list_store_iter_nth_child): ditto
+ (gtk_list_store_iter_parent): ditto
+
+ * gtk/gtktreestore.c (gtk_tree_store_get_path): g_return_if_fail
+ on iter->user_data != NULL instead of silently accepting it.
+ (gtk_tree_store_iter_next): ditto. Also, don't modify iter unless
+ we are returning TRUE.
+ (gtk_tree_store_iter_children): ditto
+ (gtk_tree_store_iter_nth_child): ditto
+ (gtk_tree_store_iter_parent): ditto
+ (gtk_tree_store_insert): remove handling of parent->user_data ==
+ NULL, replace with parent == NULL
+
+ * gtk/gtktreemodel.c (inserted_callback): put some fixes in here,
+ and a comment explaining things
+
+ * gtk/gtktreestore.c: add GtkTreeDragSource/GtkTreeDragDest
+ interface support to GtkTreeStore.
+
+ * gtk/gtktreemodel.c (gtk_tree_path_prev): didn't properly return
+ FALSE if no prev, fix
+
+ * gtk/gtktreeview.c (set_source_row): use a row reference
+ (set_dest_row): use a row reference
+
Sat Jan 27 15:52:02 2001 Jonathan Blandford <jrb@redhat.com>
* gtk/gtktreeselection.c (gtk_tree_selection_unselect_iter): Fix
diff --git a/ChangeLog.pre-2-8 b/ChangeLog.pre-2-8
index 3d676d25e3..6f11860751 100644
--- a/ChangeLog.pre-2-8
+++ b/ChangeLog.pre-2-8
@@ -1,3 +1,58 @@
+2001-01-30 Havoc Pennington <hp@redhat.com>
+
+ * gtk/gtkliststore.c (gtk_list_store_insert_before): fix bug in
+ here where prev pointer was set to the wrong thing
+
+ * gtk/gtktreemodel.c (gtk_tree_path_is_ancestor): new function
+ (gtk_tree_path_is_descendant): new function
+
+ * gtk/gtkliststore.c (gtk_list_store_iter_n_children): return
+ cached length
+ (gtk_list_store_get_iter): don't modify iter if we can't get the
+ path.
+
+ * gtk/gtkliststore.h (struct _GtkListStore): cache the length
+
+ * gtk/gtktreednd.h: add virtual function row_drop_possible() to
+ GtkTreeDragDest
+
+ * gtk/gtktreestore.c (copy_node_data): fix varargs type error that
+ was causing segfault
+
+ * gtk/gtktreedatalist.c (_gtk_tree_data_list_node_copy): set next
+ pointer to NULL
+
+ * gtk/gtktreestore.c (gtk_tree_store_append): fix memleak
+
+ * gtk/gtkliststore.c (gtk_list_store_iter_next): don't modify iter
+ on returning FALSE
+ (gtk_list_store_iter_children): ditto
+ (gtk_list_store_iter_nth_child): ditto
+ (gtk_list_store_iter_nth_child): ditto
+ (gtk_list_store_iter_parent): ditto
+
+ * gtk/gtktreestore.c (gtk_tree_store_get_path): g_return_if_fail
+ on iter->user_data != NULL instead of silently accepting it.
+ (gtk_tree_store_iter_next): ditto. Also, don't modify iter unless
+ we are returning TRUE.
+ (gtk_tree_store_iter_children): ditto
+ (gtk_tree_store_iter_nth_child): ditto
+ (gtk_tree_store_iter_parent): ditto
+ (gtk_tree_store_insert): remove handling of parent->user_data ==
+ NULL, replace with parent == NULL
+
+ * gtk/gtktreemodel.c (inserted_callback): put some fixes in here,
+ and a comment explaining things
+
+ * gtk/gtktreestore.c: add GtkTreeDragSource/GtkTreeDragDest
+ interface support to GtkTreeStore.
+
+ * gtk/gtktreemodel.c (gtk_tree_path_prev): didn't properly return
+ FALSE if no prev, fix
+
+ * gtk/gtktreeview.c (set_source_row): use a row reference
+ (set_dest_row): use a row reference
+
Sat Jan 27 15:52:02 2001 Jonathan Blandford <jrb@redhat.com>
* gtk/gtktreeselection.c (gtk_tree_selection_unselect_iter): Fix
diff --git a/gtk/gtkliststore.c b/gtk/gtkliststore.c
index ef3300430f..2191146157 100644
--- a/gtk/gtkliststore.c
+++ b/gtk/gtkliststore.c
@@ -80,7 +80,20 @@ static gboolean gtk_list_store_drag_data_get (GtkTreeDragSource *drag_sourc
static gboolean gtk_list_store_drag_data_received (GtkTreeDragDest *drag_dest,
GtkTreePath *dest,
GtkSelectionData *selection_data);
-
+static gboolean gtk_list_store_row_drop_possible (GtkTreeDragDest *drag_dest,
+ GtkTreeModel *src_model,
+ GtkTreePath *src_path,
+ GtkTreePath *dest_path);
+static void
+validate_list_store (GtkListStore *list_store)
+{
+ if (gtk_debug_flags & GTK_DEBUG_TREE)
+ {
+ g_assert (g_slist_length (list_store->root) == list_store->length);
+
+ g_assert (g_slist_last (list_store->root) == list_store->tail);
+ }
+}
GtkType
gtk_list_store_get_type (void)
@@ -210,6 +223,7 @@ static void
gtk_list_store_drag_dest_init (GtkTreeDragDestIface *iface)
{
iface->drag_data_received = gtk_list_store_drag_data_received;
+ iface->row_drop_possible = gtk_list_store_row_drop_possible;
}
static void
@@ -218,6 +232,7 @@ gtk_list_store_init (GtkListStore *list_store)
list_store->root = NULL;
list_store->tail = NULL;
list_store->stamp = g_random_int ();
+ list_store->length = 0;
}
GtkListStore *
@@ -323,14 +338,26 @@ gtk_list_store_get_iter (GtkTreeModel *tree_model,
GtkTreeIter *iter,
GtkTreePath *path)
{
+ GSList *list;
+ gint i;
+
g_return_val_if_fail (GTK_IS_LIST_STORE (tree_model), FALSE);
- g_return_val_if_fail (gtk_tree_path_get_depth (path) > 0, FALSE);
+ g_return_val_if_fail (gtk_tree_path_get_depth (path) > 0, FALSE);
+
+ i = gtk_tree_path_get_indices (path)[0];
+
+ if (i >= GTK_LIST_STORE (tree_model)->length)
+ return FALSE;
- iter->stamp = GTK_LIST_STORE (tree_model)->stamp;
- iter->user_data = g_slist_nth (G_SLIST (GTK_LIST_STORE (tree_model)->root),
- gtk_tree_path_get_indices (path)[0]);
+ list = g_slist_nth (G_SLIST (GTK_LIST_STORE (tree_model)->root),
+ i);
- return iter->user_data != NULL;
+ /* If this fails, list_store->length has gotten mangled. */
+ g_assert (list);
+
+ iter->stamp = GTK_LIST_STORE (tree_model)->stamp;
+ iter->user_data = list;
+ return TRUE;
}
static GtkTreePath *
@@ -391,9 +418,13 @@ gtk_list_store_iter_next (GtkTreeModel *tree_model,
g_return_val_if_fail (GTK_IS_LIST_STORE (tree_model), FALSE);
g_return_val_if_fail (GTK_LIST_STORE (tree_model)->stamp == iter->stamp, FALSE);
- iter->user_data = G_SLIST (iter->user_data)->next;
-
- return (iter->user_data != NULL);
+ if (G_SLIST (iter->user_data)->next)
+ {
+ iter->user_data = G_SLIST (iter->user_data)->next;
+ return TRUE;
+ }
+ else
+ return FALSE;
}
static gboolean
@@ -401,18 +432,22 @@ gtk_list_store_iter_children (GtkTreeModel *tree_model,
GtkTreeIter *iter,
GtkTreeIter *parent)
{
+ /* this is a list, nodes have no children */
if (parent)
- {
- iter->stamp = 0;
- iter->user_data = NULL;
- return FALSE;
- }
- else
+ return FALSE;
+
+ /* but if parent == NULL we return the list itself as children of the
+ * "root"
+ */
+
+ if (GTK_LIST_STORE (tree_model)->root)
{
iter->stamp = GTK_LIST_STORE (tree_model)->stamp;
iter->user_data = GTK_LIST_STORE (tree_model)->root;
return TRUE;
}
+ else
+ return FALSE;
}
static gboolean
@@ -427,9 +462,9 @@ gtk_list_store_iter_n_children (GtkTreeModel *tree_model,
GtkTreeIter *iter)
{
if (iter == NULL)
- return g_slist_length (G_SLIST (GTK_LIST_STORE (tree_model)->root));
-
- return 0;
+ return GTK_LIST_STORE (tree_model)->length;
+ else
+ return 0;
}
static gboolean
@@ -438,24 +473,23 @@ gtk_list_store_iter_nth_child (GtkTreeModel *tree_model,
GtkTreeIter *parent,
gint n)
{
+ GSList *child;
+
g_return_val_if_fail (GTK_IS_LIST_STORE (tree_model), FALSE);
if (parent)
- {
- g_return_val_if_fail (iter->stamp == GTK_LIST_STORE (tree_model)->stamp, FALSE);
- iter->stamp = 0;
- iter->user_data = NULL;
+ return FALSE;
- return FALSE;
- }
+ child = g_slist_nth (G_SLIST (GTK_LIST_STORE (tree_model)->root), n);
- iter->user_data = g_slist_nth (G_SLIST (GTK_LIST_STORE (tree_model)->root), n);
- if (iter->user_data)
- iter->stamp = GTK_LIST_STORE (tree_model)->stamp;
+ if (child)
+ {
+ iter->user_data = child;
+ iter->stamp = GTK_LIST_STORE (tree_model)->stamp;
+ return TRUE;
+ }
else
- iter->stamp = 0;
-
- return (iter->user_data != NULL);
+ return FALSE;
}
static gboolean
@@ -463,9 +497,6 @@ gtk_list_store_iter_parent (GtkTreeModel *tree_model,
GtkTreeIter *iter,
GtkTreeIter *child)
{
- iter->stamp = 0;
- iter->user_data = NULL;
-
return FALSE;
}
@@ -674,11 +705,12 @@ remove_link_saving_prev (GSList *list,
if (tmp == link)
{
if (prev)
- prev->next = tmp->next;
- if (list == tmp)
+ prev->next = link->next;
+
+ if (list == link)
list = list->next;
- tmp->next = NULL;
+ link->next = NULL;
break;
}
@@ -709,6 +741,8 @@ gtk_list_store_remove_silently (GtkListStore *list_store,
list_store->root = remove_link_saving_prev (G_SLIST (list_store->root),
G_SLIST (iter->user_data),
&prev);
+
+ list_store->length -= 1;
if (iter->user_data == list_store->tail)
list_store->tail = prev;
@@ -725,13 +759,16 @@ gtk_list_store_remove (GtkListStore *list_store,
g_return_if_fail (list_store != NULL);
g_return_if_fail (GTK_IS_LIST_STORE (list_store));
- g_return_if_fail (iter->user_data != NULL);
-
+ g_return_if_fail (iter->user_data != NULL);
path = gtk_list_store_get_path (GTK_TREE_MODEL (list_store), iter);
+ validate_list_store (list_store);
+
gtk_list_store_remove_silently (list_store, iter, path);
+ validate_list_store (list_store);
+
gtk_signal_emit_by_name (GTK_OBJECT (list_store),
"deleted",
path);
@@ -753,6 +790,8 @@ insert_after (GtkListStore *list_store,
/* if list was the tail, the new node is the new tail */
if (sibling == list_store->tail)
list_store->tail = new_list;
+
+ list_store->length += 1;
}
void
@@ -789,6 +828,8 @@ gtk_list_store_insert (GtkListStore *list_store,
iter->stamp = list_store->stamp;
iter->user_data = new_list;
+
+ validate_list_store (list_store);
path = gtk_tree_path_new ();
gtk_tree_path_append_index (path, position);
@@ -819,7 +860,8 @@ gtk_list_store_insert_before (GtkListStore *list_store,
new_list = g_slist_alloc ();
- prev = list = list_store->root;
+ prev = NULL;
+ list = list_store->root;
while (list && list != sibling->user_data)
{
prev = list;
@@ -854,6 +896,10 @@ gtk_list_store_insert_before (GtkListStore *list_store,
iter->stamp = list_store->stamp;
iter->user_data = new_list;
+
+ list_store->length += 1;
+
+ validate_list_store (list_store);
path = gtk_tree_path_new ();
gtk_tree_path_append_index (path, i);
@@ -895,6 +941,8 @@ gtk_list_store_insert_after (GtkListStore *list_store,
iter->stamp = list_store->stamp;
iter->user_data = new_list;
+
+ validate_list_store (list_store);
path = gtk_tree_path_new ();
gtk_tree_path_append_index (path, i);
@@ -923,6 +971,10 @@ gtk_list_store_prepend (GtkListStore *list_store,
G_SLIST (iter->user_data)->next = G_SLIST (list_store->root);
list_store->root = iter->user_data;
+ list_store->length += 1;
+
+ validate_list_store (list_store);
+
path = gtk_tree_path_new ();
gtk_tree_path_append_index (path, 0);
gtk_signal_emit_by_name (GTK_OBJECT (list_store),
@@ -951,6 +1003,10 @@ gtk_list_store_append (GtkListStore *list_store,
list_store->root = iter->user_data;
list_store->tail = iter->user_data;
+
+ list_store->length += 1;
+
+ validate_list_store (list_store);
path = gtk_tree_path_new ();
gtk_tree_path_append_index (path, i);
@@ -1037,7 +1093,10 @@ gtk_list_store_drag_data_received (GtkTreeDragDest *drag_dest,
if (!gtk_tree_model_get_iter (src_model,
&src_iter,
src_path))
- goto out;
+ {
+ g_print ("can't get source path as iter\n");
+ goto out;
+ }
/* Get the path to insert _after_ (dest is the path to insert _before_) */
prev = gtk_tree_path_copy (dest);
@@ -1051,6 +1110,8 @@ gtk_list_store_drag_data_received (GtkTreeDragDest *drag_dest,
&dest_iter);
retval = TRUE;
+
+ g_print ("prepending to list\n");
}
else
{
@@ -1063,7 +1124,11 @@ gtk_list_store_drag_data_received (GtkTreeDragDest *drag_dest,
&dest_iter,
&tmp_iter);
retval = TRUE;
+
+ g_print ("inserting into list\n");
}
+ else
+ g_print ("can't get iter to insert after\n");
}
gtk_tree_path_free (prev);
@@ -1111,6 +1176,7 @@ gtk_list_store_drag_data_received (GtkTreeDragDest *drag_dest,
/* FIXME maybe add some data targets eventually, or handle text
* targets in the simple case.
*/
+ g_print ("not accepting target\n");
}
out:
@@ -1120,3 +1186,29 @@ gtk_list_store_drag_data_received (GtkTreeDragDest *drag_dest,
return retval;
}
+
+static gboolean
+gtk_list_store_row_drop_possible (GtkTreeDragDest *drag_dest,
+ GtkTreeModel *src_model,
+ GtkTreePath *src_path,
+ GtkTreePath *dest_path)
+{
+ gint *indices;
+
+ g_return_val_if_fail (GTK_IS_LIST_STORE (drag_dest), FALSE);
+
+ if (src_model != GTK_TREE_MODEL (drag_dest))
+ return FALSE;
+
+ if (gtk_tree_path_get_depth (dest_path) != 1)
+ return FALSE;
+
+ /* can drop before any existing node, or before one past any existing. */
+
+ indices = gtk_tree_path_get_indices (dest_path);
+
+ if (indices[0] <= GTK_LIST_STORE (drag_dest)->length)
+ return TRUE;
+ else
+ return FALSE;
+}
diff --git a/gtk/gtkliststore.h b/gtk/gtkliststore.h
index 55ad276a01..de591de53f 100644
--- a/gtk/gtkliststore.h
+++ b/gtk/gtkliststore.h
@@ -45,6 +45,7 @@ struct _GtkListStore
GSList *tail;
gint n_columns;
GType *column_headers;
+ gint length;
};
struct _GtkListStoreClass
diff --git a/gtk/gtktreedatalist.c b/gtk/gtktreedatalist.c
index b55b730af5..862a64107b 100644
--- a/gtk/gtktreedatalist.c
+++ b/gtk/gtktreedatalist.c
@@ -239,9 +239,12 @@ _gtk_tree_data_list_node_copy (GtkTreeDataList *list,
GType type)
{
GtkTreeDataList *new_list;
+
+ g_return_val_if_fail (list != NULL, NULL);
new_list = _gtk_tree_data_list_alloc ();
-
+ new_list->next = NULL;
+
switch (type)
{
case G_TYPE_UINT:
@@ -279,3 +282,6 @@ _gtk_tree_data_list_node_copy (GtkTreeDataList *list,
return new_list;
}
+
+
+
diff --git a/gtk/gtktreednd.c b/gtk/gtktreednd.c
index f798022c25..bdf9e4abde 100644
--- a/gtk/gtktreednd.c
+++ b/gtk/gtktreednd.c
@@ -155,6 +155,38 @@ gtk_tree_drag_dest_drag_data_received (GtkTreeDragDest *drag_dest,
return (* iface->drag_data_received) (drag_dest, dest, selection_data);
}
+
+/**
+ * gtk_tree_drag_dest_drop_possible:
+ * @drag_dest: a #GtkTreeDragDest
+ * @src_model: #GtkTreeModel being dragged from
+ * @src_path: row being dragged
+ * @dest_path: destination row
+ *
+ * Determines whether a drop is possible before the given @dest_path,
+ * at the same depth as @dest_path. i.e., can we drop @src_model such
+ * that it now resides at @dest_path. @dest_path does not have to
+ * exist; the return value will almost certainly be %FALSE if the
+ * parent of @dest_path doesn't exist, though.
+ *
+ * Return value: %TRUE if a drop is possible before @dest_path
+ **/
+gboolean
+gtk_tree_drag_dest_row_drop_possible (GtkTreeDragDest *drag_dest,
+ GtkTreeModel *src_model,
+ GtkTreePath *src_path,
+ GtkTreePath *dest_path)
+{
+ GtkTreeDragDestIface *iface = GTK_TREE_DRAG_DEST_GET_IFACE (drag_dest);
+
+ g_return_val_if_fail (iface->row_drop_possible != NULL, FALSE);
+ g_return_val_if_fail (GTK_IS_TREE_MODEL (src_model), FALSE);
+ g_return_val_if_fail (src_path != NULL, FALSE);
+ g_return_val_if_fail (dest_path != NULL, FALSE);
+
+ return (* iface->row_drop_possible) (drag_dest, src_model, src_path, dest_path);
+}
+
typedef struct _TreeRowData TreeRowData;
struct _TreeRowData
diff --git a/gtk/gtktreednd.h b/gtk/gtktreednd.h
index 1257ed25f6..8e9513ec24 100644
--- a/gtk/gtktreednd.h
+++ b/gtk/gtktreednd.h
@@ -41,11 +41,11 @@ struct _GtkTreeDragSourceIface
/* VTable - not signals */
- gboolean (* drag_data_get) (GtkTreeDragSource *dragsource,
+ gboolean (* drag_data_get) (GtkTreeDragSource *drag_source,
GtkTreePath *path,
GtkSelectionData *selection_data);
- gboolean (* drag_data_delete) (GtkTreeDragSource *dragsource,
+ gboolean (* drag_data_delete) (GtkTreeDragSource *drag_source,
GtkTreePath *path);
};
@@ -76,10 +76,14 @@ struct _GtkTreeDragDestIface
/* VTable - not signals */
- gboolean (* drag_data_received) (GtkTreeDragDest *dragdest,
+ gboolean (* drag_data_received) (GtkTreeDragDest *drag_dest,
GtkTreePath *dest,
GtkSelectionData *selection_data);
+ gboolean (* row_drop_possible) (GtkTreeDragDest *drag_dest,
+ GtkTreeModel *src_model,
+ GtkTreePath *src_path,
+ GtkTreePath *dest_path);
};
GType gtk_tree_drag_dest_get_type (void) G_GNUC_CONST;
@@ -91,6 +95,12 @@ gboolean gtk_tree_drag_dest_drag_data_received (GtkTreeDragDest *drag_dest,
GtkTreePath *dest,
GtkSelectionData *selection_data);
+/* Returns TRUE if we can drop before path; path may not exist. */
+gboolean gtk_tree_drag_dest_row_drop_possible (GtkTreeDragDest *drag_dest,
+ GtkTreeModel *src_model,
+ GtkTreePath *src_path,
+ GtkTreePath *dest_path);
+
/* The selection data would normally have target type GTK_TREE_MODEL_ROW in this
* case. If the target is wrong these functions return FALSE.
*/
diff --git a/gtk/gtktreemodel.c b/gtk/gtktreemodel.c
index 2b719a3d49..da6e5feea8 100644
--- a/gtk/gtktreemodel.c
+++ b/gtk/gtktreemodel.c
@@ -323,6 +323,73 @@ gtk_tree_path_compare (const GtkTreePath *a,
}
/**
+ * gtk_tree_path_is_ancestor:
+ * @path: a #GtkTreePath
+ * @descendant: another #GtkTreePath
+ *
+ *
+ *
+ * Return value: %TRUE if @descendant is contained inside @path
+ **/
+gboolean
+gtk_tree_path_is_ancestor (GtkTreePath *path,
+ GtkTreePath *descendant)
+{
+ gint i;
+
+ g_return_val_if_fail (path != NULL, FALSE);
+ g_return_val_if_fail (descendant != NULL, FALSE);
+
+ /* can't be an ancestor if we're deeper */
+ if (path->depth >= descendant->depth)
+ return FALSE;
+
+ i = 0;
+ while (i < path->depth)
+ {
+ if (path->indices[i] != descendant->indices[i])
+ return FALSE;
+ ++i;
+ }
+
+ return TRUE;
+}
+
+/**
+ * gtk_tree_path_is_descendant:
+ * @path: a #GtkTreePath
+ * @ancestor: another #GtkTreePath
+ *
+ *
+ *
+ * Return value: %TRUE if @ancestor contains @path somewhere below it
+ **/
+gboolean
+gtk_tree_path_is_descendant (GtkTreePath *path,
+ GtkTreePath *ancestor)
+{
+ gint i;
+
+ g_return_val_if_fail (path != NULL, FALSE);
+ g_return_val_if_fail (ancestor != NULL, FALSE);
+
+ /* can't be a descendant if we're shallower in the tree */
+ if (path->depth <= ancestor->depth)
+ return FALSE;
+
+ i = 0;
+ while (i < ancestor->depth)
+ {
+ if (path->indices[i] != ancestor->indices[i])
+ return FALSE;
+ ++i;
+ }
+
+ return TRUE;
+}
+
+
+/**
* gtk_tree_path_next:
* @path: A #GtkTreePath.
*
@@ -350,10 +417,10 @@ gtk_tree_path_prev (GtkTreePath *path)
{
g_return_val_if_fail (path != NULL, FALSE);
- if (path->indices[path->depth] == 0)
+ if (path->indices[path->depth - 1] == 0)
return FALSE;
- path->indices[path->depth - 1] --;
+ path->indices[path->depth - 1] -= 1;
return TRUE;
}
@@ -437,6 +504,15 @@ inserted_callback (GtkTreeModel *tree_model,
RowRefList *refs = data;
GSList *tmp_list;
+ /* This function corrects the path stored in the reference to
+ * account for an insertion. Note that it's called _after_ the insertion
+ * with the path to the newly-inserted row. Which means that
+ * the inserted path is in a different "coordinate system" than
+ * the old path (e.g. if the inserted path was just before the old path,
+ * then inserted path and old path will be the same, and old path must be
+ * moved down one).
+ */
+
tmp_list = refs->list;
while (tmp_list != NULL)
@@ -449,40 +525,21 @@ inserted_callback (GtkTreeModel *tree_model,
if (reference->path)
{
- gint i;
gint depth = gtk_tree_path_get_depth (path);
- gint *indices = gtk_tree_path_get_indices (path);
gint ref_depth = gtk_tree_path_get_depth (reference->path);
- gint *ref_indices = gtk_tree_path_get_indices (reference->path);
-
- for (i = 0; i < depth && i < ref_depth; i++)
+
+ if (ref_depth >= depth)
{
- if (indices[i] < ref_indices[i])
- {
- /* inserted node was before the referenced row;
- * move referenced path down 1
- */
- ref_indices[i] += 1;
- break;
- }
- else if (indices[i] > ref_indices[i])
- {
- /* inserted node was past the referenced row */
- break;
- }
- else if (i == depth - 1)
- {
- /* referenced row or its parent was inserted, this
- * is possible if you create the path and row reference
- * before you actually insert the row.
- */
- break;
- }
+ gint *indices = gtk_tree_path_get_indices (path);
+ gint *ref_indices = gtk_tree_path_get_indices (reference->path);
+ gint i;
+
+ /* This is the depth that might affect us. */
+ i = depth - 1;
+
+ if (indices[i] <= ref_indices[i])
+ ref_indices[i] += 1;
}
-
- /* If we didn't break out of the for loop, the inserted path
- * was a child of the referenced path
- */
}
tmp_list = g_slist_next (tmp_list);
@@ -497,6 +554,17 @@ deleted_callback (GtkTreeModel *tree_model,
RowRefList *refs = data;
GSList *tmp_list;
+ /* This function corrects the path stored in the reference to
+ * account for an deletion. Note that it's called _after_ the
+ * deletion with the old path of the just-deleted row. Which means
+ * that the deleted path is the same now-defunct "coordinate system"
+ * as the path saved in the reference, which is what we want to fix.
+ *
+ * Note that this is different from the situation in "inserted," so
+ * while you might think you can cut-and-paste between these
+ * functions, it's not going to work. ;-)
+ */
+
tmp_list = refs->list;
while (tmp_list != NULL)
@@ -509,41 +577,29 @@ deleted_callback (GtkTreeModel *tree_model,
if (reference->path)
{
- gint i;
gint depth = gtk_tree_path_get_depth (path);
- gint *indices = gtk_tree_path_get_indices (path);
gint ref_depth = gtk_tree_path_get_depth (reference->path);
- gint *ref_indices = gtk_tree_path_get_indices (reference->path);
- for (i = 0; i < depth && i < ref_depth; i++)
+ if (ref_depth >= depth)
{
+ /* Need to adjust path upward */
+ gint *indices = gtk_tree_path_get_indices (path);
+ gint *ref_indices = gtk_tree_path_get_indices (reference->path);
+ gint i;
+
+ i = depth - 1;
if (indices[i] < ref_indices[i])
+ ref_indices[i] -= 1;
+ else if (indices[i] == ref_indices[i])
{
- /* deleted node was before the referenced row;
- * move referenced path up 1
- */
- ref_indices[i] -= 1;
- break;
- }
- else if (indices[i] > ref_indices[i])
- {
- /* deleted node is past the referenced row */
- break;
- }
- else if (i == depth - 1)
- {
- /* referenced row or its parent was deleted, mark it
- * invalid
+ /* the referenced node itself, or its parent, was
+ * deleted, mark invalid
*/
+
gtk_tree_path_free (reference->path);
reference->path = NULL;
- break;
}
}
-
- /* If we didn't break out of the for loop, the deleted path
- * was a child of the referenced path
- */
}
tmp_list = g_slist_next (tmp_list);
@@ -722,7 +778,6 @@ gtk_tree_iter_free (GtkTreeIter *iter)
g_return_if_fail (iter != NULL);
g_free (iter);
-
}
/**
diff --git a/gtk/gtktreemodel.h b/gtk/gtktreemodel.h
index 202d874bcf..3ede12308b 100644
--- a/gtk/gtktreemodel.h
+++ b/gtk/gtktreemodel.h
@@ -134,6 +134,11 @@ gboolean gtk_tree_path_prev (GtkTreePath *path);
gboolean gtk_tree_path_up (GtkTreePath *path);
void gtk_tree_path_down (GtkTreePath *path);
+gboolean gtk_tree_path_is_ancestor (GtkTreePath *path,
+ GtkTreePath *descendant);
+gboolean gtk_tree_path_is_descendant (GtkTreePath *path,
+ GtkTreePath *ancestor);
+
/* Row reference (an object that tracks model changes so it refers to the
* same row always; a path refers to a position, not a fixed row)
*/
diff --git a/gtk/gtktreestore.c b/gtk/gtktreestore.c
index aa8c658368..d44c468197 100644
--- a/gtk/gtktreestore.c
+++ b/gtk/gtktreestore.c
@@ -20,6 +20,7 @@
#include "gtktreemodel.h"
#include "gtktreestore.h"
#include "gtktreedatalist.h"
+#include "gtktreednd.h"
#include "gtksignal.h"
#include <string.h>
#include <gobject/gvaluecollector.h>
@@ -40,6 +41,8 @@ static guint tree_store_signals[LAST_SIGNAL] = { 0 };
static void gtk_tree_store_init (GtkTreeStore *tree_store);
static void gtk_tree_store_class_init (GtkTreeStoreClass *tree_store_class);
static void gtk_tree_store_tree_model_init (GtkTreeModelIface *iface);
+static void gtk_tree_store_drag_source_init(GtkTreeDragSourceIface *iface);
+static void gtk_tree_store_drag_dest_init (GtkTreeDragDestIface *iface);
static guint gtk_tree_store_get_flags (GtkTreeModel *tree_model);
static gint gtk_tree_store_get_n_columns (GtkTreeModel *tree_model);
static GType gtk_tree_store_get_column_type (GtkTreeModel *tree_model,
@@ -68,6 +71,32 @@ static gboolean gtk_tree_store_iter_parent (GtkTreeModel *tree_mode
GtkTreeIter *child);
+static gboolean gtk_tree_store_drag_data_delete (GtkTreeDragSource *drag_source,
+ GtkTreePath *path);
+static gboolean gtk_tree_store_drag_data_get (GtkTreeDragSource *drag_source,
+ GtkTreePath *path,
+ GtkSelectionData *selection_data);
+static gboolean gtk_tree_store_drag_data_received (GtkTreeDragDest *drag_dest,
+ GtkTreePath *dest,
+ GtkSelectionData *selection_data);
+static gboolean gtk_tree_store_row_drop_possible (GtkTreeDragDest *drag_dest,
+ GtkTreeModel *src_model,
+ GtkTreePath *src_path,
+ GtkTreePath *dest_path);
+
+static void validate_gnode (GNode *node);
+
+static inline void
+validate_tree (GtkTreeStore *tree_store)
+{
+ if (gtk_debug_flags & GTK_DEBUG_TREE)
+ {
+ g_assert (G_NODE (tree_store->root)->parent == NULL);
+
+ validate_gnode (G_NODE (tree_store->root));
+ }
+}
+
GtkType
gtk_tree_store_get_type (void)
{
@@ -95,10 +124,34 @@ gtk_tree_store_get_type (void)
NULL
};
+ static const GInterfaceInfo drag_source_info =
+ {
+ (GInterfaceInitFunc) gtk_tree_store_drag_source_init,
+ NULL,
+ NULL
+ };
+
+ static const GInterfaceInfo drag_dest_info =
+ {
+ (GInterfaceInitFunc) gtk_tree_store_drag_dest_init,
+ NULL,
+ NULL
+ };
+
tree_store_type = g_type_register_static (GTK_TYPE_OBJECT, "GtkTreeStore", &tree_store_info, 0);
+
g_type_add_interface_static (tree_store_type,
GTK_TYPE_TREE_MODEL,
&tree_model_info);
+
+ g_type_add_interface_static (tree_store_type,
+ GTK_TYPE_TREE_DRAG_SOURCE,
+ &drag_source_info);
+ g_type_add_interface_static (tree_store_type,
+ GTK_TYPE_TREE_DRAG_DEST,
+ &drag_dest_info);
+
+
}
return tree_store_type;
@@ -165,6 +218,20 @@ gtk_tree_store_tree_model_init (GtkTreeModelIface *iface)
}
static void
+gtk_tree_store_drag_source_init (GtkTreeDragSourceIface *iface)
+{
+ iface->drag_data_delete = gtk_tree_store_drag_data_delete;
+ iface->drag_data_get = gtk_tree_store_drag_data_get;
+}
+
+static void
+gtk_tree_store_drag_dest_init (GtkTreeDragDestIface *iface)
+{
+ iface->drag_data_received = gtk_tree_store_drag_data_received;
+ iface->row_drop_possible = gtk_tree_store_row_drop_possible;
+}
+
+static void
gtk_tree_store_init (GtkTreeStore *tree_store)
{
tree_store->root = g_node_new (NULL);
@@ -242,7 +309,7 @@ gtk_tree_store_set_column_type (GtkTreeStore *tree_store,
/* fulfill the GtkTreeModel requirements */
/* NOTE: GtkTreeStore::root is a GNode, that acts as the parent node. However,
- * it is not visible to the tree or to the user., and the path "1" refers to the
+ * it is not visible to the tree or to the user., and the path "0" refers to the
* first child of GtkTreeStore::root.
*/
@@ -281,13 +348,13 @@ gtk_tree_store_get_path (GtkTreeModel *tree_model,
GtkTreePath *retval;
GNode *tmp_node;
gint i = 0;
-
+
g_return_val_if_fail (tree_model != NULL, NULL);
g_return_val_if_fail (GTK_IS_TREE_STORE (tree_model), NULL);
g_return_val_if_fail (iter != NULL, NULL);
+ g_return_val_if_fail (iter->user_data != NULL, NULL);
- if (iter->user_data == NULL)
- return NULL;
+ validate_tree ((GtkTreeStore*)tree_model);
g_assert (G_NODE (iter->user_data)->parent != NULL);
@@ -299,7 +366,8 @@ gtk_tree_store_get_path (GtkTreeModel *tree_model,
else
{
GtkTreeIter tmp_iter = *iter;
- tmp_iter.user_data = G_NODE (tmp_iter.user_data)->parent;
+
+ tmp_iter.user_data = G_NODE (iter->user_data)->parent;
retval = gtk_tree_store_get_path (tree_model,
&tmp_iter);
@@ -372,12 +440,15 @@ static gboolean
gtk_tree_store_iter_next (GtkTreeModel *tree_model,
GtkTreeIter *iter)
{
- if (iter->user_data == NULL)
+ g_return_val_if_fail (iter->user_data != NULL, FALSE);
+
+ if (G_NODE (iter->user_data)->next)
+ {
+ iter->user_data = G_NODE (iter->user_data)->next;
+ return TRUE;
+ }
+ else
return FALSE;
-
- iter->user_data = G_NODE (iter->user_data)->next;
-
- return (iter->user_data != NULL);
}
static gboolean
@@ -385,13 +456,23 @@ gtk_tree_store_iter_children (GtkTreeModel *tree_model,
GtkTreeIter *iter,
GtkTreeIter *parent)
{
- iter->stamp = GTK_TREE_STORE (tree_model)->stamp;
+ GNode *children;
+
+ g_return_val_if_fail (parent == NULL || parent->user_data != NULL, FALSE);
+
if (parent)
- iter->user_data = G_NODE (parent->user_data)->children;
+ children = G_NODE (parent->user_data)->children;
else
- iter->user_data = G_NODE (GTK_TREE_STORE (tree_model)->root)->children;
+ children = G_NODE (GTK_TREE_STORE (tree_model)->root)->children;
- return iter->user_data != NULL;
+ if (children)
+ {
+ iter->stamp = GTK_TREE_STORE (tree_model)->stamp;
+ iter->user_data = children;
+ return TRUE;
+ }
+ else
+ return FALSE;
}
static gboolean
@@ -401,6 +482,7 @@ gtk_tree_store_iter_has_child (GtkTreeModel *tree_model,
g_return_val_if_fail (tree_model != NULL, FALSE);
g_return_val_if_fail (GTK_IS_TREE_STORE (tree_model), FALSE);
g_return_val_if_fail (iter != NULL, FALSE);
+ g_return_val_if_fail (iter->user_data != NULL, FALSE);
return G_NODE (iter->user_data)->children != NULL;
}
@@ -414,11 +496,14 @@ gtk_tree_store_iter_n_children (GtkTreeModel *tree_model,
g_return_val_if_fail (tree_model != NULL, 0);
g_return_val_if_fail (GTK_IS_TREE_STORE (tree_model), 0);
-
+ g_return_val_if_fail (iter != NULL, FALSE);
+ g_return_val_if_fail (iter->user_data != NULL, FALSE);
+
if (iter == NULL)
node = G_NODE (GTK_TREE_STORE (tree_model)->root)->children;
else
node = G_NODE (iter->user_data)->children;
+
while (node)
{
i++;
@@ -435,24 +520,27 @@ gtk_tree_store_iter_nth_child (GtkTreeModel *tree_model,
gint n)
{
GNode *parent_node;
+ GNode *child;
g_return_val_if_fail (tree_model != NULL, FALSE);
g_return_val_if_fail (GTK_IS_TREE_STORE (tree_model), FALSE);
- g_return_val_if_fail (iter != NULL, FALSE);
+ g_return_val_if_fail (parent == NULL || parent->user_data != NULL, FALSE);
if (parent == NULL)
parent_node = GTK_TREE_STORE (tree_model)->root;
else
parent_node = parent->user_data;
- iter->user_data = g_node_nth_child (parent_node, n);
+ child = g_node_nth_child (parent_node, n);
- if (iter->user_data == NULL)
- iter->stamp = 0;
+ if (child)
+ {
+ iter->user_data = child;
+ iter->stamp = GTK_TREE_STORE (tree_model)->stamp;
+ return TRUE;
+ }
else
- iter->stamp = GTK_TREE_STORE (tree_model)->stamp;
-
- return (iter->user_data != NULL);
+ return FALSE;
}
static gboolean
@@ -460,19 +548,23 @@ gtk_tree_store_iter_parent (GtkTreeModel *tree_model,
GtkTreeIter *iter,
GtkTreeIter *child)
{
- g_assert (G_NODE (child->user_data)->parent != NULL);
+ GNode *parent;
- iter->stamp = GTK_TREE_STORE (tree_model)->stamp;
- iter->user_data = G_NODE (child->user_data)->parent;
+ g_return_val_if_fail (iter != NULL, FALSE);
+ g_return_val_if_fail (iter->user_data != NULL, FALSE);
+
+ parent = G_NODE (child->user_data)->parent;
+
+ g_assert (parent != NULL);
- if (iter->user_data == GTK_TREE_STORE (tree_model)->root)
+ if (parent != GTK_TREE_STORE (tree_model)->root)
{
- iter->stamp = 0;
- iter->user_data = NULL;
- return FALSE;
+ iter->user_data = parent;
+ iter->stamp = GTK_TREE_STORE (tree_model)->stamp;
+ return TRUE;
}
-
- return TRUE;
+ else
+ return FALSE;
}
/*
@@ -708,22 +800,27 @@ gtk_tree_store_insert (GtkTreeStore *model,
gint position)
{
GtkTreePath *path;
+ GNode *parent_node;
g_return_if_fail (model != NULL);
g_return_if_fail (GTK_IS_TREE_STORE (model));
- if (parent->user_data == NULL)
- parent->user_data = model->root;
+ if (parent)
+ parent_node = parent->user_data;
+ else
+ parent_node = model->root;
iter->stamp = model->stamp;
iter->user_data = g_node_new (NULL);
- g_node_insert (G_NODE (parent->user_data), position, G_NODE (iter->user_data));
+ g_node_insert (parent_node, position, G_NODE (iter->user_data));
path = gtk_tree_store_get_path (GTK_TREE_MODEL (model), iter);
gtk_signal_emit_by_name (GTK_OBJECT (model),
"inserted",
path, iter);
gtk_tree_path_free (path);
+
+ validate_tree ((GtkTreeStore*)model);
}
void
@@ -733,7 +830,7 @@ gtk_tree_store_insert_before (GtkTreeStore *model,
GtkTreeIter *sibling)
{
GtkTreePath *path;
- GNode *parent_node = NULL;
+ GNode *parent_node = NULL;
GNode *new_node;
g_return_if_fail (model != NULL);
@@ -767,6 +864,8 @@ gtk_tree_store_insert_before (GtkTreeStore *model,
"inserted",
path, iter);
gtk_tree_path_free (path);
+
+ validate_tree ((GtkTreeStore*)model);
}
void
@@ -811,6 +910,8 @@ gtk_tree_store_insert_after (GtkTreeStore *model,
"inserted",
path, iter);
gtk_tree_path_free (path);
+
+ validate_tree ((GtkTreeStore*)model);
}
void
@@ -861,6 +962,8 @@ gtk_tree_store_prepend (GtkTreeStore *model,
{
gtk_tree_store_insert_after (model, iter, parent, NULL);
}
+
+ validate_tree ((GtkTreeStore*)model);
}
void
@@ -873,19 +976,19 @@ gtk_tree_store_append (GtkTreeStore *model,
g_return_if_fail (model != NULL);
g_return_if_fail (GTK_IS_TREE_STORE (model));
g_return_if_fail (iter != NULL);
-
+
if (parent == NULL)
parent_node = model->root;
else
parent_node = parent->user_data;
- iter->stamp = model->stamp;
- iter->user_data = g_node_new (NULL);
-
if (parent_node->children == NULL)
{
GtkTreePath *path;
+ iter->stamp = model->stamp;
+ iter->user_data = g_node_new (NULL);
+
g_node_append (parent_node, G_NODE (iter->user_data));
if (parent_node != model->root)
@@ -901,6 +1004,7 @@ gtk_tree_store_append (GtkTreeStore *model,
{
path = gtk_tree_store_get_path (GTK_TREE_MODEL (model), iter);
}
+
gtk_signal_emit_by_name (GTK_OBJECT (model),
"inserted",
path,
@@ -911,6 +1015,8 @@ gtk_tree_store_append (GtkTreeStore *model,
{
gtk_tree_store_insert_before (model, iter, parent, NULL);
}
+
+ validate_tree ((GtkTreeStore*)model);
}
gboolean
@@ -938,3 +1044,309 @@ gtk_tree_store_iter_depth (GtkTreeStore *model,
return g_node_depth (G_NODE (iter->user_data)) - 1;
}
+
+/* DND */
+
+
+
+static gboolean
+gtk_tree_store_drag_data_delete (GtkTreeDragSource *drag_source,
+ GtkTreePath *path)
+{
+ GtkTreeIter iter;
+
+ g_return_val_if_fail (GTK_IS_TREE_STORE (drag_source), FALSE);
+
+ if (gtk_tree_model_get_iter (GTK_TREE_MODEL (drag_source),
+ &iter,
+ path))
+ {
+ g_print ("data_delete deleting tree row\n");
+ gtk_tree_store_remove (GTK_TREE_STORE (drag_source),
+ &iter);
+ return TRUE;
+ }
+ else
+ {
+ g_print ("data_delete path not in tree\n");
+ return FALSE;
+ }
+}
+
+static gboolean
+gtk_tree_store_drag_data_get (GtkTreeDragSource *drag_source,
+ GtkTreePath *path,
+ GtkSelectionData *selection_data)
+{
+ g_return_val_if_fail (GTK_IS_TREE_STORE (drag_source), FALSE);
+
+ /* Note that we don't need to handle the GTK_TREE_MODEL_ROW
+ * target, because the default handler does it for us, but
+ * we do anyway for the convenience of someone maybe overriding the
+ * default handler.
+ */
+
+ if (gtk_selection_data_set_tree_row (selection_data,
+ GTK_TREE_MODEL (drag_source),
+ path))
+ {
+ return TRUE;
+ }
+ else
+ {
+ /* FIXME handle text targets at least. */
+ }
+
+ return FALSE;
+}
+
+static void
+copy_node_data (GtkTreeStore *tree_store,
+ GtkTreeIter *src_iter,
+ GtkTreeIter *dest_iter)
+{
+ GtkTreeDataList *dl = G_NODE (src_iter->user_data)->data;
+ GtkTreeDataList *copy_head = NULL;
+ GtkTreeDataList *copy_prev = NULL;
+ GtkTreeDataList *copy_iter = NULL;
+ gint col;
+
+ col = 0;
+ while (dl)
+ {
+ copy_iter = _gtk_tree_data_list_node_copy (dl,
+ tree_store->column_headers[col]);
+
+ g_print ("copied col %d type %s\n", col,
+ g_type_name (tree_store->column_headers[col]));
+
+ if (copy_head == NULL)
+ copy_head = copy_iter;
+
+ if (copy_prev)
+ copy_prev->next = copy_iter;
+
+ copy_prev = copy_iter;
+
+ dl = dl->next;
+ ++col;
+ }
+
+ G_NODE (dest_iter->user_data)->data = copy_head;
+
+ gtk_signal_emit_by_name (GTK_OBJECT (tree_store),
+ "changed",
+ NULL, dest_iter);
+}
+
+static void
+recursive_node_copy (GtkTreeStore *tree_store,
+ GtkTreeIter *src_iter,
+ GtkTreeIter *dest_iter)
+{
+ GtkTreeIter child;
+ GtkTreeModel *model;
+
+ model = GTK_TREE_MODEL (tree_store);
+
+ copy_node_data (tree_store, src_iter, dest_iter);
+
+ if (gtk_tree_model_iter_children (model,
+ &child,
+ src_iter))
+ {
+ /* Need to create children and recurse. Note our
+ * dependence on persistent iterators here.
+ */
+ do
+ {
+ GtkTreeIter copy;
+
+ /* Gee, a really slow algorithm... ;-) FIXME */
+ gtk_tree_store_append (tree_store,
+ &copy,
+ dest_iter);
+
+ recursive_node_copy (tree_store, &child, &copy);
+ }
+ while (gtk_tree_model_iter_next (model, &child));
+ }
+}
+
+static gboolean
+gtk_tree_store_drag_data_received (GtkTreeDragDest *drag_dest,
+ GtkTreePath *dest,
+ GtkSelectionData *selection_data)
+{
+ GtkTreeModel *tree_model;
+ GtkTreeStore *tree_store;
+ GtkTreeModel *src_model = NULL;
+ GtkTreePath *src_path = NULL;
+ gboolean retval = FALSE;
+
+ g_return_val_if_fail (GTK_IS_TREE_STORE (drag_dest), FALSE);
+
+ tree_model = GTK_TREE_MODEL (drag_dest);
+ tree_store = GTK_TREE_STORE (drag_dest);
+
+ validate_tree (tree_store);
+
+ if (gtk_selection_data_get_tree_row (selection_data,
+ &src_model,
+ &src_path) &&
+ src_model == tree_model)
+ {
+ /* Copy the given row to a new position */
+ GtkTreeIter src_iter;
+ GtkTreeIter dest_iter;
+ GtkTreePath *prev;
+
+ if (!gtk_tree_model_get_iter (src_model,
+ &src_iter,
+ src_path))
+ {
+ g_print ("can't get source path as iter\n");
+ goto out;
+ }
+
+ /* Get the path to insert _after_ (dest is the path to insert _before_) */
+ prev = gtk_tree_path_copy (dest);
+
+ if (!gtk_tree_path_prev (prev))
+ {
+ GtkTreeIter dest_parent;
+ GtkTreePath *parent;
+ GtkTreeIter *dest_parent_p;
+
+ /* dest was the first spot at the current depth; which means
+ * we are supposed to prepend.
+ */
+
+ /* Get the parent, NULL if parent is the root */
+ dest_parent_p = NULL;
+ parent = gtk_tree_path_copy (dest);
+ if (gtk_tree_path_up (parent))
+ {
+ gtk_tree_model_get_iter (tree_model,
+ &dest_parent,
+ parent);
+ dest_parent_p = &dest_parent;
+ }
+ gtk_tree_path_free (parent);
+ parent = NULL;
+
+ gtk_tree_store_prepend (GTK_TREE_STORE (tree_model),
+ &dest_iter,
+ dest_parent_p);
+
+ retval = TRUE;
+
+ g_print ("prepending to tree\n");
+ }
+ else
+ {
+ if (gtk_tree_model_get_iter (GTK_TREE_MODEL (tree_model),
+ &dest_iter,
+ prev))
+ {
+ GtkTreeIter tmp_iter = dest_iter;
+ gtk_tree_store_insert_after (GTK_TREE_STORE (tree_model),
+ &dest_iter,
+ NULL,
+ &tmp_iter);
+ retval = TRUE;
+
+ g_print ("inserting into tree\n");
+ }
+ else
+ g_print ("can't get iter to insert after\n");
+ }
+
+ gtk_tree_path_free (prev);
+
+ /* If we succeeded in creating dest_iter, walk src_iter tree branch,
+ * duplicating it below dest_iter.
+ */
+
+ if (retval)
+ {
+ recursive_node_copy (tree_store,
+ &src_iter,
+ &dest_iter);
+ }
+ }
+ else
+ {
+ /* FIXME maybe add some data targets eventually, or handle text
+ * targets in the simple case.
+ */
+ g_print ("not accepting target\n");
+ }
+
+ out:
+
+ if (src_path)
+ gtk_tree_path_free (src_path);
+
+ return retval;
+}
+
+static gboolean
+gtk_tree_store_row_drop_possible (GtkTreeDragDest *drag_dest,
+ GtkTreeModel *src_model,
+ GtkTreePath *src_path,
+ GtkTreePath *dest_path)
+{
+ /* can only drag to ourselves */
+ if (src_model != GTK_TREE_MODEL (drag_dest))
+ return FALSE;
+
+ /* Can't drop into ourself. */
+ if (gtk_tree_path_is_ancestor (src_path,
+ dest_path))
+ return FALSE;
+
+ /* Can't drop if dest_path's parent doesn't exist */
+ {
+ GtkTreeIter iter;
+ GtkTreePath *tmp = gtk_tree_path_copy (dest_path);
+
+ /* if we can't go up, we know the parent exists, the root
+ * always exists.
+ */
+ if (gtk_tree_path_up (tmp))
+ {
+ if (!gtk_tree_model_get_iter (GTK_TREE_MODEL (drag_dest),
+ &iter, tmp))
+ {
+ if (tmp)
+ gtk_tree_path_free (tmp);
+ return FALSE;
+ }
+ }
+
+ if (tmp)
+ gtk_tree_path_free (tmp);
+ }
+
+ /* Can otherwise drop anywhere. */
+ return TRUE;
+}
+
+static void
+validate_gnode (GNode* node)
+{
+ GNode *iter;
+
+ iter = node->children;
+ while (iter != NULL)
+ {
+ g_assert (iter->parent == node);
+ if (iter->prev)
+ g_assert (iter->prev->next == iter);
+ validate_gnode (iter);
+ iter = iter->next;
+ }
+}
+
+
diff --git a/gtk/gtktreeview.c b/gtk/gtktreeview.c
index 9d26b0a33b..db5de4e46b 100644
--- a/gtk/gtktreeview.c
+++ b/gtk/gtktreeview.c
@@ -4787,37 +4787,71 @@ gtk_tree_view_tree_to_widget_coords (GtkTreeView *tree_view,
/* Drag-and-drop */
-void
+static void
set_source_row (GdkDragContext *context,
+ GtkTreeModel *model,
GtkTreePath *source_row)
{
g_object_set_data_full (G_OBJECT (context),
"gtk-tree-view-source-row",
- source_row ? gtk_tree_path_copy (source_row) : NULL,
- (GDestroyNotify) (source_row ? gtk_tree_path_free : NULL));
+ source_row ? gtk_tree_row_reference_new (model, source_row) : NULL,
+ (GDestroyNotify) (source_row ? gtk_tree_row_reference_free : NULL));
}
-GtkTreePath*
+static GtkTreePath*
get_source_row (GdkDragContext *context)
{
- return g_object_get_data (G_OBJECT (context), "gtk-tree-view-source-row");
+ GtkTreeRowReference *ref =
+ g_object_get_data (G_OBJECT (context), "gtk-tree-view-source-row");
+
+ if (ref)
+ return gtk_tree_row_reference_get_path (ref);
+ else
+ return NULL;
}
-void
+static void
set_dest_row (GdkDragContext *context,
+ GtkTreeModel *model,
GtkTreePath *dest_row)
{
g_object_set_data_full (G_OBJECT (context),
"gtk-tree-view-dest-row",
- dest_row ? gtk_tree_path_copy (dest_row) : NULL,
- (GDestroyNotify) (dest_row ? gtk_tree_path_free : NULL));
+ dest_row ? gtk_tree_row_reference_new (model, dest_row) : NULL,
+ (GDestroyNotify) (dest_row ? gtk_tree_row_reference_free : NULL));
}
-GtkTreePath*
+static GtkTreePath*
get_dest_row (GdkDragContext *context)
{
- return g_object_get_data (G_OBJECT (context), "gtk-tree-view-dest-row");
+ GtkTreeRowReference *ref =
+ g_object_get_data (G_OBJECT (context), "gtk-tree-view-dest-row");
+
+ if (ref)
+ return gtk_tree_row_reference_get_path (ref);
+ else
+ return NULL;
+}
+
+/* Get/set whether drag_motion requested the drag data and
+ * drag_data_received should thus not actually insert the data,
+ * since the data doesn't result from a drop.
+ */
+static void
+set_status_pending (GdkDragContext *context,
+ GdkDragAction suggested_action)
+{
+ g_object_set_data (G_OBJECT (context),
+ "gtk-tree-view-status-pending",
+ GINT_TO_POINTER (suggested_action));
+}
+
+static GdkDragAction
+get_status_pending (GdkDragContext *context)
+{
+ return GPOINTER_TO_INT (g_object_get_data (G_OBJECT (context),
+ "gtk-tree-view-status-pending"));
}
typedef struct _TreeViewDragInfo TreeViewDragInfo;
@@ -5234,6 +5268,7 @@ gtk_tree_view_maybe_begin_dragging_row (GtkTreeView *tree_view,
GtkTreePath *path = NULL;
gint button;
gint cell_x, cell_y;
+ GtkTreeModel *model;
di = get_info (tree_view);
@@ -5242,12 +5277,17 @@ gtk_tree_view_maybe_begin_dragging_row (GtkTreeView *tree_view,
if (tree_view->priv->pressed_button < 0)
return FALSE;
-
+
if (!gtk_drag_check_threshold (GTK_WIDGET (tree_view),
tree_view->priv->press_start_x,
tree_view->priv->press_start_y,
event->x, event->y))
return FALSE;
+
+ model = gtk_tree_view_get_model (tree_view);
+
+ if (model == NULL)
+ return FALSE;
button = tree_view->priv->pressed_button;
tree_view->priv->pressed_button = -1;
@@ -5297,7 +5337,7 @@ gtk_tree_view_maybe_begin_dragging_row (GtkTreeView *tree_view,
gdk_pixmap_unref (row_pix);
}
- set_source_row (context, path);
+ set_source_row (context, model, path);
gtk_tree_path_free (path);
return TRUE;
@@ -5357,7 +5397,7 @@ gtk_tree_view_drag_data_get (GtkWidget *widget,
gtk_tree_drag_source_drag_data_get (GTK_TREE_DRAG_SOURCE (model),
source_row,
selection_data))
- return;
+ goto done;
/* If drag_data_get does nothing, try providing row data. */
if (selection_data->target == gdk_atom_intern ("GTK_TREE_MODEL_ROW", FALSE))
@@ -5366,6 +5406,9 @@ gtk_tree_view_drag_data_get (GtkWidget *widget,
model,
source_row);
}
+
+ done:
+ gtk_tree_path_free (source_row);
}
@@ -5378,13 +5421,14 @@ check_model_dnd (GtkTreeModel *model,
{
g_warning ("You must override the default '%s' handler "
"on GtkTreeView when using models that don't support "
- "the %s interface. The simplest way to do this "
+ "the %s interface and enabling drag-and-drop. The simplest way to do this "
"is to connect to '%s' and call "
"gtk_signal_emit_stop_by_name() in your signal handler to prevent "
"the default handler from running. Look at the source code "
"for the default handler in gtktreeview.c to get an idea what "
"your handler should do. (gtktreeview.c is in the GTK source "
- "code.)",
+ "code.) If you're using GTK from a language other than C, "
+ "there may be a more natural way to override default handlers, e.g. via derivation.",
signal, g_type_name (required_iface), signal);
return FALSE;
}
@@ -5404,6 +5448,8 @@ gtk_tree_view_drag_data_delete (GtkWidget *widget,
tree_view = GTK_TREE_VIEW (widget);
model = gtk_tree_view_get_model (tree_view);
+ g_print ("data_delete\n");
+
if (!check_model_dnd (model, GTK_TYPE_TREE_DRAG_SOURCE, "drag_data_delete"))
return;
@@ -5414,11 +5460,15 @@ gtk_tree_view_drag_data_delete (GtkWidget *widget,
source_row = get_source_row (context);
-
+ if (source_row == NULL)
+ return;
+
gtk_tree_drag_source_drag_data_delete (GTK_TREE_DRAG_SOURCE (model),
source_row);
-
- set_source_row (context, NULL);
+
+ gtk_tree_path_free (source_row);
+
+ set_source_row (context, NULL, NULL);
}
static void
@@ -5488,7 +5538,8 @@ set_destination_row (GtkTreeView *tree_view,
GdkDragContext *context,
gint x,
gint y,
- GdkDragAction *suggested_action)
+ GdkDragAction *suggested_action,
+ GdkAtom *target)
{
GtkTreePath *path = NULL;
GtkTreeViewDropPosition pos;
@@ -5498,6 +5549,7 @@ set_destination_row (GtkTreeView *tree_view,
GtkTreePath *old_dest_path = NULL;
*suggested_action = 0;
+ *target = GDK_NONE;
widget = GTK_WIDGET (tree_view);
@@ -5520,8 +5572,8 @@ set_destination_row (GtkTreeView *tree_view,
return FALSE; /* no longer a drop site */
}
- /* We don't take this target */
- if (gtk_drag_dest_find_target (widget, context, di->dest_target_list) == GDK_NONE)
+ *target = gtk_drag_dest_find_target (widget, context, di->dest_target_list);
+ if (*target == GDK_NONE)
{
g_print ("bad target, not accepting\n");
return FALSE;
@@ -5608,12 +5660,13 @@ gtk_tree_view_drag_motion (GtkWidget *widget,
GtkTreeViewDropPosition pos;
GtkTreeView *tree_view;
GdkDragAction suggested_action = 0;
+ GdkAtom target;
tree_view = GTK_TREE_VIEW (widget);
g_print ("motion\n");
- if (!set_destination_row (tree_view, context, x, y, &suggested_action))
+ if (!set_destination_row (tree_view, context, x, y, &suggested_action, &target))
return FALSE;
ensure_scroll_timeout (tree_view);
@@ -5633,11 +5686,24 @@ gtk_tree_view_drag_motion (GtkWidget *widget,
pos == GTK_TREE_VIEW_DROP_INTO_OR_BEFORE))
{
tree_view->priv->open_dest_timeout =
- gtk_timeout_add (250, open_row_timeout, tree_view);
+ gtk_timeout_add (500, open_row_timeout, tree_view);
}
- g_print ("status\n");
- gdk_drag_status (context, suggested_action, time);
+ if (target == gdk_atom_intern ("GTK_TREE_MODEL_ROW", FALSE))
+ {
+ /* Request data so we can use the source row when
+ * determining whether to accept the drop
+ */
+ set_status_pending (context, suggested_action);
+ g_print ("motion requesting the drop data\n");
+ gtk_drag_get_data (widget, context, target, time);
+ }
+ else
+ {
+ set_status_pending (context, 0);
+ g_print ("motion sending positive status\n");
+ gdk_drag_status (context, suggested_action, time);
+ }
}
if (path)
@@ -5646,6 +5712,36 @@ gtk_tree_view_drag_motion (GtkWidget *widget,
return TRUE;
}
+static GtkTreePath*
+get_logical_dest_row (GtkTreeView *tree_view)
+
+{
+ /* adjust path to point to the row the drop goes in front of */
+ GtkTreePath *path = NULL;
+ GtkTreeViewDropPosition pos;
+
+ gtk_tree_view_get_drag_dest_row (tree_view, &path, &pos);
+
+ if (path == NULL)
+ return NULL;
+
+ if (pos == GTK_TREE_VIEW_DROP_BEFORE)
+ ; /* do nothing */
+ else if (pos == GTK_TREE_VIEW_DROP_INTO_OR_BEFORE ||
+ pos == GTK_TREE_VIEW_DROP_INTO_OR_AFTER)
+ {
+ /* get first child, drop before it */
+ gtk_tree_path_append_index (path, 0);
+ }
+ else
+ {
+ g_assert (pos == GTK_TREE_VIEW_DROP_AFTER);
+ gtk_tree_path_next (path);
+ }
+
+ return path;
+}
+
static gboolean
gtk_tree_view_drag_drop (GtkWidget *widget,
GdkDragContext *context,
@@ -5653,9 +5749,8 @@ gtk_tree_view_drag_drop (GtkWidget *widget,
gint y,
guint time)
{
- GtkTreePath *path = NULL;
- GtkTreeViewDropPosition pos;
GtkTreeView *tree_view;
+ GtkTreePath *path;
GdkDragAction suggested_action = 0;
GdkAtom target = GDK_NONE;
TreeViewDragInfo *di;
@@ -5669,30 +5764,30 @@ gtk_tree_view_drag_drop (GtkWidget *widget,
remove_scroll_timeout (GTK_TREE_VIEW (widget));
remove_open_timeout (GTK_TREE_VIEW (widget));
-
- di = get_info (tree_view);
-
+
+ di = get_info (tree_view);
+
if (di == NULL)
return FALSE;
if (!check_model_dnd (model, GTK_TYPE_TREE_DRAG_DEST, "drag_drop"))
return FALSE;
- if (!set_destination_row (tree_view, context, x, y, &suggested_action))
+ if (!set_destination_row (tree_view, context, x, y, &suggested_action, &target))
return FALSE;
- gtk_tree_view_get_drag_dest_row (tree_view, &path, &pos);
+ path = get_logical_dest_row (tree_view);
- if (path != NULL && di->dest_target_list)
+ if (target != GDK_NONE && path != NULL)
{
- target = gtk_drag_dest_find_target (widget, context, di->dest_target_list);
+ g_print ("have target\n");
- if (target != GDK_NONE)
- {
- g_print ("have target\n");
-
- set_dest_row (context, path);
- }
+ /* in case a motion had requested drag data, change things so we
+ * treat drag data receives as a drop.
+ */
+ set_status_pending (context, 0);
+
+ set_dest_row (context, model, path);
}
if (path)
@@ -5722,11 +5817,13 @@ gtk_tree_view_drag_data_received (GtkWidget *widget,
guint info,
guint time)
{
+ GtkTreePath *path;
TreeViewDragInfo *di;
gboolean accepted = FALSE;
GtkTreeModel *model;
GtkTreeView *tree_view;
GtkTreePath *dest_row;
+ GdkDragAction suggested_action;
tree_view = GTK_TREE_VIEW (widget);
@@ -5742,6 +5839,58 @@ gtk_tree_view_drag_data_received (GtkWidget *widget,
if (di == NULL)
return;
+ suggested_action = get_status_pending (context);
+
+ if (suggested_action)
+ {
+ /* We are getting this data due to a request in drag_motion,
+ * rather than due to a request in drag_drop, so we are just
+ * supposed to call drag_status, not actually paste in the
+ * data.
+ */
+ path = get_logical_dest_row (tree_view);
+
+ if (path == NULL)
+ suggested_action = 0;
+
+ if (suggested_action)
+ {
+ GtkTreeModel *src_model = NULL;
+ GtkTreePath *src_path = NULL;
+
+ if (!gtk_selection_data_get_tree_row (selection_data,
+ &src_model,
+ &src_path))
+ suggested_action = 0;
+
+ if (suggested_action)
+ {
+ if (!gtk_tree_drag_dest_row_drop_possible (GTK_TREE_DRAG_DEST (model),
+ src_model,
+ src_path,
+ path))
+ suggested_action = 0;
+
+ gtk_tree_path_free (src_path);
+ }
+ }
+
+ g_print ("suggested action %d in drag_data_received\n", suggested_action);
+
+ gdk_drag_status (context, suggested_action, time);
+
+ if (path)
+ gtk_tree_path_free (path);
+
+ /* If you can't drop, remove user drop indicator until the next motion */
+ if (suggested_action == 0)
+ gtk_tree_view_set_drag_dest_row (GTK_TREE_VIEW (widget),
+ NULL,
+ GTK_TREE_VIEW_DROP_BEFORE);
+
+ return;
+ }
+
dest_row = get_dest_row (context);
if (dest_row == NULL)
@@ -5753,16 +5902,17 @@ gtk_tree_view_drag_data_received (GtkWidget *widget,
dest_row,
selection_data))
accepted = TRUE;
-
-
- /* Don't clear drop_row, we may need it in drag_data_delete */
}
+
+ g_print ("accepted: %d\n", accepted);
gtk_drag_finish (context,
accepted,
(context->action == GDK_ACTION_MOVE),
time);
- g_print ("accepted: %d\n", accepted);
-}
+ gtk_tree_path_free (dest_row);
+ /* drop dest_row */
+ set_dest_row (context, NULL, NULL);
+}
diff --git a/gtk/gtktreeview.h b/gtk/gtktreeview.h
index 22890ae66a..fd36f4d0a6 100644
--- a/gtk/gtktreeview.h
+++ b/gtk/gtktreeview.h
@@ -194,9 +194,9 @@ void gtk_tree_view_unset_rows_drag_dest (GtkTreeView *tree_view);
void gtk_tree_view_set_drag_dest_row (GtkTreeView *tree_view,
GtkTreePath *path,
GtkTreeViewDropPosition pos);
-void gtk_tree_view_get_drag_dest_row (GtkTreeView *tree_view,
- GtkTreePath **path,
- GtkTreeViewDropPosition *pos);
+void gtk_tree_view_get_drag_dest_row (GtkTreeView *tree_view,
+ GtkTreePath **path,
+ GtkTreeViewDropPosition *pos);
gboolean gtk_tree_view_get_dest_row_at_pos (GtkTreeView *tree_view,
gint drag_x,
gint drag_y,