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