c81e03faea1bf125adcac650a48a6efed113cc1c
[ardour.git] / libs / gtkmm2ext / treeutils.cc
1 /*
2     Copyright (C) 2010 Paul Davis
3
4     This program is free software; you can redistribute it and/or modify
5     it under the terms of the GNU General Public License as published by
6     the Free Software Foundation; either version 2 of the License, or
7     (at your option) any later version.
8
9     This program 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
12     GNU General Public License for more details.
13
14     You should have received a copy of the GNU General Public License
15     along with this program; if not, write to the Free Software
16     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
17
18 */
19
20 #include "gtkmm2ext/treeutils.h"
21
22 using namespace Glib;
23 using namespace Gtk;
24
25 void
26 Gtkmm2ext::treeview_select_one (RefPtr<TreeSelection> selection, RefPtr<TreeModel> model, TreeView& view,
27                                 TreeIter iter, TreePath path, TreeViewColumn* col)
28 {
29         if (!view.row_expanded (path)) {
30                 // cerr << "!! selecting a row that isn't expanded! " << path.to_string() << endl;
31         }
32
33         selection->unselect_all ();
34         view.set_cursor (path, *col, true);
35 }
36
37 void
38 Gtkmm2ext::treeview_select_previous (TreeView& view, RefPtr<TreeModel> model, TreeViewColumn* col)
39 {
40         RefPtr<TreeSelection> selection = view.get_selection();
41         TreeView::Selection::ListHandle_Path rows = selection->get_selected_rows ();
42
43         if (selection->count_selected_rows() == 0 || !col || model->children().size() < 2) {
44                 return;
45         }
46
47         TreeView::Selection::ListHandle_Path::iterator i = rows.begin();
48         TreeModel::Path start = *i;
49         TreePath prev = start;
50         TreeIter iter;
51
52         iter = model->get_iter (prev);
53
54         if (iter == model->children().begin()) {
55
56                 /* at the start, go to the end */
57
58                 TreeIter x = iter;
59                 while (iter != model->children().end()) {
60                         x = iter;
61                         iter++;
62                 }
63
64                 /* "x" is now an iterator for the last row */
65
66                 iter = x;
67                 prev = model->get_path (iter);
68
69         } else {
70                 
71                 prev.prev();
72         }
73
74         if (prev == start) {
75                 /* can't go back, go up */
76
77                 if (!prev.empty()) {
78                         prev.up ();
79                 }
80         }
81
82         iter = model->get_iter (prev);
83
84         if (iter) {
85
86                 treeview_select_one (selection, model, view, iter, prev, col);
87
88         } else {
89
90                 /* can't move to previous, so restart at selected and move up the tree */
91
92                 prev = start;
93                 prev.up ();
94
95                 if (!prev.empty()) {
96                         iter = model->get_iter (prev);
97
98                         if (!iter) {
99                                 /* can't move up the tree*/
100                                 return;
101                         } else {
102                                 /* moved up from child to parent, now move to ??? */
103                                 prev.prev();
104                         }
105
106                         iter = model->get_iter (prev);
107                 }
108                 
109                 if (iter) {
110                         treeview_select_one (selection, model, view, iter, prev, col);
111                 } else {
112
113                         /* we could not forward, so wrap around to the first row */
114
115                         /* grr: no nice way to get an iter for the 
116                            last row, because there is no operator--
117                            for TreeIter
118                         */
119
120                         TreeIter x = model->children().begin();
121                         TreeIter px = x;
122                         while (x != model->children().end()) {
123                                 px = x;
124                                 x++;
125                         }
126                         prev = model->get_path (px);
127                         treeview_select_one (selection, model, view, px, prev, col);
128                 }
129         }
130 }
131
132 void
133 Gtkmm2ext::treeview_select_next (TreeView& view, RefPtr<TreeModel> model, TreeViewColumn* col)
134 {
135         RefPtr<TreeSelection> selection = view.get_selection();
136         TreeView::Selection::ListHandle_Path rows = selection->get_selected_rows ();
137
138         if (selection->count_selected_rows() == 0 || !col || model->children().size() < 2) {
139                 return;
140         }
141
142         /* start with the last selected row, not the first */
143
144         TreeView::Selection::ListHandle_Path::iterator i = rows.begin();
145         TreeView::Selection::ListHandle_Path::iterator p = i;
146
147         /* get the last selected row */
148
149         while (i != rows.end()) {
150                 p = i;
151                 ++i;
152         }
153
154         TreeModel::Path start = *p;
155         TreePath next = start;
156         TreeIter iter;
157
158         /* if the row we intend to start from has children but it is not expanded,
159            do not try to go down.
160         */
161
162         iter = model->get_iter (start);
163
164         TreeRow row = (*iter);
165         bool down_allowed = true;
166
167         if (!row.children().empty()) {
168                 TreePath tp = model->get_path (iter);
169
170                 if (!view.row_expanded (tp)) {
171                         down_allowed = false;
172                 }
173         }
174
175         start = next;
176
177         if (down_allowed) {
178                 next.down ();
179                 TreeIter iter = model->get_iter (next);
180                 if (!iter) {
181                         /* can't go down, so move to next */
182                         next = start;
183                         next.next ();
184                 }
185         } else {
186                 next.next ();
187         }
188
189         iter = model->get_iter (next);
190
191         if (iter) {
192
193                 treeview_select_one (selection, model, view, iter, next, col);
194
195         } else {
196
197                 /* can't move down/next, so restart at selected and move up the tree */
198
199                 next = start;
200                 next.up ();
201
202                 if (!next.empty()) {
203                         iter = model->get_iter (next);
204
205                         if (!iter) {
206                                 /* can't move up the tree*/
207                                 return;
208                         } else {
209                                 /* moved up from child to parent, now move to next */
210                                 next.next();
211                         }
212
213                         iter = model->get_iter (next);
214                 }
215                 
216                 if (iter) {
217                         treeview_select_one (selection, model, view, iter, next, col);
218                 } else {
219                         /* we could not forward, so wrap around to the first row */
220                         next = model->get_path (model->children().begin());
221                         treeview_select_one (selection, model, view, model->children().begin(), next, col);
222                 }
223         }
224 }