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