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