]> Pileus Git - ~andy/gtk/commitdiff
add GtkTreeRowReference which holds a handle to a specific row (particular
authorHavoc Pennington <hp@redhat.com>
Sat, 27 Jan 2001 00:50:38 +0000 (00:50 +0000)
committerHavoc Pennington <hp@src.gnome.org>
Sat, 27 Jan 2001 00:50:38 +0000 (00:50 +0000)
2001-01-26  Havoc Pennington  <hp@redhat.com>

* gtk/gtktreemodel.c, gtk/gtktreemodel.h: add GtkTreeRowReference
which holds a handle to a specific row (particular set of values
in the model, i.e. pointer-identity row).

* gtk/gtktreeview.c, gtk/gtktreeprivate.h, gtk/gtktreeselection.c:
use GtkTreeRowReference for anchor, cursor, and drag_dest_row.
Still need to use it for the src/dest row saved on the drag context.

12 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/gtktreemodel.c
gtk/gtktreemodel.h
gtk/gtktreeprivate.h
gtk/gtktreeselection.c
gtk/gtktreeview.c

index d0e503736565a5f9eae2f9f7a6b6bbcb005040b7..5a769d35403e139182fc2e8953166df6df8e7849 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,13 @@
+2001-01-26  Havoc Pennington  <hp@redhat.com>
+
+       * gtk/gtktreemodel.c, gtk/gtktreemodel.h: add GtkTreeRowReference
+       which holds a handle to a specific row (particular set of values
+       in the model, i.e. pointer-identity row).
+
+       * gtk/gtktreeview.c, gtk/gtktreeprivate.h, gtk/gtktreeselection.c:
+       use GtkTreeRowReference for anchor, cursor, and drag_dest_row.
+       Still need to use it for the src/dest row saved on the drag context.
+
 2001-01-26  Havoc Pennington  <hp@redhat.com>
 
        * gtk/gtktextlayout.c (convert_color): adapt to handle PangoColor
index d0e503736565a5f9eae2f9f7a6b6bbcb005040b7..5a769d35403e139182fc2e8953166df6df8e7849 100644 (file)
@@ -1,3 +1,13 @@
+2001-01-26  Havoc Pennington  <hp@redhat.com>
+
+       * gtk/gtktreemodel.c, gtk/gtktreemodel.h: add GtkTreeRowReference
+       which holds a handle to a specific row (particular set of values
+       in the model, i.e. pointer-identity row).
+
+       * gtk/gtktreeview.c, gtk/gtktreeprivate.h, gtk/gtktreeselection.c:
+       use GtkTreeRowReference for anchor, cursor, and drag_dest_row.
+       Still need to use it for the src/dest row saved on the drag context.
+
 2001-01-26  Havoc Pennington  <hp@redhat.com>
 
        * gtk/gtktextlayout.c (convert_color): adapt to handle PangoColor
index d0e503736565a5f9eae2f9f7a6b6bbcb005040b7..5a769d35403e139182fc2e8953166df6df8e7849 100644 (file)
@@ -1,3 +1,13 @@
+2001-01-26  Havoc Pennington  <hp@redhat.com>
+
+       * gtk/gtktreemodel.c, gtk/gtktreemodel.h: add GtkTreeRowReference
+       which holds a handle to a specific row (particular set of values
+       in the model, i.e. pointer-identity row).
+
+       * gtk/gtktreeview.c, gtk/gtktreeprivate.h, gtk/gtktreeselection.c:
+       use GtkTreeRowReference for anchor, cursor, and drag_dest_row.
+       Still need to use it for the src/dest row saved on the drag context.
+
 2001-01-26  Havoc Pennington  <hp@redhat.com>
 
        * gtk/gtktextlayout.c (convert_color): adapt to handle PangoColor
index d0e503736565a5f9eae2f9f7a6b6bbcb005040b7..5a769d35403e139182fc2e8953166df6df8e7849 100644 (file)
@@ -1,3 +1,13 @@
+2001-01-26  Havoc Pennington  <hp@redhat.com>
+
+       * gtk/gtktreemodel.c, gtk/gtktreemodel.h: add GtkTreeRowReference
+       which holds a handle to a specific row (particular set of values
+       in the model, i.e. pointer-identity row).
+
+       * gtk/gtktreeview.c, gtk/gtktreeprivate.h, gtk/gtktreeselection.c:
+       use GtkTreeRowReference for anchor, cursor, and drag_dest_row.
+       Still need to use it for the src/dest row saved on the drag context.
+
 2001-01-26  Havoc Pennington  <hp@redhat.com>
 
        * gtk/gtktextlayout.c (convert_color): adapt to handle PangoColor
index d0e503736565a5f9eae2f9f7a6b6bbcb005040b7..5a769d35403e139182fc2e8953166df6df8e7849 100644 (file)
@@ -1,3 +1,13 @@
+2001-01-26  Havoc Pennington  <hp@redhat.com>
+
+       * gtk/gtktreemodel.c, gtk/gtktreemodel.h: add GtkTreeRowReference
+       which holds a handle to a specific row (particular set of values
+       in the model, i.e. pointer-identity row).
+
+       * gtk/gtktreeview.c, gtk/gtktreeprivate.h, gtk/gtktreeselection.c:
+       use GtkTreeRowReference for anchor, cursor, and drag_dest_row.
+       Still need to use it for the src/dest row saved on the drag context.
+
 2001-01-26  Havoc Pennington  <hp@redhat.com>
 
        * gtk/gtktextlayout.c (convert_color): adapt to handle PangoColor
index d0e503736565a5f9eae2f9f7a6b6bbcb005040b7..5a769d35403e139182fc2e8953166df6df8e7849 100644 (file)
@@ -1,3 +1,13 @@
+2001-01-26  Havoc Pennington  <hp@redhat.com>
+
+       * gtk/gtktreemodel.c, gtk/gtktreemodel.h: add GtkTreeRowReference
+       which holds a handle to a specific row (particular set of values
+       in the model, i.e. pointer-identity row).
+
+       * gtk/gtktreeview.c, gtk/gtktreeprivate.h, gtk/gtktreeselection.c:
+       use GtkTreeRowReference for anchor, cursor, and drag_dest_row.
+       Still need to use it for the src/dest row saved on the drag context.
+
 2001-01-26  Havoc Pennington  <hp@redhat.com>
 
        * gtk/gtktextlayout.c (convert_color): adapt to handle PangoColor
index d0e503736565a5f9eae2f9f7a6b6bbcb005040b7..5a769d35403e139182fc2e8953166df6df8e7849 100644 (file)
@@ -1,3 +1,13 @@
+2001-01-26  Havoc Pennington  <hp@redhat.com>
+
+       * gtk/gtktreemodel.c, gtk/gtktreemodel.h: add GtkTreeRowReference
+       which holds a handle to a specific row (particular set of values
+       in the model, i.e. pointer-identity row).
+
+       * gtk/gtktreeview.c, gtk/gtktreeprivate.h, gtk/gtktreeselection.c:
+       use GtkTreeRowReference for anchor, cursor, and drag_dest_row.
+       Still need to use it for the src/dest row saved on the drag context.
+
 2001-01-26  Havoc Pennington  <hp@redhat.com>
 
        * gtk/gtktextlayout.c (convert_color): adapt to handle PangoColor
index c1afaa3e51b3bc60d433eb308840cfa63c6b892f..2b719a3d49503684030a6a17dac5a180d368ab9f 100644 (file)
@@ -393,6 +393,297 @@ gtk_tree_path_down (GtkTreePath *path)
   gtk_tree_path_append_index (path, 0);
 }
 
