tizen 2.3 release
[framework/web/wearable/wrt-commons.git] / modules / event / include / dpl / event / property.h
1 /*
2  * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved
3  *
4  *    Licensed under the Apache License, Version 2.0 (the "License");
5  *    you may not use this file except in compliance with the License.
6  *    You may obtain a copy of the License at
7  *
8  *        http://www.apache.org/licenses/LICENSE-2.0
9  *
10  *    Unless required by applicable law or agreed to in writing, software
11  *    distributed under the License is distributed on an "AS IS" BASIS,
12  *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  *    See the License for the specific language governing permissions and
14  *    limitations under the License.
15  */
16 /*
17  * @file    property.h
18  * @author  Przemyslaw Dobrowolski (p.dobrowolsk@samsung.com)
19  * @version 1.0
20  * @brief   Header file for property
21  */
22 #ifndef DPL_PROPERTY_H
23 #define DPL_PROPERTY_H
24
25 #include <functional>
26
27 #include <dpl/event/model.h>
28 #include <dpl/event/event_support.h>
29 #include <dpl/assert.h>
30 #include <dpl/noncopyable.h>
31 #include <dpl/read_write_mutex.h>
32 #include <dpl/once.h>
33
34 namespace DPL {
35 namespace Event {
36 /**
37  * Property is a class that encapsulates model's property fields.
38  * Its main purpose is to automate things related to model's properties
39  * such as: data storage, synchronization and event emitting.
40  *
41  * Property is a template of the following schema:
42  *
43  * template class Property<type, property access rights, property storage mode>
44  *
45  * Type is an internal type that property is encapsulating. It is required
46  * that the type is default-constructible and copyable.
47  *
48  * Property access rights control which operations are allowed to be
49  * executed on property.
50  *
51  * Property storage mode is a mode describing where and how internal data should
52  * be stored.
53  *
54  * Property modifiers:
55  *
56  * PropertyStorageCached: The data is stored internally as one copy. It can
57  *                        never be changed from external.
58  *
59  * PropertyStorageDynamic: The data is stored remotely and is accessed via
60  *                         provided delegates. It can change at any time
61  *                         if external mechanism changes its value.
62  *
63  * PropertyStorageDynamicCached: The data is stored internally, but only after
64  *                               it has been retrieved by delegates. The
65  *                               changed data is stored internally and also set
66  *                               remotely with delegate. After the value has
67  *                               been received from external source, it will
68  *                               never be updated externally.
69  *
70  * Property access modes:
71  *
72  * PropertyReadOnly: Property is a read-only property.
73  *                   It doesn't have Set() method.
74  *
75  * PropertyReadWrite: Property is a read-write property. It have both Get()
76  *                    and Set() methods.
77  *
78  * Examples:
79  *
80  * Note: All properties, if not specified otherwise in template arguments,
81  * have read-write access rights and cached data storage.
82  *
83  * Simple property with int:
84  * @code DPL::Property<int> Number;
85  *
86  * A property with string:
87  * @code DPL::Property<std::string> Name;
88  *
89  * A read-only float property:
90  * @code DPL::Property<float, DPL::PropertyReadOnly> Gravity;
91  *
92  * A read-write string property:
93  * @code DPL::Property<std::string, DPL::PropertyReadWrite> Caption;
94  *
95  * A read-write string property which is stored internally:
96  * @code DPL::Property<std::string,
97  *                     DPL::PropertyReadWrite,
98  *                     DPL::PropertyStorageCached> Name;
99  *
100  * A read-write string property which is stored externally:
101  * @code DPL::Property<std::string,
102  *                     DPL::PropertyReadWrite,
103  *                     DPL::PropertyStorageDynamic> RemoteName;
104  *
105  * A read-write string property which is stored externally, but also cached:
106  * @code DPL::Property<std::string,
107  *                     DPL::PropertyReadOnly,
108  *                     DPL::PropertyStorageDynamicCached> CachedName;
109  *
110  * A model is an agregation of many properties. Whenever some of them change,
111  * an event with this change is emmited along with model handle which
112  * contains this property. These changes can be listened to. To achieve this,
113  * one have to add a delegate which contains changed property value and
114  * a pointer to the model.
115  *
116  * Example of a model with a property:
117  *
118  * @code
119  * class MyModel: public DPL::Model
120  * {
121  * public:
122  *     DPL::Property<int> Number1;
123  *     DPL::Property<int> Number2;
124  *     DPL::Property<int, DPL::PropertyReadOnly> Number3;
125  *
126  *     // Read write property delegate method can be static
127  *     static int ReadCustomValue(Model *model);
128  *
129  *     // Read write property delegate method can also be method
130  *     void WriteCustomValue(const int &value, Model *model);
131  *
132  *     MyModel()
133  *      : // Initialize property with default value and this model
134  *        Number1(this),
135  *
136  *        // Initialize property with 123 and this model
137  *        Number2(this, 123),
138  *
139  *        // Initialize property with 0 and custom read delegate and this model
140  *        Number3(this, 0, &ReadCustomValue),
141  *
142  *        // Initialize property with 7 and custom read-write delegates
143  *        // and this model
144  *        Number4(this, 7, &ReadCustomValue,
145  *                std::bind(&WriteCustomValue, this)
146  *     {
147  *     }
148  * };
149  *
150  * DPL's delegate mechanism is a general solution, which is capable of
151  * binding various types of functions and method as a delegate and
152  * using them in unified way.
153  *
154  * Example of registering and unregistering for model's property changes:
155  *
156  * @code
157  * class SomeModel : public DPL::Model
158  * {
159  * public:
160  *     DPL::Property<int> Value;
161  *
162  *     SomeModel()
163  *         : Value(this)
164  *     {
165  *     }
166  * };
167  *
168  * void ValueChanged(const int &value, Model *model)
169  * {
170  *     std::cout << "Value changed to: " << value << std::endl;
171  * }
172  *
173  * int main()
174  * {
175  *     SomeModel model;
176  *
177  *     // Register a global function as property changed listener
178  *     model.AddListener(&ValueChanged);
179  *     [...]
180  *     model.RemoveListener(&ValueChanged);
181  *
182  *     // Register a class method as property changed listener
183  *     class Receiver
184  *     {
185  *     public:
186  *         void OnValueChanged(const int &value, Model *model)
187  *         {
188  *             [...]
189  *         }
190  *     } receiver;
191  *
192  *     model.AddListener(
193  *         std::bind(&Receiver::OnValueChanged, &receiver));
194  *     [...]
195  *     model.RemoveListener(
196  *         std::bind(&Receiver::OnValueChanged, &receiver));
197  * }
198  */
199 struct PropertyStorageCached {};        ///< Always use cached
200 struct PropertyStorageDynamic {};       ///< Always use dynamic
201 struct PropertyStorageDynamicCached {}; ///< Use dynamic then cache
202
203 struct PropertyReadOnly {};  ///< Read only, not setter available
204 struct PropertyReadWrite {}; ///< Read and write
205
206 template<typename Type>
207 struct PropertyEvent
208 {
209     PropertyEvent(const Type &v, Model *s) :
210         value(v),
211         sender(s)
212     {}
213
214     Type value;
215     Model *sender;
216 };
217
218 template<typename ReadDelegateType, typename WriteDelegateType>
219 class PropertyStorageMethodDynamicBase
220 {
221   protected:
222     ReadDelegateType m_readValue;
223     WriteDelegateType m_writeValue;
224
225     PropertyStorageMethodDynamicBase(ReadDelegateType readValue,
226                                      WriteDelegateType writeValue) :
227         m_readValue(readValue),
228         m_writeValue(writeValue)
229     {}
230 };
231
232 template<typename Type>
233 class PropertyStorageMethodCachedBase
234 {
235   protected:
236     mutable Type m_value;
237
238     PropertyStorageMethodCachedBase()
239     {}
240 };
241
242 class PropertyStorageMethodBase
243 {
244   protected:
245     explicit PropertyStorageMethodBase(Model *model) :
246         m_model(model)
247     {}
248
249     Model *m_model;
250 };
251
252 template<typename Type,
253          typename StorageMethod,
254          typename ReadDelegateType,
255          typename WriteDelegateType>
256 class PropertyStorageMethod;
257
258 template<typename Type,
259          typename ReadDelegateType,
260          typename WriteDelegateType>
261 class PropertyStorageMethod<Type,
262                             PropertyStorageCached,
263                             ReadDelegateType,
264                             WriteDelegateType>:
265     protected PropertyStorageMethodBase,
266     protected PropertyStorageMethodCachedBase<Type>
267 {
268   public:
269     PropertyStorageMethod(Model *model,
270                           ReadDelegateType /*readValue*/,
271                           WriteDelegateType /*writeValue*/) :
272         PropertyStorageMethodBase(model)
273     {}
274
275     Type Get() const
276     {
277         return this->m_value;
278     }
279
280     void Set(const Type &value)
281     {
282         this->m_value = value;
283     }
284 };
285
286 template<typename Type, typename ReadDelegateType, typename WriteDelegateType>
287 class PropertyStorageMethod<Type,
288                             PropertyStorageDynamic,
289                             ReadDelegateType,
290                             WriteDelegateType>:
291     protected PropertyStorageMethodBase,
292     protected PropertyStorageMethodDynamicBase<ReadDelegateType,
293                                                WriteDelegateType>
294 {
295   public:
296     PropertyStorageMethod(Model *model,
297                           ReadDelegateType readValue,
298                           WriteDelegateType writeValue) :
299         PropertyStorageMethodBase(model),
300         PropertyStorageMethodDynamicBase<ReadDelegateType, WriteDelegateType>(
301             readValue,
302             writeValue)
303     {}
304
305     Type Get() const
306     {
307         Assert(this->m_readValue);
308         return this->m_readValue(m_model);
309     }
310
311     void Set(const Type &value)
312     {
313         Assert(this->m_writeValue);
314         this->m_writeValue(value, m_model);
315     }
316 };
317
318 template<typename Type, typename ReadDelegateType, typename WriteDelegateType>
319 class PropertyStorageMethod<Type,
320                             PropertyStorageDynamicCached,
321                             ReadDelegateType,
322                             WriteDelegateType>:
323     protected PropertyStorageMethodBase,
324     protected PropertyStorageMethodDynamicBase<ReadDelegateType,
325                                                WriteDelegateType>,
326     protected PropertyStorageMethodCachedBase<Type>
327 {
328   private:
329     typedef PropertyStorageMethod<Type,
330                                   PropertyStorageDynamicCached,
331                                   ReadDelegateType,
332                                   WriteDelegateType> ThisType;
333
334     // These two are mutable
335     void OnceEnsure() const
336     {
337         this->m_value = this->m_readValue(m_model);
338     }
339
340     void OnceDisable() const
341     {}
342
343   protected:
344     mutable Once m_once;
345
346   public:
347     PropertyStorageMethod(Model *model,
348                           ReadDelegateType readValue,
349                           WriteDelegateType writeValue) :
350         PropertyStorageMethodBase(model),
351         PropertyStorageMethodDynamicBase<ReadDelegateType, WriteDelegateType>(
352             readValue, writeValue)
353     {}
354
355     Type Get() const
356     {
357         Assert(this->m_readValue);
358         m_once.Call(std::bind(&ThisType::OnceEnsure, this));
359         return this->m_value;
360     }
361
362     void Set(const Type &value)
363     {
364         Assert(this->m_writeValue);
365
366         this->m_writeValue(value, m_model);
367         this->m_value = value;
368         m_once.Call(std::bind(&ThisType::OnceDisable, this));
369     }
370 };
371
372 template<typename Type, typename StorageMethod>
373 class PropertyBase :
374     protected EventSupport<PropertyEvent<Type> >
375 {
376   public:
377     typedef typename EventSupport<PropertyEvent<Type> >::EventListenerType
378     EventListenerType;
379
380     typedef typename EventSupport<PropertyEvent<Type> >::DelegateType
381     DelegateType;
382
383     typedef std::function<Type(Model *)>
384     ReadDelegateType;
385
386     typedef std::function<void (const Type &, Model *)>
387     WriteDelegateType;
388
389   protected:
390     PropertyStorageMethod<Type,
391                           StorageMethod,
392                           ReadDelegateType,
393                           WriteDelegateType> m_storage;
394     Model *m_model;
395
396     PropertyBase(Model *model,
397                  ReadDelegateType readValue,
398                  WriteDelegateType writeValue) :
399         m_storage(model, readValue, writeValue),
400         m_model(model)
401     {}
402
403   public:
404     virtual Type Get() const
405     {
406         ReadWriteMutex::ScopedReadLock lock(&m_model->m_mutex);
407         return m_storage.Get();
408     }
409
410     void AddListener(DelegateType delegate)
411     {
412         EventSupport<PropertyEvent<Type> >::AddListener(delegate);
413     }
414
415     void RemoveListener(DelegateType delegate)
416     {
417         EventSupport<PropertyEvent<Type> >::RemoveListener(delegate);
418     }
419 };
420
421 template<typename Type,
422          typename AccessType = PropertyReadWrite,
423          typename StorageMethod = PropertyStorageCached>
424 class Property;
425
426 template<typename Type, typename StorageMethod>
427 class Property<Type, PropertyReadOnly, StorageMethod>:
428     public PropertyBase<Type, StorageMethod>
429 {
430   public:
431     typedef typename PropertyBase<Type, StorageMethod>::EventListenerType
432     EventListenerType;
433
434     typedef typename PropertyBase<Type, StorageMethod>::DelegateType
435     DelegateType;
436
437     typedef typename PropertyBase<Type, StorageMethod>::ReadDelegateType
438     ReadDelegateType;
439
440     typedef typename PropertyBase<Type, StorageMethod>::WriteDelegateType
441     WriteDelegateType;
442
443   public:
444     explicit Property(Model *model,
445                       ReadDelegateType readValue = NULL) :
446         PropertyBase<Type, StorageMethod>(model, readValue, NULL)
447     {}
448
449     Property(Model *model,
450              const Type &value,
451              ReadDelegateType readValue = NULL) :
452         PropertyBase<Type, StorageMethod>(model, readValue, NULL)
453     {
454         this->m_storage.Set(value);
455     }
456 };
457
458 template<typename Type, typename StorageMethod>
459 class Property<Type, PropertyReadWrite, StorageMethod>:
460     public PropertyBase<Type, StorageMethod>
461 {
462   public:
463     typedef typename PropertyBase<Type, StorageMethod>::EventListenerType
464     EventListenerType;
465
466     typedef typename PropertyBase<Type, StorageMethod>::DelegateType
467     DelegateType;
468
469     typedef typename PropertyBase<Type, StorageMethod>::ReadDelegateType
470     ReadDelegateType;
471
472     typedef typename PropertyBase<Type, StorageMethod>::WriteDelegateType
473     WriteDelegateType;
474
475   public:
476     explicit Property(Model *model,
477                       ReadDelegateType readValue = NULL,
478                       WriteDelegateType writeValue = NULL) :
479         PropertyBase<Type, StorageMethod>(model, readValue, writeValue)
480     {}
481
482     Property(Model *model,
483              const Type &value,
484              ReadDelegateType readValue = NULL,
485              WriteDelegateType writeValue = NULL) :
486         PropertyBase<Type, StorageMethod>(model, readValue, writeValue)
487     {
488         this->m_storage.Set(value);
489     }
490
491     virtual void Set(const Type &value)
492     {
493         ReadWriteMutex::ScopedWriteLock lock(&this->m_model->m_mutex);
494
495         if (this->m_storage.Get() == value) {
496             return;
497         }
498
499         this->m_storage.Set(value);
500
501         this->EmitEvent(PropertyEvent<Type>(value, this->m_model),
502                         EmitMode::Auto);
503     }
504
505     void SetWithoutLock(const Type &value)
506     {
507         if (this->m_storage.Get() == value) {
508             return;
509         }
510
511         this->m_storage.Set(value);
512     }
513 };
514 }
515 } // namespace DPL
516
517 #endif // DPL_PROPERTY_H