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
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>
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.
43 * Property is a template of the following schema:
45 * template class Property<type, property access rights, property storage mode>
47 * Type is an internal type that property is encapsulating. It is required
48 * that the type is default-constructible and copyable.
50 * Property access rights control which operations are allowed to be
51 * executed on property.
53 * Property storage mode is a mode describing where and how internal data should
58 * PropertyStorageCached: The data is stored internally as one copy. It can
59 * never be changed from external.
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.
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.
72 * Property access modes:
74 * PropertyReadOnly: Property is a read-only property.
75 * It doesn't have Set() method.
77 * PropertyReadWrite: Property is a read-write property. It have both Get()
82 * Note: All properties, if not specified otherwise in template arguments,
83 * have read-write access rights and cached data storage.
85 * Simple property with int:
86 * @code DPL::Property<int> Number;
88 * A property with string:
89 * @code DPL::Property<std::string> Name;
91 * A read-only float property:
92 * @code DPL::Property<float, DPL::PropertyReadOnly> Gravity;
94 * A read-write string property:
95 * @code DPL::Property<std::string, DPL::PropertyReadWrite> Caption;
97 * A read-write string property which is stored internally:
98 * @code DPL::Property<std::string,
99 * DPL::PropertyReadWrite,
100 * DPL::PropertyStorageCached> Name;
102 * A read-write string property which is stored externally:
103 * @code DPL::Property<std::string,
104 * DPL::PropertyReadWrite,
105 * DPL::PropertyStorageDynamic> RemoteName;
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;
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.
118 * Example of a model with a property:
121 * class MyModel: public DPL::Model
124 * DPL::Property<int> Number1;
125 * DPL::Property<int> Number2;
126 * DPL::Property<int, DPL::PropertyReadOnly> Number3;
128 * // Read write property delegate method can be static
129 * static int ReadCustomValue(Model *model);
131 * // Read write property delegate method can also be method
132 * void WriteCustomValue(const int &value, Model *model);
135 * : // Initialize property with default value and this model
138 * // Initialize property with 123 and this model
139 * Number2(this, 123),
141 * // Initialize property with 0 and custom read delegate and this model
142 * Number3(this, 0, &ReadCustomValue),
144 * // Initialize property with 7 and custom read-write delegates
146 * Number4(this, 7, &ReadCustomValue,
147 * DPL::MakeDelegate(this, &WriteCustomValue)
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.
156 * Example of registering and unregistering for model's property changes:
159 * class SomeModel : public DPL::Model
162 * DPL::Property<int> Value;
170 * void ValueChanged(const int &value, Model *model)
172 * std::cout << "Value changed to: " << value << std::endl;
179 * // Register a global function as property changed listener
180 * model.AddListener(&ValueChanged);
182 * model.RemoveListener(&ValueChanged);
184 * // Register a class method as property changed listener
188 * void OnValueChanged(const int &value, Model *model)
195 * DPL::MakeDelegate(&receiver, &Receiver::OnValueChanged));
197 * model.RemoveListener(
198 * DPL::MakeDelegate(&receiver, &Receiver::OnValueChanged));
201 struct PropertyStorageCached {}; ///< Always use cached
202 struct PropertyStorageDynamic {}; ///< Always use dynamic
203 struct PropertyStorageDynamicCached {}; ///< Use dynamic then cache
205 struct PropertyReadOnly {}; ///< Read only, not setter available
206 struct PropertyReadWrite {}; ///< Read and write
209 template<typename Type>
212 PropertyEvent(const Type &v, Model *s)
222 template<typename ReadDelegateType, typename WriteDelegateType>
223 class PropertyStorageMethodDynamicBase
226 ReadDelegateType m_readValue;
227 WriteDelegateType m_writeValue;
229 PropertyStorageMethodDynamicBase(ReadDelegateType readValue,
230 WriteDelegateType writeValue)
231 : m_readValue(readValue),
232 m_writeValue(writeValue)
237 template<typename Type>
238 class PropertyStorageMethodCachedBase
241 mutable Type m_value;
243 PropertyStorageMethodCachedBase()
248 class PropertyStorageMethodBase
251 explicit PropertyStorageMethodBase(Model *model)
259 template<typename Type,
260 typename StorageMethod,
261 typename ReadDelegateType,
262 typename WriteDelegateType>
263 class PropertyStorageMethod;
265 template<typename Type,
266 typename ReadDelegateType,
267 typename WriteDelegateType>
268 class PropertyStorageMethod<Type,
269 PropertyStorageCached,
272 : protected PropertyStorageMethodBase,
273 protected PropertyStorageMethodCachedBase<Type>
276 PropertyStorageMethod(Model *model,
277 ReadDelegateType /*readValue*/,
278 WriteDelegateType /*writeValue*/)
279 : PropertyStorageMethodBase(model)
285 return this->m_value;
288 void Set(const Type &value)
290 this->m_value = value;
294 template<typename Type, typename ReadDelegateType, typename WriteDelegateType>
295 class PropertyStorageMethod<Type,
296 PropertyStorageDynamic,
299 : protected PropertyStorageMethodBase,
300 protected PropertyStorageMethodDynamicBase<ReadDelegateType,
304 PropertyStorageMethod(Model *model,
305 ReadDelegateType readValue,
306 WriteDelegateType writeValue)
307 : PropertyStorageMethodBase(model),
308 PropertyStorageMethodDynamicBase<ReadDelegateType, WriteDelegateType>(
316 Assert(!this->m_readValue.empty());
317 return this->m_readValue(m_model);
320 void Set(const Type &value)
322 Assert(!this->m_writeValue.empty());
323 this->m_writeValue(value, m_model);
327 template<typename Type, typename ReadDelegateType, typename WriteDelegateType>
328 class PropertyStorageMethod<Type,
329 PropertyStorageDynamicCached,
332 : protected PropertyStorageMethodBase,
333 protected PropertyStorageMethodDynamicBase<ReadDelegateType,
335 protected PropertyStorageMethodCachedBase<Type>
338 typedef PropertyStorageMethod<Type,
339 PropertyStorageDynamicCached,
341 WriteDelegateType> ThisType;
343 // These two are mutable
344 void OnceEnsure() const
346 this->m_value = this->m_readValue(m_model);
349 void OnceDisable() const
357 PropertyStorageMethod(Model *model,
358 ReadDelegateType readValue,
359 WriteDelegateType writeValue)
360 : PropertyStorageMethodBase(model),
361 PropertyStorageMethodDynamicBase<ReadDelegateType, WriteDelegateType>(
362 readValue, writeValue)
368 Assert(!this->m_readValue.empty());
369 m_once.Call(Once::Delegate(this, &ThisType::OnceEnsure));
370 return this->m_value;
373 void Set(const Type &value)
375 Assert(!this->m_writeValue.empty());
377 this->m_writeValue(value, m_model);
378 this->m_value = value;
379 m_once.Call(Once::Delegate(this, &ThisType::OnceDisable));
383 template<typename Type, typename StorageMethod>
385 : protected EventSupport<PropertyEvent<Type> >
388 typedef typename EventSupport<PropertyEvent<Type> >::EventListenerType
391 typedef typename EventSupport<PropertyEvent<Type> >::DelegateType
394 typedef FastDelegate<Type (Model *)>
397 typedef FastDelegate<void (const Type &, Model *)>
401 PropertyStorageMethod<Type,
404 WriteDelegateType> m_storage;
407 PropertyBase(Model *model,
408 ReadDelegateType readValue,
409 WriteDelegateType writeValue)
410 : m_storage(model, readValue, writeValue),
416 virtual Type Get() const
418 ReadWriteMutex::ScopedReadLock lock(&m_model->m_mutex);
419 return m_storage.Get();
422 void AddListener(DelegateType delegate)
424 EventSupport<PropertyEvent<Type> >::AddListener(delegate);
427 void RemoveListener(DelegateType delegate)
429 EventSupport<PropertyEvent<Type> >::RemoveListener(delegate);
433 template<typename Type,
434 typename AccessType = PropertyReadWrite,
435 typename StorageMethod = PropertyStorageCached>
438 template<typename Type, typename StorageMethod>
439 class Property<Type, PropertyReadOnly, StorageMethod>
440 : public PropertyBase<Type, StorageMethod>
443 typedef typename PropertyBase<Type, StorageMethod>::EventListenerType
446 typedef typename PropertyBase<Type, StorageMethod>::DelegateType
449 typedef typename PropertyBase<Type, StorageMethod>::ReadDelegateType
452 typedef typename PropertyBase<Type, StorageMethod>::WriteDelegateType
456 explicit Property(Model *model,
457 ReadDelegateType readValue = NULL)
458 : PropertyBase<Type, StorageMethod>(model, readValue, NULL)
462 Property(Model *model,
464 ReadDelegateType readValue = NULL)
465 : PropertyBase<Type, StorageMethod>(model, readValue, NULL)
467 this->m_storage.Set(value);
471 template<typename Type, typename StorageMethod>
472 class Property<Type, PropertyReadWrite, StorageMethod>
473 : public PropertyBase<Type, StorageMethod>
476 typedef typename PropertyBase<Type, StorageMethod>::EventListenerType
479 typedef typename PropertyBase<Type, StorageMethod>::DelegateType
482 typedef typename PropertyBase<Type, StorageMethod>::ReadDelegateType
485 typedef typename PropertyBase<Type, StorageMethod>::WriteDelegateType
489 explicit Property(Model *model,
490 ReadDelegateType readValue = NULL,
491 WriteDelegateType writeValue = NULL)
492 : PropertyBase<Type, StorageMethod>(model, readValue, writeValue)
496 Property(Model *model,
498 ReadDelegateType readValue = NULL,
499 WriteDelegateType writeValue = NULL)
500 : PropertyBase<Type, StorageMethod>(model, readValue, writeValue)
502 this->m_storage.Set(value);
505 virtual void Set(const Type &value)
507 ReadWriteMutex::ScopedWriteLock lock(&this->m_model->m_mutex);
509 if (this->m_storage.Get() == value)
512 this->m_storage.Set(value);
514 this->EmitEvent(PropertyEvent<Type>(value, this->m_model),
518 void SetWithoutLock(const Type &value)
520 if (this->m_storage.Get() == value)
523 this->m_storage.Set(value);
530 #endif // DPL_PROPERTY_H