+struct _GtkTreeRowReference
+{
+  GtkTreeModel *model;
+  GtkTreePath *path;
+};
+
+typedef struct _RowRefList RowRefList;
+
+struct _RowRefList
+{
+  GSList *list;
+};
+
+static void
+release_row_references (gpointer data)
+{
+  RowRefList *refs = data;
+  GSList *tmp_list = NULL;
+  
+  tmp_list = refs->list;
+  while (tmp_list != NULL)
+    {
+      GtkTreeRowReference *reference = tmp_list->data;
+
+      reference->model = NULL;
+
+      /* we don't free the reference, users are responsible for that. */
+
+      tmp_list = g_slist_next (tmp_list);
+    }
+
+  g_slist_free (refs->list);
+  g_free (refs);
+}
+
+static void
+inserted_callback (GtkTreeModel *tree_model,
+                   GtkTreePath  *path,
+                   GtkTreeIter  *iter,
+                   gpointer      data)
+{
+  RowRefList *refs = data;
+  GSList *tmp_list;
+
+  tmp_list = refs->list;
+
+  while (tmp_list != NULL)
+    {
+      GtkTreeRowReference *reference = tmp_list->data;
+
+      /* if reference->path == NULL then the reference was already
+       * deleted.
+       */
+      
+      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 (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;
+                }
+            }
+
+          /* 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);
+    }
+}
+
+static void
+deleted_callback (GtkTreeModel *tree_model,
+                  GtkTreePath  *path,
+                  gpointer      data)
+{
+  RowRefList *refs = data;
+  GSList *tmp_list;
+
+  tmp_list = refs->list;
+
+  while (tmp_list != NULL)
+    {
+      GtkTreeRowReference *reference = tmp_list->data;
+
+      /* if reference->path == NULL then the reference was already
+       * deleted.
+       */
+      
+      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 (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
+                   */
+                  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);
+    }
+}
+
+static void
+reordered_callback (GtkTreeModel *tree_model,
+                    GtkTreePath  *path,
+                    gint         *new_order,
+                    gpointer      data)
+{
+
+  /* FIXME */
+}
+
+static void
+connect_ref_callbacks (GtkTreeModel *model,
+                       RowRefList   *refs)
+{
+  g_signal_connect_data (G_OBJECT (model),
+                         "inserted",
+                         (GCallback) inserted_callback,
+                         refs,
+                         NULL,
+                         FALSE,
+                         FALSE);
+
+  g_signal_connect_data (G_OBJECT (model),
+                         "deleted",
+                         (GCallback) deleted_callback,
+                         refs,
+                         NULL,
+                         FALSE,
+                         FALSE);
+
+#if 0
+  /* FIXME */
+  g_signal_connect_data (G_OBJECT (model),
+                         "reordered",
+                         (GCallback) reordered_callback,
+                         refs,
+                         NULL,
+                         FALSE,
+                         FALSE);
+#endif
+}
+
+static void
+disconnect_ref_callbacks (GtkTreeModel *model,
+                          RowRefList   *refs)
+{
+  g_signal_handlers_disconnect_matched (G_OBJECT (model),
+                                        G_SIGNAL_MATCH_DATA,
+                                        0,
+                                        0,
+                                        NULL,
+                                        NULL,
+                                        refs);
+}
+
+GtkTreeRowReference*
+gtk_tree_row_reference_new (GtkTreeModel *model,
+                            GtkTreePath  *path)
+{
+  GtkTreeRowReference *reference;
+  RowRefList *refs;
+  
+  reference = g_new (GtkTreeRowReference, 1);
+
+  reference->model = model;
+  reference->path = gtk_tree_path_copy (path);
+
+  refs = g_object_get_data (G_OBJECT (model),
+                            "gtk-tree-row-refs");
+
+  if (refs == NULL)
+    {
+      refs = g_new (RowRefList, 1);
+      refs->list = NULL;
+      connect_ref_callbacks (model, refs);
+      g_object_set_data_full (G_OBJECT (model),
+                              "gtk-tree-row-refs",
+                              refs,
+                              release_row_references);  
+    }
+  
+  refs->list = g_slist_prepend (refs->list, reference);
+  
+  return reference;
+}
+
+GtkTreePath*
+gtk_tree_row_reference_get_path (GtkTreeRowReference *reference)
+{
+  g_return_val_if_fail (reference != NULL, NULL);
+
+  if (reference->model == NULL)
+    return NULL;
+
+  if (reference->path == NULL)
+    return NULL;
+
+  return gtk_tree_path_copy (reference->path);
+}
+
+void
+gtk_tree_row_reference_free (GtkTreeRowReference *reference)
+{
+  RowRefList *refs;
+
+  g_return_if_fail (reference != NULL);
+  
+  if (reference->model)
+    {
+      refs = g_object_get_data (G_OBJECT (reference->model),
+                                "gtk-tree-row-refs");
+
+      if (refs == NULL)
+        {
+          g_warning (G_STRLOC": bad row reference, model has no outstanding row references");
+          return;
+        }
+          
+      refs->list = g_slist_remove (refs->list, reference);
+
+      if (refs->list == NULL)
+        {
+          disconnect_ref_callbacks (reference->model, refs);
+          g_object_set_data (G_OBJECT (reference->model),
+                             "gtk-tree-row-refs",
+                             NULL);
+        }
+    }
+  
+  if (reference->path)
+    gtk_tree_path_free (reference->path);
+
+  g_free (reference);
+}
 
 /**
  * gtk_tree_iter_copy:
index b15b92b673afca63de5e2b39df6da13ef6a254c7..202d874bcfecaa28e32b88444bcb848f27aa5436 100644 (file)
@@ -32,10 +32,11 @@ extern "C" {
 #define GTK_TREE_MODEL_GET_IFACE(obj)  ((GtkTreeModelIface *)g_type_interface_peek (((GTypeInstance *)GTK_TREE_MODEL (obj))->g_class, GTK_TYPE_TREE_MODEL))
                                        
 
-typedef struct _GtkTreeIter       GtkTreeIter;
-typedef struct _GtkTreePath       GtkTreePath;
-typedef struct _GtkTreeModel      GtkTreeModel; /* Dummy typedef */
-typedef struct _GtkTreeModelIface GtkTreeModelIface;
+typedef struct _GtkTreeIter         GtkTreeIter;
+typedef struct _GtkTreePath         GtkTreePath;
+typedef struct _GtkTreeRowReference GtkTreeRowReference;
+typedef struct _GtkTreeModel        GtkTreeModel; /* Dummy typedef */
+typedef struct _GtkTreeModelIface   GtkTreeModelIface;
 
 
 typedef enum
