]> Pileus Git - ~andy/gtk/blob - gtk/gtktreeselection.c
treeview: Signal selection changes to the accessible
[~andy/gtk] / gtk / gtktreeselection.c
1 /* gtktreeselection.h
2  * Copyright (C) 2000  Red Hat, Inc.,  Jonathan Blandford <jrb@redhat.com>
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Library General Public
6  * License as published by the Free Software Foundation; either
7  * version 2 of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * Library General Public License for more details.
13  *
14  * You should have received a copy of the GNU Library General Public
15  * License along with this library; if not, write to the
16  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
17  * Boston, MA 02111-1307, USA.
18  */
19
20 #include "config.h"
21 #include <string.h>
22 #include "gtktreeselection.h"
23 #include "gtktreeprivate.h"
24 #include "gtkrbtree.h"
25 #include "gtkmarshalers.h"
26 #include "gtkintl.h"
27 #include "gtktypebuiltins.h"
28 #include "a11y/gtktreeviewaccessible.h"
29
30
31 /**
32  * SECTION:gtktreeselection
33  * @Short_description: The selection object for GtkTreeView
34  * @Title: GtkTreeSelection
35  * @See_also: #GtkTreeView, #GtkTreeViewColumn, #GtkTreeDnd, #GtkTreeMode,
36  *   #GtkTreeSortable, #GtkTreeModelSort, #GtkListStore, #GtkTreeStore,
37  *   #GtkCellRenderer, #GtkCellEditable, #GtkCellRendererPixbuf,
38  *   #GtkCellRendererText, #GtkCellRendererToggle
39  *
40  * The #GtkTreeSelection object is a helper object to manage the selection
41  * for a #GtkTreeView widget.  The #GtkTreeSelection object is
42  * automatically created when a new #GtkTreeView widget is created, and
43  * cannot exist independentally of this widget.  The primary reason the
44  * #GtkTreeSelection objects exists is for cleanliness of code and API.
45  * That is, there is no conceptual reason all these functions could not be
46  * methods on the #GtkTreeView widget instead of a separate function.
47  *
48  * The #GtkTreeSelection object is gotten from a #GtkTreeView by calling
49  * gtk_tree_view_get_selection().  It can be manipulated to check the
50  * selection status of the tree, as well as select and deselect individual
51  * rows.  Selection is done completely view side.  As a result, multiple
52  * views of the same model can have completely different selections.
53  * Additionally, you cannot change the selection of a row on the model that
54  * is not currently displayed by the view without expanding its parents
55  * first.
56  *
57  * One of the important things to remember when monitoring the selection of
58  * a view is that the #GtkTreeSelection::changed signal is mostly a hint.
59  * That is,it may only emit one signal when a range of rows is selected.
60  * Additionally, it may on occasion emit a #GtkTreeSelection::changed signal
61  * when nothing has happened (mostly as a result of programmers calling
62  * select_row on an already selected row).
63  */
64
65 struct _GtkTreeSelectionPrivate
66 {
67   GtkTreeView *tree_view;
68   GtkSelectionMode type;
69   GtkTreeSelectionFunc user_func;
70   gpointer user_data;
71   GDestroyNotify destroy;
72 };
73
74 static void gtk_tree_selection_finalize          (GObject               *object);
75 static gint gtk_tree_selection_real_select_all   (GtkTreeSelection      *selection);
76 static gint gtk_tree_selection_real_unselect_all (GtkTreeSelection      *selection);
77 static gint gtk_tree_selection_real_select_node  (GtkTreeSelection      *selection,
78                                                   GtkRBTree             *tree,
79                                                   GtkRBNode             *node,
80                                                   gboolean               select);
81 static void gtk_tree_selection_set_property      (GObject               *object,
82                                                   guint                  prop_id,
83                                                   const GValue          *value,
84                                                   GParamSpec            *pspec);
85 static void gtk_tree_selection_get_property      (GObject               *object,
86                                                   guint                  prop_id,
87                                                   GValue                *value,
88                                                   GParamSpec            *pspec);
89
90 enum
91 {
92   PROP_0,
93   PROP_MODE,
94   N_PROPERTIES
95 };
96
97 enum
98 {
99   CHANGED,
100   LAST_SIGNAL
101 };
102
103 static GParamSpec *properties[N_PROPERTIES];
104 static guint tree_selection_signals [LAST_SIGNAL] = { 0 };
105
106 G_DEFINE_TYPE (GtkTreeSelection, gtk_tree_selection, G_TYPE_OBJECT)
107
108 static void
109 gtk_tree_selection_class_init (GtkTreeSelectionClass *class)
110 {
111   GObjectClass *object_class;
112
113   object_class = (GObjectClass*) class;
114
115   object_class->finalize = gtk_tree_selection_finalize;
116   object_class->set_property = gtk_tree_selection_set_property;
117   object_class->get_property = gtk_tree_selection_get_property;
118   class->changed = NULL;
119
120   /* Properties */
121   
122   /**
123    * GtkTreeSelection:mode:
124    *
125    * Selection mode.
126    * See gtk_tree_selection_set_mode() for more information on this property.
127    *
128    * Since: 3.2
129    */
130   properties[PROP_MODE] = g_param_spec_enum ("mode",
131                                              P_("Mode"),
132                                              P_("Selection mode"),
133                                              GTK_TYPE_SELECTION_MODE,
134                                              GTK_SELECTION_SINGLE,
135                                              G_PARAM_READWRITE |
136                                              G_PARAM_STATIC_STRINGS);
137
138   /* Install all properties */
139   g_object_class_install_properties (object_class, N_PROPERTIES, properties);
140   
141   /* Signals */
142   
143   /**
144    * GtkTreeSelection::changed:
145    * @treeselection: the object which received the signal.
146    *
147    * Emitted whenever the selection has (possibly) changed. Please note that
148    * this signal is mostly a hint.  It may only be emitted once when a range
149    * of rows are selected, and it may occasionally be emitted when nothing
150    * has happened.
151    */
152   tree_selection_signals[CHANGED] =
153     g_signal_new (I_("changed"),
154                   G_OBJECT_CLASS_TYPE (object_class),
155                   G_SIGNAL_RUN_FIRST,
156                   G_STRUCT_OFFSET (GtkTreeSelectionClass, changed),
157                   NULL, NULL,
158                   _gtk_marshal_VOID__VOID,
159                   G_TYPE_NONE, 0);
160
161   g_type_class_add_private (class, sizeof (GtkTreeSelectionPrivate));
162 }
163
164 static void
165 gtk_tree_selection_init (GtkTreeSelection *selection)
166 {
167   GtkTreeSelectionPrivate *priv;
168
169   selection->priv = G_TYPE_INSTANCE_GET_PRIVATE (selection,
170                                                  GTK_TYPE_TREE_SELECTION,
171                                                  GtkTreeSelectionPrivate);
172   priv = selection->priv;
173
174   priv->type = GTK_SELECTION_SINGLE;
175 }
176
177 static void
178 gtk_tree_selection_finalize (GObject *object)
179 {
180   GtkTreeSelection *selection = GTK_TREE_SELECTION (object);
181   GtkTreeSelectionPrivate *priv = selection->priv;
182
183   if (priv->destroy)
184     priv->destroy (priv->user_data);
185
186   /* chain parent_class' handler */
187   G_OBJECT_CLASS (gtk_tree_selection_parent_class)->finalize (object);
188 }
189
190 static void
191 gtk_tree_selection_set_property (GObject *object,
192                                  guint prop_id,
193                                  const GValue *value,
194                                  GParamSpec *pspec)
195 {
196   g_return_if_fail (GTK_IS_TREE_SELECTION (object));
197
198   switch (prop_id)
199     {
200       case PROP_MODE:
201         gtk_tree_selection_set_mode (GTK_TREE_SELECTION (object), g_value_get_enum (value));
202         break;
203       default:
204         G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
205         break;
206     }
207 }
208
209 static void
210 gtk_tree_selection_get_property (GObject *object,
211                                  guint prop_id,
212                                  GValue *value,
213                                  GParamSpec *pspec)
214 {
215   g_return_if_fail (GTK_IS_TREE_SELECTION (object));
216
217   switch (prop_id)
218     {
219       case PROP_MODE:
220         g_value_set_enum (value, gtk_tree_selection_get_mode (GTK_TREE_SELECTION (object)));
221         break;
222       default:
223         G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
224         break;
225     }
226 }
227
228 /**
229  * _gtk_tree_selection_new:
230  *
231  * Creates a new #GtkTreeSelection object.  This function should not be invoked,
232  * as each #GtkTreeView will create its own #GtkTreeSelection.
233  *
234  * Return value: A newly created #GtkTreeSelection object.
235  **/
236 GtkTreeSelection*
237 _gtk_tree_selection_new (void)
238 {
239   GtkTreeSelection *selection;
240
241   selection = g_object_new (GTK_TYPE_TREE_SELECTION, NULL);
242
243   return selection;
244 }
245
246 /**
247  * _gtk_tree_selection_new_with_tree_view:
248  * @tree_view: The #GtkTreeView.
249  *
250  * Creates a new #GtkTreeSelection object.  This function should not be invoked,
251  * as each #GtkTreeView will create its own #GtkTreeSelection.
252  *
253  * Return value: A newly created #GtkTreeSelection object.
254  **/
255 GtkTreeSelection*
256 _gtk_tree_selection_new_with_tree_view (GtkTreeView *tree_view)
257 {
258   GtkTreeSelection *selection;
259
260   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), NULL);
261
262   selection = _gtk_tree_selection_new ();
263   _gtk_tree_selection_set_tree_view (selection, tree_view);
264
265   return selection;
266 }
267
268 /**
269  * _gtk_tree_selection_set_tree_view:
270  * @selection: A #GtkTreeSelection.
271  * @tree_view: The #GtkTreeView.
272  *
273  * Sets the #GtkTreeView of @selection.  This function should not be invoked, as
274  * it is used internally by #GtkTreeView.
275  **/
276 void
277 _gtk_tree_selection_set_tree_view (GtkTreeSelection *selection,
278                                    GtkTreeView      *tree_view)
279 {
280   GtkTreeSelectionPrivate *priv;
281
282   g_return_if_fail (GTK_IS_TREE_SELECTION (selection));
283   if (tree_view != NULL)
284     g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
285
286   priv = selection->priv;
287
288   priv->tree_view = tree_view;
289 }
290
291 /**
292  * gtk_tree_selection_set_mode:
293  * @selection: A #GtkTreeSelection.
294  * @type: The selection mode
295  *
296  * Sets the selection mode of the @selection.  If the previous type was
297  * #GTK_SELECTION_MULTIPLE, then the anchor is kept selected, if it was
298  * previously selected.
299  **/
300 void
301 gtk_tree_selection_set_mode (GtkTreeSelection *selection,
302                              GtkSelectionMode  type)
303 {
304   GtkTreeSelectionPrivate *priv;
305   GtkTreeSelectionFunc tmp_func;
306
307   g_return_if_fail (GTK_IS_TREE_SELECTION (selection));
308
309   priv = selection->priv;
310
311   if (priv->type == type)
312     return;
313
314   if (type == GTK_SELECTION_NONE)
315     {
316       /* We do this so that we unconditionally unset all rows
317        */
318       tmp_func = priv->user_func;
319       priv->user_func = NULL;
320       gtk_tree_selection_unselect_all (selection);
321       priv->user_func = tmp_func;
322
323       _gtk_tree_view_set_anchor_path (priv->tree_view, NULL);
324     }
325   else if (type == GTK_SELECTION_SINGLE ||
326            type == GTK_SELECTION_BROWSE)
327     {
328       GtkRBTree *tree = NULL;
329       GtkRBNode *node = NULL;
330       gint selected = FALSE;
331       GtkTreePath *anchor_path = NULL;
332
333       anchor_path = _gtk_tree_view_get_anchor_path (priv->tree_view);
334
335       if (anchor_path)
336         {
337           _gtk_tree_view_find_node (priv->tree_view,
338                                     anchor_path,
339                                     &tree,
340                                     &node);
341           
342           if (node && GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_SELECTED))
343             selected = TRUE;
344         }
345
346       /* We do this so that we unconditionally unset all rows
347        */
348       tmp_func = priv->user_func;
349       priv->user_func = NULL;
350       gtk_tree_selection_unselect_all (selection);
351       priv->user_func = tmp_func;
352
353       if (node && selected)
354         _gtk_tree_selection_internal_select_node (selection,
355                                                   node,
356                                                   tree,
357                                                   anchor_path,
358                                                   0,
359                                                   FALSE);
360       if (anchor_path)
361         gtk_tree_path_free (anchor_path);
362     }
363
364   priv->type = type;
365   
366   g_object_notify_by_pspec (G_OBJECT (selection), properties[PROP_MODE]);
367 }
368
369 /**
370  * gtk_tree_selection_get_mode:
371  * @selection: a #GtkTreeSelection
372  *
373  * Gets the selection mode for @selection. See
374  * gtk_tree_selection_set_mode().
375  *
376  * Return value: the current selection mode
377  **/
378 GtkSelectionMode
379 gtk_tree_selection_get_mode (GtkTreeSelection *selection)
380 {
381   g_return_val_if_fail (GTK_IS_TREE_SELECTION (selection), GTK_SELECTION_SINGLE);
382
383   return selection->priv->type;
384 }
385
386 /**
387  * gtk_tree_selection_set_select_function:
388  * @selection: A #GtkTreeSelection.
389  * @func: The selection function. May be %NULL
390  * @data: The selection function's data. May be %NULL
391  * @destroy: The destroy function for user data.  May be %NULL
392  *
393  * Sets the selection function.
394  *
395  * If set, this function is called before any node is selected or unselected,
396  * giving some control over which nodes are selected. The select function
397  * should return %TRUE if the state of the node may be toggled, and %FALSE
398  * if the state of the node should be left unchanged.
399  */
400 void
401 gtk_tree_selection_set_select_function (GtkTreeSelection     *selection,
402                                         GtkTreeSelectionFunc  func,
403                                         gpointer              data,
404                                         GDestroyNotify        destroy)
405 {
406   GtkTreeSelectionPrivate *priv;
407
408   g_return_if_fail (GTK_IS_TREE_SELECTION (selection));
409
410   priv = selection->priv;
411
412   if (priv->destroy)
413     priv->destroy (priv->user_data);
414
415   priv->user_func = func;
416   priv->user_data = data;
417   priv->destroy = destroy;
418 }
419
420 /**
421  * gtk_tree_selection_get_select_function: (skip)
422  * @selection: A #GtkTreeSelection.
423  *
424  * Returns the current selection function.
425  *
426  * Return value: The function.
427  *
428  * Since: 2.14
429  **/
430 GtkTreeSelectionFunc
431 gtk_tree_selection_get_select_function (GtkTreeSelection *selection)
432 {
433   g_return_val_if_fail (GTK_IS_TREE_SELECTION (selection), NULL);
434
435   return selection->priv->user_func;
436 }
437
438 /**
439  * gtk_tree_selection_get_user_data: (skip)
440  * @selection: A #GtkTreeSelection.
441  *
442  * Returns the user data for the selection function.
443  *
444  * Return value: The user data.
445  **/
446 gpointer
447 gtk_tree_selection_get_user_data (GtkTreeSelection *selection)
448 {
449   g_return_val_if_fail (GTK_IS_TREE_SELECTION (selection), NULL);
450
451   return selection->priv->user_data;
452 }
453
454 /**
455  * gtk_tree_selection_get_tree_view:
456  * @selection: A #GtkTreeSelection
457  * 
458  * Returns the tree view associated with @selection.
459  * 
460  * Return value: (transfer none): A #GtkTreeView
461  **/
462 GtkTreeView *
463 gtk_tree_selection_get_tree_view (GtkTreeSelection *selection)
464 {
465   g_return_val_if_fail (GTK_IS_TREE_SELECTION (selection), NULL);
466
467   return selection->priv->tree_view;
468 }
469
470 /**
471  * gtk_tree_selection_get_selected:
472  * @selection: A #GtkTreeSelection.
473  * @model: (out) (allow-none) (transfer none): A pointer to set to the #GtkTreeModel, or NULL.
474  * @iter: (out) (allow-none): The #GtkTreeIter, or NULL.
475  *
476  * Sets @iter to the currently selected node if @selection is set to
477  * #GTK_SELECTION_SINGLE or #GTK_SELECTION_BROWSE.  @iter may be NULL if you
478  * just want to test if @selection has any selected nodes.  @model is filled
479  * with the current model as a convenience.  This function will not work if you
480  * use @selection is #GTK_SELECTION_MULTIPLE.
481  *
482  * Return value: TRUE, if there is a selected node.
483  **/
484 gboolean
485 gtk_tree_selection_get_selected (GtkTreeSelection  *selection,
486                                  GtkTreeModel     **model,
487                                  GtkTreeIter       *iter)
488 {
489   GtkTreeSelectionPrivate *priv;
490   GtkRBTree *tree;
491   GtkRBNode *node;
492   GtkTreePath *anchor_path;
493   gboolean retval;
494   gboolean found_node;
495
496   g_return_val_if_fail (GTK_IS_TREE_SELECTION (selection), FALSE);
497
498   priv = selection->priv;
499
500   g_return_val_if_fail (priv->type != GTK_SELECTION_MULTIPLE, FALSE);
501   g_return_val_if_fail (priv->tree_view != NULL, FALSE);
502
503   /* Clear the iter */
504   if (iter)
505     memset (iter, 0, sizeof (GtkTreeIter));
506
507   if (model)
508     *model = gtk_tree_view_get_model (priv->tree_view);
509
510   anchor_path = _gtk_tree_view_get_anchor_path (priv->tree_view);
511
512   if (anchor_path == NULL)
513     return FALSE;
514
515   retval = FALSE;
516
517   found_node = !_gtk_tree_view_find_node (priv->tree_view,
518                                           anchor_path,
519                                           &tree,
520                                           &node);
521
522   if (found_node && GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_SELECTED))
523     {
524       /* we only want to return the anchor if it exists in the rbtree and
525        * is selected.
526        */
527       if (iter == NULL)
528         retval = TRUE;
529       else
530         retval = gtk_tree_model_get_iter (gtk_tree_view_get_model (priv->tree_view),
531                                           iter,
532                                           anchor_path);
533     }
534   else
535     {
536       /* We don't want to return the anchor if it isn't actually selected.
537        */
538       retval = FALSE;
539     }
540
541   gtk_tree_path_free (anchor_path);
542
543   return retval;
544 }
545
546 /**
547  * gtk_tree_selection_get_selected_rows:
548  * @selection: A #GtkTreeSelection.
549  * @model: (out) (allow-none) (transfer none): A pointer to set to the #GtkTreeModel, or %NULL.
550  *
551  * Creates a list of path of all selected rows. Additionally, if you are
552  * planning on modifying the model after calling this function, you may
553  * want to convert the returned list into a list of #GtkTreeRowReference<!-- -->s.
554  * To do this, you can use gtk_tree_row_reference_new().
555  *
556  * To free the return value, use:
557  * |[
558  * g_list_free_full (list, (GDestroyNotify) gtk_tree_path_free);
559  * ]|
560  *
561  * Return value: (element-type GtkTreePath) (transfer full): A #GList containing a #GtkTreePath for each selected row.
562  *
563  * Since: 2.2
564  **/
565 GList *
566 gtk_tree_selection_get_selected_rows (GtkTreeSelection   *selection,
567                                       GtkTreeModel      **model)
568 {
569   GtkTreeSelectionPrivate *priv;
570   GList *list = NULL;
571   GtkRBTree *tree = NULL;
572   GtkRBNode *node = NULL;
573   GtkTreePath *path;
574
575   g_return_val_if_fail (GTK_IS_TREE_SELECTION (selection), NULL);
576
577   priv = selection->priv;
578
579   g_return_val_if_fail (priv->tree_view != NULL, NULL);
580
581   if (model)
582     *model = gtk_tree_view_get_model (priv->tree_view);
583
584   tree = _gtk_tree_view_get_rbtree (priv->tree_view);
585
586   if (tree == NULL || tree->root == NULL)
587     return NULL;
588
589   if (priv->type == GTK_SELECTION_NONE)
590     return NULL;
591   else if (priv->type != GTK_SELECTION_MULTIPLE)
592     {
593       GtkTreeIter iter;
594
595       if (gtk_tree_selection_get_selected (selection, NULL, &iter))
596         {
597           GtkTreePath *path;
598
599           path = gtk_tree_model_get_path (gtk_tree_view_get_model (priv->tree_view), &iter);
600           list = g_list_append (list, path);
601
602           return list;
603         }
604
605       return NULL;
606     }
607
608   node = _gtk_rbtree_first (tree);
609   path = gtk_tree_path_new_first ();
610
611   do
612     {
613       if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_SELECTED))
614         list = g_list_prepend (list, gtk_tree_path_copy (path));
615
616       if (node->children)
617         {
618           tree = node->children;
619           node = _gtk_rbtree_first (tree);
620
621           gtk_tree_path_append_index (path, 0);
622         }
623       else
624         {
625           gboolean done = FALSE;
626
627           do
628             {
629               node = _gtk_rbtree_next (tree, node);
630               if (node != NULL)
631                 {
632                   done = TRUE;
633                   gtk_tree_path_next (path);
634                 }
635               else
636                 {
637                   node = tree->parent_node;
638                   tree = tree->parent_tree;
639
640                   if (!tree)
641                     {
642                       gtk_tree_path_free (path);
643
644                       goto done; 
645                     }
646
647                   gtk_tree_path_up (path);
648                 }
649             }
650           while (!done);
651         }
652     }
653   while (TRUE);
654
655   gtk_tree_path_free (path);
656
657  done:
658   return g_list_reverse (list);
659 }
660
661 static void
662 gtk_tree_selection_count_selected_rows_helper (GtkRBTree *tree,
663                                                GtkRBNode *node,
664                                                gpointer   data)
665 {
666   gint *count = (gint *)data;
667
668   if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_SELECTED))
669     (*count)++;
670
671   if (node->children)
672     _gtk_rbtree_traverse (node->children, node->children->root,
673                           G_PRE_ORDER,
674                           gtk_tree_selection_count_selected_rows_helper, data);
675 }
676
677 /**
678  * gtk_tree_selection_count_selected_rows:
679  * @selection: A #GtkTreeSelection.
680  *
681  * Returns the number of rows that have been selected in @tree.
682  *
683  * Return value: The number of rows selected.
684  * 
685  * Since: 2.2
686  **/
687 gint
688 gtk_tree_selection_count_selected_rows (GtkTreeSelection *selection)
689 {
690   GtkTreeSelectionPrivate *priv;
691   gint count = 0;
692   GtkRBTree *tree;
693
694   g_return_val_if_fail (GTK_IS_TREE_SELECTION (selection), 0);
695
696   priv = selection->priv;
697
698   g_return_val_if_fail (priv->tree_view != NULL, 0);
699
700   tree = _gtk_tree_view_get_rbtree (priv->tree_view);
701
702   if (tree == NULL || tree->root == NULL)
703     return 0;
704
705   if (priv->type == GTK_SELECTION_SINGLE ||
706       priv->type == GTK_SELECTION_BROWSE)
707     {
708       if (gtk_tree_selection_get_selected (selection, NULL, NULL))
709         return 1;
710       else
711         return 0;
712     }
713
714   _gtk_rbtree_traverse (tree, tree->root,
715                         G_PRE_ORDER,
716                         gtk_tree_selection_count_selected_rows_helper,
717                         &count);
718
719   return count;
720 }
721
722 /* gtk_tree_selection_selected_foreach helper */
723 static void
724 model_changed (gpointer data)
725 {
726   gboolean *stop = (gboolean *)data;
727
728   *stop = TRUE;
729 }
730
731 /**
732  * gtk_tree_selection_selected_foreach:
733  * @selection: A #GtkTreeSelection.
734  * @func: (scope call): The function to call for each selected node.
735  * @data: user data to pass to the function.
736  *
737  * Calls a function for each selected node. Note that you cannot modify
738  * the tree or selection from within this function. As a result,
739  * gtk_tree_selection_get_selected_rows() might be more useful.
740  **/
741 void
742 gtk_tree_selection_selected_foreach (GtkTreeSelection            *selection,
743                                      GtkTreeSelectionForeachFunc  func,
744                                      gpointer                     data)
745 {
746   GtkTreeSelectionPrivate *priv;
747   GtkTreePath *path;
748   GtkRBTree *tree;
749   GtkRBNode *node;
750   GtkTreeIter iter;
751   GtkTreeModel *model;
752
753   gulong inserted_id, deleted_id, reordered_id, changed_id;
754   gboolean stop = FALSE;
755
756   g_return_if_fail (GTK_IS_TREE_SELECTION (selection));
757
758   priv = selection->priv;
759
760   g_return_if_fail (priv->tree_view != NULL);
761
762   tree = _gtk_tree_view_get_rbtree (priv->tree_view);
763
764   if (func == NULL || tree == NULL || tree->root == NULL)
765     return;
766
767   model = gtk_tree_view_get_model (priv->tree_view);
768
769   if (priv->type == GTK_SELECTION_SINGLE ||
770       priv->type == GTK_SELECTION_BROWSE)
771     {
772       path = _gtk_tree_view_get_anchor_path (priv->tree_view);
773
774       if (path)
775         {
776           gtk_tree_model_get_iter (model, &iter, path);
777           (* func) (model, path, &iter, data);
778           gtk_tree_path_free (path);
779         }
780       return;
781     }
782
783   node = _gtk_rbtree_first (tree);
784
785   g_object_ref (model);
786
787   /* connect to signals to monitor changes in treemodel */
788   inserted_id = g_signal_connect_swapped (model, "row-inserted",
789                                           G_CALLBACK (model_changed),
790                                           &stop);
791   deleted_id = g_signal_connect_swapped (model, "row-deleted",
792                                          G_CALLBACK (model_changed),
793                                          &stop);
794   reordered_id = g_signal_connect_swapped (model, "rows-reordered",
795                                            G_CALLBACK (model_changed),
796                                            &stop);
797   changed_id = g_signal_connect_swapped (priv->tree_view, "notify::model",
798                                          G_CALLBACK (model_changed), 
799                                          &stop);
800
801   /* find the node internally */
802   path = gtk_tree_path_new_first ();
803
804   do
805     {
806       if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_SELECTED))
807         {
808           gtk_tree_model_get_iter (model, &iter, path);
809           (* func) (model, path, &iter, data);
810         }
811
812       if (stop)
813         goto out;
814
815       if (node->children)
816         {
817           tree = node->children;
818           node = _gtk_rbtree_first (tree);
819
820           gtk_tree_path_append_index (path, 0);
821         }
822       else
823         {
824           gboolean done = FALSE;
825
826           do
827             {
828               node = _gtk_rbtree_next (tree, node);
829               if (node != NULL)
830                 {
831                   done = TRUE;
832                   gtk_tree_path_next (path);
833                 }
834               else
835                 {
836                   node = tree->parent_node;
837                   tree = tree->parent_tree;
838
839                   if (tree == NULL)
840                     {
841                       /* we've run out of tree */
842                       /* We're done with this function */
843
844                       goto out;
845                     }
846
847                   gtk_tree_path_up (path);
848                 }
849             }
850           while (!done);
851         }
852     }
853   while (TRUE);
854
855 out:
856   if (path)
857     gtk_tree_path_free (path);
858
859   g_signal_handler_disconnect (model, inserted_id);
860   g_signal_handler_disconnect (model, deleted_id);
861   g_signal_handler_disconnect (model, reordered_id);
862   g_signal_handler_disconnect (priv->tree_view, changed_id);
863   g_object_unref (model);
864
865   /* check if we have to spew a scary message */
866   if (stop)
867     g_warning ("The model has been modified from within gtk_tree_selection_selected_foreach.\n"
868                "This function is for observing the selections of the tree only.  If\n"
869                "you are trying to get all selected items from the tree, try using\n"
870                "gtk_tree_selection_get_selected_rows instead.\n");
871 }
872
873 /**
874  * gtk_tree_selection_select_path:
875  * @selection: A #GtkTreeSelection.
876  * @path: The #GtkTreePath to be selected.
877  *
878  * Select the row at @path.
879  **/
880 void
881 gtk_tree_selection_select_path (GtkTreeSelection *selection,
882                                 GtkTreePath      *path)
883 {
884   GtkTreeSelectionPrivate *priv;
885   GtkRBNode *node;
886   GtkRBTree *tree;
887   gboolean ret;
888   GtkTreeSelectMode mode = 0;
889
890   g_return_if_fail (GTK_IS_TREE_SELECTION (selection));
891
892   priv = selection->priv;
893
894   g_return_if_fail (priv->tree_view != NULL);
895   g_return_if_fail (path != NULL);
896
897   ret = _gtk_tree_view_find_node (priv->tree_view,
898                                   path,
899                                   &tree,
900                                   &node);
901
902   if (node == NULL || GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_SELECTED) ||
903       ret == TRUE)
904     return;
905
906   if (priv->type == GTK_SELECTION_MULTIPLE)
907     mode = GTK_TREE_SELECT_MODE_TOGGLE;
908
909   _gtk_tree_selection_internal_select_node (selection,
910                                             node,
911                                             tree,
912                                             path,
913                                             mode,
914                                             FALSE);
915 }
916
917 /**
918  * gtk_tree_selection_unselect_path:
919  * @selection: A #GtkTreeSelection.
920  * @path: The #GtkTreePath to be unselected.
921  *
922  * Unselects the row at @path.
923  **/
924 void
925 gtk_tree_selection_unselect_path (GtkTreeSelection *selection,
926                                   GtkTreePath      *path)
927 {
928   GtkTreeSelectionPrivate *priv;
929   GtkRBNode *node;
930   GtkRBTree *tree;
931   gboolean ret;
932
933   g_return_if_fail (GTK_IS_TREE_SELECTION (selection));
934
935   priv = selection->priv;
936
937   g_return_if_fail (priv->tree_view != NULL);
938   g_return_if_fail (path != NULL);
939
940   ret = _gtk_tree_view_find_node (priv->tree_view,
941                                   path,
942                                   &tree,
943                                   &node);
944
945   if (node == NULL || !GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_SELECTED) ||
946       ret == TRUE)
947     return;
948
949   _gtk_tree_selection_internal_select_node (selection,
950                                             node,
951                                             tree,
952                                             path,
953                                             GTK_TREE_SELECT_MODE_TOGGLE,
954                                             TRUE);
955 }
956
957 /**
958  * gtk_tree_selection_select_iter:
959  * @selection: A #GtkTreeSelection.
960  * @iter: The #GtkTreeIter to be selected.
961  *
962  * Selects the specified iterator.
963  **/
964 void
965 gtk_tree_selection_select_iter (GtkTreeSelection *selection,
966                                 GtkTreeIter      *iter)
967 {
968   GtkTreeSelectionPrivate *priv;
969   GtkTreePath *path;
970   GtkTreeModel *model;
971
972   g_return_if_fail (GTK_IS_TREE_SELECTION (selection));
973
974   priv = selection->priv;
975
976   g_return_if_fail (priv->tree_view != NULL);
977
978   model = gtk_tree_view_get_model (priv->tree_view);
979   g_return_if_fail (model != NULL);
980   g_return_if_fail (iter != NULL);
981
982   path = gtk_tree_model_get_path (model, iter);
983
984   if (path == NULL)
985     return;
986
987   gtk_tree_selection_select_path (selection, path);
988   gtk_tree_path_free (path);
989 }
990
991
992 /**
993  * gtk_tree_selection_unselect_iter:
994  * @selection: A #GtkTreeSelection.
995  * @iter: The #GtkTreeIter to be unselected.
996  *
997  * Unselects the specified iterator.
998  **/
999 void
1000 gtk_tree_selection_unselect_iter (GtkTreeSelection *selection,
1001                                   GtkTreeIter      *iter)
1002 {
1003   GtkTreeSelectionPrivate *priv;
1004   GtkTreePath *path;
1005   GtkTreeModel *model;
1006
1007   g_return_if_fail (GTK_IS_TREE_SELECTION (selection));
1008
1009   priv = selection->priv;
1010
1011   g_return_if_fail (priv->tree_view != NULL);
1012
1013   model = gtk_tree_view_get_model (priv->tree_view);
1014   g_return_if_fail (model != NULL);
1015   g_return_if_fail (iter != NULL);
1016
1017   path = gtk_tree_model_get_path (model, iter);
1018
1019   if (path == NULL)
1020     return;
1021
1022   gtk_tree_selection_unselect_path (selection, path);
1023   gtk_tree_path_free (path);
1024 }
1025
1026 /**
1027  * gtk_tree_selection_path_is_selected:
1028  * @selection: A #GtkTreeSelection.
1029  * @path: A #GtkTreePath to check selection on.
1030  * 
1031  * Returns %TRUE if the row pointed to by @path is currently selected.  If @path
1032  * does not point to a valid location, %FALSE is returned
1033  * 
1034  * Return value: %TRUE if @path is selected.
1035  **/
1036 gboolean
1037 gtk_tree_selection_path_is_selected (GtkTreeSelection *selection,
1038                                      GtkTreePath      *path)
1039 {
1040   GtkTreeSelectionPrivate *priv;
1041   GtkRBNode *node;
1042   GtkRBTree *tree;
1043   gboolean ret;
1044
1045   g_return_val_if_fail (GTK_IS_TREE_SELECTION (selection), FALSE);
1046
1047   priv = selection->priv;
1048
1049   g_return_val_if_fail (path != NULL, FALSE);
1050   g_return_val_if_fail (priv->tree_view != NULL, FALSE);
1051
1052   if (gtk_tree_view_get_model (priv->tree_view) == NULL)
1053     return FALSE;
1054
1055   ret = _gtk_tree_view_find_node (priv->tree_view,
1056                                   path,
1057                                   &tree,
1058                                   &node);
1059
1060   if ((node == NULL) || !GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_SELECTED) ||
1061       ret == TRUE)
1062     return FALSE;
1063
1064   return TRUE;
1065 }
1066
1067 /**
1068  * gtk_tree_selection_iter_is_selected:
1069  * @selection: A #GtkTreeSelection
1070  * @iter: A valid #GtkTreeIter
1071  * 
1072  * Returns %TRUE if the row at @iter is currently selected.
1073  * 
1074  * Return value: %TRUE, if @iter is selected
1075  **/
1076 gboolean
1077 gtk_tree_selection_iter_is_selected (GtkTreeSelection *selection,
1078                                      GtkTreeIter      *iter)
1079 {
1080   GtkTreeSelectionPrivate *priv;
1081   GtkTreePath *path;
1082   GtkTreeModel *model;
1083   gboolean retval;
1084
1085   g_return_val_if_fail (GTK_IS_TREE_SELECTION (selection), FALSE);
1086
1087   priv = selection->priv;
1088
1089   g_return_val_if_fail (iter != NULL, FALSE);
1090   g_return_val_if_fail (priv->tree_view != NULL, FALSE);
1091
1092   model = gtk_tree_view_get_model (priv->tree_view);
1093   g_return_val_if_fail (model != NULL, FALSE);
1094
1095   path = gtk_tree_model_get_path (model, iter);
1096   if (path == NULL)
1097     return FALSE;
1098
1099   retval = gtk_tree_selection_path_is_selected (selection, path);
1100   gtk_tree_path_free (path);
1101
1102   return retval;
1103 }
1104
1105
1106 /* Wish I was in python, right now... */
1107 struct _TempTuple {
1108   GtkTreeSelection *selection;
1109   gint dirty;
1110 };
1111
1112 static void
1113 select_all_helper (GtkRBTree  *tree,
1114                    GtkRBNode  *node,
1115                    gpointer    data)
1116 {
1117   struct _TempTuple *tuple = data;
1118
1119   if (node->children)
1120     _gtk_rbtree_traverse (node->children,
1121                           node->children->root,
1122                           G_PRE_ORDER,
1123                           select_all_helper,
1124                           data);
1125   if (!GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_SELECTED))
1126     {
1127       tuple->dirty = gtk_tree_selection_real_select_node (tuple->selection, tree, node, TRUE) || tuple->dirty;
1128     }
1129 }
1130
1131
1132 /* We have a real_{un,}select_all function that doesn't emit the signal, so we
1133  * can use it in other places without fear of the signal being emitted.
1134  */
1135 static gint
1136 gtk_tree_selection_real_select_all (GtkTreeSelection *selection)
1137 {
1138   GtkTreeSelectionPrivate *priv = selection->priv;
1139   struct _TempTuple *tuple;
1140   GtkRBTree *tree;
1141
1142   tree = _gtk_tree_view_get_rbtree (priv->tree_view);
1143
1144   if (tree == NULL)
1145     return FALSE;
1146
1147   /* Mark all nodes selected */
1148   tuple = g_new (struct _TempTuple, 1);
1149   tuple->selection = selection;
1150   tuple->dirty = FALSE;
1151
1152   _gtk_rbtree_traverse (tree, tree->root,
1153                         G_PRE_ORDER,
1154                         select_all_helper,
1155                         tuple);
1156   if (tuple->dirty)
1157     {
1158       g_free (tuple);
1159       return TRUE;
1160     }
1161   g_free (tuple);
1162   return FALSE;
1163 }
1164
1165 /**
1166  * gtk_tree_selection_select_all:
1167  * @selection: A #GtkTreeSelection.
1168  *
1169  * Selects all the nodes. @selection must be set to #GTK_SELECTION_MULTIPLE
1170  * mode.
1171  **/
1172 void
1173 gtk_tree_selection_select_all (GtkTreeSelection *selection)
1174 {
1175   GtkTreeSelectionPrivate *priv;
1176
1177   g_return_if_fail (GTK_IS_TREE_SELECTION (selection));
1178
1179   priv = selection->priv;
1180
1181   g_return_if_fail (priv->tree_view != NULL);
1182
1183   if (_gtk_tree_view_get_rbtree (priv->tree_view) == NULL ||
1184       gtk_tree_view_get_model (priv->tree_view) == NULL)
1185     return;
1186
1187   g_return_if_fail (priv->type == GTK_SELECTION_MULTIPLE);
1188
1189   if (gtk_tree_selection_real_select_all (selection))
1190     g_signal_emit (selection, tree_selection_signals[CHANGED], 0);
1191 }
1192
1193 static void
1194 unselect_all_helper (GtkRBTree  *tree,
1195                      GtkRBNode  *node,
1196                      gpointer    data)
1197 {
1198   struct _TempTuple *tuple = data;
1199
1200   if (node->children)
1201     _gtk_rbtree_traverse (node->children,
1202                           node->children->root,
1203                           G_PRE_ORDER,
1204                           unselect_all_helper,
1205                           data);
1206   if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_SELECTED))
1207     {
1208       tuple->dirty = gtk_tree_selection_real_select_node (tuple->selection, tree, node, FALSE) || tuple->dirty;
1209     }
1210 }
1211
1212 static gboolean
1213 gtk_tree_selection_real_unselect_all (GtkTreeSelection *selection)
1214 {
1215   GtkTreeSelectionPrivate *priv = selection->priv;
1216   struct _TempTuple *tuple;
1217
1218   if (priv->type == GTK_SELECTION_SINGLE ||
1219       priv->type == GTK_SELECTION_BROWSE)
1220     {
1221       GtkRBTree *tree = NULL;
1222       GtkRBNode *node = NULL;
1223       GtkTreePath *anchor_path;
1224
1225       anchor_path = _gtk_tree_view_get_anchor_path (priv->tree_view);
1226
1227       if (anchor_path == NULL)
1228         return FALSE;
1229
1230       _gtk_tree_view_find_node (priv->tree_view,
1231                                 anchor_path,
1232                                 &tree,
1233                                 &node);
1234
1235       gtk_tree_path_free (anchor_path);
1236
1237       if (tree == NULL)
1238         return FALSE;
1239
1240       if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_SELECTED))
1241         {
1242           if (gtk_tree_selection_real_select_node (selection, tree, node, FALSE))
1243             {
1244               _gtk_tree_view_set_anchor_path (priv->tree_view, NULL);
1245               return TRUE;
1246             }
1247         }
1248       return FALSE;
1249     }
1250   else
1251     {
1252       GtkRBTree *tree;
1253
1254       tuple = g_new (struct _TempTuple, 1);
1255       tuple->selection = selection;
1256       tuple->dirty = FALSE;
1257
1258       tree = _gtk_tree_view_get_rbtree (priv->tree_view);
1259       _gtk_rbtree_traverse (tree, tree->root,
1260                             G_PRE_ORDER,
1261                             unselect_all_helper,
1262                             tuple);
1263
1264       if (tuple->dirty)
1265         {
1266           g_free (tuple);
1267           return TRUE;
1268         }
1269       g_free (tuple);
1270       return FALSE;
1271     }
1272 }
1273
1274 /**
1275  * gtk_tree_selection_unselect_all:
1276  * @selection: A #GtkTreeSelection.
1277  *
1278  * Unselects all the nodes.
1279  **/
1280 void
1281 gtk_tree_selection_unselect_all (GtkTreeSelection *selection)
1282 {
1283   GtkTreeSelectionPrivate *priv;
1284
1285   g_return_if_fail (GTK_IS_TREE_SELECTION (selection));
1286
1287   priv = selection->priv;
1288
1289   g_return_if_fail (priv->tree_view != NULL);
1290
1291   if (_gtk_tree_view_get_rbtree (priv->tree_view) == NULL ||
1292       gtk_tree_view_get_model (priv->tree_view) == NULL)
1293     return;
1294   
1295   if (gtk_tree_selection_real_unselect_all (selection))
1296     g_signal_emit (selection, tree_selection_signals[CHANGED], 0);
1297 }
1298
1299 enum
1300 {
1301   RANGE_SELECT,
1302   RANGE_UNSELECT
1303 };
1304
1305 static gint
1306 gtk_tree_selection_real_modify_range (GtkTreeSelection *selection,
1307                                       gint              mode,
1308                                       GtkTreePath      *start_path,
1309                                       GtkTreePath      *end_path)
1310 {
1311   GtkTreeSelectionPrivate *priv = selection->priv;
1312   GtkRBNode *start_node, *end_node;
1313   GtkRBTree *start_tree, *end_tree;
1314   GtkTreePath *anchor_path = NULL;
1315   gboolean dirty = FALSE;
1316
1317   switch (gtk_tree_path_compare (start_path, end_path))
1318     {
1319     case 1:
1320       _gtk_tree_view_find_node (priv->tree_view,
1321                                 end_path,
1322                                 &start_tree,
1323                                 &start_node);
1324       _gtk_tree_view_find_node (priv->tree_view,
1325                                 start_path,
1326                                 &end_tree,
1327                                 &end_node);
1328       anchor_path = start_path;
1329       break;
1330     case 0:
1331       _gtk_tree_view_find_node (priv->tree_view,
1332                                 start_path,
1333                                 &start_tree,
1334                                 &start_node);
1335       end_tree = start_tree;
1336       end_node = start_node;
1337       anchor_path = start_path;
1338       break;
1339     case -1:
1340       _gtk_tree_view_find_node (priv->tree_view,
1341                                 start_path,
1342                                 &start_tree,
1343                                 &start_node);
1344       _gtk_tree_view_find_node (priv->tree_view,
1345                                 end_path,
1346                                 &end_tree,
1347                                 &end_node);
1348       anchor_path = start_path;
1349       break;
1350     }
1351
1352   g_return_val_if_fail (start_node != NULL, FALSE);
1353   g_return_val_if_fail (end_node != NULL, FALSE);
1354
1355   if (anchor_path)
1356     _gtk_tree_view_set_anchor_path (priv->tree_view, anchor_path);
1357
1358   do
1359     {
1360       dirty |= gtk_tree_selection_real_select_node (selection, start_tree, start_node, (mode == RANGE_SELECT)?TRUE:FALSE);
1361
1362       if (start_node == end_node)
1363         break;
1364
1365       if (start_node->children)
1366         {
1367           start_tree = start_node->children;
1368           start_node = _gtk_rbtree_first (start_tree);
1369         }
1370       else
1371         {
1372           _gtk_rbtree_next_full (start_tree, start_node, &start_tree, &start_node);
1373           if (start_tree == NULL)
1374             {
1375               /* we just ran out of tree.  That means someone passed in bogus values.
1376                */
1377               return dirty;
1378             }
1379         }
1380     }
1381   while (TRUE);
1382
1383   return dirty;
1384 }
1385
1386 /**
1387  * gtk_tree_selection_select_range:
1388  * @selection: A #GtkTreeSelection.
1389  * @start_path: The initial node of the range.
1390  * @end_path: The final node of the range.
1391  *
1392  * Selects a range of nodes, determined by @start_path and @end_path inclusive.
1393  * @selection must be set to #GTK_SELECTION_MULTIPLE mode. 
1394  **/
1395 void
1396 gtk_tree_selection_select_range (GtkTreeSelection *selection,
1397                                  GtkTreePath      *start_path,
1398                                  GtkTreePath      *end_path)
1399 {
1400   GtkTreeSelectionPrivate *priv;
1401
1402   g_return_if_fail (GTK_IS_TREE_SELECTION (selection));
1403
1404   priv = selection->priv;
1405
1406   g_return_if_fail (priv->tree_view != NULL);
1407   g_return_if_fail (priv->type == GTK_SELECTION_MULTIPLE);
1408   g_return_if_fail (gtk_tree_view_get_model (priv->tree_view) != NULL);
1409
1410   if (gtk_tree_selection_real_modify_range (selection, RANGE_SELECT, start_path, end_path))
1411     g_signal_emit (selection, tree_selection_signals[CHANGED], 0);
1412 }
1413
1414 /**
1415  * gtk_tree_selection_unselect_range:
1416  * @selection: A #GtkTreeSelection.
1417  * @start_path: The initial node of the range.
1418  * @end_path: The initial node of the range.
1419  *
1420  * Unselects a range of nodes, determined by @start_path and @end_path
1421  * inclusive.
1422  *
1423  * Since: 2.2
1424  **/
1425 void
1426 gtk_tree_selection_unselect_range (GtkTreeSelection *selection,
1427                                    GtkTreePath      *start_path,
1428                                    GtkTreePath      *end_path)
1429 {
1430   GtkTreeSelectionPrivate *priv;
1431
1432   g_return_if_fail (GTK_IS_TREE_SELECTION (selection));
1433
1434   priv = selection->priv;
1435
1436   g_return_if_fail (priv->tree_view != NULL);
1437   g_return_if_fail (gtk_tree_view_get_model (priv->tree_view) != NULL);
1438
1439   if (gtk_tree_selection_real_modify_range (selection, RANGE_UNSELECT, start_path, end_path))
1440     g_signal_emit (selection, tree_selection_signals[CHANGED], 0);
1441 }
1442
1443 gboolean
1444 _gtk_tree_selection_row_is_selectable (GtkTreeSelection *selection,
1445                                        GtkRBNode        *node,
1446                                        GtkTreePath      *path)
1447 {
1448   GtkTreeSelectionPrivate *priv = selection->priv;
1449   GtkTreeIter iter;
1450   GtkTreeModel *model;
1451   GtkTreeViewRowSeparatorFunc separator_func;
1452   gpointer separator_data;
1453   gboolean sensitive = FALSE;
1454
1455   model = gtk_tree_view_get_model (priv->tree_view);
1456
1457   _gtk_tree_view_get_row_separator_func (priv->tree_view,
1458                                          &separator_func, &separator_data);
1459
1460   if (!gtk_tree_model_get_iter (model, &iter, path))
1461     sensitive = TRUE;
1462
1463   if (!sensitive && separator_func)
1464     {
1465       /* never allow separators to be selected */
1466       if ((* separator_func) (model, &iter, separator_data))
1467         return FALSE;
1468     }
1469
1470   if (priv->user_func)
1471     return (*priv->user_func) (selection, model, path,
1472                                     GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_SELECTED),
1473                                     priv->user_data);
1474   else
1475     return TRUE;
1476 }
1477
1478
1479 /* Called internally by gtktreeview.c It handles actually selecting the tree.
1480  */
1481
1482 /*
1483  * docs about the 'override_browse_mode', we set this flag when we want to
1484  * unset select the node and override the select browse mode behaviour (that is
1485  * 'one node should *always* be selected').
1486  */
1487 void
1488 _gtk_tree_selection_internal_select_node (GtkTreeSelection *selection,
1489                                           GtkRBNode        *node,
1490                                           GtkRBTree        *tree,
1491                                           GtkTreePath      *path,
1492                                           GtkTreeSelectMode mode,
1493                                           gboolean          override_browse_mode)
1494 {
1495   GtkTreeSelectionPrivate *priv = selection->priv;
1496   gint flags;
1497   gint dirty = FALSE;
1498   GtkTreePath *anchor_path = NULL;
1499
1500   if (priv->type == GTK_SELECTION_NONE)
1501     return;
1502
1503   anchor_path = _gtk_tree_view_get_anchor_path (priv->tree_view);
1504
1505   if (priv->type == GTK_SELECTION_SINGLE ||
1506       priv->type == GTK_SELECTION_BROWSE)
1507     {
1508       /* just unselect */
1509       if (priv->type == GTK_SELECTION_BROWSE && override_browse_mode)
1510         {
1511           dirty = gtk_tree_selection_real_unselect_all (selection);
1512         }
1513       /* Did we try to select the same node again? */
1514       else if (priv->type == GTK_SELECTION_SINGLE &&
1515                anchor_path && gtk_tree_path_compare (path, anchor_path) == 0)
1516         {
1517           if ((mode & GTK_TREE_SELECT_MODE_TOGGLE) == GTK_TREE_SELECT_MODE_TOGGLE)
1518             {
1519               dirty = gtk_tree_selection_real_unselect_all (selection);
1520             }
1521         }
1522       else
1523         {
1524           if (anchor_path)
1525             {
1526               /* We only want to select the new node if we can unselect the old one,
1527                * and we can select the new one. */
1528               dirty = _gtk_tree_selection_row_is_selectable (selection, node, path);
1529
1530               /* if dirty is FALSE, we weren't able to select the new one, otherwise, we try to
1531                * unselect the new one
1532                */
1533               if (dirty)
1534                 dirty = gtk_tree_selection_real_unselect_all (selection);
1535
1536               /* if dirty is TRUE at this point, we successfully unselected the
1537                * old one, and can then select the new one */
1538               if (dirty)
1539                 {
1540
1541                   _gtk_tree_view_set_anchor_path (priv->tree_view, NULL);
1542
1543                   if (gtk_tree_selection_real_select_node (selection, tree, node, TRUE))
1544                     _gtk_tree_view_set_anchor_path (priv->tree_view, path);
1545                 }
1546             }
1547           else
1548             {
1549               if (gtk_tree_selection_real_select_node (selection, tree, node, TRUE))
1550                 {
1551                   dirty = TRUE;
1552
1553                   _gtk_tree_view_set_anchor_path (priv->tree_view, path);
1554                 }
1555             }
1556         }
1557     }
1558   else if (priv->type == GTK_SELECTION_MULTIPLE)
1559     {
1560       if ((mode & GTK_TREE_SELECT_MODE_EXTEND) == GTK_TREE_SELECT_MODE_EXTEND
1561           && (anchor_path == NULL))
1562         {
1563           _gtk_tree_view_set_anchor_path (priv->tree_view, path);
1564
1565           dirty = gtk_tree_selection_real_select_node (selection, tree, node, TRUE);
1566         }
1567       else if ((mode & (GTK_TREE_SELECT_MODE_EXTEND | GTK_TREE_SELECT_MODE_TOGGLE)) == (GTK_TREE_SELECT_MODE_EXTEND | GTK_TREE_SELECT_MODE_TOGGLE))
1568         {
1569           gtk_tree_selection_select_range (selection,
1570                                            anchor_path,
1571                                            path);
1572         }
1573       else if ((mode & GTK_TREE_SELECT_MODE_TOGGLE) == GTK_TREE_SELECT_MODE_TOGGLE)
1574         {
1575           flags = node->flags;
1576
1577           _gtk_tree_view_set_anchor_path (priv->tree_view, path);
1578
1579           if ((flags & GTK_RBNODE_IS_SELECTED) == GTK_RBNODE_IS_SELECTED)
1580             dirty |= gtk_tree_selection_real_select_node (selection, tree, node, FALSE);
1581           else
1582             dirty |= gtk_tree_selection_real_select_node (selection, tree, node, TRUE);
1583         }
1584       else if ((mode & GTK_TREE_SELECT_MODE_EXTEND) == GTK_TREE_SELECT_MODE_EXTEND)
1585         {
1586           dirty = gtk_tree_selection_real_unselect_all (selection);
1587           dirty |= gtk_tree_selection_real_modify_range (selection,
1588                                                          RANGE_SELECT,
1589                                                          anchor_path,
1590                                                          path);
1591         }
1592       else
1593         {
1594           dirty = gtk_tree_selection_real_unselect_all (selection);
1595
1596           _gtk_tree_view_set_anchor_path (priv->tree_view, path);
1597
1598           dirty |= gtk_tree_selection_real_select_node (selection, tree, node, TRUE);
1599         }
1600     }
1601
1602   if (anchor_path)
1603     gtk_tree_path_free (anchor_path);
1604
1605   if (dirty)
1606     g_signal_emit (selection, tree_selection_signals[CHANGED], 0);  
1607 }
1608
1609
1610 void 
1611 _gtk_tree_selection_emit_changed (GtkTreeSelection *selection)
1612 {
1613   g_signal_emit (selection, tree_selection_signals[CHANGED], 0);  
1614 }
1615
1616 /* NOTE: Any {un,}selection ever done _MUST_ be done through this function!
1617  */
1618
1619 static gint
1620 gtk_tree_selection_real_select_node (GtkTreeSelection *selection,
1621                                      GtkRBTree        *tree,
1622                                      GtkRBNode        *node,
1623                                      gboolean          select)
1624 {
1625   GtkTreeSelectionPrivate *priv = selection->priv;
1626   gboolean toggle = FALSE;
1627   GtkTreePath *path = NULL;
1628
1629   select = !! select;
1630
1631   if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_SELECTED) != select)
1632     {
1633       path = _gtk_tree_path_new_from_rbtree (tree, node);
1634       toggle = _gtk_tree_selection_row_is_selectable (selection, node, path);
1635       gtk_tree_path_free (path);
1636     }
1637
1638   if (toggle)
1639     {
1640       if (!GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_SELECTED))
1641         {
1642           GTK_RBNODE_SET_FLAG (node, GTK_RBNODE_IS_SELECTED);
1643           _gtk_tree_view_accessible_add_state (priv->tree_view, tree, node, GTK_CELL_RENDERER_SELECTED);
1644         }
1645       else
1646         {
1647           GTK_RBNODE_UNSET_FLAG (node, GTK_RBNODE_IS_SELECTED);
1648           _gtk_tree_view_accessible_remove_state (priv->tree_view, tree, node, GTK_CELL_RENDERER_SELECTED);
1649         }
1650
1651       _gtk_tree_view_queue_draw_node (priv->tree_view, tree, node, NULL);
1652
1653       return TRUE;
1654     }
1655
1656   return FALSE;
1657 }