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