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>
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>
41 //.........................................................................
44 //.........................................................................
46 using namespace ::com::sun::star::uno
;
47 using namespace ::com::sun::star::lang
;
48 using namespace ::com::sun::star::beans
;
50 //--------------------------------------------------------------------------
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()
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();
164 m_aHoldProperties
.push_back(Any(_pInitialValue
, _rType
));
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(),
188 PropertyDescriptionNameMatch( _rName
)
190 return pos
!= m_aProperties
.end();
193 //--------------------------------------------------------------------------
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
)
213 for ( PropertiesIterator checkConflicts
= m_aProperties
.begin();
214 checkConflicts
!= m_aProperties
.end();
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!");
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 //--------------------------------------------------------------------------
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
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
);
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
;
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
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
);
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();
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
)
334 _rOldValue
= *pPropContainer
;
335 _rConvertedValue
= aNewRequestedValue
;
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
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
;
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
)
386 _rOldValue
.setValue(aPos
->aLocation
.pDerivedClassMember
, aPos
->aProperty
.Type
);
387 _rConvertedValue
= *pNewValue
;
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
408 switch (aPos
->eLocated
)
410 case PropertyDescription::ltHoldMyself
:
411 m_aHoldProperties
[aPos
->aLocation
.nOwnClassVectorIndex
] = _rValue
;
414 case PropertyDescription::ltDerivedClassAnyType
:
415 *reinterpret_cast< Any
* >(aPos
->aLocation
.pDerivedClassMember
) = _rValue
;
418 case PropertyDescription::ltDerivedClassRealType
:
419 #if OSL_DEBUG_LEVEL > 0
422 // copy the data from the to-be-set value
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!");
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
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
];
457 case PropertyDescription::ltDerivedClassAnyType
:
458 _rValue
= *reinterpret_cast<Any
*>(aPos
->aLocation
.pDerivedClassMember
);
460 case PropertyDescription::ltDerivedClassRealType
:
461 _rValue
.setValue(aPos
->aLocation
.pDerivedClassMember
, aPos
->aProperty
.Type
);
466 //--------------------------------------------------------------------------
467 OPropertyContainerHelper::PropertiesIterator
OPropertyContainerHelper::searchHandle(sal_Int32 _nHandle
)
469 // search a lower bound
470 PropertiesIterator aLowerBound
= ::std::lower_bound(
471 m_aProperties
.begin(),
474 PropertyDescriptionHandleCompare());
476 // check for identity
477 if ((aLowerBound
!= m_aProperties
.end()) && aLowerBound
->aProperty
.Handle
!= _nHandle
)
478 aLowerBound
= m_aProperties
.end();
483 //--------------------------------------------------------------------------
484 const Property
& OPropertyContainerHelper::getProperty( const ::rtl::OUString
& _rName
) const
486 ConstPropertiesIterator pos
= ::std::find_if(
487 m_aProperties
.begin(),
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
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();
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());
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
548 //.........................................................................
549 } // namespace comphelper
550 //.........................................................................