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"
36 /** 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<T>& operator=(PropertyTemplate<T> const& s) {
49 /* XXX: isn't there a nicer place to do this? */
50 _have_old = s._have_old;
51 _property_id = s._property_id;
53 _current = s._current;
58 T & operator=(T const& v) {
63 T & operator+=(T const& v) {
68 bool operator==(const T& other) const {
69 return _current == other;
72 bool operator!=(const T& other) const {
73 return _current != other;
76 operator T const &() const {
80 T const& val () const {
84 void clear_history () {
88 void add_history_state (XMLNode* history_node) const {
89 /* We can get to the current state of a scalar property like this one simply
90 by knowing what the new state is.
92 history_node->add_property (property_name(), to_string (_current));
95 /** Try to set state from the property of an XML node.
96 * @param node XML node.
97 * @return true if the value of the property is changed
99 bool set_state_from_owner_state (XMLNode const& owner_state) {
101 XMLProperty const* p = owner_state.property (property_name());
104 T const v = from_string (p->value ());
115 void add_state_to_owner_state (XMLNode& owner_state) const {
116 owner_state.add_property (property_name(), to_string (_current));
119 bool changed () const { return _have_old; }
120 void set_state_from_property (PropertyBase const * p) {
121 T v = dynamic_cast<const PropertyTemplate<T>* > (p)->val ();
128 /** Constructs a PropertyTemplate with a default
129 value for _old and _current.
132 PropertyTemplate (PropertyDescriptor<T> p)
133 : PropertyBase (p.property_id)
136 void set (T const& v) {
144 virtual std::string to_string (T const& v) const = 0;
145 virtual T from_string (std::string const& s) const = 0;
153 std::ostream & operator<<(std::ostream& os, PropertyTemplate<T> const& s)
155 return os << s.val ();
158 /** Representation of a single piece of scalar state in a Stateful; for use
159 * with types that can be written to / read from stringstreams.
162 class Property : public PropertyTemplate<T>
165 Property (PropertyDescriptor<T> q, T const& v)
166 : PropertyTemplate<T> (q, v)
169 void diff (PropertyList& undo, PropertyList& redo, Command* /*ignored*/) const {
170 if (this->_have_old) {
171 undo.add (new Property<T> (this->property_id(), this->_old));
172 redo.add (new Property<T> (this->property_id(), this->_current));
176 Property<T>* maybe_clone_self_if_found_in_history_node (const XMLNode& node) const {
177 const XMLProperty* prop = node.property (this->property_name());
181 return new Property<T> (this->property_id(), from_string (prop->value()));
184 T & operator=(T const& v) {
186 return this->_current;
190 friend class PropertyFactory;
192 Property (PropertyDescriptor<T> q)
193 : PropertyTemplate<T> (q)
196 /* Note that we do not set a locale for the streams used
197 * in to_string() or from_string(), because we want the
198 * format to be portable across locales (i.e. C or
199 * POSIX). Also, there is the small matter of
200 * std::locale aborting on OS X if used with anything
201 * other than C or POSIX locales.
203 virtual std::string to_string (T const& v) const {
205 s.precision (12); // in case its floating point
210 virtual T from_string (std::string const& s) const {
211 std::stringstream t (s);
219 /** Specialization, for std::string which is common and special (see to_string() and from_string()
220 * Using stringstream to read from a std::string is easy to get wrong because of whitespace
224 class Property<std::string> : public PropertyTemplate<std::string>
227 Property (PropertyDescriptor<std::string> q, std::string const& v)
228 : PropertyTemplate<std::string> (q, v)
231 void diff (PropertyList& before, PropertyList& after, Command* /*ignored*/) const {
232 if (this->_have_old) {
233 before.add (new Property<std::string> (PropertyDescriptor<std::string> (this->property_id()), this->_old));
234 after.add (new Property<std::string> (PropertyDescriptor<std::string> (this->property_id()), this->_current));
238 std::string & operator=(std::string const& v) {
240 return this->_current;
244 std::string to_string (std::string const& v) const {
248 std::string from_string (std::string const& s) const {
255 class EnumProperty : public Property<T>
258 EnumProperty (PropertyDescriptor<T> q, T const& v)
262 T & operator=(T const& v) {
264 return this->_current;
268 std::string to_string (T const & v) const {
269 return enum_2_string (v);
272 T from_string (std::string const & s) const {
273 return static_cast<T> (string_2_enum (s, this->_current));
277 } /* namespace PBD */
279 #include "pbd/property_list_impl.h"
280 #include "pbd/property_basics_impl.h"
282 #endif /* __pbd_properties_h__ */