X-Git-Url: https://main.carlh.net/gitweb/?a=blobdiff_plain;f=libs%2Fpbd%2Fstateful.cc;h=105af75861d4e87ed4b120a78f4df4c0f1174db5;hb=cfe42bc4ea9a5a6234f43c173e14fdd89af39589;hp=a8dd7a41778960f623111c9edf88dfc4a6df84d1;hpb=ce7a5e1c9fa3edf2d9cc66875505e402a0aaa6f6;p=ardour.git diff --git a/libs/pbd/stateful.cc b/libs/pbd/stateful.cc index a8dd7a4177..105af75861 100644 --- a/libs/pbd/stateful.cc +++ b/libs/pbd/stateful.cc @@ -20,9 +20,14 @@ #include +#include +#include + +#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" @@ -36,6 +41,8 @@ int Stateful::current_state_version = 0; int Stateful::loading_state_version = 0; Stateful::Stateful () + : _properties (new OwnedPropertyList) + , _stateful_frozen (0) { _extra_xml = 0; _instant_xml = 0; @@ -43,6 +50,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. @@ -61,28 +70,48 @@ Stateful::add_extra_xml (XMLNode& 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; + + if (_extra_xml) { + node = _extra_xml->child (str.c_str()); } - const XMLNodeList& nlist = _extra_xml->children(); - XMLNodeConstIterator i; + if (!node && add_if_missing) { + node = new XMLNode (str); + add_extra_xml (*node); + } - for (i = nlist.begin(); i != nlist.end(); ++i) { - if ((*i)->name() == str) { - return (*i); - } - } + return node; +} - return 0; +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"); @@ -91,12 +120,10 @@ 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); - - instant_xml_path /= "instant.xml"; + std::string instant_xml_path = Glib::build_filename (directory_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 @@ -112,24 +139,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 { @@ -149,91 +175,227 @@ 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 -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 = PropertyChange (0); - - for (OwnedPropertyList::iterator i = _properties.begin(); i != _properties.end(); ++i) { - c = PropertyChange (c | i->second->set_state (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; } PropertyChange -Stateful::set_properties (const PropertyList& property_list) +Stateful::apply_changes (const PropertyList& property_list) { - PropertyChange c = PropertyChange (0); + 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()) { - c = PropertyChange (c|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 (); + post_set (c); + + 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->add_state (node); + 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::Threads::Mutex::Lock lm (_lock); + if (property_changes_suspended ()) { + _pending_changed.add (what_changed); + return; + } + } + + PropertyChanged (what_changed); +} + +void +Stateful::suspend_property_changes () +{ + g_atomic_int_add (&_stateful_frozen, 1); +} + +void +Stateful::resume_property_changes () +{ + PropertyChange what_changed; + + { + Glib::Threads::Mutex::Lock lm (_lock); + + if (property_changes_suspended() && g_atomic_int_dec_and_test (&_stateful_frozen) == FALSE) { + 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& 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->clear_owned_changes (); + } +} + +bool +Stateful::set_id (const XMLNode& node) +{ + const XMLProperty* prop; + + 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) +{ + _id = str; +} + } // namespace PBD