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

source code of gtk/gtk/gtktreeselection.c