Ardour  8.12
properties.h
Go to the documentation of this file.
1 /*
2  * Copyright (C) 2010-2012 Carl Hetherington <carl@carlh.net>
3  * Copyright (C) 2010-2016 Paul Davis <paul@linuxaudiosystems.com>
4  * Copyright (C) 2010 David Robillard <d@drobilla.net>
5  * Copyright (C) 2014-2015 Robin Gareus <robin@gareus.org>
6  * Copyright (C) 2015-2016 Tim Mayberry <mojofunk@gmail.com>
7  *
8  * This program is free software; you can redistribute it and/or modify
9  * it under the terms of the GNU General Public License as published by
10  * the Free Software Foundation; either version 2 of the License, or
11  * (at your option) any later version.
12  *
13  * This program is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16  * GNU General Public License for more details.
17  *
18  * You should have received a copy of the GNU General Public License along
19  * with this program; if not, write to the Free Software Foundation, Inc.,
20  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
21  */
22 
23 #ifndef __pbd_properties_h__
24 #define __pbd_properties_h__
25 
26 #include <string>
27 #include <list>
28 #include <set>
29 
30 #include "pbd/libpbd_visibility.h"
31 #include "pbd/xml++.h"
32 #include "pbd/property_basics.h"
33 #include "pbd/property_list.h"
34 #include "pbd/enumwriter.h"
35 #include "pbd/stateful.h"
36 #include "pbd/string_convert.h"
37 
38 namespace PBD {
39 
41 template<class T>
42 class /*LIBPBD_API*/ PropertyTemplate : public PropertyBase
43 {
44 public:
47  , _have_old (false)
48  , _current (v)
49  {}
50 
51  PropertyTemplate (PropertyDescriptor<T> p, T const& o, T const& c)
53  , _have_old (true)
54  , _current (c)
55  , _old (o)
56  {}
57 
60  , _have_old (false)
61  , _current (s._current)
62  {}
63 
64 
65  /* OPERATORS / ACCESSORS */
66 
67  T & operator=(T const& v) {
68  set (v);
69  return _current;
70  }
71 
72  /* This will mean that, if fred and jim are both PropertyTemplates,
73  * fred = jim will result in fred taking on jim's current value,
74  * but NOT jim's property ID.
75  */
77  set (p._current);
78  return *this;
79  }
80 
81  T & operator+=(T const& v) {
82  set (_current + v);
83  return _current;
84  }
85 
86  T operator- (T const other) const {
87  return _current - other;
88  }
89 
90  bool operator< (T const &other) const {
91  return _current < other;
92  }
93 
94  bool operator> (T const &other) const {
95  return _current > other;
96  }
97 
98  bool operator==(const T& other) const {
99  return _current == other;
100  }
101 
102  bool operator!=(const T& other) const {
103  return _current != other;
104  }
105 
106  operator T const &() const {
107  return _current;
108  }
109 
110  T const& val () const {
111  return _current;
112  }
113 
115  return _current;
116  }
117 
118  /* MANAGEMENT OF Stateful State */
119 
120  bool set_value (XMLNode const & node) {
121 
122  XMLProperty const* p = node.property (property_name());
123 
124  if (p) {
125  T const v = from_string (p->value ());
126 
127  if (v != _current) {
128  set (v);
129  return true;
130  }
131  }
132 
133  return false;
134  }
135 
136  void get_value (XMLNode & node) const {
138  }
139 
140 
141  /* MANAGEMENT OF HISTORY */
142 
143  void clear_changes () {
144  _have_old = false;
145  }
146 
147  bool changed () const { return _have_old; }
148 
149  void invert () {
150  T const tmp = _current;
151  _current = _old;
152  _old = tmp;
153  }
154 
155 
156  /* TRANSFERRING HISTORY TO / FROM A StatefulDiffCommand */
157 
158  void get_changes_as_xml (XMLNode* history_node) const {
159  XMLNode* node = history_node->add_child (property_name());
160  node->set_property ("from", _old);
161  node->set_property ("to", _current);
162  }
163 
164  void get_changes_as_properties (PropertyList& changes, Command *) const {
165  if (this->_have_old) {
166  changes.add (clone ());
167  }
168  }
169 
170 
171  /* VARIOUS */
172 
173  void apply_change (PropertyBase const * p) {
174  T v = dynamic_cast<const PropertyTemplate<T>* > (p)->val ();
175  if (v != _current) {
176  set (v);
177  }
178  }
179 
180 protected:
181 
182  void set (T const& v) {
183  if (v != _current) {
184  if (!_have_old) {
185  _old = _current;
186  _have_old = true;
187  } else {
188  if (v == _old) {
189  /* value has been reset to the value
190  at the start of a history transaction,
191  before clear_changes() is called.
192  thus there is effectively no apparent
193  history for this property.
194  */
195  _have_old = false;
196  }
197  }
198 
199  _current = v;
200  }
201  }
202 
203  virtual std::string to_string (T const& v) const = 0;
204  virtual T from_string (std::string const& s) const = 0;
205 
206  bool _have_old;
208  T _old;
209 
210 private:
211  /* disallow copy-construction; it's not obvious whether it should mean
212  a copy of just the value, or the value and property ID.
213  */
215 };
216 
217 template<class T> /*LIBPBD_API*/
218 std::ostream & operator<<(std::ostream& os, PropertyTemplate<T> const& s)
219 {
220  return os << s.val ();
221 }
222 
226 template<class T>
227 class /*LIBPBD_API*/ Property : public PropertyTemplate<T>
228 {
229 public:
231  : PropertyTemplate<T> (q, v)
232  {}
233 
234  Property (PropertyDescriptor<T> q, T const& o, T const& c)
235  : PropertyTemplate<T> (q, o, c)
236  {}
237 
239  : PropertyTemplate<T> (q, v)
240  {}
241 
242  Property<T>* clone () const {
243  return new Property<T> (this->property_id(), this->_old, this->_current);
244  }
245 
246  Property<T>* clone_from_xml (const XMLNode& node) const {
247  XMLNodeList const & children = node.children ();
248  XMLNodeList::const_iterator i = children.begin();
249  while (i != children.end() && (*i)->name() != this->property_name()) {
250  ++i;
251  }
252 
253  if (i == children.end()) {
254  return 0;
255  }
256  XMLProperty const * from = (*i)->property ("from");
257  XMLProperty const * to = (*i)->property ("to");
258 
259  if (!from || !to) {
260  return 0;
261  }
262 
263  return new Property<T> (this->property_id(), from_string (from->value()), from_string (to->value ()));
264  }
265 
266  T & operator=(T const& v) {
267  this->set (v);
268  return this->_current;
269  }
270 
272  this->set (v);
273  return *this;
274  }
275 
276 private:
277  friend class PropertyFactory;
278 
279  /* no copy-construction */
281 
282  /* Note that we do not set a locale for the streams used
283  * in to_string() or from_string(), because we want the
284  * format to be portable across locales (i.e. C or
285  * POSIX). Also, there is the small matter of
286  * std::locale aborting on OS X if used with anything
287  * other than C or POSIX locales.
288  */
289  virtual std::string to_string (T const& v) const {
290  return PBD::to_string (v);
291  }
292 
293  virtual T from_string (std::string const& s) const {
294  return PBD::string_to<T>(s);
295  }
296 
297 };
298 
303 template<>
304 class /*LIBPBD_API*/ Property<std::string> : public PropertyTemplate<std::string>
305 {
306 public:
307  Property (PropertyDescriptor<std::string> d, std::string const & v)
308  : PropertyTemplate<std::string> (d, v)
309  {}
310 
311  Property (PropertyDescriptor<std::string> d, std::string const & o, std::string const & c)
312  : PropertyTemplate<std::string> (d, o, c)
313  {}
314 
316  return new Property<std::string> (this->property_id(), _old, _current);
317  }
318 
319  std::string & operator= (std::string const& v) {
320  this->set (v);
321  return this->_current;
322  }
323 
324 private:
325  std::string to_string (std::string const& v) const {
326  return v;
327  }
328 
329  std::string from_string (std::string const& s) const {
330  return s;
331  }
332 
333  /* no copy-construction */
335 };
336 
337 template<class T>
338 class /*LIBPBD_API*/ EnumProperty : public Property<T>
339 {
340 public:
342  : Property<T> (q, v)
343  {}
344 
345  T & operator=(T const& v) {
346  this->set (v);
347  return this->_current;
348  }
349 
350 private:
351  std::string to_string (T const & v) const {
352  return enum_2_string (v);
353  }
354 
355  T from_string (std::string const & s) const {
356  return static_cast<T> (string_2_enum (s, this->_current));
357  }
358 
359  /* no copy-construction */
362 };
363 
371 template <class T>
372 class /*LIBPBD_API*/ SharedStatefulProperty : public PropertyBase
373 {
374 public:
375  typedef std::shared_ptr<T> Ptr;
376 
378  : PropertyBase (d)
379  , _current (p)
380  {
381 
382  }
383 
385  : PropertyBase (d)
386  , _old (o)
387  , _current (c)
388  {
389 
390  }
391 
392  bool set_value (XMLNode const & node) {
393 
394  /* Look for our node */
395  XMLNode* n = node.child (property_name ());
396  if (!n) {
397  return false;
398  }
399 
400  /* And there should be one child which is the state of our T */
401  XMLNodeList const & children = n->children ();
402  if (children.size() != 1) {
403  return false;
404  }
405 
406  _current->set_state (*children.front (), Stateful::current_state_version);
407  return true;
408  }
409 
410  void get_value (XMLNode & node) const {
411  XMLNode* n = node.add_child (property_name ());
412  n->add_child_nocopy (_current->get_state ());
413  }
414 
415  void clear_changes () {
416  /* We are starting to change things, so _old gets set up
417  with the current state.
418  */
419  _old.reset (new T (*_current.get()));
420  }
421 
422  bool changed () const {
423  if (!_old) {
424  return false;
425  }
426  /* Expensive, but, hey; this requires operator!= in our T */
427  return (*_old != *_current);
428  }
429 
430  void invert () {
431  _current.swap (_old);
432  }
433 
434  void get_changes_as_xml (XMLNode* history_node) const {
435  /* We express the diff as before and after state, just
436  as MementoCommand does.
437  */
438  XMLNode* p = history_node->add_child (property_name ());
439  XMLNode* from = p->add_child ("from");
440  from->add_child_nocopy (_old->get_state ());
441  XMLNode* to = p->add_child ("to");
442  to->add_child_nocopy (_current->get_state ());
443  }
444 
445  void get_changes_as_properties (PropertyList& changes, Command *) const {
446  if (changed ()) {
447  changes.add (clone ());
448  }
449  }
450 
451  void apply_change (PropertyBase const * p) {
452  *_current = *(dynamic_cast<SharedStatefulProperty const *> (p))->val ();
453  }
454 
455  Ptr val () const {
456  return _current;
457  }
458 
459  T* operator-> () const {
460  return _current.operator-> ();
461  }
462 
463  operator bool () const {
464  return _current ? true : false;
465  }
466 
467 protected:
468 
471 
472 private:
473 
474  /* No copy-construction nor assignment */
477 };
478 
479 } /* namespace PBD */
480 
481 #include "pbd/property_list_impl.h"
483 
484 #endif /* __pbd_properties_h__ */
EnumProperty(EnumProperty const &)
T & operator=(T const &v)
Definition: properties.h:345
EnumProperty(PropertyDescriptor< T > q, T const &v)
Definition: properties.h:341
std::string to_string(T const &v) const
Definition: properties.h:351
T from_string(std::string const &s) const
Definition: properties.h:355
virtual PropertyBase * clone() const =0
const gchar * property_name() const
PropertyID property_id() const
bool add(PropertyBase *prop)
bool changed() const
Definition: properties.h:147
bool operator<(T const &other) const
Definition: properties.h:90
PropertyTemplate(PropertyDescriptor< T > p, PropertyTemplate< T > const &s)
Definition: properties.h:58
PropertyTemplate(PropertyDescriptor< T > p, T const &v)
Definition: properties.h:45
PropertyTemplate(PropertyDescriptor< T > p, T const &o, T const &c)
Definition: properties.h:51
bool set_value(XMLNode const &node)
Definition: properties.h:120
T operator-(T const other) const
Definition: properties.h:86
virtual T from_string(std::string const &s) const =0
void get_value(XMLNode &node) const
Definition: properties.h:136
bool operator>(T const &other) const
Definition: properties.h:94
bool operator!=(const T &other) const
Definition: properties.h:102
virtual std::string to_string(T const &v) const =0
T & operator+=(T const &v)
Definition: properties.h:81
PropertyTemplate(PropertyTemplate< T > const &)
void get_changes_as_properties(PropertyList &changes, Command *) const
Definition: properties.h:164
T const & val() const
Definition: properties.h:110
bool operator==(const T &other) const
Definition: properties.h:98
void apply_change(PropertyBase const *p)
Definition: properties.h:173
T & operator=(T const &v)
Definition: properties.h:67
void get_changes_as_xml(XMLNode *history_node) const
Definition: properties.h:158
void set(T const &v)
Definition: properties.h:182
std::string to_string(std::string const &v) const
Definition: properties.h:325
Property(Property< std::string > const &)
Property(PropertyDescriptor< std::string > d, std::string const &v)
Definition: properties.h:307
Property< std::string > * clone() const
Definition: properties.h:315
Property(PropertyDescriptor< std::string > d, std::string const &o, std::string const &c)
Definition: properties.h:311
std::string from_string(std::string const &s) const
Definition: properties.h:329
Property< T > * clone_from_xml(const XMLNode &node) const
Definition: properties.h:246
Property< T > * clone() const
Definition: properties.h:242
Property(PropertyDescriptor< T > q, T const &o, T const &c)
Definition: properties.h:234
friend class PropertyFactory
Definition: properties.h:277
Property< T > & operator=(Property< T > const &v)
Definition: properties.h:271
virtual T from_string(std::string const &s) const
Definition: properties.h:293
Property(Property< T > const &)
virtual std::string to_string(T const &v) const
Definition: properties.h:289
T & operator=(T const &v)
Definition: properties.h:266
Property(PropertyDescriptor< T > q, T const &v)
Definition: properties.h:230
Property(PropertyDescriptor< T > q, Property< T > const &v)
Definition: properties.h:238
void get_value(XMLNode &node) const
Definition: properties.h:410
void get_changes_as_properties(PropertyList &changes, Command *) const
Definition: properties.h:445
std::shared_ptr< T > Ptr
Definition: properties.h:375
SharedStatefulProperty(PropertyID d, Ptr o, Ptr c)
Definition: properties.h:384
SharedStatefulProperty(PropertyID d, Ptr p)
Definition: properties.h:377
SharedStatefulProperty(SharedStatefulProperty< T > const &)
SharedStatefulProperty< T > & operator=(SharedStatefulProperty< T > const &)
void apply_change(PropertyBase const *p)
Definition: properties.h:451
bool set_value(XMLNode const &node)
Definition: properties.h:392
void get_changes_as_xml(XMLNode *history_node) const
Definition: properties.h:434
static int current_state_version
Definition: stateful.h:102
Definition: xml++.h:114
const XMLNodeList & children(const std::string &str=std::string()) const
bool set_property(const char *name, const std::string &value)
XMLProperty const * property(const char *) const
XMLNode * child(const char *) const
void add_child_nocopy(XMLNode &)
XMLNode * add_child(const char *)
const std::string & value() const
Definition: xml++.h:58
#define string_2_enum(str, e)
Definition: enumwriter.h:98
#define enum_2_string(e)
Definition: enumwriter.h:97
Definition: axis_view.h:42
GQuark PropertyID
std::string to_string(ARDOUR::timepos_t val)
std::ostream & operator<<(std::ostream &os, PropertyTemplate< T > const &s)
Definition: properties.h:218
std::vector< XMLNode * > XMLNodeList
Definition: xml++.h:66