Fix deadlock.
[ardour.git] / libs / pbd / stateful.cc
index 9a1a11612858fabe1e68af99c87beade0ba0ba1c..c33418ce39fdcf82b3551aa3669e9a349e8e61d4 100644 (file)
 
 #include <unistd.h>
 
+#include "pbd/debug.h"
 #include "pbd/stateful.h"
+#include "pbd/property_list.h"
+#include "pbd/properties.h"
 #include "pbd/destructible.h"
 #include "pbd/filesystem.h"
 #include "pbd/xml++.h"
@@ -36,6 +39,8 @@ int Stateful::current_state_version = 0;
 int Stateful::loading_state_version = 0;
 
 Stateful::Stateful ()
+        : _frozen (0)
+        , _properties (new OwnedPropertyList)
 {
        _extra_xml = 0;
        _instant_xml = 0;
@@ -43,6 +48,8 @@ Stateful::Stateful ()
 
 Stateful::~Stateful ()
 {
+        delete _properties;
+
        // Do not delete _extra_xml.  The use of add_child_nocopy() 
        // means it needs to live on indefinately.
 
@@ -149,57 +156,39 @@ Stateful::instant_xml (const string& str, const sys::path& directory_path)
        return 0;
 }
 
-/** Forget about any old state for this object */      
+/** Forget about any changes to this object's properties */
 void
-Stateful::clear_history ()
+Stateful::clear_changes ()
 {
-       for (OwnedPropertyList::iterator i = _properties.begin(); i != _properties.end(); ++i) {
-               i->second->clear_history ();
+       for (OwnedPropertyList::iterator i = _properties->begin(); i != _properties->end(); ++i) {
+               i->second->clear_changes ();
        }
 }
 
-/** @return A pair of XMLNodes representing state that has changed since the last time clear_history
- *  was called on this object; the first is the state before, the second the state after.
- *
- *  It is the caller's responsibility to delete the returned XMLNodes.
- */
-pair<XMLNode *, XMLNode *>
-Stateful::diff () const
+PropertyList *
+Stateful::get_changes_as_properties (Command* cmd) const
 {
-       XMLNode* old = new XMLNode (_xml_node_name);
-       XMLNode* current = new XMLNode (_xml_node_name);
-
-       for (OwnedPropertyList::const_iterator i = _properties.begin(); i != _properties.end(); ++i) {
-               i->second->diff (old, current);
+       PropertyList* pl = new PropertyList;
+       
+       for (OwnedPropertyList::const_iterator i = _properties->begin(); i != _properties->end(); ++i) {
+               i->second->get_changes_as_properties (*pl, cmd);
        }
 
-       return make_pair (old, current);
+       return pl;
 }
 
-/** Modifies PropertyChange @param c to indicate what properties have changed since the last
-    time clear_history was called on this object. Note that not all properties have change
-    values - if this object has any such Property members, they will never show up in
-    the value of @param c. Note also that @param c is not cleared by this function.
-*/
-void
-Stateful::changed (PropertyChange& c) const
-{
-       for (OwnedPropertyList::const_iterator i = _properties.begin(); i != _properties.end(); ++i) {
-               i->second->diff (c);
-       }
-}      
-       
-/** Set state of some/all _properties from an XML node.
- *  @param node Node.
- *  @return PropertyChanges made.
+/** Set our property values from an XML node.
+ *  Derived types can call this from ::set_state() (or elsewhere)
+ *  to get basic property setting done.
+ *  @return IDs of properties that were changed.
  */
 PropertyChange
-Stateful::set_properties (XMLNode const & node)
+Stateful::set_values (XMLNode const & node)
 {
        PropertyChange c;
-
-       for (OwnedPropertyList::iterator i = _properties.begin(); i != _properties.end(); ++i) {
-               if (i->second->set_state (node)) {
+        
+       for (OwnedPropertyList::iterator i = _properties->begin(); i != _properties->end(); ++i) {
+               if (i->second->set_value (node)) {
                        c.add (i->first);
                }
        }
@@ -210,34 +199,160 @@ Stateful::set_properties (XMLNode const & node)
 }
 
 PropertyChange
-Stateful::set_properties (const PropertyList& property_list)
+Stateful::apply_changes (const PropertyList& property_list)
 {
        PropertyChange c;
        PropertyList::const_iterator p;
 
-       for (OwnedPropertyList::iterator i = _properties.begin(); i != _properties.end(); ++i) {
-               if ((p = property_list.find (i->first)) != property_list.end()) {
-                       if (set_property (*p->second)) {
+        DEBUG_TRACE (DEBUG::Stateful, string_compose ("Stateful %1 setting properties from list of %2\n", this, property_list.size()));
+
+        for (PropertyList::const_iterator pp = property_list.begin(); pp != property_list.end(); ++pp) {
+                DEBUG_TRACE (DEBUG::Stateful, string_compose ("in plist: %1\n", pp->second->property_name()));
+        }
+        
+        for (PropertyList::const_iterator i = property_list.begin(); i != property_list.end(); ++i) {
+                if ((p = _properties->find (i->first)) != _properties->end()) {
+
+                        DEBUG_TRACE (
+                               DEBUG::Stateful,
+                               string_compose ("actually setting property %1 using %2\n", p->second->property_name(), i->second->property_name())
+                               );
+                       
+                       if (apply_changes (*i->second)) {
                                c.add (i->first);
                        }
-               }
+               } else {
+                        DEBUG_TRACE (DEBUG::Stateful, string_compose ("passed in property %1 not found in own property list\n",
+                                                                      i->second->property_name()));
+                }
        }
        
        post_set ();
 
+       send_change (c);
+
        return c;
 }
 
-
 /** Add property states to an XML node.
- *  @param node Node.
+ *  @param owner_state Node.
  */
 void
-Stateful::add_properties (XMLNode & node)
+Stateful::add_properties (XMLNode& owner_state)
+{
+       for (OwnedPropertyList::iterator i = _properties->begin(); i != _properties->end(); ++i) {
+               i->second->get_value (owner_state);
+       }
+}
+
+void
+Stateful::add_property (PropertyBase& s)
+{
+        _properties->add (s);
+}
+
+void
+Stateful::send_change (const PropertyChange& what_changed)
+{
+       if (what_changed.empty()) {
+               return;
+       }
+
+       {
+               Glib::Mutex::Lock lm (_lock);
+               if (_frozen) {
+                       _pending_changed.add (what_changed);
+                       return;
+               }
+       }
+
+       PropertyChanged (what_changed);
+}
+
+void
+Stateful::suspend_property_changes ()
+{
+        _frozen++;
+}
+
+void
+Stateful::resume_property_changes ()
+{
+       PropertyChange what_changed;
+
+       {
+               Glib::Mutex::Lock lm (_lock);
+
+               if (_frozen && --_frozen > 0) {
+                       return;
+               }
+
+               if (!_pending_changed.empty()) {
+                       what_changed = _pending_changed;
+                       _pending_changed.clear ();
+               }
+       }
+
+        mid_thaw (what_changed);
+
+        send_change (what_changed);
+}
+
+bool
+Stateful::changed() const  
+{
+       for (OwnedPropertyList::const_iterator i = _properties->begin(); i != _properties->end(); ++i) {
+                if (i->second->changed()) {
+                        return true;
+                }
+        }
+
+        return false;
+}
+
+bool
+Stateful::apply_changes (const PropertyBase& prop)
+{
+       OwnedPropertyList::iterator i = _properties->find (prop.property_id());
+       if (i == _properties->end()) {
+               return false;
+       }
+
+       i->second->apply_changes (&prop);
+       return true;
+}
+
+PropertyList*
+Stateful::property_factory (const XMLNode& history_node) const
+{
+        PropertyList* prop_list = new PropertyList;
+
+        for (OwnedPropertyList::const_iterator i = _properties->begin(); i != _properties->end(); ++i) {
+                PropertyBase* prop = i->second->clone_from_xml (history_node);
+
+                if (prop) {
+                        prop_list->add (prop);
+                }
+        }
+
+        return prop_list;
+}
+
+void
+Stateful::rdiff (vector<Command*>& cmds) const
+{
+       for (OwnedPropertyList::const_iterator i = _properties->begin(); i != _properties->end(); ++i) {
+               i->second->rdiff (cmds);
+       }
+}
+
+void
+Stateful::clear_owned_changes ()
 {
-       for (OwnedPropertyList::iterator i = _properties.begin(); i != _properties.end(); ++i) {
-               i->second->add_state (node);
+       for (OwnedPropertyList::iterator i = _properties->begin(); i != _properties->end(); ++i) {
+               i->second->clear_owned_changes ();
        }
 }
+  
 
 } // namespace PBD