diff options
author | Carl Hetherington <carl@carlh.net> | 2010-08-25 17:31:57 +0000 |
---|---|---|
committer | Carl Hetherington <carl@carlh.net> | 2010-08-25 17:31:57 +0000 |
commit | 21855b71d2eb8006fda96aefacfa60140ae747d3 (patch) | |
tree | a5a5148ef41be377a0670bf708845b7197baf5d4 /libs | |
parent | 803f3a6a307bea4bdd804041a0e0a846f48938ee (diff) |
Modify StatefulDiffCommand undo record to only contain the changes in one direction, as the other direction can be inferred. Breaks session history file compatibility.
git-svn-id: svn://localhost/ardour2/branches/3.0@7684 d708f5d6-7413-0410-9779-e7cbd77b26cf
Diffstat (limited to 'libs')
-rw-r--r-- | libs/ardour/ardour/playlist.h | 4 | ||||
-rw-r--r-- | libs/ardour/playlist.cc | 7 | ||||
-rw-r--r-- | libs/pbd/pbd/properties.h | 76 | ||||
-rw-r--r-- | libs/pbd/pbd/property_basics.h | 22 | ||||
-rw-r--r-- | libs/pbd/pbd/property_list.h | 6 | ||||
-rw-r--r-- | libs/pbd/pbd/sequence_property.h | 81 | ||||
-rw-r--r-- | libs/pbd/pbd/stateful.h | 4 | ||||
-rw-r--r-- | libs/pbd/pbd/stateful_diff_command.h | 3 | ||||
-rw-r--r-- | libs/pbd/property_list.cc | 30 | ||||
-rw-r--r-- | libs/pbd/stateful.cc | 23 | ||||
-rw-r--r-- | libs/pbd/stateful_diff_command.cc | 38 |
11 files changed, 173 insertions, 121 deletions
diff --git a/libs/ardour/ardour/playlist.h b/libs/ardour/ardour/playlist.h index b60fa62879..50ddd22469 100644 --- a/libs/ardour/ardour/playlist.h +++ b/libs/ardour/ardour/playlist.h @@ -63,10 +63,12 @@ class RegionListProperty : public PBD::SequenceProperty<std::list<boost::shared_ public: RegionListProperty (Playlist&); + RegionListProperty* clone () const; + boost::shared_ptr<Region> lookup_id (const PBD::ID& id); private: - PBD::SequenceProperty<std::list<boost::shared_ptr<Region> > >* create () const; + RegionListProperty* create () const; friend class Playlist; /* we live and die with our playlist, no lifetime management needed */ diff --git a/libs/ardour/playlist.cc b/libs/ardour/playlist.cc index 2062f343d9..e6b8abf21a 100644 --- a/libs/ardour/playlist.cc +++ b/libs/ardour/playlist.cc @@ -124,7 +124,12 @@ RegionListProperty::lookup_id (const ID& id) return ret; } -SequenceProperty<std::list<boost::shared_ptr<Region> > >* RegionListProperty::create () const +RegionListProperty* RegionListProperty::clone () const +{ + return new RegionListProperty (*this); +} + +RegionListProperty* RegionListProperty::create () const { return new RegionListProperty (_playlist); } diff --git a/libs/pbd/pbd/properties.h b/libs/pbd/pbd/properties.h index 13790973e2..41a5f74881 100644 --- a/libs/pbd/pbd/properties.h +++ b/libs/pbd/pbd/properties.h @@ -24,7 +24,7 @@ #include <sstream> #include <list> #include <set> -#include <glib.h> +#include <iostream> #include "pbd/xml++.h" #include "pbd/property_basics.h" @@ -45,6 +45,13 @@ public: , _current (v) {} + PropertyTemplate (PropertyDescriptor<T> p, T const& o, T const& c) + : PropertyBase (p.property_id) + , _have_old (true) + , _current (c) + , _old (o) + {} + PropertyTemplate<T>& operator=(PropertyTemplate<T> const& s) { /* XXX: isn't there a nicer place to do this? */ _have_old = s._have_old; @@ -85,11 +92,10 @@ public: _have_old = false; } - void get_change (XMLNode* history_node) const { - /* We can get to the current state of a scalar property like this one simply - by knowing what the new state is. - */ - history_node->add_property (property_name(), to_string (_current)); + void get_changes_as_xml (XMLNode* history_node) const { + XMLNode* node = history_node->add_child (property_name()); + node->add_property ("from", to_string (_old)); + node->add_property ("to", to_string (_current)); } bool set_value (XMLNode const & node) { @@ -114,13 +120,21 @@ public: bool changed () const { return _have_old; } - void apply_change (PropertyBase const * p) { + void apply_changes (PropertyBase const * p) { T v = dynamic_cast<const PropertyTemplate<T>* > (p)->val (); + std::cout << "Apply changes: " << v << " cf " << _current << "\n"; if (v != _current) { set (v); } } + void invert () { + T const tmp = _current; + _current = _old; + _old = tmp; + std::cout << "Inverted to " << _old << " -> " << _current << "\n"; + } + protected: /** Constructs a PropertyTemplate with a default value for _old and _current. @@ -175,20 +189,39 @@ public: Property (PropertyDescriptor<T> q, T const& v) : PropertyTemplate<T> (q, v) {} - - void diff (PropertyList& undo, PropertyList& redo, Command* /*ignored*/) const { + + Property (PropertyDescriptor<T> q, T const& o, T const& c) + : PropertyTemplate<T> (q, o, c) + {} + + Property<T>* clone () const { + return new Property<T> (*this); + } + + void get_changes_as_properties (PropertyList& changes, Command *) const { if (this->_have_old) { - undo.add (new Property<T> (this->property_id(), this->_old)); - redo.add (new Property<T> (this->property_id(), this->_current)); + changes.add (new Property<T> (*this)); } } Property<T>* maybe_clone_self_if_found_in_history_node (const XMLNode& node) const { - const XMLProperty* prop = node.property (this->property_name()); - if (!prop) { - return 0; - } - return new Property<T> (this->property_id(), from_string (prop->value())); + XMLNodeList const & children = node.children (); + XMLNodeList::const_iterator i = children.begin(); + while (i != children.end() && (*i)->name() != this->property_name()) { + ++i; + } + + if (i == children.end()) { + return 0; + } + XMLProperty* from = (*i)->property ("from"); + XMLProperty* to = (*i)->property ("to"); + + if (!from || !to) { + return 0; + } + + return new Property<T> (this->property_id(), from_string (from->value()), from_string (to->value ())); } T & operator=(T const& v) { @@ -238,11 +271,14 @@ public: : PropertyTemplate<std::string> (q, v) {} - void diff (PropertyList& before, PropertyList& after, Command* /*ignored*/) const { + Property<std::string>* clone () const { + return new Property<std::string> (*this); + } + + void get_changes_as_properties (PropertyList& changes, Command* /*ignored*/) const { if (this->_have_old) { - before.add (new Property<std::string> (PropertyDescriptor<std::string> (this->property_id()), this->_old)); - after.add (new Property<std::string> (PropertyDescriptor<std::string> (this->property_id()), this->_current)); - } + changes.add (new Property<std::string> (*this)); + } } std::string & operator=(std::string const& v) { diff --git a/libs/pbd/pbd/property_basics.h b/libs/pbd/pbd/property_basics.h index 433a25a59b..f329916284 100644 --- a/libs/pbd/pbd/property_basics.h +++ b/libs/pbd/pbd/property_basics.h @@ -87,6 +87,8 @@ public: {} virtual ~PropertyBase () {} + + virtual PropertyBase* clone () const = 0; /** Forget about any old value for this state */ virtual void clear_history () = 0; @@ -94,15 +96,10 @@ public: /** Tell any things we own to forget about their old values */ virtual void clear_owned_history () {} - /** Get any change in this property as XML and add it to a node */ - virtual void get_change (XMLNode *) const = 0; - - /** Add information to two property lists: one that allows - * undo of the changes in this property's state betwen now and - * the last call to clear_history, and one that allows redo - * of those changes. - */ - virtual void diff (PropertyList& undo, PropertyList& redo, Command*) const = 0; + /** Get any changes in this property as XML and add it to a node */ + virtual void get_changes_as_xml (XMLNode *) const = 0; + + virtual void get_changes_as_properties (PropertyList& changes, Command *) const = 0; /** Collect StatefulDiffCommands for changes to anything that we own */ virtual void rdiff (std::vector<StatefulDiffCommand*> &) const {} @@ -122,8 +119,11 @@ public: */ virtual bool changed() const = 0; - /** Apply a change contained in another Property to this one */ - virtual void apply_change (PropertyBase const *) = 0; + /** Apply changes contained in another Property to this one */ + virtual void apply_changes (PropertyBase const *) = 0; + + /** Invert the changes in this property */ + virtual void invert () = 0; const gchar*property_name () const { return g_quark_to_string (_property_id); } PropertyID property_id () const { return _property_id; } diff --git a/libs/pbd/pbd/property_list.h b/libs/pbd/pbd/property_list.h index 04112bad80..12b7995009 100644 --- a/libs/pbd/pbd/property_list.h +++ b/libs/pbd/pbd/property_list.h @@ -32,11 +32,13 @@ namespace PBD { class PropertyList : public std::map<PropertyID, PropertyBase*> { public: - PropertyList(); + PropertyList (); + PropertyList (PropertyList const &); virtual ~PropertyList(); - void get_changes (XMLNode *); + void get_changes_as_xml (XMLNode *); + void invert (); /** Add a property (of some kind) to the list. Used when constructing PropertyLists that describe a change/operation. diff --git a/libs/pbd/pbd/sequence_property.h b/libs/pbd/pbd/sequence_property.h index 0077410421..573bb4b539 100644 --- a/libs/pbd/pbd/sequence_property.h +++ b/libs/pbd/pbd/sequence_property.h @@ -79,37 +79,29 @@ class SequenceProperty : public PropertyBase SequenceProperty (PropertyID id, const boost::function<void(const ChangeRecord&)>& update) : PropertyBase (id), _update_callback (update) {} - - virtual typename Container::value_type lookup_id (const PBD::ID&) = 0; - - void invert_changes () { - /* reverse the adds/removes so that this property's change member - correctly describes how to undo the changes it currently - reflects. A derived instance of this type of property will - create a diff() pair by copying the property twice, and - calling this method on the "before" item of the pair. - */ + virtual typename Container::value_type lookup_id (const PBD::ID&) = 0; - _change.removed.swap (_change.added); + void invert () { + _changes.removed.swap (_changes.added); } - void get_change (XMLNode* history_node) const { + void get_changes_as_xml (XMLNode* history_node) const { XMLNode* child = new XMLNode (PBD::capitalize (property_name())); history_node->add_child_nocopy (*child); /* record the change described in our change member */ - if (!_change.added.empty()) { - for (typename ChangeContainer::iterator i = _change.added.begin(); i != _change.added.end(); ++i) { + if (!_changes.added.empty()) { + for (typename ChangeContainer::iterator i = _changes.added.begin(); i != _changes.added.end(); ++i) { XMLNode* add_node = new XMLNode ("Add"); child->add_child_nocopy (*add_node); add_node->add_property ("id", (*i)->id().to_s()); } } - if (!_change.removed.empty()) { - for (typename ChangeContainer::iterator i = _change.removed.begin(); i != _change.removed.end(); ++i) { + if (!_changes.removed.empty()) { + for (typename ChangeContainer::iterator i = _changes.removed.begin(); i != _changes.removed.end(); ++i) { XMLNode* remove_node = new XMLNode ("Remove"); child->add_child_nocopy (*remove_node); remove_node->add_property ("id", (*i)->id().to_s()); @@ -130,16 +122,16 @@ class SequenceProperty : public PropertyBase } bool changed () const { - return !_change.added.empty() || !_change.removed.empty(); + return !_changes.added.empty() || !_changes.removed.empty(); } void clear_history () { - _change.added.clear (); - _change.removed.clear (); + _changes.added.clear (); + _changes.removed.clear (); } - void apply_change (PropertyBase const * p) { - const ChangeRecord& change (dynamic_cast<const SequenceProperty*> (p)->change ()); + void apply_changes (PropertyBase const * p) { + const ChangeRecord& change (dynamic_cast<const SequenceProperty*> (p)->changes ()); update (change); } @@ -154,14 +146,10 @@ class SequenceProperty : public PropertyBase _update_callback (cr); } - void diff (PBD::PropertyList& undo, PBD::PropertyList& redo, Command* cmd) const { + void get_changes_as_properties (PBD::PropertyList& changes, Command* cmd) const { if (changed ()) { - /* list of the removed/added items since clear_history() was last called */ SequenceProperty<Container>* a = copy_for_history (); - - /* the same list, but with removed/added lists swapped (for undo purposes) */ - SequenceProperty<Container>* b = copy_for_history (); - b->invert_changes (); + changes.add (a); if (cmd) { /* whenever one of the items emits DropReferences, make sure @@ -170,13 +158,10 @@ class SequenceProperty : public PropertyBase with this diff(). */ - for (typename ChangeContainer::iterator i = a->change().added.begin(); i != a->change().added.end(); ++i) { + for (typename ChangeContainer::iterator i = a->changes().added.begin(); i != a->changes().added.end(); ++i) { (*i)->DropReferences.connect_same_thread (*cmd, boost::bind (&Destructible::drop_references, cmd)); } } - - undo.add (b); - redo.add (a); } } @@ -190,7 +175,7 @@ class SequenceProperty : public PropertyBase SequenceProperty<Container>* p = create (); - if (p->set_change (**i)) { + if (p->set_changes (**i)) { return p; } else { delete p; @@ -232,51 +217,51 @@ class SequenceProperty : public PropertyBase typename Container::const_reverse_iterator rend() const { return _val.rend(); } typename Container::iterator insert (typename Container::iterator i, const typename Container::value_type& v) { - _change.add (v); + _changes.add (v); return _val.insert (i, v); } typename Container::iterator erase (typename Container::iterator i) { if (i != _val.end()) { - _change.remove (*i); + _changes.remove (*i); } return _val.erase (i); } typename Container::iterator erase (typename Container::iterator f, typename Container::iterator l) { for (typename Container::const_iterator i = f; i != l; ++i) { - _change.remove (*i); + _changes.remove (*i); } return _val.erase (f, l); } void push_back (const typename Container::value_type& v) { - _change.add (v); + _changes.add (v); _val.push_back (v); } void push_front (const typename Container::value_type& v) { - _change.add (v); + _changes.add (v); _val.push_front (v); } void pop_front () { if (!_val.empty()) { - _change.remove (front()); + _changes.remove (front()); } _val.pop_front (); } void pop_back () { if (!_val.empty()) { - _change.remove (back()); + _changes.remove (back()); } _val.pop_back (); } void clear () { for (typename Container::iterator i = _val.begin(); i != _val.end(); ++i) { - _change.remove (*i); + _changes.remove (*i); } _val.clear (); } @@ -291,10 +276,10 @@ class SequenceProperty : public PropertyBase Container& operator= (const Container& other) { for (typename Container::iterator i = _val.begin(); i != _val.end(); ++i) { - _change.remove (*i); + _changes.remove (*i); } for (typename Container::iterator i = other.begin(); i != other.end(); ++i) { - _change.add (*i); + _changes.add (*i); } return _val = other; } @@ -323,18 +308,18 @@ class SequenceProperty : public PropertyBase _val.sort (comp); } - const ChangeRecord& change() const { return _change; } + const ChangeRecord& changes () const { return _changes; } protected: Container _val; - ChangeRecord _change; + ChangeRecord _changes; boost::function<void(const ChangeRecord&)> _update_callback; /** Load serialized change history. * @return true if loading succeeded, false otherwise */ - bool set_change (XMLNode const & history_node) { + bool set_changes (XMLNode const & history_node) { const XMLNodeList& children (history_node.children()); @@ -348,9 +333,9 @@ class SequenceProperty : public PropertyBase return false; } if ((*i)->name() == "Add") { - _change.added.insert (v); + _changes.added.insert (v); } else if ((*i)->name() == "Remove") { - _change.removed.insert (v); + _changes.removed.insert (v); } } } @@ -370,7 +355,7 @@ private: SequenceProperty<Container>* copy_for_history () const { SequenceProperty<Container>* copy = create (); /* this is all we need */ - copy->_change = _change; + copy->_changes = _changes; return copy; } }; diff --git a/libs/pbd/pbd/stateful.h b/libs/pbd/pbd/stateful.h index af26caab07..050540dcd1 100644 --- a/libs/pbd/pbd/stateful.h +++ b/libs/pbd/pbd/stateful.h @@ -49,7 +49,7 @@ class Stateful { virtual XMLNode& get_state (void) = 0; virtual int set_state (const XMLNode&, int version) = 0; - virtual bool apply_change (PropertyBase const &); + virtual bool apply_changes (PropertyBase const &); PropertyChange apply_changes (PropertyList const &); const OwnedPropertyList& properties() const { return *_properties; } @@ -69,7 +69,7 @@ class Stateful { void clear_history (); virtual void clear_owned_history (); - void diff (PropertyList&, PropertyList&, Command*) const; + PropertyList* get_changes_as_properties (Command *) const; virtual void rdiff (std::vector<StatefulDiffCommand*> &) const; bool changed() const; diff --git a/libs/pbd/pbd/stateful_diff_command.h b/libs/pbd/pbd/stateful_diff_command.h index 25cdfbba12..2d5c234d76 100644 --- a/libs/pbd/pbd/stateful_diff_command.h +++ b/libs/pbd/pbd/stateful_diff_command.h @@ -47,8 +47,7 @@ public: private: boost::weak_ptr<Stateful> _object; ///< the object in question - PBD::PropertyList* _undo; ///< its (partial) state before the command, to allow undo - PBD::PropertyList* _redo; ///< its (partial) state after the operation, to allow redo + PBD::PropertyList* _changes; ///< property changes to execute this command }; }; diff --git a/libs/pbd/property_list.cc b/libs/pbd/property_list.cc index 5c0de4bacf..efae95e45e 100644 --- a/libs/pbd/property_list.cc +++ b/libs/pbd/property_list.cc @@ -27,6 +27,20 @@ using namespace PBD; PropertyList::PropertyList() : _property_owner (true) { + +} + +PropertyList::PropertyList (PropertyList const & other) + : std::map<PropertyID, PropertyBase*> (other) + , _property_owner (other._property_owner) +{ + if (_property_owner) { + /* make our own copies of the properties */ + clear (); + for (std::map<PropertyID, PropertyBase*>::const_iterator i = other.begin(); i != other.end(); ++i) { + insert (std::make_pair (i->first, i->second->clone ())); + } + } } PropertyList::~PropertyList () @@ -39,13 +53,13 @@ PropertyList::~PropertyList () } void -PropertyList::get_changes (XMLNode* history_node) +PropertyList::get_changes_as_xml (XMLNode* history_node) { for (const_iterator i = begin(); i != end(); ++i) { - DEBUG_TRACE (DEBUG::Properties, string_compose ("Add before/after to %1 for %2\n", + DEBUG_TRACE (DEBUG::Properties, string_compose ("Add changes to %1 for %2\n", history_node->name(), i->second->property_name())); - i->second->get_change (history_node); + i->second->get_changes_as_xml (history_node); } } @@ -53,7 +67,15 @@ bool PropertyList::add (PropertyBase* prop) { return insert (value_type (prop->property_id(), prop)).second; -} +} + +void +PropertyList::invert () +{ + for (iterator i = begin(); i != end(); ++i) { + i->second->invert (); + } +} OwnedPropertyList::OwnedPropertyList () { diff --git a/libs/pbd/stateful.cc b/libs/pbd/stateful.cc index 6ea8f19128..204e62685e 100644 --- a/libs/pbd/stateful.cc +++ b/libs/pbd/stateful.cc @@ -166,12 +166,16 @@ Stateful::clear_history () } } -void -Stateful::diff (PropertyList& before, PropertyList& after, Command* cmd) const +PropertyList * +Stateful::get_changes_as_properties (Command* cmd) const { + PropertyList* pl = new PropertyList; + for (OwnedPropertyList::const_iterator i = _properties->begin(); i != _properties->end(); ++i) { - i->second->diff (before, after, cmd); + i->second->get_changes_as_properties (*pl, cmd); } + + return pl; } /** Set our property values from an XML node. @@ -209,8 +213,13 @@ Stateful::apply_changes (const PropertyList& property_list) for (PropertyList::const_iterator i = property_list.begin(); i != property_list.end(); ++i) { if ((p = _properties->find (i->first)) != _properties->end()) { - DEBUG_TRACE (DEBUG::Stateful, string_compose ("actually setting property %1\n", p->second->property_name())); - if (apply_change (*i->second)) { + + DEBUG_TRACE ( + DEBUG::Stateful, + string_compose ("actually setting property %1 using %2\n", p->second->property_name(), i->second->property_name()) + ); + + if (apply_changes (*i->second)) { c.add (i->first); } } else { @@ -303,14 +312,14 @@ Stateful::changed() const } bool -Stateful::apply_change (const PropertyBase& prop) +Stateful::apply_changes (const PropertyBase& prop) { OwnedPropertyList::iterator i = _properties->find (prop.property_id()); if (i == _properties->end()) { return false; } - i->second->apply_change (&prop); + i->second->apply_changes (&prop); return true; } diff --git a/libs/pbd/stateful_diff_command.cc b/libs/pbd/stateful_diff_command.cc index 857235b803..ffd56c8fb1 100644 --- a/libs/pbd/stateful_diff_command.cc +++ b/libs/pbd/stateful_diff_command.cc @@ -34,10 +34,9 @@ using namespace PBD; StatefulDiffCommand::StatefulDiffCommand (boost::shared_ptr<StatefulDestructible> s) : _object (s) - , _undo (new PropertyList) - , _redo (new PropertyList) + , _changes (0) { - s->diff (*_undo, *_redo, this); + _changes = s->get_changes_as_properties (this); /* if the stateful object that this command refers to goes away, be sure to notify owners of this command. @@ -48,21 +47,17 @@ StatefulDiffCommand::StatefulDiffCommand (boost::shared_ptr<StatefulDestructible StatefulDiffCommand::StatefulDiffCommand (boost::shared_ptr<StatefulDestructible> s, XMLNode const & n) : _object (s) - , _undo (0) - , _redo (0) + , _changes (0) { const XMLNodeList& children (n.children()); for (XMLNodeList::const_iterator i = children.begin(); i != children.end(); ++i) { - if ((*i)->name() == X_("Undo")) { - _undo = s->property_factory (**i); - } else if ((*i)->name() == X_("Do")) { - _redo = s->property_factory (**i); + if ((*i)->name() == X_("Changes")) { + _changes = s->property_factory (**i); } - } + } - assert (_undo != 0); - assert (_redo != 0); + assert (_changes != 0); /* if the stateful object that this command refers to goes away, be sure to notify owners of this command. @@ -75,8 +70,7 @@ StatefulDiffCommand::~StatefulDiffCommand () { drop_references (); - delete _undo; - delete _redo; + delete _changes; } void @@ -85,7 +79,7 @@ StatefulDiffCommand::operator() () boost::shared_ptr<Stateful> s (_object.lock()); if (s) { - s->apply_changes (*_redo); + s->apply_changes (*_changes); } } @@ -95,8 +89,9 @@ StatefulDiffCommand::undo () boost::shared_ptr<Stateful> s (_object.lock()); if (s) { - std::cerr << "Undoing a stateful diff command\n"; - s->apply_changes (*_undo); + PropertyList p = *_changes; + p.invert (); + s->apply_changes (p); } } @@ -115,14 +110,11 @@ StatefulDiffCommand::get_state () node->add_property ("obj-id", s->id().to_s()); node->add_property ("type-name", demangled_name (*s.get())); - XMLNode* undo = new XMLNode (X_("Undo")); - XMLNode* redo = new XMLNode (X_("Do")); + XMLNode* changes = new XMLNode (X_("Changes")); - _undo->get_changes (undo); - _redo->get_changes (redo); + _changes->get_changes_as_xml (changes); - node->add_child_nocopy (*undo); - node->add_child_nocopy (*redo); + node->add_child_nocopy (*changes); return *node; } |