add realloc pool to MSVC project
[ardour.git] / libs / pbd / stateful.cc
index c33418ce39fdcf82b3551aa3669e9a349e8e61d4..3fb11a3a509359bf6878a0c63e9849c72b94e81f 100644 (file)
@@ -1,5 +1,5 @@
 /*
-    Copyright (C) 2000-2001 Paul Davis 
+    Copyright (C) 2000-2001 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
     $Id: stateful.cc 629 2006-06-21 23:01:03Z paul $
 */
 
+#ifdef COMPILER_MSVC
+#include <io.h>      // Microsoft's nearest equivalent to <unistd.h>
+#else
 #include <unistd.h>
+#endif
+
+#include <glibmm/fileutils.h>
+#include <glibmm/miscutils.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"
 #include "pbd/error.h"
 
@@ -38,19 +44,21 @@ namespace PBD {
 int Stateful::current_state_version = 0;
 int Stateful::loading_state_version = 0;
 
+Glib::Threads::Private<bool> Stateful::_regenerate_xml_or_string_ids;
+
 Stateful::Stateful ()
-        : _frozen (0)
-        , _properties (new OwnedPropertyList)
+       : _extra_xml (0)
+       , _instant_xml (0)
+       , _properties (new OwnedPropertyList)
+       , _stateful_frozen (0)
 {
-       _extra_xml = 0;
-       _instant_xml = 0;
 }
 
 Stateful::~Stateful ()
 {
-        delete _properties;
+       delete _properties;
 
-       // Do not delete _extra_xml.  The use of add_child_nocopy() 
+       // Do not delete _extra_xml.  The use of add_child_nocopy()
        // means it needs to live on indefinately.
 
        delete _instant_xml;
@@ -63,33 +71,53 @@ Stateful::add_extra_xml (XMLNode& node)
                _extra_xml = new XMLNode ("Extra");
        }
 
-       _extra_xml->remove_nodes (node.name());
+       _extra_xml->remove_nodes_and_delete (node.name());
        _extra_xml->add_child_nocopy (node);
 }
 
 XMLNode *
