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