]> Pileus Git - ~andy/gtk/blob - gtk/gtktreeselection.c
A bunch of trivial doc fixes.
[~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 "gtktreeselection.h"
21 #include "gtktreeprivate.h"
22 #include "gtkrbtree.h"
23 #include "gtkmarshalers.h"
24 #include "gtksignal.h"
25
26 static void gtk_tree_selection_init              (GtkTreeSelection      *selection);
27 static void gtk_tree_selection_class_init        (GtkTreeSelectionClass *class);
28
29 static void gtk_tree_selection_finalize          (GObject               *object);
30 static gint gtk_tree_selection_real_select_all   (GtkTreeSelection      *selection);
31 static gint gtk_tree_selection_real_unselect_all (GtkTreeSelection      *selection);
32 static gint gtk_tree_selection_real_select_node  (GtkTreeSelection      *selection,
33                                                   GtkRBTree             *tree,
34                                                   GtkRBNode             *node,
35                                                   gboolean               select);
36
37 enum
38 {
39   CHANGED,
40   LAST_SIGNAL
41 };
42
43 static GObjectClass *parent_class = NULL;
44 static guint tree_selection_signals [LAST_SIGNAL] = { 0 };
45
46 GtkType
47 gtk_tree_selection_get_type (void)
48 {
49   static GtkType selection_type = 0;
50
51   if (!selection_type)
52     {
53       static const GTypeInfo selection_info =
54       {
55         sizeof (GtkTreeSelectionClass),
56         NULL,           /* base_init */
57         NULL,           /* base_finalize */
58         (GClassInitFunc) gtk_tree_selection_class_init,
59         NULL,           /* class_finalize */
60         NULL,           /* class_data */
61         sizeof (GtkTreeSelection),
62         0,              /* n_preallocs */
63         (GInstanceInitFunc) gtk_tree_selection_init
64       };
65
66       selection_type = g_type_register_static (G_TYPE_OBJECT, "GtkTreeSelection", &selection_info, 0);
67     }
68
69   return selection_type;
70 }
71
72 static void
73 gtk_tree_selection_class_init (GtkTreeSelectionClass *class)
74 {
75   GObjectClass *object_class;
76
77   object_class = (GObjectClass*) class;
78   parent_class = g_type_class_peek_parent (class);
79
80   object_class->finalize = gtk_tree_selection_finalize;
81   class->changed = NULL;
82
83   tree_selection_signals[CHANGED] =
84     gtk_signal_new ("changed",
85                     GTK_RUN_FIRST,
86                     GTK_CLASS_TYPE (object_class),
87                     GTK_SIGNAL_OFFSET (GtkTreeSelectionClass, changed),
88                     _gtk_marshal_VOID__VOID,
89                     GTK_TYPE_NONE, 0);
90 }
91
92 static void
93 gtk_tree_selection_init (GtkTreeSelection *selection)
94 {
95   selection->type = GTK_SELECTION_SINGLE;
96 }
97
98 static void
99 gtk_tree_selection_finalize (GObject *object)
100 {
101   GtkTreeSelection *selection = GTK_TREE_SELECTION (object);
102
103   if (selection->destroy)
104     {
105       GtkDestroyNotify d = selection->destroy;
106
107       selection->destroy = NULL;
108       d (selection->user_data);
109     }
110
111   /* chain parent_class' handler */
112   G_OBJECT_CLASS (parent_class)->finalize (object);
113 }
114
115 /**
116  * _gtk_tree_selection_new:
117  *
118  * Creates a new #GtkTreeSelection object.  This function should not be invoked,
119  * as each #GtkTreeView will create it's own #GtkTreeSelection.
120  *
121  * Return value: A newly created #GtkTreeSelection object.
122  **/
123 GtkTreeSelection*
124 _gtk_tree_selection_new (void)
125 {
126   GtkTreeSelection *selection;
127
128   selection = GTK_TREE_SELECTION (g_object_new (GTK_TYPE_TREE_SELECTION, NULL));
129
130   return selection;
131 }
132
133 /**
134  * _gtk_tree_selection_new_with_tree_view:
135  * @tree_view: The #GtkTreeView.
136  *
137  * Creates a new #GtkTreeSelection object.  This function should not be invoked,
138  * as each #GtkTreeView will create it's own #GtkTreeSelection.
139  *
140  * Return value: A newly created #GtkTreeSelection object.
141  **/
142 GtkTreeSelection*
143 _gtk_tree_selection_new_with_tree_view (GtkTreeView *tree_view)
144 {
145   GtkTreeSelection *selection;
146
147   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), NULL);
148
149   selection = _gtk_tree_selection_new ();
150   _gtk_tree_selection_set_tree_view (selection, tree_view);
151
152   return selection;
153 }
154
155 /**
156  * _gtk_tree_selection_set_tree_view:
157  * @selection: A #GtkTreeSelection.
158  * @tree_view: The #GtkTreeView.
159  *
160  * Sets the #GtkTreeView of @selection.  This function should not be invoked, as
161  * it is used internally by #GtkTreeView.
162  **/
163 void
164 _gtk_tree_selection_set_tree_view (GtkTreeSelection *selection,
165                                    GtkTreeView      *tree_view)
166 {
167   g_return_if_fail (GTK_IS_TREE_SELECTION (selection));
168   if (tree_view != NULL)
169     g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
170
171   selection->tree_view = tree_view;
172 }
173
174 /**
175  * gtk_tree_selection_set_mode:
176  * @selection: A #GtkTreeSelection.
177  * @type: The selection mode
178  *
179  * Sets the selection mode of the @selection.  If the previous type was
180  * #GTK_SELECTION_MULTIPLE, then the anchor is kept selected, if it was
181  * previously selected.
182  **/
183 void
184 gtk_tree_selection_set_mode (GtkTreeSelection *selection,
185                              GtkSelectionMode  type)
186 {
187   GtkTreeSelectionFunc tmp_func;
188   g_return_if_fail (GTK_IS_TREE_SELECTION (selection));
189
190   if (selection->type == type)
191     return;
192
193   
194   if (type == GTK_SELECTION_NONE)
195     {
196       /* We do this so that we unconditionally unset all rows
197        */
198       tmp_func = selection->user_func;
199       selection->user_func = NULL;
200       gtk_tree_selection_unselect_all (selection);
201       selection->user_func = tmp_func;
202
203       gtk_tree_row_reference_free (selection->tree_view->priv->anchor);
204       selection->tree_view->priv->anchor = NULL;
205     }
206   else if (type == GTK_SELECTION_SINGLE ||
207            type == GTK_SELECTION_BROWSE)
208     {
209       GtkRBTree *tree = NULL;
210       GtkRBNode *node = NULL;
211       gint selected = FALSE;
212       GtkTreePath *anchor_path = NULL;
213
214       if (selection->tree_view->priv->anchor)
215         {
216           anchor_path = gtk_tree_row_reference_get_path (selection->tree_view->priv->anchor);
217
218           if (anchor_path)
219             {
220               _gtk_tree_view_find_node (selection->tree_view,
221                                         anchor_path,
222                                         &tree,
223                                         &node);
224
225               if (node && GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_SELECTED))
226                 selected = TRUE;
227             }
228         }
229
230       /* We do this so that we unconditionally unset all rows
231        */
232       tmp_func = selection->user_func;
233       selection->user_func = NULL;
234       gtk_tree_selection_unselect_all (selection);
235       selection->user_func = tmp_func;
236
237       if (node && selected)
238         _gtk_tree_selection_internal_select_node (selection,
239                                                   node,
240                                                   tree,
241                                                   anchor_path,
242                                                   0,
243                                                   FALSE);
244       if (anchor_path)
245         gtk_tree_path_free (anchor_path);
246     }
247
248   selection->type = type;
249 }
250
251 /**
252  * gtk_tree_selection_get_mode:
253  * @selection: a #GtkTreeSelection
254  *
255  * Gets the selection mode for @selection. See
256  * gtk_tree_selection_set_mode().
257  *
258  * Return value: the current selection mode
259  **/
260 GtkSelectionMode
261 gtk_tree_selection_get_mode (GtkTreeSelection *selection)
262 {
263   g_return_val_if_fail (GTK_IS_TREE_SELECTION (selection), GTK_SELECTION_SINGLE);
264
265   return selection->type;
266 }
267
268 /**
269  * gtk_tree_selection_set_select_function:
270  * @selection: A #GtkTreeSelection.
271  * @func: The selection function.
272  * @data: The selection function's data.
273  * @destroy: The destroy function for user data.  May be NULL.
274  *
275  * Sets the selection function.  If set, this function is called before any node
276  * is selected or unselected, giving some control over which nodes are selected.
277  * The select function should return %TRUE if the state of the node may be toggled,
278  * and %FALSE if the state of the node should be left unchanged.
279  **/
280 void
281 gtk_tree_selection_set_select_function (GtkTreeSelection     *selection,
282                                         GtkTreeSelectionFunc  func,
283                                         gpointer              data,
284                                         GtkDestroyNotify      destroy)
285 {
286   g_return_if_fail (GTK_IS_TREE_SELECTION (selection));
287   g_return_if_fail (func != NULL);
288
289   if (selection->destroy)
290     {
291       GtkDestroyNotify d = selection->destroy;
292
293       selection->destroy = NULL;
294       d (selection->user_data);
295     }
296
297   selection->user_func = func;
298   selection->user_data = data;
299   selection->destroy = destroy;
300 }
301
302 /**
303  * gtk_tree_selection_get_user_data:
304  * @selection: A #GtkTreeSelection.
305  *
306  * Returns the user data for the selection function.
307  *
308  * Return value: The user data.
309  **/
310 gpointer
311 gtk_tree_selection_get_user_data (GtkTreeSelection *selection)
312 {
313   g_return_val_if_fail (GTK_IS_TREE_SELECTION (selection), NULL);
314
315   return selection->user_data;
316 }
317
318 /**
319  * gtk_tree_selection_get_tree_view:
320  * @selection: A #GtkTreeSelection
321  * 
322  * Returns the tree view associated with @selection.
323  * 
324  * Return value: A #GtkTreeView
325  **/
326 GtkTreeView *
327 gtk_tree_selection_get_tree_view (GtkTreeSelection *selection)
328 {
329   g_return_val_if_fail (GTK_IS_TREE_SELECTION (selection), NULL);
330
331   return selection->tree_view;
332 }
333
334 /**
335  * gtk_tree_selection_get_selected:
336  * @selection: A #GtkTreeSelection.
337  * @model: A pointer set to the #GtkTreeModel, or NULL.
338  * @iter: The #GtkTreeIter, or NULL.
339  *
340  * Sets @iter to the currently selected node if @selection is set to
341  * #GTK_SELECTION_SINGLE or #GTK_SELECTION_BROWSE.  @iter may be NULL if you
342  * just want to test if @selection has any selected nodes.  @model is filled
343  * with the current model as a convenience.  This function will not work if you
344  * use @selection is #GTK_SELECTION_MULTIPLE.
345  *
346  * Return value: TRUE, if there is a selected node.
347  **/
348 gboolean
349 gtk_tree_selection_get_selected (GtkTreeSelection  *selection,
350                                  GtkTreeModel     **model,
351                                  GtkTreeIter       *iter)
352 {
353   GtkRBTree *tree;
354   GtkRBNode *node;
355   GtkTreePath *anchor_path;
356   gboolean retval;
357   gboolean found_node;
358
359   g_return_val_if_fail (GTK_IS_TREE_SELECTION (selection), FALSE);
360   g_return_val_if_fail (selection->type != GTK_SELECTION_MULTIPLE, FALSE);
361   g_return_val_if_fail (selection->tree_view != NULL, FALSE);
362   g_return_val_if_fail (selection->tree_view->priv->model != NULL, FALSE);
363
364   if (model)
365     *model = selection->tree_view->priv->model;
366
367   if (selection->tree_view->priv->anchor == NULL)
368     return FALSE;
369
370   anchor_path = gtk_tree_row_reference_get_path (selection->tree_view->priv->anchor);
371
372   if (anchor_path == NULL)
373     return FALSE;
374
375   retval = FALSE;
376
377   found_node = !_gtk_tree_view_find_node (selection->tree_view,
378                                           anchor_path,
379                                           &tree,
380                                           &node);
381
382   if (found_node && GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_SELECTED))
383     {
384       /* we only want to return the anchor if it exists in the rbtree and
385        * is selected.
386        */
387       if (iter == NULL)
388         retval = TRUE;
389       else
390         retval = gtk_tree_model_get_iter (selection->tree_view->priv->model,
391                                           iter,
392                                           anchor_path);
393     }
394   else
395     {
396       /* We don't want to return the anchor if it isn't actually selected.
397        */
398       retval = FALSE;
399     }
400
401   gtk_tree_path_free (anchor_path);
402
403   return retval;
404 }
405
406 /**
407  * gtk_tree_selection_selected_foreach:
408  * @selection: A #GtkTreeSelection.
409  * @func: The function to call for each selected node.
410  * @data: user data to pass to the function.
411  *
412  * Calls a function for each selected node.
413  **/
414 void
415 gtk_tree_selection_selected_foreach (GtkTreeSelection            *selection,
416                                      GtkTreeSelectionForeachFunc  func,
417                                      gpointer                     data)
418 {
419   GtkTreePath *path;
420   GtkRBTree *tree;
421   GtkRBNode *node;
422   GtkTreeIter iter;
423
424   g_return_if_fail (GTK_IS_TREE_SELECTION (selection));
425   g_return_if_fail (selection->tree_view != NULL);
426   g_return_if_fail (selection->tree_view->priv->model != NULL);
427
428   if (func == NULL ||
429       selection->tree_view->priv->tree == NULL ||
430       selection->tree_view->priv->tree->root == NULL)
431     return;
432
433   if (selection->type == GTK_SELECTION_SINGLE ||
434       selection->type == GTK_SELECTION_BROWSE)
435     {
436       if (gtk_tree_row_reference_valid (selection->tree_view->priv->anchor))
437         {
438           path = gtk_tree_row_reference_get_path (selection->tree_view->priv->anchor);
439           gtk_tree_model_get_iter (selection->tree_view->priv->model, &iter, path);
440           (* func) (selection->tree_view->priv->model, path, &iter, data);
441           gtk_tree_path_free (path);
442         }
443       return;
444     }
445
446   tree = selection->tree_view->priv->tree;
447   node = selection->tree_view->priv->tree->root;
448   
449   while (node->left != tree->nil)
450     node = node->left;
451
452   /* find the node internally */
453   path = gtk_tree_path_new_first ();
454   gtk_tree_model_get_iter (selection->tree_view->priv->model,
455                            &iter, path);
456
457   do
458     {
459       if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_SELECTED))
460         (* func) (selection->tree_view->priv->model, path, &iter, data);
461       if (node->children)
462         {
463           gboolean has_child;
464           GtkTreeIter tmp;
465
466           tree = node->children;
467           node = tree->root;
468           while (node->left != tree->nil)
469             node = node->left;
470           tmp = iter;
471           has_child = gtk_tree_model_iter_children (selection->tree_view->priv->model, &iter, &tmp);
472           gtk_tree_path_append_index (path, 0);
473           /* Sanity Check! */
474           TREE_VIEW_INTERNAL_ASSERT_VOID (has_child);
475         }
476       else
477         {
478           gboolean done = FALSE;
479           do
480             {
481               node = _gtk_rbtree_next (tree, node);
482               if (node != NULL)
483                 {
484                   gboolean has_next;
485
486                   has_next = gtk_tree_model_iter_next (selection->tree_view->priv->model, &iter);
487                   done = TRUE;
488                   gtk_tree_path_next (path);
489
490                   /* Sanity Check! */
491                   TREE_VIEW_INTERNAL_ASSERT_VOID (has_next);
492                 }
493               else
494                 {
495                   gboolean has_parent;
496                   GtkTreeIter tmp_iter = iter;
497
498                   node = tree->parent_node;
499                   tree = tree->parent_tree;
500                   if (tree == NULL)
501                     {
502                       gtk_tree_path_free (path);
503                       /* we've run out of tree */
504                       /* We're done with this function */
505                       return;
506                     }
507                   has_parent = gtk_tree_model_iter_parent (selection->tree_view->priv->model, &iter, &tmp_iter);
508                   gtk_tree_path_up (path);
509                   /* Sanity check */
510                   TREE_VIEW_INTERNAL_ASSERT_VOID (has_parent);
511                 }
512             }
513           while (!done);
514         }
515     }
516   while (TRUE);
517 }
518
519 /**
520  * gtk_tree_selection_select_path:
521  * @selection: A #GtkTreeSelection.
522  * @path: The #GtkTreePath to be selected.
523  *
524  * Select the row at @path.
525  **/
526 void
527 gtk_tree_selection_select_path (GtkTreeSelection *selection,
528                                 GtkTreePath      *path)
529 {
530   GtkRBNode *node;
531   GtkRBTree *tree;
532   GdkModifierType state = 0;
533   gboolean ret;
534
535   g_return_if_fail (GTK_IS_TREE_SELECTION (selection));
536   g_return_if_fail (selection->tree_view != NULL);
537   g_return_if_fail (path != NULL);
538
539   ret = _gtk_tree_view_find_node (selection->tree_view,
540                                   path,
541                                   &tree,
542                                   &node);
543
544   if (node == NULL || GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_SELECTED) ||
545       ret == TRUE)
546     return;
547
548   if (selection->type == GTK_SELECTION_MULTIPLE)
549     state = GDK_CONTROL_MASK;
550
551   _gtk_tree_selection_internal_select_node (selection,
552                                             node,
553                                             tree,
554                                             path,
555                                             state,
556                                             FALSE);
557 }
558
559 /**
560  * gtk_tree_selection_unselect_path:
561  * @selection: A #GtkTreeSelection.
562  * @path: The #GtkTreePath to be unselected.
563  *
564  * Unselects the row at @path.
565  **/
566 void
567 gtk_tree_selection_unselect_path (GtkTreeSelection *selection,
568                                   GtkTreePath      *path)
569 {
570   GtkRBNode *node;
571   GtkRBTree *tree;
572   gboolean ret;
573
574   g_return_if_fail (GTK_IS_TREE_SELECTION (selection));
575   g_return_if_fail (selection->tree_view != NULL);
576   g_return_if_fail (path != NULL);
577
578   ret = _gtk_tree_view_find_node (selection->tree_view,
579                                   path,
580                                   &tree,
581                                   &node);
582
583   if (node == NULL || !GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_SELECTED) ||
584       ret == TRUE)
585     return;
586
587   _gtk_tree_selection_internal_select_node (selection,
588                                             node,
589                                             tree,
590                                             path,
591                                             GDK_CONTROL_MASK,
592                                             TRUE);
593 }
594
595 /**
596  * gtk_tree_selection_select_iter:
597  * @selection: A #GtkTreeSelection.
598  * @iter: The #GtkTreeIter to be selected.
599  *
600  * Selects the specified iterator.
601  **/
602 void
603 gtk_tree_selection_select_iter (GtkTreeSelection *selection,
604                                 GtkTreeIter      *iter)
605 {
606   GtkTreePath *path;
607
608   g_return_if_fail (GTK_IS_TREE_SELECTION (selection));
609   g_return_if_fail (selection->tree_view != NULL);
610   g_return_if_fail (selection->tree_view->priv->model != NULL);
611   g_return_if_fail (iter != NULL);
612
613   path = gtk_tree_model_get_path (selection->tree_view->priv->model,
614                                   iter);
615
616   if (path == NULL)
617     return;
618
619   gtk_tree_selection_select_path (selection, path);
620   gtk_tree_path_free (path);
621 }
622
623
624 /**
625  * gtk_tree_selection_unselect_iter:
626  * @selection: A #GtkTreeSelection.
627  * @iter: The #GtkTreeIter to be unselected.
628  *
629  * Unselects the specified iterator.
630  **/
631 void
632 gtk_tree_selection_unselect_iter (GtkTreeSelection *selection,
633                                   GtkTreeIter      *iter)
634 {
635   GtkTreePath *path;
636
637   g_return_if_fail (GTK_IS_TREE_SELECTION (selection));
638   g_return_if_fail (selection->tree_view != NULL);
639   g_return_if_fail (selection->tree_view->priv->model != NULL);
640   g_return_if_fail (iter != NULL);
641
642   path = gtk_tree_model_get_path (selection->tree_view->priv->model,
643                                   iter);
644
645   if (path == NULL)
646     return;
647
648   gtk_tree_selection_unselect_path (selection, path);
649   gtk_tree_path_free (path);
650 }
651
652 /**
653  * gtk_tree_selection_path_is_selected:
654  * @selection: A #GtkTreeSelection.
655  * @path: A #GtkTreePath to check selection on.
656  * 
657  * Returns %TRUE if the row pointed to by @path is currently selected.  If @path
658  * does not point to a valid location, %FALSE is returned
659  * 
660  * Return value: %TRUE if @path is selected.
661  **/
662 gboolean
663 gtk_tree_selection_path_is_selected (GtkTreeSelection *selection,
664                                      GtkTreePath      *path)
665 {
666   GtkRBNode *node;
667   GtkRBTree *tree;
668   gboolean ret;
669
670   g_return_val_if_fail (GTK_IS_TREE_SELECTION (selection), FALSE);
671   g_return_val_if_fail (path != NULL, FALSE);
672   g_return_val_if_fail (selection->tree_view != NULL, FALSE);
673   g_return_val_if_fail (selection->tree_view->priv->model != NULL, FALSE);
674
675   ret = _gtk_tree_view_find_node (selection->tree_view,
676                                   path,
677                                   &tree,
678                                   &node);
679
680   if ((node == NULL) || !GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_SELECTED) ||
681       ret == TRUE)
682     return FALSE;
683
684   return TRUE;
685 }
686
687 /**
688  * gtk_tree_selection_iter_is_selected:
689  * @selection: A #GtkTreeSelection
690  * @iter: A valid #GtkTreeIter
691  * 
692  * Returns %TRUE if the row pointed to by @path is currently selected.
693  * 
694  * Return value: %TRUE, if @iter is selected
695  **/
696 gboolean
697 gtk_tree_selection_iter_is_selected (GtkTreeSelection *selection,
698                                      GtkTreeIter      *iter)
699 {
700   GtkTreePath *path;
701   gboolean retval;
702
703   g_return_val_if_fail (GTK_IS_TREE_SELECTION (selection), FALSE);
704   g_return_val_if_fail (iter != NULL, FALSE);
705   g_return_val_if_fail (selection->tree_view != NULL, FALSE);
706   g_return_val_if_fail (selection->tree_view->priv->model != NULL, FALSE);
707
708   path = gtk_tree_model_get_path (selection->tree_view->priv->model, iter);
709   if (path == NULL)
710     return FALSE;
711
712   retval = gtk_tree_selection_path_is_selected (selection, path);
713   gtk_tree_path_free (path);
714
715   return retval;
716 }
717
718
719 /* Wish I was in python, right now... */
720 struct _TempTuple {
721   GtkTreeSelection *selection;
722   gint dirty;
723 };
724
725 static void
726 select_all_helper (GtkRBTree  *tree,
727                    GtkRBNode  *node,
728                    gpointer    data)
729 {
730   struct _TempTuple *tuple = data;
731
732   if (node->children)
733     _gtk_rbtree_traverse (node->children,
734                           node->children->root,
735                           G_PRE_ORDER,
736                           select_all_helper,
737                           data);
738   if (!GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_SELECTED))
739     {
740       tuple->dirty = gtk_tree_selection_real_select_node (tuple->selection, tree, node, TRUE) || tuple->dirty;
741     }
742 }
743
744
745 /* We have a real_{un,}select_all function that doesn't emit the signal, so we
746  * can use it in other places without fear of the signal being emitted.
747  */
748 static gint
749 gtk_tree_selection_real_select_all (GtkTreeSelection *selection)
750 {
751   struct _TempTuple *tuple;
752
753   if (selection->tree_view->priv->tree == NULL)
754     return FALSE;
755
756   /* Mark all nodes selected */
757   tuple = g_new (struct _TempTuple, 1);
758   tuple->selection = selection;
759   tuple->dirty = FALSE;
760
761   _gtk_rbtree_traverse (selection->tree_view->priv->tree,
762                         selection->tree_view->priv->tree->root,
763                         G_PRE_ORDER,
764                         select_all_helper,
765                         tuple);
766   if (tuple->dirty)
767     {
768       g_free (tuple);
769       return TRUE;
770     }
771   g_free (tuple);
772   return FALSE;
773 }
774
775 /**
776  * gtk_tree_selection_select_all:
777  * @selection: A #GtkTreeSelection.
778  *
779  * Selects all the nodes.  @selection is must be set to #GTK_SELECTION_MULTIPLE
780  * mode.
781  **/
782 void
783 gtk_tree_selection_select_all (GtkTreeSelection *selection)
784 {
785   g_return_if_fail (GTK_IS_TREE_SELECTION (selection));
786   g_return_if_fail (selection->tree_view != NULL);
787   if (selection->tree_view->priv->tree == NULL)
788     return;
789   g_return_if_fail (selection->type == GTK_SELECTION_MULTIPLE);
790
791   if (gtk_tree_selection_real_select_all (selection))
792     g_signal_emit (G_OBJECT (selection), tree_selection_signals[CHANGED], 0);
793 }
794
795 static void
796 unselect_all_helper (GtkRBTree  *tree,
797                      GtkRBNode  *node,
798                      gpointer    data)
799 {
800   struct _TempTuple *tuple = data;
801
802   if (node->children)
803     _gtk_rbtree_traverse (node->children,
804                           node->children->root,
805                           G_PRE_ORDER,
806                           unselect_all_helper,
807                           data);
808   if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_SELECTED))
809     {
810       tuple->dirty = gtk_tree_selection_real_select_node (tuple->selection, tree, node, FALSE) || tuple->dirty;
811     }
812 }
813
814 static gint
815 gtk_tree_selection_real_unselect_all (GtkTreeSelection *selection)
816 {
817   struct _TempTuple *tuple;
818
819   if (selection->type == GTK_SELECTION_SINGLE ||
820       selection->type == GTK_SELECTION_BROWSE)
821     {
822       GtkRBTree *tree = NULL;
823       GtkRBNode *node = NULL;
824       GtkTreePath *anchor_path;
825
826       if (selection->tree_view->priv->anchor == NULL)
827         return FALSE;
828
829       anchor_path = gtk_tree_row_reference_get_path (selection->tree_view->priv->anchor);
830
831       if (anchor_path == NULL)
832         return FALSE;
833
834       _gtk_tree_view_find_node (selection->tree_view,
835                                 anchor_path,
836                                 &tree,
837                                 &node);
838
839       gtk_tree_path_free (anchor_path);
840
841       if (tree == NULL)
842         return FALSE;
843
844       if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_SELECTED))
845         {
846           if (gtk_tree_selection_real_select_node (selection, tree, node, FALSE))
847             {
848               gtk_tree_row_reference_free (selection->tree_view->priv->anchor);
849               selection->tree_view->priv->anchor = NULL;
850               return TRUE;
851             }
852         }
853       return FALSE;
854     }
855   else
856     {
857       tuple = g_new (struct _TempTuple, 1);
858       tuple->selection = selection;
859       tuple->dirty = FALSE;
860
861       _gtk_rbtree_traverse (selection->tree_view->priv->tree,
862                             selection->tree_view->priv->tree->root,
863                             G_PRE_ORDER,
864                             unselect_all_helper,
865                             tuple);
866
867       if (tuple->dirty)
868         {
869           g_free (tuple);
870           return TRUE;
871         }
872       g_free (tuple);
873       return FALSE;
874     }
875 }
876
877 /**
878  * gtk_tree_selection_unselect_all:
879  * @selection: A #GtkTreeSelection.
880  *
881  * Unselects all the nodes.
882  **/
883 void
884 gtk_tree_selection_unselect_all (GtkTreeSelection *selection)
885 {
886   g_return_if_fail (GTK_IS_TREE_SELECTION (selection));
887   g_return_if_fail (selection->tree_view != NULL);
888   if (selection->tree_view->priv->tree == NULL)
889     return;
890   
891   if (selection->tree_view->priv->tree == NULL)
892     return;
893
894   if (gtk_tree_selection_real_unselect_all (selection))
895     g_signal_emit (G_OBJECT (selection), tree_selection_signals[CHANGED], 0);
896 }
897
898 static gint
899 gtk_tree_selection_real_select_range (GtkTreeSelection *selection,
900                                       GtkTreePath      *start_path,
901                                       GtkTreePath      *end_path)
902 {
903   GtkRBNode *start_node, *end_node;
904   GtkRBTree *start_tree, *end_tree;
905   gboolean dirty = FALSE;
906
907   switch (gtk_tree_path_compare (start_path, end_path))
908     {
909     case 1:
910       _gtk_tree_view_find_node (selection->tree_view,
911                                 end_path,
912                                 &start_tree,
913                                 &start_node);
914       _gtk_tree_view_find_node (selection->tree_view,
915                                 start_path,
916                                 &end_tree,
917                                 &end_node);
918       break;
919     case 0:
920       _gtk_tree_view_find_node (selection->tree_view,
921                                 start_path,
922                                 &start_tree,
923                                 &start_node);
924       end_tree = start_tree;
925       end_node = start_node;
926       break;
927     case -1:
928       _gtk_tree_view_find_node (selection->tree_view,
929                                 start_path,
930                                 &start_tree,
931                                 &start_node);
932       _gtk_tree_view_find_node (selection->tree_view,
933                                 end_path,
934                                 &end_tree,
935                                 &end_node);
936       break;
937     }
938
939   g_return_val_if_fail (start_node != NULL, FALSE);
940   g_return_val_if_fail (end_node != NULL, FALSE);
941
942   do
943     {
944       dirty |= gtk_tree_selection_real_select_node (selection, start_tree, start_node, TRUE);
945
946       if (start_node == end_node)
947         break;
948
949       if (start_node->children)
950         {
951           start_tree = start_node->children;
952           start_node = start_tree->root;
953           while (start_node->left != start_tree->nil)
954             start_node = start_node->left;
955         }
956       else
957         {
958           _gtk_rbtree_next_full (start_tree, start_node, &start_tree, &start_node);
959           if (start_tree == NULL)
960             {
961               /* we just ran out of tree.  That means someone passed in bogus values.
962                */
963               return dirty;
964             }
965         }
966     }
967   while (TRUE);
968
969   return dirty;
970 }
971
972 /**
973  * gtk_tree_selection_select_range:
974  * @selection: A #GtkTreeSelection.
975  * @start_path: The initial node of the range.
976  * @end_path: The final node of the range.
977  *
978  * Selects a range of nodes, determined by @start_path and @end_path inclusive.
979  **/
980 void
981 gtk_tree_selection_select_range (GtkTreeSelection *selection,
982                                  GtkTreePath      *start_path,
983                                  GtkTreePath      *end_path)
984 {
985   g_return_if_fail (GTK_IS_TREE_SELECTION (selection));
986   g_return_if_fail (selection->tree_view != NULL);
987
988   if (gtk_tree_selection_real_select_range (selection, start_path, end_path))
989     g_signal_emit (G_OBJECT (selection), tree_selection_signals[CHANGED], 0);
990 }
991
992 /* Called internally by gtktreeview.c It handles actually selecting the tree.
993  */
994
995 /*
996  * docs about the 'override_browse_mode', we set this flag when we want to
997  * unset select the node and override the select browse mode behaviour (that is
998  * 'one node should *always* be selected').
999  */
1000 void
1001 _gtk_tree_selection_internal_select_node (GtkTreeSelection *selection,
1002                                           GtkRBNode        *node,
1003                                           GtkRBTree        *tree,
1004                                           GtkTreePath      *path,
1005                                           GdkModifierType   state,
1006                                           gboolean          override_browse_mode)
1007 {
1008   gint flags;
1009   gint dirty = FALSE;
1010   GtkTreePath *anchor_path = NULL;
1011
1012   if (selection->type == GTK_SELECTION_NONE)
1013     return;
1014
1015   if (selection->tree_view->priv->anchor)
1016     anchor_path = gtk_tree_row_reference_get_path (selection->tree_view->priv->anchor);
1017
1018   if (selection->type == GTK_SELECTION_SINGLE ||
1019       selection->type == GTK_SELECTION_BROWSE)
1020     {
1021       /* just unselect */
1022       if (selection->type == GTK_SELECTION_BROWSE && override_browse_mode)
1023         {
1024           dirty = gtk_tree_selection_real_unselect_all (selection);
1025         }
1026       /* Did we try to select the same node again? */
1027       else if (selection->type == GTK_SELECTION_SINGLE &&
1028                anchor_path && gtk_tree_path_compare (path, anchor_path) == 0)
1029         {
1030           if ((state & GDK_CONTROL_MASK) == GDK_CONTROL_MASK)
1031             {
1032               dirty = gtk_tree_selection_real_unselect_all (selection);
1033             }
1034         }
1035       else
1036         {
1037           if (anchor_path)
1038             {
1039               /* We only want to select the new node if we can unselect the old one,
1040                * and we can select the new one. */
1041               if (selection->user_func)
1042                 {
1043                   if ((*selection->user_func) (selection, selection->tree_view->priv->model, path,
1044                                                GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_SELECTED),
1045                                                selection->user_data))
1046                     dirty = TRUE;
1047                 }
1048               else
1049                 {
1050                   dirty = TRUE;
1051                 }
1052
1053               /* if dirty is FALSE, we weren't able to select the new one, otherwise, we try to
1054                * unselect the new one
1055                */
1056               if (dirty)
1057                 dirty = gtk_tree_selection_real_unselect_all (selection);
1058
1059               /* if dirty is TRUE at this point, we successfully unselected the
1060                * old one, and can then select the new one */
1061               if (dirty)
1062                 {
1063                   if (selection->tree_view->priv->anchor)
1064                     gtk_tree_row_reference_free (selection->tree_view->priv->anchor);
1065                   if (gtk_tree_selection_real_select_node (selection, tree, node, TRUE))
1066                     {
1067                       selection->tree_view->priv->anchor =
1068                         gtk_tree_row_reference_new_proxy (G_OBJECT (selection->tree_view), selection->tree_view->priv->model, path);
1069                     }
1070                 }
1071             }
1072           else
1073             {
1074               if (gtk_tree_selection_real_select_node (selection, tree, node, TRUE))
1075                 {
1076                   dirty = TRUE;
1077                   selection->tree_view->priv->anchor =
1078                     gtk_tree_row_reference_new_proxy (G_OBJECT (selection->tree_view), selection->tree_view->priv->model, path);
1079                 }
1080             }
1081         }
1082     }
1083   else if (selection->type == GTK_SELECTION_MULTIPLE)
1084     {
1085       if (((state & GDK_SHIFT_MASK) == GDK_SHIFT_MASK) && (anchor_path == NULL))
1086         {
1087           if (selection->tree_view->priv->anchor)
1088             gtk_tree_row_reference_free (selection->tree_view->priv->anchor);
1089
1090           selection->tree_view->priv->anchor =
1091             gtk_tree_row_reference_new_proxy (G_OBJECT (selection->tree_view), selection->tree_view->priv->model, path);
1092           dirty = gtk_tree_selection_real_select_node (selection, tree, node, TRUE);
1093         }
1094       else if ((state & (GDK_CONTROL_MASK|GDK_SHIFT_MASK)) == (GDK_SHIFT_MASK|GDK_CONTROL_MASK))
1095         {
1096           gtk_tree_selection_select_range (selection,
1097                                            anchor_path,
1098                                            path);
1099         }
1100       else if ((state & GDK_CONTROL_MASK) == GDK_CONTROL_MASK)
1101         {
1102           flags = node->flags;
1103           if (selection->tree_view->priv->anchor)
1104             gtk_tree_row_reference_free (selection->tree_view->priv->anchor);
1105
1106           selection->tree_view->priv->anchor =
1107             gtk_tree_row_reference_new_proxy (G_OBJECT (selection->tree_view), selection->tree_view->priv->model, path);
1108
1109           if ((flags & GTK_RBNODE_IS_SELECTED) == GTK_RBNODE_IS_SELECTED)
1110             dirty |= gtk_tree_selection_real_select_node (selection, tree, node, FALSE);
1111           else
1112             dirty |= gtk_tree_selection_real_select_node (selection, tree, node, TRUE);
1113         }
1114       else if ((state & GDK_SHIFT_MASK) == GDK_SHIFT_MASK)
1115         {
1116           dirty = gtk_tree_selection_real_unselect_all (selection);
1117           dirty |= gtk_tree_selection_real_select_range (selection,
1118                                                          anchor_path,
1119                                                          path);
1120         }
1121       else
1122         {
1123           dirty = gtk_tree_selection_real_unselect_all (selection);
1124
1125           if (selection->tree_view->priv->anchor)
1126             gtk_tree_row_reference_free (selection->tree_view->priv->anchor);
1127
1128           selection->tree_view->priv->anchor =
1129             gtk_tree_row_reference_new_proxy (G_OBJECT (selection->tree_view), selection->tree_view->priv->model, path);
1130
1131           dirty |= gtk_tree_selection_real_select_node (selection, tree, node, TRUE);
1132         }
1133     }
1134
1135   if (anchor_path)
1136     gtk_tree_path_free (anchor_path);
1137
1138   if (dirty)
1139     g_signal_emit (G_OBJECT (selection), tree_selection_signals[CHANGED], 0);
1140 }
1141
1142 /* NOTE: Any {un,}selection ever done _MUST_ be done through this function!
1143  */
1144
1145 static gint
1146 gtk_tree_selection_real_select_node (GtkTreeSelection *selection,
1147                                      GtkRBTree        *tree,
1148                                      GtkRBNode        *node,
1149                                      gboolean          select)
1150 {
1151   gboolean selected = FALSE;
1152   GtkTreePath *path = NULL;
1153
1154   select = !! select;
1155
1156   if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_SELECTED) != select)
1157     {
1158       path = _gtk_tree_view_find_path (selection->tree_view, tree, node);
1159       if (selection->user_func)
1160         {
1161           if ((*selection->user_func) (selection, selection->tree_view->priv->model, path,
1162                                        GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_SELECTED),
1163                                        selection->user_data))
1164             selected = TRUE;
1165         }
1166       else
1167         selected = TRUE;
1168       gtk_tree_path_free (path);
1169     }
1170
1171   if (selected == TRUE)
1172     {
1173       node->flags ^= GTK_RBNODE_IS_SELECTED;
1174
1175       _gtk_tree_view_queue_draw_node (selection->tree_view, tree, node, NULL);
1176       
1177       return TRUE;
1178     }
1179
1180   return FALSE;
1181 }
1182