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