/* -*- 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 #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include using namespace ::com::sun::star; using namespace ::com::sun::star::uno; using namespace ::com::sun::star::script; using namespace ::com::sun::star::lang; using namespace ::com::sun::star::beans; using namespace ::com::sun::star::container; using namespace ::com::sun::star::reflection; using namespace ::com::sun::star::awt; using namespace ::com::sun::star::io; using namespace ::cppu; namespace { void SFURL_firing_impl( const ScriptEvent& aScriptEvent, Any* pRet, const Reference< frame::XModel >& xModel ) { SAL_INFO("basic", "Processing script url " << aScriptEvent.ScriptCode); try { Reference< provider::XScriptProvider > xScriptProvider; if ( xModel.is() ) { Reference< provider::XScriptProviderSupplier > xSupplier( xModel, UNO_QUERY ); OSL_ENSURE( xSupplier.is(), "SFURL_firing_impl: failed to get script provider supplier" ); if ( xSupplier.is() ) xScriptProvider.set( xSupplier->getScriptProvider() ); } else { Reference< XComponentContext > xContext( comphelper::getProcessComponentContext() ); Reference< provider::XScriptProviderFactory > xFactory = provider::theMasterScriptProviderFactory::get( xContext ); Any aCtx; aCtx <<= OUString("user"); xScriptProvider = xFactory->createScriptProvider( aCtx ); } if ( !xScriptProvider.is() ) { SAL_INFO("basic", "Failed to create msp"); return; } Sequence< Any > inArgs( 0 ); Sequence< Any > outArgs( 0 ); Sequence< sal_Int16 > outIndex; // get Arguments for script inArgs = aScriptEvent.Arguments; Reference< provider::XScript > xScript = xScriptProvider->getScript( aScriptEvent.ScriptCode ); if ( !xScript.is() ) { SAL_INFO("basic", "Failed to Failed to obtain XScript"); return; } Any result = xScript->invoke( inArgs, outIndex, outArgs ); if ( pRet ) { *pRet = result; } } catch ( const RuntimeException& ) { TOOLS_INFO_EXCEPTION("basic", "" ); } catch ( const Exception& ) { TOOLS_INFO_EXCEPTION("basic", "" ); } } class BasicScriptListener_Impl : public WeakImplHelper< XScriptListener > { StarBASICRef maBasicRef; Reference< frame::XModel > m_xModel; void firing_impl(const ScriptEvent& aScriptEvent, Any* pRet); public: BasicScriptListener_Impl( StarBASIC* pBasic, const Reference< frame::XModel >& xModel ) : maBasicRef( pBasic ), m_xModel( xModel ) {} // Methods of XAllListener virtual void SAL_CALL firing(const ScriptEvent& aScriptEvent) override; virtual Any SAL_CALL approveFiring(const ScriptEvent& aScriptEvent) override; // Methods of XEventListener virtual void SAL_CALL disposing(const EventObject& Source) override; }; // Methods XAllListener void BasicScriptListener_Impl::firing( const ScriptEvent& aScriptEvent ) { SolarMutexGuard g; firing_impl( aScriptEvent, nullptr ); } Any BasicScriptListener_Impl::approveFiring( const ScriptEvent& aScriptEvent ) { SolarMutexGuard g; Any aRetAny; firing_impl( aScriptEvent, &aRetAny ); return aRetAny; } // Methods XEventListener void BasicScriptListener_Impl::disposing(const EventObject& ) { // TODO: ??? //SolarMutexGuard aGuard; //xSbxObj.Clear(); } void BasicScriptListener_Impl::firing_impl( const ScriptEvent& aScriptEvent, Any* pRet ) { if( aScriptEvent.ScriptType == "StarBasic" ) { // Full qualified name? OUString aMacro( aScriptEvent.ScriptCode ); OUString aLibName; OUString aLocation; if( comphelper::string::getTokenCount(aMacro, '.') == 3 ) { sal_Int32 nLast = 0; OUString aFullLibName = aMacro.getToken( 0, '.', nLast ); sal_Int32 nIndex = aFullLibName.indexOf( ':' ); if (nIndex >= 0) { aLocation = aFullLibName.copy( 0, nIndex ); aLibName = aFullLibName.copy( nIndex + 1 ); } aMacro = aMacro.copy( nLast ); } SbxObject* p = maBasicRef.get(); SbxObject* pParent = p->GetParent(); SbxObject* pParentParent = pParent ? pParent->GetParent() : nullptr; StarBASICRef xAppStandardBasic; StarBASICRef xDocStandardBasic; if( pParentParent ) { // Own basic must be document library xAppStandardBasic = static_cast(pParentParent); xDocStandardBasic = static_cast(pParent); } else if( pParent ) { OUString aName = p->GetName(); if( aName == "Standard" ) { // Own basic is doc standard lib xDocStandardBasic = static_cast(p); } xAppStandardBasic = static_cast(pParent); } else { xAppStandardBasic = static_cast(p); } bool bSearchLib = true; StarBASICRef xLibSearchBasic; if( aLocation == "application" ) { xLibSearchBasic = xAppStandardBasic; } else if( aLocation == "document" ) { xLibSearchBasic = xDocStandardBasic; } else { bSearchLib = false; } SbxVariable* pMethVar = nullptr; // Be still tolerant and make default search if no search basic exists if( bSearchLib && xLibSearchBasic.is() ) { sal_Int32 nCount = xLibSearchBasic->GetObjects()->Count(); for( sal_Int32 nObj = -1; nObj < nCount ; nObj++ ) { StarBASIC* pBasic; if( nObj == -1 ) { pBasic = xLibSearchBasic.get(); } else { SbxVariable* pVar = xLibSearchBasic->GetObjects()->Get(nObj); pBasic = dynamic_cast( pVar ); } if( pBasic ) { OUString aName = pBasic->GetName(); if( aName == aLibName ) { // Search only in the lib, not automatically in application basic SbxFlagBits nFlags = pBasic->GetFlags(); pBasic->ResetFlag( SbxFlagBits::GlobalSearch ); pMethVar = pBasic->Find( aMacro, SbxClassType::DontCare ); pBasic->SetFlags( nFlags ); break; } } } } // Default: Be tolerant and search everywhere if( (!pMethVar || dynamic_cast( pMethVar) == nullptr) && maBasicRef.is() ) { pMethVar = maBasicRef->FindQualified( aMacro, SbxClassType::DontCare ); } SbMethod* pMeth = dynamic_cast( pMethVar ); if( !pMeth ) { return; } // Setup parameters SbxArrayRef xArray; sal_Int32 nCnt = aScriptEvent.Arguments.getLength(); if( nCnt ) { xArray = new SbxArray; const Any *pArgs = aScriptEvent.Arguments.getConstArray(); for( sal_Int32 i = 0; i < nCnt; i++ ) { SbxVariableRef xVar = new SbxVariable( SbxVARIANT ); unoToSbxValue( xVar.get(), pArgs[i] ); xArray->Put(xVar.get(), sal::static_int_cast(i + 1)); } } // Call method SbxVariableRef xValue = pRet ? new SbxVariable : nullptr; if( xArray.is() ) { pMeth->SetParameters( xArray.get() ); } pMeth->Call( xValue.get() ); if( pRet ) { *pRet = sbxToUnoValue( xValue.get() ); } pMeth->SetParameters( nullptr ); } else // scripting framework script { //callBasic via scripting framework SFURL_firing_impl( aScriptEvent, pRet, m_xModel ); } } css::uno::Reference< css::container::XNameContainer > implFindDialogLibForDialog( const Any& rDlgAny, SbxObject* pBasic ) { css::uno::Reference< css::container::XNameContainer > aRetDlgLib; SbxVariable* pDlgLibContVar = pBasic->Find("DialogLibraries", SbxClassType::Object); if( auto pDlgLibContUnoObj = dynamic_cast( pDlgLibContVar) ) { Any aDlgLibContAny = pDlgLibContUnoObj->getUnoAny(); Reference< XLibraryContainer > xDlgLibContNameAccess( aDlgLibContAny, UNO_QUERY ); OSL_ENSURE( xDlgLibContNameAccess.is(), "implFindDialogLibForDialog: no lib container for the given dialog!" ); if( xDlgLibContNameAccess.is() ) { Sequence< OUString > aLibNames = xDlgLibContNameAccess->getElementNames(); const OUString* pLibNames = aLibNames.getConstArray(); sal_Int32 nLibNameCount = aLibNames.getLength(); for( sal_Int32 iLib = 0 ; iLib < nLibNameCount ; iLib++ ) { if ( !xDlgLibContNameAccess->isLibraryLoaded( pLibNames[ iLib ] ) ) // if the library isn't loaded, then the dialog cannot originate from this lib continue; Any aDlgLibAny = xDlgLibContNameAccess->getByName( pLibNames[ iLib ] ); Reference< XNameContainer > xDlgLibNameCont( aDlgLibAny, UNO_QUERY ); OSL_ENSURE( xDlgLibNameCont.is(), "implFindDialogLibForDialog: invalid dialog lib!" ); if( xDlgLibNameCont.is() ) { Sequence< OUString > aDlgNames = xDlgLibNameCont->getElementNames(); const OUString* pDlgNames = aDlgNames.getConstArray(); sal_Int32 nDlgNameCount = aDlgNames.getLength(); for( sal_Int32 iDlg = 0 ; iDlg < nDlgNameCount ; iDlg++ ) { Any aDlgAny = xDlgLibNameCont->getByName( pDlgNames[ iDlg ] ); if( aDlgAny == rDlgAny ) { aRetDlgLib = xDlgLibNameCont; break; } } } } } } return aRetDlgLib; } css::uno::Reference< css::container::XNameContainer > implFindDialogLibForDialogBasic( const Any& aAnyISP, SbxObject* pBasic, StarBASIC*& pFoundBasic ) { css::uno::Reference< css::container::XNameContainer > aDlgLib; // Find dialog library for dialog, direct access is not possible here StarBASIC* pStartedBasic = static_cast(pBasic); SbxObject* pParentBasic = pStartedBasic ? pStartedBasic->GetParent() : nullptr; SbxObject* pParentParentBasic = pParentBasic ? pParentBasic->GetParent() : nullptr; SbxObject* pSearchBasic1 = nullptr; SbxObject* pSearchBasic2 = nullptr; if( pParentParentBasic ) { pSearchBasic1 = pParentBasic; pSearchBasic2 = pParentParentBasic; } else { pSearchBasic1 = pStartedBasic; pSearchBasic2 = pParentBasic; } if( pSearchBasic1 ) { aDlgLib = implFindDialogLibForDialog( aAnyISP, pSearchBasic1 ); if ( aDlgLib.is() ) pFoundBasic = static_cast(pSearchBasic1); else if( pSearchBasic2 ) { aDlgLib = implFindDialogLibForDialog( aAnyISP, pSearchBasic2 ); if ( aDlgLib.is() ) pFoundBasic = static_cast(pSearchBasic2); } } return aDlgLib; } } void RTL_Impl_CreateUnoDialog( SbxArray& rPar ) { Reference< XComponentContext > xContext( comphelper::getProcessComponentContext() ); // We need at least 1 parameter if (rPar.Count() < 2) { StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT ); return; } // Get dialog SbxBaseRef pObj = rPar.Get(1)->GetObject(); if( !(pObj.is() && dynamic_cast( pObj.get() ) != nullptr) ) { StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT ); return; } SbUnoObject* pUnoObj = static_cast(pObj.get()); Any aAnyISP = pUnoObj->getUnoAny(); TypeClass eType = aAnyISP.getValueType().getTypeClass(); if( eType != TypeClass_INTERFACE ) { StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT ); return; } // Create new uno dialog Reference< XNameContainer > xDialogModel( xContext->getServiceManager()->createInstanceWithContext( "com.sun.star.awt.UnoControlDialogModel", xContext), UNO_QUERY ); if( !xDialogModel.is() ) { return; } Reference< XInputStreamProvider > xISP; aAnyISP >>= xISP; if( !xISP.is() ) { return; } // Import the DialogModel Reference< XInputStream > xInput( xISP->createInputStream() ); // i83963 Force decoration uno::Reference< beans::XPropertySet > xDlgModPropSet( xDialogModel, uno::UNO_QUERY ); if( xDlgModPropSet.is() ) { try { bool bDecoration = true; OUString aDecorationPropName("Decoration"); Any aDecorationAny = xDlgModPropSet->getPropertyValue( aDecorationPropName ); aDecorationAny >>= bDecoration; if( !bDecoration ) { xDlgModPropSet->setPropertyValue( aDecorationPropName, Any( true ) ); xDlgModPropSet->setPropertyValue( "Title", Any( OUString() ) ); } } catch(const UnknownPropertyException& ) {} } css::uno::Reference< css::container::XNameContainer > aDlgLib; bool bDocDialog = false; StarBASIC* pFoundBasic = nullptr; SAL_INFO("basic", "About to try get a hold of ThisComponent"); Reference< frame::XModel > xModel = StarBASIC::GetModelFromBasic( GetSbData()->pInst->GetBasic() ) ; aDlgLib = implFindDialogLibForDialogBasic( aAnyISP, GetSbData()->pInst->GetBasic(), pFoundBasic ); // If we found the dialog then it belongs to the Search basic if ( !pFoundBasic ) { Reference< frame::XDesktop2 > xDesktop = frame::Desktop::create( xContext ); Reference< container::XEnumeration > xModels; Reference< container::XEnumerationAccess > xComponents = xDesktop->getComponents(); if ( xComponents.is() ) { xModels = xComponents->createEnumeration(); } if ( xModels.is() ) { while ( xModels->hasMoreElements() ) { Reference< frame::XModel > xNextModel( xModels->nextElement(), UNO_QUERY ); if ( xNextModel.is() ) { BasicManager* pMgr = basic::BasicManagerRepository::getDocumentBasicManager( xNextModel ); if ( pMgr ) { aDlgLib = implFindDialogLibForDialogBasic( aAnyISP, pMgr->GetLib(0), pFoundBasic ); } if ( aDlgLib.is() ) { bDocDialog = true; xModel = xNextModel; break; } } } } } if ( pFoundBasic ) { bDocDialog = pFoundBasic->IsDocBasic(); } Reference< XScriptListener > xScriptListener = new BasicScriptListener_Impl( GetSbData()->pInst->GetBasic(), xModel ); // Create a "living" Dialog Reference< XControl > xCntrl; try { Reference< XDialogProvider > xDlgProv; if( bDocDialog ) xDlgProv = css::awt::DialogProvider::createWithModelAndScripting( xContext, xModel, xInput, aDlgLib, xScriptListener ); else xDlgProv = css::awt::DialogProvider::createWithModelAndScripting( xContext, uno::Reference< frame::XModel >(), xInput, aDlgLib, xScriptListener ); xCntrl.set( xDlgProv->createDialog(OUString() ), UNO_QUERY_THROW ); // Add dialog model to dispose vector Reference< XComponent > xDlgComponent( xCntrl->getModel(), UNO_QUERY ); GetSbData()->pInst->getComponentVector().push_back( xDlgComponent ); // need ThisComponent from calling script } // preserve existing bad behaviour, it's possible... but probably // illegal to open 2 dialogs ( they ARE modal ) when this happens, sometimes // create dialog fails. So, in this case let's not throw, just leave basic // detect the unset object. catch(const uno::Exception& ) { } // Return dialog Any aRetVal; aRetVal <<= xCntrl; SbxVariableRef refVar = rPar.Get(0); unoToSbxValue( refVar.get(), aRetVal ); } /* vim:set shiftwidth=4 softtabstop=4 expandtab: */