Fix a crash when running single-threaded and dragging the time slider.
[synfig.git] / synfig-studio / trunk / src / gtkmm / canvastreestore.cpp
1 /* === S Y N F I G ========================================================= */
2 /*!     \file canvastreestore.cpp
3 **      \brief Template File
4 **
5 **      $Id$
6 **
7 **      \legal
8 **      Copyright (c) 2002-2005 Robert B. Quattlebaum Jr., Adrian Bentley
9 **
10 **      This package is free software; you can redistribute it and/or
11 **      modify it under the terms of the GNU General Public License as
12 **      published by the Free Software Foundation; either version 2 of
13 **      the License, or (at your option) any later version.
14 **
15 **      This package is distributed in the hope that it will be useful,
16 **      but WITHOUT ANY WARRANTY; without even the implied warranty of
17 **      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18 **      General Public License for more details.
19 **      \endlegal
20 */
21 /* ========================================================================= */
22
23 /* === H E A D E R S ======================================================= */
24
25 #ifdef USING_PCH
26 #       include "pch.h"
27 #else
28 #ifdef HAVE_CONFIG_H
29 #       include <config.h>
30 #endif
31
32 #include "canvastreestore.h"
33 #include <synfig/valuenode.h>
34 #include "iconcontroler.h"
35 #include <synfig/valuenode_timedswap.h>
36 #include <synfig/valuenode_animated.h>
37 #include <gtkmm/button.h>
38 #include <synfigapp/instance.h>
39 #include "cellrenderer_value.h"
40 #include "cellrenderer_timetrack.h"
41 #include <ETL/clock>
42
43 #endif
44
45 /* === U S I N G =========================================================== */
46
47 using namespace std;
48 using namespace etl;
49 using namespace synfig;
50 using namespace studio;
51
52 /* === M A C R O S ========================================================= */
53
54 /* === G L O B A L S ======================================================= */
55
56 /* === P R O C E D U R E S ================================================= */
57
58 /* === M E T H O D S ======================================================= */
59
60 static CanvasTreeStore::Model& ModelHack()
61 {
62         static CanvasTreeStore::Model* model(0);
63         if(!model)model=new CanvasTreeStore::Model;
64         return *model;
65 }
66
67 CanvasTreeStore::CanvasTreeStore(etl::loose_handle<synfigapp::CanvasInterface> canvas_interface_):
68         Gtk::TreeStore(ModelHack()),
69         canvas_interface_               (canvas_interface_)
70 {
71 }
72
73 CanvasTreeStore::~CanvasTreeStore()
74 {
75 }
76
77 void
78 CanvasTreeStore::get_value_vfunc(const Gtk::TreeModel::iterator& iter, int column, Glib::ValueBase& value)const
79 {
80         if(column==model.value.index())
81         {
82                 synfigapp::ValueDesc value_desc((*iter)[model.value_desc]);
83
84                 Glib::Value<synfig::ValueBase> x;
85                 g_value_init(x.gobj(),x.value_type());
86
87                 if(!value_desc)
88                 {
89                         x.set(ValueBase());
90                 }
91                 else
92                 if(value_desc.is_const())
93                         x.set(value_desc.get_value());
94                 else
95                 if(value_desc.is_value_node())
96                         x.set((*value_desc.get_value_node())(canvas_interface()->get_time()));
97                 else
98                 {
99                         synfig::error(__FILE__":%d: Unable to figure out value",__LINE__);
100                         return;
101                 }
102
103                 g_value_init(value.gobj(),x.value_type());
104                 g_value_copy(x.gobj(),value.gobj());
105         }
106         else
107         if(column==model.is_value_node.index())
108         {
109                 synfigapp::ValueDesc value_desc((*iter)[model.value_desc]);
110
111                 Glib::Value<bool> x;
112                 g_value_init(x.gobj(),x.value_type());
113
114                 x.set(value_desc && value_desc.is_value_node());
115
116                 g_value_init(value.gobj(),x.value_type());
117                 g_value_copy(x.gobj(),value.gobj());
118         }
119         else
120         if(column==model.is_shared.index())
121         {
122                 synfigapp::ValueDesc value_desc((*iter)[model.value_desc]);
123
124                 Glib::Value<bool> x;
125                 g_value_init(x.gobj(),x.value_type());
126
127                 x.set(value_desc.is_value_node() && value_desc.get_value_node()->rcount()>1);
128
129                 g_value_init(value.gobj(),x.value_type());
130                 g_value_copy(x.gobj(),value.gobj());
131         }
132         else
133         if(column==model.is_exported.index())
134         {
135                 synfigapp::ValueDesc value_desc((*iter)[model.value_desc]);
136
137                 Glib::Value<bool> x;
138                 g_value_init(x.gobj(),x.value_type());
139
140                 x.set(value_desc.is_value_node() && value_desc.get_value_node()->is_exported());
141
142                 g_value_init(value.gobj(),x.value_type());
143                 g_value_copy(x.gobj(),value.gobj());
144         }
145         else
146         if(column==model.is_canvas.index())
147         {
148                 synfigapp::ValueDesc value_desc((*iter)[model.value_desc]);
149
150                 Glib::Value<bool> x;
151                 g_value_init(x.gobj(),x.value_type());
152
153                 x.set(!value_desc && (Canvas::Handle)(*iter)[model.canvas]);
154
155                 g_value_init(value.gobj(),x.value_type());
156                 g_value_copy(x.gobj(),value.gobj());
157         }
158         else
159         if(column==model.id.index())
160         {
161                 synfigapp::ValueDesc value_desc((*iter)[model.value_desc]);
162
163                 Glib::Value<Glib::ustring> x;
164                 g_value_init(x.gobj(),x.value_type());
165
166                 if(value_desc && value_desc.is_value_node())
167                         x.set(value_desc.get_value_node()->get_id());
168                 else if(!value_desc && Canvas::Handle((*iter)[model.canvas]))
169                         x.set(Canvas::Handle((*iter)[model.canvas])->get_id());
170                 else
171                         return Gtk::TreeStore::get_value_vfunc(iter,column,value);
172
173                 g_value_init(value.gobj(),x.value_type());
174                 g_value_copy(x.gobj(),value.gobj());
175         }
176         else
177         if(column==model.is_editable.index())
178         {
179                 synfigapp::ValueDesc value_desc((*iter)[model.value_desc]);
180
181                 Glib::Value<bool> x;
182                 g_value_init(x.gobj(),x.value_type());
183
184                 x.set(!value_desc.is_value_node() || synfigapp::is_editable(value_desc.get_value_node()));
185
186                 g_value_init(value.gobj(),x.value_type());
187                 g_value_copy(x.gobj(),value.gobj());
188         }
189         else
190         if(column==model.type.index())
191         {
192                 synfigapp::ValueDesc value_desc((*iter)[model.value_desc]);
193
194                 Glib::Value<Glib::ustring> x;
195                 g_value_init(x.gobj(),x.value_type());
196
197                 // Set the type
198                 if(!value_desc)
199                 {
200                         if((*iter)[model.is_canvas])
201                                 x.set(_("Canvas"));
202                 }
203                 else
204                 {
205                         if(!value_desc.is_value_node() || value_desc.get_value_node()->get_name()=="constant")
206                         {
207                                 x.set(ValueBase::type_name(value_desc.get_value_type()));
208                         }
209                         else
210                         {
211                                 x.set(value_desc.get_value_node()->get_local_name());
212                         }
213                 }
214
215                 g_value_init(value.gobj(),x.value_type());
216                 g_value_copy(x.gobj(),value.gobj());
217         }
218         else
219         if(column==model.label.index())
220         {
221                 synfigapp::ValueDesc value_desc((*iter)[model.value_desc]);
222
223                 Glib::Value<Glib::ustring> x;
224                 g_value_init(x.gobj(),x.value_type());
225
226                 // Set the type
227                 if(!value_desc)
228                 {
229                         Canvas::Handle canvas((*iter)[model.canvas]);
230                         if(canvas)
231                         {
232                                 if(!canvas->get_id().empty())
233                                         x.set(canvas->get_id());
234                                 else
235                                 if(!canvas->get_name().empty())
236                                         x.set(canvas->get_name());
237                                 else
238                                         x.set(_("[Unnamed]"));
239                                 x.set(_("Canvas"));
240                         }
241                         return Gtk::TreeStore::get_value_vfunc(iter,column,value);
242                 }
243                 else
244                 {
245                         ValueNode::Handle value_node=value_desc.get_value_node();
246
247                         // Setup the row's label
248                         if(value_node->get_id().empty())
249                                 x.set(Glib::ustring((*iter)[model.name]));
250                         else if(Glib::ustring((*iter)[model.name]).empty())
251                                 x.set(value_node->get_id());
252                         else
253                                 x.set(Glib::ustring((*iter)[model.name])+" ("+value_node->get_id()+')');
254                 }
255
256                 g_value_init(value.gobj(),x.value_type());
257                 g_value_copy(x.gobj(),value.gobj());
258         }
259         else
260         if(column==model.icon.index())
261         {
262                 synfigapp::ValueDesc value_desc((*iter)[model.value_desc]);
263                 if(!value_desc)
264                         return Gtk::TreeStore::get_value_vfunc(iter,column,value);
265
266                 Glib::Value<Glib::RefPtr<Gdk::Pixbuf> > x;
267                 g_value_init(x.gobj(),x.value_type());
268
269                 x.set(get_tree_pixbuf(value_desc.get_value_type()));
270
271                 g_value_init(value.gobj(),x.value_type());
272                 g_value_copy(x.gobj(),value.gobj());
273         }
274         else
275                 Gtk::TreeStore::get_value_vfunc(iter,column,value);
276 }
277
278 bool
279 CanvasTreeStore::find_first_value_desc(const synfigapp::ValueDesc& value_desc, Gtk::TreeIter& iter)
280 {
281         iter=children().begin();
282         while(iter && value_desc!=(*iter)[model.value_desc])
283         {
284                 if(!iter->children().empty())
285                 {
286                         Gtk::TreeIter iter2(iter->children().begin());
287                         if(iter2 && value_desc==(*iter2)[model.value_desc] || find_next_value_desc(value_desc, iter2))
288                         {
289                                 iter=iter2;
290                                 return true;
291                         }
292                 }
293                 Gtk::TreeIter iter2(++iter);
294                 if(!iter2)
295                         iter==iter->parent();
296                 else
297                         iter=iter2;
298         }
299         return (bool)iter && value_desc==(*iter)[model.value_desc];
300 }
301
302 bool
303 CanvasTreeStore::find_next_value_desc(const synfigapp::ValueDesc& value_desc, Gtk::TreeIter& iter)
304 {
305         if(!iter) return find_first_value_desc(value_desc,iter);
306
307         if(iter) do {
308                 if(!iter->children().empty())
309                 {
310                         Gtk::TreeIter iter2(iter->children().begin());
311                         if(iter2 && value_desc==(*iter2)[model.value_desc] || find_next_value_desc(value_desc, iter2))
312                         {
313                                 iter=iter2;
314                                 return true;
315                         }
316                 }
317                 Gtk::TreeIter iter2(++iter);
318                 if(!iter2)
319                 {
320                         iter==iter->parent();
321                         if(iter)++iter;
322                 }
323                 else
324                         iter=iter2;
325         } while(iter && value_desc!=(*iter)[model.value_desc]);
326         return (bool)iter && value_desc==(*iter)[model.value_desc];
327 }
328
329 bool
330 CanvasTreeStore::find_first_value_node(const ValueNode::Handle& value_node, Gtk::TreeIter& iter)
331 {
332         iter=children().begin();
333         while(iter && value_node!=(ValueNode::Handle)(*iter)[model.value_node])
334         {
335                 if(!iter->children().empty())
336                 {
337                         Gtk::TreeIter iter2(iter->children().begin());
338                         if(iter2 && value_node==(ValueNode::Handle)(*iter2)[model.value_node] || find_next_value_node(value_node, iter2))
339                         {
340                                 iter=iter2;
341                                 return true;
342                         }
343                 }
344                 Gtk::TreeIter iter2(++iter);
345                 if(!iter2)
346                         iter==iter->parent();
347                 else
348                         iter=iter2;
349         }
350         return (bool)iter && value_node==(ValueNode::Handle)(*iter)[model.value_node];
351 }
352
353 bool
354 CanvasTreeStore::find_next_value_node(const ValueNode::Handle& value_node, Gtk::TreeIter& iter)
355 {
356         if(!iter) return find_first_value_node(value_node,iter);
357
358         if(iter) do {
359                 if(!iter->children().empty())
360                 {
361                         Gtk::TreeIter iter2(iter->children().begin());
362                         if(iter2 && value_node==(ValueNode::Handle)(*iter2)[model.value_node] || find_next_value_node(value_node, iter2))
363                         {
364                                 iter=iter2;
365                                 return true;
366                         }
367                 }
368                 Gtk::TreeIter iter2(++iter);
369                 if(!iter2)
370                 {
371                         iter==iter->parent();
372                         if(iter)++iter;
373                 }
374                 else
375                         iter=iter2;
376         } while(iter && value_node!=(ValueNode::Handle)(*iter)[model.value_node]);
377         return (bool)iter && value_node==(ValueNode::Handle)(*iter)[model.value_node];
378 }
379
380 void
381 CanvasTreeStore::set_row(Gtk::TreeRow row,synfigapp::ValueDesc value_desc, bool do_children)
382 {
383         Gtk::TreeModel::Children children = row.children();
384         while(!children.empty() && erase(children.begin()));
385
386         row[model.value_desc]=value_desc;
387         try
388         {
389                 //row[model.icon] = get_tree_pixbuf(value_desc.get_value_type());
390
391                 if(value_desc.is_value_node())
392                 {
393                         ValueNode::Handle value_node=value_desc.get_value_node();
394
395                         assert(value_node);
396
397                         row[model.value_node] = value_node;
398                         //row[model.is_canvas] = false;
399                         //row[model.is_value_node] = true;
400                         //row[model.is_editable] = synfigapp::is_editable(value_node);
401                         //row[model.id]=value_node->get_id();
402
403                         // Set the canvas
404                         if(value_desc.parent_is_canvas())
405                                 row[model.canvas]=value_desc.get_canvas();
406                         else
407                                 row[model.canvas]=canvas_interface()->get_canvas();
408
409                         LinkableValueNode::Handle linkable;
410                         linkable=LinkableValueNode::Handle::cast_dynamic(value_node);
411
412                         if(linkable && do_children)
413                         {
414                                 row[model.link_count] = linkable->link_count();
415                                 for(int i=0;i<linkable->link_count();i++)
416                                 {
417                                         Gtk::TreeRow child_row=*(append(row.children()));
418                                         child_row[model.link_id] = i;
419                                         child_row[model.canvas] = static_cast<Canvas::Handle>(row[model.canvas]);
420                                         child_row[model.name] = linkable->link_local_name(i);
421                                         set_row(child_row,synfigapp::ValueDesc(linkable,i));
422                                 }
423                         }
424                         return;
425                 }
426                 else
427                 {
428                         //row[model.is_value_node] = false;
429                         //row[model.is_editable] = true;
430                         //row[model.label] = Glib::ustring(row[model.name]);
431                         return;
432                 }
433         }
434         catch(synfig::Exception::IDNotFound x)
435         {
436                 synfig::error(__FILE__":%d: IDNotFound thrown",__LINE__);
437                 erase(row);
438                 return;
439         }
440
441         // We should never get to this point
442         assert(0);
443 }
444
445 void
446 CanvasTreeStore::refresh_row(Gtk::TreeModel::Row &row, bool do_children)
447 {
448         synfigapp::ValueDesc value_desc=row[model.value_desc];
449
450         if(value_desc)
451         {
452                 if((bool)row[model.is_value_node] != value_desc.is_value_node() ||
453                         (!bool(row[model.is_value_node]) && row[model.link_count]!=0))
454                 {
455                         set_row(row,value_desc,do_children);
456                         return;
457                 }
458
459                 if(row[model.is_value_node])
460                 {
461                         ValueNode::Handle value_node(value_desc.get_value_node());
462
463                         if(ValueNode::Handle(row[model.value_node])!=value_node)
464                         {
465                                 rebuild_row(row,do_children);
466                                 return;
467                         }
468
469                         //row[model.id]=value_node->get_id();
470
471                         // Setup the row's label
472                         /*
473                         if(value_node->get_id().empty())
474                                 row[model.label] = Glib::ustring(row[model.name]);
475                         else if(Glib::ustring(row[model.name]).empty())
476                                 row[model.label] = value_node->get_id();
477                         else
478                                 row[model.label] = Glib::ustring(row[model.name])+" ("+value_node->get_id()+')';
479                         */
480
481                         LinkableValueNode::Handle linkable;
482                         linkable=LinkableValueNode::Handle::cast_dynamic(value_node);
483                         if(do_children && linkable && ((int)row[model.link_count] != linkable->link_count()))
484                         {
485         //                      Gtk::TreeModel::Children children = row.children();
486         //                      while(!children.empty() && erase(children.begin()));
487
488                                 set_row(row,value_desc);
489                                 return;
490                         }
491                 }
492                 else
493                 {
494                         //row[model.label] = Glib::ustring(row[model.name]);
495                         //row[model.is_value_node] = false;
496                         //row[model.is_editable] = true;
497                 }
498         }
499         if(!do_children)
500                 return;
501
502         Gtk::TreeModel::Children children = row.children();
503         Gtk::TreeModel::Children::iterator iter;
504
505         if(!children.empty())
506         for(iter = children.begin(); iter != children.end(); ++iter)
507         {
508                 Gtk::TreeRow row=*iter;
509                 refresh_row(row);
510         }
511 }
512
513 void
514 CanvasTreeStore::rebuild_row(Gtk::TreeModel::Row &row, bool do_children)
515 {
516         synfigapp::ValueDesc value_desc=(synfigapp::ValueDesc)row[model.value_desc];
517
518         if(value_desc && value_desc.get_value_node())
519         {
520                 ValueNode::Handle value_node;
521                 value_node=value_desc.get_value_node();
522
523                 assert(value_node);if(!value_node)return;
524
525                 if(value_node && value_node!=(ValueNode::Handle)row[model.value_node])
526                 {
527 //                      Gtk::TreeModel::Children children = row.children();
528 //                      while(!children.empty() && erase(children.begin()));
529
530                         set_row(row,value_desc,do_children);
531                         return;
532                 }
533
534                 LinkableValueNode::Handle linkable;
535                 linkable=LinkableValueNode::Handle::cast_dynamic(value_node);
536
537                 if( do_children && linkable && (int)row[model.link_count] != linkable->link_count())
538                 {
539 //                      Gtk::TreeModel::Children children = row.children();
540 //                      while(!children.empty() && erase(children.begin()));
541
542                         set_row(row,value_desc);
543                         return;
544                 }
545
546                 //if(!value_node)
547                 //      value_node=row[model.value_node];
548
549                 row[model.id]=value_node->get_id();
550
551                 // Setup the row's label
552                 if(value_node->get_id().empty())
553                         row[model.label] = Glib::ustring(row[model.name]);
554                 else if(Glib::ustring(row[model.name]).empty())
555                         row[model.label] = value_node->get_id();
556                 else
557                         row[model.label] = Glib::ustring(row[model.name])+" ("+value_node->get_id()+')';
558         }
559         else
560         {
561                 row[model.label] = Glib::ustring(row[model.name]);
562                 row[model.is_value_node] = false;
563                 row[model.is_editable] = true;
564                 Gtk::TreeModel::Children children = row.children();
565                 while(!children.empty() && erase(children.begin()));
566         }
567         if(!do_children)
568                 return;
569
570         Gtk::TreeModel::Children children = row.children();
571         Gtk::TreeModel::Children::iterator iter;
572         if(!children.empty())
573         for(iter = children.begin(); iter != children.end(); ++iter)
574         {
575                 Gtk::TreeRow row=*iter;
576                 rebuild_row(row);
577         }
578 }
579
580 CellRenderer_ValueBase*
581 CanvasTreeStore::add_cell_renderer_value(Gtk::TreeView::Column* column)
582 {
583         const CanvasTreeStore::Model model;
584
585         CellRenderer_ValueBase* ret;
586
587         ret=Gtk::manage( new CellRenderer_ValueBase() );
588
589         column->pack_start(*ret,true);
590         column->add_attribute(ret->property_value(), model.value);
591         column->add_attribute(ret->property_editable(), model.is_editable);
592         column->add_attribute(ret->property_canvas(), model.canvas);
593
594         return ret;
595 }
596
597 CellRenderer_TimeTrack*
598 CanvasTreeStore::add_cell_renderer_value_node(Gtk::TreeView::Column* column)
599 {
600         const CanvasTreeStore::Model model;
601
602         CellRenderer_TimeTrack* ret;
603
604         ret = Gtk::manage( new CellRenderer_TimeTrack() );
605
606         column->pack_start(*ret,true);
607         //column->add_attribute(ret->property_visible(), model.is_value_node);
608         column->add_attribute(ret->property_value_desc(), model.value_desc);
609         column->add_attribute(ret->property_canvas(), model.canvas);
610
611
612         return ret;
613 }