tizen 2.4 release
[framework/web/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  * PropertyStorageDynamicInitCached: The data is stored internally at construction
71  *                                   with read delegate. Changed data is stored
72  *                                   internally and also set remotely with delegate.
73  *
74  * Property access modes:
75  *
76  * PropertyReadOnly: Property is a read-only property.
77  *                   It doesn't have Set() method.
78  *
79  * PropertyReadWrite: Property is a read-write property. It have both Get()
80  *                    and Set() methods.
81  *
82  * Examples:
83  *
84  * Note: All properties, if not specified otherwise in template arguments,
85  * have read-write access rights and cached data storage.
86  *
87  * Simple property with int:
88  * @code DPL::Property<int> Number;
89  *
90  * A property with string:
91  * @code DPL::Property<std::string> Name;
92  *
93  * A read-only float property:
94  * @code DPL::Property<float, DPL::PropertyReadOnly> Gravity;
95  *
96  * A read-write string property:
97  * @code DPL::Property<std::string, DPL::PropertyReadWrite> Caption;
98  *
99  * A read-write string property which is stored internally:
100  * @code DPL::Property<std::string,
101  *                     DPL::PropertyReadWrite,
102  *                     DPL::PropertyStorageCached> Name;
103  *
104  * A read-write string property which is stored externally:
105  * @code DPL::Property<std::string,
106  *                     DPL::PropertyReadWrite,
107  *                     DPL::PropertyStorageDynamic> RemoteName;
108  *
109  * A read-write string property which is stored externally, but also cached:
110  * @code DPL::Property<std::string,
111  *                     DPL::PropertyReadOnly,
112  *                     DPL::PropertyStorageDynamicCached> CachedName;
113  *
114  * A model is an agregation of many properties. Whenever some of them change,
115  * an event with this change is emmited along with model handle which
116  * contains this property. These changes can be listened to. To achieve this,
117  * one have to add a delegate which contains changed property value and
118  * a pointer to the model.
119  *
120  * Example of a model with a property:
121  *
122  * @code
123  * class MyModel: public DPL::Model
124  * {
125  * public:
126  *     DPL::Property<int> Number1;
127  *     DPL::Property<int> Number2;
128  *     DPL::Property<int, DPL::PropertyReadOnly> Number3;
129  *
130  *     // Read write property delegate method can be static
131  *     static int ReadCustomValue(Model *model);
132  *
133  *     // Read write property delegate method can also be method
134  *     void WriteCustomValue(const int &value, Model *model);
135  *
136  *     MyModel()
137  *      : // Initialize property with default value and this model
138  *        Number1(this),
139  *
140  *        // Initialize property with 123 and this model
141  *        Number2(this, 123),
142  *
143  *        // Initialize property with 0 and custom read delegate and this model
144  *        Number3(this, 0, &ReadCustomValue),
145  *
146  *        // Initialize property with 7 and custom read-write delegates
147  *        // and this model
148  *        Number4(this, 7, &ReadCustomValue,
149  *                std::bind(&WriteCustomValue, this)
150  *     {
151  *     }
152  * };
153  *
154  * DPL's delegate mechanism is a general solution, which is capable of
155  * binding various types of functions and method as a delegate and
156  * using them in unified way.
157  *
158  * Example of registering and unregistering for model's property changes:
159  *
160  * @code
161  * class SomeModel : public DPL::Model
162  * {
163  * public:
164  *     DPL::Property<int> Value;
165  *
166  *     SomeModel()
167  *         : Value(this)
168  *     {
169  *     }
170  * };
171  *
172  * void ValueChanged(const int &value, Model *model)
173  * {
174  *     std::cout << "Value changed to: " << value << std::endl;
175  * }
176  *
177  * int main()
178  * {
179  *     SomeModel model;
180  *
181  *     // Register a global function as property changed listener
182  *     model.AddListener(&ValueChanged);
183  *     [...]
184  *     model.RemoveListener(&ValueChanged);
185  *
186  *     // Register a class method as property changed listener
187  *     class Receiver
188  *     {
189  *     public:
190  *         void OnValueChanged(const int &value, Model *model)
191  *         {
192  *             [...]
193  *         }
194  *     } receiver;
195  *
196  *     model.AddListener(
197  *         std::bind(&Receiver::OnValueChanged, &receiver));
198  *     [...]
199  *     model.RemoveListener(
200  *         std::bind(&Receiver::OnValueChanged, &receiver));
201  * }
202  */
203 struct PropertyStorageCached {};              ///< Always use cached
204 struct PropertyStorageDynamic {};             ///< Always use dynamic
205 struct PropertyStorageDynamicCached {};       ///< Use dynamic then cache
206 struct PropertyStorageDynamicInitCached {};   ///< Use cached with dynamic initialization
207
208 struct PropertyReadOnly {};  ///< Read only, not setter available
209 struct PropertyReadWrite {}; ///< Read and write
210
211 template<typename Type>
212 struct PropertyEvent
213 {
214     PropertyEvent(const Type &v, Model *s) :
215         value(v),
216         sender(s)
217     {}
218
219     Type value;
220     Model *sender;
221 };
222
223 template<typename ReadDelegateType, typename WriteDelegateType>
224 class PropertyStorageMethodDynamicBase
225 {
226   protected:
227     ReadDelegateType m_readValue;
228     WriteDelegateType m_writeValue;
229
230     PropertyStorageMethodDynamicBase(ReadDelegateType readValue,
231                                      WriteDelegateType writeValue) :
232         m_readValue(readValue),
233         m_writeValue(writeValue)
234     {}
235 };
236
237 template<typename Type>
238 class PropertyStorageMethodCachedBase
239 {
240   protected:
241     mutable Type m_value;
242
243     PropertyStorageMethodCachedBase()
244     {}
245 };
246
247 class PropertyStorageMethodBase
248 {
249   protected:
250     explicit PropertyStorageMethodBase(Model *model) :
251         m_model(model)
252     {}
253
254     Model *m_model;
255 };
256
257 template<typename Type,
258          typename StorageMethod,
259          typename ReadDelegateType,
260          typename WriteDelegateType>
261 class PropertyStorageMethod;
262
263 template<typename Type,
264          typename ReadDelegateType,
265          typename WriteDelegateType>
266 class PropertyStorageMethod<Type,
267                             PropertyStorageCached,
268                             ReadDelegateType,
269                             WriteDelegateType>:
270     protected PropertyStorageMethodBase,
271     protected PropertyStorageMethodCachedBase<Type>
272 {
273   public:
274     PropertyStorageMethod(Model *model,
275                           ReadDelegateType /*readValue*/,
276                           WriteDelegateType /*writeValue*/) :
277         PropertyStorageMethodBase(model)
278     {}
279
280     Type Get() const
281     {
282         return this->m_value;
283     }
284
285     void Set(const Type &value)
286     {
287         this->m_value = value;
288     }
289 };
290
291 template<typename Type, typename ReadDelegateType, typename WriteDelegateType>
292 class PropertyStorageMethod<Type,
293                             PropertyStorageDynamic,
294                             ReadDelegateType,
295                             WriteDelegateType>:
296     protected PropertyStorageMethodBase,
297     protected PropertyStorageMethodDynamicBase<ReadDelegateType,
298                                                WriteDelegateType>
299 {
300   public:
301     PropertyStorageMethod(Model *model,
302                           ReadDelegateType readValue,
303                           WriteDelegateType writeValue) :
304         PropertyStorageMethodBase(model),
305         PropertyStorageMethodDynamicBase<ReadDelegateType, WriteDelegateType>(
306             readValue,
307             writeValue)
308     {}
309
310     Type Get() const
311     {
312         Assert(this->m_readValue);
313         return this->m_readValue(m_model);
314     }
315
316     void Set(const Type &value)
317     {
318         Assert(this->m_writeValue);
319         this->m_writeValue(value, m_model);
320     }
321 };
322
323 template<typename Type, typename ReadDelegateType, typename WriteDelegateType>
324 class PropertyStorageMethod<Type,
325                             PropertyStorageDynamicCached,
326                             ReadDelegateType,
327                             WriteDelegateType>:
328     protected PropertyStorageMethodBase,
329     protected PropertyStorageMethodDynamicBase<ReadDelegateType,
330                                                WriteDelegateType>,
331     protected PropertyStorageMethodCachedBase<Type>
332 {
333   private:
334     typedef PropertyStorageMethod<Type,
335                                   PropertyStorageDynamicCached,
336                                   ReadDelegateType,
337                                   WriteDelegateType> ThisType;
338
339     // These two are mutable
340     void OnceEnsure() const
341     {
342         this->m_value = this->m_readValue(m_model);
343     }
344
345     void OnceDisable() const
346     {}
347
348   protected:
349     mutable Once m_once;
350
351   public:
352     PropertyStorageMethod(Model *model,
353                           ReadDelegateType readValue,
354                           WriteDelegateType writeValue) :
355         PropertyStorageMethodBase(model),
356         PropertyStorageMethodDynamicBase<ReadDelegateType, WriteDelegateType>(
357             readValue, writeValue)
358     {}
359
360     Type Get() const
361     {
362         Assert(this->m_readValue);
363         m_once.Call(std::bind(&ThisType::OnceEnsure, this));
364         return this->m_value;
365     }
366
367     void Set(const Type &value)
368     {
369         Assert(this->m_writeValue);
370
371         this->m_writeValue(value, m_model);
372         this->m_value = value;
373         m_once.Call(std::bind(&ThisType::OnceDisable, this));
374     }
375 };
376
377 template<typename Type,
378          typename ReadDelegateType,
379          typename WriteDelegateType>
380 class PropertyStorageMethod<Type,
381                             PropertyStorageDynamicInitCached,
382                             ReadDelegateType,
383                             WriteDelegateType>:
384     protected PropertyStorageMethodBase,
385     protected PropertyStorageMethodDynamicBase<ReadDelegateType,
386                                                WriteDelegateType>,
387     protected PropertyStorageMethodCachedBase<Type>
388 {
389   public:
390     PropertyStorageMethod(Model *model,
391                           ReadDelegateType readValue,
392                           WriteDelegateType writeValue) :
393         PropertyStorageMethodBase(model),
394         PropertyStorageMethodDynamicBase<ReadDelegateType, WriteDelegateType>(
395             readValue, writeValue)
396     {
397         this->m_value = this->m_readValue(m_model);
398     }
399
400     Type Get() const
401     {
402         return this->m_value;
403     }
404
405     void Set(const Type& value)
406     {
407         this->m_value = value;
408         this->m_writeValue(value, m_model);
409     }
410 };
411
412 template<typename Type, typename StorageMethod>
413 class PropertyBase :
414     protected EventSupport<PropertyEvent<Type> >
415 {
416   public:
417     typedef typename EventSupport<PropertyEvent<Type> >::EventListenerType
418     EventListenerType;
419
420     typedef typename EventSupport<PropertyEvent<Type> >::DelegateType
421     DelegateType;
422
423     typedef std::function<Type(Model *)>
424     ReadDelegateType;
425
426     typedef std::function<void (const Type &, Model *)>
427     WriteDelegateType;
428
429   protected:
430     PropertyStorageMethod<Type,
431                           StorageMethod,
432                           ReadDelegateType,
433                           WriteDelegateType> m_storage;
434     Model *m_model;
435
436     PropertyBase(Model *model,
437                  ReadDelegateType readValue,
438                  WriteDelegateType writeValue) :
439         m_storage(model, readValue, writeValue),
440         m_model(model)
441     {}
442
443   public:
444     virtual Type Get() const
445     {
446         ReadWriteMutex::ScopedReadLock lock(&m_model->m_mutex);
447         return m_storage.Get();
448     }
449
450     void AddListener(DelegateType delegate)
451     {
452         EventSupport<PropertyEvent<Type> >::AddListener(delegate);
453     }
454
455     void RemoveListener(DelegateType delegate)
456     {
457         EventSupport<PropertyEvent<Type> >::RemoveListener(delegate);
458     }
459 };
460
461 template<typename Type,
462          typename AccessType = PropertyReadWrite,
463          typename StorageMethod = PropertyStorageCached>
464 class Property;
465
466 template<typename Type, typename StorageMethod>
467 class Property<Type, PropertyReadOnly, StorageMethod>:
468     public PropertyBase<Type, StorageMethod>
469 {
470   public:
471     typedef typename PropertyBase<Type, StorageMethod>::EventListenerType
472     EventListenerType;
473
474     typedef typename PropertyBase<Type, StorageMethod>::DelegateType
475     DelegateType;
476
477     typedef typename PropertyBase<Type, StorageMethod>::ReadDelegateType
478     ReadDelegateType;
479
480     typedef typename PropertyBase<Type, StorageMethod>::WriteDelegateType
481     WriteDelegateType;
482
483   public:
484     explicit Property(Model *model,
485                       ReadDelegateType readValue = NULL) :
486         PropertyBase<Type, StorageMethod>(model, readValue, NULL)
487     {}
488
489     Property(Model *model,
490              const Type &value,
491              ReadDelegateType readValue = NULL) :
492         PropertyBase<Type, StorageMethod>(model, readValue, NULL)
493     {
494         this->m_storage.Set(value);
495     }
496 };
497
498 template<typename Type, typename StorageMethod>
499 class Property<Type, PropertyReadWrite, StorageMethod>:
500     public PropertyBase<Type, StorageMethod>
501 {
502   public:
503     typedef typename PropertyBase<Type, StorageMethod>::EventListenerType
504     EventListenerType;
505
506     typedef typename PropertyBase<Type, StorageMethod>::DelegateType
507     DelegateType;
508
509     typedef typename PropertyBase<Type, StorageMethod>::ReadDelegateType
510     ReadDelegateType;
511
512     typedef typename PropertyBase<Type, StorageMethod>::WriteDelegateType
513     WriteDelegateType;
514
515   public:
516     explicit Property(Model *model,
517                       ReadDelegateType readValue = NULL,
518                       WriteDelegateType writeValue = NULL) :
519         PropertyBase<Type, StorageMethod>(model, readValue, writeValue)
520     {}
521
522     Property(Model *model,
523              const Type &value,
524              ReadDelegateType readValue = NULL,
525              WriteDelegateType writeValue = NULL) :
526         PropertyBase<Type, StorageMethod>(model, readValue, writeValue)
527     {
528         this->m_storage.Set(value);
529     }
530
531     virtual void Set(const Type &value)
532     {
533         ReadWriteMutex::ScopedWriteLock lock(&this->m_model->m_mutex);
534
535         if (this->m_storage.Get() == value) {
536             return;
537         }
538
539         this->m_storage.Set(value);
540
541         this->EmitEvent(PropertyEvent<Type>(value, this->m_model),
542                         EmitMode::Auto);
543     }
544
545     void SetWithoutLock(const Type &value)
546     {
547         if (this->m_storage.Get() == value) {
548             return;
549         }
550
551         this->m_storage.Set(value);
552     }
553 };
554 }
555 } // namespace DPL
556
557 #endif // DPL_PROPERTY_H