1 /* === S Y N F I G ========================================================= */
2 /*! \file childrentreestore.cpp
3 ** \brief Template File
4 **
5 ** $Id$
6 **
7 ** \legal
8 ** Copyright (c) 2002-2005 Robert B. Quattlebaum Jr., Adrian Bentley
9 ** Copyright (c) 2007 Chris Moore
10 **
11 ** This package is free software; you can redistribute it and/or
12 ** modify it under the terms of the GNU General Public License as
13 ** published by the Free Software Foundation; either version 2 of
14 ** the License, or (at your option) any later version.
15 **
16 ** This package is distributed in the hope that it will be useful,
17 ** but WITHOUT ANY WARRANTY; without even the implied warranty of
18 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
19 ** General Public License for more details.
20 ** \endlegal
21 */
22 /* ========================================================================= */
23
24 /* === H E A D E R S ======================================================= */
25
26 #ifdef USING_PCH
27 # include "pch.h"
28 #else
29 #ifdef HAVE_CONFIG_H
30 # include <config.h>
31 #endif
32
33 #include <glibmm/main.h>
34
35 #include <synfig/general.h>
36
37 #include "trees/childrentreestore.h"
38 #include "iconcontroller.h"
39 #include <gtkmm/button.h>
40 #include <synfig/paramdesc.h>
41 #include <ETL/clock>
42
43 #include <gui/localization.h>
44
45 class Profiler : private etl::clock
46 {
47 const std::string name;
48 public:
Profiler(const std::string & name)49 Profiler(const std::string& name):name(name) { reset(); }
~Profiler()50 ~Profiler() { float time(operator()()); synfig::info("%s: took %f msec",name.c_str(),time*1000); }
51 };
52
53 #endif
54
55 /* === U S I N G =========================================================== */
56
57 using namespace std;
58 using namespace etl;
59 using namespace synfig;
60 using namespace studio;
61
62 /* === M A C R O S ========================================================= */
63
64 /* === G L O B A L S ======================================================= */
65
66 /* === P R O C E D U R E S ================================================= */
67
68 /* === M E T H O D S ======================================================= */
69
ModelHack()70 static ChildrenTreeStore::Model& ModelHack()
71 {
72 static ChildrenTreeStore::Model* model(0);
73 if(!model)model=new ChildrenTreeStore::Model;
74 return *model;
75 }
76
ChildrenTreeStore(etl::loose_handle<synfigapp::CanvasInterface> canvas_interface_)77 ChildrenTreeStore::ChildrenTreeStore(etl::loose_handle<synfigapp::CanvasInterface> canvas_interface_):
78 Gtk::TreeStore (ModelHack()),
79 CanvasTreeStore (canvas_interface_)
80 {
81 canvas_row=*append();
82 canvas_row[model.label]=_("Canvases");
83 canvas_row[model.is_canvas] = false;
84 canvas_row[model.is_value_node] = false;
85
86 value_node_row=*append();
87 value_node_row[model.label]=_("ValueBase Nodes");
88 value_node_row[model.is_canvas] = false;
89 value_node_row[model.is_value_node] = false;
90
91 // Connect all the signals
92 canvas_interface()->signal_value_node_changed().connect(sigc::mem_fun(*this,&studio::ChildrenTreeStore::on_value_node_changed));
93 canvas_interface()->signal_value_node_renamed().connect(sigc::mem_fun(*this,&studio::ChildrenTreeStore::on_value_node_renamed));
94 canvas_interface()->signal_value_node_added().connect(sigc::mem_fun(*this,&studio::ChildrenTreeStore::on_value_node_added));
95 canvas_interface()->signal_value_node_deleted().connect(sigc::mem_fun(*this,&studio::ChildrenTreeStore::on_value_node_deleted));
96 canvas_interface()->signal_value_node_replaced().connect(sigc::mem_fun(*this,&studio::ChildrenTreeStore::on_value_node_replaced));
97 canvas_interface()->signal_canvas_added().connect(sigc::mem_fun(*this,&studio::ChildrenTreeStore::on_canvas_added));
98 canvas_interface()->signal_canvas_removed().connect(sigc::mem_fun(*this,&studio::ChildrenTreeStore::on_canvas_removed));
99
100 rebuild();
101 }
102
~ChildrenTreeStore()103 ChildrenTreeStore::~ChildrenTreeStore()
104 {
105 }
106
107 Glib::RefPtr<ChildrenTreeStore>
create(etl::loose_handle<synfigapp::CanvasInterface> canvas_interface_)108 ChildrenTreeStore::create(etl::loose_handle<synfigapp::CanvasInterface> canvas_interface_)
109 {
110 return Glib::RefPtr<ChildrenTreeStore>(new ChildrenTreeStore(canvas_interface_));
111 }
112
113 void
rebuild()114 ChildrenTreeStore::rebuild()
115 {
116 // Profiler profiler("ChildrenTreeStore::rebuild()");
117 rebuild_value_nodes();
118 rebuild_canvases();
119 }
120
121 void
refresh()122 ChildrenTreeStore::refresh()
123 {
124 // Profiler profiler("ChildrenTreeStore::refresh()");
125 refresh_value_nodes();
126 refresh_canvases();
127 }
128
129 void
rebuild_value_nodes()130 ChildrenTreeStore::rebuild_value_nodes()
131 {
132 Gtk::TreeModel::Children children(value_node_row.children());
133
134 while(!children.empty())erase(children.begin());
135
136 clear_changed_queue();
137
138 std::for_each(
139 canvas_interface()->get_canvas()->value_node_list().rbegin(), canvas_interface()->get_canvas()->value_node_list().rend(),
140 sigc::mem_fun(*this, &studio::ChildrenTreeStore::on_value_node_added)
141 );
142 }
143
144 void
refresh_value_nodes()145 ChildrenTreeStore::refresh_value_nodes()
146 {
147 Gtk::TreeModel::Children children(value_node_row.children());
148
149 Gtk::TreeModel::Children::iterator iter;
150
151 if(!children.empty())
152 for(iter = children.begin(); iter != children.end(); ++iter)
153 {
154 Gtk::TreeRow row=*iter;
155 refresh_row(row);
156 }
157 }
158
159 void
rebuild_canvases()160 ChildrenTreeStore::rebuild_canvases()
161 {
162 Gtk::TreeModel::Children children(canvas_row.children());
163
164 while(!children.empty())erase(children.begin());
165
166 std::for_each(
167 canvas_interface()->get_canvas()->children().rbegin(), canvas_interface()->get_canvas()->children().rend(),
168 sigc::mem_fun(*this, &studio::ChildrenTreeStore::on_canvas_added)
169 );
170 }
171
172 void
refresh_canvases()173 ChildrenTreeStore::refresh_canvases()
174 {
175 rebuild_canvases();
176 }
177
178 void
refresh_row(Gtk::TreeModel::Row & row,bool)179 ChildrenTreeStore::refresh_row(Gtk::TreeModel::Row &row, bool /*do_children*/)
180 {
181 CanvasTreeStore::refresh_row(row,false);
182
183 if((bool)row[model.is_value_node])
184 {
185 changed_set_.erase(row[model.value_node]);
186 }
187
188 }
189
190 void
on_canvas_added(synfig::Canvas::Handle canvas)191 ChildrenTreeStore::on_canvas_added(synfig::Canvas::Handle canvas)
192 {
193 Gtk::TreeRow row = *(prepend(canvas_row.children()));
194
195 row[model.icon] = Gtk::Button().render_icon_pixbuf(Gtk::StockID("synfig-type_canvas"),Gtk::ICON_SIZE_SMALL_TOOLBAR);
196 row[model.id] = canvas->get_id();
197 row[model.name] = canvas->get_name();
198
199 if(!canvas->get_id().empty())
200 row[model.label] = canvas->get_id();
201 else
202 if(!canvas->get_name().empty())
203 row[model.label] = canvas->get_name();
204 else
205 row[model.label] = _("[Unnamed]");
206
207 row[model.canvas] = canvas;
208 row[model.type] = _("Canvas");
209 //row[model.is_canvas] = true;
210 //row[model.is_value_node] = false;
211 }
212
213 void
on_canvas_removed(synfig::Canvas::Handle)214 ChildrenTreeStore::on_canvas_removed(synfig::Canvas::Handle /*canvas*/)
215 {
216 rebuild_canvases();
217 }
218
219 void
on_value_node_added(synfig::ValueNode::Handle value_node)220 ChildrenTreeStore::on_value_node_added(synfig::ValueNode::Handle value_node)
221 {
222 // if(value_node->get_id().find("Unnamed")!=String::npos)
223 // return;
224
225 Gtk::TreeRow row = *prepend(value_node_row.children());
226
227 set_row(row,synfigapp::ValueDesc(canvas_interface()->get_canvas(),value_node->get_id()),false);
228 }
229
230 void
on_value_node_deleted(synfig::ValueNode::Handle value_node)231 ChildrenTreeStore::on_value_node_deleted(synfig::ValueNode::Handle value_node)
232 {
233 Gtk::TreeIter iter;
234 //int i(0);
235
236 if(find_first_value_node(value_node,iter))
237 {
238 erase(iter);
239 }
240 //rebuild_value_nodes();
241 }
242
243 bool
execute_changed_value_nodes()244 ChildrenTreeStore::execute_changed_value_nodes()
245 {
246 // Profiler profiler("ChildrenTreeStore::execute_changed_value_nodes()");
247 if(!replaced_set_.empty())
248 rebuild_value_nodes();
249
250 etl::clock timer;
251 timer.reset();
252
253 while(!changed_set_.empty())
254 {
255 ValueNode::Handle value_node(*changed_set_.begin());
256 changed_set_.erase(value_node);
257
258 Gtk::TreeIter iter;
259
260 try
261 {
262 Gtk::TreeIter iter;
263 int i(0);
264
265 if(!value_node->is_exported() && find_first_value_node(value_node,iter))
266 {
267 rebuild_value_nodes();
268 continue;
269 }
270
271 if(value_node->is_exported() && find_first_value_node(value_node,iter)) do
272 {
273 Gtk::TreeRow row(*iter);
274 i++;
275 refresh_row(row);
276 }while(find_next_value_node(value_node,iter));
277
278 if(!i)
279 {
280 refresh_value_nodes();
281 return false;
282 }
283
284 }
285 catch(...)
286 {
287 rebuild_value_nodes();
288 return false;
289 }
290
291 // If we are taking too long...
292 if(timer()>4)
293 {
294 refresh_value_nodes();
295 return false;
296 }
297 }
298
299 return false;
300 }
301
302 void
on_value_node_changed(synfig::ValueNode::Handle value_node)303 ChildrenTreeStore::on_value_node_changed(synfig::ValueNode::Handle value_node)
304 {
305
306 if(!value_node->is_exported())
307 return;
308 changed_connection.disconnect();
309 // if(!execute_changed_queued())
310 // changed_connection=Glib::signal_idle().connect(sigc::mem_fun(*this,&ChildrenTreeStore::execute_changed_value_nodes));
311 changed_connection=Glib::signal_timeout().connect(sigc::mem_fun(*this,&ChildrenTreeStore::execute_changed_value_nodes),150);
312
313 changed_set_.insert(value_node);
314 /*
315 try
316 {
317 Gtk::TreeIter iter;
318 int i(0);
319 while(find_next_value_node(value_node,iter))
320 {
321 Gtk::TreeRow row(*iter);
322 i++;
323 refresh_row(row);
324 }
325 if(!i)
326 {
327 refresh_value_nodes();
328 }
329 }
330 catch(...)
331 {
332 rebuild_value_nodes();
333 }
334 */
335 }
336
337 void
on_value_node_renamed(synfig::ValueNode::Handle value_node)338 ChildrenTreeStore::on_value_node_renamed(synfig::ValueNode::Handle value_node __attribute__ ((unused)))
339 {
340 rebuild_value_nodes();
341 }
342
343 void
on_value_node_replaced(synfig::ValueNode::Handle replaced_value_node,synfig::ValueNode::Handle)344 ChildrenTreeStore::on_value_node_replaced(synfig::ValueNode::Handle replaced_value_node,synfig::ValueNode::Handle /*new_value_node*/)
345 {
346 changed_connection.disconnect();
347 //if(!execute_changed_queued())
348 // changed_connection=Glib::signal_idle().connect(sigc::mem_fun(*this,&ChildrenTreeStore::execute_changed_value_nodes));
349 changed_connection=Glib::signal_timeout().connect(sigc::mem_fun(*this,&ChildrenTreeStore::execute_changed_value_nodes),150);
350
351 replaced_set_.insert(replaced_value_node);
352 }
353
354 void
set_value_impl(const Gtk::TreeModel::iterator & iter,int column,const Glib::ValueBase & value)355 ChildrenTreeStore::set_value_impl(const Gtk::TreeModel::iterator& iter, int column, const Glib::ValueBase& value)
356 {
357 if(column>=get_n_columns_vfunc())
358 {
359 g_warning("LayerTreeStore::set_value_impl: Bad column (%d)",column);
360 return;
361 }
362
363 if(!g_value_type_compatible(G_VALUE_TYPE(value.gobj()),get_column_type_vfunc(column)))
364 {
365 g_warning("LayerTreeStore::set_value_impl: Bad value type");
366 return;
367 }
368
369 try
370 {
371 if(column==model.value.index())
372 {
373 Glib::Value<synfig::ValueBase> x;
374 g_value_init(x.gobj(),model.value.type());
375 g_value_copy(value.gobj(),x.gobj());
376
377 synfigapp::ValueDesc value_desc((*iter)[model.value_desc]);
378 if(value_desc)
379 {
380 canvas_interface()->change_value(value_desc,x.get());
381 row_changed(get_path(*iter),*iter);
382 }
383
384 return;
385 }
386 else
387 CanvasTreeStore::set_value_impl(iter,column, value);
388 }
389 catch(std::exception x)
390 {
391 g_warning("%s", x.what());
392 }
393 }
394