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