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