]> Pileus Git - ~andy/gtk/blob - gtk/gtktreeselection.c
small doc fixes.
[~andy/gtk] / gtk / gtktreeselection.c
1 /* gtktreeselection.h
2  * Copyright (C) 2000  Red Hat, Inc.,  Jonathan Blandford <jrb@redhat.com>
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Library General Public
6  * License as published by the Free Software Foundation; either
7  * version 2 of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * Library General Public License for more details.
13  *
14  * You should have received a copy of the GNU Library General Public
15  * License along with this library; if not, write to the
16  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
17  * Boston, MA 02111-1307, USA.
18  */
19
20 #include "gtktreeselection.h"
21 #include "gtktreeprivate.h"
22 #include "gtkrbtree.h"
23 #include "gtkmarshalers.h"
24
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 GType
46 gtk_tree_selection_get_type (void)
47 {
48   static GType 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 =
66         g_type_register_static (G_TYPE_OBJECT, "GtkTreeSelection",
67                                 &selection_info, 0);
68     }
69
70   return selection_type;
71 }
72
73 static void
74 gtk_tree_selection_class_init (GtkTreeSelectionClass *class)
75 {
76   GObjectClass *object_class;
77
78   object_class = (GObjectClass*) class;
79   parent_class = g_type_class_peek_parent (class);
80
81   object_class->finalize = gtk_tree_selection_finalize;
82   class->changed = NULL;
83
84   tree_selection_signals[CHANGED] =
85     g_signal_new ("changed",
86                   G_OBJECT_CLASS_TYPE (object_class),
87                   G_SIGNAL_RUN_FIRST,
88                   G_STRUCT_OFFSET (GtkTreeSelectionClass, changed),
89                   NULL, NULL,
90                   _gtk_marshal_VOID__VOID,
91                   G_TYPE_NONE, 0);
92 }
93
94 static void
95 gtk_tree_selection_init (GtkTreeSelection *selection)
96 {
97   selection->type = GTK_SELECTION_SINGLE;
98 }
99
100 static void
101 gtk_tree_selection_finalize (GObject *object)
102 {
103   GtkTreeSelection *selection = GTK_TREE_SELECTION (object);
104
105   if (selection->destroy)
106     {
107       GtkDestroyNotify d = selection->destroy;
108
109       selection->destroy = NULL;
110       d (selection->user_data);
111     }
112
113   /* chain parent_class' handler */
114   G_OBJECT_CLASS (parent_class)->finalize (object);
115 }
116
117 /**
118  * _gtk_tree_selection_new:
119  *
120  * Creates a new #GtkTreeSelection object.  This function should not be invoked,
121  * as each #GtkTreeView will create it's own #GtkTreeSelection.
122  *
123  * Return value: A newly created #GtkTreeSelection object.
124  **/
125 GtkTreeSelection*
126 _gtk_tree_selection_new (void)
127 {
128   GtkTreeSelection *selection;
129
130   selection = g_object_new (GTK_TYPE_TREE_SELECTION, NULL);
131
132   return selection;
133 }
134
135 /**
136  * _gtk_tree_selection_new_with_tree_view:
137  * @tree_view: The #GtkTreeView.
138  *
139  * Creates a new #GtkTreeSelection object.  This function should not be invoked,
140  * as each #GtkTreeView will create it's own #GtkTreeSelection.
141  *
142  * Return value: A newly created #GtkTreeSelection object.
143  **/
144 GtkTreeSelection*
145 _gtk_tree_selection_new_with_tree_view (GtkTreeView *tree_view)
146 {
147   GtkTreeSelection *selection;
148
149   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), NULL);
150
151   selection = _gtk_tree_selection_new ();
152   _gtk_tree_selection_set_tree_view (selection, tree_view);
153
154   return selection;
155 }
156
157 /**
158  * _gtk_tree_selection_set_tree_view:
159  * @selection: A #GtkTreeSelection.
160  * @tree_view: The #GtkTreeView.
161  *
162  * Sets the #GtkTreeView of @selection.  This function should not be invoked, as
163  * it is used internally by #GtkTreeView.
164  **/
165 void
166 _gtk_tree_selection_set_tree_view (GtkTreeSelection *selection,
167                                    GtkTreeView      *tree_view)
168 {
169   g_return_if_fail (GTK_IS_TREE_SELECTION (selection));
170   if (tree_view != NULL)
171     g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
172
173   selection->tree_view = tree_view;
174 }
175
176 /**
177  * gtk_tree_selection_set_mode:
178  * @selection: A #GtkTreeSelection.
179  * @type: The selection mode
180  *
181  * Sets the selection mode of the @selection.  If the previous type was
182  * #GTK_SELECTION_MULTIPLE, then the anchor is kept selected, if it was
183  * previously selected.
184  **/
185 void
186 gtk_tree_selection_set_mode (GtkTreeSelection *selection,
187                              GtkSelectionMode  type)
188 {
189   GtkTreeSelectionFunc tmp_func;
190   g_return_if_fail (GTK_IS_TREE_SELECTION (selection));
191
192   if (selection->type == type)
193     return;
194
195   
196   if (type == GTK_SELECTION_NONE)
197     {
198       /* We do this so that we unconditionally unset all rows
199        */
200       tmp_func = selection->user_func;
201       selection->user_func = NULL;
202       gtk_tree_selection_unselect_all (selection);
203       selection->user_func = tmp_func;
204
205       gtk_tree_row_reference_free (selection->tree_view->priv->anchor);
206       selection->tree_view->priv->anchor = NULL;
207     }
208   else if (type == GTK_SELECTION_SINGLE ||
209            type == GTK_SELECTION_BROWSE)
210     {
211       GtkRBTree *tree = NULL;
212       GtkRBNode *node = NULL;
213       gint selected = FALSE;
214       GtkTreePath *anchor_path = NULL;
215
216       if (selection->tree_view->priv->anchor)
217         {
218           anchor_path = gtk_tree_row_reference_get_path (selection->tree_view->priv->anchor);
219
220           if (anchor_path)
221             {
222               _gtk_tree_view_find_node (selection->tree_view,
223                                         anchor_path,
224                                         &tree,
225                                         &node);
226
227               if (node && GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_SELECTED))
228                 selected = TRUE;
229             }
230         }
231
232       /* We do this so that we unconditionally unset all rows
233        */
234       tmp_func = selection->user_func;
235       selection->user_func = NULL;
236       gtk_tree_selection_unselect_all (selection);
237       selection->user_func = tmp_func;
238
239       if (node && selected)
240         _gtk_tree_selection_internal_select_node (selection,
241                                                   node,
242                                                   tree,
243                                                   anchor_path,
244                                                   0,
245                                                   FALSE);
246       if (anchor_path)
247         gtk_tree_path_free (anchor_path);
248     }
249
250   selection->type = type;
251 }
252
253 /**
254  * gtk_tree_selection_get_mode:
255  * @selection: a #GtkTreeSelection
256  *
257  * Gets the selection mode for @selection. See
258  * gtk_tree_selection_set_mode().
259  *
260  * Return value: the current selection mode
261  **/
262 GtkSelectionMode
263 gtk_tree_selection_get_mode (GtkTreeSelection *selection)
264 {
265   g_return_val_if_fail (GTK_IS_TREE_SELECTION (selection), GTK_SELECTION_SINGLE);
266
267   return selection->type;
268 }
269
270 /**
271  * gtk_tree_selection_set_select_function:
272  * @selection: A #GtkTreeSelection.
273  * @func: The selection function.
274  * @data: The selection function's data.
275  * @destroy: The destroy function for user data.  May be NULL.
276  *
277  * Sets the selection function.  If set, this function is called before any node
278  * is selected or unselected, giving some control over which nodes are selected.
279  * The select function should return %TRUE if the state of the node may be toggled,
280  * and %FALSE if the state of the node should be left unchanged.
281  **/
282 void
283 gtk_tree_selection_set_select_function (GtkTreeSelection     *selection,
284                                         GtkTreeSelectionFunc  func,
285                                         gpointer              data,
286                                         GtkDestroyNotify      destroy)
287 {
288   g_return_if_fail (GTK_IS_TREE_SELECTION (selection));
289   g_return_if_fail (func != NULL);
290
291   if (selection->destroy)
292     {
293       GtkDestroyNotify d = selection->destroy;
294
295       selection->destroy = NULL;
296       d (selection->user_data);
297     }
298
299   selection->user_func = func;
300   selection->user_data = data;
301   selection->destroy = destroy;
302 }
303
304 /**
305  * gtk_tree_selection_get_user_data:
306  * @selection: A #GtkTreeSelection.
307  *
308  * Returns the user data for the selection function.
309  *
310  * Return value: The user data.
311  **/
312 gpointer
313 gtk_tree_selection_get_user_data (GtkTreeSelection *selection)
314 {
315   g_return_val_if_fail (GTK_IS_TREE_SELECTION (selection), NULL);
316
317   return selection->user_data;
318 }
319
320 /**
321  * gtk_tree_selection_get_tree_view:
322  * @selection: A #GtkTreeSelection
323  * 
324  * Returns the tree view associated with @selection.
325  * 
326  * Return value: A #GtkTreeView
327  **/
328 GtkTreeView *
329 gtk_tree_selection_get_tree_view (GtkTreeSelection *selection)
330 {
331   g_return_val_if_fail (GTK_IS_TREE_SELECTION (selection), NULL);
332
333   return selection->tree_view;
334 }
335
336 /**
337  * gtk_tree_selection_get_selected:
338  * @selection: A #GtkTreeSelection.
339  * @model: A pointer to set to the #GtkTreeModel, or NULL.
340  * @iter: The #GtkTreeIter, or NULL.
341  *
342  * Sets @iter to the currently selected node if @selection is set to
343  * #GTK_SELECTION_SINGLE or #GTK_SELECTION_BROWSE.  @iter may be NULL if you
344  * just want to test if @selection has any selected nodes.  @model is filled
345  * with the current model as a convenience.  This function will not work if you
346  * use @selection is #GTK_SELECTION_MULTIPLE.
347  *
348  * Return value: TRUE, if there is a selected node.
349  **/
350 gboolean
351 gtk_tree_selection_get_selected (GtkTreeSelection  *selection,
352                                  GtkTreeModel     **model,
353                                  GtkTreeIter       *iter)
354 {
355   GtkRBTree *tree;
356   GtkRBNode *node;
357   GtkTreePath *anchor_path;
358   gboolean retval;
359   gboolean found_node;
360
361   g_return_val_if_fail (GTK_IS_TREE_SELECTION (selection), FALSE);
362   g_return_val_if_fail (selection->type != GTK_SELECTION_MULTIPLE, FALSE);
363   g_return_val_if_fail (selection->tree_view != NULL, FALSE);
364   g_return_val_if_fail (selection->tree_view->priv->model != NULL, FALSE);
365
366   if (model)
367     *model = selection->tree_view->priv->model;
368
369   if (selection->tree_view->priv->anchor == NULL)
370     return FALSE;
371
372   anchor_path = gtk_tree_row_reference_get_path (selection->tree_view->priv->anchor);
373
374   if (anchor_path == NULL)
375     return FALSE;
376
377   retval = FALSE;
378
379   found_node = !_gtk_tree_view_find_node (selection->tree_view,
380                                           anchor_path,
381                                           &tree,
382                                           &node);
383
384   if (found_node && GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_SELECTED))
385     {
386       /* we only want to return the anchor if it exists in the rbtree and
387        * is selected.
388        */
389       if (iter == NULL)
390         retval = TRUE;
391       else
392         retval = gtk_tree_model_get_iter (selection->tree_view->priv->model,
393                                           iter,
394                                           anchor_path);
395     }
396   else
397     {
398       /* We don't want to return the anchor if it isn't actually selected.
399        */
400       retval = FALSE;
401     }
402
403   gtk_tree_path_free (anchor_path);
404
405   return retval;
406 }
407
408 /**
409  * gtk_tree_selection_get_selected_rows:
410  * @selection: A #GtkTreeSelection.
411  * @model: A pointer to set to the #GtkTreeModel, or NULL.
412  *
413  * Creates a list of path of all selected rows. Additionally, if you are
414  * planning on modifying the model after calling this function, you may
415  * want to convert the returned list into a list of #GtkTreeRowReference<!-- -->s.
416  * To do this, you can use gtk_tree_row_reference_new_proxy().
417  *
418  * To free the return value, use:
419  * <informalexample><programlisting>
420  * g_list_foreach (list, gtk_tree_path_free, NULL);
421  * g_list_free (list);
422  * </programlisting></informalexample>
423  *
424  * Return value: A #GList containing a #GtkTreePath for each selected row.
425  **/
426 GList *
427 gtk_tree_selection_get_selected_rows (GtkTreeSelection   *selection,
428                                       GtkTreeModel      **model)
429 {
430   GList *list = NULL;
431   GtkRBTree *tree = NULL;
432   GtkRBNode *node = NULL;
433   GtkTreePath *path;
434
435   g_return_val_if_fail (GTK_IS_TREE_SELECTION (selection), NULL);
436   g_return_val_if_fail (selection->tree_view != NULL, NULL);
437   g_return_val_if_fail (selection->tree_view->priv->model != NULL, NULL);
438
439   if (selection->tree_view->priv->tree == NULL ||
440       selection->tree_view->priv->tree->root == NULL)
441     return NULL;
442
443   if (model)
444     *model = selection->tree_view->priv->model;
445
446   if (selection->type == GTK_SELECTION_NONE)
447     return NULL;
448   else if (selection->type != GTK_SELECTION_MULTIPLE)
449     {
450       GtkTreeIter iter;
451
452       if (gtk_tree_selection_get_selected (selection, NULL, &iter))
453         {
454           GtkTreePath *path;
455
456           path = gtk_tree_model_get_path (*model, &iter);
457           list = g_list_append (list, path);
458
459           return list;
460         }
461
462       return NULL;
463     }
464
465   tree = selection->tree_view->priv->tree;
466   node = selection->tree_view->priv->tree->root;
467
468   while (node->left != tree->nil)
469     node = node->left;
470   path = gtk_tree_path_new_first ();
471
472   do
473     {
474       if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_SELECTED))
475         list = g_list_append (list, gtk_tree_path_copy (path));
476
477       if (node->children)
478         {
479           tree = node->children;
480           node = tree->root;
481
482           while (node->left != tree->nil)
483             node = node->left;
484
485           gtk_tree_path_append_index (path, 0);
486         }
487       else
488         {
489           gboolean done = FALSE;
490
491           do
492             {
493               node = _gtk_rbtree_next (tree, node);
494               if (node != NULL)
495                 {
496                   done = TRUE;
497                   gtk_tree_path_next (path);
498                 }
499               else
500                 {
501                   node = tree->parent_node;
502                   tree = tree->parent_tree;
503
504                   if (!tree)
505                     {
506                       gtk_tree_path_free (path);
507                       return list;
508                     }
509
510                   gtk_tree_path_up (path);
511                 }
512             }
513           while (!done);
514         }
515     }
516   while (TRUE);
517
518   gtk_tree_path_free (path);
519
520   return list;
521 }
522
523 static void
524 gtk_tree_selection_count_selected_rows_helper (GtkRBTree *tree,
525                                                GtkRBNode *node,
526                                                gpointer   data)
527 {
528   gint *count = (gint *)data;
529
530   if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_SELECTED))
531     (*count)++;
532
533   if (node->children)
534     _gtk_rbtree_traverse (node->children, node->children->root,
535                           G_PRE_ORDER,
536                           gtk_tree_selection_count_selected_rows_helper, data);
537 }
538
539 /**
540  * gtk_tree_selection_count_selected_rows:
541  * @selection: A #GtkTreeSelection.
542  *
543  * Returns the number of rows that have been selected in @tree.
544  *
545  * Return value: The number of rows selected.
546  **/
547 gint
548 gtk_tree_selection_count_selected_rows (GtkTreeSelection *selection)
549 {
550   gint count = 0;
551   GtkRBTree *tree;
552   GtkRBNode *node;
553
554   g_return_val_if_fail (GTK_IS_TREE_SELECTION (selection), 0);
555   g_return_val_if_fail (selection->tree_view != NULL, 0);
556   g_return_val_if_fail (selection->tree_view->priv->model != NULL, 0);
557
558   if (selection->tree_view->priv->tree == NULL ||
559       selection->tree_view->priv->tree->root == NULL)
560     return 0;
561
562   if (selection->type == GTK_SELECTION_SINGLE ||
563       selection->type == GTK_SELECTION_BROWSE)
564     {
565       if (gtk_tree_selection_get_selected (selection, NULL, NULL))
566         return 1;
567       else
568         return 0;
569     }
570
571   tree = selection->tree_view->priv->tree;
572   node = selection->tree_view->priv->tree->root;
573
574   _gtk_rbtree_traverse (selection->tree_view->priv->tree,
575                         selection->tree_view->priv->tree->root,
576                         G_PRE_ORDER,
577                         gtk_tree_selection_count_selected_rows_helper,
578                         &count);
579
580   return count;
581 }
582
583 /* gtk_tree_selection_selected_foreach helper */
584 static void
585 model_changed (gpointer data)
586 {
587   gboolean *stop = (gboolean *)data;
588
589   *stop = TRUE;
590 }
591
592 /**
593  * gtk_tree_selection_selected_foreach:
594  * @selection: A #GtkTreeSelection.
595  * @func: The function to call for each selected node.
596  * @data: user data to pass to the function.
597  *
598  * Calls a function for each selected node. Note that you cannot modify
599  * the tree or selection from within this function. As a result,
600  * gtk_tree_selection_get_selected_rows() might be more useful.
601  **/
602 void
603 gtk_tree_selection_selected_foreach (GtkTreeSelection            *selection,
604                                      GtkTreeSelectionForeachFunc  func,
605                                      gpointer                     data)
606 {
607   GtkTreePath *path;
608   GtkRBTree *tree;
609   GtkRBNode *node;
610   GtkTreeIter iter;
611
612   guint inserted_id, deleted_id, reordered_id;
613   gboolean stop = FALSE, has_next = FALSE, has_parent = FALSE;
614
615   g_return_if_fail (GTK_IS_TREE_SELECTION (selection));
616   g_return_if_fail (selection->tree_view != NULL);
617   g_return_if_fail (selection->tree_view->priv->model != NULL);
618
619   if (func == NULL ||
620       selection->tree_view->priv->tree == NULL ||
621       selection->tree_view->priv->tree->root == NULL)
622     return;
623
624   if (selection->type == GTK_SELECTION_SINGLE ||
625       selection->type == GTK_SELECTION_BROWSE)
626     {
627       if (gtk_tree_row_reference_valid (selection->tree_view->priv->anchor))
628         {
629           path = gtk_tree_row_reference_get_path (selection->tree_view->priv->anchor);
630           gtk_tree_model_get_iter (selection->tree_view->priv->model, &iter, path);
631           (* func) (selection->tree_view->priv->model, path, &iter, data);
632           gtk_tree_path_free (path);
633         }
634       return;
635     }
636
637   tree = selection->tree_view->priv->tree;
638   node = selection->tree_view->priv->tree->root;
639   
640   while (node->left != tree->nil)
641     node = node->left;
642
643   /* connect to signals to monitor changes in treemodel */
644   inserted_id = g_signal_connect_swapped (selection->tree_view->priv->model,
645                                           "row_inserted",
646                                           G_CALLBACK (model_changed),
647                                           &stop);
648   deleted_id = g_signal_connect_swapped (selection->tree_view->priv->model,
649                                          "row_deleted",
650                                          G_CALLBACK (model_changed),
651                                          &stop);
652   reordered_id = g_signal_connect_swapped (selection->tree_view->priv->model,
653                                            "rows_reordered",
654                                            G_CALLBACK (model_changed),
655                                            &stop);
656
657   /* find the node internally */
658   path = gtk_tree_path_new_first ();
659   gtk_tree_model_get_iter (selection->tree_view->priv->model,
660                            &iter, path);
661
662   do
663     {
664       if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_SELECTED))
665         (* func) (selection->tree_view->priv->model, path, &iter, data);
666
667       if (stop)
668         goto out;
669
670       if (node->children)
671         {
672           gboolean has_child;
673           GtkTreeIter tmp;
674
675           tree = node->children;
676           node = tree->root;
677           while (node->left != tree->nil)
678             node = node->left;
679           tmp = iter;
680           has_child = gtk_tree_model_iter_children (selection->tree_view->priv->model, &iter, &tmp);
681           gtk_tree_path_append_index (path, 0);
682
683           /* we do the sanity check at the bottom of this function */
684           if (has_child)
685             goto out;
686         }
687       else
688         {
689           gboolean done = FALSE;
690           do
691             {
692               node = _gtk_rbtree_next (tree, node);
693               if (node != NULL)
694                 {
695                   gboolean has_next;
696
697                   has_next = gtk_tree_model_iter_next (selection->tree_view->priv->model, &iter);
698                   done = TRUE;
699                   gtk_tree_path_next (path);
700
701                   /* Sanity Check! */
702                   TREE_VIEW_INTERNAL_ASSERT_VOID (has_next);
703                 }
704               else
705                 {
706                   gboolean has_parent;
707                   GtkTreeIter tmp_iter = iter;
708
709                   node = tree->parent_node;
710                   tree = tree->parent_tree;
711                   if (tree == NULL)
712                     {
713                       /* we've run out of tree */
714                       /* We're done with this function */
715
716                       goto out;
717                     }
718
719                   has_parent = gtk_tree_model_iter_parent (selection->tree_view->priv->model, &iter, &tmp_iter);
720                   gtk_tree_path_up (path);
721
722                   /* we do the sanity check at the bottom of this function */
723                   if (has_parent)
724                     goto out;
725                 }
726             }
727           while (!done);
728         }
729     }
730   while (TRUE);
731
732 out:
733   if (path)
734     gtk_tree_path_free (path);
735
736   g_signal_handler_disconnect (selection->tree_view->priv->model,
737                                inserted_id);
738   g_signal_handler_disconnect (selection->tree_view->priv->model,
739                                deleted_id);
740   g_signal_handler_disconnect (selection->tree_view->priv->model,
741                                reordered_id);
742
743   /* check if we have to spew a scary message */
744   if (has_next)
745     TREE_VIEW_INTERNAL_ASSERT_VOID (has_next);
746   if (has_parent)
747     TREE_VIEW_INTERNAL_ASSERT_VOID (has_parent);
748   if (stop)
749     g_warning
750       ("The model has been modified from within gtk_tree_selection_foreach.\n"
751        "This function is for observing the selections of the tree only.  If\n"
752        "you are trying to get all selected items from the tree, try using\n"
753        "gtk_tree_selection_get_selected_rows instead.\n");
754 }
755
756 /**
757  * gtk_tree_selection_select_path:
758  * @selection: A #GtkTreeSelection.
759  * @path: The #GtkTreePath to be selected.
760  *
761  * Select the row at @path.
762  **/
763 void
764 gtk_tree_selection_select_path (GtkTreeSelection *selection,
765                                 GtkTreePath      *path)
766 {
767   GtkRBNode *node;
768   GtkRBTree *tree;
769   GdkModifierType state = 0;
770   gboolean ret;
771
772   g_return_if_fail (GTK_IS_TREE_SELECTION (selection));
773   g_return_if_fail (selection->tree_view != NULL);
774   g_return_if_fail (path != NULL);
775
776   ret = _gtk_tree_view_find_node (selection->tree_view,
777                                   path,
778                                   &tree,
779                                   &node);
780
781   if (node == NULL || GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_SELECTED) ||
782       ret == TRUE)
783     return;
784
785   if (selection->type == GTK_SELECTION_MULTIPLE)
786     state = GDK_CONTROL_MASK;
787
788   _gtk_tree_selection_internal_select_node (selection,
789                                             node,
790                                             tree,
791                                             path,
792                                             state,
793                                             FALSE);
794 }
795
796 /**
797  * gtk_tree_selection_unselect_path:
798  * @selection: A #GtkTreeSelection.
799  * @path: The #GtkTreePath to be unselected.
800  *
801  * Unselects the row at @path.
802  **/
803 void
804 gtk_tree_selection_unselect_path (GtkTreeSelection *selection,
805                                   GtkTreePath      *path)
806 {
807   GtkRBNode *node;
808   GtkRBTree *tree;
809   gboolean ret;
810
811   g_return_if_fail (GTK_IS_TREE_SELECTION (selection));
812   g_return_if_fail (selection->tree_view != NULL);
813   g_return_if_fail (path != NULL);
814
815   ret = _gtk_tree_view_find_node (selection->tree_view,
816                                   path,
817                                   &tree,
818                                   &node);
819
820   if (node == NULL || !GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_SELECTED) ||
821       ret == TRUE)
822     return;
823
824   _gtk_tree_selection_internal_select_node (selection,
825                                             node,
826                                             tree,
827                                             path,
828                                             GDK_CONTROL_MASK,
829                                             TRUE);
830 }
831
832 /**
833  * gtk_tree_selection_select_iter:
834  * @selection: A #GtkTreeSelection.
835  * @iter: The #GtkTreeIter to be selected.
836  *
837  * Selects the specified iterator.
838  **/
839 void
840 gtk_tree_selection_select_iter (GtkTreeSelection *selection,
841                                 GtkTreeIter      *iter)
842 {
843   GtkTreePath *path;
844
845   g_return_if_fail (GTK_IS_TREE_SELECTION (selection));
846   g_return_if_fail (selection->tree_view != NULL);
847   g_return_if_fail (selection->tree_view->priv->model != NULL);
848   g_return_if_fail (iter != NULL);
849
850   path = gtk_tree_model_get_path (selection->tree_view->priv->model,
851                                   iter);
852
853   if (path == NULL)
854     return;
855
856   gtk_tree_selection_select_path (selection, path);
857   gtk_tree_path_free (path);
858 }
859
860
861 /**
862  * gtk_tree_selection_unselect_iter:
863  * @selection: A #GtkTreeSelection.
864  * @iter: The #GtkTreeIter to be unselected.
865  *
866  * Unselects the specified iterator.
867  **/
868 void
869 gtk_tree_selection_unselect_iter (GtkTreeSelection *selection,
870                                   GtkTreeIter      *iter)
871 {
872   GtkTreePath *path;
873
874   g_return_if_fail (GTK_IS_TREE_SELECTION (selection));
875   g_return_if_fail (selection->tree_view != NULL);
876   g_return_if_fail (selection->tree_view->priv->model != NULL);
877   g_return_if_fail (iter != NULL);
878
879   path = gtk_tree_model_get_path (selection->tree_view->priv->model,
880                                   iter);
881
882   if (path == NULL)
883     return;
884
885   gtk_tree_selection_unselect_path (selection, path);
886   gtk_tree_path_free (path);
887 }
888
889 /**
890  * gtk_tree_selection_path_is_selected:
891  * @selection: A #GtkTreeSelection.
892  * @path: A #GtkTreePath to check selection on.
893  * 
894  * Returns %TRUE if the row pointed to by @path is currently selected.  If @path
895  * does not point to a valid location, %FALSE is returned
896  * 
897  * Return value: %TRUE if @path is selected.
898  **/
899 gboolean
900 gtk_tree_selection_path_is_selected (GtkTreeSelection *selection,
901                                      GtkTreePath      *path)
902 {
903   GtkRBNode *node;
904   GtkRBTree *tree;
905   gboolean ret;
906
907   g_return_val_if_fail (GTK_IS_TREE_SELECTION (selection), FALSE);
908   g_return_val_if_fail (path != NULL, FALSE);
909   g_return_val_if_fail (selection->tree_view != NULL, FALSE);
910   g_return_val_if_fail (selection->tree_view->priv->model != NULL, FALSE);
911
912   ret = _gtk_tree_view_find_node (selection->tree_view,
913                                   path,
914                                   &tree,
915                                   &node);
916
917   if ((node == NULL) || !GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_SELECTED) ||
918       ret == TRUE)
919     return FALSE;
920
921   return TRUE;
922 }
923
924 /**
925  * gtk_tree_selection_iter_is_selected:
926  * @selection: A #GtkTreeSelection
927  * @iter: A valid #GtkTreeIter
928  * 
929  * Returns %TRUE if the row at @iter is currently selected.
930  * 
931  * Return value: %TRUE, if @iter is selected
932  **/
933 gboolean
934 gtk_tree_selection_iter_is_selected (GtkTreeSelection *selection,
935                                      GtkTreeIter      *iter)
936 {
937   GtkTreePath *path;
938   gboolean retval;
939
940   g_return_val_if_fail (GTK_IS_TREE_SELECTION (selection), FALSE);
941   g_return_val_if_fail (iter != NULL, FALSE);
942   g_return_val_if_fail (selection->tree_view != NULL, FALSE);
943   g_return_val_if_fail (selection->tree_view->priv->model != NULL, FALSE);
944
945   path = gtk_tree_model_get_path (selection->tree_view->priv->model, iter);
946   if (path == NULL)
947     return FALSE;
948
949   retval = gtk_tree_selection_path_is_selected (selection, path);
950   gtk_tree_path_free (path);
951
952   return retval;
953 }
954
955
956 /* Wish I was in python, right now... */
957 struct _TempTuple {
958   GtkTreeSelection *selection;
959   gint dirty;
960 };
961
962 static void
963 select_all_helper (GtkRBTree  *tree,
964                    GtkRBNode  *node,
965                    gpointer    data)
966 {
967   struct _TempTuple *tuple = data;
968
969   if (node->children)
970     _gtk_rbtree_traverse (node->children,
971                           node->children->root,
972                           G_PRE_ORDER,
973                           select_all_helper,
974                           data);
975   if (!GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_SELECTED))
976     {
977       tuple->dirty = gtk_tree_selection_real_select_node (tuple->selection, tree, node, TRUE) || tuple->dirty;
978     }
979 }
980
981
982 /* We have a real_{un,}select_all function that doesn't emit the signal, so we
983  * can use it in other places without fear of the signal being emitted.
984  */
985 static gint
986 gtk_tree_selection_real_select_all (GtkTreeSelection *selection)
987 {
988   struct _TempTuple *tuple;
989
990   if (selection->tree_view->priv->tree == NULL)
991     return FALSE;
992
993   /* Mark all nodes selected */
994   tuple = g_new (struct _TempTuple, 1);
995   tuple->selection = selection;
996   tuple->dirty = FALSE;
997
998   _gtk_rbtree_traverse (selection->tree_view->priv->tree,
999                         selection->tree_view->priv->tree->root,
1000                         G_PRE_ORDER,
1001                         select_all_helper,
1002                         tuple);
1003   if (tuple->dirty)
1004     {
1005       g_free (tuple);
1006       return TRUE;
1007     }
1008   g_free (tuple);
1009   return FALSE;
1010 }
1011
1012 /**
1013  * gtk_tree_selection_select_all:
1014  * @selection: A #GtkTreeSelection.
1015  *
1016  * Selects all the nodes.  @selection is must be set to #GTK_SELECTION_MULTIPLE
1017  * mode.
1018  **/
1019 void
1020 gtk_tree_selection_select_all (GtkTreeSelection *selection)
1021 {
1022   g_return_if_fail (GTK_IS_TREE_SELECTION (selection));
1023   g_return_if_fail (selection->tree_view != NULL);
1024   if (selection->tree_view->priv->tree == NULL)
1025     return;
1026   g_return_if_fail (selection->type == GTK_SELECTION_MULTIPLE);
1027
1028   if (gtk_tree_selection_real_select_all (selection))
1029     g_signal_emit (selection, tree_selection_signals[CHANGED], 0);
1030 }
1031
1032 static void
1033 unselect_all_helper (GtkRBTree  *tree,
1034                      GtkRBNode  *node,
1035                      gpointer    data)
1036 {
1037   struct _TempTuple *tuple = data;
1038
1039   if (node->children)
1040     _gtk_rbtree_traverse (node->children,
1041                           node->children->root,
1042                           G_PRE_ORDER,
1043                           unselect_all_helper,
1044                           data);
1045   if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_SELECTED))
1046     {
1047       tuple->dirty = gtk_tree_selection_real_select_node (tuple->selection, tree, node, FALSE) || tuple->dirty;
1048     }
1049 }
1050
1051 static gint
1052 gtk_tree_selection_real_unselect_all (GtkTreeSelection *selection)
1053 {
1054   struct _TempTuple *tuple;
1055
1056   if (selection->type == GTK_SELECTION_SINGLE ||
1057       selection->type == GTK_SELECTION_BROWSE)
1058     {
1059       GtkRBTree *tree = NULL;
1060       GtkRBNode *node = NULL;
1061       GtkTreePath *anchor_path;
1062
1063       if (selection->tree_view->priv->anchor == NULL)
1064         return FALSE;
1065
1066       anchor_path = gtk_tree_row_reference_get_path (selection->tree_view->priv->anchor);
1067
1068       if (anchor_path == NULL)
1069         return FALSE;
1070
1071       _gtk_tree_view_find_node (selection->tree_view,
1072                                 anchor_path,
1073                                 &tree,
1074                                 &node);
1075
1076       gtk_tree_path_free (anchor_path);
1077
1078       if (tree == NULL)
1079         return FALSE;
1080
1081       if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_SELECTED))
1082         {
1083           if (gtk_tree_selection_real_select_node (selection, tree, node, FALSE))
1084             {
1085               gtk_tree_row_reference_free (selection->tree_view->priv->anchor);
1086               selection->tree_view->priv->anchor = NULL;
1087               return TRUE;
1088             }
1089         }
1090       return FALSE;
1091     }
1092   else
1093     {
1094       tuple = g_new (struct _TempTuple, 1);
1095       tuple->selection = selection;
1096       tuple->dirty = FALSE;
1097
1098       _gtk_rbtree_traverse (selection->tree_view->priv->tree,
1099                             selection->tree_view->priv->tree->root,
1100                             G_PRE_ORDER,
1101                             unselect_all_helper,
1102                             tuple);
1103
1104       if (tuple->dirty)
1105         {
1106           g_free (tuple);
1107           return TRUE;
1108         }
1109       g_free (tuple);
1110       return FALSE;
1111     }
1112 }
1113
1114 /**
1115  * gtk_tree_selection_unselect_all:
1116  * @selection: A #GtkTreeSelection.
1117  *
1118  * Unselects all the nodes.
1119  **/
1120 void
1121 gtk_tree_selection_unselect_all (GtkTreeSelection *selection)
1122 {
1123   g_return_if_fail (GTK_IS_TREE_SELECTION (selection));
1124   g_return_if_fail (selection->tree_view != NULL);
1125   if (selection->tree_view->priv->tree == NULL)
1126     return;
1127   
1128   if (selection->tree_view->priv->tree == NULL)
1129     return;
1130
1131   if (gtk_tree_selection_real_unselect_all (selection))
1132     g_signal_emit (selection, tree_selection_signals[CHANGED], 0);
1133 }
1134
1135 enum
1136 {
1137   RANGE_SELECT,
1138   RANGE_UNSELECT
1139 };
1140
1141 static gint
1142 gtk_tree_selection_real_modify_range (GtkTreeSelection *selection,
1143                                       gint              mode,
1144                                       GtkTreePath      *start_path,
1145                                       GtkTreePath      *end_path)
1146 {
1147   GtkRBNode *start_node, *end_node;
1148   GtkRBTree *start_tree, *end_tree;
1149   gboolean dirty = FALSE;
1150
1151   switch (gtk_tree_path_compare (start_path, end_path))
1152     {
1153     case 1:
1154       _gtk_tree_view_find_node (selection->tree_view,
1155                                 end_path,
1156                                 &start_tree,
1157                                 &start_node);
1158       _gtk_tree_view_find_node (selection->tree_view,
1159                                 start_path,
1160                                 &end_tree,
1161                                 &end_node);
1162       break;
1163     case 0:
1164       _gtk_tree_view_find_node (selection->tree_view,
1165                                 start_path,
1166                                 &start_tree,
1167                                 &start_node);
1168       end_tree = start_tree;
1169       end_node = start_node;
1170       break;
1171     case -1:
1172       _gtk_tree_view_find_node (selection->tree_view,
1173                                 start_path,
1174                                 &start_tree,
1175                                 &start_node);
1176       _gtk_tree_view_find_node (selection->tree_view,
1177                                 end_path,
1178                                 &end_tree,
1179                                 &end_node);
1180       break;
1181     }
1182
1183   g_return_val_if_fail (start_node != NULL, FALSE);
1184   g_return_val_if_fail (end_node != NULL, FALSE);
1185
1186   do
1187     {
1188       dirty |= gtk_tree_selection_real_select_node (selection, start_tree, start_node, (mode == RANGE_SELECT)?TRUE:FALSE);
1189
1190       if (start_node == end_node)
1191         break;
1192
1193       if (start_node->children)
1194         {
1195           start_tree = start_node->children;
1196           start_node = start_tree->root;
1197           while (start_node->left != start_tree->nil)
1198             start_node = start_node->left;
1199         }
1200       else
1201         {
1202           _gtk_rbtree_next_full (start_tree, start_node, &start_tree, &start_node);
1203           if (start_tree == NULL)
1204             {
1205               /* we just ran out of tree.  That means someone passed in bogus values.
1206                */
1207               return dirty;
1208             }
1209         }
1210     }
1211   while (TRUE);
1212
1213   return dirty;
1214 }
1215
1216 /**
1217  * gtk_tree_selection_select_range:
1218  * @selection: A #GtkTreeSelection.
1219  * @start_path: The initial node of the range.
1220  * @end_path: The final node of the range.
1221  *
1222  * Selects a range of nodes, determined by @start_path and @end_path inclusive.
1223  **/
1224 void
1225 gtk_tree_selection_select_range (GtkTreeSelection *selection,
1226                                  GtkTreePath      *start_path,
1227                                  GtkTreePath      *end_path)
1228 {
1229   g_return_if_fail (GTK_IS_TREE_SELECTION (selection));
1230   g_return_if_fail (selection->tree_view != NULL);
1231
1232   if (gtk_tree_selection_real_modify_range (selection, RANGE_SELECT, start_path, end_path))
1233     g_signal_emit (selection, tree_selection_signals[CHANGED], 0);
1234 }
1235
1236 /**
1237  * gtk_tree_selection_unselect_range:
1238  * @selection: A #GtkTreeSelection.
1239  * @start_path: The initial node of the range.
1240  * @end_path: The initial node of the range.
1241  *
1242  * Unselects a range of nodes, determined by @start_path and @end_path
1243  * inclusive.
1244  **/
1245 void
1246 gtk_tree_selection_unselect_range (GtkTreeSelection *selection,
1247                                    GtkTreePath      *start_path,
1248                                    GtkTreePath      *end_path)
1249 {
1250   g_return_if_fail (GTK_IS_TREE_SELECTION (selection));
1251   g_return_if_fail (selection->tree_view != NULL);
1252
1253   if (gtk_tree_selection_real_modify_range (selection, RANGE_UNSELECT, start_path, end_path))
1254     g_signal_emit (selection, tree_selection_signals[CHANGED], 0);
1255 }
1256
1257 /* Called internally by gtktreeview.c It handles actually selecting the tree.
1258  */
1259
1260 /*
1261  * docs about the 'override_browse_mode', we set this flag when we want to
1262  * unset select the node and override the select browse mode behaviour (that is
1263  * 'one node should *always* be selected').
1264  */
1265 void
1266 _gtk_tree_selection_internal_select_node (GtkTreeSelection *selection,
1267                                           GtkRBNode        *node,
1268                                           GtkRBTree        *tree,
1269                                           GtkTreePath      *path,
1270                                           GdkModifierType   state,
1271                                           gboolean          override_browse_mode)
1272 {
1273   gint flags;
1274   gint dirty = FALSE;
1275   GtkTreePath *anchor_path = NULL;
1276
1277   if (selection->type == GTK_SELECTION_NONE)
1278     return;
1279
1280   if (selection->tree_view->priv->anchor)
1281     anchor_path = gtk_tree_row_reference_get_path (selection->tree_view->priv->anchor);
1282
1283   if (selection->type == GTK_SELECTION_SINGLE ||
1284       selection->type == GTK_SELECTION_BROWSE)
1285     {
1286       /* just unselect */
1287       if (selection->type == GTK_SELECTION_BROWSE && override_browse_mode)
1288         {
1289           dirty = gtk_tree_selection_real_unselect_all (selection);
1290         }
1291       /* Did we try to select the same node again? */
1292       else if (selection->type == GTK_SELECTION_SINGLE &&
1293                anchor_path && gtk_tree_path_compare (path, anchor_path) == 0)
1294         {
1295           if ((state & GDK_CONTROL_MASK) == GDK_CONTROL_MASK)
1296             {
1297               dirty = gtk_tree_selection_real_unselect_all (selection);
1298             }
1299         }
1300       else
1301         {
1302           if (anchor_path)
1303             {
1304               /* We only want to select the new node if we can unselect the old one,
1305                * and we can select the new one. */
1306               if (selection->user_func)
1307                 {
1308                   if ((*selection->user_func) (selection, selection->tree_view->priv->model, path,
1309                                                GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_SELECTED),
1310                                                selection->user_data))
1311                     dirty = TRUE;
1312                 }
1313               else
1314                 {
1315                   dirty = TRUE;
1316                 }
1317
1318               /* if dirty is FALSE, we weren't able to select the new one, otherwise, we try to
1319                * unselect the new one
1320                */
1321               if (dirty)
1322                 dirty = gtk_tree_selection_real_unselect_all (selection);
1323
1324               /* if dirty is TRUE at this point, we successfully unselected the
1325                * old one, and can then select the new one */
1326               if (dirty)
1327                 {
1328                   if (selection->tree_view->priv->anchor)
1329                     gtk_tree_row_reference_free (selection->tree_view->priv->anchor);
1330                   if (gtk_tree_selection_real_select_node (selection, tree, node, TRUE))
1331                     {
1332                       selection->tree_view->priv->anchor =
1333                         gtk_tree_row_reference_new_proxy (G_OBJECT (selection->tree_view), selection->tree_view->priv->model, path);
1334                     }
1335                 }
1336             }
1337           else
1338             {
1339               if (gtk_tree_selection_real_select_node (selection, tree, node, TRUE))
1340                 {
1341                   dirty = TRUE;
1342                   if (selection->tree_view->priv->anchor)
1343                     gtk_tree_row_reference_free (selection->tree_view->priv->anchor);
1344
1345                   selection->tree_view->priv->anchor =
1346                     gtk_tree_row_reference_new_proxy (G_OBJECT (selection->tree_view), selection->tree_view->priv->model, path);
1347                 }
1348             }
1349         }
1350     }
1351   else if (selection->type == GTK_SELECTION_MULTIPLE)
1352     {
1353       if (((state & GDK_SHIFT_MASK) == GDK_SHIFT_MASK) && (anchor_path == NULL))
1354         {
1355           if (selection->tree_view->priv->anchor)
1356             gtk_tree_row_reference_free (selection->tree_view->priv->anchor);
1357
1358           selection->tree_view->priv->anchor =
1359             gtk_tree_row_reference_new_proxy (G_OBJECT (selection->tree_view), selection->tree_view->priv->model, path);
1360           dirty = gtk_tree_selection_real_select_node (selection, tree, node, TRUE);
1361         }
1362       else if ((state & (GDK_CONTROL_MASK|GDK_SHIFT_MASK)) == (GDK_SHIFT_MASK|GDK_CONTROL_MASK))
1363         {
1364           gtk_tree_selection_select_range (selection,
1365                                            anchor_path,
1366                                            path);
1367         }
1368       else if ((state & GDK_CONTROL_MASK) == GDK_CONTROL_MASK)
1369         {
1370           flags = node->flags;
1371           if (selection->tree_view->priv->anchor)
1372             gtk_tree_row_reference_free (selection->tree_view->priv->anchor);
1373
1374           selection->tree_view->priv->anchor =
1375             gtk_tree_row_reference_new_proxy (G_OBJECT (selection->tree_view), selection->tree_view->priv->model, path);
1376
1377           if ((flags & GTK_RBNODE_IS_SELECTED) == GTK_RBNODE_IS_SELECTED)
1378             dirty |= gtk_tree_selection_real_select_node (selection, tree, node, FALSE);
1379           else
1380             dirty |= gtk_tree_selection_real_select_node (selection, tree, node, TRUE);
1381         }
1382       else if ((state & GDK_SHIFT_MASK) == GDK_SHIFT_MASK)
1383         {
1384           dirty = gtk_tree_selection_real_unselect_all (selection);
1385           dirty |= gtk_tree_selection_real_modify_range (selection,
1386                                                          RANGE_SELECT,
1387                                                          anchor_path,
1388                                                          path);
1389         }
1390       else
1391         {
1392           dirty = gtk_tree_selection_real_unselect_all (selection);
1393
1394           if (selection->tree_view->priv->anchor)
1395             gtk_tree_row_reference_free (selection->tree_view->priv->anchor);
1396
1397           selection->tree_view->priv->anchor =
1398             gtk_tree_row_reference_new_proxy (G_OBJECT (selection->tree_view), selection->tree_view->priv->model, path);
1399
1400           dirty |= gtk_tree_selection_real_select_node (selection, tree, node, TRUE);
1401         }
1402     }
1403
1404   if (anchor_path)
1405     gtk_tree_path_free (anchor_path);
1406
1407   if (dirty)
1408     g_signal_emit (selection, tree_selection_signals[CHANGED], 0);
1409 }
1410
1411 /* NOTE: Any {un,}selection ever done _MUST_ be done through this function!
1412  */
1413
1414 static gint
1415 gtk_tree_selection_real_select_node (GtkTreeSelection *selection,
1416                                      GtkRBTree        *tree,
1417                                      GtkRBNode        *node,
1418                                      gboolean          select)
1419 {
1420   gboolean selected = FALSE;
1421   GtkTreePath *path = NULL;
1422
1423   select = !! select;
1424
1425   if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_SELECTED) != select)
1426     {
1427       path = _gtk_tree_view_find_path (selection->tree_view, tree, node);
1428       if (selection->user_func)
1429         {
1430           if ((*selection->user_func) (selection, selection->tree_view->priv->model, path,
1431                                        GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_SELECTED),
1432                                        selection->user_data))
1433             selected = TRUE;
1434         }
1435       else
1436         selected = TRUE;
1437       gtk_tree_path_free (path);
1438     }
1439
1440   if (selected == TRUE)
1441     {
1442       node->flags ^= GTK_RBNODE_IS_SELECTED;
1443
1444       _gtk_tree_view_queue_draw_node (selection->tree_view, tree, node, NULL);
1445       
1446       return TRUE;
1447     }
1448
1449   return FALSE;
1450 }
1451