@@ -133,6 +134,16 @@ gboolean     gtk_tree_path_prev             (GtkTreePath       *path);
 gboolean     gtk_tree_path_up               (GtkTreePath       *path);
 void         gtk_tree_path_down             (GtkTreePath       *path);
 
+/* 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)
+ */
+
+GtkTreeRowReference *gtk_tree_row_reference_new      (GtkTreeModel        *model,
+                                                      GtkTreePath         *path);
+/* returns NULL if the row was deleted or the model was destroyed. */
+GtkTreePath         *gtk_tree_row_reference_get_path (GtkTreeRowReference *reference);
+void                 gtk_tree_row_reference_free     (GtkTreeRowReference *reference);
+
 
 /* GtkTreeIter operations */
 GtkTreeIter *gtk_tree_iter_copy             (GtkTreeIter       *iter);
index 0a09ee0d603b5749d0e5b0d64ade805734c4833e..6b2daa56962ceb85019497b79948a57cd04e9b76 100644 (file)
@@ -72,8 +72,8 @@ struct _GtkTreeViewPrivate
   gint expander_column;
   
   /* Selection stuff */
-  GtkTreePath *anchor;
-  GtkTreePath *cursor;
+  GtkTreeRowReference *anchor;
+  GtkTreeRowReference *cursor;
 
   /* Column Resizing */
   GdkCursor *cursor_drag;
@@ -97,7 +97,7 @@ struct _GtkTreeViewPrivate
   guint scroll_timeout;
   
   /* Row drag-and-drop */
-  GtkTreePath *drag_dest_row;
+  GtkTreeRowReference *drag_dest_row;
   GtkTreeViewDropPosition drag_dest_pos;
   guint open_dest_timeout;
   
