Line data Source code
1 : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 : /*
3 : * This file is part of the LibreOffice project.
4 : *
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/.
8 : *
9 : * This file incorporates work covered by the following license notice:
10 : *
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 .
18 : */
19 :
20 : #include <comphelper/propagg.hxx>
21 : #include <comphelper/property.hxx>
22 : #include <cppuhelper/queryinterface.hxx>
23 : #include <osl/diagnose.h>
24 : #include <com/sun/star/beans/PropertyAttribute.hpp>
25 :
26 : #if OSL_DEBUG_LEVEL > 0
27 : #include <typeinfo>
28 : #include <rtl/strbuf.hxx>
29 : #endif
30 :
31 : #include <algorithm>
32 : #include <set>
33 : #include <boost/scoped_array.hpp>
34 :
35 :
36 : namespace comphelper
37 : {
38 :
39 :
40 : using namespace ::com::sun::star::uno;
41 : using namespace ::com::sun::star::lang;
42 : using namespace ::com::sun::star::beans;
43 :
44 : using namespace internal;
45 :
46 :
47 : namespace
48 : {
49 99134 : const Property* lcl_findPropertyByName( const Sequence< Property >& _rProps, const OUString& _rName )
50 : {
51 99134 : sal_Int32 nLen = _rProps.getLength();
52 99134 : const Property* pProperties = _rProps.getConstArray();
53 99134 : Property aNameProp(_rName, 0, Type(), 0);
54 99134 : const Property* pResult = ::std::lower_bound(pProperties, pProperties + nLen, aNameProp, PropertyCompareByName());
55 99134 : if ( pResult && ( pResult == pProperties + nLen || pResult->Name != _rName) )
56 273 : pResult = NULL;
57 :
58 99134 : return pResult;
59 : }
60 : }
61 :
62 826 : OPropertyArrayAggregationHelper::OPropertyArrayAggregationHelper(
63 : const Sequence< Property >& _rProperties, const Sequence< Property >& _rAggProperties,
64 : IPropertyInfoService* _pInfoService, sal_Int32 _nFirstAggregateId )
65 826 : :m_aProperties( _rProperties )
66 : {
67 826 : sal_Int32 nDelegatorProps = _rProperties.getLength();
68 826 : sal_Int32 nAggregateProps = _rAggProperties.getLength();
69 :
70 : // make room for all properties
71 826 : sal_Int32 nMergedProps = nDelegatorProps + nAggregateProps;
72 826 : m_aProperties.realloc( nMergedProps );
73 :
74 826 : const Property* pAggregateProps = _rAggProperties.getConstArray();
75 826 : const Property* pDelegateProps = _rProperties.getConstArray();
76 826 : Property* pMergedProps = m_aProperties.getArray();
77 :
78 : // if properties are present both at the delegatee and the aggregate, then the former are supposed to win.
79 : // So, we'll need an existence check.
80 826 : ::std::set< OUString > aDelegatorProps;
81 :
82 : // create the map for the delegator properties
83 826 : sal_Int32 nMPLoop = 0;
84 18981 : for ( ; nMPLoop < nDelegatorProps; ++nMPLoop, ++pDelegateProps )
85 : {
86 18155 : m_aPropertyAccessors[ pDelegateProps->Handle ] = OPropertyAccessor( -1, nMPLoop, false );
87 : OSL_ENSURE( aDelegatorProps.find( pDelegateProps->Name ) == aDelegatorProps.end(),
88 : "OPropertyArrayAggregationHelper::OPropertyArrayAggregationHelper: duplicate delegatee property!" );
89 18155 : aDelegatorProps.insert( pDelegateProps->Name );
90 : }
91 :
92 : // create the map for the aggregate properties
93 826 : sal_Int32 nAggregateHandle = _nFirstAggregateId;
94 826 : pMergedProps += nDelegatorProps;
95 42303 : for ( ; nMPLoop < nMergedProps; ++pAggregateProps )
96 : {
97 : // if the aggregate property is present at the delegatee already, ignore it
98 41477 : if ( aDelegatorProps.find( pAggregateProps->Name ) != aDelegatorProps.end() )
99 : {
100 327 : --nMergedProps;
101 327 : continue;
102 : }
103 :
104 : // next aggregate property - remember it
105 41150 : *pMergedProps = *pAggregateProps;
106 :
107 : // determine the handle for the property which we will expose to the outside world
108 41150 : sal_Int32 nHandle = -1;
109 : // ask the infor service first
110 41150 : if ( _pInfoService )
111 39809 : nHandle = _pInfoService->getPreferredPropertyId( pMergedProps->Name );
112 :
113 41150 : if ( -1 == nHandle )
114 : // no handle from the info service -> default
115 24298 : nHandle = nAggregateHandle++;
116 : else
117 : { // check if we alread have a property with the given handle
118 16852 : const Property* pPropsTilNow = m_aProperties.getConstArray();
119 800393 : for ( sal_Int32 nCheck = 0; nCheck < nMPLoop; ++nCheck, ++pPropsTilNow )
120 783541 : if ( pPropsTilNow->Handle == nHandle )
121 : { // conflicts -> use another one (which we don't check anymore, assuming _nFirstAggregateId was large enough)
122 0 : nHandle = nAggregateHandle++;
123 0 : break;
124 : }
125 : }
126 :
127 : // remember the accessor for this property
128 41150 : m_aPropertyAccessors[ nHandle ] = OPropertyAccessor( pMergedProps->Handle, nMPLoop, true );
129 41150 : pMergedProps->Handle = nHandle;
130 :
131 41150 : ++nMPLoop;
132 41150 : ++pMergedProps;
133 : }
134 826 : m_aProperties.realloc( nMergedProps );
135 826 : pMergedProps = m_aProperties.getArray(); // reset, needed again below
136 :
137 : // sort the properties by name
138 826 : ::std::sort( pMergedProps, pMergedProps+nMergedProps, PropertyCompareByName());
139 :
140 826 : pMergedProps = m_aProperties.getArray();
141 :
142 : // sync the map positions
143 60131 : for ( nMPLoop = 0; nMPLoop < nMergedProps; ++nMPLoop, ++pMergedProps )
144 60131 : m_aPropertyAccessors[ pMergedProps->Handle ].nPos = nMPLoop;
145 826 : }
146 :
147 :
148 56096 : OPropertyArrayAggregationHelper::PropertyOrigin OPropertyArrayAggregationHelper::classifyProperty( const OUString& _rName )
149 : {
150 56096 : PropertyOrigin eOrigin = UNKNOWN_PROPERTY;
151 : // look up the name
152 56096 : const Property* pPropertyDescriptor = lcl_findPropertyByName( m_aProperties, _rName );
153 56096 : if ( pPropertyDescriptor )
154 : {
155 : // look up the handle for this name
156 56094 : ConstPropertyAccessorMapIterator aPos = m_aPropertyAccessors.find( pPropertyDescriptor->Handle );
157 : OSL_ENSURE( m_aPropertyAccessors.end() != aPos, "OPropertyArrayAggregationHelper::classifyProperty: should have this handle in my map!" );
158 56094 : if ( m_aPropertyAccessors.end() != aPos )
159 : {
160 56094 : eOrigin = aPos->second.bAggregate ? AGGREGATE_PROPERTY : DELEGATOR_PROPERTY;
161 : }
162 : }
163 56096 : return eOrigin;
164 : }
165 :
166 :
167 0 : Property OPropertyArrayAggregationHelper::getPropertyByName( const OUString& _rPropertyName ) throw( UnknownPropertyException )
168 : {
169 0 : const Property* pProperty = findPropertyByName( _rPropertyName );
170 :
171 0 : if ( !pProperty )
172 0 : throw UnknownPropertyException();
173 :
174 0 : return *pProperty;
175 : }
176 :
177 :
178 126 : sal_Bool OPropertyArrayAggregationHelper::hasPropertyByName(const OUString& _rPropertyName)
179 : {
180 126 : return NULL != findPropertyByName( _rPropertyName );
181 : }
182 :
183 :
184 43038 : const Property* OPropertyArrayAggregationHelper::findPropertyByName(const :: OUString& _rName ) const
185 : {
186 43038 : return lcl_findPropertyByName( m_aProperties, _rName );
187 : }
188 :
189 :
190 42912 : sal_Int32 OPropertyArrayAggregationHelper::getHandleByName(const OUString& _rPropertyName)
191 : {
192 42912 : const Property* pProperty = findPropertyByName( _rPropertyName );
193 42912 : return pProperty ? pProperty->Handle : -1;
194 : }
195 :
196 :
197 46106 : sal_Bool OPropertyArrayAggregationHelper::fillPropertyMembersByHandle(
198 : OUString* _pPropName, sal_Int16* _pAttributes, sal_Int32 _nHandle)
199 : {
200 46106 : ConstPropertyAccessorMapIterator i = m_aPropertyAccessors.find(_nHandle);
201 46106 : bool bRet = i != m_aPropertyAccessors.end();
202 46106 : if (bRet)
203 : {
204 45853 : const ::com::sun::star::beans::Property& rProperty = m_aProperties.getConstArray()[(*i).second.nPos];
205 45853 : if (_pPropName)
206 9645 : *_pPropName = rProperty.Name;
207 45853 : if (_pAttributes)
208 25703 : *_pAttributes = rProperty.Attributes;
209 : }
210 46106 : return bRet;
211 : }
212 :
213 :
214 806 : bool OPropertyArrayAggregationHelper::getPropertyByHandle( sal_Int32 _nHandle, Property& _rProperty ) const
215 : {
216 806 : ConstPropertyAccessorMapIterator pos = m_aPropertyAccessors.find(_nHandle);
217 806 : if ( pos != m_aPropertyAccessors.end() )
218 : {
219 806 : _rProperty = m_aProperties[ pos->second.nPos ];
220 806 : return true;
221 : }
222 0 : return false;
223 : }
224 :
225 :
226 97898 : bool OPropertyArrayAggregationHelper::fillAggregatePropertyInfoByHandle(
227 : OUString* _pPropName, sal_Int32* _pOriginalHandle, sal_Int32 _nHandle) const
228 : {
229 97898 : ConstPropertyAccessorMapIterator i = m_aPropertyAccessors.find(_nHandle);
230 97898 : bool bRet = i != m_aPropertyAccessors.end() && (*i).second.bAggregate;
231 97898 : if (bRet)
232 : {
233 72529 : if (_pOriginalHandle)
234 72529 : *_pOriginalHandle = (*i).second.nOriginalHandle;
235 72529 : if (_pPropName)
236 : {
237 : OSL_ENSURE((*i).second.nPos < m_aProperties.getLength(),"Invalid index for sequence!");
238 72178 : const ::com::sun::star::beans::Property& rProperty = m_aProperties.getConstArray()[(*i).second.nPos];
239 72178 : *_pPropName = rProperty.Name;
240 : }
241 : }
242 97898 : return bRet;
243 : }
244 :
245 :
246 :
247 22955 : ::com::sun::star::uno::Sequence< ::com::sun::star::beans::Property> OPropertyArrayAggregationHelper::getProperties()
248 : {
249 22955 : return m_aProperties;
250 : }
251 :
252 :
253 :
254 2859 : sal_Int32 OPropertyArrayAggregationHelper::fillHandles(
255 : sal_Int32* _pHandles, const ::com::sun::star::uno::Sequence< OUString >& _rPropNames )
256 : {
257 2859 : sal_Int32 nHitCount = 0;
258 2859 : const OUString* pReqProps = _rPropNames.getConstArray();
259 2859 : sal_Int32 nReqLen = _rPropNames.getLength();
260 :
261 : #if OSL_DEBUG_LEVEL > 0
262 : // assure that the sequence is sorted
263 : {
264 : const OUString* pLookup = _rPropNames.getConstArray();
265 : const OUString* pEnd = _rPropNames.getConstArray() + _rPropNames.getLength() - 1;
266 : for (; pLookup < pEnd; ++pLookup)
267 : {
268 : const OUString* pCompare = pLookup + 1;
269 : const OUString* pCompareEnd = pEnd + 1;
270 : for (; pCompare < pCompareEnd; ++pCompare)
271 : {
272 : OSL_ENSURE(pLookup->compareTo(*pCompare) < 0, "OPropertyArrayAggregationHelper::fillHandles : property names are not sorted!");
273 : }
274 : }
275 : }
276 : #endif
277 :
278 2859 : const ::com::sun::star::beans::Property* pCur = m_aProperties.getConstArray();
279 2859 : const ::com::sun::star::beans::Property* pEnd = m_aProperties.getConstArray() + m_aProperties.getLength();
280 :
281 70725 : for( sal_Int32 i = 0; i < nReqLen; ++i )
282 : {
283 : // determine the logarithm
284 67866 : sal_uInt32 n = (sal_uInt32)(pEnd - pCur);
285 67866 : sal_Int32 nLog = 0;
286 495681 : while( n )
287 : {
288 359949 : nLog += 1;
289 359949 : n = n >> 1;
290 : }
291 :
292 : // (Number of properties yet to be found) * (Log2 of properties yet to be searched)
293 67866 : if( (nReqLen - i) * nLog >= pEnd - pCur )
294 : {
295 : // linear search is better
296 213654 : while( pCur < pEnd && pReqProps[i] > pCur->Name )
297 : {
298 86872 : pCur++;
299 : }
300 63391 : if( pCur < pEnd && pReqProps[i] == pCur->Name )
301 : {
302 63391 : _pHandles[i] = pCur->Handle;
303 63391 : nHitCount++;
304 : }
305 : else
306 0 : _pHandles[i] = -1;
307 : }
308 : else
309 : {
310 : // binary search is better
311 4475 : sal_Int32 nCompVal = 1;
312 4475 : const ::com::sun::star::beans::Property* pOldEnd = pEnd--;
313 4475 : const ::com::sun::star::beans::Property* pMid = pCur;
314 :
315 26278 : while( nCompVal != 0 && pCur <= pEnd )
316 : {
317 17328 : pMid = (pEnd - pCur) / 2 + pCur;
318 :
319 17328 : nCompVal = pReqProps[i].compareTo( pMid->Name );
320 :
321 17328 : if( nCompVal > 0 )
322 5326 : pCur = pMid + 1;
323 : else
324 12002 : pEnd = pMid - 1;
325 : }
326 :
327 4475 : if( nCompVal == 0 )
328 : {
329 4475 : _pHandles[i] = pMid->Handle;
330 4475 : nHitCount++;
331 4475 : pCur = pMid +1;
332 : }
333 0 : else if( nCompVal > 0 )
334 : {
335 0 : _pHandles[i] = -1;
336 0 : pCur = pMid + 1;
337 : }
338 : else
339 : {
340 0 : _pHandles[i] = -1;
341 0 : pCur = pMid;
342 : }
343 4475 : pEnd = pOldEnd;
344 : }
345 : }
346 2859 : return nHitCount;
347 : }
348 :
349 : namespace internal
350 : {
351 : class PropertyForwarder
352 : {
353 : private:
354 : OPropertySetAggregationHelper& m_rAggregationHelper;
355 : ::std::set< sal_Int32 > m_aProperties;
356 : sal_Int32 m_nCurrentlyForwarding;
357 :
358 : public:
359 : explicit PropertyForwarder( OPropertySetAggregationHelper& _rAggregationHelper );
360 : ~PropertyForwarder();
361 :
362 : /** declares that the forwarder should be responsible for the given property
363 :
364 : @param _nHandle
365 : the public handle (<em>not</em> the original handle!) of the property
366 : */
367 : void takeResponsibilityFor( sal_Int32 _nHandle );
368 :
369 : /** checks whether the forwarder is responsible for the given property
370 : */
371 : bool isResponsibleFor( sal_Int32 _nHandle );
372 :
373 : /// actually forwards a property value to the aggregate
374 : void doForward( sal_Int32 _nHandle, const Any& _rValue ) throw ( Exception );
375 :
376 4981 : sal_Int32 getCurrentlyForwardedProperty( ) const { return m_nCurrentlyForwarding; }
377 : };
378 :
379 :
380 936 : PropertyForwarder::PropertyForwarder( OPropertySetAggregationHelper& _rAggregationHelper )
381 : :m_rAggregationHelper( _rAggregationHelper )
382 936 : ,m_nCurrentlyForwarding( -1 )
383 : {
384 936 : }
385 :
386 :
387 855 : PropertyForwarder::~PropertyForwarder()
388 : {
389 855 : }
390 :
391 :
392 184 : void PropertyForwarder::takeResponsibilityFor( sal_Int32 _nHandle )
393 : {
394 184 : m_aProperties.insert( _nHandle );
395 184 : }
396 :
397 :
398 806 : bool PropertyForwarder::isResponsibleFor( sal_Int32 _nHandle )
399 : {
400 806 : return m_aProperties.find( _nHandle ) != m_aProperties.end();
401 : }
402 :
403 :
404 180 : void PropertyForwarder::doForward( sal_Int32 _nHandle, const Any& _rValue ) throw ( Exception )
405 : {
406 : OSL_ENSURE( m_rAggregationHelper.m_xAggregateSet.is(), "PropertyForwarder::doForward: no property set!" );
407 180 : if ( m_rAggregationHelper.m_xAggregateSet.is() )
408 : {
409 180 : m_rAggregationHelper.forwardingPropertyValue( _nHandle );
410 :
411 : OSL_ENSURE( m_nCurrentlyForwarding == -1, "PropertyForwarder::doForward: reentrance?" );
412 180 : m_nCurrentlyForwarding = _nHandle;
413 :
414 : try
415 : {
416 180 : m_rAggregationHelper.m_xAggregateSet->setPropertyValue( m_rAggregationHelper.getPropertyName( _nHandle ), _rValue );
417 : // TODO: cache the property name? (it's a O(log n) search)
418 : }
419 0 : catch( const Exception& )
420 : {
421 0 : m_rAggregationHelper.forwardedPropertyValue( _nHandle );
422 0 : throw;
423 : }
424 :
425 180 : m_nCurrentlyForwarding = -1;
426 :
427 180 : m_rAggregationHelper.forwardedPropertyValue( _nHandle );
428 : }
429 180 : }
430 : }
431 :
432 936 : OPropertySetAggregationHelper::OPropertySetAggregationHelper( ::cppu::OBroadcastHelper& rBHlp )
433 : :OPropertyStateHelper( rBHlp )
434 936 : ,m_bListening( false )
435 : {
436 936 : m_pForwarder = new PropertyForwarder( *this );
437 936 : }
438 :
439 :
440 1710 : OPropertySetAggregationHelper::~OPropertySetAggregationHelper()
441 : {
442 855 : delete m_pForwarder;
443 855 : }
444 :
445 :
446 91417 : ::com::sun::star::uno::Any SAL_CALL OPropertySetAggregationHelper::queryInterface(const ::com::sun::star::uno::Type& _rType) throw( ::com::sun::star::uno::RuntimeException, std::exception)
447 : {
448 91417 : ::com::sun::star::uno::Any aReturn = OPropertyStateHelper::queryInterface(_rType);
449 :
450 91417 : if ( !aReturn.hasValue() )
451 109842 : aReturn = cppu::queryInterface(_rType
452 : ,static_cast< ::com::sun::star::beans::XPropertiesChangeListener*>(this)
453 : ,static_cast< ::com::sun::star::beans::XVetoableChangeListener*>(this)
454 : ,static_cast< ::com::sun::star::lang::XEventListener*>(static_cast< ::com::sun::star::beans::XPropertiesChangeListener*>(this))
455 54921 : );
456 :
457 91417 : return aReturn;
458 : }
459 :
460 :
461 849 : void OPropertySetAggregationHelper::disposing()
462 : {
463 849 : osl::MutexGuard aGuard(rBHelper.rMutex);
464 :
465 849 : if ( m_xAggregateSet.is() && m_bListening )
466 : {
467 : // register as a single listener
468 681 : m_xAggregateMultiSet->removePropertiesChangeListener(this);
469 681 : m_xAggregateSet->removeVetoableChangeListener(OUString(), this);
470 681 : m_bListening = false;
471 : }
472 :
473 849 : OPropertyStateHelper::disposing();
474 849 : }
475 :
476 :
477 145 : void SAL_CALL OPropertySetAggregationHelper::disposing(const ::com::sun::star::lang::EventObject& _rSource) throw ( ::com::sun::star::uno::RuntimeException, std::exception)
478 : {
479 : OSL_ENSURE(m_xAggregateSet.is(), "OPropertySetAggregationHelper::disposing : don't have an aggregate anymore !");
480 145 : if (_rSource.Source == m_xAggregateSet)
481 0 : m_bListening = false;
482 145 : }
483 :
484 :
485 4365 : void SAL_CALL OPropertySetAggregationHelper::propertiesChange(const ::com::sun::star::uno::Sequence< ::com::sun::star::beans::PropertyChangeEvent>& _rEvents) throw( ::com::sun::star::uno::RuntimeException, std::exception)
486 : {
487 : OSL_ENSURE(m_xAggregateSet.is(), "OPropertySetAggregationHelper::propertiesChange : have no aggregate !");
488 :
489 4365 : sal_Int32 nLen = _rEvents.getLength();
490 4365 : cppu::IPropertyArrayHelper& rPH = getInfoHelper();
491 :
492 4365 : if (1 == nLen)
493 : {
494 4164 : const ::com::sun::star::beans::PropertyChangeEvent& evt = _rEvents.getConstArray()[0];
495 : OSL_ENSURE(!evt.PropertyName.isEmpty(), "OPropertySetAggregationHelper::propertiesChange : invalid event !");
496 : // we had a bug where this assertion would have us saved a whole day :) (72514)
497 4164 : sal_Int32 nHandle = rPH.getHandleByName( evt.PropertyName );
498 :
499 : // If nHandle is -1 the event marks a (aggregate) property which we hide to callers
500 : // If isCurrentlyForwardingProperty( nHandle ) is <TRUE/>, then we ourself triggered
501 : // setting this property. In this case, it will be notified later (by the OPropertySetHelper
502 : // implementation)
503 :
504 4164 : if ( ( nHandle != -1 ) && !isCurrentlyForwardingProperty( nHandle ) )
505 3995 : fire(&nHandle, &evt.NewValue, &evt.OldValue, 1, sal_False);
506 : }
507 : else
508 : {
509 201 : boost::scoped_array<sal_Int32> pHandles(new sal_Int32[nLen]);
510 402 : boost::scoped_array< ::com::sun::star::uno::Any> pNewValues(new ::com::sun::star::uno::Any[nLen]);
511 402 : boost::scoped_array< ::com::sun::star::uno::Any> pOldValues(new ::com::sun::star::uno::Any[nLen]);
512 :
513 201 : const ::com::sun::star::beans::PropertyChangeEvent* pEvents = _rEvents.getConstArray();
514 201 : sal_Int32 nDest = 0;
515 1018 : for (sal_Int32 nSource=0; nSource<nLen; ++nSource, ++pEvents)
516 : {
517 817 : sal_Int32 nHandle = rPH.getHandleByName(pEvents->PropertyName);
518 817 : if ( ( nHandle != -1 ) && !isCurrentlyForwardingProperty( nHandle ) )
519 : { // same as above : -1 is valid (73247) ...
520 817 : pHandles[nDest] = nHandle;
521 817 : pNewValues[nDest] = pEvents->NewValue;
522 817 : pOldValues[nDest] = pEvents->OldValue;
523 817 : ++nDest;
524 : }
525 : }
526 :
527 201 : if (nDest)
528 390 : fire(pHandles.get(), pNewValues.get(), pOldValues.get(), nDest, sal_False);
529 : }
530 4365 : }
531 :
532 :
533 0 : void SAL_CALL OPropertySetAggregationHelper::vetoableChange(const ::com::sun::star::beans::PropertyChangeEvent& _rEvent) throw( ::com::sun::star::beans::PropertyVetoException, ::com::sun::star::uno::RuntimeException, std::exception)
534 : {
535 : OSL_ENSURE(m_xAggregateSet.is(), "OPropertySetAggregationHelper::vetoableChange : have no aggregate !");
536 :
537 0 : cppu::IPropertyArrayHelper& rPH = getInfoHelper();
538 :
539 0 : sal_Int32 nHandle = rPH.getHandleByName(_rEvent.PropertyName);
540 0 : fire(&nHandle, &_rEvent.NewValue, &_rEvent.OldValue, 1, sal_True);
541 0 : }
542 :
543 :
544 927 : void OPropertySetAggregationHelper::setAggregation(const ::com::sun::star::uno::Reference< ::com::sun::star::uno::XInterface >& _rxDelegate)
545 : throw( ::com::sun::star::lang::IllegalArgumentException )
546 : {
547 927 : osl::MutexGuard aGuard(rBHelper.rMutex);
548 :
549 927 : if (m_bListening && m_xAggregateSet.is())
550 : {
551 0 : m_xAggregateMultiSet->removePropertiesChangeListener(this);
552 0 : m_xAggregateSet->removeVetoableChangeListener(OUString(), this);
553 0 : m_bListening = false;
554 : }
555 :
556 927 : m_xAggregateState.set(_rxDelegate, css::uno::UNO_QUERY);
557 927 : m_xAggregateSet.set(_rxDelegate, css::uno::UNO_QUERY);
558 927 : m_xAggregateMultiSet.set(_rxDelegate, css::uno::UNO_QUERY);
559 927 : m_xAggregateFastSet.set(_rxDelegate, css::uno::UNO_QUERY);
560 :
561 : // must support XPropertySet and XMultiPropertySet
562 927 : if ( m_xAggregateSet.is() && !m_xAggregateMultiSet.is() )
563 0 : throw ::com::sun::star::lang::IllegalArgumentException();
564 927 : }
565 :
566 :
567 1043 : void OPropertySetAggregationHelper::startListening()
568 : {
569 1043 : osl::MutexGuard aGuard(rBHelper.rMutex);
570 :
571 1043 : if (!m_bListening && m_xAggregateSet.is())
572 : {
573 : // register as a single listener
574 744 : ::com::sun::star::uno::Sequence< OUString > aPropertyNames;
575 744 : m_xAggregateMultiSet->addPropertiesChangeListener(aPropertyNames, this);
576 744 : m_xAggregateSet->addVetoableChangeListener(OUString(), this);
577 :
578 744 : m_bListening = true;
579 1043 : }
580 1043 : }
581 :
582 :
583 132 : void SAL_CALL OPropertySetAggregationHelper::addVetoableChangeListener(const OUString& _rPropertyName,
584 : const ::com::sun::star::uno::Reference< ::com::sun::star::beans::XVetoableChangeListener>& _rxListener)
585 : throw( ::com::sun::star::beans::UnknownPropertyException, ::com::sun::star::lang::WrappedTargetException, ::com::sun::star::uno::RuntimeException, std::exception)
586 : {
587 132 : OPropertySetHelper::addVetoableChangeListener(_rPropertyName, _rxListener);
588 132 : if (!m_bListening)
589 0 : startListening();
590 132 : }
591 :
592 :
593 4814 : void SAL_CALL OPropertySetAggregationHelper::addPropertyChangeListener(const OUString& _rPropertyName,
594 : const ::com::sun::star::uno::Reference< ::com::sun::star::beans::XPropertyChangeListener>& _rxListener)
595 : throw( ::com::sun::star::beans::UnknownPropertyException, ::com::sun::star::lang::WrappedTargetException, ::com::sun::star::uno::RuntimeException, std::exception)
596 : {
597 4814 : OPropertySetHelper::addPropertyChangeListener(_rPropertyName, _rxListener);
598 4814 : if (!m_bListening)
599 954 : startListening();
600 4814 : }
601 :
602 :
603 555 : void SAL_CALL OPropertySetAggregationHelper::addPropertiesChangeListener(const ::com::sun::star::uno::Sequence< OUString >& _rPropertyNames,
604 : const ::com::sun::star::uno::Reference< ::com::sun::star::beans::XPropertiesChangeListener>& _rxListener)
605 : throw( ::com::sun::star::uno::RuntimeException, std::exception)
606 : {
607 555 : OPropertySetHelper::addPropertiesChangeListener(_rPropertyNames, _rxListener);
608 555 : if (!m_bListening)
609 89 : startListening();
610 555 : }
611 :
612 :
613 351 : sal_Int32 OPropertySetAggregationHelper::getOriginalHandle(sal_Int32 nHandle) const
614 : {
615 351 : OPropertyArrayAggregationHelper& rPH = static_cast<OPropertyArrayAggregationHelper&>( const_cast<OPropertySetAggregationHelper*>(this)->getInfoHelper() );
616 351 : sal_Int32 nOriginalHandle = -1;
617 351 : (void)rPH.fillAggregatePropertyInfoByHandle(NULL, &nOriginalHandle, nHandle);
618 351 : return nOriginalHandle;
619 : }
620 :
621 :
622 614 : OUString OPropertySetAggregationHelper::getPropertyName( sal_Int32 _nHandle ) const
623 : {
624 614 : OPropertyArrayAggregationHelper& rPH = static_cast< OPropertyArrayAggregationHelper& >( const_cast<OPropertySetAggregationHelper*>(this)->getInfoHelper() );
625 614 : Property aProperty;
626 614 : OSL_VERIFY( rPH.getPropertyByHandle( _nHandle, aProperty ) );
627 614 : return aProperty.Name;
628 : }
629 :
630 :
631 9062 : void SAL_CALL OPropertySetAggregationHelper::setFastPropertyValue(sal_Int32 _nHandle, const ::com::sun::star::uno::Any& _rValue)
632 : throw( ::com::sun::star::beans::UnknownPropertyException, ::com::sun::star::beans::PropertyVetoException,
633 : ::com::sun::star::lang::IllegalArgumentException, ::com::sun::star::lang::WrappedTargetException,
634 : ::com::sun::star::uno::RuntimeException, std::exception)
635 : {
636 9062 : OPropertyArrayAggregationHelper& rPH = static_cast< OPropertyArrayAggregationHelper& >( getInfoHelper() );
637 9062 : OUString aPropName;
638 9062 : sal_Int32 nOriginalHandle = -1;
639 :
640 : // does the handle belong to the aggregation ?
641 9062 : if (rPH.fillAggregatePropertyInfoByHandle(&aPropName, &nOriginalHandle, _nHandle))
642 5355 : if (m_xAggregateFastSet.is())
643 5053 : m_xAggregateFastSet->setFastPropertyValue(nOriginalHandle, _rValue);
644 : else
645 302 : m_xAggregateSet->setPropertyValue(aPropName, _rValue);
646 : else
647 3747 : OPropertySetHelper::setFastPropertyValue(_nHandle, _rValue);
648 9022 : }
649 :
650 :
651 44838 : void OPropertySetAggregationHelper::getFastPropertyValue( ::com::sun::star::uno::Any& rValue, sal_Int32 nHandle) const
652 : {
653 44838 : OPropertyArrayAggregationHelper& rPH = static_cast<OPropertyArrayAggregationHelper&>( const_cast<OPropertySetAggregationHelper*>(this)->getInfoHelper() );
654 44838 : OUString aPropName;
655 44838 : sal_Int32 nOriginalHandle = -1;
656 :
657 44838 : if (rPH.fillAggregatePropertyInfoByHandle(&aPropName, &nOriginalHandle, nHandle))
658 : {
659 44404 : if (m_xAggregateFastSet.is())
660 44404 : rValue = m_xAggregateFastSet->getFastPropertyValue(nOriginalHandle);
661 : else
662 0 : rValue = m_xAggregateSet->getPropertyValue(aPropName);
663 : }
664 434 : else if ( m_pForwarder->isResponsibleFor( nHandle ) )
665 : {
666 : // this is a property which has been "overwritten" in our instance (thus
667 : // fillAggregatePropertyInfoByHandle didn't find it)
668 434 : rValue = m_xAggregateSet->getPropertyValue( getPropertyName( nHandle ) );
669 44838 : }
670 44838 : }
671 :
672 :
673 39531 : ::com::sun::star::uno::Any SAL_CALL OPropertySetAggregationHelper::getFastPropertyValue(sal_Int32 nHandle)
674 : throw( ::com::sun::star::beans::UnknownPropertyException,
675 : ::com::sun::star::lang::WrappedTargetException,
676 : ::com::sun::star::uno::RuntimeException, std::exception)
677 : {
678 39531 : OPropertyArrayAggregationHelper& rPH = static_cast< OPropertyArrayAggregationHelper& >( getInfoHelper() );
679 39531 : OUString aPropName;
680 39531 : sal_Int32 nOriginalHandle = -1;
681 39531 : ::com::sun::star::uno::Any aValue;
682 :
683 39531 : if (rPH.fillAggregatePropertyInfoByHandle(&aPropName, &nOriginalHandle, nHandle))
684 : {
685 19438 : if (m_xAggregateFastSet.is())
686 12983 : aValue = m_xAggregateFastSet->getFastPropertyValue(nOriginalHandle);
687 : else
688 6455 : aValue = m_xAggregateSet->getPropertyValue(aPropName);
689 : }
690 : else
691 20093 : aValue = OPropertySetHelper::getFastPropertyValue(nHandle);
692 :
693 39334 : return aValue;
694 : }
695 :
696 :
697 866 : void SAL_CALL OPropertySetAggregationHelper::setPropertyValues(
698 : const Sequence< OUString >& _rPropertyNames, const Sequence< Any >& _rValues )
699 : throw ( PropertyVetoException, IllegalArgumentException, WrappedTargetException, RuntimeException, std::exception )
700 : {
701 : OSL_ENSURE( !rBHelper.bInDispose, "OPropertySetAggregationHelper::setPropertyValues : do not use within the dispose call !");
702 : OSL_ENSURE( !rBHelper.bDisposed, "OPropertySetAggregationHelper::setPropertyValues : object is disposed" );
703 :
704 : // check where the properties come from
705 866 : if (!m_xAggregateSet.is())
706 51 : OPropertySetHelper::setPropertyValues(_rPropertyNames, _rValues);
707 815 : else if (_rPropertyNames.getLength() == 1) // use the more efficient way
708 : {
709 : try
710 : {
711 51 : setPropertyValue( _rPropertyNames[0], _rValues[0] );
712 : }
713 0 : catch( const UnknownPropertyException& )
714 : {
715 : // by definition of XMultiPropertySet::setPropertyValues, unknown properties are to be ignored
716 : #if OSL_DEBUG_LEVEL > 0
717 : OStringBuffer aMessage;
718 : aMessage.append( "OPropertySetAggregationHelper::setPropertyValues: unknown property '" );
719 : aMessage.append( OUStringToOString( _rPropertyNames[0], RTL_TEXTENCODING_ASCII_US ) );
720 : aMessage.append( "'" );
721 : aMessage.append( "\n(implementation " );
722 : aMessage.append( typeid( *this ).name() );
723 : aMessage.append( ")" );
724 : OSL_FAIL( aMessage.getStr() );
725 : #endif
726 : }
727 : }
728 : else
729 : {
730 764 : OPropertyArrayAggregationHelper& rPH = static_cast< OPropertyArrayAggregationHelper& >( getInfoHelper() );
731 :
732 : // determine which properties belong to the aggregate, and which ones to the delegator
733 764 : const OUString* pNames = _rPropertyNames.getConstArray();
734 764 : sal_Int32 nAggCount(0);
735 764 : sal_Int32 nLen(_rPropertyNames.getLength());
736 :
737 29325 : for ( sal_Int32 i = 0; i < nLen; ++i, ++pNames )
738 : {
739 28563 : OPropertyArrayAggregationHelper::PropertyOrigin ePropOrg = rPH.classifyProperty( *pNames );
740 28563 : if ( OPropertyArrayAggregationHelper::UNKNOWN_PROPERTY == ePropOrg )
741 2 : throw WrappedTargetException( OUString(), static_cast< XMultiPropertySet* >( this ), makeAny( UnknownPropertyException( ) ) );
742 : // due to a flaw in the API design, this method is not allowed to throw an UnknownPropertyException
743 : // so we wrap it into a WrappedTargetException
744 :
745 28561 : if ( OPropertyArrayAggregationHelper::AGGREGATE_PROPERTY == ePropOrg )
746 21337 : ++nAggCount;
747 : }
748 :
749 762 : pNames = _rPropertyNames.getConstArray(); // reset, we'll need it again below ...
750 :
751 : // all properties belong to the aggregate
752 762 : if (nAggCount == nLen)
753 21 : m_xAggregateMultiSet->setPropertyValues(_rPropertyNames, _rValues);
754 :
755 : // all properties belong to the aggregating object
756 741 : else if (nAggCount == 0)
757 42 : OPropertySetHelper::setPropertyValues(_rPropertyNames, _rValues);
758 :
759 : // mixed
760 : else
761 : {
762 699 : const ::com::sun::star::uno::Any* pValues = _rValues.getConstArray();
763 :
764 : try
765 : {
766 : // dividing the Names and _rValues
767 :
768 : // aggregate's names
769 699 : Sequence< OUString > AggPropertyNames( nAggCount );
770 699 : OUString* pAggNames = AggPropertyNames.getArray();
771 : // aggregate's values
772 1398 : Sequence< Any > AggValues( nAggCount );
773 699 : Any* pAggValues = AggValues.getArray();
774 :
775 : // delegator names
776 1398 : Sequence< OUString > DelPropertyNames( nLen - nAggCount );
777 699 : OUString* pDelNames = DelPropertyNames.getArray();
778 :
779 : // delegator values
780 1398 : Sequence< Any > DelValues( nLen - nAggCount );
781 699 : Any* pDelValues = DelValues.getArray();
782 :
783 28232 : for ( sal_Int32 i = 0; i < nLen; ++i, ++pNames, ++pValues )
784 : {
785 27533 : if ( OPropertyArrayAggregationHelper::AGGREGATE_PROPERTY == rPH.classifyProperty( *pNames ) )
786 : {
787 21179 : *pAggNames++ = *pNames;
788 21179 : *pAggValues++ = *pValues;
789 : }
790 : else
791 : {
792 6354 : *pDelNames++ = *pNames;
793 6354 : *pDelValues++ = *pValues;
794 : }
795 : }
796 :
797 : // reset, needed below
798 699 : pDelValues = DelValues.getArray();
799 :
800 1398 : boost::scoped_array<sal_Int32> pHandles(new sal_Int32[ nLen - nAggCount ]);
801 :
802 : // get the map table
803 699 : cppu::IPropertyArrayHelper& rPH2 = getInfoHelper();
804 :
805 : // fill the handle array
806 699 : sal_Int32 nHitCount = rPH2.fillHandles( pHandles.get(), DelPropertyNames );
807 699 : if (nHitCount != 0)
808 : {
809 699 : boost::scoped_array< ::com::sun::star::uno::Any> pConvertedValues(new ::com::sun::star::uno::Any[ nHitCount ]);
810 1398 : boost::scoped_array< ::com::sun::star::uno::Any> pOldValues(new ::com::sun::star::uno::Any[ nHitCount ]);
811 699 : nHitCount = 0;
812 : sal_Int32 i;
813 :
814 : {
815 : // must lock the mutex outside the loop. So all values are consistent.
816 699 : osl::MutexGuard aGuard( rBHelper.rMutex );
817 7053 : for( i = 0; i < (nLen - nAggCount); ++i )
818 : {
819 6354 : if( pHandles[i] != -1 )
820 : {
821 : sal_Int16 nAttributes;
822 6354 : rPH2.fillPropertyMembersByHandle( NULL, &nAttributes, pHandles[i] );
823 6354 : if( nAttributes & ::com::sun::star::beans::PropertyAttribute::READONLY )
824 0 : throw ::com::sun::star::beans::PropertyVetoException();
825 : // Will the property change?
826 12708 : if( convertFastPropertyValue( pConvertedValues[ nHitCount ], pOldValues[nHitCount],
827 12708 : pHandles[i], pDelValues[i] ) )
828 : {
829 : // only increment if the property really change
830 535 : pHandles[nHitCount] = pHandles[i];
831 535 : nHitCount++;
832 : }
833 : }
834 699 : }
835 : // release guard to fire events
836 : }
837 :
838 : // fire vetoable events
839 699 : fire( pHandles.get(), pConvertedValues.get(), pOldValues.get(), nHitCount, sal_True );
840 :
841 : // setting the agg Properties
842 699 : m_xAggregateMultiSet->setPropertyValues(AggPropertyNames, AggValues);
843 :
844 : {
845 : // must lock the mutex outside the loop.
846 698 : osl::MutexGuard aGuard( rBHelper.rMutex );
847 : // Loop over all changed properties
848 1227 : for( i = 0; i < nHitCount; i++ )
849 : {
850 : // Will the property change?
851 529 : setFastPropertyValue_NoBroadcast( pHandles[i], pConvertedValues[i] );
852 698 : }
853 : // release guard to fire events
854 : }
855 :
856 : // fire change events
857 1397 : fire( pHandles.get(), pConvertedValues.get(), pOldValues.get(), nHitCount, sal_False );
858 : }
859 : else
860 699 : m_xAggregateMultiSet->setPropertyValues(AggPropertyNames, AggValues);
861 :
862 : }
863 1 : catch(::com::sun::star::uno::Exception&)
864 : {
865 1 : throw;
866 : }
867 : }
868 : }
869 843 : }
870 :
871 : // XPropertyState
872 :
873 502 : ::com::sun::star::beans::PropertyState SAL_CALL OPropertySetAggregationHelper::getPropertyState(const OUString& _rPropertyName)
874 : throw( ::com::sun::star::beans::UnknownPropertyException, ::com::sun::star::uno::RuntimeException, std::exception)
875 : {
876 502 : OPropertyArrayAggregationHelper& rPH = static_cast< OPropertyArrayAggregationHelper& >( getInfoHelper() );
877 502 : sal_Int32 nHandle = rPH.getHandleByName( _rPropertyName );
878 :
879 502 : if (nHandle == -1)
880 : {
881 0 : throw ::com::sun::star::beans::UnknownPropertyException();
882 : }
883 :
884 502 : OUString aPropName;
885 502 : sal_Int32 nOriginalHandle = -1;
886 502 : if (rPH.fillAggregatePropertyInfoByHandle(&aPropName, &nOriginalHandle, nHandle))
887 : {
888 436 : if (m_xAggregateState.is())
889 436 : return m_xAggregateState->getPropertyState(_rPropertyName);
890 : else
891 0 : return ::com::sun::star::beans::PropertyState_DIRECT_VALUE;
892 : }
893 : else
894 66 : return getPropertyStateByHandle(nHandle);
895 : }
896 :
897 :
898 18 : void SAL_CALL OPropertySetAggregationHelper::setPropertyToDefault(const OUString& _rPropertyName)
899 : throw( ::com::sun::star::beans::UnknownPropertyException, ::com::sun::star::uno::RuntimeException, std::exception)
900 : {
901 18 : OPropertyArrayAggregationHelper& rPH = static_cast< OPropertyArrayAggregationHelper& >( getInfoHelper() );
902 18 : sal_Int32 nHandle = rPH.getHandleByName(_rPropertyName);
903 18 : if (nHandle == -1)
904 : {
905 0 : throw ::com::sun::star::beans::UnknownPropertyException();
906 : }
907 :
908 18 : OUString aPropName;
909 18 : sal_Int32 nOriginalHandle = -1;
910 18 : if (rPH.fillAggregatePropertyInfoByHandle(&aPropName, &nOriginalHandle, nHandle))
911 : {
912 15 : if (m_xAggregateState.is())
913 15 : m_xAggregateState->setPropertyToDefault(_rPropertyName);
914 : }
915 : else
916 : {
917 : try
918 : {
919 3 : setPropertyToDefaultByHandle( nHandle );
920 : }
921 0 : catch( const UnknownPropertyException& ) { throw; }
922 0 : catch( const RuntimeException& ) { throw; }
923 0 : catch( const Exception& )
924 : {
925 : OSL_FAIL( "OPropertySetAggregationHelper::setPropertyToDefault: caught an exception which is not allowed to leave here!" );
926 : }
927 18 : }
928 18 : }
929 :
930 :
931 18 : ::com::sun::star::uno::Any SAL_CALL OPropertySetAggregationHelper::getPropertyDefault(const OUString& aPropertyName)
932 : throw( ::com::sun::star::beans::UnknownPropertyException, ::com::sun::star::lang::WrappedTargetException, ::com::sun::star::uno::RuntimeException, std::exception)
933 : {
934 18 : OPropertyArrayAggregationHelper& rPH = static_cast< OPropertyArrayAggregationHelper& >( getInfoHelper() );
935 18 : sal_Int32 nHandle = rPH.getHandleByName( aPropertyName );
936 :
937 18 : if ( nHandle == -1 )
938 0 : throw ::com::sun::star::beans::UnknownPropertyException();
939 :
940 18 : OUString aPropName;
941 18 : sal_Int32 nOriginalHandle = -1;
942 18 : if (rPH.fillAggregatePropertyInfoByHandle(&aPropName, &nOriginalHandle, nHandle))
943 : {
944 15 : if (m_xAggregateState.is())
945 15 : return m_xAggregateState->getPropertyDefault(aPropertyName);
946 : else
947 0 : return ::com::sun::star::uno::Any();
948 : }
949 : else
950 3 : return getPropertyDefaultByHandle(nHandle);
951 : }
952 :
953 :
954 192 : sal_Bool SAL_CALL OPropertySetAggregationHelper::convertFastPropertyValue( Any& _rConvertedValue, Any& _rOldValue, sal_Int32 _nHandle, const Any& _rValue ) throw(IllegalArgumentException)
955 : {
956 192 : bool bModified = false;
957 :
958 : OSL_ENSURE( m_pForwarder->isResponsibleFor( _nHandle ), "OPropertySetAggregationHelper::convertFastPropertyValue: this is no forwarded property - did you use declareForwardedProperty for it?" );
959 192 : if ( m_pForwarder->isResponsibleFor( _nHandle ) )
960 : {
961 : // need to determine the type of the property for conversion
962 192 : OPropertyArrayAggregationHelper& rPH = static_cast< OPropertyArrayAggregationHelper& >( getInfoHelper() );
963 192 : Property aProperty;
964 192 : OSL_VERIFY( rPH.getPropertyByHandle( _nHandle, aProperty ) );
965 :
966 384 : Any aCurrentValue;
967 192 : getFastPropertyValue( aCurrentValue, _nHandle );
968 384 : bModified = tryPropertyValue( _rConvertedValue, _rOldValue, _rValue, aCurrentValue, aProperty.Type );
969 : }
970 :
971 192 : return bModified;
972 : }
973 :
974 :
975 180 : void SAL_CALL OPropertySetAggregationHelper::setFastPropertyValue_NoBroadcast( sal_Int32 _nHandle, const Any& _rValue ) throw ( Exception, std::exception )
976 : {
977 : OSL_ENSURE( m_pForwarder->isResponsibleFor( _nHandle ), "OPropertySetAggregationHelper::setFastPropertyValue_NoBroadcast: this is no forwarded property - did you use declareForwardedProperty for it?" );
978 180 : if ( m_pForwarder->isResponsibleFor( _nHandle ) )
979 180 : m_pForwarder->doForward( _nHandle, _rValue );
980 180 : }
981 :
982 :
983 184 : void OPropertySetAggregationHelper::declareForwardedProperty( sal_Int32 _nHandle )
984 : {
985 : OSL_ENSURE( !m_pForwarder->isResponsibleFor( _nHandle ), "OPropertySetAggregationHelper::declareForwardedProperty: already declared!" );
986 184 : m_pForwarder->takeResponsibilityFor( _nHandle );
987 184 : }
988 :
989 :
990 0 : void OPropertySetAggregationHelper::forwardingPropertyValue( sal_Int32 )
991 : {
992 : // not interested in
993 0 : }
994 :
995 :
996 0 : void OPropertySetAggregationHelper::forwardedPropertyValue( sal_Int32 )
997 : {
998 : // not interested in
999 0 : }
1000 :
1001 :
1002 4981 : bool OPropertySetAggregationHelper::isCurrentlyForwardingProperty( sal_Int32 _nHandle ) const
1003 : {
1004 4981 : return m_pForwarder->getCurrentlyForwardedProperty() == _nHandle;
1005 : }
1006 :
1007 :
1008 : } // namespace comphelper
1009 :
1010 :
1011 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|