Attempting to fix 1823053 - renaming an exported valuenode causes a crash.
[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 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_renamed().connect(sigc::mem_fun(*this,&studio::ChildrenTreeStore::on_value_node_renamed));
88         canvas_interface()->signal_value_node_added().connect(sigc::mem_fun(*this,&studio::ChildrenTreeStore::on_value_node_added));
89         canvas_interface()->signal_value_node_deleted().connect(sigc::mem_fun(*this,&studio::ChildrenTreeStore::on_value_node_deleted));
90         canvas_interface()->signal_value_node_replaced().connect(sigc::mem_fun(*this,&studio::ChildrenTreeStore::on_value_node_replaced));
91         canvas_interface()->signal_canvas_added().connect(sigc::mem_fun(*this,&studio::ChildrenTreeStore::on_canvas_added));
92         canvas_interface()->signal_canvas_removed().connect(sigc::mem_fun(*this,&studio::ChildrenTreeStore::on_canvas_removed));
93
94         rebuild();
95 }
96
97 ChildrenTreeStore::~ChildrenTreeStore()
98 {
99 }
100
101 Glib::RefPtr<ChildrenTreeStore>
102 ChildrenTreeStore::create(etl::loose_handle<synfigapp::CanvasInterface> canvas_interface_)
103 {
104         return Glib::RefPtr<ChildrenTreeStore>(new ChildrenTreeStore(canvas_interface_));
105 }
106
107 void
108 ChildrenTreeStore::rebuild()
109 {
110         Profiler profiler("ChildrenTreeStore::rebuild()");
111         rebuild_value_nodes();
112         rebuild_canvases();
113 }
114
115 void
116 ChildrenTreeStore::refresh()
117 {
118         Profiler profiler("ChildrenTreeStore::refresh()");
119         refresh_value_nodes();
120         refresh_canvases();
121 }
122
123 void
124 ChildrenTreeStore::rebuild_value_nodes()
125 {
126         Gtk::TreeModel::Children children(value_node_row.children());
127
128         while(!children.empty())erase(children.begin());
129
130         clear_changed_queue();
131
132         std::for_each(
133                 canvas_interface()->get_canvas()->value_node_list().rbegin(), canvas_interface()->get_canvas()->value_node_list().rend(),
134                 sigc::mem_fun(*this, &studio::ChildrenTreeStore::on_value_node_added)
135         );
136 }
137
138 void
139 ChildrenTreeStore::refresh_value_nodes()
140 {
141         Gtk::TreeModel::Children children(value_node_row.children());
142
143         Gtk::TreeModel::Children::iterator iter;
144
145         if(!children.empty())
146                 for(iter = children.begin(); iter != children.end(); ++iter)
147                 {
148                         Gtk::TreeRow row=*iter;
149                         //DEBUGPOINT();
150                         refresh_row(row);
151                 }
152 }
153
154 void
155 ChildrenTreeStore::rebuild_canvases()
156 {
157         Gtk::TreeModel::Children children(canvas_row.children());
158
159         while(!children.empty())erase(children.begin());
160
161         std::for_each(
162                 canvas_interface()->get_canvas()->children().rbegin(), canvas_interface()->get_canvas()->children().rend(),
163                 sigc::mem_fun(*this, &studio::ChildrenTreeStore::on_canvas_added)
164         );
165 }
166
167 void
168 ChildrenTreeStore::refresh_canvases()
169 {
170         rebuild_canvases();
171 }
172
173 void
174 ChildrenTreeStore::refresh_row(Gtk::TreeModel::Row &row, bool /*do_children*/)
175 {
176         CanvasTreeStore::refresh_row(row,false);
177
178         if((bool)row[model.is_value_node])
179         {
180                 changed_set_.erase(row[model.value_node]);
181         }
182
183 }
184
185 void
186 ChildrenTreeStore::on_canvas_added(Canvas::Handle canvas)
187 {
188         Gtk::TreeRow row = *(prepend(canvas_row.children()));
189
190         row[model.icon] = Gtk::Button().render_icon(Gtk::StockID("synfig-canvas"),Gtk::ICON_SIZE_SMALL_TOOLBAR);
191         row[model.id] = canvas->get_id();
192         row[model.name] = canvas->get_name();
193
194         if(!canvas->get_id().empty())
195                 row[model.label] = canvas->get_id();
196         else
197         if(!canvas->get_name().empty())
198                 row[model.label] = canvas->get_name();
199         else
200                 row[model.label] = _("[Unnamed]");
201
202         row[model.canvas] = canvas;
203         row[model.type] = _("Canvas");
204         //row[model.is_canvas] = true;
205         //row[model.is_value_node] = false;
206 }
207
208 void
209 ChildrenTreeStore::on_canvas_removed(Canvas::Handle /*canvas*/)
210 {
211         rebuild_canvases();
212 }
213
214 void
215 ChildrenTreeStore::on_value_node_added(ValueNode::Handle value_node)
216 {
217 //      if(value_node->get_id().find("Unnamed")!=String::npos)
218 //              return;
219
220         Gtk::TreeRow row = *prepend(value_node_row.children());
221
222         set_row(row,synfigapp::ValueDesc(canvas_interface()->get_canvas(),value_node->get_id()),false);
223 }
224
225 void
226 ChildrenTreeStore::on_value_node_deleted(etl::handle<ValueNode> value_node)
227 {
228         Gtk::TreeIter iter;
229         //int i(0);
230
231         if(find_first_value_node(value_node,iter))
232         {
233                 erase(iter);
234         }
235         //rebuild_value_nodes();
236 }
237
238 bool
239 ChildrenTreeStore::execute_changed_value_nodes()
240 {
241         Profiler profiler("ChildrenTreeStore::execute_changed_value_nodes()");
242         DEBUGPOINT();
243         if(!replaced_set_.empty())
244                 rebuild_value_nodes();
245
246         etl::clock timer;
247         timer.reset();
248
249         while(!changed_set_.empty())
250         {
251                 ValueNode::Handle value_node(*changed_set_.begin());
252                 changed_set_.erase(value_node);
253
254                 Gtk::TreeIter iter;
255
256                 try
257                 {
258                         Gtk::TreeIter iter;
259                         int i(0);
260
261                         if(!value_node->is_exported() && find_first_value_node(value_node,iter))
262                         {
263                                 rebuild_value_nodes();
264                                 continue;
265                         }
266
267                         if(value_node->is_exported() && find_first_value_node(value_node,iter)) do
268                         {
269                                 Gtk::TreeRow row(*iter);
270                                 i++;
271                                 refresh_row(row);
272                         }while(find_next_value_node(value_node,iter));
273
274                         if(!i)
275                         {
276                                 refresh_value_nodes();
277                                 return false;
278                         }
279
280                 }
281                 catch(...)
282                 {
283                         rebuild_value_nodes();
284                         return false;
285                 }
286
287                 // If we are taking too long...
288                 if(timer()>4)
289                 {
290                         refresh_value_nodes();
291                         return false;
292                 }
293         }
294
295         return false;
296 }
297
298 void
299 ChildrenTreeStore::on_value_node_changed(etl::handle<ValueNode> value_node)
300 {
301
302         if(!value_node->is_exported())
303                 return;
304         changed_connection.disconnect();
305 //      if(!execute_changed_queued())
306 //              changed_connection=Glib::signal_idle().connect(sigc::mem_fun(*this,&ChildrenTreeStore::execute_changed_value_nodes));
307         changed_connection=Glib::signal_timeout().connect(sigc::mem_fun(*this,&ChildrenTreeStore::execute_changed_value_nodes),150);
308
309         changed_set_.insert(value_node);
310         /*
311         try
312         {
313                 Gtk::TreeIter iter;
314                 int i(0);
315                 while(find_next_value_node(value_node,iter))
316                 {
317                         Gtk::TreeRow row(*iter);
318                         i++;
319                         refresh_row(row);
320                 }
321                 if(!i)
322                 {
323                         refresh_value_nodes();
324                 }
325         }
326         catch(...)
327         {
328                 rebuild_value_nodes();
329         }
330         */
331 }
332
333 void
334 ChildrenTreeStore::on_value_node_renamed(etl::handle<ValueNode> value_node)
335 {
336         rebuild_value_nodes();
337 }
338
339 void
340 ChildrenTreeStore::on_value_node_replaced(synfig::ValueNode::Handle replaced_value_node,synfig::ValueNode::Handle /*new_value_node*/)
341 {
342         changed_connection.disconnect();
343         //if(!execute_changed_queued())
344 //              changed_connection=Glib::signal_idle().connect(sigc::mem_fun(*this,&ChildrenTreeStore::execute_changed_value_nodes));
345                 changed_connection=Glib::signal_timeout().connect(sigc::mem_fun(*this,&ChildrenTreeStore::execute_changed_value_nodes),150);
346
347         replaced_set_.insert(replaced_value_node);
348 }
349
350 void
351 ChildrenTreeStore::set_value_impl(const Gtk::TreeModel::iterator& iter, int column, const Glib::ValueBase& value)
352 {
353         if(column>=get_n_columns_vfunc())
354         {
355                 g_warning("LayerTreeStore::set_value_impl: Bad column (%d)",column);
356                 return;
357         }
358
359         if(!g_value_type_compatible(G_VALUE_TYPE(value.gobj()),get_column_type_vfunc(column)))
360         {
361                 g_warning("LayerTreeStore::set_value_impl: Bad value type");
362                 return;
363         }
364
365         try
366         {
367                 if(column==model.value.index())
368                 {
369                         Glib::Value<synfig::ValueBase> x;
370                         g_value_init(x.gobj(),model.value.type());
371                         g_value_copy(value.gobj(),x.gobj());
372
373                         synfigapp::ValueDesc value_desc((*iter)[model.value_desc]);
374                         if(value_desc)
375                         {
376                                 canvas_interface()->change_value(value_desc,x.get());
377                                 row_changed(get_path(*iter),*iter);
378                         }
379
380                         return;
381                 }
382                 else
383                         CanvasTreeStore::set_value_impl(iter,column, value);
384         }
385         catch(std::exception x)
386         {
387                 g_warning(x.what());
388         }
389 }