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