2
Copyright (C) 2010 Paul Davis
4
This program is free software; you can redistribute it and/or modify
5
it under the terms of the GNU General Public License as published by
6
the Free Software Foundation; either version 2 of the License, or
7
(at your option) any later version.
9
This program is distributed in the hope that it will be useful,
10
but WITHOUT ANY WARRANTY; without even the implied warranty of
11
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12
GNU General Public License for more details.
14
You should have received a copy of the GNU General Public License
15
along with this program; if not, write to the Free Software
16
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20
#ifndef __pbd_properties_h__
21
#define __pbd_properties_h__
29
#include "pbd/xml++.h"
30
#include "pbd/property_basics.h"
31
#include "pbd/property_list.h"
32
#include "pbd/enumwriter.h"
33
#include "pbd/stateful.h"
37
/** Parent class for classes which represent a single scalar property in a Stateful object */
39
class PropertyTemplate : public PropertyBase
42
PropertyTemplate (PropertyDescriptor<T> p, T const& v)
43
: PropertyBase (p.property_id)
48
PropertyTemplate (PropertyDescriptor<T> p, T const& o, T const& c)
49
: PropertyBase (p.property_id)
55
PropertyTemplate (PropertyDescriptor<T> p, PropertyTemplate<T> const & s)
56
: PropertyBase (p.property_id)
58
, _current (s._current)
62
/* OPERATORS / ACCESSORS */
64
T & operator=(T const& v) {
69
/* This will mean that, if fred and jim are both PropertyTemplates,
70
* fred = jim will result in fred taking on jim's current value,
71
* but NOT jim's property ID.
73
PropertyTemplate<T> & operator= (PropertyTemplate<T> const & p) {
78
T & operator+=(T const& v) {
83
bool operator==(const T& other) const {
84
return _current == other;
87
bool operator!=(const T& other) const {
88
return _current != other;
91
operator T const &() const {
95
T const& val () const {
100
/* MANAGEMENT OF Stateful State */
102
bool set_value (XMLNode const & node) {
104
XMLProperty const* p = node.property (property_name());
107
T const v = from_string (p->value ());
118
void get_value (XMLNode & node) const {
119
node.add_property (property_name(), to_string (_current));
123
/* MANAGEMENT OF HISTORY */
125
void clear_changes () {
129
bool changed () const { return _have_old; }
132
T const tmp = _current;
138
/* TRANSFERRING HISTORY TO / FROM A StatefulDiffCommand */
140
void get_changes_as_xml (XMLNode* history_node) const {
141
XMLNode* node = history_node->add_child (property_name());
142
node->add_property ("from", to_string (_old));
143
node->add_property ("to", to_string (_current));
146
void get_changes_as_properties (PropertyList& changes, Command *) const {
147
if (this->_have_old) {
148
changes.add (clone ());
155
void apply_changes (PropertyBase const * p) {
156
T v = dynamic_cast<const PropertyTemplate<T>* > (p)->val ();
164
void set (T const& v) {
171
/* value has been reset to the value
172
at the start of a history transaction,
173
before clear_changes() is called.
174
thus there is effectively no apparent
175
history for this property.
185
virtual std::string to_string (T const& v) const = 0;
186
virtual T from_string (std::string const& s) const = 0;
193
/* disallow copy-construction; it's not obvious whether it should mean
194
a copy of just the value, or the value and property ID.
196
PropertyTemplate (PropertyTemplate<T> const &);
200
std::ostream & operator<<(std::ostream& os, PropertyTemplate<T> const& s)
202
return os << s.val ();
205
/** Representation of a single piece of scalar state in a Stateful; for use
206
* with types that can be written to / read from stringstreams.
209
class Property : public PropertyTemplate<T>
212
Property (PropertyDescriptor<T> q, T const& v)
213
: PropertyTemplate<T> (q, v)
216
Property (PropertyDescriptor<T> q, T const& o, T const& c)
217
: PropertyTemplate<T> (q, o, c)
220
Property (PropertyDescriptor<T> q, Property<T> const& v)
221
: PropertyTemplate<T> (q, v)
224
Property<T>* clone () const {
225
return new Property<T> (this->property_id(), this->_old, this->_current);
228
Property<T>* clone_from_xml (const XMLNode& node) const {
229
XMLNodeList const & children = node.children ();
230
XMLNodeList::const_iterator i = children.begin();
231
while (i != children.end() && (*i)->name() != this->property_name()) {
235
if (i == children.end()) {
238
XMLProperty* from = (*i)->property ("from");
239
XMLProperty* to = (*i)->property ("to");
245
return new Property<T> (this->property_id(), from_string (from->value()), from_string (to->value ()));
248
T & operator=(T const& v) {
250
return this->_current;
254
friend class PropertyFactory;
256
/* no copy-construction */
257
Property (Property<T> const &);
259
/* Note that we do not set a locale for the streams used
260
* in to_string() or from_string(), because we want the
261
* format to be portable across locales (i.e. C or
262
* POSIX). Also, there is the small matter of
263
* std::locale aborting on OS X if used with anything
264
* other than C or POSIX locales.
266
virtual std::string to_string (T const& v) const {
268
s.precision (12); // in case its floating point
273
virtual T from_string (std::string const& s) const {
274
std::stringstream t (s);
282
/** Specialization, for std::string which is common and special (see to_string() and from_string()
283
* Using stringstream to read from a std::string is easy to get wrong because of whitespace
287
class Property<std::string> : public PropertyTemplate<std::string>
290
Property (PropertyDescriptor<std::string> d, std::string const & v)
291
: PropertyTemplate<std::string> (d, v)
294
Property (PropertyDescriptor<std::string> d, std::string const & o, std::string const & c)
295
: PropertyTemplate<std::string> (d, o, c)
298
Property<std::string>* clone () const {
299
return new Property<std::string> (this->property_id(), _old, _current);
302
std::string & operator= (std::string const& v) {
304
return this->_current;
308
std::string to_string (std::string const& v) const {
312
std::string from_string (std::string const& s) const {
316
/* no copy-construction */
317
Property (Property<std::string> const &);
321
class EnumProperty : public Property<T>
324
EnumProperty (PropertyDescriptor<T> q, T const& v)
328
T & operator=(T const& v) {
330
return this->_current;
334
std::string to_string (T const & v) const {
335
return enum_2_string (v);
338
T from_string (std::string const & s) const {
339
return static_cast<T> (string_2_enum (s, this->_current));
342
/* no copy-construction */
343
EnumProperty (EnumProperty const &);
346
/** A Property which holds a shared_ptr to a Stateful object,
347
* and handles undo using the somewhat inefficient approach
348
* of saving the complete XML state of its object before and
349
* after changes. A sort of half-way house between the old
350
* complete-state undo system and the new difference-based
354
class SharedStatefulProperty : public PropertyBase
357
typedef boost::shared_ptr<T> Ptr;
359
SharedStatefulProperty (PropertyID d, Ptr p)
366
SharedStatefulProperty (PropertyID d, Ptr o, Ptr c)
374
bool set_value (XMLNode const & node) {
376
/* Look for our node */
377
XMLNode* n = node.child (property_name ());
382
/* And there should be one child which is the state of our T */
383
XMLNodeList const & children = n->children ();
384
if (children.size() != 1) {
388
_current->set_state (*children.front (), Stateful::current_state_version);
392
void get_value (XMLNode & node) const {
393
XMLNode* n = node.add_child (property_name ());
394
n->add_child_nocopy (_current->get_state ());
397
void clear_changes () {
398
/* We are starting to change things, so _old gets set up
399
with the current state.
401
_old.reset (new T (*_current.get()));
404
bool changed () const {
405
/* Expensive, but, hey; this requires operator!= in
408
return (*_old != *_current);
412
_current.swap (_old);
415
void get_changes_as_xml (XMLNode* history_node) const {
416
/* We express the diff as before and after state, just
417
as MementoCommand does.
419
XMLNode* p = history_node->add_child (property_name ());
420
XMLNode* from = p->add_child ("from");
421
from->add_child_nocopy (_old->get_state ());
422
XMLNode* to = p->add_child ("to");
423
to->add_child_nocopy (_current->get_state ());
426
void get_changes_as_properties (PropertyList& changes, Command *) const {
428
changes.add (clone ());
432
void apply_changes (PropertyBase const * p) {
433
*_current = *(dynamic_cast<SharedStatefulProperty const *> (p))->val ();
440
T* operator-> () const {
441
return _current.operator-> ();
444
operator bool () const {
455
/* No copy-construction nor assignment */
456
SharedStatefulProperty (SharedStatefulProperty<T> const &);
457
SharedStatefulProperty<T>& operator= (SharedStatefulProperty<T> const &);
460
} /* namespace PBD */
462
#include "pbd/property_list_impl.h"
463
#include "pbd/property_basics_impl.h"
465
#endif /* __pbd_properties_h__ */