/* -*- 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 "vbaeventshelper.hxx" #include "excelvbahelper.hxx" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "vbaapplication.hxx" using namespace ::com::sun::star; using namespace ::com::sun::star::script::vba::VBAEventId; using namespace ::ooo::vba; namespace { /** Extracts a sheet index from the specified element of the passed sequence. The element may be an integer, a Calc range or ranges object, or a VBA Range object. @throws lang::IllegalArgumentException @throws uno::RuntimeException */ SCTAB lclGetTabFromArgs( const uno::Sequence< uno::Any >& rArgs, sal_Int32 nIndex ) { VbaEventsHelperBase::checkArgument( rArgs, nIndex ); // first try to extract a sheet index sal_Int32 nTab = -1; if( rArgs[ nIndex ] >>= nTab ) { if( (nTab < 0) || (nTab > MAXTAB) ) throw lang::IllegalArgumentException(); return static_cast< SCTAB >( nTab ); } // try VBA Range object uno::Reference< excel::XRange > xVbaRange = getXSomethingFromArgs< excel::XRange >( rArgs, nIndex ); if( xVbaRange.is() ) { uno::Reference< XHelperInterface > xVbaHelper( xVbaRange, uno::UNO_QUERY_THROW ); // TODO: in the future, the parent may be an excel::XChart (chart sheet) -> will there be a common base interface? uno::Reference< excel::XWorksheet > xVbaSheet( xVbaHelper->getParent(), uno::UNO_QUERY_THROW ); // VBA sheet index is 1-based return static_cast< SCTAB >( xVbaSheet->getIndex() - 1 ); } // try single UNO range object uno::Reference< sheet::XCellRangeAddressable > xCellRangeAddressable = getXSomethingFromArgs< sheet::XCellRangeAddressable >( rArgs, nIndex ); if( xCellRangeAddressable.is() ) return xCellRangeAddressable->getRangeAddress().Sheet; // at last, try UNO range list uno::Reference< sheet::XSheetCellRangeContainer > xRanges = getXSomethingFromArgs< sheet::XSheetCellRangeContainer >( rArgs, nIndex ); if( xRanges.is() ) { uno::Sequence< table::CellRangeAddress > aRangeAddresses = xRanges->getRangeAddresses(); if( aRangeAddresses.getLength() > 0 ) return aRangeAddresses[ 0 ].Sheet; } throw lang::IllegalArgumentException(); } /** Returns the AWT container window of the passed controller. */ uno::Reference< awt::XWindow > lclGetWindowForController( const uno::Reference< frame::XController >& rxController ) { if( rxController.is() ) try { uno::Reference< frame::XFrame > xFrame( rxController->getFrame(), uno::UNO_SET_THROW ); return xFrame->getContainerWindow(); } catch( uno::Exception& ) { } return nullptr; } } // namespace // This class is to process Workbook window related event class ScVbaEventListener : public ::cppu::WeakImplHelper< awt::XTopWindowListener, awt::XWindowListener, frame::XBorderResizeListener, util::XChangesListener > { public: ScVbaEventListener( ScVbaEventsHelper& rVbaEvents, const uno::Reference< frame::XModel >& rxModel, ScDocShell* pDocShell ); /** Starts listening to the passed document controller. */ void startControllerListening( const uno::Reference< frame::XController >& rxController ); /** Stops listening to the passed document controller. */ void stopControllerListening( const uno::Reference< frame::XController >& rxController ); // XTopWindowListener virtual void SAL_CALL windowOpened( const lang::EventObject& rEvent ) override; virtual void SAL_CALL windowClosing( const lang::EventObject& rEvent ) override; virtual void SAL_CALL windowClosed( const lang::EventObject& rEvent ) override; virtual void SAL_CALL windowMinimized( const lang::EventObject& rEvent ) override; virtual void SAL_CALL windowNormalized( const lang::EventObject& rEvent ) override; virtual void SAL_CALL windowActivated( const lang::EventObject& rEvent ) override; virtual void SAL_CALL windowDeactivated( const lang::EventObject& rEvent ) override; // XWindowListener virtual void SAL_CALL windowResized( const awt::WindowEvent& rEvent ) override; virtual void SAL_CALL windowMoved( const awt::WindowEvent& rEvent ) override; virtual void SAL_CALL windowShown( const lang::EventObject& rEvent ) override; virtual void SAL_CALL windowHidden( const lang::EventObject& rEvent ) override; // XBorderResizeListener virtual void SAL_CALL borderWidthsChanged( const uno::Reference< uno::XInterface >& rSource, const frame::BorderWidths& aNewSize ) override; // XChangesListener virtual void SAL_CALL changesOccurred( const util::ChangesEvent& rEvent ) override; // XEventListener virtual void SAL_CALL disposing( const lang::EventObject& rEvent ) override; private: /** Starts listening to the document model. */ void startModelListening(); /** Stops listening to the document model. */ void stopModelListening(); /** Returns the controller for the passed VCL window. */ uno::Reference< frame::XController > getControllerForWindow( vcl::Window* pWindow ) const; /** Calls the Workbook_Window[Activate|Deactivate] event handler. */ void processWindowActivateEvent( vcl::Window* pWindow, bool bActivate ); /** Posts a Workbook_WindowResize user event. */ void postWindowResizeEvent( vcl::Window* pWindow ); /** Callback link for Application::PostUserEvent(). */ DECL_LINK( processWindowResizeEvent, void*, void ); private: typedef ::std::map< VclPtr, uno::Reference< frame::XController > > WindowControllerMap; ::osl::Mutex maMutex; ScVbaEventsHelper& mrVbaEvents; uno::Reference< frame::XModel > mxModel; ScDocShell* const mpDocShell; WindowControllerMap maControllers; /// Maps VCL top windows to their controllers. std::multiset< VclPtr > m_PostedWindows; /// Keeps processWindowResizeEvent windows from being deleted between postWindowResizeEvent and processWindowResizeEvent VclPtr mpActiveWindow; /// Currently activated window, to prevent multiple (de)activation. bool mbWindowResized; /// True = window resize system event processed. bool mbBorderChanged; /// True = borders changed system event processed. bool mbDisposed; }; ScVbaEventListener::ScVbaEventListener( ScVbaEventsHelper& rVbaEvents, const uno::Reference< frame::XModel >& rxModel, ScDocShell* pDocShell ) : mrVbaEvents( rVbaEvents ), mxModel( rxModel ), mpDocShell( pDocShell ), mpActiveWindow( nullptr ), mbWindowResized( false ), mbBorderChanged( false ), mbDisposed( !rxModel.is() ) { if( !mxModel.is() ) return; startModelListening(); try { uno::Reference< frame::XController > xController( mxModel->getCurrentController(), uno::UNO_QUERY_THROW ); startControllerListening( xController ); } catch( uno::Exception& ) { } } void ScVbaEventListener::startControllerListening( const uno::Reference< frame::XController >& rxController ) { ::osl::MutexGuard aGuard( maMutex ); uno::Reference< awt::XWindow > xWindow = lclGetWindowForController( rxController ); if( xWindow.is() ) try { xWindow->addWindowListener( this ); } catch( uno::Exception& ) {} uno::Reference< awt::XTopWindow > xTopWindow( xWindow, uno::UNO_QUERY ); if( xTopWindow.is() ) try { xTopWindow->addTopWindowListener( this ); } catch( uno::Exception& ) {} uno::Reference< frame::XControllerBorder > xControllerBorder( rxController, uno::UNO_QUERY ); if( xControllerBorder.is() ) try { xControllerBorder->addBorderResizeListener( this ); } catch( uno::Exception& ) {} if( VclPtr pWindow = VCLUnoHelper::GetWindow( xWindow ) ) { maControllers[ pWindow ] = rxController; } } void ScVbaEventListener::stopControllerListening( const uno::Reference< frame::XController >& rxController ) { ::osl::MutexGuard aGuard( maMutex ); uno::Reference< awt::XWindow > xWindow = lclGetWindowForController( rxController ); if( xWindow.is() ) try { xWindow->removeWindowListener( this ); } catch( uno::Exception& ) {} uno::Reference< awt::XTopWindow > xTopWindow( xWindow, uno::UNO_QUERY ); if( xTopWindow.is() ) try { xTopWindow->removeTopWindowListener( this ); } catch( uno::Exception& ) {} uno::Reference< frame::XControllerBorder > xControllerBorder( rxController, uno::UNO_QUERY ); if( xControllerBorder.is() ) try { xControllerBorder->removeBorderResizeListener( this ); } catch( uno::Exception& ) {} if( VclPtr pWindow = VCLUnoHelper::GetWindow( xWindow ) ) { maControllers.erase( pWindow ); if( pWindow == mpActiveWindow ) mpActiveWindow = nullptr; } } void SAL_CALL ScVbaEventListener::windowOpened( const lang::EventObject& /*rEvent*/ ) { } void SAL_CALL ScVbaEventListener::windowClosing( const lang::EventObject& /*rEvent*/ ) { } void SAL_CALL ScVbaEventListener::windowClosed( const lang::EventObject& /*rEvent*/ ) { } void SAL_CALL ScVbaEventListener::windowMinimized( const lang::EventObject& /*rEvent*/ ) { } void SAL_CALL ScVbaEventListener::windowNormalized( const lang::EventObject& /*rEvent*/ ) { } void SAL_CALL ScVbaEventListener::windowActivated( const lang::EventObject& rEvent ) { ::osl::MutexGuard aGuard( maMutex ); if( !mbDisposed ) { uno::Reference< awt::XWindow > xWindow( rEvent.Source, uno::UNO_QUERY ); VclPtr pWindow = VCLUnoHelper::GetWindow( xWindow ); // do not fire activation event multiple time for the same window if( pWindow && (pWindow != mpActiveWindow) ) { // if another window is active, fire deactivation event first if( mpActiveWindow ) processWindowActivateEvent( mpActiveWindow, false ); // fire activation event for the new window processWindowActivateEvent( pWindow, true ); mpActiveWindow = pWindow; } } } void SAL_CALL ScVbaEventListener::windowDeactivated( const lang::EventObject& rEvent ) { ::osl::MutexGuard aGuard( maMutex ); if( !mbDisposed ) { uno::Reference< awt::XWindow > xWindow( rEvent.Source, uno::UNO_QUERY ); VclPtr pWindow = VCLUnoHelper::GetWindow( xWindow ); // do not fire the deactivation event, if the window is not active (prevent multiple deactivation) if( pWindow && (pWindow == mpActiveWindow) ) processWindowActivateEvent( pWindow, false ); // forget pointer to the active window mpActiveWindow = nullptr; } } void SAL_CALL ScVbaEventListener::windowResized( const awt::WindowEvent& rEvent ) { ::osl::MutexGuard aGuard( maMutex ); mbWindowResized = true; if( !mbDisposed && mbBorderChanged ) { uno::Reference< awt::XWindow > xWindow( rEvent.Source, uno::UNO_QUERY ); postWindowResizeEvent( VCLUnoHelper::GetWindow( xWindow ) ); } } void SAL_CALL ScVbaEventListener::windowMoved( const awt::WindowEvent& /*rEvent*/ ) { } void SAL_CALL ScVbaEventListener::windowShown( const lang::EventObject& /*rEvent*/ ) { } void SAL_CALL ScVbaEventListener::windowHidden( const lang::EventObject& /*rEvent*/ ) { } void SAL_CALL ScVbaEventListener::borderWidthsChanged( const uno::Reference< uno::XInterface >& rSource, const frame::BorderWidths& /*aNewSize*/ ) { ::osl::MutexGuard aGuard( maMutex ); mbBorderChanged = true; if( !mbDisposed && mbWindowResized ) { uno::Reference< frame::XController > xController( rSource, uno::UNO_QUERY ); uno::Reference< awt::XWindow > xWindow = lclGetWindowForController( xController ); postWindowResizeEvent( VCLUnoHelper::GetWindow( xWindow ) ); } } void SAL_CALL ScVbaEventListener::changesOccurred( const util::ChangesEvent& rEvent ) { ::osl::MutexGuard aGuard( maMutex ); sal_Int32 nCount = rEvent.Changes.getLength(); if( mbDisposed || !mpDocShell || (nCount == 0) ) return; util::ElementChange aChange = rEvent.Changes[ 0 ]; OUString sOperation; aChange.Accessor >>= sOperation; if( !sOperation.equalsIgnoreAsciiCase("cell-change") ) return; if( nCount == 1 ) { uno::Reference< table::XCellRange > xRangeObj; aChange.ReplacedElement >>= xRangeObj; if( xRangeObj.is() ) { uno::Sequence< uno::Any > aArgs( 1 ); aArgs[0] <<= xRangeObj; mrVbaEvents.processVbaEventNoThrow( WORKSHEET_CHANGE, aArgs ); } return; } ScRangeList aRangeList; for( sal_Int32 nIndex = 0; nIndex < nCount; ++nIndex ) { aChange = rEvent.Changes[ nIndex ]; aChange.Accessor >>= sOperation; uno::Reference< table::XCellRange > xRangeObj; aChange.ReplacedElement >>= xRangeObj; if( xRangeObj.is() && sOperation.equalsIgnoreAsciiCase("cell-change") ) { uno::Reference< sheet::XCellRangeAddressable > xCellRangeAddressable( xRangeObj, uno::UNO_QUERY ); if( xCellRangeAddressable.is() ) { ScRange aRange; ScUnoConversion::FillScRange( aRange, xCellRangeAddressable->getRangeAddress() ); aRangeList.push_back( aRange ); } } } if (!aRangeList.empty()) { uno::Reference< sheet::XSheetCellRangeContainer > xRanges( new ScCellRangesObj( mpDocShell, aRangeList ) ); uno::Sequence< uno::Any > aArgs(1); aArgs[0] <<= xRanges; mrVbaEvents.processVbaEventNoThrow( WORKSHEET_CHANGE, aArgs ); } } void SAL_CALL ScVbaEventListener::disposing( const lang::EventObject& rEvent ) { ::osl::MutexGuard aGuard( maMutex ); uno::Reference< frame::XModel > xModel( rEvent.Source, uno::UNO_QUERY ); if( xModel.is() ) { OSL_ENSURE( xModel.get() == mxModel.get(), "ScVbaEventListener::disposing - disposing from unknown model" ); stopModelListening(); mbDisposed = true; return; } uno::Reference< frame::XController > xController( rEvent.Source, uno::UNO_QUERY ); if( xController.is() ) { stopControllerListening( xController ); return; } } // private -------------------------------------------------------------------- void ScVbaEventListener::startModelListening() { try { uno::Reference< util::XChangesNotifier > xChangesNotifier( mxModel, uno::UNO_QUERY_THROW ); xChangesNotifier->addChangesListener( this ); } catch( uno::Exception& ) { } } void ScVbaEventListener::stopModelListening() { try { uno::Reference< util::XChangesNotifier > xChangesNotifier( mxModel, uno::UNO_QUERY_THROW ); xChangesNotifier->removeChangesListener( this ); } catch( uno::Exception& ) { } } uno::Reference< frame::XController > ScVbaEventListener::getControllerForWindow( vcl::Window* pWindow ) const { WindowControllerMap::const_iterator aIt = maControllers.find( pWindow ); return (aIt == maControllers.end()) ? uno::Reference< frame::XController >() : aIt->second; } void ScVbaEventListener::processWindowActivateEvent( vcl::Window* pWindow, bool bActivate ) { uno::Reference< frame::XController > xController = getControllerForWindow( pWindow ); if( xController.is() ) { uno::Sequence< uno::Any > aArgs( 1 ); aArgs[ 0 ] <<= xController; mrVbaEvents.processVbaEventNoThrow( bActivate ? WORKBOOK_WINDOWACTIVATE : WORKBOOK_WINDOWDEACTIVATE, aArgs ); } } void ScVbaEventListener::postWindowResizeEvent( vcl::Window* pWindow ) { // check that the passed window is still alive (it must be registered in maControllers) if( pWindow && (maControllers.count( pWindow ) > 0) ) { mbWindowResized = mbBorderChanged = false; acquire(); // ensure we don't get deleted before the timer fires m_PostedWindows.insert(pWindow); Application::PostUserEvent( LINK( this, ScVbaEventListener, processWindowResizeEvent ), pWindow ); } } IMPL_LINK( ScVbaEventListener, processWindowResizeEvent, void*, p, void ) { vcl::Window* pWindow = static_cast(p); ::osl::MutexGuard aGuard( maMutex ); /* Check that the passed window is still alive (it must be registered in maControllers). While closing a document, postWindowResizeEvent() may be called on the last window which posts a user event via Application::PostUserEvent to call this event handler. VCL will trigger the handler some time later. Sometimes, the window gets deleted before. This is handled via the disposing() function which removes the window pointer from the member maControllers. Thus, checking whether maControllers contains pWindow ensures that the window is still alive. */ if( !mbDisposed && pWindow && !pWindow->IsDisposed() && (maControllers.count(pWindow) > 0) ) { // do not fire event unless all mouse buttons have been released vcl::Window::PointerState aPointerState = pWindow->GetPointerState(); if( (aPointerState.mnState & (MOUSE_LEFT | MOUSE_MIDDLE | MOUSE_RIGHT)) == 0 ) { uno::Reference< frame::XController > xController = getControllerForWindow( pWindow ); if( xController.is() ) { uno::Sequence< uno::Any > aArgs( 1 ); aArgs[ 0 ] <<= xController; // #163419# do not throw exceptions into application core mrVbaEvents.processVbaEventNoThrow( WORKBOOK_WINDOWRESIZE, aArgs ); } } } { // note: there may be multiple processWindowResizeEvent outstanding // for pWindow, so it may have been added to m_PostedWindows multiple // times - so this must delete exactly one of these elements! auto const iter(m_PostedWindows.find(pWindow)); assert(iter != m_PostedWindows.end()); m_PostedWindows.erase(iter); } release(); } ScVbaEventsHelper::ScVbaEventsHelper( const uno::Sequence< uno::Any >& rArgs ) : VbaEventsHelperBase( rArgs ), mbOpened( false ) { mpDocShell = dynamic_cast< ScDocShell* >( mpShell ); // mpShell from base class mpDoc = mpDocShell ? &mpDocShell->GetDocument() : nullptr; if( !mxModel.is() || !mpDocShell || !mpDoc ) return; // global auto registerAutoEvent = [this](sal_Int32 nID, const sal_Char* sName) { registerEventHandler(nID, script::ModuleType::NORMAL, (OString("Auto_").concat(sName)).getStr(), -1, uno::Any(false)); }; registerAutoEvent(AUTO_OPEN, "Open"); registerAutoEvent(AUTO_CLOSE, "Close"); // Workbook auto registerWorkbookEvent = [this](sal_Int32 nID, const sal_Char* sName, sal_Int32 nCancelIndex) { registerEventHandler(nID, script::ModuleType::DOCUMENT, (OString("Workbook_").concat(sName)).getStr(), nCancelIndex, uno::Any(false)); }; registerWorkbookEvent( WORKBOOK_ACTIVATE, "Activate", -1 ); registerWorkbookEvent( WORKBOOK_DEACTIVATE, "Deactivate", -1 ); registerWorkbookEvent( WORKBOOK_OPEN, "Open", -1 ); registerWorkbookEvent( WORKBOOK_BEFORECLOSE, "BeforeClose", 0 ); registerWorkbookEvent( WORKBOOK_BEFOREPRINT, "BeforePrint", 0 ); registerWorkbookEvent( WORKBOOK_BEFORESAVE, "BeforeSave", 1 ); registerWorkbookEvent( WORKBOOK_AFTERSAVE, "AfterSave", -1 ); registerWorkbookEvent( WORKBOOK_NEWSHEET, "NewSheet", -1 ); registerWorkbookEvent( WORKBOOK_WINDOWACTIVATE, "WindowActivate", -1 ); registerWorkbookEvent( WORKBOOK_WINDOWDEACTIVATE, "WindowDeactivate", -1 ); registerWorkbookEvent( WORKBOOK_WINDOWRESIZE, "WindowResize", -1 ); // Worksheet events. All events have a corresponding workbook event. auto registerWorksheetEvent = [this](sal_Int32 nID, const sal_Char* sName, sal_Int32 nCancelIndex) { registerEventHandler(nID, script::ModuleType::DOCUMENT, (OString("Worksheet_").concat(sName)).getStr(), nCancelIndex, uno::Any(true)); registerEventHandler(USERDEFINED_START + nID, script::ModuleType::DOCUMENT, (OString("Workbook_Worksheet").concat(sName)).getStr(), ((nCancelIndex >= 0) ? (nCancelIndex + 1) : -1), uno::Any(false)); }; registerWorksheetEvent( WORKSHEET_ACTIVATE, "Activate", -1 ); registerWorksheetEvent( WORKSHEET_DEACTIVATE, "Deactivate", -1 ); registerWorksheetEvent( WORKSHEET_BEFOREDOUBLECLICK, "BeforeDoubleClick", 1 ); registerWorksheetEvent( WORKSHEET_BEFORERIGHTCLICK, "BeforeRightClick", 1 ); registerWorksheetEvent( WORKSHEET_CALCULATE, "Calculate", -1 ); registerWorksheetEvent( WORKSHEET_CHANGE, "Change", -1 ); registerWorksheetEvent( WORKSHEET_SELECTIONCHANGE, "SelectionChange", -1 ); registerWorksheetEvent( WORKSHEET_FOLLOWHYPERLINK, "FollowHyperlink", -1 ); } ScVbaEventsHelper::~ScVbaEventsHelper() { } void SAL_CALL ScVbaEventsHelper::notifyEvent( const css::document::EventObject& rEvent ) { static const uno::Sequence< uno::Any > saEmptyArgs; if( (rEvent.EventName == GlobalEventConfig::GetEventName( GlobalEventId::OPENDOC )) || (rEvent.EventName == GlobalEventConfig::GetEventName( GlobalEventId::CREATEDOC )) ) // CREATEDOC triggered e.g. during VBA Workbooks.Add { processVbaEventNoThrow( WORKBOOK_OPEN, saEmptyArgs ); } else if( rEvent.EventName == GlobalEventConfig::GetEventName( GlobalEventId::ACTIVATEDOC ) ) { processVbaEventNoThrow( WORKBOOK_ACTIVATE, saEmptyArgs ); } else if( rEvent.EventName == GlobalEventConfig::GetEventName( GlobalEventId::DEACTIVATEDOC ) ) { processVbaEventNoThrow( WORKBOOK_DEACTIVATE, saEmptyArgs ); } else if( (rEvent.EventName == GlobalEventConfig::GetEventName( GlobalEventId::SAVEDOCDONE )) || (rEvent.EventName == GlobalEventConfig::GetEventName( GlobalEventId::SAVEASDOCDONE )) || (rEvent.EventName == GlobalEventConfig::GetEventName( GlobalEventId::SAVETODOCDONE )) ) { uno::Sequence< uno::Any > aArgs( 1 ); aArgs[ 0 ] <<= true; processVbaEventNoThrow( WORKBOOK_AFTERSAVE, aArgs ); } else if( (rEvent.EventName == GlobalEventConfig::GetEventName( GlobalEventId::SAVEDOCFAILED )) || (rEvent.EventName == GlobalEventConfig::GetEventName( GlobalEventId::SAVEASDOCFAILED )) || (rEvent.EventName == GlobalEventConfig::GetEventName( GlobalEventId::SAVETODOCFAILED )) ) { uno::Sequence< uno::Any > aArgs( 1 ); aArgs[ 0 ] <<= false; processVbaEventNoThrow( WORKBOOK_AFTERSAVE, aArgs ); } else if( rEvent.EventName == GlobalEventConfig::GetEventName( GlobalEventId::CLOSEDOC ) ) { /* Trigger the WORKBOOK_WINDOWDEACTIVATE and WORKBOOK_DEACTIVATE events and stop listening to the model (done in base class). */ uno::Reference< frame::XController > xController( mxModel->getCurrentController() ); if( xController.is() ) { uno::Sequence< uno::Any > aArgs( 1 ); aArgs[ 0 ] <<= xController; processVbaEventNoThrow( WORKBOOK_WINDOWDEACTIVATE, aArgs ); } processVbaEventNoThrow( WORKBOOK_DEACTIVATE, saEmptyArgs ); } else if( rEvent.EventName == GlobalEventConfig::GetEventName( GlobalEventId::VIEWCREATED ) ) { uno::Reference< frame::XController > xController( mxModel->getCurrentController() ); if( mxListener.get() && xController.is() ) mxListener->startControllerListening( xController ); } VbaEventsHelperBase::notifyEvent( rEvent ); } OUString ScVbaEventsHelper::getImplementationName() { return OUString("ScVbaEventsHelper"); } css::uno::Sequence ScVbaEventsHelper::getSupportedServiceNames() { return css::uno::Sequence{ "com.sun.star.script.vba.VBASpreadsheetEventProcessor"}; } // protected ------------------------------------------------------------------ bool ScVbaEventsHelper::implPrepareEvent( EventQueue& rEventQueue, const EventHandlerInfo& rInfo, const uno::Sequence< uno::Any >& rArgs ) { // document and document shell are needed during event processing if( !mpShell || !mpDoc ) throw uno::RuntimeException(); /* For document events: check if events are enabled via the Application.EnableEvents symbol (this is an Excel-only attribute). Check this again for every event, as the event handler may change the state of the EnableEvents symbol. Global events such as AUTO_OPEN and AUTO_CLOSE are always enabled. */ bool bExecuteEvent = (rInfo.mnModuleType != script::ModuleType::DOCUMENT) || ScVbaApplication::getDocumentEventsEnabled(); // framework and Calc fire a few events before 'OnLoad', ignore them if( bExecuteEvent ) bExecuteEvent = (rInfo.mnEventId == WORKBOOK_OPEN) ? !mbOpened : mbOpened; // special handling for some events if( bExecuteEvent ) switch( rInfo.mnEventId ) { case WORKBOOK_OPEN: { // execute delayed Activate event too (see above) rEventQueue.emplace_back(WORKBOOK_ACTIVATE ); uno::Sequence< uno::Any > aArgs( 1 ); aArgs[ 0 ] <<= mxModel->getCurrentController(); rEventQueue.emplace_back( WORKBOOK_WINDOWACTIVATE, aArgs ); rEventQueue.emplace_back(AUTO_OPEN ); // remember initial selection maOldSelection <<= mxModel->getCurrentSelection(); } break; case WORKSHEET_SELECTIONCHANGE: // if selection is not changed, then do not fire the event bExecuteEvent = isSelectionChanged( rArgs, 0 ); break; } if( bExecuteEvent ) { // add workbook event associated to a sheet event bool bSheetEvent = false; if( (rInfo.maUserData >>= bSheetEvent) && bSheetEvent ) rEventQueue.emplace_back( rInfo.mnEventId + USERDEFINED_START, rArgs ); } return bExecuteEvent; } uno::Sequence< uno::Any > ScVbaEventsHelper::implBuildArgumentList( const EventHandlerInfo& rInfo, const uno::Sequence< uno::Any >& rArgs ) { // fill arguments for workbook events associated to sheet events according to sheet events, sheet will be added below bool bSheetEventAsBookEvent = rInfo.mnEventId > USERDEFINED_START; sal_Int32 nEventId = bSheetEventAsBookEvent ? (rInfo.mnEventId - USERDEFINED_START) : rInfo.mnEventId; uno::Sequence< uno::Any > aVbaArgs; switch( nEventId ) { // *** Workbook *** // no arguments case WORKBOOK_ACTIVATE: case WORKBOOK_DEACTIVATE: case WORKBOOK_OPEN: break; // 1 arg: cancel case WORKBOOK_BEFORECLOSE: case WORKBOOK_BEFOREPRINT: aVbaArgs.realloc( 1 ); // current cancel state will be inserted by caller break; // 2 args: saveAs, cancel case WORKBOOK_BEFORESAVE: aVbaArgs.realloc( 2 ); checkArgumentType< bool >( rArgs, 0 ); aVbaArgs[ 0 ] = rArgs[ 0 ]; // current cancel state will be inserted by caller break; // 1 arg: success case WORKBOOK_AFTERSAVE: aVbaArgs.realloc( 1 ); checkArgumentType< bool >( rArgs, 0 ); aVbaArgs[ 0 ] = rArgs[ 0 ]; break; // 1 arg: window case WORKBOOK_WINDOWACTIVATE: case WORKBOOK_WINDOWDEACTIVATE: case WORKBOOK_WINDOWRESIZE: aVbaArgs.realloc( 1 ); aVbaArgs[ 0 ] = createWindow( rArgs, 0 ); break; // 1 arg: worksheet case WORKBOOK_NEWSHEET: aVbaArgs.realloc( 1 ); aVbaArgs[ 0 ] = createWorksheet( rArgs, 0 ); break; // *** Worksheet *** // no arguments case WORKSHEET_ACTIVATE: case WORKSHEET_CALCULATE: case WORKSHEET_DEACTIVATE: break; // 1 arg: range case WORKSHEET_CHANGE: case WORKSHEET_SELECTIONCHANGE: aVbaArgs.realloc( 1 ); aVbaArgs[ 0 ] = createRange( rArgs, 0 ); break; // 2 args: range, cancel case WORKSHEET_BEFOREDOUBLECLICK: case WORKSHEET_BEFORERIGHTCLICK: aVbaArgs.realloc( 2 ); aVbaArgs[ 0 ] = createRange( rArgs, 0 ); // current cancel state will be inserted by caller break; // 1 arg: hyperlink case WORKSHEET_FOLLOWHYPERLINK: aVbaArgs.realloc( 1 ); aVbaArgs[ 0 ] = createHyperlink( rArgs, 0 ); break; } /* For workbook events associated to sheet events, the workbook event gets the same arguments but with a Worksheet object in front of them. */ if( bSheetEventAsBookEvent ) { sal_Int32 nLength = aVbaArgs.getLength(); uno::Sequence< uno::Any > aVbaArgs2( nLength + 1 ); aVbaArgs2[ 0 ] = createWorksheet( rArgs, 0 ); for( sal_Int32 nIndex = 0; nIndex < nLength; ++nIndex ) aVbaArgs2[ nIndex + 1 ] = aVbaArgs[ nIndex ]; aVbaArgs = aVbaArgs2; } return aVbaArgs; } void ScVbaEventsHelper::implPostProcessEvent( EventQueue& rEventQueue, const EventHandlerInfo& rInfo, bool bCancel ) { switch( rInfo.mnEventId ) { case WORKBOOK_OPEN: mbOpened = true; // register the listeners if( !mxListener.is() ) mxListener = new ScVbaEventListener( *this, mxModel, mpDocShell ); break; case WORKBOOK_BEFORECLOSE: /* Execute Auto_Close only if not cancelled by event handler, but before UI asks user whether to cancel closing the document. */ if( !bCancel ) rEventQueue.emplace_back(AUTO_CLOSE ); break; } } OUString ScVbaEventsHelper::implGetDocumentModuleName( const EventHandlerInfo& rInfo, const uno::Sequence< uno::Any >& rArgs ) const { bool bSheetEvent = false; rInfo.maUserData >>= bSheetEvent; SCTAB nTab = bSheetEvent ? lclGetTabFromArgs( rArgs, 0 ) : -1; if( bSheetEvent && (nTab < 0) ) throw lang::IllegalArgumentException(); OUString aCodeName; if( bSheetEvent ) mpDoc->GetCodeName( nTab, aCodeName ); else aCodeName = mpDoc->GetCodeName(); return aCodeName; } // private -------------------------------------------------------------------- namespace { /** Compares the passed range lists representing sheet selections. Ignores selections that refer to different sheets (returns false in this case). */ bool lclSelectionChanged( const ScRangeList& rLeft, const ScRangeList& rRight ) { // one of the range lists empty? -> return false, if both lists empty bool bLeftEmpty = rLeft.empty(); bool bRightEmpty = rRight.empty(); if( bLeftEmpty || bRightEmpty ) return !(bLeftEmpty && bRightEmpty); // check sheet indexes of the range lists (assuming that all ranges in a list are on the same sheet) if (rLeft[0].aStart.Tab() != rRight[0].aStart.Tab()) return false; // compare all ranges return rLeft != rRight; } } // namespace bool ScVbaEventsHelper::isSelectionChanged( const uno::Sequence< uno::Any >& rArgs, sal_Int32 nIndex ) { uno::Reference< uno::XInterface > xOldSelection( maOldSelection, uno::UNO_QUERY ); uno::Reference< uno::XInterface > xNewSelection = getXSomethingFromArgs< uno::XInterface >( rArgs, nIndex, false ); ScCellRangesBase* pOldCellRanges = ScCellRangesBase::getImplementation( xOldSelection ); ScCellRangesBase* pNewCellRanges = ScCellRangesBase::getImplementation( xNewSelection ); bool bChanged = !pOldCellRanges || !pNewCellRanges || lclSelectionChanged( pOldCellRanges->GetRangeList(), pNewCellRanges->GetRangeList() ); maOldSelection <<= xNewSelection; return bChanged; } uno::Any ScVbaEventsHelper::createWorksheet( const uno::Sequence< uno::Any >& rArgs, sal_Int32 nIndex ) const { // extract sheet index, will throw, if parameter is invalid SCTAB nTab = lclGetTabFromArgs( rArgs, nIndex ); return uno::Any( excel::getUnoSheetModuleObj( mxModel, nTab ) ); } uno::Any ScVbaEventsHelper::createRange( const uno::Sequence< uno::Any >& rArgs, sal_Int32 nIndex ) const { // it is possible to pass an existing VBA Range object uno::Reference< excel::XRange > xVbaRange = getXSomethingFromArgs< excel::XRange >( rArgs, nIndex ); if( !xVbaRange.is() ) { uno::Reference< sheet::XSheetCellRangeContainer > xRanges = getXSomethingFromArgs< sheet::XSheetCellRangeContainer >( rArgs, nIndex ); uno::Reference< table::XCellRange > xRange = getXSomethingFromArgs< table::XCellRange >( rArgs, nIndex ); if ( !xRanges.is() && !xRange.is() ) throw lang::IllegalArgumentException(); uno::Sequence< uno::Any > aArgs( 2 ); if ( xRanges.is() ) { aArgs[ 0 ] <<= excel::getUnoSheetModuleObj( xRanges ); aArgs[ 1 ] <<= xRanges; } else { aArgs[ 0 ] <<= excel::getUnoSheetModuleObj( xRange ); aArgs[ 1 ] <<= xRange; } xVbaRange.set( createVBAUnoAPIServiceWithArgs( mpShell, "ooo.vba.excel.Range", aArgs ), uno::UNO_QUERY_THROW ); } return uno::Any( xVbaRange ); } uno::Any ScVbaEventsHelper::createHyperlink( const uno::Sequence< uno::Any >& rArgs, sal_Int32 nIndex ) const { uno::Reference< table::XCell > xCell = getXSomethingFromArgs< table::XCell >( rArgs, nIndex, false ); uno::Sequence< uno::Any > aArgs( 2 ); aArgs[ 0 ] <<= excel::getUnoSheetModuleObj( xCell ); aArgs[ 1 ] <<= xCell; uno::Reference< uno::XInterface > xHyperlink( createVBAUnoAPIServiceWithArgs( mpShell, "ooo.vba.excel.Hyperlink", aArgs ), uno::UNO_SET_THROW ); return uno::Any( xHyperlink ); } uno::Any ScVbaEventsHelper::createWindow( const uno::Sequence< uno::Any >& rArgs, sal_Int32 nIndex ) const { uno::Sequence< uno::Any > aArgs( 3 ); aArgs[ 0 ] <<= getVBADocument( mxModel ); aArgs[ 1 ] <<= mxModel; aArgs[ 2 ] <<= getXSomethingFromArgs< frame::XController >( rArgs, nIndex, false ); uno::Reference< uno::XInterface > xWindow( createVBAUnoAPIServiceWithArgs( mpShell, "ooo.vba.excel.Window", aArgs ), uno::UNO_SET_THROW ); return uno::Any( xWindow ); } extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface * ScVbaEventsHelper_get_implementation( css::uno::XComponentContext * /*context*/, css::uno::Sequence const &arguments) { return cppu::acquire(new ScVbaEventsHelper(arguments)); } /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ ='libreoffice-6-4-7'>libreoffice-6-4-7 LibreOffice 核心代码仓库文档基金会
summaryrefslogtreecommitdiff
path: root/unoxml
AgeCommit message (Collapse)Author
2015-04-25remove some @author tags from suspiciously unidiomatic codeMichael Stahl
Change-Id: I3930420fe502978f8e14a688f2eb99c74d185f7b
2015-04-13loplugin:staticmethodsNoel Grandin
Change-Id: I33a8ca28b0c3bf1c31758d93238e74927bebde9c
2015-03-31Reduce to static_cast any reinterpret_cast from void pointersStephan Bergmann
Change-Id: Ia275bf01d6c72e01e9144a99121f4a9858e88c8a
2015-03-28Clean up C-style casts from pointers to voidStephan Bergmann
Change-Id: Ie12eb8940ebb6059d234f5af25800812c085002a
2015-03-26const_cast: convert some C-style casts and remove some redundant onesStephan Bergmann
Change-Id: I85007c6fdceca1c070ca9b4cb62715a5c92bfe15
2015-03-13tdf#43157: Fix format string violations in OSL_TRACE etc.Stephan Bergmann
...for a 32-bit build, similar to what ee11e221d2108212619e1bbe7f029e7d9afdba32 "tdf#43157: Fix format string violations in OSL_TRACE etc." did for a 64-bit build Change-Id: I05dd79ede3e66cb9ab7a33792319eb34b34c82dd
2015-02-06fdo#75757: Remove inheritance from std::vectorMatthew Pottage
Deprecated comphelper/sequenceasvector.hxx. Rewritten code using it. Using instead the functions containerToSequence and sequenceToContainer, found in include/comphelper/sequence.hxx. One class that inherits from it (in framework/inc/stdtypes.h), and the code using that has been left. Signed-off-by: Michael Stahl <mstahl@redhat.com> Conflicts: writerfilter/source/dmapper/DomainMapper.cxx writerfilter/source/dmapper/TblStylePrHandler.hxx writerfilter/source/dmapper/WrapPolygonHandler.hxx Change-Id: Ice61c94ffb052e389281aebb7cdf185134221061
2015-02-05Updated all precompiled headers.Ashod Nakashian
Change-Id: I955c8ac4dbe002d23531df7eb10fb4444d6b5157 Reviewed-on: https://gerrit.libreoffice.org/14292 Tested-by: Jenkins <ci@libreoffice.org> Reviewed-by: Caolán McNamara <caolanm@redhat.com> Tested-by: Caolán McNamara <caolanm@redhat.com>
2015-01-29callcatcher: large newly detected unused methods post de-virtualizationCaolán McNamara
i.e lots now able to be detected after... commit b44cbb26efe1d0b0950b1e1613e131b506dc3876 Author: Noel Grandin <noel@peralex.com> Date: Tue Jan 20 12:38:10 2015 +0200 new loplugin: change virtual methods to non-virtual Where we can prove that the virtual method is never overriden. In the case of pure-virtual methods, we remove the method entirely. Sometimes this leads to entire methods and fields being eliminated. Change-Id: I605e2fa56f7186c3d3a764f3cd30f5cf7f881f9d
2015-01-28remove unused typedefsNoel Grandin
found with some minor modifications to find/find-unused-defines.sh Change-Id: I18cc479adedc7a0dada68a4aeef08300e62631dd Reviewed-on: https://gerrit.libreoffice.org/14194 Tested-by: Jenkins <ci@libreoffice.org> Reviewed-by: Noel Grandin <noelgrandin@gmail.com>
2015-01-26new loplugin: change virtual methods to non-virtualNoel Grandin
Where we can prove that the virtual method is never overriden. In the case of pure-virtual methods, we remove the method entirely. Sometimes this leads to entire methods and fields being eliminated. Change-Id: I138ef81c95f115dbd8c023a83cfc7e9d5d6d14ae
2015-01-22loplugin:cstylecastStephan Bergmann
Change-Id: I126e06a0c7b442dfc4fcad7c05ff6caf07896a8f
2015-01-20Some more loplugin:cstylecast: unoxmlStephan Bergmann
Change-Id: I7467e033c998d9ee4283a146088c3b09d161f3cd
2015-01-19fdo#39440 reduce scope of local variablesMichael Weghorn
This addresses some cppcheck warnings. Change-Id: I1cd8b118e2598b8b18fb445851a3bb41e554267b Reviewed-on: https://gerrit.libreoffice.org/13967 Tested-by: Jenkins <ci@libreoffice.org> Reviewed-by: Noel Grandin <noelgrandin@gmail.com>
2015-01-02boost::unordered_map->std::unordered_mapCaolán McNamara
you can get debug stl this way Change-Id: Ia70a3e7c7c452390e8bee34975d296c9318e4a19
2014-12-19java: reduce visibility of some methods and fieldsNoel Grandin
found by UCDetector Change-Id: I0a0a00d1fae1fed2e6aef198b7a1482d7e7e29f0
2014-12-19java: static fields that should not be staticNoel Grandin
Found by FindBugs. Change-Id: I223841f7bb8c515c9612322abc0b13e134385abd
2014-12-18unoxml: Use appropriate OUString functions on string constantsStephan Bergmann
Change-Id: I6be6717b1714e2f7115ec8e27c5026a439bf1b05
2014-12-17Introduce rtl::OUStringLiteral1Stephan Bergmann
...to use single ASCII character literals "more directly" in the OUString API (instead of having to go via an intermediary OUString ctor call). Especially useful for character literals that are defined as const variables or via macros ("direct" uses of character literals in the OUString API can often simply be replaced with single-character string literals, for improved readability). (The functions overloaded for OUStringLiteral1 are those that are actually used by the existing LO code; more could potentially be added. The asymmetry in the operator ==/!= parameter types is by design, though---writing code like 'x' == s is an abomination that shall not be abetted.) Change-Id: Ic5264714be7439eed56b5dfca6ccaee277306f1f
2014-12-15java: remove some unused fields and variablesNoel Grandin
Change-Id: I5d6071096307adbe7df0178000346cf915afa3e7 Reviewed-on: https://gerrit.libreoffice.org/13477 Reviewed-by: Noel Grandin <noelgrandin@gmail.com> Tested-by: Noel Grandin <noelgrandin@gmail.com>
2014-12-15unoxml: Use appropriate OUString functions on string constantsStephan Bergmann
Change-Id: If4467034e026409dc9d6f0b5ffcafcf98ff8778e
2014-12-11document 440749 Explicit null dereferencedCaolán McNamara
Change-Id: I9f2e97504953742f09981632b7901fcd2fae6747
2014-12-11java: reduce visibility of fields and methodsNoel Grandin
found by PMD Change-Id: Id6737916b68ccbdbdeec5d314747a38410923ac6 Reviewed-on: https://gerrit.libreoffice.org/13409 Tested-by: LibreOffice gerrit bot <gerrit@libreoffice.org> Reviewed-by: Noel Grandin <noelgrandin@gmail.com>
2014-12-10java: improve use of WrappedTargetException to set cause properlyNoel Grandin
since we introduced the new constructors that pass the cause all the way up to java.lang.Throwable. Also simplify some exeception printing sites, because Throwable will correctly print out child exceptions for us. Change-Id: Ibbecce3c6f971fbc80d6de2052ab4f33a4503c0a
2014-12-10java: simplify the getMSF() methodsNoel Grandin
Change-Id: Ib459799f4a3224f8c9683ac4b6cf37982d2077a3 Reviewed-on: https://gerrit.libreoffice.org/13406 Reviewed-by: Noel Grandin <noelgrandin@gmail.com> Tested-by: Noel Grandin <noelgrandin@gmail.com>
2014-11-18cppu: clean up public headers with include-what-you-useMichael Stahl
Unfortunately iwyu gets quite confused by the weird cyclic dependencies between various foo.h/foo.hxx and cppumaker generated headers, so it's not obvious if any improvement here is realistic... Change-Id: I0bc66f98b146712e28cabc18d56c11c08418c721
2014-11-17sal: clean up public headers with include-what-you-useMichael Stahl
Sadly cannot forward declare "struct {...} TimeValue;". rtl/(u)?string.hxx still include sal/log.hxx but removing osl/diagnose.h was painful enough for now... Change-Id: Id41e17f3870c4f24c53ce7b11f2c40a3d14d1f05
2014-11-14fdo#86023 - O[U]String needs a 'clear' methodBrij Mohan Lal Srivastava
Added clear() method to OString and OUString class, Updated appropriate call-sites. Change-Id: I0ba97fa6dc7af3e31b605953089a4e8e9c3e61ac Signed-off-by: Stephan Bergmann <sbergman@redhat.com>
2014-11-06Revert "use the new OUString::fromUtf8 method"Stephan Bergmann
This reverts commit 05050cdb23de586870bf479a9df5ced06828d498, not all places that use e.g. OStringToOUString to convert potential UTF-8 are guaranteed to fulfil the prerequisites necessary to use fromUtf8 (and some places like e.g. in codemaker are happy with the best-effort effect of OStringToOUString's OSTRING_TO_OUSTRING_CVTFLAGS).
2014-11-06use the new OUString::fromUtf8 methodNoel Grandin
Change-Id: I771004b7ccab3344a67e827e45bc34c22ffa5f77
2014-11-05fdo#38835 strip out OUString globalsNoel Grandin
they are largely unnecessary these days, since our OUString infrastructure gained optimised handling for static char constants. Change-Id: I07f73484f82d0582252cb4324d4107c998432c37
2014-11-03coverity#705527 drop testlistener that logs to c:\listener.outCaolán McNamara
Change-Id: Id9eab9e44d4b0e705289fa45be0fc2343903de09
2014-11-03coverity#982488 unchecked dynamic_castDavid Tardon
Change-Id: I7008b3a96400a4d1520a03d985c0b421ff587bcb
2014-10-13coverity#707458 Uncaught exception (better fix)Michael Stahl
getStatementsGraph_NoLock() cannot throw the exception because of the i_Internal=true parameter, which may confuse Converity; but possibly xIter->nextElement() could throw this in a multi-threaded scenario... Change-Id: I204c0e5b38fee919d6cfe9247bde76b6ea78ed0f
2014-10-10coverity#707458 Uncaught exceptionCaolán McNamara
Change-Id: Ia446cc0b8b26bb158b36ca64cbf45bf172f37bdf
2014-10-01coverity#1242932 Uncaught exceptionCaolán McNamara
Change-Id: I13ef24dfa1c82ad14737dac77b18e92d3abeb96b
2014-10-01unoxml: std::auto_ptr -> std::unique_ptrStephan Bergmann
Change-Id: Ib7da2401529bbff92611abdab44d26ff009e38b3
2014-09-26Remove unused files and move test to qa/Matúš Kukan
Change-Id: Ia8c022c958f5547d710f9cb196672b89292bbb49
2014-09-25unoxml: domtest needs unotest library on WNTMichael Stahl
Change-Id: I9614e1495e6d990e050c651c2aed0ba0e43d51fe
2014-09-25fdo#39625 Make existing CppUnit tests workTobias Madl
As in the ticket description, this test is now working, but some parts of it are still commented out, because they are waiting for a fix of another bug (Bug 84237). Once it is fixed, it should be possible to just uncomment them, and then they should work. Change-Id: I73d1cc7391080e357c08cb3442616e2901070c1f Signed-off-by: Stephan Bergmann <sbergman@redhat.com> (with minor amendments)
2014-09-22fdo#84086 Fix assorted use-after-free bugsMatthew J. Francis
Change-Id: Iec004fffdb0afbe27bd69f379db90f6d904a8a65 Reviewed-on: https://gerrit.libreoffice.org/11553 Reviewed-by: Noel Grandin <noelgrandin@gmail.com> Tested-by: Noel Grandin <noelgrandin@gmail.com>
2014-08-14java: remove commented out codeNoel Grandin
Change-Id: I05c907a38b562231e968c17f14e09ef80e0a6ed1
2014-08-12java: add @Override annotation to overriding methodsNoel Grandin
Change-Id: I086964c6f6ce52c60c52b6dbc445d3c21d22c80a