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