#include <set>
#include <iostream>
+#include "pbd/libpbd_visibility.h"
#include "pbd/xml++.h"
#include "pbd/property_basics.h"
#include "pbd/property_list.h"
#include "pbd/enumwriter.h"
+#include "pbd/stateful.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
+class /*LIBPBD_API*/ PropertyTemplate : public PropertyBase
{
public:
PropertyTemplate (PropertyDescriptor<T> p, T const& v)
, _current (s._current)
{}
+
+ /* OPERATORS / ACCESSORS */
+
T & operator=(T const& v) {
set (v);
return _current;
*/
PropertyTemplate<T> & operator= (PropertyTemplate<T> const & p) {
set (p._current);
+ return *this;
}
T & operator+=(T const& v) {
return _current;
}
- void clear_changes () {
- _have_old = false;
- }
- 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));
- }
+ /* MANAGEMENT OF Stateful State */
bool set_value (XMLNode const & node) {
node.add_property (property_name(), to_string (_current));
}
- bool changed () const { return _have_old; }
-
- void apply_changes (PropertyBase const * p) {
- T v = dynamic_cast<const PropertyTemplate<T>* > (p)->val ();
- if (v != _current) {
- set (v);
- }
+
+ /* MANAGEMENT OF HISTORY */
+
+ void clear_changes () {
+ _have_old = false;
}
+ bool changed () const { return _have_old; }
+
void invert () {
T const tmp = _current;
_current = _old;
_old = tmp;
}
- void get_changes_as_properties (PropertyList& changes, Command *) const {
- if (this->_have_old) {
+
+ /* 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:
void set (T const& 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;
- }
+ 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;
PropertyTemplate (PropertyTemplate<T> const &);
};
-template<class T>
+template<class T> /*LIBPBD_API*/
std::ostream & operator<<(std::ostream& os, PropertyTemplate<T> const& s)
{
return os << s.val ();
* with types that can be written to / read from stringstreams.
*/
template<class T>
-class Property : public PropertyTemplate<T>
+class /*LIBPBD_API*/ Property : public PropertyTemplate<T>
{
public:
Property (PropertyDescriptor<T> q, T const& 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 {
+
+ 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()) {
}
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);
* separators, etc.
*/
template<>
-class Property<std::string> : public PropertyTemplate<std::string>
+class /*LIBPBD_API*/ Property<std::string> : public PropertyTemplate<std::string>
{
public:
Property (PropertyDescriptor<std::string> d, std::string const & v)
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);
}
private:
std::string to_string (std::string const& v) const {
- return _current;
+ return v;
}
std::string from_string (std::string const& s) const {
};
template<class T>
-class EnumProperty : public Property<T>
+class /*LIBPBD_API*/ EnumProperty : public Property<T>
{
public:
EnumProperty (PropertyDescriptor<T> q, T const& v)
/* no copy-construction */
EnumProperty (EnumProperty const &);
};
-
+
+/** A Property which holds a shared_ptr to a Stateful object,
+ * and handles undo using the somewhat inefficient approach
+ * of saving the complete XML state of its object before and
+ * after changes. A sort of half-way house between the old
+ * complete-state undo system and the new difference-based
+ * one.
+ */
+template <class T>
+class /*LIBPBD_API*/ SharedStatefulProperty : public PropertyBase
+{
+public:
+ typedef boost::shared_ptr<T> Ptr;
+
+ SharedStatefulProperty (PropertyID d, Ptr p)
+ : PropertyBase (d)
+ , _current (p)
+ {
+
+ }
+
+ SharedStatefulProperty (PropertyID d, Ptr o, Ptr c)
+ : PropertyBase (d)
+ , _old (o)
+ , _current (c)
+ {
+
+ }
+
+ bool set_value (XMLNode const & node) {
+
+ /* Look for our node */
+ XMLNode* n = node.child (property_name ());
+ if (!n) {
+ return false;
+ }
+
+ /* And there should be one child which is the state of our T */
+ XMLNodeList const & children = n->children ();
+ if (children.size() != 1) {
+ return false;
+ }
+
+ _current->set_state (*children.front (), Stateful::current_state_version);
+ return true;
+ }
+
+ void get_value (XMLNode & node) const {
+ XMLNode* n = node.add_child (property_name ());
+ n->add_child_nocopy (_current->get_state ());
+ }
+
+ void clear_changes () {
+ /* We are starting to change things, so _old gets set up
+ with the current state.
+ */
+ _old.reset (new T (*_current.get()));
+ }
+
+ bool changed () const {
+ /* Expensive, but, hey; this requires operator!= in
+ our T
+ */
+ return (*_old != *_current);
+ }
+
+ void invert () {
+ _current.swap (_old);
+ }
+
+ void get_changes_as_xml (XMLNode* history_node) const {
+ /* We express the diff as before and after state, just
+ as MementoCommand does.
+ */
+ XMLNode* p = history_node->add_child (property_name ());
+ XMLNode* from = p->add_child ("from");
+ from->add_child_nocopy (_old->get_state ());
+ XMLNode* to = p->add_child ("to");
+ to->add_child_nocopy (_current->get_state ());
+ }
+
+ void get_changes_as_properties (PropertyList& changes, Command *) const {
+ if (changed ()) {
+ changes.add (clone ());
+ }
+ }
+
+ void apply_changes (PropertyBase const * p) {
+ *_current = *(dynamic_cast<SharedStatefulProperty const *> (p))->val ();
+ }
+
+ Ptr val () const {
+ return _current;
+ }
+
+ T* operator-> () const {
+ return _current.operator-> ();
+ }
+
+ operator bool () const {
+ return _current ? true : false;
+ }
+
+protected:
+
+ Ptr _old;
+ Ptr _current;
+
+private:
+
+ /* No copy-construction nor assignment */
+ SharedStatefulProperty (SharedStatefulProperty<T> const &);
+ SharedStatefulProperty<T>& operator= (SharedStatefulProperty<T> const &);
+};
+
} /* namespace PBD */
#include "pbd/property_list_impl.h"