update dev300-m58
[ooovba.git] / sc / source / ui / vba / vbaeventshelper.cxx
blob78b3ede4306885bac976517a65930f3b0672f776
1 /*************************************************************************
3 * OpenOffice.org - a multi-platform office productivity suite
5 * $RCSfile: vbaeventshelper.cxx,v $
7 * $Revision: 1.0 $
9 * last change: $Author: vg $ $Date: 2007/12/07 10:42:26 $
11 * The Contents of this file are made available subject to
12 * the terms of GNU Lesser General Public License Version 2.1.
15 * GNU Lesser General Public License Version 2.1
16 * =============================================
17 * Copyright 2005 by Sun Microsystems, Inc.
18 * 901 San Antonio Road, Palo Alto, CA 94303, USA
20 * This library is free software; you can redistribute it and/or
21 * modify it under the terms of the GNU Lesser General Public
22 * License version 2.1, as published by the Free Software Foundation.
24 * This library is distributed in the hope that it will be useful,
25 * but WITHOUT ANY WARRANTY; without even the implied warranty of
26 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
27 * Lesser General Public License for more details.
29 * You should have received a copy of the GNU Lesser General Public
30 * License along with this library; if not, write to the Free Software
31 * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
32 * MA 02111-1307 USA
34 ************************************************************************/
35 #include "vbaeventshelper.hxx"
36 #include <vbahelper/helperdecl.hxx>
37 #include <sfx2/objsh.hxx>
38 #include "scextopt.hxx"
39 #include <sfx2/evntconf.hxx>
40 #include <sfx2/event.hxx>
41 #include <sfx2/sfx.hrc>
42 #include <toolkit/unohlp.hxx>
43 #include <comphelper/processfactory.hxx>
44 #include <cppuhelper/implbase1.hxx>
45 #include <com/sun/star/sheet/XSheetCellRangeContainer.hpp>
46 #include <com/sun/star/document/XEventsSupplier.hpp>
47 #include <com/sun/star/sheet/XCellRangeReferrer.hpp>
48 #include <com/sun/star/table/XCell.hpp>
49 #include <com/sun/star/sheet/XSpreadsheetDocument.hpp>
50 #include <com/sun/star/sheet/XSpreadsheet.hpp>
51 #include <com/sun/star/container/XNamed.hpp>
52 #include <com/sun/star/awt/WindowEvent.hpp>
53 #include <com/sun/star/lang/EventObject.hpp>
54 #include <com/sun/star/util/XCloseListener.hpp>
55 #include <com/sun/star/util/XCloseBroadcaster.hpp>
56 #include <com/sun/star/frame/XControllerBorder.hpp>
57 #include <com/sun/star/frame/XBorderResizeListener.hpp>
58 #include <com/sun/star/util/XChangesListener.hpp>
59 #include <com/sun/star/util/ElementChange.hpp>
60 #include <com/sun/star/util/XChangesNotifier.hpp>
61 #include <com/sun/star/sheet/XCellRangeAddressable.hpp>
62 #include <cellsuno.hxx>
63 #include <convuno.hxx>
64 #include <map>
65 #include <svx/msvbahelper.hxx>
66 #include <vcl/svapp.hxx>
68 using namespace std;
69 using namespace com::sun::star;
70 using namespace ooo::vba;
71 using namespace com::sun::star::document::VbaEventId;
73 typedef ::cppu::WeakImplHelper1< util::XChangesListener > WorksheetChangeListener_BASE;
75 class WorksheetChangeListener : public WorksheetChangeListener_BASE
77 private:
78 ScVbaEventsHelper* pVbaEventsHelper;
79 public:
80 WorksheetChangeListener(ScVbaEventsHelper* pHelper ) : pVbaEventsHelper( pHelper ){}
81 virtual void SAL_CALL changesOccurred(const util::ChangesEvent& aEvent) throw (uno::RuntimeException);
82 virtual void SAL_CALL disposing(const lang::EventObject& aSource) throw(uno::RuntimeException){}
85 void WorksheetChangeListener::changesOccurred(const util::ChangesEvent& aEvent) throw (uno::RuntimeException)
87 sal_Int32 nCount = aEvent.Changes.getLength();
88 if( nCount == 0 )
89 return;
91 util::ElementChange aChange = aEvent.Changes[ 0 ];
92 rtl::OUString sOperation;
93 aChange.Accessor >>= sOperation;
94 if( !sOperation.equalsIgnoreAsciiCaseAscii("cell-change") )
95 return;
97 if( nCount == 1 )
99 uno::Reference< table::XCellRange > xRangeObj;
100 aChange.ReplacedElement >>= xRangeObj;
101 if( xRangeObj.is() )
103 uno::Sequence< uno::Any > aArgs(1);
104 aArgs[0] <<= xRangeObj;
105 pVbaEventsHelper->ProcessCompatibleVbaEvent( VBAEVENT_WORKSHEET_CHANGE, aArgs );
107 return;
110 ScRangeList aRangeList;
111 for( sal_Int32 nIndex = 0; nIndex < nCount; ++nIndex )
113 aChange = aEvent.Changes[ nIndex ];
114 aChange.Accessor >>= sOperation;
115 uno::Reference< table::XCellRange > xRangeObj;
116 aChange.ReplacedElement >>= xRangeObj;
117 if( xRangeObj.is() && sOperation.equalsIgnoreAsciiCaseAscii("cell-change") )
119 uno::Reference< sheet::XCellRangeAddressable > xCellRangeAddressable( xRangeObj, uno::UNO_QUERY );
120 if( xCellRangeAddressable.is() )
122 ScRange aRange;
123 ScUnoConversion::FillScRange( aRange, xCellRangeAddressable->getRangeAddress() );
124 aRangeList.Append( aRange );
129 if( aRangeList.Count() > 0 )
131 uno::Reference< sheet::XSheetCellRangeContainer > xRanges( new ScCellRangesObj( pVbaEventsHelper->getDocumentShell(), aRangeList ) );
132 uno::Sequence< uno::Any > aArgs(1);
133 aArgs[0] <<= xRanges;
134 pVbaEventsHelper->ProcessCompatibleVbaEvent( VBAEVENT_WORKSHEET_CHANGE, aArgs );
138 typedef ::cppu::WeakImplHelper3< awt::XWindowListener, util::XCloseListener, frame::XBorderResizeListener > WindowListener_BASE;
140 // This class is to process Workbook window related event
141 class VbaEventsListener : public WindowListener_BASE
143 ::osl::Mutex m_aMutex;
144 ScVbaEventsHelper* pVbaEventsHelper;
145 uno::Reference< frame::XModel > m_xModel;
146 sal_Bool m_bWindowResized;
147 sal_Bool m_bBorderChanged;
148 protected :
149 uno::Reference< awt::XWindow > GetContainerWindow();
150 uno::Reference< frame::XFrame > GetFrame();
151 sal_Bool IsMouseReleased();
152 DECL_LINK( fireResizeMacro, void* );
153 void processWindowResizeMacro();
154 public :
155 VbaEventsListener( ScVbaEventsHelper* pHelper );
156 ~VbaEventsListener();
157 void startEventsLinstener();
158 void stopEventsLinstener();
159 // XWindowListener
160 virtual void SAL_CALL windowResized( const awt::WindowEvent& aEvent ) throw ( uno::RuntimeException );
161 virtual void SAL_CALL windowMoved( const awt::WindowEvent& aEvent ) throw ( uno::RuntimeException );
162 virtual void SAL_CALL windowShown( const lang::EventObject& aEvent ) throw ( uno::RuntimeException );
163 virtual void SAL_CALL windowHidden( const lang::EventObject& aEvent ) throw ( uno::RuntimeException );
164 virtual void SAL_CALL disposing( const lang::EventObject& aEvent ) throw ( uno::RuntimeException );
165 // XCloseListener
166 virtual void SAL_CALL queryClosing( const lang::EventObject& Source, ::sal_Bool GetsOwnership ) throw (util::CloseVetoException, uno::RuntimeException);
167 virtual void SAL_CALL notifyClosing( const lang::EventObject& Source ) throw (uno::RuntimeException);
168 // XBorderResizeListener
169 virtual void SAL_CALL borderWidthsChanged( const uno::Reference< uno::XInterface >& aObject, const frame::BorderWidths& aNewSize ) throw (uno::RuntimeException);
171 VbaEventsListener::VbaEventsListener( ScVbaEventsHelper* pHelper ) : pVbaEventsHelper( pHelper )
173 OSL_TRACE("VbaEventsListener::VbaEventsListener( 0x%x ) - ctor ", this );
174 m_xModel.set( pVbaEventsHelper->getDocument()->GetDocumentShell()->GetModel(), uno::UNO_QUERY );
175 m_bWindowResized = sal_False;
176 m_bBorderChanged = sal_False;
179 VbaEventsListener::~VbaEventsListener()
181 OSL_TRACE("VbaEventsListener::~VbaEventsListener( 0x%x ) - dtor ", this );
183 uno::Reference< frame::XFrame >
184 VbaEventsListener::GetFrame()
188 if( pVbaEventsHelper )
190 if( m_xModel.is() )
192 uno::Reference< frame::XController > xController( m_xModel->getCurrentController(), uno::UNO_QUERY );
193 if( xController.is() )
195 uno::Reference< frame::XFrame > xFrame( xController->getFrame(), uno::UNO_QUERY );
196 if( xFrame.is() )
198 return xFrame;
204 catch( uno::Exception& /*e*/ )
207 return uno::Reference< frame::XFrame >();
209 uno::Reference< awt::XWindow >
210 VbaEventsListener::GetContainerWindow()
214 uno::Reference< frame::XFrame > xFrame( GetFrame(), uno::UNO_QUERY );
215 if( xFrame.is() )
217 uno::Reference< awt::XWindow > xWindow( xFrame->getContainerWindow(), uno::UNO_QUERY );
218 if( xWindow.is() )
219 return xWindow;
222 catch( uno::Exception& /*e*/ )
225 return uno::Reference< awt::XWindow >();
227 sal_Bool
228 VbaEventsListener::IsMouseReleased()
230 Window* pWindow = (VCLUnoHelper::GetWindow( GetContainerWindow() ) );
231 if( pWindow )
233 Window::PointerState aPointerState = pWindow->GetPointerState();
234 if( !aPointerState.mnState & ( MOUSE_LEFT | MOUSE_MIDDLE | MOUSE_RIGHT ) )
235 return sal_True;
237 return sal_False;
239 void
240 VbaEventsListener::startEventsLinstener()
242 if( m_xModel.is() )
244 // add window listener
245 uno::Reference< awt::XWindow > xWindow( GetContainerWindow(), uno::UNO_QUERY );
246 if( xWindow.is() )
247 xWindow->addWindowListener( this );
248 // add close listener
249 //uno::Reference< util::XCloseBroadcaster > xCloseBroadcaster( GetFrame(), uno::UNO_QUERY );
250 uno::Reference< util::XCloseBroadcaster > xCloseBroadcaster( m_xModel, uno::UNO_QUERY );
251 if( xCloseBroadcaster.is() )
253 xCloseBroadcaster->addCloseListener( this );
255 // add Border resize listener
256 uno::Reference< frame::XController > xController( m_xModel->getCurrentController(), uno::UNO_QUERY );
257 if( xController.is() )
259 uno::Reference< frame::XControllerBorder > xControllerBorder( xController, uno::UNO_QUERY );
260 if( xControllerBorder.is() )
262 xControllerBorder->addBorderResizeListener( this );
267 void
268 VbaEventsListener::stopEventsLinstener()
270 if( m_xModel.is() )
272 uno::Reference< awt::XWindow > xWindow( GetContainerWindow(), uno::UNO_QUERY );
273 if( xWindow.is() )
275 xWindow->removeWindowListener( this );
277 //uno::Reference< util::XCloseBroadcaster > xCloseBroadcaster( GetFrame(), uno::UNO_QUERY );
278 uno::Reference< util::XCloseBroadcaster > xCloseBroadcaster( m_xModel, uno::UNO_QUERY );
279 if( xCloseBroadcaster.is() )
281 xCloseBroadcaster->removeCloseListener( this );
283 uno::Reference< frame::XController > xController( m_xModel->getCurrentController(), uno::UNO_QUERY );
284 if( xController.is() )
286 uno::Reference< frame::XControllerBorder > xControllerBorder( xController, uno::UNO_QUERY );
287 if( xControllerBorder.is() )
289 xControllerBorder->removeBorderResizeListener( this );
292 pVbaEventsHelper = NULL;
296 void
297 VbaEventsListener::processWindowResizeMacro()
299 OSL_TRACE("**** Attempt to FIRE MACRO **** ");
300 if( pVbaEventsHelper )
301 pVbaEventsHelper->ProcessCompatibleVbaEvent( VBAEVENT_WORKBOOK_WINDOWRESIZE, uno::Sequence< uno::Any >() );
304 IMPL_LINK( VbaEventsListener, fireResizeMacro, void*, pParam )
306 if ( pVbaEventsHelper )
308 if( IsMouseReleased() )
309 processWindowResizeMacro();
311 release();
312 return 0;
315 void SAL_CALL
316 VbaEventsListener::windowResized( const awt::WindowEvent& /*aEvent*/ ) throw ( uno::RuntimeException )
318 ::osl::MutexGuard aGuard( m_aMutex );
319 // Workbook_window_resize event
320 m_bWindowResized = sal_True;
321 Window* pWindow = (VCLUnoHelper::GetWindow( GetContainerWindow() ) );
323 if( pWindow && m_bBorderChanged )
325 m_bBorderChanged = m_bWindowResized = sal_False;
326 acquire(); // ensure we don't get deleted before the event is handled
327 Application::PostUserEvent( LINK( this, VbaEventsListener, fireResizeMacro ), NULL );
330 void SAL_CALL
331 VbaEventsListener::windowMoved( const awt::WindowEvent& /*aEvent*/ ) throw ( uno::RuntimeException )
333 // not interest this time
335 void SAL_CALL
336 VbaEventsListener::windowShown( const lang::EventObject& /*aEvent*/ ) throw ( uno::RuntimeException )
338 // not interest this time
340 void SAL_CALL
341 VbaEventsListener::windowHidden( const lang::EventObject& /*aEvent*/ ) throw ( uno::RuntimeException )
343 // not interest this time
345 void SAL_CALL
346 VbaEventsListener::disposing( const lang::EventObject& /*aEvent*/ ) throw ( uno::RuntimeException )
348 ::osl::MutexGuard aGuard( m_aMutex );
349 OSL_TRACE("VbaEventsListener::disposing(0x%x)", this);
350 pVbaEventsHelper = NULL;
352 void SAL_CALL
353 VbaEventsListener::queryClosing( const lang::EventObject& Source, ::sal_Bool GetsOwnership ) throw (util::CloseVetoException, uno::RuntimeException)
355 // it can cancel the close, but need to throw a CloseVetoException, and it will be transmit to caller.
357 void SAL_CALL
358 VbaEventsListener::notifyClosing( const lang::EventObject& Source ) throw (uno::RuntimeException)
360 ::osl::MutexGuard aGuard( m_aMutex );
361 stopEventsLinstener();
363 void SAL_CALL
364 VbaEventsListener::borderWidthsChanged( const uno::Reference< uno::XInterface >& aObject, const frame::BorderWidths& aNewSize ) throw (uno::RuntimeException)
366 ::osl::MutexGuard aGuard( m_aMutex );
367 // work with WindowResized event to guard Window Resize event.
368 m_bBorderChanged = sal_True;
369 Window* pWindow = (VCLUnoHelper::GetWindow( GetContainerWindow() ) );
370 if( pWindow && m_bWindowResized )
372 m_bWindowResized = m_bBorderChanged = sal_False;
373 acquire(); // ensure we don't get deleted before the timer fires.
374 Application::PostUserEvent( LINK( this, VbaEventsListener, fireResizeMacro ), NULL );
378 class ImplVbaEventNameInfo
380 private:
381 map< sal_Int32, rtl::OUString > m_aEventNameMap;
383 protected:
384 static ImplVbaEventNameInfo* pImplVbaEventNameInfo;
385 ImplVbaEventNameInfo() { InitImplVbaEventNameInfo(); }
386 private:
387 void insert( const sal_Int32 nId, const rtl::OUString& sEventName )
389 m_aEventNameMap.insert( make_pair( nId, sEventName ) );
391 void InitImplVbaEventNameInfo();
392 public:
393 virtual ~ImplVbaEventNameInfo();
394 rtl::OUString getEventName( const sal_Int32 nId )
396 map< sal_Int32, rtl::OUString >::iterator iter = m_aEventNameMap.find( nId );
397 if( iter != m_aEventNameMap.end() )
398 return iter->second;
399 return rtl::OUString();
401 static ImplVbaEventNameInfo* GetImplVbaEventNameInfo();
403 ImplVbaEventNameInfo* ImplVbaEventNameInfo::pImplVbaEventNameInfo = NULL;
405 ImplVbaEventNameInfo::~ImplVbaEventNameInfo()
407 if( pImplVbaEventNameInfo )
409 delete pImplVbaEventNameInfo;
410 pImplVbaEventNameInfo = NULL;
414 ImplVbaEventNameInfo*
415 ImplVbaEventNameInfo::GetImplVbaEventNameInfo()
417 if( !pImplVbaEventNameInfo )
419 pImplVbaEventNameInfo = new ImplVbaEventNameInfo;
421 return pImplVbaEventNameInfo;
424 #define CREATEOUSTRING(asciistr) rtl::OUString::createFromAscii(asciistr)
426 #define INSERT_EVENT_INFO( Object, Event, ObjectName, EventName ) \
427 insert( VBAEVENT_##Object##_##Event, ObjectName + CREATEOUSTRING( EventName ) )
429 #define INSERT_WORKSHEET_EVENT_INFO( Event, EventName ) \
430 INSERT_EVENT_INFO( WORKSHEET, Event,CREATEOUSTRING("Worksheet_"), EventName ); \
431 INSERT_EVENT_INFO( WORKBOOK_SHEET, Event, CREATEOUSTRING("Workbook_Sheet"), EventName )
433 #define INSERT_WORKBOOK_EVENT_INFO( Event, EventName ) \
434 INSERT_EVENT_INFO( WORKBOOK, Event, CREATEOUSTRING("Workbook_"), EventName )
436 void ImplVbaEventNameInfo::InitImplVbaEventNameInfo()
438 INSERT_WORKSHEET_EVENT_INFO( ACTIVATE, "Activate");
439 INSERT_WORKSHEET_EVENT_INFO( BEFOREDOUBLECLICK, "BeforeDoubleClick" );
440 INSERT_WORKSHEET_EVENT_INFO( BEFORERIGHTCLICK, "BeforeRightClick" );
441 INSERT_WORKSHEET_EVENT_INFO( CALCULATE, "Calculate" );
442 INSERT_WORKSHEET_EVENT_INFO( CHANGE, "Change" );
443 INSERT_WORKSHEET_EVENT_INFO( DEACTIVATE, "Deactivate" );
444 INSERT_WORKSHEET_EVENT_INFO( FOLLOWHYPERLINK, "FollowHyperlink" );
445 INSERT_WORKSHEET_EVENT_INFO( PIVOTTABLEUPDATE, "PivotTableUpdate" );
446 INSERT_WORKSHEET_EVENT_INFO( SELECTIONCHANGE, "SelectionChange" );
448 // Workbook
449 INSERT_WORKBOOK_EVENT_INFO( ACTIVATE, "Activate" );
450 INSERT_WORKBOOK_EVENT_INFO( DEACTIVATE, "Deactivate" );
451 INSERT_WORKBOOK_EVENT_INFO( OPEN, "Open" );
452 // AUTOOPEN doesn't be used. TODO, this should be "auto_open"
453 insert( VBAEVENT_WORKBOOK_AUTOOPEN, CREATEOUSTRING("Auto_Open") );
454 INSERT_WORKBOOK_EVENT_INFO( BEFORECLOSE, "BeforeClose" );
455 INSERT_WORKBOOK_EVENT_INFO( BEFOREPRINT, "BeforePrint" );
456 INSERT_WORKBOOK_EVENT_INFO( BEFORESAVE, "BeforeSave" );
457 INSERT_WORKBOOK_EVENT_INFO( NEWSHEET, "NewSheet" );
458 INSERT_WORKBOOK_EVENT_INFO( WINDOWACTIVATE, "WindowActivate" );
459 INSERT_WORKBOOK_EVENT_INFO( WINDOWDEACTIVATE, "WindowDeactivate" );
460 INSERT_WORKBOOK_EVENT_INFO( WINDOWRESIZE, "WindowResize" );
463 ScVbaEventsHelper::ScVbaEventsHelper( uno::Sequence< css::uno::Any > const& aArgs, uno::Reference< uno::XComponentContext > const& xContext )
464 : m_xContext( xContext ), mbOpened( sal_False ), mbIgnoreEvents( sal_False )
466 uno::Reference< frame::XModel > xModel ( getXSomethingFromArgs< frame::XModel >( aArgs, 0 ), uno::UNO_QUERY );
467 pDocShell = excel::getDocShell( xModel );
468 pDoc = pDocShell->GetDocument();
469 // Add worksheet change listener
470 uno::Reference< util::XChangesNotifier > xChangesNotifier( xModel, uno::UNO_QUERY );
471 if( xChangesNotifier.is() )
472 xChangesNotifier->addChangesListener( uno::Reference< util::XChangesListener >( new WorksheetChangeListener( this ) ) );
475 ScVbaEventsHelper::~ScVbaEventsHelper()
479 rtl::OUString
480 ScVbaEventsHelper::getEventName( const sal_Int32 nId )
482 rtl::OUString sEventName;
483 ImplVbaEventNameInfo* pEventInfo = ImplVbaEventNameInfo::GetImplVbaEventNameInfo();
484 if( pEventInfo )
485 sEventName = pEventInfo->getEventName( nId );
486 return sEventName;
489 uno::Any ScVbaEventsHelper::createWorkSheet( SfxObjectShell* pShell, SCTAB nTab )
491 uno::Any aRet;
494 uno::Reference< lang::XMultiComponentFactory > xSMgr( ::comphelper::getProcessServiceFactory(), uno::UNO_QUERY_THROW );
495 uno::Reference< beans::XPropertySet > xProps( xSMgr, uno::UNO_QUERY_THROW );
496 uno::Reference<uno::XComponentContext > xCtx( xProps->getPropertyValue( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "DefaultContext" ))), uno::UNO_QUERY_THROW );
497 // Eventually we will be able to pull the Workbook/Worksheet objects
498 // directly from basic and register them as listeners
500 // create Workbook
501 uno::Sequence< uno::Any > aArgs(2);
502 aArgs[0] = uno::Any( uno::Reference< uno::XInterface >() );
503 aArgs[1] = uno::Any( pShell->GetModel() );
504 uno::Reference< uno::XInterface > xWorkbook( ov::createVBAUnoAPIServiceWithArgs( pShell, "ooo.vba.excel.Workbook", aArgs ), uno::UNO_QUERY );
506 // create WorkSheet
507 String sSheetName;
508 pDoc->GetName( nTab, sSheetName );
509 aArgs = uno::Sequence< uno::Any >(3);
510 aArgs[ 0 ] <<= xWorkbook;
511 aArgs[ 1 ] <<= pShell->GetModel();
512 aArgs[ 2 ] = uno::makeAny( rtl::OUString( sSheetName ) );
513 aRet <<= ov::createVBAUnoAPIServiceWithArgs( pShell, "ooo.vba.excel.Worksheet", aArgs );
515 catch( uno::Exception& e )
518 return aRet;
521 uno::Any ScVbaEventsHelper::createRange( const uno::Any& aRange )
523 uno::Any aRet;
526 uno::Reference< sheet::XSheetCellRangeContainer > xRanges( aRange, uno::UNO_QUERY );
527 uno::Reference< table::XCellRange > xRange( aRange, uno::UNO_QUERY );
528 uno::Reference< lang::XMultiComponentFactory > xSMgr( ::comphelper::getProcessServiceFactory(), uno::UNO_QUERY_THROW );
529 uno::Reference< beans::XPropertySet > xProps( xSMgr, uno::UNO_QUERY_THROW );
530 if ( xRanges.is() || xRange.is() )
532 uno::Reference<uno::XComponentContext > xCtx( xProps->getPropertyValue( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "DefaultContext" ))), uno::UNO_QUERY_THROW );
533 uno::Sequence< uno::Any > aArgs(2);
534 aArgs[0] = uno::Any( uno::Reference< uno::XInterface >() ); // dummy parent
535 if ( xRanges.is() )
537 aArgs[1] <<= xRanges;
539 else if ( xRange.is() )
541 aArgs[1] <<= xRange;
543 else
545 throw uno::RuntimeException(); //
547 aRet <<= ov::createVBAUnoAPIServiceWithArgs( pDoc->GetDocumentShell(), "ooo.vba.excel.Range", aArgs );
550 catch( uno::Exception& e )
553 return aRet;
556 uno::Any ScVbaEventsHelper::createHyperlink( const uno::Any& rCell )
558 uno::Any aRet;
561 uno::Reference< lang::XMultiComponentFactory > xSMgr( ::comphelper::getProcessServiceFactory(), uno::UNO_QUERY_THROW );
562 uno::Reference< beans::XPropertySet > xProps( xSMgr, uno::UNO_QUERY_THROW );
563 uno::Reference< table::XCell > xCell( rCell, uno::UNO_QUERY );
564 if( xCell.is() )
566 uno::Reference<uno::XComponentContext > xCtx( xProps->getPropertyValue( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "DefaultContext" ))), uno::UNO_QUERY_THROW );
567 uno::Sequence< uno::Any > aArgs(2);
568 aArgs[0] = uno::Any( uno::Reference< uno::XInterface >() ); // dummy parent
569 aArgs[1] <<= rCell;
571 aRet <<= ov::createVBAUnoAPIServiceWithArgs( pDoc->GetDocumentShell(), "ooo.vba.excel.Hyperlink", aArgs );
573 else
575 throw uno::RuntimeException(); //
578 catch( uno::Exception& e )
581 return aRet;
584 uno::Any ScVbaEventsHelper::createWindow( SfxObjectShell* pShell )
588 uno::Reference< lang::XMultiServiceFactory > xSF( comphelper::getProcessServiceFactory(), uno::UNO_QUERY );
589 uno::Reference< frame::XModel > xModel( pShell->GetModel(), uno::UNO_QUERY );
590 uno::Sequence< uno::Any > aWindowArgs(2);
591 aWindowArgs[0] = uno::Any( uno::Reference< uno::XInterface > () );
592 aWindowArgs[1] = uno::Any( xModel );
593 uno::Reference< uno::XInterface > xWindow( xSF->createInstanceWithArguments( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM("ooo.vba.excel.Window" ) ), aWindowArgs ), uno::UNO_QUERY );
594 if( xWindow.is() )
595 return uno::makeAny( xWindow );
597 catch( uno::Exception& e )
600 return uno::Any();
603 String ScVbaEventsHelper::getSheetModuleName( SCTAB nTab )
605 ScExtDocOptions* pExtOptions = pDoc->GetExtDocOptions();
606 String aCodeName;
607 pDoc->GetName( nTab, aCodeName);
608 // Use code name if that exists
609 if ( pExtOptions )
610 aCodeName = pExtOptions->GetCodeName( nTab );
611 return aCodeName;
614 rtl::OUString
615 ScVbaEventsHelper::getMacroPath( const sal_Int32 nEventId, const SCTAB nTab )
617 SfxObjectShell* pShell = pDoc->GetDocumentShell();
618 String sMacroName = getEventName( nEventId );
619 VBAMacroResolvedInfo sMacroResolvedInfo;
620 switch( nEventId )
622 // Worksheet
623 case VBAEVENT_WORKSHEET_ACTIVATE :
624 case VBAEVENT_WORKSHEET_BEFOREDOUBLECLICK :
625 case VBAEVENT_WORKSHEET_BEFORERIGHTCLICK :
626 case VBAEVENT_WORKSHEET_CALCULATE :
627 case VBAEVENT_WORKSHEET_CHANGE :
628 case VBAEVENT_WORKSHEET_DEACTIVATE :
629 case VBAEVENT_WORKSHEET_FOLLOWHYPERLINK :
630 case VBAEVENT_WORKSHEET_PIVOTTABLEUPDATE :
631 case VBAEVENT_WORKSHEET_SELECTIONCHANGE :
633 String aSheetModuleName = getSheetModuleName( nTab );
634 sMacroName.Insert( '.', 0 ).Insert( aSheetModuleName, 0);
635 sMacroResolvedInfo = resolveVBAMacro( pShell, sMacroName );
636 break;
638 // Workbook
639 case VBAEVENT_WORKBOOK_ACTIVATE :
640 case VBAEVENT_WORKBOOK_DEACTIVATE :
641 case VBAEVENT_WORKBOOK_OPEN :
642 case VBAEVENT_WORKBOOK_BEFORECLOSE :
643 case VBAEVENT_WORKBOOK_BEFOREPRINT :
644 case VBAEVENT_WORKBOOK_BEFORESAVE :
645 case VBAEVENT_WORKBOOK_NEWSHEET :
646 case VBAEVENT_WORKBOOK_WINDOWACTIVATE :
647 case VBAEVENT_WORKBOOK_WINDOWDEACTIVATE :
648 case VBAEVENT_WORKBOOK_WINDOWRESIZE :
649 // Workbook_sheet
650 case VBAEVENT_WORKBOOK_SHEET_ACTIVATE :
651 case VBAEVENT_WORKBOOK_SHEET_BEFOREDOUBLECLICK :
652 case VBAEVENT_WORKBOOK_SHEET_BEFORERIGHTCLICK :
653 case VBAEVENT_WORKBOOK_SHEET_CALCULATE :
654 case VBAEVENT_WORKBOOK_SHEET_CHANGE :
655 case VBAEVENT_WORKBOOK_SHEET_DEACTIVATE :
656 case VBAEVENT_WORKBOOK_SHEET_FOLLOWHYPERLINK :
657 case VBAEVENT_WORKBOOK_SHEET_PIVOTTABLEUPDATE :
658 case VBAEVENT_WORKBOOK_SHEET_SELECTIONCHANGE :
660 ScExtDocOptions* pExtOptions = pDoc->GetExtDocOptions();
661 String sWorkbookModuleName = pDoc->GetCodeName();
662 if( pExtOptions )
664 ScExtDocSettings aExtDocSettings = pExtOptions->GetDocSettings();
665 sWorkbookModuleName = aExtDocSettings.maGlobCodeName;
668 sMacroName.Insert( '.', 0 ).Insert( sWorkbookModuleName, 0);
669 sMacroResolvedInfo = resolveVBAMacro( pShell, sMacroName );
670 break;
672 case VBAEVENT_WORKBOOK_AUTOOPEN :
674 sMacroResolvedInfo = resolveVBAMacro( pShell, sMacroName );
675 break;
677 default:
678 break;
680 return sMacroResolvedInfo.ResolvedMacro();
683 sal_Bool ScVbaEventsHelper::processVbaEvent( const sal_Int32 nEventId, const uno::Sequence< uno::Any >& rArgs, const SCTAB nTab )
685 SfxObjectShell* pShell = pDoc->GetDocumentShell();
687 sal_Bool result = sal_False;
688 sal_Bool bCancel = sal_False;
689 uno::Sequence< uno::Any > aArgs;
690 uno::Any aRet;
691 uno::Any aDummyCaller;
693 // For most cases, there is no corresponsible event macro in the document.
694 // It is better fo check if the event macro exists before process the arguments to improve performance.
695 rtl::OUString sMacroPath = getMacroPath( nEventId, nTab );
696 if( sMacroPath.getLength() )
698 switch( nEventId )
700 case VBAEVENT_WORKSHEET_ACTIVATE:
701 case VBAEVENT_WORKSHEET_CALCULATE:
702 case VBAEVENT_WORKSHEET_DEACTIVATE:
703 case VBAEVENT_WORKBOOK_ACTIVATE:
704 case VBAEVENT_WORKBOOK_DEACTIVATE:
705 case VBAEVENT_WORKBOOK_OPEN:
706 case VBAEVENT_WORKBOOK_AUTOOPEN:
708 // no arguments
709 break;
711 case VBAEVENT_WORKBOOK_SHEET_DEACTIVATE:
712 case VBAEVENT_WORKBOOK_SHEET_CALCULATE:
713 case VBAEVENT_WORKBOOK_SHEET_ACTIVATE:
714 case VBAEVENT_WORKBOOK_NEWSHEET:
716 aArgs = uno::Sequence< uno::Any >(1);
717 aArgs[0] = createWorkSheet( pShell, nTab );
718 break;
720 case VBAEVENT_WORKSHEET_CHANGE:
721 case VBAEVENT_WORKSHEET_SELECTIONCHANGE:
723 // one argument: range
724 uno::Any aRange = createRange( rArgs[0] );
725 aArgs = uno::Sequence< uno::Any >(1);
726 aArgs[0] = aRange;
727 break;
729 case VBAEVENT_WORKBOOK_SHEET_CHANGE:
730 case VBAEVENT_WORKBOOK_SHEET_SELECTIONCHANGE:
732 uno::Any aRange = createRange( rArgs[0] );
733 aArgs = uno::Sequence< uno::Any >(2);
734 aArgs[0] = createWorkSheet( pShell, nTab );
735 aArgs[1] = aRange;
736 break;
738 case VBAEVENT_WORKSHEET_BEFOREDOUBLECLICK:
739 case VBAEVENT_WORKSHEET_BEFORERIGHTCLICK:
741 // two aruments: range and cancel
742 uno::Any aRange = createRange( rArgs[0] );
743 aArgs = uno::Sequence< uno::Any >(2);
744 aArgs[0] = aRange;
745 aArgs[1] <<= bCancel;
746 // TODO: process "cancel" action
747 break;
749 case VBAEVENT_WORKBOOK_SHEET_BEFOREDOUBLECLICK:
750 case VBAEVENT_WORKBOOK_SHEET_BEFORERIGHTCLICK:
752 uno::Any aRange = createRange( rArgs[0] );
753 aArgs = uno::Sequence< uno::Any >(3);
754 aArgs[0] = createWorkSheet( pShell, nTab );
755 aArgs[1] = aRange;
756 aArgs[2] <<= bCancel;
757 // TODO: process "cancel" action
758 break;
760 case VBAEVENT_WORKSHEET_FOLLOWHYPERLINK:
762 // one argument: hyperlink
763 uno::Any aHyperlink = createHyperlink( rArgs[0] );
764 aArgs = uno::Sequence< uno::Any >(1);
765 aArgs[0] = aHyperlink;
766 break;
768 case VBAEVENT_WORKBOOK_SHEET_FOLLOWHYPERLINK:
770 uno::Any aHyperlink = createHyperlink( rArgs[0] );
771 aArgs = uno::Sequence< uno::Any >(2);
772 aArgs[0] = createWorkSheet( pShell, nTab );
773 aArgs[1] = aHyperlink;
774 break;
776 case VBAEVENT_WORKSHEET_PIVOTTABLEUPDATE:
777 case VBAEVENT_WORKBOOK_SHEET_PIVOTTABLEUPDATE:
779 // one argument: pivottable
780 // TODO: not support yet
781 return result;
783 case VBAEVENT_WORKBOOK_BEFORECLOSE:
784 case VBAEVENT_WORKBOOK_BEFOREPRINT:
786 // process Cancel argument
787 aArgs = uno::Sequence< uno::Any >(1);
788 aArgs[0] <<= bCancel;
789 executeMacro( pShell, sMacroPath, aArgs, aRet, aDummyCaller );
790 aArgs[0] >>= bCancel;
791 return bCancel;
793 case VBAEVENT_WORKBOOK_BEFORESAVE:
795 // two arguments: SaveAs and Cancel
796 aArgs = uno::Sequence< uno::Any >(2);
797 aArgs[0] = rArgs[0];
798 aArgs[1] <<= bCancel;
799 executeMacro( pShell, sMacroPath, aArgs, aRet, aDummyCaller );
800 aArgs[1] >>= bCancel;
801 return bCancel;
803 case VBAEVENT_WORKBOOK_WINDOWACTIVATE:
804 case VBAEVENT_WORKBOOK_WINDOWDEACTIVATE:
805 case VBAEVENT_WORKBOOK_WINDOWRESIZE:
807 // one argument: windows
808 aArgs = uno::Sequence< uno::Any >(1);
809 aArgs[0] = createWindow( pShell );
810 break;
812 default:
813 return result;
816 // excute the macro
817 result = executeMacro( pShell, sMacroPath, aArgs, aRet, aDummyCaller );
820 return result;
823 SCTAB ScVbaEventsHelper::getTabFromArgs( const uno::Sequence< uno::Any > aArgs, const sal_Int32 nPos )
825 SCTAB nTab = -1;
826 uno::Reference< sheet::XCellRangeAddressable > xCellRangeAddressable( getXSomethingFromArgs< sheet::XCellRangeAddressable >( aArgs, nPos ), uno::UNO_QUERY );
827 if( xCellRangeAddressable.is() )
829 table::CellRangeAddress aAddress = xCellRangeAddressable->getRangeAddress();
830 nTab = aAddress.Sheet;
832 else
834 uno::Reference< sheet::XSheetCellRangeContainer > xRanges( getXSomethingFromArgs< sheet::XSheetCellRangeContainer >( aArgs, nPos ), uno::UNO_QUERY );
835 if( xRanges.is() )
837 uno::Sequence< table::CellRangeAddress > aRangeAddresses = xRanges->getRangeAddresses();
838 if( aRangeAddresses.getLength() > 0 )
840 nTab = aRangeAddresses[ 0 ].Sheet;
844 return nTab;
847 sal_Bool SAL_CALL
848 ScVbaEventsHelper::ProcessCompatibleVbaEvent( sal_Int32 nEventId, const uno::Sequence< uno::Any >& aArgs ) throw (uno::RuntimeException)
850 SfxObjectShell* pShell = pDoc->GetDocumentShell();
851 if( !pShell || mbIgnoreEvents)
852 return sal_False;
854 // In order to better support "withevents" in the future,
855 // it is better to process a event at a time
856 SCTAB nTab = INVALID_TAB;
857 switch( nEventId )
859 // Worksheet
860 case VBAEVENT_WORKSHEET_ACTIVATE:
862 aArgs[0] >>= nTab;
863 if( nTab != INVALID_TAB )
865 // process the event
866 processVbaEvent( nEventId, aArgs, nTab );
867 // recursive process related workbook sheet event.
868 ProcessCompatibleVbaEvent( VBAEVENT_WORKBOOK_SHEET_ACTIVATE, aArgs );
870 break;
872 case VBAEVENT_WORKSHEET_BEFOREDOUBLECLICK:
874 nTab = getTabFromArgs( aArgs );
875 if( nTab != INVALID_TAB )
877 processVbaEvent( nEventId, aArgs, nTab );
878 ProcessCompatibleVbaEvent( VBAEVENT_WORKBOOK_SHEET_BEFOREDOUBLECLICK, aArgs );
880 break;
882 case VBAEVENT_WORKSHEET_BEFORERIGHTCLICK:
884 nTab = getTabFromArgs( aArgs );
885 if( nTab != INVALID_TAB )
887 processVbaEvent( nEventId, aArgs, nTab );
888 ProcessCompatibleVbaEvent( VBAEVENT_WORKBOOK_SHEET_BEFORERIGHTCLICK, aArgs );
890 break;
892 case VBAEVENT_WORKSHEET_CALCULATE:
894 aArgs[0] >>= nTab;
895 if( nTab != INVALID_TAB )
897 processVbaEvent( nEventId, aArgs, nTab );
898 ProcessCompatibleVbaEvent( VBAEVENT_WORKBOOK_SHEET_CALCULATE, aArgs );
900 break;
902 case VBAEVENT_WORKSHEET_CHANGE:
904 nTab = getTabFromArgs( aArgs );
905 if( nTab != INVALID_TAB )
907 processVbaEvent( nEventId, aArgs, nTab );
908 ProcessCompatibleVbaEvent( VBAEVENT_WORKBOOK_SHEET_CHANGE, aArgs );
910 break;
912 case VBAEVENT_WORKSHEET_DEACTIVATE:
914 aArgs[0] >>= nTab;
915 if( nTab != INVALID_TAB )
917 processVbaEvent( nEventId, aArgs, nTab );
918 ProcessCompatibleVbaEvent( VBAEVENT_WORKBOOK_SHEET_DEACTIVATE, aArgs );
920 break;
922 case VBAEVENT_WORKSHEET_FOLLOWHYPERLINK:
924 nTab = getTabFromArgs( aArgs );
925 if( nTab != INVALID_TAB )
927 processVbaEvent( nEventId, aArgs, nTab );
928 ProcessCompatibleVbaEvent( VBAEVENT_WORKBOOK_SHEET_FOLLOWHYPERLINK, aArgs );
930 break;
932 case VBAEVENT_WORKSHEET_PIVOTTABLEUPDATE:
933 // TODO
934 break;
935 case VBAEVENT_WORKSHEET_SELECTIONCHANGE:
937 nTab = getTabFromArgs( aArgs );
938 if( nTab != INVALID_TAB )
940 processVbaEvent( nEventId, aArgs, nTab );
941 ProcessCompatibleVbaEvent( VBAEVENT_WORKBOOK_SHEET_SELECTIONCHANGE, aArgs );
943 break;
945 // Workbook_sheet
946 case VBAEVENT_WORKBOOK_SHEET_ACTIVATE:
947 case VBAEVENT_WORKBOOK_SHEET_CALCULATE:
948 case VBAEVENT_WORKBOOK_SHEET_DEACTIVATE:
950 aArgs[0] >>= nTab;
951 if( nTab != INVALID_TAB )
953 processVbaEvent( nEventId, aArgs, nTab );
955 break;
957 case VBAEVENT_WORKBOOK_SHEET_BEFOREDOUBLECLICK:
958 case VBAEVENT_WORKBOOK_SHEET_BEFORERIGHTCLICK:
959 case VBAEVENT_WORKBOOK_SHEET_CHANGE:
960 case VBAEVENT_WORKBOOK_SHEET_FOLLOWHYPERLINK:
961 case VBAEVENT_WORKBOOK_SHEET_SELECTIONCHANGE:
963 nTab = getTabFromArgs( aArgs );
964 if( nTab != INVALID_TAB )
966 processVbaEvent( nEventId, aArgs, nTab );
968 break;
970 case VBAEVENT_WORKBOOK_SHEET_PIVOTTABLEUPDATE:
971 // TODO
972 break;
973 // Workbook
974 case VBAEVENT_WORKBOOK_ACTIVATE:
976 // if workbook open event do not be fired. fired it before
977 // workbook activate event to compatible with MSO.
978 if( mbOpened )
980 // process workbook activate event
981 processVbaEvent( nEventId, aArgs );
982 // process workbook window activate event at the same time
983 ProcessCompatibleVbaEvent( VBAEVENT_WORKBOOK_WINDOWACTIVATE, aArgs );
985 break;
987 case VBAEVENT_WORKBOOK_DEACTIVATE:
989 processVbaEvent( nEventId, aArgs );
990 // same as workbook window deactivate
991 ProcessCompatibleVbaEvent( VBAEVENT_WORKBOOK_WINDOWDEACTIVATE, aArgs );
992 break;
994 case VBAEVENT_WORKBOOK_OPEN:
996 // process workbook open macro
997 // does auto open work here?
998 if( !mbOpened )
1000 processVbaEvent( nEventId, aArgs );
1001 processVbaEvent( VBAEVENT_WORKBOOK_AUTOOPEN, aArgs );
1002 mbOpened = sal_True;
1003 ProcessCompatibleVbaEvent( VBAEVENT_WORKBOOK_ACTIVATE, aArgs );
1005 // register the window listener.
1006 if( !m_xVbaEventsListener.is() )
1008 m_xVbaEventsListener = new VbaEventsListener( this );
1009 VbaEventsListener* pEventsListener = dynamic_cast< VbaEventsListener* >( m_xVbaEventsListener.get() );
1010 pEventsListener->startEventsLinstener();
1012 break;
1014 case VBAEVENT_WORKBOOK_BEFORECLOSE:
1016 sal_Bool bCancel = processVbaEvent( nEventId, aArgs );
1017 if( m_xVbaEventsListener.is() && !bCancel )
1019 VbaEventsListener* pEventsListener = dynamic_cast< VbaEventsListener* >( m_xVbaEventsListener.get() );
1020 pEventsListener->stopEventsLinstener();
1021 m_xVbaEventsListener = NULL;
1023 return bCancel;
1025 case VBAEVENT_WORKBOOK_BEFOREPRINT:
1026 case VBAEVENT_WORKBOOK_BEFORESAVE:
1027 case VBAEVENT_WORKBOOK_WINDOWACTIVATE:
1028 case VBAEVENT_WORKBOOK_WINDOWDEACTIVATE:
1029 case VBAEVENT_WORKBOOK_WINDOWRESIZE:
1031 return processVbaEvent( nEventId, aArgs );
1033 case VBAEVENT_WORKBOOK_NEWSHEET:
1035 aArgs[0] >>= nTab;
1036 if( nTab != INVALID_TAB )
1038 processVbaEvent( nEventId, aArgs, nTab );
1040 break;
1042 default:
1043 OSL_TRACE( "Invalid Event" );
1046 return sal_True;
1049 ::sal_Bool SAL_CALL
1050 ScVbaEventsHelper::getIgnoreEvents() throw (uno::RuntimeException)
1052 return mbIgnoreEvents;
1055 void SAL_CALL
1056 ScVbaEventsHelper::setIgnoreEvents( ::sal_Bool _ignoreevents ) throw (uno::RuntimeException)
1058 mbIgnoreEvents = _ignoreevents;
1062 namespace vbaeventshelper
1064 namespace sdecl = comphelper::service_decl;
1065 sdecl::class_<ScVbaEventsHelper, sdecl::with_args<true> > serviceImpl;
1066 extern sdecl::ServiceDecl const serviceDecl(
1067 serviceImpl,
1068 "ScVbaEventsHelper",
1069 "com.sun.star.document.VbaEventsHelper" );