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