No-op: rename a few variables and add/fix some comments.
[ardour.git] / libs / pbd / pbd / properties.h
1 /*
2     Copyright (C) 2010 Paul Davis
3
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.
8
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.
13
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.
17
18 */
19
20 #ifndef __pbd_properties_h__
21 #define __pbd_properties_h__
22
23 #include <string>
24 #include <sstream>
25 #include <list>
26 #include <set>
27 #include <glib.h>
28
29 #include "pbd/xml++.h"
30 #include "pbd/property_basics.h"
31 #include "pbd/property_list.h"
32
33 namespace PBD {
34
35 /** Parent class for classes which represent a single scalar property in a Stateful object 
36  */
37 template<class T>
38 class PropertyTemplate : public PropertyBase
39 {
40 public:
41         PropertyTemplate (PropertyDescriptor<T> p, T const& v)
42                 : PropertyBase (p.property_id)
43                 , _have_old (false)
44                 , _current (v)
45         {}
46
47         PropertyTemplate<T>& operator=(PropertyTemplate<T> const& s) {
48                 /* XXX: isn't there a nicer place to do this? */
49                 _have_old    = s._have_old;
50                 _property_id = s._property_id;
51
52                 _current = s._current;
53                 _old     = s._old;
54                 return *this;
55         }
56
57         T & operator=(T const& v) {
58                 set (v);
59                 return _current;
60         }
61
62         T & operator+=(T const& v) {
63                 set (_current + v);
64                 return _current;
65         }
66
67         bool operator==(const T& other) const {
68                 return _current == other;
69         }
70
71         bool operator!=(const T& other) const {
72                 return _current != other;
73         }
74
75         operator T const &() const {
76                 return _current;
77         }
78
79         T const& val () const {
80                 return _current;
81         }
82
83         void clear_history () {
84                 _have_old = false;
85         }
86
87         void add_history_state (XMLNode* history_node) const {
88                 /* We can get to the current state of a scalar property like this one simply
89                    by knowing what the new state is.
90                 */
91                 history_node->add_property (property_name(), to_string (_current));
92         }
93
94         /** Try to set state from the property of an XML node.
95          *  @param node XML node.
96          *  @return true if the value of the property is changed
97          */
98         bool set_state_from_owner_state (XMLNode const& owner_state) {
99
100                 XMLProperty const* p = owner_state.property (property_name());
101
102                 if (p) {
103                         T const v = from_string (p->value ());
104
105                         if (v != _current) {
106                                 set (v);
107                                 return true;
108                         }
109                 }
110
111                 return false;
112         }
113
114         void add_state_to_owner_state (XMLNode& owner_state) const {
115                 owner_state.add_property (property_name(), to_string (_current));
116         }
117
118         bool changed () const { return _have_old; }
119         void set_state_from_property (PropertyBase const * p) {
120                 T v = dynamic_cast<const PropertyTemplate<T>* > (p)->val ();
121                 if (v != _current) {
122                         set (v);
123                 }
124         }
125
126 protected:
127         /** Constructs a PropertyTemplate with a default
128             value for _old and _current.
129         */
130
131         PropertyTemplate (PropertyDescriptor<T> p)
132                 : PropertyBase (p.property_id)
133         {}
134
135         void set (T const& v) {
136                 if (!_have_old) {
137                         _old      = _current;
138                         _have_old = true;
139                 }
140                 _current  = v;
141         }
142
143         virtual std::string to_string (T const& v) const             = 0;
144         virtual T           from_string (std::string const& s) const = 0;
145
146         bool _have_old;
147         T _current;
148         T _old;
149 };
150
151 template<class T>
152 std::ostream & operator<<(std::ostream& os, PropertyTemplate<T> const& s)
153 {
154         return os << s.val ();
155 }
156
157 /** Representation of a single piece of scalar state in a Stateful; for use
158  *  with types that can be written to / read from stringstreams.
159  */
160 template<class T>
161 class Property : public PropertyTemplate<T>
162 {
163 public:
164         Property (PropertyDescriptor<T> q, T const& v)
165                 : PropertyTemplate<T> (q, v)
166         {}
167         
168         void diff (PropertyList& undo, PropertyList& redo) const {
169                 if (this->_have_old) {
170                         undo.add (new Property<T> (this->property_id(), this->_old));
171                         redo.add (new Property<T> (this->property_id(), this->_current));
172                 }
173         }
174
175         Property<T>* maybe_clone_self_if_found_in_history_node (const XMLNode& node) const {
176                 const XMLProperty* prop = node.property (this->property_name());
177                 if (!prop) {
178                         return 0;
179                 }
180                 return new Property<T> (this->property_id(), from_string (prop->value()));
181         }
182
183         T & operator=(T const& v) {
184                 this->set (v);
185                 return this->_current;
186         }
187
188 private:
189         friend class PropertyFactory;
190
191         Property (PropertyDescriptor<T> q)
192                 : PropertyTemplate<T> (q)
193         {}
194
195         /* Note that we do not set a locale for the streams used
196          * in to_string() or from_string(), because we want the
197          * format to be portable across locales (i.e. C or
198          * POSIX). Also, there is the small matter of
199          * std::locale aborting on OS X if used with anything
200          * other than C or POSIX locales.
201          */
202         std::string to_string (T const& v) const {
203                 std::stringstream s;
204                 s.precision (12); // in case its floating point
205                 s << v;
206                 return s.str ();
207         }
208
209         T from_string (std::string const& s) const {
210                 std::stringstream t (s);
211                 T                 v;
212                 t >> v;
213                 return v;
214         }
215
216 };
217
218 /** Specialization, for std::string which is common and special (see to_string() and from_string()
219  *  Using stringstream to read from a std::string is easy to get wrong because of whitespace
220  *  separators, etc.
221  */
222 template<>
223 class Property<std::string> : public PropertyTemplate<std::string>
224 {
225 public:
226         Property (PropertyDescriptor<std::string> q, std::string const& v)
227                 : PropertyTemplate<std::string> (q, v)
228         {}
229
230         void diff (PropertyList& before, PropertyList& after) const {
231                 if (this->_have_old) {
232                         before.add (new Property<std::string> (PropertyDescriptor<std::string> (this->property_id()), this->_old));
233                         after.add (new Property<std::string> (PropertyDescriptor<std::string> (this->property_id()), this->_current));
234                 }
235         }
236
237         std::string & operator=(std::string const& v) {
238                 this->set (v);
239                 return this->_current;
240         }
241
242 private:
243         std::string to_string (std::string const& v) const {
244                 return _current;
245         }
246
247         std::string from_string (std::string const& s) const {
248                 return s;
249         }
250
251 };
252
253 } /* namespace PBD */
254
255 #include "pbd/property_list_impl.h"
256 #include "pbd/property_basics_impl.h"
257
258 #endif /* __pbd_properties_h__ */