2 * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
18 * @author Przemyslaw Dobrowolski (p.dobrowolsk@samsung.com)
20 * @brief Header file for property
22 #ifndef DPL_PROPERTY_H
23 #define DPL_PROPERTY_H
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>
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.
41 * Property is a template of the following schema:
43 * template class Property<type, property access rights, property storage mode>
45 * Type is an internal type that property is encapsulating. It is required
46 * that the type is default-constructible and copyable.
48 * Property access rights control which operations are allowed to be
49 * executed on property.
51 * Property storage mode is a mode describing where and how internal data should
56 * PropertyStorageCached: The data is stored internally as one copy. It can
57 * never be changed from external.
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.
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.
70 * Property access modes:
72 * PropertyReadOnly: Property is a read-only property.
73 * It doesn't have Set() method.
75 * PropertyReadWrite: Property is a read-write property. It have both Get()
80 * Note: All properties, if not specified otherwise in template arguments,
81 * have read-write access rights and cached data storage.
83 * Simple property with int:
84 * @code DPL::Property<int> Number;
86 * A property with string:
87 * @code DPL::Property<std::string> Name;
89 * A read-only float property:
90 * @code DPL::Property<float, DPL::PropertyReadOnly> Gravity;
92 * A read-write string property:
93 * @code DPL::Property<std::string, DPL::PropertyReadWrite> Caption;
95 * A read-write string property which is stored internally:
96 * @code DPL::Property<std::string,
97 * DPL::PropertyReadWrite,
98 * DPL::PropertyStorageCached> Name;
100 * A read-write string property which is stored externally:
101 * @code DPL::Property<std::string,
102 * DPL::PropertyReadWrite,
103 * DPL::PropertyStorageDynamic> RemoteName;
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;
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.
116 * Example of a model with a property:
119 * class MyModel: public DPL::Model
122 * DPL::Property<int> Number1;
123 * DPL::Property<int> Number2;
124 * DPL::Property<int, DPL::PropertyReadOnly> Number3;
126 * // Read write property delegate method can be static
127 * static int ReadCustomValue(Model *model);
129 * // Read write property delegate method can also be method
130 * void WriteCustomValue(const int &value, Model *model);
133 * : // Initialize property with default value and this model
136 * // Initialize property with 123 and this model
137 * Number2(this, 123),
139 * // Initialize property with 0 and custom read delegate and this model
140 * Number3(this, 0, &ReadCustomValue),
142 * // Initialize property with 7 and custom read-write delegates
144 * Number4(this, 7, &ReadCustomValue,
145 * std::bind(&WriteCustomValue, this)
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.
154 * Example of registering and unregistering for model's property changes:
157 * class SomeModel : public DPL::Model
160 * DPL::Property<int> Value;
168 * void ValueChanged(const int &value, Model *model)
170 * std::cout << "Value changed to: " << value << std::endl;
177 * // Register a global function as property changed listener
178 * model.AddListener(&ValueChanged);
180 * model.RemoveListener(&ValueChanged);
182 * // Register a class method as property changed listener
186 * void OnValueChanged(const int &value, Model *model)
193 * std::bind(&Receiver::OnValueChanged, &receiver));
195 * model.RemoveListener(
196 * std::bind(&Receiver::OnValueChanged, &receiver));
199 struct PropertyStorageCached {}; ///< Always use cached
200 struct PropertyStorageDynamic {}; ///< Always use dynamic
201 struct PropertyStorageDynamicCached {}; ///< Use dynamic then cache
203 struct PropertyReadOnly {}; ///< Read only, not setter available
204 struct PropertyReadWrite {}; ///< Read and write
206 template<typename Type>
209 PropertyEvent(const Type &v, Model *s) :
218 template<typename ReadDelegateType, typename WriteDelegateType>
219 class PropertyStorageMethodDynamicBase
222 ReadDelegateType m_readValue;
223 WriteDelegateType m_writeValue;
225 PropertyStorageMethodDynamicBase(ReadDelegateType readValue,
226 WriteDelegateType writeValue) :
227 m_readValue(readValue),
228 m_writeValue(writeValue)
232 template<typename Type>
233 class PropertyStorageMethodCachedBase
236 mutable Type m_value;
238 PropertyStorageMethodCachedBase()
242 class PropertyStorageMethodBase
245 explicit PropertyStorageMethodBase(Model *model) :
252 template<typename Type,
253 typename StorageMethod,
254 typename ReadDelegateType,
255 typename WriteDelegateType>
256 class PropertyStorageMethod;
258 template<typename Type,
259 typename ReadDelegateType,
260 typename WriteDelegateType>
261 class PropertyStorageMethod<Type,
262 PropertyStorageCached,
265 protected PropertyStorageMethodBase,
266 protected PropertyStorageMethodCachedBase<Type>
269 PropertyStorageMethod(Model *model,
270 ReadDelegateType /*readValue*/,
271 WriteDelegateType /*writeValue*/) :
272 PropertyStorageMethodBase(model)
277 return this->m_value;
280 void Set(const Type &value)
282 this->m_value = value;
286 template<typename Type, typename ReadDelegateType, typename WriteDelegateType>
287 class PropertyStorageMethod<Type,
288 PropertyStorageDynamic,
291 protected PropertyStorageMethodBase,
292 protected PropertyStorageMethodDynamicBase<ReadDelegateType,
296 PropertyStorageMethod(Model *model,
297 ReadDelegateType readValue,
298 WriteDelegateType writeValue) :
299 PropertyStorageMethodBase(model),
300 PropertyStorageMethodDynamicBase<ReadDelegateType, WriteDelegateType>(
307 Assert(this->m_readValue);
308 return this->m_readValue(m_model);
311 void Set(const Type &value)
313 Assert(this->m_writeValue);
314 this->m_writeValue(value, m_model);
318 template<typename Type, typename ReadDelegateType, typename WriteDelegateType>
319 class PropertyStorageMethod<Type,
320 PropertyStorageDynamicCached,
323 protected PropertyStorageMethodBase,
324 protected PropertyStorageMethodDynamicBase<ReadDelegateType,
326 protected PropertyStorageMethodCachedBase<Type>
329 typedef PropertyStorageMethod<Type,
330 PropertyStorageDynamicCached,
332 WriteDelegateType> ThisType;
334 // These two are mutable
335 void OnceEnsure() const
337 this->m_value = this->m_readValue(m_model);
340 void OnceDisable() const
347 PropertyStorageMethod(Model *model,
348 ReadDelegateType readValue,
349 WriteDelegateType writeValue) :
350 PropertyStorageMethodBase(model),
351 PropertyStorageMethodDynamicBase<ReadDelegateType, WriteDelegateType>(
352 readValue, writeValue)
357 Assert(this->m_readValue);
358 m_once.Call(std::bind(&ThisType::OnceEnsure, this));
359 return this->m_value;
362 void Set(const Type &value)
364 Assert(this->m_writeValue);
366 this->m_writeValue(value, m_model);
367 this->m_value = value;
368 m_once.Call(std::bind(&ThisType::OnceDisable, this));
372 template<typename Type, typename StorageMethod>
374 protected EventSupport<PropertyEvent<Type> >
377 typedef typename EventSupport<PropertyEvent<Type> >::EventListenerType
380 typedef typename EventSupport<PropertyEvent<Type> >::DelegateType
383 typedef std::function<Type(Model *)>
386 typedef std::function<void (const Type &, Model *)>
390 PropertyStorageMethod<Type,
393 WriteDelegateType> m_storage;
396 PropertyBase(Model *model,
397 ReadDelegateType readValue,
398 WriteDelegateType writeValue) :
399 m_storage(model, readValue, writeValue),
404 virtual Type Get() const
406 ReadWriteMutex::ScopedReadLock lock(&m_model->m_mutex);
407 return m_storage.Get();
410 void AddListener(DelegateType delegate)
412 EventSupport<PropertyEvent<Type> >::AddListener(delegate);
415 void RemoveListener(DelegateType delegate)
417 EventSupport<PropertyEvent<Type> >::RemoveListener(delegate);
421 template<typename Type,
422 typename AccessType = PropertyReadWrite,
423 typename StorageMethod = PropertyStorageCached>
426 template<typename Type, typename StorageMethod>
427 class Property<Type, PropertyReadOnly, StorageMethod>:
428 public PropertyBase<Type, StorageMethod>
431 typedef typename PropertyBase<Type, StorageMethod>::EventListenerType
434 typedef typename PropertyBase<Type, StorageMethod>::DelegateType
437 typedef typename PropertyBase<Type, StorageMethod>::ReadDelegateType
440 typedef typename PropertyBase<Type, StorageMethod>::WriteDelegateType
444 explicit Property(Model *model,
445 ReadDelegateType readValue = NULL) :
446 PropertyBase<Type, StorageMethod>(model, readValue, NULL)
449 Property(Model *model,
451 ReadDelegateType readValue = NULL) :
452 PropertyBase<Type, StorageMethod>(model, readValue, NULL)
454 this->m_storage.Set(value);
458 template<typename Type, typename StorageMethod>
459 class Property<Type, PropertyReadWrite, StorageMethod>:
460 public PropertyBase<Type, StorageMethod>
463 typedef typename PropertyBase<Type, StorageMethod>::EventListenerType
466 typedef typename PropertyBase<Type, StorageMethod>::DelegateType
469 typedef typename PropertyBase<Type, StorageMethod>::ReadDelegateType
472 typedef typename PropertyBase<Type, StorageMethod>::WriteDelegateType
476 explicit Property(Model *model,
477 ReadDelegateType readValue = NULL,
478 WriteDelegateType writeValue = NULL) :
479 PropertyBase<Type, StorageMethod>(model, readValue, writeValue)
482 Property(Model *model,
484 ReadDelegateType readValue = NULL,
485 WriteDelegateType writeValue = NULL) :
486 PropertyBase<Type, StorageMethod>(model, readValue, writeValue)
488 this->m_storage.Set(value);
491 virtual void Set(const Type &value)
493 ReadWriteMutex::ScopedWriteLock lock(&this->m_model->m_mutex);
495 if (this->m_storage.Get() == value) {
499 this->m_storage.Set(value);
501 this->EmitEvent(PropertyEvent<Type>(value, this->m_model),
505 void SetWithoutLock(const Type &value)
507 if (this->m_storage.Get() == value) {
511 this->m_storage.Set(value);
517 #endif // DPL_PROPERTY_H