Branch data Line data Source code
1 : : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 : : /*************************************************************************
3 : : *
4 : : * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5 : : *
6 : : * Copyright 2000, 2010 Oracle and/or its affiliates.
7 : : *
8 : : * OpenOffice.org - a multi-platform office productivity suite
9 : : *
10 : : * This file is part of OpenOffice.org.
11 : : *
12 : : * OpenOffice.org is free software: you can redistribute it and/or modify
13 : : * it under the terms of the GNU Lesser General Public License version 3
14 : : * only, as published by the Free Software Foundation.
15 : : *
16 : : * OpenOffice.org is distributed in the hope that it will be useful,
17 : : * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 : : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 : : * GNU Lesser General Public License version 3 for more details
20 : : * (a copy is included in the LICENSE file that accompanied this code).
21 : : *
22 : : * You should have received a copy of the GNU Lesser General Public License
23 : : * version 3 along with OpenOffice.org. If not, see
24 : : * <http://www.openoffice.org/license.html>
25 : : * for a copy of the LGPLv3 License.
26 : : *
27 : : ************************************************************************/
28 : : #ifndef _PROPERTYSETBASE_HXX
29 : : #define _PROPERTYSETBASE_HXX
30 : :
31 : : #include <cppuhelper/weak.hxx>
32 : : #include <com/sun/star/lang/XTypeProvider.hpp>
33 : : #include <comphelper/propstate.hxx>
34 : : #include <comphelper/propertysetinfo.hxx>
35 : : #include <comphelper/proparrhlp.hxx>
36 : : #include <rtl/ref.hxx>
37 : :
38 : : // include for inlined helper function below
39 : : #include <com/sun/star/lang/IllegalArgumentException.hpp>
40 : : #include <com/sun/star/beans/PropertyAttribute.hpp>
41 : :
42 : : #include <map>
43 : :
44 : : // forward declarations for method arguments
45 : : namespace com { namespace sun { namespace star { namespace uno {
46 : : class Any;
47 : : class RuntimeException;
48 : : template<class T> class Sequence;
49 : : } } } }
50 : :
51 : : /** base class which encapsulates accessing (reading/writing) concrete property values
52 : : */
53 : : class PropertyAccessorBase : public ::rtl::IReference
54 : : {
55 : : private:
56 : : oslInterlockedCount m_refCount;
57 : :
58 : : protected:
59 : 0 : PropertyAccessorBase() : m_refCount( 0 ) { }
60 : : virtual ~PropertyAccessorBase();
61 : :
62 : : public:
63 : : virtual oslInterlockedCount SAL_CALL acquire();
64 : : virtual oslInterlockedCount SAL_CALL release();
65 : :
66 : : virtual bool approveValue( const com::sun::star::uno::Any& rValue ) const = 0;
67 : : virtual void setValue( const com::sun::star::uno::Any& rValue ) = 0;
68 : : virtual void getValue( com::sun::star::uno::Any& rValue ) const = 0;
69 : : virtual bool isWriteable() const = 0;
70 : : };
71 : :
72 : :
73 : : /** helper class for implementing property accessors through public member functions
74 : : */
75 : : template< typename CLASS, typename VALUE, class WRITER, class READER >
76 [ # # ][ # # ]: 0 : class GenericPropertyAccessor : public PropertyAccessorBase
[ # # ][ # # ]
[ # # ]
77 : : {
78 : : public:
79 : : typedef WRITER Writer;
80 : : typedef READER Reader;
81 : :
82 : : private:
83 : : CLASS* m_pInstance;
84 : : Writer m_pWriter;
85 : : Reader m_pReader;
86 : :
87 : : public:
88 : 0 : GenericPropertyAccessor( CLASS* pInstance, Writer pWriter, Reader pReader )
89 : : :m_pInstance( pInstance )
90 : : ,m_pWriter( pWriter )
91 : 0 : ,m_pReader( pReader )
92 : : {
93 : 0 : }
94 : :
95 : 0 : virtual bool approveValue( const com::sun::star::uno::Any& rValue ) const
96 : : {
97 [ # # ]: 0 : VALUE aVal;
98 [ # # ][ # # ]: 0 : return ( rValue >>= aVal );
[ # # ][ # # ]
[ # # ][ # # ]
99 : : }
100 : :
101 : 0 : virtual void setValue( const com::sun::star::uno::Any& rValue )
102 : : {
103 [ # # ]: 0 : VALUE aTypedVal = VALUE();
104 [ # # # # ]: 0 : OSL_VERIFY( rValue >>= aTypedVal );
[ # # # #
# ]
105 [ # # ][ # # ]: 0 : (m_pInstance->*m_pWriter)( aTypedVal );
[ # # ][ # # ]
[ # # # # ]
[ # # ][ # # ]
[ # # # # ]
[ # # ]
[ # # # # ]
[ # # ]
[ # # # ]
[ # # # # ]
[ # # ][ # # ]
[ # # ][ # # ]
106 : 0 : }
107 : :
108 : 0 : virtual void getValue( com::sun::star::uno::Any& rValue ) const
109 : : {
110 [ # # ][ # # ]: 0 : rValue = com::sun::star::uno::makeAny( (m_pInstance->*m_pReader)() );
[ # # ][ # # ]
[ # # ][ # # ]
[ # # # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ]
111 : 0 : }
112 : :
113 : 0 : virtual bool isWriteable() const
114 : : {
115 : 0 : return m_pWriter != 0;
116 : : }
117 : : };
118 : :
119 : : /** helper class for implementing property accessors via non-UNO methods
120 : : */
121 : : template< typename CLASS, typename VALUE >
122 [ # # ][ # # ]: 0 : class DirectPropertyAccessor
[ # # ][ # # ]
123 : : :public GenericPropertyAccessor < CLASS
124 : : , VALUE
125 : : , void (CLASS::*)( const VALUE& )
126 : : , VALUE (CLASS::*)() const
127 : : >
128 : : {
129 : : protected:
130 : : typedef void (CLASS::*Writer)( const VALUE& );
131 : : typedef VALUE (CLASS::*Reader)() const;
132 : : public:
133 : 0 : DirectPropertyAccessor( CLASS* pInstance, Writer pWriter, Reader pReader )
134 : 0 : :GenericPropertyAccessor< CLASS, VALUE, Writer, Reader >( pInstance, pWriter, pReader )
135 : : {
136 : 0 : }
137 : : };
138 : :
139 : : /** helper class for implementing non-UNO accessors to a boolean property
140 : : */
141 : : template< typename CLASS, typename DUMMY >
142 [ # # ]: 0 : class BooleanPropertyAccessor
143 : : :public GenericPropertyAccessor < CLASS
144 : : , bool
145 : : , void (CLASS::*)( bool )
146 : : , bool (CLASS::*)() const
147 : : >
148 : : {
149 : : protected:
150 : : typedef void (CLASS::*Writer)( bool );
151 : : typedef bool (CLASS::*Reader)() const;
152 : : public:
153 : 0 : BooleanPropertyAccessor( CLASS* pInstance, Writer pWriter, Reader pReader )
154 : 0 : :GenericPropertyAccessor< CLASS, bool, Writer, Reader >( pInstance, pWriter, pReader )
155 : : {
156 : 0 : }
157 : : };
158 : :
159 : : /** helper class for implementing property accessors via UNO methods
160 : : */
161 : : template< typename CLASS, typename VALUE >
162 [ # # ]: 0 : class APIPropertyAccessor
163 : : :public GenericPropertyAccessor < CLASS
164 : : , VALUE
165 : : , void (SAL_CALL CLASS::*)( const VALUE& )
166 : : , VALUE (SAL_CALL CLASS::*)()
167 : : >
168 : : {
169 : : protected:
170 : : typedef void (SAL_CALL CLASS::*Writer)( const VALUE& );
171 : : typedef VALUE (SAL_CALL CLASS::*Reader)();
172 : : public:
173 : 0 : APIPropertyAccessor( CLASS* pInstance, Writer pWriter, Reader pReader )
174 : 0 : :GenericPropertyAccessor< CLASS, VALUE, Writer, Reader >( pInstance, pWriter, pReader )
175 : : {
176 : 0 : }
177 : : };
178 : :
179 : : /** bridges two XPropertySet helper implementations
180 : :
181 : : The <type scope="comphelper">OStatefulPropertySet</type> (basically, the
182 : : <type scope="cppu">OPropertySetHelper</type>) implements a comprehensive framework
183 : : for property sets, including property change notifications.
184 : : However, it lacks some easy possibilities to declare the supported properties.
185 : : Other helper structs and classes allow for this, but are lacking needed features
186 : : such as property change notifications.
187 : :
188 : : The <type>PropertySetBase</type> bridges various implementations,
189 : : so you have the best of both worlds.
190 : : */
191 : : class PropertySetBase : public ::comphelper::OStatefulPropertySet
192 : : {
193 : : private:
194 : : typedef com::sun::star::uno::Any Any_t;
195 : :
196 : : typedef ::std::map< const sal_Int32, ::rtl::Reference< PropertyAccessorBase > > PropertyAccessors;
197 : : typedef ::std::vector< ::com::sun::star::beans::Property > PropertyArray;
198 : : typedef ::std::map< const sal_Int32, Any_t > PropertyValueCache;
199 : :
200 : : PropertyArray m_aProperties;
201 : : cppu::IPropertyArrayHelper* m_pProperties;
202 : : PropertyAccessors m_aAccessors;
203 : : PropertyValueCache m_aCache;
204 : :
205 : : protected:
206 : : PropertySetBase();
207 : : virtual ~PropertySetBase();
208 : :
209 : : /** registers a new property to be supported by this instance
210 : : @param rProperty
211 : : the descriptor for the to-be-supported property
212 : : @param rAccessor
213 : : an instance which is able to provide read and possibly write access to
214 : : the property.
215 : : @precond
216 : : Must not be called after any of the property set related UNO interfaces
217 : : has been used. Usually, you will do a number of <member>registerProperty</member>
218 : : calls in the constructor of your class.
219 : : */
220 : : void registerProperty(
221 : : const com::sun::star::beans::Property& rProperty,
222 : : const ::rtl::Reference< PropertyAccessorBase >& rAccessor
223 : : );
224 : :
225 : : /** notifies a change in a given property value, if necessary
226 : :
227 : : The necessity of the notification is determined by a cached value for the given
228 : : property. Caching happens after notification.
229 : :
230 : : That is, when you call <member>notifyAndCachePropertyValue</member> for the first time,
231 : : a value for the given property is default constructed, and considered to be the "old value".
232 : : If this value differs from the current value, then this change is notified to all interested
233 : : listeners. Finally, the current value is remembered.
234 : :
235 : : Subsequent calls to <member>notifyAndCachePropertyValue</member> use the remembered value as
236 : : "old value", and from then on behave as the first call.
237 : :
238 : : @param nHandle
239 : : the handle of the property. Must denote a property supported by this instance, i.e.
240 : : one previously registered via <member>registerProperty</member>.
241 : :
242 : : @precond
243 : : our ref count must not be 0. The reason is that during this method's execution,
244 : : the instance might be acquired and released, which would immediately destroy
245 : : the instance if it has a ref count of 0.
246 : :
247 : : @seealso initializePropertyValueCache
248 : : */
249 : : void notifyAndCachePropertyValue( sal_Int32 nHandle );
250 : :
251 : : /** initializes the property value cache for the given property, with its current value
252 : :
253 : : Usually used to initialize the cache with values which are different from default
254 : : constructed values. Say you have a boolean property whose initial state
255 : : is <TRUE/>. Say you call <member>notifyAndCachePropertyValue</member> the first time: it will
256 : : default construct the "old value" for this property as <FALSE/>, and thus <b>not</b> do
257 : : any notifications if the "current value" is also <FALSE/> - which might be wrong, since
258 : : the guessing of the "old value" differed from the real initial value which was <TRUE/>.
259 : :
260 : : Too confusing? Okay, than just call this method for every property you have.
261 : :
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 : : @param rValue
266 : : the value to cache
267 : : @seealso notifyAndCachePropertyValue
268 : : */
269 : : void initializePropertyValueCache( sal_Int32 nHandle );
270 : :
271 : : /// OPropertysetHelper methods
272 : : virtual sal_Bool SAL_CALL convertFastPropertyValue( Any_t& rConvertedValue, Any_t& rOldValue, sal_Int32 nHandle, const Any_t& rValue )
273 : : throw (::com::sun::star::lang::IllegalArgumentException);
274 : : virtual void SAL_CALL setFastPropertyValue_NoBroadcast( sal_Int32 nHandle, const Any_t& rValue )
275 : : throw (::com::sun::star::uno::Exception);
276 : : virtual void SAL_CALL getFastPropertyValue( Any_t& rValue, sal_Int32 nHandle ) const;
277 : :
278 : : virtual cppu::IPropertyArrayHelper& SAL_CALL getInfoHelper();
279 : : virtual ::com::sun::star::uno::Reference< ::com::sun::star::beans::XPropertySetInfo > SAL_CALL getPropertySetInfo( ) throw(::com::sun::star::uno::RuntimeException);
280 : :
281 : : public:
282 : : /// helper struct for granting selective access to some notification-related methods
283 : 0 : struct NotifierAccess { friend struct PropertyChangeNotifier; private: NotifierAccess() { } };
284 : : /** retrieves the current property value for the given handle
285 : : @param nHandle
286 : : the handle of the property. Must denote a property supported by this instance, i.e.
287 : : one previously registered via <member>registerProperty</member>.
288 : : @see registerProperty
289 : : */
290 : 0 : inline void getCurrentPropertyValueByHandle( sal_Int32 nHandle, Any_t& /* [out] */ rValue, const NotifierAccess& ) const
291 : : {
292 : 0 : getFastPropertyValue( rValue, nHandle );
293 : 0 : }
294 : :
295 : : /** notifies a change in a given property to all interested listeners
296 : : */
297 : 0 : inline void notifyPropertyChange( sal_Int32 nHandle, const Any_t& rOldValue, const Any_t& rNewValue, const NotifierAccess& ) const
298 : : {
299 : 0 : const_cast< PropertySetBase* >( this )->firePropertyChange( nHandle, rNewValue, rOldValue );
300 : 0 : }
301 : :
302 : : using ::comphelper::OStatefulPropertySet::getFastPropertyValue;
303 : :
304 : : private:
305 : : /** locates a property given by handle
306 : : @param nHandle
307 : : the handle of the property. Must denote a property supported by this instance, i.e.
308 : : one previously registered via <member>registerProperty</member>.
309 : : @see registerProperty
310 : : */
311 : : PropertyAccessorBase& locatePropertyHandler( sal_Int32 nHandle ) const;
312 : : };
313 : :
314 : : /** a helper class for notifying property changes in a <type>PropertySetBase</type> instance.
315 : :
316 : : You can create an instance of this class on the stack of a method which is to programmatically
317 : : change the value of a property. In its constructor, the instance will acquire the current property
318 : : value, and in its destructor, it will notify the change of this property's value (if necessary).
319 : :
320 : : You do not need this class if you are modifying property values by using the X(Fast|Multi)PropertSet
321 : : methods, since those already care for property notifications. You only need it if you're changing
322 : : the internal representation of your property directly.
323 : :
324 : : Also note that usually, notifications in the UNO world should be done without a locked mutex. So
325 : : if you use this class in conjunction with a <type>MutexGuard</type>, ensure that you <b>first</b>
326 : : instantiate the <type>PropertyChangeNotifier</type>, and <b>then</b> the <type>MutexGuard</type>,
327 : : so your mutex is released before the notification happens.
328 : : */
329 : : struct PropertyChangeNotifier
330 : : {
331 : : private:
332 : : const PropertySetBase& m_rPropertySet;
333 : : sal_Int32 m_nHandle;
334 : : com::sun::star::uno::Any m_aOldValue;
335 : :
336 : : public:
337 : : /** constructs a PropertyChangeNotifier
338 : : @param rPropertySet
339 : : the property set implementation whose property is going to be changed. Note
340 : : that this property set implementation must live at least as long as the
341 : : PropertyChangeNotifier instance does.
342 : : @param nHandle
343 : : the handle of the property which is going to be changed. Must be a valid property
344 : : handle for the given <arg>rPropertySet</arg>
345 : : */
346 : 0 : inline PropertyChangeNotifier( const PropertySetBase& rPropertySet, sal_Int32 nHandle )
347 : : :m_rPropertySet( rPropertySet )
348 : 0 : ,m_nHandle( nHandle )
349 : : {
350 [ # # ]: 0 : m_rPropertySet.getCurrentPropertyValueByHandle( m_nHandle, m_aOldValue, PropertySetBase::NotifierAccess() );
351 : 0 : }
352 : 0 : inline ~PropertyChangeNotifier()
353 : 0 : {
354 : 0 : com::sun::star::uno::Any aNewValue;
355 [ # # ]: 0 : m_rPropertySet.getCurrentPropertyValueByHandle( m_nHandle, aNewValue, PropertySetBase::NotifierAccess() );
356 [ # # ]: 0 : if ( aNewValue != m_aOldValue )
357 : : {
358 [ # # ]: 0 : m_rPropertySet.notifyPropertyChange( m_nHandle, m_aOldValue, aNewValue, PropertySetBase::NotifierAccess() );
359 : 0 : }
360 : 0 : }
361 : : };
362 : :
363 : :
364 : : #define PROPERTY_FLAGS( NAME, TYPE, FLAG ) com::sun::star::beans::Property( \
365 : : ::rtl::OUString( #NAME, sizeof( #NAME ) - 1, RTL_TEXTENCODING_ASCII_US ), \
366 : : HANDLE_##NAME, getCppuType( static_cast< TYPE* >( NULL ) ), FLAG )
367 : : #define PROPERTY( NAME, TYPE ) PROPERTY_FLAGS( NAME, TYPE, com::sun::star::beans::PropertyAttribute::BOUND )
368 : : #define PROPERTY_RO( NAME, TYPE ) PROPERTY_FLAGS( NAME, TYPE, com::sun::star::beans::PropertyAttribute::BOUND | com::sun::star::beans::PropertyAttribute::READONLY )
369 : :
370 : : #endif
371 : :
372 : : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|