fix bug in here where prev pointer was set to the wrong thing

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
This commit is contained in:
Havoc Pennington 2001-01-31 00:57:49 +00:00 committed by Havoc Pennington
parent a8e3c2058d
commit 5cd2993201
17 changed files with 1339 additions and 191 deletions

View File

@ -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> Sat Jan 27 15:52:02 2001 Jonathan Blandford <jrb@redhat.com>
* gtk/gtktreeselection.c (gtk_tree_selection_unselect_iter): Fix * gtk/gtktreeselection.c (gtk_tree_selection_unselect_iter): Fix

View File

@ -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> Sat Jan 27 15:52:02 2001 Jonathan Blandford <jrb@redhat.com>
* gtk/gtktreeselection.c (gtk_tree_selection_unselect_iter): Fix * gtk/gtktreeselection.c (gtk_tree_selection_unselect_iter): Fix

View File

@ -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> Sat Jan 27 15:52:02 2001 Jonathan Blandford <jrb@redhat.com>
* gtk/gtktreeselection.c (gtk_tree_selection_unselect_iter): Fix * gtk/gtktreeselection.c (gtk_tree_selection_unselect_iter): Fix

View File

@ -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> Sat Jan 27 15:52:02 2001 Jonathan Blandford <jrb@redhat.com>
* gtk/gtktreeselection.c (gtk_tree_selection_unselect_iter): Fix * gtk/gtktreeselection.c (gtk_tree_selection_unselect_iter): Fix

View File

@ -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> Sat Jan 27 15:52:02 2001 Jonathan Blandford <jrb@redhat.com>
* gtk/gtktreeselection.c (gtk_tree_selection_unselect_iter): Fix * gtk/gtktreeselection.c (gtk_tree_selection_unselect_iter): Fix

View File

@ -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> Sat Jan 27 15:52:02 2001 Jonathan Blandford <jrb@redhat.com>
* gtk/gtktreeselection.c (gtk_tree_selection_unselect_iter): Fix * gtk/gtktreeselection.c (gtk_tree_selection_unselect_iter): Fix

View File

@ -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> Sat Jan 27 15:52:02 2001 Jonathan Blandford <jrb@redhat.com>
* gtk/gtktreeselection.c (gtk_tree_selection_unselect_iter): Fix * gtk/gtktreeselection.c (gtk_tree_selection_unselect_iter): Fix

View File

