1 /*
2  * Copyright (C) 2017 Paul Davis <paul@linuxaudiosystems.com>
3  * Copyright (C) 2017 Robin Gareus <robin@gareus.org>
4  *
5  * This program is free software; you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License as published by
7  * the Free Software Foundation; either version 2 of the License, or
8  * (at your option) any later version.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License along
16  * with this program; if not, write to the Free Software Foundation, Inc.,
17  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18  */
19 
20 #include <iostream>
21 
22 #include "ardour/session.h"
23 #include "ardour/types.h"
24 
25 #include "axis_provider.h"
26 #include "stripable_treemodel.h"
27 
28 using namespace ARDOUR;
29 
Glue(boost::shared_ptr<Stripable> s)30 StripableTreeModel::Glue::Glue (boost::shared_ptr<Stripable> s)
31 	: stripable (s)
32 {
33 }
34 
StripableTreeModel(AxisViewProvider & avp)35 StripableTreeModel::StripableTreeModel (AxisViewProvider& avp)
36 	: Glib::ObjectBase( typeid(StripableTreeModel) ) //register a custom GType.
37 	, Glib::Object() //The custom GType is actually registered here.
38 	, axis_view_provider (avp)
39 {
40 	n_columns = columns.size();
41 }
42 
43 void
set_session(Session & s)44 StripableTreeModel::set_session (Session& s)
45 {
46 	_session = &s;
47 }
48 
~StripableTreeModel()49 StripableTreeModel::~StripableTreeModel()
50 {
51 }
52 
53 Glib::RefPtr<StripableTreeModel>
create(AxisViewProvider & avp)54 StripableTreeModel::create (AxisViewProvider& avp)
55 {
56 	return Glib::RefPtr<StripableTreeModel> (new StripableTreeModel (avp));
57 }
58 
59 Gtk::TreeModelFlags
get_flags_vfunc() const60 StripableTreeModel::get_flags_vfunc() const
61 {
62 	return Gtk::TREE_MODEL_LIST_ONLY;
63 }
64 
65 int
get_n_columns_vfunc() const66 StripableTreeModel::get_n_columns_vfunc() const
67 {
68 	return n_columns;
69 }
70 
71 GType
get_column_type_vfunc(int index) const72 StripableTreeModel::get_column_type_vfunc (int index) const
73 {
74 	if (index <= n_columns) {
75 		return columns.types()[index];
76 	}
77 	return 0;
78 }
79 
80 void
get_value_vfunc(const TreeModel::iterator & iter,int column,Glib::ValueBase & value) const81 StripableTreeModel::get_value_vfunc (const TreeModel::iterator& iter, int column, Glib::ValueBase& value) const
82 {
83 	if (!_session) {
84 		return;
85 	}
86 
87 	if (column > n_columns) {
88 		return;
89 	}
90 
91 	const Glue* glue = (const Glue*)iter.gobj()->user_data;
92 	boost::shared_ptr<Stripable> iter_stripable = glue->stripable.lock();
93 
94 	if (!iter_stripable) {
95 		return;
96 	}
97 
98 	switch (column) {
99 	case 0:
100 		return text_value (iter_stripable, value);
101 	}
102 }
103 
104 void
text_value(boost::shared_ptr<Stripable> stripable,Glib::ValueBase & value) const105 StripableTreeModel::text_value (boost::shared_ptr<Stripable> stripable, Glib::ValueBase& value) const
106 {
107 	StringColumn::ValueType val;
108 	val.set (stripable->name());
109 	value = val;
110 }
111 
112 bool
iter_next_vfunc(const iterator & iter,iterator & iter_next) const113 StripableTreeModel::iter_next_vfunc (const iterator& iter, iterator& iter_next) const
114 {
115 	if (!_session) {
116 		return false;
117 	}
118 
119 	const Glue* glue = (const Glue*)iter.gobj()->user_data;
120 	boost::shared_ptr<Stripable> iter_stripable = glue->stripable.lock();
121 
122 	if (!iter_stripable) {
123 		return false;
124 	}
125 
126 	//initialize the next iterator:
127 	iter_next = iterator();
128 
129 	StripableList sl;
130 	_session->get_stripables (sl);
131 	if (sl.empty()) {
132 		return false;
133 	}
134 	sl.sort (Stripable::Sorter());
135 
136 	for (StripableList::const_iterator s = sl.begin(); s != sl.end(); ++s) {
137 
138 		if (*s == iter_stripable) {
139 			++s;
140 			if (s != sl.end()) {
141 				Glue* new_glue = new Glue (iter_stripable);
142 				iter_next.gobj()->user_data = (void*)new_glue;
143 				remember_glue_item (new_glue);
144 				return true; //success
145 			}
146 			break;
147 		}
148 	}
149 
150 	return false; //There is no next row.
151 }
152 
153 bool
iter_children_vfunc(const iterator & parent,iterator & iter) const154 StripableTreeModel::iter_children_vfunc(const iterator& parent, iterator& iter) const
155 {
156 	return false;
157 }
158 
159 bool
iter_has_child_vfunc(const iterator & iter) const160 StripableTreeModel::iter_has_child_vfunc(const iterator& iter) const
161 {
162 	return false;
163 }
164 
165 int
iter_n_children_vfunc(const iterator & iter) const166 StripableTreeModel::iter_n_children_vfunc(const iterator& iter) const
167 {
168 	return 0;
169 }
170 
171 int
iter_n_root_children_vfunc() const172 StripableTreeModel::iter_n_root_children_vfunc() const
173 {
174 	if (_session) {
175 		StripableList sl;
176 		_session->get_stripables (sl);
177 		return sl.size();
178 	}
179 	return 0;
180 }
181 
182 bool
iter_nth_child_vfunc(const iterator & parent,int,iterator & iter) const183 StripableTreeModel::iter_nth_child_vfunc(const iterator& parent, int /* n */, iterator& iter) const
184 {
185 	iter = iterator(); //Set is as invalid, as the TreeModel documentation says that it should be.
186 	return false; //There are no children.
187 }
188 
189 bool
iter_nth_root_child_vfunc(int n,iterator & iter) const190 StripableTreeModel::iter_nth_root_child_vfunc(int n, iterator& iter) const
191 {
192 	iter = iterator(); //clear the input parameter.
193 	if (!_session) {
194 		return false;
195 	}
196 
197 	StripableList sl;
198 	_session->get_stripables (sl);
199 
200 	if (sl.empty()) {
201 		return false;
202 	}
203 
204 	sl.sort (Stripable::Sorter());
205 
206 	StripableList::const_iterator s;
207 
208 	for (s = sl.begin(); s != sl.end() && n > 0; ++s, --n);
209 
210 	if (s != sl.end()) {
211 		Glue* new_glue = new Glue (*s);
212 		iter.gobj()->user_data = new_glue;
213 		remember_glue_item (new_glue);
214 		return true;
215 	}
216 
217 	return false; //There are no children.
218 }
219 
220 bool
iter_parent_vfunc(const iterator & child,iterator & iter) const221 StripableTreeModel::iter_parent_vfunc(const iterator& child, iterator& iter) const
222 {
223 	iter = iterator(); //Set is as invalid, as the TreeModel documentation says that it should be.
224 	return false; //There are no children, so no parents.
225 }
226 
227 Gtk::TreeModel::Path
get_path_vfunc(const iterator &) const228 StripableTreeModel::get_path_vfunc(const iterator& /* iter */) const
229 {
230 	//TODO:
231 	return Path();
232 }
233 
234 bool
get_iter_vfunc(const Path & path,iterator & iter) const235 StripableTreeModel::get_iter_vfunc (const Path& path, iterator& iter) const
236 {
237 	unsigned sz = path.size();
238 
239 	if (!sz || sz > 1) {
240 		/* path must refer to something, but not children since we
241 		   don't do children.
242 		*/
243 		iter = iterator(); //Set is as invalid, as the TreeModel documentation says that it should be.
244 		return false;
245 	}
246 
247 	return iter_nth_root_child_vfunc (path[0], iter);
248 }
249 
250 bool
iter_is_valid(const iterator & iter) const251 StripableTreeModel::iter_is_valid(const iterator& iter) const
252 {
253 	const Glue* glue = (const Glue*)iter.gobj()->user_data;
254 
255 	if (!glue->stripable.lock()) {
256 		return false;
257 	}
258 
259 	return Gtk::TreeModel::iter_is_valid(iter);
260 }
261 
262 void
remember_glue_item(Glue * item) const263 StripableTreeModel::remember_glue_item (Glue* item) const
264 {
265 	glue_list.insert (item);
266 }
267