merged tag ooo/OOO330_m14
[LibreOffice.git] / comphelper / source / property / propertycontainerhelper.cxx
blob0b420a3eebd8380c13942d3a640c048d2ed2c33b
1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5 * Copyright 2000, 2010 Oracle and/or its affiliates.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * This file is part of OpenOffice.org.
11 * OpenOffice.org is free software: you can redistribute it and/or modify
12 * it under the terms of the GNU Lesser General Public License version 3
13 * only, as published by the Free Software Foundation.
15 * OpenOffice.org is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU Lesser General Public License version 3 for more details
19 * (a copy is included in the LICENSE file that accompanied this code).
21 * You should have received a copy of the GNU Lesser General Public License
22 * version 3 along with OpenOffice.org. If not, see
23 * <http://www.openoffice.org/license.html>
24 * for a copy of the LGPLv3 License.
26 ************************************************************************/
28 // MARKER(update_precomp.py): autogen include statement, do not remove
29 #include "precompiled_comphelper.hxx"
30 #include <comphelper/propertycontainerhelper.hxx>
31 #include <comphelper/property.hxx>
32 #include <osl/diagnose.h>
33 #include <uno/data.h>
34 #include <com/sun/star/uno/genfunc.h>
35 #include <com/sun/star/beans/PropertyAttribute.hpp>
36 #include <com/sun/star/beans/UnknownPropertyException.hpp>
37 #include <rtl/ustrbuf.hxx>
39 #include <algorithm>
41 //.........................................................................
42 namespace comphelper
44 //.........................................................................
46 using namespace ::com::sun::star::uno;
47 using namespace ::com::sun::star::lang;
48 using namespace ::com::sun::star::beans;
50 //--------------------------------------------------------------------------
51 namespace
53 // comparing two property descriptions
54 struct PropertyDescriptionCompareByHandle : public ::std::binary_function< PropertyDescription, PropertyDescription, bool >
56 bool operator() (const PropertyDescription& x, const PropertyDescription& y) const
58 return x.aProperty.Handle < y.aProperty.Handle;
61 // comparing two property descriptions
62 struct PropertyDescriptionHandleCompare : public ::std::binary_function< PropertyDescription, sal_Int32, bool >
64 bool operator() (const PropertyDescription& x, const sal_Int32& y) const
66 return x.aProperty.Handle < y;
68 bool operator() (const sal_Int32& x, const PropertyDescription& y) const
70 return x < y.aProperty.Handle;
73 // comparing two property descriptions (by name)
74 struct PropertyDescriptionNameMatch : public ::std::unary_function< PropertyDescription, bool >
76 ::rtl::OUString m_rCompare;
77 PropertyDescriptionNameMatch( const ::rtl::OUString& _rCompare ) : m_rCompare( _rCompare ) { }
79 bool operator() (const PropertyDescription& x ) const
81 return x.aProperty.Name.equals(m_rCompare);
86 //==========================================================================
87 //= OPropertyContainerHelper
88 //==========================================================================
89 //--------------------------------------------------------------------------
90 OPropertyContainerHelper::OPropertyContainerHelper()
91 :m_bUnused(sal_False)
95 // -------------------------------------------------------------------------
96 OPropertyContainerHelper::~OPropertyContainerHelper()
100 //--------------------------------------------------------------------------
101 void OPropertyContainerHelper::registerProperty(const ::rtl::OUString& _rName, sal_Int32 _nHandle,
102 sal_Int32 _nAttributes, void* _pPointerToMember, const Type& _rMemberType)
104 OSL_ENSURE((_nAttributes & PropertyAttribute::MAYBEVOID) == 0,
105 "OPropertyContainerHelper::registerProperty: don't use this for properties which may be void ! There is a method called \"registerMayBeVoidProperty\" for this !");
106 OSL_ENSURE(!_rMemberType.equals(::getCppuType(static_cast< Any* >(NULL))),
107 "OPropertyContainerHelper::registerProperty: don't give my the type of an uno::Any ! Really can't handle this !");
108 OSL_ENSURE(_pPointerToMember,
109 "OPropertyContainerHelper::registerProperty: you gave me nonsense : the pointer must be non-NULL");
111 PropertyDescription aNewProp;
112 aNewProp.aProperty = Property( _rName, _nHandle, _rMemberType, (sal_Int16)_nAttributes );
113 aNewProp.eLocated = PropertyDescription::ltDerivedClassRealType;
114 aNewProp.aLocation.pDerivedClassMember = _pPointerToMember;
116 implPushBackProperty(aNewProp);
119 //--------------------------------------------------------------------------
120 void OPropertyContainerHelper::revokeProperty( sal_Int32 _nHandle )
122 PropertiesIterator aPos = searchHandle( _nHandle );
123 if ( aPos == m_aProperties.end() )
124 throw UnknownPropertyException();
125 m_aProperties.erase( aPos );
128 //--------------------------------------------------------------------------
129 void OPropertyContainerHelper::registerMayBeVoidProperty(const ::rtl::OUString& _rName, sal_Int32 _nHandle, sal_Int32 _nAttributes,
130 Any* _pPointerToMember, const Type& _rExpectedType)
132 OSL_ENSURE((_nAttributes & PropertyAttribute::MAYBEVOID) != 0,
133 "OPropertyContainerHelper::registerMayBeVoidProperty: why calling this when the attributes say nothing about may-be-void ?");
134 OSL_ENSURE(!_rExpectedType.equals(::getCppuType(static_cast< Any* >(NULL))),
135 "OPropertyContainerHelper::registerMayBeVoidProperty: don't give my the type of an uno::Any ! Really can't handle this !");
136 OSL_ENSURE(_pPointerToMember,
137 "OPropertyContainerHelper::registerMayBeVoidProperty: you gave me nonsense : the pointer must be non-NULL");
139 _nAttributes |= PropertyAttribute::MAYBEVOID;
141 PropertyDescription aNewProp;
142 aNewProp.aProperty = Property( _rName, _nHandle, _rExpectedType, (sal_Int16)_nAttributes );
143 aNewProp.eLocated = PropertyDescription::ltDerivedClassAnyType;
144 aNewProp.aLocation.pDerivedClassMember = _pPointerToMember;
146 implPushBackProperty(aNewProp);
150 //--------------------------------------------------------------------------
151 void OPropertyContainerHelper::registerPropertyNoMember(const ::rtl::OUString& _rName, sal_Int32 _nHandle, sal_Int32 _nAttributes,
152 const Type& _rType, const void* _pInitialValue)
154 OSL_ENSURE(!_rType.equals(::getCppuType(static_cast< Any* >(NULL))),
155 "OPropertyContainerHelper::registerPropertyNoMember : don't give my the type of an uno::Any ! Really can't handle this !");
156 OSL_ENSURE(_pInitialValue || ((_nAttributes & PropertyAttribute::MAYBEVOID) != 0),
157 "OPropertyContainerHelper::registerPropertyNoMember : you should not ommit the initial value if the property can't be void ! This will definitivly crash later !");
159 PropertyDescription aNewProp;
160 aNewProp.aProperty = Property( _rName, _nHandle, _rType, (sal_Int16)_nAttributes );
161 aNewProp.eLocated = PropertyDescription::ltHoldMyself;
162 aNewProp.aLocation.nOwnClassVectorIndex = m_aHoldProperties.size();
163 if (_pInitialValue)
164 m_aHoldProperties.push_back(Any(_pInitialValue, _rType));
165 else
166 m_aHoldProperties.push_back(Any());
168 implPushBackProperty(aNewProp);
171 //--------------------------------------------------------------------------
172 sal_Bool OPropertyContainerHelper::isRegisteredProperty( sal_Int32 _nHandle ) const
174 return const_cast< OPropertyContainerHelper* >( this )->searchHandle( _nHandle ) != m_aProperties.end();
177 //--------------------------------------------------------------------------
178 sal_Bool OPropertyContainerHelper::isRegisteredProperty( const ::rtl::OUString& _rName ) const
180 // TODO: the current structure is from a time where properties were
181 // static, not dynamic. Since we allow that properties are also dynamic,
182 // i.e. registered and revoked even though the XPropertySet has already been
183 // accessed, a vector is not really the best data structure anymore ...
185 ConstPropertiesIterator pos = ::std::find_if(
186 m_aProperties.begin(),
187 m_aProperties.end(),
188 PropertyDescriptionNameMatch( _rName )
190 return pos != m_aProperties.end();
193 //--------------------------------------------------------------------------
194 namespace
196 struct ComparePropertyWithHandle
198 bool operator()( const PropertyDescription& _rLHS, sal_Int32 _nRHS ) const
200 return _rLHS.aProperty.Handle < _nRHS;
202 bool operator()( sal_Int32 _nLHS, const PropertyDescription& _rRHS ) const
204 return _nLHS < _rRHS.aProperty.Handle;
209 //--------------------------------------------------------------------------
210 void OPropertyContainerHelper::implPushBackProperty(const PropertyDescription& _rProp)
212 #ifdef DBG_UTIL
213 for ( PropertiesIterator checkConflicts = m_aProperties.begin();
214 checkConflicts != m_aProperties.end();
215 ++checkConflicts
218 OSL_ENSURE(checkConflicts->aProperty.Name != _rProp.aProperty.Name, "OPropertyContainerHelper::implPushBackProperty: name already exists!");
219 OSL_ENSURE(checkConflicts->aProperty.Handle != _rProp.aProperty.Handle, "OPropertyContainerHelper::implPushBackProperty: handle already exists!");
221 #endif
223 PropertiesIterator pos = ::std::lower_bound(
224 m_aProperties.begin(), m_aProperties.end(),
225 _rProp.aProperty.Handle, ComparePropertyWithHandle() );
227 m_aProperties.insert( pos, _rProp );
230 //--------------------------------------------------------------------------
231 namespace
233 void lcl_throwIllegalPropertyValueTypeException( const PropertyDescription& _rProperty, const Any& _rValue )
235 ::rtl::OUStringBuffer aErrorMessage;
236 aErrorMessage.appendAscii( "The given value cannot be converted to the required property type." );
237 aErrorMessage.appendAscii( "\n(property name \"" );
238 aErrorMessage.append( _rProperty.aProperty.Name );
239 aErrorMessage.appendAscii( "\", found value type \"" );
240 aErrorMessage.append( _rValue.getValueType().getTypeName() );
241 aErrorMessage.appendAscii( "\", required property type \"" );
242 aErrorMessage.append( _rProperty.aProperty.Type.getTypeName() );
243 aErrorMessage.appendAscii( "\")" );
244 throw IllegalArgumentException( aErrorMessage.makeStringAndClear(), NULL, 4 );
248 //--------------------------------------------------------------------------
249 sal_Bool OPropertyContainerHelper::convertFastPropertyValue(
250 Any& _rConvertedValue, Any& _rOldValue, sal_Int32 _nHandle, const Any& _rValue ) SAL_THROW( (IllegalArgumentException) )
252 sal_Bool bModified = sal_False;
254 // get the property somebody is asking for
255 PropertiesIterator aPos = searchHandle(_nHandle);
256 if (aPos == m_aProperties.end())
258 OSL_ENSURE( false, "OPropertyContainerHelper::convertFastPropertyValue: unknown handle!" );
259 // should not happen if the derived class has built a correct property set info helper to be used by
260 // our base class OPropertySetHelper
261 return bModified;
264 switch (aPos->eLocated)
266 // similar handling for the two cases where the value is stored in an any
267 case PropertyDescription::ltHoldMyself:
268 case PropertyDescription::ltDerivedClassAnyType:
270 sal_Bool bMayBeVoid = ((aPos->aProperty.Attributes & PropertyAttribute::MAYBEVOID) != 0);
273 // non modifiable version of the value-to-be-set
274 Any aNewRequestedValue( _rValue );
276 // normalization
277 // (#102329# - 2002-08-14 - fs@openoffice.org)
278 // (#i29490# - 2004-06-16 - fs@openoffice.org)
279 if ( !aNewRequestedValue.getValueType().equals( aPos->aProperty.Type ) )
280 { // the actually given value is not of the same type as the one required
281 Any aProperlyTyped( NULL, aPos->aProperty.Type.getTypeLibType() );
283 if ( uno_type_assignData(
284 const_cast< void* >( aProperlyTyped.getValue() ), aProperlyTyped.getValueType().getTypeLibType(),
285 const_cast< void* >( aNewRequestedValue.getValue() ), aNewRequestedValue.getValueType().getTypeLibType(),
286 reinterpret_cast< uno_QueryInterfaceFunc >( cpp_queryInterface ),
287 reinterpret_cast< uno_AcquireFunc >( cpp_acquire ),
288 reinterpret_cast< uno_ReleaseFunc >( cpp_release )
292 // we were able to query the given XInterface-derivee for the interface
293 // which is required for this property
294 aNewRequestedValue = aProperlyTyped;
298 // argument check
299 if ( ! ( (bMayBeVoid && !aNewRequestedValue.hasValue()) // void is allowed if the attribute says so
300 || (aNewRequestedValue.getValueType().equals(aPos->aProperty.Type)) // else the types have to be equal
304 lcl_throwIllegalPropertyValueTypeException( *aPos, _rValue );
307 Any* pPropContainer = NULL;
308 // the pointer to the any which holds the property value, no matter if located in the derived clas
309 // or in out vector
311 if (PropertyDescription::ltHoldMyself == aPos->eLocated)
313 OSL_ENSURE(aPos->aLocation.nOwnClassVectorIndex < (sal_Int32)m_aHoldProperties.size(),
314 "OPropertyContainerHelper::convertFastPropertyValue: invalid position !");
315 PropertyContainerIterator aIter = m_aHoldProperties.begin() + aPos->aLocation.nOwnClassVectorIndex;
316 pPropContainer = &(*aIter);
318 else
319 pPropContainer = reinterpret_cast<Any*>(aPos->aLocation.pDerivedClassMember);
321 // check if the new value differs from the current one
322 if (!pPropContainer->hasValue() || !aNewRequestedValue.hasValue())
323 bModified = pPropContainer->hasValue() != aNewRequestedValue.hasValue();
324 else
325 bModified = !uno_type_equalData(
326 const_cast< void* >( pPropContainer->getValue() ), aPos->aProperty.Type.getTypeLibType(),
327 const_cast< void* >( aNewRequestedValue.getValue() ), aPos->aProperty.Type.getTypeLibType(),
328 reinterpret_cast< uno_QueryInterfaceFunc >( cpp_queryInterface ),
329 reinterpret_cast< uno_ReleaseFunc >( cpp_release )
332 if (bModified)
334 _rOldValue = *pPropContainer;
335 _rConvertedValue = aNewRequestedValue;
338 break;
339 case PropertyDescription::ltDerivedClassRealType:
340 // let the UNO runtime library do any possible conversion
341 // this may include a change of the type - for instance, if a LONG is required,
342 // but a short is given, then this is valid, as it can be converted without any potential
343 // data loss
345 Any aProperlyTyped;
346 const Any* pNewValue = &_rValue;
348 if (!_rValue.getValueType().equals(aPos->aProperty.Type))
350 sal_Bool bConverted = sal_False;
352 // a temporary any of the correct (required) type
353 aProperlyTyped = Any( NULL, aPos->aProperty.Type.getTypeLibType() );
354 // (need this as we do not want to overwrite the derived class member here)
356 if ( uno_type_assignData(
357 const_cast<void*>(aProperlyTyped.getValue()), aProperlyTyped.getValueType().getTypeLibType(),
358 const_cast<void*>(_rValue.getValue()), _rValue.getValueType().getTypeLibType(),
359 reinterpret_cast< uno_QueryInterfaceFunc >( cpp_queryInterface ),
360 reinterpret_cast< uno_AcquireFunc >( cpp_acquire ),
361 reinterpret_cast< uno_ReleaseFunc >( cpp_release )
365 // could query for the requested interface
366 bConverted = sal_True;
367 pNewValue = &aProperlyTyped;
370 if ( !bConverted )
371 lcl_throwIllegalPropertyValueTypeException( *aPos, _rValue );
374 // from here on, we should have the proper type
375 OSL_ENSURE( pNewValue->getValueType() == aPos->aProperty.Type,
376 "OPropertyContainerHelper::convertFastPropertyValue: conversion failed!" );
377 bModified = !uno_type_equalData(
378 aPos->aLocation.pDerivedClassMember, aPos->aProperty.Type.getTypeLibType(),
379 const_cast<void*>(pNewValue->getValue()), aPos->aProperty.Type.getTypeLibType(),
380 reinterpret_cast< uno_QueryInterfaceFunc >( cpp_queryInterface ),
381 reinterpret_cast< uno_ReleaseFunc >( cpp_release )
384 if (bModified)
386 _rOldValue.setValue(aPos->aLocation.pDerivedClassMember, aPos->aProperty.Type);
387 _rConvertedValue = *pNewValue;
389 break;
392 return bModified;
395 //--------------------------------------------------------------------------
396 void OPropertyContainerHelper::setFastPropertyValue(sal_Int32 _nHandle, const Any& _rValue) SAL_THROW( (Exception) )
398 // get the property somebody is asking for
399 PropertiesIterator aPos = searchHandle(_nHandle);
400 if (aPos == m_aProperties.end())
402 OSL_ENSURE( false, "OPropertyContainerHelper::setFastPropertyValue: unknown handle!" );
403 // should not happen if the derived class has built a correct property set info helper to be used by
404 // our base class OPropertySetHelper
405 return;
408 switch (aPos->eLocated)
410 case PropertyDescription::ltHoldMyself:
411 m_aHoldProperties[aPos->aLocation.nOwnClassVectorIndex] = _rValue;
412 break;
414 case PropertyDescription::ltDerivedClassAnyType:
415 *reinterpret_cast< Any* >(aPos->aLocation.pDerivedClassMember) = _rValue;
416 break;
418 case PropertyDescription::ltDerivedClassRealType:
419 #if OSL_DEBUG_LEVEL > 0
420 sal_Bool bSuccess =
421 #endif
422 // copy the data from the to-be-set value
423 uno_type_assignData(
424 aPos->aLocation.pDerivedClassMember, aPos->aProperty.Type.getTypeLibType(),
425 const_cast< void* >( _rValue.getValue() ), _rValue.getValueType().getTypeLibType(),
426 reinterpret_cast< uno_QueryInterfaceFunc >( cpp_queryInterface ),
427 reinterpret_cast< uno_AcquireFunc >( cpp_acquire ),
428 reinterpret_cast< uno_ReleaseFunc >( cpp_release ) );
430 OSL_ENSURE( bSuccess,
431 "OPropertyContainerHelper::setFastPropertyValue: ooops .... the value could not be assigned!");
433 break;
437 //--------------------------------------------------------------------------
438 void OPropertyContainerHelper::getFastPropertyValue(Any& _rValue, sal_Int32 _nHandle) const
440 // get the property somebody is asking for
441 PropertiesIterator aPos = const_cast<OPropertyContainerHelper*>(this)->searchHandle(_nHandle);
442 if (aPos == m_aProperties.end())
444 OSL_ENSURE( false, "OPropertyContainerHelper::getFastPropertyValue: unknown handle!" );
445 // should not happen if the derived class has built a correct property set info helper to be used by
446 // our base class OPropertySetHelper
447 return;
450 switch (aPos->eLocated)
452 case PropertyDescription::ltHoldMyself:
453 OSL_ENSURE(aPos->aLocation.nOwnClassVectorIndex < (sal_Int32)m_aHoldProperties.size(),
454 "OPropertyContainerHelper::convertFastPropertyValue: invalid position !");
455 _rValue = m_aHoldProperties[aPos->aLocation.nOwnClassVectorIndex];
456 break;
457 case PropertyDescription::ltDerivedClassAnyType:
458 _rValue = *reinterpret_cast<Any*>(aPos->aLocation.pDerivedClassMember);
459 break;
460 case PropertyDescription::ltDerivedClassRealType:
461 _rValue.setValue(aPos->aLocation.pDerivedClassMember, aPos->aProperty.Type);
462 break;
466 //--------------------------------------------------------------------------
467 OPropertyContainerHelper::PropertiesIterator OPropertyContainerHelper::searchHandle(sal_Int32 _nHandle)
469 // search a lower bound
470 PropertiesIterator aLowerBound = ::std::lower_bound(
471 m_aProperties.begin(),
472 m_aProperties.end(),
473 _nHandle,
474 PropertyDescriptionHandleCompare());
476 // check for identity
477 if ((aLowerBound != m_aProperties.end()) && aLowerBound->aProperty.Handle != _nHandle)
478 aLowerBound = m_aProperties.end();
480 return aLowerBound;
483 //--------------------------------------------------------------------------
484 const Property& OPropertyContainerHelper::getProperty( const ::rtl::OUString& _rName ) const
486 ConstPropertiesIterator pos = ::std::find_if(
487 m_aProperties.begin(),
488 m_aProperties.end(),
489 PropertyDescriptionNameMatch( _rName )
491 if ( pos == m_aProperties.end() )
492 throw UnknownPropertyException( _rName, NULL );
494 return pos->aProperty;
497 //--------------------------------------------------------------------------
498 void OPropertyContainerHelper::modifyAttributes(sal_Int32 _nHandle, sal_Int32 _nAddAttrib, sal_Int32 _nRemoveAttrib)
500 // get the property somebody is asking for
501 PropertiesIterator aPos = searchHandle(_nHandle);
502 if (aPos == m_aProperties.end())
504 OSL_ENSURE( false, "OPropertyContainerHelper::modifyAttributes: unknown handle!" );
505 // should not happen if the derived class has built a correct property set info helper to be used by
506 // our base class OPropertySetHelper
507 return;
509 aPos->aProperty.Handle |= _nAddAttrib;
510 aPos->aProperty.Handle &= ~_nRemoveAttrib;
513 //--------------------------------------------------------------------------
514 void OPropertyContainerHelper::describeProperties(Sequence< Property >& _rProps) const
516 Sequence< Property > aOwnProps(m_aProperties.size());
517 Property* pOwnProps = aOwnProps.getArray();
519 for ( ConstPropertiesIterator aLoop = m_aProperties.begin();
520 aLoop != m_aProperties.end();
521 ++aLoop, ++pOwnProps
524 pOwnProps->Name = aLoop->aProperty.Name;
525 pOwnProps->Handle = aLoop->aProperty.Handle;
526 pOwnProps->Attributes = (sal_Int16)aLoop->aProperty.Attributes;
527 pOwnProps->Type = aLoop->aProperty.Type;
530 // as our property vector is sorted by handles, not by name, we have to sort aOwnProps
531 ::std::sort(aOwnProps.getArray(), aOwnProps.getArray() + aOwnProps.getLength(), PropertyCompareByName());
533 // unfortunally the STL merge function does not allow the output range to overlap one of the input ranges,
534 // so we need an extra sequence
535 Sequence< Property > aOutput;
536 aOutput.realloc(_rProps.getLength() + aOwnProps.getLength());
537 // do the merge
538 ::std::merge( _rProps.getConstArray(), _rProps.getConstArray() + _rProps.getLength(), // input 1
539 aOwnProps.getConstArray(), aOwnProps.getConstArray() + aOwnProps.getLength(), // input 2
540 aOutput.getArray(), // output
541 PropertyCompareByName() // compare operator
544 // copy the output
545 _rProps = aOutput;
548 //.........................................................................
549 } // namespace comphelper
550 //.........................................................................