add GtkTreeRowReference which holds a handle to a specific row (particular

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.
This commit is contained in:
Havoc Pennington 2001-01-27 00:50:38 +00:00 committed by Havoc Pennington
parent ef4356b567
commit d8d019a1e9
12 changed files with 674 additions and 141 deletions

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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:

View 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);

View 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;

View 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);
GtkTreePath *anchor_path;
if (node && GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_SELECTED))
selected = TRUE;
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]);
}

View 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 */)
{