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