1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
19 #ifndef _PROPERTYSETBASE_HXX
20 #define _PROPERTYSETBASE_HXX
22 #include <cppuhelper/weak.hxx>
23 #include <com/sun/star/lang/XTypeProvider.hpp>
24 #include <comphelper/propstate.hxx>
25 #include <comphelper/propertysetinfo.hxx>
26 #include <comphelper/proparrhlp.hxx>
27 #include <rtl/ref.hxx>
29 // include for inlined helper function below
30 #include <com/sun/star/lang/IllegalArgumentException.hpp>
31 #include <com/sun/star/beans/PropertyAttribute.hpp>
35 // forward declarations for method arguments
36 namespace com
{ namespace sun
{ namespace star
{ namespace uno
{
38 class RuntimeException
;
39 template<class T
> class Sequence
;
42 /** base class which encapsulates accessing (reading/writing) concrete property values
44 class PropertyAccessorBase
: public ::rtl::IReference
47 oslInterlockedCount m_refCount
;
50 PropertyAccessorBase() : m_refCount( 0 ) { }
51 virtual ~PropertyAccessorBase();
54 virtual oslInterlockedCount SAL_CALL
acquire();
55 virtual oslInterlockedCount SAL_CALL
release();
57 virtual bool approveValue( const com::sun::star::uno::Any
& rValue
) const = 0;
58 virtual void setValue( const com::sun::star::uno::Any
& rValue
) = 0;
59 virtual void getValue( com::sun::star::uno::Any
& rValue
) const = 0;
60 virtual bool isWriteable() const = 0;
64 /** helper class for implementing property accessors through public member functions
66 template< typename CLASS
, typename VALUE
, class WRITER
, class READER
>
67 class GenericPropertyAccessor
: public PropertyAccessorBase
70 typedef WRITER Writer
;
71 typedef READER Reader
;
79 GenericPropertyAccessor( CLASS
* pInstance
, Writer pWriter
, Reader pReader
)
80 :m_pInstance( pInstance
)
86 virtual bool approveValue( const com::sun::star::uno::Any
& rValue
) const
89 return ( rValue
>>= aVal
);
92 virtual void setValue( const com::sun::star::uno::Any
& rValue
)
94 VALUE aTypedVal
= VALUE();
95 OSL_VERIFY( rValue
>>= aTypedVal
);
96 (m_pInstance
->*m_pWriter
)( aTypedVal
);
99 virtual void getValue( com::sun::star::uno::Any
& rValue
) const
101 rValue
= com::sun::star::uno::makeAny( (m_pInstance
->*m_pReader
)() );
104 virtual bool isWriteable() const
106 return m_pWriter
!= 0;
110 /** helper class for implementing property accessors via non-UNO methods
112 template< typename CLASS
, typename VALUE
>
113 class DirectPropertyAccessor
114 :public GenericPropertyAccessor
< CLASS
116 , void (CLASS::*)( const VALUE
& )
117 , VALUE (CLASS::*)() const
121 typedef void (CLASS::*Writer
)( const VALUE
& );
122 typedef VALUE (CLASS::*Reader
)() const;
124 DirectPropertyAccessor( CLASS
* pInstance
, Writer pWriter
, Reader pReader
)
125 :GenericPropertyAccessor
< CLASS
, VALUE
, Writer
, Reader
>( pInstance
, pWriter
, pReader
)
130 /** helper class for implementing non-UNO accessors to a boolean property
132 template< typename CLASS
, typename DUMMY
>
133 class BooleanPropertyAccessor
134 :public GenericPropertyAccessor
< CLASS
136 , void (CLASS::*)( bool )
137 , bool (CLASS::*)() const
141 typedef void (CLASS::*Writer
)( bool );
142 typedef bool (CLASS::*Reader
)() const;
144 BooleanPropertyAccessor( CLASS
* pInstance
, Writer pWriter
, Reader pReader
)
145 :GenericPropertyAccessor
< CLASS
, bool, Writer
, Reader
>( pInstance
, pWriter
, pReader
)
150 /** helper class for implementing property accessors via UNO methods
152 template< typename CLASS
, typename VALUE
>
153 class APIPropertyAccessor
154 :public GenericPropertyAccessor
< CLASS
156 , void (SAL_CALL
CLASS::*)( const VALUE
& )
157 , VALUE (SAL_CALL
CLASS::*)()
161 typedef void (SAL_CALL
CLASS::*Writer
)( const VALUE
& );
162 typedef VALUE (SAL_CALL
CLASS::*Reader
)();
164 APIPropertyAccessor( CLASS
* pInstance
, Writer pWriter
, Reader pReader
)
165 :GenericPropertyAccessor
< CLASS
, VALUE
, Writer
, Reader
>( pInstance
, pWriter
, pReader
)
170 /** bridges two XPropertySet helper implementations
172 The <type scope="comphelper">OStatefulPropertySet</type> (basically, the
173 <type scope="cppu">OPropertySetHelper</type>) implements a comprehensive framework
174 for property sets, including property change notifications.
175 However, it lacks some easy possibilities to declare the supported properties.
176 Other helper structs and classes allow for this, but are lacking needed features
177 such as property change notifications.
179 The <type>PropertySetBase</type> bridges various implementations,
180 so you have the best of both worlds.
182 class PropertySetBase
: public ::comphelper::OStatefulPropertySet
185 typedef com::sun::star::uno::Any Any_t
;
187 typedef ::std::map
< const sal_Int32
, ::rtl::Reference
< PropertyAccessorBase
> > PropertyAccessors
;
188 typedef ::std::vector
< ::com::sun::star::beans::Property
> PropertyArray
;
189 typedef ::std::map
< const sal_Int32
, Any_t
> PropertyValueCache
;
191 PropertyArray m_aProperties
;
192 cppu::IPropertyArrayHelper
* m_pProperties
;
193 PropertyAccessors m_aAccessors
;
194 PropertyValueCache m_aCache
;
198 virtual ~PropertySetBase();
200 /** registers a new property to be supported by this instance
202 the descriptor for the to-be-supported property
204 an instance which is able to provide read and possibly write access to
207 Must not be called after any of the property set related UNO interfaces
208 has been used. Usually, you will do a number of <member>registerProperty</member>
209 calls in the constructor of your class.
211 void registerProperty(
212 const com::sun::star::beans::Property
& rProperty
,
213 const ::rtl::Reference
< PropertyAccessorBase
>& rAccessor
216 /** notifies a change in a given property value, if necessary
218 The necessity of the notification is determined by a cached value for the given
219 property. Caching happens after notification.
221 That is, when you call <member>notifyAndCachePropertyValue</member> for the first time,
222 a value for the given property is default constructed, and considered to be the "old value".
223 If this value differs from the current value, then this change is notified to all interested
224 listeners. Finally, the current value is remembered.
226 Subsequent calls to <member>notifyAndCachePropertyValue</member> use the remembered value as
227 "old value", and from then on behave as the first call.
230 the handle of the property. Must denote a property supported by this instance, i.e.
231 one previously registered via <member>registerProperty</member>.
234 our ref count must not be 0. The reason is that during this method's execution,
235 the instance might be acquired and released, which would immediately destroy
236 the instance if it has a ref count of 0.
238 @seealso initializePropertyValueCache
240 void notifyAndCachePropertyValue( sal_Int32 nHandle
);
242 /** initializes the property value cache for the given property, with its current value
244 Usually used to initialize the cache with values which are different from default
245 constructed values. Say you have a boolean property whose initial state
246 is <TRUE/>. Say you call <member>notifyAndCachePropertyValue</member> the first time: it will
247 default construct the "old value" for this property as <FALSE/>, and thus <b>not</b> do
248 any notifications if the "current value" is also <FALSE/> - which might be wrong, since
249 the guessing of the "old value" differed from the real initial value which was <TRUE/>.
251 Too confusing? Okay, than just call this method for every property you have.
254 the handle of the property. Must denote a property supported by this instance, i.e.
255 one previously registered via <member>registerProperty</member>.
258 @seealso notifyAndCachePropertyValue
260 void initializePropertyValueCache( sal_Int32 nHandle
);
262 /// OPropertysetHelper methods
263 virtual sal_Bool SAL_CALL
convertFastPropertyValue( Any_t
& rConvertedValue
, Any_t
& rOldValue
, sal_Int32 nHandle
, const Any_t
& rValue
)
264 throw (::com::sun::star::lang::IllegalArgumentException
);
265 virtual void SAL_CALL
setFastPropertyValue_NoBroadcast( sal_Int32 nHandle
, const Any_t
& rValue
)
266 throw (::com::sun::star::uno::Exception
);
267 virtual void SAL_CALL
getFastPropertyValue( Any_t
& rValue
, sal_Int32 nHandle
) const;
269 virtual cppu::IPropertyArrayHelper
& SAL_CALL
getInfoHelper();
270 virtual ::com::sun::star::uno::Reference
< ::com::sun::star::beans::XPropertySetInfo
> SAL_CALL
getPropertySetInfo( ) throw(::com::sun::star::uno::RuntimeException
);
273 /// helper struct for granting selective access to some notification-related methods
274 struct NotifierAccess
{ friend struct PropertyChangeNotifier
; private: NotifierAccess() { } };
275 /** retrieves the current property value for the given handle
277 the handle of the property. Must denote a property supported by this instance, i.e.
278 one previously registered via <member>registerProperty</member>.
279 @see registerProperty
281 inline void getCurrentPropertyValueByHandle( sal_Int32 nHandle
, Any_t
& /* [out] */ rValue
, const NotifierAccess
& ) const
283 getFastPropertyValue( rValue
, nHandle
);
286 /** notifies a change in a given property to all interested listeners
288 inline void notifyPropertyChange( sal_Int32 nHandle
, const Any_t
& rOldValue
, const Any_t
& rNewValue
, const NotifierAccess
& ) const
290 const_cast< PropertySetBase
* >( this )->firePropertyChange( nHandle
, rNewValue
, rOldValue
);
293 using ::comphelper::OStatefulPropertySet::getFastPropertyValue
;
296 /** locates a property given by handle
298 the handle of the property. Must denote a property supported by this instance, i.e.
299 one previously registered via <member>registerProperty</member>.
300 @see registerProperty
302 PropertyAccessorBase
& locatePropertyHandler( sal_Int32 nHandle
) const;
305 /** a helper class for notifying property changes in a <type>PropertySetBase</type> instance.
307 You can create an instance of this class on the stack of a method which is to programmatically
308 change the value of a property. In its constructor, the instance will acquire the current property
309 value, and in its destructor, it will notify the change of this property's value (if necessary).
311 You do not need this class if you are modifying property values by using the X(Fast|Multi)PropertSet
312 methods, since those already care for property notifications. You only need it if you're changing
313 the internal representation of your property directly.
315 Also note that usually, notifications in the UNO world should be done without a locked mutex. So
316 if you use this class in conjunction with a <type>MutexGuard</type>, ensure that you <b>first</b>
317 instantiate the <type>PropertyChangeNotifier</type>, and <b>then</b> the <type>MutexGuard</type>,
318 so your mutex is released before the notification happens.
320 struct PropertyChangeNotifier
323 const PropertySetBase
& m_rPropertySet
;
325 com::sun::star::uno::Any m_aOldValue
;
328 /** constructs a PropertyChangeNotifier
330 the property set implementation whose property is going to be changed. Note
331 that this property set implementation must live at least as long as the
332 PropertyChangeNotifier instance does.
334 the handle of the property which is going to be changed. Must be a valid property
335 handle for the given <arg>rPropertySet</arg>
337 inline PropertyChangeNotifier( const PropertySetBase
& rPropertySet
, sal_Int32 nHandle
)
338 :m_rPropertySet( rPropertySet
)
339 ,m_nHandle( nHandle
)
341 m_rPropertySet
.getCurrentPropertyValueByHandle( m_nHandle
, m_aOldValue
, PropertySetBase::NotifierAccess() );
343 inline ~PropertyChangeNotifier()
345 com::sun::star::uno::Any aNewValue
;
346 m_rPropertySet
.getCurrentPropertyValueByHandle( m_nHandle
, aNewValue
, PropertySetBase::NotifierAccess() );
347 if ( aNewValue
!= m_aOldValue
)
349 m_rPropertySet
.notifyPropertyChange( m_nHandle
, m_aOldValue
, aNewValue
, PropertySetBase::NotifierAccess() );
355 #define PROPERTY_FLAGS( NAME, TYPE, FLAG ) com::sun::star::beans::Property( \
356 OUString( #NAME, sizeof( #NAME ) - 1, RTL_TEXTENCODING_ASCII_US ), \
357 HANDLE_##NAME, getCppuType( static_cast< TYPE* >( NULL ) ), FLAG )
358 #define PROPERTY( NAME, TYPE ) PROPERTY_FLAGS( NAME, TYPE, com::sun::star::beans::PropertyAttribute::BOUND )
359 #define PROPERTY_RO( NAME, TYPE ) PROPERTY_FLAGS( NAME, TYPE, com::sun::star::beans::PropertyAttribute::BOUND | com::sun::star::beans::PropertyAttribute::READONLY )
363 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */