From ed5640d8b587fbcfed7dd7967f3de04b37a76f26 Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Sun, 7 Apr 2024 11:06:44 +0200 Subject: Adding upstream version 4:7.4.7. Signed-off-by: Daniel Baumann --- basctl/source/basicide/scriptdocument.cxx | 1505 +++++++++++++++++++++++++++++ 1 file changed, 1505 insertions(+) create mode 100644 basctl/source/basicide/scriptdocument.cxx (limited to 'basctl/source/basicide/scriptdocument.cxx') diff --git a/basctl/source/basicide/scriptdocument.cxx b/basctl/source/basicide/scriptdocument.cxx new file mode 100644 index 000000000..e23cfbe7a --- /dev/null +++ b/basctl/source/basicide/scriptdocument.cxx @@ -0,0 +1,1505 @@ +/* -*- 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 "documentenumeration.hxx" + +#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 +#include +#include + + +namespace basctl +{ + using ::com::sun::star::uno::Sequence; + using ::com::sun::star::uno::Reference; + using ::com::sun::star::frame::XModel; + using ::com::sun::star::beans::XPropertySet; + using ::com::sun::star::script::XLibraryContainer; + using ::com::sun::star::uno::UNO_QUERY_THROW; + using ::com::sun::star::uno::UNO_SET_THROW; + using ::com::sun::star::uno::Exception; + using ::com::sun::star::container::XNameContainer; + using ::com::sun::star::container::NoSuchElementException; + using ::com::sun::star::uno::UNO_QUERY; + using ::com::sun::star::task::XStatusIndicator; + using ::com::sun::star::uno::Any; + using ::com::sun::star::script::XLibraryContainer2; + using ::com::sun::star::uri::UriReferenceFactory; + using ::com::sun::star::uri::XUriReferenceFactory; + using ::com::sun::star::uri::XUriReference; + using ::com::sun::star::uno::XComponentContext; + using ::com::sun::star::util::XMacroExpander; + using ::com::sun::star::util::theMacroExpander; + using ::com::sun::star::io::XInputStreamProvider; + using ::com::sun::star::uno::Any; + using ::com::sun::star::io::XInputStream; + using ::com::sun::star::frame::XStorable; + using ::com::sun::star::util::XModifiable; + using ::com::sun::star::frame::XController; + using ::com::sun::star::frame::XFrame; + using ::com::sun::star::util::URL; + using ::com::sun::star::frame::XDispatchProvider; + using ::com::sun::star::frame::XDispatch; + using ::com::sun::star::beans::PropertyValue; + using ::com::sun::star::awt::XWindow2; + using ::com::sun::star::document::XEmbeddedScripts; + using ::com::sun::star::script::ModuleInfo; + using ::com::sun::star::script::vba::XVBACompatibility; + using ::com::sun::star::script::vba::XVBAModuleInfo; + + namespace FrameSearchFlag = ::com::sun::star::frame::FrameSearchFlag; + + + namespace + { + class FilterDocuments : public docs::IDocumentDescriptorFilter + { + public: + explicit FilterDocuments(bool _bFilterInvisible) + : m_bFilterInvisible(_bFilterInvisible) + { + } + + virtual ~FilterDocuments() {} + + virtual bool includeDocument( const docs::DocumentDescriptor& _rDocument ) const override; + + private: + static bool impl_isDocumentVisible_nothrow( const docs::DocumentDescriptor& _rDocument ); + + private: + bool m_bFilterInvisible; + }; + + bool FilterDocuments::impl_isDocumentVisible_nothrow( const docs::DocumentDescriptor& _rDocument ) + { + try + { + for (auto const& controller : _rDocument.aControllers) + { + Reference< XFrame > xFrame( controller->getFrame(), UNO_SET_THROW ); + Reference< XWindow2 > xContainer( xFrame->getContainerWindow(), UNO_QUERY_THROW ); + if ( xContainer->isVisible() ) + return true; + } + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION("basctl.basicide"); + } + return false; + } + + bool FilterDocuments::includeDocument( const docs::DocumentDescriptor& _rDocument ) const + { + Reference< XEmbeddedScripts > xScripts( _rDocument.xModel, UNO_QUERY ); + if ( !xScripts.is() ) + return false; + return !m_bFilterInvisible || impl_isDocumentVisible_nothrow( _rDocument ); + } + + void lcl_getAllModels_throw( docs::Documents& _out_rModels, bool _bVisibleOnly ) + { + _out_rModels.clear(); + + FilterDocuments aFilter( _bVisibleOnly ); + docs::DocumentEnumeration aEnum( + comphelper::getProcessComponentContext(), &aFilter ); + + aEnum.getDocuments( _out_rModels ); + } + } + + class ScriptDocument::Impl : public DocumentEventListener + { + private: + bool m_bIsApplication; + bool m_bValid; + bool m_bDocumentClosed; + Reference< XModel > m_xDocument; + Reference< XModifiable > m_xDocModify; + Reference< XEmbeddedScripts > m_xScriptAccess; + std::unique_ptr< DocumentEventNotifier > m_pDocListener; + + public: + Impl (); + explicit Impl(Reference const& rxDocument); + virtual ~Impl() override; + + /** determines whether the instance refers to a valid "document" with script and + dialog libraries + */ + bool isValid() const { return m_bValid; } + /** determines whether the instance refers to a non-closed document + */ + bool isAlive() const { return m_bValid && ( m_bIsApplication || !m_bDocumentClosed ); } + /// determines whether the "document" refers to the application in real + bool isApplication() const { return m_bValid && m_bIsApplication; } + /// determines whether the document refers to a real document (instead of the application) + bool isDocument() const { return m_bValid && !m_bIsApplication; } + + /** invalidates the instance + */ + void invalidate(); + + const Reference< XModel >& + getDocumentRef() const { return m_xDocument; } + + /// returns a library container belonging to the document + Reference< XLibraryContainer > + getLibraryContainer( LibraryContainerType _eType ) const; + + /// determines whether a given library is part of the shared installation + bool isLibraryShared( const OUString& _rLibName, LibraryContainerType _eType ); + + /** returns the current frame of the document + + To be called for documents only, not for the application. + + If is returned, an assertion will be raised in non-product builds. + */ + bool getCurrentFrame( Reference< XFrame >& _out_rxFrame ) const; + + // versions with the same signature/semantics as in ScriptDocument itself + bool isReadOnly() const; + bool isInVBAMode() const; + BasicManager* + getBasicManager() const; + Reference< XModel > + getDocument() const; + void setDocumentModified() const; + bool isDocumentModified() const; + void saveDocument( const Reference< XStatusIndicator >& _rxStatusIndicator ) const; + + OUString getTitle() const; + OUString getURL() const; + + bool allowMacros() const; + + Reference< XNameContainer > + getLibrary( LibraryContainerType _eType, const OUString& _rLibName, bool _bLoadLibrary ) const; + bool hasLibrary( LibraryContainerType _eType, const OUString& _rLibName ) const; + Reference< XNameContainer > + getOrCreateLibrary( LibraryContainerType _eType, const OUString& _rLibName ) const; + + void loadLibraryIfExists( LibraryContainerType _eType, const OUString& _rLibrary ); + + bool removeModuleOrDialog( LibraryContainerType _eType, const OUString& _rLibName, const OUString& _rModuleName ); + bool hasModuleOrDialog( LibraryContainerType _eType, const OUString& _rLibName, const OUString& _rModName ) const; + bool getModuleOrDialog( LibraryContainerType _eType, const OUString& _rLibName, const OUString& _rObjectName, Any& _out_rModuleOrDialog ); + bool renameModuleOrDialog( LibraryContainerType _eType, const OUString& _rLibName, const OUString& _rOldName, const OUString& _rNewName, const Reference< XNameContainer >& _rxExistingDialogModel ); + bool createModule( const OUString& _rLibName, const OUString& _rModName, bool _bCreateMain, OUString& _out_rNewModuleCode ) const; + bool insertModuleOrDialog( LibraryContainerType _eType, const OUString& _rObjectName, const OUString& _rModName, const Any& _rElement ) const; + bool updateModule( const OUString& _rLibName, const OUString& _rModName, const OUString& _rModuleCode ) const; + bool createDialog( const OUString& _rLibName, const OUString& _rDialogName, Reference< XInputStreamProvider >& _out_rDialogProvider ) const; + + protected: + // DocumentEventListener + virtual void onDocumentCreated( const ScriptDocument& _rDocument ) override; + virtual void onDocumentOpened( const ScriptDocument& _rDocument ) override; + virtual void onDocumentSave( const ScriptDocument& _rDocument ) override; + virtual void onDocumentSaveDone( const ScriptDocument& _rDocument ) override; + virtual void onDocumentSaveAs( const ScriptDocument& _rDocument ) override; + virtual void onDocumentSaveAsDone( const ScriptDocument& _rDocument ) override; + virtual void onDocumentClosed( const ScriptDocument& _rDocument ) override; + virtual void onDocumentTitleChanged( const ScriptDocument& _rDocument ) override; + virtual void onDocumentModeChanged( const ScriptDocument& _rDocument ) override; + + private: + bool impl_initDocument_nothrow( const Reference< XModel >& _rxModel ); + }; + + + ScriptDocument::Impl::Impl() + :m_bIsApplication( true ) + ,m_bValid( true ) + ,m_bDocumentClosed( false ) + { + } + + ScriptDocument::Impl::Impl( const Reference< XModel >& _rxDocument ) + :m_bIsApplication( false ) + ,m_bValid( false ) + ,m_bDocumentClosed( false ) + { + if ( _rxDocument.is() ) + impl_initDocument_nothrow( _rxDocument ); + } + + ScriptDocument::Impl::~Impl() + { + invalidate(); + } + + void ScriptDocument::Impl::invalidate() + { + m_bIsApplication = false; + m_bValid = false; + m_bDocumentClosed = false; + + m_xDocument.clear(); + m_xDocModify.clear(); + m_xScriptAccess.clear(); + + if (m_pDocListener) + m_pDocListener->dispose(); + } + + bool ScriptDocument::Impl::impl_initDocument_nothrow( const Reference< XModel >& _rxModel ) + { + try + { + m_xDocument.set ( _rxModel, UNO_SET_THROW ); + m_xDocModify.set ( _rxModel, UNO_QUERY_THROW ); + m_xScriptAccess.set ( _rxModel, UNO_QUERY ); + + m_bValid = m_xScriptAccess.is(); + + if ( m_bValid ) + m_pDocListener.reset( new DocumentEventNotifier( *this, _rxModel ) ); + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION("basctl.basicide"); + m_bValid = false; + } + + if ( !m_bValid ) + { + invalidate(); + } + + return m_bValid; + } + + Reference< XLibraryContainer > ScriptDocument::Impl::getLibraryContainer( LibraryContainerType _eType ) const + { + OSL_ENSURE( isValid(), "ScriptDocument::Impl::getLibraryContainer: invalid!" ); + + Reference< XLibraryContainer > xContainer; + if ( !isValid() ) + return xContainer; + + try + { + if ( isApplication() ) + xContainer.set( _eType == E_SCRIPTS ? SfxGetpApp()->GetBasicContainer() : SfxGetpApp()->GetDialogContainer(), UNO_QUERY_THROW ); + else + { + xContainer.set( + _eType == E_SCRIPTS ? m_xScriptAccess->getBasicLibraries() : m_xScriptAccess->getDialogLibraries(), + UNO_QUERY_THROW ); + } + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION("basctl.basicide"); + } + return xContainer; + } + + bool ScriptDocument::Impl::isReadOnly() const + { + OSL_ENSURE( isValid(), "ScriptDocument::Impl::isReadOnly: invalid state!" ); + OSL_ENSURE( !isApplication(), "ScriptDocument::Impl::isReadOnly: not allowed to be called for the application!" ); + + bool bIsReadOnly = true; + if ( isValid() && !isApplication() ) + { + try + { + // note that XStorable is required by the OfficeDocument service + Reference< XStorable > xDocStorable( m_xDocument, UNO_QUERY_THROW ); + bIsReadOnly = xDocStorable->isReadonly(); + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION("basctl.basicide"); + } + } + return bIsReadOnly; + } + + bool ScriptDocument::Impl::isInVBAMode() const + { + bool bResult = false; + if ( !isApplication() ) + { + Reference< XVBACompatibility > xVBACompat( getLibraryContainer( E_SCRIPTS ), UNO_QUERY ); + if ( xVBACompat.is() ) + bResult = xVBACompat->getVBACompatibilityMode(); + } + return bResult; + } + + BasicManager* ScriptDocument::Impl::getBasicManager() const + { + try + { + OSL_ENSURE( isValid(), "ScriptDocument::Impl::getBasicManager: invalid state!" ); + if ( !isValid() ) + return nullptr; + + if ( isApplication() ) + return SfxApplication::GetBasicManager(); + + return ::basic::BasicManagerRepository::getDocumentBasicManager( m_xDocument ); + } + catch (const css::ucb::ContentCreationException&) + { + TOOLS_WARN_EXCEPTION( "basctl.basicide", "ScriptDocument::getBasicManager" ); + } + return nullptr; + } + + Reference< XModel > ScriptDocument::Impl::getDocument() const + { + OSL_ENSURE( isValid(), "ScriptDocument::Impl::getDocument: invalid state!" ); + OSL_ENSURE( isDocument(), "ScriptDocument::Impl::getDocument: for documents only!" ); + if ( !isValid() || !isDocument() ) + return nullptr; + + return m_xDocument; + } + + + Reference< XNameContainer > ScriptDocument::Impl::getLibrary( LibraryContainerType _eType, const OUString& _rLibName, bool _bLoadLibrary ) const + { + OSL_ENSURE( isValid(), "ScriptDocument::Impl::getLibrary: invalid state!" ); + + Reference< XNameContainer > xContainer; + try + { + Reference< XLibraryContainer > xLibContainer = getLibraryContainer( _eType ); + if ( isValid() && xLibContainer.is() ) + xContainer.set( xLibContainer->getByName( _rLibName ), UNO_QUERY_THROW ); + + if ( !xContainer.is() ) + throw NoSuchElementException(); + + // load library + if ( _bLoadLibrary && !xLibContainer->isLibraryLoaded( _rLibName ) ) + xLibContainer->loadLibrary( _rLibName ); + } + catch( const NoSuchElementException& ) + { + throw; // allowed to leave + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION("basctl.basicide"); + } + + return xContainer; + } + + + bool ScriptDocument::Impl::hasLibrary( LibraryContainerType _eType, const OUString& _rLibName ) const + { + bool bHas = false; + try + { + Reference< XLibraryContainer > xLibContainer = getLibraryContainer( _eType ); + bHas = xLibContainer.is() && xLibContainer->hasByName( _rLibName ); + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION("basctl.basicide"); + } + return bHas; + } + + + Reference< XNameContainer > ScriptDocument::Impl::getOrCreateLibrary( LibraryContainerType _eType, const OUString& _rLibName ) const + { + Reference< XNameContainer > xLibrary; + try + { + Reference< XLibraryContainer > xLibContainer( getLibraryContainer( _eType ), UNO_SET_THROW ); + if ( xLibContainer->hasByName( _rLibName ) ) + xLibrary.set( xLibContainer->getByName( _rLibName ), UNO_QUERY_THROW ); + else + xLibrary.set( xLibContainer->createLibrary( _rLibName ), UNO_SET_THROW ); + + if ( !xLibContainer->isLibraryLoaded( _rLibName ) ) + xLibContainer->loadLibrary( _rLibName ); + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION("basctl.basicide"); + } + return xLibrary; + } + + + void ScriptDocument::Impl::loadLibraryIfExists( LibraryContainerType _eType, const OUString& _rLibrary ) + { + try + { + Reference< XLibraryContainer > xLibContainer( getLibraryContainer( _eType ) ); + if ( xLibContainer.is() && xLibContainer->hasByName( _rLibrary ) && !xLibContainer->isLibraryLoaded( _rLibrary ) ) + xLibContainer->loadLibrary( _rLibrary ); + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION("basctl.basicide"); + } + } + + + bool ScriptDocument::Impl::removeModuleOrDialog( LibraryContainerType _eType, const OUString& _rLibName, const OUString& _rModuleName ) + { + OSL_ENSURE( isValid(), "ScriptDocument::Impl::removeModuleOrDialog: invalid!" ); + if ( !isValid() ) + return false; + try + { + Reference< XNameContainer > xLib( getLibrary( _eType, _rLibName, true ) ); + if ( xLib.is() ) + { + xLib->removeByName( _rModuleName ); + Reference< XVBAModuleInfo > xVBAModuleInfo(xLib, UNO_QUERY); + if(xVBAModuleInfo.is() && xVBAModuleInfo->hasModuleInfo(_rModuleName)) + xVBAModuleInfo->removeModuleInfo(_rModuleName); + return true; + } + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION("basctl.basicide"); + } + return false; + } + + + bool ScriptDocument::Impl::hasModuleOrDialog( LibraryContainerType _eType, const OUString& _rLibName, const OUString& _rModName ) const + { + OSL_ENSURE( isValid(), "ScriptDocument::Impl::hasModuleOrDialog: invalid!" ); + if ( !isValid() ) + return false; + + try + { + Reference< XNameContainer > xLib( getLibrary( _eType, _rLibName, true ) ); + if ( xLib.is() ) + return xLib->hasByName( _rModName ); + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION("basctl.basicide"); + } + return false; + } + + + bool ScriptDocument::Impl::getModuleOrDialog( LibraryContainerType _eType, const OUString& _rLibName, const OUString& _rObjectName, Any& _out_rModuleOrDialog ) + { + OSL_ENSURE( isValid(), "ScriptDocument::Impl::getModuleOrDialog: invalid!" ); + if ( !isValid() ) + return false; + + _out_rModuleOrDialog.clear(); + try + { + Reference< XNameContainer > xLib( getLibrary( _eType, _rLibName, true ), UNO_SET_THROW ); + if ( xLib->hasByName( _rObjectName ) ) + { + _out_rModuleOrDialog = xLib->getByName( _rObjectName ); + return true; + } + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION("basctl.basicide"); + } + return false; + } + + + bool ScriptDocument::Impl::renameModuleOrDialog( LibraryContainerType _eType, const OUString& _rLibName, + const OUString& _rOldName, const OUString& _rNewName, const Reference< XNameContainer >& _rxExistingDialogModel ) + { + OSL_ENSURE( isValid(), "ScriptDocument::Impl::renameModuleOrDialog: invalid!" ); + if ( !isValid() ) + return false; + + try + { + Reference< XNameContainer > xLib( getLibrary( _eType, _rLibName, true ), UNO_SET_THROW ); + + // get element + Any aElement( xLib->getByName( _rOldName ) ); + + // remove element from container + xLib->removeByName( _rOldName ); + + // if it's a dialog, import and export, to reflect the new name + if ( _eType == E_DIALOGS ) + { + // create dialog model + Reference< XComponentContext > aContext( + comphelper::getProcessComponentContext() ); + Reference< XNameContainer > xDialogModel; + if ( _rxExistingDialogModel.is() ) + xDialogModel = _rxExistingDialogModel; + else + xDialogModel.set( + ( aContext->getServiceManager()-> + createInstanceWithContext( + "com.sun.star.awt.UnoControlDialogModel", + aContext ) ), + UNO_QUERY_THROW ); + + // import dialog model + Reference< XInputStreamProvider > xISP( aElement, UNO_QUERY_THROW ); + if ( !_rxExistingDialogModel.is() ) + { + Reference< XInputStream > xInput( xISP->createInputStream(), UNO_SET_THROW ); + ::xmlscript::importDialogModel( xInput, xDialogModel, aContext, isDocument() ? getDocument() : Reference< XModel >() ); + } + + // set new name as property + Reference< XPropertySet > xDlgPSet( xDialogModel, UNO_QUERY_THROW ); + xDlgPSet->setPropertyValue( DLGED_PROP_NAME, Any( _rNewName ) ); + + // export dialog model + xISP = ::xmlscript::exportDialogModel( xDialogModel, aContext, isDocument() ? getDocument() : Reference< XModel >() ); + aElement <<= xISP; + } + + // insert element by new name in container + if ( _eType == E_SCRIPTS ) + { + Reference< XVBAModuleInfo > xVBAModuleInfo( xLib, UNO_QUERY ); + if ( xVBAModuleInfo.is() && xVBAModuleInfo->hasModuleInfo( _rOldName ) ) + { + ModuleInfo sModuleInfo = xVBAModuleInfo->getModuleInfo( _rOldName ); + xVBAModuleInfo->removeModuleInfo( _rOldName ); + xVBAModuleInfo->insertModuleInfo( _rNewName, sModuleInfo ); + } + } + xLib->insertByName( _rNewName, aElement ); + return true; + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION("basctl.basicide"); + } + return false; + } + + + bool ScriptDocument::Impl::createModule( const OUString& _rLibName, const OUString& _rModName, bool _bCreateMain, OUString& _out_rNewModuleCode ) const + { + _out_rNewModuleCode.clear(); + try + { + Reference< XNameContainer > xLib( getLibrary( E_SCRIPTS, _rLibName, true ) ); + if ( !xLib.is() || xLib->hasByName( _rModName ) ) + return false; + + // create new module + _out_rNewModuleCode = "REM ***** BASIC *****\n\n" ; + if ( _bCreateMain ) + _out_rNewModuleCode += "Sub Main\n\nEnd Sub\n" ; + + Reference< XVBAModuleInfo > xVBAModuleInfo(xLib, UNO_QUERY); + if (xVBAModuleInfo.is()) + { + css::script::ModuleInfo aModuleInfo; + aModuleInfo.ModuleType = css::script::ModuleType::NORMAL; + xVBAModuleInfo->insertModuleInfo(_rModName, aModuleInfo); + } + + // insert module into library + xLib->insertByName( _rModName, Any( _out_rNewModuleCode ) ); + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION("basctl.basicide"); + return false; + } + + return true; + } + + + bool ScriptDocument::Impl::insertModuleOrDialog( LibraryContainerType _eType, const OUString& _rLibName, const OUString& _rObjectName, const Any& _rElement ) const + { + try + { + Reference< XNameContainer > xLib( getOrCreateLibrary( _eType, _rLibName ), UNO_SET_THROW ); + if ( xLib->hasByName( _rObjectName ) ) + return false; + + xLib->insertByName( _rObjectName, _rElement ); + return true; + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION("basctl.basicide"); + } + return false; + } + + + bool ScriptDocument::Impl::updateModule( const OUString& _rLibName, const OUString& _rModName, const OUString& _rModuleCode ) const + { + try + { + Reference< XNameContainer > xLib( getOrCreateLibrary( E_SCRIPTS, _rLibName ), UNO_SET_THROW ); + if ( !xLib->hasByName( _rModName ) ) + return false; + xLib->replaceByName( _rModName, Any( _rModuleCode ) ); + return true; + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION("basctl.basicide"); + } + return false; + } + + + bool ScriptDocument::Impl::createDialog( const OUString& _rLibName, const OUString& _rDialogName, Reference< XInputStreamProvider >& _out_rDialogProvider ) const + { + try + { + Reference< XNameContainer > xLib( getLibrary( E_DIALOGS, _rLibName, true ), UNO_SET_THROW ); + + // create dialog + _out_rDialogProvider.clear(); + if ( xLib->hasByName( _rDialogName ) ) + return false; + + // create new dialog model + Reference< XComponentContext > aContext( + comphelper::getProcessComponentContext() ); + Reference< XNameContainer > xDialogModel( + aContext->getServiceManager()->createInstanceWithContext( + "com.sun.star.awt.UnoControlDialogModel", aContext ), + UNO_QUERY_THROW ); + + // set name property + Reference< XPropertySet > xDlgPSet( xDialogModel, UNO_QUERY_THROW ); + xDlgPSet->setPropertyValue( DLGED_PROP_NAME, Any( _rDialogName ) ); + + // export dialog model + _out_rDialogProvider = ::xmlscript::exportDialogModel( xDialogModel, aContext, isDocument() ? getDocument() : Reference< XModel >() ); + + // insert dialog into library + xLib->insertByName( _rDialogName, Any( _out_rDialogProvider ) ); + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION("basctl.basicide"); + } + + return _out_rDialogProvider.is(); + } + + + void ScriptDocument::Impl::setDocumentModified() const + { + OSL_ENSURE( isValid() && isDocument(), "ScriptDocument::Impl::setDocumentModified: only to be called for real documents!" ); + if ( isValid() && isDocument() ) + { + try + { + m_xDocModify->setModified( true ); + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION("basctl.basicide"); + } + } + } + + + bool ScriptDocument::Impl::isDocumentModified() const + { + OSL_ENSURE( isValid() && isDocument(), "ScriptDocument::Impl::isDocumentModified: only to be called for real documents!" ); + bool bIsModified = false; + if ( isValid() && isDocument() ) + { + try + { + bIsModified = m_xDocModify->isModified(); + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION("basctl.basicide"); + } + } + return bIsModified; + } + + + void ScriptDocument::Impl::saveDocument( const Reference< XStatusIndicator >& _rxStatusIndicator ) const + { + Reference< XFrame > xFrame; + if ( !getCurrentFrame( xFrame ) ) + return; + + Sequence< PropertyValue > aArgs; + if ( _rxStatusIndicator.is() ) + { + aArgs = ::comphelper::InitPropertySequence({ + { "StatusIndicator", Any(_rxStatusIndicator) } + }); + } + + try + { + URL aURL; + aURL.Complete = ".uno:Save" ; + aURL.Main = aURL.Complete; + aURL.Protocol = ".uno:" ; + aURL.Path = "Save" ; + + Reference< XDispatchProvider > xDispProv( xFrame, UNO_QUERY_THROW ); + Reference< XDispatch > xDispatch( + xDispProv->queryDispatch( aURL, "_self", FrameSearchFlag::AUTO ), + UNO_SET_THROW ); + + xDispatch->dispatch( aURL, aArgs ); + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION("basctl.basicide"); + } + } + + + OUString ScriptDocument::Impl::getTitle() const + { + OSL_PRECOND( isValid() && isDocument(), "ScriptDocument::Impl::getTitle: for documents only!" ); + + OUString sTitle; + if ( isValid() && isDocument() ) + { + sTitle = ::comphelper::DocumentInfo::getDocumentTitle( m_xDocument ); + } + return sTitle; + } + + + OUString ScriptDocument::Impl::getURL() const + { + OSL_PRECOND( isValid() && isDocument(), "ScriptDocument::Impl::getURL: for documents only!" ); + + OUString sURL; + if ( isValid() && isDocument() ) + { + try + { + sURL = m_xDocument->getURL(); + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION("basctl.basicide"); + } + } + return sURL; + } + + + bool ScriptDocument::Impl::allowMacros() const + { + OSL_ENSURE( isValid() && isDocument(), "ScriptDocument::Impl::allowMacros: for documents only!" ); + bool bAllow = false; + if ( isValid() && isDocument() ) + { + try + { + bAllow = m_xScriptAccess->getAllowMacroExecution(); + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION("basctl.basicide"); + } + } + return bAllow; + } + + + bool ScriptDocument::Impl::getCurrentFrame( Reference< XFrame >& _out_rxFrame ) const + { + _out_rxFrame.clear(); + OSL_PRECOND( isValid() && isDocument(), "ScriptDocument::Impl::getCurrentFrame: documents only!" ); + if ( !isValid() || !isDocument() ) + return false; + + try + { + Reference< XModel > xDocument( m_xDocument, UNO_SET_THROW ); + Reference< XController > xController( xDocument->getCurrentController(), UNO_SET_THROW ); + _out_rxFrame.set( xController->getFrame(), UNO_SET_THROW ); + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION("basctl.basicide"); + } + + return _out_rxFrame.is(); + } + + + bool ScriptDocument::Impl::isLibraryShared( const OUString& _rLibName, LibraryContainerType _eType ) + { + bool bIsShared = false; + try + { + Reference< XLibraryContainer2 > xLibContainer( getLibraryContainer( _eType ), UNO_QUERY_THROW ); + + if ( !xLibContainer->hasByName( _rLibName ) || !xLibContainer->isLibraryLink( _rLibName ) ) + return false; + OUString aFileURL; + Reference< XComponentContext > xContext( ::comphelper::getProcessComponentContext() ); + Reference< XUriReferenceFactory > xUriFac = UriReferenceFactory::create(xContext); + + OUString aLinkURL( xLibContainer->getLibraryLinkURL( _rLibName ) ); + Reference< XUriReference > xUriRef( xUriFac->parse( aLinkURL ), UNO_SET_THROW ); + + OUString aScheme = xUriRef->getScheme(); + if ( aScheme.equalsIgnoreAsciiCase("file") ) + { + aFileURL = aLinkURL; + } + else if ( aScheme.equalsIgnoreAsciiCase("vnd.sun.star.pkg") ) + { + OUString aAuthority = xUriRef->getAuthority(); + if ( aAuthority.matchIgnoreAsciiCase("vnd.sun.star.expand:") ) + { + OUString aDecodedURL( aAuthority.copy( sizeof ( "vnd.sun.star.expand:" ) - 1 ) ); + aDecodedURL = ::rtl::Uri::decode( aDecodedURL, rtl_UriDecodeWithCharset, RTL_TEXTENCODING_UTF8 ); + Reference< XMacroExpander > xMacroExpander = theMacroExpander::get(xContext); + aFileURL = xMacroExpander->expandMacros( aDecodedURL ); + } + } + + if ( !aFileURL.isEmpty() ) + { + ::osl::DirectoryItem aFileItem; + ::osl::FileStatus aFileStatus( osl_FileStatus_Mask_FileURL ); + OSL_VERIFY( ::osl::DirectoryItem::get( aFileURL, aFileItem ) == ::osl::FileBase::E_None ); + OSL_VERIFY( aFileItem.getFileStatus( aFileStatus ) == ::osl::FileBase::E_None ); + OUString aCanonicalFileURL( aFileStatus.getFileURL() ); + + if( aCanonicalFileURL.indexOf( "share/basic" ) >= 0 || + aCanonicalFileURL.indexOf( "share/uno_packages" ) >= 0 || + aCanonicalFileURL.indexOf( "share/extensions" ) >= 0 ) + bIsShared = true; + } + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION("basctl.basicide"); + } + + return bIsShared; + } + + + void ScriptDocument::Impl::onDocumentCreated( const ScriptDocument& /*_rDocument*/ ) + { + // not interested in + } + + void ScriptDocument::Impl::onDocumentOpened( const ScriptDocument& /*_rDocument*/ ) + { + // not interested in + } + + void ScriptDocument::Impl::onDocumentSave( const ScriptDocument& /*_rDocument*/ ) + { + // not interested in + } + + void ScriptDocument::Impl::onDocumentSaveDone( const ScriptDocument& /*_rDocument*/ ) + { + // not interested in + } + + void ScriptDocument::Impl::onDocumentSaveAs( const ScriptDocument& /*_rDocument*/ ) + { + // not interested in + } + + void ScriptDocument::Impl::onDocumentSaveAsDone( const ScriptDocument& /*_rDocument*/ ) + { + // not interested in + } + + void ScriptDocument::Impl::onDocumentClosed( const ScriptDocument& _rDocument ) + { + DBG_TESTSOLARMUTEX(); + OSL_PRECOND( isValid(), "ScriptDocument::Impl::onDocumentClosed: should not be listening if I'm not valid!" ); + + bool bMyDocument = m_xDocument == _rDocument.getDocument(); + OSL_PRECOND( bMyDocument, "ScriptDocument::Impl::onDocumentClosed: didn't want to know *this*!" ); + if ( bMyDocument ) + { + m_bDocumentClosed = true; + } + } + + + void ScriptDocument::Impl::onDocumentTitleChanged( const ScriptDocument& /*_rDocument*/ ) + { + // not interested in + } + + void ScriptDocument::Impl::onDocumentModeChanged( const ScriptDocument& /*_rDocument*/ ) + { + // not interested in + } + + + ScriptDocument::ScriptDocument() + :m_pImpl(std::make_shared()) + { } + + + ScriptDocument::ScriptDocument( ScriptDocument::SpecialDocument _eType ) + :m_pImpl( std::make_shared( Reference< XModel >() ) ) + { + OSL_ENSURE( _eType == NoDocument, "ScriptDocument::ScriptDocument: unknown SpecialDocument type!" ); + } + + + ScriptDocument::ScriptDocument( const Reference< XModel >& _rxDocument ) + :m_pImpl( std::make_shared( _rxDocument ) ) + { + OSL_ENSURE( _rxDocument.is(), "ScriptDocument::ScriptDocument: document must not be NULL!" ); + // a NULL document results in an uninitialized instance, and for this + // purpose, there is a dedicated constructor + } + + + const ScriptDocument& ScriptDocument::getApplicationScriptDocument() + { + static ScriptDocument s_aApplicationScripts; + return s_aApplicationScripts; + } + + + ScriptDocument ScriptDocument::getDocumentForBasicManager( const BasicManager* _pManager ) + { + if ( _pManager == SfxApplication::GetBasicManager() ) + return getApplicationScriptDocument(); + + docs::Documents aDocuments; + lcl_getAllModels_throw( aDocuments, false ); + + for (auto const& doc : aDocuments) + { + const BasicManager* pDocBasicManager = ::basic::BasicManagerRepository::getDocumentBasicManager( doc.xModel ); + if ( ( pDocBasicManager != SfxApplication::GetBasicManager() ) + && ( pDocBasicManager == _pManager ) + ) + { + return ScriptDocument( doc.xModel ); + } + } + + OSL_FAIL( "ScriptDocument::getDocumentForBasicManager: did not find a document for this manager!" ); + return ScriptDocument( NoDocument ); + } + + + ScriptDocument ScriptDocument::getDocumentWithURLOrCaption( std::u16string_view _rUrlOrCaption ) + { + ScriptDocument aDocument( getApplicationScriptDocument() ); + if ( _rUrlOrCaption.empty() ) + return aDocument; + + docs::Documents aDocuments; + lcl_getAllModels_throw( aDocuments, false ); + + for (auto const& doc : aDocuments) + { + const ScriptDocument aCheck( doc.xModel ); + if ( _rUrlOrCaption == aCheck.getTitle() + || _rUrlOrCaption == aCheck.m_pImpl->getURL() + ) + { + aDocument = aCheck; + break; + } + } + + return aDocument; + } + + ScriptDocuments ScriptDocument::getAllScriptDocuments( ScriptDocument::ScriptDocumentList _eListType ) + { + ScriptDocuments aScriptDocs; + + // include application? + if ( _eListType == AllWithApplication ) + aScriptDocs.push_back( getApplicationScriptDocument() ); + + // obtain documents + try + { + docs::Documents aDocuments; + lcl_getAllModels_throw( aDocuments, true /* exclude invisible */ ); + + for (auto const& doc : aDocuments) + { + // exclude documents without script/library containers + ScriptDocument aDoc( doc.xModel ); + if ( !aDoc.isValid() ) + continue; + + aScriptDocs.push_back( aDoc ); + } + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION("basctl.basicide"); + } + + // sort document list by doc title? + if ( _eListType == DocumentsSorted ) + { + auto const sort = comphelper::string::NaturalStringSorter( + comphelper::getProcessComponentContext(), + Application::GetSettings().GetUILanguageTag().getLocale()); + std::sort(aScriptDocs.begin(), aScriptDocs.end(), + [&sort](const ScriptDocument& rLHS, const ScriptDocument& rRHS) { + return sort.compare(rLHS.getTitle(), rRHS.getTitle()) < 0; + }); + } + + return aScriptDocs; + } + + + bool ScriptDocument::operator==( const ScriptDocument& _rhs ) const + { + return m_pImpl->getDocumentRef() == _rhs.m_pImpl->getDocumentRef(); + } + + + sal_Int32 ScriptDocument::hashCode() const + { + return sal::static_int_cast(reinterpret_cast< sal_IntPtr >( m_pImpl->getDocumentRef().get() )); + } + + + bool ScriptDocument::isValid() const + { + return m_pImpl->isValid(); + } + + + bool ScriptDocument::isAlive() const + { + return m_pImpl->isAlive(); + } + + + Reference< XLibraryContainer > ScriptDocument::getLibraryContainer( LibraryContainerType _eType ) const + { + return m_pImpl->getLibraryContainer( _eType ); + } + + + Reference< XNameContainer > ScriptDocument::getLibrary( LibraryContainerType _eType, const OUString& _rLibName, bool _bLoadLibrary ) const + { + return m_pImpl->getLibrary( _eType, _rLibName, _bLoadLibrary ); + } + + + bool ScriptDocument::hasLibrary( LibraryContainerType _eType, const OUString& _rLibName ) const + { + return m_pImpl->hasLibrary( _eType, _rLibName ); + } + + + Reference< XNameContainer > ScriptDocument::getOrCreateLibrary( LibraryContainerType _eType, const OUString& _rLibName ) const + { + return m_pImpl->getOrCreateLibrary( _eType, _rLibName ); + } + + + void ScriptDocument::loadLibraryIfExists( LibraryContainerType _eType, const OUString& _rLibrary ) + { + m_pImpl->loadLibraryIfExists( _eType, _rLibrary ); + } + + + Sequence< OUString > ScriptDocument::getObjectNames( LibraryContainerType _eType, const OUString& _rLibName ) const + { + Sequence< OUString > aModuleNames; + + try + { + if ( hasLibrary( _eType, _rLibName ) ) + { + Reference< XNameContainer > xLib( getLibrary( _eType, _rLibName, false ) ); + if ( xLib.is() ) + aModuleNames = xLib->getElementNames(); + } + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION("basctl.basicide"); + } + + // sort + auto const sort = comphelper::string::NaturalStringSorter( + comphelper::getProcessComponentContext(), + Application::GetSettings().GetUILanguageTag().getLocale()); + auto [begin, end] = asNonConstRange(aModuleNames); + std::sort(begin, end, + [&sort](const OUString& rLHS, const OUString& rRHS) { + return sort.compare(rLHS, rRHS) < 0; + }); + return aModuleNames; + } + + + OUString ScriptDocument::createObjectName( LibraryContainerType _eType, const OUString& _rLibName ) const + { + OUString aObjectName; + + OUString aBaseName = _eType == E_SCRIPTS ? OUString("Module") : OUString("Dialog"); + + const Sequence< OUString > aUsedNames( getObjectNames( _eType, _rLibName ) ); + std::set< OUString > aUsedNamesCheck( aUsedNames.begin(), aUsedNames.end() ); + + bool bValid = false; + sal_Int32 i = 1; + while ( !bValid ) + { + aObjectName = aBaseName + + OUString::number( i ); + + if ( aUsedNamesCheck.find( aObjectName ) == aUsedNamesCheck.end() ) + bValid = true; + + ++i; + } + + return aObjectName; + } + + + Sequence< OUString > ScriptDocument::getLibraryNames() const + { + return GetMergedLibraryNames( getLibraryContainer( E_SCRIPTS ), getLibraryContainer( E_DIALOGS ) ); + } + + + bool ScriptDocument::isReadOnly() const + { + return m_pImpl->isReadOnly(); + } + + + bool ScriptDocument::isApplication() const + { + return m_pImpl->isApplication(); + } + + bool ScriptDocument::isInVBAMode() const + { + return m_pImpl->isInVBAMode(); + } + + + BasicManager* ScriptDocument::getBasicManager() const + { + return m_pImpl->getBasicManager(); + } + + + Reference< XModel > ScriptDocument::getDocument() const + { + return m_pImpl->getDocument(); + } + + + Reference< XModel > ScriptDocument::getDocumentOrNull() const + { + if ( isDocument() ) + return m_pImpl->getDocument(); + return nullptr; + } + + + bool ScriptDocument::removeModule( const OUString& _rLibName, const OUString& _rModuleName ) const + { + return m_pImpl->removeModuleOrDialog( E_SCRIPTS, _rLibName, _rModuleName ); + } + + + bool ScriptDocument::hasModule( const OUString& _rLibName, const OUString& _rModuleName ) const + { + return m_pImpl->hasModuleOrDialog( E_SCRIPTS, _rLibName, _rModuleName ); + } + + + bool ScriptDocument::getModule( const OUString& _rLibName, const OUString& _rModName, OUString& _out_rModuleSource ) const + { + Any aCode; + if ( !m_pImpl->getModuleOrDialog( E_SCRIPTS, _rLibName, _rModName, aCode ) ) + return false; + OSL_VERIFY( aCode >>= _out_rModuleSource ); + return true; + } + + + bool ScriptDocument::renameModule( const OUString& _rLibName, const OUString& _rOldName, const OUString& _rNewName ) const + { + return m_pImpl->renameModuleOrDialog( E_SCRIPTS, _rLibName, _rOldName, _rNewName, nullptr ); + } + + + bool ScriptDocument::createModule( const OUString& _rLibName, const OUString& _rModName, bool _bCreateMain, OUString& _out_rNewModuleCode ) const + { + if ( !m_pImpl->createModule( _rLibName, _rModName, _bCreateMain, _out_rNewModuleCode ) ) + return false; + + // doc shell modified + MarkDocumentModified( *const_cast< ScriptDocument* >( this ) ); // here? + return true; + } + + + bool ScriptDocument::insertModule( const OUString& _rLibName, const OUString& _rModName, const OUString& _rModuleCode ) const + { + return m_pImpl->insertModuleOrDialog( E_SCRIPTS, _rLibName, _rModName, Any( _rModuleCode ) ); + } + + + bool ScriptDocument::updateModule( const OUString& _rLibName, const OUString& _rModName, const OUString& _rModuleCode ) const + { + return m_pImpl->updateModule( _rLibName, _rModName, _rModuleCode ); + } + + + bool ScriptDocument::removeDialog( const OUString& _rLibName, const OUString& _rDialogName ) const + { + return m_pImpl->removeModuleOrDialog( E_DIALOGS, _rLibName, _rDialogName ); + } + + + bool ScriptDocument::hasDialog( const OUString& _rLibName, const OUString& _rDialogName ) const + { + return m_pImpl->hasModuleOrDialog( E_DIALOGS, _rLibName, _rDialogName ); + } + + + bool ScriptDocument::getDialog( const OUString& _rLibName, const OUString& _rDialogName, Reference< XInputStreamProvider >& _out_rDialogProvider ) const + { + Any aCode; + if ( !m_pImpl->getModuleOrDialog( E_DIALOGS, _rLibName, _rDialogName, aCode ) ) + return false; + OSL_VERIFY( aCode >>= _out_rDialogProvider ); + return _out_rDialogProvider.is(); + } + + + bool ScriptDocument::renameDialog( const OUString& _rLibName, const OUString& _rOldName, const OUString& _rNewName, const Reference< XNameContainer >& _rxExistingDialogModel ) const + { + return m_pImpl->renameModuleOrDialog( E_DIALOGS, _rLibName, _rOldName, _rNewName, _rxExistingDialogModel ); + } + + + bool ScriptDocument::createDialog( const OUString& _rLibName, const OUString& _rDialogName, Reference< XInputStreamProvider >& _out_rDialogProvider ) const + { + if ( !m_pImpl->createDialog( _rLibName, _rDialogName, _out_rDialogProvider ) ) + return false; + + MarkDocumentModified( *const_cast< ScriptDocument* >( this ) ); // here? + return true; + } + + + bool ScriptDocument::insertDialog( const OUString& _rLibName, const OUString& _rDialogName, const Reference< XInputStreamProvider >& _rxDialogProvider ) const + { + return m_pImpl->insertModuleOrDialog( E_DIALOGS, _rLibName, _rDialogName, Any( _rxDialogProvider ) ); + } + + + void ScriptDocument::setDocumentModified() const + { + m_pImpl->setDocumentModified(); + } + + + bool ScriptDocument::isDocumentModified() const + { + return m_pImpl->isDocumentModified(); + } + + + void ScriptDocument::saveDocument( const Reference< XStatusIndicator >& _rxStatusIndicator ) const + { + m_pImpl->saveDocument( _rxStatusIndicator ); + } + + + LibraryLocation ScriptDocument::getLibraryLocation( const OUString& _rLibName ) const + { + LibraryLocation eLocation = LIBRARY_LOCATION_UNKNOWN; + if ( !_rLibName.isEmpty() ) + { + if ( isDocument() ) + { + eLocation = LIBRARY_LOCATION_DOCUMENT; + } + else + { + if ( ( hasLibrary( E_SCRIPTS, _rLibName ) && !m_pImpl->isLibraryShared( _rLibName, E_SCRIPTS ) ) + || ( hasLibrary( E_DIALOGS, _rLibName ) && !m_pImpl->isLibraryShared( _rLibName, E_DIALOGS ) ) + ) + { + eLocation = LIBRARY_LOCATION_USER; + } + else + { + eLocation = LIBRARY_LOCATION_SHARE; + } + } + } + + return eLocation; + } + + + OUString ScriptDocument::getTitle( LibraryLocation _eLocation, LibraryType _eType ) const + { + OUString aTitle; + + switch ( _eLocation ) + { + case LIBRARY_LOCATION_USER: + { + switch ( _eType ) + { + case LibraryType::Module: aTitle = IDEResId(RID_STR_USERMACROS); break; + case LibraryType::Dialog: aTitle = IDEResId(RID_STR_USERDIALOGS); break; + case LibraryType::All: aTitle = IDEResId(RID_STR_USERMACROSDIALOGS); break; + default: + break; + } + } + break; + case LIBRARY_LOCATION_SHARE: + { + switch ( _eType ) + { + case LibraryType::Module: aTitle = IDEResId(RID_STR_SHAREMACROS); break; + case LibraryType::Dialog: aTitle = IDEResId(RID_STR_SHAREDIALOGS); break; + case LibraryType::All: aTitle = IDEResId(RID_STR_SHAREMACROSDIALOGS); break; + default: + break; + } + } + break; + case LIBRARY_LOCATION_DOCUMENT: + aTitle = getTitle(); + break; + default: + break; + } + + return aTitle; + } + + + OUString ScriptDocument::getTitle() const + { + return m_pImpl->getTitle(); + } + + + bool ScriptDocument::isActive() const + { + bool bIsActive( false ); + try + { + Reference< XFrame > xFrame; + if ( m_pImpl->getCurrentFrame( xFrame ) ) + bIsActive = xFrame->isActive(); + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION("basctl.basicide"); + } + return bIsActive; + } + + + bool ScriptDocument::allowMacros() const + { + return m_pImpl->allowMacros(); + } + +} // namespace basctl + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ -- cgit v1.2.3