clear_history -> clear_changes and some comments.
[ardour.git] / libs / pbd / pbd / properties.h
index 274dfffd9c327150e19da26b42276646d551f614..aeb0c3e0696e83feae1ba06fbfdce04446a61181 100644 (file)
 #include <sstream>
 #include <list>
 #include <set>
-#include <glib.h>
+#include <iostream>
 
 #include "pbd/xml++.h"
 #include "pbd/property_basics.h"
 #include "pbd/property_list.h"
+#include "pbd/enumwriter.h"
 
 namespace PBD {
 
@@ -40,9 +41,17 @@ class PropertyTemplate : public PropertyBase
 public:
        PropertyTemplate (PropertyDescriptor<T> p, T const& v)
                : PropertyBase (p.property_id)
+               , _have_old (false)
                , _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;
@@ -79,22 +88,19 @@ public:
                return _current;
        }
 
-        /** If this property has been changed since the last clear_history() call
-            (or its construction), add an (XML) property describing the old value 
-            to the XMLNode @param old and another describing the current value to
-            the XMLNode @param current.
-        */
-       void add_history_state (XMLNode* history_node) const {
-                history_node->add_property (property_name(), to_string (_current));
+       void clear_changes () {
+               _have_old = false;
        }
 
-       /** 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_from_owner_state (XMLNode const& owner_state) {
+       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));
+       }
 
-               XMLProperty const* p = owner_state.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 ());
@@ -108,8 +114,25 @@ public:
                return false;
        }
 
-       void add_state_to_owner_state (XMLNode& owner_state) const {
-                owner_state.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<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:
@@ -122,14 +145,30 @@ protected:
        {}
 
        void set (T const& v) {
-               _old      = _current;
-               _have_old = true;
-               _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;
        virtual T           from_string (std::string const& s) const = 0;
 
+       bool _have_old;
        T _current;
        T _old;
 };
@@ -150,20 +189,39 @@ public:
        Property (PropertyDescriptor<T> q, T const& v)
                : PropertyTemplate<T> (q, v)
        {}
-        
-        void diff (PropertyList& before, PropertyList& after) 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) {
-                        before.add (new Property<T> (this->property_id(), this->_old));
-                        after.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()));
+        Property<T>* 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<T> (this->property_id(), from_string (from->value()), from_string (to->value ()));
         }
 
        T & operator=(T const& v) {
@@ -185,14 +243,14 @@ private:
         * std::locale aborting on OS X if used with anything
         * other than C or POSIX locales.
         */
-       std::string to_string (T const& v) const {
+       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;
@@ -213,11 +271,14 @@ public:
                : PropertyTemplate<std::string> (q, v)
        {}
 
-        void diff (PropertyList& before, PropertyList& after) 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) {
@@ -236,6 +297,29 @@ private:
 
 };
 
+template<class T>
+class EnumProperty : public Property<T>
+{
+public:
+       EnumProperty (PropertyDescriptor<T> q, T const& v)
+               : Property<T> (q, v)
+       {}
+
+       T & operator=(T const& v) {
+               this->set (v);
+               return this->_current;
+       }
+
+private:
+       std::string to_string (T const & v) const {
+               return enum_2_string (v);
+       }
+
+       T from_string (std::string const & s) const {
+               return static_cast<T> (string_2_enum (s, this->_current));
+       }
+};
+       
 } /* namespace PBD */
 
 #include "pbd/property_list_impl.h"