new file
[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 <list>
25 #include <glib/glib.h>
26
27 class XMLNode;
28
29 namespace PBD {
30
31 enum PropertyChange {
32         range_guarantee = ~0
33 };
34
35 PropertyChange new_change ();
36
37 /** Base (non template) part of Property */     
38 class PropertyBase
39 {
40 public:
41         PropertyBase (GQuark quark, PropertyChange c)
42                 : _have_old (false)
43                 , _property_quark (q)
44                 , _change (c)
45         {
46
47         }
48
49         /** Forget about any old value for this state */
50         void clear_history () {
51                 _have_old = false;
52         }
53
54         virtual void diff (XMLNode *, XMLNode *) const = 0;
55         virtual PropertyChange set_state (XMLNode const &) = 0;
56         virtual void add_state (XMLNode &) const = 0;
57
58         std::string property_name() const { return g_quark_to_string (_property_quark); }
59         PropertyChange change() const { return _change; }
60
61         bool operator== (GQuark q) const {
62                 return _property_quark == q;
63         }
64
65 protected:
66         bool _have_old;
67         GQuark _property_quark;
68         PropertyChange _change;
69 };
70
71 /** Parent class for classes which represent a single property in a Stateful object */
72 template <class T>
73 class PropertyTemplate : public PropertyBase
74 {
75 public:
76         PropertyTemplate (GQuark q, PropertyChange c, T const & v)
77                 : PropertyBase (q, c)
78                 , _current (v)
79         {
80
81         }
82
83         PropertyTemplate<T> & operator= (PropertyTemplate<T> const & s) {
84                 /* XXX: isn't there a nicer place to do this? */
85                 _have_old = s._have_old;
86                 _property_quark = s._property_quark;
87                 _change = s._change;
88                 
89                 _current = s._current;
90                 _old = s._old;
91                 return *this;
92         }
93
94         T & operator= (T const & v) {
95                 set (v);
96                 return _current;
97         }
98
99         T & operator+= (T const & v) {
100                 set (_current + v);
101                 return _current;
102         }
103         
104         bool operator== (const T& other) const {
105                 return _current == other;
106         }
107
108         bool operator!= (const T& other) const {
109                 return _current != other;
110         }
111
112         operator T const & () const {
113                 return _current;
114         }
115
116         T const & val () const {
117                 return _current;
118         }
119
120         void diff (XMLNode* old, XMLNode* current) const {
121                 if (_have_old) {
122                         old->add_property (g_quark_to_string (_property_quark), to_string (_old));
123                         current->add_property (g_quark_to_string (_property_quark), to_string (_current));
124                 }
125         }
126
127         /** Try to set state from the property of an XML node.
128          *  @param node XML node.
129          *  @return PropertyChange effected, or 0.
130          */
131         PropertyChange set_state (XMLNode const & node) {
132                 XMLProperty const * p = node.property (g_quark_to_string (_property_quark));
133
134                 if (p) {
135                         T const v = from_string (p->value ());
136
137                         if (v == _current) {
138                                 return PropertyChange (0);
139                         }
140
141                         set (v);
142                         return _change;
143                 }
144
145                 return PropertyChange (0);
146         }
147
148         void add_state (XMLNode & node) const {
149                 node.add_property (g_quark_to_string (_property_quark), to_string (_current));
150         }
151
152 protected:
153         void set (T const & v) {
154                 _old = _current;
155                 _have_old = true;
156                 _current = v;
157         }
158
159         virtual std::string to_string (T const & v) const = 0;
160         virtual T from_string (std::string const & s) const = 0;
161                 
162         T _current;
163         T _old;
164 };
165
166 template<class T>       
167 std::ostream& operator<< (std::ostream& os, PropertyTemplate<T> const & s)
168 {
169         return os << s.val();
170 }
171
172 /** Representation of a single piece of state in a Stateful; for use
173  *  with types that can be written to / read from stringstreams.
174  */
175 template <class T>
176 class Property : public PropertyTemplate<T>
177 {
178 public:
179         Property (GQuark q, PropertyChange c, T const & v)
180                 : PropertyTemplate<T> (q, c, v)
181         {
182
183         }
184         
185         T & operator= (T const & v) {
186                 this->set (v);
187                 return this->_current;
188         }
189         
190 private:        
191         std::string to_string (T const & v) const {
192                 // XXX LocaleGuard
193                 std::stringstream s;
194                 s.precision (12); // in case its floating point
195                 s << v;
196                 return s.str ();
197         }
198
199         T from_string (std::string const & s) const {
200                 // XXX LocaleGuard      
201                 std::stringstream t (s);
202                 T v;
203                 t.precision (12); // in case its floating point
204                 t >> v;
205                 return v;
206         }
207 };
208
209 } /* namespace PBD */
210
211 #endif /* __pbd_properties_h__ */