index 628bcb323c82f11b3f78028c12f620657c283d92..6baf5d2ff7fef3af80ca8e78d2f2dc8a92990ae2 100644 (file)
@@ -180,13 +180,22 @@ gtk_tree_selection_set_mode (GtkTreeSelection     *selection,
 
       if (selection->tree_view->priv->anchor)
        {
-         _gtk_tree_view_find_node (selection->tree_view,
-                                   selection->tree_view->priv->anchor,
-                                   &tree,
-                                   &node);
-
-         if (node && GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_SELECTED))
-           selected = TRUE;
+          GtkTreePath *anchor_path;
+
+          anchor_path = gtk_tree_row_reference_get_path (selection->tree_view->priv->anchor);
+
+          if (anchor_path)
+            {
+              _gtk_tree_view_find_node (selection->tree_view,
+                                        anchor_path,
+                                        &tree,
+                                        &node);
+              
+              if (node && GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_SELECTED))
+                selected = TRUE;
+
+              gtk_tree_path_free (anchor_path);
+            }
        }
       /* FIXME: if user_func is set, then it needs to unconditionally unselect
        * all.
@@ -267,7 +276,9 @@ gtk_tree_selection_get_selected (GtkTreeSelection  *selection,
 {
   GtkRBTree *tree;
   GtkRBNode *node;
-
+  GtkTreePath *anchor_path;
+  gboolean retval;
+  
   g_return_val_if_fail (selection != NULL, FALSE);
   g_return_val_if_fail (GTK_IS_TREE_SELECTION (selection), FALSE);
 
@@ -276,24 +287,43 @@ gtk_tree_selection_get_selected (GtkTreeSelection  *selection,
   
   if (selection->tree_view->priv->anchor == NULL)
     return FALSE;
-  else if (iter == NULL)
-    return TRUE;
+
+  anchor_path = gtk_tree_row_reference_get_path (selection->tree_view->priv->anchor);
+
+  if (anchor_path == NULL)
+    return FALSE;
+  
+  if (iter == NULL)
+    {
+      gtk_tree_path_free (anchor_path);
+      return TRUE;
+    }
 
   g_return_val_if_fail (selection->tree_view != NULL, FALSE);
   g_return_val_if_fail (selection->tree_view->priv->model != NULL, FALSE);
 
+  retval = FALSE;
+  
   if (!_gtk_tree_view_find_node (selection->tree_view,
-                               selection->tree_view->priv->anchor,
-                               &tree,
-                               &node) &&
+                                 anchor_path,
+                                 &tree,
+                                 &node) &&
       ! GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_SELECTED))
-    /* We don't want to return the anchor if it isn't actually selected.
-     */
-      return FALSE;
+    {
+      /* We don't want to return the anchor if it isn't actually selected.
+       */
+      retval = FALSE;
+    }
+  else
+    {
+      retval = gtk_tree_model_get_iter (selection->tree_view->priv->model,
+                                        iter,
+                                        anchor_path);
+    }
 
