Extract translatable strings from some more files
[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, 2008 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         //! \todo what is going on here?  why the need for this KeyframeTreeStore_Class at all?
202         // Glib::Object         (Glib::ConstructParams(keyframe_tree_store_class_.init(), (char*) 0, (char*) 0)),
203         canvas_interface_       (canvas_interface_)
204 {
205         reset_stamp();
206         //reset_path_table();
207
208         canvas_interface()->signal_keyframe_added().connect(sigc::mem_fun(*this,&studio::KeyframeTreeStore::add_keyframe));
209         canvas_interface()->signal_keyframe_removed().connect(sigc::mem_fun(*this,&studio::KeyframeTreeStore::remove_keyframe));
210         canvas_interface()->signal_keyframe_changed().connect(sigc::mem_fun(*this,&studio::KeyframeTreeStore::change_keyframe));
211 }
212
213 KeyframeTreeStore::~KeyframeTreeStore()
214 {
215         if (getenv("SYNFIG_DEBUG_DESTRUCTORS"))
216                 synfig::info("KeyframeTreeStore::~KeyframeTreeStore(): Deleted");
217 }
218
219 Glib::RefPtr<KeyframeTreeStore>
220 KeyframeTreeStore::create(etl::loose_handle<synfigapp::CanvasInterface> canvas_interface_)
221 {
222         KeyframeTreeStore *store(new KeyframeTreeStore(canvas_interface_));
223         Glib::RefPtr<KeyframeTreeStore> ret(store);
224         assert(ret);
225         return ret;
226 }
227
228 void
229 KeyframeTreeStore::reset_stamp()
230 {
231         stamp_=time(0)+reinterpret_cast<long>(this);
232 }
233
234 /*
235 void
236 KeyframeTreeStore::reset_path_table()
237 {
238         Gtk::TreeModel::Children::iterator iter;
239         const Gtk::TreeModel::Children children(children());
240         path_table_.clear();
241         for(iter = children.begin(); iter != children.end(); ++iter)
242         {
243                 Gtk::TreeModel::Row row(*iter);
244                 path_table_[(Keyframe)row[model.keyframe]]=TreeRowReferenceHack(Glib::RefPtr<KeyframeTreeStore>(this),Gtk::TreePath(row));
245         }
246 }
247 */
248
249
250 inline bool
251 KeyframeTreeStore::iterator_sane(const GtkTreeIter* iter)const
252 {
253         if(iter && iter->stamp==stamp_)
254                 return true;
255         g_warning("KeyframeTreeStore::iterator_sane(): Bad iterator stamp");
256         return false;
257 }
258
259 inline bool
260 KeyframeTreeStore::iterator_sane(const Gtk::TreeModel::iterator& iter)const
261 {
262         return iterator_sane(iter->gobj());
263 }
264
265 inline void
266 KeyframeTreeStore::dump_iterator(const GtkTreeIter* /*gtk_iter*/, const Glib::ustring &/*name*/)const
267 {
268 #if 0
269         if(!gtk_iter)
270         {
271                 g_warning("KeyframeTreeStore::dump_iterator: \"%s\" is NULL (Root?)",name.c_str());
272                 return;
273         }
274
275         _keyframe_iterator *iter(static_cast<_keyframe_iterator*>(gtk_iter->user_data));
276
277         if(gtk_iter->stamp!=stamp_ || !iter)
278         {
279                 g_warning("KeyframeTreeStore::dump_iterator: \"%s\" is INVALID",name.c_str());
280                 return;
281         }
282
283         if((unsigned)iter->index>=canvas_interface()->get_canvas()->keyframe_list().size())
284                 g_warning("KeyframeTreeStore::dump_iterator: \"%s\"(%p) has bad index(index:%d)",name.c_str(),gtk_iter,iter->index);
285
286         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());
287 #endif
288 }
289
290 inline void
291 KeyframeTreeStore::dump_iterator(const Gtk::TreeModel::iterator& iter, const Glib::ustring &name)const
292 {
293         dump_iterator(iter->gobj(),name);
294 }
295
296 int
297 KeyframeTreeStore::time_sorter(const Gtk::TreeModel::iterator &rhs,const Gtk::TreeModel::iterator &lhs)
298 {
299         const Model model;
300
301         _keyframe_iterator *rhs_iter(static_cast<_keyframe_iterator*>(rhs->gobj()->user_data));
302         _keyframe_iterator *lhs_iter(static_cast<_keyframe_iterator*>(lhs->gobj()->user_data));
303
304         Time diff(rhs_iter->iter->get_time()-lhs_iter->iter->get_time());
305         if(diff<0)
306                 return -1;
307         if(diff>0)
308                 return 1;
309         return 0;
310 }
311
312 int
313 KeyframeTreeStore::description_sorter(const Gtk::TreeModel::iterator &rhs,const Gtk::TreeModel::iterator &lhs)
314 {
315         const Model model;
316
317         _keyframe_iterator *rhs_iter(static_cast<_keyframe_iterator*>(rhs->gobj()->user_data));
318         _keyframe_iterator *lhs_iter(static_cast<_keyframe_iterator*>(lhs->gobj()->user_data));
319
320         int comp = rhs_iter->iter->get_description().compare(lhs_iter->iter->get_description());
321         if (comp > 0) return 1;
322         if (comp < 0) return -1;
323         return 0;
324 }
325
326 void
327 KeyframeTreeStore::set_value_impl(const Gtk::TreeModel::iterator& row, int column, const Glib::ValueBase& value)
328 {
329         if(!iterator_sane(row))
330                 return;
331
332         if(column>=get_n_columns_vfunc())
333         {
334                 g_warning("KeyframeTreeStore::set_value_impl: Bad column (%d)",column);
335                 return;
336         }
337
338         if(!g_value_type_compatible(G_VALUE_TYPE(value.gobj()),get_column_type_vfunc(column)))
339         {
340                 g_warning("KeyframeTreeStore::set_value_impl: Bad value type");
341                 return;
342         }
343
344         _keyframe_iterator *iter(static_cast<_keyframe_iterator*>(row.gobj()->user_data));
345
346         try
347         {
348                 if(column==model.time_delta.index())
349                 {
350                         Glib::Value<synfig::Time> x;
351                         g_value_init(x.gobj(),model.time.type());
352                         g_value_copy(value.gobj(),x.gobj());
353
354                         Time new_delta(x.get());
355                         if(new_delta<=Time::zero()+Time::epsilon())
356                         {
357                                 // Bad value
358                                 return;
359                         }
360
361                         Time old_delta((*row)[model.time_delta]);
362                         if(old_delta<=Time::zero()+Time::epsilon())
363                         {
364                                 // Bad old delta
365                                 return;
366                         }
367                         // row(row) on the next line is bad - don't use it, because it leaves 'row' uninitialized
368                         //Gtk::TreeModel::iterator row(row);
369                         //row++;
370                         //if(!row)return;
371
372                         Time change_delta(new_delta-old_delta);
373
374                         if(change_delta<=Time::zero()+Time::epsilon() &&change_delta>=Time::zero()-Time::epsilon())
375                         {
376                                 // Not an error, just no change
377                                 return;
378                         }
379
380                         {
381                                 Keyframe keyframe((*row)[model.keyframe]);
382                                 synfigapp::Action::Handle action(synfigapp::Action::create("keyframe_set_delta"));
383
384                                 if(!action)return;
385
386                                 action->set_param("canvas",canvas_interface()->get_canvas());
387                                 action->set_param("canvas_interface",canvas_interface());
388                                 action->set_param("keyframe",keyframe);
389                                 action->set_param("delta",change_delta);
390
391                                 canvas_interface()->get_instance()->perform_action(action);
392                         }
393
394                         return;
395                 }
396                 else
397                 if(column==model.time.index())
398                 {
399                         OneMoment one_moment;
400
401                         Glib::Value<synfig::Time> x;
402                         g_value_init(x.gobj(),model.time.type());
403                         g_value_copy(value.gobj(),x.gobj());
404                         synfig::Keyframe keyframe(*iter->iter);
405
406                         synfig::info("KeyframeTreeStore::set_value_impl():old_time=%s",keyframe.get_time().get_string().c_str());
407                         keyframe.set_time(x.get());
408                         synfig::info("KeyframeTreeStore::set_value_impl():new_time=%s",keyframe.get_time().get_string().c_str());
409
410                         synfigapp::Action::Handle action(synfigapp::Action::create("keyframe_set"));
411
412                         if(!action)
413                                 return;
414
415                         action->set_param("canvas",canvas_interface()->get_canvas());
416                         action->set_param("canvas_interface",canvas_interface());
417                         action->set_param("keyframe",keyframe);
418
419                         canvas_interface()->get_instance()->perform_action(action);
420                 }
421                 else if(column==model.description.index())
422                 {
423                         Glib::Value<Glib::ustring> x;
424                         g_value_init(x.gobj(),model.description.type());
425                         g_value_copy(value.gobj(),x.gobj());
426                         synfig::Keyframe keyframe(*iter->iter);
427                         keyframe.set_description(x.get());
428
429                         synfigapp::Action::Handle action(synfigapp::Action::create("keyframe_set"));
430
431                         if(!action)
432                                 return;
433
434                         action->set_param("canvas",canvas_interface()->get_canvas());
435                         action->set_param("canvas_interface",canvas_interface());
436                         action->set_param("keyframe",keyframe);
437
438                         canvas_interface()->get_instance()->perform_action(action);
439                 }
440                 else if(column==model.keyframe.index())
441                 {
442                         g_warning("KeyframeTreeStore::set_value_impl: This column is read-only");
443                 }
444                 else
445                 {
446                         assert(0);
447                 }
448         }
449         catch(std::exception x)
450         {
451                 g_warning(x.what());
452         }
453 }
454
455 Gtk::TreeModelFlags
456 KeyframeTreeStore::get_flags_vfunc ()
457 {
458         return Gtk::TREE_MODEL_LIST_ONLY;
459 }
460
461 int
462 KeyframeTreeStore::get_n_columns_vfunc ()
463 {
464         return model.size();
465 }
466
467 GType
468 KeyframeTreeStore::get_column_type_vfunc (int index)
469 {
470         return model.types()[index];
471 }
472
473 bool
474 KeyframeTreeStore::iter_next_vfunc (const iterator& xiter, iterator& iter_next) const
475 {
476         if(!iterator_sane(xiter)) return false;
477
478         _keyframe_iterator *iter(static_cast<_keyframe_iterator*>(xiter.gobj()->user_data));
479
480         if(iter->iter==canvas_interface()->get_canvas()->keyframe_list().end())
481                 return false;
482
483         _keyframe_iterator *next(new _keyframe_iterator());
484         iter_next.gobj()->user_data=static_cast<gpointer>(next);
485         next->ref_count=1;
486         next->index=iter->index+1;
487         next->iter=iter->iter;
488         ++next->iter;
489
490         if(next->iter==canvas_interface()->get_canvas()->keyframe_list().end())
491                 return false;
492
493         iter_next.gobj()->stamp=stamp_;
494
495         return true;
496 }
497
498 /*
499 bool
500 KeyframeTreeStore::iter_next_vfunc (GtkTreeIter* gtk_iter)
501 {
502         if(!iterator_sane(gtk_iter)) return false;
503
504         _keyframe_iterator *iter(static_cast<_keyframe_iterator*>(gtk_iter->user_data));
505
506         // If we are already at the end, then we are very invalid
507         if(iter->iter==canvas_interface()->get_canvas()->keyframe_list().end())
508                 return false;
509
510         ++(iter->iter);
511
512         if(iter->iter==canvas_interface()->get_canvas()->keyframe_list().end())
513         {
514                 --(iter->iter);
515                 return false;
516         }
517         (iter->index)++;
518         return true;
519 }
520
521 bool
522 KeyframeTreeStore::iter_children_vfunc (GtkTreeIter* gtk_iter, const GtkTreeIter* parent)
523 {
524         dump_iterator(gtk_iter,"gtk_iter");
525         dump_iterator(parent,"parent");
526
527         if(!parent || !iterator_sane(parent))
528         {
529                 clear_iterator(gtk_iter);
530                 return false;
531         }
532
533         _keyframe_iterator *iter(new _keyframe_iterator());
534         iter->ref_count=1;
535         iter->index=0;
536         iter->iter=canvas_interface()->get_canvas()->keyframe_list().begin();
537
538         gtk_iter->user_data=static_cast<gpointer>(iter);
539         gtk_iter->stamp=stamp_;
540
541         return true;
542 }
543
544 bool
545 KeyframeTreeStore::iter_has_child_vfunc (const GtkTreeIter*parent)
546 {
547         dump_iterator(parent,"parent");
548
549         if(parent)
550                 return false;
551
552         return true;
553 }
554
555 int
556 KeyframeTreeStore::iter_n_children_vfunc (const GtkTreeIter* parent)
557 {
558         dump_iterator(parent,"parent");
559
560         if(parent)
561                 return 0;
562
563         return canvas_interface()->get_canvas()->keyframe_list().size();
564 }
565 */
566
567 int
568 KeyframeTreeStore::iter_n_root_children_vfunc () const
569 {
570         return canvas_interface()->get_canvas()->keyframe_list().size();
571 }
572
573 bool
574 KeyframeTreeStore::iter_nth_root_child_vfunc (int n, iterator& xiter)const
575 {
576         if(canvas_interface()->get_canvas()->keyframe_list().size()==0)
577         {
578                 return false;
579         }
580
581         if(n<0)
582         {
583                 g_warning("KeyframeTreeStore::iter_nth_root_child_vfunc: Out of range (negative index)");
584                 return false;
585         }
586         if(n && (unsigned)n>=canvas_interface()->get_canvas()->keyframe_list().size())
587         {
588                 g_warning("KeyframeTreeStore::iter_nth_child_vfunc: Out of range (large index)");
589                 return false;
590         }
591
592         _keyframe_iterator *iter(new _keyframe_iterator());
593         iter->ref_count=1;
594         iter->index=n;
595         iter->iter=canvas_interface()->get_canvas()->keyframe_list().begin();
596         while(n--)
597         {
598                 if(iter->iter==canvas_interface()->get_canvas()->keyframe_list().end())
599                 {
600                         g_warning("KeyframeTreeStore::iter_nth_child_vfunc: >>>BUG<<< in %s on line %d",__FILE__,__LINE__);
601                         delete iter;
602                         return false;
603                 }
604                 ++iter->iter;
605         }
606         xiter.gobj()->user_data=static_cast<gpointer>(iter);
607         xiter.gobj()->stamp=stamp_;
608         return true;
609 }
610
611 /*
612 bool
613 KeyframeTreeStore::iter_nth_child_vfunc (GtkTreeIter* gtk_iter, const GtkTreeIter* parent, int n)
614 {
615         dump_iterator(parent,"parent");
616
617         if(parent)
618         {
619                 g_warning("KeyframeTreeStore::iter_nth_child_vfunc: I am a list");
620                 clear_iterator(gtk_iter);
621                 return false;
622         }
623
624
625
626         _keyframe_iterator *iter(new _keyframe_iterator());
627         iter->ref_count=1;
628         iter->index=n;
629         iter->iter=canvas_interface()->get_canvas()->keyframe_list().begin();
630         while(n--)
631         {
632                 if(iter->iter==canvas_interface()->get_canvas()->keyframe_list().end())
633                 {
634                         g_warning("KeyframeTreeStore::iter_nth_child_vfunc: >>>BUG<<< in %s on line %d",__FILE__,__LINE__);
635                         delete iter;
636                         clear_iterator(gtk_iter);
637                         return false;
638                 }
639                 ++iter->iter;
640         }
641
642         gtk_iter->user_data=static_cast<gpointer>(iter);
643         gtk_iter->stamp=stamp_;
644         return true;
645 }
646
647 bool
648 KeyframeTreeStore::iter_parent_vfunc (GtkTreeIter* gtk_iter, const GtkTreeIter* child)
649 {
650         dump_iterator(child,"child");
651         iterator_sane(child);
652         clear_iterator(gtk_iter);
653         return false;
654 }
655 */
656
657 void
658 KeyframeTreeStore::ref_node_vfunc (iterator& xiter)const
659 {
660         GtkTreeIter* gtk_iter(xiter.gobj());
661         if(!gtk_iter || !iterator_sane(gtk_iter)) return;
662
663         _keyframe_iterator *iter(static_cast<_keyframe_iterator*>(gtk_iter->user_data));
664         iter->ref_count++;
665 }
666
667 void
668 KeyframeTreeStore::unref_node_vfunc (iterator& xiter)const
669 {
670         GtkTreeIter* gtk_iter(xiter.gobj());
671         if(!gtk_iter || !iterator_sane(gtk_iter)) return;
672
673         _keyframe_iterator *iter(static_cast<_keyframe_iterator*>(gtk_iter->user_data));
674         iter->ref_count--;
675         if(!iter->ref_count)
676         {
677                 delete iter;
678
679                 // Make this iterator invalid
680                 gtk_iter->stamp=0;
681         }
682 }
683
684 Gtk::TreeModel::Path
685 KeyframeTreeStore::get_path_vfunc (const iterator& gtk_iter)const
686 {
687         Gtk::TreeModel::Path path;
688
689         // If this is the root node, then return
690         // a root path
691         if(!iterator_sane(gtk_iter))
692                 return path;
693
694         _keyframe_iterator *iter(static_cast<_keyframe_iterator*>(gtk_iter->gobj()->user_data));
695
696         path.append_index(iter->index);
697
698         return path;
699 }
700
701 bool
702 KeyframeTreeStore::get_iter_vfunc (const Gtk::TreeModel::Path& path, iterator& iter)const
703 {
704         if(path.get_depth()>=1)
705                 return iter_nth_root_child_vfunc(path.front(),iter);
706
707         // Error case
708         g_warning("KeyframeTreeStore::get_iter_vfunc(): Bad path \"%s\"",path.to_string().c_str());
709         //clear_iterator(iter);
710         return false;
711 }
712
713 bool
714 KeyframeTreeStore::iter_is_valid (const iterator& iter) const
715 {
716         return iterator_sane(iter);
717 }
718
719 void
720 KeyframeTreeStore::get_value_vfunc (const Gtk::TreeModel::iterator& gtk_iter, int column, Glib::ValueBase& value)const
721 {
722         dump_iterator(gtk_iter,"gtk_iter");
723         if(!iterator_sane(gtk_iter))
724                 return;
725
726         _keyframe_iterator *iter(static_cast<_keyframe_iterator*>(gtk_iter->gobj()->user_data));
727
728         switch(column)
729         {
730         case 0:         // Time
731         {
732                 Glib::Value<synfig::Time> x;
733                 g_value_init(x.gobj(),x.value_type());
734                 x.set(iter->iter->get_time());
735                 g_value_init(value.gobj(),x.value_type());
736                 g_value_copy(x.gobj(),value.gobj());
737                 return;
738         }
739         case 3:         // Time Delta
740         {
741                 Glib::Value<synfig::Time> x;
742                 g_value_init(x.gobj(),x.value_type());
743
744                 synfig::Keyframe prev_keyframe(*iter->iter);
745                 synfig::Keyframe keyframe;
746                 {
747                         KeyframeList::iterator tmp(iter->iter);
748                         tmp++;
749                         if(tmp==get_canvas()->keyframe_list().end())
750                         {
751                                 x.set(Time(0));
752                                 g_value_init(value.gobj(),x.value_type());
753                                 g_value_copy(x.gobj(),value.gobj());
754                                 return;
755                         }
756                         keyframe=*tmp;
757                 }
758
759                 Time delta(0);
760                 try {
761                         delta=keyframe.get_time()-prev_keyframe.get_time();
762                 }catch(...) { }
763                 x.set(delta);
764                 g_value_init(value.gobj(),x.value_type());
765                 g_value_copy(x.gobj(),value.gobj());
766                 return;
767         }
768         case 1:         // Description
769         {
770                 g_value_init(value.gobj(),G_TYPE_STRING);
771                 g_value_set_string(value.gobj(),iter->iter->get_description().c_str());
772                 return;
773         }
774         case 2:         // Keyframe
775         {
776                 Glib::Value<synfig::Keyframe> x;
777                 g_value_init(x.gobj(),x.value_type());
778                 x.set(*iter->iter);
779                 g_value_init(value.gobj(),x.value_type());
780                 g_value_copy(x.gobj(),value.gobj());
781                 return;
782         }
783         default:
784                 break;
785         }
786 }
787
788 Gtk::TreeModel::Row
789 KeyframeTreeStore::find_row(const synfig::Keyframe &keyframe)
790 {
791         Gtk::TreeModel::Row row(*(children().begin()));
792         dump_iterator(row,"find_row,begin");
793         const GtkTreeIter *gtk_iter(row.gobj());
794         if(!iterator_sane(gtk_iter))
795                 throw std::runtime_error(_("Unable to find Keyframe in table"));
796
797         _keyframe_iterator *iter(static_cast<_keyframe_iterator*>(gtk_iter->user_data));
798
799         synfig::KeyframeList &keyframe_list(canvas_interface()->get_canvas()->keyframe_list());
800         if(keyframe_list.empty())
801                 throw std::runtime_error(_("There are no keyframes n this canvas"));
802
803         iter->index=0;
804
805         for(iter->iter=keyframe_list.begin();iter->iter!=keyframe_list.end() && *iter->iter!=keyframe;++iter->iter)
806         {
807                 iter->index++;
808         }
809         if(iter->iter==keyframe_list.end())
810                 throw std::runtime_error(_("Unable to find Keyframe in table"));
811         return row;
812 }
813
814 void
815 KeyframeTreeStore::add_keyframe(synfig::Keyframe keyframe)
816 {
817         try
818         {
819                 Gtk::TreeRow row(find_row(keyframe));
820                 dump_iterator(row.gobj(),"add_keyframe,row");
821                 Gtk::TreePath path(get_path(row));
822
823                 row_inserted(path,row);
824
825                 old_keyframe_list=get_canvas()->keyframe_list();
826                 //old_keyframe_list.add(keyframe);
827                 //old_keyframe_list.sort();
828         }
829         catch(std::exception x)
830         {
831                 g_warning(x.what());
832         }
833 }
834
835 void
836 KeyframeTreeStore::remove_keyframe(synfig::Keyframe keyframe)
837 {
838         try
839         {
840                 if(1)
841                 {
842                         Gtk::TreeRow row(find_row(keyframe));
843                         dump_iterator(row,"remove_keyframe,row");
844                         Gtk::TreePath path(get_path(row));
845                         row_deleted(path);
846
847                         old_keyframe_list.erase(keyframe);
848                 }
849                 else
850                 {
851                         g_warning("KeyframeTreeStore::remove_keyframe: Keyframe not in table");
852                 }
853         }
854         catch(std::exception x)
855         {
856                 g_warning(x.what());
857         }
858 }
859
860 void
861 KeyframeTreeStore::change_keyframe(synfig::Keyframe keyframe)
862 {
863         try
864         {
865                 Gtk::TreeRow row(find_row(keyframe));
866
867                 unsigned int new_index(get_index_from_model_iter(row));
868                 unsigned int old_index(0);
869                 synfig::KeyframeList::iterator iter;
870                 for(old_index=0,iter=old_keyframe_list.begin();iter!=old_keyframe_list.end() && (UniqueID)*iter!=(UniqueID)keyframe;++iter,old_index++)
871                         ;
872
873                 if(iter!=old_keyframe_list.end() && new_index!=old_index)
874                 {
875                         std::vector<int> new_order;
876                         for(unsigned int i=0;i<old_keyframe_list.size();i++)
877                         {
878                                 new_order.push_back(i);
879                         }
880                         if(new_order.size()>new_index)
881                         {
882                                 new_order.erase(new_order.begin()+new_index);
883                                 new_order.insert(new_order.begin()+old_index,new_index);
884
885                                 //new_order[old_index]=
886
887                                 rows_reordered (Path(), iterator(), &new_order[0]);
888                         }
889                         old_keyframe_list=get_canvas()->keyframe_list();
890
891                         row=find_row(keyframe);
892                 }
893
894                 dump_iterator(row,"change_keyframe,row");
895                 row_changed(get_path(row),row);
896         }
897         catch(std::exception x)
898         {
899                 g_warning(x.what());
900         }
901 }