summaryrefslogtreecommitdiff
path: root/sc/source/ui/vba/vbaeventshelper.cxx
diff options
context:
space:
mode:
Diffstat (limited to 'sc/source/ui/vba/vbaeventshelper.cxx')
-rwxr-xr-xsc/source/ui/vba/vbaeventshelper.cxx753
1 files changed, 753 insertions, 0 deletions
diff --git a/sc/source/ui/vba/vbaeventshelper.cxx b/sc/source/ui/vba/vbaeventshelper.cxx
new file mode 100755
index 000000000000..45667adf2f2c
--- /dev/null
+++ b/sc/source/ui/vba/vbaeventshelper.cxx
@@ -0,0 +1,753 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+#include "vbaeventshelper.hxx"
+
+#include <com/sun/star/awt/XWindowListener.hpp>
+#include <com/sun/star/frame/XBorderResizeListener.hpp>
+#include <com/sun/star/frame/XControllerBorder.hpp>
+#include <com/sun/star/script/vba/VBAEventId.hpp>
+#include <com/sun/star/sheet/XCellRangeAddressable.hpp>
+#include <com/sun/star/sheet/XSheetCellRangeContainer.hpp>
+#include <com/sun/star/table/XCellRange.hpp>
+#include <com/sun/star/util/XChangesListener.hpp>
+#include <com/sun/star/util/XChangesNotifier.hpp>
+#include <com/sun/star/util/XCloseListener.hpp>
+
+#include <ooo/vba/excel/XApplication.hpp>
+
+#include <cppuhelper/implbase4.hxx>
+#include <toolkit/unohlp.hxx>
+#include <vbahelper/helperdecl.hxx>
+#include <vcl/svapp.hxx>
+#include <vcl/window.hxx>
+
+#include "cellsuno.hxx"
+#include "convuno.hxx"
+
+using namespace ::com::sun::star;
+using namespace ::com::sun::star::script::vba::VBAEventId;
+using namespace ::ooo::vba;
+
+// ============================================================================
+
+typedef ::cppu::WeakImplHelper4<
+ awt::XWindowListener, util::XCloseListener, frame::XBorderResizeListener, util::XChangesListener > ScVbaEventsListener_BASE;
+
+// This class is to process Workbook window related event
+class ScVbaEventsListener : public ScVbaEventsListener_BASE
+{
+public :
+ ScVbaEventsListener( ScVbaEventsHelper& rVbaEvents, const uno::Reference< frame::XModel >& rxModel, ScDocShell* pDocShell );
+ virtual ~ScVbaEventsListener();
+
+ void startListening();
+ void stopListening();
+
+ // XWindowListener
+ virtual void SAL_CALL windowResized( const awt::WindowEvent& aEvent ) throw (uno::RuntimeException);
+ virtual void SAL_CALL windowMoved( const awt::WindowEvent& aEvent ) throw (uno::RuntimeException);
+ virtual void SAL_CALL windowShown( const lang::EventObject& aEvent ) throw (uno::RuntimeException);
+ virtual void SAL_CALL windowHidden( const lang::EventObject& aEvent ) throw (uno::RuntimeException);
+ virtual void SAL_CALL disposing( const lang::EventObject& aEvent ) throw (uno::RuntimeException);
+
+ // XCloseListener
+ virtual void SAL_CALL queryClosing( const lang::EventObject& Source, ::sal_Bool GetsOwnership ) throw (util::CloseVetoException, uno::RuntimeException);
+ virtual void SAL_CALL notifyClosing( const lang::EventObject& Source ) throw (uno::RuntimeException);
+
+ // XBorderResizeListener
+ virtual void SAL_CALL borderWidthsChanged( const uno::Reference< uno::XInterface >& aObject, const frame::BorderWidths& aNewSize ) throw (uno::RuntimeException);
+
+ // XChangesListener
+ virtual void SAL_CALL changesOccurred( const util::ChangesEvent& aEvent ) throw (uno::RuntimeException);
+
+private:
+ uno::Reference< frame::XFrame > getFrame();
+ uno::Reference< awt::XWindow > getContainerWindow();
+ bool isMouseReleased();
+ DECL_LINK( fireResizeMacro, void* );
+ void processWindowResizeMacro();
+
+private:
+ ::osl::Mutex maMutex;
+ ScVbaEventsHelper& mrVbaEvents;
+ uno::Reference< frame::XModel > mxModel;
+ ScDocShell* mpDocShell;
+ bool mbWindowResized;
+ bool mbBorderChanged;
+ bool mbDisposed;
+};
+
+// ----------------------------------------------------------------------------
+
+ScVbaEventsListener::ScVbaEventsListener( ScVbaEventsHelper& rVbaEvents, const uno::Reference< frame::XModel >& rxModel, ScDocShell* pDocShell ) :
+ mrVbaEvents( rVbaEvents ),
+ mxModel( rxModel ),
+ mpDocShell( pDocShell ),
+ mbWindowResized( false ),
+ mbBorderChanged( false ),
+ mbDisposed( !rxModel.is() )
+{
+ OSL_TRACE( "ScVbaEventsListener::ScVbaEventsListener( 0x%x ) - ctor ", this );
+}
+
+ScVbaEventsListener::~ScVbaEventsListener()
+{
+ OSL_TRACE( "ScVbaEventsListener::~ScVbaEventsListener( 0x%x ) - dtor ", this );
+ stopListening();
+}
+
+void ScVbaEventsListener::startListening()
+{
+ if( !mbDisposed )
+ {
+ // add window listener
+ try
+ {
+ uno::Reference< awt::XWindow > xWindow( getContainerWindow(), uno::UNO_QUERY_THROW );
+ xWindow->addWindowListener( this );
+ }
+ catch( uno::Exception& )
+ {
+ }
+ // add close listener
+ try
+ {
+ uno::Reference< util::XCloseBroadcaster > xCloseBroadcaster( mxModel, uno::UNO_QUERY_THROW );
+ xCloseBroadcaster->addCloseListener( this );
+ }
+ catch( uno::Exception& )
+ {
+ }
+ // add Border resize listener
+ try
+ {
+ uno::Reference< frame::XControllerBorder > xControllerBorder( mxModel->getCurrentController(), uno::UNO_QUERY_THROW );
+ xControllerBorder->addBorderResizeListener( this );
+ }
+ catch( uno::Exception& )
+ {
+ }
+ // add content change listener
+ try
+ {
+ uno::Reference< util::XChangesNotifier > xChangesNotifier( mxModel, uno::UNO_QUERY_THROW );
+ xChangesNotifier->addChangesListener( this );
+ }
+ catch( uno::Exception& )
+ {
+ }
+ }
+}
+
+void ScVbaEventsListener::stopListening()
+{
+ if( !mbDisposed )
+ {
+ try
+ {
+ uno::Reference< awt::XWindow > xWindow( getContainerWindow(), uno::UNO_QUERY_THROW );
+ xWindow->removeWindowListener( this );
+ }
+ catch( uno::Exception& )
+ {
+ }
+ try
+ {
+ uno::Reference< util::XCloseBroadcaster > xCloseBroadcaster( mxModel, uno::UNO_QUERY_THROW );
+ xCloseBroadcaster->removeCloseListener( this );
+ }
+ catch( uno::Exception& )
+ {
+ }
+ try
+ {
+ uno::Reference< frame::XControllerBorder > xControllerBorder( mxModel->getCurrentController(), uno::UNO_QUERY_THROW );
+ xControllerBorder->removeBorderResizeListener( this );
+ }
+ catch( uno::Exception& )
+ {
+ }
+ try
+ {
+ uno::Reference< util::XChangesNotifier > xChangesNotifier( mxModel, uno::UNO_QUERY_THROW );
+ xChangesNotifier->removeChangesListener( this );
+ }
+ catch( uno::Exception& )
+ {
+ }
+ }
+ mbDisposed = true;
+}
+
+void SAL_CALL ScVbaEventsListener::windowResized( const awt::WindowEvent& /*aEvent*/ ) throw ( uno::RuntimeException )
+{
+ ::osl::MutexGuard aGuard( maMutex );
+ // Workbook_window_resize event
+ mbWindowResized = true;
+ if( !mbDisposed && mbBorderChanged )
+ {
+ if( /*Window* pWindow =*/ VCLUnoHelper::GetWindow( getContainerWindow() ) )
+ {
+ mbBorderChanged = mbWindowResized = false;
+ acquire(); // ensure we don't get deleted before the event is handled
+ Application::PostUserEvent( LINK( this, ScVbaEventsListener, fireResizeMacro ), 0 );
+ }
+ }
+}
+
+void SAL_CALL ScVbaEventsListener::windowMoved( const awt::WindowEvent& /*aEvent*/ ) throw ( uno::RuntimeException )
+{
+ // not interest this time
+}
+
+void SAL_CALL ScVbaEventsListener::windowShown( const lang::EventObject& /*aEvent*/ ) throw ( uno::RuntimeException )
+{
+ // not interest this time
+}
+
+void SAL_CALL ScVbaEventsListener::windowHidden( const lang::EventObject& /*aEvent*/ ) throw ( uno::RuntimeException )
+{
+ // not interest this time
+}
+
+void SAL_CALL ScVbaEventsListener::disposing( const lang::EventObject& /*aEvent*/ ) throw ( uno::RuntimeException )
+{
+ ::osl::MutexGuard aGuard( maMutex );
+ OSL_TRACE( "ScVbaEventsListener::disposing( 0x%x )", this );
+ mbDisposed = true;
+}
+
+void SAL_CALL ScVbaEventsListener::queryClosing( const lang::EventObject& /*Source*/, sal_Bool /*GetsOwnership*/ ) throw (util::CloseVetoException, uno::RuntimeException)
+{
+ // it can cancel the close, but need to throw a CloseVetoException, and it will be transmit to caller.
+}
+
+void SAL_CALL ScVbaEventsListener::notifyClosing( const lang::EventObject& /*Source*/ ) throw (uno::RuntimeException)
+{
+ ::osl::MutexGuard aGuard( maMutex );
+ stopListening();
+}
+
+void SAL_CALL ScVbaEventsListener::borderWidthsChanged( const uno::Reference< uno::XInterface >& /*aObject*/, const frame::BorderWidths& /*aNewSize*/ ) throw (uno::RuntimeException)
+{
+ ::osl::MutexGuard aGuard( maMutex );
+ // work with WindowResized event to guard Window Resize event.
+ mbBorderChanged = true;
+ if( !mbDisposed && mbWindowResized )
+ {
+ if( /*Window* pWindow =*/ VCLUnoHelper::GetWindow( getContainerWindow() ) )
+ {
+ mbWindowResized = mbBorderChanged = false;
+ acquire(); // ensure we don't get deleted before the timer fires.
+ Application::PostUserEvent( LINK( this, ScVbaEventsListener, fireResizeMacro ), 0 );
+ }
+ }
+}
+
+void SAL_CALL ScVbaEventsListener::changesOccurred( const util::ChangesEvent& aEvent ) throw (uno::RuntimeException)
+{
+ sal_Int32 nCount = aEvent.Changes.getLength();
+ if( nCount == 0 )
+ return;
+
+ util::ElementChange aChange = aEvent.Changes[ 0 ];
+ rtl::OUString sOperation;
+ aChange.Accessor >>= sOperation;
+ if( !sOperation.equalsIgnoreAsciiCaseAscii("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.processVbaEvent( WORKSHEET_CHANGE, aArgs );
+ }
+ return;
+ }
+
+ ScRangeList aRangeList;
+ for( sal_Int32 nIndex = 0; nIndex < nCount; ++nIndex )
+ {
+ aChange = aEvent.Changes[ nIndex ];
+ aChange.Accessor >>= sOperation;
+ uno::Reference< table::XCellRange > xRangeObj;
+ aChange.ReplacedElement >>= xRangeObj;
+ if( xRangeObj.is() && sOperation.equalsIgnoreAsciiCaseAscii("cell-change") )
+ {
+ uno::Reference< sheet::XCellRangeAddressable > xCellRangeAddressable( xRangeObj, uno::UNO_QUERY );
+ if( xCellRangeAddressable.is() )
+ {
+ ScRange aRange;
+ ScUnoConversion::FillScRange( aRange, xCellRangeAddressable->getRangeAddress() );
+ aRangeList.Append( aRange );
+ }
+ }
+ }
+
+ if( (aRangeList.Count() > 0) && mpDocShell )
+ {
+ uno::Reference< sheet::XSheetCellRangeContainer > xRanges( new ScCellRangesObj( mpDocShell, aRangeList ) );
+ uno::Sequence< uno::Any > aArgs(1);
+ aArgs[0] <<= xRanges;
+ mrVbaEvents.processVbaEvent( WORKSHEET_CHANGE, aArgs );
+ }
+}
+
+// ----------------------------------------------------------------------------
+
+uno::Reference< frame::XFrame > ScVbaEventsListener::getFrame()
+{
+ if( !mbDisposed && mxModel.is() ) try
+ {
+ uno::Reference< frame::XController > xController( mxModel->getCurrentController(), uno::UNO_QUERY_THROW );
+ return xController->getFrame();
+ }
+ catch( uno::Exception& )
+ {
+ }
+ return uno::Reference< frame::XFrame >();
+}
+
+uno::Reference< awt::XWindow > ScVbaEventsListener::getContainerWindow()
+{
+ try
+ {
+ uno::Reference< frame::XFrame > xFrame( getFrame(), uno::UNO_SET_THROW );
+ return xFrame->getContainerWindow();
+ }
+ catch( uno::Exception& )
+ {
+ }
+ return uno::Reference< awt::XWindow >();
+}
+
+bool ScVbaEventsListener::isMouseReleased()
+{
+ if( Window* pWindow = VCLUnoHelper::GetWindow( getContainerWindow() ) )
+ {
+ Window::PointerState aPointerState = pWindow->GetPointerState();
+ return (aPointerState.mnState & ( MOUSE_LEFT | MOUSE_MIDDLE | MOUSE_RIGHT )) == 0;
+ }
+ return false;
+}
+
+IMPL_LINK( ScVbaEventsListener, fireResizeMacro, void*, EMPTYARG )
+{
+ if( !mbDisposed && isMouseReleased() )
+ processWindowResizeMacro();
+ release();
+ return 0;
+}
+
+void ScVbaEventsListener::processWindowResizeMacro()
+{
+ OSL_TRACE( "**** Attempt to FIRE MACRO **** " );
+ if( !mbDisposed )
+ mrVbaEvents.processVbaEvent( WORKBOOK_WINDOWRESIZE, uno::Sequence< uno::Any >() );
+}
+
+// ============================================================================
+
+ScVbaEventsHelper::ScVbaEventsHelper( const uno::Sequence< uno::Any >& rArgs, const uno::Reference< uno::XComponentContext >& xContext ) :
+ VbaEventsHelperBase( rArgs, xContext ),
+ mbOpened( false )
+{
+ mpDocShell = dynamic_cast< ScDocShell* >( mpShell ); // mpShell from base class
+ mpDoc = mpDocShell ? mpDocShell->GetDocument() : 0;
+
+ if( !mxModel.is() || !mpDocShell || !mpDoc )
+ return;
+
+#define REGISTER_EVENT( eventid, eventname, type, cancelindex, worksheet ) \
+ registerEventHandler( eventid, eventname, type, cancelindex, uno::Any( worksheet ) )
+
+#define REGISTER_WORKBOOK_EVENT( eventid, eventname, cancelindex ) \
+ REGISTER_EVENT( WORKBOOK_##eventid, "Workbook_" eventname, EVENTHANDLER_DOCUMENT, cancelindex, false )
+
+#define REGISTER_WORKSHEET_EVENT( eventid, eventname, cancelindex ) \
+ REGISTER_EVENT( WORKSHEET_##eventid, "Worksheet_" eventname, EVENTHANDLER_DOCUMENT, cancelindex, true ); \
+ REGISTER_EVENT( (USERDEFINED_START + WORKSHEET_##eventid), "Workbook_Sheet" eventname, EVENTHANDLER_DOCUMENT, (((cancelindex) >= 0) ? ((cancelindex) + 1) : -1), false )
+
+ // global
+ REGISTER_EVENT( AUTO_OPEN, "Auto_Open", EVENTHANDLER_GLOBAL, -1, false );
+ REGISTER_EVENT( AUTO_CLOSE, "Auto_Close", EVENTHANDLER_GLOBAL, -1, false );
+
+ // Workbook
+ REGISTER_WORKBOOK_EVENT( ACTIVATE, "Activate", -1 );
+ REGISTER_WORKBOOK_EVENT( DEACTIVATE, "Deactivate", -1 );
+ REGISTER_WORKBOOK_EVENT( OPEN, "Open", -1 );
+ REGISTER_WORKBOOK_EVENT( BEFORECLOSE, "BeforeClose", 0 );
+ REGISTER_WORKBOOK_EVENT( BEFOREPRINT, "BeforePrint", 0 );
+ REGISTER_WORKBOOK_EVENT( BEFORESAVE, "BeforeSave", 1 );
+ REGISTER_WORKBOOK_EVENT( AFTERSAVE, "AfterSave", -1 );
+ REGISTER_WORKBOOK_EVENT( NEWSHEET, "NewSheet", -1 );
+ REGISTER_WORKBOOK_EVENT( WINDOWACTIVATE, "WindowActivate", -1 );
+ REGISTER_WORKBOOK_EVENT( WINDOWDEACTIVATE, "WindowDeactivate", -1 );
+ REGISTER_WORKBOOK_EVENT( WINDOWRESIZE, "WindowResize", -1 );
+
+ // Worksheet events. All events have a corresponding workbook event.
+ REGISTER_WORKSHEET_EVENT( ACTIVATE, "Activate", -1 );
+ REGISTER_WORKSHEET_EVENT( DEACTIVATE, "Deactivate", -1 );
+ REGISTER_WORKSHEET_EVENT( BEFOREDOUBLECLICK, "BeforeDoubleClick", 1 );
+ REGISTER_WORKSHEET_EVENT( BEFORERIGHTCLICK, "BeforeRightClick", 1 );
+ REGISTER_WORKSHEET_EVENT( CALCULATE, "Calculate", -1 );
+ REGISTER_WORKSHEET_EVENT( CHANGE, "Change", -1 );
+ REGISTER_WORKSHEET_EVENT( SELECTIONCHANGE, "SelectionChange", -1 );
+ REGISTER_WORKSHEET_EVENT( FOLLOWHYPERLINK, "FollowHyperlink", -1 );
+
+#undef REGISTER_EVENT
+#undef REGISTER_WORKBOOK_EVENT
+#undef REGISTER_WORKSHEET_EVENT
+}
+
+ScVbaEventsHelper::~ScVbaEventsHelper()
+{
+}
+
+void SAL_CALL ScVbaEventsHelper::disposing( const lang::EventObject& rSource ) throw (uno::RuntimeException)
+{
+ mxListener.clear();
+ VbaEventsHelperBase::disposing( rSource );
+}
+
+// protected ------------------------------------------------------------------
+
+bool ScVbaEventsHelper::implEventsEnabled() throw (uno::RuntimeException)
+{
+ // document and document shell are needed during event processing
+ if( !mpDocShell || !mpDoc )
+ throw uno::RuntimeException();
+
+ // get Application object and check if events are enabled (this is an Excel-only attribute)
+ uno::Reference< excel::XApplication > xApplication( mxApplication.get(), uno::UNO_QUERY );
+ if( !xApplication.is() && mpShell )
+ {
+ uno::Any aVBAGlobals;
+ mpShell->GetBasicManager()->GetGlobalUNOConstant( "VBAGlobals", aVBAGlobals );
+ uno::Reference< XHelperInterface > xHelperInterface( aVBAGlobals, uno::UNO_QUERY );
+ if( xHelperInterface.is() )
+ {
+ xApplication.set( xHelperInterface->Application(), uno::UNO_QUERY );
+ mxApplication = xApplication;
+ }
+ }
+ if( !xApplication.is() )
+ throw uno::RuntimeException();
+
+ // return whether event processing is enabled
+ return xApplication->getEnableEvents();
+}
+
+bool ScVbaEventsHelper::implPrepareEvent( EventQueue& rEventQueue,
+ const EventHandlerInfo& rInfo, const uno::Sequence< uno::Any >& rArgs ) throw (uno::RuntimeException)
+{
+ // check preconditions for some events, add more events if needed
+ bool bExecuteEvent = true;
+ switch( rInfo.mnEventId )
+ {
+ case WORKBOOK_ACTIVATE:
+ // while loading, framework fires this before 'opened' event, delay it
+ bExecuteEvent = mbOpened;
+ break;
+ case WORKBOOK_OPEN:
+ bExecuteEvent = !mbOpened;
+ if( bExecuteEvent )
+ {
+ // execute delayed Activate event too (see above)
+ rEventQueue.push_back( WORKBOOK_ACTIVATE );
+ rEventQueue.push_back( WORKBOOK_WINDOWACTIVATE );
+ rEventQueue.push_back( AUTO_OPEN );
+ }
+ break;
+ case WORKSHEET_SELECTIONCHANGE:
+ // if selection is not changed, then do not fire the event
+ bExecuteEvent = mbOpened && isSelectionChanged( rArgs, 0 );
+ break;
+ }
+
+ // add workbook event associated to a sheet event
+ bool bSheetEvent = false;
+ rInfo.maUserData >>= bSheetEvent;
+ if( bSheetEvent && bExecuteEvent )
+ rEventQueue.push_back( EventQueueEntry( rInfo.mnEventId + USERDEFINED_START, rArgs ) );
+
+ return bExecuteEvent;
+}
+
+uno::Sequence< uno::Any > ScVbaEventsHelper::implBuildArgumentList( const EventHandlerInfo& rInfo,
+ const uno::Sequence< uno::Any >& rArgs ) throw (lang::IllegalArgumentException)
+{
+ // 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();
+ 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 /*bSuccess*/, bool bCancel ) throw (uno::RuntimeException)
+{
+ switch( rInfo.mnEventId )
+ {
+ case WORKBOOK_OPEN:
+ mbOpened = true;
+ // register the listeners
+ if( !mxListener.is() )
+ {
+ mxListener = new ScVbaEventsListener( *this, mxModel, mpDocShell );
+ mxListener->startListening();
+ }
+ 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.push_back( AUTO_CLOSE );
+ break;
+ }
+}
+
+::rtl::OUString ScVbaEventsHelper::implGetDocumentModuleName( const EventHandlerInfo& rInfo,
+ const uno::Sequence< uno::Any >& rArgs ) const throw (lang::IllegalArgumentException)
+{
+ bool bSheetEvent = false;
+ rInfo.maUserData >>= bSheetEvent;
+ SCTAB nTab = bSheetEvent ? getTabFromArgs( rArgs, 0 ) : -1;
+ if( bSheetEvent && (nTab < 0) )
+ throw lang::IllegalArgumentException();
+
+ String aCodeName;
+ if( bSheetEvent )
+ mpDoc->GetCodeName( nTab, aCodeName );
+ else
+ aCodeName = mpDoc->GetCodeName();
+ return aCodeName;
+}
+
+// private --------------------------------------------------------------------
+
+SCTAB ScVbaEventsHelper::getTabFromArgs( const uno::Sequence< uno::Any >& rArgs, sal_Int32 nIndex ) throw (lang::IllegalArgumentException)
+{
+ checkArgument( rArgs, nIndex );
+
+ // first try to extract a sheet index
+ SCTAB nTab = -1;
+ if( rArgs[ nIndex ] >>= nTab )
+ return nTab;
+
+ // next, try single range object
+ uno::Reference< sheet::XCellRangeAddressable > xCellRangeAddressable = getXSomethingFromArgs< sheet::XCellRangeAddressable >( rArgs, nIndex );
+ if( xCellRangeAddressable.is() )
+ return xCellRangeAddressable->getRangeAddress().Sheet;
+
+ // at last, try 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();
+}
+
+bool ScVbaEventsHelper::isSelectionChanged( const uno::Sequence< uno::Any >& rArgs, sal_Int32 nIndex ) throw (lang::IllegalArgumentException, uno::RuntimeException)
+{
+ uno::Reference< uno::XInterface > xNewSelection = getXSomethingFromArgs< uno::XInterface >( rArgs, nIndex, false );
+ if( ScCellRangesBase* pNewCellRanges = ScCellRangesBase::getImplementation( xNewSelection ) )
+ {
+ bool bChanged = maOldSelection != pNewCellRanges->GetRangeList();
+ maOldSelection = pNewCellRanges->GetRangeList();
+ return bChanged;
+ }
+ maOldSelection.Clear();
+ return true;
+}
+
+uno::Any ScVbaEventsHelper::createWorksheet( const uno::Sequence< uno::Any >& rArgs, sal_Int32 nIndex ) const
+ throw (lang::IllegalArgumentException, uno::RuntimeException)
+{
+ // Eventually we will be able to pull the Workbook/Worksheet objects
+ // directly from basic and register them as listeners
+
+ // extract sheet index, will throw, if parameter is invalid
+ SCTAB nTab = getTabFromArgs( rArgs, nIndex );
+
+ // create Workbook
+ uno::Sequence< uno::Any > aArgs( 2 );
+ aArgs[ 0 ] <<= uno::Reference< uno::XInterface >();
+ aArgs[ 1 ] <<= mxModel;
+ uno::Reference< uno::XInterface > xWorkbook( createVBAUnoAPIServiceWithArgs( mpShell, "ooo.vba.excel.Workbook", aArgs ), uno::UNO_SET_THROW );
+
+ // create WorkSheet
+ String aSheetName;
+ mpDoc->GetName( nTab, aSheetName );
+ aArgs = uno::Sequence< uno::Any >( 3 );
+ aArgs[ 0 ] <<= xWorkbook;
+ aArgs[ 1 ] <<= mxModel;
+ aArgs[ 2 ] <<= ::rtl::OUString( aSheetName );
+ uno::Reference< uno::XInterface > xWorksheet( createVBAUnoAPIServiceWithArgs( mpShell, "ooo.vba.excel.Worksheet", aArgs ), uno::UNO_SET_THROW );
+ return uno::Any( xWorksheet );
+}
+
+uno::Any ScVbaEventsHelper::createRange( const uno::Sequence< uno::Any >& rArgs, sal_Int32 nIndex ) const
+ throw (lang::IllegalArgumentException, uno::RuntimeException)
+{
+ 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 );
+ aArgs[ 0 ] <<= uno::Reference< uno::XInterface >(); // dummy parent
+ if ( xRanges.is() )
+ aArgs[ 1 ] <<= xRanges;
+ else
+ aArgs[ 1 ] <<= xRange;
+ uno::Reference< uno::XInterface > xVbaRange( createVBAUnoAPIServiceWithArgs( mpShell, "ooo.vba.excel.Range", aArgs ), uno::UNO_SET_THROW );
+ return uno::Any( xVbaRange );
+}
+
+uno::Any ScVbaEventsHelper::createHyperlink( const uno::Sequence< uno::Any >& rArgs, sal_Int32 nIndex ) const
+ throw (lang::IllegalArgumentException, uno::RuntimeException)
+{
+ uno::Sequence< uno::Any > aArgs( 2 );
+ aArgs[ 0 ] <<= uno::Reference< uno::XInterface >(); // dummy parent
+ aArgs[ 1 ] <<= getXSomethingFromArgs< table::XCell >( rArgs, nIndex, false );
+ 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 throw (uno::RuntimeException)
+{
+ uno::Sequence< uno::Any > aArgs( 2 );
+ aArgs[ 0 ] <<= createVBAUnoAPIService( mpShell, "ooo.vba.Application" );
+ aArgs[ 1 ] <<= mxModel;
+ uno::Reference< uno::XInterface > xWindow( createVBAUnoAPIServiceWithArgs( mpShell, "ooo.vba.excel.Window", aArgs ), uno::UNO_SET_THROW );
+ return uno::Any( xWindow );
+}
+
+// ============================================================================
+
+namespace vbaeventshelper
+{
+namespace sdecl = comphelper::service_decl;
+sdecl::class_<ScVbaEventsHelper, sdecl::with_args<true> > serviceImpl;
+extern sdecl::ServiceDecl const serviceDecl(
+ serviceImpl,
+ "ScVbaEventsHelper",
+ "com.sun.star.script.vba.VBASpreadsheetEventProcessor" );
+}
+
+// ============================================================================