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 .
21 #include <comphelper/propstate.hxx>
22 #include <rtl/ref.hxx>
23 #include <salhelper/simplereferenceobject.hxx>
25 // include for inlined helper function below
26 #include <com/sun/star/beans/PropertyAttribute.hpp>
31 namespace com::sun::star::uno
{
33 class RuntimeException
;
34 template<class T
> class Sequence
;
37 /** base class which encapsulates accessing (reading/writing) concrete property values
39 class PropertyAccessorBase
: public salhelper::SimpleReferenceObject
42 PropertyAccessorBase() { }
43 virtual ~PropertyAccessorBase() override
;
47 virtual bool approveValue( const css::uno::Any
& rValue
) const = 0;
48 virtual void setValue( const css::uno::Any
& rValue
) = 0;
49 virtual void getValue( css::uno::Any
& rValue
) const = 0;
50 virtual bool isWriteable() const = 0;
54 /** helper class for implementing property accessors through public member functions
56 template< typename CLASS
, typename VALUE
, class WRITER
, class READER
>
57 class GenericPropertyAccessor
: public PropertyAccessorBase
60 typedef WRITER Writer
;
61 typedef READER Reader
;
69 GenericPropertyAccessor( CLASS
* pInstance
, Writer pWriter
, Reader pReader
)
70 :m_pInstance( pInstance
)
76 virtual bool approveValue( const css::uno::Any
& rValue
) const override
79 return ( rValue
>>= aVal
);
82 virtual void setValue( const css::uno::Any
& rValue
) override
84 VALUE aTypedVal
= VALUE();
85 OSL_VERIFY( rValue
>>= aTypedVal
);
86 (m_pInstance
->*m_pWriter
)( aTypedVal
);
89 virtual void getValue( css::uno::Any
& rValue
) const override
91 rValue
= css::uno::Any( (m_pInstance
->*m_pReader
)() );
94 virtual bool isWriteable() const override
96 return m_pWriter
!= nullptr;
100 /** helper class for implementing property accessors via non-UNO methods
102 template< typename CLASS
, typename VALUE
>
103 class DirectPropertyAccessor
104 :public GenericPropertyAccessor
< CLASS
106 , void (CLASS::*)( const VALUE
& )
107 , VALUE (CLASS::*)() const
111 typedef void (CLASS::*Writer
)( const VALUE
& );
112 typedef VALUE (CLASS::*Reader
)() const;
114 DirectPropertyAccessor( CLASS
* pInstance
, Writer pWriter
, Reader pReader
)
115 :GenericPropertyAccessor
< CLASS
, VALUE
, Writer
, Reader
>( pInstance
, pWriter
, pReader
)
120 /** helper class for implementing non-UNO accessors to a boolean property
122 template< typename CLASS
>
123 class BooleanPropertyAccessor
124 :public GenericPropertyAccessor
< CLASS
126 , void (CLASS::*)( bool )
127 , bool (CLASS::*)() const
131 typedef void (CLASS::*Writer
)( bool );
132 typedef bool (CLASS::*Reader
)() const;
134 BooleanPropertyAccessor( CLASS
* pInstance
, Writer pWriter
, Reader pReader
)
135 :GenericPropertyAccessor
< CLASS
, bool, Writer
, Reader
>( pInstance
, pWriter
, pReader
)
140 /** helper class for implementing property accessors via UNO methods
142 template< typename CLASS
, typename VALUE
>
143 class APIPropertyAccessor
144 :public GenericPropertyAccessor
< CLASS
146 , void (SAL_CALL
CLASS::*)( const VALUE
& )
147 , VALUE (SAL_CALL
CLASS::*)()
151 typedef void (SAL_CALL
CLASS::*Writer
)( const VALUE
& );
152 typedef VALUE (SAL_CALL
CLASS::*Reader
)();
154 APIPropertyAccessor( CLASS
* pInstance
, Writer pWriter
, Reader pReader
)
155 :GenericPropertyAccessor
< CLASS
, VALUE
, Writer
, Reader
>( pInstance
, pWriter
, pReader
)
160 /** bridges two XPropertySet helper implementations
162 The <type scope="comphelper">OStatefulPropertySet</type> (basically, the
163 <type scope="cppu">OPropertySetHelper</type>) implements a comprehensive framework
164 for property sets, including property change notifications.
165 However, it lacks some easy possibilities to declare the supported properties.
166 Other helper structs and classes allow for this, but are lacking needed features
167 such as property change notifications.
169 The <type>PropertySetBase</type> bridges various implementations,
170 so you have the best of both worlds.
172 class PropertySetBase
: public ::comphelper::OStatefulPropertySet
175 typedef ::std::map
< const sal_Int32
, ::rtl::Reference
< PropertyAccessorBase
> > PropertyAccessors
;
176 typedef ::std::vector
< css::beans::Property
> PropertyArray
;
177 typedef ::std::map
< const sal_Int32
, css::uno::Any
> PropertyValueCache
;
179 PropertyArray m_aProperties
;
180 std::unique_ptr
<cppu::IPropertyArrayHelper
> m_pProperties
;
181 PropertyAccessors m_aAccessors
;
182 PropertyValueCache m_aCache
;
186 virtual ~PropertySetBase() override
;
188 /** registers a new property to be supported by this instance
190 the descriptor for the to-be-supported property
192 an instance which is able to provide read and possibly write access to
195 Must not be called after any of the property set related UNO interfaces
196 has been used. Usually, you will do a number of <member>registerProperty</member>
197 calls in the constructor of your class.
199 void registerProperty(
200 const css::beans::Property
& rProperty
,
201 const ::rtl::Reference
< PropertyAccessorBase
>& rAccessor
204 /** notifies a change in a given property value, if necessary
206 The necessity of the notification is determined by a cached value for the given
207 property. Caching happens after notification.
209 That is, when you call <member>notifyAndCachePropertyValue</member> for the first time,
210 a value for the given property is default constructed, and considered to be the "old value".
211 If this value differs from the current value, then this change is notified to all interested
212 listeners. Finally, the current value is remembered.
214 Subsequent calls to <member>notifyAndCachePropertyValue</member> use the remembered value as
215 "old value", and from then on behave as the first call.
218 the handle of the property. Must denote a property supported by this instance, i.e.
219 one previously registered via <member>registerProperty</member>.
222 our ref count must not be 0. The reason is that during this method's execution,
223 the instance might be acquired and released, which would immediately destroy
224 the instance if it has a ref count of 0.
226 @seealso initializePropertyValueCache
228 void notifyAndCachePropertyValue( sal_Int32 nHandle
);
230 /** initializes the property value cache for the given property, with its current value
232 Usually used to initialize the cache with values which are different from default
233 constructed values. Say you have a boolean property whose initial state
234 is <TRUE/>. Say you call <member>notifyAndCachePropertyValue</member> the first time: it will
235 default construct the "old value" for this property as <FALSE/>, and thus <b>not</b> do
236 any notifications if the "current value" is also <FALSE/> - which might be wrong, since
237 the guessing of the "old value" differed from the real initial value which was <TRUE/>.
239 Too confusing? Okay, then just call this method for every property you have.
242 the handle of the property. Must denote a property supported by this instance, i.e.
243 one previously registered via <member>registerProperty</member>.
246 @seealso notifyAndCachePropertyValue
248 void initializePropertyValueCache( sal_Int32 nHandle
);
250 /// OPropertysetHelper methods
251 virtual sal_Bool SAL_CALL
convertFastPropertyValue( css::uno::Any
& rConvertedValue
, css::uno::Any
& rOldValue
, sal_Int32 nHandle
, const css::uno::Any
& rValue
) override
;
252 virtual void SAL_CALL
setFastPropertyValue_NoBroadcast( sal_Int32 nHandle
, const css::uno::Any
& rValue
) override
;
253 virtual void SAL_CALL
getFastPropertyValue( css::uno::Any
& rValue
, sal_Int32 nHandle
) const override
;
255 virtual cppu::IPropertyArrayHelper
& SAL_CALL
getInfoHelper() override
;
256 virtual css::uno::Reference
< css::beans::XPropertySetInfo
> SAL_CALL
getPropertySetInfo( ) override
;
259 /// helper struct for granting selective access to some notification-related methods
260 struct NotifierAccess
{ friend struct PropertyChangeNotifier
; private: NotifierAccess() { } };
261 /** retrieves the current property value for the given handle
263 the handle of the property. Must denote a property supported by this instance, i.e.
264 one previously registered via <member>registerProperty</member>.
265 @see registerProperty
267 void getCurrentPropertyValueByHandle( sal_Int32 nHandle
, css::uno::Any
& /* [out] */ rValue
, const NotifierAccess
& ) const
269 getFastPropertyValue( rValue
, nHandle
);
272 /** notifies a change in a given property to all interested listeners
274 void notifyPropertyChange( sal_Int32 nHandle
, const css::uno::Any
& rOldValue
, const css::uno::Any
& rNewValue
, const NotifierAccess
& ) const
276 const_cast< PropertySetBase
* >( this )->firePropertyChange( nHandle
, rNewValue
, rOldValue
);
279 using ::comphelper::OStatefulPropertySet::getFastPropertyValue
;
282 /** locates a property given by handle
284 the handle of the property. Must denote a property supported by this instance, i.e.
285 one previously registered via <member>registerProperty</member>.
286 @see registerProperty
288 PropertyAccessorBase
& locatePropertyHandler( sal_Int32 nHandle
) const;
291 /** a helper class for notifying property changes in a <type>PropertySetBase</type> instance.
293 You can create an instance of this class on the stack of a method which is to programmatically
294 change the value of a property. In its constructor, the instance will acquire the current property
295 value, and in its destructor, it will notify the change of this property's value (if necessary).
297 You do not need this class if you are modifying property values by using the X(Fast|Multi)PropertSet
298 methods, since those already care for property notifications. You only need it if you're changing
299 the internal representation of your property directly.
301 Also note that usually, notifications in the UNO world should be done without a locked mutex. So
302 if you use this class in conjunction with a <type>MutexGuard</type>, ensure that you <b>first</b>
303 instantiate the <type>PropertyChangeNotifier</type>, and <b>then</b> the <type>MutexGuard</type>,
304 so your mutex is released before the notification happens.
306 struct PropertyChangeNotifier
309 const PropertySetBase
& m_rPropertySet
;
311 css::uno::Any m_aOldValue
;
314 /** constructs a PropertyChangeNotifier
316 the property set implementation whose property is going to be changed. Note
317 that this property set implementation must live at least as long as the
318 PropertyChangeNotifier instance does.
320 the handle of the property which is going to be changed. Must be a valid property
321 handle for the given <arg>rPropertySet</arg>
323 PropertyChangeNotifier( const PropertySetBase
& rPropertySet
, sal_Int32 nHandle
)
324 :m_rPropertySet( rPropertySet
)
325 ,m_nHandle( nHandle
)
327 m_rPropertySet
.getCurrentPropertyValueByHandle( m_nHandle
, m_aOldValue
, PropertySetBase::NotifierAccess() );
329 ~PropertyChangeNotifier()
331 css::uno::Any aNewValue
;
332 m_rPropertySet
.getCurrentPropertyValueByHandle( m_nHandle
, aNewValue
, PropertySetBase::NotifierAccess() );
333 if ( aNewValue
!= m_aOldValue
)
335 m_rPropertySet
.notifyPropertyChange( m_nHandle
, m_aOldValue
, aNewValue
, PropertySetBase::NotifierAccess() );
340 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */