]> Pileus Git - ~andy/gtk/blob - gtk/gtktreeselection.c
802d806ecfd99f1694192dea4bb8ecab9f5ff0ba
[~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 static gint gtk_tree_selection_real_select_all   (GtkTreeSelection      *selection);
28 static gint gtk_tree_selection_real_unselect_all (GtkTreeSelection      *selection);
29 static gint gtk_tree_selection_real_select_node  (GtkTreeSelection      *selection,
30                                                   GtkRBTree             *tree,
31                                                   GtkRBNode             *node,
32                                                   gboolean               select);
33
34 enum {
35   SELECTION_CHANGED,
36   LAST_SIGNAL
37 };
38
39 static GtkObjectClass *parent_class = NULL;
40 static guint tree_selection_signals[LAST_SIGNAL] = { 0 };
41
42 GtkType
43 gtk_tree_selection_get_type (void)
44 {
45   static GtkType selection_type = 0;
46
47   if (!selection_type)
48     {
49       static const GTypeInfo selection_info =
50       {
51         sizeof (GtkTreeSelectionClass),
52         NULL,           /* base_init */
53         NULL,           /* base_finalize */
54         (GClassInitFunc) gtk_tree_selection_class_init,
55         NULL,           /* class_finalize */
56         NULL,           /* class_data */
57         sizeof (GtkTreeSelection),
58         0,              /* n_preallocs */
59         (GInstanceInitFunc) gtk_tree_selection_init
60       };
61
62       selection_type = g_type_register_static (GTK_TYPE_OBJECT, "GtkTreeSelection", &selection_info, 0);
63     }
64
65   return selection_type;
66 }
67
68 static void
69 gtk_tree_selection_class_init (GtkTreeSelectionClass *class)
70 {
71   GtkObjectClass *object_class;
72
73   object_class = (GtkObjectClass*) class;
74   parent_class = g_type_class_peek_parent (class);
75
76   tree_selection_signals[SELECTION_CHANGED] =
77     gtk_signal_new ("selection_changed",
78                     GTK_RUN_FIRST,
79                     GTK_CLASS_TYPE (object_class),
80                     GTK_SIGNAL_OFFSET (GtkTreeSelectionClass, selection_changed),
81                     gtk_marshal_VOID__VOID,
82                     GTK_TYPE_NONE, 0);
83
84   gtk_object_class_add_signals (object_class, tree_selection_signals, LAST_SIGNAL);
85
86   class->selection_changed = NULL;
87 }
88
89 static void
90 gtk_tree_selection_init (GtkTreeSelection *selection)
91 {
92   selection->type = GTK_TREE_SELECTION_SINGLE;
93 }
94
95 /**
96  * gtk_tree_selection_new:
97  * @void: 
98  * 
99  * Creates a new #GtkTreeSelection object.  This function should not be invoked,
100  * as each #GtkTreeView will create it's own #GtkTreeSelection.
101  * 
102  * Return value: A newly created #GtkTreeSelection object.
103  **/
104 GtkObject *
105 gtk_tree_selection_new (void)
106 {
107   GtkObject *selection;
108
109   selection = GTK_OBJECT (gtk_type_new (GTK_TYPE_TREE_SELECTION));
110
111   return selection;
112 }
113
114 /**
115  * gtk_tree_selection_new_with_tree_view:
116  * @tree_view: The #GtkTreeView.
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 GtkObject *
124 gtk_tree_selection_new_with_tree_view (GtkTreeView *tree_view)
125 {
126   GtkObject *selection;
127
128   g_return_val_if_fail (tree_view != NULL, NULL);
129   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), NULL);
130
131   selection = gtk_tree_selection_new ();
132   gtk_tree_selection_set_tree_view (GTK_TREE_SELECTION (selection), tree_view);
133
134   return selection;
135 }
136
137 /**
138  * gtk_tree_selection_set_tree_view:
139  * @selection: A #GtkTreeSelection.
140  * @tree_view: The #GtkTreeView.
141  * 
142  * Sets the #GtkTreeView of @selection.  This function should not be invoked, as
143  * it is used internally by #GtkTreeView.
144  **/
145 void
146 gtk_tree_selection_set_tree_view (GtkTreeSelection *selection,
147                                   GtkTreeView      *tree_view)
148 {
149   g_return_if_fail (selection != NULL);
150   g_return_if_fail (GTK_IS_TREE_SELECTION (selection));
151   if (tree_view != NULL)
152     g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
153
154   selection->tree_view = tree_view;
155   tree_view->priv->selection = selection;
156 }
157
158 /**
159  * gtk_tree_selection_set_type:
160  * @selection: A #GtkTreeSelection.
161  * @type: The selection type.
162  * 
163  * Sets the selection type of the @selection.  If the previous type was
164  * #GTK_TREE_SELECTION_MULTI and @type is #GTK_TREE_SELECTION_SINGLE, then
165  * the anchor is kept selected, if it was previously selected.
166  **/
167 void
168 gtk_tree_selection_set_type (GtkTreeSelection     *selection,
169                              GtkTreeSelectionType  type)
170 {
171   g_return_if_fail (selection != NULL);
172   g_return_if_fail (GTK_IS_TREE_SELECTION (selection));
173
174   if (selection->type == type)
175     return;
176
177   if (type == GTK_TREE_SELECTION_SINGLE)
178     {
179       GtkRBTree *tree = NULL;
180       GtkRBNode *node = NULL;
181       gint selected = FALSE;
182
183       if (selection->tree_view->priv->anchor)
184         {
185           _gtk_tree_view_find_node (selection->tree_view,
186                                     selection->tree_view->priv->anchor,
187                                     &tree,
188                                     &node);
189
190           if (node && GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_SELECTED))
191             selected = TRUE;
192         }
193       /* FIXME: if user_func is set, then it needs to unconditionally unselect
194        * all.
195        */
196       gtk_tree_selection_unselect_all (selection);
197       if (node && selected)
198         GTK_RBNODE_SET_FLAG (node, GTK_RBNODE_IS_SELECTED);
199     }
200   selection->type = type;
201 }
202
203 /**
204  * gtk_tree_selection_set_select_function:
205  * @selection: A #GtkTreeSelection.
206  * @func: The selection function.
207  * @data: The selection function's data.
208  * 
209  * Sets the selection function.  If set, this function is called before any node
210  * is selected or unselected, giving some control over which nodes are selected.
211  **/
212 void
213 gtk_tree_selection_set_select_function (GtkTreeSelection     *selection,
214                                         GtkTreeSelectionFunc  func,
215                                         gpointer              data)
216 {
217   g_return_if_fail (selection != NULL);
218   g_return_if_fail (GTK_IS_TREE_SELECTION (selection));
219   g_return_if_fail (func != NULL);
220
221   selection->user_func = func;
222   selection->user_data = data;
223 }
224
225 /**
226  * gtk_tree_selection_get_user_data:
227  * @selection: A #GtkTreeSelection.
228  * 
229  * Returns the user data for the selection function.
230  * 
231  * Return value: The user data.
232  **/
233 gpointer
234 gtk_tree_selection_get_user_data (GtkTreeSelection *selection)
235 {
236   g_return_val_if_fail (selection != NULL, NULL);
237   g_return_val_if_fail (GTK_IS_TREE_SELECTION (selection), NULL);
238
239   return selection->user_data;
240 }
241
242 /**
243  * gtk_tree_selection_get_selected:
244  * @selection: A #GtkTreeSelection.
245  * 
246  * Returns the currently selected node if @selection is set to
247  * #GTK_TREE_SELECTION_SINGLE.  Otherwise, it returns the anchor.
248  * 
249  * Return value: The selected #GtkTreeNode.
250  **/
251 GtkTreeNode
252 gtk_tree_selection_get_selected (GtkTreeSelection *selection)
253 {
254   GtkTreeNode *retval;
255   GtkRBTree *tree;
256   GtkRBNode *node;
257
258   g_return_val_if_fail (selection != NULL, NULL);
259   g_return_val_if_fail (GTK_IS_TREE_SELECTION (selection), NULL);
260
261   if (selection->tree_view->priv->anchor == NULL)
262     return NULL;
263
264   g_return_val_if_fail (selection->tree_view != NULL, NULL);
265   g_return_val_if_fail (selection->tree_view->priv->model != NULL, NULL);
266
267   if (!_gtk_tree_view_find_node (selection->tree_view,
268                                 selection->tree_view->priv->anchor,
269                                 &tree,
270                                 &node) &&
271       ! GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_SELECTED))
272     /* We don't want to return the anchor if it isn't actually selected.
273      */
274
275       return NULL;
276
277   retval = gtk_tree_model_get_node (selection->tree_view->priv->model,
278                                     selection->tree_view->priv->anchor);
279   return retval;
280 }
281
282 /**
283  * gtk_tree_selection_selected_foreach:
284  * @selection: A #GtkTreeSelection.
285  * @func: The function to call for each selected node.
286  * @data: user data to pass to the function.
287  * 
288  * Calls a function for each selected node.
289  **/
290 void
291 gtk_tree_selection_selected_foreach (GtkTreeSelection            *selection,
292                                      GtkTreeSelectionForeachFunc  func,
293                                      gpointer                     data)
294 {
295   GtkTreePath *path;
296   GtkRBTree *tree;
297   GtkRBNode *node;
298   GtkTreeNode tree_node;
299
300   g_return_if_fail (selection != NULL);
301   g_return_if_fail (GTK_IS_TREE_SELECTION (selection));
302   g_return_if_fail (selection->tree_view != NULL);
303   g_return_if_fail (selection->tree_view->priv->model != NULL);
304
305   if (func == NULL ||
306       selection->tree_view->priv->tree == NULL ||
307       selection->tree_view->priv->tree->root == NULL)
308     return;
309
310   tree = selection->tree_view->priv->tree;
311   node = selection->tree_view->priv->tree->root;
312
313   while (node->left != tree->nil)
314     node = node->left;
315
316   /* find the node internally */
317   path = gtk_tree_path_new_root ();
318   tree_node = gtk_tree_model_get_node (selection->tree_view->priv->model, path);
319   gtk_tree_path_free (path);
320
321   do
322     {
323       if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_SELECTED))
324         (* func) (selection->tree_view->priv->model, tree_node, data);
325       if (node->children)
326         {
327           tree = node->children;
328           node = tree->root;
329           while (node->left != tree->nil)
330             node = node->left;
331           tree_node = gtk_tree_model_node_children (selection->tree_view->priv->model, tree_node);
332
333           /* Sanity Check! */
334           TREE_VIEW_INTERNAL_ASSERT_VOID (tree_node != NULL);
335         }
336       else
337         {
338           gboolean done = FALSE;
339           do
340             {
341               node = _gtk_rbtree_next (tree, node);
342               if (node != NULL)
343                 {
344                   gtk_tree_model_node_next (selection->tree_view->priv->model, &tree_node);
345                   done = TRUE;
346
347                   /* Sanity Check! */
348                   TREE_VIEW_INTERNAL_ASSERT_VOID (tree_node != NULL);
349                 }
350               else
351                 {
352                   node = tree->parent_node;
353                   tree = tree->parent_tree;
354                   if (tree == NULL)
355                     /* we've run out of tree */
356                     /* We're done with this function */
357                     return;
358                   tree_node = gtk_tree_model_node_parent (selection->tree_view->priv->model, tree_node);
359
360                   /* Sanity check */
361                   TREE_VIEW_INTERNAL_ASSERT_VOID (tree_node != NULL);
362                 }
363             }
364           while (!done);
365         }
366     }
367   while (TRUE);
368 }
369
370 /**
371  * gtk_tree_selection_select_path:
372  * @selection: A #GtkTreeSelection.
373  * @path: The #GtkTreePath to be selected.
374  * 
375  * Select the row at @path.
376  **/
377 void
378 gtk_tree_selection_select_path (GtkTreeSelection *selection,
379                                 GtkTreePath      *path)
380 {
381   GtkRBNode *node;
382   GtkRBTree *tree;
383   GdkModifierType state = 0;
384
385   g_return_if_fail (selection != NULL);
386   g_return_if_fail (GTK_IS_TREE_SELECTION (selection));
387   g_return_if_fail (selection->tree_view != NULL);
388   g_return_if_fail (path != NULL);
389
390   _gtk_tree_view_find_node (selection->tree_view,
391                             path,
392                             &tree,
393                             &node);
394
395   if (node == NULL || GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_SELECTED))
396     return;
397
398   if (selection->type == GTK_TREE_SELECTION_MULTI)
399     state = GDK_CONTROL_MASK;
400
401   _gtk_tree_selection_internal_select_node (selection,
402                                             node,
403                                             tree,
404                                             path,
405                                             state);
406 }
407
408 /**
409  * gtk_tree_selection_unselect_path:
410  * @selection: A #GtkTreeSelection.
411  * @path: The #GtkTreePath to be unselected.
412  * 
413  * Unselects the row at @path.
414  **/
415 void
416 gtk_tree_selection_unselect_path (GtkTreeSelection *selection,
417                                   GtkTreePath      *path)
418 {
419   GtkRBNode *node;
420   GtkRBTree *tree;
421
422   g_return_if_fail (selection != NULL);
423   g_return_if_fail (GTK_IS_TREE_SELECTION (selection));
424   g_return_if_fail (selection->tree_view != NULL);
425   g_return_if_fail (path != NULL);
426
427   _gtk_tree_view_find_node (selection->tree_view,
428                             path,
429                             &tree,
430                             &node);
431
432   if (node == NULL || !GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_SELECTED))
433     return;
434
435   _gtk_tree_selection_internal_select_node (selection,
436                                             node,
437                                             tree,
438                                             path,
439                                             GDK_CONTROL_MASK);
440 }
441
442 /**
443  * gtk_tree_selection_select_node:
444  * @selection: A #GtkTreeSelection.
445  * @tree_node: The #GtkTreeNode to be selected.
446  * 
447  * Selects the specified node.
448  **/
449 void
450 gtk_tree_selection_select_node (GtkTreeSelection *selection,
451                                 GtkTreeNode       tree_node)
452 {
453   GtkTreePath *path;
454
455   g_return_if_fail (selection != NULL);
456   g_return_if_fail (GTK_IS_TREE_SELECTION (selection));
457   g_return_if_fail (selection->tree_view != NULL);
458   g_return_if_fail (selection->tree_view->priv->model != NULL);
459
460   path = gtk_tree_model_get_path (selection->tree_view->priv->model,
461                                   tree_node);
462
463   if (path == NULL)
464     return;
465
466   gtk_tree_selection_select_path (selection, path);
467   gtk_tree_path_free (path);
468 }
469
470
471 /**
472  * gtk_tree_selection_unselect_node:
473  * @selection: A #GtkTreeSelection.
474  * @tree_node: The #GtkTreeNode to be unselected.
475  * 
476  * Unselects the specified node.
477  **/
478 void
479 gtk_tree_selection_unselect_node (GtkTreeSelection *selection,
480                                   GtkTreeNode       tree_node)
481 {
482   GtkTreePath *path;
483
484   g_return_if_fail (selection != NULL);
485   g_return_if_fail (GTK_IS_TREE_SELECTION (selection));
486   g_return_if_fail (selection->tree_view != NULL);
487
488   path = gtk_tree_model_get_path (selection->tree_view->priv->model,
489                                   tree_node);
490
491   if (path == NULL)
492     return;
493
494   gtk_tree_selection_select_path (selection, path);
495   gtk_tree_path_free (path);
496 }
497
498 /* Wish I was in python, right now... */
499 struct _TempTuple {
500   GtkTreeSelection *selection;
501   gint dirty;
502 };
503
504 static void
505 select_all_helper (GtkRBTree  *tree,
506                    GtkRBNode  *node,
507                    gpointer    data)
508 {
509   struct _TempTuple *tuple = data;
510
511   if (node->children)
512     _gtk_rbtree_traverse (node->children,
513                           node->children->root,
514                           G_PRE_ORDER,
515                           select_all_helper,
516                           data);
517   if (!GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_SELECTED))
518     {
519       tuple->dirty = gtk_tree_selection_real_select_node (tuple->selection, tree, node, TRUE) || tuple->dirty;
520     }
521 }
522
523
524 /* We have a real_{un,}select_all function that doesn't emit the signal, so we
525  * can use it in other places without fear of the signal being emitted.
526  */
527 static gint
528 gtk_tree_selection_real_select_all (GtkTreeSelection *selection)
529 {
530   struct _TempTuple *tuple;
531   if (selection->tree_view->priv->tree == NULL)
532     return FALSE;
533
534   if (selection->type == GTK_TREE_SELECTION_SINGLE)
535     {
536       GtkRBTree *tree;
537       GtkRBNode *node;
538       gint dirty;
539       
540       dirty = gtk_tree_selection_real_unselect_all (selection);
541
542       tree = selection->tree_view->priv->tree;
543       node = tree->root;
544       do
545         {
546           while (node->right != selection->tree_view->priv->tree->nil)
547             node = node->right;
548
549           if (node->children)
550             {
551               tree = node->children;
552               node = tree->root;
553             }
554           else
555             break;
556         } while (TRUE);
557
558       dirty |= gtk_tree_selection_real_select_node (selection, tree, node, TRUE);
559
560       return dirty;
561     }
562
563   tuple = g_new (struct _TempTuple, 1);
564   tuple->selection = selection;
565   tuple->dirty = FALSE;
566
567   _gtk_rbtree_traverse (selection->tree_view->priv->tree,
568                         selection->tree_view->priv->tree->root,
569                         G_PRE_ORDER,
570                         select_all_helper,
571                         tuple);
572   if (tuple->dirty)
573     {
574       g_free (tuple);
575       return TRUE;
576     }
577   g_free (tuple);
578   return FALSE;
579 }
580
581 /**
582  * gtk_tree_selection_select_all:
583  * @selection: A #GtkTreeSelection.
584  * 
585  * Selects all the nodes.  If the type of @selection is
586  * #GTK_TREE_SELECTION_SINGLE, then the last row is selected.
587  **/
588 void
589 gtk_tree_selection_select_all (GtkTreeSelection *selection)
590 {
591   g_return_if_fail (selection != NULL);
592   g_return_if_fail (GTK_IS_TREE_SELECTION (selection));
593   g_return_if_fail (selection->tree_view != NULL);
594   g_return_if_fail (selection->tree_view->priv->tree != NULL);
595
596   if (gtk_tree_selection_real_select_all (selection))
597     gtk_signal_emit (GTK_OBJECT (selection), tree_selection_signals[SELECTION_CHANGED]);
598 }
599
600 static void
601 unselect_all_helper (GtkRBTree  *tree,
602                      GtkRBNode  *node,
603                      gpointer    data)
604 {
605   struct _TempTuple *tuple = data;
606
607   if (node->children)
608     _gtk_rbtree_traverse (node->children,
609                           node->children->root,
610                           G_PRE_ORDER,
611                           unselect_all_helper,
612                           data);
613   if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_SELECTED))
614     {
615       tuple->dirty = gtk_tree_selection_real_select_node (tuple->selection, tree, node, FALSE) || tuple->dirty;
616     }
617 }
618
619 static gint
620 gtk_tree_selection_real_unselect_all (GtkTreeSelection *selection)
621 {
622   struct _TempTuple *tuple;
623
624   if (selection->type == GTK_TREE_SELECTION_SINGLE)
625     {
626       GtkRBTree *tree = NULL;
627       GtkRBNode *node = NULL;
628       if (selection->tree_view->priv->anchor == NULL)
629         return FALSE;
630
631       _gtk_tree_view_find_node (selection->tree_view,
632                                 selection->tree_view->priv->anchor,
633                                 &tree,
634                                 &node);
635       if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_SELECTED))
636         {
637           gtk_tree_selection_real_select_node (selection, tree, node, FALSE);
638           return TRUE;
639         }
640       return FALSE;
641     }
642
643   tuple = g_new (struct _TempTuple, 1);
644   tuple->selection = selection;
645   tuple->dirty = FALSE;
646
647   _gtk_rbtree_traverse (selection->tree_view->priv->tree,
648                         selection->tree_view->priv->tree->root,
649                         G_PRE_ORDER,
650                         unselect_all_helper,
651                         tuple);
652
653   if (tuple->dirty)
654     {
655       g_free (tuple);
656       return TRUE;
657     }
658   g_free (tuple);
659   return FALSE;
660 }
661
662 /**
663  * gtk_tree_selection_unselect_all:
664  * @selection: A #GtkTreeSelection.
665  * 
666  * Unselects all the nodes.
667  **/
668 void
669 gtk_tree_selection_unselect_all (GtkTreeSelection *selection)
670 {
671   g_return_if_fail (selection != NULL);
672   g_return_if_fail (GTK_IS_TREE_SELECTION (selection));
673   g_return_if_fail (selection->tree_view != NULL);
674   g_return_if_fail (selection->tree_view->priv->tree != NULL);
675   if (selection->tree_view->priv->tree == NULL)
676     return;
677
678   if (gtk_tree_selection_real_unselect_all (selection))
679     gtk_signal_emit (GTK_OBJECT (selection), tree_selection_signals[SELECTION_CHANGED]);
680 }
681
682 static gint
683 gtk_tree_selection_real_select_range (GtkTreeSelection *selection,
684                                       GtkTreePath      *start_path,
685                                       GtkTreePath      *end_path)
686 {
687   GtkRBNode *start_node, *end_node;
688   GtkRBTree *start_tree, *end_tree;
689   gboolean dirty = FALSE;
690
691   switch (gtk_tree_path_compare (start_path, end_path))
692     {
693     case -1:
694       _gtk_tree_view_find_node (selection->tree_view,
695                                 end_path,
696                                 &start_tree,
697                                 &start_node);
698       _gtk_tree_view_find_node (selection->tree_view,
699                                 start_path,
700                                 &end_tree,
701                                 &end_node);
702       break;
703     case 0:
704       _gtk_tree_view_find_node (selection->tree_view,
705                                 start_path,
706                                 &start_tree,
707                                 &start_node);
708       end_tree = start_tree;
709       end_node = start_node;
710       break;
711     case 1:
712       _gtk_tree_view_find_node (selection->tree_view,
713                                 start_path,
714                                 &start_tree,
715                                 &start_node);
716       _gtk_tree_view_find_node (selection->tree_view,
717                                 end_path,
718                                 &end_tree,
719                                 &end_node);
720       break;
721     }
722
723   g_return_val_if_fail (start_node != NULL, FALSE);
724   g_return_val_if_fail (end_node != NULL, FALSE);
725
726   do
727     {
728       if (GTK_RBNODE_FLAG_SET (start_node, GTK_RBNODE_IS_SELECTED))
729         {
730           dirty = gtk_tree_selection_real_select_node (selection, start_tree, start_node, FALSE);
731         }
732
733       if (start_node == end_node)
734         break;
735
736       if (start_node->children)
737         {
738           start_tree = start_node->children;
739           start_node = start_tree->root;
740           while (start_node->left != start_tree->nil)
741             start_node = start_node->left;
742         }
743       else
744         {
745           gboolean done = FALSE;
746           do
747             {
748               start_node = _gtk_rbtree_next (start_tree, start_node);
749               if (start_node != NULL)
750                 {
751                   done = TRUE;
752                 }
753               else
754                 {
755                   start_node = start_tree->parent_node;
756                   start_tree = start_tree->parent_tree;
757                   if (start_tree == NULL)
758                     /* we've run out of tree */
759                     /* This means we never found end node!! */
760                     break;
761                 }
762             }
763           while (!done);
764         }
765     }
766   while (TRUE);
767
768   return dirty;
769 }
770
771 /**
772  * gtk_tree_selection_select_range:
773  * @selection: A #GtkTreeSelection.
774  * @start_path: The initial node of the range.
775  * @end_path: The final node of the range.
776  * 
777  * Selects a range of nodes, determined by @start_path and @end_path inclusive.
778  **/
779 void
780 gtk_tree_selection_select_range (GtkTreeSelection *selection,
781                                  GtkTreePath      *start_path,
782                                  GtkTreePath      *end_path)
783 {
784   g_return_if_fail (selection != NULL);
785   g_return_if_fail (GTK_IS_TREE_SELECTION (selection));
786   g_return_if_fail (selection->tree_view != NULL);
787
788   if (gtk_tree_selection_real_select_range (selection, start_path, end_path))
789     gtk_signal_emit (GTK_OBJECT (selection), tree_selection_signals[SELECTION_CHANGED]);
790 }
791 /* Called internally by gtktreeview.c It handles actually selecting the tree.
792  * This should almost certainly ever be called by anywhere else.
793  */
794 void
795 _gtk_tree_selection_internal_select_node (GtkTreeSelection *selection,
796                                           GtkRBNode        *node,
797                                           GtkRBTree        *tree,
798                                           GtkTreePath      *path,
799                                           GdkModifierType   state)
800 {
801   gint flags;
802   gint dirty = FALSE;
803
804   if (((state & GDK_SHIFT_MASK) == GDK_SHIFT_MASK) && (selection->tree_view->priv->anchor == NULL))
805     {
806       selection->tree_view->priv->anchor = gtk_tree_path_copy (path);
807       dirty = gtk_tree_selection_real_select_node (selection, tree, node, TRUE);
808     }
809   else if ((state & (GDK_CONTROL_MASK|GDK_SHIFT_MASK)) == (GDK_SHIFT_MASK|GDK_CONTROL_MASK))
810     {
811       gtk_tree_selection_select_range (selection,
812                                        selection->tree_view->priv->anchor,
813                                        path);
814     }
815   else if ((state & GDK_CONTROL_MASK) == GDK_CONTROL_MASK)
816     {
817       flags = node->flags;
818       if (selection->type == GTK_TREE_SELECTION_SINGLE)
819         dirty = gtk_tree_selection_real_unselect_all (selection);
820
821       if (selection->tree_view->priv->anchor)
822         gtk_tree_path_free (selection->tree_view->priv->anchor);
823       selection->tree_view->priv->anchor = gtk_tree_path_copy (path);
824
825       if ((flags & GTK_RBNODE_IS_SELECTED) == GTK_RBNODE_IS_SELECTED)
826         dirty |= gtk_tree_selection_real_select_node (selection, tree, node, FALSE);
827       else
828         dirty |= gtk_tree_selection_real_select_node (selection, tree, node, TRUE);
829     }
830   else if ((state & GDK_SHIFT_MASK) == GDK_SHIFT_MASK)
831     {
832       dirty = gtk_tree_selection_real_unselect_all (selection);
833       dirty |= gtk_tree_selection_real_select_range (selection,
834                                                      selection->tree_view->priv->anchor,
835                                                      path);
836     }
837   else
838     {
839       dirty = gtk_tree_selection_real_unselect_all (selection);
840       if (selection->tree_view->priv->anchor)
841         gtk_tree_path_free (selection->tree_view->priv->anchor);
842       selection->tree_view->priv->anchor = gtk_tree_path_copy (path);
843       dirty |= gtk_tree_selection_real_select_node (selection, tree, node, TRUE);
844     }
845
846   if (dirty)
847     gtk_signal_emit (GTK_OBJECT (selection), tree_selection_signals[SELECTION_CHANGED]);
848 }
849
850 /* NOTE: Any {un,}selection ever done _MUST_ be done through this function!
851  */
852
853 /* FIXME: user_func can screw up GTK_TREE_SELECTION_SINGLE.  If it prevents
854  * unselection of a node, it can keep more then one node selected.
855  */
856 static gint
857 gtk_tree_selection_real_select_node (GtkTreeSelection *selection,
858                                      GtkRBTree        *tree,
859                                      GtkRBNode        *node,
860                                      gboolean          select)
861 {
862   gboolean selected = FALSE;
863   GtkTreePath *path = NULL;
864
865   if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_SELECTED) != select)
866     {
867       path = _gtk_tree_view_find_path (selection->tree_view, tree, node);
868       if (selection->user_func)
869         {
870           if ((*selection->user_func) (selection, selection->tree_view->priv->model, path, selection->user_data))
871             selected = TRUE;
872         }
873       else
874         selected = TRUE;
875     }
876   if (selected == TRUE)
877     {
878       GtkTreeNode tree_node;
879       tree_node = gtk_tree_model_get_node (selection->tree_view->priv->model, path);
880
881       node->flags ^= GTK_RBNODE_IS_SELECTED;
882
883       /* FIXME: just draw the one node*/
884       gtk_widget_queue_draw (GTK_WIDGET (selection->tree_view));
885       return TRUE;
886     }
887
888   return FALSE;
889 }
890