fix baseline build (old cairo) - 'cairo_rectangle_int_t' does not name a type
[LibreOffice.git] / sc / source / ui / vba / vbaeventshelper.cxx
blobd92f6408400652c1a73f96732ccb7b172c294b84
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include "vbaeventshelper.hxx"
22 #include <com/sun/star/awt/XTopWindow.hpp>
23 #include <com/sun/star/awt/XTopWindowListener.hpp>
24 #include <com/sun/star/awt/XWindowListener.hpp>
25 #include <com/sun/star/frame/XBorderResizeListener.hpp>
26 #include <com/sun/star/frame/XControllerBorder.hpp>
27 #include <com/sun/star/script/ModuleType.hpp>
28 #include <com/sun/star/script/vba/VBAEventId.hpp>
29 #include <com/sun/star/sheet/XCellRangeAddressable.hpp>
30 #include <com/sun/star/sheet/XSheetCellRangeContainer.hpp>
31 #include <com/sun/star/table/XCellRange.hpp>
32 #include <com/sun/star/util/XChangesListener.hpp>
33 #include <com/sun/star/util/XChangesNotifier.hpp>
35 #include <cppuhelper/implbase4.hxx>
36 #include <toolkit/helper/vclunohelper.hxx>
37 #include <unotools/eventcfg.hxx>
38 #include <vcl/svapp.hxx>
39 #include <vcl/window.hxx>
41 #include "cellsuno.hxx"
42 #include "convuno.hxx"
43 #include "vbaapplication.hxx"
45 using namespace ::com::sun::star;
46 using namespace ::com::sun::star::script::vba::VBAEventId;
47 using namespace ::ooo::vba;
49 namespace {
51 /** Extracts a sheet index from the specified element of the passed sequence.
52 The element may be an integer, a Calc range or ranges object, or a VBA Range object. */
53 SCTAB lclGetTabFromArgs( const uno::Sequence< uno::Any >& rArgs, sal_Int32 nIndex ) throw (lang::IllegalArgumentException, uno::RuntimeException)
55 VbaEventsHelperBase::checkArgument( rArgs, nIndex );
57 // first try to extract a sheet index
58 sal_Int32 nTab = -1;
59 if( rArgs[ nIndex ] >>= nTab )
61 if( (nTab < 0) || (nTab > MAXTAB) )
62 throw lang::IllegalArgumentException();
63 return static_cast< SCTAB >( nTab );
66 // try VBA Range object
67 uno::Reference< excel::XRange > xVbaRange = getXSomethingFromArgs< excel::XRange >( rArgs, nIndex );
68 if( xVbaRange.is() )
70 uno::Reference< XHelperInterface > xVbaHelper( xVbaRange, uno::UNO_QUERY_THROW );
71 // TODO: in the future, the parent may be an excel::XChart (chart sheet) -> will there be a common base interface?
72 uno::Reference< excel::XWorksheet > xVbaSheet( xVbaHelper->getParent(), uno::UNO_QUERY_THROW );
73 // VBA sheet index is 1-based
74 return static_cast< SCTAB >( xVbaSheet->getIndex() - 1 );
77 // try single UNO range object
78 uno::Reference< sheet::XCellRangeAddressable > xCellRangeAddressable = getXSomethingFromArgs< sheet::XCellRangeAddressable >( rArgs, nIndex );
79 if( xCellRangeAddressable.is() )
80 return xCellRangeAddressable->getRangeAddress().Sheet;
82 // at last, try UNO range list
83 uno::Reference< sheet::XSheetCellRangeContainer > xRanges = getXSomethingFromArgs< sheet::XSheetCellRangeContainer >( rArgs, nIndex );
84 if( xRanges.is() )
86 uno::Sequence< table::CellRangeAddress > aRangeAddresses = xRanges->getRangeAddresses();
87 if( aRangeAddresses.getLength() > 0 )
88 return aRangeAddresses[ 0 ].Sheet;
91 throw lang::IllegalArgumentException();
94 /** Returns the AWT container window of the passed controller. */
95 uno::Reference< awt::XWindow > lclGetWindowForController( const uno::Reference< frame::XController >& rxController )
97 if( rxController.is() ) try
99 uno::Reference< frame::XFrame > xFrame( rxController->getFrame(), uno::UNO_SET_THROW );
100 return xFrame->getContainerWindow();
102 catch( uno::Exception& )
105 return 0;
108 } // namespace
110 typedef ::cppu::WeakImplHelper4< awt::XTopWindowListener, awt::XWindowListener, frame::XBorderResizeListener, util::XChangesListener > ScVbaEventListener_BASE;
112 // This class is to process Workbook window related event
113 class ScVbaEventListener : public ScVbaEventListener_BASE
115 public :
116 ScVbaEventListener( ScVbaEventsHelper& rVbaEvents, const uno::Reference< frame::XModel >& rxModel, ScDocShell* pDocShell );
117 virtual ~ScVbaEventListener();
119 /** Starts listening to the passed document controller. */
120 void startControllerListening( const uno::Reference< frame::XController >& rxController );
121 /** Stops listening to the passed document controller. */
122 void stopControllerListening( const uno::Reference< frame::XController >& rxController );
124 // XTopWindowListener
125 virtual void SAL_CALL windowOpened( const lang::EventObject& rEvent ) throw (uno::RuntimeException, std::exception) SAL_OVERRIDE;
126 virtual void SAL_CALL windowClosing( const lang::EventObject& rEvent ) throw (uno::RuntimeException, std::exception) SAL_OVERRIDE;
127 virtual void SAL_CALL windowClosed( const lang::EventObject& rEvent ) throw (uno::RuntimeException, std::exception) SAL_OVERRIDE;
128 virtual void SAL_CALL windowMinimized( const lang::EventObject& rEvent ) throw (uno::RuntimeException, std::exception) SAL_OVERRIDE;
129 virtual void SAL_CALL windowNormalized( const lang::EventObject& rEvent ) throw (uno::RuntimeException, std::exception) SAL_OVERRIDE;
130 virtual void SAL_CALL windowActivated( const lang::EventObject& rEvent ) throw (uno::RuntimeException, std::exception) SAL_OVERRIDE;
131 virtual void SAL_CALL windowDeactivated( const lang::EventObject& rEvent ) throw (uno::RuntimeException, std::exception) SAL_OVERRIDE;
133 // XWindowListener
134 virtual void SAL_CALL windowResized( const awt::WindowEvent& rEvent ) throw (uno::RuntimeException, std::exception) SAL_OVERRIDE;
135 virtual void SAL_CALL windowMoved( const awt::WindowEvent& rEvent ) throw (uno::RuntimeException, std::exception) SAL_OVERRIDE;
136 virtual void SAL_CALL windowShown( const lang::EventObject& rEvent ) throw (uno::RuntimeException, std::exception) SAL_OVERRIDE;
137 virtual void SAL_CALL windowHidden( const lang::EventObject& rEvent ) throw (uno::RuntimeException, std::exception) SAL_OVERRIDE;
139 // XBorderResizeListener
140 virtual void SAL_CALL borderWidthsChanged( const uno::Reference< uno::XInterface >& rSource, const frame::BorderWidths& aNewSize ) throw (uno::RuntimeException, std::exception) SAL_OVERRIDE;
142 // XChangesListener
143 virtual void SAL_CALL changesOccurred( const util::ChangesEvent& rEvent ) throw (uno::RuntimeException, std::exception) SAL_OVERRIDE;
145 // XEventListener
146 virtual void SAL_CALL disposing( const lang::EventObject& rEvent ) throw (uno::RuntimeException, std::exception) SAL_OVERRIDE;
148 private:
149 /** Starts listening to the document model. */
150 void startModelListening();
151 /** Stops listening to the document model. */
152 void stopModelListening();
154 /** Returns the controller for the passed VCL window. */
155 uno::Reference< frame::XController > getControllerForWindow( vcl::Window* pWindow ) const;
157 /** Calls the Workbook_Window[Activate|Deactivate] event handler. */
158 void processWindowActivateEvent( vcl::Window* pWindow, bool bActivate );
159 /** Posts a Workbook_WindowResize user event. */
160 void postWindowResizeEvent( vcl::Window* pWindow );
161 /** Callback link for Application::PostUserEvent(). */
162 DECL_LINK( processWindowResizeEvent, vcl::Window* );
164 private:
165 typedef ::std::map< VclPtr<vcl::Window>, uno::Reference< frame::XController > > WindowControllerMap;
167 ::osl::Mutex maMutex;
168 ScVbaEventsHelper& mrVbaEvents;
169 uno::Reference< frame::XModel > mxModel;
170 ScDocShell* mpDocShell;
171 WindowControllerMap maControllers; /// Maps VCL top windows to their controllers.
172 std::multiset< VclPtr<vcl::Window> > m_PostedWindows; /// Keeps processWindowResizeEvent windows from being deleted between postWindowResizeEvent and processWindowResizeEvent
173 VclPtr<vcl::Window> mpActiveWindow; /// Currently activated window, to prevent multiple (de)activation.
174 bool mbWindowResized; /// True = window resize system event processed.
175 bool mbBorderChanged; /// True = borders changed system event processed.
176 bool mbDisposed;
179 ScVbaEventListener::ScVbaEventListener( ScVbaEventsHelper& rVbaEvents, const uno::Reference< frame::XModel >& rxModel, ScDocShell* pDocShell ) :
180 mrVbaEvents( rVbaEvents ),
181 mxModel( rxModel ),
182 mpDocShell( pDocShell ),
183 mpActiveWindow( 0 ),
184 mbWindowResized( false ),
185 mbBorderChanged( false ),
186 mbDisposed( !rxModel.is() )
188 if( !mxModel.is() )
189 return;
191 startModelListening();
194 uno::Reference< frame::XController > xController( mxModel->getCurrentController(), uno::UNO_QUERY_THROW );
195 startControllerListening( xController );
197 catch( uno::Exception& )
202 ScVbaEventListener::~ScVbaEventListener()
206 void ScVbaEventListener::startControllerListening( const uno::Reference< frame::XController >& rxController )
208 ::osl::MutexGuard aGuard( maMutex );
210 uno::Reference< awt::XWindow > xWindow = lclGetWindowForController( rxController );
211 if( xWindow.is() )
212 try { xWindow->addWindowListener( this ); } catch( uno::Exception& ) {}
214 uno::Reference< awt::XTopWindow > xTopWindow( xWindow, uno::UNO_QUERY );
215 if( xTopWindow.is() )
216 try { xTopWindow->addTopWindowListener( this ); } catch( uno::Exception& ) {}
218 uno::Reference< frame::XControllerBorder > xControllerBorder( rxController, uno::UNO_QUERY );
219 if( xControllerBorder.is() )
220 try { xControllerBorder->addBorderResizeListener( this ); } catch( uno::Exception& ) {}
222 if( vcl::Window* pWindow = VCLUnoHelper::GetWindow( xWindow ) )
224 maControllers[ pWindow ] = rxController;
228 void ScVbaEventListener::stopControllerListening( const uno::Reference< frame::XController >& rxController )
230 ::osl::MutexGuard aGuard( maMutex );
232 uno::Reference< awt::XWindow > xWindow = lclGetWindowForController( rxController );
233 if( xWindow.is() )
234 try { xWindow->removeWindowListener( this ); } catch( uno::Exception& ) {}
236 uno::Reference< awt::XTopWindow > xTopWindow( xWindow, uno::UNO_QUERY );
237 if( xTopWindow.is() )
238 try { xTopWindow->removeTopWindowListener( this ); } catch( uno::Exception& ) {}
240 uno::Reference< frame::XControllerBorder > xControllerBorder( rxController, uno::UNO_QUERY );
241 if( xControllerBorder.is() )
242 try { xControllerBorder->removeBorderResizeListener( this ); } catch( uno::Exception& ) {}
244 if( vcl::Window* pWindow = VCLUnoHelper::GetWindow( xWindow ) )
246 maControllers.erase( pWindow );
247 if( pWindow == mpActiveWindow )
248 mpActiveWindow = 0;
252 void SAL_CALL ScVbaEventListener::windowOpened( const lang::EventObject& /*rEvent*/ ) throw (uno::RuntimeException, std::exception)
256 void SAL_CALL ScVbaEventListener::windowClosing( const lang::EventObject& /*rEvent*/ ) throw (uno::RuntimeException, std::exception)
260 void SAL_CALL ScVbaEventListener::windowClosed( const lang::EventObject& /*rEvent*/ ) throw (uno::RuntimeException, std::exception)
264 void SAL_CALL ScVbaEventListener::windowMinimized( const lang::EventObject& /*rEvent*/ ) throw (uno::RuntimeException, std::exception)
268 void SAL_CALL ScVbaEventListener::windowNormalized( const lang::EventObject& /*rEvent*/ ) throw (uno::RuntimeException, std::exception)
272 void SAL_CALL ScVbaEventListener::windowActivated( const lang::EventObject& rEvent ) throw (uno::RuntimeException, std::exception)
274 ::osl::MutexGuard aGuard( maMutex );
276 if( !mbDisposed )
278 uno::Reference< awt::XWindow > xWindow( rEvent.Source, uno::UNO_QUERY );
279 vcl::Window* pWindow = VCLUnoHelper::GetWindow( xWindow );
280 OSL_TRACE( "ScVbaEventListener::windowActivated - pWindow = 0x%p, mpActiveWindow = 0x%p", pWindow, mpActiveWindow.get() );
281 // do not fire activation event multiple time for the same window
282 if( pWindow && (pWindow != mpActiveWindow) )
284 // if another window is active, fire deactivation event first
285 if( mpActiveWindow )
286 processWindowActivateEvent( mpActiveWindow, false );
287 // fire activation event for the new window
288 processWindowActivateEvent( pWindow, true );
289 mpActiveWindow = pWindow;
294 void SAL_CALL ScVbaEventListener::windowDeactivated( const lang::EventObject& rEvent ) throw (uno::RuntimeException, std::exception)
296 ::osl::MutexGuard aGuard( maMutex );
298 if( !mbDisposed )
300 uno::Reference< awt::XWindow > xWindow( rEvent.Source, uno::UNO_QUERY );
301 vcl::Window* pWindow = VCLUnoHelper::GetWindow( xWindow );
302 OSL_TRACE( "ScVbaEventListener::windowDeactivated - pWindow = 0x%p, mpActiveWindow = 0x%p", pWindow, mpActiveWindow.get() );
303 // do not fire the deactivation event, if the window is not active (prevent multiple deactivation)
304 if( pWindow && (pWindow == mpActiveWindow) )
305 processWindowActivateEvent( pWindow, false );
306 // forget pointer to the active window
307 mpActiveWindow = 0;
311 void SAL_CALL ScVbaEventListener::windowResized( const awt::WindowEvent& rEvent ) throw (uno::RuntimeException, std::exception)
313 ::osl::MutexGuard aGuard( maMutex );
315 mbWindowResized = true;
316 if( !mbDisposed && mbBorderChanged )
318 uno::Reference< awt::XWindow > xWindow( rEvent.Source, uno::UNO_QUERY );
319 postWindowResizeEvent( VCLUnoHelper::GetWindow( xWindow ) );
323 void SAL_CALL ScVbaEventListener::windowMoved( const awt::WindowEvent& /*rEvent*/ ) throw (uno::RuntimeException, std::exception)
327 void SAL_CALL ScVbaEventListener::windowShown( const lang::EventObject& /*rEvent*/ ) throw (uno::RuntimeException, std::exception)
331 void SAL_CALL ScVbaEventListener::windowHidden( const lang::EventObject& /*rEvent*/ ) throw (uno::RuntimeException, std::exception)
335 void SAL_CALL ScVbaEventListener::borderWidthsChanged( const uno::Reference< uno::XInterface >& rSource, const frame::BorderWidths& /*aNewSize*/ ) throw (uno::RuntimeException, std::exception)
337 ::osl::MutexGuard aGuard( maMutex );
339 mbBorderChanged = true;
340 if( !mbDisposed && mbWindowResized )
342 uno::Reference< frame::XController > xController( rSource, uno::UNO_QUERY );
343 uno::Reference< awt::XWindow > xWindow = lclGetWindowForController( xController );
344 postWindowResizeEvent( VCLUnoHelper::GetWindow( xWindow ) );
348 void SAL_CALL ScVbaEventListener::changesOccurred( const util::ChangesEvent& rEvent ) throw (uno::RuntimeException, std::exception)
350 ::osl::MutexGuard aGuard( maMutex );
352 sal_Int32 nCount = rEvent.Changes.getLength();
353 if( mbDisposed || !mpDocShell || (nCount == 0) )
354 return;
356 util::ElementChange aChange = rEvent.Changes[ 0 ];
357 OUString sOperation;
358 aChange.Accessor >>= sOperation;
359 if( !sOperation.equalsIgnoreAsciiCase("cell-change") )
360 return;
362 if( nCount == 1 )
364 uno::Reference< table::XCellRange > xRangeObj;
365 aChange.ReplacedElement >>= xRangeObj;
366 if( xRangeObj.is() )
368 uno::Sequence< uno::Any > aArgs( 1 );
369 aArgs[0] <<= xRangeObj;
370 mrVbaEvents.processVbaEventNoThrow( WORKSHEET_CHANGE, aArgs );
372 return;
375 ScRangeList aRangeList;
376 for( sal_Int32 nIndex = 0; nIndex < nCount; ++nIndex )
378 aChange = rEvent.Changes[ nIndex ];
379 aChange.Accessor >>= sOperation;
380 uno::Reference< table::XCellRange > xRangeObj;
381 aChange.ReplacedElement >>= xRangeObj;
382 if( xRangeObj.is() && sOperation.equalsIgnoreAsciiCase("cell-change") )
384 uno::Reference< sheet::XCellRangeAddressable > xCellRangeAddressable( xRangeObj, uno::UNO_QUERY );
385 if( xCellRangeAddressable.is() )
387 ScRange aRange;
388 ScUnoConversion::FillScRange( aRange, xCellRangeAddressable->getRangeAddress() );
389 aRangeList.Append( aRange );
394 if (!aRangeList.empty())
396 uno::Reference< sheet::XSheetCellRangeContainer > xRanges( new ScCellRangesObj( mpDocShell, aRangeList ) );
397 uno::Sequence< uno::Any > aArgs(1);
398 aArgs[0] <<= xRanges;
399 mrVbaEvents.processVbaEventNoThrow( WORKSHEET_CHANGE, aArgs );
403 void SAL_CALL ScVbaEventListener::disposing( const lang::EventObject& rEvent ) throw (uno::RuntimeException, std::exception)
405 ::osl::MutexGuard aGuard( maMutex );
407 uno::Reference< frame::XModel > xModel( rEvent.Source, uno::UNO_QUERY );
408 if( xModel.is() )
410 OSL_ENSURE( xModel.get() == mxModel.get(), "ScVbaEventListener::disposing - disposing from unknown model" );
411 stopModelListening();
412 mbDisposed = true;
413 return;
416 uno::Reference< frame::XController > xController( rEvent.Source, uno::UNO_QUERY );
417 if( xController.is() )
419 stopControllerListening( xController );
420 return;
424 // private --------------------------------------------------------------------
426 void ScVbaEventListener::startModelListening()
430 uno::Reference< util::XChangesNotifier > xChangesNotifier( mxModel, uno::UNO_QUERY_THROW );
431 xChangesNotifier->addChangesListener( this );
433 catch( uno::Exception& )
438 void ScVbaEventListener::stopModelListening()
442 uno::Reference< util::XChangesNotifier > xChangesNotifier( mxModel, uno::UNO_QUERY_THROW );
443 xChangesNotifier->removeChangesListener( this );
445 catch( uno::Exception& )
450 uno::Reference< frame::XController > ScVbaEventListener::getControllerForWindow( vcl::Window* pWindow ) const
452 WindowControllerMap::const_iterator aIt = maControllers.find( pWindow );
453 return (aIt == maControllers.end()) ? uno::Reference< frame::XController >() : aIt->second;
456 void ScVbaEventListener::processWindowActivateEvent( vcl::Window* pWindow, bool bActivate )
458 uno::Reference< frame::XController > xController = getControllerForWindow( pWindow );
459 if( xController.is() )
461 uno::Sequence< uno::Any > aArgs( 1 );
462 aArgs[ 0 ] <<= xController;
463 mrVbaEvents.processVbaEventNoThrow( bActivate ? WORKBOOK_WINDOWACTIVATE : WORKBOOK_WINDOWDEACTIVATE, aArgs );
467 void ScVbaEventListener::postWindowResizeEvent( vcl::Window* pWindow )
469 // check that the passed window is still alive (it must be registered in maControllers)
470 if( pWindow && (maControllers.count( pWindow ) > 0) )
472 mbWindowResized = mbBorderChanged = false;
473 acquire(); // ensure we don't get deleted before the timer fires
474 m_PostedWindows.insert(pWindow);
475 Application::PostUserEvent( LINK( this, ScVbaEventListener, processWindowResizeEvent ), pWindow );
479 IMPL_LINK( ScVbaEventListener, processWindowResizeEvent, vcl::Window*, pWindow )
481 ::osl::MutexGuard aGuard( maMutex );
483 /* Check that the passed window is still alive (it must be registered in
484 maControllers). While closing a document, postWindowResizeEvent() may
485 be called on the last window which posts a user event via
486 Application::PostUserEvent to call this event handler. VCL will trigger
487 the handler some time later. Sometimes, the window gets deleted before.
488 This is handled via the disposing() function which removes the window
489 pointer from the member maControllers. Thus, checking whether
490 maControllers contains pWindow ensures that the window is still alive. */
491 if( !mbDisposed && pWindow && !pWindow->IsDisposed() && (maControllers.count(pWindow) > 0) )
493 // do not fire event unless all mouse buttons have been released
494 vcl::Window::PointerState aPointerState = pWindow->GetPointerState();
495 if( (aPointerState.mnState & (MOUSE_LEFT | MOUSE_MIDDLE | MOUSE_RIGHT)) == 0 )
497 uno::Reference< frame::XController > xController = getControllerForWindow( pWindow );
498 if( xController.is() )
500 uno::Sequence< uno::Any > aArgs( 1 );
501 aArgs[ 0 ] <<= xController;
502 // #163419# do not throw exceptions into application core
503 mrVbaEvents.processVbaEventNoThrow( WORKBOOK_WINDOWRESIZE, aArgs );
508 // note: there may be multiple processWindowResizeEvent outstanding
509 // for pWindow, so it may have been added to m_PostedWindows multiple
510 // times - so this must delete exactly one of these elements!
511 auto const iter(m_PostedWindows.find(pWindow));
512 assert(iter != m_PostedWindows.end());
513 m_PostedWindows.erase(iter);
515 release();
516 return 0;
519 ScVbaEventsHelper::ScVbaEventsHelper( const uno::Sequence< uno::Any >& rArgs, const uno::Reference< uno::XComponentContext >& xContext ) :
520 VbaEventsHelperBase( rArgs, xContext ),
521 mbOpened( false )
523 mpDocShell = dynamic_cast< ScDocShell* >( mpShell ); // mpShell from base class
524 mpDoc = mpDocShell ? &mpDocShell->GetDocument() : 0;
526 if( !mxModel.is() || !mpDocShell || !mpDoc )
527 return;
529 #define REGISTER_EVENT( eventid, moduletype, classname, eventname, cancelindex, worksheet ) \
530 registerEventHandler( eventid, moduletype, classname "_" eventname, cancelindex, uno::Any( worksheet ) )
531 #define REGISTER_AUTO_EVENT( eventid, eventname ) \
532 REGISTER_EVENT( AUTO_##eventid, script::ModuleType::NORMAL, "Auto", eventname, -1, false )
533 #define REGISTER_WORKBOOK_EVENT( eventid, eventname, cancelindex ) \
534 REGISTER_EVENT( WORKBOOK_##eventid, script::ModuleType::DOCUMENT, "Workbook", eventname, cancelindex, false )
535 #define REGISTER_WORKSHEET_EVENT( eventid, eventname, cancelindex ) \
536 REGISTER_EVENT( WORKSHEET_##eventid, script::ModuleType::DOCUMENT, "Worksheet", eventname, cancelindex, true ); \
537 REGISTER_EVENT( (USERDEFINED_START + WORKSHEET_##eventid), script::ModuleType::DOCUMENT, "Workbook", "Sheet" eventname, (((cancelindex) >= 0) ? ((cancelindex) + 1) : -1), false )
539 // global
540 REGISTER_AUTO_EVENT( OPEN, "Open" );
541 REGISTER_AUTO_EVENT( CLOSE, "Close" );
543 // Workbook
544 REGISTER_WORKBOOK_EVENT( ACTIVATE, "Activate", -1 );
545 REGISTER_WORKBOOK_EVENT( DEACTIVATE, "Deactivate", -1 );
546 REGISTER_WORKBOOK_EVENT( OPEN, "Open", -1 );
547 REGISTER_WORKBOOK_EVENT( BEFORECLOSE, "BeforeClose", 0 );
548 REGISTER_WORKBOOK_EVENT( BEFOREPRINT, "BeforePrint", 0 );
549 REGISTER_WORKBOOK_EVENT( BEFORESAVE, "BeforeSave", 1 );
550 REGISTER_WORKBOOK_EVENT( AFTERSAVE, "AfterSave", -1 );
551 REGISTER_WORKBOOK_EVENT( NEWSHEET, "NewSheet", -1 );
552 REGISTER_WORKBOOK_EVENT( WINDOWACTIVATE, "WindowActivate", -1 );
553 REGISTER_WORKBOOK_EVENT( WINDOWDEACTIVATE, "WindowDeactivate", -1 );
554 REGISTER_WORKBOOK_EVENT( WINDOWRESIZE, "WindowResize", -1 );
556 // Worksheet events. All events have a corresponding workbook event.
557 REGISTER_WORKSHEET_EVENT( ACTIVATE, "Activate", -1 );
558 REGISTER_WORKSHEET_EVENT( DEACTIVATE, "Deactivate", -1 );
559 REGISTER_WORKSHEET_EVENT( BEFOREDOUBLECLICK, "BeforeDoubleClick", 1 );
560 REGISTER_WORKSHEET_EVENT( BEFORERIGHTCLICK, "BeforeRightClick", 1 );
561 REGISTER_WORKSHEET_EVENT( CALCULATE, "Calculate", -1 );
562 REGISTER_WORKSHEET_EVENT( CHANGE, "Change", -1 );
563 REGISTER_WORKSHEET_EVENT( SELECTIONCHANGE, "SelectionChange", -1 );
564 REGISTER_WORKSHEET_EVENT( FOLLOWHYPERLINK, "FollowHyperlink", -1 );
566 #undef REGISTER_WORKSHEET_EVENT
567 #undef REGISTER_WORKBOOK_EVENT
568 #undef REGISTER_AUTO_EVENT
569 #undef REGISTER_EVENT
572 ScVbaEventsHelper::~ScVbaEventsHelper()
576 void SAL_CALL ScVbaEventsHelper::notifyEvent( const css::document::EventObject& rEvent ) throw (css::uno::RuntimeException, std::exception)
578 static const uno::Sequence< uno::Any > saEmptyArgs;
579 if( (rEvent.EventName == GlobalEventConfig::GetEventName( GlobalEventId::OPENDOC )) ||
580 (rEvent.EventName == GlobalEventConfig::GetEventName( GlobalEventId::CREATEDOC )) ) // CREATEDOC triggered e.g. during VBA Workbooks.Add
582 processVbaEventNoThrow( WORKBOOK_OPEN, saEmptyArgs );
584 else if( rEvent.EventName == GlobalEventConfig::GetEventName( GlobalEventId::ACTIVATEDOC ) )
586 processVbaEventNoThrow( WORKBOOK_ACTIVATE, saEmptyArgs );
588 else if( rEvent.EventName == GlobalEventConfig::GetEventName( GlobalEventId::DEACTIVATEDOC ) )
590 processVbaEventNoThrow( WORKBOOK_DEACTIVATE, saEmptyArgs );
592 else if( (rEvent.EventName == GlobalEventConfig::GetEventName( GlobalEventId::SAVEDOCDONE )) ||
593 (rEvent.EventName == GlobalEventConfig::GetEventName( GlobalEventId::SAVEASDOCDONE )) ||
594 (rEvent.EventName == GlobalEventConfig::GetEventName( GlobalEventId::SAVETODOCDONE )) )
596 uno::Sequence< uno::Any > aArgs( 1 );
597 aArgs[ 0 ] <<= true;
598 processVbaEventNoThrow( WORKBOOK_AFTERSAVE, aArgs );
600 else if( (rEvent.EventName == GlobalEventConfig::GetEventName( GlobalEventId::SAVEDOCFAILED )) ||
601 (rEvent.EventName == GlobalEventConfig::GetEventName( GlobalEventId::SAVEASDOCFAILED )) ||
602 (rEvent.EventName == GlobalEventConfig::GetEventName( GlobalEventId::SAVETODOCFAILED )) )
604 uno::Sequence< uno::Any > aArgs( 1 );
605 aArgs[ 0 ] <<= false;
606 processVbaEventNoThrow( WORKBOOK_AFTERSAVE, aArgs );
608 else if( rEvent.EventName == GlobalEventConfig::GetEventName( GlobalEventId::CLOSEDOC ) )
610 /* Trigger the WORKBOOK_WINDOWDEACTIVATE and WORKBOOK_DEACTIVATE
611 events and stop listening to the model (done in base class). */
612 uno::Reference< frame::XController > xController( mxModel->getCurrentController() );
613 if( xController.is() )
615 uno::Sequence< uno::Any > aArgs( 1 );
616 aArgs[ 0 ] <<= xController;
617 processVbaEventNoThrow( WORKBOOK_WINDOWDEACTIVATE, aArgs );
619 processVbaEventNoThrow( WORKBOOK_DEACTIVATE, saEmptyArgs );
621 else if( rEvent.EventName == GlobalEventConfig::GetEventName( GlobalEventId::VIEWCREATED ) )
623 uno::Reference< frame::XController > xController( mxModel->getCurrentController() );
624 if( mxListener.get() && xController.is() )
625 mxListener->startControllerListening( xController );
627 VbaEventsHelperBase::notifyEvent( rEvent );
630 OUString ScVbaEventsHelper::getImplementationName()
631 throw (css::uno::RuntimeException, std::exception)
633 return OUString("ScVbaEventsHelper");
636 css::uno::Sequence<OUString> ScVbaEventsHelper::getSupportedServiceNames()
637 throw (css::uno::RuntimeException, std::exception)
639 return css::uno::Sequence<OUString>{
640 "com.sun.star.script.vba.VBASpreadsheetEventProcessor"};
643 // protected ------------------------------------------------------------------
645 bool ScVbaEventsHelper::implPrepareEvent( EventQueue& rEventQueue,
646 const EventHandlerInfo& rInfo, const uno::Sequence< uno::Any >& rArgs ) throw (uno::RuntimeException)
648 // document and document shell are needed during event processing
649 if( !mpShell || !mpDoc )
650 throw uno::RuntimeException();
652 /* For document events: check if events are enabled via the
653 Application.EnableEvents symbol (this is an Excel-only attribute).
654 Check this again for every event, as the event handler may change the
655 state of the EnableEvents symbol. Global events such as AUTO_OPEN and
656 AUTO_CLOSE are always enabled. */
657 bool bExecuteEvent = (rInfo.mnModuleType != script::ModuleType::DOCUMENT) || ScVbaApplication::getDocumentEventsEnabled();
659 // framework and Calc fire a few events before 'OnLoad', ignore them
660 if( bExecuteEvent )
661 bExecuteEvent = (rInfo.mnEventId == WORKBOOK_OPEN) ? !mbOpened : mbOpened;
663 // special handling for some events
664 if( bExecuteEvent ) switch( rInfo.mnEventId )
666 case WORKBOOK_OPEN:
668 // execute delayed Activate event too (see above)
669 rEventQueue.push_back( WORKBOOK_ACTIVATE );
670 uno::Sequence< uno::Any > aArgs( 1 );
671 aArgs[ 0 ] <<= mxModel->getCurrentController();
672 rEventQueue.push_back( EventQueueEntry( WORKBOOK_WINDOWACTIVATE, aArgs ) );
673 rEventQueue.push_back( AUTO_OPEN );
674 // remember initial selection
675 maOldSelection <<= mxModel->getCurrentSelection();
677 break;
678 case WORKSHEET_SELECTIONCHANGE:
679 // if selection is not changed, then do not fire the event
680 bExecuteEvent = isSelectionChanged( rArgs, 0 );
681 break;
684 if( bExecuteEvent )
686 // add workbook event associated to a sheet event
687 bool bSheetEvent = false;
688 if( (rInfo.maUserData >>= bSheetEvent) && bSheetEvent )
689 rEventQueue.push_back( EventQueueEntry( rInfo.mnEventId + USERDEFINED_START, rArgs ) );
692 return bExecuteEvent;
695 uno::Sequence< uno::Any > ScVbaEventsHelper::implBuildArgumentList( const EventHandlerInfo& rInfo,
696 const uno::Sequence< uno::Any >& rArgs ) throw (lang::IllegalArgumentException, uno::RuntimeException)
698 // fill arguments for workbook events associated to sheet events according to sheet events, sheet will be added below
699 bool bSheetEventAsBookEvent = rInfo.mnEventId > USERDEFINED_START;
700 sal_Int32 nEventId = bSheetEventAsBookEvent ? (rInfo.mnEventId - USERDEFINED_START) : rInfo.mnEventId;
702 uno::Sequence< uno::Any > aVbaArgs;
703 switch( nEventId )
705 // *** Workbook ***
707 // no arguments
708 case WORKBOOK_ACTIVATE:
709 case WORKBOOK_DEACTIVATE:
710 case WORKBOOK_OPEN:
711 break;
712 // 1 arg: cancel
713 case WORKBOOK_BEFORECLOSE:
714 case WORKBOOK_BEFOREPRINT:
715 aVbaArgs.realloc( 1 );
716 // current cancel state will be inserted by caller
717 break;
718 // 2 args: saveAs, cancel
719 case WORKBOOK_BEFORESAVE:
720 aVbaArgs.realloc( 2 );
721 checkArgumentType< bool >( rArgs, 0 );
722 aVbaArgs[ 0 ] = rArgs[ 0 ];
723 // current cancel state will be inserted by caller
724 break;
725 // 1 arg: success
726 case WORKBOOK_AFTERSAVE:
727 aVbaArgs.realloc( 1 );
728 checkArgumentType< bool >( rArgs, 0 );
729 aVbaArgs[ 0 ] = rArgs[ 0 ];
730 break;
731 // 1 arg: window
732 case WORKBOOK_WINDOWACTIVATE:
733 case WORKBOOK_WINDOWDEACTIVATE:
734 case WORKBOOK_WINDOWRESIZE:
735 aVbaArgs.realloc( 1 );
736 aVbaArgs[ 0 ] = createWindow( rArgs, 0 );
737 break;
738 // 1 arg: worksheet
739 case WORKBOOK_NEWSHEET:
740 aVbaArgs.realloc( 1 );
741 aVbaArgs[ 0 ] = createWorksheet( rArgs, 0 );
742 break;
744 // *** Worksheet ***
746 // no arguments
747 case WORKSHEET_ACTIVATE:
748 case WORKSHEET_CALCULATE:
749 case WORKSHEET_DEACTIVATE:
750 break;
751 // 1 arg: range
752 case WORKSHEET_CHANGE:
753 case WORKSHEET_SELECTIONCHANGE:
754 aVbaArgs.realloc( 1 );
755 aVbaArgs[ 0 ] = createRange( rArgs, 0 );
756 break;
757 // 2 args: range, cancel
758 case WORKSHEET_BEFOREDOUBLECLICK:
759 case WORKSHEET_BEFORERIGHTCLICK:
760 aVbaArgs.realloc( 2 );
761 aVbaArgs[ 0 ] = createRange( rArgs, 0 );
762 // current cancel state will be inserted by caller
763 break;
764 // 1 arg: hyperlink
765 case WORKSHEET_FOLLOWHYPERLINK:
766 aVbaArgs.realloc( 1 );
767 aVbaArgs[ 0 ] = createHyperlink( rArgs, 0 );
768 break;
771 /* For workbook events associated to sheet events, the workbook event gets
772 the same arguments but with a Worksheet object in front of them. */
773 if( bSheetEventAsBookEvent )
775 sal_Int32 nLength = aVbaArgs.getLength();
776 uno::Sequence< uno::Any > aVbaArgs2( nLength + 1 );
777 aVbaArgs2[ 0 ] = createWorksheet( rArgs, 0 );
778 for( sal_Int32 nIndex = 0; nIndex < nLength; ++nIndex )
779 aVbaArgs2[ nIndex + 1 ] = aVbaArgs[ nIndex ];
780 aVbaArgs = aVbaArgs2;
783 return aVbaArgs;
786 void ScVbaEventsHelper::implPostProcessEvent( EventQueue& rEventQueue,
787 const EventHandlerInfo& rInfo, bool bCancel ) throw (uno::RuntimeException)
789 switch( rInfo.mnEventId )
791 case WORKBOOK_OPEN:
792 mbOpened = true;
793 // register the listeners
794 if( !mxListener.is() )
795 mxListener = new ScVbaEventListener( *this, mxModel, mpDocShell );
796 break;
797 case WORKBOOK_BEFORECLOSE:
798 /* Execute Auto_Close only if not cancelled by event handler, but
799 before UI asks user whether to cancel closing the document. */
800 if( !bCancel )
801 rEventQueue.push_back( AUTO_CLOSE );
802 break;
806 OUString ScVbaEventsHelper::implGetDocumentModuleName( const EventHandlerInfo& rInfo,
807 const uno::Sequence< uno::Any >& rArgs ) const
808 throw (lang::IllegalArgumentException, uno::RuntimeException)
810 bool bSheetEvent = false;
811 rInfo.maUserData >>= bSheetEvent;
812 SCTAB nTab = bSheetEvent ? lclGetTabFromArgs( rArgs, 0 ) : -1;
813 if( bSheetEvent && (nTab < 0) )
814 throw lang::IllegalArgumentException();
816 OUString aCodeName;
817 if( bSheetEvent )
818 mpDoc->GetCodeName( nTab, aCodeName );
819 else
820 aCodeName = mpDoc->GetCodeName();
821 return aCodeName;
824 // private --------------------------------------------------------------------
826 namespace {
828 /** Compares the passed range lists representing sheet selections. Ignores
829 selections that refer to different sheets (returns false in this case). */
830 bool lclSelectionChanged( const ScRangeList& rLeft, const ScRangeList& rRight )
832 // one of the range lists empty? -> return false, if both lists empty
833 bool bLeftEmpty = rLeft.empty();
834 bool bRightEmpty = rRight.empty();
835 if( bLeftEmpty || bRightEmpty )
836 return !(bLeftEmpty && bRightEmpty);
838 // check sheet indexes of the range lists (assuming that all ranges in a list are on the same sheet)
839 if (rLeft[0]->aStart.Tab() != rRight[0]->aStart.Tab())
840 return false;
842 // compare all ranges
843 return rLeft != rRight;
846 } // namespace
848 bool ScVbaEventsHelper::isSelectionChanged( const uno::Sequence< uno::Any >& rArgs, sal_Int32 nIndex ) throw (lang::IllegalArgumentException, uno::RuntimeException)
850 uno::Reference< uno::XInterface > xOldSelection( maOldSelection, uno::UNO_QUERY );
851 uno::Reference< uno::XInterface > xNewSelection = getXSomethingFromArgs< uno::XInterface >( rArgs, nIndex, false );
852 ScCellRangesBase* pOldCellRanges = ScCellRangesBase::getImplementation( xOldSelection );
853 ScCellRangesBase* pNewCellRanges = ScCellRangesBase::getImplementation( xNewSelection );
854 bool bChanged = !pOldCellRanges || !pNewCellRanges || lclSelectionChanged( pOldCellRanges->GetRangeList(), pNewCellRanges->GetRangeList() );
855 maOldSelection <<= xNewSelection;
856 return bChanged;
859 uno::Any ScVbaEventsHelper::createWorksheet( const uno::Sequence< uno::Any >& rArgs, sal_Int32 nIndex ) const
860 throw (lang::IllegalArgumentException, uno::RuntimeException)
862 // extract sheet index, will throw, if parameter is invalid
863 SCTAB nTab = lclGetTabFromArgs( rArgs, nIndex );
864 return uno::Any( excel::getUnoSheetModuleObj( mxModel, nTab ) );
867 uno::Any ScVbaEventsHelper::createRange( const uno::Sequence< uno::Any >& rArgs, sal_Int32 nIndex ) const
868 throw (lang::IllegalArgumentException, uno::RuntimeException)
870 // it is possible to pass an existing VBA Range object
871 uno::Reference< excel::XRange > xVbaRange = getXSomethingFromArgs< excel::XRange >( rArgs, nIndex );
872 if( !xVbaRange.is() )
874 uno::Reference< sheet::XSheetCellRangeContainer > xRanges = getXSomethingFromArgs< sheet::XSheetCellRangeContainer >( rArgs, nIndex );
875 uno::Reference< table::XCellRange > xRange = getXSomethingFromArgs< table::XCellRange >( rArgs, nIndex );
876 if ( !xRanges.is() && !xRange.is() )
877 throw lang::IllegalArgumentException();
879 uno::Sequence< uno::Any > aArgs( 2 );
880 if ( xRanges.is() )
882 aArgs[ 0 ] <<= excel::getUnoSheetModuleObj( xRanges );
883 aArgs[ 1 ] <<= xRanges;
885 else
887 aArgs[ 0 ] <<= excel::getUnoSheetModuleObj( xRange );
888 aArgs[ 1 ] <<= xRange;
890 xVbaRange.set( createVBAUnoAPIServiceWithArgs( mpShell, "ooo.vba.excel.Range", aArgs ), uno::UNO_QUERY_THROW );
892 return uno::Any( xVbaRange );
895 uno::Any ScVbaEventsHelper::createHyperlink( const uno::Sequence< uno::Any >& rArgs, sal_Int32 nIndex ) const
896 throw (lang::IllegalArgumentException, uno::RuntimeException)
898 uno::Reference< table::XCell > xCell = getXSomethingFromArgs< table::XCell >( rArgs, nIndex, false );
899 uno::Sequence< uno::Any > aArgs( 2 );
900 aArgs[ 0 ] <<= excel::getUnoSheetModuleObj( xCell );
901 aArgs[ 1 ] <<= xCell;
902 uno::Reference< uno::XInterface > xHyperlink( createVBAUnoAPIServiceWithArgs( mpShell, "ooo.vba.excel.Hyperlink", aArgs ), uno::UNO_SET_THROW );
903 return uno::Any( xHyperlink );
906 uno::Any ScVbaEventsHelper::createWindow( const uno::Sequence< uno::Any >& rArgs, sal_Int32 nIndex ) const
907 throw (lang::IllegalArgumentException, uno::RuntimeException)
909 uno::Sequence< uno::Any > aArgs( 3 );
910 aArgs[ 0 ] <<= getVBADocument( mxModel );
911 aArgs[ 1 ] <<= mxModel;
912 aArgs[ 2 ] <<= getXSomethingFromArgs< frame::XController >( rArgs, nIndex, false );
913 uno::Reference< uno::XInterface > xWindow( createVBAUnoAPIServiceWithArgs( mpShell, "ooo.vba.excel.Window", aArgs ), uno::UNO_SET_THROW );
914 return uno::Any( xWindow );
917 extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface * SAL_CALL
918 ScVbaEventsHelper_get_implementation(
919 css::uno::XComponentContext *context,
920 css::uno::Sequence<css::uno::Any> const &arguments)
922 return cppu::acquire(new ScVbaEventsHelper(arguments, context));
925 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */