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