~ubuntu-branches/ubuntu/utopic/ardour3/utopic

« back to all changes in this revision

Viewing changes to libs/pbd/pbd/properties.h

  • Committer: Package Import Robot
  • Author(s): Felipe Sateler
  • Date: 2013-09-21 19:05:02 UTC
  • Revision ID: package-import@ubuntu.com-20130921190502-8gsftrku6jnzhd7v
Tags: upstream-3.4~dfsg
ImportĀ upstreamĀ versionĀ 3.4~dfsg

Show diffs side-by-side

added added

removed removed

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