+/* === S Y N F I G ========================================================= */
+/*! \file valuenode_dynamiclist.cpp
+** \brief Implementation of the "Dynamic List" valuenode conversion.
+**
+** $Id$
+**
+** \legal
+** Copyright (c) 2002-2005 Robert B. Quattlebaum Jr., Adrian Bentley
+** Copyright (c) 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 "valuenode_dynamiclist.h"
+#include "valuenode_const.h"
+#include "valuenode_composite.h"
+#include "general.h"
+#include "exception.h"
+#include <vector>
+#include <list>
+#include <algorithm>
+#include "canvas.h"
+
+#endif
+
+/* === U S I N G =========================================================== */
+
+using namespace std;
+using namespace etl;
+using namespace synfig;
+
+/* === M A C R O S ========================================================= */
+
+/* === G L O B A L S ======================================================= */
+
+/* === P R O C E D U R E S ================================================= */
+
+/* === M E T H O D S ======================================================= */
+
+ValueNode_DynamicList::ListEntry::ListEntry():
+ index(0)
+{
+}
+
+ValueNode_DynamicList::ListEntry::ListEntry(const ValueNode::Handle &value_node):
+ value_node(value_node),
+ index(0)
+{
+}
+
+ValueNode_DynamicList::ListEntry::ListEntry(const ValueNode::Handle &value_node,Time begin, Time end):
+ value_node(value_node)
+{
+ add(begin,false);
+ add(end,false);
+ add((begin+end)*0.5,true);
+}
+
+ValueNode_DynamicList::ListEntry::ActivepointList::iterator
+ValueNode_DynamicList::ListEntry::add(Time time, bool status, int priority)
+{
+ typedef synfig::ValueNode_DynamicList::ListEntry::ActivepointList::iterator iterator;
+
+ //! \optimize
+ Activepoint ap(time,status,priority);
+ ap.set_parent_index(get_index());
+ ap.set_parent_value_node(get_parent_value_node());
+ timing_info.push_back(ap);
+ iterator iter(--iterator(timing_info.end()));
+ timing_info.sort();
+
+ return iter;
+}
+
+ValueNode_DynamicList::ListEntry::ActivepointList::iterator
+ValueNode_DynamicList::ListEntry::add(const Activepoint &x)
+{
+ typedef synfig::ValueNode_DynamicList::ListEntry::ActivepointList::iterator iterator;
+
+ //! \optimize
+ Activepoint ap(x);
+ ap.set_parent_index(get_index());
+ ap.set_parent_value_node(get_parent_value_node());
+ timing_info.push_back(ap);
+ iterator iter(--iterator(timing_info.end()));
+ timing_info.sort();
+
+ return iter;
+}
+
+void
+ValueNode_DynamicList::reindex()
+{
+ int i(0);
+
+ std::vector<ListEntry>::iterator iter;
+
+ for(iter=list.begin();iter!=list.end();++iter)
+ {
+ assert(iter->value_node);
+ if(iter->index!=i || iter->get_parent_value_node().get()!=this)
+ {
+ ActivepointList::iterator iter2;
+
+ if(iter->timing_info.size()) // is this line really necessary?
+ for(iter2=iter->timing_info.begin();iter2!=iter->timing_info.end();++iter2)
+ {
+ iter2->set_parent_index(i);
+ iter2->set_parent_value_node(this);
+ }
+ iter->index=i;
+ iter->set_parent_value_node(this);
+ }
+ }
+}
+
+ValueNode_DynamicList::ListEntry
+ValueNode_DynamicList::create_list_entry(int index, Time time, Real origin)
+{
+ ValueNode_DynamicList::ListEntry ret;
+
+
+ synfig::ValueBase prev,next;
+
+ index=index%link_count();
+
+ assert(index>=0);
+
+ ret.index=index;
+ ret.set_parent_value_node(this);
+
+ next=(*list[index].value_node)(time);
+
+ if(index!=0)
+ prev=(*list[index-1].value_node)(time);
+ else
+ {
+ if(get_loop())
+ prev=(*list[link_count()-1].value_node)(time);
+ else
+ {
+ prev=next;
+ }
+ }
+
+
+ switch(get_contained_type())
+ {
+ case ValueBase::TYPE_VECTOR:
+ {
+ Vector a(prev.get(Vector())), b(next.get(Vector()));
+ ret.value_node=ValueNode_Const::create((b-a)*origin+a);
+ break;
+ }
+ case ValueBase::TYPE_REAL:
+ {
+ Real a(prev.get(Real())), b(next.get(Real()));
+ ret.value_node=ValueNode_Const::create((b-a)*origin+a);
+ break;
+ }
+ case ValueBase::TYPE_COLOR:
+ {
+ Color a(prev.get(Color())), b(next.get(Color()));
+ ret.value_node=ValueNode_Composite::create((b-a)*origin+a);
+ break;
+ }
+ case ValueBase::TYPE_ANGLE:
+ {
+ Angle a(prev.get(Angle())), b(next.get(Angle()));
+ ret.value_node=ValueNode_Const::create((b-a)*origin+a);
+ break;
+ }
+ case ValueBase::TYPE_TIME:
+ {
+ Time a(prev.get(Time())), b(next.get(Time()));
+ ret.value_node=ValueNode_Const::create((b-a)*origin+a);
+ break;
+ }
+ default:
+ ret.value_node=ValueNode_Const::create(get_contained_type());
+ break;
+ }
+
+
+ return ret;
+}
+
+ValueNode_DynamicList::ListEntry::ActivepointList::iterator
+ValueNode_DynamicList::ListEntry::find(const UniqueID& x)
+{
+ return std::find(timing_info.begin(),timing_info.end(),x);
+}
+
+ValueNode_DynamicList::ListEntry::ActivepointList::const_iterator
+ValueNode_DynamicList::ListEntry::find(const UniqueID& x)const
+{
+ return std::find(timing_info.begin(),timing_info.end(),x);
+}
+
+void
+ValueNode_DynamicList::ListEntry::erase(const UniqueID& x)
+{
+ timing_info.erase(find(x));
+}
+
+ValueNode_DynamicList::ListEntry::ActivepointList::iterator
+ValueNode_DynamicList::ListEntry::find(const Time& x)
+{
+ typedef synfig::ValueNode_DynamicList::ListEntry::ActivepointList ActivepointList;
+
+ ActivepointList::iterator iter;
+
+ for(iter=timing_info.begin();iter!=timing_info.end();++iter)
+ if(iter->time==x)
+ return iter;
+
+ throw Exception::NotFound("ValueNode_DynamicList::ListEntry::find():"+x.get_string());
+}
+
+ValueNode_DynamicList::ListEntry::ActivepointList::const_iterator
+ValueNode_DynamicList::ListEntry::find(const Time& x)const
+{
+ typedef synfig::ValueNode_DynamicList::ListEntry::ActivepointList ActivepointList;
+
+ ActivepointList::const_iterator iter;
+
+ for(iter=timing_info.begin();iter!=timing_info.end();++iter)
+ if(iter->time==x)
+ return iter;
+
+ throw Exception::NotFound("ValueNode_DynamicList::ListEntry::find()const:"+x.get_string());
+}
+
+ValueNode_DynamicList::ListEntry::ActivepointList::iterator
+ValueNode_DynamicList::ListEntry::find_next(const Time& x)
+{
+ typedef synfig::ValueNode_DynamicList::ListEntry::ActivepointList ActivepointList;
+
+ ActivepointList::iterator iter;
+
+ for(iter=timing_info.begin();iter!=timing_info.end();++iter)
+ if(iter->time>x)
+ return iter;
+
+ throw Exception::NotFound("ValueNode_DynamicList::ListEntry::find_next():"+x.get_string());
+}
+
+ValueNode_DynamicList::ListEntry::ActivepointList::const_iterator
+ValueNode_DynamicList::ListEntry::find_next(const Time& x)const
+{
+ typedef synfig::ValueNode_DynamicList::ListEntry::ActivepointList ActivepointList;
+
+ ActivepointList::const_iterator iter;
+
+ for(iter=timing_info.begin();iter!=timing_info.end();++iter)
+ if(iter->time>x)
+ return iter;
+
+ throw Exception::NotFound("ValueNode_DynamicList::ListEntry::find_next()const:"+x.get_string());
+}
+
+ValueNode_DynamicList::ListEntry::ActivepointList::iterator
+ValueNode_DynamicList::ListEntry::find_prev(const Time& x)
+{
+ typedef synfig::ValueNode_DynamicList::ListEntry::ActivepointList ActivepointList;
+
+ ActivepointList::iterator iter;
+ iter=timing_info.end();
+ do
+ {
+ --iter;
+ if(iter->time<x)
+ return iter;
+ }
+ while(iter!=timing_info.begin());
+
+ throw Exception::NotFound("ValueNode_DynamicList::ListEntry::find_prev():"+x.get_string());
+}
+
+ValueNode_DynamicList::ListEntry::ActivepointList::const_iterator
+ValueNode_DynamicList::ListEntry::find_prev(const Time& x)const
+{
+ typedef synfig::ValueNode_DynamicList::ListEntry::ActivepointList ActivepointList;
+
+ ActivepointList::const_iterator iter;
+ iter=timing_info.end();
+ do
+ {
+ --iter;
+ if(iter->time<x)
+ return iter;
+ }
+ while(iter!=timing_info.begin());
+
+ throw Exception::NotFound("ValueNode_DynamicList::ListEntry::find_prev()const:"+x.get_string());
+}
+
+int
+ValueNode_DynamicList::ListEntry::find(const Time& begin,const Time& end,std::vector<Activepoint*>& selected)
+{
+ Time curr_time(begin);
+ int ret(0);
+
+ // try to grab first waypoint
+ try
+ {
+ ActivepointList::iterator iter;
+ iter=find(curr_time);
+ selected.push_back(&*iter);
+ ret++;
+ }
+ catch(...) { }
+
+ try
+ {
+ ActivepointList::iterator iter;
+ while(true)
+ {
+ iter=find_next(curr_time);
+ curr_time=iter->get_time();
+ if(curr_time>=end)
+ break;
+ selected.push_back(&*iter);
+ ret++;
+ }
+ }
+ catch(...) { }
+
+ return ret;
+}
+
+float
+ValueNode_DynamicList::ListEntry::amount_at_time(const Time &t,bool *rising)const
+{
+ typedef synfig::ValueNode_DynamicList::ListEntry::Activepoint Activepoint;
+ typedef synfig::ValueNode_DynamicList::ListEntry::ActivepointList ActivepointList;
+
+ if(timing_info.empty())
+ return 1.0f;
+
+ try
+ {
+ ActivepointList::const_iterator iter;
+ iter=find(t);
+ return iter->state?1.0f:0.0f;
+ }
+ catch(...) { }
+
+ ActivepointList::const_iterator prev_iter;
+ ActivepointList::const_iterator next_iter;
+
+ try { prev_iter=find_prev(t); }
+ catch(...) { return find_next(t)->state?1.0f:0.0f; }
+
+ try { next_iter=find_next(t); }
+ catch(...) { return prev_iter->state?1.0f:0.0f; }
+
+ if(next_iter->state==prev_iter->state)
+ return next_iter->state?1.0f:0.0f;
+
+ if(rising)*rising=next_iter->state;
+
+ if(next_iter->state==true)
+ return float((t-prev_iter->time)/(next_iter->time-prev_iter->time));
+
+ return float((next_iter->time-t)/(next_iter->time-prev_iter->time));
+}
+
+Activepoint
+ValueNode_DynamicList::ListEntry::new_activepoint_at_time(const Time& time)const
+{
+ Activepoint activepoint;
+
+ activepoint.set_state(status_at_time(time));
+ activepoint.set_priority(0);
+
+ return activepoint;
+}
+
+bool
+ValueNode_DynamicList::ListEntry::status_at_time(const Time &t)const
+{
+ typedef synfig::ValueNode_DynamicList::ListEntry::Activepoint Activepoint;
+ typedef synfig::ValueNode_DynamicList::ListEntry::ActivepointList ActivepointList;
+
+ ActivepointList::const_iterator entry_iter;
+ ActivepointList::const_iterator prev_iter;
+ bool state(true);
+
+ // New "symmetric" state mechanism
+ if(!timing_info.empty())
+ {
+ if(timing_info.size()==1)
+ state=timing_info.front().state;
+ else
+ {
+ //! \optimize Perhaps we should use a binary search...?
+ // This will give us the first activepoint that is after t.
+ for(entry_iter=timing_info.begin();entry_iter!=timing_info.end();++entry_iter)
+ {
+ if(entry_iter->time==t)
+ {
+ // If we hit the entry right on the nose, then we don't
+ // have to do anything more
+ return entry_iter->state;
+ }
+ if(entry_iter->time>t)
+ break;
+
+ }
+ prev_iter=entry_iter;
+ prev_iter--;
+
+ // ie:
+ //
+ // |-------|---t---|-------|
+ // prev_iter^ ^entry_iter
+
+ if(entry_iter==timing_info.end())
+ {
+ state=prev_iter->state;
+ }
+ else
+ if(entry_iter==timing_info.begin())
+ {
+ state=entry_iter->state;
+ }
+ else
+ if(entry_iter->priority==prev_iter->priority)
+ {
+ state=entry_iter->state || prev_iter->state;
+ }
+ else
+ if(entry_iter->priority>prev_iter->priority)
+ {
+ state=entry_iter->state;
+ }
+ else
+ {
+ state=prev_iter->state;
+ }
+ }
+ }
+ return state;
+}
+
+
+
+
+void
+ValueNode_DynamicList::add(const ValueNode::Handle &value_node, int index)
+{
+ ListEntry list_entry(value_node);
+ list_entry.timing_info.size();
+
+ if(index<0 || index>=(int)list.size())
+ {
+ list.push_back(list_entry);
+ }
+ else
+ {
+ list.insert(list.begin()+index,list_entry);
+ }
+
+ add_child(value_node.get());
+ reindex();
+ //changed();
+
+ if(get_parent_canvas())
+ get_parent_canvas()->signal_value_node_child_added()(this,value_node);
+ else if(get_root_canvas() && get_parent_canvas())
+ get_root_canvas()->signal_value_node_child_added()(this,value_node);
+}
+
+void
+ValueNode_DynamicList::add(const ListEntry &list_entry, int index)
+{
+ if(index<0 || index>=(int)list.size())
+ list.push_back(list_entry);
+ else
+ list.insert(list.begin()+index,list_entry);
+ add_child(list_entry.value_node.get());
+
+ reindex();
+ //changed();
+
+ if(get_parent_canvas())
+ get_parent_canvas()->signal_value_node_child_added()(this,list_entry.value_node);
+ else if(get_root_canvas() && get_parent_canvas())
+ get_root_canvas()->signal_value_node_child_added()(this,list_entry.value_node);
+}
+
+void
+ValueNode_DynamicList::erase(const ValueNode::Handle &value_node_)
+{
+ ValueNode::Handle value_node(value_node_);
+
+ assert(value_node);
+ if(!value_node)
+ throw String("ValueNode_DynamicList::erase(): Passed bad value node");
+
+ std::vector<ListEntry>::iterator iter;
+ for(iter=list.begin();iter!=list.end();++iter)
+ if(iter->value_node==value_node)
+ {
+ list.erase(iter);
+ if(value_node)
+ {
+ remove_child(value_node.get());
+ // changed to fix bug 1420091 - it seems that when a .sif file containing a bline layer encapsulated inside
+ // another layer, get_parent_canvas() is false and get_root_canvas() is true, but when we come to erase a
+ // vertex, both are true. So the signal is sent to the parent, but the signal wasn't sent to the parent
+ // when it was added. This probably isn't the right fix, but it seems to work for now. Note that the same
+ // strange "if (X) else if (Y && X)" code is also present in the two previous functions, above.
+
+ // if(get_parent_canvas())
+ // get_parent_canvas()->signal_value_node_child_removed()(this,value_node);
+ // else if(get_root_canvas() && get_parent_canvas())
+ // get_root_canvas()->signal_value_node_child_removed()(this,value_node);
+ if(get_root_canvas())
+ get_root_canvas()->signal_value_node_child_removed()(this,value_node);
+ }
+ break;
+ }
+ reindex();
+}
+
+
+ValueNode_DynamicList::ValueNode_DynamicList(ValueBase::Type container_type):
+ LinkableValueNode(ValueBase::TYPE_LIST),
+ container_type (container_type),
+ loop_(false)
+{
+ DCAST_HACK_ENABLE();
+}
+
+ValueNode_DynamicList::Handle
+ValueNode_DynamicList::create(ValueBase::Type id)
+{
+ return new ValueNode_DynamicList(id);
+}
+
+ValueNode_DynamicList::~ValueNode_DynamicList()
+{
+ unlink_all();
+}
+
+ValueNode_DynamicList*
+ValueNode_DynamicList::create_from(const ValueBase &value)
+{
+ //vector<ValueBase> value_list(value.operator vector<ValueBase>());
+ vector<ValueBase> value_list(value.get_list());
+
+ vector<ValueBase>::iterator iter;
+
+ if(value_list.empty())
+ return 0;
+
+ ValueNode_DynamicList* value_node(new ValueNode_DynamicList(value_list.front().get_type()));
+
+ // when creating a list of vectors, start it off being looped.
+ // I think the only time this is used if for creating polygons,
+ // and we want them to be looped by default
+ if (value_node->get_contained_type() == ValueBase::TYPE_VECTOR)
+ value_node->set_loop(true);
+
+ for(iter=value_list.begin();iter!=value_list.end();++iter)
+ {
+ ValueNode::Handle item(ValueNode_Const::create(*iter));
+ value_node->add(ListEntry(item));
+ assert(value_node->list.back().value_node);
+ }
+ return value_node;
+}
+
+ValueBase
+ValueNode_DynamicList::operator()(Time t)const
+{
+ std::vector<ValueBase> ret_list;
+ std::vector<ListEntry>::const_iterator iter;
+
+ assert(container_type);
+
+ for(iter=list.begin();iter!=list.end();++iter)
+ {
+ bool state(iter->status_at_time(t));
+
+ if(state)
+ {
+ if(iter->value_node->get_type()==container_type)
+ ret_list.push_back((*iter->value_node)(t));
+ else
+ {
+ synfig::warning(string("ValueNode_DynamicList::operator()():")+_("List type/item type mismatch, throwing away mismatch"));
+ }
+ }
+ }
+
+ if(list.empty())
+ synfig::warning(string("ValueNode_DynamicList::operator()():")+_("No entries in list"));
+ else
+ if(ret_list.empty())
+ synfig::warning(string("ValueNode_DynamicList::operator()():")+_("No entries in ret_list"));
+
+ return ret_list;
+}
+
+bool
+ValueNode_DynamicList::set_link_vfunc(int i,ValueNode::Handle x)
+{
+ assert(i>=0);
+
+ if((unsigned)i>=list.size())
+ return false;
+ if(x->get_type()!=container_type)
+ return false;
+ list[i].value_node=x;
+ return true;
+}
+
+ValueNode::LooseHandle
+ValueNode_DynamicList::get_link_vfunc(int i)const
+{
+ assert(i>=0);
+
+ if((unsigned)i>=list.size())
+ return 0;
+ return list[i].value_node;
+}
+
+int
+ValueNode_DynamicList::link_count()const
+{
+ return list.size();
+}
+
+String
+ValueNode_DynamicList::link_local_name(int i)const
+{
+ assert(i>=0 && i<link_count());
+
+ return etl::strprintf(_("Item %03d"),i+1);
+}
+
+ValueNode*
+ValueNode_DynamicList::clone(const GUID& deriv_guid)const
+{
+ { ValueNode* x(find_value_node(get_guid()^deriv_guid).get()); if(x)return x; }
+
+ ValueNode_DynamicList* ret=new ValueNode_DynamicList(container_type);
+ ret->set_guid(get_guid()^deriv_guid);
+
+ std::vector<ListEntry>::const_iterator iter;
+
+ for(iter=list.begin();iter!=list.end();++iter)
+ {
+ if(iter->value_node->is_exported())
+ ret->add(*iter);
+ else
+ {
+ ListEntry list_entry(*iter);
+ //list_entry.value_node=find_value_node(iter->value_node->get_guid()^deriv_guid).get();
+ //if(!list_entry.value_node)
+ list_entry.value_node=iter->value_node->clone(deriv_guid);
+ ret->add(list_entry);
+ //ret->list.back().value_node=iter->value_node.clone();
+ }
+ }
+ ret->set_loop(get_loop());
+ return ret;
+}
+
+String
+ValueNode_DynamicList::link_name(int i)const
+{
+ return strprintf("item%04d",i);
+}
+
+int
+ValueNode_DynamicList::get_link_index_from_name(const String &name)const
+{
+ throw Exception::BadLinkName(name);
+}
+
+String
+ValueNode_DynamicList::get_name()const
+{
+ return "dynamic_list";
+}
+
+String
+ValueNode_DynamicList::get_local_name()const
+{
+ return _("Dynamic List");
+}
+
+bool
+ValueNode_DynamicList::check_type(ValueBase::Type type)
+{
+ return type==ValueBase::TYPE_LIST;
+}
+
+void
+ValueNode_DynamicList::set_member_canvas(etl::loose_handle<Canvas> canvas)
+{
+ for (vector<ListEntry>::iterator iter = list.begin(); iter != list.end(); iter++)
+ iter->value_node->set_parent_canvas(canvas);
+}
+
+ValueBase::Type
+ValueNode_DynamicList::get_contained_type()const
+{
+ return container_type;
+}
+
+LinkableValueNode*
+ValueNode_DynamicList::create_new()const
+{
+ assert(0);
+
+ return 0;
+}
+
+int
+ValueNode_DynamicList::find_next_valid_entry(int orig_item, Time t)const
+{
+ int curr_item;
+
+ for(curr_item=orig_item+1;curr_item!=orig_item;curr_item++)
+ {
+ if(curr_item==(int)list.size())
+ {
+ curr_item=0;
+ continue;
+ }
+ if(list[curr_item].status_at_time(t))
+ return curr_item;
+ }
+ return curr_item;
+}
+
+int
+ValueNode_DynamicList::find_prev_valid_entry(int orig_item, Time t)const
+{
+ int curr_item;
+
+ for(curr_item=orig_item-1;curr_item!=orig_item;curr_item--)
+ {
+ if(curr_item==-1)
+ {
+ curr_item=list.size();
+ continue;
+ }
+ if(list[curr_item].status_at_time(t))
+ return curr_item;
+ }
+ return curr_item;
+}
+
+const synfig::Node::time_set & ValueNode_DynamicList::ListEntry::get_times() const
+{
+ synfig::ActivepointList::const_iterator j = timing_info.begin(),
+ end = timing_info.end();
+
+ //must remerge with all the other values because we don't know if we've changed...
+ times = value_node->get_times();
+
+ for(; j != end; ++j)
+ {
+ TimePoint t;
+ t.set_time(j->get_time());
+ t.set_guid(j->get_guid());
+
+ times.insert(t);
+ }
+
+ return times;
+}
+
+void ValueNode_DynamicList::get_times_vfunc(Node::time_set &set) const
+{
+ //add in the active points
+ int size = list.size();
+
+ //rebuild all the info...
+ for(int i = 0; i < size; ++i)
+ {
+ const Node::time_set & tset= list[i].get_times();
+ set.insert(tset.begin(),tset.end());
+ }
+}
+
+
+//new find functions that don't throw
+struct timecmp
+{
+ Time t;
+
+ timecmp(const Time &c) :t(c) {}
+
+ bool operator()(const Activepoint &rhs) const
+ {
+ return t.is_equal(rhs.get_time());
+ }
+};
+
+ValueNode_DynamicList::ListEntry::findresult ValueNode_DynamicList::ListEntry::find_uid(const UniqueID& x)
+{
+ findresult f;
+ f.second = false;
+
+ f.first = std::find(timing_info.begin(),timing_info.end(),x);
+
+ if(f.first != timing_info.end())
+ {
+ f.second = true;
+ }
+
+ return f;
+}
+
+ValueNode_DynamicList::ListEntry::const_findresult ValueNode_DynamicList::ListEntry::find_uid(const UniqueID& x) const
+{
+ const_findresult f;
+ f.second = false;
+
+ f.first = std::find(timing_info.begin(),timing_info.end(),x);
+
+ if(f.first != timing_info.end())
+ {
+ f.second = true;
+ }
+
+ return f;
+}
+
+ValueNode_DynamicList::ListEntry::findresult ValueNode_DynamicList::ListEntry::find_time(const Time& x)
+{
+ findresult f;
+ f.second = false;
+
+ f.first = std::find_if(timing_info.begin(),timing_info.end(),timecmp(x));
+
+ if(f.first != timing_info.end())
+ {
+ f.second = true;
+ }
+
+ return f;
+}
+
+ValueNode_DynamicList::ListEntry::const_findresult ValueNode_DynamicList::ListEntry::find_time(const Time& x)const
+{
+ const_findresult f;
+ f.second = false;
+
+ f.first = std::find_if(timing_info.begin(),timing_info.end(),timecmp(x));
+
+ if(f.first != timing_info.end())
+ {
+ f.second = true;
+ }
+
+ return f;
+}
+
+void
+ValueNode_DynamicList::insert_time(const Time& location, const Time& delta)
+{
+ if(!delta)
+ return;
+
+ std::vector<ListEntry>::iterator iter(list.begin());
+ for(;iter!=list.end();++iter)
+ {
+ try
+ {
+ ListEntry& item(*iter);
+
+ ActivepointList::iterator iter(item.find_next(location));
+ for(;iter!=item.timing_info.end();++iter)
+ {
+ iter->set_time(iter->get_time()+delta);
+ }
+ }
+ catch(Exception::NotFound) { }
+ }
+ changed();
+}