summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--libs/ardour/ardour/playlist.h4
-rw-r--r--libs/ardour/playlist.cc7
-rw-r--r--libs/pbd/pbd/properties.h76
-rw-r--r--libs/pbd/pbd/property_basics.h22
-rw-r--r--libs/pbd/pbd/property_list.h6
-rw-r--r--libs/pbd/pbd/sequence_property.h81
-rw-r--r--libs/pbd/pbd/stateful.h4
-rw-r--r--libs/pbd/pbd/stateful_diff_command.h3
-rw-r--r--libs/pbd/property_list.cc30
-rw-r--r--libs/pbd/stateful.cc23
-rw-r--r--libs/pbd/stateful_diff_command.cc38
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;
}