-  return gtk_tree_model_get_iter (selection->tree_view->priv->model,
-                                 iter,
-                                 selection->tree_view->priv->anchor);
+  gtk_tree_path_free (anchor_path);
+  
+  return retval;
 }
 
 /**
@@ -661,13 +691,23 @@ gtk_tree_selection_real_unselect_all (GtkTreeSelection *selection)
     {
       GtkRBTree *tree = NULL;
       GtkRBNode *node = NULL;
+      GtkTreePath *anchor_path;
+      
       if (selection->tree_view->priv->anchor == NULL)
        return FALSE;
 
+      anchor_path = gtk_tree_row_reference_get_path (selection->tree_view->priv->anchor);
+
+      if (anchor_path == NULL)
+        return FALSE;
+      
       _gtk_tree_view_find_node (selection->tree_view,
-                               selection->tree_view->priv->anchor,
+                                anchor_path,
                                &tree,
                                &node);
+
+      gtk_tree_path_free (anchor_path);
+      
       if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_SELECTED))
        {
          gtk_tree_selection_real_select_node (selection, tree, node, FALSE);
@@ -839,16 +879,25 @@ _gtk_tree_selection_internal_select_node (GtkTreeSelection *selection,
 {
   gint flags;
   gint dirty = FALSE;
+  GtkTreePath *anchor_path = NULL;
 
-  if (((state & GDK_SHIFT_MASK) == GDK_SHIFT_MASK) && (selection->tree_view->priv->anchor == NULL))
+  if (selection->tree_view->priv->anchor)
+    anchor_path = gtk_tree_row_reference_get_path (selection->tree_view->priv->anchor);
+
+  if (((state & GDK_SHIFT_MASK) == GDK_SHIFT_MASK) && (anchor_path == NULL))
     {
-      selection->tree_view->priv->anchor = gtk_tree_path_copy (path);
+      if (selection->tree_view->priv->anchor)
+        gtk_tree_row_reference_free (selection->tree_view->priv->anchor);
+      
+      selection->tree_view->priv->anchor =
+        gtk_tree_row_reference_new (selection->tree_view->priv->model,
+                                    path);
       dirty = gtk_tree_selection_real_select_node (selection, tree, node, TRUE);
     }
   else if ((state & (GDK_CONTROL_MASK|GDK_SHIFT_MASK)) == (GDK_SHIFT_MASK|GDK_CONTROL_MASK))
     {
       gtk_tree_selection_select_range (selection,
-                                      selection->tree_view->priv->anchor,
+                                       anchor_path,
                                       path);
     }
   else if ((state & GDK_CONTROL_MASK) == GDK_CONTROL_MASK)
@@ -858,8 +907,11 @@ _gtk_tree_selection_internal_select_node (GtkTreeSelection *selection,
        dirty = gtk_tree_selection_real_unselect_all (selection);
 
       if (selection->tree_view->priv->anchor)
-       gtk_tree_path_free (selection->tree_view->priv->anchor);
-      selection->tree_view->priv->anchor = gtk_tree_path_copy (path);
+        gtk_tree_row_reference_free (selection->tree_view->priv->anchor);
+      
+      selection->tree_view->priv->anchor =
+        gtk_tree_row_reference_new (selection->tree_view->priv->model,
+                                    path);      
 
       if ((flags & GTK_RBNODE_IS_SELECTED) == GTK_RBNODE_IS_SELECTED)
        dirty |= gtk_tree_selection_real_select_node (selection, tree, node, FALSE);
@@ -870,18 +922,26 @@ _gtk_tree_selection_internal_select_node (GtkTreeSelection *selection,
     {
       dirty = gtk_tree_selection_real_unselect_all (selection);
       dirty |= gtk_tree_selection_real_select_range (selection,
-                                                    selection->tree_view->priv->anchor,
+                                                     anchor_path,
                                                     path);
     }
   else
     {
       dirty = gtk_tree_selection_real_unselect_all (selection);
+
       if (selection->tree_view->priv->anchor)
-       gtk_tree_path_free (selection->tree_view->priv->anchor);
-      selection->tree_view->priv->anchor = gtk_tree_path_copy (path);
+        gtk_tree_row_reference_free (selection->tree_view->priv->anchor);
+      
+      selection->tree_view->priv->anchor =
+        gtk_tree_row_reference_new (selection->tree_view->priv->model,
+                                    path);
+      
       dirty |= gtk_tree_selection_real_select_node (selection, tree, node, TRUE);
     }
 
+  if (anchor_path)
+    gtk_tree_path_free (anchor_path);
+  
   if (dirty)
     gtk_signal_emit (GTK_OBJECT (selection), tree_selection_signals[SELECTION_CHANGED]);
 }
index 73d5a9fd376e49a2d1af60afb62f483f06e8cbfb..9d26b0a33b3f0a767ac73247ed0d0d86696e3aa9 100644 (file)
@@ -362,7 +362,7 @@ gtk_tree_view_finalize (GObject *object)
     gtk_tree_path_free (tree_view->priv->scroll_to_path);
 
   if (tree_view->priv->drag_dest_row)
-    gtk_tree_path_free (tree_view->priv->drag_dest_row);
+    gtk_tree_row_reference_free (tree_view->priv->drag_dest_row);
   
   g_free (tree_view->priv);
   if (G_OBJECT_CLASS (parent_class)->finalize)
@@ -987,6 +987,8 @@ gtk_tree_view_bin_expose (GtkWidget      *widget,
   gboolean last_selected;
   gint highlight_x;
   gint bin_window_width;
+  GtkTreePath *cursor_path;
+  GtkTreePath *drag_dest_path;
   
   g_return_val_if_fail (widget != NULL, FALSE);
   g_return_val_if_fail (GTK_IS_TREE_VIEW (widget), FALSE);
@@ -1026,11 +1028,21 @@ gtk_tree_view_bin_expose (GtkWidget      *widget,
   depth = gtk_tree_path_get_depth (path);
   gtk_tree_path_free (path);
 
+  cursor_path = NULL;
+  drag_dest_path = NULL;
+  
   if (tree_view->priv->cursor)
-    _gtk_tree_view_find_node (tree_view, tree_view->priv->cursor, &cursor_tree, &cursor);
+    cursor_path = gtk_tree_row_reference_get_path (tree_view->priv->cursor);
+
+  if (cursor_path)
+    _gtk_tree_view_find_node (tree_view, cursor_path,
+                              &cursor_tree, &cursor);
 
   if (tree_view->priv->drag_dest_row)
-    _gtk_tree_view_find_node (tree_view, tree_view->priv->drag_dest_row,
+    drag_dest_path = gtk_tree_row_reference_get_path (tree_view->priv->drag_dest_row);
+
+  if (drag_dest_path)
+    _gtk_tree_view_find_node (tree_view, drag_dest_path,
                               &drag_highlight_tree, &drag_highlight);
 
   gdk_drawable_get_size (tree_view->priv->bin_window,
@@ -1161,7 +1173,7 @@ gtk_tree_view_bin_expose (GtkWidget      *widget,
             case GTK_TREE_VIEW_DROP_INTO_OR_BEFORE:
             case GTK_TREE_VIEW_DROP_INTO_OR_AFTER:
               gtk_tree_view_draw_node_focus_rect (widget,
-                                                  tree_view->priv->drag_dest_row);
+                                                  drag_dest_path);
               break;
             }
 
@@ -1235,6 +1247,12 @@ gtk_tree_view_bin_expose (GtkWidget      *widget,
     }
   while (y_offset < event->area.height);
 
+  if (cursor_path)
+    gtk_tree_path_free (cursor_path);
+
+  if (drag_dest_path)
+    gtk_tree_path_free (drag_dest_path);
+  
   return TRUE;
 }
 
@@ -1778,7 +1796,8 @@ static void
 gtk_tree_view_draw_focus (GtkWidget *widget)
 {
   GtkTreeView *tree_view;
-
+  GtkTreePath *cursor_path;
+  
   g_return_if_fail (widget != NULL);
   g_return_if_fail (GTK_IS_TREE_VIEW (widget));
 
@@ -1786,10 +1805,15 @@ gtk_tree_view_draw_focus (GtkWidget *widget)
 
   if (! GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_DRAW_KEYFOCUS))
     return;
+
   if (tree_view->priv->cursor == NULL)
     return;
 
-  gtk_tree_view_draw_node_focus_rect (widget, tree_view->priv->cursor);
+  cursor_path = gtk_tree_row_reference_get_path (tree_view->priv->cursor);
+  if (cursor_path == NULL)
+    return;
+  
+  gtk_tree_view_draw_node_focus_rect (widget, cursor_path);
 }
 
 
@@ -2034,7 +2058,8 @@ gtk_tree_view_focus (GtkContainer     *container,
   GdkEvent *event;
   GtkRBTree *cursor_tree;
   GtkRBNode *cursor_node;
-
+  GtkTreePath *cursor_path;
+  
   g_return_val_if_fail (container != NULL, FALSE);
   g_return_val_if_fail (GTK_IS_TREE_VIEW (container), FALSE);
   g_return_val_if_fail (GTK_WIDGET_VISIBLE (container), FALSE);
@@ -2075,13 +2100,32 @@ gtk_tree_view_focus (GtkContainer     *container,
 
          /* if there is no keyboard focus yet, we select the first node
           */
