6f50961e69
which seem to have snuck back in since the great rounds of removals. Change-Id: I85f7f5f4801c0b48dae8b50f51f83595b286d6a1 Reviewed-on: https://gerrit.libreoffice.org/62229 Tested-by: Jenkins Reviewed-by: Noel Grandin <noel.grandin@collabora.co.uk>
2476 lines
94 KiB
C++
2476 lines
94 KiB
C++
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
|
|
/*
|
|
* This file is part of the LibreOffice project.
|
|
*
|
|
* This Source Code Form is subject to the terms of the Mozilla Public
|
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
|
*
|
|
* This file incorporates work covered by the following license notice:
|
|
*
|
|
* Licensed to the Apache Software Foundation (ASF) under one or more
|
|
* contributor license agreements. See the NOTICE file distributed
|
|
* with this work for additional information regarding copyright
|
|
* ownership. The ASF licenses this file to you under the Apache
|
|
* License, Version 2.0 (the "License"); you may not use this file
|
|
* except in compliance with the License. You may obtain a copy of
|
|
* the License at http://www.apache.org/licenses/LICENSE-2.0 .
|
|
*/
|
|
|
|
#include <sal/config.h>
|
|
|
|
#include <cassert>
|
|
#include <cstddef>
|
|
#include <limits>
|
|
#include <map>
|
|
#include <memory>
|
|
#include <set>
|
|
|
|
#include <o3tl/any.hxx>
|
|
#include <osl/diagnose.h>
|
|
#include <osl/mutex.hxx>
|
|
#include <osl/thread.h>
|
|
#include <sal/log.hxx>
|
|
#include <cppuhelper/basemutex.hxx>
|
|
#include <cppuhelper/compbase.hxx>
|
|
#include <cppuhelper/queryinterface.hxx>
|
|
#include <cppuhelper/weak.hxx>
|
|
#include <cppuhelper/component.hxx>
|
|
#include <cppuhelper/factory.hxx>
|
|
#include <cppuhelper/implbase.hxx>
|
|
#include <cppuhelper/supportsservice.hxx>
|
|
#include <cppuhelper/typeprovider.hxx>
|
|
#include <comphelper/sequence.hxx>
|
|
#include <salhelper/simplereferenceobject.hxx>
|
|
|
|
#include <com/sun/star/uno/DeploymentException.hpp>
|
|
#include <com/sun/star/lang/NoSuchMethodException.hpp>
|
|
#include <com/sun/star/lang/XSingleServiceFactory.hpp>
|
|
#include <com/sun/star/lang/XServiceInfo.hpp>
|
|
#include <com/sun/star/lang/XEventListener.hpp>
|
|
#include <com/sun/star/lang/XUnoTunnel.hpp>
|
|
#include <com/sun/star/reflection/XIdlReflection.hpp>
|
|
#include <com/sun/star/reflection/XIdlClass.hpp>
|
|
#include <com/sun/star/reflection/XIdlField2.hpp>
|
|
#include <com/sun/star/reflection/theCoreReflection.hpp>
|
|
#include <com/sun/star/beans/UnknownPropertyException.hpp>
|
|
#include <com/sun/star/beans/Property.hpp>
|
|
#include <com/sun/star/beans/XPropertySet.hpp>
|
|
#include <com/sun/star/beans/XFastPropertySet.hpp>
|
|
#include <com/sun/star/beans/XIntrospection.hpp>
|
|
#include <com/sun/star/beans/XIntrospectionAccess.hpp>
|
|
#include <com/sun/star/beans/XMaterialHolder.hpp>
|
|
#include <com/sun/star/beans/XExactName.hpp>
|
|
#include <com/sun/star/beans/PropertyAttribute.hpp>
|
|
#include <com/sun/star/beans/PropertyConcept.hpp>
|
|
#include <com/sun/star/beans/MethodConcept.hpp>
|
|
#include <com/sun/star/container/XNameContainer.hpp>
|
|
#include <com/sun/star/container/XIndexContainer.hpp>
|
|
#include <com/sun/star/container/XEnumerationAccess.hpp>
|
|
|
|
#include <rtl/ref.hxx>
|
|
#include <rtl/ustrbuf.hxx>
|
|
#include <rtl/strbuf.hxx>
|
|
#include <unordered_map>
|
|
|
|
using namespace css::uno;
|
|
using namespace css::lang;
|
|
using namespace css::reflection;
|
|
using namespace css::container;
|
|
using namespace css::registry;
|
|
using namespace css::beans;
|
|
using namespace css::beans::PropertyAttribute;
|
|
using namespace css::beans::PropertyConcept;
|
|
using namespace css::beans::MethodConcept;
|
|
using namespace cppu;
|
|
using namespace osl;
|
|
|
|
namespace
|
|
{
|
|
|
|
typedef WeakImplHelper< XIntrospectionAccess, XMaterialHolder, XExactName,
|
|
XPropertySet, XFastPropertySet, XPropertySetInfo,
|
|
XNameContainer, XIndexContainer, XEnumerationAccess,
|
|
XIdlArray, XUnoTunnel > IntrospectionAccessHelper;
|
|
|
|
|
|
// Special value for Method-Concept, to be able to mark "normal" functions
|
|
#define MethodConcept_NORMAL_IMPL 0x80000000
|
|
|
|
|
|
// Method to assert, if a class is derived from another class
|
|
bool isDerivedFrom( const Reference<XIdlClass>& xToTestClass, const Reference<XIdlClass>& xDerivedFromClass )
|
|
{
|
|
Sequence< Reference<XIdlClass> > aClassesSeq = xToTestClass->getSuperclasses();
|
|
const Reference<XIdlClass>* pClassesArray = aClassesSeq.getConstArray();
|
|
|
|
sal_Int32 nSuperClassCount = aClassesSeq.getLength();
|
|
for ( sal_Int32 i = 0; i < nSuperClassCount; ++i )
|
|
{
|
|
const Reference<XIdlClass>& rxClass = pClassesArray[i];
|
|
|
|
if ( xDerivedFromClass->equals( rxClass ) ||
|
|
isDerivedFrom( rxClass, xDerivedFromClass )
|
|
)
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
|
|
// *** Classification of Properties (no enum, to be able to use Sequence) ***
|
|
// Properties from a PropertySet-Interface
|
|
#define MAP_PROPERTY_SET 0
|
|
// Properties from Fields
|
|
#define MAP_FIELD 1
|
|
// Properties that get described with get/set methods
|
|
#define MAP_GETSET 2
|
|
// Properties with only a set method
|
|
#define MAP_SETONLY 3
|
|
|
|
|
|
// Increments by which the size of sequences get adjusted
|
|
#define ARRAY_SIZE_STEP 20
|
|
|
|
|
|
//*** IntrospectionAccessStatic_Impl ***
|
|
|
|
// Equals to the old IntrospectionAccessImpl, forms now a static
|
|
// part of the new Instance-related ImplIntrospectionAccess
|
|
|
|
// Hashtable for the search of names
|
|
typedef std::unordered_map
|
|
<
|
|
OUString,
|
|
sal_Int32
|
|
>
|
|
IntrospectionNameMap;
|
|
|
|
|
|
// Hashtable to assign exact names to the Lower-Case
|
|
// converted names, for the support of XExactName
|
|
typedef std::unordered_map
|
|
<
|
|
OUString,
|
|
OUString
|
|
>
|
|
LowerToExactNameMap;
|
|
|
|
|
|
class ImplIntrospectionAccess;
|
|
class IntrospectionAccessStatic_Impl: public salhelper::SimpleReferenceObject
|
|
{
|
|
friend class Implementation;
|
|
friend class ImplIntrospectionAccess;
|
|
|
|
// Holding CoreReflection
|
|
Reference< XIdlReflection > mxCoreReflection;
|
|
|
|
// InterfaceSequences, to save additional information in a property
|
|
// for example the Field at MAP_FIELD, the get/set-Methods at MAP_GETSET, et cetera
|
|
std::vector< Reference<XInterface> > aInterfaceSeq1;
|
|
std::vector< Reference<XInterface> > aInterfaceSeq2;
|
|
|
|
// Hashtables for names
|
|
IntrospectionNameMap maPropertyNameMap;
|
|
IntrospectionNameMap maMethodNameMap;
|
|
LowerToExactNameMap maLowerToExactNameMap;
|
|
|
|
// Vector of all Properties, also for delivering from getProperties()
|
|
std::vector<Property> maAllPropertySeq;
|
|
|
|
// Mapping of properties to Access-Types
|
|
std::vector<sal_Int16> maMapTypeSeq;
|
|
|
|
// Classification of found methods
|
|
std::vector<sal_Int32> maPropertyConceptSeq;
|
|
|
|
// Number of Properties
|
|
sal_Int32 mnPropCount;
|
|
|
|
// Number of Properties, which are assigned to particular concepts
|
|
//sal_Int32 mnDangerousPropCount;
|
|
sal_Int32 mnPropertySetPropCount;
|
|
sal_Int32 mnAttributePropCount;
|
|
sal_Int32 mnMethodPropCount;
|
|
|
|
// Flags which indicate if various interfaces are present
|
|
bool mbFastPropSet;
|
|
bool mbElementAccess;
|
|
bool mbNameAccess;
|
|
bool mbNameReplace;
|
|
bool mbNameContainer;
|
|
bool mbIndexAccess;
|
|
bool mbIndexReplace;
|
|
bool mbIndexContainer;
|
|
bool mbEnumerationAccess;
|
|
bool mbIdlArray;
|
|
bool mbUnoTunnel;
|
|
|
|
// Original handles of FastPropertySets
|
|
std::unique_ptr<sal_Int32[]> mpOrgPropertyHandleArray;
|
|
|
|
// MethodSequence, that accepts all methods
|
|
std::vector< Reference<XIdlMethod> > maAllMethodSeq;
|
|
|
|
// Classification of found methods
|
|
std::vector<sal_Int32> maMethodConceptSeq;
|
|
|
|
// Number of methods
|
|
sal_Int32 mnMethCount;
|
|
|
|
// Sequence of Listener, that can be registered
|
|
std::vector< Type > maSupportedListenerSeq;
|
|
|
|
// Helper-methods for adjusting sizes of Sequences
|
|
void checkPropertyArraysSize( sal_Int32 iNextIndex );
|
|
static void checkInterfaceArraySize( std::vector< Reference<XInterface> >& rSeq, std::vector<Reference<XInterface>>& rInterfaceVec,
|
|
sal_Int32 iNextIndex );
|
|
|
|
public:
|
|
explicit IntrospectionAccessStatic_Impl( Reference< XIdlReflection > const & xCoreReflection_ );
|
|
sal_Int32 getPropertyIndex( const OUString& aPropertyName ) const;
|
|
sal_Int32 getMethodIndex( const OUString& aMethodName ) const;
|
|
|
|
// Methods of XIntrospectionAccess (OLD, now only Impl)
|
|
void setPropertyValue(const Any& obj, const OUString& aPropertyName, const Any& aValue) const;
|
|
// void setPropertyValue(Any& obj, const OUString& aPropertyName, const Any& aValue) const;
|
|
Any getPropertyValue(const Any& obj, const OUString& aPropertyName) const;
|
|
void setPropertyValueByIndex(const Any& obj, sal_Int32 nIndex, const Any& aValue) const;
|
|
// void setPropertyValueByIndex(Any& obj, sal_Int32 nIndex, const Any& aValue) const;
|
|
Any getPropertyValueByIndex(const Any& obj, sal_Int32 nIndex) const;
|
|
|
|
const std::vector<Property>& getProperties() const { return maAllPropertySeq; }
|
|
const std::vector< Reference<XIdlMethod> >& getMethods() const { return maAllMethodSeq; }
|
|
const std::vector< Type >& getSupportedListeners() const { return maSupportedListenerSeq; }
|
|
const std::vector<sal_Int32>& getPropertyConcepts() const { return maPropertyConceptSeq; }
|
|
const std::vector<sal_Int32>& getMethodConcepts() const { return maMethodConceptSeq; }
|
|
};
|
|
|
|
|
|
// Ctor
|
|
IntrospectionAccessStatic_Impl::IntrospectionAccessStatic_Impl( Reference< XIdlReflection > const & xCoreReflection_ )
|
|
: mxCoreReflection( xCoreReflection_ )
|
|
{
|
|
aInterfaceSeq1.resize( ARRAY_SIZE_STEP );
|
|
aInterfaceSeq2.resize( ARRAY_SIZE_STEP );
|
|
|
|
// Property-Data
|
|
maAllPropertySeq.resize( ARRAY_SIZE_STEP );
|
|
maMapTypeSeq.resize( ARRAY_SIZE_STEP );
|
|
maPropertyConceptSeq.resize( ARRAY_SIZE_STEP );
|
|
|
|
mbFastPropSet = false;
|
|
mbElementAccess = false;
|
|
mbNameAccess = false;
|
|
mbNameReplace = false;
|
|
mbNameContainer = false;
|
|
mbIndexAccess = false;
|
|
mbIndexReplace = false;
|
|
mbIndexContainer = false;
|
|
mbEnumerationAccess = false;
|
|
mbIdlArray = false;
|
|
mbUnoTunnel = false;
|
|
|
|
mpOrgPropertyHandleArray = nullptr;
|
|
|
|
mnPropCount = 0;
|
|
//mnDangerousPropCount = 0;
|
|
mnPropertySetPropCount = 0;
|
|
mnAttributePropCount = 0;
|
|
mnMethodPropCount = 0;
|
|
|
|
// Method-Data
|
|
mnMethCount = 0;
|
|
}
|
|
|
|
sal_Int32 IntrospectionAccessStatic_Impl::getPropertyIndex( const OUString& aPropertyName ) const
|
|
{
|
|
IntrospectionAccessStatic_Impl* pThis = const_cast<IntrospectionAccessStatic_Impl*>(this);
|
|
IntrospectionNameMap::iterator aIt = pThis->maPropertyNameMap.find( aPropertyName );
|
|
if (aIt != pThis->maPropertyNameMap.end())
|
|
return aIt->second;
|
|
|
|
return -1;
|
|
}
|
|
|
|
sal_Int32 IntrospectionAccessStatic_Impl::getMethodIndex( const OUString& aMethodName ) const
|
|
{
|
|
IntrospectionAccessStatic_Impl* pThis = const_cast<IntrospectionAccessStatic_Impl*>(this);
|
|
IntrospectionNameMap::iterator aIt = pThis->maMethodNameMap.find( aMethodName );
|
|
if (aIt != pThis->maMethodNameMap.end())
|
|
{
|
|
return aIt->second;
|
|
}
|
|
|
|
// #95159 Check if full qualified name matches
|
|
sal_Int32 nSearchFrom = aMethodName.getLength();
|
|
while( true )
|
|
{
|
|
// Strategy: Search back until the first '_' is found
|
|
sal_Int32 nFound = aMethodName.lastIndexOf( '_', nSearchFrom );
|
|
if( nFound == -1 )
|
|
break;
|
|
|
|
OUString aPureMethodName = aMethodName.copy( nFound + 1 );
|
|
|
|
aIt = pThis->maMethodNameMap.find( aPureMethodName );
|
|
if (aIt != pThis->maMethodNameMap.end())
|
|
{
|
|
// Check if it can be a type?
|
|
// Problem: Does not work if package names contain _ ?!
|
|
OUString aStr = aMethodName.copy( 0, nFound );
|
|
OUString aTypeName = aStr.replace( '_', '.' );
|
|
Reference< XIdlClass > xClass = mxCoreReflection->forName( aTypeName );
|
|
if( xClass.is() )
|
|
{
|
|
// If this is a valid class it could be the right method
|
|
|
|
// Could be the right method, type has to be checked
|
|
const sal_Int32 iHashResult = aIt->second;
|
|
|
|
const Reference<XIdlMethod> xMethod = maAllMethodSeq[iHashResult];
|
|
|
|
Reference< XIdlClass > xMethClass = xMethod->getDeclaringClass();
|
|
if( xClass->equals( xMethClass ) )
|
|
{
|
|
return iHashResult;
|
|
}
|
|
else
|
|
{
|
|
// Could also be another method with the same name
|
|
// Iterate over all methods
|
|
size_t nLen = maAllMethodSeq.size();
|
|
for (size_t i = 0; i < nLen; ++i)
|
|
{
|
|
const Reference<XIdlMethod> xMethod2 = maAllMethodSeq[ i ];
|
|
if( xMethod2->getName() == aPureMethodName )
|
|
{
|
|
Reference< XIdlClass > xMethClass2 = xMethod2->getDeclaringClass();
|
|
|
|
if( xClass->equals( xMethClass2 ) )
|
|
{
|
|
return i;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
nSearchFrom = nFound - 1;
|
|
if( nSearchFrom < 0 )
|
|
break;
|
|
}
|
|
return -1;
|
|
}
|
|
|
|
void IntrospectionAccessStatic_Impl::setPropertyValue( const Any& obj, const OUString& aPropertyName, const Any& aValue ) const
|
|
//void IntrospectionAccessStatic_Impl::setPropertyValue( Any& obj, const OUString& aPropertyName, const Any& aValue ) const
|
|
{
|
|
sal_Int32 i = getPropertyIndex( aPropertyName );
|
|
if( i == -1 )
|
|
throw UnknownPropertyException(aPropertyName);
|
|
setPropertyValueByIndex( obj, i, aValue );
|
|
}
|
|
|
|
void IntrospectionAccessStatic_Impl::setPropertyValueByIndex(const Any& obj, sal_Int32 nSequenceIndex, const Any& aValue) const
|
|
//void IntrospectionAccessStatic_Impl::setPropertyValueByIndex( Any& obj, sal_Int32 nSequenceIndex, const Any& aValue) const
|
|
{
|
|
// Is the passed object something that fits?
|
|
Reference<XInterface> xInterface;
|
|
if( !(obj >>= xInterface) )
|
|
{
|
|
TypeClass eObjType = obj.getValueType().getTypeClass();
|
|
if( nSequenceIndex >= mnPropCount)
|
|
throw IllegalArgumentException(
|
|
"IntrospectionAccessStatic_Impl::setPropertyValueByIndex(), index > propertyCount, " +
|
|
OUString::number(nSequenceIndex) + " > " + OUString::number(mnPropCount),
|
|
Reference<XInterface>(), 0);
|
|
if( eObjType != TypeClass_STRUCT && eObjType != TypeClass_EXCEPTION )
|
|
throw IllegalArgumentException(
|
|
"IntrospectionAccessStatic_Impl::setPropertyValueByIndex(), expected struct or exception, got" +
|
|
obj.getValueType().getTypeName(), Reference<XInterface>(), 0);
|
|
}
|
|
|
|
// Test flags
|
|
if( (maAllPropertySeq[ nSequenceIndex ].Attributes & READONLY) != 0 )
|
|
{
|
|
throw UnknownPropertyException(
|
|
"IntrospectionAccessStatic_Impl::setPropertyValueByIndex(), property at index " + OUString::number(nSequenceIndex) + " is readonly");
|
|
}
|
|
|
|
switch( maMapTypeSeq[ nSequenceIndex ] )
|
|
{
|
|
case MAP_PROPERTY_SET:
|
|
{
|
|
// Get Property
|
|
const Property& rProp = maAllPropertySeq[ nSequenceIndex ];
|
|
|
|
// Convert Interface-Parameter to the correct type
|
|
bool bUseCopy = false;
|
|
Any aRealValue;
|
|
|
|
if( auto valInterface = o3tl::tryAccess<
|
|
css::uno::Reference<css::uno::XInterface>>(aValue) )
|
|
{
|
|
Type aPropType = rProp.Type;
|
|
OUString aTypeName( aPropType.getTypeName() );
|
|
Reference< XIdlClass > xPropClass = mxCoreReflection->forName( aTypeName );
|
|
//Reference<XIdlClass> xPropClass = rProp.Type;
|
|
if( xPropClass.is() && xPropClass->getTypeClass() == TypeClass_INTERFACE )
|
|
{
|
|
if( valInterface->is() )
|
|
{
|
|
//Any queryInterface( const Type& rType );
|
|
aRealValue = (*valInterface)->queryInterface( aPropType );
|
|
if( aRealValue.hasValue() )
|
|
bUseCopy = true;
|
|
}
|
|
}
|
|
}
|
|
|
|
// Do we have a FastPropertySet and a valid Handle?
|
|
// CAUTION: At this point we exploit that the PropertySet
|
|
// gets queried at the beginning of the Introspection-Process.
|
|
sal_Int32 nOrgHandle;
|
|
if( mbFastPropSet && ( nOrgHandle = mpOrgPropertyHandleArray[ nSequenceIndex ] ) != -1 )
|
|
{
|
|
// Retrieve PropertySet-Interface
|
|
Reference<XFastPropertySet> xFastPropSet =
|
|
Reference<XFastPropertySet>::query( xInterface );
|
|
if( xFastPropSet.is() )
|
|
{
|
|
xFastPropSet->setFastPropertyValue( nOrgHandle, bUseCopy ? aRealValue : aValue );
|
|
}
|
|
else
|
|
{
|
|
// throw UnknownPropertyException
|
|
}
|
|
}
|
|
// else take the normal one
|
|
else
|
|
{
|
|
// Retrieve PropertySet-Interface
|
|
Reference<XPropertySet> xPropSet =
|
|
Reference<XPropertySet>::query( xInterface );
|
|
if( xPropSet.is() )
|
|
{
|
|
xPropSet->setPropertyValue( rProp.Name, bUseCopy ? aRealValue : aValue );
|
|
}
|
|
else
|
|
{
|
|
// throw UnknownPropertyException
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
|
|
case MAP_FIELD:
|
|
{
|
|
Reference<XIdlField> xField = static_cast<XIdlField*>(aInterfaceSeq1[ nSequenceIndex ].get());
|
|
Reference<XIdlField2> xField2(xField, UNO_QUERY);
|
|
if( xField2.is() )
|
|
{
|
|
xField2->set( const_cast<Any&>(obj), aValue );
|
|
// IllegalArgumentException
|
|
// NullPointerException
|
|
} else
|
|
if( xField.is() )
|
|
{
|
|
xField->set( obj, aValue );
|
|
// IllegalArgumentException
|
|
// NullPointerException
|
|
}
|
|
else
|
|
{
|
|
// throw IllegalArgumentException();
|
|
}
|
|
}
|
|
break;
|
|
|
|
case MAP_GETSET:
|
|
case MAP_SETONLY:
|
|
{
|
|
// Fetch set method
|
|
Reference<XIdlMethod> xMethod = static_cast<XIdlMethod*>(aInterfaceSeq2[ nSequenceIndex ].get());
|
|
if( xMethod.is() )
|
|
{
|
|
Sequence<Any> args( 1 );
|
|
args.getArray()[0] = aValue;
|
|
xMethod->invoke( obj, args );
|
|
}
|
|
else
|
|
{
|
|
// throw IllegalArgumentException();
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
Any IntrospectionAccessStatic_Impl::getPropertyValue( const Any& obj, const OUString& aPropertyName ) const
|
|
{
|
|
sal_Int32 i = getPropertyIndex( aPropertyName );
|
|
if( i != -1 )
|
|
return getPropertyValueByIndex( obj, i );
|
|
|
|
throw UnknownPropertyException(aPropertyName);
|
|
}
|
|
|
|
Any IntrospectionAccessStatic_Impl::getPropertyValueByIndex(const Any& obj, sal_Int32 nSequenceIndex) const
|
|
{
|
|
Any aRet;
|
|
|
|
// Is there anything suitable in the passed object?
|
|
Reference<XInterface> xInterface;
|
|
if( !(obj >>= xInterface) )
|
|
{
|
|
TypeClass eObjType = obj.getValueType().getTypeClass();
|
|
if( nSequenceIndex >= mnPropCount || ( eObjType != TypeClass_STRUCT && eObjType != TypeClass_EXCEPTION ) )
|
|
{
|
|
// throw IllegalArgumentException();
|
|
return aRet;
|
|
}
|
|
}
|
|
|
|
switch( maMapTypeSeq[ nSequenceIndex ] )
|
|
{
|
|
case MAP_PROPERTY_SET:
|
|
{
|
|
// Acquire property
|
|
const Property& rProp = maAllPropertySeq[ nSequenceIndex ];
|
|
|
|
// Do we have a FastPropertySet and a valid handle?
|
|
// NOTE: At this point is exploited that the PropertySet
|
|
// is queried at the beginning of introspection process.
|
|
sal_Int32 nOrgHandle;
|
|
if( mbFastPropSet && ( nOrgHandle = mpOrgPropertyHandleArray[ nSequenceIndex ] ) != -1 )
|
|
{
|
|
// Fetch the PropertySet interface
|
|
Reference<XFastPropertySet> xFastPropSet =
|
|
Reference<XFastPropertySet>::query( xInterface );
|
|
if( xFastPropSet.is() )
|
|
{
|
|
aRet = xFastPropSet->getFastPropertyValue( nOrgHandle);
|
|
}
|
|
else
|
|
{
|
|
// throw UnknownPropertyException
|
|
return aRet;
|
|
}
|
|
}
|
|
// Otherwise use the normal one
|
|
else
|
|
{
|
|
// Fetch the PropertySet interface
|
|
Reference<XPropertySet> xPropSet =
|
|
Reference<XPropertySet>::query( xInterface );
|
|
if( xPropSet.is() )
|
|
{
|
|
aRet = xPropSet->getPropertyValue( rProp.Name );
|
|
}
|
|
else
|
|
{
|
|
// throw UnknownPropertyException
|
|
return aRet;
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
|
|
case MAP_FIELD:
|
|
{
|
|
Reference<XIdlField> xField = static_cast<XIdlField*>(aInterfaceSeq1[ nSequenceIndex ].get());
|
|
if( xField.is() )
|
|
{
|
|
aRet = xField->get( obj );
|
|
// IllegalArgumentException
|
|
// NullPointerException
|
|
}
|
|
else
|
|
{
|
|
// throw IllegalArgumentException();
|
|
return aRet;
|
|
}
|
|
}
|
|
break;
|
|
|
|
case MAP_GETSET:
|
|
{
|
|
// Fetch get method
|
|
Reference<XIdlMethod> xMethod = static_cast<XIdlMethod*>(aInterfaceSeq1[ nSequenceIndex ].get());
|
|
if( xMethod.is() )
|
|
{
|
|
Sequence<Any> args;
|
|
aRet = xMethod->invoke( obj, args );
|
|
}
|
|
else
|
|
{
|
|
// throw IllegalArgumentException();
|
|
return aRet;
|
|
}
|
|
}
|
|
break;
|
|
|
|
case MAP_SETONLY:
|
|
// Get method does not exist
|
|
// throw WriteOnlyPropertyException();
|
|
return aRet;
|
|
}
|
|
return aRet;
|
|
}
|
|
|
|
|
|
// Helper method to adjust the size of the vectors
|
|
void IntrospectionAccessStatic_Impl::checkPropertyArraysSize( sal_Int32 iNextIndex )
|
|
{
|
|
sal_Int32 nLen = static_cast<sal_Int32>(maAllPropertySeq.size());
|
|
if( iNextIndex >= nLen )
|
|
{
|
|
maAllPropertySeq.resize( nLen + ARRAY_SIZE_STEP );
|
|
maMapTypeSeq.resize( nLen + ARRAY_SIZE_STEP );
|
|
maPropertyConceptSeq.resize( nLen + ARRAY_SIZE_STEP );
|
|
}
|
|
}
|
|
|
|
void IntrospectionAccessStatic_Impl::checkInterfaceArraySize( std::vector< Reference<XInterface> >& rSeq,
|
|
std::vector<Reference<XInterface>>& rInterfaceVec, sal_Int32 iNextIndex )
|
|
{
|
|
sal_Int32 nLen = rSeq.size();
|
|
if( iNextIndex >= nLen )
|
|
{
|
|
// Synchronize new size with ARRAY_SIZE_STEP
|
|
sal_Int32 nMissingSize = iNextIndex - nLen + 1;
|
|
sal_Int32 nSteps = nMissingSize / ARRAY_SIZE_STEP + 1;
|
|
sal_Int32 nNewSize = nLen + nSteps * ARRAY_SIZE_STEP;
|
|
|
|
rSeq.resize( nNewSize );
|
|
rInterfaceVec = rSeq;
|
|
}
|
|
}
|
|
|
|
|
|
//*** ImplIntrospectionAccess ***
|
|
|
|
|
|
// New Impl class as part of the introspection conversion to instance-bound
|
|
// Introspection with property access via XPropertySet. The old class
|
|
// ImplIntrospectionAccess lives on as IntrospectionAccessStatic_Impl
|
|
class ImplIntrospectionAccess : public IntrospectionAccessHelper
|
|
{
|
|
friend class Implementation;
|
|
|
|
// Object under examination
|
|
Any const maInspectedObject;
|
|
|
|
// As interface
|
|
Reference<XInterface> mxIface;
|
|
|
|
// Static introspection data
|
|
rtl::Reference< IntrospectionAccessStatic_Impl > mpStaticImpl;
|
|
|
|
// Last Sequence that came with getProperties (optimization)
|
|
Sequence<Property> maLastPropertySeq;
|
|
sal_Int32 mnLastPropertyConcept;
|
|
|
|
// Last Sequence that came with getMethods (optimization)
|
|
Sequence<Reference<XIdlMethod> > maLastMethodSeq;
|
|
sal_Int32 mnLastMethodConcept;
|
|
|
|
// Guards the caching of queried interfaces
|
|
osl::Mutex m_aMutex;
|
|
|
|
// Original interfaces of the objects
|
|
Reference<XElementAccess> mxObjElementAccess;
|
|
Reference<XNameContainer> mxObjNameContainer;
|
|
Reference<XNameReplace> mxObjNameReplace;
|
|
Reference<XNameAccess> mxObjNameAccess;
|
|
Reference<XIndexContainer> mxObjIndexContainer;
|
|
Reference<XIndexReplace> mxObjIndexReplace;
|
|
Reference<XIndexAccess> mxObjIndexAccess;
|
|
Reference<XEnumerationAccess> mxObjEnumerationAccess;
|
|
Reference<XIdlArray> mxObjIdlArray;
|
|
|
|
Reference<XElementAccess> getXElementAccess();
|
|
Reference<XNameContainer> getXNameContainer();
|
|
Reference<XNameReplace> getXNameReplace();
|
|
Reference<XNameAccess> getXNameAccess();
|
|
Reference<XIndexContainer> getXIndexContainer();
|
|
Reference<XIndexReplace> getXIndexReplace();
|
|
Reference<XIndexAccess> getXIndexAccess();
|
|
Reference<XEnumerationAccess> getXEnumerationAccess();
|
|
Reference<XIdlArray> getXIdlArray();
|
|
|
|
void cacheXNameContainer();
|
|
void cacheXIndexContainer();
|
|
|
|
public:
|
|
ImplIntrospectionAccess( const Any& obj, rtl::Reference< IntrospectionAccessStatic_Impl > const & pStaticImpl_ );
|
|
|
|
// Methods from XIntrospectionAccess
|
|
virtual sal_Int32 SAL_CALL getSuppliedMethodConcepts() override;
|
|
virtual sal_Int32 SAL_CALL getSuppliedPropertyConcepts() override;
|
|
virtual Property SAL_CALL getProperty(const OUString& Name, sal_Int32 PropertyConcepts) override;
|
|
virtual sal_Bool SAL_CALL hasProperty(const OUString& Name, sal_Int32 PropertyConcepts) override;
|
|
virtual Sequence< Property > SAL_CALL getProperties(sal_Int32 PropertyConcepts) override;
|
|
virtual Reference<XIdlMethod> SAL_CALL getMethod(const OUString& Name, sal_Int32 MethodConcepts) override;
|
|
virtual sal_Bool SAL_CALL hasMethod(const OUString& Name, sal_Int32 MethodConcepts) override;
|
|
virtual Sequence< Reference<XIdlMethod> > SAL_CALL getMethods(sal_Int32 MethodConcepts) override;
|
|
virtual Sequence< Type > SAL_CALL getSupportedListeners() override;
|
|
using OWeakObject::queryAdapter;
|
|
virtual Reference<XInterface> SAL_CALL queryAdapter( const Type& rType ) override;
|
|
|
|
// Methods from XMaterialHolder
|
|
virtual Any SAL_CALL getMaterial() override;
|
|
|
|
// Methods from XExactName
|
|
virtual OUString SAL_CALL getExactName( const OUString& rApproximateName ) override;
|
|
|
|
// Methods from XInterface
|
|
virtual Any SAL_CALL queryInterface( const Type& rType ) override;
|
|
virtual void SAL_CALL acquire() throw() override { OWeakObject::acquire(); }
|
|
virtual void SAL_CALL release() throw() override { OWeakObject::release(); }
|
|
|
|
// Methods from XPropertySet
|
|
virtual Reference<XPropertySetInfo> SAL_CALL getPropertySetInfo() override;
|
|
virtual void SAL_CALL setPropertyValue(const OUString& aPropertyName, const Any& aValue) override;
|
|
virtual Any SAL_CALL getPropertyValue(const OUString& aPropertyName) override;
|
|
virtual void SAL_CALL addPropertyChangeListener(const OUString& aPropertyName, const Reference<XPropertyChangeListener>& aListener) override;
|
|
virtual void SAL_CALL removePropertyChangeListener(const OUString& aPropertyName, const Reference<XPropertyChangeListener>& aListener) override;
|
|
virtual void SAL_CALL addVetoableChangeListener(const OUString& aPropertyName, const Reference<XVetoableChangeListener>& aListener) override;
|
|
virtual void SAL_CALL removeVetoableChangeListener(const OUString& aPropertyName, const Reference<XVetoableChangeListener>& aListener) override;
|
|
|
|
// Methods from XFastPropertySet
|
|
virtual void SAL_CALL setFastPropertyValue(sal_Int32 nHandle, const Any& aValue) override;
|
|
virtual Any SAL_CALL getFastPropertyValue(sal_Int32 nHandle) override;
|
|
|
|
// Methods from XPropertySetInfo
|
|
virtual Sequence< Property > SAL_CALL getProperties() override;
|
|
virtual Property SAL_CALL getPropertyByName(const OUString& Name) override;
|
|
virtual sal_Bool SAL_CALL hasPropertyByName(const OUString& Name) override;
|
|
|
|
// Methods from XElementAccess
|
|
virtual Type SAL_CALL getElementType() override;
|
|
virtual sal_Bool SAL_CALL hasElements() override;
|
|
|
|
// Methods from XNameAccess
|
|
virtual Any SAL_CALL getByName(const OUString& Name) override;
|
|
virtual Sequence< OUString > SAL_CALL getElementNames() override;
|
|
virtual sal_Bool SAL_CALL hasByName(const OUString& Name) override;
|
|
|
|
// Methods from XNameReplace
|
|
virtual void SAL_CALL replaceByName(const OUString& Name, const Any& Element) override;
|
|
|
|
// Methods from XNameContainer
|
|
virtual void SAL_CALL insertByName(const OUString& Name, const Any& Element) override;
|
|
virtual void SAL_CALL removeByName(const OUString& Name) override;
|
|
|
|
// Methods from XIndexAccess
|
|
virtual sal_Int32 SAL_CALL getCount() override;
|
|
virtual Any SAL_CALL getByIndex(sal_Int32 Index) override;
|
|
|
|
// Methods from XIndexReplace
|
|
virtual void SAL_CALL replaceByIndex(sal_Int32 Index, const Any& Element) override;
|
|
|
|
// Methods from XIndexContainer
|
|
virtual void SAL_CALL insertByIndex(sal_Int32 Index, const Any& Element) override;
|
|
virtual void SAL_CALL removeByIndex(sal_Int32 Index) override;
|
|
|
|
// Methods from XEnumerationAccess
|
|
virtual Reference<XEnumeration> SAL_CALL createEnumeration() override;
|
|
|
|
// Methods from XIdlArray
|
|
virtual void SAL_CALL realloc(Any& array, sal_Int32 length) override;
|
|
virtual sal_Int32 SAL_CALL getLen(const Any& array) override;
|
|
virtual Any SAL_CALL get(const Any& array, sal_Int32 index) override;
|
|
virtual void SAL_CALL set(Any& array, sal_Int32 index, const Any& value) override;
|
|
|
|
// Methods from XUnoTunnel
|
|
virtual sal_Int64 SAL_CALL getSomething( const Sequence< sal_Int8 >& aIdentifier ) override;
|
|
};
|
|
|
|
ImplIntrospectionAccess::ImplIntrospectionAccess
|
|
( const Any& obj, rtl::Reference< IntrospectionAccessStatic_Impl > const & pStaticImpl_ )
|
|
: maInspectedObject( obj ), mpStaticImpl( pStaticImpl_ ) //, maAdapter()
|
|
{
|
|
// Save object as an interface if possible
|
|
maInspectedObject >>= mxIface;
|
|
|
|
mnLastPropertyConcept = -1;
|
|
mnLastMethodConcept = -1;
|
|
}
|
|
|
|
Reference<XElementAccess> ImplIntrospectionAccess::getXElementAccess()
|
|
{
|
|
ResettableGuard< Mutex > aGuard( m_aMutex );
|
|
|
|
if( !mxObjElementAccess.is() )
|
|
{
|
|
aGuard.clear();
|
|
Reference<XElementAccess> xElementAccess( mxIface, UNO_QUERY );
|
|
aGuard.reset();
|
|
if( !mxObjElementAccess.is() )
|
|
mxObjElementAccess = xElementAccess;
|
|
}
|
|
return mxObjElementAccess;
|
|
}
|
|
|
|
void ImplIntrospectionAccess::cacheXNameContainer()
|
|
{
|
|
Reference<XNameContainer> xNameContainer;
|
|
Reference<XNameReplace> xNameReplace;
|
|
Reference<XNameAccess> xNameAccess;
|
|
if (mpStaticImpl->mbNameContainer)
|
|
{
|
|
xNameContainer.set( mxIface, UNO_QUERY );
|
|
xNameReplace.set( xNameContainer, UNO_QUERY );
|
|
xNameAccess.set( xNameContainer, UNO_QUERY );
|
|
}
|
|
else if (mpStaticImpl->mbNameReplace)
|
|
{
|
|
xNameReplace.set( mxIface, UNO_QUERY );
|
|
xNameAccess.set( xNameReplace, UNO_QUERY );
|
|
}
|
|
else if (mpStaticImpl->mbNameAccess)
|
|
{
|
|
xNameAccess.set( mxIface, UNO_QUERY );
|
|
}
|
|
|
|
{
|
|
MutexGuard aGuard( m_aMutex );
|
|
if( !mxObjNameContainer.is() )
|
|
mxObjNameContainer = xNameContainer;
|
|
if( !mxObjNameReplace.is() )
|
|
mxObjNameReplace = xNameReplace;
|
|
if( !mxObjNameAccess.is() )
|
|
mxObjNameAccess = xNameAccess;
|
|
}
|
|
}
|
|
|
|
Reference<XNameContainer> ImplIntrospectionAccess::getXNameContainer()
|
|
{
|
|
ClearableGuard< Mutex > aGuard( m_aMutex );
|
|
|
|
if( !mxObjNameContainer.is() )
|
|
{
|
|
aGuard.clear();
|
|
cacheXNameContainer();
|
|
}
|
|
return mxObjNameContainer;
|
|
}
|
|
|
|
Reference<XNameReplace> ImplIntrospectionAccess::getXNameReplace()
|
|
{
|
|
ClearableGuard< Mutex > aGuard( m_aMutex );
|
|
|
|
if( !mxObjNameReplace.is() )
|
|
{
|
|
aGuard.clear();
|
|
cacheXNameContainer();
|
|
}
|
|
return mxObjNameReplace;
|
|
}
|
|
|
|
Reference<XNameAccess> ImplIntrospectionAccess::getXNameAccess()
|
|
{
|
|
ClearableGuard< Mutex > aGuard( m_aMutex );
|
|
|
|
if( !mxObjNameAccess.is() )
|
|
{
|
|
aGuard.clear();
|
|
cacheXNameContainer();
|
|
}
|
|
return mxObjNameAccess;
|
|
}
|
|
|
|
void ImplIntrospectionAccess::cacheXIndexContainer()
|
|
{
|
|
Reference<XIndexContainer> xIndexContainer;
|
|
Reference<XIndexReplace> xIndexReplace;
|
|
Reference<XIndexAccess> xIndexAccess;
|
|
if (mpStaticImpl->mbIndexContainer)
|
|
{
|
|
xIndexContainer.set( mxIface, UNO_QUERY );
|
|
xIndexReplace.set( xIndexContainer, UNO_QUERY );
|
|
xIndexAccess.set( xIndexContainer, UNO_QUERY );
|
|
}
|
|
else if (mpStaticImpl->mbIndexReplace)
|
|
{
|
|
xIndexReplace.set( mxIface, UNO_QUERY );
|
|
xIndexAccess.set( xIndexReplace, UNO_QUERY );
|
|
}
|
|
else if (mpStaticImpl->mbIndexAccess)
|
|
{
|
|
xIndexAccess.set( mxIface, UNO_QUERY );
|
|
}
|
|
|
|
{
|
|
MutexGuard aGuard( m_aMutex );
|
|
if( !mxObjIndexContainer.is() )
|
|
mxObjIndexContainer = xIndexContainer;
|
|
if( !mxObjIndexReplace.is() )
|
|
mxObjIndexReplace = xIndexReplace;
|
|
if( !mxObjIndexAccess.is() )
|
|
mxObjIndexAccess = xIndexAccess;
|
|
}
|
|
}
|
|
|
|
Reference<XIndexContainer> ImplIntrospectionAccess::getXIndexContainer()
|
|
{
|
|
ClearableGuard< Mutex > aGuard( m_aMutex );
|
|
|
|
if( !mxObjIndexContainer.is() )
|
|
{
|
|
aGuard.clear();
|
|
cacheXIndexContainer();
|
|
}
|
|
return mxObjIndexContainer;
|
|
}
|
|
|
|
Reference<XIndexReplace> ImplIntrospectionAccess::getXIndexReplace()
|
|
{
|
|
ClearableGuard< Mutex > aGuard( m_aMutex );
|
|
|
|
if( !mxObjIndexReplace.is() )
|
|
{
|
|
aGuard.clear();
|
|
cacheXIndexContainer();
|
|
}
|
|
return mxObjIndexReplace;
|
|
}
|
|
|
|
Reference<XIndexAccess> ImplIntrospectionAccess::getXIndexAccess()
|
|
{
|
|
ClearableGuard< Mutex > aGuard( m_aMutex );
|
|
|
|
if( !mxObjIndexAccess.is() )
|
|
{
|
|
aGuard.clear();
|
|
cacheXIndexContainer();
|
|
}
|
|
return mxObjIndexAccess;
|
|
}
|
|
|
|
Reference<XEnumerationAccess> ImplIntrospectionAccess::getXEnumerationAccess()
|
|
{
|
|
ResettableGuard< Mutex > aGuard( m_aMutex );
|
|
|
|
if( !mxObjEnumerationAccess.is() )
|
|
{
|
|
aGuard.clear();
|
|
Reference<XEnumerationAccess> xEnumerationAccess( mxIface, UNO_QUERY );
|
|
aGuard.reset();
|
|
if( !mxObjEnumerationAccess.is() )
|
|
mxObjEnumerationAccess = xEnumerationAccess;
|
|
}
|
|
return mxObjEnumerationAccess;
|
|
}
|
|
|
|
Reference<XIdlArray> ImplIntrospectionAccess::getXIdlArray()
|
|
{
|
|
ResettableGuard< Mutex > aGuard( m_aMutex );
|
|
|
|
if( !mxObjIdlArray.is() )
|
|
{
|
|
aGuard.clear();
|
|
Reference<XIdlArray> xIdlArray( mxIface, UNO_QUERY );
|
|
aGuard.reset();
|
|
if( !mxObjIdlArray.is() )
|
|
mxObjIdlArray = xIdlArray;
|
|
}
|
|
return mxObjIdlArray;
|
|
}
|
|
|
|
// Methods from XInterface
|
|
Any SAL_CALL ImplIntrospectionAccess::queryInterface( const Type& rType )
|
|
{
|
|
Any aRet( ::cppu::queryInterface(
|
|
rType,
|
|
static_cast< XIntrospectionAccess * >( this ),
|
|
static_cast< XMaterialHolder * >( this ),
|
|
static_cast< XExactName * >( this ),
|
|
static_cast< XPropertySet * >( this ),
|
|
static_cast< XFastPropertySet * >( this ),
|
|
static_cast< XPropertySetInfo * >( this ) ) );
|
|
if( !aRet.hasValue() )
|
|
aRet = OWeakObject::queryInterface( rType );
|
|
|
|
if( !aRet.hasValue() )
|
|
{
|
|
// Wrapper for the object interfaces
|
|
( mpStaticImpl->mbElementAccess && (aRet = ::cppu::queryInterface
|
|
( rType, static_cast< XElementAccess* >( static_cast< XNameAccess* >( this ) ) ) ).hasValue() )
|
|
|| ( mpStaticImpl->mbNameAccess && (aRet = ::cppu::queryInterface( rType, static_cast< XNameAccess* >( this ) ) ).hasValue() )
|
|
|| ( mpStaticImpl->mbNameReplace && (aRet = ::cppu::queryInterface( rType, static_cast< XNameReplace* >( this ) ) ).hasValue() )
|
|
|| ( mpStaticImpl->mbNameContainer && (aRet = ::cppu::queryInterface( rType, static_cast< XNameContainer* >( this ) ) ).hasValue() )
|
|
|| ( mpStaticImpl->mbIndexAccess && (aRet = ::cppu::queryInterface( rType, static_cast< XIndexAccess* >( this ) ) ).hasValue() )
|
|
|| ( mpStaticImpl->mbIndexReplace && (aRet = ::cppu::queryInterface( rType, static_cast< XIndexReplace* >( this ) ) ).hasValue() )
|
|
|| ( mpStaticImpl->mbIndexContainer && (aRet = ::cppu::queryInterface( rType, static_cast< XIndexContainer* >( this ) ) ).hasValue() )
|
|
|| ( mpStaticImpl->mbEnumerationAccess && (aRet = ::cppu::queryInterface( rType, static_cast< XEnumerationAccess* >( this ) ) ).hasValue() )
|
|
|| ( mpStaticImpl->mbIdlArray && (aRet = ::cppu::queryInterface( rType, static_cast< XIdlArray* >( this ) ) ).hasValue() )
|
|
|| ( mpStaticImpl->mbUnoTunnel && (aRet = ::cppu::queryInterface( rType, static_cast< XUnoTunnel* >( this ) ) ).hasValue() );
|
|
}
|
|
return aRet;
|
|
}
|
|
|
|
|
|
//*** Implementation of ImplIntrospectionAdapter ***
|
|
|
|
|
|
// Methods from XPropertySet
|
|
Reference<XPropertySetInfo> ImplIntrospectionAccess::getPropertySetInfo()
|
|
{
|
|
return static_cast<XPropertySetInfo *>(this);
|
|
}
|
|
|
|
void ImplIntrospectionAccess::setPropertyValue(const OUString& aPropertyName, const Any& aValue)
|
|
{
|
|
mpStaticImpl->setPropertyValue( maInspectedObject, aPropertyName, aValue );
|
|
}
|
|
|
|
Any ImplIntrospectionAccess::getPropertyValue(const OUString& aPropertyName)
|
|
{
|
|
return mpStaticImpl->getPropertyValue( maInspectedObject, aPropertyName );
|
|
}
|
|
|
|
void ImplIntrospectionAccess::addPropertyChangeListener(const OUString& aPropertyName, const Reference<XPropertyChangeListener>& aListener)
|
|
{
|
|
if( mxIface.is() )
|
|
{
|
|
Reference<XPropertySet> xPropSet =
|
|
Reference<XPropertySet>::query( mxIface );
|
|
//Reference<XPropertySet> xPropSet( mxIface, USR_QUERY );
|
|
if( xPropSet.is() )
|
|
xPropSet->addPropertyChangeListener(aPropertyName, aListener);
|
|
}
|
|
}
|
|
|
|
void ImplIntrospectionAccess::removePropertyChangeListener(const OUString& aPropertyName, const Reference<XPropertyChangeListener>& aListener)
|
|
{
|
|
if( mxIface.is() )
|
|
{
|
|
Reference<XPropertySet> xPropSet =
|
|
Reference<XPropertySet>::query( mxIface );
|
|
//Reference<XPropertySet> xPropSet( mxIface, USR_QUERY );
|
|
if( xPropSet.is() )
|
|
xPropSet->removePropertyChangeListener(aPropertyName, aListener);
|
|
}
|
|
}
|
|
|
|
void ImplIntrospectionAccess::addVetoableChangeListener(const OUString& aPropertyName, const Reference<XVetoableChangeListener>& aListener)
|
|
{
|
|
if( mxIface.is() )
|
|
{
|
|
Reference<XPropertySet> xPropSet =
|
|
Reference<XPropertySet>::query( mxIface );
|
|
//Reference<XPropertySet> xPropSet( mxIface, USR_QUERY );
|
|
if( xPropSet.is() )
|
|
xPropSet->addVetoableChangeListener(aPropertyName, aListener);
|
|
}
|
|
}
|
|
|
|
void ImplIntrospectionAccess::removeVetoableChangeListener(const OUString& aPropertyName, const Reference<XVetoableChangeListener>& aListener)
|
|
{
|
|
if( mxIface.is() )
|
|
{
|
|
Reference<XPropertySet> xPropSet =
|
|
Reference<XPropertySet>::query( mxIface );
|
|
if( xPropSet.is() )
|
|
xPropSet->removeVetoableChangeListener(aPropertyName, aListener);
|
|
}
|
|
}
|
|
|
|
|
|
// Methods from XFastPropertySet
|
|
void ImplIntrospectionAccess::setFastPropertyValue(sal_Int32, const Any&)
|
|
{
|
|
}
|
|
|
|
Any ImplIntrospectionAccess::getFastPropertyValue(sal_Int32)
|
|
{
|
|
return Any();
|
|
}
|
|
|
|
// Methods from XPropertySetInfo
|
|
Sequence< Property > ImplIntrospectionAccess::getProperties()
|
|
{
|
|
return comphelper::containerToSequence(mpStaticImpl->getProperties());
|
|
}
|
|
|
|
Property ImplIntrospectionAccess::getPropertyByName(const OUString& Name)
|
|
{
|
|
return getProperty( Name, PropertyConcept::ALL );
|
|
}
|
|
|
|
sal_Bool ImplIntrospectionAccess::hasPropertyByName(const OUString& Name)
|
|
{
|
|
return hasProperty( Name, PropertyConcept::ALL );
|
|
}
|
|
|
|
// Methods from XElementAccess
|
|
Type ImplIntrospectionAccess::getElementType()
|
|
{
|
|
return getXElementAccess()->getElementType();
|
|
}
|
|
|
|
sal_Bool ImplIntrospectionAccess::hasElements()
|
|
{
|
|
return getXElementAccess()->hasElements();
|
|
}
|
|
|
|
// Methods from XNameAccess
|
|
Any ImplIntrospectionAccess::getByName(const OUString& Name)
|
|
{
|
|
return getXNameAccess()->getByName( Name );
|
|
}
|
|
|
|
Sequence< OUString > ImplIntrospectionAccess::getElementNames()
|
|
{
|
|
return getXNameAccess()->getElementNames();
|
|
}
|
|
|
|
sal_Bool ImplIntrospectionAccess::hasByName(const OUString& Name)
|
|
{
|
|
return getXNameAccess()->hasByName( Name );
|
|
}
|
|
|
|
// Methods from XNameContainer
|
|
void ImplIntrospectionAccess::insertByName(const OUString& Name, const Any& Element)
|
|
{
|
|
getXNameContainer()->insertByName( Name, Element );
|
|
}
|
|
|
|
void ImplIntrospectionAccess::replaceByName(const OUString& Name, const Any& Element)
|
|
{
|
|
getXNameReplace()->replaceByName( Name, Element );
|
|
}
|
|
|
|
void ImplIntrospectionAccess::removeByName(const OUString& Name)
|
|
{
|
|
getXNameContainer()->removeByName( Name );
|
|
}
|
|
|
|
// Methods from XIndexAccess
|
|
// Already in XNameAccess: virtual Reference<XIdlClass> getElementType() const
|
|
sal_Int32 ImplIntrospectionAccess::getCount()
|
|
{
|
|
return getXIndexAccess()->getCount();
|
|
}
|
|
|
|
Any ImplIntrospectionAccess::getByIndex(sal_Int32 Index)
|
|
{
|
|
return getXIndexAccess()->getByIndex( Index );
|
|
}
|
|
|
|
// Methods from XIndexContainer
|
|
void ImplIntrospectionAccess::insertByIndex(sal_Int32 Index, const Any& Element)
|
|
{
|
|
getXIndexContainer()->insertByIndex( Index, Element );
|
|
}
|
|
|
|
void ImplIntrospectionAccess::replaceByIndex(sal_Int32 Index, const Any& Element)
|
|
{
|
|
getXIndexReplace()->replaceByIndex( Index, Element );
|
|
}
|
|
|
|
void ImplIntrospectionAccess::removeByIndex(sal_Int32 Index)
|
|
{
|
|
getXIndexContainer()->removeByIndex( Index );
|
|
}
|
|
|
|
// Methods from XEnumerationAccess
|
|
// Already in XNameAccess: virtual Reference<XIdlClass> getElementType() const;
|
|
Reference<XEnumeration> ImplIntrospectionAccess::createEnumeration()
|
|
{
|
|
return getXEnumerationAccess()->createEnumeration();
|
|
}
|
|
|
|
// Methods from XIdlArray
|
|
void ImplIntrospectionAccess::realloc(Any& array, sal_Int32 length)
|
|
{
|
|
getXIdlArray()->realloc( array, length );
|
|
}
|
|
|
|
sal_Int32 ImplIntrospectionAccess::getLen(const Any& array)
|
|
{
|
|
return getXIdlArray()->getLen( array );
|
|
}
|
|
|
|
Any ImplIntrospectionAccess::get(const Any& array, sal_Int32 index)
|
|
{
|
|
return getXIdlArray()->get( array, index );
|
|
}
|
|
|
|
void ImplIntrospectionAccess::set(Any& array, sal_Int32 index, const Any& value)
|
|
{
|
|
getXIdlArray()->set( array, index, value );
|
|
}
|
|
|
|
// Methods from XUnoTunnel
|
|
sal_Int64 ImplIntrospectionAccess::getSomething( const Sequence< sal_Int8 >& aIdentifier )
|
|
{
|
|
return Reference<XUnoTunnel>::query( mxIface )->getSomething( aIdentifier );
|
|
}
|
|
|
|
|
|
//*** Implementation of ImplIntrospectionAccess ***
|
|
|
|
// Methods from XIntrospectionAccess
|
|
sal_Int32 ImplIntrospectionAccess::getSuppliedMethodConcepts()
|
|
{
|
|
return MethodConcept::DANGEROUS |
|
|
PROPERTY |
|
|
LISTENER |
|
|
ENUMERATION |
|
|
NAMECONTAINER |
|
|
INDEXCONTAINER;
|
|
}
|
|
|
|
sal_Int32 ImplIntrospectionAccess::getSuppliedPropertyConcepts()
|
|
{
|
|
return PropertyConcept::DANGEROUS |
|
|
PROPERTYSET |
|
|
ATTRIBUTES |
|
|
METHODS;
|
|
}
|
|
|
|
Property ImplIntrospectionAccess::getProperty(const OUString& Name, sal_Int32 PropertyConcepts)
|
|
{
|
|
Property aRet;
|
|
sal_Int32 i = mpStaticImpl->getPropertyIndex( Name );
|
|
bool bFound = false;
|
|
if( i != -1 )
|
|
{
|
|
sal_Int32 nConcept = mpStaticImpl->getPropertyConcepts()[ i ];
|
|
if( (PropertyConcepts & nConcept) != 0 )
|
|
{
|
|
aRet = mpStaticImpl->getProperties()[ i ];
|
|
bFound = true;
|
|
}
|
|
}
|
|
if( !bFound )
|
|
throw NoSuchElementException(Name);
|
|
return aRet;
|
|
}
|
|
|
|
sal_Bool ImplIntrospectionAccess::hasProperty(const OUString& Name, sal_Int32 PropertyConcepts)
|
|
{
|
|
sal_Int32 i = mpStaticImpl->getPropertyIndex( Name );
|
|
bool bRet = false;
|
|
if( i != -1 )
|
|
{
|
|
sal_Int32 nConcept = mpStaticImpl->getPropertyConcepts()[ i ];
|
|
if( (PropertyConcepts & nConcept) != 0 )
|
|
bRet = true;
|
|
}
|
|
return bRet;
|
|
}
|
|
|
|
Sequence< Property > ImplIntrospectionAccess::getProperties(sal_Int32 PropertyConcepts)
|
|
{
|
|
// If all supported concepts are required, simply pass through the sequence
|
|
sal_Int32 nAllSupportedMask = PROPERTYSET |
|
|
ATTRIBUTES |
|
|
METHODS;
|
|
if( ( PropertyConcepts & nAllSupportedMask ) == nAllSupportedMask )
|
|
{
|
|
return comphelper::containerToSequence(mpStaticImpl->getProperties());
|
|
}
|
|
|
|
// Same sequence as last time?
|
|
if( mnLastPropertyConcept == PropertyConcepts )
|
|
{
|
|
return maLastPropertySeq;
|
|
}
|
|
|
|
// Number of properties to be delivered
|
|
sal_Int32 nCount = 0;
|
|
|
|
// There are currently no DANGEROUS properties
|
|
// if( PropertyConcepts & DANGEROUS )
|
|
// nCount += mpStaticImpl->mnDangerousPropCount;
|
|
if( PropertyConcepts & PROPERTYSET )
|
|
nCount += mpStaticImpl->mnPropertySetPropCount;
|
|
if( PropertyConcepts & ATTRIBUTES )
|
|
nCount += mpStaticImpl->mnAttributePropCount;
|
|
if( PropertyConcepts & METHODS )
|
|
nCount += mpStaticImpl->mnMethodPropCount;
|
|
|
|
// Realloc sequence according to the required number
|
|
maLastPropertySeq.realloc( nCount );
|
|
Property* pDestProps = maLastPropertySeq.getArray();
|
|
|
|
// Go through all the properties and apply according to the concept
|
|
const std::vector<Property>& rPropSeq = mpStaticImpl->getProperties();
|
|
const std::vector<sal_Int32>& rConcepts = mpStaticImpl->getPropertyConcepts();
|
|
sal_Int32 nLen = static_cast<sal_Int32>(rPropSeq.size());
|
|
|
|
sal_Int32 iDest = 0;
|
|
for( sal_Int32 i = 0 ; i < nLen ; i++ )
|
|
{
|
|
sal_Int32 nConcept = rConcepts[ i ];
|
|
if( nConcept & PropertyConcepts )
|
|
pDestProps[ iDest++ ] = rPropSeq[ i ];
|
|
}
|
|
|
|
// Remember PropertyConcept representing maLastPropertySeq
|
|
mnLastPropertyConcept = PropertyConcepts;
|
|
|
|
// Supply assembled Sequence
|
|
return maLastPropertySeq;
|
|
}
|
|
|
|
Reference<XIdlMethod> ImplIntrospectionAccess::getMethod(const OUString& Name, sal_Int32 MethodConcepts)
|
|
{
|
|
Reference<XIdlMethod> xRet;
|
|
sal_Int32 i = mpStaticImpl->getMethodIndex( Name );
|
|
if( i != -1 )
|
|
{
|
|
|
|
sal_Int32 nConcept = mpStaticImpl->getMethodConcepts()[ i ];
|
|
if( (MethodConcepts & nConcept) != 0 )
|
|
{
|
|
xRet = mpStaticImpl->getMethods()[i];
|
|
}
|
|
}
|
|
if( !xRet.is() )
|
|
throw NoSuchMethodException(Name);
|
|
return xRet;
|
|
}
|
|
|
|
sal_Bool ImplIntrospectionAccess::hasMethod(const OUString& Name, sal_Int32 MethodConcepts)
|
|
{
|
|
sal_Int32 i = mpStaticImpl->getMethodIndex( Name );
|
|
bool bRet = false;
|
|
if( i != -1 )
|
|
{
|
|
sal_Int32 nConcept = mpStaticImpl->getMethodConcepts()[ i ];
|
|
if( (MethodConcepts & nConcept) != 0 )
|
|
bRet = true;
|
|
}
|
|
return bRet;
|
|
}
|
|
|
|
Sequence< Reference<XIdlMethod> > ImplIntrospectionAccess::getMethods(sal_Int32 MethodConcepts)
|
|
{
|
|
// If all supported concepts are required, simply pass through the sequence
|
|
sal_Int32 nAllSupportedMask = MethodConcept::DANGEROUS |
|
|
PROPERTY |
|
|
LISTENER |
|
|
ENUMERATION |
|
|
NAMECONTAINER |
|
|
INDEXCONTAINER |
|
|
MethodConcept_NORMAL_IMPL;
|
|
if( ( MethodConcepts & nAllSupportedMask ) == nAllSupportedMask )
|
|
{
|
|
return comphelper::containerToSequence(mpStaticImpl->getMethods());
|
|
}
|
|
|
|
// Same sequence as last time?
|
|
if( mnLastMethodConcept == MethodConcepts )
|
|
{
|
|
return maLastMethodSeq;
|
|
}
|
|
|
|
// Get method sequences
|
|
const std::vector< Reference<XIdlMethod> >& aMethodSeq = mpStaticImpl->getMethods();
|
|
sal_Int32 nLen = static_cast<sal_Int32>(aMethodSeq.size());
|
|
|
|
// Realloc sequence according to the required number
|
|
// Unlike Properties, the number can not be determined by counters in
|
|
// inspect() beforehand, since methods can belong to several concepts
|
|
maLastMethodSeq.realloc( nLen );
|
|
Reference<XIdlMethod>* pDestMethods = maLastMethodSeq.getArray();
|
|
|
|
// Go through all the methods and apply according to the concept
|
|
sal_Int32 iDest = 0;
|
|
for( sal_Int32 i = 0 ; i < nLen ; i++ )
|
|
{
|
|
sal_Int32 nConcept = mpStaticImpl->getMethodConcepts()[ i ];
|
|
if( nConcept & MethodConcepts )
|
|
pDestMethods[ iDest++ ] = aMethodSeq[ i ];
|
|
}
|
|
|
|
// Bring to the correct length
|
|
maLastMethodSeq.realloc( iDest );
|
|
|
|
// Remember MethodConcept representing maLastMethodSeq
|
|
mnLastMethodConcept = MethodConcepts;
|
|
|
|
// Supply assembled Sequence
|
|
return maLastMethodSeq;
|
|
}
|
|
|
|
Sequence< Type > ImplIntrospectionAccess::getSupportedListeners()
|
|
{
|
|
return comphelper::containerToSequence(mpStaticImpl->getSupportedListeners());
|
|
}
|
|
|
|
Reference<XInterface> SAL_CALL ImplIntrospectionAccess::queryAdapter( const Type& rType )
|
|
{
|
|
Reference<XInterface> xRet;
|
|
if( rType == cppu::UnoType<XInterface>::get()
|
|
|| rType == cppu::UnoType<XPropertySet>::get()
|
|
|| rType == cppu::UnoType<XFastPropertySet>::get()
|
|
|| rType == cppu::UnoType<XPropertySetInfo>::get()
|
|
|| rType == cppu::UnoType<XElementAccess>::get()
|
|
|| rType == cppu::UnoType<XNameAccess>::get()
|
|
|| rType == cppu::UnoType<XNameReplace>::get()
|
|
|| rType == cppu::UnoType<XNameContainer>::get()
|
|
|| rType == cppu::UnoType<XIndexAccess>::get()
|
|
|| rType == cppu::UnoType<XIndexReplace>::get()
|
|
|| rType == cppu::UnoType<XIndexContainer>::get()
|
|
|| rType == cppu::UnoType<XEnumerationAccess>::get()
|
|
|| rType == cppu::UnoType<XIdlArray>::get()
|
|
|| rType == cppu::UnoType<XUnoTunnel>::get() )
|
|
{
|
|
queryInterface( rType ) >>= xRet;
|
|
}
|
|
return xRet;
|
|
}
|
|
|
|
// Methods from XMaterialHolder
|
|
Any ImplIntrospectionAccess::getMaterial()
|
|
{
|
|
return maInspectedObject;
|
|
}
|
|
|
|
// Methods from XExactName
|
|
OUString ImplIntrospectionAccess::getExactName( const OUString& rApproximateName )
|
|
{
|
|
OUString aRetStr;
|
|
LowerToExactNameMap::iterator aIt =
|
|
mpStaticImpl->maLowerToExactNameMap.find( rApproximateName.toAsciiLowerCase() );
|
|
if (aIt != mpStaticImpl->maLowerToExactNameMap.end())
|
|
aRetStr = (*aIt).second;
|
|
return aRetStr;
|
|
}
|
|
|
|
struct TypeKey {
|
|
TypeKey(
|
|
css::uno::Reference<css::beans::XPropertySetInfo> const & theProperties,
|
|
std::vector<css::uno::Type> const & theTypes):
|
|
properties(theProperties)
|
|
{
|
|
//TODO: Could even sort the types lexicographically first, to increase
|
|
// the chance of matches between different implementations' getTypes(),
|
|
// but the old scheme of using getImplementationId() would have missed
|
|
// those matches, too:
|
|
OUStringBuffer b;
|
|
for (const css::uno::Type& rType : theTypes) {
|
|
b.append(rType.getTypeName());
|
|
b.append('*'); // arbitrary delimiter not used by type grammar
|
|
}
|
|
types = b.makeStringAndClear();
|
|
}
|
|
|
|
css::uno::Reference<css::beans::XPropertySetInfo> properties;
|
|
OUString types;
|
|
};
|
|
|
|
struct TypeKeyLess {
|
|
bool operator ()(TypeKey const & key1, TypeKey const & key2) const {
|
|
if (key1.properties.get() < key2.properties.get()) {
|
|
return true;
|
|
}
|
|
if (key1.properties.get() > key2.properties.get()) {
|
|
return false;
|
|
}
|
|
return key1.types < key2.types;
|
|
}
|
|
};
|
|
|
|
template<typename Key, typename Less> class Cache {
|
|
public:
|
|
rtl::Reference<IntrospectionAccessStatic_Impl> find(Key const & key) const {
|
|
typename Map::const_iterator i(map_.find(key));
|
|
if (i == map_.end()) {
|
|
return rtl::Reference<IntrospectionAccessStatic_Impl>();
|
|
} else {
|
|
if (i->second.hits < std::numeric_limits<unsigned>::max()) {
|
|
++i->second.hits;
|
|
}
|
|
assert(i->second.access.is());
|
|
return i->second.access;
|
|
}
|
|
}
|
|
|
|
void insert(
|
|
Key const & key,
|
|
rtl::Reference<IntrospectionAccessStatic_Impl> const & access)
|
|
{
|
|
assert(access.is());
|
|
typename Map::size_type const MAX = 100;
|
|
assert(map_.size() <= MAX);
|
|
if (map_.size() == MAX) {
|
|
typename Map::iterator del(map_.begin());
|
|
for (typename Map::iterator i(map_.begin()); i != map_.end(); ++i) {
|
|
if (i->second.hits < del->second.hits) {
|
|
del = i;
|
|
}
|
|
}
|
|
map_.erase(del);
|
|
}
|
|
bool ins = map_.emplace(key, Data(access)).second;
|
|
assert(ins); (void)ins;
|
|
}
|
|
|
|
void clear() { map_.clear(); }
|
|
|
|
private:
|
|
struct Data {
|
|
explicit Data(
|
|
rtl::Reference<IntrospectionAccessStatic_Impl> const & theAccess):
|
|
access(theAccess), hits(1)
|
|
{}
|
|
|
|
rtl::Reference<IntrospectionAccessStatic_Impl> access;
|
|
mutable unsigned hits;
|
|
};
|
|
|
|
typedef std::map<Key, Data, Less> Map;
|
|
|
|
Map map_;
|
|
};
|
|
|
|
typedef
|
|
cppu::WeakComponentImplHelper<
|
|
css::lang::XServiceInfo, css::beans::XIntrospection>
|
|
Implementation_Base;
|
|
|
|
class Implementation: private cppu::BaseMutex, public Implementation_Base {
|
|
public:
|
|
explicit Implementation(
|
|
css::uno::Reference<css::uno::XComponentContext> const & context):
|
|
Implementation_Base(m_aMutex),
|
|
reflection_(css::reflection::theCoreReflection::get(context))
|
|
{}
|
|
|
|
private:
|
|
virtual void SAL_CALL disposing() override {
|
|
osl::MutexGuard g(m_aMutex);
|
|
reflection_.clear();
|
|
typeCache_.clear();
|
|
}
|
|
|
|
virtual OUString SAL_CALL getImplementationName() override
|
|
{ return OUString("com.sun.star.comp.stoc.Introspection"); }
|
|
|
|
virtual sal_Bool SAL_CALL supportsService(OUString const & ServiceName) override
|
|
{ return cppu::supportsService(this, ServiceName); }
|
|
|
|
virtual css::uno::Sequence<OUString> SAL_CALL
|
|
getSupportedServiceNames() override
|
|
{
|
|
Sequence<OUString> s { "com.sun.star.beans.Introspection" };
|
|
return s;
|
|
}
|
|
|
|
virtual css::uno::Reference<css::beans::XIntrospectionAccess> SAL_CALL
|
|
inspect(css::uno::Any const & aObject) override;
|
|
|
|
css::uno::Reference<css::reflection::XIdlReflection> reflection_;
|
|
Cache<TypeKey, TypeKeyLess> typeCache_;
|
|
};
|
|
|
|
css::uno::Reference<css::beans::XIntrospectionAccess> Implementation::inspect(
|
|
css::uno::Any const & aObject)
|
|
{
|
|
css::uno::Reference<css::reflection::XIdlReflection> reflection;
|
|
{
|
|
osl::MutexGuard g(m_aMutex);
|
|
if (rBHelper.bDisposed || rBHelper.bInDispose) {
|
|
throw css::lang::DisposedException(
|
|
getImplementationName(), static_cast<OWeakObject *>(this));
|
|
}
|
|
reflection = reflection_;
|
|
}
|
|
css::uno::Any aToInspectObj;
|
|
css::uno::Type t;
|
|
if (aObject >>= t) {
|
|
css::uno::Reference<css::reflection::XIdlClass> c(
|
|
reflection->forName(t.getTypeName()));
|
|
if (!c.is()) {
|
|
SAL_WARN("stoc", "cannot reflect type " << t.getTypeName());
|
|
return css::uno::Reference<css::beans::XIntrospectionAccess>();
|
|
}
|
|
aToInspectObj <<= c;
|
|
} else {
|
|
aToInspectObj = aObject;
|
|
}
|
|
|
|
// Examine object
|
|
TypeClass eType = aToInspectObj.getValueType().getTypeClass();
|
|
if( eType != TypeClass_INTERFACE && eType != TypeClass_STRUCT && eType != TypeClass_EXCEPTION )
|
|
return css::uno::Reference<css::beans::XIntrospectionAccess>();
|
|
|
|
if( auto x = o3tl::tryAccess<Reference<XInterface>>(aToInspectObj) )
|
|
{
|
|
if( !x->is() )
|
|
return css::uno::Reference<css::beans::XIntrospectionAccess>();
|
|
}
|
|
|
|
// Pointer to possibly needed new IntrospectionAccessStatic_Impl instance
|
|
rtl::Reference< IntrospectionAccessStatic_Impl > pAccess;
|
|
|
|
// Check: Is a matching access object already cached?
|
|
std::vector< Reference<XIdlClass> > SupportedClassSeq;
|
|
std::vector< Type > SupportedTypesSeq;
|
|
Reference<XTypeProvider> xTypeProvider;
|
|
Reference<XPropertySetInfo> xPropSetInfo;
|
|
Reference<XPropertySet> xPropSet;
|
|
|
|
// Look for interfaces XTypeProvider and PropertySet
|
|
if( eType == TypeClass_INTERFACE )
|
|
{
|
|
xTypeProvider.set( aToInspectObj, UNO_QUERY );
|
|
if( xTypeProvider.is() )
|
|
{
|
|
SupportedTypesSeq = comphelper::sequenceToContainer<std::vector<Type>>(xTypeProvider->getTypes());
|
|
} else {
|
|
SAL_WARN(
|
|
"stoc",
|
|
"object of type \"" << aToInspectObj.getValueTypeName()
|
|
<< "\" lacks XTypeProvider");
|
|
SupportedTypesSeq = { aToInspectObj.getValueType() };
|
|
}
|
|
// Now try to get the PropertySetInfo
|
|
xPropSet.set( aToInspectObj, UNO_QUERY );
|
|
if( xPropSet.is() )
|
|
xPropSetInfo = xPropSet->getPropertySetInfo();
|
|
|
|
} else {
|
|
SupportedTypesSeq = { aToInspectObj.getValueType() };
|
|
}
|
|
|
|
{
|
|
osl::MutexGuard g(m_aMutex);
|
|
if (rBHelper.bDisposed || rBHelper.bInDispose) {
|
|
throw css::lang::DisposedException(
|
|
getImplementationName(), static_cast<OWeakObject *>(this));
|
|
}
|
|
TypeKey key(xPropSetInfo, SupportedTypesSeq);
|
|
pAccess = typeCache_.find(key);
|
|
if (pAccess.is()) {
|
|
return new ImplIntrospectionAccess(aToInspectObj, pAccess);
|
|
}
|
|
pAccess = new IntrospectionAccessStatic_Impl(reflection);
|
|
typeCache_.insert(key, pAccess);
|
|
}
|
|
|
|
// No access cached -> create new
|
|
std::vector<Property>& rAllPropArray = pAccess->maAllPropertySeq;
|
|
std::vector<Reference<XInterface>>& rInterfaces1 = pAccess->aInterfaceSeq1;
|
|
std::vector<Reference<XInterface>>& rInterfaces2 = pAccess->aInterfaceSeq2;
|
|
std::vector<sal_Int16>& rMapTypeArray = pAccess->maMapTypeSeq;
|
|
std::vector<sal_Int32>& rPropertyConceptArray = pAccess->maPropertyConceptSeq;
|
|
sal_Int32 i;
|
|
|
|
// References to important data from pAccess
|
|
sal_Int32& rPropCount = pAccess->mnPropCount;
|
|
IntrospectionNameMap& rPropNameMap = pAccess->maPropertyNameMap;
|
|
IntrospectionNameMap& rMethodNameMap = pAccess->maMethodNameMap;
|
|
LowerToExactNameMap& rLowerToExactNameMap = pAccess->maLowerToExactNameMap;
|
|
|
|
|
|
//*** Perform analysis ***
|
|
|
|
if( eType == TypeClass_INTERFACE )
|
|
{
|
|
size_t nTypeCount = SupportedTypesSeq.size();
|
|
if( nTypeCount )
|
|
{
|
|
SupportedClassSeq.resize( nTypeCount );
|
|
|
|
for( i = 0 ; i < static_cast<sal_Int32>(nTypeCount) ; i++ )
|
|
SupportedClassSeq[i] = reflection->forName( SupportedTypesSeq[i].getTypeName() );
|
|
}
|
|
|
|
// First look for particular interfaces that are of particular
|
|
// importance to the introspection
|
|
|
|
// Is XPropertySet present?
|
|
if( xPropSet.is() && xPropSetInfo.is() )
|
|
{
|
|
// Is there also a FastPropertySet?
|
|
Reference<XFastPropertySet> xDummy( aToInspectObj, UNO_QUERY );
|
|
bool bFast = pAccess->mbFastPropSet = xDummy.is();
|
|
|
|
Sequence<Property> aPropSeq = xPropSetInfo->getProperties();
|
|
const Property* pProps = aPropSeq.getConstArray();
|
|
sal_Int32 nLen = aPropSeq.getLength();
|
|
|
|
// For a FastPropertySet we must remember the original handles
|
|
if( bFast )
|
|
pAccess->mpOrgPropertyHandleArray.reset( new sal_Int32[ nLen ] );
|
|
|
|
for( i = 0 ; i < nLen ; i++ )
|
|
{
|
|
// Put property in its own list
|
|
pAccess->checkPropertyArraysSize( rPropCount );
|
|
Property& rProp = rAllPropArray[ rPropCount ];
|
|
rProp = pProps[ i ];
|
|
|
|
if( bFast )
|
|
pAccess->mpOrgPropertyHandleArray[ i ] = rProp.Handle;
|
|
|
|
// Enter PropCount as a handle for its own FastPropertySet
|
|
rProp.Handle = rPropCount;
|
|
|
|
// Remember type of property
|
|
rMapTypeArray[ rPropCount ] = MAP_PROPERTY_SET;
|
|
rPropertyConceptArray[ rPropCount ] = PROPERTYSET;
|
|
pAccess->mnPropertySetPropCount++;
|
|
|
|
// Enter name in hash table if not already known
|
|
OUString aPropName = rProp.Name;
|
|
|
|
// Do we already have the name?
|
|
IntrospectionNameMap::iterator aIt = rPropNameMap.find( aPropName );
|
|
if( aIt == rPropNameMap.end() )
|
|
{
|
|
// New entry in the hash table
|
|
rPropNameMap[ aPropName ] = rPropCount;
|
|
|
|
// Maintain table for XExactName
|
|
rLowerToExactNameMap[ aPropName.toAsciiLowerCase() ] = aPropName;
|
|
}
|
|
else
|
|
{
|
|
SAL_WARN( "stoc", "Introspection: Property \"" <<
|
|
aPropName << "\" found more than once in PropertySet" );
|
|
}
|
|
|
|
// Adjust count
|
|
rPropCount++;
|
|
}
|
|
}
|
|
|
|
// Indices in the export table
|
|
sal_Int32 iAllExportedMethod = 0;
|
|
sal_Int32 iAllSupportedListener = 0;
|
|
|
|
std::set<OUString> seen;
|
|
|
|
// Flag, whether XInterface methods should be recorded
|
|
// (this must be done only once, allowed initially)
|
|
bool bXInterfaceIsInvalid = false;
|
|
|
|
// Flag whether the XInterface methods have already been recorded. If
|
|
// sal_True, bXInterfaceIsInvalid is activated at the end of the interface
|
|
// loop, and XInterface methods are cut off thereafter.
|
|
bool bFoundXInterface = false;
|
|
|
|
size_t nClassCount = SupportedClassSeq.size();
|
|
for( sal_Int32 nIdx = 0 ; nIdx < static_cast<sal_Int32>(nClassCount); nIdx++ )
|
|
{
|
|
Reference<XIdlClass> xImplClass2 = SupportedClassSeq[nIdx];
|
|
while( xImplClass2.is() )
|
|
{
|
|
// Fetch interfaces from the implementation
|
|
Sequence< Reference<XIdlClass> > aClassSeq = xImplClass2->getInterfaces();
|
|
sal_Int32 nIfaceCount = aClassSeq.getLength();
|
|
|
|
aClassSeq.realloc( nIfaceCount + 1 );
|
|
aClassSeq.getArray()[ nIfaceCount ] = xImplClass2;
|
|
nIfaceCount++;
|
|
|
|
const Reference<XIdlClass>* pParamArray = aClassSeq.getConstArray();
|
|
|
|
for( sal_Int32 j = 0 ; j < nIfaceCount ; j++ )
|
|
{
|
|
const Reference<XIdlClass>& rxIfaceClass = pParamArray[j];
|
|
if (!seen.insert(rxIfaceClass->getName()).second) {
|
|
continue;
|
|
}
|
|
|
|
// 2. Register fields as properties
|
|
|
|
// Get fields
|
|
Sequence< Reference<XIdlField> > fields = rxIfaceClass->getFields();
|
|
const Reference<XIdlField>* pFields = fields.getConstArray();
|
|
sal_Int32 nLen = fields.getLength();
|
|
|
|
for( i = 0 ; i < nLen ; i++ )
|
|
{
|
|
Reference<XIdlField> xField = pFields[i];
|
|
Reference<XIdlClass> xPropType = xField->getType();
|
|
|
|
// Is the property sequence big enough?
|
|
pAccess->checkPropertyArraysSize( rPropCount );
|
|
|
|
// Enter in own property array
|
|
Property& rProp = rAllPropArray[ rPropCount ];
|
|
OUString aFieldName = xField->getName();
|
|
rProp.Name = aFieldName;
|
|
rProp.Handle = rPropCount;
|
|
Type aFieldType( xPropType->getTypeClass(), xPropType->getName() );
|
|
rProp.Type = aFieldType;
|
|
FieldAccessMode eAccessMode = xField->getAccessMode();
|
|
rProp.Attributes = (eAccessMode == FieldAccessMode_READONLY ||
|
|
eAccessMode == FieldAccessMode_CONST)
|
|
? READONLY : 0;
|
|
|
|
// Enter name in hash table
|
|
OUString aPropName = rProp.Name;
|
|
|
|
// Do we have the name already?
|
|
IntrospectionNameMap::iterator aIt = rPropNameMap.find( aPropName );
|
|
if (aIt != rPropNameMap.end())
|
|
continue;
|
|
|
|
// New entry in the hash table
|
|
rPropNameMap[ aPropName ] = rPropCount;
|
|
|
|
// Maintain table for XExactName
|
|
rLowerToExactNameMap[ aPropName.toAsciiLowerCase() ] = aPropName;
|
|
|
|
// Remember field
|
|
IntrospectionAccessStatic_Impl::checkInterfaceArraySize( pAccess->aInterfaceSeq1,
|
|
rInterfaces1, rPropCount );
|
|
rInterfaces1[ rPropCount ] = xField;
|
|
|
|
// Remember type of property
|
|
rMapTypeArray[ rPropCount ] = MAP_FIELD;
|
|
rPropertyConceptArray[ rPropCount ] = ATTRIBUTES;
|
|
pAccess->mnAttributePropCount++;
|
|
|
|
// Adjust count
|
|
rPropCount++;
|
|
}
|
|
|
|
|
|
// 3. Methods
|
|
|
|
// Counter for found listeners
|
|
sal_Int32 nListenerCount = 0;
|
|
|
|
// Get and remember all methods
|
|
Sequence< Reference<XIdlMethod> > methods = rxIfaceClass->getMethods();
|
|
const Reference<XIdlMethod>* pSourceMethods = methods.getConstArray();
|
|
sal_Int32 nSourceMethodCount = methods.getLength();
|
|
|
|
// 3. a) Search get/set and listener methods
|
|
|
|
// Create field for information about the methods, so that methods which are not
|
|
// related to properties or listeners can easily be found later.
|
|
// New: initialise MethodConceptArray
|
|
enum MethodType
|
|
{
|
|
STANDARD_METHOD, // normal method, not related to properties or listeners
|
|
GETSET_METHOD, // belongs to a get/set property
|
|
ADD_LISTENER_METHOD, // add method of a listener interface
|
|
REMOVE_LISTENER_METHOD, // remove method of a listener interface
|
|
INVALID_METHOD // method whose class is not considered, e.g. XPropertySet
|
|
};
|
|
std::unique_ptr<MethodType[]> pMethodTypes( new MethodType[ nSourceMethodCount ] );
|
|
std::unique_ptr<sal_Int32[]> pLocalMethodConcepts( new sal_Int32[ nSourceMethodCount ] );
|
|
for( i = 0 ; i < nSourceMethodCount ; i++ )
|
|
{
|
|
pMethodTypes[ i ] = STANDARD_METHOD;
|
|
pLocalMethodConcepts[ i ] = 0;
|
|
}
|
|
|
|
for( i = 0 ; i < nSourceMethodCount ; i++ )
|
|
{
|
|
// Address method
|
|
const Reference<XIdlMethod>& rxMethod_i = pSourceMethods[i];
|
|
sal_Int32& rMethodConcept_i = pLocalMethodConcepts[ i ];
|
|
|
|
// Fetch name
|
|
OUString aMethName = rxMethod_i->getName();
|
|
|
|
// Catalogue methods
|
|
// Filter all (?) methods of XInterface so e.g. acquire and release
|
|
// can not be called from scripting
|
|
OUString className(
|
|
rxMethod_i->getDeclaringClass()->getName());
|
|
if (className == "com.sun.star.uno.XInterface") {
|
|
bFoundXInterface = true;
|
|
|
|
if( bXInterfaceIsInvalid )
|
|
{
|
|
pMethodTypes[ i ] = INVALID_METHOD;
|
|
continue;
|
|
}
|
|
else
|
|
{
|
|
if( aMethName != "queryInterface" )
|
|
{
|
|
rMethodConcept_i |= MethodConcept::DANGEROUS;
|
|
continue;
|
|
}
|
|
}
|
|
} else if (className == "com.sun.star.uno.XAggregation")
|
|
{
|
|
if( aMethName == "setDelegator" )
|
|
{
|
|
rMethodConcept_i |= MethodConcept::DANGEROUS;
|
|
continue;
|
|
}
|
|
} else if (className
|
|
== "com.sun.star.container.XElementAccess")
|
|
{
|
|
rMethodConcept_i |= ( NAMECONTAINER |
|
|
INDEXCONTAINER |
|
|
ENUMERATION );
|
|
pAccess->mbElementAccess = true;
|
|
} else if (className
|
|
== "com.sun.star.container.XNameContainer")
|
|
{
|
|
rMethodConcept_i |= NAMECONTAINER;
|
|
pAccess->mbNameContainer = true;
|
|
pAccess->mbNameReplace = true;
|
|
pAccess->mbNameAccess = true;
|
|
pAccess->mbElementAccess = true;
|
|
} else if (className
|
|
== "com.sun.star.container.XNameReplace")
|
|
{
|
|
rMethodConcept_i |= NAMECONTAINER;
|
|
pAccess->mbNameReplace = true;
|
|
pAccess->mbNameAccess = true;
|
|
pAccess->mbElementAccess = true;
|
|
} else if (className
|
|
== "com.sun.star.container.XNameAccess")
|
|
{
|
|
rMethodConcept_i |= NAMECONTAINER;
|
|
pAccess->mbNameAccess = true;
|
|
pAccess->mbElementAccess = true;
|
|
} else if (className
|
|
== "com.sun.star.container.XIndexContainer")
|
|
{
|
|
rMethodConcept_i |= INDEXCONTAINER;
|
|
pAccess->mbIndexContainer = true;
|
|
pAccess->mbIndexReplace = true;
|
|
pAccess->mbIndexAccess = true;
|
|
pAccess->mbElementAccess = true;
|
|
} else if (className
|
|
== "com.sun.star.container.XIndexReplace")
|
|
{
|
|
rMethodConcept_i |= INDEXCONTAINER;
|
|
pAccess->mbIndexReplace = true;
|
|
pAccess->mbIndexAccess = true;
|
|
pAccess->mbElementAccess = true;
|
|
} else if (className
|
|
== "com.sun.star.container.XIndexAccess")
|
|
{
|
|
rMethodConcept_i |= INDEXCONTAINER;
|
|
pAccess->mbIndexAccess = true;
|
|
pAccess->mbElementAccess = true;
|
|
} else if (className
|
|
== "com.sun.star.container.XEnumerationAccess")
|
|
{
|
|
rMethodConcept_i |= ENUMERATION;
|
|
pAccess->mbEnumerationAccess = true;
|
|
pAccess->mbElementAccess = true;
|
|
} else if (className
|
|
== "com.sun.star.reflection.XIdlArray")
|
|
{
|
|
pAccess->mbIdlArray = true;
|
|
} else if (className
|
|
== "com.sun.star.lang.XUnoTunnel")
|
|
{
|
|
pAccess->mbUnoTunnel = true;
|
|
}
|
|
|
|
// If the name is too short, it isn't anything
|
|
if( aMethName.getLength() <= 3 )
|
|
continue;
|
|
|
|
// Is it a get method?
|
|
OUString aPropName;
|
|
if( aMethName.startsWith("get", &aPropName) )
|
|
{
|
|
// Get methods must not have any parameters
|
|
Sequence< Reference<XIdlClass> > getParams = rxMethod_i->getParameterTypes();
|
|
if( getParams.getLength() > 0 )
|
|
{
|
|
continue;
|
|
}
|
|
|
|
// Do we have the name already?
|
|
IntrospectionNameMap::iterator aIt = rPropNameMap.find( aPropName );
|
|
if (aIt != rPropNameMap.end())
|
|
{
|
|
/* TODO
|
|
SAL_INFO("stoc",(
|
|
String( "Introspection: Property \"" ) +
|
|
OOUStringToString( aPropName, CHARSET_SYSTEM ) +
|
|
String( "\" found more than once" ) );
|
|
*/
|
|
continue;
|
|
}
|
|
|
|
// It is already at least a read-only property
|
|
rMethodConcept_i |= PROPERTY;
|
|
|
|
pMethodTypes[i] = GETSET_METHOD;
|
|
Reference<XIdlClass> xGetRetType = rxMethod_i->getReturnType();
|
|
|
|
// Is the property sequence big enough?
|
|
pAccess->checkPropertyArraysSize( rPropCount );
|
|
|
|
// Write it in its property array
|
|
Property& rProp = rAllPropArray[ rPropCount ];
|
|
rProp.Name = aPropName;
|
|
rProp.Handle = rPropCount;
|
|
rProp.Type = Type( xGetRetType->getTypeClass(), xGetRetType->getName() );
|
|
rProp.Attributes = READONLY;
|
|
|
|
// New entry in the hash table
|
|
rPropNameMap[ aPropName ] = rPropCount;
|
|
|
|
// Maintain table for XExactName
|
|
rLowerToExactNameMap[ aPropName.toAsciiLowerCase() ] = aPropName;
|
|
|
|
// Remember get method
|
|
IntrospectionAccessStatic_Impl::checkInterfaceArraySize( pAccess->aInterfaceSeq1,
|
|
rInterfaces1, rPropCount );
|
|
rInterfaces1[ rPropCount ] = rxMethod_i;
|
|
|
|
// Remember type of property
|
|
rMapTypeArray[ rPropCount ] = MAP_GETSET;
|
|
rPropertyConceptArray[ rPropCount ] = METHODS;
|
|
pAccess->mnMethodPropCount++;
|
|
|
|
// Search for matching set method
|
|
sal_Int32 k;
|
|
for( k = 0 ; k < nSourceMethodCount ; k++ )
|
|
{
|
|
// Address method
|
|
const Reference<XIdlMethod>& rxMethod_k = pSourceMethods[k];
|
|
|
|
// Accept only methods that are not already assigned
|
|
if( k == i || pMethodTypes[k] != STANDARD_METHOD )
|
|
continue;
|
|
|
|
// Get name and evaluate
|
|
OUString aMethName2 = rxMethod_k->getName();
|
|
OUString aPropName2;
|
|
if (!(aMethName2.startsWith("set", &aPropName2)
|
|
&& aPropName2 == aPropName))
|
|
continue;
|
|
|
|
// A set method must return void
|
|
Reference<XIdlClass> xSetRetType = rxMethod_k->getReturnType();
|
|
if( xSetRetType->getTypeClass() != TypeClass_VOID )
|
|
{
|
|
continue;
|
|
}
|
|
|
|
// A set method may only have one parameter
|
|
Sequence< Reference<XIdlClass> > setParams = rxMethod_k->getParameterTypes();
|
|
sal_Int32 nParamCount = setParams.getLength();
|
|
if( nParamCount != 1 )
|
|
{
|
|
continue;
|
|
}
|
|
|
|
// Next, the return type must correspond to the parameter type
|
|
const Reference<XIdlClass>* pParamArray2 = setParams.getConstArray();
|
|
Reference<XIdlClass> xParamType = pParamArray2[ 0 ];
|
|
if( xParamType->equals( xGetRetType ) )
|
|
{
|
|
pLocalMethodConcepts[ k ] = PROPERTY;
|
|
|
|
pMethodTypes[k] = GETSET_METHOD;
|
|
|
|
// Delete read-only flag again
|
|
rProp.Attributes &= ~READONLY;
|
|
|
|
// Remember set method
|
|
IntrospectionAccessStatic_Impl::checkInterfaceArraySize( pAccess->aInterfaceSeq2,
|
|
rInterfaces2, rPropCount );
|
|
rInterfaces2[ rPropCount ] = rxMethod_k;
|
|
}
|
|
}
|
|
|
|
// Adjust count
|
|
rPropCount++;
|
|
}
|
|
|
|
// Is it an add listener method?
|
|
else if( aMethName.startsWith("add", &aPropName) )
|
|
{
|
|
// Does it end with "Listener"?
|
|
OUString aListenerName;
|
|
if( !aPropName.endsWith("Listener", &aListenerName) )
|
|
continue;
|
|
|
|
// TODO: More accurate tests could still be carried out here
|
|
// - Return type
|
|
// - Number and type of parameters
|
|
|
|
|
|
// Search for matching remove method, otherwise not applicable
|
|
sal_Int32 k;
|
|
for( k = 0 ; k < nSourceMethodCount ; k++ )
|
|
{
|
|
// Address method
|
|
const Reference<XIdlMethod>& rxMethod_k = pSourceMethods[k];
|
|
|
|
// Accept only methods that are not already assigned
|
|
if( k == i || pMethodTypes[k] != STANDARD_METHOD )
|
|
continue;
|
|
|
|
// Get name and evaluate
|
|
OUString aMethName2 = rxMethod_k->getName();
|
|
OUString aListenerName2;
|
|
if (!(aMethName2.startsWith(
|
|
"remove", &aPropName)
|
|
&& aPropName.endsWith(
|
|
"Listener", &aListenerName2)
|
|
&& aListenerName2 == aListenerName))
|
|
continue;
|
|
|
|
// TODO: More accurate tests could still be carried out here
|
|
// - Return type
|
|
// - Number and type of parameters
|
|
|
|
|
|
// Methods are recognised as a listener interface
|
|
rMethodConcept_i |= LISTENER;
|
|
pLocalMethodConcepts[ k ] |= LISTENER;
|
|
|
|
pMethodTypes[i] = ADD_LISTENER_METHOD;
|
|
pMethodTypes[k] = REMOVE_LISTENER_METHOD;
|
|
nListenerCount++;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
// A set method could still exist without a corresponding get method,
|
|
// this must be a write-only property
|
|
for( i = 0 ; i < nSourceMethodCount ; i++ )
|
|
{
|
|
// Address method
|
|
const Reference<XIdlMethod>& rxMethod_i = pSourceMethods[i];
|
|
|
|
// Accept only methods that are not already assigned
|
|
if( pMethodTypes[i] != STANDARD_METHOD )
|
|
continue;
|
|
|
|
// Get name
|
|
OUString aMethName = rxMethod_i->getName();
|
|
|
|
// If the name is too short, it isn't anything
|
|
if( aMethName.getLength() <= 3 )
|
|
continue;
|
|
|
|
// Is it a set method without associated get method?
|
|
OUString aPropName;
|
|
if( aMethName.startsWith("set", &aPropName) )
|
|
{
|
|
// A set method must return void
|
|
Reference<XIdlClass> xSetRetType = rxMethod_i->getReturnType();
|
|
if( xSetRetType->getTypeClass() != TypeClass_VOID )
|
|
{
|
|
continue;
|
|
}
|
|
|
|
// A set method may only have one parameter
|
|
Sequence< Reference<XIdlClass> > setParams = rxMethod_i->getParameterTypes();
|
|
sal_Int32 nParamCount = setParams.getLength();
|
|
if( nParamCount != 1 )
|
|
{
|
|
continue;
|
|
}
|
|
|
|
// Do we have the name already?
|
|
IntrospectionNameMap::iterator aIt = rPropNameMap.find( aPropName );
|
|
if (aIt != rPropNameMap.end())
|
|
{
|
|
/* TODO:
|
|
SAL_INFO("stoc",(
|
|
String( "Introspection: Property \"" ) +
|
|
OOUStringToString( aPropName, CHARSET_SYSTEM ) +
|
|
String( "\" found more than once" ) );
|
|
*/
|
|
continue;
|
|
}
|
|
|
|
// Now we know it's a write only property
|
|
pLocalMethodConcepts[ i ] = PROPERTY;
|
|
|
|
pMethodTypes[i] = GETSET_METHOD;
|
|
Reference<XIdlClass> xGetRetType = setParams.getConstArray()[0];
|
|
|
|
// Is the property sequence big enough?
|
|
pAccess->checkPropertyArraysSize( rPropCount );
|
|
|
|
// Write it in its property array
|
|
Property& rProp = rAllPropArray[ rPropCount ];
|
|
rProp.Name = aPropName;
|
|
rProp.Handle = rPropCount;
|
|
rProp.Type = Type( xGetRetType->getTypeClass(), xGetRetType->getName() );
|
|
rProp.Attributes = 0; // PROPERTY_WRITEONLY ???
|
|
|
|
// New entry in the hash table
|
|
rPropNameMap[ aPropName ] = rPropCount;
|
|
|
|
// Maintain table for XExactName
|
|
rLowerToExactNameMap[ aPropName.toAsciiLowerCase() ] = aPropName;
|
|
|
|
// Remember set method
|
|
IntrospectionAccessStatic_Impl::checkInterfaceArraySize( pAccess->aInterfaceSeq2,
|
|
rInterfaces2, rPropCount );
|
|
rInterfaces2[ rPropCount ] = rxMethod_i;
|
|
|
|
// Remember type of property
|
|
rMapTypeArray[ rPropCount ] = MAP_SETONLY;
|
|
rPropertyConceptArray[ rPropCount ] = METHODS;
|
|
pAccess->mnMethodPropCount++;
|
|
|
|
// Adjust count
|
|
rPropCount++;
|
|
}
|
|
}
|
|
|
|
|
|
// 4. Place methods in overall sequence
|
|
|
|
// How many methods in the method sequence
|
|
sal_Int32 nExportedMethodCount = 0;
|
|
sal_Int32 nSupportedListenerCount = 0;
|
|
for( i = 0 ; i < nSourceMethodCount ; i++ )
|
|
{
|
|
if( pMethodTypes[ i ] != INVALID_METHOD )
|
|
{
|
|
nExportedMethodCount++;
|
|
}
|
|
if( pMethodTypes[ i ] == ADD_LISTENER_METHOD )
|
|
{
|
|
nSupportedListenerCount++;
|
|
}
|
|
}
|
|
|
|
// Enlarge sequences in the access object accordingly
|
|
pAccess->maAllMethodSeq.resize( nExportedMethodCount + iAllExportedMethod );
|
|
pAccess->maMethodConceptSeq.resize( nExportedMethodCount + iAllExportedMethod );
|
|
pAccess->maSupportedListenerSeq.resize( nSupportedListenerCount + iAllSupportedListener );
|
|
|
|
// Write in methods
|
|
for( i = 0 ; i < nSourceMethodCount ; i++ )
|
|
{
|
|
if( pMethodTypes[ i ] != INVALID_METHOD )
|
|
{
|
|
// Address method
|
|
const Reference<XIdlMethod>& rxMethod = pSourceMethods[i];
|
|
|
|
// Enter name in hash table if not already known
|
|
OUString aMethName2 = rxMethod->getName();
|
|
IntrospectionNameMap::iterator aIt = rMethodNameMap.find( aMethName2 );
|
|
if( aIt == rMethodNameMap.end() )
|
|
{
|
|
// Enter
|
|
rMethodNameMap[ aMethName2 ] = iAllExportedMethod;
|
|
|
|
// Maintain table for XExactName
|
|
rLowerToExactNameMap[ aMethName2.toAsciiLowerCase() ] = aMethName2;
|
|
}
|
|
else
|
|
{
|
|
sal_Int32 iHashResult = aIt->second;
|
|
|
|
Reference<XIdlMethod> xExistingMethod = pAccess->maAllMethodSeq[iHashResult];
|
|
|
|
Reference< XIdlClass > xExistingMethClass =
|
|
xExistingMethod->getDeclaringClass();
|
|
Reference< XIdlClass > xNewMethClass = rxMethod->getDeclaringClass();
|
|
if( xExistingMethClass->equals( xNewMethClass ) )
|
|
continue;
|
|
}
|
|
|
|
pAccess->maAllMethodSeq[iAllExportedMethod] = rxMethod;
|
|
|
|
// If a concept has been set, is the method "normal"?
|
|
sal_Int32& rMethodConcept_i = pLocalMethodConcepts[ i ];
|
|
if( !rMethodConcept_i )
|
|
rMethodConcept_i = MethodConcept_NORMAL_IMPL;
|
|
pAccess->maMethodConceptSeq[ iAllExportedMethod ] = rMethodConcept_i;
|
|
iAllExportedMethod++;
|
|
}
|
|
if( pMethodTypes[ i ] == ADD_LISTENER_METHOD )
|
|
{
|
|
// Determine class of listener
|
|
const Reference<XIdlMethod>& rxMethod = pSourceMethods[i];
|
|
|
|
// Enter void as default class
|
|
css::uno::Reference<css::reflection::XIdlClass>
|
|
xListenerClass(
|
|
reflection->forName(
|
|
cppu::UnoType<void>::get()
|
|
.getTypeName()));
|
|
// Old: Reference<XIdlClass> xListenerClass = Void_getReflection()->getIdlClass();
|
|
|
|
// Option 1: Search for parameters for a listener class
|
|
// Disadvantage: Superclasses should be searched recursively
|
|
Sequence< Reference<XIdlClass> > aParams = rxMethod->getParameterTypes();
|
|
const Reference<XIdlClass>* pParamArray2 = aParams.getConstArray();
|
|
|
|
css::uno::Reference<css::reflection::XIdlClass>
|
|
xEventListenerClass(
|
|
reflection->forName(
|
|
cppu::UnoType<
|
|
css::lang::XEventListener>::get()
|
|
.getTypeName()));
|
|
// Old: Reference<XIdlClass> xEventListenerClass = XEventListener_getReflection()->getIdlClass();
|
|
sal_Int32 nParamCount = aParams.getLength();
|
|
sal_Int32 k;
|
|
for( k = 0 ; k < nParamCount ; k++ )
|
|
{
|
|
const Reference<XIdlClass>& rxClass = pParamArray2[k];
|
|
|
|
// Are we derived from a listener?
|
|
if( rxClass->equals( xEventListenerClass ) ||
|
|
isDerivedFrom( rxClass, xEventListenerClass ) )
|
|
{
|
|
xListenerClass = rxClass;
|
|
break;
|
|
}
|
|
}
|
|
|
|
// Option 2: Unload the name of the method
|
|
// Disadvantage: Does not work with test listeners, where it does not exist
|
|
//aMethName = rxMethod->getName();
|
|
//aListenerName = aMethName.Copy( 3, aMethName.Len()-8-3 );
|
|
//Reference<XIdlClass> xListenerClass = reflection->forName( aListenerName );
|
|
Type aListenerType( TypeClass_INTERFACE, xListenerClass->getName() );
|
|
pAccess->maSupportedListenerSeq[ iAllSupportedListener ] = aListenerType;
|
|
iAllSupportedListener++;
|
|
}
|
|
}
|
|
|
|
// When there were XInterface methods in this run,
|
|
// ignore them in the future
|
|
if( bFoundXInterface )
|
|
bXInterfaceIsInvalid = true;
|
|
}
|
|
|
|
// Do superclasses exist? Then continue here
|
|
Sequence< Reference<XIdlClass> > aSuperClassSeq = xImplClass2->getSuperclasses();
|
|
|
|
// Currently only one superclass is considered
|
|
if( aSuperClassSeq.getLength() >= 1 )
|
|
{
|
|
xImplClass2 = aSuperClassSeq.getConstArray()[0];
|
|
OSL_ENSURE( xImplClass2.is(), "super class null" );
|
|
}
|
|
else
|
|
{
|
|
xImplClass2 = nullptr;
|
|
}
|
|
}
|
|
}
|
|
|
|
// Apply number of exported methods and adapt Sequences
|
|
// (can be different because duplicate methods are thrown
|
|
// out only after the determination of nExportedMethodCount)
|
|
sal_Int32& rMethCount = pAccess->mnMethCount;
|
|
rMethCount = iAllExportedMethod;
|
|
pAccess->maAllMethodSeq.resize( rMethCount );
|
|
pAccess->maMethodConceptSeq.resize( rMethCount );
|
|
|
|
// Resize the property sequences
|
|
pAccess->maAllPropertySeq.resize( rPropCount );
|
|
pAccess->maPropertyConceptSeq.resize( rPropCount );
|
|
pAccess->maMapTypeSeq.resize( rPropCount );
|
|
}
|
|
// Register struct fields as properties
|
|
else //if( eType == TypeClass_STRUCT )
|
|
{
|
|
// Is it an interface or a struct?
|
|
//Reference<XIdlClass> xClassRef = aToInspectObj.getReflection()->getIdlClass();
|
|
css::uno::Reference<css::reflection::XIdlClass> xClassRef(
|
|
reflection->forName(aToInspectObj.getValueTypeName()));
|
|
if( !xClassRef.is() )
|
|
{
|
|
SAL_WARN( "stoc", "Can't get XIdlClass from Reflection" );
|
|
return new ImplIntrospectionAccess(aToInspectObj, pAccess);
|
|
}
|
|
|
|
// Get fields
|
|
Sequence< Reference<XIdlField> > fields = xClassRef->getFields();
|
|
const Reference<XIdlField>* pFields = fields.getConstArray();
|
|
sal_Int32 nLen = fields.getLength();
|
|
|
|
for( i = 0 ; i < nLen ; i++ )
|
|
{
|
|
Reference<XIdlField> xField = pFields[i];
|
|
Reference<XIdlClass> xPropType = xField->getType();
|
|
OUString aPropName = xField->getName();
|
|
|
|
// Is the property sequence big enough?
|
|
pAccess->checkPropertyArraysSize( rPropCount );
|
|
|
|
// Write it in its property array
|
|
Property& rProp = rAllPropArray[ rPropCount ];
|
|
rProp.Name = aPropName;
|
|
rProp.Handle = rPropCount;
|
|
rProp.Type = Type( xPropType->getTypeClass(), xPropType->getName() );
|
|
FieldAccessMode eAccessMode = xField->getAccessMode();
|
|
rProp.Attributes = (eAccessMode == FieldAccessMode_READONLY ||
|
|
eAccessMode == FieldAccessMode_CONST)
|
|
? READONLY : 0;
|
|
|
|
//FieldAccessMode eAccessMode = xField->getAccessMode();
|
|
//rProp.Attributes = (eAccessMode == FieldAccessMode::READONLY || eAccessMode == CONST)
|
|
//? PropertyAttribute::READONLY : 0;
|
|
|
|
// Write name in hash table
|
|
rPropNameMap[ aPropName ] = rPropCount;
|
|
|
|
// Maintain table for XExactName
|
|
rLowerToExactNameMap[ aPropName.toAsciiLowerCase() ] = aPropName;
|
|
|
|
// Remember field
|
|
IntrospectionAccessStatic_Impl::checkInterfaceArraySize( pAccess->aInterfaceSeq1,
|
|
rInterfaces1, rPropCount );
|
|
rInterfaces1[ rPropCount ] = xField;
|
|
|
|
// Remember type of property
|
|
rMapTypeArray[ rPropCount ] = MAP_FIELD;
|
|
rPropertyConceptArray[ rPropCount ] = ATTRIBUTES;
|
|
pAccess->mnAttributePropCount++;
|
|
|
|
// Adjust count
|
|
rPropCount++;
|
|
}
|
|
}
|
|
|
|
// Set property sequence to the correct length
|
|
pAccess->maAllPropertySeq.resize( pAccess->mnPropCount );
|
|
|
|
return new ImplIntrospectionAccess(aToInspectObj, pAccess);
|
|
}
|
|
|
|
struct Instance {
|
|
explicit Instance(
|
|
css::uno::Reference<css::uno::XComponentContext> const & context):
|
|
instance(new Implementation(context))
|
|
{}
|
|
|
|
rtl::Reference<cppu::OWeakObject> instance;
|
|
};
|
|
|
|
struct Singleton:
|
|
public rtl::StaticWithArg<
|
|
Instance, css::uno::Reference<css::uno::XComponentContext>, Singleton>
|
|
{};
|
|
|
|
}
|
|
|
|
extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface *
|
|
com_sun_star_comp_stoc_Introspection_get_implementation(
|
|
css::uno::XComponentContext * context,
|
|
css::uno::Sequence<css::uno::Any> const & arguments)
|
|
{
|
|
SAL_WARN_IF(
|
|
arguments.hasElements(), "stoc", "unexpected singleton arguments");
|
|
return cppu::acquire(Singleton::get(context).instance.get());
|
|
}
|
|
|
|
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|