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