X-Git-Url: https://main.carlh.net/gitweb/?a=blobdiff_plain;f=libs%2Fpbd%2Fpbd%2Fstateful.h;h=4808bc2911f816b3e6e5634342dab488a5bd0433;hb=0aac62e013e15e380001dafae39d554f8765a4a1;hp=80d7aa796acda33063f33f0fc1e6672460a9e8bb;hpb=3c00a7ca2ae34cb65c8d3394d9a012f20c69ee77;p=ardour.git diff --git a/libs/pbd/pbd/stateful.h b/libs/pbd/pbd/stateful.h index 80d7aa796a..4808bc2911 100644 --- a/libs/pbd/pbd/stateful.h +++ b/libs/pbd/pbd/stateful.h @@ -21,9 +21,13 @@ #define __pbd_stateful_h__ #include +#include #include + #include "pbd/id.h" #include "pbd/xml++.h" +#include "pbd/property_basics.h" +#include "pbd/signals.h" class XMLNode; @@ -33,145 +37,8 @@ namespace sys { class path; } -enum Change { - range_guarantee = ~0 -}; - -Change new_change (); - -/** Base (non template) part of State */ -class StateBase -{ -public: - StateBase (std::string const & p, Change c) - : _have_old (false) - , _xml_property_name (p) - , _change (c) - { - - } - - StateBase (StateBase const & s) - : _have_old (s._have_old) - , _xml_property_name (s._xml_property_name) - , _change (s._change) - { - - } - - /** Forget about any old value for this state */ - void clear_history () { - _have_old = false; - } - - virtual void diff (XMLNode *, XMLNode *) const = 0; - virtual Change set_state (XMLNode const &) = 0; - virtual void add_state (XMLNode &) const = 0; - -protected: - bool _have_old; - std::string _xml_property_name; - Change _change; -}; - -/** Class to represent a single piece of state in a Stateful object */ -template -class State : public StateBase -{ -public: - State (std::string const & p, Change c, T const & v) - : StateBase (p, c) - , _current (v) - { - - } - - State (State const & s) - : StateBase (s) - { - _current = s._current; - _old = s._old; - } - - State & operator= (State const & s) { - /* XXX: isn't there a nicer place to do this? */ - _have_old = s._have_old; - _xml_property_name = s._xml_property_name; - _change = s._change; - - _current = s._current; - _old = s._old; - return *this; - } - - T & operator= (T const & v) { - set (v); - return _current; - } - - T & operator+= (T const & v) { - set (_current + v); - return _current; - } - - operator T () const { - return _current; - } - - T const & get () const { - return _current; - } - - void diff (XMLNode* old, XMLNode* current) const { - if (_have_old) { - old->add_property (_xml_property_name.c_str(), to_string (_old)); - current->add_property (_xml_property_name.c_str(), to_string (_current)); - } - } - - /** Try to set state from the property of an XML node. - * @param node XML node. - * @return Change effected, or 0. - */ - Change set_state (XMLNode const & node) { - XMLProperty const * p = node.property (_xml_property_name.c_str()); - - if (p) { - std::stringstream s (p->value ()); - T v; - s >> v; - - if (v == _current) { - return Change (0); - } - - set (v); - return _change; - } - - return Change (0); - } - - void add_state (XMLNode & node) const { - node.add_property (_xml_property_name.c_str(), to_string (_current)); - } - -private: - void set (T const & v) { - _old = _current; - _have_old = true; - _current = v; - } - - std::string to_string (T const & v) const { - std::stringstream s; - s << v; - return s.str (); - } - - T _current; - T _old; -}; +class PropertyList; +class OwnedPropertyList; /** Base class for objects with saveable and undoable state */ class Stateful { @@ -180,39 +47,83 @@ class Stateful { virtual ~Stateful(); virtual XMLNode& get_state (void) = 0; - virtual int set_state (const XMLNode&, int version) = 0; - void add_state (StateBase & s) { - _states.push_back (&s); - } + virtual bool apply_changes (PropertyBase const &); + PropertyChange apply_changes (PropertyList const &); + + const OwnedPropertyList& properties() const { return *_properties; } - /* Extra XML nodes */ + void add_property (PropertyBase& s); + + /* Extra XML node: so that 3rd parties can attach state to the XMLNode + representing the state of this object. + */ void add_extra_xml (XMLNode&); - XMLNode *extra_xml (const std::string& str); + XMLNode *extra_xml (const std::string& str, bool add_if_missing = false); + void save_extra_xml (const XMLNode&); const PBD::ID& id() const { return _id; } + bool set_id (const XMLNode&); + void set_id (const std::string&); + void reset_id (); + + /* history management */ + + void clear_changes (); + virtual void clear_owned_changes (); + PropertyList* get_changes_as_properties (Command *) const; + virtual void rdiff (std::vector &) const; + bool changed() const; - void clear_history (); - std::pair diff (); + /* create a property list from an XMLNode + */ + virtual PropertyList* property_factory (const XMLNode&) const; + + /* How stateful's notify of changes to their properties + */ + PBD::Signal1 PropertyChanged; static int current_state_version; static int loading_state_version; + virtual void suspend_property_changes (); + virtual void resume_property_changes (); + + bool property_changes_suspended() const { return g_atomic_int_get (const_cast(&_stateful_frozen)) > 0; } + protected: - void add_instant_xml (XMLNode&, const sys::path& directory_path); - XMLNode *instant_xml (const std::string& str, const sys::path& directory_path); - Change set_state_using_states (XMLNode const &); - void add_states (XMLNode &); + void add_instant_xml (XMLNode&, const std::string& directory_path); + XMLNode *instant_xml (const std::string& str, const std::string& directory_path); + void add_properties (XMLNode &); + + PropertyChange set_values (XMLNode const &); + + /* derived classes can implement this to do cross-checking + of property values after either a PropertyList or XML + driven property change. + */ + virtual void post_set (const PropertyChange&) { }; XMLNode *_extra_xml; XMLNode *_instant_xml; - PBD::ID _id; + PBD::PropertyChange _pending_changed; + Glib::Threads::Mutex _lock; std::string _xml_node_name; ///< name of node to use for this object in XML - std::list _states; ///< state variables that this object has + OwnedPropertyList* _properties; + + virtual void send_change (const PropertyChange&); + /** derived classes can implement this in order to process a property change + within thaw() just before send_change() is called. + */ + virtual void mid_thaw (const PropertyChange&) { } + + private: + PBD::ID _id; + gint _stateful_frozen; }; } // namespace PBD