ardour
properties.h
Go to the documentation of this file.
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 <iostream>
28 
29 #include "pbd/libpbd_visibility.h"
30 #include "pbd/xml++.h"
31 #include "pbd/property_basics.h"
32 #include "pbd/property_list.h"
33 #include "pbd/enumwriter.h"
34 #include "pbd/stateful.h"
35 
36 namespace PBD {
37 
39 template<class T>
40 class /*LIBPBD_API*/ PropertyTemplate : public PropertyBase
41 {
42 public:
45  , _have_old (false)
46  , _current (v)
47  {}
48 
49  PropertyTemplate (PropertyDescriptor<T> p, T const& o, T const& c)
51  , _have_old (true)
52  , _current (c)
53  , _old (o)
54  {}
55 
58  , _have_old (false)
59  , _current (s._current)
60  {}
61 
62 
63  /* OPERATORS / ACCESSORS */
64 
65  T & operator=(T const& v) {
66  set (v);
67  return _current;
68  }
69 
70  /* This will mean that, if fred and jim are both PropertyTemplates,
71  * fred = jim will result in fred taking on jim's current value,
72  * but NOT jim's property ID.
73  */
75  set (p._current);
76  return *this;
77  }
78 
79  T & operator+=(T const& v) {
80  set (_current + v);
81  return _current;
82  }
83 
84  bool operator==(const T& other) const {
85  return _current == other;
86  }
87 
88  bool operator!=(const T& other) const {
89  return _current != other;
90  }
91 
92  operator T const &() const {
93  return _current;
94  }
95 
96  T const& val () const {
97  return _current;
98  }
99 
100 
101  /* MANAGEMENT OF Stateful State */
102 
103  bool set_value (XMLNode const & node) {
104 
105  XMLProperty const* p = node.property (property_name());
106 
107  if (p) {
108  T const v = from_string (p->value ());
109 
110  if (v != _current) {
111  set (v);
112  return true;
113  }
114  }
115 
116  return false;
117  }
118 
119  void get_value (XMLNode & node) const {
121  }
122 
123 
124  /* MANAGEMENT OF HISTORY */
125 
126  void clear_changes () {
127  _have_old = false;
128  }
129 
130  bool changed () const { return _have_old; }
131 
132  void invert () {
133  T const tmp = _current;
134  _current = _old;
135  _old = tmp;
136  }
137 
138 
139  /* TRANSFERRING HISTORY TO / FROM A StatefulDiffCommand */
140 
141  void get_changes_as_xml (XMLNode* history_node) const {
142  XMLNode* node = history_node->add_child (property_name());
143  node->add_property ("from", to_string (_old));
144  node->add_property ("to", to_string (_current));
145  }
146 
147  void get_changes_as_properties (PropertyList& changes, Command *) const {
148  if (this->_have_old) {
149  changes.add (clone ());
150  }
151  }
152 
153 
154  /* VARIOUS */
155 
156  void apply_changes (PropertyBase const * p) {
157  T v = dynamic_cast<const PropertyTemplate<T>* > (p)->val ();
158  if (v != _current) {
159  set (v);
160  }
161  }
162 
163 protected:
164 
165  void set (T const& v) {
166  if (v != _current) {
167  if (!_have_old) {
168  _old = _current;
169  _have_old = true;
170  } else {
171  if (v == _old) {
172  /* value has been reset to the value
173  at the start of a history transaction,
174  before clear_changes() is called.
175  thus there is effectively no apparent
176  history for this property.
177  */
178  _have_old = false;
179  }
180  }
181 
182  _current = v;
183  }
184  }
185 
186  virtual std::string to_string (T const& v) const = 0;
187  virtual T from_string (std::string const& s) const = 0;
188 
189  bool _have_old;
191  T _old;
192 
193 private:
194  /* disallow copy-construction; it's not obvious whether it should mean
195  a copy of just the value, or the value and property ID.
196  */
198 };
199 
200 template<class T> /*LIBPBD_API*/
201 std::ostream & operator<<(std::ostream& os, PropertyTemplate<T> const& s)
202 {
203  return os << s.val ();
204 }
205 
209 template<class T>
210 class /*LIBPBD_API*/ Property : public PropertyTemplate<T>
211 {
212 public:
214  : PropertyTemplate<T> (q, v)
215  {}
216 
217  Property (PropertyDescriptor<T> q, T const& o, T const& c)
218  : PropertyTemplate<T> (q, o, c)
219  {}
220 
222  : PropertyTemplate<T> (q, v)
223  {}
224 
225  Property<T>* clone () const {
226  return new Property<T> (this->property_id(), this->_old, this->_current);
227  }
228 
229  Property<T>* clone_from_xml (const XMLNode& node) const {
230  XMLNodeList const & children = node.children ();
231  XMLNodeList::const_iterator i = children.begin();
232  while (i != children.end() && (*i)->name() != this->property_name()) {
233  ++i;
234  }
235 
236  if (i == children.end()) {
237  return 0;
238  }
239  XMLProperty* from = (*i)->property ("from");
240  XMLProperty* to = (*i)->property ("to");
241 
242  if (!from || !to) {
243  return 0;
244  }
245 
246  return new Property<T> (this->property_id(), from_string (from->value()), from_string (to->value ()));
247  }
248 
249  T & operator=(T const& v) {
250  this->set (v);
251  return this->_current;
252  }
253 
254 private:
255  friend class PropertyFactory;
256 
257  /* no copy-construction */
258  Property (Property<T> const &);
259 
260  /* Note that we do not set a locale for the streams used
261  * in to_string() or from_string(), because we want the
262  * format to be portable across locales (i.e. C or
263  * POSIX). Also, there is the small matter of
264  * std::locale aborting on OS X if used with anything
265  * other than C or POSIX locales.
266  */
267  virtual std::string to_string (T const& v) const {
268  std::stringstream s;
269  s.precision (12); // in case its floating point
270  s << v;
271  return s.str ();
272  }
273 
274  virtual T from_string (std::string const& s) const {
275  std::stringstream t (s);
276  T v;
277  t >> v;
278  return v;
279  }
280 
281 };
282 
287 template<>
288 class /*LIBPBD_API*/ Property<std::string> : public PropertyTemplate<std::string>
289 {
290 public:
291  Property (PropertyDescriptor<std::string> d, std::string const & v)
292  : PropertyTemplate<std::string> (d, v)
293  {}
294 
295  Property (PropertyDescriptor<std::string> d, std::string const & o, std::string const & c)
296  : PropertyTemplate<std::string> (d, o, c)
297  {}
298 
300  return new Property<std::string> (this->property_id(), _old, _current);
301  }
302 
303  std::string & operator= (std::string const& v) {
304  this->set (v);
305  return this->_current;
306  }
307 
308 private:
309  std::string to_string (std::string const& v) const {
310  return v;
311  }
312 
313  std::string from_string (std::string const& s) const {
314  return s;
315  }
316 
317  /* no copy-construction */
319 };
320 
321 template<class T>
322 class /*LIBPBD_API*/ EnumProperty : public Property<T>
323 {
324 public:
326  : Property<T> (q, v)
327  {}
328 
329  T & operator=(T const& v) {
330  this->set (v);
331  return this->_current;
332  }
333 
334 private:
335  std::string to_string (T const & v) const {
336  return enum_2_string (v);
337  }
338 
339  T from_string (std::string const & s) const {
340  return static_cast<T> (string_2_enum (s, this->_current));
341  }
342 
343  /* no copy-construction */
344  EnumProperty (EnumProperty const &);
345 };
346 
354 template <class T>
355 class /*LIBPBD_API*/ SharedStatefulProperty : public PropertyBase
356 {
357 public:
359 
361  : PropertyBase (d)
362  , _current (p)
363  {
364 
365  }
366 
368  : PropertyBase (d)
369  , _old (o)
370  , _current (c)
371  {
372 
373  }
374 
375  bool set_value (XMLNode const & node) {
376 
377  /* Look for our node */
378  XMLNode* n = node.child (property_name ());
379  if (!n) {
380  return false;
381  }
382 
383  /* And there should be one child which is the state of our T */
384  XMLNodeList const & children = n->children ();
385  if (children.size() != 1) {
386  return false;
387  }
388 
389  _current->set_state (*children.front (), Stateful::current_state_version);
390  return true;
391  }
392 
393  void get_value (XMLNode & node) const {
394  XMLNode* n = node.add_child (property_name ());
395  n->add_child_nocopy (_current->get_state ());
396  }
397 
398  void clear_changes () {
399  /* We are starting to change things, so _old gets set up
400  with the current state.
401  */
402  _old.reset (new T (*_current.get()));
403  }
404 
405  bool changed () const {
406  /* Expensive, but, hey; this requires operator!= in
407  our T
408  */
409  return (*_old != *_current);
410  }
411 
412  void invert () {
413  _current.swap (_old);
414  }
415 
416  void get_changes_as_xml (XMLNode* history_node) const {
417  /* We express the diff as before and after state, just
418  as MementoCommand does.
419  */
420  XMLNode* p = history_node->add_child (property_name ());
421  XMLNode* from = p->add_child ("from");
422  from->add_child_nocopy (_old->get_state ());
423  XMLNode* to = p->add_child ("to");
424  to->add_child_nocopy (_current->get_state ());
425  }
426 
427  void get_changes_as_properties (PropertyList& changes, Command *) const {
428  if (changed ()) {
429  changes.add (clone ());
430  }
431  }
432 
433  void apply_changes (PropertyBase const * p) {
434  *_current = *(dynamic_cast<SharedStatefulProperty const *> (p))->val ();
435  }
436 
437  Ptr val () const {
438  return _current;
439  }
440 
441  T* operator-> () const {
442  return _current.operator-> ();
443  }
444 
445  operator bool () const {
446  return _current ? true : false;
447  }
448 
449 protected:
450 
451  Ptr _old;
452  Ptr _current;
453 
454 private:
455 
456  /* No copy-construction nor assignment */
459 };
460 
461 } /* namespace PBD */
462 
463 #include "pbd/property_list_impl.h"
465 
466 #endif /* __pbd_properties_h__ */
std::string to_string(std::string const &v) const
Definition: properties.h:309
void apply_changes(PropertyBase const *p)
Definition: properties.h:156
const std::string & value() const
Definition: xml++.h:159
#define enum_2_string(e)
Definition: enumwriter.h:97
Property(PropertyDescriptor< T > q, Property< T > const &v)
Definition: properties.h:221
T const & val() const
Definition: properties.h:96
virtual std::string to_string(T const &v) const =0
friend class PropertyFactory
Definition: properties.h:255
Definition: Beats.hpp:239
const XMLNodeList & children(const std::string &str=std::string()) const
Definition: xml++.cc:329
SharedStatefulProperty(PropertyID d, Ptr o, Ptr c)
Definition: properties.h:367
Property< T > * clone_from_xml(const XMLNode &node) const
Definition: properties.h:229
XMLNode * add_child(const char *)
Definition: xml++.cc:351
PropertyTemplate(PropertyDescriptor< T > p, T const &v)
Definition: properties.h:43
bool set_value(XMLNode const &node)
Definition: properties.h:375
Property(PropertyDescriptor< T > q, T const &o, T const &c)
Definition: properties.h:217
virtual PropertyBase * clone() const =0
void get_changes_as_properties(PropertyList &changes, Command *) const
Definition: properties.h:147
std::list< XMLNode * > XMLNodeList
Definition: xml++.h:44
GQuark PropertyID
T & operator=(T const &v)
Definition: properties.h:65
PropertyID property_id() const
Property< std::string > * clone() const
Definition: properties.h:299
static int current_state_version
Definition: stateful.h:89
void apply_changes(PropertyBase const *p)
Definition: properties.h:433
XMLProperty * property(const char *)
Definition: xml++.cc:413
#define string_2_enum(str, e)
Definition: enumwriter.h:98
void set(T const &v)
Definition: properties.h:165
T & operator+=(T const &v)
Definition: properties.h:79
void get_changes_as_properties(PropertyList &changes, Command *) const
Definition: properties.h:427
void get_changes_as_xml(XMLNode *history_node) const
Definition: properties.h:416
T & operator=(T const &v)
Definition: properties.h:249
PropertyTemplate(PropertyDescriptor< T > p, PropertyTemplate< T > const &s)
Definition: properties.h:56
std::string from_string(std::string const &s) const
Definition: properties.h:313
bool changed() const
Definition: properties.h:130
T * get() const
Definition: shared_ptr.hpp:268
void get_value(XMLNode &node) const
Definition: properties.h:119
Property(PropertyDescriptor< std::string > d, std::string const &v)
Definition: properties.h:291
Property(PropertyDescriptor< std::string > d, std::string const &o, std::string const &c)
Definition: properties.h:295
bool set_value(XMLNode const &node)
Definition: properties.h:103
XMLProperty * add_property(const char *name, const std::string &value)
bool operator!=(const T &other) const
Definition: properties.h:88
void add_child_nocopy(XMLNode &)
Definition: xml++.cc:357
const gchar * property_name() const
PropertyTemplate(PropertyDescriptor< T > p, T const &o, T const &c)
Definition: properties.h:49
void get_value(XMLNode &node) const
Definition: properties.h:393
virtual T from_string(std::string const &s) const
Definition: properties.h:274
Definition: xml++.h:95
EnumProperty(PropertyDescriptor< T > q, T const &v)
Definition: properties.h:325
void swap(shared_ptr< T > &other)
Definition: shared_ptr.hpp:321
Definition: debug.h:30
XMLNode * child(const char *) const
Definition: xml++.cc:309
virtual std::string to_string(T const &v) const
Definition: properties.h:267
std::string to_string(T const &v) const
Definition: properties.h:335
T & operator=(T const &v)
Definition: properties.h:329
Property(PropertyDescriptor< T > q, T const &v)
Definition: properties.h:213
void get_changes_as_xml(XMLNode *history_node) const
Definition: properties.h:141
boost::shared_ptr< T > Ptr
Definition: properties.h:358
bool add(PropertyBase *prop)
virtual T from_string(std::string const &s) const =0
SharedStatefulProperty< T > & operator=(SharedStatefulProperty< T > const &)
bool operator==(const T &other) const
Definition: properties.h:84
SharedStatefulProperty(PropertyID d, Ptr p)
Definition: properties.h:360
Property< T > * clone() const
Definition: properties.h:225
T from_string(std::string const &s) const
Definition: properties.h:339