summaryrefslogtreecommitdiff
path: root/libs/pbd
diff options
context:
space:
mode:
authorPaul Davis <paul@linuxaudiosystems.com>2010-02-18 13:59:49 +0000
committerPaul Davis <paul@linuxaudiosystems.com>2010-02-18 13:59:49 +0000
commitce7a5e1c9fa3edf2d9cc66875505e402a0aaa6f6 (patch)
tree8a798270cd892823c7eeef99c2f3cdd4bf657bb3 /libs/pbd
parentcdcc4d3720d8168a158f6a5a5f23e9ce981bc68c (diff)
the Properties & 64bit region commit
git-svn-id: svn://localhost/ardour2/branches/3.0@6695 d708f5d6-7413-0410-9779-e7cbd77b26cf
Diffstat (limited to 'libs/pbd')
-rw-r--r--libs/pbd/pbd/properties.h121
-rw-r--r--libs/pbd/pbd/stateful.h231
-rw-r--r--libs/pbd/property.cc4
-rw-r--r--libs/pbd/stateful.cc88
-rw-r--r--libs/pbd/wscript1
5 files changed, 175 insertions, 270 deletions
diff --git a/libs/pbd/pbd/properties.h b/libs/pbd/pbd/properties.h
index 5bab97229c..10c661102d 100644
--- a/libs/pbd/pbd/properties.h
+++ b/libs/pbd/pbd/properties.h
@@ -21,26 +21,35 @@
#define __pbd_properties_h__
#include <string>
+#include <sstream>
#include <list>
-#include <glib/glib.h>
+#include <glib.h>
-class XMLNode;
+#include "pbd/xml++.h"
namespace PBD {
enum PropertyChange {
- range_guarantee = ~0
+ range_guarantee = ~0ULL
};
PropertyChange new_change ();
+typedef GQuark PropertyID;
+
+template<typename T>
+struct PropertyDescriptor {
+ PropertyID id;
+ typedef T value_type;
+};
+
/** Base (non template) part of Property */
class PropertyBase
{
public:
- PropertyBase (GQuark quark, PropertyChange c)
+ PropertyBase (PropertyID pid, PropertyChange c)
: _have_old (false)
- , _property_quark (q)
+ , _property_id (pid)
, _change (c)
{
@@ -52,19 +61,21 @@ public:
}
virtual void diff (XMLNode *, XMLNode *) const = 0;
+ virtual void diff (PropertyChange&) const = 0;
virtual PropertyChange set_state (XMLNode const &) = 0;
virtual void add_state (XMLNode &) const = 0;
- std::string property_name() const { return g_quark_to_string (_property_quark); }
+ const gchar* property_name() const { return g_quark_to_string (_property_id); }
PropertyChange change() const { return _change; }
+ PropertyID id() const { return _property_id; }
- bool operator== (GQuark q) const {
- return _property_quark == q;
+ bool operator== (PropertyID pid) const {
+ return _property_id == pid;
}
protected:
bool _have_old;
- GQuark _property_quark;
+ PropertyID _property_id;
PropertyChange _change;
};
@@ -73,17 +84,16 @@ template <class T>
class PropertyTemplate : public PropertyBase
{
public:
- PropertyTemplate (GQuark q, PropertyChange c, T const & v)
- : PropertyBase (q, c)
+ PropertyTemplate (PropertyDescriptor<T> p, PropertyChange c, T const & v)
+ : PropertyBase (p.id, c)
, _current (v)
{
}
-
PropertyTemplate<T> & operator= (PropertyTemplate<T> const & s) {
/* XXX: isn't there a nicer place to do this? */
_have_old = s._have_old;
- _property_quark = s._property_quark;
+ _property_id = s._property_id;
_change = s._change;
_current = s._current;
@@ -119,8 +129,14 @@ public:
void diff (XMLNode* old, XMLNode* current) const {
if (_have_old) {
- old->add_property (g_quark_to_string (_property_quark), to_string (_old));
- current->add_property (g_quark_to_string (_property_quark), to_string (_current));
+ old->add_property (g_quark_to_string (_property_id), to_string (_old));
+ current->add_property (g_quark_to_string (_property_id), to_string (_current));
+ }
+ }
+
+ void diff (PropertyChange& c) const {
+ if (_have_old && _change) {
+ c = PropertyChange (c | _change);
}
}
@@ -129,24 +145,23 @@ public:
* @return PropertyChange effected, or 0.
*/
PropertyChange set_state (XMLNode const & node) {
- XMLProperty const * p = node.property (g_quark_to_string (_property_quark));
+ XMLProperty const * p = node.property (g_quark_to_string (_property_id));
+ PropertyChange c = PropertyChange (0);
if (p) {
T const v = from_string (p->value ());
- if (v == _current) {
- return PropertyChange (0);
+ if (v != _current) {
+ set (v);
+ c = _change;
}
-
- set (v);
- return _change;
}
- return PropertyChange (0);
+ return c;
}
void add_state (XMLNode & node) const {
- node.add_property (g_quark_to_string (_property_quark), to_string (_current));
+ node.add_property (g_quark_to_string (_property_id), to_string (_current));
}
protected:
@@ -176,11 +191,17 @@ template <class T>
class Property : public PropertyTemplate<T>
{
public:
- Property (GQuark q, PropertyChange c, T const & v)
+ Property (PropertyDescriptor<T> q, PropertyChange c, T const & v)
: PropertyTemplate<T> (q, c, v)
{
}
+
+ Property (PropertyDescriptor<T> q, T const & v)
+ : PropertyTemplate<T> (q, PropertyChange (0), v)
+ {
+
+ }
T & operator= (T const & v) {
this->set (v);
@@ -188,8 +209,14 @@ public:
}
private:
- std::string to_string (T const & v) const {
- // XXX LocaleGuard
+ /* note that we do not set a locale for the streams used
+ in to_string() or from_string(), because we want the
+ format to be portable across locales (i.e. C or
+ POSIX). Also, there is the small matter of
+ std::locale aborting on OS X if used with anything
+ other than C or POSIX locales.
+ */
+ std::string to_string (T const & v) const {
std::stringstream s;
s.precision (12); // in case its floating point
s << v;
@@ -197,15 +224,53 @@ private:
}
T from_string (std::string const & s) const {
- // XXX LocaleGuard
std::stringstream t (s);
T v;
- t.precision (12); // in case its floating point
t >> v;
return v;
}
};
+class PropertyList : public std::map<PropertyID,PropertyBase*>
+{
+public:
+ PropertyList() : property_owner (true) {}
+ virtual ~PropertyList() {
+ if (property_owner)
+ for (std::map<PropertyID,PropertyBase*>::iterator i = begin(); i != end(); ++i) {
+ delete i->second;
+ }
+ }
+ /* classes that own property lists use this to add their
+ property members to their plists.
+ */
+ bool add (PropertyBase& p) {
+ return insert (value_type (p.id(), &p)).second;
+ }
+
+ /* code that is constructing a property list for use
+ in setting the state of an object uses this.
+ */
+ template<typename T, typename V> bool add (PropertyDescriptor<T> pid, const V& v) {
+ return insert (value_type (pid.id, new Property<T> (pid, (T) v))).second;
+ }
+
+protected:
+ bool property_owner;
+};
+
+/** A variant of PropertyList that does not delete its
+ property list in its destructor. Objects with their
+ own Properties store them in an OwnedPropertyList
+ to avoid having them deleted at the wrong time.
+*/
+
+class OwnedPropertyList : public PropertyList
+{
+public:
+ OwnedPropertyList() { property_owner = false; }
+};
+
} /* namespace PBD */
#endif /* __pbd_properties_h__ */
diff --git a/libs/pbd/pbd/stateful.h b/libs/pbd/pbd/stateful.h
index 02224bb5e1..9ef1a9ef73 100644
--- a/libs/pbd/pbd/stateful.h
+++ b/libs/pbd/pbd/stateful.h
@@ -21,10 +21,12 @@
#define __pbd_stateful_h__
#include <string>
+#include <list>
#include <cassert>
#include "pbd/id.h"
#include "pbd/xml++.h"
#include "pbd/enumwriter.h"
+#include "pbd/properties.h"
class XMLNode;
@@ -34,201 +36,6 @@ 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 T>
-class StateTemplate : public StateBase
-{
-public:
- StateTemplate (std::string const & p, Change c, T const & v)
- : StateBase (p, c)
- , _current (v)
- {
-
- }
-
- StateTemplate<T> & operator= (StateTemplate<T> 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<class T>
-std::ostream& operator<< (std::ostream& os, StateTemplate<T> 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 T>
-class State : public StateTemplate<T>
-{
-public:
- State (std::string const & p, Change c, T const & v)
- : StateTemplate<T> (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 T>
-class EnumState : public StateTemplate<T>
-{
-public:
- EnumState (std::string const & p, Change c, T const & v)
- : StateTemplate<T> (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));
- }
-};
-
/** Base class for objects with saveable and undoable state */
class Stateful {
public:
@@ -236,14 +43,21 @@ class Stateful {
virtual ~Stateful();
virtual XMLNode& get_state (void) = 0;
-
virtual int set_state (const XMLNode&, int version) = 0;
+ /* derived types do not have to implement this, but probably should
+ give it serious attention.
+ */
+ virtual PropertyChange set_property (const PropertyBase&) { return PropertyChange (0); }
- void add_state (StateBase & s) {
- _states.push_back (&s);
+ PropertyChange set_properties (const PropertyList&);
+
+ void add_property (PropertyBase& s) {
+ _properties.add (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);
@@ -251,7 +65,8 @@ class Stateful {
const PBD::ID& id() const { return _id; }
void clear_history ();
- std::pair<XMLNode *, XMLNode*> diff ();
+ std::pair<XMLNode *, XMLNode*> diff () const;
+ void changed (PropertyChange&) const;
static int current_state_version;
static int loading_state_version;
@@ -260,15 +75,25 @@ class Stateful {
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_properties (XMLNode &);
+ /* derived types can call this from ::set_state() (or elsewhere)
+ to get basic property setting done.
+ */
+ PropertyChange set_properties (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 () { };
XMLNode *_extra_xml;
XMLNode *_instant_xml;
PBD::ID _id;
std::string _xml_node_name; ///< name of node to use for this object in XML
- std::list<StateBase*> _states; ///< state variables that this object has
+ OwnedPropertyList _properties;
};
} // namespace PBD
diff --git a/libs/pbd/property.cc b/libs/pbd/property.cc
index 83bcf0fa2d..58e81c056b 100644
--- a/libs/pbd/property.cc
+++ b/libs/pbd/property.cc
@@ -17,6 +17,8 @@
*/
+#include <stdint.h>
+
#include "pbd/properties.h"
#include "pbd/error.h"
@@ -25,7 +27,7 @@
using namespace PBD;
PropertyChange
-new_change ()
+PBD::new_change ()
{
static uint64_t change_bit = 1;
diff --git a/libs/pbd/stateful.cc b/libs/pbd/stateful.cc
index a50c54d7f5..a8dd7a4177 100644
--- a/libs/pbd/stateful.cc
+++ b/libs/pbd/stateful.cc
@@ -35,27 +35,6 @@ namespace PBD {
int Stateful::current_state_version = 0;
int Stateful::loading_state_version = 0;
-PBD::Change
-new_change ()
-{
- Change c;
- static uint32_t change_bit = 1;
-
- /* catch out-of-range */
- if (!change_bit)
- {
- fatal << _("programming error: ")
- << "change_bit out of range in ARDOUR::new_change()"
- << endmsg;
- /*NOTREACHED*/
- }
-
- c = Change (change_bit);
- change_bit <<= 1; // if it shifts too far, change_bit == 0
-
- return c;
-}
-
Stateful::Stateful ()
{
_extra_xml = 0;
@@ -174,8 +153,8 @@ Stateful::instant_xml (const string& str, const sys::path& directory_path)
void
Stateful::clear_history ()
{
- for (list<StateBase*>::iterator i = _states.begin(); i != _states.end(); ++i) {
- (*i)->clear_history ();
+ for (OwnedPropertyList::iterator i = _properties.begin(); i != _properties.end(); ++i) {
+ i->second->clear_history ();
}
}
@@ -185,42 +164,75 @@ Stateful::clear_history ()
* It is the caller's responsibility to delete the returned XMLNodes.
*/
pair<XMLNode *, XMLNode *>
-Stateful::diff ()
+Stateful::diff () const
{
XMLNode* old = new XMLNode (_xml_node_name);
XMLNode* current = new XMLNode (_xml_node_name);
- for (list<StateBase*>::iterator i = _states.begin(); i != _states.end(); ++i) {
- (*i)->diff (old, current);
+ for (OwnedPropertyList::const_iterator i = _properties.begin(); i != _properties.end(); ++i) {
+ i->second->diff (old, current);
}
return make_pair (old, current);
}
+
+/** 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 _states from an XML node.
+/** Set state of some/all _properties from an XML node.
* @param node Node.
- * @return Changes made.
+ * @return PropertyChanges made.
*/
-Change
-Stateful::set_state_using_states (XMLNode const & node)
+PropertyChange
+Stateful::set_properties (XMLNode const & node)
{
- Change c = Change (0);
-
- for (list<StateBase*>::iterator i = _states.begin(); i != _states.end(); ++i) {
- c = Change (c | (*i)->set_state (node));
+ PropertyChange c = PropertyChange (0);
+
+ for (OwnedPropertyList::iterator i = _properties.begin(); i != _properties.end(); ++i) {
+ c = PropertyChange (c | i->second->set_state (node));
+ }
+
+ post_set ();
+
+ return c;
+}
+
+PropertyChange
+Stateful::set_properties (const PropertyList& property_list)
+{
+ PropertyChange c = PropertyChange (0);
+ 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)));
+ }
}
+
+ post_set ();
return c;
}
-/** Add state of _states to an XML node.
+
+/** Add property states to an XML node.
* @param node Node.
*/
void
-Stateful::add_states (XMLNode & node)
+Stateful::add_properties (XMLNode & node)
{
- for (list<StateBase*>::iterator i = _states.begin(); i != _states.end(); ++i) {
- (*i)->add_state (node);
+ for (OwnedPropertyList::iterator i = _properties.begin(); i != _properties.end(); ++i) {
+ i->second->add_state (node);
}
}
diff --git a/libs/pbd/wscript b/libs/pbd/wscript
index 8bd00bcff9..1c328e0410 100644
--- a/libs/pbd/wscript
+++ b/libs/pbd/wscript
@@ -74,6 +74,7 @@ def build(bld):
mountpoint.cc
pathscanner.cc
pool.cc
+ property.cc
pthread_utils.cc
receiver.cc
search_path.cc