Line data Source code
1 : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 : /*
3 : * This file is part of the LibreOffice project.
4 : *
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/.
8 : *
9 : * This file incorporates work covered by the following license notice:
10 : *
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 .
18 : */
19 :
20 : #include "vbaeventshelper.hxx"
21 :
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>
34 :
35 : #include <cppuhelper/implbase4.hxx>
36 : #include <toolkit/helper/vclunohelper.hxx>
37 : #include <unotools/eventcfg.hxx>
38 : #include <vbahelper/helperdecl.hxx>
39 : #include <vcl/svapp.hxx>
40 : #include <vcl/window.hxx>
41 :
42 : #include "cellsuno.hxx"
43 : #include "convuno.hxx"
44 : #include "vbaapplication.hxx"
45 :
46 : using namespace ::com::sun::star;
47 : using namespace ::com::sun::star::script::vba::VBAEventId;
48 : using namespace ::ooo::vba;
49 :
50 :
51 : // ============================================================================
52 :
53 : namespace {
54 :
55 : /** Extracts a sheet index from the specified element of the passed sequence.
56 : The element may be an integer, a Calc range or ranges object, or a VBA Range object. */
57 1290 : SCTAB lclGetTabFromArgs( const uno::Sequence< uno::Any >& rArgs, sal_Int32 nIndex ) throw (lang::IllegalArgumentException)
58 : {
59 1290 : VbaEventsHelperBase::checkArgument( rArgs, nIndex );
60 :
61 : // first try to extract a sheet index
62 1290 : sal_Int32 nTab = -1;
63 1290 : if( rArgs[ nIndex ] >>= nTab )
64 : {
65 662 : if( (nTab < 0) || (nTab > MAXTAB) )
66 0 : throw lang::IllegalArgumentException();
67 662 : return static_cast< SCTAB >( nTab );
68 : }
69 :
70 : // try VBA Range object
71 628 : uno::Reference< excel::XRange > xVbaRange = getXSomethingFromArgs< excel::XRange >( rArgs, nIndex );
72 628 : if( xVbaRange.is() )
73 : {
74 547 : uno::Reference< XHelperInterface > xVbaHelper( xVbaRange, uno::UNO_QUERY_THROW );
75 : // TODO: in the future, the parent may be an excel::XChart (chart sheet) -> will there be a common base interface?
76 1094 : uno::Reference< excel::XWorksheet > xVbaSheet( xVbaHelper->getParent(), uno::UNO_QUERY_THROW );
77 : // VBA sheet index is 1-based
78 1094 : return static_cast< SCTAB >( xVbaSheet->getIndex() - 1 );
79 : }
80 :
81 : // try single UNO range object
82 162 : uno::Reference< sheet::XCellRangeAddressable > xCellRangeAddressable = getXSomethingFromArgs< sheet::XCellRangeAddressable >( rArgs, nIndex );
83 81 : if( xCellRangeAddressable.is() )
84 70 : return xCellRangeAddressable->getRangeAddress().Sheet;
85 :
86 : // at last, try UNO range list
87 22 : uno::Reference< sheet::XSheetCellRangeContainer > xRanges = getXSomethingFromArgs< sheet::XSheetCellRangeContainer >( rArgs, nIndex );
88 11 : if( xRanges.is() )
89 : {
90 3 : uno::Sequence< table::CellRangeAddress > aRangeAddresses = xRanges->getRangeAddresses();
91 3 : if( aRangeAddresses.getLength() > 0 )
92 3 : return aRangeAddresses[ 0 ].Sheet;
93 : }
94 :
95 636 : throw lang::IllegalArgumentException();
96 : }
97 :
98 : /** Returns the AWT container window of the passed controller. */
99 52 : uno::Reference< awt::XWindow > lclGetWindowForController( const uno::Reference< frame::XController >& rxController )
100 : {
101 52 : if( rxController.is() ) try
102 : {
103 52 : uno::Reference< frame::XFrame > xFrame( rxController->getFrame(), uno::UNO_SET_THROW );
104 52 : return xFrame->getContainerWindow();
105 : }
106 0 : catch( uno::Exception& )
107 : {
108 : }
109 0 : return 0;
110 : }
111 :
112 : } // namespace
113 :
114 : // ============================================================================
115 :
116 : typedef ::cppu::WeakImplHelper4< awt::XTopWindowListener, awt::XWindowListener, frame::XBorderResizeListener, util::XChangesListener > ScVbaEventListener_BASE;
117 :
118 : // This class is to process Workbook window related event
119 : class ScVbaEventListener : public ScVbaEventListener_BASE
120 : {
121 : public :
122 : ScVbaEventListener( ScVbaEventsHelper& rVbaEvents, const uno::Reference< frame::XModel >& rxModel, ScDocShell* pDocShell );
123 : virtual ~ScVbaEventListener();
124 :
125 : /** Starts listening to the passed document controller. */
126 : void startControllerListening( const uno::Reference< frame::XController >& rxController );
127 : /** Stops listening to the passed document controller. */
128 : void stopControllerListening( const uno::Reference< frame::XController >& rxController );
129 :
130 : // XTopWindowListener
131 : virtual void SAL_CALL windowOpened( const lang::EventObject& rEvent ) throw (uno::RuntimeException);
132 : virtual void SAL_CALL windowClosing( const lang::EventObject& rEvent ) throw (uno::RuntimeException);
133 : virtual void SAL_CALL windowClosed( const lang::EventObject& rEvent ) throw (uno::RuntimeException);
134 : virtual void SAL_CALL windowMinimized( const lang::EventObject& rEvent ) throw (uno::RuntimeException);
135 : virtual void SAL_CALL windowNormalized( const lang::EventObject& rEvent ) throw (uno::RuntimeException);
136 : virtual void SAL_CALL windowActivated( const lang::EventObject& rEvent ) throw (uno::RuntimeException);
137 : virtual void SAL_CALL windowDeactivated( const lang::EventObject& rEvent ) throw (uno::RuntimeException);
138 :
139 : // XWindowListener
140 : virtual void SAL_CALL windowResized( const awt::WindowEvent& rEvent ) throw (uno::RuntimeException);
141 : virtual void SAL_CALL windowMoved( const awt::WindowEvent& rEvent ) throw (uno::RuntimeException);
142 : virtual void SAL_CALL windowShown( const lang::EventObject& rEvent ) throw (uno::RuntimeException);
143 : virtual void SAL_CALL windowHidden( const lang::EventObject& rEvent ) throw (uno::RuntimeException);
144 :
145 : // XBorderResizeListener
146 : virtual void SAL_CALL borderWidthsChanged( const uno::Reference< uno::XInterface >& rSource, const frame::BorderWidths& aNewSize ) throw (uno::RuntimeException);
147 :
148 : // XChangesListener
149 : virtual void SAL_CALL changesOccurred( const util::ChangesEvent& rEvent ) throw (uno::RuntimeException);
150 :
151 : // XEventListener
152 : virtual void SAL_CALL disposing( const lang::EventObject& rEvent ) throw (uno::RuntimeException);
153 :
154 : private:
155 : /** Starts listening to the document model. */
156 : void startModelListening();
157 : /** Stops listening to the document model. */
158 : void stopModelListening();
159 :
160 : /** Returns the controller for the passed VCL window. */
161 : uno::Reference< frame::XController > getControllerForWindow( Window* pWindow ) const;
162 :
163 : /** Calls the Workbook_Window[Activate|Deactivate] event handler. */
164 : void processWindowActivateEvent( Window* pWindow, bool bActivate );
165 : /** Posts a Workbook_WindowResize user event. */
166 : void postWindowResizeEvent( Window* pWindow );
167 : /** Callback link for Application::PostUserEvent(). */
168 : DECL_LINK( processWindowResizeEvent, Window* );
169 :
170 : private:
171 : typedef ::std::map< Window*, uno::Reference< frame::XController > > WindowControllerMap;
172 :
173 : ::osl::Mutex maMutex;
174 : ScVbaEventsHelper& mrVbaEvents;
175 : uno::Reference< frame::XModel > mxModel;
176 : ScDocShell* mpDocShell;
177 : WindowControllerMap maControllers; /// Maps VCL top windows to their controllers.
178 : Window* mpActiveWindow; /// Currently activated window, to prevent multiple (de)activation.
179 : bool mbWindowResized; /// True = window resize system event processed.
180 : bool mbBorderChanged; /// True = borders changed system event processed.
181 : bool mbDisposed;
182 : };
183 :
184 : // ----------------------------------------------------------------------------
185 :
186 25 : ScVbaEventListener::ScVbaEventListener( ScVbaEventsHelper& rVbaEvents, const uno::Reference< frame::XModel >& rxModel, ScDocShell* pDocShell ) :
187 : mrVbaEvents( rVbaEvents ),
188 : mxModel( rxModel ),
189 : mpDocShell( pDocShell ),
190 : mpActiveWindow( 0 ),
191 : mbWindowResized( false ),
192 : mbBorderChanged( false ),
193 25 : mbDisposed( !rxModel.is() )
194 : {
195 25 : if( !mxModel.is() )
196 25 : return;
197 :
198 25 : startModelListening();
199 : try
200 : {
201 25 : uno::Reference< frame::XController > xController( mxModel->getCurrentController(), uno::UNO_QUERY_THROW );
202 25 : startControllerListening( xController );
203 : }
204 0 : catch( uno::Exception& )
205 : {
206 : }
207 : }
208 :
209 0 : ScVbaEventListener::~ScVbaEventListener()
210 : {
211 0 : }
212 :
213 25 : void ScVbaEventListener::startControllerListening( const uno::Reference< frame::XController >& rxController )
214 : {
215 25 : ::osl::MutexGuard aGuard( maMutex );
216 :
217 50 : uno::Reference< awt::XWindow > xWindow = lclGetWindowForController( rxController );
218 25 : if( xWindow.is() )
219 25 : try { xWindow->addWindowListener( this ); } catch( uno::Exception& ) {}
220 :
221 50 : uno::Reference< awt::XTopWindow > xTopWindow( xWindow, uno::UNO_QUERY );
222 25 : if( xTopWindow.is() )
223 25 : try { xTopWindow->addTopWindowListener( this ); } catch( uno::Exception& ) {}
224 :
225 50 : uno::Reference< frame::XControllerBorder > xControllerBorder( rxController, uno::UNO_QUERY );
226 25 : if( xControllerBorder.is() )
227 25 : try { xControllerBorder->addBorderResizeListener( this ); } catch( uno::Exception& ) {}
228 :
229 25 : if( Window* pWindow = VCLUnoHelper::GetWindow( xWindow ) )
230 50 : maControllers[ pWindow ] = rxController;
231 25 : }
232 :
233 25 : void ScVbaEventListener::stopControllerListening( const uno::Reference< frame::XController >& rxController )
234 : {
235 25 : ::osl::MutexGuard aGuard( maMutex );
236 :
237 50 : uno::Reference< awt::XWindow > xWindow = lclGetWindowForController( rxController );
238 25 : if( xWindow.is() )
239 25 : try { xWindow->removeWindowListener( this ); } catch( uno::Exception& ) {}
240 :
241 50 : uno::Reference< awt::XTopWindow > xTopWindow( xWindow, uno::UNO_QUERY );
242 25 : if( xTopWindow.is() )
243 25 : try { xTopWindow->removeTopWindowListener( this ); } catch( uno::Exception& ) {}
244 :
245 50 : uno::Reference< frame::XControllerBorder > xControllerBorder( rxController, uno::UNO_QUERY );
246 25 : if( xControllerBorder.is() )
247 25 : try { xControllerBorder->removeBorderResizeListener( this ); } catch( uno::Exception& ) {}
248 :
249 25 : if( Window* pWindow = VCLUnoHelper::GetWindow( xWindow ) )
250 : {
251 25 : maControllers.erase( pWindow );
252 25 : if( pWindow == mpActiveWindow )
253 5 : mpActiveWindow = 0;
254 25 : }
255 25 : }
256 :
257 4 : void SAL_CALL ScVbaEventListener::windowOpened( const lang::EventObject& /*rEvent*/ ) throw (uno::RuntimeException)
258 : {
259 4 : }
260 :
261 0 : void SAL_CALL ScVbaEventListener::windowClosing( const lang::EventObject& /*rEvent*/ ) throw (uno::RuntimeException)
262 : {
263 0 : }
264 :
265 4 : void SAL_CALL ScVbaEventListener::windowClosed( const lang::EventObject& /*rEvent*/ ) throw (uno::RuntimeException)
266 : {
267 4 : }
268 :
269 2 : void SAL_CALL ScVbaEventListener::windowMinimized( const lang::EventObject& /*rEvent*/ ) throw (uno::RuntimeException)
270 : {
271 2 : }
272 :
273 2 : void SAL_CALL ScVbaEventListener::windowNormalized( const lang::EventObject& /*rEvent*/ ) throw (uno::RuntimeException)
274 : {
275 2 : }
276 :
277 55 : void SAL_CALL ScVbaEventListener::windowActivated( const lang::EventObject& rEvent ) throw (uno::RuntimeException)
278 : {
279 55 : ::osl::MutexGuard aGuard( maMutex );
280 :
281 55 : if( !mbDisposed )
282 : {
283 55 : uno::Reference< awt::XWindow > xWindow( rEvent.Source, uno::UNO_QUERY );
284 55 : Window* pWindow = VCLUnoHelper::GetWindow( xWindow );
285 : OSL_TRACE( "ScVbaEventListener::windowActivated - pWindow = 0x%x, mpActiveWindow = 0x%x", pWindow, mpActiveWindow );
286 : // do not fire activation event multiple time for the same window
287 55 : if( pWindow && (pWindow != mpActiveWindow) )
288 : {
289 : // if another window is active, fire deactivation event first
290 55 : if( mpActiveWindow )
291 0 : processWindowActivateEvent( mpActiveWindow, false );
292 : // fire activation event for the new window
293 55 : processWindowActivateEvent( pWindow, true );
294 55 : mpActiveWindow = pWindow;
295 55 : }
296 55 : }
297 55 : }
298 :
299 55 : void SAL_CALL ScVbaEventListener::windowDeactivated( const lang::EventObject& rEvent ) throw (uno::RuntimeException)
300 : {
301 55 : ::osl::MutexGuard aGuard( maMutex );
302 :
303 55 : if( !mbDisposed )
304 : {
305 55 : uno::Reference< awt::XWindow > xWindow( rEvent.Source, uno::UNO_QUERY );
306 55 : Window* pWindow = VCLUnoHelper::GetWindow( xWindow );
307 : OSL_TRACE( "ScVbaEventListener::windowDeactivated - pWindow = 0x%x, mpActiveWindow = 0x%x", pWindow, mpActiveWindow );
308 : // do not fire the deactivation event, if the window is not active (prevent multiple deactivation)
309 55 : if( pWindow && (pWindow == mpActiveWindow) )
310 50 : processWindowActivateEvent( pWindow, false );
311 : // forget pointer to the active window
312 55 : mpActiveWindow = 0;
313 55 : }
314 55 : }
315 :
316 31 : void SAL_CALL ScVbaEventListener::windowResized( const awt::WindowEvent& rEvent ) throw (uno::RuntimeException)
317 : {
318 31 : ::osl::MutexGuard aGuard( maMutex );
319 :
320 31 : mbWindowResized = true;
321 31 : if( !mbDisposed && mbBorderChanged )
322 : {
323 4 : uno::Reference< awt::XWindow > xWindow( rEvent.Source, uno::UNO_QUERY );
324 4 : postWindowResizeEvent( VCLUnoHelper::GetWindow( xWindow ) );
325 31 : }
326 31 : }
327 :
328 31 : void SAL_CALL ScVbaEventListener::windowMoved( const awt::WindowEvent& /*rEvent*/ ) throw (uno::RuntimeException)
329 : {
330 31 : }
331 :
332 4 : void SAL_CALL ScVbaEventListener::windowShown( const lang::EventObject& /*rEvent*/ ) throw (uno::RuntimeException)
333 : {
334 4 : }
335 :
336 4 : void SAL_CALL ScVbaEventListener::windowHidden( const lang::EventObject& /*rEvent*/ ) throw (uno::RuntimeException)
337 : {
338 4 : }
339 :
340 34 : void SAL_CALL ScVbaEventListener::borderWidthsChanged( const uno::Reference< uno::XInterface >& rSource, const frame::BorderWidths& /*aNewSize*/ ) throw (uno::RuntimeException)
341 : {
342 34 : ::osl::MutexGuard aGuard( maMutex );
343 :
344 34 : mbBorderChanged = true;
345 34 : if( !mbDisposed && mbWindowResized )
346 : {
347 2 : uno::Reference< frame::XController > xController( rSource, uno::UNO_QUERY );
348 4 : uno::Reference< awt::XWindow > xWindow = lclGetWindowForController( xController );
349 4 : postWindowResizeEvent( VCLUnoHelper::GetWindow( xWindow ) );
350 34 : }
351 34 : }
352 :
353 0 : void SAL_CALL ScVbaEventListener::changesOccurred( const util::ChangesEvent& rEvent ) throw (uno::RuntimeException)
354 : {
355 0 : ::osl::MutexGuard aGuard( maMutex );
356 :
357 0 : sal_Int32 nCount = rEvent.Changes.getLength();
358 0 : if( mbDisposed || !mpDocShell || (nCount == 0) )
359 0 : return;
360 :
361 0 : util::ElementChange aChange = rEvent.Changes[ 0 ];
362 0 : OUString sOperation;
363 0 : aChange.Accessor >>= sOperation;
364 0 : if( !sOperation.equalsIgnoreAsciiCase("cell-change") )
365 0 : return;
366 :
367 0 : if( nCount == 1 )
368 : {
369 0 : uno::Reference< table::XCellRange > xRangeObj;
370 0 : aChange.ReplacedElement >>= xRangeObj;
371 0 : if( xRangeObj.is() )
372 : {
373 0 : uno::Sequence< uno::Any > aArgs( 1 );
374 0 : aArgs[0] <<= xRangeObj;
375 0 : mrVbaEvents.processVbaEventNoThrow( WORKSHEET_CHANGE, aArgs );
376 : }
377 0 : return;
378 : }
379 :
380 0 : ScRangeList aRangeList;
381 0 : for( sal_Int32 nIndex = 0; nIndex < nCount; ++nIndex )
382 : {
383 0 : aChange = rEvent.Changes[ nIndex ];
384 0 : aChange.Accessor >>= sOperation;
385 0 : uno::Reference< table::XCellRange > xRangeObj;
386 0 : aChange.ReplacedElement >>= xRangeObj;
387 0 : if( xRangeObj.is() && sOperation.equalsIgnoreAsciiCase("cell-change") )
388 : {
389 0 : uno::Reference< sheet::XCellRangeAddressable > xCellRangeAddressable( xRangeObj, uno::UNO_QUERY );
390 0 : if( xCellRangeAddressable.is() )
391 : {
392 0 : ScRange aRange;
393 0 : ScUnoConversion::FillScRange( aRange, xCellRangeAddressable->getRangeAddress() );
394 0 : aRangeList.Append( aRange );
395 0 : }
396 : }
397 0 : }
398 :
399 0 : if (!aRangeList.empty())
400 : {
401 0 : uno::Reference< sheet::XSheetCellRangeContainer > xRanges( new ScCellRangesObj( mpDocShell, aRangeList ) );
402 0 : uno::Sequence< uno::Any > aArgs(1);
403 0 : aArgs[0] <<= xRanges;
404 0 : mrVbaEvents.processVbaEventNoThrow( WORKSHEET_CHANGE, aArgs );
405 0 : }
406 : }
407 :
408 25 : void SAL_CALL ScVbaEventListener::disposing( const lang::EventObject& rEvent ) throw (uno::RuntimeException)
409 : {
410 25 : ::osl::MutexGuard aGuard( maMutex );
411 :
412 25 : uno::Reference< frame::XModel > xModel( rEvent.Source, uno::UNO_QUERY );
413 25 : if( xModel.is() )
414 : {
415 : OSL_ENSURE( xModel.get() == mxModel.get(), "ScVbaEventListener::disposing - disposing from unknown model" );
416 0 : stopModelListening();
417 0 : mbDisposed = true;
418 0 : return;
419 : }
420 :
421 25 : uno::Reference< frame::XController > xController( rEvent.Source, uno::UNO_QUERY );
422 25 : if( xController.is() )
423 : {
424 25 : stopControllerListening( xController );
425 25 : return;
426 0 : }
427 : }
428 :
429 : // private --------------------------------------------------------------------
430 :
431 25 : void ScVbaEventListener::startModelListening()
432 : {
433 : try
434 : {
435 25 : uno::Reference< util::XChangesNotifier > xChangesNotifier( mxModel, uno::UNO_QUERY_THROW );
436 25 : xChangesNotifier->addChangesListener( this );
437 : }
438 0 : catch( uno::Exception& )
439 : {
440 : }
441 25 : }
442 :
443 0 : void ScVbaEventListener::stopModelListening()
444 : {
445 : try
446 : {
447 0 : uno::Reference< util::XChangesNotifier > xChangesNotifier( mxModel, uno::UNO_QUERY_THROW );
448 0 : xChangesNotifier->removeChangesListener( this );
449 : }
450 0 : catch( uno::Exception& )
451 : {
452 : }
453 0 : }
454 :
455 110 : uno::Reference< frame::XController > ScVbaEventListener::getControllerForWindow( Window* pWindow ) const
456 : {
457 110 : WindowControllerMap::const_iterator aIt = maControllers.find( pWindow );
458 110 : return (aIt == maControllers.end()) ? uno::Reference< frame::XController >() : aIt->second;
459 : }
460 :
461 105 : void ScVbaEventListener::processWindowActivateEvent( Window* pWindow, bool bActivate )
462 : {
463 105 : uno::Reference< frame::XController > xController = getControllerForWindow( pWindow );
464 105 : if( xController.is() )
465 : {
466 105 : uno::Sequence< uno::Any > aArgs( 1 );
467 105 : aArgs[ 0 ] <<= xController;
468 105 : mrVbaEvents.processVbaEventNoThrow( bActivate ? WORKBOOK_WINDOWACTIVATE : WORKBOOK_WINDOWDEACTIVATE, aArgs );
469 105 : }
470 105 : }
471 :
472 6 : void ScVbaEventListener::postWindowResizeEvent( Window* pWindow )
473 : {
474 : // check that the passed window is still alive (it must be registered in maControllers)
475 6 : if( pWindow && (maControllers.count( pWindow ) > 0) )
476 : {
477 6 : mbWindowResized = mbBorderChanged = false;
478 6 : acquire(); // ensure we don't get deleted before the timer fires
479 6 : Application::PostUserEvent( LINK( this, ScVbaEventListener, processWindowResizeEvent ), pWindow );
480 : }
481 6 : }
482 :
483 12 : IMPL_LINK( ScVbaEventListener, processWindowResizeEvent, Window*, EMPTYARG pWindow )
484 : {
485 6 : ::osl::MutexGuard aGuard( maMutex );
486 :
487 : /* Check that the passed window is still alive (it must be registered in
488 : maControllers). While closing a document, postWindowResizeEvent() may
489 : be called on the last window which posts a user event via
490 : Application::PostUserEvent to call this event handler. VCL will trigger
491 : the handler some time later. Sometimes, the window gets deleted before.
492 : This is handled via the disposing() function which removes the window
493 : pointer from the member maControllers. Thus, checking whether
494 : maControllers contains pWindow ensures that the window is still alive. */
495 6 : if( !mbDisposed && pWindow && (maControllers.count( pWindow ) > 0) )
496 : {
497 : // do not fire event unless all mouse buttons have been released
498 5 : Window::PointerState aPointerState = pWindow->GetPointerState();
499 5 : if( (aPointerState.mnState & (MOUSE_LEFT | MOUSE_MIDDLE | MOUSE_RIGHT)) == 0 )
500 : {
501 5 : uno::Reference< frame::XController > xController = getControllerForWindow( pWindow );
502 5 : if( xController.is() )
503 : {
504 5 : uno::Sequence< uno::Any > aArgs( 1 );
505 5 : aArgs[ 0 ] <<= xController;
506 : // #163419# do not throw exceptions into application core
507 5 : mrVbaEvents.processVbaEventNoThrow( WORKBOOK_WINDOWRESIZE, aArgs );
508 5 : }
509 : }
510 : }
511 6 : release();
512 6 : return 0;
513 : }
514 :
515 : // ============================================================================
516 :
517 26 : ScVbaEventsHelper::ScVbaEventsHelper( const uno::Sequence< uno::Any >& rArgs, const uno::Reference< uno::XComponentContext >& xContext ) :
518 : VbaEventsHelperBase( rArgs, xContext ),
519 26 : mbOpened( false )
520 : {
521 26 : mpDocShell = dynamic_cast< ScDocShell* >( mpShell ); // mpShell from base class
522 26 : mpDoc = mpDocShell ? mpDocShell->GetDocument() : 0;
523 :
524 26 : if( !mxModel.is() || !mpDocShell || !mpDoc )
525 26 : return;
526 :
527 : #define REGISTER_EVENT( eventid, moduletype, classname, eventname, cancelindex, worksheet ) \
528 : registerEventHandler( eventid, moduletype, classname "_" eventname, cancelindex, uno::Any( worksheet ) )
529 : #define REGISTER_AUTO_EVENT( eventid, eventname ) \
530 : REGISTER_EVENT( AUTO_##eventid, script::ModuleType::NORMAL, "Auto", eventname, -1, false )
531 : #define REGISTER_WORKBOOK_EVENT( eventid, eventname, cancelindex ) \
532 : REGISTER_EVENT( WORKBOOK_##eventid, script::ModuleType::DOCUMENT, "Workbook", eventname, cancelindex, false )
533 : #define REGISTER_WORKSHEET_EVENT( eventid, eventname, cancelindex ) \
534 : REGISTER_EVENT( WORKSHEET_##eventid, script::ModuleType::DOCUMENT, "Worksheet", eventname, cancelindex, true ); \
535 : REGISTER_EVENT( (USERDEFINED_START + WORKSHEET_##eventid), script::ModuleType::DOCUMENT, "Workbook", "Sheet" eventname, (((cancelindex) >= 0) ? ((cancelindex) + 1) : -1), false )
536 :
537 : // global
538 26 : REGISTER_AUTO_EVENT( OPEN, "Open" );
539 26 : REGISTER_AUTO_EVENT( CLOSE, "Close" );
540 :
541 : // Workbook
542 26 : REGISTER_WORKBOOK_EVENT( ACTIVATE, "Activate", -1 );
543 26 : REGISTER_WORKBOOK_EVENT( DEACTIVATE, "Deactivate", -1 );
544 26 : REGISTER_WORKBOOK_EVENT( OPEN, "Open", -1 );
545 26 : REGISTER_WORKBOOK_EVENT( BEFORECLOSE, "BeforeClose", 0 );
546 26 : REGISTER_WORKBOOK_EVENT( BEFOREPRINT, "BeforePrint", 0 );
547 26 : REGISTER_WORKBOOK_EVENT( BEFORESAVE, "BeforeSave", 1 );
548 26 : REGISTER_WORKBOOK_EVENT( AFTERSAVE, "AfterSave", -1 );
549 26 : REGISTER_WORKBOOK_EVENT( NEWSHEET, "NewSheet", -1 );
550 26 : REGISTER_WORKBOOK_EVENT( WINDOWACTIVATE, "WindowActivate", -1 );
551 26 : REGISTER_WORKBOOK_EVENT( WINDOWDEACTIVATE, "WindowDeactivate", -1 );
552 26 : REGISTER_WORKBOOK_EVENT( WINDOWRESIZE, "WindowResize", -1 );
553 :
554 : // Worksheet events. All events have a corresponding workbook event.
555 26 : REGISTER_WORKSHEET_EVENT( ACTIVATE, "Activate", -1 );
556 26 : REGISTER_WORKSHEET_EVENT( DEACTIVATE, "Deactivate", -1 );
557 26 : REGISTER_WORKSHEET_EVENT( BEFOREDOUBLECLICK, "BeforeDoubleClick", 1 );
558 26 : REGISTER_WORKSHEET_EVENT( BEFORERIGHTCLICK, "BeforeRightClick", 1 );
559 26 : REGISTER_WORKSHEET_EVENT( CALCULATE, "Calculate", -1 );
560 26 : REGISTER_WORKSHEET_EVENT( CHANGE, "Change", -1 );
561 26 : REGISTER_WORKSHEET_EVENT( SELECTIONCHANGE, "SelectionChange", -1 );
562 26 : REGISTER_WORKSHEET_EVENT( FOLLOWHYPERLINK, "FollowHyperlink", -1 );
563 :
564 : #undef REGISTER_WORKSHEET_EVENT
565 : #undef REGISTER_WORKBOOK_EVENT
566 : #undef REGISTER_AUTO_EVENT
567 : #undef REGISTER_EVENT
568 : }
569 :
570 0 : ScVbaEventsHelper::~ScVbaEventsHelper()
571 : {
572 0 : }
573 :
574 259 : void SAL_CALL ScVbaEventsHelper::notifyEvent( const css::document::EventObject& rEvent ) throw (css::uno::RuntimeException)
575 : {
576 259 : static const uno::Sequence< uno::Any > saEmptyArgs;
577 988 : if( (rEvent.EventName == GlobalEventConfig::GetEventName( STR_EVENT_OPENDOC )) ||
578 729 : (rEvent.EventName == GlobalEventConfig::GetEventName( STR_EVENT_CREATEDOC )) ) // CREATEDOC triggered e.g. during VBA Workbooks.Add
579 : {
580 25 : processVbaEventNoThrow( WORKBOOK_OPEN, saEmptyArgs );
581 : }
582 234 : else if( rEvent.EventName == GlobalEventConfig::GetEventName( STR_EVENT_ACTIVATEDOC ) )
583 : {
584 24 : processVbaEventNoThrow( WORKBOOK_ACTIVATE, saEmptyArgs );
585 : }
586 210 : else if( rEvent.EventName == GlobalEventConfig::GetEventName( STR_EVENT_DEACTIVATEDOC ) )
587 : {
588 1 : processVbaEventNoThrow( WORKBOOK_DEACTIVATE, saEmptyArgs );
589 : }
590 1254 : else if( (rEvent.EventName == GlobalEventConfig::GetEventName( STR_EVENT_SAVEDOCDONE )) ||
591 1461 : (rEvent.EventName == GlobalEventConfig::GetEventName( STR_EVENT_SAVEASDOCDONE )) ||
592 625 : (rEvent.EventName == GlobalEventConfig::GetEventName( STR_EVENT_SAVETODOCDONE )) )
593 : {
594 1 : uno::Sequence< uno::Any > aArgs( 1 );
595 1 : aArgs[ 0 ] <<= true;
596 1 : processVbaEventNoThrow( WORKBOOK_AFTERSAVE, aArgs );
597 : }
598 1248 : else if( (rEvent.EventName == GlobalEventConfig::GetEventName( STR_EVENT_SAVEDOCFAILED )) ||
599 1456 : (rEvent.EventName == GlobalEventConfig::GetEventName( STR_EVENT_SAVEASDOCFAILED )) ||
600 624 : (rEvent.EventName == GlobalEventConfig::GetEventName( STR_EVENT_SAVETODOCFAILED )) )
601 : {
602 0 : uno::Sequence< uno::Any > aArgs( 1 );
603 0 : aArgs[ 0 ] <<= false;
604 0 : processVbaEventNoThrow( WORKBOOK_AFTERSAVE, aArgs );
605 : }
606 208 : else if( rEvent.EventName == GlobalEventConfig::GetEventName( STR_EVENT_CLOSEDOC ) )
607 : {
608 : /* Trigger the WORKBOOK_WINDOWDEACTIVATE and WORKBOOK_DEACTIVATE
609 : events and stop listening to the model (done in base class). */
610 26 : uno::Reference< frame::XController > xController( mxModel->getCurrentController() );
611 26 : if( xController.is() )
612 : {
613 26 : uno::Sequence< uno::Any > aArgs( 1 );
614 26 : aArgs[ 0 ] <<= xController;
615 26 : processVbaEventNoThrow( WORKBOOK_WINDOWDEACTIVATE, aArgs );
616 : }
617 26 : processVbaEventNoThrow( WORKBOOK_DEACTIVATE, saEmptyArgs );
618 : }
619 182 : else if( rEvent.EventName == GlobalEventConfig::GetEventName( STR_EVENT_VIEWCREATED ) )
620 : {
621 24 : uno::Reference< frame::XController > xController( mxModel->getCurrentController() );
622 24 : if( mxListener.get() && xController.is() )
623 0 : mxListener->startControllerListening( xController );
624 : }
625 259 : VbaEventsHelperBase::notifyEvent( rEvent );
626 259 : }
627 :
628 : // protected ------------------------------------------------------------------
629 :
630 1934 : bool ScVbaEventsHelper::implPrepareEvent( EventQueue& rEventQueue,
631 : const EventHandlerInfo& rInfo, const uno::Sequence< uno::Any >& rArgs ) throw (uno::RuntimeException)
632 : {
633 : // document and document shell are needed during event processing
634 1934 : if( !mpShell || !mpDoc )
635 0 : throw uno::RuntimeException();
636 :
637 : /* For document events: check if events are enabled via the
638 : Application.EnableEvents symbol (this is an Excel-only attribute).
639 : Check this again for every event, as the event handler may change the
640 : state of the EnableEvents symbol. Global events such as AUTO_OPEN and
641 : AUTO_CLOSE are always enabled. */
642 1934 : bool bExecuteEvent = (rInfo.mnModuleType != script::ModuleType::DOCUMENT) || ScVbaApplication::getDocumentEventsEnabled();
643 :
644 : // framework and Calc fire a few events before 'OnLoad', ignore them
645 1934 : if( bExecuteEvent )
646 1934 : bExecuteEvent = (rInfo.mnEventId == WORKBOOK_OPEN) ? !mbOpened : mbOpened;
647 :
648 : // special handling for some events
649 1934 : if( bExecuteEvent ) switch( rInfo.mnEventId )
650 : {
651 : case WORKBOOK_OPEN:
652 : {
653 : // execute delayed Activate event too (see above)
654 25 : rEventQueue.push_back( WORKBOOK_ACTIVATE );
655 25 : uno::Sequence< uno::Any > aArgs( 1 );
656 25 : aArgs[ 0 ] <<= mxModel->getCurrentController();
657 25 : rEventQueue.push_back( EventQueueEntry( WORKBOOK_WINDOWACTIVATE, aArgs ) );
658 25 : rEventQueue.push_back( AUTO_OPEN );
659 : // remember initial selection
660 25 : maOldSelection <<= mxModel->getCurrentSelection();
661 : }
662 25 : break;
663 : case WORKSHEET_SELECTIONCHANGE:
664 : // if selection is not changed, then do not fire the event
665 311 : bExecuteEvent = isSelectionChanged( rArgs, 0 );
666 311 : break;
667 : }
668 :
669 1934 : if( bExecuteEvent )
670 : {
671 : // add workbook event associated to a sheet event
672 1528 : bool bSheetEvent = false;
673 1528 : if( (rInfo.maUserData >>= bSheetEvent) && bSheetEvent )
674 636 : rEventQueue.push_back( EventQueueEntry( rInfo.mnEventId + USERDEFINED_START, rArgs ) );
675 : }
676 :
677 1934 : return bExecuteEvent;
678 : }
679 :
680 34 : uno::Sequence< uno::Any > ScVbaEventsHelper::implBuildArgumentList( const EventHandlerInfo& rInfo,
681 : const uno::Sequence< uno::Any >& rArgs ) throw (lang::IllegalArgumentException)
682 : {
683 : // fill arguments for workbook events associated to sheet events according to sheet events, sheet will be added below
684 34 : bool bSheetEventAsBookEvent = rInfo.mnEventId > USERDEFINED_START;
685 34 : sal_Int32 nEventId = bSheetEventAsBookEvent ? (rInfo.mnEventId - USERDEFINED_START) : rInfo.mnEventId;
686 :
687 34 : uno::Sequence< uno::Any > aVbaArgs;
688 34 : switch( nEventId )
689 : {
690 : // *** Workbook ***
691 :
692 : // no arguments
693 : case WORKBOOK_ACTIVATE:
694 : case WORKBOOK_DEACTIVATE:
695 : case WORKBOOK_OPEN:
696 0 : break;
697 : // 1 arg: cancel
698 : case WORKBOOK_BEFORECLOSE:
699 : case WORKBOOK_BEFOREPRINT:
700 0 : aVbaArgs.realloc( 1 );
701 : // current cancel state will be inserted by caller
702 0 : break;
703 : // 2 args: saveAs, cancel
704 : case WORKBOOK_BEFORESAVE:
705 0 : aVbaArgs.realloc( 2 );
706 0 : checkArgumentType< bool >( rArgs, 0 );
707 0 : aVbaArgs[ 0 ] = rArgs[ 0 ];
708 : // current cancel state will be inserted by caller
709 0 : break;
710 : // 1 arg: success
711 : case WORKBOOK_AFTERSAVE:
712 0 : aVbaArgs.realloc( 1 );
713 0 : checkArgumentType< bool >( rArgs, 0 );
714 0 : aVbaArgs[ 0 ] = rArgs[ 0 ];
715 0 : break;
716 : // 1 arg: window
717 : case WORKBOOK_WINDOWACTIVATE:
718 : case WORKBOOK_WINDOWDEACTIVATE:
719 : case WORKBOOK_WINDOWRESIZE:
720 0 : aVbaArgs.realloc( 1 );
721 0 : aVbaArgs[ 0 ] = createWindow( rArgs, 0 );
722 0 : break;
723 : // 1 arg: worksheet
724 : case WORKBOOK_NEWSHEET:
725 0 : aVbaArgs.realloc( 1 );
726 0 : aVbaArgs[ 0 ] = createWorksheet( rArgs, 0 );
727 0 : break;
728 :
729 : // *** Worksheet ***
730 :
731 : // no arguments
732 : case WORKSHEET_ACTIVATE:
733 : case WORKSHEET_CALCULATE:
734 : case WORKSHEET_DEACTIVATE:
735 0 : break;
736 : // 1 arg: range
737 : case WORKSHEET_CHANGE:
738 : case WORKSHEET_SELECTIONCHANGE:
739 34 : aVbaArgs.realloc( 1 );
740 34 : aVbaArgs[ 0 ] = createRange( rArgs, 0 );
741 34 : break;
742 : // 2 args: range, cancel
743 : case WORKSHEET_BEFOREDOUBLECLICK:
744 : case WORKSHEET_BEFORERIGHTCLICK:
745 0 : aVbaArgs.realloc( 2 );
746 0 : aVbaArgs[ 0 ] = createRange( rArgs, 0 );
747 : // current cancel state will be inserted by caller
748 0 : break;
749 : // 1 arg: hyperlink
750 : case WORKSHEET_FOLLOWHYPERLINK:
751 0 : aVbaArgs.realloc( 1 );
752 0 : aVbaArgs[ 0 ] = createHyperlink( rArgs, 0 );
753 0 : break;
754 : }
755 :
756 : /* For workbook events associated to sheet events, the workbook event gets
757 : the same arguments but with a Worksheet object in front of them. */
758 34 : if( bSheetEventAsBookEvent )
759 : {
760 0 : sal_Int32 nLength = aVbaArgs.getLength();
761 0 : uno::Sequence< uno::Any > aVbaArgs2( nLength + 1 );
762 0 : aVbaArgs2[ 0 ] = createWorksheet( rArgs, 0 );
763 0 : for( sal_Int32 nIndex = 0; nIndex < nLength; ++nIndex )
764 0 : aVbaArgs2[ nIndex + 1 ] = aVbaArgs[ nIndex ];
765 0 : aVbaArgs = aVbaArgs2;
766 : }
767 :
768 34 : return aVbaArgs;
769 : }
770 :
771 1926 : void ScVbaEventsHelper::implPostProcessEvent( EventQueue& rEventQueue,
772 : const EventHandlerInfo& rInfo, bool bCancel ) throw (uno::RuntimeException)
773 : {
774 1926 : switch( rInfo.mnEventId )
775 : {
776 : case WORKBOOK_OPEN:
777 26 : mbOpened = true;
778 : // register the listeners
779 26 : if( !mxListener.is() )
780 25 : mxListener = new ScVbaEventListener( *this, mxModel, mpDocShell );
781 26 : break;
782 : case WORKBOOK_BEFORECLOSE:
783 : /* Execute Auto_Close only if not cancelled by event handler, but
784 : before UI asks user whether to cancel closing the document. */
785 1 : if( !bCancel )
786 1 : rEventQueue.push_back( AUTO_CLOSE );
787 1 : break;
788 : }
789 1926 : }
790 :
791 2770 : OUString ScVbaEventsHelper::implGetDocumentModuleName( const EventHandlerInfo& rInfo,
792 : const uno::Sequence< uno::Any >& rArgs ) const throw (lang::IllegalArgumentException)
793 : {
794 2770 : bool bSheetEvent = false;
795 2770 : rInfo.maUserData >>= bSheetEvent;
796 2770 : SCTAB nTab = bSheetEvent ? lclGetTabFromArgs( rArgs, 0 ) : -1;
797 2762 : if( bSheetEvent && (nTab < 0) )
798 0 : throw lang::IllegalArgumentException();
799 :
800 2762 : OUString aCodeName;
801 2762 : if( bSheetEvent )
802 1282 : mpDoc->GetCodeName( nTab, aCodeName );
803 : else
804 1480 : aCodeName = mpDoc->GetCodeName();
805 2762 : return aCodeName;
806 : }
807 :
808 : // private --------------------------------------------------------------------
809 :
810 : namespace {
811 :
812 : /** Compares the passed range lists representing sheet selections. Ignores
813 : selections that refer to different sheets (returns false in this case). */
814 301 : bool lclSelectionChanged( const ScRangeList& rLeft, const ScRangeList& rRight )
815 : {
816 : // one of the range lists empty? -> return false, if both lists empty
817 301 : bool bLeftEmpty = rLeft.empty();
818 301 : bool bRightEmpty = rRight.empty();
819 301 : if( bLeftEmpty || bRightEmpty )
820 0 : return !(bLeftEmpty && bRightEmpty);
821 :
822 : // check sheet indexes of the range lists (assuming that all ranges in a list are on the same sheet)
823 301 : if (rLeft[0]->aStart.Tab() != rRight[0]->aStart.Tab())
824 4 : return false;
825 :
826 : // compare all ranges
827 297 : return rLeft != rRight;
828 : }
829 :
830 : } // namespace
831 :
832 311 : bool ScVbaEventsHelper::isSelectionChanged( const uno::Sequence< uno::Any >& rArgs, sal_Int32 nIndex ) throw (lang::IllegalArgumentException, uno::RuntimeException)
833 : {
834 311 : uno::Reference< uno::XInterface > xOldSelection( maOldSelection, uno::UNO_QUERY );
835 622 : uno::Reference< uno::XInterface > xNewSelection = getXSomethingFromArgs< uno::XInterface >( rArgs, nIndex, false );
836 311 : ScCellRangesBase* pOldCellRanges = ScCellRangesBase::getImplementation( xOldSelection );
837 311 : ScCellRangesBase* pNewCellRanges = ScCellRangesBase::getImplementation( xNewSelection );
838 311 : bool bChanged = !pOldCellRanges || !pNewCellRanges || lclSelectionChanged( pOldCellRanges->GetRangeList(), pNewCellRanges->GetRangeList() );
839 311 : maOldSelection <<= xNewSelection;
840 622 : return bChanged;
841 : }
842 :
843 0 : uno::Any ScVbaEventsHelper::createWorksheet( const uno::Sequence< uno::Any >& rArgs, sal_Int32 nIndex ) const
844 : throw (lang::IllegalArgumentException, uno::RuntimeException)
845 : {
846 : // extract sheet index, will throw, if parameter is invalid
847 0 : SCTAB nTab = lclGetTabFromArgs( rArgs, nIndex );
848 0 : return uno::Any( excel::getUnoSheetModuleObj( mxModel, nTab ) );
849 : }
850 :
851 34 : uno::Any ScVbaEventsHelper::createRange( const uno::Sequence< uno::Any >& rArgs, sal_Int32 nIndex ) const
852 : throw (lang::IllegalArgumentException, uno::RuntimeException)
853 : {
854 : // it is possible to pass an existing VBA Range object
855 34 : uno::Reference< excel::XRange > xVbaRange = getXSomethingFromArgs< excel::XRange >( rArgs, nIndex );
856 34 : if( !xVbaRange.is() )
857 : {
858 18 : uno::Reference< sheet::XSheetCellRangeContainer > xRanges = getXSomethingFromArgs< sheet::XSheetCellRangeContainer >( rArgs, nIndex );
859 36 : uno::Reference< table::XCellRange > xRange = getXSomethingFromArgs< table::XCellRange >( rArgs, nIndex );
860 18 : if ( !xRanges.is() && !xRange.is() )
861 0 : throw lang::IllegalArgumentException();
862 :
863 36 : uno::Sequence< uno::Any > aArgs( 2 );
864 18 : if ( xRanges.is() )
865 : {
866 2 : aArgs[ 0 ] <<= excel::getUnoSheetModuleObj( xRanges );
867 2 : aArgs[ 1 ] <<= xRanges;
868 : }
869 : else
870 : {
871 16 : aArgs[ 0 ] <<= excel::getUnoSheetModuleObj( xRange );
872 16 : aArgs[ 1 ] <<= xRange;
873 : }
874 36 : xVbaRange.set( createVBAUnoAPIServiceWithArgs( mpShell, "ooo.vba.excel.Range", aArgs ), uno::UNO_QUERY_THROW );
875 : }
876 34 : return uno::Any( xVbaRange );
877 : }
878 :
879 0 : uno::Any ScVbaEventsHelper::createHyperlink( const uno::Sequence< uno::Any >& rArgs, sal_Int32 nIndex ) const
880 : throw (lang::IllegalArgumentException, uno::RuntimeException)
881 : {
882 0 : uno::Reference< table::XCell > xCell = getXSomethingFromArgs< table::XCell >( rArgs, nIndex, false );
883 0 : uno::Sequence< uno::Any > aArgs( 2 );
884 0 : aArgs[ 0 ] <<= excel::getUnoSheetModuleObj( xCell );
885 0 : aArgs[ 1 ] <<= xCell;
886 0 : uno::Reference< uno::XInterface > xHyperlink( createVBAUnoAPIServiceWithArgs( mpShell, "ooo.vba.excel.Hyperlink", aArgs ), uno::UNO_SET_THROW );
887 0 : return uno::Any( xHyperlink );
888 : }
889 :
890 0 : uno::Any ScVbaEventsHelper::createWindow( const uno::Sequence< uno::Any >& rArgs, sal_Int32 nIndex ) const
891 : throw (lang::IllegalArgumentException, uno::RuntimeException)
892 : {
893 0 : uno::Sequence< uno::Any > aArgs( 3 );
894 0 : aArgs[ 0 ] <<= getVBADocument( mxModel );
895 0 : aArgs[ 1 ] <<= mxModel;
896 0 : aArgs[ 2 ] <<= getXSomethingFromArgs< frame::XController >( rArgs, nIndex, false );
897 0 : uno::Reference< uno::XInterface > xWindow( createVBAUnoAPIServiceWithArgs( mpShell, "ooo.vba.excel.Window", aArgs ), uno::UNO_SET_THROW );
898 0 : return uno::Any( xWindow );
899 : }
900 :
901 : // ============================================================================
902 :
903 : namespace vbaeventshelper
904 : {
905 : namespace sdecl = comphelper::service_decl;
906 2 : sdecl::class_<ScVbaEventsHelper, sdecl::with_args<true> > serviceImpl;
907 2 : extern sdecl::ServiceDecl const serviceDecl(
908 : serviceImpl,
909 : "ScVbaEventsHelper",
910 : "com.sun.star.script.vba.VBASpreadsheetEventProcessor" );
911 6 : }
912 :
913 : // ============================================================================
914 :
915 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|