@ -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, static gboolean gtk_list_store_drag_data_received (GtkTreeDragDest *drag_dest,
GtkTreePath *dest, GtkTreePath *dest,
GtkSelectionData *selection_data); 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 GtkType
gtk_list_store_get_type (void) gtk_list_store_get_type (void)
@ -210,6 +223,7 @@ static void
gtk_list_store_drag_dest_init (GtkTreeDragDestIface *iface) gtk_list_store_drag_dest_init (GtkTreeDragDestIface *iface)
{ {
iface->drag_data_received = gtk_list_store_drag_data_received; iface->drag_data_received = gtk_list_store_drag_data_received;
iface->row_drop_possible = gtk_list_store_row_drop_possible;
} }
static void static void
@ -218,6 +232,7 @@ gtk_list_store_init (GtkListStore *list_store)
list_store->root = NULL; list_store->root = NULL;
list_store->tail = NULL; list_store->tail = NULL;
list_store->stamp = g_random_int (); list_store->stamp = g_random_int ();
list_store->length = 0;
} }
GtkListStore * GtkListStore *
@ -323,14 +338,26 @@ gtk_list_store_get_iter (GtkTreeModel *tree_model,
GtkTreeIter *iter, GtkTreeIter *iter,
GtkTreePath *path) GtkTreePath *path)
{ {
GSList *list;
gint i;
g_return_val_if_fail (GTK_IS_LIST_STORE (tree_model), FALSE); 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;
list = g_slist_nth (G_SLIST (GTK_LIST_STORE (tree_model)->root),
i);
/* If this fails, list_store->length has gotten mangled. */
g_assert (list);
iter->stamp = GTK_LIST_STORE (tree_model)->stamp; iter->stamp = GTK_LIST_STORE (tree_model)->stamp;
iter->user_data = g_slist_nth (G_SLIST (GTK_LIST_STORE (tree_model)->root), iter->user_data = list;
gtk_tree_path_get_indices (path)[0]); return TRUE;
return iter->user_data != NULL;
} }
static GtkTreePath * 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_IS_LIST_STORE (tree_model), FALSE);
g_return_val_if_fail (GTK_LIST_STORE (tree_model)->stamp == iter->stamp, FALSE); g_return_val_if_fail (GTK_LIST_STORE (tree_model)->stamp == iter->stamp, FALSE);
iter->user_data = G_SLIST (iter->user_data)->next; if (G_SLIST (iter->user_data)->next)
{
return (iter->user_data != NULL); iter->user_data = G_SLIST (iter->user_data)->next;
return TRUE;
}
else
return FALSE;
} }
static gboolean static gboolean
@ -401,18 +432,22 @@ gtk_list_store_iter_children (GtkTreeModel *tree_model,
GtkTreeIter *iter, GtkTreeIter *iter,
GtkTreeIter *parent) GtkTreeIter *parent)
{ {
/* this is a list, nodes have no children */
if (parent) if (parent)
{ return FALSE;
iter->stamp = 0;
iter->user_data = NULL; /* but if parent == NULL we return the list itself as children of the
return FALSE; * "root"
} */
else
if (GTK_LIST_STORE (tree_model)->root)
{ {
iter->stamp = GTK_LIST_STORE (tree_model)->stamp; iter->stamp = GTK_LIST_STORE (tree_model)->stamp;
iter->user_data = GTK_LIST_STORE (tree_model)->root; iter->user_data = GTK_LIST_STORE (tree_model)->root;
return TRUE; return TRUE;
} }
else
return FALSE;
} }
static gboolean static gboolean
@ -427,9 +462,9 @@ gtk_list_store_iter_n_children (GtkTreeModel *tree_model,
GtkTreeIter *iter) GtkTreeIter *iter)
{ {
if (iter == NULL) if (iter == NULL)
return g_slist_length (G_SLIST (GTK_LIST_STORE (tree_model)->root)); return GTK_LIST_STORE (tree_model)->length;
else
return 0; return 0;
} }
static gboolean static gboolean
@ -438,24 +473,23 @@ gtk_list_store_iter_nth_child (GtkTreeModel *tree_model,
GtkTreeIter *parent, GtkTreeIter *parent,
gint n) gint n)
{ {
GSList *child;
g_return_val_if_fail (GTK_IS_LIST_STORE (tree_model), FALSE); g_return_val_if_fail (GTK_IS_LIST_STORE (tree_model), FALSE);
if (parent) if (parent)
return FALSE;
child = g_slist_nth (G_SLIST (GTK_LIST_STORE (tree_model)->root), n);
if (child)
{ {
g_return_val_if_fail (iter->stamp == GTK_LIST_STORE (tree_model)->stamp, FALSE); iter->user_data = child;
iter->stamp = 0; iter->stamp = GTK_LIST_STORE (tree_model)->stamp;
iter->user_data = NULL; return TRUE;
return FALSE;
} }
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;
else else
iter->stamp = 0; return FALSE;
return (iter->user_data != NULL);
} }
static gboolean static gboolean
@ -463,9 +497,6 @@ gtk_list_store_iter_parent (GtkTreeModel *tree_model,
GtkTreeIter *iter, GtkTreeIter *iter,
GtkTreeIter *child) GtkTreeIter *child)
{ {
iter->stamp = 0;
iter->user_data = NULL;
return FALSE; return FALSE;
} }
@ -674,11 +705,12 @@ remove_link_saving_prev (GSList *list,
if (tmp == link) if (tmp == link)
{ {
if (prev) if (prev)
prev->next = tmp->next; prev->next = link->next;
if (list == tmp)
if (list == link)
list = list->next; list = list->next;
tmp->next = NULL; link->next = NULL;
break; 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), list_store->root = remove_link_saving_prev (G_SLIST (list_store->root),
G_SLIST (iter->user_data), G_SLIST (iter->user_data),
&prev); &prev);
list_store->length -= 1;
if (iter->user_data == list_store->tail) if (iter->user_data == list_store->tail)
list_store->tail = prev; 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 (list_store != NULL);
g_return_if_fail (GTK_IS_LIST_STORE (list_store)); 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); 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); gtk_list_store_remove_silently (list_store, iter, path);
validate_list_store (list_store);
gtk_signal_emit_by_name (GTK_OBJECT (list_store), gtk_signal_emit_by_name (GTK_OBJECT (list_store),
"deleted", "deleted",
path); path);
@ -753,6 +790,8 @@ insert_after (GtkListStore *list_store,
/* if list was the tail, the new node is the new tail */ /* if list was the tail, the new node is the new tail */
if (sibling == list_store->tail) if (sibling == list_store->tail)
list_store->tail = new_list; list_store->tail = new_list;
list_store->length += 1;
} }
void void
@ -789,6 +828,8 @@ gtk_list_store_insert (GtkListStore *list_store,
iter->stamp = list_store->stamp; iter->stamp = list_store->stamp;
iter->user_data = new_list; iter->user_data = new_list;
validate_list_store (list_store);
path = gtk_tree_path_new (); path = gtk_tree_path_new ();
gtk_tree_path_append_index (path, position); gtk_tree_path_append_index (path, position);
@ -819,7 +860,8 @@ gtk_list_store_insert_before (GtkListStore *list_store,
new_list = g_slist_alloc (); new_list = g_slist_alloc ();
prev = list = list_store->root; prev = NULL;
list = list_store->root;
while (list && list != sibling->user_data) while (list && list != sibling->user_data)
{ {
prev = list; prev = list;
@ -854,6 +896,10 @@ gtk_list_store_insert_before (GtkListStore *list_store,
iter->stamp = list_store->stamp; iter->stamp = list_store->stamp;
iter->user_data = new_list; iter->user_data = new_list;
list_store->length += 1;
validate_list_store (list_store);
path = gtk_tree_path_new (); path = gtk_tree_path_new ();
gtk_tree_path_append_index (path, i); 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->stamp = list_store->stamp;
iter->user_data = new_list; iter->user_data = new_list;
validate_list_store (list_store);
path = gtk_tree_path_new (); path = gtk_tree_path_new ();
gtk_tree_path_append_index (path, i); 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); G_SLIST (iter->user_data)->next = G_SLIST (list_store->root);
list_store->root = iter->user_data; list_store->root = iter->user_data;
list_store->length += 1;
validate_list_store (list_store);
path = gtk_tree_path_new (); path = gtk_tree_path_new ();
gtk_tree_path_append_index (path, 0); gtk_tree_path_append_index (path, 0);
gtk_signal_emit_by_name (GTK_OBJECT (list_store), 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->root = iter->user_data;
list_store->tail = iter->user_data; list_store->tail = iter->user_data;
list_store->length += 1;
validate_list_store (list_store);
path = gtk_tree_path_new (); path = gtk_tree_path_new ();
gtk_tree_path_append_index (path, i); 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, if (!gtk_tree_model_get_iter (src_model,
&src_iter, &src_iter,
src_path)) 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_) */ /* Get the path to insert _after_ (dest is the path to insert _before_) */
prev = gtk_tree_path_copy (dest); prev = gtk_tree_path_copy (dest);
@ -1051,6 +1110,8 @@ gtk_list_store_drag_data_received (GtkTreeDragDest *drag_dest,
&dest_iter); &dest_iter);
retval = TRUE; retval = TRUE;
g_print ("prepending to list\n");
} }
else else
{ {
@ -1063,7 +1124,11 @@ gtk_list_store_drag_data_received (GtkTreeDragDest *drag_dest,
&dest_iter, &dest_iter,
&tmp_iter); &tmp_iter);
retval = TRUE; retval = TRUE;
g_print ("inserting into list\n");
} }
else
g_print ("can't get iter to insert after\n");
} }
gtk_tree_path_free (prev); 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 /* FIXME maybe add some data targets eventually, or handle text
* targets in the simple case. * targets in the simple case.
*/ */
g_print ("not accepting target\n");
} }
out: out:
@ -1120,3 +1186,29 @@ gtk_list_store_drag_data_received (GtkTreeDragDest *drag_dest,
return retval; 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;
}

View File

@ -45,6 +45,7 @@ struct _GtkListStore
GSList *tail; GSList *tail;
gint n_columns; gint n_columns;
GType *column_headers; GType *column_headers;
gint length;
}; };
struct _GtkListStoreClass struct _GtkListStoreClass

View File

@ -239,9 +239,12 @@ _gtk_tree_data_list_node_copy (GtkTreeDataList *list,
GType type) GType type)
{ {
GtkTreeDataList *new_list; GtkTreeDataList *new_list;
g_return_val_if_fail (list != NULL, NULL);
new_list = _gtk_tree_data_list_alloc (); new_list = _gtk_tree_data_list_alloc ();
new_list->next = NULL;
switch (type) switch (type)
{ {
case G_TYPE_UINT: case G_TYPE_UINT:
@ -279,3 +282,6 @@ _gtk_tree_data_list_node_copy (GtkTreeDataList *list,
return new_list; return new_list;
} }

View File

@ -155,6 +155,38 @@ gtk_tree_drag_dest_drag_data_received (GtkTreeDragDest *drag_dest,
return (* iface->drag_data_received) (drag_dest, dest, selection_data); 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; typedef struct _TreeRowData TreeRowData;
struct _TreeRowData struct _TreeRowData

View File

@ -41,11 +41,11 @@ struct _GtkTreeDragSourceIface
/* VTable - not signals */ /* VTable - not signals */
gboolean (* drag_data_get) (GtkTreeDragSource *dragsource, gboolean (* drag_data_get) (GtkTreeDragSource *drag_source,
GtkTreePath *path, GtkTreePath *path,
GtkSelectionData *selection_data); GtkSelectionData *selection_data);
gboolean (* drag_data_delete) (GtkTreeDragSource *dragsource, gboolean (* drag_data_delete) (GtkTreeDragSource *drag_source,
GtkTreePath *path); GtkTreePath *path);
}; };
@ -76,10 +76,14 @@ struct _GtkTreeDragDestIface
/* VTable - not signals */ /* VTable - not signals */
gboolean (* drag_data_received) (GtkTreeDragDest *dragdest, gboolean (* drag_data_received) (GtkTreeDragDest *drag_dest,
GtkTreePath *dest, GtkTreePath *dest,
GtkSelectionData *selection_data); 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; 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, GtkTreePath *dest,
GtkSelectionData *selection_data); 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 /* The selection data would normally have target type GTK_TREE_MODEL_ROW in this
* case. If the target is wrong these functions return FALSE. * case. If the target is wrong these functions return FALSE.
*/ */

View File

@ -322,6 +322,73 @@ gtk_tree_path_compare (const GtkTreePath *a,
return (a->depth < b->depth?1:-1); return (a->depth < b->depth?1:-1);
} }
/**
* 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: * gtk_tree_path_next:
* @path: A #GtkTreePath. * @path: A #GtkTreePath.
@ -350,10 +417,10 @@ gtk_tree_path_prev (GtkTreePath *path)
{ {
g_return_val_if_fail (path != NULL, FALSE); g_return_val_if_fail (path != NULL, FALSE);
if (path->indices[path->depth] == 0) if (path->indices[path->depth - 1] == 0)
return FALSE; return FALSE;
path->indices[path->depth - 1] --; path->indices[path->depth - 1] -= 1;
return TRUE; return TRUE;
} }
@ -437,6 +504,15 @@ inserted_callback (GtkTreeModel *tree_model,
RowRefList *refs = data; RowRefList *refs = data;
GSList *tmp_list; 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; tmp_list = refs->list;
while (tmp_list != NULL) while (tmp_list != NULL)
@ -449,40 +525,21 @@ inserted_callback (GtkTreeModel *tree_model,
if (reference->path) if (reference->path)
{ {
gint i;
gint depth = gtk_tree_path_get_depth (path); 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_depth = gtk_tree_path_get_depth (reference->path);
gint *ref_indices = gtk_tree_path_get_indices (reference->path);
if (ref_depth >= depth)
for (i = 0; i < depth && i < ref_depth; i++)
{ {
if (indices[i] < ref_indices[i]) gint *indices = gtk_tree_path_get_indices (path);
{ gint *ref_indices = gtk_tree_path_get_indices (reference->path);
/* inserted node was before the referenced row; gint i;
* 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;
}
}
/* If we didn't break out of the for loop, the inserted path /* This is the depth that might affect us. */
* was a child of the referenced path i = depth - 1;
*/
if (indices[i] <= ref_indices[i])
ref_indices[i] += 1;
}
} }
tmp_list = g_slist_next (tmp_list); tmp_list = g_slist_next (tmp_list);
@ -497,6 +554,17 @@ deleted_callback (GtkTreeModel *tree_model,
RowRefList *refs = data; RowRefList *refs = data;
GSList *tmp_list; 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; tmp_list = refs->list;
while (tmp_list != NULL) while (tmp_list != NULL)
@ -509,41 +577,29 @@ deleted_callback (GtkTreeModel *tree_model,
if (reference->path) if (reference->path)
{ {
gint i;
gint depth = gtk_tree_path_get_depth (path); 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_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]) if (indices[i] < ref_indices[i])
ref_indices[i] -= 1;
else if (indices[i] == ref_indices[i])
{ {
/* deleted node was before the referenced row; /* the referenced node itself, or its parent, was
* move referenced path up 1 * deleted, mark invalid
*/
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
*/ */
gtk_tree_path_free (reference->path); gtk_tree_path_free (reference->path);
reference->path = NULL; 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); tmp_list = g_slist_next (tmp_list);
@ -722,7 +778,6 @@ gtk_tree_iter_free (GtkTreeIter *iter)
g_return_if_fail (iter != NULL); g_return_if_fail (iter != NULL);
g_free (iter); g_free (iter);
} }
/** /**

View File

@ -134,6 +134,11 @@ gboolean gtk_tree_path_prev (GtkTreePath *path);
gboolean gtk_tree_path_up (GtkTreePath *path); gboolean gtk_tree_path_up (GtkTreePath *path);
void gtk_tree_path_down (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 /* 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) * same row always; a path refers to a position, not a fixed row)
*/ */

View File

@ -20,6 +20,7 @@
#include "gtktreemodel.h" #include "gtktreemodel.h"
#include "gtktreestore.h" #include "gtktreestore.h"
#include "gtktreedatalist.h" #include "gtktreedatalist.h"
#include "gtktreednd.h"
#include "gtksignal.h" #include "gtksignal.h"
#include <string.h> #include <string.h>
#include <gobject/gvaluecollector.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_init (GtkTreeStore *tree_store);
static void gtk_tree_store_class_init (GtkTreeStoreClass *tree_store_class); 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_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 guint gtk_tree_store_get_flags (GtkTreeModel *tree_model);
static gint gtk_tree_store_get_n_columns (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, 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); 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 GtkType
gtk_tree_store_get_type (void) gtk_tree_store_get_type (void)
{ {
@ -95,10 +124,34 @@ gtk_tree_store_get_type (void)
NULL 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); tree_store_type = g_type_register_static (GTK_TYPE_OBJECT, "GtkTreeStore", &tree_store_info, 0);
g_type_add_interface_static (tree_store_type, g_type_add_interface_static (tree_store_type,
GTK_TYPE_TREE_MODEL, GTK_TYPE_TREE_MODEL,
&tree_model_info); &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; return tree_store_type;
@ -164,6 +217,20 @@ gtk_tree_store_tree_model_init (GtkTreeModelIface *iface)
iface->iter_parent = gtk_tree_store_iter_parent; iface->iter_parent = gtk_tree_store_iter_parent;
} }
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 static void
gtk_tree_store_init (GtkTreeStore *tree_store) gtk_tree_store_init (GtkTreeStore *tree_store)
{ {
@ -242,7 +309,7 @@ gtk_tree_store_set_column_type (GtkTreeStore *tree_store,
/* fulfill the GtkTreeModel requirements */ /* fulfill the GtkTreeModel requirements */
/* NOTE: GtkTreeStore::root is a GNode, that acts as the parent node. However, /* 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. * first child of GtkTreeStore::root.
*/ */
@ -281,13 +348,13 @@ gtk_tree_store_get_path (GtkTreeModel *tree_model,
GtkTreePath *retval; GtkTreePath *retval;
GNode *tmp_node; GNode *tmp_node;
gint i = 0; gint i = 0;
g_return_val_if_fail (tree_model != NULL, NULL); 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 (GTK_IS_TREE_STORE (tree_model), NULL);
g_return_val_if_fail (iter != NULL, NULL); g_return_val_if_fail (iter != NULL, NULL);
g_return_val_if_fail (iter->user_data != NULL, NULL);
if (iter->user_data == NULL) validate_tree ((GtkTreeStore*)tree_model);
return NULL;
g_assert (G_NODE (iter->user_data)->parent != NULL); g_assert (G_NODE (iter->user_data)->parent != NULL);
@ -299,7 +366,8 @@ gtk_tree_store_get_path (GtkTreeModel *tree_model,
else else
{ {
GtkTreeIter tmp_iter = *iter; 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, retval = gtk_tree_store_get_path (tree_model,
&tmp_iter); &tmp_iter);
@ -372,12 +440,15 @@ static gboolean
gtk_tree_store_iter_next (GtkTreeModel *tree_model, gtk_tree_store_iter_next (GtkTreeModel *tree_model,
GtkTreeIter *iter) 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; return FALSE;
iter->user_data = G_NODE (iter->user_data)->next;
return (iter->user_data != NULL);
} }
static gboolean static gboolean
@ -385,13 +456,23 @@ gtk_tree_store_iter_children (GtkTreeModel *tree_model,
GtkTreeIter *iter, GtkTreeIter *iter,
GtkTreeIter *parent) GtkTreeIter *parent)
{ {
iter->stamp = GTK_TREE_STORE (tree_model)->stamp; GNode *children;
if (parent)
iter->user_data = G_NODE (parent->user_data)->children;
else
iter->user_data = G_NODE (GTK_TREE_STORE (tree_model)->root)->children;
return iter->user_data != NULL; g_return_val_if_fail (parent == NULL || parent->user_data != NULL, FALSE);
if (parent)
children = G_NODE (parent->user_data)->children;
else
children = G_NODE (GTK_TREE_STORE (tree_model)->root)->children;
if (children)
{
iter->stamp = GTK_TREE_STORE (tree_model)->stamp;
iter->user_data = children;
return TRUE;
}
else
return FALSE;
} }
static gboolean 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 (tree_model != NULL, FALSE);
g_return_val_if_fail (GTK_IS_TREE_STORE (tree_model), 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 != NULL, FALSE);
g_return_val_if_fail (iter->user_data != NULL, FALSE);
return G_NODE (iter->user_data)->children != NULL; 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 (tree_model != NULL, 0);
g_return_val_if_fail (GTK_IS_TREE_STORE (tree_model), 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) if (iter == NULL)
node = G_NODE (GTK_TREE_STORE (tree_model)->root)->children; node = G_NODE (GTK_TREE_STORE (tree_model)->root)->children;
else else
node = G_NODE (iter->user_data)->children; node = G_NODE (iter->user_data)->children;
while (node) while (node)
{ {
i++; i++;
@ -435,24 +520,27 @@ gtk_tree_store_iter_nth_child (GtkTreeModel *tree_model,
gint n) gint n)
{ {
GNode *parent_node; GNode *parent_node;
GNode *child;
g_return_val_if_fail (tree_model != NULL, FALSE); 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 (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) if (parent == NULL)
parent_node = GTK_TREE_STORE (tree_model)->root; parent_node = GTK_TREE_STORE (tree_model)->root;
else else
parent_node = parent->user_data; 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) if (child)
iter->stamp = 0; {
iter->user_data = child;
iter->stamp = GTK_TREE_STORE (tree_model)->stamp;
return TRUE;
}
else else
iter->stamp = GTK_TREE_STORE (tree_model)->stamp; return FALSE;
return (iter->user_data != NULL);
} }
static gboolean static gboolean
@ -460,19 +548,23 @@ gtk_tree_store_iter_parent (GtkTreeModel *tree_model,
GtkTreeIter *iter, GtkTreeIter *iter,
GtkTreeIter *child) GtkTreeIter *child)
{ {
g_assert (G_NODE (child->user_data)->parent != NULL); GNode *parent;
iter->stamp = GTK_TREE_STORE (tree_model)->stamp; g_return_val_if_fail (iter != NULL, FALSE);
iter->user_data = G_NODE (child->user_data)->parent; g_return_val_if_fail (iter->user_data != NULL, FALSE);
if (iter->user_data == GTK_TREE_STORE (tree_model)->root) parent = G_NODE (child->user_data)->parent;
g_assert (parent != NULL);
if (parent != GTK_TREE_STORE (tree_model)->root)
{ {
iter->stamp = 0; iter->user_data = parent;
iter->user_data = NULL; iter->stamp = GTK_TREE_STORE (tree_model)->stamp;
return FALSE; return TRUE;
} }
else
return TRUE; return FALSE;
} }
/* /*
@ -708,22 +800,27 @@ gtk_tree_store_insert (GtkTreeStore *model,
gint position) gint position)
{ {
GtkTreePath *path; GtkTreePath *path;
GNode *parent_node;
g_return_if_fail (model != NULL); g_return_if_fail (model != NULL);
g_return_if_fail (GTK_IS_TREE_STORE (model)); g_return_if_fail (GTK_IS_TREE_STORE (model));
if (parent->user_data == NULL) if (parent)
parent->user_data = model->root; parent_node = parent->user_data;
else
parent_node = model->root;
iter->stamp = model->stamp; iter->stamp = model->stamp;
iter->user_data = g_node_new (NULL); 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); path = gtk_tree_store_get_path (GTK_TREE_MODEL (model), iter);
gtk_signal_emit_by_name (GTK_OBJECT (model), gtk_signal_emit_by_name (GTK_OBJECT (model),
"inserted", "inserted",
path, iter); path, iter);
gtk_tree_path_free (path); gtk_tree_path_free (path);
validate_tree ((GtkTreeStore*)model);
} }
void void
@ -733,7 +830,7 @@ gtk_tree_store_insert_before (GtkTreeStore *model,
GtkTreeIter *sibling) GtkTreeIter *sibling)
{ {
GtkTreePath *path; GtkTreePath *path;
GNode *parent_node = NULL; GNode *parent_node = NULL;
GNode *new_node; GNode *new_node;
g_return_if_fail (model != NULL); g_return_if_fail (model != NULL);
@ -767,6 +864,8 @@ gtk_tree_store_insert_before (GtkTreeStore *model,
"inserted", "inserted",
path, iter); path, iter);
gtk_tree_path_free (path); gtk_tree_path_free (path);
validate_tree ((GtkTreeStore*)model);
} }
void void
@ -811,6 +910,8 @@ gtk_tree_store_insert_after (GtkTreeStore *model,
"inserted", "inserted",
path, iter); path, iter);
gtk_tree_path_free (path); gtk_tree_path_free (path);
validate_tree ((GtkTreeStore*)model);
} }
void void
@ -861,6 +962,8 @@ gtk_tree_store_prepend (GtkTreeStore *model,
{ {
gtk_tree_store_insert_after (model, iter, parent, NULL); gtk_tree_store_insert_after (model, iter, parent, NULL);
} }
validate_tree ((GtkTreeStore*)model);
} }
void void
@ -873,19 +976,19 @@ gtk_tree_store_append (GtkTreeStore *model,
g_return_if_fail (model != NULL); g_return_if_fail (model != NULL);
g_return_if_fail (GTK_IS_TREE_STORE (model)); g_return_if_fail (GTK_IS_TREE_STORE (model));
g_return_if_fail (iter != NULL); g_return_if_fail (iter != NULL);
if (parent == NULL) if (parent == NULL)
parent_node = model->root; parent_node = model->root;
else else
parent_node = parent->user_data; parent_node = parent->user_data;
iter->stamp = model->stamp;
iter->user_data = g_node_new (NULL);
if (parent_node->children == NULL) if (parent_node->children == NULL)
{ {
GtkTreePath *path; GtkTreePath *path;
iter->stamp = model->stamp;
iter->user_data = g_node_new (NULL);
g_node_append (parent_node, G_NODE (iter->user_data)); g_node_append (parent_node, G_NODE (iter->user_data));
if (parent_node != model->root) 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); path = gtk_tree_store_get_path (GTK_TREE_MODEL (model), iter);
} }
gtk_signal_emit_by_name (GTK_OBJECT (model), gtk_signal_emit_by_name (GTK_OBJECT (model),
"inserted", "inserted",
path, path,
@ -911,6 +1015,8 @@ gtk_tree_store_append (GtkTreeStore *model,
{ {
gtk_tree_store_insert_before (model, iter, parent, NULL); gtk_tree_store_insert_before (model, iter, parent, NULL);
} }
validate_tree ((GtkTreeStore*)model);
} }
gboolean gboolean
@ -938,3 +1044,309 @@ gtk_tree_store_iter_depth (GtkTreeStore *model,
return g_node_depth (G_NODE (iter->user_data)) - 1; 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;
}
}

View File

@ -4787,37 +4787,71 @@ gtk_tree_view_tree_to_widget_coords (GtkTreeView *tree_view,
/* Drag-and-drop */ /* Drag-and-drop */
void static void
set_source_row (GdkDragContext *context, set_source_row (GdkDragContext *context,
GtkTreeModel *model,
GtkTreePath *source_row) GtkTreePath *source_row)
{ {
g_object_set_data_full (G_OBJECT (context), g_object_set_data_full (G_OBJECT (context),
"gtk-tree-view-source-row", "gtk-tree-view-source-row",
source_row ? gtk_tree_path_copy (source_row) : NULL, source_row ? gtk_tree_row_reference_new (model, source_row) : NULL,
(GDestroyNotify) (source_row ? gtk_tree_path_free : NULL)); (GDestroyNotify) (source_row ? gtk_tree_row_reference_free : NULL));
} }
GtkTreePath* static GtkTreePath*
get_source_row (GdkDragContext *context) 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, set_dest_row (GdkDragContext *context,
GtkTreeModel *model,
GtkTreePath *dest_row) GtkTreePath *dest_row)
{ {
g_object_set_data_full (G_OBJECT (context), g_object_set_data_full (G_OBJECT (context),
"gtk-tree-view-dest-row", "gtk-tree-view-dest-row",
dest_row ? gtk_tree_path_copy (dest_row) : NULL, dest_row ? gtk_tree_row_reference_new (model, dest_row) : NULL,
(GDestroyNotify) (dest_row ? gtk_tree_path_free : NULL)); (GDestroyNotify) (dest_row ? gtk_tree_row_reference_free : NULL));
} }
GtkTreePath* static GtkTreePath*
get_dest_row (GdkDragContext *context) 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; typedef struct _TreeViewDragInfo TreeViewDragInfo;
@ -5234,6 +5268,7 @@ gtk_tree_view_maybe_begin_dragging_row (GtkTreeView *tree_view,
GtkTreePath *path = NULL; GtkTreePath *path = NULL;
gint button; gint button;
gint cell_x, cell_y; gint cell_x, cell_y;
GtkTreeModel *model;
di = get_info (tree_view); 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) if (tree_view->priv->pressed_button < 0)
return FALSE; return FALSE;
if (!gtk_drag_check_threshold (GTK_WIDGET (tree_view), if (!gtk_drag_check_threshold (GTK_WIDGET (tree_view),
tree_view->priv->press_start_x, tree_view->priv->press_start_x,
tree_view->priv->press_start_y, tree_view->priv->press_start_y,
event->x, event->y)) event->x, event->y))
return FALSE; return FALSE;
model = gtk_tree_view_get_model (tree_view);
if (model == NULL)
return FALSE;
button = tree_view->priv->pressed_button; button = tree_view->priv->pressed_button;
tree_view->priv->pressed_button = -1; 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); gdk_pixmap_unref (row_pix);
} }
set_source_row (context, path); set_source_row (context, model, path);
gtk_tree_path_free (path); gtk_tree_path_free (path);
return TRUE; 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), gtk_tree_drag_source_drag_data_get (GTK_TREE_DRAG_SOURCE (model),
source_row, source_row,
selection_data)) selection_data))
return; goto done;
/* If drag_data_get does nothing, try providing row data. */ /* If drag_data_get does nothing, try providing row data. */
if (selection_data->target == gdk_atom_intern ("GTK_TREE_MODEL_ROW", FALSE)) 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, model,
source_row); 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 " g_warning ("You must override the default '%s' handler "
"on GtkTreeView when using models that don't support " "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 " "is to connect to '%s' and call "
"gtk_signal_emit_stop_by_name() in your signal handler to prevent " "gtk_signal_emit_stop_by_name() in your signal handler to prevent "
"the default handler from running. Look at the source code " "the default handler from running. Look at the source code "
"for the default handler in gtktreeview.c to get an idea what " "for the default handler in gtktreeview.c to get an idea what "
"your handler should do. (gtktreeview.c is in the GTK source " "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); signal, g_type_name (required_iface), signal);
return FALSE; return FALSE;
} }
@ -5404,6 +5448,8 @@ gtk_tree_view_drag_data_delete (GtkWidget *widget,
tree_view = GTK_TREE_VIEW (widget); tree_view = GTK_TREE_VIEW (widget);
model = gtk_tree_view_get_model (tree_view); 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")) if (!check_model_dnd (model, GTK_TYPE_TREE_DRAG_SOURCE, "drag_data_delete"))
return; return;
@ -5414,11 +5460,15 @@ gtk_tree_view_drag_data_delete (GtkWidget *widget,
source_row = get_source_row (context); source_row = get_source_row (context);
if (source_row == NULL)
return;
gtk_tree_drag_source_drag_data_delete (GTK_TREE_DRAG_SOURCE (model), gtk_tree_drag_source_drag_data_delete (GTK_TREE_DRAG_SOURCE (model),
source_row); source_row);
set_source_row (context, NULL); gtk_tree_path_free (source_row);
set_source_row (context, NULL, NULL);
} }
static void static void
@ -5488,7 +5538,8 @@ set_destination_row (GtkTreeView *tree_view,
GdkDragContext *context, GdkDragContext *context,
gint x, gint x,
gint y, gint y,
GdkDragAction *suggested_action) GdkDragAction *suggested_action,
GdkAtom *target)
{ {
GtkTreePath *path = NULL; GtkTreePath *path = NULL;
GtkTreeViewDropPosition pos; GtkTreeViewDropPosition pos;
@ -5498,6 +5549,7 @@ set_destination_row (GtkTreeView *tree_view,
GtkTreePath *old_dest_path = NULL; GtkTreePath *old_dest_path = NULL;
*suggested_action = 0; *suggested_action = 0;
*target = GDK_NONE;
widget = GTK_WIDGET (tree_view); widget = GTK_WIDGET (tree_view);
@ -5520,8 +5572,8 @@ set_destination_row (GtkTreeView *tree_view,
return FALSE; /* no longer a drop site */ return FALSE; /* no longer a drop site */
} }
/* We don't take this target */ *target = gtk_drag_dest_find_target (widget, context, di->dest_target_list);
if (gtk_drag_dest_find_target (widget, context, di->dest_target_list) == GDK_NONE) if (*target == GDK_NONE)
{ {
g_print ("bad target, not accepting\n"); g_print ("bad target, not accepting\n");
return FALSE; return FALSE;
@ -5608,12 +5660,13 @@ gtk_tree_view_drag_motion (GtkWidget *widget,
GtkTreeViewDropPosition pos; GtkTreeViewDropPosition pos;
GtkTreeView *tree_view; GtkTreeView *tree_view;
GdkDragAction suggested_action = 0; GdkDragAction suggested_action = 0;
GdkAtom target;
tree_view = GTK_TREE_VIEW (widget); tree_view = GTK_TREE_VIEW (widget);
g_print ("motion\n"); 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; return FALSE;
ensure_scroll_timeout (tree_view); ensure_scroll_timeout (tree_view);
@ -5633,11 +5686,24 @@ gtk_tree_view_drag_motion (GtkWidget *widget,
pos == GTK_TREE_VIEW_DROP_INTO_OR_BEFORE)) pos == GTK_TREE_VIEW_DROP_INTO_OR_BEFORE))
{ {
tree_view->priv->open_dest_timeout = 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"); if (target == gdk_atom_intern ("GTK_TREE_MODEL_ROW", FALSE))
gdk_drag_status (context, suggested_action, time); {
/* 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) if (path)
@ -5646,6 +5712,36 @@ gtk_tree_view_drag_motion (GtkWidget *widget,
return TRUE; 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 static gboolean
gtk_tree_view_drag_drop (GtkWidget *widget, gtk_tree_view_drag_drop (GtkWidget *widget,
GdkDragContext *context, GdkDragContext *context,
@ -5653,9 +5749,8 @@ gtk_tree_view_drag_drop (GtkWidget *widget,
gint y, gint y,
guint time) guint time)
{ {
GtkTreePath *path = NULL;
GtkTreeViewDropPosition pos;
GtkTreeView *tree_view; GtkTreeView *tree_view;
GtkTreePath *path;
GdkDragAction suggested_action = 0; GdkDragAction suggested_action = 0;
GdkAtom target = GDK_NONE; GdkAtom target = GDK_NONE;
TreeViewDragInfo *di; TreeViewDragInfo *di;
@ -5669,30 +5764,30 @@ gtk_tree_view_drag_drop (GtkWidget *widget,
remove_scroll_timeout (GTK_TREE_VIEW (widget)); remove_scroll_timeout (GTK_TREE_VIEW (widget));
remove_open_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) if (di == NULL)
return FALSE; return FALSE;
if (!check_model_dnd (model, GTK_TYPE_TREE_DRAG_DEST, "drag_drop")) if (!check_model_dnd (model, GTK_TYPE_TREE_DRAG_DEST, "drag_drop"))
return FALSE; 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; 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) /* in case a motion had requested drag data, change things so we
{ * treat drag data receives as a drop.
g_print ("have target\n"); */
set_status_pending (context, 0);
set_dest_row (context, path);
} set_dest_row (context, model, path);
} }
if (path) if (path)
@ -5722,11 +5817,13 @@ gtk_tree_view_drag_data_received (GtkWidget *widget,
guint info, guint info,
guint time) guint time)
{ {
GtkTreePath *path;
TreeViewDragInfo *di; TreeViewDragInfo *di;
gboolean accepted = FALSE; gboolean accepted = FALSE;
GtkTreeModel *model; GtkTreeModel *model;
GtkTreeView *tree_view; GtkTreeView *tree_view;
GtkTreePath *dest_row; GtkTreePath *dest_row;
GdkDragAction suggested_action;
tree_view = GTK_TREE_VIEW (widget); tree_view = GTK_TREE_VIEW (widget);
@ -5742,6 +5839,58 @@ gtk_tree_view_drag_data_received (GtkWidget *widget,
if (di == NULL) if (di == NULL)
return; 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); dest_row = get_dest_row (context);
if (dest_row == NULL) if (dest_row == NULL)
@ -5753,16 +5902,17 @@ gtk_tree_view_drag_data_received (GtkWidget *widget,
dest_row, dest_row,
selection_data)) selection_data))
accepted = TRUE; 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, gtk_drag_finish (context,
accepted, accepted,
(context->action == GDK_ACTION_MOVE), (context->action == GDK_ACTION_MOVE),
time); time);
g_print ("accepted: %d\n", accepted);
gtk_tree_path_free (dest_row);
/* drop dest_row */
set_dest_row (context, NULL, NULL);
} }

View File

@ -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, void gtk_tree_view_set_drag_dest_row (GtkTreeView *tree_view,
GtkTreePath *path, GtkTreePath *path,
GtkTreeViewDropPosition pos); GtkTreeViewDropPosition pos);
void gtk_tree_view_get_drag_dest_row (GtkTreeView *tree_view, void gtk_tree_view_get_drag_dest_row (GtkTreeView *tree_view,
GtkTreePath **path, GtkTreePath **path,
GtkTreeViewDropPosition *pos); GtkTreeViewDropPosition *pos);
gboolean gtk_tree_view_get_dest_row_at_pos (GtkTreeView *tree_view, gboolean gtk_tree_view_get_dest_row_at_pos (GtkTreeView *tree_view,
gint drag_x, gint drag_x,
gint drag_y, gint drag_y,