Update git submodules
[LibreOffice.git] / forms / source / xforms / propertysetbase.hxx
blobd6ae9740588023a5a38769ed3dfb7b04b136abd1
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
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 #pragma once
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>
28 #include <map>
29 #include <memory>
31 namespace com::sun::star::uno {
32 class Any;
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
41 protected:
42 PropertyAccessorBase() { }
43 virtual ~PropertyAccessorBase() override;
45 public:
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
59 public:
60 typedef WRITER Writer;
61 typedef READER Reader;
63 private:
64 CLASS* m_pInstance;
65 Writer m_pWriter;
66 Reader m_pReader;
68 public:
69 GenericPropertyAccessor( CLASS* pInstance, Writer pWriter, Reader pReader )
70 :m_pInstance( pInstance )
71 ,m_pWriter( pWriter )
72 ,m_pReader( pReader )
76 virtual bool approveValue( const css::uno::Any& rValue ) const override
78 VALUE aVal;
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
105 , VALUE
106 , void (CLASS::*)( const VALUE& )
107 , VALUE (CLASS::*)() const
110 protected:
111 typedef void (CLASS::*Writer)( const VALUE& );
112 typedef VALUE (CLASS::*Reader)() const;
113 public:
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
125 , bool
126 , void (CLASS::*)( bool )
127 , bool (CLASS::*)() const
130 protected:
131 typedef void (CLASS::*Writer)( bool );
132 typedef bool (CLASS::*Reader)() const;
133 public:
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
145 , VALUE
146 , void (SAL_CALL CLASS::*)( const VALUE& )
147 , VALUE (SAL_CALL CLASS::*)()
150 protected:
151 typedef void (SAL_CALL CLASS::*Writer)( const VALUE& );
152 typedef VALUE (SAL_CALL CLASS::*Reader)();
153 public:
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
174 private:
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;
184 protected:
185 PropertySetBase();
186 virtual ~PropertySetBase() override;
188 /** registers a new property to be supported by this instance
189 @param rProperty
190 the descriptor for the to-be-supported property
191 @param rAccessor
192 an instance which is able to provide read and possibly write access to
193 the property.
194 @precond
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.
217 @param nHandle
218 the handle of the property. Must denote a property supported by this instance, i.e.
219 one previously registered via <member>registerProperty</member>.
221 @precond
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.
241 @param nHandle
242 the handle of the property. Must denote a property supported by this instance, i.e.
243 one previously registered via <member>registerProperty</member>.
244 @param rValue
245 the value to cache
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;
258 public:
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
262 @param nHandle
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;
281 private:
282 /** locates a property given by handle
283 @param nHandle
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
308 private:
309 const PropertySetBase& m_rPropertySet;
310 sal_Int32 m_nHandle;
311 css::uno::Any m_aOldValue;
313 public:
314 /** constructs a PropertyChangeNotifier
315 @param rPropertySet
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.
319 @param nHandle
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: */