]> Pileus Git - ~andy/gtk/commitdiff
fix bug in here where prev pointer was set to the wrong thing
authorHavoc Pennington <hp@redhat.com>
Wed, 31 Jan 2001 00:57:49 +0000 (00:57 +0000)
committerHavoc Pennington <hp@src.gnome.org>
Wed, 31 Jan 2001 00:57:49 +0000 (00:57 +0000)
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

17 files changed:
ChangeLog
ChangeLog.pre-2-0
ChangeLog.pre-2-10
ChangeLog.pre-2-2
ChangeLog.pre-2-4
ChangeLog.pre-2-6
ChangeLog.pre-2-8
gtk/gtkliststore.c
gtk/gtkliststore.h
gtk/gtktreedatalist.c
gtk/gtktreednd.c
gtk/gtktreednd.h
gtk/gtktreemodel.c
gtk/gtktreemodel.h
gtk/gtktreestore.c
gtk/gtktreeview.c
gtk/gtktreeview.h

index 3d676d25e3b30b580ba6985c253d6b3a9876b31a..6f1186075149d641d3195c3cc47d3983fc789c8d 100644 (file)
--- 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
index 3d676d25e3b30b580ba6985c253d6b3a9876b31a..6f1186075149d641d3195c3cc47d3983fc789c8d 100644 (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>
 
        * gtk/gtktreeselection.c (gtk_tree_selection_unselect_iter): Fix
index 3d676d25e3b30b580ba6985c253d6b3a9876b31a..6f1186075149d641d3195c3cc47d3983fc789c8d 100644 (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>
 
        * gtk/gtktreeselection.c (gtk_tree_selection_unselect_iter): Fix
index 3d676d25e3b30b580ba6985c253d6b3a9876b31a..6f1186075149d641d3195c3cc47d3983fc789c8d 100644 (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>
 
        * gtk/gtktreeselection.c (gtk_tree_selection_unselect_iter): Fix
index 3d676d25e3b30b580ba6985c253d6b3a9876b31a..6f1186075149d641d3195c3cc47d3983fc789c8d 100644 (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>
 
        * gtk/gtktreeselection.c (gtk_tree_selection_unselect_iter): Fix
index 3d676d25e3b30b580ba6985c253d6b3a9876b31a..6f1186075149d641d3195c3cc47d3983fc789c8d 100644 (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>
 
        * gtk/gtktreeselection.c (gtk_tree_selection_unselect_iter): Fix
index 3d676d25e3b30b580ba6985c253d6b3a9876b31a..6f1186075149d641d3195c3cc47d3983fc789c8d 100644 (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>
 
        * gtk/gtktreeselection.c (gtk_tree_selection_unselect_iter): Fix
index ef3300430fd2bcb0dfcdce98125936f09065f30c..2191146157f7525e67649e015e1a96f63c75e676 100644 (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,
                                                    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;
+}
index 55ad276a01bbb8a9c7d0584c382e2f83e74700ba..de591de53f92efe91f3b3c0b2fc706751110cc69 100644 (file)
@@ -45,6 +45,7 @@ struct _GtkListStore
   GSList *tail;
   gint n_columns;
   GType *column_headers;
+  gint length;
 };
 
 struct _GtkListStoreClass
index b55b730af50092c9c5a3f53c502eca9d4ed7b3dd..862a64107bc3c7a57e3861ab99f9299d8011451f 100644 (file)
@@ -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;
 }
+
+
+
index f798022c25dfb1c3cc9fe98f08facc0f1f07ccb6..bdf9e4abdea730d2843b1d27e9784bc1a4189e5f 100644 (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);
 }
 
+
+/**
+ * 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
index 1257ed25f667ce3f619433bf6bf99fe20b7c6ac7..8e9513ec2430b313db5b0232b17bf356e9f894a8 100644 (file)
@@ -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.
  */
index 2b719a3d49503684030a6a17dac5a180d368ab9f..da6e5feea8727e3b2270ac1b195cc26b631db457 100644 (file)
@@ -322,6 +322,73 @@ gtk_tree_path_compare (const GtkTreePath *a,
   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:
  * @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);
-
 }
 
 /**
index 202d874bcfecaa28e32b88444bcb848f27aa5436..3ede12308ba4db4405e724b2b667d3385b05a380 100644 (file)
@@ -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)
  */
index aa8c658368f94105507269517bf95d1a6522edff..d44c46819713f6e9b97aff01163c430e2e195569 100644 (file)
@@ -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;
@@ -164,6 +217,20 @@ gtk_tree_store_tree_model_init (GtkTreeModelIface *iface)
   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
 gtk_tree_store_init (GtkTreeStore *tree_store)
 {
@@ -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;
+    }
+}
+
+
index 9d26b0a33b3f0a767ac73247ed0d0d86696e3aa9..db5de4e46b030f2b8a23161b029aed9bf6fb35f6 100644 (file)
@@ -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);
+}
index 22890ae66ae53dcf6eee491d7e20a1c61c244c99..fd36f4d0a68e97cd64ae87a06da0ff1c0cc6ad9b 100644 (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,
                                                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,