Updated core
[LibreOffice.git] / comphelper / source / property / propertycontainerhelper.cxx
blob6715567276d053aee51b19306d0213fa32d395d8
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
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/.
9 * This file incorporates work covered by the following license notice:
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 .
20 #include <comphelper/propertycontainerhelper.hxx>
21 #include <comphelper/property.hxx>
22 #include <osl/diagnose.h>
23 #include <uno/data.h>
24 #include <com/sun/star/uno/genfunc.h>
25 #include <com/sun/star/beans/PropertyAttribute.hpp>
26 #include <com/sun/star/beans/UnknownPropertyException.hpp>
27 #include <rtl/ustrbuf.hxx>
29 #include <algorithm>
31 //.........................................................................
32 namespace comphelper
34 //.........................................................................
36 using namespace ::com::sun::star::uno;
37 using namespace ::com::sun::star::lang;
38 using namespace ::com::sun::star::beans;
40 //--------------------------------------------------------------------------
41 namespace
43 // comparing two property descriptions
44 struct PropertyDescriptionCompareByHandle : public ::std::binary_function< PropertyDescription, PropertyDescription, bool >
46 bool operator() (const PropertyDescription& x, const PropertyDescription& y) const
48 return x.aProperty.Handle < y.aProperty.Handle;
51 // comparing two property descriptions
52 struct PropertyDescriptionHandleCompare : public ::std::binary_function< PropertyDescription, PropertyDescription, bool >
54 bool operator() (const PropertyDescription& x, const PropertyDescription& y) const
56 return x.aProperty.Handle < y.aProperty.Handle;
59 // comparing two property descriptions (by name)
60 struct PropertyDescriptionNameMatch : public ::std::unary_function< PropertyDescription, bool >
62 OUString m_rCompare;
63 PropertyDescriptionNameMatch( const OUString& _rCompare ) : m_rCompare( _rCompare ) { }
65 bool operator() (const PropertyDescription& x ) const
67 return x.aProperty.Name.equals(m_rCompare);
72 //==========================================================================
73 //= OPropertyContainerHelper
74 //==========================================================================
75 //--------------------------------------------------------------------------
76 OPropertyContainerHelper::OPropertyContainerHelper()
77 :m_bUnused(sal_False)
81 // -------------------------------------------------------------------------
82 OPropertyContainerHelper::~OPropertyContainerHelper()
86 //--------------------------------------------------------------------------
87 void OPropertyContainerHelper::registerProperty(const OUString& _rName, sal_Int32 _nHandle,
88 sal_Int32 _nAttributes, void* _pPointerToMember, const Type& _rMemberType)
90 OSL_ENSURE((_nAttributes & PropertyAttribute::MAYBEVOID) == 0,
91 "OPropertyContainerHelper::registerProperty: don't use this for properties which may be void ! There is a method called \"registerMayBeVoidProperty\" for this !");
92 OSL_ENSURE(!_rMemberType.equals(::getCppuType(static_cast< Any* >(NULL))),
93 "OPropertyContainerHelper::registerProperty: don't give my the type of an uno::Any ! Really can't handle this !");
94 OSL_ENSURE(_pPointerToMember,
95 "OPropertyContainerHelper::registerProperty: you gave me nonsense : the pointer must be non-NULL");
97 PropertyDescription aNewProp;
98 aNewProp.aProperty = Property( _rName, _nHandle, _rMemberType, (sal_Int16)_nAttributes );
99 aNewProp.eLocated = PropertyDescription::ltDerivedClassRealType;
100 aNewProp.aLocation.pDerivedClassMember = _pPointerToMember;
102 implPushBackProperty(aNewProp);
105 //--------------------------------------------------------------------------
106 void OPropertyContainerHelper::revokeProperty( sal_Int32 _nHandle )
108 PropertiesIterator aPos = searchHandle( _nHandle );
109 if ( aPos == m_aProperties.end() )
110 throw UnknownPropertyException();
111 m_aProperties.erase( aPos );
114 //--------------------------------------------------------------------------
115 void OPropertyContainerHelper::registerMayBeVoidProperty(const OUString& _rName, sal_Int32 _nHandle, sal_Int32 _nAttributes,
116 Any* _pPointerToMember, const Type& _rExpectedType)
118 OSL_ENSURE((_nAttributes & PropertyAttribute::MAYBEVOID) != 0,
119 "OPropertyContainerHelper::registerMayBeVoidProperty: why calling this when the attributes say nothing about may-be-void ?");
120 OSL_ENSURE(!_rExpectedType.equals(::getCppuType(static_cast< Any* >(NULL))),
121 "OPropertyContainerHelper::registerMayBeVoidProperty: don't give my the type of an uno::Any ! Really can't handle this !");
122 OSL_ENSURE(_pPointerToMember,
123 "OPropertyContainerHelper::registerMayBeVoidProperty: you gave me nonsense : the pointer must be non-NULL");
125 _nAttributes |= PropertyAttribute::MAYBEVOID;
127 PropertyDescription aNewProp;
128 aNewProp.aProperty = Property( _rName, _nHandle, _rExpectedType, (sal_Int16)_nAttributes );
129 aNewProp.eLocated = PropertyDescription::ltDerivedClassAnyType;
130 aNewProp.aLocation.pDerivedClassMember = _pPointerToMember;
132 implPushBackProperty(aNewProp);
136 //--------------------------------------------------------------------------
137 void OPropertyContainerHelper::registerPropertyNoMember(const OUString& _rName, sal_Int32 _nHandle, sal_Int32 _nAttributes,
138 const Type& _rType, const void* _pInitialValue)
140 OSL_ENSURE(!_rType.equals(::getCppuType(static_cast< Any* >(NULL))),
141 "OPropertyContainerHelper::registerPropertyNoMember : don't give my the type of an uno::Any ! Really can't handle this !");
142 OSL_ENSURE(_pInitialValue || ((_nAttributes & PropertyAttribute::MAYBEVOID) != 0),
143 "OPropertyContainerHelper::registerPropertyNoMember : you should not ommit the initial value if the property can't be void ! This will definitivly crash later !");
145 PropertyDescription aNewProp;
146 aNewProp.aProperty = Property( _rName, _nHandle, _rType, (sal_Int16)_nAttributes );
147 aNewProp.eLocated = PropertyDescription::ltHoldMyself;
148 aNewProp.aLocation.nOwnClassVectorIndex = m_aHoldProperties.size();
149 if (_pInitialValue)
150 m_aHoldProperties.push_back(Any(_pInitialValue, _rType));
151 else
152 m_aHoldProperties.push_back(Any());
154 implPushBackProperty(aNewProp);
157 //--------------------------------------------------------------------------
158 sal_Bool OPropertyContainerHelper::isRegisteredProperty( sal_Int32 _nHandle ) const
160 return const_cast< OPropertyContainerHelper* >( this )->searchHandle( _nHandle ) != m_aProperties.end();
163 //--------------------------------------------------------------------------
164 sal_Bool OPropertyContainerHelper::isRegisteredProperty( const OUString& _rName ) const
166 // TODO: the current structure is from a time where properties were
167 // static, not dynamic. Since we allow that properties are also dynamic,
168 // i.e. registered and revoked even though the XPropertySet has already been
169 // accessed, a vector is not really the best data structure anymore ...
171 ConstPropertiesIterator pos = ::std::find_if(
172 m_aProperties.begin(),
173 m_aProperties.end(),
174 PropertyDescriptionNameMatch( _rName )
176 return pos != m_aProperties.end();
179 //--------------------------------------------------------------------------
180 namespace
182 struct ComparePropertyHandles
184 bool operator()( const PropertyDescription& _rLHS, const PropertyDescription& _nRHS ) const
186 return _rLHS.aProperty.Handle < _nRHS.aProperty.Handle;
191 //--------------------------------------------------------------------------
192 void OPropertyContainerHelper::implPushBackProperty(const PropertyDescription& _rProp)
194 #ifdef DBG_UTIL
195 for ( PropertiesIterator checkConflicts = m_aProperties.begin();
196 checkConflicts != m_aProperties.end();
197 ++checkConflicts
200 OSL_ENSURE(checkConflicts->aProperty.Name != _rProp.aProperty.Name, "OPropertyContainerHelper::implPushBackProperty: name already exists!");
201 OSL_ENSURE(checkConflicts->aProperty.Handle != _rProp.aProperty.Handle, "OPropertyContainerHelper::implPushBackProperty: handle already exists!");
203 #endif
205 PropertiesIterator pos = ::std::lower_bound(
206 m_aProperties.begin(), m_aProperties.end(),
207 _rProp, ComparePropertyHandles() );
209 m_aProperties.insert( pos, _rProp );
212 //--------------------------------------------------------------------------
213 namespace
215 void lcl_throwIllegalPropertyValueTypeException( const PropertyDescription& _rProperty, const Any& _rValue )
217 OUStringBuffer aErrorMessage;
218 aErrorMessage.appendAscii( "The given value cannot be converted to the required property type." );
219 aErrorMessage.appendAscii( "\n(property name \"" );
220 aErrorMessage.append( _rProperty.aProperty.Name );
221 aErrorMessage.appendAscii( "\", found value type \"" );
222 aErrorMessage.append( _rValue.getValueType().getTypeName() );
223 aErrorMessage.appendAscii( "\", required property type \"" );
224 aErrorMessage.append( _rProperty.aProperty.Type.getTypeName() );
225 aErrorMessage.appendAscii( "\")" );
226 throw IllegalArgumentException( aErrorMessage.makeStringAndClear(), NULL, 4 );
230 //--------------------------------------------------------------------------
231 sal_Bool OPropertyContainerHelper::convertFastPropertyValue(
232 Any& _rConvertedValue, Any& _rOldValue, sal_Int32 _nHandle, const Any& _rValue ) SAL_THROW( (IllegalArgumentException) )
234 sal_Bool bModified = sal_False;
236 // get the property somebody is asking for
237 PropertiesIterator aPos = searchHandle(_nHandle);
238 if (aPos == m_aProperties.end())
240 OSL_FAIL( "OPropertyContainerHelper::convertFastPropertyValue: unknown handle!" );
241 // should not happen if the derived class has built a correct property set info helper to be used by
242 // our base class OPropertySetHelper
243 return bModified;
246 switch (aPos->eLocated)
248 // similar handling for the two cases where the value is stored in an any
249 case PropertyDescription::ltHoldMyself:
250 case PropertyDescription::ltDerivedClassAnyType:
252 sal_Bool bMayBeVoid = ((aPos->aProperty.Attributes & PropertyAttribute::MAYBEVOID) != 0);
255 // non modifiable version of the value-to-be-set
256 Any aNewRequestedValue( _rValue );
258 // normalization
259 // #i29490#
260 if ( !aNewRequestedValue.getValueType().equals( aPos->aProperty.Type ) )
261 { // the actually given value is not of the same type as the one required
262 Any aProperlyTyped( NULL, aPos->aProperty.Type.getTypeLibType() );
264 if ( uno_type_assignData(
265 const_cast< void* >( aProperlyTyped.getValue() ), aProperlyTyped.getValueType().getTypeLibType(),
266 const_cast< void* >( aNewRequestedValue.getValue() ), aNewRequestedValue.getValueType().getTypeLibType(),
267 reinterpret_cast< uno_QueryInterfaceFunc >( cpp_queryInterface ),
268 reinterpret_cast< uno_AcquireFunc >( cpp_acquire ),
269 reinterpret_cast< uno_ReleaseFunc >( cpp_release )
273 // we were able to query the given XInterface-derivee for the interface
274 // which is required for this property
275 aNewRequestedValue = aProperlyTyped;
279 // argument check
280 if ( ! ( (bMayBeVoid && !aNewRequestedValue.hasValue()) // void is allowed if the attribute says so
281 || (aNewRequestedValue.getValueType().equals(aPos->aProperty.Type)) // else the types have to be equal
285 lcl_throwIllegalPropertyValueTypeException( *aPos, _rValue );
288 Any* pPropContainer = NULL;
289 // the pointer to the any which holds the property value, no matter if located in the derived clas
290 // or in out vector
292 if (PropertyDescription::ltHoldMyself == aPos->eLocated)
294 OSL_ENSURE(aPos->aLocation.nOwnClassVectorIndex < (sal_Int32)m_aHoldProperties.size(),
295 "OPropertyContainerHelper::convertFastPropertyValue: invalid position !");
296 PropertyContainerIterator aIter = m_aHoldProperties.begin() + aPos->aLocation.nOwnClassVectorIndex;
297 pPropContainer = &(*aIter);
299 else
300 pPropContainer = reinterpret_cast<Any*>(aPos->aLocation.pDerivedClassMember);
302 // check if the new value differs from the current one
303 if (!pPropContainer->hasValue() || !aNewRequestedValue.hasValue())
304 bModified = pPropContainer->hasValue() != aNewRequestedValue.hasValue();
305 else
306 bModified = !uno_type_equalData(
307 const_cast< void* >( pPropContainer->getValue() ), aPos->aProperty.Type.getTypeLibType(),
308 const_cast< void* >( aNewRequestedValue.getValue() ), aPos->aProperty.Type.getTypeLibType(),
309 reinterpret_cast< uno_QueryInterfaceFunc >( cpp_queryInterface ),
310 reinterpret_cast< uno_ReleaseFunc >( cpp_release )
313 if (bModified)
315 _rOldValue = *pPropContainer;
316 _rConvertedValue = aNewRequestedValue;
319 break;
320 case PropertyDescription::ltDerivedClassRealType:
321 // let the UNO runtime library do any possible conversion
322 // this may include a change of the type - for instance, if a LONG is required,
323 // but a short is given, then this is valid, as it can be converted without any potential
324 // data loss
326 Any aProperlyTyped;
327 const Any* pNewValue = &_rValue;
329 if (!_rValue.getValueType().equals(aPos->aProperty.Type))
331 sal_Bool bConverted = sal_False;
333 // a temporary any of the correct (required) type
334 aProperlyTyped = Any( NULL, aPos->aProperty.Type.getTypeLibType() );
335 // (need this as we do not want to overwrite the derived class member here)
337 if ( uno_type_assignData(
338 const_cast<void*>(aProperlyTyped.getValue()), aProperlyTyped.getValueType().getTypeLibType(),
339 const_cast<void*>(_rValue.getValue()), _rValue.getValueType().getTypeLibType(),
340 reinterpret_cast< uno_QueryInterfaceFunc >( cpp_queryInterface ),
341 reinterpret_cast< uno_AcquireFunc >( cpp_acquire ),
342 reinterpret_cast< uno_ReleaseFunc >( cpp_release )
346 // could query for the requested interface
347 bConverted = sal_True;
348 pNewValue = &aProperlyTyped;
351 if ( !bConverted )
352 lcl_throwIllegalPropertyValueTypeException( *aPos, _rValue );
355 // from here on, we should have the proper type
356 OSL_ENSURE( pNewValue->getValueType() == aPos->aProperty.Type,
357 "OPropertyContainerHelper::convertFastPropertyValue: conversion failed!" );
358 bModified = !uno_type_equalData(
359 aPos->aLocation.pDerivedClassMember, aPos->aProperty.Type.getTypeLibType(),
360 const_cast<void*>(pNewValue->getValue()), aPos->aProperty.Type.getTypeLibType(),
361 reinterpret_cast< uno_QueryInterfaceFunc >( cpp_queryInterface ),
362 reinterpret_cast< uno_ReleaseFunc >( cpp_release )
365 if (bModified)
367 _rOldValue.setValue(aPos->aLocation.pDerivedClassMember, aPos->aProperty.Type);
368 _rConvertedValue = *pNewValue;
370 break;
373 return bModified;
376 //--------------------------------------------------------------------------
377 void OPropertyContainerHelper::setFastPropertyValue(sal_Int32 _nHandle, const Any& _rValue) SAL_THROW( (Exception) )
379 // get the property somebody is asking for
380 PropertiesIterator aPos = searchHandle(_nHandle);
381 if (aPos == m_aProperties.end())
383 OSL_FAIL( "OPropertyContainerHelper::setFastPropertyValue: unknown handle!" );
384 // should not happen if the derived class has built a correct property set info helper to be used by
385 // our base class OPropertySetHelper
386 return;
389 switch (aPos->eLocated)
391 case PropertyDescription::ltHoldMyself:
392 m_aHoldProperties[aPos->aLocation.nOwnClassVectorIndex] = _rValue;
393 break;
395 case PropertyDescription::ltDerivedClassAnyType:
396 *reinterpret_cast< Any* >(aPos->aLocation.pDerivedClassMember) = _rValue;
397 break;
399 case PropertyDescription::ltDerivedClassRealType:
400 #if OSL_DEBUG_LEVEL > 0
401 sal_Bool bSuccess =
402 #endif
403 // copy the data from the to-be-set value
404 uno_type_assignData(
405 aPos->aLocation.pDerivedClassMember, aPos->aProperty.Type.getTypeLibType(),
406 const_cast< void* >( _rValue.getValue() ), _rValue.getValueType().getTypeLibType(),
407 reinterpret_cast< uno_QueryInterfaceFunc >( cpp_queryInterface ),
408 reinterpret_cast< uno_AcquireFunc >( cpp_acquire ),
409 reinterpret_cast< uno_ReleaseFunc >( cpp_release ) );
411 OSL_ENSURE( bSuccess,
412 "OPropertyContainerHelper::setFastPropertyValue: ooops .... the value could not be assigned!");
414 break;
418 //--------------------------------------------------------------------------
419 void OPropertyContainerHelper::getFastPropertyValue(Any& _rValue, sal_Int32 _nHandle) const
421 // get the property somebody is asking for
422 PropertiesIterator aPos = const_cast<OPropertyContainerHelper*>(this)->searchHandle(_nHandle);
423 if (aPos == m_aProperties.end())
425 OSL_FAIL( "OPropertyContainerHelper::getFastPropertyValue: unknown handle!" );
426 // should not happen if the derived class has built a correct property set info helper to be used by
427 // our base class OPropertySetHelper
428 return;
431 switch (aPos->eLocated)
433 case PropertyDescription::ltHoldMyself:
434 OSL_ENSURE(aPos->aLocation.nOwnClassVectorIndex < (sal_Int32)m_aHoldProperties.size(),
435 "OPropertyContainerHelper::convertFastPropertyValue: invalid position !");
436 _rValue = m_aHoldProperties[aPos->aLocation.nOwnClassVectorIndex];
437 break;
438 case PropertyDescription::ltDerivedClassAnyType:
439 _rValue = *reinterpret_cast<Any*>(aPos->aLocation.pDerivedClassMember);
440 break;
441 case PropertyDescription::ltDerivedClassRealType:
442 _rValue.setValue(aPos->aLocation.pDerivedClassMember, aPos->aProperty.Type);
443 break;
447 //--------------------------------------------------------------------------
448 OPropertyContainerHelper::PropertiesIterator OPropertyContainerHelper::searchHandle(sal_Int32 _nHandle)
450 PropertyDescription aHandlePropDesc;
451 aHandlePropDesc.aProperty.Handle = _nHandle;
452 // search a lower bound
453 PropertiesIterator aLowerBound = ::std::lower_bound(
454 m_aProperties.begin(),
455 m_aProperties.end(),
456 aHandlePropDesc,
457 PropertyDescriptionHandleCompare());
459 // check for identity
460 if ((aLowerBound != m_aProperties.end()) && aLowerBound->aProperty.Handle != _nHandle)
461 aLowerBound = m_aProperties.end();
463 return aLowerBound;
466 //--------------------------------------------------------------------------
467 const Property& OPropertyContainerHelper::getProperty( const OUString& _rName ) const
469 ConstPropertiesIterator pos = ::std::find_if(
470 m_aProperties.begin(),
471 m_aProperties.end(),
472 PropertyDescriptionNameMatch( _rName )
474 if ( pos == m_aProperties.end() )
475 throw UnknownPropertyException( _rName, NULL );
477 return pos->aProperty;
480 //--------------------------------------------------------------------------
481 void OPropertyContainerHelper::describeProperties(Sequence< Property >& _rProps) const
483 Sequence< Property > aOwnProps(m_aProperties.size());
484 Property* pOwnProps = aOwnProps.getArray();
486 for ( ConstPropertiesIterator aLoop = m_aProperties.begin();
487 aLoop != m_aProperties.end();
488 ++aLoop, ++pOwnProps
491 pOwnProps->Name = aLoop->aProperty.Name;
492 pOwnProps->Handle = aLoop->aProperty.Handle;
493 pOwnProps->Attributes = (sal_Int16)aLoop->aProperty.Attributes;
494 pOwnProps->Type = aLoop->aProperty.Type;
497 // as our property vector is sorted by handles, not by name, we have to sort aOwnProps
498 ::std::sort(aOwnProps.getArray(), aOwnProps.getArray() + aOwnProps.getLength(), PropertyCompareByName());
500 // unfortunally the STL merge function does not allow the output range to overlap one of the input ranges,
501 // so we need an extra sequence
502 Sequence< Property > aOutput;
503 aOutput.realloc(_rProps.getLength() + aOwnProps.getLength());
504 // do the merge
505 ::std::merge( _rProps.getConstArray(), _rProps.getConstArray() + _rProps.getLength(), // input 1
506 aOwnProps.getConstArray(), aOwnProps.getConstArray() + aOwnProps.getLength(), // input 2
507 aOutput.getArray(), // output
508 PropertyCompareByName() // compare operator
511 // copy the output
512 _rProps = aOutput;
515 //.........................................................................
516 } // namespace comphelper
517 //.........................................................................
520 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */