X-Git-Url: https://main.carlh.net/gitweb/?a=blobdiff_plain;f=libs%2Fpbd%2Fpbd%2Fproperties.h;h=aeb0c3e0696e83feae1ba06fbfdce04446a61181;hb=f30402d073aeae5d24462416407e73d1e0314e71;hp=931b2676bda687efa5d3c84cc15ac97aa4d44b9c;hpb=fa701b8c065251d242342b86a54d91826d2290a0;p=ardour.git diff --git a/libs/pbd/pbd/properties.h b/libs/pbd/pbd/properties.h index 931b2676bd..aeb0c3e069 100644 --- a/libs/pbd/pbd/properties.h +++ b/libs/pbd/pbd/properties.h @@ -1,5 +1,5 @@ /* - Copyright (C) 2010 Paul Davis + Copyright (C) 2010 Paul Davis This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -24,154 +24,83 @@ #include #include #include -#include +#include #include "pbd/xml++.h" +#include "pbd/property_basics.h" +#include "pbd/property_list.h" +#include "pbd/enumwriter.h" namespace PBD { -typedef GQuark PropertyID; - -template -struct PropertyDescriptor { - PropertyID id; - typedef T value_type; -}; - -class PropertyChange : public std::set -{ - public: - PropertyChange() { } - template PropertyChange(PropertyDescriptor p) { insert (p.id); } - PropertyChange(const PropertyChange& other) : std::set (other) { } - - PropertyChange operator= (const PropertyChange& other) { - clear (); - insert (other.begin(), other.end()); - return *this; - } - - template PropertyChange operator= (PropertyDescriptor p) { - clear (); - insert (p.id); - return *this; - } - - template bool contains (PropertyDescriptor p) const { return find (p.id) != end(); } - - bool contains (const PropertyChange& other) const { - for (const_iterator x = other.begin(); x != other.end(); ++x) { - if (find (*x) != end()) { - return true; - } - } - return false; - } - - void add (PropertyID id) { (void) insert (id); } - void add (const PropertyChange& other) { (void) insert (other.begin(), other.end()); } - template void add (PropertyDescriptor p) { (void) insert (p.id); } -}; - -/** Base (non template) part of Property */ -class PropertyBase -{ -public: - PropertyBase (PropertyID pid) - : _have_old (false) - , _property_id (pid) - { - - } - - /** Forget about any old value for this state */ - void clear_history () { - _have_old = false; - } - - virtual void diff (XMLNode *, XMLNode *) const = 0; - virtual void diff (PropertyChange&) const = 0; - virtual bool set_state (XMLNode const &) = 0; - virtual void add_state (XMLNode &) const = 0; - - const gchar* property_name() const { return g_quark_to_string (_property_id); } - PropertyID id() const { return _property_id; } - - bool operator== (PropertyID pid) const { - return _property_id == pid; - } - -protected: - bool _have_old; - PropertyID _property_id; -}; - -/** Parent class for classes which represent a single property in a Stateful object */ -template +/** Parent class for classes which represent a single scalar property in a Stateful object + */ +template class PropertyTemplate : public PropertyBase { public: - PropertyTemplate (PropertyDescriptor p, T const & v) - : PropertyBase (p.id) + PropertyTemplate (PropertyDescriptor p, T const& v) + : PropertyBase (p.property_id) + , _have_old (false) , _current (v) - { - - } - PropertyTemplate & operator= (PropertyTemplate const & s) { + {} + + PropertyTemplate (PropertyDescriptor p, T const& o, T const& c) + : PropertyBase (p.property_id) + , _have_old (true) + , _current (c) + , _old (o) + {} + + PropertyTemplate& operator=(PropertyTemplate const& s) { /* XXX: isn't there a nicer place to do this? */ - _have_old = s._have_old; + _have_old = s._have_old; _property_id = s._property_id; - + _current = s._current; - _old = s._old; + _old = s._old; return *this; } - T & operator= (T const & v) { + T & operator=(T const& v) { set (v); return _current; } - T & operator+= (T const & v) { + T & operator+=(T const& v) { set (_current + v); return _current; } - - bool operator== (const T& other) const { + + bool operator==(const T& other) const { return _current == other; } - bool operator!= (const T& other) const { + bool operator!=(const T& other) const { return _current != other; } - operator T const & () const { + operator T const &() const { return _current; } - T const & val () const { + T const& val () const { return _current; } - void diff (XMLNode* old, XMLNode* current) const { - if (_have_old) { - old->add_property (property_name(), to_string (_old)); - current->add_property (property_name(), to_string (_current)); - } + void clear_changes () { + _have_old = false; } - - void diff (PropertyChange& c) const { - if (_have_old) { - c.add (_property_id); - } + + 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)); } - /** Try to set state from the property of an XML node. - * @param node XML node. - * @return true if the value of the property is changed - */ - bool set_state (XMLNode const & node) { - XMLProperty const * p = node.property (property_name()); + bool set_value (XMLNode const & node) { + + XMLProperty const* p = node.property (property_name()); if (p) { T const v = from_string (p->value ()); @@ -180,145 +109,220 @@ public: set (v); return true; } - } + } return false; } - void add_state (XMLNode & node) const { - node.add_property (property_name(), to_string (_current)); + void get_value (XMLNode & node) const { + 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); + } + } + + void invert () { + T const tmp = _current; + _current = _old; + _old = tmp; + std::cout << "Inverted to " << _old << " -> " << _current << "\n"; } protected: - void set (T const & v) { - _old = _current; - _have_old = true; - _current = v; + /** Constructs a PropertyTemplate with a default + value for _old and _current. + */ + + PropertyTemplate (PropertyDescriptor p) + : PropertyBase (p.property_id) + {} + + 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; + } } - virtual std::string to_string (T const & v) const = 0; - virtual T from_string (std::string const & s) const = 0; - + virtual std::string to_string (T const& v) const = 0; + virtual T from_string (std::string const& s) const = 0; + + bool _have_old; T _current; T _old; }; -template -std::ostream& operator<< (std::ostream& os, PropertyTemplate const & s) +template +std::ostream & operator<<(std::ostream& os, PropertyTemplate const& s) { - return os << s.val(); + return os << s.val (); } -/** Representation of a single piece of state in a Stateful; for use +/** Representation of a single piece of scalar state in a Stateful; for use * with types that can be written to / read from stringstreams. */ -template +template class Property : public PropertyTemplate { public: - Property (PropertyDescriptor q, T const & v) + Property (PropertyDescriptor q, T const& v) : PropertyTemplate (q, v) - { + {} + + Property (PropertyDescriptor q, T const& o, T const& c) + : PropertyTemplate (q, o, c) + {} + Property* clone () const { + return new Property (*this); } - T & operator= (T const & v) { + void get_changes_as_properties (PropertyList& changes, Command *) const { + if (this->_have_old) { + changes.add (new Property (*this)); + } + } + + 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()) { + ++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 (this->property_id(), from_string (from->value()), from_string (to->value ())); + } + + T & operator=(T const& v) { this->set (v); return this->_current; } - -private: - /* note that we do not set a locale for the streams used - in to_string() or from_string(), because we want the - format to be portable across locales (i.e. C or - POSIX). Also, there is the small matter of - std::locale aborting on OS X if used with anything - other than C or POSIX locales. - */ - std::string to_string (T const & v) const { + +private: + friend class PropertyFactory; + + Property (PropertyDescriptor q) + : PropertyTemplate (q) + {} + + /* Note that we do not set a locale for the streams used + * in to_string() or from_string(), because we want the + * format to be portable across locales (i.e. C or + * POSIX). Also, there is the small matter of + * std::locale aborting on OS X if used with anything + * other than C or POSIX locales. + */ + virtual std::string to_string (T const& v) const { std::stringstream s; s.precision (12); // in case its floating point s << v; return s.str (); } - - T from_string (std::string const & s) const { + + virtual T from_string (std::string const& s) const { std::stringstream t (s); - T v; + T v; t >> v; return v; } + }; /** Specialization, for std::string which is common and special (see to_string() and from_string() - Using stringstream to read from a std::string is easy to get wrong because of whitespace - delineation, etc. + * Using stringstream to read from a std::string is easy to get wrong because of whitespace + * separators, etc. */ -template <> +template<> class Property : public PropertyTemplate { public: - Property (PropertyDescriptor q, std::string const & v) + Property (PropertyDescriptor q, std::string const& v) : PropertyTemplate (q, v) - { + {} + Property* clone () const { + return new Property (*this); } + + 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 { + +private: + std::string to_string (std::string const& v) const { return _current; } - - std::string from_string (std::string const & s) const { + + std::string from_string (std::string const& s) const { return s; } + }; -class PropertyList : public std::map +template +class EnumProperty : public Property { public: - PropertyList() : property_owner (true) {} - virtual ~PropertyList() { - if (property_owner) - for (std::map::iterator i = begin(); i != end(); ++i) { - delete i->second; - } - } - /* classes that own property lists use this to add their - property members to their plists. - */ - bool add (PropertyBase& p) { - return insert (value_type (p.id(), &p)).second; - } - - /* code that is constructing a property list for use - in setting the state of an object uses this. - */ - template bool add (PropertyDescriptor pid, const V& v) { - return insert (value_type (pid.id, new Property (pid, (T) v))).second; - } + EnumProperty (PropertyDescriptor q, T const& v) + : Property (q, v) + {} -protected: - bool property_owner; -}; + T & operator=(T const& v) { + this->set (v); + return this->_current; + } -/** A variant of PropertyList that does not delete its - property list in its destructor. Objects with their - own Properties store them in an OwnedPropertyList - to avoid having them deleted at the wrong time. -*/ +private: + std::string to_string (T const & v) const { + return enum_2_string (v); + } -class OwnedPropertyList : public PropertyList -{ -public: - OwnedPropertyList() { property_owner = false; } + T from_string (std::string const & s) const { + return static_cast (string_2_enum (s, this->_current)); + } }; - + } /* namespace PBD */ +#include "pbd/property_list_impl.h" +#include "pbd/property_basics_impl.h" + #endif /* __pbd_properties_h__ */