X-Git-Url: https://main.carlh.net/gitweb/?a=blobdiff_plain;f=libs%2Fpbd%2Fpbd%2Fproperties.h;h=684fc37ffe95d3f4b8e5669047f8ce986f1ee81e;hb=5c51b302cec5942a37f468903c4183b0a6c50695;hp=41a5f748810ffe79b26873b81a91a239a14e8ef4;hpb=21855b71d2eb8006fda96aefacfa60140ae747d3;p=ardour.git diff --git a/libs/pbd/pbd/properties.h b/libs/pbd/pbd/properties.h index 41a5f74881..684fc37ffe 100644 --- a/libs/pbd/pbd/properties.h +++ b/libs/pbd/pbd/properties.h @@ -26,17 +26,18 @@ #include #include +#include "pbd/libpbd_visibility.h" #include "pbd/xml++.h" #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 +class /*LIBPBD_API*/ PropertyTemplate : public PropertyBase { public: PropertyTemplate (PropertyDescriptor p, T const& v) @@ -51,22 +52,30 @@ public: , _current (c) , _old (o) {} - - PropertyTemplate& operator=(PropertyTemplate const& s) { - /* XXX: isn't there a nicer place to do this? */ - _have_old = s._have_old; - _property_id = s._property_id; - _current = s._current; - _old = s._old; - return *this; - } + PropertyTemplate (PropertyDescriptor p, PropertyTemplate const & s) + : PropertyBase (p.property_id) + , _have_old (false) + , _current (s._current) + {} + + + /* OPERATORS / ACCESSORS */ T & operator=(T const& v) { set (v); return _current; } + /* This will mean that, if fred and jim are both PropertyTemplates, + * fred = jim will result in fred taking on jim's current value, + * but NOT jim's property ID. + */ + PropertyTemplate & operator= (PropertyTemplate const & p) { + set (p._current); + return *this; + } + T & operator+=(T const& v) { set (_current + v); return _current; @@ -88,16 +97,9 @@ public: return _current; } - void clear_history () { - _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()); @@ -118,51 +120,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 (); - std::cout << "Apply changes: " << v << " cf " << _current << "\n"; - 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; - std::cout << "Inverted to " << _old << " -> " << _current << "\n"; } -protected: - /** Constructs a PropertyTemplate with a default - value for _old and _current. - */ - PropertyTemplate (PropertyDescriptor p) - : PropertyBase (p.property_id) - {} + /* 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_history() 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; @@ -171,9 +189,15 @@ protected: bool _have_old; T _current; T _old; + +private: + /* disallow copy-construction; it's not obvious whether it should mean + a copy of just the value, or the value and property ID. + */ + PropertyTemplate (PropertyTemplate const &); }; -template +template /*LIBPBD_API*/ std::ostream & operator<<(std::ostream& os, PropertyTemplate const& s) { return os << s.val (); @@ -183,7 +207,7 @@ std::ostream & operator<<(std::ostream& os, PropertyTemplate const& s) * with types that can be written to / read from stringstreams. */ template -class Property : public PropertyTemplate +class /*LIBPBD_API*/ Property : public PropertyTemplate { public: Property (PropertyDescriptor q, T const& v) @@ -194,17 +218,15 @@ public: : PropertyTemplate (q, o, c) {} + Property (PropertyDescriptor q, Property const& v) + : PropertyTemplate (q, v) + {} + Property* clone () const { - return new Property (*this); + return new Property (this->property_id(), this->_old, this->_current); } - void get_changes_as_properties (PropertyList& changes, Command *) const { - if (this->_have_old) { - changes.add (new Property (*this)); - } - } - - Property* maybe_clone_self_if_found_in_history_node (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()) { @@ -222,7 +244,7 @@ public: } return new Property (this->property_id(), from_string (from->value()), from_string (to->value ())); - } + } T & operator=(T const& v) { this->set (v); @@ -232,9 +254,8 @@ public: private: friend class PropertyFactory; - Property (PropertyDescriptor q) - : PropertyTemplate (q) - {} + /* no copy-construction */ + Property (Property const &); /* Note that we do not set a locale for the streams used * in to_string() or from_string(), because we want the @@ -264,41 +285,41 @@ private: * separators, etc. */ template<> -class Property : public PropertyTemplate +class /*LIBPBD_API*/ Property : public PropertyTemplate { public: - Property (PropertyDescriptor q, std::string const& v) - : PropertyTemplate (q, v) + Property (PropertyDescriptor d, std::string const & v) + : PropertyTemplate (d, v) {} + Property (PropertyDescriptor d, std::string const & o, std::string const & c) + : PropertyTemplate (d, o, c) + {} + Property* clone () const { - return new Property (*this); + return new Property (this->property_id(), _old, _current); } - - void get_changes_as_properties (PropertyList& changes, Command* /*ignored*/) const { - if (this->_have_old) { - changes.add (new Property (*this)); - } - } - std::string & operator=(std::string const& v) { + std::string & operator= (std::string const& v) { this->set (v); return this->_current; } private: std::string to_string (std::string const& v) const { - return _current; + return v; } std::string from_string (std::string const& s) const { return s; } + /* no copy-construction */ + Property (Property const &); }; template -class EnumProperty : public Property +class /*LIBPBD_API*/ EnumProperty : public Property { public: EnumProperty (PropertyDescriptor q, T const& v) @@ -318,8 +339,125 @@ private: T from_string (std::string const & s) const { return static_cast (string_2_enum (s, this->_current)); } + + /* 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 /*LIBPBD_API*/ 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 ? true : false; + } + +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"