X-Git-Url: https://main.carlh.net/gitweb/?a=blobdiff_plain;f=libs%2Fpbd%2Fpbd%2Fproperties.h;h=e65929c60ce8e234d8ab401637d6882627d32f96;hb=a459f96e38f569503e6d983808210d9d43a396ec;hp=fa8e4cf3eb552d541eb7c2bd972fba51cab865bb;hpb=2221fc139c0cc90b4f529e7d064ae3617c6ffe34;p=ardour.git diff --git a/libs/pbd/pbd/properties.h b/libs/pbd/pbd/properties.h index fa8e4cf3eb..e65929c60c 100644 --- a/libs/pbd/pbd/properties.h +++ b/libs/pbd/pbd/properties.h @@ -30,11 +30,11 @@ #include "pbd/property_basics.h" #include "pbd/property_list.h" #include "pbd/enumwriter.h" +#include "pbd/stateful.h" namespace PBD { -/** Parent class for classes which represent a single scalar property in a Stateful object - */ +/** Parent class for classes which represent a single scalar property in a Stateful object */ template class PropertyTemplate : public PropertyBase { @@ -58,6 +58,9 @@ public: , _current (s._current) {} + + /* OPERATORS / ACCESSORS */ + T & operator=(T const& v) { set (v); return _current; @@ -93,16 +96,9 @@ public: return _current; } - void clear_changes () { - _have_old = false; - } - - 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)); - } + /* MANAGEMENT OF Stateful State */ + bool set_value (XMLNode const & node) { XMLProperty const* p = node.property (property_name()); @@ -123,48 +119,67 @@ public: node.add_property (property_name(), to_string (_current)); } - bool changed () const { return _have_old; } - void apply_changes (PropertyBase const * p) { - T v = dynamic_cast* > (p)->val (); - if (v != _current) { - set (v); - } + /* MANAGEMENT OF HISTORY */ + + void clear_changes () { + _have_old = false; } + bool changed () const { return _have_old; } + void invert () { T const tmp = _current; _current = _old; _old = tmp; } - void get_changes_as_properties (PropertyList& changes, Command *) const { - if (this->_have_old) { + + /* TRANSFERRING HISTORY TO / FROM A StatefulDiffCommand */ + + 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)); + } + + void get_changes_as_properties (PropertyList& changes, Command *) const { + if (this->_have_old) { changes.add (clone ()); - } - } + } + } + + + /* VARIOUS */ + + void apply_changes (PropertyBase const * p) { + T v = dynamic_cast* > (p)->val (); + if (v != _current) { + set (v); + } + } protected: void set (T const& v) { - if (v != _current) { - if (!_have_old) { - _old = _current; - _have_old = true; - } else { - if (v == _old) { - /* value has been reset to the value - at the start of a history transaction, - before clear_changes() is called. - thus there is effectively no apparent - history for this property. - */ - _have_old = false; - } - } - - _current = v; - } + if (v != _current) { + if (!_have_old) { + _old = _current; + _have_old = true; + } else { + if (v == _old) { + /* value has been reset to the value + at the start of a history transaction, + before clear_changes() is called. + thus there is effectively no apparent + history for this property. + */ + _have_old = false; + } + } + + _current = v; + } } virtual std::string to_string (T const& v) const = 0; @@ -210,7 +225,7 @@ public: return new Property (this->property_id(), this->_old, this->_current); } - Property* clone_from_xml (const XMLNode& node) const { + Property* clone_from_xml (const XMLNode& node) const { XMLNodeList const & children = node.children (); XMLNodeList::const_iterator i = children.begin(); while (i != children.end() && (*i)->name() != this->property_name()) { @@ -228,7 +243,7 @@ public: } return new Property (this->property_id(), from_string (from->value()), from_string (to->value ())); - } + } T & operator=(T const& v) { this->set (v); @@ -291,7 +306,7 @@ public: private: std::string to_string (std::string const& v) const { - return _current; + return v; } std::string from_string (std::string const& s) const { @@ -327,7 +342,121 @@ private: /* no copy-construction */ EnumProperty (EnumProperty const &); }; + +/** A Property which holds a shared_ptr to a Stateful object, + * and handles undo using the somewhat inefficient approach + * of saving the complete XML state of its object before and + * after changes. A sort of half-way house between the old + * complete-state undo system and the new difference-based + * one. + */ +template +class SharedStatefulProperty : public PropertyBase +{ +public: + typedef boost::shared_ptr Ptr; + SharedStatefulProperty (PropertyID d, Ptr p) + : PropertyBase (d) + , _current (p) + { + + } + + SharedStatefulProperty (PropertyID d, Ptr o, Ptr c) + : PropertyBase (d) + , _old (o) + , _current (c) + { + + } + + bool set_value (XMLNode const & node) { + + /* Look for our node */ + XMLNode* n = node.child (property_name ()); + if (!n) { + return false; + } + + /* And there should be one child which is the state of our T */ + XMLNodeList const & children = n->children (); + if (children.size() != 1) { + return false; + } + + _current->set_state (*children.front (), Stateful::current_state_version); + return true; + } + + void get_value (XMLNode & node) const { + XMLNode* n = node.add_child (property_name ()); + n->add_child_nocopy (_current->get_state ()); + } + + void clear_changes () { + /* We are starting to change things, so _old gets set up + with the current state. + */ + _old.reset (new T (*_current.get())); + } + + bool changed () const { + /* Expensive, but, hey; this requires operator!= in + our T + */ + return (*_old != *_current); + } + + void invert () { + _current.swap (_old); + } + + void get_changes_as_xml (XMLNode* history_node) const { + /* We express the diff as before and after state, just + as MementoCommand does. + */ + XMLNode* p = history_node->add_child (property_name ()); + XMLNode* from = p->add_child ("from"); + from->add_child_nocopy (_old->get_state ()); + XMLNode* to = p->add_child ("to"); + to->add_child_nocopy (_current->get_state ()); + } + + void get_changes_as_properties (PropertyList& changes, Command *) const { + if (changed ()) { + changes.add (clone ()); + } + } + + void apply_changes (PropertyBase const * p) { + *_current = *(dynamic_cast (p))->val (); + } + + Ptr val () const { + return _current; + } + + T* operator-> () const { + return _current.operator-> (); + } + + operator bool () const { + return _current; + } + +protected: + + Ptr _old; + Ptr _current; + +private: + + /* No copy-construction nor assignment */ + SharedStatefulProperty (SharedStatefulProperty const &); + SharedStatefulProperty& operator= (SharedStatefulProperty const &); +}; + } /* namespace PBD */ #include "pbd/property_list_impl.h"