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