update dev300-m58
[ooovba.git] / comphelper / source / property / propertycontainerhelper.cxx
blob858b58c315704f4716d352823bba860d2d09e125
1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: propertycontainerhelper.cxx,v $
10 * $Revision: 1.12 $
12 * This file is part of OpenOffice.org.
14 * OpenOffice.org is free software: you can redistribute it and/or modify
15 * it under the terms of the GNU Lesser General Public License version 3
16 * only, as published by the Free Software Foundation.
18 * OpenOffice.org is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU Lesser General Public License version 3 for more details
22 * (a copy is included in the LICENSE file that accompanied this code).
24 * You should have received a copy of the GNU Lesser General Public License
25 * version 3 along with OpenOffice.org. If not, see
26 * <http://www.openoffice.org/license.html>
27 * for a copy of the LGPLv3 License.
29 ************************************************************************/
31 // MARKER(update_precomp.py): autogen include statement, do not remove
32 #include "precompiled_comphelper.hxx"
33 #include <comphelper/propertycontainerhelper.hxx>
34 #include <comphelper/property.hxx>
35 #include <osl/diagnose.h>
36 #include <uno/data.h>
37 #include <com/sun/star/uno/genfunc.h>
38 #include <com/sun/star/beans/PropertyAttribute.hpp>
39 #include <com/sun/star/beans/UnknownPropertyException.hpp>
40 #include <rtl/ustrbuf.hxx>
42 #include <algorithm>
44 //.........................................................................
45 namespace comphelper
47 //.........................................................................
49 using namespace ::com::sun::star::uno;
50 using namespace ::com::sun::star::lang;
51 using namespace ::com::sun::star::beans;
53 //--------------------------------------------------------------------------
54 namespace
56 // comparing two property descriptions
57 struct PropertyDescriptionCompareByHandle : public ::std::binary_function< PropertyDescription, PropertyDescription, bool >
59 bool operator() (const PropertyDescription& x, const PropertyDescription& y) const
61 return x.aProperty.Handle < y.aProperty.Handle;
64 // comparing two property descriptions
65 struct PropertyDescriptionHandleCompare : public ::std::binary_function< PropertyDescription, sal_Int32, bool >
67 bool operator() (const PropertyDescription& x, const sal_Int32& y) const
69 return x.aProperty.Handle < y;
71 bool operator() (const sal_Int32& x, const PropertyDescription& y) const
73 return x < y.aProperty.Handle;
76 // comparing two property descriptions (by name)
77 struct PropertyDescriptionNameMatch : public ::std::unary_function< PropertyDescription, bool >
79 ::rtl::OUString m_rCompare;
80 PropertyDescriptionNameMatch( const ::rtl::OUString& _rCompare ) : m_rCompare( _rCompare ) { }
82 bool operator() (const PropertyDescription& x ) const
84 return x.aProperty.Name.equals(m_rCompare);
89 //==========================================================================
90 //= OPropertyContainerHelper
91 //==========================================================================
92 //--------------------------------------------------------------------------
93 OPropertyContainerHelper::OPropertyContainerHelper()
94 :m_bUnused(sal_False)
98 // -------------------------------------------------------------------------
99 OPropertyContainerHelper::~OPropertyContainerHelper()
103 //--------------------------------------------------------------------------
104 void OPropertyContainerHelper::registerProperty(const ::rtl::OUString& _rName, sal_Int32 _nHandle,
105 sal_Int32 _nAttributes, void* _pPointerToMember, const Type& _rMemberType)
107 OSL_ENSURE((_nAttributes & PropertyAttribute::MAYBEVOID) == 0,
108 "OPropertyContainerHelper::registerProperty: don't use this for properties which may be void ! There is a method called \"registerMayBeVoidProperty\" for this !");
109 OSL_ENSURE(!_rMemberType.equals(::getCppuType(static_cast< Any* >(NULL))),
110 "OPropertyContainerHelper::registerProperty: don't give my the type of an uno::Any ! Really can't handle this !");
111 OSL_ENSURE(_pPointerToMember,
112 "OPropertyContainerHelper::registerProperty: you gave me nonsense : the pointer must be non-NULL");
114 PropertyDescription aNewProp;
115 aNewProp.aProperty = Property( _rName, _nHandle, _rMemberType, (sal_Int16)_nAttributes );
116 aNewProp.eLocated = PropertyDescription::ltDerivedClassRealType;
117 aNewProp.aLocation.pDerivedClassMember = _pPointerToMember;
119 implPushBackProperty(aNewProp);
122 //--------------------------------------------------------------------------
123 void OPropertyContainerHelper::revokeProperty( sal_Int32 _nHandle )
125 PropertiesIterator aPos = searchHandle( _nHandle );
126 if ( aPos == m_aProperties.end() )
127 throw UnknownPropertyException();
128 m_aProperties.erase( aPos );
131 //--------------------------------------------------------------------------
132 void OPropertyContainerHelper::registerMayBeVoidProperty(const ::rtl::OUString& _rName, sal_Int32 _nHandle, sal_Int32 _nAttributes,
133 Any* _pPointerToMember, const Type& _rExpectedType)
135 OSL_ENSURE((_nAttributes & PropertyAttribute::MAYBEVOID) != 0,
136 "OPropertyContainerHelper::registerMayBeVoidProperty: why calling this when the attributes say nothing about may-be-void ?");
137 OSL_ENSURE(!_rExpectedType.equals(::getCppuType(static_cast< Any* >(NULL))),
138 "OPropertyContainerHelper::registerMayBeVoidProperty: don't give my the type of an uno::Any ! Really can't handle this !");
139 OSL_ENSURE(_pPointerToMember,
140 "OPropertyContainerHelper::registerMayBeVoidProperty: you gave me nonsense : the pointer must be non-NULL");
142 _nAttributes |= PropertyAttribute::MAYBEVOID;
144 PropertyDescription aNewProp;
145 aNewProp.aProperty = Property( _rName, _nHandle, _rExpectedType, (sal_Int16)_nAttributes );
146 aNewProp.eLocated = PropertyDescription::ltDerivedClassAnyType;
147 aNewProp.aLocation.pDerivedClassMember = _pPointerToMember;
149 implPushBackProperty(aNewProp);
153 //--------------------------------------------------------------------------
154 void OPropertyContainerHelper::registerPropertyNoMember(const ::rtl::OUString& _rName, sal_Int32 _nHandle, sal_Int32 _nAttributes,
155 const Type& _rType, const void* _pInitialValue)
157 OSL_ENSURE(!_rType.equals(::getCppuType(static_cast< Any* >(NULL))),
158 "OPropertyContainerHelper::registerPropertyNoMember : don't give my the type of an uno::Any ! Really can't handle this !");
159 OSL_ENSURE(_pInitialValue || ((_nAttributes & PropertyAttribute::MAYBEVOID) != 0),
160 "OPropertyContainerHelper::registerPropertyNoMember : you should not ommit the initial value if the property can't be void ! This will definitivly crash later !");
162 PropertyDescription aNewProp;
163 aNewProp.aProperty = Property( _rName, _nHandle, _rType, (sal_Int16)_nAttributes );
164 aNewProp.eLocated = PropertyDescription::ltHoldMyself;
165 aNewProp.aLocation.nOwnClassVectorIndex = m_aHoldProperties.size();
166 if (_pInitialValue)
167 m_aHoldProperties.push_back(Any(_pInitialValue, _rType));
168 else
169 m_aHoldProperties.push_back(Any());
171 implPushBackProperty(aNewProp);
174 //--------------------------------------------------------------------------
175 sal_Bool OPropertyContainerHelper::isRegisteredProperty( sal_Int32 _nHandle ) const
177 return const_cast< OPropertyContainerHelper* >( this )->searchHandle( _nHandle ) != m_aProperties.end();
180 //--------------------------------------------------------------------------
181 sal_Bool OPropertyContainerHelper::isRegisteredProperty( const ::rtl::OUString& _rName ) const
183 // TODO: the current structure is from a time where properties were
184 // static, not dynamic. Since we allow that properties are also dynamic,
185 // i.e. registered and revoked even though the XPropertySet has already been
186 // accessed, a vector is not really the best data structure anymore ...
188 ConstPropertiesIterator pos = ::std::find_if(
189 m_aProperties.begin(),
190 m_aProperties.end(),
191 PropertyDescriptionNameMatch( _rName )
193 return pos != m_aProperties.end();
196 //--------------------------------------------------------------------------
197 namespace
199 struct ComparePropertyWithHandle
201 bool operator()( const PropertyDescription& _rLHS, sal_Int32 _nRHS ) const
203 return _rLHS.aProperty.Handle < _nRHS;
205 bool operator()( sal_Int32 _nLHS, const PropertyDescription& _rRHS ) const
207 return _nLHS < _rRHS.aProperty.Handle;
212 //--------------------------------------------------------------------------
213 void OPropertyContainerHelper::implPushBackProperty(const PropertyDescription& _rProp)
215 #ifdef DBG_UTIL
216 for ( PropertiesIterator checkConflicts = m_aProperties.begin();
217 checkConflicts != m_aProperties.end();
218 ++checkConflicts
221 OSL_ENSURE(checkConflicts->aProperty.Name != _rProp.aProperty.Name, "OPropertyContainerHelper::implPushBackProperty: name already exists!");
222 OSL_ENSURE(checkConflicts->aProperty.Handle != _rProp.aProperty.Handle, "OPropertyContainerHelper::implPushBackProperty: handle already exists!");
224 #endif
226 PropertiesIterator pos = ::std::lower_bound(
227 m_aProperties.begin(), m_aProperties.end(),
228 _rProp.aProperty.Handle, ComparePropertyWithHandle() );
230 m_aProperties.insert( pos, _rProp );
233 //--------------------------------------------------------------------------
234 namespace
236 void lcl_throwIllegalPropertyValueTypeException( const PropertyDescription& _rProperty, const Any& _rValue )
238 ::rtl::OUStringBuffer aErrorMessage;
239 aErrorMessage.appendAscii( "The given value cannot be converted to the required property type." );
240 aErrorMessage.appendAscii( "\n(property name \"" );
241 aErrorMessage.append( _rProperty.aProperty.Name );
242 aErrorMessage.appendAscii( "\", found value type \"" );
243 aErrorMessage.append( _rValue.getValueType().getTypeName() );
244 aErrorMessage.appendAscii( "\", required property type \"" );
245 aErrorMessage.append( _rProperty.aProperty.Type.getTypeName() );
246 aErrorMessage.appendAscii( "\")" );
247 throw IllegalArgumentException( aErrorMessage.makeStringAndClear(), NULL, 4 );
251 //--------------------------------------------------------------------------
252 sal_Bool OPropertyContainerHelper::convertFastPropertyValue(
253 Any& _rConvertedValue, Any& _rOldValue, sal_Int32 _nHandle, const Any& _rValue ) SAL_THROW( (IllegalArgumentException) )
255 sal_Bool bModified = sal_False;
257 // get the property somebody is asking for
258 PropertiesIterator aPos = searchHandle(_nHandle);
259 if (aPos == m_aProperties.end())
261 OSL_ENSURE( false, "OPropertyContainerHelper::convertFastPropertyValue: unknown handle!" );
262 // should not happen if the derived class has built a correct property set info helper to be used by
263 // our base class OPropertySetHelper
264 return bModified;
267 switch (aPos->eLocated)
269 // similar handling for the two cases where the value is stored in an any
270 case PropertyDescription::ltHoldMyself:
271 case PropertyDescription::ltDerivedClassAnyType:
273 sal_Bool bMayBeVoid = ((aPos->aProperty.Attributes & PropertyAttribute::MAYBEVOID) != 0);
276 // non modifiable version of the value-to-be-set
277 Any aNewRequestedValue( _rValue );
279 // normalization
280 // (#102329# - 2002-08-14 - fs@openoffice.org)
281 // (#i29490# - 2004-06-16 - fs@openoffice.org)
282 if ( !aNewRequestedValue.getValueType().equals( aPos->aProperty.Type ) )
283 { // the actually given value is not of the same type as the one required
284 Any aProperlyTyped( NULL, aPos->aProperty.Type.getTypeLibType() );
286 if ( uno_type_assignData(
287 const_cast< void* >( aProperlyTyped.getValue() ), aProperlyTyped.getValueType().getTypeLibType(),
288 const_cast< void* >( aNewRequestedValue.getValue() ), aNewRequestedValue.getValueType().getTypeLibType(),
289 reinterpret_cast< uno_QueryInterfaceFunc >( cpp_queryInterface ),
290 reinterpret_cast< uno_AcquireFunc >( cpp_acquire ),
291 reinterpret_cast< uno_ReleaseFunc >( cpp_release )
295 // we were able to query the given XInterface-derivee for the interface
296 // which is required for this property
297 aNewRequestedValue = aProperlyTyped;
301 // argument check
302 if ( ! ( (bMayBeVoid && !aNewRequestedValue.hasValue()) // void is allowed if the attribute says so
303 || (aNewRequestedValue.getValueType().equals(aPos->aProperty.Type)) // else the types have to be equal
307 lcl_throwIllegalPropertyValueTypeException( *aPos, _rValue );
310 Any* pPropContainer = NULL;
311 // the pointer to the any which holds the property value, no matter if located in the derived clas
312 // or in out vector
314 if (PropertyDescription::ltHoldMyself == aPos->eLocated)
316 OSL_ENSURE(aPos->aLocation.nOwnClassVectorIndex < (sal_Int32)m_aHoldProperties.size(),
317 "OPropertyContainerHelper::convertFastPropertyValue: invalid position !");
318 PropertyContainerIterator aIter = m_aHoldProperties.begin() + aPos->aLocation.nOwnClassVectorIndex;
319 pPropContainer = &(*aIter);
321 else
322 pPropContainer = reinterpret_cast<Any*>(aPos->aLocation.pDerivedClassMember);
324 // check if the new value differs from the current one
325 if (!pPropContainer->hasValue() || !aNewRequestedValue.hasValue())
326 bModified = pPropContainer->hasValue() != aNewRequestedValue.hasValue();
327 else
328 bModified = !uno_type_equalData(
329 const_cast< void* >( pPropContainer->getValue() ), aPos->aProperty.Type.getTypeLibType(),
330 const_cast< void* >( aNewRequestedValue.getValue() ), aPos->aProperty.Type.getTypeLibType(),
331 reinterpret_cast< uno_QueryInterfaceFunc >( cpp_queryInterface ),
332 reinterpret_cast< uno_ReleaseFunc >( cpp_release )
335 if (bModified)
337 _rOldValue = *pPropContainer;
338 _rConvertedValue = aNewRequestedValue;
341 break;
342 case PropertyDescription::ltDerivedClassRealType:
343 // let the UNO runtime library do any possible conversion
344 // this may include a change of the type - for instance, if a LONG is required,
345 // but a short is given, then this is valid, as it can be converted without any potential
346 // data loss
348 Any aProperlyTyped;
349 const Any* pNewValue = &_rValue;
351 if (!_rValue.getValueType().equals(aPos->aProperty.Type))
353 sal_Bool bConverted = sal_False;
355 // a temporary any of the correct (required) type
356 aProperlyTyped = Any( NULL, aPos->aProperty.Type.getTypeLibType() );
357 // (need this as we do not want to overwrite the derived class member here)
359 if ( uno_type_assignData(
360 const_cast<void*>(aProperlyTyped.getValue()), aProperlyTyped.getValueType().getTypeLibType(),
361 const_cast<void*>(_rValue.getValue()), _rValue.getValueType().getTypeLibType(),
362 reinterpret_cast< uno_QueryInterfaceFunc >( cpp_queryInterface ),
363 reinterpret_cast< uno_AcquireFunc >( cpp_acquire ),
364 reinterpret_cast< uno_ReleaseFunc >( cpp_release )
368 // could query for the requested interface
369 bConverted = sal_True;
370 pNewValue = &aProperlyTyped;
373 if ( !bConverted )
374 lcl_throwIllegalPropertyValueTypeException( *aPos, _rValue );
377 // from here on, we should have the proper type
378 OSL_ENSURE( pNewValue->getValueType() == aPos->aProperty.Type,
379 "OPropertyContainerHelper::convertFastPropertyValue: conversion failed!" );
380 bModified = !uno_type_equalData(
381 aPos->aLocation.pDerivedClassMember, aPos->aProperty.Type.getTypeLibType(),
382 const_cast<void*>(pNewValue->getValue()), aPos->aProperty.Type.getTypeLibType(),
383 reinterpret_cast< uno_QueryInterfaceFunc >( cpp_queryInterface ),
384 reinterpret_cast< uno_ReleaseFunc >( cpp_release )
387 if (bModified)
389 _rOldValue.setValue(aPos->aLocation.pDerivedClassMember, aPos->aProperty.Type);
390 _rConvertedValue = *pNewValue;
392 break;
395 return bModified;
398 //--------------------------------------------------------------------------
399 void OPropertyContainerHelper::setFastPropertyValue(sal_Int32 _nHandle, const Any& _rValue) SAL_THROW( (Exception) )
401 // get the property somebody is asking for
402 PropertiesIterator aPos = searchHandle(_nHandle);
403 if (aPos == m_aProperties.end())
405 OSL_ENSURE( false, "OPropertyContainerHelper::setFastPropertyValue: unknown handle!" );
406 // should not happen if the derived class has built a correct property set info helper to be used by
407 // our base class OPropertySetHelper
408 return;
411 switch (aPos->eLocated)
413 case PropertyDescription::ltHoldMyself:
414 m_aHoldProperties[aPos->aLocation.nOwnClassVectorIndex] = _rValue;
415 break;
417 case PropertyDescription::ltDerivedClassAnyType:
418 *reinterpret_cast< Any* >(aPos->aLocation.pDerivedClassMember) = _rValue;
419 break;
421 case PropertyDescription::ltDerivedClassRealType:
422 #if OSL_DEBUG_LEVEL > 0
423 sal_Bool bSuccess =
424 #endif
425 // copy the data from the to-be-set value
426 uno_type_assignData(
427 aPos->aLocation.pDerivedClassMember, aPos->aProperty.Type.getTypeLibType(),
428 const_cast< void* >( _rValue.getValue() ), _rValue.getValueType().getTypeLibType(),
429 reinterpret_cast< uno_QueryInterfaceFunc >( cpp_queryInterface ),
430 reinterpret_cast< uno_AcquireFunc >( cpp_acquire ),
431 reinterpret_cast< uno_ReleaseFunc >( cpp_release ) );
433 OSL_ENSURE( bSuccess,
434 "OPropertyContainerHelper::setFastPropertyValue: ooops .... the value could not be assigned!");
436 break;
440 //--------------------------------------------------------------------------
441 void OPropertyContainerHelper::getFastPropertyValue(Any& _rValue, sal_Int32 _nHandle) const
443 // get the property somebody is asking for
444 PropertiesIterator aPos = const_cast<OPropertyContainerHelper*>(this)->searchHandle(_nHandle);
445 if (aPos == m_aProperties.end())
447 OSL_ENSURE( false, "OPropertyContainerHelper::getFastPropertyValue: unknown handle!" );
448 // should not happen if the derived class has built a correct property set info helper to be used by
449 // our base class OPropertySetHelper
450 return;
453 switch (aPos->eLocated)
455 case PropertyDescription::ltHoldMyself:
456 OSL_ENSURE(aPos->aLocation.nOwnClassVectorIndex < (sal_Int32)m_aHoldProperties.size(),
457 "OPropertyContainerHelper::convertFastPropertyValue: invalid position !");
458 _rValue = m_aHoldProperties[aPos->aLocation.nOwnClassVectorIndex];
459 break;
460 case PropertyDescription::ltDerivedClassAnyType:
461 _rValue = *reinterpret_cast<Any*>(aPos->aLocation.pDerivedClassMember);
462 break;
463 case PropertyDescription::ltDerivedClassRealType:
464 _rValue.setValue(aPos->aLocation.pDerivedClassMember, aPos->aProperty.Type);
465 break;
469 //--------------------------------------------------------------------------
470 OPropertyContainerHelper::PropertiesIterator OPropertyContainerHelper::searchHandle(sal_Int32 _nHandle)
472 // search a lower bound
473 PropertiesIterator aLowerBound = ::std::lower_bound(
474 m_aProperties.begin(),
475 m_aProperties.end(),
476 _nHandle,
477 PropertyDescriptionHandleCompare());
479 // check for identity
480 if ((aLowerBound != m_aProperties.end()) && aLowerBound->aProperty.Handle != _nHandle)
481 aLowerBound = m_aProperties.end();
483 return aLowerBound;
486 //--------------------------------------------------------------------------
487 const Property& OPropertyContainerHelper::getProperty( const ::rtl::OUString& _rName ) const
489 ConstPropertiesIterator pos = ::std::find_if(
490 m_aProperties.begin(),
491 m_aProperties.end(),
492 PropertyDescriptionNameMatch( _rName )
494 if ( pos == m_aProperties.end() )
495 throw UnknownPropertyException( _rName, NULL );
497 return pos->aProperty;
500 //--------------------------------------------------------------------------
501 void OPropertyContainerHelper::modifyAttributes(sal_Int32 _nHandle, sal_Int32 _nAddAttrib, sal_Int32 _nRemoveAttrib)
503 // get the property somebody is asking for
504 PropertiesIterator aPos = searchHandle(_nHandle);
505 if (aPos == m_aProperties.end())
507 OSL_ENSURE( false, "OPropertyContainerHelper::modifyAttributes: unknown handle!" );
508 // should not happen if the derived class has built a correct property set info helper to be used by
509 // our base class OPropertySetHelper
510 return;
512 aPos->aProperty.Handle |= _nAddAttrib;
513 aPos->aProperty.Handle &= ~_nRemoveAttrib;
516 //--------------------------------------------------------------------------
517 void OPropertyContainerHelper::describeProperties(Sequence< Property >& _rProps) const
519 Sequence< Property > aOwnProps(m_aProperties.size());
520 Property* pOwnProps = aOwnProps.getArray();
522 for ( ConstPropertiesIterator aLoop = m_aProperties.begin();
523 aLoop != m_aProperties.end();
524 ++aLoop, ++pOwnProps
527 pOwnProps->Name = aLoop->aProperty.Name;
528 pOwnProps->Handle = aLoop->aProperty.Handle;
529 pOwnProps->Attributes = (sal_Int16)aLoop->aProperty.Attributes;
530 pOwnProps->Type = aLoop->aProperty.Type;
533 // as our property vector is sorted by handles, not by name, we have to sort aOwnProps
534 ::std::sort(aOwnProps.getArray(), aOwnProps.getArray() + aOwnProps.getLength(), PropertyCompareByName());
536 // unfortunally the STL merge function does not allow the output range to overlap one of the input ranges,
537 // so we need an extra sequence
538 Sequence< Property > aOutput;
539 aOutput.realloc(_rProps.getLength() + aOwnProps.getLength());
540 // do the merge
541 ::std::merge( _rProps.getConstArray(), _rProps.getConstArray() + _rProps.getLength(), // input 1
542 aOwnProps.getConstArray(), aOwnProps.getConstArray() + aOwnProps.getLength(), // input 2
543 aOutput.getArray(), // output
544 PropertyCompareByName() // compare operator
547 // copy the output
548 _rProps = aOutput;
551 //.........................................................................
552 } // namespace comphelper
553 //.........................................................................