]> Pileus Git - ~andy/gtk/blob - gtk/gtktreeselection.c
4fe966a3165e8e1b59bf598039cdbb71fda11751
[~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       if (anchor_path)
244         gtk_tree_path_free (anchor_path);
245     }
246
247   selection->type = type;
248 }
249
250 /**
251  * gtk_tree_selection_get_mode:
252  * @selection: a #GtkTreeSelection
253  *
254  * Gets the selection mode for @selection. See
255  * gtk_tree_selection_set_mode().
256  *
257  * Return value: the current selection mode
258  **/
259 GtkSelectionMode
260 gtk_tree_selection_get_mode (GtkTreeSelection *selection)
261 {
262   g_return_val_if_fail (GTK_IS_TREE_SELECTION (selection), GTK_SELECTION_SINGLE);
263
264   return selection->type;
265 }
266
267 /**
268  * gtk_tree_selection_set_select_function:
269  * @selection: A #GtkTreeSelection.
270  * @func: The selection function.
271  * @data: The selection function's data.
272  * @destroy: The destroy function for user data.  May be NULL.
273  *
274  * Sets the selection function.  If set, this function is called before any node
275  * is selected or unselected, giving some control over which nodes are selected.
276  * The select function should return %TRUE if the state of the node may be toggled,
277  * and %FALSE if the state of the node should be left unchanged.
278  **/
279 void
280 gtk_tree_selection_set_select_function (GtkTreeSelection     *selection,
281                                         GtkTreeSelectionFunc  func,
282                                         gpointer              data,
283                                         GtkDestroyNotify      destroy)
284 {
285   g_return_if_fail (GTK_IS_TREE_SELECTION (selection));
286   g_return_if_fail (func != NULL);
287
288   if (selection->destroy)
289     {
290       GtkDestroyNotify d = selection->destroy;
291
292       selection->destroy = NULL;
293       d (selection->user_data);
294     }
295
296   selection->user_func = func;
297   selection->user_data = data;
298   selection->destroy = destroy;
299 }
300
301 /**
302  * gtk_tree_selection_get_user_data:
303  * @selection: A #GtkTreeSelection.
304  *
305  * Returns the user data for the selection function.
306  *
307  * Return value: The user data.
308  **/
309 gpointer
310 gtk_tree_selection_get_user_data (GtkTreeSelection *selection)
311 {
312   g_return_val_if_fail (GTK_IS_TREE_SELECTION (selection), NULL);
313
314   return selection->user_data;
315 }
316
317 /**
318  * gtk_tree_selection_get_tree_view:
319  * @selection: A #GtkTreeSelection
320  * 
321  * Returns the tree view associated with @selection.
322  * 
323  * Return value: A #GtkTreeView
324  **/
325 GtkTreeView *
326 gtk_tree_selection_get_tree_view (GtkTreeSelection *selection)
327 {
328   g_return_val_if_fail (GTK_IS_TREE_SELECTION (selection), NULL);
329
330   return selection->tree_view;
331 }
332
333 /**
334  * gtk_tree_selection_get_selected:
335  * @selection: A #GtkTreeSelection.
336  * @model: A pointer set to the #GtkTreeModel, or NULL.
337  * @iter: The #GtkTreeIter, or NULL.
338  *
339  * Sets @iter to the currently selected node if @selection is set to
340  * #GTK_SELECTION_SINGLE or #GTK_SELECTION_BROWSE.  @iter may be NULL if you
341  * just want to test if @selection has any selected nodes.  @model is filled
342  * with the current model as a convenience.  This function will not work if you
343  * use @selection is #GTK_SELECTION_MULTIPLE.
344  *
345  * Return value: TRUE, if there is a selected node.
346  **/
347 gboolean
348 gtk_tree_selection_get_selected (GtkTreeSelection  *selection,
349                                  GtkTreeModel     **model,
350                                  GtkTreeIter       *iter)
351 {
352   GtkRBTree *tree;
353   GtkRBNode *node;
354   GtkTreePath *anchor_path;
355   gboolean retval;
356
357   g_return_val_if_fail (GTK_IS_TREE_SELECTION (selection), FALSE);
358   g_return_val_if_fail (selection->type != GTK_SELECTION_MULTIPLE, FALSE);
359   g_return_val_if_fail (selection->tree_view != NULL, FALSE);
360   g_return_val_if_fail (selection->tree_view->priv->model != NULL, FALSE);
361
362   if (model)
363     *model = selection->tree_view->priv->model;
364
365   if (selection->tree_view->priv->anchor == NULL)
366     return FALSE;
367
368   anchor_path = gtk_tree_row_reference_get_path (selection->tree_view->priv->anchor);
369
370   if (anchor_path == NULL)
371     return FALSE;
372
373   if (iter == NULL)
374     {
375       gtk_tree_path_free (anchor_path);
376       return TRUE;
377     }
378
379   retval = FALSE;
380
381   if (!_gtk_tree_view_find_node (selection->tree_view,
382                                  anchor_path,
383                                  &tree,
384                                  &node) &&
385       ! GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_SELECTED))
386     {
387       /* We don't want to return the anchor if it isn't actually selected.
388        */
389       retval = FALSE;
390     }
391   else
392     {
393       retval = gtk_tree_model_get_iter (selection->tree_view->priv->model,
394                                         iter,
395                                         anchor_path);
396     }
397
398   gtk_tree_path_free (anchor_path);
399
400   return retval;
401 }
402
403 /**
404  * gtk_tree_selection_selected_foreach:
405  * @selection: A #GtkTreeSelection.
406  * @func: The function to call for each selected node.
407  * @data: user data to pass to the function.
408  *
409  * Calls a function for each selected node.
410  **/
411 void
412 gtk_tree_selection_selected_foreach (GtkTreeSelection            *selection,
413                                      GtkTreeSelectionForeachFunc  func,
414                                      gpointer                     data)
415 {
416   GtkTreePath *path;
417   GtkRBTree *tree;
418   GtkRBNode *node;
419   GtkTreeIter iter;
420
421   g_return_if_fail (GTK_IS_TREE_SELECTION (selection));
422   g_return_if_fail (selection->tree_view != NULL);
423   g_return_if_fail (selection->tree_view->priv->model != NULL);
424
425   if (func == NULL ||
426       selection->tree_view->priv->tree == NULL ||
427       selection->tree_view->priv->tree->root == NULL)
428     return;
429
430   if (selection->type == GTK_SELECTION_SINGLE ||
431       selection->type == GTK_SELECTION_BROWSE)
432     {
433       if (gtk_tree_row_reference_valid (selection->tree_view->priv->anchor))
434         {
435           path = gtk_tree_row_reference_get_path (selection->tree_view->priv->anchor);
436           gtk_tree_model_get_iter (selection->tree_view->priv->model, &iter, path);
437           (* func) (selection->tree_view->priv->model, path, &iter, data);
438           gtk_tree_path_free (path);
439         }
440       return;
441     }
442
443   tree = selection->tree_view->priv->tree;
444   node = selection->tree_view->priv->tree->root;
445   
446   while (node->left != tree->nil)
447     node = node->left;
448
449   /* find the node internally */
450   path = gtk_tree_path_new_first ();
451   gtk_tree_model_get_iter (selection->tree_view->priv->model,
452                            &iter, path);
453
454   do
455     {
456       if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_SELECTED))
457         (* func) (selection->tree_view->priv->model, path, &iter, data);
458       if (node->children)
459         {
460           gboolean has_child;
461           GtkTreeIter tmp;
462
463           tree = node->children;
464           node = tree->root;
465           while (node->left != tree->nil)
466             node = node->left;
467           tmp = iter;
468           has_child = gtk_tree_model_iter_children (selection->tree_view->priv->model, &iter, &tmp);
469           gtk_tree_path_append_index (path, 0);
470           /* Sanity Check! */
471           TREE_VIEW_INTERNAL_ASSERT_VOID (has_child);
472         }
473       else
474         {
475           gboolean done = FALSE;
476           do
477             {
478               node = _gtk_rbtree_next (tree, node);
479               if (node != NULL)
480                 {
481                   gboolean has_next;
482
483                   has_next = gtk_tree_model_iter_next (selection->tree_view->priv->model, &iter);
484                   done = TRUE;
485                   gtk_tree_path_next (path);
486
487                   /* Sanity Check! */
488                   TREE_VIEW_INTERNAL_ASSERT_VOID (has_next);
489                 }
490               else
491                 {
492                   gboolean has_parent;
493                   GtkTreeIter tmp_iter = iter;
494
495                   node = tree->parent_node;
496                   tree = tree->parent_tree;
497                   if (tree == NULL)
498                     {
499                       gtk_tree_path_free (path);
500                       /* we've run out of tree */
501                       /* We're done with this function */
502                       return;
503                     }
504                   has_parent = gtk_tree_model_iter_parent (selection->tree_view->priv->model, &iter, &tmp_iter);
505                   gtk_tree_path_up (path);
506                   /* Sanity check */
507                   TREE_VIEW_INTERNAL_ASSERT_VOID (has_parent);
508                 }
509             }
510           while (!done);
511         }
512     }
513   while (TRUE);
514 }
515
516 /**
517  * gtk_tree_selection_select_path:
518  * @selection: A #GtkTreeSelection.
519  * @path: The #GtkTreePath to be selected.
520  *
521  * Select the row at @path.
522  **/
523 void
524 gtk_tree_selection_select_path (GtkTreeSelection *selection,
525                                 GtkTreePath      *path)
526 {
527   GtkRBNode *node;
528   GtkRBTree *tree;
529   GdkModifierType state = 0;
530   gboolean ret;
531
532   g_return_if_fail (GTK_IS_TREE_SELECTION (selection));
533   g_return_if_fail (selection->tree_view != NULL);
534   g_return_if_fail (path != NULL);
535
536   ret = _gtk_tree_view_find_node (selection->tree_view,
537                                   path,
538                                   &tree,
539                                   &node);
540
541   if (node == NULL || GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_SELECTED) ||
542       ret == TRUE)
543     return;
544
545   if (selection->type == GTK_SELECTION_MULTIPLE)
546     state = GDK_CONTROL_MASK;
547
548   _gtk_tree_selection_internal_select_node (selection,
549                                             node,
550                                             tree,
551                                             path,
552                                             state);
553 }
554
555 /**
556  * gtk_tree_selection_unselect_path:
557  * @selection: A #GtkTreeSelection.
558  * @path: The #GtkTreePath to be unselected.
559  *
560  * Unselects the row at @path.
561  **/
562 void
563 gtk_tree_selection_unselect_path (GtkTreeSelection *selection,
564                                   GtkTreePath      *path)
565 {
566   GtkRBNode *node;
567   GtkRBTree *tree;
568   gboolean ret;
569
570   g_return_if_fail (GTK_IS_TREE_SELECTION (selection));
571   g_return_if_fail (selection->tree_view != NULL);
572   g_return_if_fail (path != NULL);
573
574   ret = _gtk_tree_view_find_node (selection->tree_view,
575                                   path,
576                                   &tree,
577                                   &node);
578
579   if (node == NULL || !GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_SELECTED) ||
580       ret == TRUE)
581     return;
582
583   _gtk_tree_selection_internal_select_node (selection,
584                                             node,
585                                             tree,
586                                             path,
587                                             GDK_CONTROL_MASK);
588 }
589
590 /**
591  * gtk_tree_selection_select_iter:
592  * @selection: A #GtkTreeSelection.
593  * @iter: The #GtkTreeIter to be selected.
594  *
595  * Selects the specified iterator.
596  **/
597 void
598 gtk_tree_selection_select_iter (GtkTreeSelection *selection,
599                                 GtkTreeIter      *iter)
600 {
601   GtkTreePath *path;
602
603   g_return_if_fail (GTK_IS_TREE_SELECTION (selection));
604   g_return_if_fail (selection->tree_view != NULL);
605   g_return_if_fail (selection->tree_view->priv->model != NULL);
606   g_return_if_fail (iter != NULL);
607
608   path = gtk_tree_model_get_path (selection->tree_view->priv->model,
609                                   iter);
610
611   if (path == NULL)
612     return;
613
614   gtk_tree_selection_select_path (selection, path);
615   gtk_tree_path_free (path);
616 }
617
618
619 /**
620  * gtk_tree_selection_unselect_iter:
621  * @selection: A #GtkTreeSelection.
622  * @iter: The #GtkTreeIter to be unselected.
623  *
624  * Unselects the specified iterator.
625  **/
626 void
627 gtk_tree_selection_unselect_iter (GtkTreeSelection *selection,
628                                   GtkTreeIter      *iter)
629 {
630   GtkTreePath *path;
631
632   g_return_if_fail (GTK_IS_TREE_SELECTION (selection));
633   g_return_if_fail (selection->tree_view != NULL);
634   g_return_if_fail (selection->tree_view->priv->model != NULL);
635   g_return_if_fail (iter != NULL);
636
637   path = gtk_tree_model_get_path (selection->tree_view->priv->model,
638                                   iter);
639
640   if (path == NULL)
641     return;
642
643   gtk_tree_selection_unselect_path (selection, path);
644   gtk_tree_path_free (path);
645 }
646
647 /**
648  * gtk_tree_selection_path_is_selected:
649  * @selection: A #GtkTreeSelection.
650  * @path: A #GtkTreePath to check selection on.
651  * 
652  * Returns %TRUE if the row pointed to by @path is currently selected.  If @path
653  * does not point to a valid location, %FALSE is returned
654  * 
655  * Return value: %TRUE if @path is selected.
656  **/
657 gboolean
658 gtk_tree_selection_path_is_selected (GtkTreeSelection *selection,
659                                      GtkTreePath      *path)
660 {
661   GtkRBNode *node;
662   GtkRBTree *tree;
663   gboolean ret;
664
665   g_return_val_if_fail (GTK_IS_TREE_SELECTION (selection), FALSE);
666   g_return_val_if_fail (path != NULL, FALSE);
667   g_return_val_if_fail (selection->tree_view != NULL, FALSE);
668   g_return_val_if_fail (selection->tree_view->priv->model != NULL, FALSE);
669
670   ret = _gtk_tree_view_find_node (selection->tree_view,
671                                   path,
672                                   &tree,
673                                   &node);
674
675   if ((node == NULL) || !GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_SELECTED) ||
676       ret == TRUE)
677     return FALSE;
678
679   return TRUE;
680 }
681
682 /**
683  * gtk_tree_selection_iter_is_selected:
684  * @selection: A #GtkTreeSelection
685  * @iter: A valid #GtkTreeIter
686  * 
687  * Returns %TRUE if the row pointed to by @path is currently selected.
688  * 
689  * Return value: %TRUE, if @iter is selected
690  **/
691 gboolean
692 gtk_tree_selection_iter_is_selected (GtkTreeSelection *selection,
693                                      GtkTreeIter      *iter)
694 {
695   GtkTreePath *path;
696   gboolean retval;
697
698   g_return_val_if_fail (GTK_IS_TREE_SELECTION (selection), FALSE);
699   g_return_val_if_fail (iter != NULL, FALSE);
700   g_return_val_if_fail (selection->tree_view != NULL, FALSE);
701   g_return_val_if_fail (selection->tree_view->priv->model != NULL, FALSE);
702
703   path = gtk_tree_model_get_path (selection->tree_view->priv->model, iter);
704   if (path == NULL)
705     return FALSE;
706
707   retval = gtk_tree_selection_path_is_selected (selection, path);
708   gtk_tree_path_free (path);
709
710   return retval;
711 }
712
713
714 /* Wish I was in python, right now... */
715 struct _TempTuple {
716   GtkTreeSelection *selection;
717   gint dirty;
718 };
719
720 static void
721 select_all_helper (GtkRBTree  *tree,
722                    GtkRBNode  *node,
723                    gpointer    data)
724 {
725   struct _TempTuple *tuple = data;
726
727   if (node->children)
728     _gtk_rbtree_traverse (node->children,
729                           node->children->root,
730                           G_PRE_ORDER,
731                           select_all_helper,
732                           data);
733   if (!GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_SELECTED))
734     {
735       tuple->dirty = gtk_tree_selection_real_select_node (tuple->selection, tree, node, TRUE) || tuple->dirty;
736     }
737 }
738
739
740 /* We have a real_{un,}select_all function that doesn't emit the signal, so we
741  * can use it in other places without fear of the signal being emitted.
742  */
743 static gint
744 gtk_tree_selection_real_select_all (GtkTreeSelection *selection)
745 {
746   struct _TempTuple *tuple;
747
748   if (selection->tree_view->priv->tree == NULL)
749     return FALSE;
750
751   /* Mark all nodes selected */
752   tuple = g_new (struct _TempTuple, 1);
753   tuple->selection = selection;
754   tuple->dirty = FALSE;
755
756   _gtk_rbtree_traverse (selection->tree_view->priv->tree,
757                         selection->tree_view->priv->tree->root,
758                         G_PRE_ORDER,
759                         select_all_helper,
760                         tuple);
761   if (tuple->dirty)
762     {
763       g_free (tuple);
764       return TRUE;
765     }
766   g_free (tuple);
767   return FALSE;
768 }
769
770 /**
771  * gtk_tree_selection_select_all:
772  * @selection: A #GtkTreeSelection.
773  *
774  * Selects all the nodes.  @selection is must be set to #GTK_SELECTION_MULTIPLE
775  * mode.
776  **/
777 void
778 gtk_tree_selection_select_all (GtkTreeSelection *selection)
779 {
780   g_return_if_fail (GTK_IS_TREE_SELECTION (selection));
781   g_return_if_fail (selection->tree_view != NULL);
782   if (selection->tree_view->priv->tree == NULL)
783     return;
784   g_return_if_fail (selection->type == GTK_SELECTION_MULTIPLE);
785
786   if (gtk_tree_selection_real_select_all (selection))
787     g_signal_emit (G_OBJECT (selection), tree_selection_signals[CHANGED], 0);
788 }
789
790 static void
791 unselect_all_helper (GtkRBTree  *tree,
792                      GtkRBNode  *node,
793                      gpointer    data)
794 {
795   struct _TempTuple *tuple = data;
796
797   if (node->children)
798     _gtk_rbtree_traverse (node->children,
799                           node->children->root,
800                           G_PRE_ORDER,
801                           unselect_all_helper,
802                           data);
803   if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_SELECTED))
804     {
805       tuple->dirty = gtk_tree_selection_real_select_node (tuple->selection, tree, node, FALSE) || tuple->dirty;
806     }
807 }
808
809 static gint
810 gtk_tree_selection_real_unselect_all (GtkTreeSelection *selection)
811 {
812   struct _TempTuple *tuple;
813
814   if (selection->type == GTK_SELECTION_SINGLE ||
815       selection->type == GTK_SELECTION_BROWSE)
816     {
817       GtkRBTree *tree = NULL;
818       GtkRBNode *node = NULL;
819       GtkTreePath *anchor_path;
820
821       if (selection->tree_view->priv->anchor == NULL)
822         return FALSE;
823
824       anchor_path = gtk_tree_row_reference_get_path (selection->tree_view->priv->anchor);
825
826       if (anchor_path == NULL)
827         return FALSE;
828
829       _gtk_tree_view_find_node (selection->tree_view,
830                                 anchor_path,
831                                 &tree,
832                                 &node);
833
834       gtk_tree_path_free (anchor_path);
835
836       if (tree == NULL)
837         return FALSE;
838
839       if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_SELECTED))
840         {
841           if (gtk_tree_selection_real_select_node (selection, tree, node, FALSE))
842             {
843               gtk_tree_row_reference_free (selection->tree_view->priv->anchor);
844               selection->tree_view->priv->anchor = NULL;
845               return TRUE;
846             }
847         }
848       return FALSE;
849     }
850   else
851     {
852       tuple = g_new (struct _TempTuple, 1);
853       tuple->selection = selection;
854       tuple->dirty = FALSE;
855
856       _gtk_rbtree_traverse (selection->tree_view->priv->tree,
857                             selection->tree_view->priv->tree->root,
858                             G_PRE_ORDER,
859                             unselect_all_helper,
860                             tuple);
861
862       if (tuple->dirty)
863         {
864           g_free (tuple);
865           return TRUE;
866         }
867       g_free (tuple);
868       return FALSE;
869     }
870 }
871
872 /**
873  * gtk_tree_selection_unselect_all:
874  * @selection: A #GtkTreeSelection.
875  *
876  * Unselects all the nodes.
877  **/
878 void
879 gtk_tree_selection_unselect_all (GtkTreeSelection *selection)
880 {
881   g_return_if_fail (GTK_IS_TREE_SELECTION (selection));
882   g_return_if_fail (selection->tree_view != NULL);
883   if (selection->tree_view->priv->tree == NULL)
884     return;
885   
886   if (selection->tree_view->priv->tree == NULL)
887     return;
888
889   if (gtk_tree_selection_real_unselect_all (selection))
890     g_signal_emit (G_OBJECT (selection), tree_selection_signals[CHANGED], 0);
891 }
892
893 static gint
894 gtk_tree_selection_real_select_range (GtkTreeSelection *selection,
895                                       GtkTreePath      *start_path,
896                                       GtkTreePath      *end_path)
897 {
898   GtkRBNode *start_node, *end_node;
899   GtkRBTree *start_tree, *end_tree;
900   gboolean dirty = FALSE;
901
902   switch (gtk_tree_path_compare (start_path, end_path))
903     {
904     case 1:
905       _gtk_tree_view_find_node (selection->tree_view,
906                                 end_path,
907                                 &start_tree,
908                                 &start_node);
909       _gtk_tree_view_find_node (selection->tree_view,
910                                 start_path,
911                                 &end_tree,
912                                 &end_node);
913       break;
914     case 0:
915       _gtk_tree_view_find_node (selection->tree_view,
916                                 start_path,
917                                 &start_tree,
918                                 &start_node);
919       end_tree = start_tree;
920       end_node = start_node;
921       break;
922     case -1:
923       _gtk_tree_view_find_node (selection->tree_view,
924                                 start_path,
925                                 &start_tree,
926                                 &start_node);
927       _gtk_tree_view_find_node (selection->tree_view,
928                                 end_path,
929                                 &end_tree,
930                                 &end_node);
931       break;
932     }
933
934   g_return_val_if_fail (start_node != NULL, FALSE);
935   g_return_val_if_fail (end_node != NULL, FALSE);
936
937   do
938     {
939       dirty |= gtk_tree_selection_real_select_node (selection, start_tree, start_node, TRUE);
940
941       if (start_node == end_node)
942         break;
943
944       if (start_node->children)
945         {
946           start_tree = start_node->children;
947           start_node = start_tree->root;
948           while (start_node->left != start_tree->nil)
949             start_node = start_node->left;
950         }
951       else
952         {
953           _gtk_rbtree_next_full (start_tree, start_node, &start_tree, &start_node);
954           if (start_tree == NULL)
955             {
956               /* we just ran out of tree.  That means someone passed in bogus values.
957                */
958               return dirty;
959             }
960         }
961     }
962   while (TRUE);
963
964   return dirty;
965 }
966
967 /**
968  * gtk_tree_selection_select_range:
969  * @selection: A #GtkTreeSelection.
970  * @start_path: The initial node of the range.
971  * @end_path: The final node of the range.
972  *
973  * Selects a range of nodes, determined by @start_path and @end_path inclusive.
974  **/
975 void
976 gtk_tree_selection_select_range (GtkTreeSelection *selection,
977                                  GtkTreePath      *start_path,
978                                  GtkTreePath      *end_path)
979 {
980   g_return_if_fail (GTK_IS_TREE_SELECTION (selection));
981   g_return_if_fail (selection->tree_view != NULL);
982
983   if (gtk_tree_selection_real_select_range (selection, start_path, end_path))
984     g_signal_emit (G_OBJECT (selection), tree_selection_signals[CHANGED], 0);
985 }
986
987 /* Called internally by gtktreeview.c It handles actually selecting the tree.
988  */
989 void
990 _gtk_tree_selection_internal_select_node (GtkTreeSelection *selection,
991                                           GtkRBNode        *node,
992                                           GtkRBTree        *tree,
993                                           GtkTreePath      *path,
994                                           GdkModifierType   state)
995 {
996   gint flags;
997   gint dirty = FALSE;
998   GtkTreePath *anchor_path = NULL;
999
1000   if (selection->type == GTK_SELECTION_NONE)
1001     return;
1002
1003   if (selection->tree_view->priv->anchor)
1004     anchor_path = gtk_tree_row_reference_get_path (selection->tree_view->priv->anchor);
1005
1006   if (selection->type == GTK_SELECTION_SINGLE ||
1007       selection->type == GTK_SELECTION_BROWSE)
1008     {
1009       /* Did we try to select the same node again? */
1010       if (selection->type == GTK_SELECTION_SINGLE &&
1011           anchor_path && gtk_tree_path_compare (path, anchor_path) == 0)
1012         {
1013           if ((state & GDK_CONTROL_MASK) == GDK_CONTROL_MASK)
1014             {
1015               dirty = gtk_tree_selection_real_unselect_all (selection);
1016             }
1017         }
1018       else
1019         {
1020           if (anchor_path)
1021             {
1022               /* We only want to select the new node if we can unselect the old one,
1023                * and we can select the new one. */
1024               if (selection->user_func)
1025                 {
1026                   if ((*selection->user_func) (selection, selection->tree_view->priv->model, path,
1027                                                GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_SELECTED),
1028                                                selection->user_data))
1029                     dirty = TRUE;
1030                 }
1031               else
1032                 {
1033                   dirty = TRUE;
1034                 }
1035
1036               /* if dirty is FALSE, we weren't able to select the new one, otherwise, we try to
1037                * unselect the new one
1038                */
1039               if (dirty)
1040                 dirty = gtk_tree_selection_real_unselect_all (selection);
1041
1042               /* if dirty is TRUE at this point, we successfully unselected the
1043                * old one, and can then select the new one */
1044               if (dirty)
1045                 {
1046                   if (selection->tree_view->priv->anchor)
1047                     gtk_tree_row_reference_free (selection->tree_view->priv->anchor);
1048                   if (gtk_tree_selection_real_select_node (selection, tree, node, TRUE))
1049                     {
1050                       selection->tree_view->priv->anchor =
1051                         gtk_tree_row_reference_new_proxy (G_OBJECT (selection->tree_view), selection->tree_view->priv->model, path);
1052                     }
1053                 }
1054             }
1055           else
1056             {
1057               if (gtk_tree_selection_real_select_node (selection, tree, node, TRUE))
1058                 {
1059                   dirty = TRUE;
1060                   selection->tree_view->priv->anchor =
1061                     gtk_tree_row_reference_new_proxy (G_OBJECT (selection->tree_view), selection->tree_view->priv->model, path);
1062                 }
1063             }
1064         }
1065     }
1066   else if (selection->type == GTK_SELECTION_MULTIPLE)
1067     {
1068       if (((state & GDK_SHIFT_MASK) == GDK_SHIFT_MASK) && (anchor_path == NULL))
1069         {
1070           if (selection->tree_view->priv->anchor)
1071             gtk_tree_row_reference_free (selection->tree_view->priv->anchor);
1072
1073           selection->tree_view->priv->anchor =
1074             gtk_tree_row_reference_new_proxy (G_OBJECT (selection->tree_view), selection->tree_view->priv->model, path);
1075           dirty = gtk_tree_selection_real_select_node (selection, tree, node, TRUE);
1076         }
1077       else if ((state & (GDK_CONTROL_MASK|GDK_SHIFT_MASK)) == (GDK_SHIFT_MASK|GDK_CONTROL_MASK))
1078         {
1079           gtk_tree_selection_select_range (selection,
1080                                            anchor_path,
1081                                            path);
1082         }
1083       else if ((state & GDK_CONTROL_MASK) == GDK_CONTROL_MASK)
1084         {
1085           flags = node->flags;
1086           if (selection->tree_view->priv->anchor)
1087             gtk_tree_row_reference_free (selection->tree_view->priv->anchor);
1088
1089           selection->tree_view->priv->anchor =
1090             gtk_tree_row_reference_new_proxy (G_OBJECT (selection->tree_view), selection->tree_view->priv->model, path);
1091
1092           if ((flags & GTK_RBNODE_IS_SELECTED) == GTK_RBNODE_IS_SELECTED)
1093             dirty |= gtk_tree_selection_real_select_node (selection, tree, node, FALSE);
1094           else
1095             dirty |= gtk_tree_selection_real_select_node (selection, tree, node, TRUE);
1096         }
1097       else if ((state & GDK_SHIFT_MASK) == GDK_SHIFT_MASK)
1098         {
1099           dirty = gtk_tree_selection_real_unselect_all (selection);
1100           dirty |= gtk_tree_selection_real_select_range (selection,
1101                                                          anchor_path,
1102                                                          path);
1103         }
1104       else
1105         {
1106           dirty = gtk_tree_selection_real_unselect_all (selection);
1107
1108           if (selection->tree_view->priv->anchor)
1109             gtk_tree_row_reference_free (selection->tree_view->priv->anchor);
1110
1111           selection->tree_view->priv->anchor =
1112             gtk_tree_row_reference_new_proxy (G_OBJECT (selection->tree_view), selection->tree_view->priv->model, path);
1113
1114           dirty |= gtk_tree_selection_real_select_node (selection, tree, node, TRUE);
1115         }
1116     }
1117
1118   if (anchor_path)
1119     gtk_tree_path_free (anchor_path);
1120
1121   if (dirty)
1122     g_signal_emit (G_OBJECT (selection), tree_selection_signals[CHANGED], 0);
1123 }
1124
1125 /* NOTE: Any {un,}selection ever done _MUST_ be done through this function!
1126  */
1127
1128 static gint
1129 gtk_tree_selection_real_select_node (GtkTreeSelection *selection,
1130                                      GtkRBTree        *tree,
1131                                      GtkRBNode        *node,
1132                                      gboolean          select)
1133 {
1134   gboolean selected = FALSE;
1135   GtkTreePath *path = NULL;
1136
1137   select = !! select;
1138
1139   if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_SELECTED) != select)
1140     {
1141       path = _gtk_tree_view_find_path (selection->tree_view, tree, node);
1142       if (selection->user_func)
1143         {
1144           if ((*selection->user_func) (selection, selection->tree_view->priv->model, path,
1145                                        GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_SELECTED),
1146                                        selection->user_data))
1147             selected = TRUE;
1148         }
1149       else
1150         selected = TRUE;
1151       gtk_tree_path_free (path);
1152     }
1153
1154   if (selected == TRUE)
1155     {
1156       node->flags ^= GTK_RBNODE_IS_SELECTED;
1157
1158       _gtk_tree_view_queue_draw_node (selection->tree_view, tree, node, NULL);
1159       
1160       return TRUE;
1161     }
1162
1163   return FALSE;
1164 }
1165