X-Git-Url: https://main.carlh.net/gitweb/?a=blobdiff_plain;f=libs%2Fpbd%2Fpbd%2Fstateful.h;h=4808bc2911f816b3e6e5634342dab488a5bd0433;hb=350ed31655b00f3043e5d723606cdd50099fa91b;hp=02224bb5e1ac327c39f2ee0462962778c8ae5ae5;hpb=a1e0dc13df3cdc7033c940f0f3311a2bd47d3b2e;p=ardour.git diff --git a/libs/pbd/pbd/stateful.h b/libs/pbd/pbd/stateful.h index 02224bb5e1..4808bc2911 100644 --- a/libs/pbd/pbd/stateful.h +++ b/libs/pbd/pbd/stateful.h @@ -21,10 +21,13 @@ #define __pbd_stateful_h__ #include +#include #include + #include "pbd/id.h" #include "pbd/xml++.h" -#include "pbd/enumwriter.h" +#include "pbd/property_basics.h" +#include "pbd/signals.h" class XMLNode; @@ -34,200 +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) - { - - } - - /** 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; -}; - -/** Parent class for classes which represent a single piece of state in a Stateful object */ -template -class StateTemplate : public StateBase -{ -public: - StateTemplate (std::string const & p, Change c, T const & v) - : StateBase (p, c) - , _current (v) - { - - } - - StateTemplate & operator= (StateTemplate 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; - } - - bool operator== (const T& other) const { - return _current == other; - } - - bool operator!= (const T& other) const { - return _current != other; - } - - operator T const & () const { - return _current; - } - - T const & val () 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) { - T const v = from_string (p->value ()); - - 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)); - } - -protected: - void set (T const & v) { - _old = _current; - _have_old = true; - _current = v; - } - - virtual std::string to_string (T const & v) const = 0; - virtual T from_string (std::string const & s) const = 0; - - T _current; - T _old; -}; - -template -std::ostream& operator<< (std::ostream& os, StateTemplate const & s) -{ - os << s.val(); - return os; -} - -/** Representation of a single piece of state in a Stateful; for use - * with types that can be written to / read from stringstreams. - */ -template -class State : public StateTemplate -{ -public: - State (std::string const & p, Change c, T const & v) - : StateTemplate (p, c, v) - { - - } - - T & operator= (T const & v) { - this->set (v); - return this->_current; - } - -private: - 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 { - std::stringstream t (s); - T v; - t.precision (12); // in case its floating point - t >> v; - return v; - } -}; - -template -class EnumState : public StateTemplate -{ -public: - EnumState (std::string const & p, Change c, T const & v) - : StateTemplate (p, c, 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 & v) const { - return T (string_2_enum (v, this->_current)); - } -}; +class PropertyList; +class OwnedPropertyList; /** Base class for objects with saveable and undoable state */ class Stateful { @@ -236,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; } + + void add_property (PropertyBase& s); - /* Extra XML nodes */ + /* 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