Fix bugs in previous commit that caused FTBFS in synfig and ETL FTBFS with older...
[synfig.git] / synfig-studio / tags / synfigstudio_0_61_07_rc1 / src / gtkmm / keyframetreestore.cpp
1 /* === S Y N F I G ========================================================= */
2 /*!     \file keyframetreestore.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 "keyframetreestore.h"
34 #include <synfig/valuenode.h>
35 #include "iconcontroler.h"
36 #include <synfig/valuenode_timedswap.h>
37 #include <gtkmm/button.h>
38 #include <gtkmm/treerowreference.h>
39 #include <synfig/canvas.h>
40 #include <synfig/keyframe.h>
41 #include <time.h>
42 #include <cstdlib>
43 #include <ETL/smart_ptr>
44 #include <synfigapp/action.h>
45 #include <synfigapp/instance.h>
46 #include "onemoment.h"
47 #include <synfig/exception.h>
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 KeyframeTreeStore_Class KeyframeTreeStore::keyframe_tree_store_class_;
63
64 /* === C L A S S E S & S T R U C T S ======================================= */
65
66 struct _keyframe_iterator
67 {
68         synfig::KeyframeList::iterator iter;
69         int ref_count;
70         int index;
71 };
72
73 /*
74 Gtk::TreeModel::iterator keyframe_iter_2_model_iter(synfig::KeyframeList::iterator iter,int index)
75 {
76         Gtk::TreeModel::iterator ret;
77
78         _keyframe_iterator*& data(static_cast<_keyframe_iterator*&>(ret->gobj()->user_data));
79         data=new _keyframe_iterator();
80         data->ref_count=1;
81         data->iter=iter;
82         data->index=index;
83
84         return ret;
85 }
86 */
87
88 synfig::KeyframeList::iterator model_iter_2_keyframe_iter(Gtk::TreeModel::iterator iter)
89 {
90         _keyframe_iterator* data(static_cast<_keyframe_iterator*>(iter->gobj()->user_data));
91         if(!data)
92                 throw std::runtime_error("bad data");
93         return data->iter;
94 }
95
96 int get_index_from_model_iter(Gtk::TreeModel::iterator iter)
97 {
98         _keyframe_iterator* data(static_cast<_keyframe_iterator*>(iter->gobj()->user_data));
99         if(!data)
100                 throw std::runtime_error("bad data");
101         return data->index;
102 }
103
104
105 /*
106 #ifndef TreeRowReferenceHack
107 class TreeRowReferenceHack
108 {
109         GtkTreeRowReference *gobject_;
110 public:
111         TreeRowReferenceHack():
112                 gobject_(0)
113         {
114         }
115
116         TreeRowReferenceHack(const Glib::RefPtr<Gtk::TreeModel>& model, const Gtk::TreeModel::Path& path):
117                 gobject_ ( gtk_tree_row_reference_new(model->gobj(), const_cast<GtkTreePath*>(path.gobj())) )
118         {
119         }
120
121         TreeRowReferenceHack(const TreeRowReferenceHack &x):
122                 gobject_ ( x.gobject_?gtk_tree_row_reference_copy(x.gobject_):0 )
123         {
124
125         }
126
127         void swap(TreeRowReferenceHack & other)
128         {
129                 GtkTreeRowReference *const temp = gobject_;
130                 gobject_ = other.gobject_;
131                 other.gobject_ = temp;
132         }
133
134         const TreeRowReferenceHack &
135         operator=(const TreeRowReferenceHack &rhs)
136         {
137                 TreeRowReferenceHack temp (rhs);
138                 swap(temp);
139                 return *this;
140         }
141
142         ~TreeRowReferenceHack()
143         {
144                 if(gobject_)
145                         gtk_tree_row_reference_free(gobject_);
146         }
147
148         Gtk::TreeModel::Path get_path() { return Gtk::TreeModel::Path(gtk_tree_row_reference_get_path(gobject_),false); }
149         GtkTreeRowReference *gobj() { return gobject_; }
150 };
151 #endif
152 */
153
154 /* === P R O C E D U R E S ================================================= */
155
156 void clear_iterator(GtkTreeIter* iter)
157 {
158         iter->stamp=0;
159         iter->user_data=iter->user_data2=iter->user_data3=0;
160 }
161
162 /* === M E T H O D S ======================================================= */
163
164 const Glib::Class&
165 KeyframeTreeStore_Class::init()
166 {
167         if(!gtype_)
168         {
169                 class_init_func_ = &KeyframeTreeStore_Class::class_init_function;
170
171                 const GTypeInfo derived_info =
172                 {
173                         sizeof(GObjectClass),
174                         NULL,
175                         NULL,
176                         class_init_func_,
177                         NULL,
178                         NULL,
179                         sizeof(GObject),
180                         0,
181                         0,
182                         NULL
183                 };
184
185                 gtype_ = g_type_register_static(G_TYPE_OBJECT, "KeyframeTreeStore", &derived_info, GTypeFlags(0));
186                 Gtk::TreeModel::add_interface(get_type());
187         }
188         return *this;
189 }
190
191 void
192 KeyframeTreeStore_Class::class_init_function(gpointer /*g_class*/, gpointer /*class_data*/)
193 {
194         // ???
195 }
196
197 KeyframeTreeStore::KeyframeTreeStore(etl::loose_handle<synfigapp::CanvasInterface> canvas_interface_):
198         Glib::ObjectBase        ("KeyframeTreeStore"),
199         Glib::Object            (Glib::ConstructParams(keyframe_tree_store_class_.init(), (char*) 0)),
200         canvas_interface_       (canvas_interface_)
201 {
202         reset_stamp();
203         //reset_path_table();
204
205         canvas_interface()->signal_keyframe_added().connect(sigc::mem_fun(*this,&studio::KeyframeTreeStore::add_keyframe));
206         canvas_interface()->signal_keyframe_removed().connect(sigc::mem_fun(*this,&studio::KeyframeTreeStore::remove_keyframe));
207         canvas_interface()->signal_keyframe_changed().connect(sigc::mem_fun(*this,&studio::KeyframeTreeStore::change_keyframe));
208 }
209
210 KeyframeTreeStore::~KeyframeTreeStore()
211 {
212         synfig::info("KeyframeTreeStore::~KeyframeTreeStore(): Deleted");
213 }
214
215 Glib::RefPtr<KeyframeTreeStore>
216 KeyframeTreeStore::create(etl::loose_handle<synfigapp::CanvasInterface> canvas_interface_)
217 {
218         KeyframeTreeStore *store(new KeyframeTreeStore(canvas_interface_));
219         Glib::RefPtr<KeyframeTreeStore> ret(store);
220         assert(ret);
221         return ret;
222 }
223
224 void
225 KeyframeTreeStore::reset_stamp()
226 {
227         stamp_=time(0)+reinterpret_cast<long>(this);
228 }
229
230 /*
231 void
232 KeyframeTreeStore::reset_path_table()
233 {
234         Gtk::TreeModel::Children::iterator iter;
235         const Gtk::TreeModel::Children children(children());
236         path_table_.clear();
237         for(iter = children.begin(); iter != children.end(); ++iter)
238         {
239                 Gtk::TreeModel::Row row(*iter);
240                 path_table_[(Keyframe)row[model.keyframe]]=TreeRowReferenceHack(Glib::RefPtr<KeyframeTreeStore>(this),Gtk::TreePath(row));
241         }
242 }
243 */
244
245
246 inline bool
247 KeyframeTreeStore::iterator_sane(const GtkTreeIter* iter)const
248 {
249         if(iter && iter->stamp==stamp_)
250                 return true;
251         g_warning("KeyframeTreeStore::iterator_sane(): Bad iterator stamp");
252         return false;
253 }
254
255 inline bool
256 KeyframeTreeStore::iterator_sane(const Gtk::TreeModel::iterator& iter)const
257 {
258         return iterator_sane(iter->gobj());
259 }
260
261 inline void
262 KeyframeTreeStore::dump_iterator(const GtkTreeIter* /*gtk_iter*/, const Glib::ustring &/*name*/)const
263 {
264 #if 0
265         if(!gtk_iter)
266         {
267                 g_warning("KeyframeTreeStore::dump_iterator: \"%s\" is NULL (Root?)",name.c_str());
268                 return;
269         }
270
271         _keyframe_iterator *iter(static_cast<_keyframe_iterator*>(gtk_iter->user_data));
272
273         if(gtk_iter->stamp!=stamp_ || !iter)
274         {
275                 g_warning("KeyframeTreeStore::dump_iterator: \"%s\" is INVALID",name.c_str());
276                 return;
277         }
278
279         if((unsigned)iter->index>=canvas_interface()->get_canvas()->keyframe_list().size())
280                 g_warning("KeyframeTreeStore::dump_iterator: \"%s\"(%p) has bad index(index:%d)",name.c_str(),gtk_iter,iter->index);
281
282         g_warning("KeyframeTreeStore::dump_iterator: \"%s\"(%p) ref:%d, index:%d, time:%s",name.c_str(),gtk_iter,iter->ref_count,iter->index,iter->iter->get_time().get_string().c_str());
283 #endif
284 }
285
286 inline void
287 KeyframeTreeStore::dump_iterator(const Gtk::TreeModel::iterator& iter, const Glib::ustring &name)const
288 {
289         dump_iterator(iter->gobj(),name);
290 }
291
292 int
293 KeyframeTreeStore::time_sorter(const Gtk::TreeModel::iterator &rhs,const Gtk::TreeModel::iterator &lhs)
294 {
295         const Model model;
296
297         _keyframe_iterator *rhs_iter(static_cast<_keyframe_iterator*>(rhs->gobj()->user_data));
298         _keyframe_iterator *lhs_iter(static_cast<_keyframe_iterator*>(lhs->gobj()->user_data));
299
300         Time diff(rhs_iter->iter->get_time()-lhs_iter->iter->get_time());
301         if(diff<0)
302                 return -1;
303         if(diff>0)
304                 return 1;
305         return 0;
306 }
307
308 void
309 KeyframeTreeStore::set_value_impl(const Gtk::TreeModel::iterator& row, int column, const Glib::ValueBase& value)
310 {
311         if(!iterator_sane(row))
312                 return;
313
314         if(column>=get_n_columns_vfunc())
315         {
316                 g_warning("KeyframeTreeStore::set_value_impl: Bad column (%d)",column);
317                 return;
318         }
319
320         if(!g_value_type_compatible(G_VALUE_TYPE(value.gobj()),get_column_type_vfunc(column)))
321         {
322                 g_warning("KeyframeTreeStore::set_value_impl: Bad value type");
323                 return;
324         }
325
326         _keyframe_iterator *iter(static_cast<_keyframe_iterator*>(row.gobj()->user_data));
327
328         try
329         {
330                 if(column==model.time_delta.index())
331                 {
332                         Glib::Value<synfig::Time> x;
333                         g_value_init(x.gobj(),model.time.type());
334                         g_value_copy(value.gobj(),x.gobj());
335
336                         Time new_delta(x.get());
337                         if(new_delta<=Time::zero()+Time::epsilon())
338                         {
339                                 // Bad value
340                                 return;
341                         }
342
343                         Time old_delta((*row)[model.time_delta]);
344                         if(old_delta<=Time::zero()+Time::epsilon())
345                         {
346                                 // Bad old delta
347                                 return;
348                         }
349                         // row(row) on the next line is bad - don't use it, because it leaves 'row' uninitialised
350                         //Gtk::TreeModel::iterator row(row);
351                         //row++;
352                         //if(!row)return;
353
354                         Time change_delta(new_delta-old_delta);
355
356                         if(change_delta<=Time::zero()+Time::epsilon() &&change_delta>=Time::zero()-Time::epsilon())
357                         {
358                                 // Not an error, just no change
359                                 return;
360                         }
361
362                         {
363                                 Keyframe keyframe((*row)[model.keyframe]);
364                                 synfigapp::Action::Handle action(synfigapp::Action::create("keyframe_set_delta"));
365
366                                 if(!action)return;
367
368                                 action->set_param("canvas",canvas_interface()->get_canvas());
369                                 action->set_param("canvas_interface",canvas_interface());
370                                 action->set_param("keyframe",keyframe);
371                                 action->set_param("delta",change_delta);
372
373                                 canvas_interface()->get_instance()->perform_action(action);
374                         }
375
376                         return;
377                 }
378                 else
379                 if(column==model.time.index())
380                 {
381                         OneMoment one_moment;
382
383                         Glib::Value<synfig::Time> x;
384                         g_value_init(x.gobj(),model.time.type());
385                         g_value_copy(value.gobj(),x.gobj());
386                         synfig::Keyframe keyframe(*iter->iter);
387
388                         synfig::info("KeyframeTreeStore::set_value_impl():old_time=%s",keyframe.get_time().get_string().c_str());
389                         keyframe.set_time(x.get());
390                         synfig::info("KeyframeTreeStore::set_value_impl():new_time=%s",keyframe.get_time().get_string().c_str());
391
392                         synfigapp::Action::Handle action(synfigapp::Action::create("keyframe_set"));
393
394                         if(!action)
395                                 return;
396
397                         action->set_param("canvas",canvas_interface()->get_canvas());
398                         action->set_param("canvas_interface",canvas_interface());
399                         action->set_param("keyframe",keyframe);
400
401                         canvas_interface()->get_instance()->perform_action(action);
402                 }
403                 else if(column==model.description.index())
404                 {
405                         Glib::Value<Glib::ustring> x;
406                         g_value_init(x.gobj(),model.description.type());
407                         g_value_copy(value.gobj(),x.gobj());
408                         synfig::Keyframe keyframe(*iter->iter);
409                         keyframe.set_description(x.get());
410
411                         synfigapp::Action::Handle action(synfigapp::Action::create("keyframe_set"));
412
413                         if(!action)
414                                 return;
415
416                         action->set_param("canvas",canvas_interface()->get_canvas());
417                         action->set_param("canvas_interface",canvas_interface());
418                         action->set_param("keyframe",keyframe);
419
420                         canvas_interface()->get_instance()->perform_action(action);
421                 }
422                 else if(column==model.keyframe.index())
423                 {
424                         g_warning("KeyframeTreeStore::set_value_impl: This column is read-only");
425                 }
426                 else
427                 {
428                         assert(0);
429                 }
430         }
431         catch(std::exception x)
432         {
433                 g_warning(x.what());
434         }
435 }
436
437 Gtk::TreeModelFlags
438 KeyframeTreeStore::get_flags_vfunc ()
439 {
440         return Gtk::TREE_MODEL_LIST_ONLY;
441 }
442
443 int
444 KeyframeTreeStore::get_n_columns_vfunc ()
445 {
446         return model.size();
447 }
448
449 GType
450 KeyframeTreeStore::get_column_type_vfunc (int index)
451 {
452         return model.types()[index];
453 }
454
455 bool
456 KeyframeTreeStore::iter_next_vfunc (const iterator& xiter, iterator& iter_next) const
457 {
458         if(!iterator_sane(xiter)) return false;
459
460         _keyframe_iterator *iter(static_cast<_keyframe_iterator*>(xiter.gobj()->user_data));
461
462         if(iter->iter==canvas_interface()->get_canvas()->keyframe_list().end())
463                 return false;
464
465         _keyframe_iterator *next(new _keyframe_iterator());
466         iter_next.gobj()->user_data=static_cast<gpointer>(next);
467         next->ref_count=1;
468         next->index=iter->index+1;
469         next->iter=iter->iter;
470         ++next->iter;
471
472         if(next->iter==canvas_interface()->get_canvas()->keyframe_list().end())
473                 return false;
474
475         iter_next.gobj()->stamp=stamp_;
476
477         return true;
478 }
479
480 /*
481 bool
482 KeyframeTreeStore::iter_next_vfunc (GtkTreeIter* gtk_iter)
483 {
484         if(!iterator_sane(gtk_iter)) return false;
485
486         _keyframe_iterator *iter(static_cast<_keyframe_iterator*>(gtk_iter->user_data));
487
488         // If we are already at the end, then we are very invalid
489         if(iter->iter==canvas_interface()->get_canvas()->keyframe_list().end())
490                 return false;
491
492         ++(iter->iter);
493
494         if(iter->iter==canvas_interface()->get_canvas()->keyframe_list().end())
495         {
496                 --(iter->iter);
497                 return false;
498         }
499         (iter->index)++;
500         return true;
501 }
502
503 bool
504 KeyframeTreeStore::iter_children_vfunc (GtkTreeIter* gtk_iter, const GtkTreeIter* parent)
505 {
506         dump_iterator(gtk_iter,"gtk_iter");
507         dump_iterator(parent,"parent");
508
509         if(!parent || !iterator_sane(parent))
510         {
511                 clear_iterator(gtk_iter);
512                 return false;
513         }
514
515         _keyframe_iterator *iter(new _keyframe_iterator());
516         iter->ref_count=1;
517         iter->index=0;
518         iter->iter=canvas_interface()->get_canvas()->keyframe_list().begin();
519
520         gtk_iter->user_data=static_cast<gpointer>(iter);
521         gtk_iter->stamp=stamp_;
522
523         return true;
524 }
525
526 bool
527 KeyframeTreeStore::iter_has_child_vfunc (const GtkTreeIter*parent)
528 {
529         dump_iterator(parent,"parent");
530
531         if(parent)
532                 return false;
533
534         return true;
535 }
536
537 int
538 KeyframeTreeStore::iter_n_children_vfunc (const GtkTreeIter* parent)
539 {
540         dump_iterator(parent,"parent");
541
542         if(parent)
543                 return 0;
544
545         return canvas_interface()->get_canvas()->keyframe_list().size();
546 }
547 */
548
549 int
550 KeyframeTreeStore::iter_n_root_children_vfunc () const
551 {
552         return canvas_interface()->get_canvas()->keyframe_list().size();
553 }
554
555 bool
556 KeyframeTreeStore::iter_nth_root_child_vfunc (int n, iterator& xiter)const
557 {
558         if(canvas_interface()->get_canvas()->keyframe_list().size()==0)
559         {
560                 return false;
561         }
562
563         if(n<0)
564         {
565                 g_warning("KeyframeTreeStore::iter_nth_root_child_vfunc: Out of range (negative index)");
566                 return false;
567         }
568         if(n && (unsigned)n>=canvas_interface()->get_canvas()->keyframe_list().size())
569         {
570                 g_warning("KeyframeTreeStore::iter_nth_child_vfunc: Out of range (large index)");
571                 return false;
572         }
573
574         _keyframe_iterator *iter(new _keyframe_iterator());
575         iter->ref_count=1;
576         iter->index=n;
577         iter->iter=canvas_interface()->get_canvas()->keyframe_list().begin();
578         while(n--)
579         {
580                 if(iter->iter==canvas_interface()->get_canvas()->keyframe_list().end())
581                 {
582                         g_warning("KeyframeTreeStore::iter_nth_child_vfunc: >>>BUG<<< in %s on line %d",__FILE__,__LINE__);
583                         delete iter;
584                         return false;
585                 }
586                 ++iter->iter;
587         }
588         xiter.gobj()->user_data=static_cast<gpointer>(iter);
589         xiter.gobj()->stamp=stamp_;
590         return true;
591 }
592
593 /*
594 bool
595 KeyframeTreeStore::iter_nth_child_vfunc (GtkTreeIter* gtk_iter, const GtkTreeIter* parent, int n)
596 {
597         dump_iterator(parent,"parent");
598
599         if(parent)
600         {
601                 g_warning("KeyframeTreeStore::iter_nth_child_vfunc: I am a list");
602                 clear_iterator(gtk_iter);
603                 return false;
604         }
605
606
607
608         _keyframe_iterator *iter(new _keyframe_iterator());
609         iter->ref_count=1;
610         iter->index=n;
611         iter->iter=canvas_interface()->get_canvas()->keyframe_list().begin();
612         while(n--)
613         {
614                 if(iter->iter==canvas_interface()->get_canvas()->keyframe_list().end())
615                 {
616                         g_warning("KeyframeTreeStore::iter_nth_child_vfunc: >>>BUG<<< in %s on line %d",__FILE__,__LINE__);
617                         delete iter;
618                         clear_iterator(gtk_iter);
619                         return false;
620                 }
621                 ++iter->iter;
622         }
623
624         gtk_iter->user_data=static_cast<gpointer>(iter);
625         gtk_iter->stamp=stamp_;
626         return true;
627 }
628
629 bool
630 KeyframeTreeStore::iter_parent_vfunc (GtkTreeIter* gtk_iter, const GtkTreeIter* child)
631 {
632         dump_iterator(child,"child");
633         iterator_sane(child);
634         clear_iterator(gtk_iter);
635         return false;
636 }
637 */
638
639 void
640 KeyframeTreeStore::ref_node_vfunc (iterator& xiter)const
641 {
642         GtkTreeIter* gtk_iter(xiter.gobj());
643         if(!gtk_iter || !iterator_sane(gtk_iter)) return;
644
645         _keyframe_iterator *iter(static_cast<_keyframe_iterator*>(gtk_iter->user_data));
646         iter->ref_count++;
647 }
648
649 void
650 KeyframeTreeStore::unref_node_vfunc (iterator& xiter)const
651 {
652         GtkTreeIter* gtk_iter(xiter.gobj());
653         if(!gtk_iter || !iterator_sane(gtk_iter)) return;
654
655         _keyframe_iterator *iter(static_cast<_keyframe_iterator*>(gtk_iter->user_data));
656         iter->ref_count--;
657         if(!iter->ref_count)
658         {
659                 delete iter;
660
661                 // Make this iterator invalid
662                 gtk_iter->stamp=0;
663         }
664 }
665
666 Gtk::TreeModel::Path
667 KeyframeTreeStore::get_path_vfunc (const TreeModel::iterator& gtk_iter)const
668 {
669         Gtk::TreeModel::Path path;
670
671         // If this is the root node, then return
672         // a root path
673         if(!iterator_sane(gtk_iter))
674                 return path;
675
676         _keyframe_iterator *iter(static_cast<_keyframe_iterator*>(gtk_iter->gobj()->user_data));
677
678         path.append_index(iter->index);
679
680         return path;
681 }
682
683 bool
684 KeyframeTreeStore::get_iter_vfunc (const Gtk::TreeModel::Path& path, iterator& iter)const
685 {
686         if(path.get_depth()>=1)
687                 return iter_nth_root_child_vfunc(path.front(),iter);
688
689         // Error case
690         g_warning("KeyframeTreeStore::get_iter_vfunc(): Bad path \"%s\"",path.to_string().c_str());
691         //clear_iterator(iter);
692         return false;
693 }
694
695 bool
696 KeyframeTreeStore::iter_is_valid (const iterator& iter) const
697 {
698         return iterator_sane(iter);
699 }
700
701 void
702 KeyframeTreeStore::get_value_vfunc (const Gtk::TreeModel::iterator& gtk_iter, int column, Glib::ValueBase& value)const
703 {
704         dump_iterator(gtk_iter,"gtk_iter");
705         if(!iterator_sane(gtk_iter))
706                 return;
707
708         _keyframe_iterator *iter(static_cast<_keyframe_iterator*>(gtk_iter->gobj()->user_data));
709
710         switch(column)
711         {
712         case 0:         // Time
713         {
714                 Glib::Value<synfig::Time> x;
715                 g_value_init(x.gobj(),x.value_type());
716                 x.set(iter->iter->get_time());
717                 g_value_init(value.gobj(),x.value_type());
718                 g_value_copy(x.gobj(),value.gobj());
719                 return;
720         }
721         case 3:         // Time Delta
722         {
723                 Glib::Value<synfig::Time> x;
724                 g_value_init(x.gobj(),x.value_type());
725
726                 synfig::Keyframe prev_keyframe(*iter->iter);
727                 synfig::Keyframe keyframe;
728                 {
729                         KeyframeList::iterator tmp(iter->iter);
730                         tmp++;
731                         if(tmp==get_canvas()->keyframe_list().end())
732                         {
733                                 x.set(Time(0));
734                                 g_value_init(value.gobj(),x.value_type());
735                                 g_value_copy(x.gobj(),value.gobj());
736                                 return;
737                         }
738                         keyframe=*tmp;
739                 }
740
741                 Time delta(0);
742                 try {
743                         delta=keyframe.get_time()-prev_keyframe.get_time();
744                 }catch(...) { }
745                 x.set(delta);
746                 g_value_init(value.gobj(),x.value_type());
747                 g_value_copy(x.gobj(),value.gobj());
748                 return;
749         }
750         case 1:         // Description
751         {
752                 g_value_init(value.gobj(),G_TYPE_STRING);
753                 g_value_set_string(value.gobj(),iter->iter->get_description().c_str());
754                 return;
755         }
756         case 2:         // Keyframe
757         {
758                 Glib::Value<synfig::Keyframe> x;
759                 g_value_init(x.gobj(),x.value_type());
760                 x.set(*iter->iter);
761                 g_value_init(value.gobj(),x.value_type());
762                 g_value_copy(x.gobj(),value.gobj());
763                 return;
764         }
765         default:
766                 break;
767         }
768 }
769
770 Gtk::TreeModel::Row
771 KeyframeTreeStore::find_row(const synfig::Keyframe &keyframe)
772 {
773         Gtk::TreeModel::Row row(*(children().begin()));
774         dump_iterator(row,"find_row,begin");
775         const GtkTreeIter *gtk_iter(row.gobj());
776         if(!iterator_sane(gtk_iter))
777                 throw std::runtime_error(_("Unable to find Keyframe in table"));
778
779         _keyframe_iterator *iter(static_cast<_keyframe_iterator*>(gtk_iter->user_data));
780
781         synfig::KeyframeList &keyframe_list(canvas_interface()->get_canvas()->keyframe_list());
782         if(keyframe_list.empty())
783                 throw std::runtime_error(_("There are no keyframes n this canvas"));
784
785         iter->index=0;
786
787         for(iter->iter=keyframe_list.begin();iter->iter!=keyframe_list.end() && *iter->iter!=keyframe;++iter->iter)
788         {
789                 iter->index++;
790         }
791         if(iter->iter==keyframe_list.end())
792                 throw std::runtime_error(_("Unable to find Keyframe in table"));
793         return row;
794 }
795
796 void
797 KeyframeTreeStore::add_keyframe(Keyframe keyframe)
798 {
799         try
800         {
801                 Gtk::TreeRow row(find_row(keyframe));
802                 dump_iterator(row.gobj(),"add_keyframe,row");
803                 Gtk::TreePath path(get_path(row));
804
805                 row_inserted(path,row);
806
807                 old_keyframe_list=get_canvas()->keyframe_list();
808                 //old_keyframe_list.add(keyframe);
809                 //old_keyframe_list.sort();
810         }
811         catch(std::exception x)
812         {
813                 g_warning(x.what());
814         }
815 }
816
817 void
818 KeyframeTreeStore::remove_keyframe(Keyframe keyframe)
819 {
820         try
821         {
822                 if(1)
823                 {
824                         Gtk::TreeRow row(find_row(keyframe));
825                         dump_iterator(row,"remove_keyframe,row");
826                         Gtk::TreePath path(get_path(row));
827                         row_deleted(path);
828
829                         old_keyframe_list.erase(keyframe);
830                 }
831                 else
832                 {
833                         g_warning("KeyframeTreeStore::remove_keyframe: Keyframe not in table");
834                 }
835         }
836         catch(std::exception x)
837         {
838                 DEBUGPOINT();
839                 g_warning(x.what());
840         }
841 }
842
843 void
844 KeyframeTreeStore::change_keyframe(Keyframe keyframe)
845 {
846         try
847         {
848                 Gtk::TreeRow row(find_row(keyframe));
849
850                 unsigned int new_index(get_index_from_model_iter(row));
851                 unsigned int old_index(0);
852                 synfig::KeyframeList::iterator iter;
853                 for(old_index=0,iter=old_keyframe_list.begin();iter!=old_keyframe_list.end() && (UniqueID)*iter!=(UniqueID)keyframe;++iter,old_index++);
854
855                 if(iter!=old_keyframe_list.end() && new_index!=old_index)
856                 {
857                         DEBUGPOINT();
858                         std::vector<int> new_order;
859                         for(unsigned int i=0;i<old_keyframe_list.size();i++)
860                         {
861                                 new_order.push_back(i);
862                         }
863                         if(new_order.size()>new_index)
864                         {
865                                 new_order.erase(new_order.begin()+new_index);
866                                 new_order.insert(new_order.begin()+old_index,new_index);
867
868                                 //new_order[old_index]=
869
870                                 rows_reordered (Path(), iterator(), &new_order[0]);
871                         }
872                         old_keyframe_list=get_canvas()->keyframe_list();
873
874                         row=find_row(keyframe);
875                 }
876
877                 dump_iterator(row,"change_keyframe,row");
878                 row_changed(get_path(row),row);
879         }
880         catch(std::exception x)
881         {
882                 DEBUGPOINT();
883                 g_warning(x.what());
884         }
885 }