#include <sstream>
#include <list>
#include <set>
-#include <glib.h>
+#include <iostream>
#include "pbd/xml++.h"
#include "pbd/property_basics.h"
#include "pbd/property_list.h"
+#include "pbd/enumwriter.h"
namespace PBD {
-/** Parent class for classes which represent a single scalar property in a Stateful object
- */
+/** Parent class for classes which represent a single scalar property in a Stateful object */
template<class T>
class PropertyTemplate : public PropertyBase
{
, _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_id = s._property_id;
+ PropertyTemplate (PropertyDescriptor<T> p, T const& o, T const& c)
+ : PropertyBase (p.property_id)
+ , _have_old (true)
+ , _current (c)
+ , _old (o)
+ {}
- _current = s._current;
- _old = s._old;
- return *this;
- }
+ PropertyTemplate (PropertyDescriptor<T> p, PropertyTemplate<T> const & s)
+ : PropertyBase (p.property_id)
+ , _have_old (false)
+ , _current (s._current)
+ {}
+
+
+ /* OPERATORS / ACCESSORS */
T & operator=(T const& v) {
set (v);
return _current;
}
+ /* This will mean that, if fred and jim are both PropertyTemplates,
+ * fred = jim will result in fred taking on jim's current value,
+ * but NOT jim's property ID.
+ */
+ PropertyTemplate<T> & operator= (PropertyTemplate<T> const & p) {
+ set (p._current);
+ return *this;
+ }
+
T & operator+=(T const& v) {
set (_current + v);
return _current;
return _current;
}
- void clear_history () {
- _have_old = false;
- }
-
- void add_history_state (XMLNode* history_node) const {
- /* We can get to the current state of a scalar property like this one simply
- by knowing what the new state is.
- */
- history_node->add_property (property_name(), to_string (_current));
- }
- /** Try to set state from the property of an XML node.
- * @param node XML node.
- * @return true if the value of the property is changed
- */
- bool set_state_from_owner_state (XMLNode const& owner_state) {
+ /* MANAGEMENT OF Stateful State */
+
+ bool set_value (XMLNode const & node) {
- XMLProperty const* p = owner_state.property (property_name());
+ XMLProperty const* p = node.property (property_name());
if (p) {
T const v = from_string (p->value ());
return false;
}
- void add_state_to_owner_state (XMLNode& owner_state) const {
- owner_state.add_property (property_name(), to_string (_current));
+ void get_value (XMLNode & node) const {
+ node.add_property (property_name(), to_string (_current));
+ }
+
+
+ /* MANAGEMENT OF HISTORY */
+
+ void clear_changes () {
+ _have_old = false;
}
bool changed () const { return _have_old; }
- void set_state_from_property (PropertyBase const * p) {
+
+ void invert () {
+ T const tmp = _current;
+ _current = _old;
+ _old = tmp;
+ }
+
+
+ /* TRANSFERRING HISTORY TO / FROM A StatefulDiffCommand */
+
+ void get_changes_as_xml (XMLNode* history_node) const {
+ XMLNode* node = history_node->add_child (property_name());
+ node->add_property ("from", to_string (_old));
+ node->add_property ("to", to_string (_current));
+ }
+
+ void get_changes_as_properties (PropertyList& changes, Command *) const {
+ if (this->_have_old) {
+ changes.add (clone ());
+ }
+ }
+
+
+ /* VARIOUS */
+
+ void apply_changes (PropertyBase const * p) {
T v = dynamic_cast<const PropertyTemplate<T>* > (p)->val ();
if (v != _current) {
set (v);
}
protected:
- /** Constructs a PropertyTemplate with a default
- value for _old and _current.
- */
-
- PropertyTemplate (PropertyDescriptor<T> p)
- : PropertyBase (p.property_id)
- {}
void set (T const& v) {
- if (!_have_old) {
- _old = _current;
- _have_old = true;
- }
- _current = v;
+ if (v != _current) {
+ if (!_have_old) {
+ _old = _current;
+ _have_old = true;
+ } else {
+ if (v == _old) {
+ /* value has been reset to the value
+ at the start of a history transaction,
+ before clear_changes() is called.
+ thus there is effectively no apparent
+ history for this property.
+ */
+ _have_old = false;
+ }
+ }
+
+ _current = v;
+ }
}
virtual std::string to_string (T const& v) const = 0;
bool _have_old;
T _current;
T _old;
+
+private:
+ /* disallow copy-construction; it's not obvious whether it should mean
+ a copy of just the value, or the value and property ID.
+ */
+ PropertyTemplate (PropertyTemplate<T> const &);
};
template<class T>
Property (PropertyDescriptor<T> q, T const& v)
: PropertyTemplate<T> (q, v)
{}
-
- void diff (PropertyList& undo, PropertyList& redo, Command* /*ignored*/) const {
- if (this->_have_old) {
- undo.add (new Property<T> (this->property_id(), this->_old));
- redo.add (new Property<T> (this->property_id(), this->_current));
- }
- }
-
- Property<T>* maybe_clone_self_if_found_in_history_node (const XMLNode& node) const {
- const XMLProperty* prop = node.property (this->property_name());
- if (!prop) {
- return 0;
- }
- return new Property<T> (this->property_id(), from_string (prop->value()));
- }
+
+ Property (PropertyDescriptor<T> q, T const& o, T const& c)
+ : PropertyTemplate<T> (q, o, c)
+ {}
+
+ Property (PropertyDescriptor<T> q, Property<T> const& v)
+ : PropertyTemplate<T> (q, v)
+ {}
+
+ Property<T>* clone () const {
+ return new Property<T> (this->property_id(), this->_old, this->_current);
+ }
+
+ Property<T>* clone_from_xml (const XMLNode& node) const {
+ XMLNodeList const & children = node.children ();
+ XMLNodeList::const_iterator i = children.begin();
+ while (i != children.end() && (*i)->name() != this->property_name()) {
+ ++i;
+ }
+
+ if (i == children.end()) {
+ return 0;
+ }
+ XMLProperty* from = (*i)->property ("from");
+ XMLProperty* to = (*i)->property ("to");
+
+ if (!from || !to) {
+ return 0;
+ }
+
+ return new Property<T> (this->property_id(), from_string (from->value()), from_string (to->value ()));
+ }
T & operator=(T const& v) {
this->set (v);
private:
friend class PropertyFactory;
- Property (PropertyDescriptor<T> q)
- : PropertyTemplate<T> (q)
- {}
+ /* no copy-construction */
+ Property (Property<T> const &);
/* Note that we do not set a locale for the streams used
* in to_string() or from_string(), because we want the
* std::locale aborting on OS X if used with anything
* other than C or POSIX locales.
*/
- std::string to_string (T const& v) const {
+ virtual 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 {
+ virtual T from_string (std::string const& s) const {
std::stringstream t (s);
T v;
t >> v;
class Property<std::string> : public PropertyTemplate<std::string>
{
public:
- Property (PropertyDescriptor<std::string> q, std::string const& v)
- : PropertyTemplate<std::string> (q, v)
+ Property (PropertyDescriptor<std::string> d, std::string const & v)
+ : PropertyTemplate<std::string> (d, v)
{}
- void diff (PropertyList& before, PropertyList& after, Command* /*ignored*/) const {
- if (this->_have_old) {
- before.add (new Property<std::string> (PropertyDescriptor<std::string> (this->property_id()), this->_old));
- after.add (new Property<std::string> (PropertyDescriptor<std::string> (this->property_id()), this->_current));
- }
- }
+ Property (PropertyDescriptor<std::string> d, std::string const & o, std::string const & c)
+ : PropertyTemplate<std::string> (d, o, c)
+ {}
+
+ Property<std::string>* clone () const {
+ return new Property<std::string> (this->property_id(), _old, _current);
+ }
- std::string & operator=(std::string const& v) {
+ std::string & operator= (std::string const& v) {
this->set (v);
return this->_current;
}
private:
std::string to_string (std::string const& v) const {
- return _current;
+ return v;
}
std::string from_string (std::string const& s) const {
return s;
}
+ /* no copy-construction */
+ Property (Property<std::string> const &);
};
+template<class T>
+class EnumProperty : public Property<T>
+{
+public:
+ EnumProperty (PropertyDescriptor<T> q, T const& v)
+ : Property<T> (q, 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 & s) const {
+ return static_cast<T> (string_2_enum (s, this->_current));
+ }
+
+ /* no copy-construction */
+ EnumProperty (EnumProperty const &);
+};
+
} /* namespace PBD */
#include "pbd/property_list_impl.h"