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 * PropertyStorageDynamicInitCached: The data is stored internally at construction
71 * with read delegate. Changed data is stored
72 * internally and also set remotely with delegate.
74 * Property access modes:
76 * PropertyReadOnly: Property is a read-only property.
77 * It doesn't have Set() method.
79 * PropertyReadWrite: Property is a read-write property. It have both Get()
84 * Note: All properties, if not specified otherwise in template arguments,
85 * have read-write access rights and cached data storage.
87 * Simple property with int:
88 * @code DPL::Property<int> Number;
90 * A property with string:
91 * @code DPL::Property<std::string> Name;
93 * A read-only float property:
94 * @code DPL::Property<float, DPL::PropertyReadOnly> Gravity;
96 * A read-write string property:
97 * @code DPL::Property<std::string, DPL::PropertyReadWrite> Caption;
99 * A read-write string property which is stored internally:
100 * @code DPL::Property<std::string,
101 * DPL::PropertyReadWrite,
102 * DPL::PropertyStorageCached> Name;
104 * A read-write string property which is stored externally:
105 * @code DPL::Property<std::string,
106 * DPL::PropertyReadWrite,
107 * DPL::PropertyStorageDynamic> RemoteName;
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;
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.
120 * Example of a model with a property:
123 * class MyModel: public DPL::Model
126 * DPL::Property<int> Number1;
127 * DPL::Property<int> Number2;
128 * DPL::Property<int, DPL::PropertyReadOnly> Number3;
130 * // Read write property delegate method can be static
131 * static int ReadCustomValue(Model *model);
133 * // Read write property delegate method can also be method
134 * void WriteCustomValue(const int &value, Model *model);
137 * : // Initialize property with default value and this model
140 * // Initialize property with 123 and this model
141 * Number2(this, 123),
143 * // Initialize property with 0 and custom read delegate and this model
144 * Number3(this, 0, &ReadCustomValue),
146 * // Initialize property with 7 and custom read-write delegates
148 * Number4(this, 7, &ReadCustomValue,
149 * std::bind(&WriteCustomValue, this)
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.
158 * Example of registering and unregistering for model's property changes:
161 * class SomeModel : public DPL::Model
164 * DPL::Property<int> Value;
172 * void ValueChanged(const int &value, Model *model)
174 * std::cout << "Value changed to: " << value << std::endl;
181 * // Register a global function as property changed listener
182 * model.AddListener(&ValueChanged);
184 * model.RemoveListener(&ValueChanged);
186 * // Register a class method as property changed listener
190 * void OnValueChanged(const int &value, Model *model)
197 * std::bind(&Receiver::OnValueChanged, &receiver));
199 * model.RemoveListener(
200 * std::bind(&Receiver::OnValueChanged, &receiver));
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
208 struct PropertyReadOnly {}; ///< Read only, not setter available
209 struct PropertyReadWrite {}; ///< Read and write
211 template<typename Type>
214 PropertyEvent(const Type &v, Model *s) :
223 template<typename ReadDelegateType, typename WriteDelegateType>
224 class PropertyStorageMethodDynamicBase
227 ReadDelegateType m_readValue;
228 WriteDelegateType m_writeValue;
230 PropertyStorageMethodDynamicBase(ReadDelegateType readValue,
231 WriteDelegateType writeValue) :
232 m_readValue(readValue),
233 m_writeValue(writeValue)
237 template<typename Type>
238 class PropertyStorageMethodCachedBase
241 mutable Type m_value;
243 PropertyStorageMethodCachedBase()
247 class PropertyStorageMethodBase
250 explicit PropertyStorageMethodBase(Model *model) :
257 template<typename Type,
258 typename StorageMethod,
259 typename ReadDelegateType,
260 typename WriteDelegateType>
261 class PropertyStorageMethod;
263 template<typename Type,
264 typename ReadDelegateType,
265 typename WriteDelegateType>
266 class PropertyStorageMethod<Type,
267 PropertyStorageCached,
270 protected PropertyStorageMethodBase,
271 protected PropertyStorageMethodCachedBase<Type>
274 PropertyStorageMethod(Model *model,
275 ReadDelegateType /*readValue*/,
276 WriteDelegateType /*writeValue*/) :
277 PropertyStorageMethodBase(model)
282 return this->m_value;
285 void Set(const Type &value)
287 this->m_value = value;
291 template<typename Type, typename ReadDelegateType, typename WriteDelegateType>
292 class PropertyStorageMethod<Type,
293 PropertyStorageDynamic,
296 protected PropertyStorageMethodBase,
297 protected PropertyStorageMethodDynamicBase<ReadDelegateType,
301 PropertyStorageMethod(Model *model,
302 ReadDelegateType readValue,
303 WriteDelegateType writeValue) :
304 PropertyStorageMethodBase(model),
305 PropertyStorageMethodDynamicBase<ReadDelegateType, WriteDelegateType>(
312 Assert(this->m_readValue);
313 return this->m_readValue(m_model);
316 void Set(const Type &value)
318 Assert(this->m_writeValue);
319 this->m_writeValue(value, m_model);
323 template<typename Type, typename ReadDelegateType, typename WriteDelegateType>
324 class PropertyStorageMethod<Type,
325 PropertyStorageDynamicCached,
328 protected PropertyStorageMethodBase,
329 protected PropertyStorageMethodDynamicBase<ReadDelegateType,
331 protected PropertyStorageMethodCachedBase<Type>
334 typedef PropertyStorageMethod<Type,
335 PropertyStorageDynamicCached,
337 WriteDelegateType> ThisType;
339 // These two are mutable
340 void OnceEnsure() const
342 this->m_value = this->m_readValue(m_model);
345 void OnceDisable() const
352 PropertyStorageMethod(Model *model,
353 ReadDelegateType readValue,
354 WriteDelegateType writeValue) :
355 PropertyStorageMethodBase(model),
356 PropertyStorageMethodDynamicBase<ReadDelegateType, WriteDelegateType>(
357 readValue, writeValue)
362 Assert(this->m_readValue);
363 m_once.Call(std::bind(&ThisType::OnceEnsure, this));
364 return this->m_value;
367 void Set(const Type &value)
369 Assert(this->m_writeValue);
371 this->m_writeValue(value, m_model);
372 this->m_value = value;
373 m_once.Call(std::bind(&ThisType::OnceDisable, this));
377 template<typename Type,
378 typename ReadDelegateType,
379 typename WriteDelegateType>
380 class PropertyStorageMethod<Type,
381 PropertyStorageDynamicInitCached,
384 protected PropertyStorageMethodBase,
385 protected PropertyStorageMethodDynamicBase<ReadDelegateType,
387 protected PropertyStorageMethodCachedBase<Type>
390 PropertyStorageMethod(Model *model,
391 ReadDelegateType readValue,
392 WriteDelegateType writeValue) :
393 PropertyStorageMethodBase(model),
394 PropertyStorageMethodDynamicBase<ReadDelegateType, WriteDelegateType>(
395 readValue, writeValue)
397 this->m_value = this->m_readValue(m_model);
402 return this->m_value;
405 void Set(const Type& value)
407 this->m_value = value;
408 this->m_writeValue(value, m_model);
412 template<typename Type, typename StorageMethod>
414 protected EventSupport<PropertyEvent<Type> >
417 typedef typename EventSupport<PropertyEvent<Type> >::EventListenerType
420 typedef typename EventSupport<PropertyEvent<Type> >::DelegateType
423 typedef std::function<Type(Model *)>
426 typedef std::function<void (const Type &, Model *)>
430 PropertyStorageMethod<Type,
433 WriteDelegateType> m_storage;
436 PropertyBase(Model *model,
437 ReadDelegateType readValue,
438 WriteDelegateType writeValue) :
439 m_storage(model, readValue, writeValue),
444 virtual Type Get() const
446 ReadWriteMutex::ScopedReadLock lock(&m_model->m_mutex);
447 return m_storage.Get();
450 void AddListener(DelegateType delegate)
452 EventSupport<PropertyEvent<Type> >::AddListener(delegate);
455 void RemoveListener(DelegateType delegate)
457 EventSupport<PropertyEvent<Type> >::RemoveListener(delegate);
461 template<typename Type,
462 typename AccessType = PropertyReadWrite,
463 typename StorageMethod = PropertyStorageCached>
466 template<typename Type, typename StorageMethod>
467 class Property<Type, PropertyReadOnly, StorageMethod>:
468 public PropertyBase<Type, StorageMethod>
471 typedef typename PropertyBase<Type, StorageMethod>::EventListenerType
474 typedef typename PropertyBase<Type, StorageMethod>::DelegateType
477 typedef typename PropertyBase<Type, StorageMethod>::ReadDelegateType
480 typedef typename PropertyBase<Type, StorageMethod>::WriteDelegateType
484 explicit Property(Model *model,
485 ReadDelegateType readValue = NULL) :
486 PropertyBase<Type, StorageMethod>(model, readValue, NULL)
489 Property(Model *model,
491 ReadDelegateType readValue = NULL) :
492 PropertyBase<Type, StorageMethod>(model, readValue, NULL)
494 this->m_storage.Set(value);
498 template<typename Type, typename StorageMethod>
499 class Property<Type, PropertyReadWrite, StorageMethod>:
500 public PropertyBase<Type, StorageMethod>
503 typedef typename PropertyBase<Type, StorageMethod>::EventListenerType
506 typedef typename PropertyBase<Type, StorageMethod>::DelegateType
509 typedef typename PropertyBase<Type, StorageMethod>::ReadDelegateType
512 typedef typename PropertyBase<Type, StorageMethod>::WriteDelegateType
516 explicit Property(Model *model,
517 ReadDelegateType readValue = NULL,
518 WriteDelegateType writeValue = NULL) :
519 PropertyBase<Type, StorageMethod>(model, readValue, writeValue)
522 Property(Model *model,
524 ReadDelegateType readValue = NULL,
525 WriteDelegateType writeValue = NULL) :
526 PropertyBase<Type, StorageMethod>(model, readValue, writeValue)
528 this->m_storage.Set(value);
531 virtual void Set(const Type &value)
533 ReadWriteMutex::ScopedWriteLock lock(&this->m_model->m_mutex);
535 if (this->m_storage.Get() == value) {
539 this->m_storage.Set(value);
541 this->EmitEvent(PropertyEvent<Type>(value, this->m_model),
545 void SetWithoutLock(const Type &value)
547 if (this->m_storage.Get() == value) {
551 this->m_storage.Set(value);
557 #endif // DPL_PROPERTY_H