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