diff options
author | Carl Hetherington <carl@carlh.net> | 2010-07-14 12:27:37 +0000 |
---|---|---|
committer | Carl Hetherington <carl@carlh.net> | 2010-07-14 12:27:37 +0000 |
commit | 66062a85b6388b28ed04f90bab3d302eec0f2a77 (patch) | |
tree | 89c1ea74a896e60e14143bc6e3dde867eac42c48 /libs | |
parent | 5ce47b52da7bb60b5b7dde94ca0bacc6ae44197a (diff) |
Fix binding of automation list undo records to MIDI sources. Should fix the remainder of #3203.
git-svn-id: svn://localhost/ardour2/branches/3.0@7411 d708f5d6-7413-0410-9779-e7cbd77b26cf
Diffstat (limited to 'libs')
-rw-r--r-- | libs/ardour/ardour/session.h | 3 | ||||
-rw-r--r-- | libs/ardour/session_command.cc | 27 | ||||
-rw-r--r-- | libs/ardour/wscript | 1 | ||||
-rw-r--r-- | libs/pbd/pbd/memento_command.h | 80 |
4 files changed, 93 insertions, 18 deletions
diff --git a/libs/ardour/ardour/session.h b/libs/ardour/ardour/session.h index f770b9b459..5255654005 100644 --- a/libs/ardour/ardour/session.h +++ b/libs/ardour/ardour/session.h @@ -1204,8 +1204,11 @@ class Session : public PBD::StatefulDestructible, public PBD::ScopedConnectionLi /* SOURCES */ mutable Glib::Mutex source_lock; + + public: typedef std::map<PBD::ID,boost::shared_ptr<Source> > SourceMap; + private: SourceMap sources; public: diff --git a/libs/ardour/session_command.cc b/libs/ardour/session_command.cc index 17ffa1e26d..dc918dfe1c 100644 --- a/libs/ardour/session_command.cc +++ b/libs/ardour/session_command.cc @@ -33,6 +33,7 @@ #include "ardour/midi_region.h" #include "ardour/session_playlists.h" #include "ardour/region_factory.h" +#include "ardour/midi_automation_list_binder.h" #include "pbd/error.h" #include "pbd/id.h" #include "pbd/statefuldestructible.h" @@ -58,7 +59,12 @@ Session::memento_command_factory(XMLNode *n) XMLNode *child = 0; /* get id */ - id = PBD::ID(n->property("obj-id")->value()); + + /* XXX: HACK! */ + bool have_id = n->property("obj-id") != 0; + if (have_id) { + id = PBD::ID(n->property("obj-id")->value()); + } /* get before/after */ @@ -121,11 +127,20 @@ Session::memento_command_factory(XMLNode *n) } } else if (obj_T == "Evoral::Curve" || obj_T == "ARDOUR::AutomationList") { - std::map<PBD::ID, AutomationList*>::iterator i = automation_lists.find(id); - if (i != automation_lists.end()) { - return new MementoCommand<AutomationList>(*i->second, before, after); - } - cerr << "Alist not found\n"; + if (have_id) { + std::map<PBD::ID, AutomationList*>::iterator i = automation_lists.find(id); + if (i != automation_lists.end()) { + return new MementoCommand<AutomationList>(*i->second, before, after); + } + } else { + return new MementoCommand<AutomationList> ( + new MidiAutomationListBinder (n, sources), + before, after + ); + } + + cerr << "Alist not found\n"; + } else if (registry.count(id)) { // For Editor and AutomationLine which are off-limits herea return new MementoCommand<PBD::StatefulDestructible>(*registry[id], before, after); } diff --git a/libs/ardour/wscript b/libs/ardour/wscript index c859a2e88d..95682ce477 100644 --- a/libs/ardour/wscript +++ b/libs/ardour/wscript @@ -112,6 +112,7 @@ libardour_sources = [ 'location.cc', 'location_importer.cc', 'meter.cc', + 'midi_automation_list_binder.cc', 'midi_buffer.cc', 'midi_clock_slave.cc', 'midi_diskstream.cc', diff --git a/libs/pbd/pbd/memento_command.h b/libs/pbd/pbd/memento_command.h index 5a385841a6..a46aea0002 100644 --- a/libs/pbd/pbd/memento_command.h +++ b/libs/pbd/pbd/memento_command.h @@ -31,6 +31,56 @@ #include <sigc++/slot.h> #include <typeinfo> +/** A class that can return a Stateful object which is the subject of a MementoCommand. + * + * The existence of this class means that the undo record can refer to objects which + * don't exist in the session file. Currently this is just used for MIDI automation; + * when MIDI automation is edited, undo records are written for the AutomationList being + * changed. However this AutomationList is a temporary structure, built by a MidiModel, + * which doesn't get written to the session file. Hence we need to be able to go from + * a MidiSource and Parameter to an AutomationList. This Binder mechanism allows this + * through MidiAutomationListBinder; the undo record stores the source and parameter, + * and these are bound to an AutomationList by the Binder. + */ +template <class obj_T> +class MementoCommandBinder : public PBD::Destructible +{ +public: + /** @return Stateful object to operate on */ + virtual obj_T* get () = 0; + + /** Add our own state to an XMLNode */ + virtual void add_state (XMLNode *) = 0; +}; + +/** A simple MementoCommandBinder which binds directly to an object */ +template <class obj_T> +class SimpleMementoCommandBinder : public MementoCommandBinder<obj_T> +{ +public: + SimpleMementoCommandBinder (obj_T& o) + : _object (o) + { + _object.Destroyed.connect_same_thread (_object_death_connection, boost::bind (&SimpleMementoCommandBinder::object_died, this)); + } + + obj_T* get () { + return &_object; + } + + void add_state (XMLNode* node) { + node->add_property ("obj_id", _object.id().to_s()); + } + + void object_died () { + this->drop_references (); + } + +private: + obj_T& _object; + PBD::ScopedConnection _object_death_connection; +}; + /** This command class is initialized with before and after mementos * (from Stateful::get_state()), so undo becomes restoring the before * memento, and redo is restoring the after memento. @@ -39,32 +89,38 @@ template <class obj_T> class MementoCommand : public Command { public: - MementoCommand(obj_T& a_object, XMLNode* a_before, XMLNode* a_after) - : obj(a_object), before(a_before), after(a_after) + MementoCommand (obj_T& a_object, XMLNode* a_before, XMLNode* a_after) + : _binder (new SimpleMementoCommandBinder<obj_T> (a_object)), before (a_before), after (a_after) { - /* if the object dies, make sure that we die and that everyone knows about it */ - obj.Destroyed.connect_same_thread (obj_death_connection, boost::bind (&MementoCommand::object_died, this)); + _binder->Destroyed.connect_same_thread (_binder_death_connection, boost::bind (&MementoCommand::binder_died, this)); } + MementoCommand (MementoCommandBinder<obj_T>* b, XMLNode* a_before, XMLNode* a_after) + : _binder (b), before (a_before), after (a_after) + { + _binder->Destroyed.connect_same_thread (_binder_death_connection, boost::bind (&MementoCommand::binder_died, this)); + } + ~MementoCommand () { drop_references (); delete before; delete after; + delete _binder; } - void object_died () { + void binder_died () { delete this; } void operator() () { if (after) { - obj.set_state(*after, Stateful::current_state_version); + _binder->get()->set_state(*after, Stateful::current_state_version); } } void undo() { if (before) { - obj.set_state(*before, Stateful::current_state_version); + _binder->get()->set_state(*before, Stateful::current_state_version); } } @@ -79,9 +135,9 @@ public: } XMLNode* node = new XMLNode(name); - - node->add_property("obj_id", obj.id().to_s()); - node->add_property("type_name", demangled_name (obj)); + _binder->add_state (node); + + node->add_property("type_name", demangled_name (*_binder->get())); if (before) { node->add_child_copy(*before); @@ -95,10 +151,10 @@ public: } protected: - obj_T& obj; + MementoCommandBinder<obj_T>* _binder; XMLNode* before; XMLNode* after; - PBD::ScopedConnection obj_death_connection; + PBD::ScopedConnection _binder_death_connection; }; #endif // __lib_pbd_memento_h__ |