1 /*************************************************************************
2  *
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * Copyright 2000, 2010 Oracle and/or its affiliates.
6  *
7  * OpenOffice.org - a multi-platform office productivity suite
8  *
9  * This file is part of OpenOffice.org.
10  *
11  * OpenOffice.org is free software: you can redistribute it and/or modify
12  * it under the terms of the GNU Lesser General Public License version 3
13  * only, as published by the Free Software Foundation.
14  *
15  * OpenOffice.org is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU Lesser General Public License version 3 for more details
19  * (a copy is included in the LICENSE file that accompanied this code).
20  *
21  * You should have received a copy of the GNU Lesser General Public License
22  * version 3 along with OpenOffice.org.  If not, see
23  * <http://www.openoffice.org/license.html>
24  * for a copy of the LGPLv3 License.
25  *
26  ************************************************************************/
27 
28 #ifndef _COMPHELPER_PROPERTY_AGGREGATION_HXX_
29 #define _COMPHELPER_PROPERTY_AGGREGATION_HXX_
30 
31 #include <com/sun/star/uno/XAggregation.hpp>
32 #include <comphelper/propstate.hxx>
33 #include "comphelper/comphelperdllapi.h"
34 
35 #include <map>
36 
37 //=========================================================================
38 //= property helper classes
39 //=========================================================================
40 
41 //.........................................................................
42 namespace comphelper
43 {
44 //.........................................................................
45 
46 //==================================================================
47 //= OPropertyAccessor
48 //= internal helper class for OPropertyArrayAggregationHelper
49 //==================================================================
50 namespace internal
51 {
52 	struct OPropertyAccessor
53 	{
54 		sal_Int32   nOriginalHandle;
55 		sal_Int32   nPos;
56 		sal_Bool    bAggregate;
57 
58 		OPropertyAccessor(sal_Int32 _nOriginalHandle, sal_Int32 _nPos, sal_Bool _bAggregate)
59 			:nOriginalHandle(_nOriginalHandle) ,nPos(_nPos) ,bAggregate(_bAggregate) { }
60 		OPropertyAccessor()
61 			:nOriginalHandle(-1) ,nPos(-1) ,bAggregate(sal_False) { }
62 
63 		sal_Bool operator==(const OPropertyAccessor& rOb) const { return nPos == rOb.nPos; }
64 		sal_Bool operator <(const OPropertyAccessor& rOb) const { return nPos < rOb.nPos; }
65 	};
66 
67 	typedef std::map< sal_Int32, OPropertyAccessor, ::std::less< sal_Int32 > >	PropertyAccessorMap;
68 	typedef PropertyAccessorMap::iterator			PropertyAccessorMapIterator;
69 	typedef PropertyAccessorMap::const_iterator		ConstPropertyAccessorMapIterator;
70 }
71 
72 //==================================================================
73 /**
74  * used as callback for a OPropertyArrayAggregationHelper
75  */
76 class IPropertyInfoService
77 {
78 public:
79 	/**	get the prefered handle for the given property
80 		@param		_rName		the property name
81 		@return					the handle the property should be refered by, or -1 if there are no
82 								preferences for the given property
83 	*/
84 	virtual	sal_Int32			getPreferedPropertyId(const ::rtl::OUString& _rName) = 0;
85 };
86 
87 /**
88  * used for implementing an cppu::IPropertyArrayHelper for classes
89  * aggregating property sets
90  */
91 
92 #define DEFAULT_AGGREGATE_PROPERTY_ID	10000
93 //------------------------------------------------------------------
94 class COMPHELPER_DLLPUBLIC OPropertyArrayAggregationHelper: public ::cppu::IPropertyArrayHelper
95 {
96 	friend class OPropertySetAggregationHelper;
97 protected:
98 
99 	::com::sun::star::uno::Sequence< ::com::sun::star::beans::Property>	m_aProperties;
100 	internal::PropertyAccessorMap			m_aPropertyAccessors;
101 
102 public:
103 	/** construct the object.
104 		@param	_rProperties	the properties of the object doing the aggregation. These properties
105 								are used without any checks, so the caller has to ensure that the names and
106 								handles are valid.
107 		@param	_rAggProperties	the properties of the aggregate, usually got via an call to getProperties on the
108 								XPropertySetInfo of the aggregate.
109 								The names of the properties are used without any checks, so the caller has to ensure
110 								that there are no doubles.
111 								The handles are stored for later quick access, but the outside-handles the
112 								aggregate properties get depend from the following two parameters.
113 		@param	_pInfoService
114 								If not NULL, the object pointed to is used to calc handles which should be used
115 								for refering the aggregate's properties from outside.
116 								If one of the properties returned from the info service conflict with other handles
117 								alread present (e.g. through _rProperties), the property is handled as if -1 was returned.
118 								If NULL (or, for a special property, a call to getPreferedPropertyId returns -1),
119 								the aggregate property(ies) get a new handle which they can be refered by from outside.
120 		@param	_nFirstAggregateId
121 								if the object is about to create new handles for the aggregate properties, it uses
122 								id's ascending from this given id.
123 								No checks are made if the handle range determined by _nFirstAggregateId conflicts with other
124 								handles within _rProperties.
125 	*/
126 	OPropertyArrayAggregationHelper(const ::com::sun::star::uno::Sequence< ::com::sun::star::beans::Property>& _rProperties,
127 									const ::com::sun::star::uno::Sequence< ::com::sun::star::beans::Property>& _rAggProperties,
128 									IPropertyInfoService* _pInfoService = NULL,
129 									sal_Int32 _nFirstAggregateId = DEFAULT_AGGREGATE_PROPERTY_ID);
130 
131 
132 	/// inherited from IPropertyArrayHelper
133 	virtual sal_Bool SAL_CALL fillPropertyMembersByHandle( ::rtl::OUString* _pPropName, sal_Int16* _pAttributes,
134 											sal_Int32 _nHandle) ;
135 
136 	/// inherited from IPropertyArrayHelper
137     virtual ::com::sun::star::uno::Sequence< ::com::sun::star::beans::Property> SAL_CALL getProperties();
138 	/// inherited from IPropertyArrayHelper
139 	virtual ::com::sun::star::beans::Property SAL_CALL getPropertyByName(const ::rtl::OUString& _rPropertyName)
140 								throw(::com::sun::star::beans::UnknownPropertyException);
141 
142 	/// inherited from IPropertyArrayHelper
143 	virtual sal_Bool  SAL_CALL hasPropertyByName(const ::rtl::OUString& _rPropertyName) ;
144 	/// inherited from IPropertyArrayHelper
145 	virtual sal_Int32 SAL_CALL getHandleByName(const ::rtl::OUString & _rPropertyName);
146 	/// inherited from IPropertyArrayHelper
147 	virtual sal_Int32 SAL_CALL fillHandles( /*out*/sal_Int32* _pHandles, const ::com::sun::star::uno::Sequence< ::rtl::OUString >& _rPropNames );
148 
149 	/** returns information about a property of the aggregate.
150 		@param	_pPropName			points to a string to recieve the property name. No name is returned if this is NULL.
151 		@param	_pOriginalHandle	points to a sal_Int32 to recieve the original property hande. No original handle is returned
152 									if this is NULL.
153 		@param	_nHandle			the handle of the property as got by, for instance, fillHandles
154 
155 		@return	sal_True, if _nHandle marks an aggregate property, otherwise sal_False
156 	*/
157 	virtual sal_Bool SAL_CALL fillAggregatePropertyInfoByHandle(::rtl::OUString* _pPropName, sal_Int32* _pOriginalHandle,
158 												   sal_Int32 _nHandle) const;
159 
160     /** returns information about a property given by handle
161     */
162     sal_Bool getPropertyByHandle( sal_Int32 _nHandle, ::com::sun::star::beans::Property& _rProperty ) const;
163 
164 
165 	enum PropertyOrigin
166 	{
167 		AGGREGATE_PROPERTY,
168 		DELEGATOR_PROPERTY,
169 		UNKNOWN_PROPERTY
170 	};
171 	/** prefer this one over the XPropertySetInfo of the aggregate!
172 
173 		<p>The reason is that OPropertyArrayAggregationHelper is the only instance which really knows
174 		which properties of the aggregate are to be exposed. <br/>
175 
176 		For instance, some derivee of OPropertySetAggregationHelper may decide to create an
177 		OPropertyArrayAggregationHelper which contains only a subset of the aggregate properties. This way,
178 		some of the aggregate properties may be hidded to the public.<br/>
179 
180 		When using the XPropertySetInfo of the aggregate set to determine the existence of a property, then this
181 		would return false positives.</p>
182 	*/
183 	PropertyOrigin	classifyProperty( const ::rtl::OUString& _rName );
184 
185 protected:
186 	const ::com::sun::star::beans::Property* findPropertyByName(const ::rtl::OUString& _rName) const;
187 };
188 
189 //==================================================================
190 namespace internal
191 {
192     class PropertyForwarder;
193 }
194 
195 /**
196  * helper class for implementing the property-set-related interfaces
197  * for an object doin' aggregation
198  * supports at least XPropertySet and XMultiPropertySet
199  *
200  */
201 class COMPHELPER_DLLPUBLIC OPropertySetAggregationHelper	:public OPropertyStateHelper
202 									,public ::com::sun::star::beans::XPropertiesChangeListener
203 									,public ::com::sun::star::beans::XVetoableChangeListener
204 {
205     friend class internal::PropertyForwarder;
206 
207 protected:
208     ::com::sun::star::uno::Reference< ::com::sun::star::beans::XPropertyState>      m_xAggregateState;
209     ::com::sun::star::uno::Reference< ::com::sun::star::beans::XPropertySet>        m_xAggregateSet;
210     ::com::sun::star::uno::Reference< ::com::sun::star::beans::XMultiPropertySet>   m_xAggregateMultiSet;
211     ::com::sun::star::uno::Reference< ::com::sun::star::beans::XFastPropertySet>    m_xAggregateFastSet;
212 
213     internal::PropertyForwarder*    m_pForwarder;
214 	sal_Bool                        m_bListening : 1;
215 
216 public:
217 	OPropertySetAggregationHelper( ::cppu::OBroadcastHelper& rBHelper );
218 
219     virtual ::com::sun::star::uno::Any SAL_CALL queryInterface(const ::com::sun::star::uno::Type& aType) throw(::com::sun::star::uno::RuntimeException);
220 
221 // XEventListener
222 	virtual void SAL_CALL disposing(const ::com::sun::star::lang::EventObject& Source) throw (::com::sun::star::uno::RuntimeException);
223 
224 // XFastPropertySet
225     virtual void SAL_CALL setFastPropertyValue(sal_Int32 nHandle, const ::com::sun::star::uno::Any& aValue) throw(::com::sun::star::beans::UnknownPropertyException, ::com::sun::star::beans::PropertyVetoException, ::com::sun::star::lang::IllegalArgumentException, ::com::sun::star::lang::WrappedTargetException, ::com::sun::star::uno::RuntimeException);
226     virtual ::com::sun::star::uno::Any SAL_CALL getFastPropertyValue(sal_Int32 nHandle) throw(::com::sun::star::beans::UnknownPropertyException, ::com::sun::star::lang::WrappedTargetException, ::com::sun::star::uno::RuntimeException);
227 
228 // XPropertySet
229 	virtual void SAL_CALL			addPropertyChangeListener(const ::rtl::OUString& aPropertyName, const ::com::sun::star::uno::Reference< ::com::sun::star::beans::XPropertyChangeListener >& xListener) throw(::com::sun::star::beans::UnknownPropertyException, ::com::sun::star::lang::WrappedTargetException, ::com::sun::star::uno::RuntimeException);
230 	virtual void SAL_CALL			addVetoableChangeListener(const ::rtl::OUString& PropertyName, const ::com::sun::star::uno::Reference< ::com::sun::star::beans::XVetoableChangeListener >& aListener) throw(::com::sun::star::beans::UnknownPropertyException, ::com::sun::star::lang::WrappedTargetException, ::com::sun::star::uno::RuntimeException);
231 
232 // XPropertiesChangeListener
233 	virtual void SAL_CALL propertiesChange(const ::com::sun::star::uno::Sequence< ::com::sun::star::beans::PropertyChangeEvent >& evt) throw(::com::sun::star::uno::RuntimeException);
234 
235 // XVetoableChangeListener
236 	virtual void SAL_CALL vetoableChange(const ::com::sun::star::beans::PropertyChangeEvent& aEvent) throw(::com::sun::star::beans::PropertyVetoException, ::com::sun::star::uno::RuntimeException);
237 
238 // XMultiPropertySet
239 	virtual void SAL_CALL	setPropertyValues(const ::com::sun::star::uno::Sequence< ::rtl::OUString >& PropertyNames, const ::com::sun::star::uno::Sequence< ::com::sun::star::uno::Any >& Values) throw(::com::sun::star::beans::PropertyVetoException, ::com::sun::star::lang::IllegalArgumentException, ::com::sun::star::lang::WrappedTargetException, ::com::sun::star::uno::RuntimeException);
240 	virtual void SAL_CALL	addPropertiesChangeListener(const ::com::sun::star::uno::Sequence< ::rtl::OUString >& aPropertyNames, const ::com::sun::star::uno::Reference< ::com::sun::star::beans::XPropertiesChangeListener >& xListener) throw(::com::sun::star::uno::RuntimeException);
241 
242 // XPropertyState
243 	virtual ::com::sun::star::beans::PropertyState SAL_CALL	getPropertyState(const ::rtl::OUString& PropertyName) throw(::com::sun::star::beans::UnknownPropertyException, ::com::sun::star::uno::RuntimeException);
244     virtual void SAL_CALL                                   setPropertyToDefault(const ::rtl::OUString& PropertyName) throw(::com::sun::star::beans::UnknownPropertyException, ::com::sun::star::uno::RuntimeException);
245 	virtual ::com::sun::star::uno::Any SAL_CALL				getPropertyDefault(const ::rtl::OUString& aPropertyName) throw(::com::sun::star::beans::UnknownPropertyException, ::com::sun::star::lang::WrappedTargetException, ::com::sun::star::uno::RuntimeException);
246 
247 // OPropertySetHelper
248 	/** still waiting to be overwritten ...
249 		you <B>must<B/> use an OPropertyArrayAggregationHelper here, as the implementation strongly relies on this.
250 	*/
251 	virtual ::cppu::IPropertyArrayHelper& SAL_CALL getInfoHelper() = 0;
252 
253     /** only implemented for "forwarded" properties, every other property must be handled
254         in the derivee, and will assert if passed herein
255     */
256 	virtual sal_Bool SAL_CALL convertFastPropertyValue( ::com::sun::star::uno::Any& _rConvertedValue, ::com::sun::star::uno::Any& _rOldValue, sal_Int32 _nHandle, const ::com::sun::star::uno::Any& _rValue ) throw(::com::sun::star::lang::IllegalArgumentException);
257 
258     /** only implemented for "forwarded" properties, every other property must be handled
259         in the derivee, and will assert if passed herein
260     */
261 	virtual void SAL_CALL setFastPropertyValue_NoBroadcast( sal_Int32 _nHandle, const ::com::sun::star::uno::Any& _rValue ) throw ( ::com::sun::star::uno::Exception );
262 
263 protected:
264 	~OPropertySetAggregationHelper();
265 
266 	virtual void SAL_CALL getFastPropertyValue(::com::sun::star::uno::Any& rValue, sal_Int32 nHandle) const;
267 	virtual void SAL_CALL disposing();
268 
269 	sal_Int32	    getOriginalHandle( sal_Int32 _nHandle ) const;
270     ::rtl::OUString getPropertyName( sal_Int32 _nHandle ) const;
271 
272     /** declares the property with the given (public) handle as one to be forwarded to the aggregate
273 
274         Sometimes, you might want to <em>overwrite</em> properties at the aggregate. That is,
275         though the aggregate implements this property, and still is to hold the property value,
276         you want to do additional handling upon setting the property, but then forward the value
277         to the aggregate.
278 
279         Use this method to declare such properties.
280 
281         When a "forwarded property" is set from outside, the class first calls
282         <member>forwardingPropertyValue</member> for any preprocessing, then forwards the property
283         value to the aggregate, and then calls <member>forwardedPropertyValue</member>.
284 
285         When you declare a property as "forwarded", the class takes care for some multi-threading
286         issues, for instance, it won't fire any property change notifications which result from
287         forwarding a property value, unless it's safe to do so (i.e. unless our mutex is
288         released).
289 
290         @see forwardingPropertyValue
291         @see forwardedPropertyValue
292     */
293     void declareForwardedProperty( sal_Int32 _nHandle );
294 
295     /** checks whether we're actually forwarding a property value to our aggregate
296 
297         @see declareForwardedProperty
298         @see forwardingPropertyValue
299         @see forwardedPropertyValue
300     */
301     bool    isCurrentlyForwardingProperty( sal_Int32 _nHandle ) const;
302 
303     /** called immediately before a property value which is overwritten in this instance
304         is forwarded to the aggregate
305 
306         @see declareForwardedProperty
307         @see forwardedPropertyValue
308     */
309     virtual void SAL_CALL forwardingPropertyValue( sal_Int32 _nHandle );
310 
311     /** called immediately after a property value which is overwritten in this instance
312         has been forwarded to the aggregate
313 
314         @see declareForwardedProperty
315         @see forwardingPropertyValue
316     */
317     virtual void SAL_CALL forwardedPropertyValue( sal_Int32 _nHandle, bool _bSuccess );
318 
319 	/// must be called before aggregation, if aggregation is used
320 	void setAggregation(const ::com::sun::star::uno::Reference< ::com::sun::star::uno::XInterface >&) throw( ::com::sun::star::lang::IllegalArgumentException );
321 	void startListening();
322 };
323 
324 //.........................................................................
325 }	// namespace comphelper
326 //.........................................................................
327 
328 #endif // _COMPHELPER_PROPERTY_AGGREGATION_HXX_
329 
330