-Stateful::extra_xml (const string& str)
+Stateful::extra_xml (const string& str, bool add_if_missing)
 {
-       if (_extra_xml == 0) {
-               return 0;
-       }
+       XMLNode* node = 0;
 
-       const XMLNodeList& nlist = _extra_xml->children();
-       XMLNodeConstIterator i;
+       if (_extra_xml) {
+               node = _extra_xml->child (str.c_str());
+       }
 
-       for (i = nlist.begin(); i != nlist.end(); ++i) {
-               if ((*i)->name() == str) {
-                       return (*i);
-               }
+       if (!node && add_if_missing) {
+               node = new XMLNode (str);
+               add_extra_xml (*node);
        }
 
-       return 0;
+       return node;
+}
+
+void
+Stateful::save_extra_xml (const XMLNode& node)
+{
+       /* Looks for the child node called "Extra" and makes _extra_xml
+          point to a copy of it. Will delete any existing node pointed
+          to by _extra_xml if a new Extra node is found, but not
+          otherwise.
+       */
+
+       const XMLNode* xtra = node.child ("Extra");
+
+       if (xtra) {
+               delete _extra_xml;
+               _extra_xml = new XMLNode (*xtra);
+       }
 }
 
 void
-Stateful::add_instant_xml (XMLNode& node, const sys::path& directory_path)
+Stateful::add_instant_xml (XMLNode& node, const std::string& directory_path)
 {
-       sys::create_directories (directory_path); // may throw
+       if (!Glib::file_test (directory_path, Glib::FILE_TEST_IS_DIR)) {
+               if (g_mkdir_with_parents (directory_path.c_str(), 0755) != 0) {
+                       error << string_compose(_("Error: could not create directory %1"), directory_path) << endmsg;
+                       return;
+               }
+       }
 
        if (_instant_xml == 0) {
                _instant_xml = new XMLNode ("instant");
@@ -98,20 +126,18 @@ Stateful::add_instant_xml (XMLNode& node, const sys::path& directory_path)
        _instant_xml->remove_nodes_and_delete (node.name());
        _instant_xml->add_child_copy (node);
 
-       sys::path instant_xml_path(directory_path);
+       std::string instant_xml_path = Glib::build_filename (directory_path, "instant.xml");
 
-       instant_xml_path /= "instant.xml";
-       
        XMLTree tree;
-       tree.set_filename(instant_xml_path.to_string());
+       tree.set_filename(instant_xml_path);
 
        /* Important: the destructor for an XMLTree deletes
           all of its nodes, starting at _root. We therefore
-          cannot simply hand it our persistent _instant_xml 
+          cannot simply hand it our persistent _instant_xml
           node as its _root, because we will lose it whenever
           the Tree goes out of scope.
 
-          So instead, copy the _instant_xml node (which does 
+          So instead, copy the _instant_xml node (which does
           a deep copy), and hand that to the tree.
        */
 
@@ -119,24 +145,23 @@ Stateful::add_instant_xml (XMLNode& node, const sys::path& directory_path)
        tree.set_root (copy);
 
        if (!tree.write()) {
-               error << string_compose(_("Error: could not write %1"), instant_xml_path.to_string()) << endmsg;
+               error << string_compose(_("Error: could not write %1"), instant_xml_path) << endmsg;
        }
 }
 
 XMLNode *
-Stateful::instant_xml (const string& str, const sys::path& directory_path)
+Stateful::instant_xml (const string& str, const std::string& directory_path)
 {
        if (_instant_xml == 0) {
 
-               sys::path instant_xml_path(directory_path);
-               instant_xml_path /= "instant.xml";
+               std::string instant_xml_path = Glib::build_filename (directory_path, "instant.xml");
 
-               if (exists(instant_xml_path)) {
+               if (Glib::file_test (instant_xml_path, Glib::FILE_TEST_EXISTS)) {
                        XMLTree tree;
-                       if (tree.read(instant_xml_path.to_string())) {
+                       if (tree.read(instant_xml_path)) {
                                _instant_xml = new XMLNode(*(tree.root()));
                        } else {
-                               warning << string_compose(_("Could not understand XML file %1"), instant_xml_path.to_string()) << endmsg;
+                               warning << string_compose(_("Could not understand XML file %1"), instant_xml_path) << endmsg;
                                return 0;
                        }
                } else {
@@ -169,7 +194,7 @@ PropertyList *
 Stateful::get_changes_as_properties (Command* cmd) const
 {
        PropertyList* pl = new PropertyList;
-       
+
        for (OwnedPropertyList::const_iterator i = _properties->begin(); i != _properties->end(); ++i) {
                i->second->get_changes_as_properties (*pl, cmd);
        }
@@ -178,7 +203,7 @@ Stateful::get_changes_as_properties (Command* cmd) const
 }
 
 /** Set our property values from an XML node.
- *  Derived types can call this from ::set_state() (or elsewhere)
+ *  Derived types can call this from set_state() (or elsewhere)
  *  to get basic property setting done.
  *  @return IDs of properties that were changed.
  */
@@ -186,14 +211,14 @@ PropertyChange
 Stateful::set_values (XMLNode const & node)
 {
        PropertyChange c;
-        
+
        for (OwnedPropertyList::iterator i = _properties->begin(); i != _properties->end(); ++i) {
                if (i->second->set_value (node)) {
                        c.add (i->first);
                }
        }
 
-       post_set ();
+       post_set (c);
 
        return c;
 }
@@ -204,30 +229,30 @@ Stateful::apply_changes (const PropertyList& property_list)
        PropertyChange c;
        PropertyList::const_iterator p;
 
-        DEBUG_TRACE (DEBUG::Stateful, string_compose ("Stateful %1 setting properties from list of %2\n", this, property_list.size()));
+       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()) {
+       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_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()));
-                }
+                       DEBUG_TRACE (DEBUG::Stateful, string_compose ("passed in property %1 not found in own property list\n",
+                                                                     i->second->property_name()));
+               }
        }
-       
-       post_set ();
+
+       post_set (c);
 
        send_change (c);
 
@@ -248,7 +273,7 @@ Stateful::add_properties (XMLNode& owner_state)
 void
 Stateful::add_property (PropertyBase& s)
 {
-        _properties->add (s);
+       _properties->add (s);
 }
 
 void
@@ -259,8 +284,8 @@ Stateful::send_change (const PropertyChange& what_changed)
        }
 
        {
-               Glib::Mutex::Lock lm (_lock);
-               if (_frozen) {
+               Glib::Threads::Mutex::Lock lm (_lock);
+               if (property_changes_suspended ()) {
                        _pending_changed.add (what_changed);
                        return;
                }
@@ -272,7 +297,7 @@ Stateful::send_change (const PropertyChange& what_changed)
 void
 Stateful::suspend_property_changes ()
 {
-        _frozen++;
+       g_atomic_int_add (&_stateful_frozen, 1);
 }
 
 void
@@ -281,9 +306,9 @@ Stateful::resume_property_changes ()
        PropertyChange what_changed;
 
        {
-               Glib::Mutex::Lock lm (_lock);
+               Glib::Threads::Mutex::Lock lm (_lock);
 
-               if (_frozen && --_frozen > 0) {
+               if (property_changes_suspended() && g_atomic_int_dec_and_test (&_stateful_frozen) == FALSE) {
                        return;
                }
 
@@ -293,21 +318,21 @@ Stateful::resume_property_changes ()
                }
        }
 
-        mid_thaw (what_changed);
+       mid_thaw (what_changed);
 
-        send_change (what_changed);
+       send_change (what_changed);
 }
 
 bool
-Stateful::changed() const  
+Stateful::changed() const
 {
        for (OwnedPropertyList::const_iterator i = _properties->begin(); i != _properties->end(); ++i) {
-                if (i->second->changed()) {
-                        return true;
-                }
-        }
+               if (i->second->changed()) {
+                       return true;
+               }
+       }
 
-        return false;
+       return false;
 }
 
 bool
@@ -325,17 +350,17 @@ Stateful::apply_changes (const PropertyBase& prop)
 PropertyList*
 Stateful::property_factory (const XMLNode& history_node) const
 {
-        PropertyList* prop_list = new PropertyList;
+       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);
+       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);
-                }
-        }
+               if (prop) {
+                       prop_list->add (prop);
+               }
+       }
 