-         if (tree_view->priv->cursor == NULL)
-           tree_view->priv->cursor = gtk_tree_path_new_root ();
 
+          cursor_path = NULL;
+
+          if (tree_view->priv->cursor)
+            cursor_path = gtk_tree_row_reference_get_path (tree_view->priv->cursor);
+          
+         if (cursor_path == NULL)
+            {
+              GtkTreePath *tmp_path = gtk_tree_path_new_root ();
+
+              if (tree_view->priv->cursor)
+                gtk_tree_row_reference_free (tree_view->priv->cursor);
+              
+              tree_view->priv->cursor =
+                gtk_tree_row_reference_new (tree_view->priv->model,
+                                            tmp_path);
+              cursor_path = tmp_path;
+            }
+          
          gtk_tree_selection_select_path (tree_view->priv->selection,
-                                         tree_view->priv->cursor);
-          /* FIXME make this more efficient */
-         gtk_widget_queue_draw (GTK_WIDGET (tree_view));
+                                          cursor_path);
+
+          gtk_tree_view_queue_draw_path (tree_view, cursor_path, NULL);          
+
+          gtk_tree_path_free (cursor_path);
+          
          return TRUE;
        }
     }
@@ -2105,36 +2149,64 @@ gtk_tree_view_focus (GtkContainer     *container,
        tree_view->priv->selection =
           _gtk_tree_selection_new_with_tree_view (tree_view);
 
-      if (tree_view->priv->cursor == NULL)
-       tree_view->priv->cursor = gtk_tree_path_new_root ();
+      cursor_path = NULL;
+      if (tree_view->priv->cursor)
+        cursor_path = gtk_tree_row_reference_get_path (tree_view->priv->cursor);
+      
+      if (cursor_path == NULL)
+        {
+          GtkTreePath *tmp_path = gtk_tree_path_new_root ();
+          
+          if (tree_view->priv->cursor)
+            gtk_tree_row_reference_free (tree_view->priv->cursor);
+          
+          tree_view->priv->cursor =
+            gtk_tree_row_reference_new (tree_view->priv->model,
+                                        tmp_path);
+          cursor_path = tmp_path;
+        }        
 
       gtk_tree_selection_select_path (tree_view->priv->selection,
-                                     tree_view->priv->cursor);
-      /* FIXME make this more efficient */
-      gtk_widget_queue_draw (GTK_WIDGET (tree_view));
+                                      cursor_path);
+
+      gtk_tree_view_queue_draw_path (tree_view, cursor_path, NULL);
+
+      gtk_tree_path_free (cursor_path);      
+
       return TRUE;
     }
 
+  cursor_path = NULL;
+  if (tree_view->priv->cursor)
+    cursor_path = gtk_tree_row_reference_get_path (tree_view->priv->cursor);
+
   /* Case 3. We have focus already, but no cursor.  We pick the first one
-   * and run with it. */
-  if (tree_view->priv->cursor == NULL)
+   * and run with it.
+   */
+  
+  if (cursor_path == NULL)
     {
-      /* We lost our cursor somehow.  Arbitrarily select the first node, and
-       * return
-       */
-      tree_view->priv->cursor = gtk_tree_path_new_root ();
-
+      GtkTreePath *tmp_path = gtk_tree_path_new_root ();
+      
+      if (tree_view->priv->cursor)
+        gtk_tree_row_reference_free (tree_view->priv->cursor);
+      
+      tree_view->priv->cursor =
+        gtk_tree_row_reference_new (tree_view->priv->model,
+                                    tmp_path);
+      cursor_path = tmp_path;
+      
       gtk_tree_selection_select_path (tree_view->priv->selection,
-                                     tree_view->priv->cursor);
-      gtk_adjustment_set_value (GTK_ADJUSTMENT (tree_view->priv->vadjustment),
-                               0.0);
-      /* FIXME make this more efficient */
-      gtk_widget_queue_draw (GTK_WIDGET (tree_view));
+                                      cursor_path);
+      
+      gtk_tree_view_queue_draw_path (tree_view, cursor_path, NULL);
+      
+      gtk_tree_path_free (cursor_path);      
+      
       return TRUE;
     }
 
