2 * Copyright (C) 2000 Red Hat, Inc., Jonathan Blandford <jrb@redhat.com>
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.
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.
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.
20 #include "gtktreeselection.h"
21 #include "gtktreeprivate.h"
22 #include "gtkrbtree.h"
23 #include "gtksignal.h"
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,
39 static GtkObjectClass *parent_class = NULL;
40 static guint tree_selection_signals[LAST_SIGNAL] = { 0 };
43 gtk_tree_selection_get_type (void)
45 static GtkType selection_type = 0;
49 static const GTypeInfo selection_info =
51 sizeof (GtkTreeSelectionClass),
53 NULL, /* base_finalize */
54 (GClassInitFunc) gtk_tree_selection_class_init,
55 NULL, /* class_finalize */
56 NULL, /* class_data */
57 sizeof (GtkTreeSelection),
59 (GInstanceInitFunc) gtk_tree_selection_init
62 selection_type = g_type_register_static (GTK_TYPE_OBJECT, "GtkTreeSelection", &selection_info);
65 return selection_type;
69 gtk_tree_selection_class_init (GtkTreeSelectionClass *class)
71 GtkObjectClass *object_class;
73 object_class = (GtkObjectClass*) class;
74 parent_class = g_type_class_peek_parent (class);
76 tree_selection_signals[SELECTION_CHANGED] =
77 gtk_signal_new ("selection_changed",
79 GTK_CLASS_TYPE (object_class),
80 GTK_SIGNAL_OFFSET (GtkTreeSelectionClass, selection_changed),
81 gtk_marshal_NONE__NONE,
84 gtk_object_class_add_signals (object_class, tree_selection_signals, LAST_SIGNAL);
86 class->selection_changed = NULL;
90 gtk_tree_selection_init (GtkTreeSelection *selection)
92 selection->type = GTK_TREE_SELECTION_SINGLE;
96 gtk_tree_selection_new (void)
100 selection = GTK_OBJECT (gtk_type_new (GTK_TYPE_TREE_SELECTION));
106 gtk_tree_selection_new_with_tree_view (GtkTreeView *tree_view)
108 GtkObject *selection;
110 g_return_val_if_fail (tree_view != NULL, NULL);
111 g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), NULL);
113 selection = gtk_tree_selection_new ();
114 gtk_tree_selection_set_tree_view (GTK_TREE_SELECTION (selection), tree_view);
120 gtk_tree_selection_set_tree_view (GtkTreeSelection *selection,
121 GtkTreeView *tree_view)
123 g_return_if_fail (selection != NULL);
124 g_return_if_fail (GTK_IS_TREE_SELECTION (selection));
125 if (tree_view != NULL)
126 g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
128 selection->tree_view = tree_view;
129 tree_view->priv->selection = selection;
133 gtk_tree_selection_set_type (GtkTreeSelection *selection,
134 GtkTreeSelectionType type)
136 g_return_if_fail (selection != NULL);
137 g_return_if_fail (GTK_IS_TREE_SELECTION (selection));
139 if (selection->type == type)
142 if (type == GTK_TREE_SELECTION_SINGLE)
144 GtkRBTree *tree = NULL;
145 GtkRBNode *node = NULL;
146 gint selected = FALSE;
148 if (selection->tree_view->priv->anchor)
150 _gtk_tree_view_find_node (selection->tree_view,
151 selection->tree_view->priv->anchor,
155 if (node && GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_SELECTED))
158 gtk_tree_selection_unselect_all (selection);
159 if (node && selected)
160 GTK_RBNODE_SET_FLAG (node, GTK_RBNODE_IS_SELECTED);
162 selection->type = type;
166 gtk_tree_selection_set_select_function (GtkTreeSelection *selection,
167 GtkTreeSelectionFunc func,
170 g_return_if_fail (selection != NULL);
171 g_return_if_fail (GTK_IS_TREE_SELECTION (selection));
172 g_return_if_fail (func != NULL);
174 selection->user_func = func;
175 selection->user_data = data;
179 gtk_tree_selection_get_user_data (GtkTreeSelection *selection)
181 g_return_val_if_fail (selection != NULL, NULL);
182 g_return_val_if_fail (GTK_IS_TREE_SELECTION (selection), NULL);
184 return selection->user_data;
188 gtk_tree_selection_get_selected (GtkTreeSelection *selection)
194 g_return_val_if_fail (selection != NULL, NULL);
195 g_return_val_if_fail (GTK_IS_TREE_SELECTION (selection), NULL);
197 if (selection->tree_view->priv->anchor == NULL)
200 g_return_val_if_fail (selection->tree_view != NULL, NULL);
201 g_return_val_if_fail (selection->tree_view->priv->model != NULL, NULL);
203 if (!_gtk_tree_view_find_node (selection->tree_view,
204 selection->tree_view->priv->anchor,
207 ! GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_SELECTED))
208 /* We don't want to return the anchor if it isn't actually selected.
213 retval = gtk_tree_model_get_node (selection->tree_view->priv->model,
214 selection->tree_view->priv->anchor);
219 gtk_tree_selection_selected_foreach (GtkTreeSelection *selection,
220 GtkTreeSelectionForeachFunc func,
226 GtkTreeNode tree_node;
228 g_return_if_fail (selection != NULL);
229 g_return_if_fail (GTK_IS_TREE_SELECTION (selection));
230 g_return_if_fail (selection->tree_view != NULL);
231 g_return_if_fail (selection->tree_view->priv->model != NULL);
234 selection->tree_view->priv->tree == NULL ||
235 selection->tree_view->priv->tree->root == NULL)
238 tree = selection->tree_view->priv->tree;
239 node = selection->tree_view->priv->tree->root;
241 while (node->left != tree->nil)
244 /* find the node internally */
245 path = gtk_tree_path_new_root ();
246 tree_node = gtk_tree_model_get_node (selection->tree_view->priv->model, path);
247 gtk_tree_path_free (path);
251 if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_SELECTED))
252 (* func) (selection->tree_view->priv->model, tree_node, data);
255 tree = node->children;
257 while (node->left != tree->nil)
259 tree_node = gtk_tree_model_node_children (selection->tree_view->priv->model, tree_node);
262 TREE_VIEW_INTERNAL_ASSERT_VOID (tree_node != NULL);
266 gboolean done = FALSE;
269 node = _gtk_rbtree_next (tree, node);
272 gtk_tree_model_node_next (selection->tree_view->priv->model, &tree_node);
276 TREE_VIEW_INTERNAL_ASSERT_VOID (tree_node != NULL);
280 node = tree->parent_node;
281 tree = tree->parent_tree;
283 /* we've run out of tree */
284 /* We're done with this function */
286 tree_node = gtk_tree_model_node_parent (selection->tree_view->priv->model, tree_node);
289 TREE_VIEW_INTERNAL_ASSERT_VOID (tree_node != NULL);
299 gtk_tree_selection_select_path (GtkTreeSelection *selection,
304 GdkModifierType state = 0;
306 g_return_if_fail (selection != NULL);
307 g_return_if_fail (GTK_IS_TREE_SELECTION (selection));
308 g_return_if_fail (selection->tree_view != NULL);
309 g_return_if_fail (path != NULL);
311 _gtk_tree_view_find_node (selection->tree_view,
316 if (node == NULL || GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_SELECTED))
319 if (selection->type == GTK_TREE_SELECTION_MULTI)
320 state = GDK_CONTROL_MASK;
322 _gtk_tree_selection_internal_select_node (selection,
330 gtk_tree_selection_unselect_path (GtkTreeSelection *selection,
336 g_return_if_fail (selection != NULL);
337 g_return_if_fail (GTK_IS_TREE_SELECTION (selection));
338 g_return_if_fail (selection->tree_view != NULL);
339 g_return_if_fail (path != NULL);
341 _gtk_tree_view_find_node (selection->tree_view,
346 if (node == NULL || !GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_SELECTED))
349 _gtk_tree_selection_internal_select_node (selection,
357 gtk_tree_selection_select_node (GtkTreeSelection *selection,
358 GtkTreeNode *tree_node)
362 g_return_if_fail (selection != NULL);
363 g_return_if_fail (GTK_IS_TREE_SELECTION (selection));
364 g_return_if_fail (selection->tree_view != NULL);
365 g_return_if_fail (selection->tree_view->priv->model != NULL);
367 path = gtk_tree_model_get_path (selection->tree_view->priv->model,
373 gtk_tree_selection_select_path (selection, path);
374 gtk_tree_path_free (path);
379 gtk_tree_selection_unselect_node (GtkTreeSelection *selection,
380 GtkTreeNode *tree_node)
384 g_return_if_fail (selection != NULL);
385 g_return_if_fail (GTK_IS_TREE_SELECTION (selection));
386 g_return_if_fail (selection->tree_view != NULL);
388 path = gtk_tree_model_get_path (selection->tree_view->priv->model,
394 gtk_tree_selection_select_path (selection, path);
395 gtk_tree_path_free (path);
398 /* Wish I was in python, right now... */
400 GtkTreeSelection *selection;
405 select_all_helper (GtkRBTree *tree,
409 struct _TempTuple *tuple = data;
412 _gtk_rbtree_traverse (node->children,
413 node->children->root,
417 if (!GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_SELECTED))
419 tuple->dirty = gtk_tree_selection_real_select_node (tuple->selection, tree, node, TRUE) || tuple->dirty;
424 /* We have a real_{un,}select_all function that doesn't emit the signal, so we
425 * can use it in other places without fear of the signal being emitted.
428 gtk_tree_selection_real_select_all (GtkTreeSelection *selection)
430 struct _TempTuple *tuple;
431 if (selection->tree_view->priv->tree == NULL)
434 if (selection->type == GTK_TREE_SELECTION_SINGLE)
440 dirty = gtk_tree_selection_real_unselect_all (selection);
442 tree = selection->tree_view->priv->tree;
446 while (node->right != selection->tree_view->priv->tree->nil)
451 tree = node->children;
458 dirty |= gtk_tree_selection_real_select_node (selection, tree, node, TRUE);
463 tuple = g_new (struct _TempTuple, 1);
464 tuple->selection = selection;
465 tuple->dirty = FALSE;
467 _gtk_rbtree_traverse (selection->tree_view->priv->tree,
468 selection->tree_view->priv->tree->root,
482 gtk_tree_selection_select_all (GtkTreeSelection *selection)
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 g_return_if_fail (selection->tree_view->priv->tree != NULL);
489 if (gtk_tree_selection_real_select_all (selection))
490 gtk_signal_emit (GTK_OBJECT (selection), tree_selection_signals[SELECTION_CHANGED]);
494 unselect_all_helper (GtkRBTree *tree,
498 struct _TempTuple *tuple = data;
501 _gtk_rbtree_traverse (node->children,
502 node->children->root,
506 if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_SELECTED))
508 tuple->dirty = gtk_tree_selection_real_select_node (tuple->selection, tree, node, FALSE) || tuple->dirty;
513 gtk_tree_selection_real_unselect_all (GtkTreeSelection *selection)
515 struct _TempTuple *tuple;
517 if (selection->type == GTK_TREE_SELECTION_SINGLE)
519 GtkRBTree *tree = NULL;
520 GtkRBNode *node = NULL;
521 if (selection->tree_view->priv->anchor == NULL)
524 _gtk_tree_view_find_node (selection->tree_view,
525 selection->tree_view->priv->anchor,
528 if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_SELECTED))
530 gtk_tree_selection_real_select_node (selection, tree, node, FALSE);
536 tuple = g_new (struct _TempTuple, 1);
537 tuple->selection = selection;
538 tuple->dirty = FALSE;
540 _gtk_rbtree_traverse (selection->tree_view->priv->tree,
541 selection->tree_view->priv->tree->root,
556 gtk_tree_selection_unselect_all (GtkTreeSelection *selection)
558 g_return_if_fail (selection != NULL);
559 g_return_if_fail (GTK_IS_TREE_SELECTION (selection));
560 g_return_if_fail (selection->tree_view != NULL);
561 g_return_if_fail (selection->tree_view->priv->tree != NULL);
562 if (selection->tree_view->priv->tree == NULL)
565 if (gtk_tree_selection_real_unselect_all (selection))
566 gtk_signal_emit (GTK_OBJECT (selection), tree_selection_signals[SELECTION_CHANGED]);
570 gtk_tree_selection_real_select_range (GtkTreeSelection *selection,
571 GtkTreePath *start_path,
572 GtkTreePath *end_path)
574 GtkRBNode *start_node, *end_node;
575 GtkRBTree *start_tree, *end_tree;
576 gboolean dirty = FALSE;
578 switch (gtk_tree_path_compare (start_path, end_path))
581 _gtk_tree_view_find_node (selection->tree_view,
585 _gtk_tree_view_find_node (selection->tree_view,
591 _gtk_tree_view_find_node (selection->tree_view,
595 end_tree = start_tree;
596 end_node = start_node;
599 _gtk_tree_view_find_node (selection->tree_view,
603 _gtk_tree_view_find_node (selection->tree_view,
610 g_return_val_if_fail (start_node != NULL, FALSE);
611 g_return_val_if_fail (end_node != NULL, FALSE);
615 if (GTK_RBNODE_FLAG_SET (start_node, GTK_RBNODE_IS_SELECTED))
617 dirty = gtk_tree_selection_real_select_node (selection, start_tree, start_node, FALSE);
620 if (start_node == end_node)
623 if (start_node->children)
625 start_tree = start_node->children;
626 start_node = start_tree->root;
627 while (start_node->left != start_tree->nil)
628 start_node = start_node->left;
632 gboolean done = FALSE;
635 start_node = _gtk_rbtree_next (start_tree, start_node);
636 if (start_node != NULL)
642 start_node = start_tree->parent_node;
643 start_tree = start_tree->parent_tree;
644 if (start_tree == NULL)
645 /* we've run out of tree */
646 /* This means we never found end node!! */
659 gtk_tree_selection_select_range (GtkTreeSelection *selection,
660 GtkTreePath *start_path,
661 GtkTreePath *end_path)
663 g_return_if_fail (selection != NULL);
664 g_return_if_fail (GTK_IS_TREE_SELECTION (selection));
665 g_return_if_fail (selection->tree_view != NULL);
667 if (gtk_tree_selection_real_select_range (selection, start_path, end_path))
668 gtk_signal_emit (GTK_OBJECT (selection), tree_selection_signals[SELECTION_CHANGED]);
670 /* Called internally by gtktreeview.c It handles actually selecting the tree.
671 * This should almost certainly ever be called by anywhere else.
674 _gtk_tree_selection_internal_select_node (GtkTreeSelection *selection,
678 GdkModifierType state)
683 if (((state & GDK_SHIFT_MASK) == GDK_SHIFT_MASK) && (selection->tree_view->priv->anchor == NULL))
685 selection->tree_view->priv->anchor = gtk_tree_path_copy (path);
686 dirty = gtk_tree_selection_real_select_node (selection, tree, node, TRUE);
688 else if ((state & (GDK_CONTROL_MASK|GDK_SHIFT_MASK)) == (GDK_SHIFT_MASK|GDK_CONTROL_MASK))
690 gtk_tree_selection_select_range (selection,
691 selection->tree_view->priv->anchor,
694 else if ((state & GDK_CONTROL_MASK) == GDK_CONTROL_MASK)
697 if (selection->type == GTK_TREE_SELECTION_SINGLE)
698 dirty = gtk_tree_selection_real_unselect_all (selection);
700 if (selection->tree_view->priv->anchor)
701 gtk_tree_path_free (selection->tree_view->priv->anchor);
702 selection->tree_view->priv->anchor = gtk_tree_path_copy (path);
704 if ((flags & GTK_RBNODE_IS_SELECTED) == GTK_RBNODE_IS_SELECTED)
705 dirty |= gtk_tree_selection_real_select_node (selection, tree, node, FALSE);
707 dirty |= gtk_tree_selection_real_select_node (selection, tree, node, TRUE);
709 else if ((state & GDK_SHIFT_MASK) == GDK_SHIFT_MASK)
711 dirty = gtk_tree_selection_real_unselect_all (selection);
712 dirty |= gtk_tree_selection_real_select_range (selection,
713 selection->tree_view->priv->anchor,
718 dirty = gtk_tree_selection_real_unselect_all (selection);
719 if (selection->tree_view->priv->anchor)
720 gtk_tree_path_free (selection->tree_view->priv->anchor);
721 selection->tree_view->priv->anchor = gtk_tree_path_copy (path);
722 dirty |= gtk_tree_selection_real_select_node (selection, tree, node, TRUE);
726 gtk_signal_emit (GTK_OBJECT (selection), tree_selection_signals[SELECTION_CHANGED]);
729 /* NOTE: Any {un,}selection ever done _MUST_ be done through this function!
732 gtk_tree_selection_real_select_node (GtkTreeSelection *selection,
737 gboolean selected = FALSE;
738 GtkTreePath *path = NULL;
740 if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_SELECTED) != select)
742 path = _gtk_tree_view_find_path (selection->tree_view, tree, node);
743 if (selection->user_func)
745 if ((*selection->user_func) (selection, selection->tree_view->priv->model, path, selection->user_data))
751 if (selected == TRUE)
753 GtkTreeNode tree_node;
754 tree_node = gtk_tree_model_get_node (selection->tree_view->priv->model, path);
756 node->flags ^= GTK_RBNODE_IS_SELECTED;
758 /* FIXME: just draw the one node*/
759 gtk_widget_queue_draw (GTK_WIDGET (selection->tree_view));