-        return prop_list;
+       return prop_list;
 }
 
 void
@@ -353,6 +378,60 @@ Stateful::clear_owned_changes ()
                i->second->clear_owned_changes ();
        }
 }
-  
+
+bool
+Stateful::set_id (const XMLNode& node)
+{
+       const XMLProperty* prop;
+       bool* regen = _regenerate_xml_or_string_ids.get();
+
+       if (regen && *regen) {
+               reset_id ();
+               return true;
+       }
+
+       if ((prop = node.property ("id")) != 0) {
+               _id = prop->value ();
+               return true;
+       }
+
+       return false;
+}
+
+void
+Stateful::reset_id ()
+{
+       _id = ID ();
+}
+
+void
+Stateful::set_id (const string& str)
+{
+       bool* regen = _regenerate_xml_or_string_ids.get();
+
+       if (regen && *regen) {
+               reset_id ();
+       } else {
+               _id = str;
+       }
+}
+
+bool
+Stateful::regenerate_xml_or_string_ids () const
+{
+       bool* regen = _regenerate_xml_or_string_ids.get();
+       if (regen && *regen) {
+               return true;
+       } else {
+               return false;
+       }
+}
+
+void
+Stateful::set_regenerate_xml_and_string_ids_in_this_thread (bool yn)
+{
+       bool* val = new bool (yn);
+       _regenerate_xml_or_string_ids.set (val);
+}
 
 } // namespace PBD