]> Pileus Git - ~andy/gtk/blob - gtk/gtktreeselection.c
Merge branch 'gdk-backend-wayland'
[~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_foreach (list, (GFunc) gtk_tree_path_free, NULL);
558  * g_list_free (list);
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 = tree->root;
609
610   while (node->left != tree->nil)
611     node = node->left;
612   path = gtk_tree_path_new_first ();
613
614   do
615     {
616       if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_SELECTED))
617         list = g_list_prepend (list, gtk_tree_path_copy (path));
618
619       if (node->children)
620         {
621           tree = node->children;
622           node = tree->root;
623
624           while (node->left != tree->nil)
625             node = node->left;
626
627           gtk_tree_path_append_index (path, 0);
628         }
629       else
630         {
631           gboolean done = FALSE;
632
633           do
634             {
635               node = _gtk_rbtree_next (tree, node);
636               if (node != NULL)
637                 {
638                   done = TRUE;
639                   gtk_tree_path_next (path);
640                 }
641               else
642                 {
643                   node = tree->parent_node;
644                   tree = tree->parent_tree;
645
646                   if (!tree)
647                     {
648                       gtk_tree_path_free (path);
649
650                       goto done; 
651                     }
652
653                   gtk_tree_path_up (path);
654                 }
655             }
656           while (!done);
657         }
658     }
659   while (TRUE);
660
661   gtk_tree_path_free (path);
662
663  done:
664   return g_list_reverse (list);
665 }
666
667 static void
668 gtk_tree_selection_count_selected_rows_helper (GtkRBTree *tree,
669                                                GtkRBNode *node,
670                                                gpointer   data)
671 {
672   gint *count = (gint *)data;
673
674   if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_SELECTED))
675     (*count)++;
676
677   if (node->children)
678     _gtk_rbtree_traverse (node->children, node->children->root,
679                           G_PRE_ORDER,
680                           gtk_tree_selection_count_selected_rows_helper, data);
681 }
682
683 /**
684  * gtk_tree_selection_count_selected_rows:
685  * @selection: A #GtkTreeSelection.
686  *
687  * Returns the number of rows that have been selected in @tree.
688  *
689  * Return value: The number of rows selected.
690  * 
691  * Since: 2.2
692  **/
693 gint
694 gtk_tree_selection_count_selected_rows (GtkTreeSelection *selection)
695 {
696   GtkTreeSelectionPrivate *priv;
697   gint count = 0;
698   GtkRBTree *tree;
699
700   g_return_val_if_fail (GTK_IS_TREE_SELECTION (selection), 0);
701
702   priv = selection->priv;
703
704   g_return_val_if_fail (priv->tree_view != NULL, 0);
705
706   tree = _gtk_tree_view_get_rbtree (priv->tree_view);
707
708   if (tree == NULL || tree->root == NULL)
709     return 0;
710
711   if (priv->type == GTK_SELECTION_SINGLE ||
712       priv->type == GTK_SELECTION_BROWSE)
713     {
714       if (gtk_tree_selection_get_selected (selection, NULL, NULL))
715         return 1;
716       else
717         return 0;
718     }
719
720   _gtk_rbtree_traverse (tree, tree->root,
721                         G_PRE_ORDER,
722                         gtk_tree_selection_count_selected_rows_helper,
723                         &count);
724
725   return count;
726 }
727
728 /* gtk_tree_selection_selected_foreach helper */
729 static void
730 model_changed (gpointer data)
731 {
732   gboolean *stop = (gboolean *)data;
733
734   *stop = TRUE;
735 }
736
737 /**
738  * gtk_tree_selection_selected_foreach:
739  * @selection: A #GtkTreeSelection.
740  * @func: (scope call): The function to call for each selected node.
741  * @data: user data to pass to the function.
742  *
743  * Calls a function for each selected node. Note that you cannot modify
744  * the tree or selection from within this function. As a result,
745  * gtk_tree_selection_get_selected_rows() might be more useful.
746  **/
747 void
748 gtk_tree_selection_selected_foreach (GtkTreeSelection            *selection,
749                                      GtkTreeSelectionForeachFunc  func,
750                                      gpointer                     data)
751 {
752   GtkTreeSelectionPrivate *priv;
753   GtkTreePath *path;
754   GtkRBTree *tree;
755   GtkRBNode *node;
756   GtkTreeIter iter;
757   GtkTreeModel *model;
758
759   gulong inserted_id, deleted_id, reordered_id, changed_id;
760   gboolean stop = FALSE;
761
762   g_return_if_fail (GTK_IS_TREE_SELECTION (selection));
763
764   priv = selection->priv;
765
766   g_return_if_fail (priv->tree_view != NULL);
767
768   tree = _gtk_tree_view_get_rbtree (priv->tree_view);
769
770   if (func == NULL || tree == NULL || tree->root == NULL)
771     return;
772
773   model = gtk_tree_view_get_model (priv->tree_view);
774
775   if (priv->type == GTK_SELECTION_SINGLE ||
776       priv->type == GTK_SELECTION_BROWSE)
777     {
778       path = _gtk_tree_view_get_anchor_path (priv->tree_view);
779
780       if (path)
781         {
782           gtk_tree_model_get_iter (model, &iter, path);
783           (* func) (model, path, &iter, data);
784           gtk_tree_path_free (path);
785         }
786       return;
787     }
788
789   node = tree->root;
790   
791   while (node->left != tree->nil)
792     node = node->left;
793
794   g_object_ref (model);
795
796   /* connect to signals to monitor changes in treemodel */
797   inserted_id = g_signal_connect_swapped (model, "row-inserted",
798                                           G_CALLBACK (model_changed),
799                                           &stop);
800   deleted_id = g_signal_connect_swapped (model, "row-deleted",
801                                          G_CALLBACK (model_changed),
802                                          &stop);
803   reordered_id = g_signal_connect_swapped (model, "rows-reordered",
804                                            G_CALLBACK (model_changed),
805                                            &stop);
806   changed_id = g_signal_connect_swapped (priv->tree_view, "notify::model",
807                                          G_CALLBACK (model_changed), 
808                                          &stop);
809
810   /* find the node internally */
811   path = gtk_tree_path_new_first ();
812
813   do
814     {
815       if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_SELECTED))
816         {
817           gtk_tree_model_get_iter (model, &iter, path);
818           (* func) (model, path, &iter, data);
819         }
820
821       if (stop)
822         goto out;
823
824       if (node->children)
825         {
826           tree = node->children;
827           node = tree->root;
828
829           while (node->left != tree->nil)
830             node = node->left;
831
832           gtk_tree_path_append_index (path, 0);
833         }
834       else
835         {
836           gboolean done = FALSE;
837
838           do
839             {
840               node = _gtk_rbtree_next (tree, node);
841               if (node != NULL)
842                 {
843                   done = TRUE;
844                   gtk_tree_path_next (path);
845                 }
846               else
847                 {
848                   node = tree->parent_node;
849                   tree = tree->parent_tree;
850
851                   if (tree == NULL)
852                     {
853                       /* we've run out of tree */
854                       /* We're done with this function */
855
856                       goto out;
857                     }
858
859                   gtk_tree_path_up (path);
860                 }
861             }
862           while (!done);
863         }
864     }
865   while (TRUE);
866
867 out:
868   if (path)
869     gtk_tree_path_free (path);
870
871   g_signal_handler_disconnect (model, inserted_id);
872   g_signal_handler_disconnect (model, deleted_id);
873   g_signal_handler_disconnect (model, reordered_id);
874   g_signal_handler_disconnect (priv->tree_view, changed_id);
875   g_object_unref (model);
876
877   /* check if we have to spew a scary message */
878   if (stop)
879     g_warning ("The model has been modified from within gtk_tree_selection_selected_foreach.\n"
880                "This function is for observing the selections of the tree only.  If\n"
881                "you are trying to get all selected items from the tree, try using\n"
882                "gtk_tree_selection_get_selected_rows instead.\n");
883 }
884
885 /**
886  * gtk_tree_selection_select_path:
887  * @selection: A #GtkTreeSelection.
888  * @path: The #GtkTreePath to be selected.
889  *
890  * Select the row at @path.
891  **/
892 void
893 gtk_tree_selection_select_path (GtkTreeSelection *selection,
894                                 GtkTreePath      *path)
895 {
896   GtkTreeSelectionPrivate *priv;
897   GtkRBNode *node;
898   GtkRBTree *tree;
899   gboolean ret;
900   GtkTreeSelectMode mode = 0;
901
902   g_return_if_fail (GTK_IS_TREE_SELECTION (selection));
903
904   priv = selection->priv;
905
906   g_return_if_fail (priv->tree_view != NULL);
907   g_return_if_fail (path != NULL);
908
909   ret = _gtk_tree_view_find_node (priv->tree_view,
910                                   path,
911                                   &tree,
912                                   &node);
913
914   if (node == NULL || GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_SELECTED) ||
915       ret == TRUE)
916     return;
917
918   if (priv->type == GTK_SELECTION_MULTIPLE)
919     mode = GTK_TREE_SELECT_MODE_TOGGLE;
920
921   _gtk_tree_selection_internal_select_node (selection,
922                                             node,
923                                             tree,
924                                             path,
925                                             mode,
926                                             FALSE);
927 }
928
929 /**
930  * gtk_tree_selection_unselect_path:
931  * @selection: A #GtkTreeSelection.
932  * @path: The #GtkTreePath to be unselected.
933  *
934  * Unselects the row at @path.
935  **/
936 void
937 gtk_tree_selection_unselect_path (GtkTreeSelection *selection,
938                                   GtkTreePath      *path)
939 {
940   GtkTreeSelectionPrivate *priv;
941   GtkRBNode *node;
942   GtkRBTree *tree;
943   gboolean ret;
944
945   g_return_if_fail (GTK_IS_TREE_SELECTION (selection));
946
947   priv = selection->priv;
948
949   g_return_if_fail (priv->tree_view != NULL);
950   g_return_if_fail (path != NULL);
951
952   ret = _gtk_tree_view_find_node (priv->tree_view,
953                                   path,
954                                   &tree,
955                                   &node);
956
957   if (node == NULL || !GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_SELECTED) ||
958       ret == TRUE)
959     return;
960
961   _gtk_tree_selection_internal_select_node (selection,
962                                             node,
963                                             tree,
964                                             path,
965                                             GTK_TREE_SELECT_MODE_TOGGLE,
966                                             TRUE);
967 }
968
969 /**
970  * gtk_tree_selection_select_iter:
971  * @selection: A #GtkTreeSelection.
972  * @iter: The #GtkTreeIter to be selected.
973  *
974  * Selects the specified iterator.
975  **/
976 void
977 gtk_tree_selection_select_iter (GtkTreeSelection *selection,
978                                 GtkTreeIter      *iter)
979 {
980   GtkTreeSelectionPrivate *priv;
981   GtkTreePath *path;
982   GtkTreeModel *model;
983
984   g_return_if_fail (GTK_IS_TREE_SELECTION (selection));
985
986   priv = selection->priv;
987
988   g_return_if_fail (priv->tree_view != NULL);
989
990   model = gtk_tree_view_get_model (priv->tree_view);
991   g_return_if_fail (model != NULL);
992   g_return_if_fail (iter != NULL);
993
994   path = gtk_tree_model_get_path (model, iter);
995
996   if (path == NULL)
997     return;
998
999   gtk_tree_selection_select_path (selection, path);
1000   gtk_tree_path_free (path);
1001 }
1002
1003
1004 /**
1005  * gtk_tree_selection_unselect_iter:
1006  * @selection: A #GtkTreeSelection.
1007  * @iter: The #GtkTreeIter to be unselected.
1008  *
1009  * Unselects the specified iterator.
1010  **/
1011 void
1012 gtk_tree_selection_unselect_iter (GtkTreeSelection *selection,
1013                                   GtkTreeIter      *iter)
1014 {
1015   GtkTreeSelectionPrivate *priv;
1016   GtkTreePath *path;
1017   GtkTreeModel *model;
1018
1019   g_return_if_fail (GTK_IS_TREE_SELECTION (selection));
1020
1021   priv = selection->priv;
1022
1023   g_return_if_fail (priv->tree_view != NULL);
1024
1025   model = gtk_tree_view_get_model (priv->tree_view);
1026   g_return_if_fail (model != NULL);
1027   g_return_if_fail (iter != NULL);
1028
1029   path = gtk_tree_model_get_path (model, iter);
1030
1031   if (path == NULL)
1032     return;
1033
1034   gtk_tree_selection_unselect_path (selection, path);
1035   gtk_tree_path_free (path);
1036 }
1037
1038 /**
1039  * gtk_tree_selection_path_is_selected:
1040  * @selection: A #GtkTreeSelection.
1041  * @path: A #GtkTreePath to check selection on.
1042  * 
1043  * Returns %TRUE if the row pointed to by @path is currently selected.  If @path
1044  * does not point to a valid location, %FALSE is returned
1045  * 
1046  * Return value: %TRUE if @path is selected.
1047  **/
1048 gboolean
1049 gtk_tree_selection_path_is_selected (GtkTreeSelection *selection,
1050                                      GtkTreePath      *path)
1051 {
1052   GtkTreeSelectionPrivate *priv;
1053   GtkRBNode *node;
1054   GtkRBTree *tree;
1055   gboolean ret;
1056
1057   g_return_val_if_fail (GTK_IS_TREE_SELECTION (selection), FALSE);
1058
1059   priv = selection->priv;
1060
1061   g_return_val_if_fail (path != NULL, FALSE);
1062   g_return_val_if_fail (priv->tree_view != NULL, FALSE);
1063
1064   if (gtk_tree_view_get_model (priv->tree_view) == NULL)
1065     return FALSE;
1066
1067   ret = _gtk_tree_view_find_node (priv->tree_view,
1068                                   path,
1069                                   &tree,
1070                                   &node);
1071
1072   if ((node == NULL) || !GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_SELECTED) ||
1073       ret == TRUE)
1074     return FALSE;
1075
1076   return TRUE;
1077 }
1078
1079 /**
1080  * gtk_tree_selection_iter_is_selected:
1081  * @selection: A #GtkTreeSelection
1082  * @iter: A valid #GtkTreeIter
1083  * 
1084  * Returns %TRUE if the row at @iter is currently selected.
1085  * 
1086  * Return value: %TRUE, if @iter is selected
1087  **/
1088 gboolean
1089 gtk_tree_selection_iter_is_selected (GtkTreeSelection *selection,
1090                                      GtkTreeIter      *iter)
1091 {
1092   GtkTreeSelectionPrivate *priv;
1093   GtkTreePath *path;
1094   GtkTreeModel *model;
1095   gboolean retval;
1096
1097   g_return_val_if_fail (GTK_IS_TREE_SELECTION (selection), FALSE);
1098
1099   priv = selection->priv;
1100
1101   g_return_val_if_fail (iter != NULL, FALSE);
1102   g_return_val_if_fail (priv->tree_view != NULL, FALSE);
1103
1104   model = gtk_tree_view_get_model (priv->tree_view);
1105   g_return_val_if_fail (model != NULL, FALSE);
1106
1107   path = gtk_tree_model_get_path (model, iter);
1108   if (path == NULL)
1109     return FALSE;
1110
1111   retval = gtk_tree_selection_path_is_selected (selection, path);
1112   gtk_tree_path_free (path);
1113
1114   return retval;
1115 }
1116
1117
1118 /* Wish I was in python, right now... */
1119 struct _TempTuple {
1120   GtkTreeSelection *selection;
1121   gint dirty;
1122 };
1123
1124 static void
1125 select_all_helper (GtkRBTree  *tree,
1126                    GtkRBNode  *node,
1127                    gpointer    data)
1128 {
1129   struct _TempTuple *tuple = data;
1130
1131   if (node->children)
1132     _gtk_rbtree_traverse (node->children,
1133                           node->children->root,
1134                           G_PRE_ORDER,
1135                           select_all_helper,
1136                           data);
1137   if (!GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_SELECTED))
1138     {
1139       tuple->dirty = gtk_tree_selection_real_select_node (tuple->selection, tree, node, TRUE) || tuple->dirty;
1140     }
1141 }
1142
1143
1144 /* We have a real_{un,}select_all function that doesn't emit the signal, so we
1145  * can use it in other places without fear of the signal being emitted.
1146  */
1147 static gint
1148 gtk_tree_selection_real_select_all (GtkTreeSelection *selection)
1149 {
1150   GtkTreeSelectionPrivate *priv = selection->priv;
1151   struct _TempTuple *tuple;
1152   GtkRBTree *tree;
1153
1154   tree = _gtk_tree_view_get_rbtree (priv->tree_view);
1155
1156   if (tree == NULL)
1157     return FALSE;
1158
1159   /* Mark all nodes selected */
1160   tuple = g_new (struct _TempTuple, 1);
1161   tuple->selection = selection;
1162   tuple->dirty = FALSE;
1163
1164   _gtk_rbtree_traverse (tree, tree->root,
1165                         G_PRE_ORDER,
1166                         select_all_helper,
1167                         tuple);
1168   if (tuple->dirty)
1169     {
1170       g_free (tuple);
1171       return TRUE;
1172     }
1173   g_free (tuple);
1174   return FALSE;
1175 }
1176
1177 /**
1178  * gtk_tree_selection_select_all:
1179  * @selection: A #GtkTreeSelection.
1180  *
1181  * Selects all the nodes. @selection must be set to #GTK_SELECTION_MULTIPLE
1182  * mode.
1183  **/
1184 void
1185 gtk_tree_selection_select_all (GtkTreeSelection *selection)
1186 {
1187   GtkTreeSelectionPrivate *priv;
1188
1189   g_return_if_fail (GTK_IS_TREE_SELECTION (selection));
1190
1191   priv = selection->priv;
1192
1193   g_return_if_fail (priv->tree_view != NULL);
1194
1195   if (_gtk_tree_view_get_rbtree (priv->tree_view) == NULL ||
1196       gtk_tree_view_get_model (priv->tree_view) == NULL)
1197     return;
1198
1199   g_return_if_fail (priv->type == GTK_SELECTION_MULTIPLE);
1200
1201   if (gtk_tree_selection_real_select_all (selection))
1202     g_signal_emit (selection, tree_selection_signals[CHANGED], 0);
1203 }
1204
1205 static void
1206 unselect_all_helper (GtkRBTree  *tree,
1207                      GtkRBNode  *node,
1208                      gpointer    data)
1209 {
1210   struct _TempTuple *tuple = data;
1211
1212   if (node->children)
1213     _gtk_rbtree_traverse (node->children,
1214                           node->children->root,
1215                           G_PRE_ORDER,
1216                           unselect_all_helper,
1217                           data);
1218   if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_SELECTED))
1219     {
1220       tuple->dirty = gtk_tree_selection_real_select_node (tuple->selection, tree, node, FALSE) || tuple->dirty;
1221     }
1222 }
1223
1224 static gboolean
1225 gtk_tree_selection_real_unselect_all (GtkTreeSelection *selection)
1226 {
1227   GtkTreeSelectionPrivate *priv = selection->priv;
1228   struct _TempTuple *tuple;
1229
1230   if (priv->type == GTK_SELECTION_SINGLE ||
1231       priv->type == GTK_SELECTION_BROWSE)
1232     {
1233       GtkRBTree *tree = NULL;
1234       GtkRBNode *node = NULL;
1235       GtkTreePath *anchor_path;
1236
1237       anchor_path = _gtk_tree_view_get_anchor_path (priv->tree_view);
1238
1239       if (anchor_path == NULL)
1240         return FALSE;
1241
1242       _gtk_tree_view_find_node (priv->tree_view,
1243                                 anchor_path,
1244                                 &tree,
1245                                 &node);
1246
1247       gtk_tree_path_free (anchor_path);
1248
1249       if (tree == NULL)
1250         return FALSE;
1251
1252       if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_SELECTED))
1253         {
1254           if (gtk_tree_selection_real_select_node (selection, tree, node, FALSE))
1255             {
1256               _gtk_tree_view_set_anchor_path (priv->tree_view, NULL);
1257               return TRUE;
1258             }
1259         }
1260       return FALSE;
1261     }
1262   else
1263     {
1264       GtkRBTree *tree;
1265
1266       tuple = g_new (struct _TempTuple, 1);
1267       tuple->selection = selection;
1268       tuple->dirty = FALSE;
1269
1270       tree = _gtk_tree_view_get_rbtree (priv->tree_view);
1271       _gtk_rbtree_traverse (tree, tree->root,
1272                             G_PRE_ORDER,
1273                             unselect_all_helper,
1274                             tuple);
1275
1276       if (tuple->dirty)
1277         {
1278           g_free (tuple);
1279           return TRUE;
1280         }
1281       g_free (tuple);
1282       return FALSE;
1283     }
1284 }
1285
1286 /**
1287  * gtk_tree_selection_unselect_all:
1288  * @selection: A #GtkTreeSelection.
1289  *
1290  * Unselects all the nodes.
1291  **/
1292 void
1293 gtk_tree_selection_unselect_all (GtkTreeSelection *selection)
1294 {
1295   GtkTreeSelectionPrivate *priv;
1296
1297   g_return_if_fail (GTK_IS_TREE_SELECTION (selection));
1298
1299   priv = selection->priv;
1300
1301   g_return_if_fail (priv->tree_view != NULL);
1302
1303   if (_gtk_tree_view_get_rbtree (priv->tree_view) == NULL ||
1304       gtk_tree_view_get_model (priv->tree_view) == NULL)
1305     return;
1306   
1307   if (gtk_tree_selection_real_unselect_all (selection))
1308     g_signal_emit (selection, tree_selection_signals[CHANGED], 0);
1309 }
1310
1311 enum
1312 {
1313   RANGE_SELECT,
1314   RANGE_UNSELECT
1315 };
1316
1317 static gint
1318 gtk_tree_selection_real_modify_range (GtkTreeSelection *selection,
1319                                       gint              mode,
1320                                       GtkTreePath      *start_path,
1321                                       GtkTreePath      *end_path)
1322 {
1323   GtkTreeSelectionPrivate *priv = selection->priv;
1324   GtkRBNode *start_node, *end_node;
1325   GtkRBTree *start_tree, *end_tree;
1326   GtkTreePath *anchor_path = NULL;
1327   gboolean dirty = FALSE;
1328
1329   switch (gtk_tree_path_compare (start_path, end_path))
1330     {
1331     case 1:
1332       _gtk_tree_view_find_node (priv->tree_view,
1333                                 end_path,
1334                                 &start_tree,
1335                                 &start_node);
1336       _gtk_tree_view_find_node (priv->tree_view,
1337                                 start_path,
1338                                 &end_tree,
1339                                 &end_node);
1340       anchor_path = start_path;
1341       break;
1342     case 0:
1343       _gtk_tree_view_find_node (priv->tree_view,
1344                                 start_path,
1345                                 &start_tree,
1346                                 &start_node);
1347       end_tree = start_tree;
1348       end_node = start_node;
1349       anchor_path = start_path;
1350       break;
1351     case -1:
1352       _gtk_tree_view_find_node (priv->tree_view,
1353                                 start_path,
1354                                 &start_tree,
1355                                 &start_node);
1356       _gtk_tree_view_find_node (priv->tree_view,
1357                                 end_path,
1358                                 &end_tree,
1359                                 &end_node);
1360       anchor_path = start_path;
1361       break;
1362     }
1363
1364   g_return_val_if_fail (start_node != NULL, FALSE);
1365   g_return_val_if_fail (end_node != NULL, FALSE);
1366
1367   if (anchor_path)
1368     _gtk_tree_view_set_anchor_path (priv->tree_view, anchor_path);
1369
1370   do
1371     {
1372       dirty |= gtk_tree_selection_real_select_node (selection, start_tree, start_node, (mode == RANGE_SELECT)?TRUE:FALSE);
1373
1374       if (start_node == end_node)
1375         break;
1376
1377       if (start_node->children)
1378         {
1379           start_tree = start_node->children;
1380           start_node = start_tree->root;
1381           while (start_node->left != start_tree->nil)
1382             start_node = start_node->left;
1383         }
1384       else
1385         {
1386           _gtk_rbtree_next_full (start_tree, start_node, &start_tree, &start_node);
1387           if (start_tree == NULL)
1388             {
1389               /* we just ran out of tree.  That means someone passed in bogus values.
1390                */
1391               return dirty;
1392             }
1393         }
1394     }
1395   while (TRUE);
1396
1397   return dirty;
1398 }
1399
1400 /**
1401  * gtk_tree_selection_select_range:
1402  * @selection: A #GtkTreeSelection.
1403  * @start_path: The initial node of the range.
1404  * @end_path: The final node of the range.
1405  *
1406  * Selects a range of nodes, determined by @start_path and @end_path inclusive.
1407  * @selection must be set to #GTK_SELECTION_MULTIPLE mode. 
1408  **/
1409 void
1410 gtk_tree_selection_select_range (GtkTreeSelection *selection,
1411                                  GtkTreePath      *start_path,
1412                                  GtkTreePath      *end_path)
1413 {
1414   GtkTreeSelectionPrivate *priv;
1415
1416   g_return_if_fail (GTK_IS_TREE_SELECTION (selection));
1417
1418   priv = selection->priv;
1419
1420   g_return_if_fail (priv->tree_view != NULL);
1421   g_return_if_fail (priv->type == GTK_SELECTION_MULTIPLE);
1422   g_return_if_fail (gtk_tree_view_get_model (priv->tree_view) != NULL);
1423
1424   if (gtk_tree_selection_real_modify_range (selection, RANGE_SELECT, start_path, end_path))
1425     g_signal_emit (selection, tree_selection_signals[CHANGED], 0);
1426 }
1427
1428 /**
1429  * gtk_tree_selection_unselect_range:
1430  * @selection: A #GtkTreeSelection.
1431  * @start_path: The initial node of the range.
1432  * @end_path: The initial node of the range.
1433  *
1434  * Unselects a range of nodes, determined by @start_path and @end_path
1435  * inclusive.
1436  *
1437  * Since: 2.2
1438  **/
1439 void
1440 gtk_tree_selection_unselect_range (GtkTreeSelection *selection,
1441                                    GtkTreePath      *start_path,
1442                                    GtkTreePath      *end_path)
1443 {
1444   GtkTreeSelectionPrivate *priv;
1445
1446   g_return_if_fail (GTK_IS_TREE_SELECTION (selection));
1447
1448   priv = selection->priv;
1449
1450   g_return_if_fail (priv->tree_view != NULL);
1451   g_return_if_fail (gtk_tree_view_get_model (priv->tree_view) != NULL);
1452
1453   if (gtk_tree_selection_real_modify_range (selection, RANGE_UNSELECT, start_path, end_path))
1454     g_signal_emit (selection, tree_selection_signals[CHANGED], 0);
1455 }
1456
1457 gboolean
1458 _gtk_tree_selection_row_is_selectable (GtkTreeSelection *selection,
1459                                        GtkRBNode        *node,
1460                                        GtkTreePath      *path)
1461 {
1462   GtkTreeSelectionPrivate *priv = selection->priv;
1463   GtkTreeIter iter;
1464   GtkTreeModel *model;
1465   GtkTreeViewRowSeparatorFunc separator_func;
1466   gpointer separator_data;
1467   gboolean sensitive = FALSE;
1468
1469   model = gtk_tree_view_get_model (priv->tree_view);
1470
1471   _gtk_tree_view_get_row_separator_func (priv->tree_view,
1472                                          &separator_func, &separator_data);
1473
1474   if (!gtk_tree_model_get_iter (model, &iter, path))
1475     sensitive = TRUE;
1476
1477   if (!sensitive && separator_func)
1478     {
1479       /* never allow separators to be selected */
1480       if ((* separator_func) (model, &iter, separator_data))
1481         return FALSE;
1482     }
1483
1484   if (priv->user_func)
1485     return (*priv->user_func) (selection, model, path,
1486                                     GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_SELECTED),
1487                                     priv->user_data);
1488   else
1489     return TRUE;
1490 }
1491
1492
1493 /* Called internally by gtktreeview.c It handles actually selecting the tree.
1494  */
1495
1496 /*
1497  * docs about the 'override_browse_mode', we set this flag when we want to
1498  * unset select the node and override the select browse mode behaviour (that is
1499  * 'one node should *always* be selected').
1500  */
1501 void
1502 _gtk_tree_selection_internal_select_node (GtkTreeSelection *selection,
1503                                           GtkRBNode        *node,
1504                                           GtkRBTree        *tree,
1505                                           GtkTreePath      *path,
1506                                           GtkTreeSelectMode mode,
1507                                           gboolean          override_browse_mode)
1508 {
1509   GtkTreeSelectionPrivate *priv = selection->priv;
1510   gint flags;
1511   gint dirty = FALSE;
1512   GtkTreePath *anchor_path = NULL;
1513
1514   if (priv->type == GTK_SELECTION_NONE)
1515     return;
1516
1517   anchor_path = _gtk_tree_view_get_anchor_path (priv->tree_view);
1518
1519   if (priv->type == GTK_SELECTION_SINGLE ||
1520       priv->type == GTK_SELECTION_BROWSE)
1521     {
1522       /* just unselect */
1523       if (priv->type == GTK_SELECTION_BROWSE && override_browse_mode)
1524         {
1525           dirty = gtk_tree_selection_real_unselect_all (selection);
1526         }
1527       /* Did we try to select the same node again? */
1528       else if (priv->type == GTK_SELECTION_SINGLE &&
1529                anchor_path && gtk_tree_path_compare (path, anchor_path) == 0)
1530         {
1531           if ((mode & GTK_TREE_SELECT_MODE_TOGGLE) == GTK_TREE_SELECT_MODE_TOGGLE)
1532             {
1533               dirty = gtk_tree_selection_real_unselect_all (selection);
1534             }
1535         }
1536       else
1537         {
1538           if (anchor_path)
1539             {
1540               /* We only want to select the new node if we can unselect the old one,
1541                * and we can select the new one. */
1542               dirty = _gtk_tree_selection_row_is_selectable (selection, node, path);
1543
1544               /* if dirty is FALSE, we weren't able to select the new one, otherwise, we try to
1545                * unselect the new one
1546                */
1547               if (dirty)
1548                 dirty = gtk_tree_selection_real_unselect_all (selection);
1549
1550               /* if dirty is TRUE at this point, we successfully unselected the
1551                * old one, and can then select the new one */
1552               if (dirty)
1553                 {
1554
1555                   _gtk_tree_view_set_anchor_path (priv->tree_view, NULL);
1556
1557                   if (gtk_tree_selection_real_select_node (selection, tree, node, TRUE))
1558                     _gtk_tree_view_set_anchor_path (priv->tree_view, path);
1559                 }
1560             }
1561           else
1562             {
1563               if (gtk_tree_selection_real_select_node (selection, tree, node, TRUE))
1564                 {
1565                   dirty = TRUE;
1566
1567                   _gtk_tree_view_set_anchor_path (priv->tree_view, path);
1568                 }
1569             }
1570         }
1571     }
1572   else if (priv->type == GTK_SELECTION_MULTIPLE)
1573     {
1574       if ((mode & GTK_TREE_SELECT_MODE_EXTEND) == GTK_TREE_SELECT_MODE_EXTEND
1575           && (anchor_path == NULL))
1576         {
1577           _gtk_tree_view_set_anchor_path (priv->tree_view, path);
1578
1579           dirty = gtk_tree_selection_real_select_node (selection, tree, node, TRUE);
1580         }
1581       else if ((mode & (GTK_TREE_SELECT_MODE_EXTEND | GTK_TREE_SELECT_MODE_TOGGLE)) == (GTK_TREE_SELECT_MODE_EXTEND | GTK_TREE_SELECT_MODE_TOGGLE))
1582         {
1583           gtk_tree_selection_select_range (selection,
1584                                            anchor_path,
1585                                            path);
1586         }
1587       else if ((mode & GTK_TREE_SELECT_MODE_TOGGLE) == GTK_TREE_SELECT_MODE_TOGGLE)
1588         {
1589           flags = node->flags;
1590
1591           _gtk_tree_view_set_anchor_path (priv->tree_view, path);
1592
1593           if ((flags & GTK_RBNODE_IS_SELECTED) == GTK_RBNODE_IS_SELECTED)
1594             dirty |= gtk_tree_selection_real_select_node (selection, tree, node, FALSE);
1595           else
1596             dirty |= gtk_tree_selection_real_select_node (selection, tree, node, TRUE);
1597         }
1598       else if ((mode & GTK_TREE_SELECT_MODE_EXTEND) == GTK_TREE_SELECT_MODE_EXTEND)
1599         {
1600           dirty = gtk_tree_selection_real_unselect_all (selection);
1601           dirty |= gtk_tree_selection_real_modify_range (selection,
1602                                                          RANGE_SELECT,
1603                                                          anchor_path,
1604                                                          path);
1605         }
1606       else
1607         {
1608           dirty = gtk_tree_selection_real_unselect_all (selection);
1609
1610           _gtk_tree_view_set_anchor_path (priv->tree_view, path);
1611
1612           dirty |= gtk_tree_selection_real_select_node (selection, tree, node, TRUE);
1613         }
1614     }
1615
1616   if (anchor_path)
1617     gtk_tree_path_free (anchor_path);
1618
1619   if (dirty)
1620     g_signal_emit (selection, tree_selection_signals[CHANGED], 0);  
1621 }
1622
1623
1624 void 
1625 _gtk_tree_selection_emit_changed (GtkTreeSelection *selection)
1626 {
1627   g_signal_emit (selection, tree_selection_signals[CHANGED], 0);  
1628 }
1629
1630 /* NOTE: Any {un,}selection ever done _MUST_ be done through this function!
1631  */
1632
1633 static gint
1634 gtk_tree_selection_real_select_node (GtkTreeSelection *selection,
1635                                      GtkRBTree        *tree,
1636                                      GtkRBNode        *node,
1637                                      gboolean          select)
1638 {
1639   GtkTreeSelectionPrivate *priv = selection->priv;
1640   gboolean toggle = FALSE;
1641   GtkTreePath *path = NULL;
1642
1643   select = !! select;
1644
1645   if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_SELECTED) != select)
1646     {
1647       path = _gtk_tree_view_find_path (priv->tree_view, tree, node);
1648       toggle = _gtk_tree_selection_row_is_selectable (selection, node, path);
1649       gtk_tree_path_free (path);
1650     }
1651
1652   if (toggle)
1653     {
1654       node->flags ^= GTK_RBNODE_IS_SELECTED;
1655
1656       _gtk_tree_view_queue_draw_node (priv->tree_view, tree, node, NULL);
1657
1658       return TRUE;
1659     }
1660
1661   return FALSE;
1662 }