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