-
-  /* Case 3. We have focus already.  Move the cursor. */
+  /* Case 4. We have focus already.  Move the cursor. */
   if (direction == GTK_DIR_LEFT)
     {
       gfloat val;
@@ -2142,6 +2214,9 @@ gtk_tree_view_focus (GtkContainer     *container,
       val = MAX (val, 0.0);
       gtk_adjustment_set_value (GTK_ADJUSTMENT (tree_view->priv->hadjustment), val);
       gtk_widget_grab_focus (GTK_WIDGET (tree_view));
+
+      gtk_tree_path_free (cursor_path);
+      
       return TRUE;
     }
   if (direction == GTK_DIR_RIGHT)
@@ -2151,14 +2226,31 @@ gtk_tree_view_focus (GtkContainer     *container,
       val = MIN (tree_view->priv->hadjustment->upper - tree_view->priv->hadjustment->page_size, val);
       gtk_adjustment_set_value (GTK_ADJUSTMENT (tree_view->priv->hadjustment), val);
       gtk_widget_grab_focus (GTK_WIDGET (tree_view));
+
+      gtk_tree_path_free (cursor_path);
+      
       return TRUE;
     }
+
   cursor_tree = NULL;
   cursor_node = NULL;
 
-  _gtk_tree_view_find_node (tree_view, tree_view->priv->cursor,
+  _gtk_tree_view_find_node (tree_view, cursor_path,
                            &cursor_tree,
                            &cursor_node);
+
+  /* undraw the old row */
+  gtk_tree_view_queue_draw_path (tree_view, cursor_path, NULL);
+  
+  gtk_tree_path_free (cursor_path);
+  cursor_path = NULL;
+
+  if (tree_view->priv->cursor)
+    {
+      gtk_tree_row_reference_free (tree_view->priv->cursor);
+      tree_view->priv->cursor = NULL;
+    }
+  
   switch (direction)
     {
     case GTK_DIR_TAB_BACKWARD:
@@ -2189,21 +2281,32 @@ gtk_tree_view_focus (GtkContainer     *container,
 
       if (event)
        gdk_event_free (event);
-      gtk_tree_path_free (tree_view->priv->cursor);
+      
+      cursor_path = _gtk_tree_view_find_path (tree_view,
+                                              cursor_tree,
+                                              cursor_node);
 
-      tree_view->priv->cursor = _gtk_tree_view_find_path (tree_view,
-                                                         cursor_tree,
-                                                         cursor_node);
-      if (tree_view->priv->cursor)
-       _gtk_tree_selection_internal_select_node (tree_view->priv->selection,
-                                                 cursor_node,
-                                                 cursor_tree,
-                                                 tree_view->priv->cursor,
-                                                 state);
+      if (cursor_path)
+        {
+          _gtk_tree_selection_internal_select_node (tree_view->priv->selection,
+                                                    cursor_node,
+                                                    cursor_tree,
+                                                    cursor_path,
+                                                    state);
+
+          tree_view->priv->cursor = gtk_tree_row_reference_new (tree_view->priv->model,
+                                                                cursor_path);
+
+
+          /* draw the newly-selected row */
+          gtk_tree_view_queue_draw_path (tree_view, cursor_path, NULL);
+          
+          gtk_tree_path_free (cursor_path);
+        }
+          
       gtk_tree_view_clamp_node_visible (tree_view, cursor_tree, cursor_node);
       gtk_widget_grab_focus (GTK_WIDGET (tree_view));
-      /* FIXME make this more efficient */
-      gtk_widget_queue_draw (GTK_WIDGET (tree_view));
+
       return TRUE;
     }
 
@@ -2402,29 +2505,6 @@ gtk_tree_view_inserted (GtkTreeModel *model,
   if (tree == NULL)
     return;
 
-  /* next, update the selection */
-  if (tree_view->priv->anchor)
-    {
-      gint *select_indices = gtk_tree_path_get_indices (tree_view->priv->anchor);
-      gint select_depth = gtk_tree_path_get_depth (tree_view->priv->anchor);
-
-      for (i = 0; i < depth && i < select_depth; i++)
-       {
-         if (indices[i] < select_indices[i])
-           {
-             select_indices[i]++;
-             break;
-           }
-         else if (indices[i] > select_indices[i])
-           break;
-         else if (i == depth - 1)
-           {
-             select_indices[i]++;
-             break;
-           }
-       }
-    }
-
   /* ref the node */
   gtk_tree_model_ref_iter (tree_view->priv->model, iter);
   max_height = gtk_tree_view_insert_iter_height (tree_view,
@@ -2525,37 +2605,27 @@ gtk_tree_view_deleted (GtkTreeModel *model,
   /* next, update the selection */
   if (tree_view->priv->anchor)
     {
-      gint i;
-      gint depth = gtk_tree_path_get_depth (path);
-      gint *indices = gtk_tree_path_get_indices (path);
-      gint select_depth = gtk_tree_path_get_depth (tree_view->priv->anchor);
-      gint *select_indices = gtk_tree_path_get_indices (tree_view->priv->anchor);
+      GtkTreePath *anchor_path;
 
-      if (gtk_tree_path_compare (path, tree_view->priv->anchor) == 0)
+      /* the row reference may not have been updated yet. If it has not,
+       * then anchor_path and path being equal indicates that the anchor
+       * row was deleted. If it has, then anchor_path == NULL indicates the
+       * the anchor row was deleted.
+       */
+      
+      anchor_path = gtk_tree_row_reference_get_path (tree_view->priv->anchor);
+
+      if (anchor_path == NULL ||
+          gtk_tree_path_compare (path, anchor_path) == 0)
        {
          if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_SELECTED) &&
-             tree_view->priv->selection)
+              tree_view->priv->selection)
            gtk_signal_emit_by_name (GTK_OBJECT (tree_view->priv->selection),
                                     "selection_changed");
        }
-      else
-       {
-         for (i = 0; i < depth && i < select_depth; i++)
-           {
-             if (indices[i] < select_indices[i])
-               {
-                 select_indices[i] = MAX (select_indices[i], 0);
-                 break;
-               }
-             else if (indices[i] > select_indices[i])
-               break;
-             else if (i == depth - 1)
-               {
-                 select_indices[i] = MAX (select_indices[i], 0);
-                 break;
-               }
-           }
-       }
+
+      if (anchor_path)
+        gtk_tree_path_free (anchor_path);
     }
 
   for (list = tree_view->priv->columns; list; list = list->next)
@@ -3432,7 +3502,7 @@ gtk_tree_view_set_model (GtkTreeView  *tree_view,
 #endif
 
       if (tree_view->priv->drag_dest_row)
-        gtk_tree_path_free (tree_view->priv->drag_dest_row);
+        gtk_tree_row_reference_free (tree_view->priv->drag_dest_row);
       
       GTK_TREE_VIEW_UNSET_FLAG (tree_view, GTK_TREE_VIEW_MODEL_SETUP);
     }
@@ -5018,26 +5088,35 @@ gtk_tree_view_set_drag_dest_row (GtkTreeView            *tree_view,
                                  GtkTreePath            *path,
                                  GtkTreeViewDropPosition pos)
 {
+  GtkTreePath *current_dest;
   /* Note; this function is exported to allow a custom DND
    * implementation, so it can't touch TreeViewDragInfo
    */
   
   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
 
-  g_print ("drag dest row %p -> %p\n", tree_view->priv->drag_dest_row, path);
+  current_dest = NULL;
   
   if (tree_view->priv->drag_dest_row)
+    current_dest = gtk_tree_row_reference_get_path (tree_view->priv->drag_dest_row);
+
+  if (current_dest)
     {
-      gtk_tree_view_queue_draw_path (tree_view, tree_view->priv->drag_dest_row, NULL);
-      gtk_tree_path_free (tree_view->priv->drag_dest_row);
+      gtk_tree_view_queue_draw_path (tree_view, current_dest, NULL);
+      gtk_tree_path_free (current_dest);
     }
 
+  if (tree_view->priv->drag_dest_row)
+    gtk_tree_row_reference_free (tree_view->priv->drag_dest_row);
+
   tree_view->priv->drag_dest_pos = pos;
   
   if (path)
     {
-      tree_view->priv->drag_dest_row = gtk_tree_path_copy (path);
-      gtk_tree_view_queue_draw_path (tree_view, tree_view->priv->drag_dest_row, NULL);
+      tree_view->priv->drag_dest_row =
+        gtk_tree_row_reference_new (tree_view->priv->model,
+                                    path);
+      gtk_tree_view_queue_draw_path (tree_view, path, NULL);
     }
   else
     tree_view->priv->drag_dest_row = NULL;
@@ -5053,7 +5132,7 @@ gtk_tree_view_get_drag_dest_row (GtkTreeView              *tree_view,
   if (path)
     {
       if (tree_view->priv->drag_dest_row)
-        *path = gtk_tree_path_copy (tree_view->priv->drag_dest_row);
+        *path = gtk_tree_row_reference_get_path (tree_view->priv->drag_dest_row);
       else
         *path = NULL;
     }
@@ -5375,19 +5454,32 @@ static gint
 open_row_timeout (gpointer data)
 {
   GtkTreeView *tree_view = data;
+  GtkTreePath *dest_path = NULL;
+  GtkTreeViewDropPosition pos;
 
-  if (tree_view->priv->drag_dest_row &&
-      (tree_view->priv->drag_dest_pos == GTK_TREE_VIEW_DROP_INTO_OR_AFTER ||
-       tree_view->priv->drag_dest_pos == GTK_TREE_VIEW_DROP_INTO_OR_BEFORE))
+  gtk_tree_view_get_drag_dest_row (tree_view,
+                                   &dest_path,
+                                   &pos);
+  
+  if (dest_path && 
+      (pos == GTK_TREE_VIEW_DROP_INTO_OR_AFTER ||
+       pos == GTK_TREE_VIEW_DROP_INTO_OR_BEFORE))
     {
       gtk_tree_view_expand_row (tree_view,
-                                tree_view->priv->drag_dest_row,
+                                dest_path,
                                 FALSE);
       tree_view->priv->open_dest_timeout = 0;
+
+      gtk_tree_path_free (dest_path);
+      
       return FALSE;
     }  
   else
-    return TRUE;
+    {
+      if (dest_path)
+        gtk_tree_path_free (dest_path);
+      return TRUE;
+    }
 }
 
 /* Returns TRUE if event should not be propagated to parent widgets */
@@ -5400,9 +5492,11 @@ set_destination_row (GtkTreeView    *tree_view,
 {
   GtkTreePath *path = NULL;
   GtkTreeViewDropPosition pos;
+  GtkTreeViewDropPosition old_pos;
   TreeViewDragInfo *di;
   GtkWidget *widget;
-
+  GtkTreePath *old_dest_path = NULL;
+  
   *suggested_action = 0;
   
   widget = GTK_WIDGET (tree_view);
@@ -5455,11 +5549,18 @@ set_destination_row (GtkTreeView    *tree_view,
   /* If we left the current row's "open" zone, unset the timeout for
    * opening the row
    */
-  if (tree_view->priv->drag_dest_row &&
-      (gtk_tree_path_compare (path, tree_view->priv->drag_dest_row) != 0 ||
+  gtk_tree_view_get_drag_dest_row (tree_view,
+                                   &old_dest_path,
+                                   &old_pos);
+  
+  if (old_dest_path &&
+      (gtk_tree_path_compare (path, old_dest_path) != 0 ||
        !(pos == GTK_TREE_VIEW_DROP_INTO_OR_AFTER ||
          pos == GTK_TREE_VIEW_DROP_INTO_OR_BEFORE)))
     remove_open_timeout (tree_view);
+
+  if (old_dest_path)
+    gtk_tree_path_free (old_dest_path);
   
   if (TRUE /* FIXME if the location droppable predicate */)
     {