Allow cross-thread request invalidators to cope with multiple requests
[ardour.git] / libs / pbd / pbd / properties.h
index 1c3519766ff7a0e32bef4fb400ad329667fe45b6..784282ee9c55d0228411e5e538843af9c9cb0bea 100644 (file)
 #include <glib.h>
 
 #include "pbd/xml++.h"
+#include "pbd/property_basics.h"
+#include "pbd/property_list.h"
 
 namespace PBD {
 
-typedef GQuark PropertyID;
-
-template<typename T>
-struct PropertyDescriptor {
-       PropertyID id;
-       typedef T value_type;
-};
-
-class PropertyChange : public std::set<PropertyID>
-{
-public:
-       PropertyChange() {}
-
-       template<typename T>
-       PropertyChange(PropertyDescriptor<T> p) { insert (p.id); }
-
-       PropertyChange(const PropertyChange& other) : std::set<PropertyID> (other) {}
-
-       PropertyChange operator=(const PropertyChange& other) {
-               clear ();
-               insert (other.begin (), other.end ());
-               return *this;
-       }
-
-       template<typename T>
-       PropertyChange operator=(PropertyDescriptor<T> p) {
-               clear ();
-               insert (p.id);
-               return *this;
-       }
-
-       template<typename T>
-       bool contains (PropertyDescriptor<T> 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<typename T>
-       void add (PropertyDescriptor<T> p) { (void)insert (p.id); }
-};
-
-/** Base (non template) part of Property */
-class PropertyBase
-{
-public:
-       PropertyBase (PropertyID pid)
-               : _property_id (pid)
-               , _have_old (false)
-       {}
-
-       /** 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:
-       PropertyID _property_id;
-       bool       _have_old;
-};
-
-/** Parent class for classes which represent a single property in a Stateful object */
+/** Parent class for classes which represent a single scalar property in a Stateful object 
+ */
 template<class T>
 class PropertyTemplate : public PropertyBase
 {
 public:
        PropertyTemplate (PropertyDescriptor<T> p, T const& v)
-               : PropertyBase (p.id)
+               : PropertyBase (p.property_id)
+               , _have_old (false)
                , _current (v)
        {}
 
@@ -156,25 +80,24 @@ public:
                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_history () {
+               _have_old = false;
        }
 
-       void diff (PropertyChange& c) const {
-               if (_have_old) {
-                       c.add (_property_id);
-               }
+       void add_history_state (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));
        }
 
        /** 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_state_from_owner_state (XMLNode const& owner_state) {
+
+               XMLProperty const* p = owner_state.property (property_name());
 
                if (p) {
                        T const v = from_string (p->value ());
@@ -188,20 +111,39 @@ public:
                return false;
        }
 
-       void add_state (XMLNode& node) const {
-               node.add_property (property_name (), to_string (_current));
+       void add_state_to_owner_state (XMLNode& owner_state) const {
+                owner_state.add_property (property_name(), to_string (_current));
+       }
+
+       bool changed () const { return _have_old; }
+       void set_state_from_property (PropertyBase const * p) {
+               T v = dynamic_cast<const PropertyTemplate<T>* > (p)->val ();
+               if (v != _current) {
+                       set (v);
+               }
        }
 
 protected:
+        /** Constructs a PropertyTemplate with a default
+            value for _old and _current.
+        */
+
+       PropertyTemplate (PropertyDescriptor<T> p)
+               : PropertyBase (p.property_id)
+       {}
+
        void set (T const& v) {
-               _old      = _current;
-               _have_old = true;
+                if (!_have_old) {
+                        _old      = _current;
+                        _have_old = true;
+                }
                _current  = v;
        }
 
        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;
 };
@@ -212,7 +154,7 @@ std::ostream & operator<<(std::ostream& os, PropertyTemplate<T> const& s)
        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<class T>
@@ -222,6 +164,21 @@ public:
        Property (PropertyDescriptor<T> q, T const& v)
                : PropertyTemplate<T> (q, v)
        {}
+        
+        void diff (PropertyList& undo, PropertyList& redo) 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));
+                }
+        }
+
+        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()));
+        }
 
        T & operator=(T const& v) {
                this->set (v);
@@ -229,6 +186,12 @@ public:
        }
 
 private:
+        friend class PropertyFactory;
+
+       Property (PropertyDescriptor<T> q)
+               : PropertyTemplate<T> (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
@@ -254,7 +217,7 @@ private:
 
 /** 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.
+ *  separators, etc.
  */
 template<>
 class Property<std::string> : public PropertyTemplate<std::string>
@@ -264,6 +227,13 @@ public:
                : PropertyTemplate<std::string> (q, v)
        {}
 
+        void diff (PropertyList& before, PropertyList& after) 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));
+                }
+        }
+
        std::string & operator=(std::string const& v) {
                this->set (v);
                return this->_current;
@@ -280,48 +250,9 @@ private:
 
 };
 
-class PropertyList : public std::map<PropertyID, PropertyBase*>
-{
-public:
-       PropertyList() : _property_owner (true) {}
-       virtual ~PropertyList() {
-               if (_property_owner) {
-                       for (std::map<PropertyID, PropertyBase*>::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<typename T, typename V>
-       bool add (PropertyDescriptor<T> pid, const V& v) {
-               return insert (value_type (pid.id, new Property<T> (pid, (T)v))).second;
-       }
-
-protected:
-       bool _property_owner;
-};
-
-/** 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.
- */
-class OwnedPropertyList : public PropertyList
-{
-public:
-       OwnedPropertyList() { _property_owner = false; }
-};
-
 } /* namespace PBD */
 
+#include "pbd/property_list_impl.h"
+#include "pbd/property_basics_impl.h"
+
 #endif /* __pbd_properties_h__ */