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 0 : const Property* lcl_findPropertyByName( const Sequence< Property >& _rProps, const OUString& _rName )
50 : {
51 0 : sal_Int32 nLen = _rProps.getLength();
52 0 : const Property* pProperties = _rProps.getConstArray();
53 0 : Property aNameProp(_rName, 0, Type(), 0);
54 0 : const Property* pResult = ::std::lower_bound(pProperties, pProperties + nLen, aNameProp, PropertyCompareByName());
55 0 : if ( pResult && ( pResult == pProperties + nLen || pResult->Name != _rName) )
56 0 : pResult = NULL;
57 :
58 0 : return pResult;
59 : }
60 : }
61 :
62 : //= OPropertyArrayAggregationHelper
63 :
64 :
65 :
66 0 : OPropertyArrayAggregationHelper::OPropertyArrayAggregationHelper(
67 : const Sequence< Property >& _rProperties, const Sequence< Property >& _rAggProperties,
68 : IPropertyInfoService* _pInfoService, sal_Int32 _nFirstAggregateId )
69 0 : :m_aProperties( _rProperties )
70 : {
71 0 : sal_Int32 nDelegatorProps = _rProperties.getLength();
72 0 : sal_Int32 nAggregateProps = _rAggProperties.getLength();
73 :
74 : // make room for all properties
75 0 : sal_Int32 nMergedProps = nDelegatorProps + nAggregateProps;
76 0 : m_aProperties.realloc( nMergedProps );
77 :
78 0 : const Property* pAggregateProps = _rAggProperties.getConstArray();
79 0 : const Property* pDelegateProps = _rProperties.getConstArray();
80 0 : 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 0 : ::std::set< OUString > aDelegatorProps;
85 :
86 : // create the map for the delegator properties
87 0 : sal_Int32 nMPLoop = 0;
88 0 : for ( ; nMPLoop < nDelegatorProps; ++nMPLoop, ++pDelegateProps )
89 : {
90 0 : m_aPropertyAccessors[ pDelegateProps->Handle ] = OPropertyAccessor( -1, nMPLoop, false );
91 : OSL_ENSURE( aDelegatorProps.find( pDelegateProps->Name ) == aDelegatorProps.end(),
92 : "OPropertyArrayAggregationHelper::OPropertyArrayAggregationHelper: duplicate delegatee property!" );
93 0 : aDelegatorProps.insert( pDelegateProps->Name );
94 : }
95 :
96 : // create the map for the aggregate properties
97 0 : sal_Int32 nAggregateHandle = _nFirstAggregateId;
98 0 : pMergedProps += nDelegatorProps;
99 0 : for ( ; nMPLoop < nMergedProps; ++pAggregateProps )
100 : {
101 : // if the aggregate property is present at the delegatee already, ignore it
102 0 : if ( aDelegatorProps.find( pAggregateProps->Name ) != aDelegatorProps.end() )
103 : {
104 0 : --nMergedProps;
105 0 : continue;
106 : }
107 :
108 : // next aggregate property - remember it
109 0 : *pMergedProps = *pAggregateProps;
110 :
111 : // determine the handle for the property which we will expose to the outside world
112 0 : sal_Int32 nHandle = -1;
113 : // ask the infor service first
114 0 : if ( _pInfoService )
115 0 : nHandle = _pInfoService->getPreferredPropertyId( pMergedProps->Name );
116 :
117 0 : if ( -1 == nHandle )
118 : // no handle from the info service -> default
119 0 : nHandle = nAggregateHandle++;
120 : else
121 : { // check if we alread have a property with the given handle
122 0 : const Property* pPropsTilNow = m_aProperties.getConstArray();
123 0 : for ( sal_Int32 nCheck = 0; nCheck < nMPLoop; ++nCheck, ++pPropsTilNow )
124 0 : 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 0 : m_aPropertyAccessors[ nHandle ] = OPropertyAccessor( pMergedProps->Handle, nMPLoop, true );
133 0 : pMergedProps->Handle = nHandle;
134 :
135 0 : ++nMPLoop;
136 0 : ++pMergedProps;
137 : }
138 0 : m_aProperties.realloc( nMergedProps );
139 0 : pMergedProps = m_aProperties.getArray(); // reset, needed again below
140 :
141 : // sort the properties by name
142 0 : ::std::sort( pMergedProps, pMergedProps+nMergedProps, PropertyCompareByName());
143 :
144 0 : pMergedProps = m_aProperties.getArray();
145 :
146 : // sync the map positions
147 0 : for ( nMPLoop = 0; nMPLoop < nMergedProps; ++nMPLoop, ++pMergedProps )
148 0 : m_aPropertyAccessors[ pMergedProps->Handle ].nPos = nMPLoop;
149 0 : }
150 :
151 :
152 0 : OPropertyArrayAggregationHelper::PropertyOrigin OPropertyArrayAggregationHelper::classifyProperty( const OUString& _rName )
153 : {
154 0 : PropertyOrigin eOrigin = UNKNOWN_PROPERTY;
155 : // look up the name
156 0 : const Property* pPropertyDescriptor = lcl_findPropertyByName( m_aProperties, _rName );
157 0 : if ( pPropertyDescriptor )
158 : {
159 : // look up the handle for this name
160 0 : ConstPropertyAccessorMapIterator aPos = m_aPropertyAccessors.find( pPropertyDescriptor->Handle );
161 : OSL_ENSURE( m_aPropertyAccessors.end() != aPos, "OPropertyArrayAggregationHelper::classifyProperty: should have this handle in my map!" );
162 0 : if ( m_aPropertyAccessors.end() != aPos )
163 : {
164 0 : eOrigin = aPos->second.bAggregate ? AGGREGATE_PROPERTY : DELEGATOR_PROPERTY;
165 : }
166 : }
167 0 : 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 0 : sal_Bool OPropertyArrayAggregationHelper::hasPropertyByName(const OUString& _rPropertyName)
183 : {
184 0 : return NULL != findPropertyByName( _rPropertyName );
185 : }
186 :
187 :
188 0 : const Property* OPropertyArrayAggregationHelper::findPropertyByName(const :: OUString& _rName ) const
189 : {
190 0 : return lcl_findPropertyByName( m_aProperties, _rName );
191 : }
192 :
193 :
194 0 : sal_Int32 OPropertyArrayAggregationHelper::getHandleByName(const OUString& _rPropertyName)
195 : {
196 0 : const Property* pProperty = findPropertyByName( _rPropertyName );
197 0 : return pProperty ? pProperty->Handle : -1;
198 : }
199 :
200 :
201 0 : sal_Bool OPropertyArrayAggregationHelper::fillPropertyMembersByHandle(
202 : OUString* _pPropName, sal_Int16* _pAttributes, sal_Int32 _nHandle)
203 : {
204 0 : ConstPropertyAccessorMapIterator i = m_aPropertyAccessors.find(_nHandle);
205 0 : bool bRet = i != m_aPropertyAccessors.end();
206 0 : if (bRet)
207 : {
208 0 : const ::com::sun::star::beans::Property& rProperty = m_aProperties.getConstArray()[(*i).second.nPos];
209 0 : if (_pPropName)
210 0 : *_pPropName = rProperty.Name;
211 0 : if (_pAttributes)
212 0 : *_pAttributes = rProperty.Attributes;
213 : }
214 0 : return bRet;
215 : }
216 :
217 :
218 0 : bool OPropertyArrayAggregationHelper::getPropertyByHandle( sal_Int32 _nHandle, Property& _rProperty ) const
219 : {
220 0 : ConstPropertyAccessorMapIterator pos = m_aPropertyAccessors.find(_nHandle);
221 0 : if ( pos != m_aPropertyAccessors.end() )
222 : {
223 0 : _rProperty = m_aProperties[ pos->second.nPos ];
224 0 : return true;
225 : }
226 0 : return false;
227 : }
228 :
229 :
230 0 : bool OPropertyArrayAggregationHelper::fillAggregatePropertyInfoByHandle(
231 : OUString* _pPropName, sal_Int32* _pOriginalHandle, sal_Int32 _nHandle) const
232 : {
233 0 : ConstPropertyAccessorMapIterator i = m_aPropertyAccessors.find(_nHandle);
234 0 : bool bRet = i != m_aPropertyAccessors.end() && (*i).second.bAggregate;
235 0 : if (bRet)
236 : {
237 0 : if (_pOriginalHandle)
238 0 : *_pOriginalHandle = (*i).second.nOriginalHandle;
239 0 : if (_pPropName)
240 : {
241 : OSL_ENSURE((*i).second.nPos < m_aProperties.getLength(),"Invalid index for sequence!");
242 0 : const ::com::sun::star::beans::Property& rProperty = m_aProperties.getConstArray()[(*i).second.nPos];
243 0 : *_pPropName = rProperty.Name;
244 : }
245 : }
246 0 : return bRet;
247 : }
248 :
249 :
250 :
251 0 : ::com::sun::star::uno::Sequence< ::com::sun::star::beans::Property> OPropertyArrayAggregationHelper::getProperties()
252 : {
253 0 : return m_aProperties;
254 : }
255 :
256 :
257 :
258 0 : sal_Int32 OPropertyArrayAggregationHelper::fillHandles(
259 : sal_Int32* _pHandles, const ::com::sun::star::uno::Sequence< OUString >& _rPropNames )
260 : {
261 0 : sal_Int32 nHitCount = 0;
262 0 : const OUString* pReqProps = _rPropNames.getConstArray();
263 0 : 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 0 : const ::com::sun::star::beans::Property* pCur = m_aProperties.getConstArray();
283 0 : const ::com::sun::star::beans::Property* pEnd = m_aProperties.getConstArray() + m_aProperties.getLength();
284 :
285 0 : for( sal_Int32 i = 0; i < nReqLen; ++i )
286 : {
287 : // determine the logarithm
288 0 : sal_uInt32 n = (sal_uInt32)(pEnd - pCur);
289 0 : sal_Int32 nLog = 0;
290 0 : while( n )
291 : {
292 0 : nLog += 1;
293 0 : n = n >> 1;
294 : }
295 :
296 : // (Number of properties yet to be found) * (Log2 of properties yet to be searched)
297 0 : if( (nReqLen - i) * nLog >= pEnd - pCur )
298 : {
299 : // linear search is better
300 0 : while( pCur < pEnd && pReqProps[i] > pCur->Name )
301 : {
302 0 : pCur++;
303 : }
304 0 : if( pCur < pEnd && pReqProps[i] == pCur->Name )
305 : {
306 0 : _pHandles[i] = pCur->Handle;
307 0 : nHitCount++;
308 : }
309 : else
310 0 : _pHandles[i] = -1;
311 : }
312 : else
313 : {
314 : // binary search is better
315 0 : sal_Int32 nCompVal = 1;
316 0 : const ::com::sun::star::beans::Property* pOldEnd = pEnd--;
317 0 : const ::com::sun::star::beans::Property* pMid = pCur;
318 :
319 0 : while( nCompVal != 0 && pCur <= pEnd )
320 : {
321 0 : pMid = (pEnd - pCur) / 2 + pCur;
322 :
323 0 : nCompVal = pReqProps[i].compareTo( pMid->Name );
324 :
325 0 : if( nCompVal > 0 )
326 0 : pCur = pMid + 1;
327 : else
328 0 : pEnd = pMid - 1;
329 : }
330 :
331 0 : if( nCompVal == 0 )
332 : {
333 0 : _pHandles[i] = pMid->Handle;
334 0 : nHitCount++;
335 0 : 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 0 : pEnd = pOldEnd;
348 : }
349 : }
350 0 : 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 0 : sal_Int32 getCurrentlyForwardedProperty( ) const { return m_nCurrentlyForwarding; }
384 : };
385 :
386 :
387 0 : PropertyForwarder::PropertyForwarder( OPropertySetAggregationHelper& _rAggregationHelper )
388 : :m_rAggregationHelper( _rAggregationHelper )
389 0 : ,m_nCurrentlyForwarding( -1 )
390 : {
391 0 : }
392 :
393 :
394 0 : PropertyForwarder::~PropertyForwarder()
395 : {
396 0 : }
397 :
398 :
399 0 : void PropertyForwarder::takeResponsibilityFor( sal_Int32 _nHandle )
400 : {
401 0 : m_aProperties.insert( _nHandle );
402 0 : }
403 :
404 :
405 0 : bool PropertyForwarder::isResponsibleFor( sal_Int32 _nHandle )
406 : {
407 0 : return m_aProperties.find( _nHandle ) != m_aProperties.end();
408 : }
409 :
410 :
411 0 : 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 0 : if ( m_rAggregationHelper.m_xAggregateSet.is() )
415 : {
416 0 : m_rAggregationHelper.forwardingPropertyValue( _nHandle );
417 :
418 : OSL_ENSURE( m_nCurrentlyForwarding == -1, "PropertyForwarder::doForward: reentrance?" );
419 0 : m_nCurrentlyForwarding = _nHandle;
420 :
421 : try
422 : {
423 0 : 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 0 : m_nCurrentlyForwarding = -1;
433 :
434 0 : m_rAggregationHelper.forwardedPropertyValue( _nHandle );
435 : }
436 0 : }
437 : }
438 :
439 :
440 : //= OPropertySetAggregationHelper
441 :
442 :
443 :
444 0 : OPropertySetAggregationHelper::OPropertySetAggregationHelper( ::cppu::OBroadcastHelper& rBHlp )
445 : :OPropertyStateHelper( rBHlp )
446 0 : ,m_bListening( false )
447 : {
448 0 : m_pForwarder = new PropertyForwarder( *this );
449 0 : }
450 :
451 :
452 0 : OPropertySetAggregationHelper::~OPropertySetAggregationHelper()
453 : {
454 0 : delete m_pForwarder;
455 0 : }
456 :
457 :
458 0 : ::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 0 : ::com::sun::star::uno::Any aReturn = OPropertyStateHelper::queryInterface(_rType);
461 :
462 0 : if ( !aReturn.hasValue() )
463 0 : 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 0 : );
468 :
469 0 : return aReturn;
470 : }
471 :
472 :
473 0 : void OPropertySetAggregationHelper::disposing()
474 : {
475 0 : osl::MutexGuard aGuard(rBHelper.rMutex);
476 :
477 0 : if ( m_xAggregateSet.is() && m_bListening )
478 : {
479 : // register as a single listener
480 0 : m_xAggregateMultiSet->removePropertiesChangeListener(this);
481 0 : m_xAggregateSet->removeVetoableChangeListener(OUString(), this);
482 0 : m_bListening = false;
483 : }
484 :
485 0 : OPropertyStateHelper::disposing();
486 0 : }
487 :
488 :
489 0 : 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 0 : if (_rSource.Source == m_xAggregateSet)
493 0 : m_bListening = false;
494 0 : }
495 :
496 :
497 0 : 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 0 : sal_Int32 nLen = _rEvents.getLength();
502 0 : cppu::IPropertyArrayHelper& rPH = getInfoHelper();
503 :
504 0 : if (1 == nLen)
505 : {
506 0 : 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 0 : 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 0 : if ( ( nHandle != -1 ) && !isCurrentlyForwardingProperty( nHandle ) )
517 0 : fire(&nHandle, &evt.NewValue, &evt.OldValue, 1, sal_False);
518 : }
519 : else
520 : {
521 0 : boost::scoped_array<sal_Int32> pHandles(new sal_Int32[nLen]);
522 0 : boost::scoped_array< ::com::sun::star::uno::Any> pNewValues(new ::com::sun::star::uno::Any[nLen]);
523 0 : boost::scoped_array< ::com::sun::star::uno::Any> pOldValues(new ::com::sun::star::uno::Any[nLen]);
524 :
525 0 : const ::com::sun::star::beans::PropertyChangeEvent* pEvents = _rEvents.getConstArray();
526 0 : sal_Int32 nDest = 0;
527 0 : for (sal_Int32 nSource=0; nSource<nLen; ++nSource, ++pEvents)
528 : {
529 0 : sal_Int32 nHandle = rPH.getHandleByName(pEvents->PropertyName);
530 0 : if ( ( nHandle != -1 ) && !isCurrentlyForwardingProperty( nHandle ) )
531 : { // same as above : -1 is valid (73247) ...
532 0 : pHandles[nDest] = nHandle;
533 0 : pNewValues[nDest] = pEvents->NewValue;
534 0 : pOldValues[nDest] = pEvents->OldValue;
535 0 : ++nDest;
536 : }
537 : }
538 :
539 0 : if (nDest)
540 0 : fire(pHandles.get(), pNewValues.get(), pOldValues.get(), nDest, sal_False);
541 : }
542 0 : }
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 0 : void OPropertySetAggregationHelper::setAggregation(const ::com::sun::star::uno::Reference< ::com::sun::star::uno::XInterface >& _rxDelegate)
557 : throw( ::com::sun::star::lang::IllegalArgumentException )
558 : {
559 0 : osl::MutexGuard aGuard(rBHelper.rMutex);
560 :
561 0 : 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 0 : m_xAggregateState = m_xAggregateState.query( _rxDelegate );
569 0 : m_xAggregateSet = m_xAggregateSet.query( _rxDelegate );
570 0 : m_xAggregateMultiSet = m_xAggregateMultiSet.query( _rxDelegate );
571 0 : m_xAggregateFastSet = m_xAggregateFastSet.query( _rxDelegate );
572 :
573 : // must support XPropertySet and XMultiPropertySet
574 0 : if ( m_xAggregateSet.is() && !m_xAggregateMultiSet.is() )
575 0 : throw ::com::sun::star::lang::IllegalArgumentException();
576 0 : }
577 :
578 :
579 0 : void OPropertySetAggregationHelper::startListening()
580 : {
581 0 : osl::MutexGuard aGuard(rBHelper.rMutex);
582 :
583 0 : if (!m_bListening && m_xAggregateSet.is())
584 : {
585 : // register as a single listener
586 0 : ::com::sun::star::uno::Sequence< OUString > aPropertyNames;
587 0 : m_xAggregateMultiSet->addPropertiesChangeListener(aPropertyNames, this);
588 0 : m_xAggregateSet->addVetoableChangeListener(OUString(), this);
589 :
590 0 : m_bListening = true;
591 0 : }
592 0 : }
593 :
594 :
595 0 : 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 0 : OPropertySetHelper::addVetoableChangeListener(_rPropertyName, _rxListener);
600 0 : if (!m_bListening)
601 0 : startListening();
602 0 : }
603 :
604 :
605 0 : 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 0 : OPropertySetHelper::addPropertyChangeListener(_rPropertyName, _rxListener);
610 0 : if (!m_bListening)
611 0 : startListening();
612 0 : }
613 :
614 :
615 0 : 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 0 : OPropertySetHelper::addPropertiesChangeListener(_rPropertyNames, _rxListener);
620 0 : if (!m_bListening)
621 0 : startListening();
622 0 : }
623 :
624 :
625 0 : sal_Int32 OPropertySetAggregationHelper::getOriginalHandle(sal_Int32 nHandle) const
626 : {
627 0 : OPropertyArrayAggregationHelper& rPH = (OPropertyArrayAggregationHelper&)const_cast<OPropertySetAggregationHelper*>(this)->getInfoHelper();
628 0 : sal_Int32 nOriginalHandle = -1;
629 0 : rPH.fillAggregatePropertyInfoByHandle(NULL, &nOriginalHandle, nHandle);
630 0 : return nOriginalHandle;
631 : }
632 :
633 :
634 0 : OUString OPropertySetAggregationHelper::getPropertyName( sal_Int32 _nHandle ) const
635 : {
636 0 : OPropertyArrayAggregationHelper& rPH = static_cast< OPropertyArrayAggregationHelper& >( const_cast<OPropertySetAggregationHelper*>(this)->getInfoHelper() );
637 0 : Property aProperty;
638 0 : OSL_VERIFY( rPH.getPropertyByHandle( _nHandle, aProperty ) );
639 0 : return aProperty.Name;
640 : }
641 :
642 :
643 0 : 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 0 : OPropertyArrayAggregationHelper& rPH = static_cast< OPropertyArrayAggregationHelper& >( getInfoHelper() );
649 0 : OUString aPropName;
650 0 : sal_Int32 nOriginalHandle = -1;
651 :
652 : // does the handle belong to the aggregation ?
653 0 : if (rPH.fillAggregatePropertyInfoByHandle(&aPropName, &nOriginalHandle, _nHandle))
654 0 : if (m_xAggregateFastSet.is())
655 0 : m_xAggregateFastSet->setFastPropertyValue(nOriginalHandle, _rValue);
656 : else
657 0 : m_xAggregateSet->setPropertyValue(aPropName, _rValue);
658 : else
659 0 : OPropertySetHelper::setFastPropertyValue(_nHandle, _rValue);
660 0 : }
661 :
662 :
663 0 : void OPropertySetAggregationHelper::getFastPropertyValue( ::com::sun::star::uno::Any& rValue, sal_Int32 nHandle) const
664 : {
665 0 : OPropertyArrayAggregationHelper& rPH = (OPropertyArrayAggregationHelper&)const_cast<OPropertySetAggregationHelper*>(this)->getInfoHelper();
666 0 : OUString aPropName;
667 0 : sal_Int32 nOriginalHandle = -1;
668 :
669 0 : if (rPH.fillAggregatePropertyInfoByHandle(&aPropName, &nOriginalHandle, nHandle))
670 : {
671 0 : if (m_xAggregateFastSet.is())
672 0 : rValue = m_xAggregateFastSet->getFastPropertyValue(nOriginalHandle);
673 : else
674 0 : rValue = m_xAggregateSet->getPropertyValue(aPropName);
675 : }
676 0 : 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 0 : rValue = m_xAggregateSet->getPropertyValue( getPropertyName( nHandle ) );
681 0 : }
682 0 : }
683 :
684 :
685 0 : ::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 0 : OPropertyArrayAggregationHelper& rPH = static_cast< OPropertyArrayAggregationHelper& >( getInfoHelper() );
691 0 : OUString aPropName;
692 0 : sal_Int32 nOriginalHandle = -1;
693 0 : ::com::sun::star::uno::Any aValue;
694 :
695 0 : if (rPH.fillAggregatePropertyInfoByHandle(&aPropName, &nOriginalHandle, nHandle))
696 : {
697 0 : if (m_xAggregateFastSet.is())
698 0 : aValue = m_xAggregateFastSet->getFastPropertyValue(nOriginalHandle);
699 : else
700 0 : aValue = m_xAggregateSet->getPropertyValue(aPropName);
701 : }
702 : else
703 0 : aValue = OPropertySetHelper::getFastPropertyValue(nHandle);
704 :
705 0 : return aValue;
706 : }
707 :
708 :
709 0 : 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 0 : if (!m_xAggregateSet.is())
718 0 : OPropertySetHelper::setPropertyValues(_rPropertyNames, _rValues);
719 0 : else if (_rPropertyNames.getLength() == 1) // use the more efficient way
720 : {
721 : try
722 : {
723 0 : 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 0 : OPropertyArrayAggregationHelper& rPH = static_cast< OPropertyArrayAggregationHelper& >( getInfoHelper() );
743 :
744 : // determine which properties belong to the aggregate, and which ones to the delegator
745 0 : const OUString* pNames = _rPropertyNames.getConstArray();
746 0 : sal_Int32 nAggCount(0);
747 0 : sal_Int32 nLen(_rPropertyNames.getLength());
748 :
749 0 : for ( sal_Int32 i = 0; i < nLen; ++i, ++pNames )
750 : {
751 0 : OPropertyArrayAggregationHelper::PropertyOrigin ePropOrg = rPH.classifyProperty( *pNames );
752 0 : if ( OPropertyArrayAggregationHelper::UNKNOWN_PROPERTY == ePropOrg )
753 0 : 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 0 : if ( OPropertyArrayAggregationHelper::AGGREGATE_PROPERTY == ePropOrg )
758 0 : ++nAggCount;
759 : }
760 :
761 0 : pNames = _rPropertyNames.getConstArray(); // reset, we'll need it again below ...
762 :
763 : // all properties belong to the aggregate
764 0 : if (nAggCount == nLen)
765 0 : m_xAggregateMultiSet->setPropertyValues(_rPropertyNames, _rValues);
766 :
767 : // all properties belong to the aggregating object
768 0 : else if (nAggCount == 0)
769 0 : OPropertySetHelper::setPropertyValues(_rPropertyNames, _rValues);
770 :
771 : // mixed
772 : else
773 : {
774 0 : 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 0 : Sequence< OUString > AggPropertyNames( nAggCount );
782 0 : OUString* pAggNames = AggPropertyNames.getArray();
783 : // aggregate's values
784 0 : Sequence< Any > AggValues( nAggCount );
785 0 : Any* pAggValues = AggValues.getArray();
786 :
787 : // delegator names
788 0 : Sequence< OUString > DelPropertyNames( nLen - nAggCount );
789 0 : OUString* pDelNames = DelPropertyNames.getArray();
790 :
791 : // delegator values
792 0 : Sequence< Any > DelValues( nLen - nAggCount );
793 0 : Any* pDelValues = DelValues.getArray();
794 :
795 0 : for ( sal_Int32 i = 0; i < nLen; ++i, ++pNames, ++pValues )
796 : {
797 0 : if ( OPropertyArrayAggregationHelper::AGGREGATE_PROPERTY == rPH.classifyProperty( *pNames ) )
798 : {
799 0 : *pAggNames++ = *pNames;
800 0 : *pAggValues++ = *pValues;
801 : }
802 : else
803 : {
804 0 : *pDelNames++ = *pNames;
805 0 : *pDelValues++ = *pValues;
806 : }
807 : }
808 :
809 : // reset, needed below
810 0 : pDelValues = DelValues.getArray();
811 :
812 0 : boost::scoped_array<sal_Int32> pHandles(new sal_Int32[ nLen - nAggCount ]);
813 :
814 : // get the map table
815 0 : cppu::IPropertyArrayHelper& rPH2 = getInfoHelper();
816 :
817 : // fill the handle array
818 0 : sal_Int32 nHitCount = rPH2.fillHandles( pHandles.get(), DelPropertyNames );
819 0 : if (nHitCount != 0)
820 : {
821 0 : boost::scoped_array< ::com::sun::star::uno::Any> pConvertedValues(new ::com::sun::star::uno::Any[ nHitCount ]);
822 0 : boost::scoped_array< ::com::sun::star::uno::Any> pOldValues(new ::com::sun::star::uno::Any[ nHitCount ]);
823 0 : nHitCount = 0;
824 : sal_Int32 i;
825 :
826 : {
827 : // must lock the mutex outside the loop. So all values are consistent.
828 0 : osl::MutexGuard aGuard( rBHelper.rMutex );
829 0 : for( i = 0; i < (nLen - nAggCount); ++i )
830 : {
831 0 : if( pHandles[i] != -1 )
832 : {
833 : sal_Int16 nAttributes;
834 0 : rPH2.fillPropertyMembersByHandle( NULL, &nAttributes, pHandles[i] );
835 0 : if( nAttributes & ::com::sun::star::beans::PropertyAttribute::READONLY )
836 0 : throw ::com::sun::star::beans::PropertyVetoException();
837 : // Will the property change?
838 0 : if( convertFastPropertyValue( pConvertedValues[ nHitCount ], pOldValues[nHitCount],
839 0 : pHandles[i], pDelValues[i] ) )
840 : {
841 : // only increment if the property really change
842 0 : pHandles[nHitCount] = pHandles[i];
843 0 : nHitCount++;
844 : }
845 : }
846 0 : }
847 : // release guard to fire events
848 : }
849 :
850 : // fire vetoable events
851 0 : fire( pHandles.get(), pConvertedValues.get(), pOldValues.get(), nHitCount, sal_True );
852 :
853 : // setting the agg Properties
854 0 : m_xAggregateMultiSet->setPropertyValues(AggPropertyNames, AggValues);
855 :
856 : {
857 : // must lock the mutex outside the loop.
858 0 : osl::MutexGuard aGuard( rBHelper.rMutex );
859 : // Loop over all changed properties
860 0 : for( i = 0; i < nHitCount; i++ )
861 : {
862 : // Will the property change?
863 0 : setFastPropertyValue_NoBroadcast( pHandles[i], pConvertedValues[i] );
864 0 : }
865 : // release guard to fire events
866 : }
867 :
868 : // fire change events
869 0 : fire( pHandles.get(), pConvertedValues.get(), pOldValues.get(), nHitCount, sal_False );
870 : }
871 : else
872 0 : m_xAggregateMultiSet->setPropertyValues(AggPropertyNames, AggValues);
873 :
874 : }
875 0 : catch(::com::sun::star::uno::Exception&)
876 : {
877 0 : throw;
878 : }
879 : }
880 : }
881 0 : }
882 :
883 : // XPropertyState
884 :
885 0 : ::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 0 : OPropertyArrayAggregationHelper& rPH = static_cast< OPropertyArrayAggregationHelper& >( getInfoHelper() );
889 0 : sal_Int32 nHandle = rPH.getHandleByName( _rPropertyName );
890 :
891 0 : if (nHandle == -1)
892 : {
893 0 : throw ::com::sun::star::beans::UnknownPropertyException();
894 : }
895 :
896 0 : OUString aPropName;
897 0 : sal_Int32 nOriginalHandle = -1;
898 0 : if (rPH.fillAggregatePropertyInfoByHandle(&aPropName, &nOriginalHandle, nHandle))
899 : {
900 0 : if (m_xAggregateState.is())
901 0 : return m_xAggregateState->getPropertyState(_rPropertyName);
902 : else
903 0 : return ::com::sun::star::beans::PropertyState_DIRECT_VALUE;
904 : }
905 : else
906 0 : return getPropertyStateByHandle(nHandle);
907 : }
908 :
909 :
910 0 : void SAL_CALL OPropertySetAggregationHelper::setPropertyToDefault(const OUString& _rPropertyName)
911 : throw( ::com::sun::star::beans::UnknownPropertyException, ::com::sun::star::uno::RuntimeException, std::exception)
912 : {
913 0 : OPropertyArrayAggregationHelper& rPH = static_cast< OPropertyArrayAggregationHelper& >( getInfoHelper() );
914 0 : sal_Int32 nHandle = rPH.getHandleByName(_rPropertyName);
915 0 : if (nHandle == -1)
916 : {
917 0 : throw ::com::sun::star::beans::UnknownPropertyException();
918 : }
919 :
920 0 : OUString aPropName;
921 0 : sal_Int32 nOriginalHandle = -1;
922 0 : if (rPH.fillAggregatePropertyInfoByHandle(&aPropName, &nOriginalHandle, nHandle))
923 : {
924 0 : if (m_xAggregateState.is())
925 0 : m_xAggregateState->setPropertyToDefault(_rPropertyName);
926 : }
927 : else
928 : {
929 : try
930 : {
931 0 : 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 0 : }
940 0 : }
941 :
942 :
943 0 : ::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 0 : OPropertyArrayAggregationHelper& rPH = static_cast< OPropertyArrayAggregationHelper& >( getInfoHelper() );
947 0 : sal_Int32 nHandle = rPH.getHandleByName( aPropertyName );
948 :
949 0 : if ( nHandle == -1 )
950 0 : throw ::com::sun::star::beans::UnknownPropertyException();
951 :
952 0 : OUString aPropName;
953 0 : sal_Int32 nOriginalHandle = -1;
954 0 : if (rPH.fillAggregatePropertyInfoByHandle(&aPropName, &nOriginalHandle, nHandle))
955 : {
956 0 : if (m_xAggregateState.is())
957 0 : return m_xAggregateState->getPropertyDefault(aPropertyName);
958 : else
959 0 : return ::com::sun::star::uno::Any();
960 : }
961 : else
962 0 : return getPropertyDefaultByHandle(nHandle);
963 : }
964 :
965 :
966 0 : sal_Bool SAL_CALL OPropertySetAggregationHelper::convertFastPropertyValue( Any& _rConvertedValue, Any& _rOldValue, sal_Int32 _nHandle, const Any& _rValue ) throw(IllegalArgumentException)
967 : {
968 0 : 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 0 : if ( m_pForwarder->isResponsibleFor( _nHandle ) )
972 : {
973 : // need to determine the type of the property for conversion
974 0 : OPropertyArrayAggregationHelper& rPH = static_cast< OPropertyArrayAggregationHelper& >( getInfoHelper() );
975 0 : Property aProperty;
976 0 : OSL_VERIFY( rPH.getPropertyByHandle( _nHandle, aProperty ) );
977 :
978 0 : Any aCurrentValue;
979 0 : getFastPropertyValue( aCurrentValue, _nHandle );
980 0 : bModified = tryPropertyValue( _rConvertedValue, _rOldValue, _rValue, aCurrentValue, aProperty.Type );
981 : }
982 :
983 0 : return bModified;
984 : }
985 :
986 :
987 0 : 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 0 : if ( m_pForwarder->isResponsibleFor( _nHandle ) )
991 0 : m_pForwarder->doForward( _nHandle, _rValue );
992 0 : }
993 :
994 :
995 0 : void OPropertySetAggregationHelper::declareForwardedProperty( sal_Int32 _nHandle )
996 : {
997 : OSL_ENSURE( !m_pForwarder->isResponsibleFor( _nHandle ), "OPropertySetAggregationHelper::declareForwardedProperty: already declared!" );
998 0 : m_pForwarder->takeResponsibilityFor( _nHandle );
999 0 : }
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 0 : bool OPropertySetAggregationHelper::isCurrentlyForwardingProperty( sal_Int32 _nHandle ) const
1015 : {
1016 0 : return m_pForwarder->getCurrentlyForwardedProperty() == _nHandle;
1017 : }
1018 :
1019 :
1020 : } // namespace comphelper
1021 :
1022 :
1023 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|