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>
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.
40 * Property is a template of the following schema:
42 * template class Property<type, property access rights, property storage mode>
44 * Type is an internal type that property is encapsulating. It is required
45 * that the type is default-constructible and copyable.
47 * Property access rights control which operations are allowed to be
48 * executed on property.
50 * Property storage mode is a mode describing where and how internal data should
55 * PropertyStorageCached: The data is stored internally as one copy. It can
56 * never be changed from external.
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.
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.
69 * Property access modes:
71 * PropertyReadOnly: Property is a read-only property.
72 * It doesn't have Set() method.
74 * PropertyReadWrite: Property is a read-write property. It have both Get()
79 * Note: All properties, if not specified otherwise in template arguments,
80 * have read-write access rights and cached data storage.
82 * Simple property with int:
83 * @code DPL::Property<int> Number;
85 * A property with string:
86 * @code DPL::Property<std::string> Name;
88 * A read-only float property:
89 * @code DPL::Property<float, DPL::PropertyReadOnly> Gravity;
91 * A read-write string property:
92 * @code DPL::Property<std::string, DPL::PropertyReadWrite> Caption;
94 * A read-write string property which is stored internally:
95 * @code DPL::Property<std::string,
96 * DPL::PropertyReadWrite,
97 * DPL::PropertyStorageCached> Name;
99 * A read-write string property which is stored externally:
100 * @code DPL::Property<std::string,
101 * DPL::PropertyReadWrite,
102 * DPL::PropertyStorageDynamic> RemoteName;
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;
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.
115 * Example of a model with a property:
118 * class MyModel: public DPL::Model
121 * DPL::Property<int> Number1;
122 * DPL::Property<int> Number2;
123 * DPL::Property<int, DPL::PropertyReadOnly> Number3;
125 * // Read write property delegate method can be static
126 * static int ReadCustomValue(Model *model);
128 * // Read write property delegate method can also be method
129 * void WriteCustomValue(const int &value, Model *model);
132 * : // Initialize property with default value and this model
135 * // Initialize property with 123 and this model
136 * Number2(this, 123),
138 * // Initialize property with 0 and custom read delegate and this model
139 * Number3(this, 0, &ReadCustomValue),
141 * // Initialize property with 7 and custom read-write delegates
143 * Number4(this, 7, &ReadCustomValue,
144 * DPL::MakeDelegate(this, &WriteCustomValue)
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.
153 * Example of registering and unregistering for model's property changes:
156 * class SomeModel : public DPL::Model
159 * DPL::Property<int> Value;
167 * void ValueChanged(const int &value, Model *model)
169 * std::cout << "Value changed to: " << value << std::endl;
176 * // Register a global function as property changed listener
177 * model.AddListener(&ValueChanged);
179 * model.RemoveListener(&ValueChanged);
181 * // Register a class method as property changed listener
185 * void OnValueChanged(const int &value, Model *model)
192 * DPL::MakeDelegate(&receiver, &Receiver::OnValueChanged));
194 * model.RemoveListener(
195 * DPL::MakeDelegate(&receiver, &Receiver::OnValueChanged));
198 struct PropertyStorageCached {}; ///< Always use cached
199 struct PropertyStorageDynamic {}; ///< Always use dynamic
200 struct PropertyStorageDynamicCached {}; ///< Use dynamic then cache
202 struct PropertyReadOnly {}; ///< Read only, not setter available
203 struct PropertyReadWrite {}; ///< Read and write
205 template<typename Type>
208 PropertyEvent(const Type &v, Model *s) :
217 template<typename ReadDelegateType, typename WriteDelegateType>
218 class PropertyStorageMethodDynamicBase
221 ReadDelegateType m_readValue;
222 WriteDelegateType m_writeValue;
224 PropertyStorageMethodDynamicBase(ReadDelegateType readValue,
225 WriteDelegateType writeValue) :
226 m_readValue(readValue),
227 m_writeValue(writeValue)
231 template<typename Type>
232 class PropertyStorageMethodCachedBase
235 mutable Type m_value;
237 PropertyStorageMethodCachedBase()
241 class PropertyStorageMethodBase
244 explicit PropertyStorageMethodBase(Model *model) :
251 template<typename Type,
252 typename StorageMethod,
253 typename ReadDelegateType,
254 typename WriteDelegateType>
255 class PropertyStorageMethod;
257 template<typename Type,
258 typename ReadDelegateType,
259 typename WriteDelegateType>
260 class PropertyStorageMethod<Type,
261 PropertyStorageCached,
264 protected PropertyStorageMethodBase,
265 protected PropertyStorageMethodCachedBase<Type>
268 PropertyStorageMethod(Model *model,
269 ReadDelegateType /*readValue*/,
270 WriteDelegateType /*writeValue*/) :
271 PropertyStorageMethodBase(model)
276 return this->m_value;
279 void Set(const Type &value)
281 this->m_value = value;
285 template<typename Type, typename ReadDelegateType, typename WriteDelegateType>
286 class PropertyStorageMethod<Type,
287 PropertyStorageDynamic,
290 protected PropertyStorageMethodBase,
291 protected PropertyStorageMethodDynamicBase<ReadDelegateType,
295 PropertyStorageMethod(Model *model,
296 ReadDelegateType readValue,
297 WriteDelegateType writeValue) :
298 PropertyStorageMethodBase(model),
299 PropertyStorageMethodDynamicBase<ReadDelegateType, WriteDelegateType>(
306 Assert(!this->m_readValue.empty());
307 return this->m_readValue(m_model);
310 void Set(const Type &value)
312 Assert(!this->m_writeValue.empty());
313 this->m_writeValue(value, m_model);
317 template<typename Type, typename ReadDelegateType, typename WriteDelegateType>
318 class PropertyStorageMethod<Type,
319 PropertyStorageDynamicCached,
322 protected PropertyStorageMethodBase,
323 protected PropertyStorageMethodDynamicBase<ReadDelegateType,
325 protected PropertyStorageMethodCachedBase<Type>
328 typedef PropertyStorageMethod<Type,
329 PropertyStorageDynamicCached,
331 WriteDelegateType> ThisType;
333 // These two are mutable
334 void OnceEnsure() const
336 this->m_value = this->m_readValue(m_model);
339 void OnceDisable() const
346 PropertyStorageMethod(Model *model,
347 ReadDelegateType readValue,
348 WriteDelegateType writeValue) :
349 PropertyStorageMethodBase(model),
350 PropertyStorageMethodDynamicBase<ReadDelegateType, WriteDelegateType>(
351 readValue, writeValue)
356 Assert(!this->m_readValue.empty());
357 m_once.Call(Once::Delegate(this, &ThisType::OnceEnsure));
358 return this->m_value;
361 void Set(const Type &value)
363 Assert(!this->m_writeValue.empty());
365 this->m_writeValue(value, m_model);
366 this->m_value = value;
367 m_once.Call(Once::Delegate(this, &ThisType::OnceDisable));
371 template<typename Type, typename StorageMethod>
373 protected EventSupport<PropertyEvent<Type> >
376 typedef typename EventSupport<PropertyEvent<Type> >::EventListenerType
379 typedef typename EventSupport<PropertyEvent<Type> >::DelegateType
382 typedef FastDelegate<Type(Model *)>
385 typedef FastDelegate<void (const Type &, Model *)>
389 PropertyStorageMethod<Type,
392 WriteDelegateType> m_storage;
395 PropertyBase(Model *model,
396 ReadDelegateType readValue,
397 WriteDelegateType writeValue) :
398 m_storage(model, readValue, writeValue),
403 virtual Type Get() const
405 ReadWriteMutex::ScopedReadLock lock(&m_model->m_mutex);
406 return m_storage.Get();
409 void AddListener(DelegateType delegate)
411 EventSupport<PropertyEvent<Type> >::AddListener(delegate);
414 void RemoveListener(DelegateType delegate)
416 EventSupport<PropertyEvent<Type> >::RemoveListener(delegate);
420 template<typename Type,
421 typename AccessType = PropertyReadWrite,
422 typename StorageMethod = PropertyStorageCached>
425 template<typename Type, typename StorageMethod>
426 class Property<Type, PropertyReadOnly, StorageMethod>:
427 public PropertyBase<Type, StorageMethod>
430 typedef typename PropertyBase<Type, StorageMethod>::EventListenerType
433 typedef typename PropertyBase<Type, StorageMethod>::DelegateType
436 typedef typename PropertyBase<Type, StorageMethod>::ReadDelegateType
439 typedef typename PropertyBase<Type, StorageMethod>::WriteDelegateType
443 explicit Property(Model *model,
444 ReadDelegateType readValue = NULL) :
445 PropertyBase<Type, StorageMethod>(model, readValue, NULL)
448 Property(Model *model,
450 ReadDelegateType readValue = NULL) :
451 PropertyBase<Type, StorageMethod>(model, readValue, NULL)
453 this->m_storage.Set(value);
457 template<typename Type, typename StorageMethod>
458 class Property<Type, PropertyReadWrite, StorageMethod>:
459 public PropertyBase<Type, StorageMethod>
462 typedef typename PropertyBase<Type, StorageMethod>::EventListenerType
465 typedef typename PropertyBase<Type, StorageMethod>::DelegateType
468 typedef typename PropertyBase<Type, StorageMethod>::ReadDelegateType
471 typedef typename PropertyBase<Type, StorageMethod>::WriteDelegateType
475 explicit Property(Model *model,
476 ReadDelegateType readValue = NULL,
477 WriteDelegateType writeValue = NULL) :
478 PropertyBase<Type, StorageMethod>(model, readValue, writeValue)
481 Property(Model *model,
483 ReadDelegateType readValue = NULL,
484 WriteDelegateType writeValue = NULL) :
485 PropertyBase<Type, StorageMethod>(model, readValue, writeValue)
487 this->m_storage.Set(value);
490 virtual void Set(const Type &value)
492 ReadWriteMutex::ScopedWriteLock lock(&this->m_model->m_mutex);
494 if (this->m_storage.Get() == value) {
498 this->m_storage.Set(value);
500 this->EmitEvent(PropertyEvent<Type>(value, this->m_model),
504 void SetWithoutLock(const Type &value)
506 if (this->m_storage.Get() == value) {
510 this->m_storage.Set(value);
516 #endif // DPL_PROPERTY_H