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