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