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