X-Git-Url: http://pileus.org/git/?a=blobdiff_plain;f=gtk%2Fgtktreeselection.c;h=10c9cd717a6908cf686251f22bd0ee58fb1e49d4;hb=5bbbc47a4c306653e8347f7afb85a940a503f755;hp=a6fc4cd0beb35bb6c6e569091de5525a43394f63;hpb=3e8866a488844f8c2ded0a7cdb26cab3af2c2390;p=~andy%2Fgtk diff --git a/gtk/gtktreeselection.c b/gtk/gtktreeselection.c index a6fc4cd0b..10c9cd717 100644 --- a/gtk/gtktreeselection.c +++ b/gtk/gtktreeselection.c @@ -12,18 +12,62 @@ * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public - * License along with this library; if not, write to the - * Free Software Foundation, Inc., 59 Temple Place - Suite 330, - * Boston, MA 02111-1307, USA. + * License along with this library. If not, see . */ +#include "config.h" +#include #include "gtktreeselection.h" #include "gtktreeprivate.h" #include "gtkrbtree.h" #include "gtkmarshalers.h" +#include "gtkintl.h" +#include "gtktypebuiltins.h" +#include "a11y/gtktreeviewaccessibleprivate.h" -static void gtk_tree_selection_init (GtkTreeSelection *selection); -static void gtk_tree_selection_class_init (GtkTreeSelectionClass *class); + +/** + * SECTION:gtktreeselection + * @Short_description: The selection object for GtkTreeView + * @Title: GtkTreeSelection + * @See_also: #GtkTreeView, #GtkTreeViewColumn, #GtkTreeDnd, #GtkTreeMode, + * #GtkTreeSortable, #GtkTreeModelSort, #GtkListStore, #GtkTreeStore, + * #GtkCellRenderer, #GtkCellEditable, #GtkCellRendererPixbuf, + * #GtkCellRendererText, #GtkCellRendererToggle + * + * The #GtkTreeSelection object is a helper object to manage the selection + * for a #GtkTreeView widget. The #GtkTreeSelection object is + * automatically created when a new #GtkTreeView widget is created, and + * cannot exist independentally of this widget. The primary reason the + * #GtkTreeSelection objects exists is for cleanliness of code and API. + * That is, there is no conceptual reason all these functions could not be + * methods on the #GtkTreeView widget instead of a separate function. + * + * The #GtkTreeSelection object is gotten from a #GtkTreeView by calling + * gtk_tree_view_get_selection(). It can be manipulated to check the + * selection status of the tree, as well as select and deselect individual + * rows. Selection is done completely view side. As a result, multiple + * views of the same model can have completely different selections. + * Additionally, you cannot change the selection of a row on the model that + * is not currently displayed by the view without expanding its parents + * first. + * + * One of the important things to remember when monitoring the selection of + * a view is that the #GtkTreeSelection::changed signal is mostly a hint. + * That is, it may only emit one signal when a range of rows is selected. + * Additionally, it may on occasion emit a #GtkTreeSelection::changed signal + * when nothing has happened (mostly as a result of programmers calling + * select_row on an already selected row). + */ + +struct _GtkTreeSelectionPrivate +{ + GtkTreeView *tree_view; + GtkSelectionMode type; + GtkTreeSelectionFunc user_func; + gpointer user_data; + GDestroyNotify destroy; +}; static void gtk_tree_selection_finalize (GObject *object); static gint gtk_tree_selection_real_select_all (GtkTreeSelection *selection); @@ -32,6 +76,21 @@ static gint gtk_tree_selection_real_select_node (GtkTreeSelection *selecti GtkRBTree *tree, GtkRBNode *node, gboolean select); +static void gtk_tree_selection_set_property (GObject *object, + guint prop_id, + const GValue *value, + GParamSpec *pspec); +static void gtk_tree_selection_get_property (GObject *object, + guint prop_id, + GValue *value, + GParamSpec *pspec); + +enum +{ + PROP_0, + PROP_MODE, + N_PROPERTIES +}; enum { @@ -39,36 +98,10 @@ enum LAST_SIGNAL }; -static GObjectClass *parent_class = NULL; +static GParamSpec *properties[N_PROPERTIES]; static guint tree_selection_signals [LAST_SIGNAL] = { 0 }; -GType -gtk_tree_selection_get_type (void) -{ - static GType selection_type = 0; - - if (!selection_type) - { - static const GTypeInfo selection_info = - { - sizeof (GtkTreeSelectionClass), - NULL, /* base_init */ - NULL, /* base_finalize */ - (GClassInitFunc) gtk_tree_selection_class_init, - NULL, /* class_finalize */ - NULL, /* class_data */ - sizeof (GtkTreeSelection), - 0, /* n_preallocs */ - (GInstanceInitFunc) gtk_tree_selection_init - }; - - selection_type = - g_type_register_static (G_TYPE_OBJECT, "GtkTreeSelection", - &selection_info, 0); - } - - return selection_type; -} +G_DEFINE_TYPE (GtkTreeSelection, gtk_tree_selection, G_TYPE_OBJECT) static void gtk_tree_selection_class_init (GtkTreeSelectionClass *class) @@ -76,49 +109,125 @@ gtk_tree_selection_class_init (GtkTreeSelectionClass *class) GObjectClass *object_class; object_class = (GObjectClass*) class; - parent_class = g_type_class_peek_parent (class); object_class->finalize = gtk_tree_selection_finalize; + object_class->set_property = gtk_tree_selection_set_property; + object_class->get_property = gtk_tree_selection_get_property; class->changed = NULL; + /* Properties */ + + /** + * GtkTreeSelection:mode: + * + * Selection mode. + * See gtk_tree_selection_set_mode() for more information on this property. + * + * Since: 3.2 + */ + properties[PROP_MODE] = g_param_spec_enum ("mode", + P_("Mode"), + P_("Selection mode"), + GTK_TYPE_SELECTION_MODE, + GTK_SELECTION_SINGLE, + G_PARAM_READWRITE | + G_PARAM_STATIC_STRINGS); + + /* Install all properties */ + g_object_class_install_properties (object_class, N_PROPERTIES, properties); + + /* Signals */ + + /** + * GtkTreeSelection::changed: + * @treeselection: the object which received the signal. + * + * Emitted whenever the selection has (possibly) changed. Please note that + * this signal is mostly a hint. It may only be emitted once when a range + * of rows are selected, and it may occasionally be emitted when nothing + * has happened. + */ tree_selection_signals[CHANGED] = - g_signal_new ("changed", + g_signal_new (I_("changed"), G_OBJECT_CLASS_TYPE (object_class), G_SIGNAL_RUN_FIRST, G_STRUCT_OFFSET (GtkTreeSelectionClass, changed), NULL, NULL, _gtk_marshal_VOID__VOID, G_TYPE_NONE, 0); + + g_type_class_add_private (class, sizeof (GtkTreeSelectionPrivate)); } static void gtk_tree_selection_init (GtkTreeSelection *selection) { - selection->type = GTK_SELECTION_SINGLE; + GtkTreeSelectionPrivate *priv; + + selection->priv = G_TYPE_INSTANCE_GET_PRIVATE (selection, + GTK_TYPE_TREE_SELECTION, + GtkTreeSelectionPrivate); + priv = selection->priv; + + priv->type = GTK_SELECTION_SINGLE; } static void gtk_tree_selection_finalize (GObject *object) { GtkTreeSelection *selection = GTK_TREE_SELECTION (object); + GtkTreeSelectionPrivate *priv = selection->priv; - if (selection->destroy) - { - GtkDestroyNotify d = selection->destroy; + if (priv->destroy) + priv->destroy (priv->user_data); + + /* chain parent_class' handler */ + G_OBJECT_CLASS (gtk_tree_selection_parent_class)->finalize (object); +} + +static void +gtk_tree_selection_set_property (GObject *object, + guint prop_id, + const GValue *value, + GParamSpec *pspec) +{ + g_return_if_fail (GTK_IS_TREE_SELECTION (object)); - selection->destroy = NULL; - d (selection->user_data); + switch (prop_id) + { + case PROP_MODE: + gtk_tree_selection_set_mode (GTK_TREE_SELECTION (object), g_value_get_enum (value)); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; } +} - /* chain parent_class' handler */ - G_OBJECT_CLASS (parent_class)->finalize (object); +static void +gtk_tree_selection_get_property (GObject *object, + guint prop_id, + GValue *value, + GParamSpec *pspec) +{ + g_return_if_fail (GTK_IS_TREE_SELECTION (object)); + + switch (prop_id) + { + case PROP_MODE: + g_value_set_enum (value, gtk_tree_selection_get_mode (GTK_TREE_SELECTION (object))); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } } /** * _gtk_tree_selection_new: * * Creates a new #GtkTreeSelection object. This function should not be invoked, - * as each #GtkTreeView will create it's own #GtkTreeSelection. + * as each #GtkTreeView will create its own #GtkTreeSelection. * * Return value: A newly created #GtkTreeSelection object. **/ @@ -137,7 +246,7 @@ _gtk_tree_selection_new (void) * @tree_view: The #GtkTreeView. * * Creates a new #GtkTreeSelection object. This function should not be invoked, - * as each #GtkTreeView will create it's own #GtkTreeSelection. + * as each #GtkTreeView will create its own #GtkTreeSelection. * * Return value: A newly created #GtkTreeSelection object. **/ @@ -166,11 +275,15 @@ void _gtk_tree_selection_set_tree_view (GtkTreeSelection *selection, GtkTreeView *tree_view) { + GtkTreeSelectionPrivate *priv; + g_return_if_fail (GTK_IS_TREE_SELECTION (selection)); if (tree_view != NULL) g_return_if_fail (GTK_IS_TREE_VIEW (tree_view)); - selection->tree_view = tree_view; + priv = selection->priv; + + priv->tree_view = tree_view; } /** @@ -186,24 +299,26 @@ void gtk_tree_selection_set_mode (GtkTreeSelection *selection, GtkSelectionMode type) { + GtkTreeSelectionPrivate *priv; GtkTreeSelectionFunc tmp_func; + g_return_if_fail (GTK_IS_TREE_SELECTION (selection)); - if (selection->type == type) + priv = selection->priv; + + if (priv->type == type) return; - if (type == GTK_SELECTION_NONE) { /* We do this so that we unconditionally unset all rows */ - tmp_func = selection->user_func; - selection->user_func = NULL; + tmp_func = priv->user_func; + priv->user_func = NULL; gtk_tree_selection_unselect_all (selection); - selection->user_func = tmp_func; + priv->user_func = tmp_func; - gtk_tree_row_reference_free (selection->tree_view->priv->anchor); - selection->tree_view->priv->anchor = NULL; + _gtk_tree_view_set_anchor_path (priv->tree_view, NULL); } else if (type == GTK_SELECTION_SINGLE || type == GTK_SELECTION_BROWSE) @@ -213,41 +328,40 @@ gtk_tree_selection_set_mode (GtkTreeSelection *selection, gint selected = FALSE; GtkTreePath *anchor_path = NULL; - if (selection->tree_view->priv->anchor) + anchor_path = _gtk_tree_view_get_anchor_path (priv->tree_view); + + if (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_view_find_node (priv->tree_view, + anchor_path, + &tree, + &node); + + if (node && GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_SELECTED)) + selected = TRUE; } /* We do this so that we unconditionally unset all rows */ - tmp_func = selection->user_func; - selection->user_func = NULL; + tmp_func = priv->user_func; + priv->user_func = NULL; gtk_tree_selection_unselect_all (selection); - selection->user_func = tmp_func; + priv->user_func = tmp_func; if (node && selected) _gtk_tree_selection_internal_select_node (selection, node, tree, anchor_path, - 0, + 0, FALSE); if (anchor_path) gtk_tree_path_free (anchor_path); } - selection->type = type; + priv->type = type; + + g_object_notify_by_pspec (G_OBJECT (selection), properties[PROP_MODE]); } /** @@ -264,45 +378,63 @@ gtk_tree_selection_get_mode (GtkTreeSelection *selection) { g_return_val_if_fail (GTK_IS_TREE_SELECTION (selection), GTK_SELECTION_SINGLE); - return selection->type; + return selection->priv->type; } /** * gtk_tree_selection_set_select_function: * @selection: A #GtkTreeSelection. - * @func: The selection function. - * @data: The selection function's data. - * @destroy: The destroy function for user data. May be NULL. + * @func: The selection function. May be %NULL + * @data: The selection function's data. May be %NULL + * @destroy: The destroy function for user data. May be %NULL * - * Sets the selection function. If set, this function is called before any node - * is selected or unselected, giving some control over which nodes are selected. - * The select function should return %TRUE if the state of the node may be toggled, - * and %FALSE if the state of the node should be left unchanged. - **/ + * Sets the selection function. + * + * If set, this function is called before any node is selected or unselected, + * giving some control over which nodes are selected. The select function + * should return %TRUE if the state of the node may be toggled, and %FALSE + * if the state of the node should be left unchanged. + */ void gtk_tree_selection_set_select_function (GtkTreeSelection *selection, GtkTreeSelectionFunc func, gpointer data, - GtkDestroyNotify destroy) + GDestroyNotify destroy) { + GtkTreeSelectionPrivate *priv; + g_return_if_fail (GTK_IS_TREE_SELECTION (selection)); - g_return_if_fail (func != NULL); - if (selection->destroy) - { - GtkDestroyNotify d = selection->destroy; + priv = selection->priv; - selection->destroy = NULL; - d (selection->user_data); - } + if (priv->destroy) + priv->destroy (priv->user_data); + + priv->user_func = func; + priv->user_data = data; + priv->destroy = destroy; +} + +/** + * gtk_tree_selection_get_select_function: (skip) + * @selection: A #GtkTreeSelection. + * + * Returns the current selection function. + * + * Return value: The function. + * + * Since: 2.14 + **/ +GtkTreeSelectionFunc +gtk_tree_selection_get_select_function (GtkTreeSelection *selection) +{ + g_return_val_if_fail (GTK_IS_TREE_SELECTION (selection), NULL); - selection->user_func = func; - selection->user_data = data; - selection->destroy = destroy; + return selection->priv->user_func; } /** - * gtk_tree_selection_get_user_data: + * gtk_tree_selection_get_user_data: (skip) * @selection: A #GtkTreeSelection. * * Returns the user data for the selection function. @@ -314,7 +446,7 @@ gtk_tree_selection_get_user_data (GtkTreeSelection *selection) { g_return_val_if_fail (GTK_IS_TREE_SELECTION (selection), NULL); - return selection->user_data; + return selection->priv->user_data; } /** @@ -323,21 +455,21 @@ gtk_tree_selection_get_user_data (GtkTreeSelection *selection) * * Returns the tree view associated with @selection. * - * Return value: A #GtkTreeView + * Return value: (transfer none): A #GtkTreeView **/ GtkTreeView * gtk_tree_selection_get_tree_view (GtkTreeSelection *selection) { g_return_val_if_fail (GTK_IS_TREE_SELECTION (selection), NULL); - return selection->tree_view; + return selection->priv->tree_view; } /** * gtk_tree_selection_get_selected: * @selection: A #GtkTreeSelection. - * @model: A pointer to set to the #GtkTreeModel, or NULL. - * @iter: The #GtkTreeIter, or NULL. + * @model: (out) (allow-none) (transfer none): A pointer to set to the #GtkTreeModel, or NULL. + * @iter: (out) (allow-none): The #GtkTreeIter, or NULL. * * Sets @iter to the currently selected node if @selection is set to * #GTK_SELECTION_SINGLE or #GTK_SELECTION_BROWSE. @iter may be NULL if you @@ -352,6 +484,7 @@ gtk_tree_selection_get_selected (GtkTreeSelection *selection, GtkTreeModel **model, GtkTreeIter *iter) { + GtkTreeSelectionPrivate *priv; GtkRBTree *tree; GtkRBNode *node; GtkTreePath *anchor_path; @@ -359,24 +492,27 @@ gtk_tree_selection_get_selected (GtkTreeSelection *selection, gboolean found_node; g_return_val_if_fail (GTK_IS_TREE_SELECTION (selection), FALSE); - g_return_val_if_fail (selection->type != GTK_SELECTION_MULTIPLE, FALSE); - g_return_val_if_fail (selection->tree_view != NULL, FALSE); - g_return_val_if_fail (selection->tree_view->priv->model != NULL, FALSE); - if (model) - *model = selection->tree_view->priv->model; + priv = selection->priv; - if (selection->tree_view->priv->anchor == NULL) - return FALSE; + g_return_val_if_fail (priv->type != GTK_SELECTION_MULTIPLE, FALSE); + g_return_val_if_fail (priv->tree_view != NULL, FALSE); + + /* Clear the iter */ + if (iter) + memset (iter, 0, sizeof (GtkTreeIter)); - anchor_path = gtk_tree_row_reference_get_path (selection->tree_view->priv->anchor); + if (model) + *model = gtk_tree_view_get_model (priv->tree_view); + + anchor_path = _gtk_tree_view_get_anchor_path (priv->tree_view); if (anchor_path == NULL) return FALSE; retval = FALSE; - found_node = !_gtk_tree_view_find_node (selection->tree_view, + found_node = !_gtk_tree_view_find_node (priv->tree_view, anchor_path, &tree, &node); @@ -389,7 +525,7 @@ gtk_tree_selection_get_selected (GtkTreeSelection *selection, if (iter == NULL) retval = TRUE; else - retval = gtk_tree_model_get_iter (selection->tree_view->priv->model, + retval = gtk_tree_model_get_iter (gtk_tree_view_get_model (priv->tree_view), iter, anchor_path); } @@ -408,44 +544,49 @@ gtk_tree_selection_get_selected (GtkTreeSelection *selection, /** * gtk_tree_selection_get_selected_rows: * @selection: A #GtkTreeSelection. - * @model: A pointer to set to the #GtkTreeModel, or NULL. + * @model: (out) (allow-none) (transfer none): A pointer to set to the #GtkTreeModel, or %NULL. * * Creates a list of path of all selected rows. Additionally, if you are * planning on modifying the model after calling this function, you may * want to convert the returned list into a list of #GtkTreeRowReferences. - * To do this, you can use gtk_tree_row_reference_new_proxy(). + * To do this, you can use gtk_tree_row_reference_new(). * * To free the return value, use: - * - * g_list_foreach (list, gtk_tree_path_free, NULL); - * g_list_free (list); - * + * |[ + * g_list_free_full (list, (GDestroyNotify) gtk_tree_path_free); + * ]| + * + * Return value: (element-type GtkTreePath) (transfer full): A #GList containing a #GtkTreePath for each selected row. * - * Return value: A #GList containing a #GtkTreePath for each selected row. + * Since: 2.2 **/ GList * gtk_tree_selection_get_selected_rows (GtkTreeSelection *selection, GtkTreeModel **model) { + GtkTreeSelectionPrivate *priv; GList *list = NULL; GtkRBTree *tree = NULL; GtkRBNode *node = NULL; GtkTreePath *path; g_return_val_if_fail (GTK_IS_TREE_SELECTION (selection), NULL); - g_return_val_if_fail (selection->tree_view != NULL, NULL); - g_return_val_if_fail (selection->tree_view->priv->model != NULL, NULL); - if (selection->tree_view->priv->tree == NULL || - selection->tree_view->priv->tree->root == NULL) - return NULL; + priv = selection->priv; + + g_return_val_if_fail (priv->tree_view != NULL, NULL); if (model) - *model = selection->tree_view->priv->model; + *model = gtk_tree_view_get_model (priv->tree_view); + + tree = _gtk_tree_view_get_rbtree (priv->tree_view); - if (selection->type == GTK_SELECTION_NONE) + if (tree == NULL || tree->root == NULL) return NULL; - else if (selection->type != GTK_SELECTION_MULTIPLE) + + if (priv->type == GTK_SELECTION_NONE) + return NULL; + else if (priv->type != GTK_SELECTION_MULTIPLE) { GtkTreeIter iter; @@ -453,7 +594,7 @@ gtk_tree_selection_get_selected_rows (GtkTreeSelection *selection, { GtkTreePath *path; - path = gtk_tree_model_get_path (*model, &iter); + path = gtk_tree_model_get_path (gtk_tree_view_get_model (priv->tree_view), &iter); list = g_list_append (list, path); return list; @@ -462,25 +603,18 @@ gtk_tree_selection_get_selected_rows (GtkTreeSelection *selection, return NULL; } - tree = selection->tree_view->priv->tree; - node = selection->tree_view->priv->tree->root; - - while (node->left != tree->nil) - node = node->left; + node = _gtk_rbtree_first (tree); path = gtk_tree_path_new_first (); do { if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_SELECTED)) - list = g_list_append (list, gtk_tree_path_copy (path)); + list = g_list_prepend (list, gtk_tree_path_copy (path)); if (node->children) { tree = node->children; - node = tree->root; - - while (node->left != tree->nil) - node = node->left; + node = _gtk_rbtree_first (tree); gtk_tree_path_append_index (path, 0); } @@ -504,7 +638,8 @@ gtk_tree_selection_get_selected_rows (GtkTreeSelection *selection, if (!tree) { gtk_tree_path_free (path); - return list; + + goto done; } gtk_tree_path_up (path); @@ -517,7 +652,8 @@ gtk_tree_selection_get_selected_rows (GtkTreeSelection *selection, gtk_tree_path_free (path); - return list; + done: + return g_list_reverse (list); } static void @@ -543,24 +679,29 @@ gtk_tree_selection_count_selected_rows_helper (GtkRBTree *tree, * Returns the number of rows that have been selected in @tree. * * Return value: The number of rows selected. + * + * Since: 2.2 **/ gint gtk_tree_selection_count_selected_rows (GtkTreeSelection *selection) { + GtkTreeSelectionPrivate *priv; gint count = 0; GtkRBTree *tree; - GtkRBNode *node; g_return_val_if_fail (GTK_IS_TREE_SELECTION (selection), 0); - g_return_val_if_fail (selection->tree_view != NULL, 0); - g_return_val_if_fail (selection->tree_view->priv->model != NULL, 0); - if (selection->tree_view->priv->tree == NULL || - selection->tree_view->priv->tree->root == NULL) + priv = selection->priv; + + g_return_val_if_fail (priv->tree_view != NULL, 0); + + tree = _gtk_tree_view_get_rbtree (priv->tree_view); + + if (tree == NULL || tree->root == NULL) return 0; - if (selection->type == GTK_SELECTION_SINGLE || - selection->type == GTK_SELECTION_BROWSE) + if (priv->type == GTK_SELECTION_SINGLE || + priv->type == GTK_SELECTION_BROWSE) { if (gtk_tree_selection_get_selected (selection, NULL, NULL)) return 1; @@ -568,11 +709,7 @@ gtk_tree_selection_count_selected_rows (GtkTreeSelection *selection) return 0; } - tree = selection->tree_view->priv->tree; - node = selection->tree_view->priv->tree->root; - - _gtk_rbtree_traverse (selection->tree_view->priv->tree, - selection->tree_view->priv->tree->root, + _gtk_rbtree_traverse (tree, tree->root, G_PRE_ORDER, gtk_tree_selection_count_selected_rows_helper, &count); @@ -592,7 +729,7 @@ model_changed (gpointer data) /** * gtk_tree_selection_selected_foreach: * @selection: A #GtkTreeSelection. - * @func: The function to call for each selected node. + * @func: (scope call): The function to call for each selected node. * @data: user data to pass to the function. * * Calls a function for each selected node. Note that you cannot modify @@ -604,111 +741,99 @@ gtk_tree_selection_selected_foreach (GtkTreeSelection *selection, GtkTreeSelectionForeachFunc func, gpointer data) { + GtkTreeSelectionPrivate *priv; GtkTreePath *path; GtkRBTree *tree; GtkRBNode *node; GtkTreeIter iter; + GtkTreeModel *model; - guint inserted_id, deleted_id, reordered_id; - gboolean stop = FALSE, has_next = TRUE, has_parent = TRUE; + gulong inserted_id, deleted_id, reordered_id, changed_id; + gboolean stop = FALSE; g_return_if_fail (GTK_IS_TREE_SELECTION (selection)); - g_return_if_fail (selection->tree_view != NULL); - g_return_if_fail (selection->tree_view->priv->model != NULL); - if (func == NULL || - selection->tree_view->priv->tree == NULL || - selection->tree_view->priv->tree->root == NULL) + priv = selection->priv; + + g_return_if_fail (priv->tree_view != NULL); + + tree = _gtk_tree_view_get_rbtree (priv->tree_view); + + if (func == NULL || tree == NULL || tree->root == NULL) return; - if (selection->type == GTK_SELECTION_SINGLE || - selection->type == GTK_SELECTION_BROWSE) + model = gtk_tree_view_get_model (priv->tree_view); + + if (priv->type == GTK_SELECTION_SINGLE || + priv->type == GTK_SELECTION_BROWSE) { - if (gtk_tree_row_reference_valid (selection->tree_view->priv->anchor)) + path = _gtk_tree_view_get_anchor_path (priv->tree_view); + + if (path) { - path = gtk_tree_row_reference_get_path (selection->tree_view->priv->anchor); - gtk_tree_model_get_iter (selection->tree_view->priv->model, &iter, path); - (* func) (selection->tree_view->priv->model, path, &iter, data); + gtk_tree_model_get_iter (model, &iter, path); + (* func) (model, path, &iter, data); gtk_tree_path_free (path); } return; } - tree = selection->tree_view->priv->tree; - node = selection->tree_view->priv->tree->root; - - while (node->left != tree->nil) - node = node->left; + node = _gtk_rbtree_first (tree); + + g_object_ref (model); /* connect to signals to monitor changes in treemodel */ - inserted_id = g_signal_connect_swapped (selection->tree_view->priv->model, - "row_inserted", + inserted_id = g_signal_connect_swapped (model, "row-inserted", G_CALLBACK (model_changed), &stop); - deleted_id = g_signal_connect_swapped (selection->tree_view->priv->model, - "row_deleted", + deleted_id = g_signal_connect_swapped (model, "row-deleted", G_CALLBACK (model_changed), &stop); - reordered_id = g_signal_connect_swapped (selection->tree_view->priv->model, - "rows_reordered", + reordered_id = g_signal_connect_swapped (model, "rows-reordered", G_CALLBACK (model_changed), &stop); + changed_id = g_signal_connect_swapped (priv->tree_view, "notify::model", + G_CALLBACK (model_changed), + &stop); /* find the node internally */ path = gtk_tree_path_new_first (); - gtk_tree_model_get_iter (selection->tree_view->priv->model, - &iter, path); do { if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_SELECTED)) - (* func) (selection->tree_view->priv->model, path, &iter, data); + { + gtk_tree_model_get_iter (model, &iter, path); + (* func) (model, path, &iter, data); + } if (stop) goto out; if (node->children) { - gboolean has_child; - GtkTreeIter tmp; - tree = node->children; - node = tree->root; - while (node->left != tree->nil) - node = node->left; - tmp = iter; - has_child = gtk_tree_model_iter_children (selection->tree_view->priv->model, &iter, &tmp); - gtk_tree_path_append_index (path, 0); + node = _gtk_rbtree_first (tree); - /* we do the sanity check at the bottom of this function */ - if (!has_child) - goto out; + gtk_tree_path_append_index (path, 0); } else { gboolean done = FALSE; + do { node = _gtk_rbtree_next (tree, node); if (node != NULL) { - gboolean has_next; - - has_next = gtk_tree_model_iter_next (selection->tree_view->priv->model, &iter); done = TRUE; gtk_tree_path_next (path); - - /* we do the sanity check at the bottom of this function */ - if (!has_next) - goto out; } else { - gboolean has_parent; - GtkTreeIter tmp_iter = iter; - node = tree->parent_node; tree = tree->parent_tree; + if (tree == NULL) { /* we've run out of tree */ @@ -717,12 +842,7 @@ gtk_tree_selection_selected_foreach (GtkTreeSelection *selection, goto out; } - has_parent = gtk_tree_model_iter_parent (selection->tree_view->priv->model, &iter, &tmp_iter); gtk_tree_path_up (path); - - /* we do the sanity check at the bottom of this function */ - if (!has_parent) - goto out; } } while (!done); @@ -734,24 +854,18 @@ out: if (path) gtk_tree_path_free (path); - g_signal_handler_disconnect (selection->tree_view->priv->model, - inserted_id); - g_signal_handler_disconnect (selection->tree_view->priv->model, - deleted_id); - g_signal_handler_disconnect (selection->tree_view->priv->model, - reordered_id); + g_signal_handler_disconnect (model, inserted_id); + g_signal_handler_disconnect (model, deleted_id); + g_signal_handler_disconnect (model, reordered_id); + g_signal_handler_disconnect (priv->tree_view, changed_id); + g_object_unref (model); /* check if we have to spew a scary message */ - if (!has_next) - TREE_VIEW_INTERNAL_ASSERT_VOID (has_next); - if (!has_parent) - TREE_VIEW_INTERNAL_ASSERT_VOID (has_parent); if (stop) - g_warning - ("The model has been modified from within gtk_tree_selection_foreach.\n" - "This function is for observing the selections of the tree only. If\n" - "you are trying to get all selected items from the tree, try using\n" - "gtk_tree_selection_get_selected_rows instead.\n"); + g_warning ("The model has been modified from within gtk_tree_selection_selected_foreach.\n" + "This function is for observing the selections of the tree only. If\n" + "you are trying to get all selected items from the tree, try using\n" + "gtk_tree_selection_get_selected_rows instead.\n"); } /** @@ -765,16 +879,20 @@ void gtk_tree_selection_select_path (GtkTreeSelection *selection, GtkTreePath *path) { + GtkTreeSelectionPrivate *priv; GtkRBNode *node; GtkRBTree *tree; - GdkModifierType state = 0; gboolean ret; + GtkTreeSelectMode mode = 0; g_return_if_fail (GTK_IS_TREE_SELECTION (selection)); - g_return_if_fail (selection->tree_view != NULL); + + priv = selection->priv; + + g_return_if_fail (priv->tree_view != NULL); g_return_if_fail (path != NULL); - ret = _gtk_tree_view_find_node (selection->tree_view, + ret = _gtk_tree_view_find_node (priv->tree_view, path, &tree, &node); @@ -783,14 +901,14 @@ gtk_tree_selection_select_path (GtkTreeSelection *selection, ret == TRUE) return; - if (selection->type == GTK_SELECTION_MULTIPLE) - state = GDK_CONTROL_MASK; + if (priv->type == GTK_SELECTION_MULTIPLE) + mode = GTK_TREE_SELECT_MODE_TOGGLE; _gtk_tree_selection_internal_select_node (selection, node, tree, path, - state, + mode, FALSE); } @@ -805,15 +923,19 @@ void gtk_tree_selection_unselect_path (GtkTreeSelection *selection, GtkTreePath *path) { + GtkTreeSelectionPrivate *priv; GtkRBNode *node; GtkRBTree *tree; gboolean ret; g_return_if_fail (GTK_IS_TREE_SELECTION (selection)); - g_return_if_fail (selection->tree_view != NULL); + + priv = selection->priv; + + g_return_if_fail (priv->tree_view != NULL); g_return_if_fail (path != NULL); - ret = _gtk_tree_view_find_node (selection->tree_view, + ret = _gtk_tree_view_find_node (priv->tree_view, path, &tree, &node); @@ -826,7 +948,7 @@ gtk_tree_selection_unselect_path (GtkTreeSelection *selection, node, tree, path, - GDK_CONTROL_MASK, + GTK_TREE_SELECT_MODE_TOGGLE, TRUE); } @@ -841,15 +963,21 @@ void gtk_tree_selection_select_iter (GtkTreeSelection *selection, GtkTreeIter *iter) { + GtkTreeSelectionPrivate *priv; GtkTreePath *path; + GtkTreeModel *model; g_return_if_fail (GTK_IS_TREE_SELECTION (selection)); - g_return_if_fail (selection->tree_view != NULL); - g_return_if_fail (selection->tree_view->priv->model != NULL); + + priv = selection->priv; + + g_return_if_fail (priv->tree_view != NULL); + + model = gtk_tree_view_get_model (priv->tree_view); + g_return_if_fail (model != NULL); g_return_if_fail (iter != NULL); - path = gtk_tree_model_get_path (selection->tree_view->priv->model, - iter); + path = gtk_tree_model_get_path (model, iter); if (path == NULL) return; @@ -870,15 +998,21 @@ void gtk_tree_selection_unselect_iter (GtkTreeSelection *selection, GtkTreeIter *iter) { + GtkTreeSelectionPrivate *priv; GtkTreePath *path; + GtkTreeModel *model; g_return_if_fail (GTK_IS_TREE_SELECTION (selection)); - g_return_if_fail (selection->tree_view != NULL); - g_return_if_fail (selection->tree_view->priv->model != NULL); + + priv = selection->priv; + + g_return_if_fail (priv->tree_view != NULL); + + model = gtk_tree_view_get_model (priv->tree_view); + g_return_if_fail (model != NULL); g_return_if_fail (iter != NULL); - path = gtk_tree_model_get_path (selection->tree_view->priv->model, - iter); + path = gtk_tree_model_get_path (model, iter); if (path == NULL) return; @@ -901,16 +1035,22 @@ gboolean gtk_tree_selection_path_is_selected (GtkTreeSelection *selection, GtkTreePath *path) { + GtkTreeSelectionPrivate *priv; GtkRBNode *node; GtkRBTree *tree; gboolean ret; g_return_val_if_fail (GTK_IS_TREE_SELECTION (selection), FALSE); + + priv = selection->priv; + g_return_val_if_fail (path != NULL, FALSE); - g_return_val_if_fail (selection->tree_view != NULL, FALSE); - g_return_val_if_fail (selection->tree_view->priv->model != NULL, FALSE); + g_return_val_if_fail (priv->tree_view != NULL, FALSE); + + if (gtk_tree_view_get_model (priv->tree_view) == NULL) + return FALSE; - ret = _gtk_tree_view_find_node (selection->tree_view, + ret = _gtk_tree_view_find_node (priv->tree_view, path, &tree, &node); @@ -935,15 +1075,22 @@ gboolean gtk_tree_selection_iter_is_selected (GtkTreeSelection *selection, GtkTreeIter *iter) { + GtkTreeSelectionPrivate *priv; GtkTreePath *path; + GtkTreeModel *model; gboolean retval; g_return_val_if_fail (GTK_IS_TREE_SELECTION (selection), FALSE); + + priv = selection->priv; + g_return_val_if_fail (iter != NULL, FALSE); - g_return_val_if_fail (selection->tree_view != NULL, FALSE); - g_return_val_if_fail (selection->tree_view->priv->model != NULL, FALSE); + g_return_val_if_fail (priv->tree_view != NULL, FALSE); - path = gtk_tree_model_get_path (selection->tree_view->priv->model, iter); + model = gtk_tree_view_get_model (priv->tree_view); + g_return_val_if_fail (model != NULL, FALSE); + + path = gtk_tree_model_get_path (model, iter); if (path == NULL) return FALSE; @@ -986,9 +1133,13 @@ select_all_helper (GtkRBTree *tree, static gint gtk_tree_selection_real_select_all (GtkTreeSelection *selection) { + GtkTreeSelectionPrivate *priv = selection->priv; struct _TempTuple *tuple; + GtkRBTree *tree; + + tree = _gtk_tree_view_get_rbtree (priv->tree_view); - if (selection->tree_view->priv->tree == NULL) + if (tree == NULL) return FALSE; /* Mark all nodes selected */ @@ -996,8 +1147,7 @@ gtk_tree_selection_real_select_all (GtkTreeSelection *selection) tuple->selection = selection; tuple->dirty = FALSE; - _gtk_rbtree_traverse (selection->tree_view->priv->tree, - selection->tree_view->priv->tree->root, + _gtk_rbtree_traverse (tree, tree->root, G_PRE_ORDER, select_all_helper, tuple); @@ -1014,17 +1164,25 @@ gtk_tree_selection_real_select_all (GtkTreeSelection *selection) * gtk_tree_selection_select_all: * @selection: A #GtkTreeSelection. * - * Selects all the nodes. @selection is must be set to #GTK_SELECTION_MULTIPLE + * Selects all the nodes. @selection must be set to #GTK_SELECTION_MULTIPLE * mode. **/ void gtk_tree_selection_select_all (GtkTreeSelection *selection) { + GtkTreeSelectionPrivate *priv; + g_return_if_fail (GTK_IS_TREE_SELECTION (selection)); - g_return_if_fail (selection->tree_view != NULL); - if (selection->tree_view->priv->tree == NULL) + + priv = selection->priv; + + g_return_if_fail (priv->tree_view != NULL); + + if (_gtk_tree_view_get_rbtree (priv->tree_view) == NULL || + gtk_tree_view_get_model (priv->tree_view) == NULL) return; - g_return_if_fail (selection->type == GTK_SELECTION_MULTIPLE); + + g_return_if_fail (priv->type == GTK_SELECTION_MULTIPLE); if (gtk_tree_selection_real_select_all (selection)) g_signal_emit (selection, tree_selection_signals[CHANGED], 0); @@ -1049,27 +1207,25 @@ unselect_all_helper (GtkRBTree *tree, } } -static gint +static gboolean gtk_tree_selection_real_unselect_all (GtkTreeSelection *selection) { + GtkTreeSelectionPrivate *priv = selection->priv; struct _TempTuple *tuple; - if (selection->type == GTK_SELECTION_SINGLE || - selection->type == GTK_SELECTION_BROWSE) + if (priv->type == GTK_SELECTION_SINGLE || + priv->type == GTK_SELECTION_BROWSE) { 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); + anchor_path = _gtk_tree_view_get_anchor_path (priv->tree_view); if (anchor_path == NULL) return FALSE; - _gtk_tree_view_find_node (selection->tree_view, + _gtk_tree_view_find_node (priv->tree_view, anchor_path, &tree, &node); @@ -1083,8 +1239,7 @@ gtk_tree_selection_real_unselect_all (GtkTreeSelection *selection) { if (gtk_tree_selection_real_select_node (selection, tree, node, FALSE)) { - gtk_tree_row_reference_free (selection->tree_view->priv->anchor); - selection->tree_view->priv->anchor = NULL; + _gtk_tree_view_set_anchor_path (priv->tree_view, NULL); return TRUE; } } @@ -1092,12 +1247,14 @@ gtk_tree_selection_real_unselect_all (GtkTreeSelection *selection) } else { + GtkRBTree *tree; + tuple = g_new (struct _TempTuple, 1); tuple->selection = selection; tuple->dirty = FALSE; - _gtk_rbtree_traverse (selection->tree_view->priv->tree, - selection->tree_view->priv->tree->root, + tree = _gtk_tree_view_get_rbtree (priv->tree_view); + _gtk_rbtree_traverse (tree, tree->root, G_PRE_ORDER, unselect_all_helper, tuple); @@ -1121,14 +1278,18 @@ gtk_tree_selection_real_unselect_all (GtkTreeSelection *selection) void gtk_tree_selection_unselect_all (GtkTreeSelection *selection) { + GtkTreeSelectionPrivate *priv; + g_return_if_fail (GTK_IS_TREE_SELECTION (selection)); - g_return_if_fail (selection->tree_view != NULL); - if (selection->tree_view->priv->tree == NULL) + + priv = selection->priv; + + g_return_if_fail (priv->tree_view != NULL); + + if (_gtk_tree_view_get_rbtree (priv->tree_view) == NULL || + gtk_tree_view_get_model (priv->tree_view) == NULL) return; - if (selection->tree_view->priv->tree == NULL) - return; - if (gtk_tree_selection_real_unselect_all (selection)) g_signal_emit (selection, tree_selection_signals[CHANGED], 0); } @@ -1145,6 +1306,7 @@ gtk_tree_selection_real_modify_range (GtkTreeSelection *selection, GtkTreePath *start_path, GtkTreePath *end_path) { + GtkTreeSelectionPrivate *priv = selection->priv; GtkRBNode *start_node, *end_node; GtkRBTree *start_tree, *end_tree; GtkTreePath *anchor_path = NULL; @@ -1153,18 +1315,18 @@ gtk_tree_selection_real_modify_range (GtkTreeSelection *selection, switch (gtk_tree_path_compare (start_path, end_path)) { case 1: - _gtk_tree_view_find_node (selection->tree_view, + _gtk_tree_view_find_node (priv->tree_view, end_path, &start_tree, &start_node); - _gtk_tree_view_find_node (selection->tree_view, + _gtk_tree_view_find_node (priv->tree_view, start_path, &end_tree, &end_node); - anchor_path = end_path; + anchor_path = start_path; break; case 0: - _gtk_tree_view_find_node (selection->tree_view, + _gtk_tree_view_find_node (priv->tree_view, start_path, &start_tree, &start_node); @@ -1173,11 +1335,11 @@ gtk_tree_selection_real_modify_range (GtkTreeSelection *selection, anchor_path = start_path; break; case -1: - _gtk_tree_view_find_node (selection->tree_view, + _gtk_tree_view_find_node (priv->tree_view, start_path, &start_tree, &start_node); - _gtk_tree_view_find_node (selection->tree_view, + _gtk_tree_view_find_node (priv->tree_view, end_path, &end_tree, &end_node); @@ -1189,15 +1351,7 @@ gtk_tree_selection_real_modify_range (GtkTreeSelection *selection, g_return_val_if_fail (end_node != NULL, FALSE); if (anchor_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_proxy (G_OBJECT (selection->tree_view), - selection->tree_view->priv->model, - anchor_path); - } + _gtk_tree_view_set_anchor_path (priv->tree_view, anchor_path); do { @@ -1209,9 +1363,7 @@ gtk_tree_selection_real_modify_range (GtkTreeSelection *selection, if (start_node->children) { start_tree = start_node->children; - start_node = start_tree->root; - while (start_node->left != start_tree->nil) - start_node = start_node->left; + start_node = _gtk_rbtree_first (start_tree); } else { @@ -1236,14 +1388,22 @@ gtk_tree_selection_real_modify_range (GtkTreeSelection *selection, * @end_path: The final node of the range. * * Selects a range of nodes, determined by @start_path and @end_path inclusive. + * @selection must be set to #GTK_SELECTION_MULTIPLE mode. **/ void gtk_tree_selection_select_range (GtkTreeSelection *selection, GtkTreePath *start_path, GtkTreePath *end_path) { + GtkTreeSelectionPrivate *priv; + g_return_if_fail (GTK_IS_TREE_SELECTION (selection)); - g_return_if_fail (selection->tree_view != NULL); + + priv = selection->priv; + + g_return_if_fail (priv->tree_view != NULL); + g_return_if_fail (priv->type == GTK_SELECTION_MULTIPLE); + g_return_if_fail (gtk_tree_view_get_model (priv->tree_view) != NULL); if (gtk_tree_selection_real_modify_range (selection, RANGE_SELECT, start_path, end_path)) g_signal_emit (selection, tree_selection_signals[CHANGED], 0); @@ -1257,19 +1417,63 @@ gtk_tree_selection_select_range (GtkTreeSelection *selection, * * Unselects a range of nodes, determined by @start_path and @end_path * inclusive. + * + * Since: 2.2 **/ void gtk_tree_selection_unselect_range (GtkTreeSelection *selection, GtkTreePath *start_path, GtkTreePath *end_path) { + GtkTreeSelectionPrivate *priv; + g_return_if_fail (GTK_IS_TREE_SELECTION (selection)); - g_return_if_fail (selection->tree_view != NULL); + + priv = selection->priv; + + g_return_if_fail (priv->tree_view != NULL); + g_return_if_fail (gtk_tree_view_get_model (priv->tree_view) != NULL); if (gtk_tree_selection_real_modify_range (selection, RANGE_UNSELECT, start_path, end_path)) g_signal_emit (selection, tree_selection_signals[CHANGED], 0); } +gboolean +_gtk_tree_selection_row_is_selectable (GtkTreeSelection *selection, + GtkRBNode *node, + GtkTreePath *path) +{ + GtkTreeSelectionPrivate *priv = selection->priv; + GtkTreeIter iter; + GtkTreeModel *model; + GtkTreeViewRowSeparatorFunc separator_func; + gpointer separator_data; + gboolean sensitive = FALSE; + + model = gtk_tree_view_get_model (priv->tree_view); + + _gtk_tree_view_get_row_separator_func (priv->tree_view, + &separator_func, &separator_data); + + if (!gtk_tree_model_get_iter (model, &iter, path)) + sensitive = TRUE; + + if (!sensitive && separator_func) + { + /* never allow separators to be selected */ + if ((* separator_func) (model, &iter, separator_data)) + return FALSE; + } + + if (priv->user_func) + return (*priv->user_func) (selection, model, path, + GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_SELECTED), + priv->user_data); + else + return TRUE; +} + + /* Called internally by gtktreeview.c It handles actually selecting the tree. */ @@ -1283,32 +1487,32 @@ _gtk_tree_selection_internal_select_node (GtkTreeSelection *selection, GtkRBNode *node, GtkRBTree *tree, GtkTreePath *path, - GdkModifierType state, + GtkTreeSelectMode mode, gboolean override_browse_mode) { + GtkTreeSelectionPrivate *priv = selection->priv; gint flags; gint dirty = FALSE; GtkTreePath *anchor_path = NULL; - if (selection->type == GTK_SELECTION_NONE) + if (priv->type == GTK_SELECTION_NONE) return; - if (selection->tree_view->priv->anchor) - anchor_path = gtk_tree_row_reference_get_path (selection->tree_view->priv->anchor); + anchor_path = _gtk_tree_view_get_anchor_path (priv->tree_view); - if (selection->type == GTK_SELECTION_SINGLE || - selection->type == GTK_SELECTION_BROWSE) + if (priv->type == GTK_SELECTION_SINGLE || + priv->type == GTK_SELECTION_BROWSE) { /* just unselect */ - if (selection->type == GTK_SELECTION_BROWSE && override_browse_mode) + if (priv->type == GTK_SELECTION_BROWSE && override_browse_mode) { dirty = gtk_tree_selection_real_unselect_all (selection); } /* Did we try to select the same node again? */ - else if (selection->type == GTK_SELECTION_SINGLE && + else if (priv->type == GTK_SELECTION_SINGLE && anchor_path && gtk_tree_path_compare (path, anchor_path) == 0) { - if ((state & GDK_CONTROL_MASK) == GDK_CONTROL_MASK) + if ((mode & GTK_TREE_SELECT_MODE_TOGGLE) == GTK_TREE_SELECT_MODE_TOGGLE) { dirty = gtk_tree_selection_real_unselect_all (selection); } @@ -1319,17 +1523,7 @@ _gtk_tree_selection_internal_select_node (GtkTreeSelection *selection, { /* We only want to select the new node if we can unselect the old one, * and we can select the new one. */ - if (selection->user_func) - { - if ((*selection->user_func) (selection, selection->tree_view->priv->model, path, - GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_SELECTED), - selection->user_data)) - dirty = TRUE; - } - else - { - dirty = TRUE; - } + dirty = _gtk_tree_selection_row_is_selectable (selection, node, path); /* if dirty is FALSE, we weren't able to select the new one, otherwise, we try to * unselect the new one @@ -1341,13 +1535,11 @@ _gtk_tree_selection_internal_select_node (GtkTreeSelection *selection, * old one, and can then select the new one */ if (dirty) { - if (selection->tree_view->priv->anchor) - gtk_tree_row_reference_free (selection->tree_view->priv->anchor); + + _gtk_tree_view_set_anchor_path (priv->tree_view, NULL); + if (gtk_tree_selection_real_select_node (selection, tree, node, TRUE)) - { - selection->tree_view->priv->anchor = - gtk_tree_row_reference_new_proxy (G_OBJECT (selection->tree_view), selection->tree_view->priv->model, path); - } + _gtk_tree_view_set_anchor_path (priv->tree_view, path); } } else @@ -1355,47 +1547,39 @@ _gtk_tree_selection_internal_select_node (GtkTreeSelection *selection, if (gtk_tree_selection_real_select_node (selection, tree, node, TRUE)) { dirty = TRUE; - 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_proxy (G_OBJECT (selection->tree_view), selection->tree_view->priv->model, path); + _gtk_tree_view_set_anchor_path (priv->tree_view, path); } } } } - else if (selection->type == GTK_SELECTION_MULTIPLE) + else if (priv->type == GTK_SELECTION_MULTIPLE) { - if (((state & GDK_SHIFT_MASK) == GDK_SHIFT_MASK) && (anchor_path == NULL)) + if ((mode & GTK_TREE_SELECT_MODE_EXTEND) == GTK_TREE_SELECT_MODE_EXTEND + && (anchor_path == NULL)) { - if (selection->tree_view->priv->anchor) - gtk_tree_row_reference_free (selection->tree_view->priv->anchor); + _gtk_tree_view_set_anchor_path (priv->tree_view, path); - selection->tree_view->priv->anchor = - gtk_tree_row_reference_new_proxy (G_OBJECT (selection->tree_view), 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)) + else if ((mode & (GTK_TREE_SELECT_MODE_EXTEND | GTK_TREE_SELECT_MODE_TOGGLE)) == (GTK_TREE_SELECT_MODE_EXTEND | GTK_TREE_SELECT_MODE_TOGGLE)) { gtk_tree_selection_select_range (selection, anchor_path, path); } - else if ((state & GDK_CONTROL_MASK) == GDK_CONTROL_MASK) + else if ((mode & GTK_TREE_SELECT_MODE_TOGGLE) == GTK_TREE_SELECT_MODE_TOGGLE) { flags = node->flags; - 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_proxy (G_OBJECT (selection->tree_view), selection->tree_view->priv->model, path); + _gtk_tree_view_set_anchor_path (priv->tree_view, path); if ((flags & GTK_RBNODE_IS_SELECTED) == GTK_RBNODE_IS_SELECTED) dirty |= gtk_tree_selection_real_select_node (selection, tree, node, FALSE); else dirty |= gtk_tree_selection_real_select_node (selection, tree, node, TRUE); } - else if ((state & GDK_SHIFT_MASK) == GDK_SHIFT_MASK) + else if ((mode & GTK_TREE_SELECT_MODE_EXTEND) == GTK_TREE_SELECT_MODE_EXTEND) { dirty = gtk_tree_selection_real_unselect_all (selection); dirty |= gtk_tree_selection_real_modify_range (selection, @@ -1407,11 +1591,7 @@ _gtk_tree_selection_internal_select_node (GtkTreeSelection *selection, { dirty = gtk_tree_selection_real_unselect_all (selection); - 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_proxy (G_OBJECT (selection->tree_view), selection->tree_view->priv->model, path); + _gtk_tree_view_set_anchor_path (priv->tree_view, path); dirty |= gtk_tree_selection_real_select_node (selection, tree, node, TRUE); } @@ -1421,7 +1601,14 @@ _gtk_tree_selection_internal_select_node (GtkTreeSelection *selection, gtk_tree_path_free (anchor_path); if (dirty) - g_signal_emit (selection, tree_selection_signals[CHANGED], 0); + g_signal_emit (selection, tree_selection_signals[CHANGED], 0); +} + + +void +_gtk_tree_selection_emit_changed (GtkTreeSelection *selection) +{ + g_signal_emit (selection, tree_selection_signals[CHANGED], 0); } /* NOTE: Any {un,}selection ever done _MUST_ be done through this function! @@ -1433,35 +1620,36 @@ gtk_tree_selection_real_select_node (GtkTreeSelection *selection, GtkRBNode *node, gboolean select) { - gboolean selected = FALSE; + GtkTreeSelectionPrivate *priv = selection->priv; + gboolean toggle = FALSE; GtkTreePath *path = NULL; select = !! select; if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_SELECTED) != select) { - path = _gtk_tree_view_find_path (selection->tree_view, tree, node); - if (selection->user_func) - { - if ((*selection->user_func) (selection, selection->tree_view->priv->model, path, - GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_SELECTED), - selection->user_data)) - selected = TRUE; - } - else - selected = TRUE; + path = _gtk_tree_path_new_from_rbtree (tree, node); + toggle = _gtk_tree_selection_row_is_selectable (selection, node, path); gtk_tree_path_free (path); } - if (selected == TRUE) + if (toggle) { - node->flags ^= GTK_RBNODE_IS_SELECTED; + if (!GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_SELECTED)) + { + GTK_RBNODE_SET_FLAG (node, GTK_RBNODE_IS_SELECTED); + _gtk_tree_view_accessible_add_state (priv->tree_view, tree, node, GTK_CELL_RENDERER_SELECTED); + } + else + { + GTK_RBNODE_UNSET_FLAG (node, GTK_RBNODE_IS_SELECTED); + _gtk_tree_view_accessible_remove_state (priv->tree_view, tree, node, GTK_CELL_RENDERER_SELECTED); + } + + _gtk_tree_view_queue_draw_node (priv->tree_view, tree, node, NULL); - _gtk_tree_view_queue_draw_node (selection->tree_view, tree, node, NULL); - return TRUE; } return FALSE; } -