diff options
Diffstat (limited to 'basic/source/classes/sbxmod.cxx')
-rw-r--r-- | basic/source/classes/sbxmod.cxx | 2566 |
1 files changed, 2566 insertions, 0 deletions
diff --git a/basic/source/classes/sbxmod.cxx b/basic/source/classes/sbxmod.cxx new file mode 100644 index 000000000000..750d48a67ca1 --- /dev/null +++ b/basic/source/classes/sbxmod.cxx @@ -0,0 +1,2566 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_basic.hxx" + +#include <list> + +#include <vcl/svapp.hxx> +#include <tools/stream.hxx> +#include <svl/brdcst.hxx> +#include <tools/shl.hxx> +#include <basic/sbx.hxx> +#include "sb.hxx" +#include <sbjsmeth.hxx> +#include "sbjsmod.hxx" +#include "sbintern.hxx" +#include "image.hxx" +#include "opcodes.hxx" +#include "runtime.hxx" +#include "token.hxx" +#include "sbunoobj.hxx" +#include "sbtrace.hxx" + +#include <svtools/syntaxhighlight.hxx> + +#include <basic/basrdll.hxx> +#include <osl/mutex.hxx> +#include <basic/sbobjmod.hxx> +#include <cppuhelper/implbase2.hxx> +#include <com/sun/star/lang/XServiceInfo.hpp> +#include <com/sun/star/script/ModuleType.hpp> +#include <com/sun/star/script/vba/XVBACompatibility.hpp> +#include <com/sun/star/document/XVbaMethodParameter.hpp> +#include <com/sun/star/beans/XPropertySet.hpp> + +using namespace com::sun::star; + +// for the bsearch +#ifdef WNT +#define CDECL _cdecl +#endif +#if defined(UNX) || defined(OS2) +#define CDECL +#endif +#ifdef UNX +#include <sys/resource.h> +#endif + +#include <stdio.h> +#include <com/sun/star/frame/XDesktop.hpp> +#include <com/sun/star/lang/XMultiServiceFactory.hpp> +#include <comphelper/processfactory.hxx> +#include <vcl/svapp.hxx> +#include <map> +#include <com/sun/star/reflection/XProxyFactory.hpp> +#include <cppuhelper/implbase1.hxx> +#include <basic/sbobjmod.hxx> +#include <com/sun/star/uno/XAggregation.hpp> +#include <map> +#include <com/sun/star/script/XInvocation.hpp> + + using namespace ::com::sun::star; +using namespace com::sun::star::lang; +using namespace com::sun::star::reflection; +using namespace com::sun::star::beans; +using namespace com::sun::star::script; + + +#include <com/sun/star/script/XLibraryContainer.hpp> +#include <com/sun/star/lang/XMultiServiceFactory.hpp> +#include <com/sun/star/awt/XDialogProvider.hpp> +#include <com/sun/star/awt/XTopWindow.hpp> +#include <com/sun/star/awt/XWindow.hpp> +#include <com/sun/star/awt/XControl.hpp> +#include <cppuhelper/implbase1.hxx> +#include <comphelper/anytostring.hxx> +#include <com/sun/star/beans/XPropertySet.hpp> + +typedef ::cppu::WeakImplHelper1< XInvocation > DocObjectWrapper_BASE; +typedef ::std::map< sal_Int16, Any, ::std::less< sal_Int16 > > OutParamMap; +::com::sun::star::uno::Any sbxToUnoValue( SbxVariable* pVar ); +void unoToSbxValue( SbxVariable* pVar, const ::com::sun::star::uno::Any& aValue ); + +class DocObjectWrapper : public DocObjectWrapper_BASE +{ + Reference< XAggregation > m_xAggProxy; + Reference< XInvocation > m_xAggInv; + Reference< XTypeProvider > m_xAggregateTypeProv; + Sequence< Type > m_Types; + SbModule* m_pMod; + SbMethodRef getMethod( const rtl::OUString& aName ) throw (RuntimeException); + SbPropertyRef getProperty( const rtl::OUString& aName ) throw (RuntimeException); + String mName; // for debugging + +public: + DocObjectWrapper( SbModule* pMod ); + virtual ~DocObjectWrapper(); + + virtual void SAL_CALL acquire() throw(); + virtual void SAL_CALL release() throw(); + + virtual Sequence< sal_Int8 > SAL_CALL getImplementationId() throw (RuntimeException) + { + if( !m_xAggregateTypeProv.is() ) + throw RuntimeException(); + return m_xAggregateTypeProv->getImplementationId(); + } + + virtual Reference< XIntrospectionAccess > SAL_CALL getIntrospection( ) throw (RuntimeException); + + virtual Any SAL_CALL invoke( const ::rtl::OUString& aFunctionName, const Sequence< Any >& aParams, Sequence< ::sal_Int16 >& aOutParamIndex, Sequence< Any >& aOutParam ) throw (IllegalArgumentException, CannotConvertException, InvocationTargetException, RuntimeException); + virtual void SAL_CALL setValue( const ::rtl::OUString& aPropertyName, const Any& aValue ) throw (UnknownPropertyException, CannotConvertException, InvocationTargetException, RuntimeException); + virtual Any SAL_CALL getValue( const ::rtl::OUString& aPropertyName ) throw (UnknownPropertyException, RuntimeException); + virtual ::sal_Bool SAL_CALL hasMethod( const ::rtl::OUString& aName ) throw (RuntimeException); + virtual ::sal_Bool SAL_CALL hasProperty( const ::rtl::OUString& aName ) throw (RuntimeException); + virtual Any SAL_CALL queryInterface( const Type& aType ) throw ( RuntimeException ); + + virtual Sequence< Type > SAL_CALL getTypes() throw ( RuntimeException ); +}; + +DocObjectWrapper::DocObjectWrapper( SbModule* pVar ) : m_pMod( pVar ), mName( pVar->GetName() ) +{ + SbObjModule* pMod = PTR_CAST(SbObjModule,pVar); + if ( pMod ) + { + if ( pMod->GetModuleType() == ModuleType::DOCUMENT ) + { + Reference< XMultiServiceFactory > xFactory = comphelper::getProcessServiceFactory(); + // Use proxy factory service to create aggregatable proxy. + SbUnoObject* pUnoObj = PTR_CAST(SbUnoObject,pMod->GetObject() ); + Reference< XInterface > xIf; + if ( pUnoObj ) + { + Any aObj = pUnoObj->getUnoAny(); + aObj >>= xIf; + if ( xIf.is() ) + { + m_xAggregateTypeProv.set( xIf, UNO_QUERY ); + m_xAggInv.set( xIf, UNO_QUERY ); + } + } + if ( xIf.is() ) + { + try + { + Reference< XMultiComponentFactory > xMFac( xFactory, UNO_QUERY_THROW ); + Reference< XPropertySet> xPSMPropertySet( xMFac, UNO_QUERY_THROW ); + Reference< XComponentContext > xCtx; + xPSMPropertySet->getPropertyValue( + String( RTL_CONSTASCII_USTRINGPARAM("DefaultContext") ) ) >>= xCtx; + Reference< XProxyFactory > xProxyFac( xMFac->createInstanceWithContext( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "com.sun.star.reflection.ProxyFactory" ) ), xCtx ), UNO_QUERY_THROW ); + m_xAggProxy = xProxyFac->createProxy( xIf ); + } + catch( Exception& ) + { + OSL_ENSURE( false, "DocObjectWrapper::DocObjectWrapper: Caught exception!" ); + } + } + + if ( m_xAggProxy.is() ) + { + osl_incrementInterlockedCount( &m_refCount ); + + /* i35609 - Fix crash on Solaris. The setDelegator call needs + to be in its own block to ensure that all temporary Reference + instances that are acquired during the call are released + before m_refCount is decremented again */ + { + m_xAggProxy->setDelegator( static_cast< cppu::OWeakObject * >( this ) ); + } + + osl_decrementInterlockedCount( &m_refCount ); + } + } + } +} + +void SAL_CALL +DocObjectWrapper::acquire() throw () +{ + osl_incrementInterlockedCount( &m_refCount ); + OSL_TRACE("DocObjectWrapper::acquire(%s) 0x%x refcount is now %d", rtl::OUStringToOString( mName, RTL_TEXTENCODING_UTF8 ).getStr(), this, m_refCount ); +} +void SAL_CALL +DocObjectWrapper::release() throw () +{ + if ( osl_decrementInterlockedCount( &m_refCount ) == 0 ) + { + OSL_TRACE("DocObjectWrapper::release(%s) 0x%x refcount is now %d", rtl::OUStringToOString( mName, RTL_TEXTENCODING_UTF8 ).getStr(), this, m_refCount ); + delete this; + } + else + OSL_TRACE("DocObjectWrapper::release(%s) 0x%x refcount is now %d", rtl::OUStringToOString( mName, RTL_TEXTENCODING_UTF8 ).getStr(), this, m_refCount ); +} + +DocObjectWrapper::~DocObjectWrapper() +{ +} + +Sequence< Type > SAL_CALL DocObjectWrapper::getTypes() + throw ( RuntimeException ) +{ + if ( m_Types.getLength() == 0 ) + { + Sequence< Type > sTypes; + if ( m_xAggregateTypeProv.is() ) + sTypes = m_xAggregateTypeProv->getTypes(); + m_Types.realloc( sTypes.getLength() + 1 ); + Type* pPtr = m_Types.getArray(); + for ( int i=0; i<m_Types.getLength(); ++i, ++pPtr ) + { + if ( i == 0 ) + *pPtr = XInvocation::static_type( NULL ); + else + *pPtr = sTypes[ i - 1 ]; + } + } + return m_Types; +} + +Reference< XIntrospectionAccess > SAL_CALL +DocObjectWrapper::getIntrospection( ) throw (RuntimeException) +{ + return NULL; +} + +Any SAL_CALL +DocObjectWrapper::invoke( const ::rtl::OUString& aFunctionName, const Sequence< Any >& aParams, Sequence< ::sal_Int16 >& aOutParamIndex, Sequence< Any >& aOutParam ) throw (IllegalArgumentException, CannotConvertException, InvocationTargetException, RuntimeException) +{ + if ( m_xAggInv.is() && m_xAggInv->hasMethod( aFunctionName ) ) + return m_xAggInv->invoke( aFunctionName, aParams, aOutParamIndex, aOutParam ); + SbMethodRef pMethod = getMethod( aFunctionName ); + if ( !pMethod ) + throw RuntimeException(); + // check number of parameters + sal_Int32 nParamsCount = aParams.getLength(); + SbxInfo* pInfo = pMethod->GetInfo(); + if ( pInfo ) + { + sal_Int32 nSbxOptional = 0; + USHORT n = 1; + for ( const SbxParamInfo* pParamInfo = pInfo->GetParam( n ); pParamInfo; pParamInfo = pInfo->GetParam( ++n ) ) + { + if ( ( pParamInfo->nFlags & SBX_OPTIONAL ) != 0 ) + ++nSbxOptional; + else + nSbxOptional = 0; + } + sal_Int32 nSbxCount = n - 1; + if ( nParamsCount < nSbxCount - nSbxOptional ) + { + throw RuntimeException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "wrong number of parameters!" ) ), Reference< XInterface >() ); + } + } + // set parameters + SbxArrayRef xSbxParams; + if ( nParamsCount > 0 ) + { + xSbxParams = new SbxArray; + const Any* pParams = aParams.getConstArray(); + for ( sal_Int32 i = 0; i < nParamsCount; ++i ) + { + SbxVariableRef xSbxVar = new SbxVariable( SbxVARIANT ); + unoToSbxValue( static_cast< SbxVariable* >( xSbxVar ), pParams[i] ); + xSbxParams->Put( xSbxVar, static_cast< USHORT >( i ) + 1 ); + + // Enable passing by ref + if ( xSbxVar->GetType() != SbxVARIANT ) + xSbxVar->SetFlag( SBX_FIXED ); + } + } + if ( xSbxParams.Is() ) + pMethod->SetParameters( xSbxParams ); + + // call method + SbxVariableRef xReturn = new SbxVariable; + + pMethod->Call( xReturn ); + Any aReturn; + // get output parameters + if ( xSbxParams.Is() ) + { + SbxInfo* pInfo_ = pMethod->GetInfo(); + if ( pInfo_ ) + { + OutParamMap aOutParamMap; + for ( USHORT n = 1, nCount = xSbxParams->Count(); n < nCount; ++n ) + { + const SbxParamInfo* pParamInfo = pInfo_->GetParam( n ); + if ( pParamInfo && ( pParamInfo->eType & SbxBYREF ) != 0 ) + { + SbxVariable* pVar = xSbxParams->Get( n ); + if ( pVar ) + { + SbxVariableRef xVar = pVar; + aOutParamMap.insert( OutParamMap::value_type( n - 1, sbxToUnoValue( xVar ) ) ); + } + } + } + sal_Int32 nOutParamCount = aOutParamMap.size(); + aOutParamIndex.realloc( nOutParamCount ); + aOutParam.realloc( nOutParamCount ); + sal_Int16* pOutParamIndex = aOutParamIndex.getArray(); + Any* pOutParam = aOutParam.getArray(); + for ( OutParamMap::iterator aIt = aOutParamMap.begin(); aIt != aOutParamMap.end(); ++aIt, ++pOutParamIndex, ++pOutParam ) + { + *pOutParamIndex = aIt->first; + *pOutParam = aIt->second; + } + } + } + + // get return value + aReturn = sbxToUnoValue( xReturn ); + + pMethod->SetParameters( NULL ); + + return aReturn; +} + +void SAL_CALL +DocObjectWrapper::setValue( const ::rtl::OUString& aPropertyName, const Any& aValue ) throw (UnknownPropertyException, CannotConvertException, InvocationTargetException, RuntimeException) +{ + if ( m_xAggInv.is() && m_xAggInv->hasProperty( aPropertyName ) ) + return m_xAggInv->setValue( aPropertyName, aValue ); + + SbPropertyRef pProperty = getProperty( aPropertyName ); + if ( !pProperty.Is() ) + throw UnknownPropertyException(); + unoToSbxValue( (SbxVariable*) pProperty, aValue ); +} + +Any SAL_CALL +DocObjectWrapper::getValue( const ::rtl::OUString& aPropertyName ) throw (UnknownPropertyException, RuntimeException) +{ + if ( m_xAggInv.is() && m_xAggInv->hasProperty( aPropertyName ) ) + return m_xAggInv->getValue( aPropertyName ); + + SbPropertyRef pProperty = getProperty( aPropertyName ); + if ( !pProperty.Is() ) + throw UnknownPropertyException(); + + SbxVariable* pProp = ( SbxVariable* ) pProperty; + if ( pProp->GetType() == SbxEMPTY ) + pProperty->Broadcast( SBX_HINT_DATAWANTED ); + + Any aRet = sbxToUnoValue( pProp ); + return aRet; +} + +::sal_Bool SAL_CALL +DocObjectWrapper::hasMethod( const ::rtl::OUString& aName ) throw (RuntimeException) +{ + if ( m_xAggInv.is() && m_xAggInv->hasMethod( aName ) ) + return sal_True; + return getMethod( aName ).Is(); +} + +::sal_Bool SAL_CALL +DocObjectWrapper::hasProperty( const ::rtl::OUString& aName ) throw (RuntimeException) +{ + sal_Bool bRes = sal_False; + if ( m_xAggInv.is() && m_xAggInv->hasProperty( aName ) ) + bRes = sal_True; + else bRes = getProperty( aName ).Is(); + return bRes; +} + +Any SAL_CALL DocObjectWrapper::queryInterface( const Type& aType ) + throw ( RuntimeException ) +{ + Any aRet = DocObjectWrapper_BASE::queryInterface( aType ); + if ( aRet.hasValue() ) + return aRet; + else if ( m_xAggProxy.is() ) + aRet = m_xAggProxy->queryAggregation( aType ); + return aRet; +} + +SbMethodRef DocObjectWrapper::getMethod( const rtl::OUString& aName ) throw (RuntimeException) +{ + SbMethodRef pMethod = NULL; + if ( m_pMod ) + { + USHORT nSaveFlgs = m_pMod->GetFlags(); + // Limit search to this module + m_pMod->ResetFlag( SBX_GBLSEARCH ); + pMethod = (SbMethod*) m_pMod->SbModule::Find( aName, SbxCLASS_METHOD ); + m_pMod->SetFlags( nSaveFlgs ); + } + + return pMethod; +} + +SbPropertyRef DocObjectWrapper::getProperty( const rtl::OUString& aName ) throw (RuntimeException) +{ + SbPropertyRef pProperty = NULL; + if ( m_pMod ) + { + USHORT nSaveFlgs = m_pMod->GetFlags(); + // Limit search to this module. + m_pMod->ResetFlag( SBX_GBLSEARCH ); + pProperty = (SbProperty*)m_pMod->SbModule::Find( aName, SbxCLASS_PROPERTY ); + m_pMod->SetFlag( nSaveFlgs ); + } + + return pProperty; +} + +TYPEINIT1(SbModule,SbxObject) +TYPEINIT1(SbMethod,SbxMethod) +TYPEINIT1(SbProperty,SbxProperty) +TYPEINIT1(SbProcedureProperty,SbxProperty) +TYPEINIT1(SbJScriptModule,SbModule) +TYPEINIT1(SbJScriptMethod,SbMethod) +TYPEINIT1(SbObjModule,SbModule) +TYPEINIT1(SbUserFormModule,SbObjModule) + +SV_DECL_VARARR(SbiBreakpoints,USHORT,4,4) +SV_IMPL_VARARR(SbiBreakpoints,USHORT) + + +SV_IMPL_VARARR(HighlightPortions, HighlightPortion) + +bool getDefaultVBAMode( StarBASIC* pb ) +{ + bool bResult = false; + if ( pb && pb->IsDocBasic() ) + { + uno::Any aDoc; + if ( pb->GetUNOConstant( "ThisComponent", aDoc ) ) + { + uno::Reference< beans::XPropertySet > xProp( aDoc, uno::UNO_QUERY ); + if ( xProp.is() ) + { + uno::Reference< script::vba::XVBACompatibility > xVBAMode( xProp->getPropertyValue( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM("BasicLibraries") ) ), uno::UNO_QUERY ); + if ( xVBAMode.is() ) + bResult = xVBAMode->getVBACompatibilityMode() == sal_True; + } + } + } + return bResult; +} + +class AsyncQuitHandler +{ + AsyncQuitHandler() {} + AsyncQuitHandler( const AsyncQuitHandler&); +public: + static AsyncQuitHandler& instance() + { + static AsyncQuitHandler dInst; + return dInst; + } + + void QuitApplication() + { + uno::Reference< lang::XMultiServiceFactory > xFactory = comphelper::getProcessServiceFactory(); + if ( xFactory.is() ) + { + uno::Reference< frame::XDesktop > xDeskTop( xFactory->createInstance( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM("com.sun.star.frame.Desktop") ) ), uno::UNO_QUERY ); + if ( xDeskTop.is() ) + xDeskTop->terminate(); + } + } + DECL_LINK( OnAsyncQuit, void* ); +}; + +IMPL_LINK( AsyncQuitHandler, OnAsyncQuit, void*, /*pNull*/ ) +{ + QuitApplication(); + return 0L; +} + +bool UnlockControllerHack( StarBASIC* pBasic ) +{ + bool bRes = false; + if ( pBasic && pBasic->IsDocBasic() ) + { + uno::Any aUnoVar; + ::rtl::OUString sVarName( ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM( "ThisComponent" )) ); + SbUnoObject* pGlobs = dynamic_cast<SbUnoObject*>( pBasic->Find( sVarName, SbxCLASS_DONTCARE ) ); + if ( pGlobs ) + aUnoVar = pGlobs->getUnoAny(); + uno::Reference< frame::XModel > xModel( aUnoVar, uno::UNO_QUERY); + if ( xModel.is() ) + { + try + { + xModel->unlockControllers(); + bRes = true; + } + catch( uno::Exception& ) + { + } + } + } + return bRes; +} + +///////////////////////////////////////////////////////////////////////////// + +// A Basic module has set EXTSEARCH, so that the elements, that the modul contains, +// could be found from other module. + +SbModule::SbModule( const String& rName, BOOL bVBACompat ) + : SbxObject( String( RTL_CONSTASCII_USTRINGPARAM("StarBASICModule") ) ), + pImage( NULL ), pBreaks( NULL ), pClassData( NULL ), mbVBACompat( bVBACompat ), pDocObject( NULL ), bIsProxyModule( false ) +{ + SetName( rName ); + SetFlag( SBX_EXTSEARCH | SBX_GBLSEARCH ); + SetModuleType( script::ModuleType::NORMAL ); + + // #i92642: Set name property to intitial name + SbxVariable* pNameProp = pProps->Find( String( RTL_CONSTASCII_USTRINGPARAM("Name") ), SbxCLASS_PROPERTY ); + if( pNameProp != NULL ) + pNameProp->PutString( GetName() ); +} + +SbModule::~SbModule() +{ + OSL_TRACE("Module named %s is destructing", rtl::OUStringToOString( GetName(), RTL_TEXTENCODING_UTF8 ).getStr() ); + if( pImage ) + delete pImage; + if( pBreaks ) + delete pBreaks; + if( pClassData ) + delete pClassData; + mxWrapper = NULL; +} + +uno::Reference< script::XInvocation > +SbModule::GetUnoModule() +{ + if ( !mxWrapper.is() ) + mxWrapper = new DocObjectWrapper( this ); + + OSL_TRACE("Module named %s returning wrapper mxWrapper (0x%x)", rtl::OUStringToOString( GetName(), RTL_TEXTENCODING_UTF8 ).getStr(), mxWrapper.get() ); + return mxWrapper; +} + +BOOL SbModule::IsCompiled() const +{ + return BOOL( pImage != 0 ); +} + +const SbxObject* SbModule::FindType( String aTypeName ) const +{ + return pImage ? pImage->FindType( aTypeName ) : NULL; +} + + +// From the code generator: deletion of images and the oposite of validation for entries + +void SbModule::StartDefinitions() +{ + delete pImage; pImage = NULL; + if( pClassData ) + pClassData->clear(); + + // methods and properties persist, but they are invalid; + // at least are the information under certain conditions clogged + USHORT i; + for( i = 0; i < pMethods->Count(); i++ ) + { + SbMethod* p = PTR_CAST(SbMethod,pMethods->Get( i ) ); + if( p ) + p->bInvalid = TRUE; + } + for( i = 0; i < pProps->Count(); ) + { + SbProperty* p = PTR_CAST(SbProperty,pProps->Get( i ) ); + if( p ) + pProps->Remove( i ); + else + i++; + } +} + +// request/create method + +SbMethod* SbModule::GetMethod( const String& rName, SbxDataType t ) +{ + SbxVariable* p = pMethods->Find( rName, SbxCLASS_METHOD ); + SbMethod* pMeth = p ? PTR_CAST(SbMethod,p) : NULL; + if( p && !pMeth ) + pMethods->Remove( p ); + if( !pMeth ) + { + pMeth = new SbMethod( rName, t, this ); + pMeth->SetParent( this ); + pMeth->SetFlags( SBX_READ ); + pMethods->Put( pMeth, pMethods->Count() ); + StartListening( pMeth->GetBroadcaster(), TRUE ); + } + // The method is per default valid, because it could be + // created from the compiler (code generator) as well. + pMeth->bInvalid = FALSE; + pMeth->ResetFlag( SBX_FIXED ); + pMeth->SetFlag( SBX_WRITE ); + pMeth->SetType( t ); + pMeth->ResetFlag( SBX_WRITE ); + if( t != SbxVARIANT ) + pMeth->SetFlag( SBX_FIXED ); + return pMeth; +} + +// request/create property + +SbProperty* SbModule::GetProperty( const String& rName, SbxDataType t ) +{ + SbxVariable* p = pProps->Find( rName, SbxCLASS_PROPERTY ); + SbProperty* pProp = p ? PTR_CAST(SbProperty,p) : NULL; + if( p && !pProp ) + pProps->Remove( p ); + if( !pProp ) + { + pProp = new SbProperty( rName, t, this ); + pProp->SetFlag( SBX_READWRITE ); + pProp->SetParent( this ); + pProps->Put( pProp, pProps->Count() ); + StartListening( pProp->GetBroadcaster(), TRUE ); + } + return pProp; +} + +SbProcedureProperty* SbModule::GetProcedureProperty + ( const String& rName, SbxDataType t ) +{ + SbxVariable* p = pProps->Find( rName, SbxCLASS_PROPERTY ); + SbProcedureProperty* pProp = p ? PTR_CAST(SbProcedureProperty,p) : NULL; + if( p && !pProp ) + pProps->Remove( p ); + if( !pProp ) + { + pProp = new SbProcedureProperty( rName, t ); + pProp->SetFlag( SBX_READWRITE ); + pProp->SetParent( this ); + pProps->Put( pProp, pProps->Count() ); + StartListening( pProp->GetBroadcaster(), TRUE ); + } + return pProp; +} + +SbIfaceMapperMethod* SbModule::GetIfaceMapperMethod + ( const String& rName, SbMethod* pImplMeth ) +{ + SbxVariable* p = pMethods->Find( rName, SbxCLASS_METHOD ); + SbIfaceMapperMethod* pMapperMethod = p ? PTR_CAST(SbIfaceMapperMethod,p) : NULL; + if( p && !pMapperMethod ) + pMethods->Remove( p ); + if( !pMapperMethod ) + { + pMapperMethod = new SbIfaceMapperMethod( rName, pImplMeth ); + pMapperMethod->SetParent( this ); + pMapperMethod->SetFlags( SBX_READ ); + pMethods->Put( pMapperMethod, pMethods->Count() ); + } + pMapperMethod->bInvalid = FALSE; + return pMapperMethod; +} + +SbIfaceMapperMethod::~SbIfaceMapperMethod() +{ +} + +TYPEINIT1(SbIfaceMapperMethod,SbMethod) + + +// From the code generator: remove invalid entries + +void SbModule::EndDefinitions( BOOL bNewState ) +{ + for( USHORT i = 0; i < pMethods->Count(); ) + { + SbMethod* p = PTR_CAST(SbMethod,pMethods->Get( i ) ); + if( p ) + { + if( p->bInvalid ) + pMethods->Remove( p ); + else + { + p->bInvalid = bNewState; + i++; + } + } + else + i++; + } + SetModified( TRUE ); +} + +void SbModule::Clear() +{ + delete pImage; pImage = NULL; + if( pClassData ) + pClassData->clear(); + SbxObject::Clear(); +} + + +SbxVariable* SbModule::Find( const XubString& rName, SbxClassType t ) +{ + // make sure a search in an uninstatiated class module will fail + SbxVariable* pRes = SbxObject::Find( rName, t ); + if ( bIsProxyModule && !GetSbData()->bRunInit ) + return NULL; + if( !pRes && pImage ) + { + SbiInstance* pInst = pINST; + if( pInst && pInst->IsCompatibility() ) + { + // Put enum types as objects into module, + // allows MyEnum.First notation + SbxArrayRef xArray = pImage->GetEnums(); + if( xArray.Is() ) + { + SbxVariable* pEnumVar = xArray->Find( rName, SbxCLASS_DONTCARE ); + SbxObject* pEnumObject = PTR_CAST( SbxObject, pEnumVar ); + if( pEnumObject ) + { + bool bPrivate = pEnumObject->IsSet( SBX_PRIVATE ); + String aEnumName = pEnumObject->GetName(); + + pRes = new SbxVariable( SbxOBJECT ); + pRes->SetName( aEnumName ); + pRes->SetParent( this ); + pRes->SetFlag( SBX_READ ); + if( bPrivate ) + pRes->SetFlag( SBX_PRIVATE ); + pRes->PutObject( pEnumObject ); + } + } + } + } + return pRes; +} + +const ::rtl::OUString& SbModule::GetSource32() const +{ + return aOUSource; +} + +const String& SbModule::GetSource() const +{ + static String aRetStr; + aRetStr = aOUSource; + return aRetStr; +} + +// Parent and BASIC are one! + +void SbModule::SetParent( SbxObject* p ) +{ + // #118083: Assertion is not valid any more + // DBG_ASSERT( !p || p->IsA( TYPE(StarBASIC) ), "Register SbModules only in BASIC" ); + pParent = p; +} + +void SbModule::SFX_NOTIFY( SfxBroadcaster& rBC, const TypeId& rBCType, + const SfxHint& rHint, const TypeId& rHintType ) +{ + const SbxHint* pHint = PTR_CAST(SbxHint,&rHint); + if( pHint ) + { + SbxVariable* pVar = pHint->GetVar(); + SbProperty* pProp = PTR_CAST(SbProperty,pVar); + SbMethod* pMeth = PTR_CAST(SbMethod,pVar); + SbProcedureProperty* pProcProperty = PTR_CAST( SbProcedureProperty, pVar ); + if( pProcProperty ) + { + + if( pHint->GetId() == SBX_HINT_DATAWANTED ) + { + String aProcName; + aProcName.AppendAscii( "Property Get " ); + aProcName += pProcProperty->GetName(); + + SbxVariable* pMethVar = Find( aProcName, SbxCLASS_METHOD ); + if( pMethVar ) + { + SbxValues aVals; + aVals.eType = SbxVARIANT; + + SbxArray* pArg = pVar->GetParameters(); + USHORT nVarParCount = (pArg != NULL) ? pArg->Count() : 0; + if( nVarParCount > 1 ) + { + SbxArrayRef xMethParameters = new SbxArray; + xMethParameters->Put( pMethVar, 0 ); // Method as parameter 0 + for( USHORT i = 1 ; i < nVarParCount ; ++i ) + { + SbxVariable* pPar = pArg->Get( i ); + xMethParameters->Put( pPar, i ); + } + + pMethVar->SetParameters( xMethParameters ); + pMethVar->Get( aVals ); + pMethVar->SetParameters( NULL ); + } + else + { + pMethVar->Get( aVals ); + } + + pVar->Put( aVals ); + } + } + else if( pHint->GetId() == SBX_HINT_DATACHANGED ) + { + SbxVariable* pMethVar = NULL; + + bool bSet = pProcProperty->isSet(); + if( bSet ) + { + pProcProperty->setSet( false ); + + String aProcName; + aProcName.AppendAscii( "Property Set " ); + aProcName += pProcProperty->GetName(); + pMethVar = Find( aProcName, SbxCLASS_METHOD ); + } + if( !pMethVar ) // Let + { + String aProcName; + aProcName.AppendAscii( "Property Let " ); + aProcName += pProcProperty->GetName(); + pMethVar = Find( aProcName, SbxCLASS_METHOD ); + } + + if( pMethVar ) + { + // Setup parameters + SbxArrayRef xArray = new SbxArray; + xArray->Put( pMethVar, 0 ); // Method as parameter 0 + xArray->Put( pVar, 1 ); + pMethVar->SetParameters( xArray ); + + SbxValues aVals; + pMethVar->Get( aVals ); + pMethVar->SetParameters( NULL ); + } + } + } + if( pProp ) + { + if( pProp->GetModule() != this ) + SetError( SbxERR_BAD_ACTION ); + } + else if( pMeth ) + { + if( pHint->GetId() == SBX_HINT_DATAWANTED ) + { + if( pMeth->bInvalid && !Compile() ) + // auto compile has not worked! + StarBASIC::Error( SbERR_BAD_PROP_VALUE ); + else + { + // Call of a subprogram + SbModule* pOld = pMOD; + pMOD = this; + Run( (SbMethod*) pVar ); + pMOD = pOld; + } + } + } + else + { + // #i92642: Special handling for name property to avoid + // side effects when using name as variable implicitely + bool bForwardToSbxObject = true; + + ULONG nId = pHint->GetId(); + if( (nId == SBX_HINT_DATAWANTED || nId == SBX_HINT_DATACHANGED) && + pVar->GetName().EqualsIgnoreCaseAscii( "name" ) ) + bForwardToSbxObject = false; + + if( bForwardToSbxObject ) + SbxObject::SFX_NOTIFY( rBC, rBCType, rHint, rHintType ); + } + } +} + +// The setting of the source makes the image invalid +// and scans the method definitions newly in + +void SbModule::SetSource( const String& r ) +{ + SetSource32( r ); +} + +void SbModule::SetSource32( const ::rtl::OUString& r ) +{ + // Default basic mode to library container mode, but.. allow Option VBASupport 0/1 override + SetVBACompat( getDefaultVBAMode( static_cast< StarBASIC*>( GetParent() ) ) ); + aOUSource = r; + StartDefinitions(); + SbiTokenizer aTok( r ); + aTok.SetCompatible( IsVBACompat() ); + while( !aTok.IsEof() ) + { + SbiToken eEndTok = NIL; + + // Searching for SUB or FUNCTION + SbiToken eLastTok = NIL; + while( !aTok.IsEof() ) + { + // #32385: not by declare + SbiToken eCurTok = aTok.Next(); + if( eLastTok != DECLARE ) + { + if( eCurTok == SUB ) + { + eEndTok = ENDSUB; break; + } + if( eCurTok == FUNCTION ) + { + eEndTok = ENDFUNC; break; + } + if( eCurTok == PROPERTY ) + { + eEndTok = ENDPROPERTY; break; + } + if( eCurTok == OPTION ) + { + eCurTok = aTok.Next(); + if( eCurTok == COMPATIBLE ) + aTok.SetCompatible( true ); + else if ( ( eCurTok == VBASUPPORT ) && ( aTok.Next() == NUMBER ) ) + { + BOOL bIsVBA = ( aTok.GetDbl()== 1 ); + SetVBACompat( bIsVBA ); + aTok.SetCompatible( bIsVBA ); + } + } + } + eLastTok = eCurTok; + } + // Definition of the method + SbMethod* pMeth = NULL; + if( eEndTok != NIL ) + { + USHORT nLine1 = aTok.GetLine(); + if( aTok.Next() == SYMBOL ) + { + String aName_( aTok.GetSym() ); + SbxDataType t = aTok.GetType(); + if( t == SbxVARIANT && eEndTok == ENDSUB ) + t = SbxVOID; + pMeth = GetMethod( aName_, t ); + pMeth->nLine1 = pMeth->nLine2 = nLine1; + // The method is for a start VALID + pMeth->bInvalid = FALSE; + } + else + eEndTok = NIL; + } + // Skip up to END SUB/END FUNCTION + if( eEndTok != NIL ) + { + while( !aTok.IsEof() ) + { + if( aTok.Next() == eEndTok ) + { + pMeth->nLine2 = aTok.GetLine(); + break; + } + } + if( aTok.IsEof() ) + pMeth->nLine2 = aTok.GetLine(); + } + } + EndDefinitions( TRUE ); +} + +void SbModule::SetComment( const String& r ) +{ + aComment = r; + SetModified( TRUE ); +} + +SbMethod* SbModule::GetFunctionForLine( USHORT nLine ) +{ + for( USHORT i = 0; i < pMethods->Count(); i++ ) + { + SbMethod* p = (SbMethod*) pMethods->Get( i ); + if( p->GetSbxId() == SBXID_BASICMETHOD ) + { + if( nLine >= p->nLine1 && nLine <= p->nLine2 ) + return p; + } + } + return NULL; +} + +// Broadcast of a hint to all Basics + +static void _SendHint( SbxObject* pObj, ULONG nId, SbMethod* p ) +{ + // Self a BASIC? + if( pObj->IsA( TYPE(StarBASIC) ) && pObj->IsBroadcaster() ) + pObj->GetBroadcaster().Broadcast( SbxHint( nId, p ) ); + // Then ask for the subobjects + SbxArray* pObjs = pObj->GetObjects(); + for( USHORT i = 0; i < pObjs->Count(); i++ ) + { + SbxVariable* pVar = pObjs->Get( i ); + if( pVar->IsA( TYPE(SbxObject) ) ) + _SendHint( PTR_CAST(SbxObject,pVar), nId, p ); + } +} + +static void SendHint( SbxObject* pObj, ULONG nId, SbMethod* p ) +{ + while( pObj->GetParent() ) + pObj = pObj->GetParent(); + _SendHint( pObj, nId, p ); +} + +// #57841 Clear Uno-Objects, which were helt in RTL functions, +// at the end of the program, so that nothing were helt. +void ClearUnoObjectsInRTL_Impl_Rek( StarBASIC* pBasic ) +{ + // delete the return value of CreateUnoService + static String aName( RTL_CONSTASCII_USTRINGPARAM("CreateUnoService") ); + SbxVariable* pVar = pBasic->GetRtl()->Find( aName, SbxCLASS_METHOD ); + if( pVar ) + pVar->SbxValue::Clear(); + + // delete the return value of CreateUnoDialog + static String aName2( RTL_CONSTASCII_USTRINGPARAM("CreateUnoDialog") ); + pVar = pBasic->GetRtl()->Find( aName2, SbxCLASS_METHOD ); + if( pVar ) + pVar->SbxValue::Clear(); + + // delete the return value of CDec + static String aName3( RTL_CONSTASCII_USTRINGPARAM("CDec") ); + pVar = pBasic->GetRtl()->Find( aName3, SbxCLASS_METHOD ); + if( pVar ) + pVar->SbxValue::Clear(); + + // delete return value of CreateObject + static String aName4( RTL_CONSTASCII_USTRINGPARAM("CreateObject") ); + pVar = pBasic->GetRtl()->Find( aName4, SbxCLASS_METHOD ); + if( pVar ) + pVar->SbxValue::Clear(); + + // Go over all Sub-Basics + SbxArray* pObjs = pBasic->GetObjects(); + USHORT nCount = pObjs->Count(); + for( USHORT i = 0 ; i < nCount ; i++ ) + { + SbxVariable* pObjVar = pObjs->Get( i ); + StarBASIC* pSubBasic = PTR_CAST( StarBASIC, pObjVar ); + if( pSubBasic ) + ClearUnoObjectsInRTL_Impl_Rek( pSubBasic ); + } +} + +void ClearUnoObjectsInRTL_Impl( StarBASIC* pBasic ) +{ + // #67781 Delete return values of the Uno-methods + clearUnoMethods(); + clearUnoServiceCtors(); + + ClearUnoObjectsInRTL_Impl_Rek( pBasic ); + + // Search for the topmost Basic + SbxObject* p = pBasic; + while( p->GetParent() ) + p = p->GetParent(); + if( ((StarBASIC*)p) != pBasic ) + ClearUnoObjectsInRTL_Impl_Rek( (StarBASIC*)p ); +} +BOOL SbModule::IsVBACompat() const +{ + return mbVBACompat; +} + +void SbModule::SetVBACompat( BOOL bCompat ) +{ + mbVBACompat = bCompat; +} +// Run a Basic-subprogram +USHORT SbModule::Run( SbMethod* pMeth ) +{ + OSL_TRACE("About to run %s, vba compatmode is %d", rtl::OUStringToOString( pMeth->GetName(), RTL_TEXTENCODING_UTF8 ).getStr(), mbVBACompat ); + static USHORT nMaxCallLevel = 0; + static String aMSOMacroRuntimeLibName = String::CreateFromAscii( "Launcher" ); + static String aMSOMacroRuntimeAppSymbol = String::CreateFromAscii( "Application" ); + + USHORT nRes = 0; + BOOL bDelInst = BOOL( pINST == NULL ); + bool bQuit = false; + StarBASICRef xBasic; + if( bDelInst ) + { +#ifdef DBG_TRACE_BASIC + dbg_InitTrace(); +#endif + // #32779: Hold Basic during the execution + xBasic = (StarBASIC*) GetParent(); + + pINST = new SbiInstance( (StarBASIC*) GetParent() ); + + // Delete the Error-Stack + SbErrorStack*& rErrStack = GetSbData()->pErrStack; + delete rErrStack; + rErrStack = NULL; + + if( nMaxCallLevel == 0 ) + { +#ifdef UNX + struct rlimit rl; + getrlimit ( RLIMIT_STACK, &rl ); + // printf( "RLIMIT_STACK = %ld\n", rl.rlim_cur ); +#endif +#if defined LINUX + // Empiric value, 900 = needed bytes/Basic call level + // for Linux including 10% safety margin + nMaxCallLevel = rl.rlim_cur / 900; +#elif defined SOLARIS + // Empiric value, 1650 = needed bytes/Basic call level + // for Solaris including 10% safety margin + nMaxCallLevel = rl.rlim_cur / 1650; +#elif defined WIN32 + nMaxCallLevel = 5800; +#else + nMaxCallLevel = MAXRECURSION; +#endif + } + } + + // Recursion to deep? + if( ++pINST->nCallLvl <= nMaxCallLevel ) + { + // Define a globale variable in all Mods + GlobalRunInit( /* bBasicStart = */ bDelInst ); + + // Appeared a compiler error? Then we don't launch + if( GetSbData()->bGlobalInitErr == FALSE ) + { + if( bDelInst ) + { + SendHint( GetParent(), SBX_HINT_BASICSTART, pMeth ); + + // 1996-10-16: #31460 New concept for StepInto/Over/Out + // For an explanation see runtime.cxx at SbiInstance::CalcBreakCallLevel() + // Identify the BreakCallLevel + pINST->CalcBreakCallLevel( pMeth->GetDebugFlags() ); + } + + SbModule* pOldMod = pMOD; + pMOD = this; + SbiRuntime* pRt = new SbiRuntime( this, pMeth, pMeth->nStart ); + +#ifdef DBG_TRACE_BASIC + dbg_traceNotifyCall( this, pMeth, pINST->nCallLvl ); +#endif + + pRt->pNext = pINST->pRun; + if( pRt->pNext ) + pRt->pNext->block(); + pINST->pRun = pRt; + if ( mbVBACompat ) + { + pINST->EnableCompatibility( TRUE ); + } + while( pRt->Step() ) {} + if( pRt->pNext ) + pRt->pNext->unblock(); + +#ifdef DBG_TRACE_BASIC + bool bLeave = true; + dbg_traceNotifyCall( this, pMeth, pINST->nCallLvl, bLeave ); +#endif + + // #63710 It can happen by an another thread handling at events, + // that the show call returns to an dialog (by closing the + // dialog per UI), before a by an event triggered further call returned, + // which stands in Basic more top in the stack and that had been run on + // a Basic-Breakpoint. Then would the instance below destroyed. And if the Basic, + // that stand still in the call, further runs, there is a GPF. + // Thus here had to be wait until the other call comes back. + if( bDelInst ) + { + // Compare here with 1 instead of 0, because before nCallLvl-- + while( pINST->nCallLvl != 1 ) + GetpApp()->Yield(); + } + + nRes = TRUE; + pINST->pRun = pRt->pNext; + pINST->nCallLvl--; // Call-Level down again + + // Exist an higher-ranking runtime instance? + // Then take over SbDEBUG_BREAK, if set + SbiRuntime* pRtNext = pRt->pNext; + if( pRtNext && (pRt->GetDebugFlags() & SbDEBUG_BREAK) ) + pRtNext->SetDebugFlags( SbDEBUG_BREAK ); + + delete pRt; + pMOD = pOldMod; + if ( pINST->nCallLvl == 0 && IsVBACompat() ) + { + // VBA always ensure screenupdating is enabled after completing + StarBASIC* pBasic = PTR_CAST(StarBASIC,GetParent()); + if ( pBasic && pBasic->IsDocBasic() ) + { + UnlockControllerHack( pBasic ); + } + } + if( bDelInst ) + { + // #57841 Clear Uno-Objects, which were helt in RTL functions, + // at the end of the program, so that nothing were helt. + ClearUnoObjectsInRTL_Impl( xBasic ); + + DBG_ASSERT(pINST->nCallLvl==0,"BASIC-Call-Level > 0"); + delete pINST, pINST = NULL, bDelInst = FALSE; + + // #i30690 + SolarMutexGuard aSolarGuard; + SendHint( GetParent(), SBX_HINT_BASICSTOP, pMeth ); + + GlobalRunDeInit(); + } + } + else + pINST->nCallLvl--; // Call-Level down again + } + else + { + pINST->nCallLvl--; // Call-Level down again + StarBASIC::FatalError( SbERR_STACK_OVERFLOW ); + } + + // VBA always ensure screenupdating is enabled after completing + StarBASIC* pBasic = PTR_CAST(StarBASIC,GetParent()); + if ( pBasic && pBasic->IsDocBasic() && !pINST ) + UnlockControllerHack( pBasic ); + if( bDelInst ) + { + // #57841 Clear Uno-Objects, which were helt in RTL functions, + // the end of the program, so that nothing were helt. + ClearUnoObjectsInRTL_Impl( xBasic ); + + delete pINST; + pINST = NULL; + } + if ( pBasic && pBasic->IsDocBasic() && pBasic->IsQuitApplication() && !pINST ) + bQuit = true; + if ( bQuit ) + { + Application::PostUserEvent( LINK( &AsyncQuitHandler::instance(), AsyncQuitHandler, OnAsyncQuit ), NULL ); + } + + return nRes; +} + +// Execute of the init method of a module after the loading +// or the compilation + +void SbModule::RunInit() +{ + if( pImage + && !pImage->bInit + && pImage->GetFlag( SBIMG_INITCODE ) ) + { + // Set flag, so that RunInit get activ (Testtool) + GetSbData()->bRunInit = TRUE; + + // BOOL bDelInst = BOOL( pINST == NULL ); + // if( bDelInst ) + // pINST = new SbiInstance( (StarBASIC*) GetParent() ); + SbModule* pOldMod = pMOD; + pMOD = this; + // The init code starts always here + SbiRuntime* pRt = new SbiRuntime( this, NULL, 0 ); + +#ifdef DBG_TRACE_BASIC + dbg_traceNotifyCall( this, NULL, 0 ); +#endif + + pRt->pNext = pINST->pRun; + pINST->pRun = pRt; + while( pRt->Step() ) {} + +#ifdef DBG_TRACE_BASIC + bool bLeave = true; + dbg_traceNotifyCall( this, NULL, 0, bLeave ); +#endif + + pINST->pRun = pRt->pNext; + delete pRt; + pMOD = pOldMod; + // if( bDelInst ) + // delete pINST, pINST = NULL; + pImage->bInit = TRUE; + pImage->bFirstInit = FALSE; + + // RunInit is not activ anymore + GetSbData()->bRunInit = FALSE; + } +} + +// Delete with private/dim declared variables + +void SbModule::AddVarName( const String& aName ) +{ + // see if the name is added allready + std::vector< String >::iterator it_end = mModuleVariableNames.end(); + for ( std::vector< String >::iterator it = mModuleVariableNames.begin(); it != it_end; ++it ) + { + if ( aName == *it ) + return; + } + mModuleVariableNames.push_back( aName ); +} + +void SbModule::RemoveVars() +{ + std::vector< String >::iterator it_end = mModuleVariableNames.end(); + for ( std::vector< String >::iterator it = mModuleVariableNames.begin(); it != it_end; ++it ) + { + // We don't want a Find being called in a derived class ( e.g. + // SbUserform because it could trigger say an initialise event + // which would cause basic to be re-run in the middle of the init ( and remember RemoveVars is called from compile and we don't want code to run as part of the compile ) + SbxVariableRef p = SbModule::Find( *it, SbxCLASS_PROPERTY ); + if( p.Is() ) + Remove (p); + } +} + +void SbModule::ClearPrivateVars() +{ + for( USHORT i = 0 ; i < pProps->Count() ; i++ ) + { + SbProperty* p = PTR_CAST(SbProperty,pProps->Get( i ) ); + if( p ) + { + // Delete not the arrays, only their content + if( p->GetType() & SbxARRAY ) + { + SbxArray* pArray = PTR_CAST(SbxArray,p->GetObject()); + if( pArray ) + { + for( USHORT j = 0 ; j < pArray->Count() ; j++ ) + { + SbxVariable* pj = PTR_CAST(SbxVariable,pArray->Get( j )); + pj->SbxValue::Clear(); + /* + USHORT nFlags = pj->GetFlags(); + pj->SetFlags( (nFlags | SBX_WRITE) & (~SBX_FIXED) ); + pj->PutEmpty(); + pj->SetFlags( nFlags ); + */ + } + } + } + else + { + p->SbxValue::Clear(); + /* + USHORT nFlags = p->GetFlags(); + p->SetFlags( (nFlags | SBX_WRITE) & (~SBX_FIXED) ); + p->PutEmpty(); + p->SetFlags( nFlags ); + */ + } + } + } +} + +// At first in this module, to remain 358-capable +// (Avoid branch in sb.cxx) +void StarBASIC::ClearAllModuleVars( void ) +{ + // Initialise the own module + for ( USHORT nMod = 0; nMod < pModules->Count(); nMod++ ) + { + SbModule* pModule = (SbModule*)pModules->Get( nMod ); + // Initialise only, if the startcode was already executed + if( pModule->pImage && pModule->pImage->bInit ) + pModule->ClearPrivateVars(); + } + +} + +// Execution of the init-code of all module +void SbModule::GlobalRunInit( BOOL bBasicStart ) +{ + // If no Basic-Start, only initialise, if the module is not initialised + if( !bBasicStart ) + if( !(pImage && !pImage->bInit) ) + return; + + // Initialise GlobalInitErr-Flag for Compiler-Error + // With the help of this flags could be located in SbModule::Run() after the call of + // GlobalRunInit, if at the intialising of the module + // an error occurred. Then it will not be launched. + GetSbData()->bGlobalInitErr = FALSE; + + // Parent of the module is a Basic + StarBASIC *pBasic = PTR_CAST(StarBASIC,GetParent()); + if( pBasic ) + { + pBasic->InitAllModules(); + + SbxObject* pParent_ = pBasic->GetParent(); + if( pParent_ ) + { + StarBASIC * pParentBasic = PTR_CAST(StarBASIC,pParent_); + if( pParentBasic ) + { + pParentBasic->InitAllModules( pBasic ); + + // #109018 Parent can also have a parent (library in doc) + SbxObject* pParentParent = pParentBasic->GetParent(); + if( pParentParent ) + { + StarBASIC * pParentParentBasic = PTR_CAST(StarBASIC,pParentParent); + if( pParentParentBasic ) + pParentParentBasic->InitAllModules( pParentBasic ); + } + } + } + } +} + +void SbModule::GlobalRunDeInit( void ) +{ + StarBASIC *pBasic = PTR_CAST(StarBASIC,GetParent()); + if( pBasic ) + { + pBasic->DeInitAllModules(); + + SbxObject* pParent_ = pBasic->GetParent(); + if( pParent_ ) + pBasic = PTR_CAST(StarBASIC,pParent_); + if( pBasic ) + pBasic->DeInitAllModules(); + } +} + +// Search for the next STMNT-Command in the code. This was used from the STMNT- +// Opcode to set the endcolumn. + +const BYTE* SbModule::FindNextStmnt( const BYTE* p, USHORT& nLine, USHORT& nCol ) const +{ + return FindNextStmnt( p, nLine, nCol, FALSE ); +} + +const BYTE* SbModule::FindNextStmnt( const BYTE* p, USHORT& nLine, USHORT& nCol, + BOOL bFollowJumps, const SbiImage* pImg ) const +{ + UINT32 nPC = (UINT32) ( p - (const BYTE*) pImage->GetCode() ); + while( nPC < pImage->GetCodeSize() ) + { + SbiOpcode eOp = (SbiOpcode ) ( *p++ ); + nPC++; + if( bFollowJumps && eOp == _JUMP && pImg ) + { + DBG_ASSERT( pImg, "FindNextStmnt: pImg==NULL with FollowJumps option" ); + UINT32 nOp1 = *p++; nOp1 |= *p++ << 8; + nOp1 |= *p++ << 16; nOp1 |= *p++ << 24; + p = (const BYTE*) pImg->GetCode() + nOp1; + } + else if( eOp >= SbOP1_START && eOp <= SbOP1_END ) + p += 4, nPC += 4; + else if( eOp == _STMNT ) + { + UINT32 nl, nc; + nl = *p++; nl |= *p++ << 8; + nl |= *p++ << 16 ; nl |= *p++ << 24; + nc = *p++; nc |= *p++ << 8; + nc |= *p++ << 16 ; nc |= *p++ << 24; + nLine = (USHORT)nl; nCol = (USHORT)nc; + return p; + } + else if( eOp >= SbOP2_START && eOp <= SbOP2_END ) + p += 8, nPC += 8; + else if( !( eOp >= SbOP0_START && eOp <= SbOP0_END ) ) + { + StarBASIC::FatalError( SbERR_INTERNAL_ERROR ); + break; + } + } + return NULL; +} + +// Test, if a line contains STMNT-Opcodes + +BOOL SbModule::IsBreakable( USHORT nLine ) const +{ + if( !pImage ) + return FALSE; + const BYTE* p = (const BYTE* ) pImage->GetCode(); + USHORT nl, nc; + while( ( p = FindNextStmnt( p, nl, nc ) ) != NULL ) + if( nl == nLine ) + return TRUE; + return FALSE; +} + +USHORT SbModule::GetBPCount() const +{ + return pBreaks ? pBreaks->Count() : 0; +} + +USHORT SbModule::GetBP( USHORT n ) const +{ + if( pBreaks && n < pBreaks->Count() ) + return pBreaks->GetObject( n ); + else + return 0; +} + +BOOL SbModule::IsBP( USHORT nLine ) const +{ + if( pBreaks ) + { + const USHORT* p = pBreaks->GetData(); + USHORT n = pBreaks->Count(); + for( USHORT i = 0; i < n; i++, p++ ) + { + USHORT b = *p; + if( b == nLine ) + return TRUE; + if( b < nLine ) + break; + } + } + return FALSE; +} + +BOOL SbModule::SetBP( USHORT nLine ) +{ + if( !IsBreakable( nLine ) ) + return FALSE; + if( !pBreaks ) + pBreaks = new SbiBreakpoints; + const USHORT* p = pBreaks->GetData(); + USHORT n = pBreaks->Count(); + USHORT i; + for( i = 0; i < n; i++, p++ ) + { + USHORT b = *p; + if( b == nLine ) + return TRUE; + if( b < nLine ) + break; + } + pBreaks->Insert( &nLine, 1, i ); + + // #38568: Set during runtime as well here SbDEBUG_BREAK + if( pINST && pINST->pRun ) + pINST->pRun->SetDebugFlags( SbDEBUG_BREAK ); + + return IsBreakable( nLine ); +} + +BOOL SbModule::ClearBP( USHORT nLine ) +{ + BOOL bRes = FALSE; + if( pBreaks ) + { + const USHORT* p = pBreaks->GetData(); + USHORT n = pBreaks->Count(); + for( USHORT i = 0; i < n; i++, p++ ) + { + USHORT b = *p; + if( b == nLine ) + { + pBreaks->Remove( i, 1 ); bRes = TRUE; break; + } + if( b < nLine ) + break; + } + if( !pBreaks->Count() ) + delete pBreaks, pBreaks = NULL; + } + return bRes; +} + +void SbModule::ClearAllBP() +{ + delete pBreaks; pBreaks = NULL; +} + +void +SbModule::fixUpMethodStart( bool bCvtToLegacy, SbiImage* pImg ) const +{ + if ( !pImg ) + pImg = pImage; + for( UINT32 i = 0; i < pMethods->Count(); i++ ) + { + SbMethod* pMeth = PTR_CAST(SbMethod,pMethods->Get( (USHORT)i ) ); + if( pMeth ) + { + //fixup method start positions + if ( bCvtToLegacy ) + pMeth->nStart = pImg->CalcLegacyOffset( pMeth->nStart ); + else + pMeth->nStart = pImg->CalcNewOffset( (USHORT)pMeth->nStart ); + } + } + +} + +BOOL SbModule::LoadData( SvStream& rStrm, USHORT nVer ) +{ + Clear(); + if( !SbxObject::LoadData( rStrm, 1 ) ) + return FALSE; + // As a precaution... + SetFlag( SBX_EXTSEARCH | SBX_GBLSEARCH ); + BYTE bImage; + rStrm >> bImage; + if( bImage ) + { + SbiImage* p = new SbiImage; + UINT32 nImgVer = 0; + + if( !p->Load( rStrm, nImgVer ) ) + { + delete p; + return FALSE; + } + // If the image is in old format, we fix up the method start offsets + if ( nImgVer < B_EXT_IMG_VERSION ) + { + fixUpMethodStart( false, p ); + p->ReleaseLegacyBuffer(); + } + aComment = p->aComment; + SetName( p->aName ); + if( p->GetCodeSize() ) + { + aOUSource = p->aOUSource; + // Old version: image away + if( nVer == 1 ) + { + SetSource32( p->aOUSource ); + delete p; + } + else + pImage = p; + } + else + { + SetSource32( p->aOUSource ); + delete p; + } + } + return TRUE; +} + +BOOL SbModule::StoreData( SvStream& rStrm ) const +{ + BOOL bFixup = ( pImage && !pImage->ExceedsLegacyLimits() ); + if ( bFixup ) + fixUpMethodStart( true ); + BOOL bRet = SbxObject::StoreData( rStrm ); + if ( !bRet ) + return FALSE; + + if( pImage ) + { + pImage->aOUSource = aOUSource; + pImage->aComment = aComment; + pImage->aName = GetName(); + rStrm << (BYTE) 1; + // # PCode is saved only for legacy formats only + // It should be noted that it probably isn't necessary + // It would be better not to store the image ( more flexible with + // formats ) + bool bRes = pImage->Save( rStrm, B_LEGACYVERSION ); + if ( bFixup ) + fixUpMethodStart( false ); // restore method starts + return bRes; + + } + else + { + SbiImage aImg; + aImg.aOUSource = aOUSource; + aImg.aComment = aComment; + aImg.aName = GetName(); + rStrm << (BYTE) 1; + return aImg.Save( rStrm ); + } +} + +BOOL SbModule::ExceedsLegacyModuleSize() +{ + if ( !IsCompiled() ) + Compile(); + if ( pImage && pImage->ExceedsLegacyLimits() ) + return true; + return false; +} + +class ErrorHdlResetter +{ + Link mErrHandler; + bool mbError; + public: + ErrorHdlResetter() : mbError( false ) + { + // save error handler + mErrHandler = StarBASIC::GetGlobalErrorHdl(); + // set new error handler + StarBASIC::SetGlobalErrorHdl( LINK( this, ErrorHdlResetter, BasicErrorHdl ) ); + } + ~ErrorHdlResetter() + { + // restore error handler + StarBASIC::SetGlobalErrorHdl(mErrHandler); + } + DECL_LINK( BasicErrorHdl, StarBASIC * ); + bool HasError() { return mbError; } +}; +IMPL_LINK( ErrorHdlResetter, BasicErrorHdl, StarBASIC *, /*pBasic*/) +{ + mbError = true; + return 0; +} + +bool SbModule::HasExeCode() +{ + // And empty Image always has the Global Chain set up + static const unsigned char pEmptyImage[] = { 0x45, 0x0 , 0x0, 0x0, 0x0 }; + // lets be stricter for the moment than VBA + + if (!IsCompiled()) + { + ErrorHdlResetter aGblErrHdl; + Compile(); + if (aGblErrHdl.HasError()) //assume unsafe on compile error + return true; + } + + bool bRes = false; + if (pImage && !(pImage->GetCodeSize() == 5 && (memcmp(pImage->GetCode(), pEmptyImage, pImage->GetCodeSize()) == 0 ))) + bRes = true; + + return bRes; +} + +// Store only image, no source +BOOL SbModule::StoreBinaryData( SvStream& rStrm ) +{ + return StoreBinaryData( rStrm, 0 ); +} + +BOOL SbModule::StoreBinaryData( SvStream& rStrm, USHORT nVer ) +{ + BOOL bRet = Compile(); + if( bRet ) + { + BOOL bFixup = ( !nVer && !pImage->ExceedsLegacyLimits() );// save in old image format, fix up method starts + + if ( bFixup ) // save in old image format, fix up method starts + fixUpMethodStart( true ); + bRet = SbxObject::StoreData( rStrm ); + if( bRet ) + { + pImage->aOUSource = ::rtl::OUString(); + pImage->aComment = aComment; + pImage->aName = GetName(); + + rStrm << (BYTE) 1; + if ( nVer ) + bRet = pImage->Save( rStrm, B_EXT_IMG_VERSION ); + else + bRet = pImage->Save( rStrm, B_LEGACYVERSION ); + if ( bFixup ) + fixUpMethodStart( false ); // restore method starts + + pImage->aOUSource = aOUSource; + } + } + return bRet; +} + +// Called for >= OO 1.0 passwd protected libraries only +// + +BOOL SbModule::LoadBinaryData( SvStream& rStrm ) +{ + ::rtl::OUString aKeepSource = aOUSource; + bool bRet = LoadData( rStrm, 2 ); + LoadCompleted(); + aOUSource = aKeepSource; + return bRet; +} + +BOOL SbModule::LoadCompleted() +{ + SbxArray* p = GetMethods(); + USHORT i; + for( i = 0; i < p->Count(); i++ ) + { + SbMethod* q = PTR_CAST(SbMethod,p->Get( i ) ); + if( q ) + q->pMod = this; + } + p = GetProperties(); + for( i = 0; i < p->Count(); i++ ) + { + SbProperty* q = PTR_CAST(SbProperty,p->Get( i ) ); + if( q ) + q->pMod = this; + } + return TRUE; +} + +///////////////////////////////////////////////////////////////////////// +// Implementation SbJScriptModule (Basic-Modul fuer JavaScript-Sourcen) +SbJScriptModule::SbJScriptModule( const String& rName ) + :SbModule( rName ) +{ +} + +BOOL SbJScriptModule::LoadData( SvStream& rStrm, USHORT nVer ) +{ + (void)nVer; + + Clear(); + if( !SbxObject::LoadData( rStrm, 1 ) ) + return FALSE; + + // Get the source string + String aTmp; + rStrm.ReadByteString( aTmp, gsl_getSystemTextEncoding() ); + aOUSource = aTmp; + //rStrm >> aSource; + return TRUE; +} + +BOOL SbJScriptModule::StoreData( SvStream& rStrm ) const +{ + if( !SbxObject::StoreData( rStrm ) ) + return FALSE; + + // Write the source string + String aTmp = aOUSource; + rStrm.WriteByteString( aTmp, gsl_getSystemTextEncoding() ); + //rStrm << aSource; + return TRUE; +} + + +///////////////////////////////////////////////////////////////////////// + +SbMethod::SbMethod( const String& r, SbxDataType t, SbModule* p ) + : SbxMethod( r, t ), pMod( p ) +{ + bInvalid = TRUE; + nStart = + nDebugFlags = + nLine1 = + nLine2 = 0; + refStatics = new SbxArray; + mCaller = 0; + // From: 1996-07.02: HACK due to 'Referenz could not be saved' + SetFlag( SBX_NO_MODIFY ); +} + +SbMethod::SbMethod( const SbMethod& r ) + : SvRefBase( r ), SbxMethod( r ) +{ + pMod = r.pMod; + bInvalid = r.bInvalid; + nStart = r.nStart; + nDebugFlags = r.nDebugFlags; + nLine1 = r.nLine1; + nLine2 = r.nLine2; + refStatics = r.refStatics; + mCaller = r.mCaller; + SetFlag( SBX_NO_MODIFY ); +} + +SbMethod::~SbMethod() +{ +} + +SbxArray* SbMethod::GetLocals() +{ + if( pINST ) + return pINST->GetLocals( this ); + else + return NULL; +} + +void SbMethod::ClearStatics() +{ + refStatics = new SbxArray; + +} +SbxArray* SbMethod::GetStatics() +{ + return refStatics; +} + +BOOL SbMethod::LoadData( SvStream& rStrm, USHORT nVer ) +{ + if( !SbxMethod::LoadData( rStrm, 1 ) ) + return FALSE; + INT16 n; + rStrm >> n; + INT16 nTempStart = (INT16)nStart; + // nDebugFlags = n; // From 1996-01-16: no longer take over + if( nVer == 2 ) + rStrm >> nLine1 >> nLine2 >> nTempStart >> bInvalid; + // From: 1996-07-02: HACK ue to 'Referenz could not be saved' + SetFlag( SBX_NO_MODIFY ); + nStart = nTempStart; + return TRUE; +} + +BOOL SbMethod::StoreData( SvStream& rStrm ) const +{ + if( !SbxMethod::StoreData( rStrm ) ) + return FALSE; + rStrm << (INT16) nDebugFlags + << (INT16) nLine1 + << (INT16) nLine2 + << (INT16) nStart + << (BYTE) bInvalid; + return TRUE; +} + +void SbMethod::GetLineRange( USHORT& l1, USHORT& l2 ) +{ + l1 = nLine1; l2 = nLine2; +} + +// Could later be deleted + +SbxInfo* SbMethod::GetInfo() +{ + return pInfo; +} + +// Interface to execute a method of the applications +// #34191# With special RefCounting, damit so that the Basic was not fired of by CloseDocument() +// The return value will be delivered as string. +ErrCode SbMethod::Call( SbxValue* pRet, SbxVariable* pCaller ) +{ + if ( pCaller ) + { + OSL_TRACE("SbMethod::Call Have been passed a caller 0x%x", pCaller ); + mCaller = pCaller; + } + // RefCount vom Modul hochzaehlen + SbModule* pMod_ = (SbModule*)GetParent(); + pMod_->AddRef(); + + // Increment the RefCount of the Basic + StarBASIC* pBasic = (StarBASIC*)pMod_->GetParent(); + pBasic->AddRef(); + + // Establish the values to get the return value + SbxValues aVals; + aVals.eType = SbxVARIANT; + + // #104083: Compile BEFORE get + if( bInvalid && !pMod_->Compile() ) + StarBASIC::Error( SbERR_BAD_PROP_VALUE ); + + Get( aVals ); + if ( pRet ) + pRet->Put( aVals ); + + // Was there an error + ErrCode nErr = SbxBase::GetError(); + SbxBase::ResetError(); + + // Release objects + pMod_->ReleaseRef(); + pBasic->ReleaseRef(); + mCaller = 0; + return nErr; +} + + +// #100883 Own Broadcast for SbMethod +void SbMethod::Broadcast( ULONG nHintId ) +{ + if( pCst && !IsSet( SBX_NO_BROADCAST ) && StaticIsEnabledBroadcasting() ) + { + // Because the method could be called from outside, test here once again + // the authorisation + if( nHintId & SBX_HINT_DATAWANTED ) + if( !CanRead() ) + return; + if( nHintId & SBX_HINT_DATACHANGED ) + if( !CanWrite() ) + return; + + if( pMod && !pMod->IsCompiled() ) + pMod->Compile(); + + // Block broadcasts while creating new method + SfxBroadcaster* pSave = pCst; + pCst = NULL; + SbMethod* pThisCopy = new SbMethod( *this ); + SbMethodRef xHolder = pThisCopy; + if( mpPar.Is() ) + { + // Enrigister this as element 0, but don't reset the parent! + if( GetType() != SbxVOID ) + mpPar->PutDirect( pThisCopy, 0 ); + SetParameters( NULL ); + } + + pCst = pSave; + pSave->Broadcast( SbxHint( nHintId, pThisCopy ) ); + + USHORT nSaveFlags = GetFlags(); + SetFlag( SBX_READWRITE ); + pCst = NULL; + Put( pThisCopy->GetValues_Impl() ); + pCst = pSave; + SetFlags( nSaveFlags ); + } +} + +///////////////////////////////////////////////////////////////////////// + +// Implementation of SbJScriptMethod (method class as a wrapper for JavaScript-functions) + +SbJScriptMethod::SbJScriptMethod( const String& r, SbxDataType t, SbModule* p ) + : SbMethod( r, t, p ) +{ +} + +SbJScriptMethod::~SbJScriptMethod() +{} + + +///////////////////////////////////////////////////////////////////////// +SbObjModule::SbObjModule( const String& rName, const com::sun::star::script::ModuleInfo& mInfo, bool bIsVbaCompatible ) + : SbModule( rName, bIsVbaCompatible ) +{ + SetModuleType( mInfo.ModuleType ); + if ( mInfo.ModuleType == script::ModuleType::FORM ) + { + SetClassName( rtl::OUString(RTL_CONSTASCII_USTRINGPARAM( "Form" )) ); + } + else if ( mInfo.ModuleObject.is() ) + SetUnoObject( uno::makeAny( mInfo.ModuleObject ) ); +} +void +SbObjModule::SetUnoObject( const uno::Any& aObj ) throw ( uno::RuntimeException ) +{ + SbUnoObject* pUnoObj = PTR_CAST(SbUnoObject,(SbxVariable*)pDocObject); + if ( pUnoObj && pUnoObj->getUnoAny() == aObj ) // object is equal, nothing to do + return; + pDocObject = new SbUnoObject( GetName(), uno::makeAny( aObj ) ); + + com::sun::star::uno::Reference< com::sun::star::lang::XServiceInfo > xServiceInfo( aObj, com::sun::star::uno::UNO_QUERY_THROW ); + if( xServiceInfo->supportsService( rtl::OUString(RTL_CONSTASCII_USTRINGPARAM( "ooo.vba.excel.Worksheet" )) ) ) + { + SetClassName( rtl::OUString(RTL_CONSTASCII_USTRINGPARAM( "Worksheet" )) ); + } + else if( xServiceInfo->supportsService( rtl::OUString(RTL_CONSTASCII_USTRINGPARAM( "ooo.vba.excel.Workbook" )) ) ) + { + SetClassName( rtl::OUString(RTL_CONSTASCII_USTRINGPARAM( "Workbook" )) ); + } +} + +SbxVariable* +SbObjModule::GetObject() +{ + return pDocObject; +} +SbxVariable* +SbObjModule::Find( const XubString& rName, SbxClassType t ) +{ + //OSL_TRACE("SbObjectModule find for %s", rtl::OUStringToOString( rName, RTL_TEXTENCODING_UTF8 ).getStr() ); + SbxVariable* pVar = NULL; + if ( pDocObject) + pVar = pDocObject->Find( rName, t ); + if ( !pVar ) + pVar = SbModule::Find( rName, t ); + return pVar; +} + +typedef ::cppu::WeakImplHelper2< awt::XTopWindowListener, awt::XWindowListener > FormObjEventListener_BASE; + +class FormObjEventListenerImpl : public FormObjEventListener_BASE +{ + SbUserFormModule* mpUserForm; + uno::Reference< lang::XComponent > mxComponent; + bool mbDisposed; + sal_Bool mbOpened; + sal_Bool mbActivated; + sal_Bool mbShowing; + FormObjEventListenerImpl(); // not defined + FormObjEventListenerImpl(const FormObjEventListenerImpl&); // not defined + +public: + FormObjEventListenerImpl( SbUserFormModule* pUserForm, const uno::Reference< lang::XComponent >& xComponent ) : + mpUserForm( pUserForm ), mxComponent( xComponent) , + mbDisposed( false ), mbOpened( sal_False ), mbActivated( sal_False ), mbShowing( sal_False ) + { + if ( mxComponent.is() ) + { + OSL_TRACE("*********** Registering the listeners"); + try + { + uno::Reference< awt::XTopWindow >( mxComponent, uno::UNO_QUERY_THROW )->addTopWindowListener( this ); + } + catch( uno::Exception& ) {} + try + { + uno::Reference< awt::XWindow >( mxComponent, uno::UNO_QUERY_THROW )->addWindowListener( this ); + } + catch( uno::Exception& ) {} + } + } + + virtual ~FormObjEventListenerImpl() + { + removeListener(); + } + + sal_Bool isShowing() const { return mbShowing; } + + void removeListener() + { + if ( mxComponent.is() && !mbDisposed ) + { + OSL_TRACE("*********** Removing the listeners"); + try + { + uno::Reference< awt::XTopWindow >( mxComponent, uno::UNO_QUERY_THROW )->removeTopWindowListener( this ); + } + catch( uno::Exception& ) {} + try + { + uno::Reference< awt::XWindow >( mxComponent, uno::UNO_QUERY_THROW )->removeWindowListener( this ); + } + catch( uno::Exception& ) {} + } + mxComponent.clear(); + } + + virtual void SAL_CALL windowOpened( const lang::EventObject& /*e*/ ) throw (uno::RuntimeException) + { + if ( mpUserForm ) + { + mbOpened = sal_True; + mbShowing = sal_True; + if ( mbActivated ) + { + mbOpened = mbActivated = sal_False; + mpUserForm->triggerActivateEvent(); + } + } + } + + + virtual void SAL_CALL windowClosing( const lang::EventObject& e ) throw (uno::RuntimeException) + { + uno::Reference< awt::XDialog > xDialog( e.Source, uno::UNO_QUERY ); + if ( xDialog.is() ) + { + uno::Reference< awt::XControl > xControl( xDialog, uno::UNO_QUERY ); + if ( xControl->getPeer().is() ) + { + uno::Reference< document::XVbaMethodParameter > xVbaMethodParameter( xControl->getPeer(), uno::UNO_QUERY ); + if ( xVbaMethodParameter.is() ) + { + sal_Int8 nCancel = 0; + sal_Int8 nCloseMode = 0; + + Sequence< Any > aParams; + aParams.realloc(2); + aParams[0] <<= nCancel; + aParams[1] <<= nCloseMode; + + mpUserForm->triggerMethod( rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("Userform_QueryClose") ), + aParams); + xVbaMethodParameter->setVbaMethodParameter( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM("Cancel")), aParams[0]); + return; + + } + } + } + + mpUserForm->triggerMethod( rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("Userform_QueryClose") ) ); + } + + + virtual void SAL_CALL windowClosed( const lang::EventObject& /*e*/ ) throw (uno::RuntimeException) + { + mbOpened = sal_False; + mbShowing = sal_False; + } + + virtual void SAL_CALL windowMinimized( const lang::EventObject& /*e*/ ) throw (uno::RuntimeException) + { + } + + virtual void SAL_CALL windowNormalized( const lang::EventObject& /*e*/ ) throw (uno::RuntimeException) + { + } + + virtual void SAL_CALL windowActivated( const lang::EventObject& /*e*/ ) throw (uno::RuntimeException) + { + if ( mpUserForm ) + { + mbActivated = sal_True; + if ( mbOpened ) + { + mbOpened = mbActivated = sal_False; + mpUserForm->triggerActivateEvent(); + } + } + } + + virtual void SAL_CALL windowDeactivated( const lang::EventObject& /*e*/ ) throw (uno::RuntimeException) + { + if ( mpUserForm ) + mpUserForm->triggerDeactivateEvent(); + } + + virtual void SAL_CALL windowResized( const awt::WindowEvent& /*e*/ ) throw (uno::RuntimeException) + { + if ( mpUserForm ) + { + mpUserForm->triggerResizeEvent(); + mpUserForm->triggerLayoutEvent(); + } + } + + virtual void SAL_CALL windowMoved( const awt::WindowEvent& /*e*/ ) throw (uno::RuntimeException) + { + if ( mpUserForm ) + mpUserForm->triggerLayoutEvent(); + } + + virtual void SAL_CALL windowShown( const lang::EventObject& /*e*/ ) throw (uno::RuntimeException) + { + } + + virtual void SAL_CALL windowHidden( const lang::EventObject& /*e*/ ) throw (uno::RuntimeException) + { + } + + virtual void SAL_CALL disposing( const lang::EventObject& /*Source*/ ) throw (uno::RuntimeException) + { + OSL_TRACE("** Userform/Dialog disposing"); + mbDisposed = true; + mxComponent.clear(); + if ( mpUserForm ) + mpUserForm->ResetApiObj(); + } +}; + +SbUserFormModule::SbUserFormModule( const String& rName, const com::sun::star::script::ModuleInfo& mInfo, bool bIsCompat ) + : SbObjModule( rName, mInfo, bIsCompat ) + , m_mInfo( mInfo ) + , mbInit( false ) +{ + m_xModel.set( mInfo.ModuleObject, uno::UNO_QUERY_THROW ); +} + +SbUserFormModule::~SbUserFormModule() +{ +} + +void SbUserFormModule::ResetApiObj() +{ + if ( m_xDialog.is() ) // probably someone close the dialog window + { + triggerTerminateEvent(); + } + pDocObject = NULL; + m_xDialog = NULL; +} + +void SbUserFormModule::triggerMethod( const String& aMethodToRun ) +{ + Sequence< Any > aArguments; + triggerMethod( aMethodToRun, aArguments ); +} +void SbUserFormModule::triggerMethod( const String& aMethodToRun, Sequence< Any >& aArguments) +{ + OSL_TRACE("*** trigger %s ***", rtl::OUStringToOString( aMethodToRun, RTL_TEXTENCODING_UTF8 ).getStr() ); + // Search method + SbxVariable* pMeth = SbObjModule::Find( aMethodToRun, SbxCLASS_METHOD ); + if( pMeth ) + { + + if ( aArguments.getLength() > 0 ) // Setup parameters + { + SbxArrayRef xArray = new SbxArray; + xArray->Put( pMeth, 0 ); // Method as parameter 0 + + for ( sal_Int32 i = 0; i < aArguments.getLength(); ++i ) + { + SbxVariableRef xSbxVar = new SbxVariable( SbxVARIANT ); + unoToSbxValue( static_cast< SbxVariable* >( xSbxVar ), aArguments[i] ); + xArray->Put( xSbxVar, static_cast< USHORT >( i ) + 1 ); + + // Enable passing by ref + if ( xSbxVar->GetType() != SbxVARIANT ) + xSbxVar->SetFlag( SBX_FIXED ); + } + pMeth->SetParameters( xArray ); + + SbxValues aVals; + pMeth->Get( aVals ); + + for ( sal_Int32 i = 0; i < aArguments.getLength(); ++i ) + { + aArguments[i] = sbxToUnoValue( xArray->Get( static_cast< USHORT >(i) + 1) ); + } + pMeth->SetParameters( NULL ); + } + else + + { + SbxValues aVals; + pMeth->Get( aVals ); + } + } +} + +void SbUserFormModule::triggerActivateEvent( void ) +{ + OSL_TRACE("**** entering SbUserFormModule::triggerActivate"); + triggerMethod( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM("UserForm_Activate") ) ); + OSL_TRACE("**** leaving SbUserFormModule::triggerActivate"); +} + +void SbUserFormModule::triggerDeactivateEvent( void ) +{ + OSL_TRACE("**** SbUserFormModule::triggerDeactivate"); + triggerMethod( rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("Userform_Deactivate") ) ); +} + +void SbUserFormModule::triggerInitializeEvent( void ) +{ + if ( mbInit ) + return; + OSL_TRACE("**** SbUserFormModule::triggerInitializeEvent"); + static String aInitMethodName( RTL_CONSTASCII_USTRINGPARAM("Userform_Initialize") ); + triggerMethod( aInitMethodName ); + mbInit = true; +} + +void SbUserFormModule::triggerTerminateEvent( void ) +{ + OSL_TRACE("**** SbUserFormModule::triggerTerminateEvent"); + static String aTermMethodName( RTL_CONSTASCII_USTRINGPARAM("Userform_Terminate") ); + triggerMethod( aTermMethodName ); + mbInit=false; +} + +void SbUserFormModule::triggerLayoutEvent( void ) +{ + static String aMethodName( RTL_CONSTASCII_USTRINGPARAM("Userform_Layout") ); + triggerMethod( aMethodName ); +} + +void SbUserFormModule::triggerResizeEvent( void ) +{ + static String aMethodName( RTL_CONSTASCII_USTRINGPARAM("Userform_Resize") ); + triggerMethod( aMethodName ); +} + +SbUserFormModuleInstance* SbUserFormModule::CreateInstance() +{ + SbUserFormModuleInstance* pInstance = new SbUserFormModuleInstance( this, GetName(), m_mInfo, IsVBACompat() ); + return pInstance; +} + +SbUserFormModuleInstance::SbUserFormModuleInstance( SbUserFormModule* pParentModule, + const String& rName, const com::sun::star::script::ModuleInfo& mInfo, bool bIsVBACompat ) + : SbUserFormModule( rName, mInfo, bIsVBACompat ) + , m_pParentModule( pParentModule ) +{ +} + +BOOL SbUserFormModuleInstance::IsClass( const XubString& rName ) const +{ + BOOL bParentNameMatches = m_pParentModule->GetName().EqualsIgnoreCaseAscii( rName ); + BOOL bRet = bParentNameMatches || SbxObject::IsClass( rName ); + return bRet; +} + +SbxVariable* SbUserFormModuleInstance::Find( const XubString& rName, SbxClassType t ) +{ + SbxVariable* pVar = m_pParentModule->Find( rName, t ); + return pVar; +} + + +void SbUserFormModule::Load() +{ + OSL_TRACE("** load() "); + // forces a load + if ( !pDocObject ) + InitObject(); +} + + +void SbUserFormModule::Unload() +{ + OSL_TRACE("** Unload() "); + + sal_Int8 nCancel = 0; + sal_Int8 nCloseMode = 1; + + Sequence< Any > aParams; + aParams.realloc(2); + aParams[0] <<= nCancel; + aParams[1] <<= nCloseMode; + + triggerMethod( rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("Userform_QueryClose") ), aParams); + + aParams[0] >>= nCancel; + // basic boolean ( and what the user might use ) can be ambiguous ( e.g. basic true = -1 ) + // test agains 0 ( false ) and assume anything else is true + // ( Note: ) this used to work ( something changes somewhere ) + if (nCancel != 0) + { + return; + } + + if ( m_xDialog.is() ) + { + triggerTerminateEvent(); + } + // Search method + SbxVariable* pMeth = SbObjModule::Find( String( RTL_CONSTASCII_USTRINGPARAM( "UnloadObject" ) ), SbxCLASS_METHOD ); + if( pMeth ) + { + OSL_TRACE("Attempting too run the UnloadObjectMethod"); + m_xDialog.clear(); //release ref to the uno object + SbxValues aVals; + bool bWaitForDispose = true; // assume dialog is showing + if ( m_DialogListener.get() ) + { + bWaitForDispose = m_DialogListener->isShowing(); + OSL_TRACE("Showing %d", bWaitForDispose ); + } + pMeth->Get( aVals); + if ( !bWaitForDispose ) + { + // we've either already got a dispose or we'er never going to get one + ResetApiObj(); + } // else wait for dispose + OSL_TRACE("UnloadObject completed ( we hope )"); + } +} + + +void SbUserFormModule::InitObject() +{ + try + { + + String aHook( RTL_CONSTASCII_USTRINGPARAM( "VBAGlobals" ) ); + SbUnoObject* pGlobs = (SbUnoObject*)GetParent()->Find( aHook, SbxCLASS_DONTCARE ); + if ( m_xModel.is() && pGlobs ) + { + + uno::Reference< lang::XMultiServiceFactory > xVBAFactory( pGlobs->getUnoAny(), uno::UNO_QUERY_THROW ); + uno::Reference< lang::XMultiServiceFactory > xFactory = comphelper::getProcessServiceFactory(); + uno::Sequence< uno::Any > aArgs(1); + aArgs[ 0 ] <<= m_xModel; + rtl::OUString sDialogUrl( RTL_CONSTASCII_USTRINGPARAM("vnd.sun.star.script:" ) ); + rtl::OUString sProjectName( RTL_CONSTASCII_USTRINGPARAM("Standard") ); + + try + { + Reference< beans::XPropertySet > xProps( m_xModel, UNO_QUERY_THROW ); + uno::Reference< script::vba::XVBACompatibility > xVBAMode( xProps->getPropertyValue( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM("BasicLibraries") ) ), uno::UNO_QUERY_THROW ); + sProjectName = xVBAMode->getProjectName(); + } + catch( Exception& /*e*/) {} + + sDialogUrl = sDialogUrl.concat( sProjectName ).concat( rtl::OUString( '.') ).concat( GetName() ).concat( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM("?location=document") ) ); + + uno::Reference< awt::XDialogProvider > xProvider( xFactory->createInstanceWithArguments( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM("com.sun.star.awt.DialogProvider")), aArgs ), uno::UNO_QUERY_THROW ); + m_xDialog = xProvider->createDialog( sDialogUrl ); + + // create vba api object + aArgs.realloc( 4 ); + aArgs[ 0 ] = uno::Any(); + aArgs[ 1 ] <<= m_xDialog; + aArgs[ 2 ] <<= m_xModel; + aArgs[ 3 ] <<= sProjectName; + pDocObject = new SbUnoObject( GetName(), uno::makeAny( xVBAFactory->createInstanceWithArguments( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM("ooo.vba.msforms.UserForm")), aArgs ) ) ); + uno::Reference< lang::XComponent > xComponent( aArgs[ 1 ], uno::UNO_QUERY_THROW ); + // remove old listener if it exists + if ( m_DialogListener.get() ) + m_DialogListener->removeListener(); + m_DialogListener = new FormObjEventListenerImpl( this, xComponent ); + + triggerInitializeEvent(); + } + } + catch( uno::Exception& ) + { + } + +} + +SbxVariable* +SbUserFormModule::Find( const XubString& rName, SbxClassType t ) +{ + if ( !pDocObject && !GetSbData()->bRunInit && pINST ) + InitObject(); + return SbObjModule::Find( rName, t ); +} +///////////////////////////////////////////////////////////////////////// + +SbProperty::SbProperty( const String& r, SbxDataType t, SbModule* p ) + : SbxProperty( r, t ), pMod( p ) +{ + bInvalid = FALSE; +} + +SbProperty::~SbProperty() +{} + +///////////////////////////////////////////////////////////////////////// + +SbProcedureProperty::~SbProcedureProperty() +{} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ |