+/* === S Y N F I G ========================================================= */
+/*! \file keyframetreestore.cpp
+** \brief Template File
+**
+** $Id$
+**
+** \legal
+** Copyright (c) 2002-2005 Robert B. Quattlebaum Jr., Adrian Bentley
+** Copyright (c) 2007, 2008 Chris Moore
+**
+** This package is free software; you can redistribute it and/or
+** modify it under the terms of the GNU General Public License as
+** published by the Free Software Foundation; either version 2 of
+** the License, or (at your option) any later version.
+**
+** This package is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+** General Public License for more details.
+** \endlegal
+*/
+/* ========================================================================= */
+
+/* === H E A D E R S ======================================================= */
+
+#ifdef USING_PCH
+# include "pch.h"
+#else
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include "keyframetreestore.h"
+#include <synfig/valuenode.h>
+#include "iconcontroller.h"
+#include <synfig/valuenode_timedswap.h>
+#include <gtkmm/button.h>
+#include <gtkmm/treerowreference.h>
+#include <synfig/canvas.h>
+#include <synfig/keyframe.h>
+#include <time.h>
+#include <cstdlib>
+#include <ETL/smart_ptr>
+#include <synfigapp/action.h>
+#include <synfigapp/instance.h>
+#include "onemoment.h"
+#include <synfig/exception.h>
+
+#include "general.h"
+
+#endif
+
+/* === U S I N G =========================================================== */
+
+using namespace std;
+using namespace etl;
+using namespace synfig;
+using namespace studio;
+
+/* === M A C R O S ========================================================= */
+
+/* === G L O B A L S ======================================================= */
+
+// KeyframeTreeStore_Class KeyframeTreeStore::keyframe_tree_store_class_;
+
+/* === C L A S S E S & S T R U C T S ======================================= */
+
+struct _keyframe_iterator
+{
+ synfig::KeyframeList::iterator iter;
+ int ref_count;
+ int index;
+};
+
+/*
+Gtk::TreeModel::iterator keyframe_iter_2_model_iter(synfig::KeyframeList::iterator iter,int index)
+{
+ Gtk::TreeModel::iterator ret;
+
+ _keyframe_iterator*& data(static_cast<_keyframe_iterator*&>(ret->gobj()->user_data));
+ data=new _keyframe_iterator();
+ data->ref_count=1;
+ data->iter=iter;
+ data->index=index;
+
+ return ret;
+}
+*/
+
+synfig::KeyframeList::iterator model_iter_2_keyframe_iter(Gtk::TreeModel::iterator iter)
+{
+ _keyframe_iterator* data(static_cast<_keyframe_iterator*>(iter->gobj()->user_data));
+ if(!data)
+ throw std::runtime_error("bad data");
+ return data->iter;
+}
+
+int get_index_from_model_iter(Gtk::TreeModel::iterator iter)
+{
+ _keyframe_iterator* data(static_cast<_keyframe_iterator*>(iter->gobj()->user_data));
+ if(!data)
+ throw std::runtime_error("bad data");
+ return data->index;
+}
+
+
+/*
+#ifndef TreeRowReferenceHack
+class TreeRowReferenceHack
+{
+ GtkTreeRowReference *gobject_;
+public:
+ TreeRowReferenceHack():
+ gobject_(0)
+ {
+ }
+
+ TreeRowReferenceHack(const Glib::RefPtr<Gtk::TreeModel>& model, const Gtk::TreeModel::Path& path):
+ gobject_ ( gtk_tree_row_reference_new(model->gobj(), const_cast<GtkTreePath*>(path.gobj())) )
+ {
+ }
+
+ TreeRowReferenceHack(const TreeRowReferenceHack &x):
+ gobject_ ( x.gobject_?gtk_tree_row_reference_copy(x.gobject_):0 )
+ {
+
+ }
+
+ void swap(TreeRowReferenceHack & other)
+ {
+ GtkTreeRowReference *const temp = gobject_;
+ gobject_ = other.gobject_;
+ other.gobject_ = temp;
+ }
+
+ const TreeRowReferenceHack &
+ operator=(const TreeRowReferenceHack &rhs)
+ {
+ TreeRowReferenceHack temp (rhs);
+ swap(temp);
+ return *this;
+ }
+
+ ~TreeRowReferenceHack()
+ {
+ if(gobject_)
+ gtk_tree_row_reference_free(gobject_);
+ }
+
+ Gtk::TreeModel::Path get_path() { return Gtk::TreeModel::Path(gtk_tree_row_reference_get_path(gobject_),false); }
+ GtkTreeRowReference *gobj() { return gobject_; }
+};
+#endif
+*/
+
+/* === P R O C E D U R E S ================================================= */
+
+void clear_iterator(GtkTreeIter* iter)
+{
+ iter->stamp=0;
+ iter->user_data=iter->user_data2=iter->user_data3=0;
+}
+
+/* === M E T H O D S ======================================================= */
+
+const Glib::Class&
+KeyframeTreeStore_Class::init()
+{
+ if(!gtype_)
+ {
+ class_init_func_ = &KeyframeTreeStore_Class::class_init_function;
+
+ const GTypeInfo derived_info =
+ {
+ sizeof(GObjectClass),
+ NULL,
+ NULL,
+ class_init_func_,
+ NULL,
+ NULL,
+ sizeof(GObject),
+ 0,
+ 0,
+ NULL
+ };
+
+ gtype_ = g_type_register_static(G_TYPE_OBJECT, "KeyframeTreeStore", &derived_info, GTypeFlags(0));
+ Gtk::TreeModel::add_interface(get_type());
+ }
+ return *this;
+}
+
+void
+KeyframeTreeStore_Class::class_init_function(gpointer /*g_class*/, gpointer /*class_data*/)
+{
+ // ???
+}
+
+KeyframeTreeStore::KeyframeTreeStore(etl::loose_handle<synfigapp::CanvasInterface> canvas_interface_):
+ Glib::ObjectBase ("KeyframeTreeStore"),
+ //! \todo what is going on here? why the need for this KeyframeTreeStore_Class at all?
+ // Glib::Object (Glib::ConstructParams(keyframe_tree_store_class_.init(), (char*) 0, (char*) 0)),
+ canvas_interface_ (canvas_interface_)
+{
+ reset_stamp();
+ //reset_path_table();
+
+ canvas_interface()->signal_keyframe_added().connect(sigc::mem_fun(*this,&studio::KeyframeTreeStore::add_keyframe));
+ canvas_interface()->signal_keyframe_removed().connect(sigc::mem_fun(*this,&studio::KeyframeTreeStore::remove_keyframe));
+ canvas_interface()->signal_keyframe_changed().connect(sigc::mem_fun(*this,&studio::KeyframeTreeStore::change_keyframe));
+}
+
+KeyframeTreeStore::~KeyframeTreeStore()
+{
+ if (getenv("SYNFIG_DEBUG_DESTRUCTORS"))
+ synfig::info("KeyframeTreeStore::~KeyframeTreeStore(): Deleted");
+}
+
+Glib::RefPtr<KeyframeTreeStore>
+KeyframeTreeStore::create(etl::loose_handle<synfigapp::CanvasInterface> canvas_interface_)
+{
+ KeyframeTreeStore *store(new KeyframeTreeStore(canvas_interface_));
+ Glib::RefPtr<KeyframeTreeStore> ret(store);
+ assert(ret);
+ return ret;
+}
+
+void
+KeyframeTreeStore::reset_stamp()
+{
+ stamp_=time(0)+reinterpret_cast<long>(this);
+}
+
+/*
+void
+KeyframeTreeStore::reset_path_table()
+{
+ Gtk::TreeModel::Children::iterator iter;
+ const Gtk::TreeModel::Children children(children());
+ path_table_.clear();
+ for(iter = children.begin(); iter != children.end(); ++iter)
+ {
+ Gtk::TreeModel::Row row(*iter);
+ path_table_[(Keyframe)row[model.keyframe]]=TreeRowReferenceHack(Glib::RefPtr<KeyframeTreeStore>(this),Gtk::TreePath(row));
+ }
+}
+*/
+
+
+inline bool
+KeyframeTreeStore::iterator_sane(const GtkTreeIter* iter)const
+{
+ if(iter && iter->stamp==stamp_)
+ return true;
+ g_warning("KeyframeTreeStore::iterator_sane(): Bad iterator stamp");
+ return false;
+}
+
+inline bool
+KeyframeTreeStore::iterator_sane(const Gtk::TreeModel::iterator& iter)const
+{
+ return iterator_sane(iter->gobj());
+}
+
+inline void
+KeyframeTreeStore::dump_iterator(const GtkTreeIter* /*gtk_iter*/, const Glib::ustring &/*name*/)const
+{
+#if 0
+ if(!gtk_iter)
+ {
+ g_warning("KeyframeTreeStore::dump_iterator: \"%s\" is NULL (Root?)",name.c_str());
+ return;
+ }
+
+ _keyframe_iterator *iter(static_cast<_keyframe_iterator*>(gtk_iter->user_data));
+
+ if(gtk_iter->stamp!=stamp_ || !iter)
+ {
+ g_warning("KeyframeTreeStore::dump_iterator: \"%s\" is INVALID",name.c_str());
+ return;
+ }
+
+ if((unsigned)iter->index>=canvas_interface()->get_canvas()->keyframe_list().size())
+ g_warning("KeyframeTreeStore::dump_iterator: \"%s\"(%p) has bad index(index:%d)",name.c_str(),gtk_iter,iter->index);
+
+ 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());
+#endif
+}
+
+inline void
+KeyframeTreeStore::dump_iterator(const Gtk::TreeModel::iterator& iter, const Glib::ustring &name)const
+{
+ dump_iterator(iter->gobj(),name);
+}
+
+int
+KeyframeTreeStore::time_sorter(const Gtk::TreeModel::iterator &rhs,const Gtk::TreeModel::iterator &lhs)
+{
+ const Model model;
+
+ _keyframe_iterator *rhs_iter(static_cast<_keyframe_iterator*>(rhs->gobj()->user_data));
+ _keyframe_iterator *lhs_iter(static_cast<_keyframe_iterator*>(lhs->gobj()->user_data));
+
+ Time diff(rhs_iter->iter->get_time()-lhs_iter->iter->get_time());
+ if(diff<0)
+ return -1;
+ if(diff>0)
+ return 1;
+ return 0;
+}
+
+int
+KeyframeTreeStore::description_sorter(const Gtk::TreeModel::iterator &rhs,const Gtk::TreeModel::iterator &lhs)
+{
+ const Model model;
+
+ _keyframe_iterator *rhs_iter(static_cast<_keyframe_iterator*>(rhs->gobj()->user_data));
+ _keyframe_iterator *lhs_iter(static_cast<_keyframe_iterator*>(lhs->gobj()->user_data));
+
+ int comp = rhs_iter->iter->get_description().compare(lhs_iter->iter->get_description());
+ if (comp > 0) return 1;
+ if (comp < 0) return -1;
+ return 0;
+}
+
+void
+KeyframeTreeStore::set_value_impl(const Gtk::TreeModel::iterator& row, int column, const Glib::ValueBase& value)
+{
+ if(!iterator_sane(row))
+ return;
+
+ if(column>=get_n_columns_vfunc())
+ {
+ g_warning("KeyframeTreeStore::set_value_impl: Bad column (%d)",column);
+ return;
+ }
+
+ if(!g_value_type_compatible(G_VALUE_TYPE(value.gobj()),get_column_type_vfunc(column)))
+ {
+ g_warning("KeyframeTreeStore::set_value_impl: Bad value type");
+ return;
+ }
+
+ _keyframe_iterator *iter(static_cast<_keyframe_iterator*>(row.gobj()->user_data));
+
+ try
+ {
+ if(column==model.time_delta.index())
+ {
+ Glib::Value<synfig::Time> x;
+ g_value_init(x.gobj(),model.time.type());
+ g_value_copy(value.gobj(),x.gobj());
+
+ Time new_delta(x.get());
+ if(new_delta<=Time::zero()+Time::epsilon())
+ {
+ // Bad value
+ return;
+ }
+
+ Time old_delta((*row)[model.time_delta]);
+ if(old_delta<=Time::zero()+Time::epsilon())
+ {
+ // Bad old delta
+ return;
+ }
+ // row(row) on the next line is bad - don't use it, because it leaves 'row' uninitialized
+ //Gtk::TreeModel::iterator row(row);
+ //row++;
+ //if(!row)return;
+
+ Time change_delta(new_delta-old_delta);
+
+ if(change_delta<=Time::zero()+Time::epsilon() &&change_delta>=Time::zero()-Time::epsilon())
+ {
+ // Not an error, just no change
+ return;
+ }
+
+ {
+ Keyframe keyframe((*row)[model.keyframe]);
+ synfigapp::Action::Handle action(synfigapp::Action::create("keyframe_set_delta"));
+
+ if(!action)return;
+
+ action->set_param("canvas",canvas_interface()->get_canvas());
+ action->set_param("canvas_interface",canvas_interface());
+ action->set_param("keyframe",keyframe);
+ action->set_param("delta",change_delta);
+
+ canvas_interface()->get_instance()->perform_action(action);
+ }
+
+ return;
+ }
+ else
+ if(column==model.time.index())
+ {
+ OneMoment one_moment;
+
+ Glib::Value<synfig::Time> x;
+ g_value_init(x.gobj(),model.time.type());
+ g_value_copy(value.gobj(),x.gobj());
+ synfig::Keyframe keyframe(*iter->iter);
+
+ synfig::info("KeyframeTreeStore::set_value_impl():old_time=%s",keyframe.get_time().get_string().c_str());
+ keyframe.set_time(x.get());
+ synfig::info("KeyframeTreeStore::set_value_impl():new_time=%s",keyframe.get_time().get_string().c_str());
+
+ synfigapp::Action::Handle action(synfigapp::Action::create("keyframe_set"));
+
+ if(!action)
+ return;
+
+ action->set_param("canvas",canvas_interface()->get_canvas());
+ action->set_param("canvas_interface",canvas_interface());
+ action->set_param("keyframe",keyframe);
+
+ canvas_interface()->get_instance()->perform_action(action);
+ }
+ else if(column==model.description.index())
+ {
+ Glib::Value<Glib::ustring> x;
+ g_value_init(x.gobj(),model.description.type());
+ g_value_copy(value.gobj(),x.gobj());
+ synfig::Keyframe keyframe(*iter->iter);
+ keyframe.set_description(x.get());
+
+ synfigapp::Action::Handle action(synfigapp::Action::create("keyframe_set"));
+
+ if(!action)
+ return;
+
+ action->set_param("canvas",canvas_interface()->get_canvas());
+ action->set_param("canvas_interface",canvas_interface());
+ action->set_param("keyframe",keyframe);
+
+ canvas_interface()->get_instance()->perform_action(action);
+ }
+ else if(column==model.keyframe.index())
+ {
+ g_warning("KeyframeTreeStore::set_value_impl: This column is read-only");
+ }
+ else
+ {
+ assert(0);
+ }
+ }
+ catch(std::exception x)
+ {
+ g_warning(x.what());
+ }
+}
+
+Gtk::TreeModelFlags
+KeyframeTreeStore::get_flags_vfunc ()
+{
+ return Gtk::TREE_MODEL_LIST_ONLY;
+}
+
+int
+KeyframeTreeStore::get_n_columns_vfunc ()
+{
+ return model.size();
+}
+
+GType
+KeyframeTreeStore::get_column_type_vfunc (int index)
+{
+ return model.types()[index];
+}
+
+bool
+KeyframeTreeStore::iter_next_vfunc (const iterator& xiter, iterator& iter_next) const
+{
+ if(!iterator_sane(xiter)) return false;
+
+ _keyframe_iterator *iter(static_cast<_keyframe_iterator*>(xiter.gobj()->user_data));
+
+ if(iter->iter==canvas_interface()->get_canvas()->keyframe_list().end())
+ return false;
+
+ _keyframe_iterator *next(new _keyframe_iterator());
+ iter_next.gobj()->user_data=static_cast<gpointer>(next);
+ next->ref_count=1;
+ next->index=iter->index+1;
+ next->iter=iter->iter;
+ ++next->iter;
+
+ if(next->iter==canvas_interface()->get_canvas()->keyframe_list().end())
+ return false;
+
+ iter_next.gobj()->stamp=stamp_;
+
+ return true;
+}
+
+/*
+bool
+KeyframeTreeStore::iter_next_vfunc (GtkTreeIter* gtk_iter)
+{
+ if(!iterator_sane(gtk_iter)) return false;
+
+ _keyframe_iterator *iter(static_cast<_keyframe_iterator*>(gtk_iter->user_data));
+
+ // If we are already at the end, then we are very invalid
+ if(iter->iter==canvas_interface()->get_canvas()->keyframe_list().end())
+ return false;
+
+ ++(iter->iter);
+
+ if(iter->iter==canvas_interface()->get_canvas()->keyframe_list().end())
+ {
+ --(iter->iter);
+ return false;
+ }
+ (iter->index)++;
+ return true;
+}
+
+bool
+KeyframeTreeStore::iter_children_vfunc (GtkTreeIter* gtk_iter, const GtkTreeIter* parent)
+{
+ dump_iterator(gtk_iter,"gtk_iter");
+ dump_iterator(parent,"parent");
+
+ if(!parent || !iterator_sane(parent))
+ {
+ clear_iterator(gtk_iter);
+ return false;
+ }
+
+ _keyframe_iterator *iter(new _keyframe_iterator());
+ iter->ref_count=1;
+ iter->index=0;
+ iter->iter=canvas_interface()->get_canvas()->keyframe_list().begin();
+
+ gtk_iter->user_data=static_cast<gpointer>(iter);
+ gtk_iter->stamp=stamp_;
+
+ return true;
+}
+
+bool
+KeyframeTreeStore::iter_has_child_vfunc (const GtkTreeIter*parent)
+{
+ dump_iterator(parent,"parent");
+
+ if(parent)
+ return false;
+
+ return true;
+}
+
+int
+KeyframeTreeStore::iter_n_children_vfunc (const GtkTreeIter* parent)
+{
+ dump_iterator(parent,"parent");
+
+ if(parent)
+ return 0;
+
+ return canvas_interface()->get_canvas()->keyframe_list().size();
+}
+*/
+
+int
+KeyframeTreeStore::iter_n_root_children_vfunc () const
+{
+ return canvas_interface()->get_canvas()->keyframe_list().size();
+}
+
+bool
+KeyframeTreeStore::iter_nth_root_child_vfunc (int n, iterator& xiter)const
+{
+ if(canvas_interface()->get_canvas()->keyframe_list().size()==0)
+ {
+ return false;
+ }
+
+ if(n<0)
+ {
+ g_warning("KeyframeTreeStore::iter_nth_root_child_vfunc: Out of range (negative index)");
+ return false;
+ }
+ if(n && (unsigned)n>=canvas_interface()->get_canvas()->keyframe_list().size())
+ {
+ g_warning("KeyframeTreeStore::iter_nth_child_vfunc: Out of range (large index)");
+ return false;
+ }
+
+ _keyframe_iterator *iter(new _keyframe_iterator());
+ iter->ref_count=1;
+ iter->index=n;
+ iter->iter=canvas_interface()->get_canvas()->keyframe_list().begin();
+ while(n--)
+ {
+ if(iter->iter==canvas_interface()->get_canvas()->keyframe_list().end())
+ {
+ g_warning("KeyframeTreeStore::iter_nth_child_vfunc: >>>BUG<<< in %s on line %d",__FILE__,__LINE__);
+ delete iter;
+ return false;
+ }
+ ++iter->iter;
+ }
+ xiter.gobj()->user_data=static_cast<gpointer>(iter);
+ xiter.gobj()->stamp=stamp_;
+ return true;
+}
+
+/*
+bool
+KeyframeTreeStore::iter_nth_child_vfunc (GtkTreeIter* gtk_iter, const GtkTreeIter* parent, int n)
+{
+ dump_iterator(parent,"parent");
+
+ if(parent)
+ {
+ g_warning("KeyframeTreeStore::iter_nth_child_vfunc: I am a list");
+ clear_iterator(gtk_iter);
+ return false;
+ }
+
+
+
+ _keyframe_iterator *iter(new _keyframe_iterator());
+ iter->ref_count=1;
+ iter->index=n;
+ iter->iter=canvas_interface()->get_canvas()->keyframe_list().begin();
+ while(n--)
+ {
+ if(iter->iter==canvas_interface()->get_canvas()->keyframe_list().end())
+ {
+ g_warning("KeyframeTreeStore::iter_nth_child_vfunc: >>>BUG<<< in %s on line %d",__FILE__,__LINE__);
+ delete iter;
+ clear_iterator(gtk_iter);
+ return false;
+ }
+ ++iter->iter;
+ }
+
+ gtk_iter->user_data=static_cast<gpointer>(iter);
+ gtk_iter->stamp=stamp_;
+ return true;
+}
+
+bool
+KeyframeTreeStore::iter_parent_vfunc (GtkTreeIter* gtk_iter, const GtkTreeIter* child)
+{
+ dump_iterator(child,"child");
+ iterator_sane(child);
+ clear_iterator(gtk_iter);
+ return false;
+}
+*/
+
+void
+KeyframeTreeStore::ref_node_vfunc (iterator& xiter)const
+{
+ GtkTreeIter* gtk_iter(xiter.gobj());
+ if(!gtk_iter || !iterator_sane(gtk_iter)) return;
+
+ _keyframe_iterator *iter(static_cast<_keyframe_iterator*>(gtk_iter->user_data));
+ iter->ref_count++;
+}
+
+void
+KeyframeTreeStore::unref_node_vfunc (iterator& xiter)const
+{
+ GtkTreeIter* gtk_iter(xiter.gobj());
+ if(!gtk_iter || !iterator_sane(gtk_iter)) return;
+
+ _keyframe_iterator *iter(static_cast<_keyframe_iterator*>(gtk_iter->user_data));
+ iter->ref_count--;
+ if(!iter->ref_count)
+ {
+ delete iter;
+
+ // Make this iterator invalid
+ gtk_iter->stamp=0;
+ }
+}
+
+Gtk::TreeModel::Path
+KeyframeTreeStore::get_path_vfunc (const iterator& gtk_iter)const
+{
+ Gtk::TreeModel::Path path;
+
+ // If this is the root node, then return
+ // a root path
+ if(!iterator_sane(gtk_iter))
+ return path;
+
+ _keyframe_iterator *iter(static_cast<_keyframe_iterator*>(gtk_iter->gobj()->user_data));
+
+ path.append_index(iter->index);
+
+ return path;
+}
+
+bool
+KeyframeTreeStore::get_iter_vfunc (const Gtk::TreeModel::Path& path, iterator& iter)const
+{
+ if(path.get_depth()>=1)
+ return iter_nth_root_child_vfunc(path.front(),iter);
+
+ // Error case
+ g_warning("KeyframeTreeStore::get_iter_vfunc(): Bad path \"%s\"",path.to_string().c_str());
+ //clear_iterator(iter);
+ return false;
+}
+
+bool
+KeyframeTreeStore::iter_is_valid (const iterator& iter) const
+{
+ return iterator_sane(iter);
+}
+
+void
+KeyframeTreeStore::get_value_vfunc (const Gtk::TreeModel::iterator& gtk_iter, int column, Glib::ValueBase& value)const
+{
+ dump_iterator(gtk_iter,"gtk_iter");
+ if(!iterator_sane(gtk_iter))
+ return;
+
+ _keyframe_iterator *iter(static_cast<_keyframe_iterator*>(gtk_iter->gobj()->user_data));
+
+ switch(column)
+ {
+ case 0: // Time
+ {
+ Glib::Value<synfig::Time> x;
+ g_value_init(x.gobj(),x.value_type());
+ x.set(iter->iter->get_time());
+ g_value_init(value.gobj(),x.value_type());
+ g_value_copy(x.gobj(),value.gobj());
+ return;
+ }
+ case 3: // Time Delta
+ {
+ Glib::Value<synfig::Time> x;
+ g_value_init(x.gobj(),x.value_type());
+
+ synfig::Keyframe prev_keyframe(*iter->iter);
+ synfig::Keyframe keyframe;
+ {
+ KeyframeList::iterator tmp(iter->iter);
+ tmp++;
+ if(tmp==get_canvas()->keyframe_list().end())
+ {
+ x.set(Time(0));
+ g_value_init(value.gobj(),x.value_type());
+ g_value_copy(x.gobj(),value.gobj());
+ return;
+ }
+ keyframe=*tmp;
+ }
+
+ Time delta(0);
+ try {
+ delta=keyframe.get_time()-prev_keyframe.get_time();
+ }catch(...) { }
+ x.set(delta);
+ g_value_init(value.gobj(),x.value_type());
+ g_value_copy(x.gobj(),value.gobj());
+ return;
+ }
+ case 1: // Description
+ {
+ g_value_init(value.gobj(),G_TYPE_STRING);
+ g_value_set_string(value.gobj(),iter->iter->get_description().c_str());
+ return;
+ }
+ case 2: // Keyframe
+ {
+ Glib::Value<synfig::Keyframe> x;
+ g_value_init(x.gobj(),x.value_type());
+ x.set(*iter->iter);
+ g_value_init(value.gobj(),x.value_type());
+ g_value_copy(x.gobj(),value.gobj());
+ return;
+ }
+ default:
+ break;
+ }
+}
+
+Gtk::TreeModel::Row
+KeyframeTreeStore::find_row(const synfig::Keyframe &keyframe)
+{
+ Gtk::TreeModel::Row row(*(children().begin()));
+ dump_iterator(row,"find_row,begin");
+ const GtkTreeIter *gtk_iter(row.gobj());
+ if(!iterator_sane(gtk_iter))
+ throw std::runtime_error(_("Unable to find Keyframe in table"));
+
+ _keyframe_iterator *iter(static_cast<_keyframe_iterator*>(gtk_iter->user_data));
+
+ synfig::KeyframeList &keyframe_list(canvas_interface()->get_canvas()->keyframe_list());
+ if(keyframe_list.empty())
+ throw std::runtime_error(_("There are no keyframes n this canvas"));
+
+ iter->index=0;
+
+ for(iter->iter=keyframe_list.begin();iter->iter!=keyframe_list.end() && *iter->iter!=keyframe;++iter->iter)
+ {
+ iter->index++;
+ }
+ if(iter->iter==keyframe_list.end())
+ throw std::runtime_error(_("Unable to find Keyframe in table"));
+ return row;
+}
+
+void
+KeyframeTreeStore::add_keyframe(synfig::Keyframe keyframe)
+{
+ try
+ {
+ Gtk::TreeRow row(find_row(keyframe));
+ dump_iterator(row.gobj(),"add_keyframe,row");
+ Gtk::TreePath path(get_path(row));
+
+ row_inserted(path,row);
+
+ old_keyframe_list=get_canvas()->keyframe_list();
+ //old_keyframe_list.add(keyframe);
+ //old_keyframe_list.sort();
+ }
+ catch(std::exception x)
+ {
+ g_warning(x.what());
+ }
+}
+
+void
+KeyframeTreeStore::remove_keyframe(synfig::Keyframe keyframe)
+{
+ try
+ {
+ if(1)
+ {
+ Gtk::TreeRow row(find_row(keyframe));
+ dump_iterator(row,"remove_keyframe,row");
+ Gtk::TreePath path(get_path(row));
+ row_deleted(path);
+
+ old_keyframe_list.erase(keyframe);
+ }
+ else
+ {
+ g_warning("KeyframeTreeStore::remove_keyframe: Keyframe not in table");
+ }
+ }
+ catch(std::exception x)
+ {
+ g_warning(x.what());
+ }
+}
+
+void
+KeyframeTreeStore::change_keyframe(synfig::Keyframe keyframe)
+{
+ try
+ {
+ Gtk::TreeRow row(find_row(keyframe));
+
+ unsigned int new_index(get_index_from_model_iter(row));
+ unsigned int old_index(0);
+ synfig::KeyframeList::iterator iter;
+ for(old_index=0,iter=old_keyframe_list.begin();iter!=old_keyframe_list.end() && (UniqueID)*iter!=(UniqueID)keyframe;++iter,old_index++)
+ ;
+
+ if(iter!=old_keyframe_list.end() && new_index!=old_index)
+ {
+ std::vector<int> new_order;
+ for(unsigned int i=0;i<old_keyframe_list.size();i++)
+ {
+ new_order.push_back(i);
+ }
+ if(new_order.size()>new_index)
+ {
+ new_order.erase(new_order.begin()+new_index);
+ new_order.insert(new_order.begin()+old_index,new_index);
+
+ //new_order[old_index]=
+
+ rows_reordered (Path(), iterator(), &new_order[0]);
+ }
+ old_keyframe_list=get_canvas()->keyframe_list();
+
+ row=find_row(keyframe);
+ }
+
+ dump_iterator(row,"change_keyframe,row");
+ row_changed(get_path(row),row);
+ }
+ catch(std::exception x)
+ {
+ g_warning(x.what());
+ }
+}