diff options
author | Daniel Rentz <dr@openoffice.org> | 2010-07-06 19:34:53 +0200 |
---|---|---|
committer | Daniel Rentz <dr@openoffice.org> | 2010-07-06 19:34:53 +0200 |
commit | 0635ddfa883cd62183753804c4c0915475f3cc2d (patch) | |
tree | 49675d43007bc799a99b3cabeb0de51cbb457608 /sc | |
parent | 3ed00acdeb3014d8491ecd3e71fb035ae8ed6a8e (diff) |
mib17: #i112634# add VBA sheet event handling, based on a patch from Noel Power
Diffstat (limited to 'sc')
-rw-r--r-- | sc/inc/document.hxx | 15 | ||||
-rw-r--r-- | sc/inc/docuno.hxx | 9 | ||||
-rwxr-xr-x | sc/inc/sheetevents.hxx | 2 | ||||
-rw-r--r--[-rwxr-xr-x] | sc/source/core/data/documen2.cxx | 30 | ||||
-rw-r--r-- | sc/source/core/data/documen3.cxx | 38 | ||||
-rw-r--r-- | sc/source/core/data/documen7.cxx | 2 | ||||
-rwxr-xr-x | sc/source/core/data/sheetevents.cxx | 35 | ||||
-rw-r--r-- | sc/source/filter/excel/excimp8.cxx | 18 | ||||
-rw-r--r-- | sc/source/filter/inc/excimp8.hxx | 1 | ||||
-rw-r--r-- | sc/source/ui/docshell/docsh.cxx | 108 | ||||
-rw-r--r-- | sc/source/ui/docshell/docsh4.cxx | 2 | ||||
-rw-r--r-- | sc/source/ui/unoobj/docuno.cxx | 108 | ||||
-rw-r--r-- | sc/source/ui/unoobj/viewuno.cxx | 140 | ||||
-rw-r--r-- | sc/source/ui/vba/makefile.mk | 2 | ||||
-rw-r--r-- | sc/source/ui/vba/service.cxx | 12 | ||||
-rw-r--r-- | sc/source/ui/vba/vbaapplication.cxx | 20 | ||||
-rw-r--r-- | sc/source/ui/vba/vbaapplication.hxx | 7 | ||||
-rwxr-xr-x | sc/source/ui/vba/vbaeventshelper.cxx | 775 | ||||
-rwxr-xr-x | sc/source/ui/vba/vbaeventshelper.hxx | 86 | ||||
-rw-r--r-- | sc/source/ui/vba/vbaglobals.cxx | 1 | ||||
-rw-r--r-- | sc/source/ui/view/gridwin.cxx | 76 | ||||
-rw-r--r-- | sc/source/ui/view/makefile.mk | 1 |
22 files changed, 1331 insertions, 157 deletions
diff --git a/sc/inc/document.hxx b/sc/inc/document.hxx index 109e71b3c..48158e69d 100644 --- a/sc/inc/document.hxx +++ b/sc/inc/document.hxx @@ -159,6 +159,9 @@ namespace com { namespace sun { namespace star { namespace embed { class XEmbeddedObject; } + namespace script { namespace vba { + class XEventProcessor; + } } } } } #include <svl/zforlist.hxx> @@ -329,6 +332,10 @@ private: Timer aTrackTimer; + // mutable for lazy construction + mutable com::sun::star::uno::Reference< com::sun::star::script::vba::XEventProcessor > + mxVbaEvents; + public: ScTabOpList aTableOpList; // list of ScInterpreterTableOpParams currently in use ScInterpreterTableOpParams aLastTableOpParams; // remember last params @@ -733,7 +740,8 @@ public: const ScSheetEvents* GetSheetEvents( SCTAB nTab ) const; void SetSheetEvents( SCTAB nTab, const ScSheetEvents* pNew ); - bool HasSheetEventScript( sal_Int32 nEvent ) const; // on any sheet + bool HasSheetEventScript( SCTAB nTab, sal_Int32 nEvent, bool bWithVbaEvents = false ) const; + bool HasAnySheetEventScript( sal_Int32 nEvent, bool bWithVbaEvents = false ) const; // on any sheet BOOL HasCalcNotification( SCTAB nTab ) const; void SetCalcNotification( SCTAB nTab ); @@ -901,7 +909,7 @@ public: BOOL IsForcedFormulaPending() const { return bForcedFormulaPending; } // if CalcFormulaTree() is currently running BOOL IsCalculatingFormulaTree() { return bCalculatingFormulaTree; } - + USHORT GetErrCode( const ScAddress& ) const; /** Shrink a range to only include data area. @@ -1751,6 +1759,9 @@ public: void GetSortParam( ScSortParam& rParam, SCTAB nTab ); void SetSortParam( ScSortParam& rParam, SCTAB nTab ); + com::sun::star::uno::Reference< com::sun::star::script::vba::XEventProcessor > + GetVbaEventProcessor() const; + /** Should only be GRAM_PODF or GRAM_ODFF. */ void SetStorageGrammar( formula::FormulaGrammar::Grammar eGrammar ); formula::FormulaGrammar::Grammar GetStorageGrammar() const diff --git a/sc/inc/docuno.hxx b/sc/inc/docuno.hxx index 00c800e95..8686fd600 100644 --- a/sc/inc/docuno.hxx +++ b/sc/inc/docuno.hxx @@ -53,6 +53,7 @@ #include <com/sun/star/beans/XPropertySet.hpp> #include <com/sun/star/sheet/XCellRangesAccess.hpp> #include <com/sun/star/util/XChangesNotifier.hpp> +#include <com/sun/star/script/vba/XCoreEventProcessor.hpp> #include <cppuhelper/implbase2.hxx> #include <cppuhelper/implbase3.hxx> #include <cppuhelper/implbase4.hxx> @@ -88,6 +89,7 @@ class SC_DLLPUBLIC ScModelObj : public SfxBaseModel, public com::sun::star::view::XRenderable, public com::sun::star::document::XLinkTargetSupplier, public com::sun::star::beans::XPropertySet, + public com::sun::star::script::vba::XCoreEventProcessor, public SvxFmMSFactory, // derived from XMultiServiceFactory public com::sun::star::lang::XServiceInfo, public ::com::sun::star::util::XChangesNotifier @@ -321,6 +323,13 @@ public: virtual void SAL_CALL removeChangesListener( const ::com::sun::star::uno::Reference< ::com::sun::star::util::XChangesListener >& aListener ) throw (::com::sun::star::uno::RuntimeException); + + // XCoreEventProcessor + virtual void SAL_CALL processCoreVbaEvent( sal_Int32 nSlotId ) + throw (::com::sun::star::lang::IllegalArgumentException, + ::com::sun::star::script::provider::ScriptFrameworkErrorException, + ::com::sun::star::util::VetoException, + ::com::sun::star::uno::RuntimeException); }; diff --git a/sc/inc/sheetevents.hxx b/sc/inc/sheetevents.hxx index a8650c078..772908f2e 100755 --- a/sc/inc/sheetevents.hxx +++ b/sc/inc/sheetevents.hxx @@ -59,6 +59,8 @@ public: void SetScript(sal_Int32 nEvent, const rtl::OUString* pNew); static rtl::OUString GetEventName(sal_Int32 nEvent); + static sal_Int32 GetVbaSheetEventId(sal_Int32 nEvent); + static sal_Int32 GetVbaDocumentEventId(sal_Int32 nEvent); }; #endif diff --git a/sc/source/core/data/documen2.cxx b/sc/source/core/data/documen2.cxx index 9ba630ad3..8a8e46aad 100755..100644 --- a/sc/source/core/data/documen2.cxx +++ b/sc/source/core/data/documen2.cxx @@ -50,6 +50,9 @@ #include <tools/tenccvt.hxx> #include <tools/list.hxx> #include <rtl/crc.h> +#include <basic/basmgr.hxx> +#include <com/sun/star/script/vba/XEventProcessor.hpp> +#include <vbahelper/vbaaccesshelper.hxx> #include "document.hxx" #include "table.hxx" @@ -93,7 +96,8 @@ #include "tabprotection.hxx" #include "formulaparserpool.hxx" #include "clipparam.hxx" -#include <basic/basmgr.hxx> + +using namespace com::sun::star; // pImpl because including lookupcache.hxx in document.hxx isn't wanted, and // dtor plus helpers are convenient. @@ -1116,11 +1120,11 @@ ULONG ScDocument::TransferTab( ScDocument* pSrcDoc, SCTAB nSrcPos, String sCodeName; String sSource; - com::sun::star::uno::Reference< com::sun::star::script::XLibraryContainer > xLibContainer = pSrcShell->GetBasicContainer(); - com::sun::star::uno::Reference< com::sun::star::container::XNameContainer > xLib; + uno::Reference< script::XLibraryContainer > xLibContainer = pSrcShell->GetBasicContainer(); + uno::Reference< container::XNameContainer > xLib; if( xLibContainer.is() ) { - com::sun::star::uno::Any aLibAny = xLibContainer->getByName( aLibName ); + uno::Any aLibAny = xLibContainer->getByName( aLibName ); aLibAny >>= xLib; } @@ -1289,6 +1293,24 @@ void ScDocument::RemoveLookupCache( ScLookupCache & rCache ) } } +uno::Reference< script::vba::XEventProcessor > ScDocument::GetVbaEventProcessor() const +{ + if( !mxVbaEvents.is() && pShell && ooo::vba::isAlienExcelDoc( *pShell ) ) + { + try + { + uno::Reference< frame::XModel > xModel( pShell->GetModel(), uno::UNO_QUERY_THROW ); + uno::Sequence< uno::Any > aArgs(1); + aArgs[0] <<= xModel; + mxVbaEvents.set( ooo::vba::createVBAUnoAPIServiceWithArgs( pShell, "com.sun.star.script.vba.SpreadsheetEventProcessor" , aArgs ), uno::UNO_QUERY_THROW ); + } + catch( uno::Exception& ) + { + } + } + return mxVbaEvents; +} + void ScDocument::ClearLookupCaches() { if( pLookupCacheMapImpl ) diff --git a/sc/source/core/data/documen3.cxx b/sc/source/core/data/documen3.cxx index da220a876..b922757f6 100644 --- a/sc/source/core/data/documen3.cxx +++ b/sc/source/core/data/documen3.cxx @@ -30,6 +30,7 @@ // INCLUDE --------------------------------------------------------------- +#include <com/sun/star/script/vba/XEventProcessor.hpp> #include "scitems.hxx" #include <editeng/langitem.hxx> #include <svl/srchitem.hxx> @@ -88,7 +89,6 @@ #include <memory> using namespace com::sun::star; -using ::std::auto_ptr; //------------------------------------------------------------------------ @@ -492,15 +492,39 @@ void ScDocument::SetSheetEvents( SCTAB nTab, const ScSheetEvents* pNew ) pTab[nTab]->SetSheetEvents( pNew ); } -bool ScDocument::HasSheetEventScript( sal_Int32 nEvent ) const +bool ScDocument::HasSheetEventScript( SCTAB nTab, sal_Int32 nEvent, bool bWithVbaEvents ) const { - for (SCTAB nTab = 0; nTab <= MAXTAB; nTab++) - if (pTab[nTab]) + if (pTab[nTab]) + { + // check if any event handler script has been configured + const ScSheetEvents* pEvents = pTab[nTab]->GetSheetEvents(); + if ( pEvents && pEvents->GetScript( nEvent ) ) + return true; + // check if VBA event handlers exist + if (bWithVbaEvents) { - const ScSheetEvents* pEvents = pTab[nTab]->GetSheetEvents(); - if ( pEvents && pEvents->GetScript( nEvent ) ) - return true; + uno::Reference< script::vba::XEventProcessor > xVbaEvents = GetVbaEventProcessor(); + if ( xVbaEvents.is() ) try + { + uno::Sequence< uno::Any > aArgs( 1 ); + aArgs[ 0 ] <<= nTab; + if (xVbaEvents->hasVbaEventHandler( ScSheetEvents::GetVbaSheetEventId( nEvent ), aArgs ) || + xVbaEvents->hasVbaEventHandler( ScSheetEvents::GetVbaDocumentEventId( nEvent ), uno::Sequence< uno::Any >() )) + return true; + } + catch( uno::Exception& ) + { + } } + } + return false; +} + +bool ScDocument::HasAnySheetEventScript( sal_Int32 nEvent, bool bWithVbaEvents ) const +{ + for (SCTAB nTab = 0; nTab <= MAXTAB; nTab++) + if (HasSheetEventScript( nTab, nEvent, bWithVbaEvents )) + return true; return false; } diff --git a/sc/source/core/data/documen7.cxx b/sc/source/core/data/documen7.cxx index 5c9e8d5c0..96484dc2f 100644 --- a/sc/source/core/data/documen7.cxx +++ b/sc/source/core/data/documen7.cxx @@ -454,7 +454,7 @@ void ScDocument::TrackFormulas( ULONG nHintId ) { erBEEPER(); // outside the loop, check if any sheet has a "calculate" event script - bool bCalcEvent = HasSheetEventScript( SC_SHEETEVENT_CALCULATE ); + bool bCalcEvent = HasAnySheetEventScript( SC_SHEETEVENT_CALCULATE, true ); SvtBroadcaster* pBC; ScFormulaCell* pTrack; ScFormulaCell* pNext; diff --git a/sc/source/core/data/sheetevents.cxx b/sc/source/core/data/sheetevents.cxx index 37546e6a3..12159e8d9 100755 --- a/sc/source/core/data/sheetevents.cxx +++ b/sc/source/core/data/sheetevents.cxx @@ -33,9 +33,9 @@ // INCLUDE --------------------------------------------------------------- -#include <tools/debug.hxx> - #include "sheetevents.hxx" +#include <com/sun/star/script/vba/EventIdentifier.hpp> +#include <tools/debug.hxx> // ----------------------------------------------------------------------- @@ -61,6 +61,37 @@ rtl::OUString ScSheetEvents::GetEventName(sal_Int32 nEvent) return rtl::OUString::createFromAscii(aEventNames[nEvent]); } +// static +sal_Int32 ScSheetEvents::GetVbaSheetEventId(sal_Int32 nEvent) +{ + using namespace ::com::sun::star::script::vba::EventIdentifier; + if (nEvent<0 || nEvent>=SC_SHEETEVENT_COUNT) + { + DBG_ERRORFILE("invalid event number"); + return NO_EVENT; + } + + static const sal_Int32 nVbaEventIds[] = + { + WORKSHEET_ACTIVATE, // SC_SHEETEVENT_FOCUS + WORKSHEET_DEACTIVATE, // SC_SHEETEVENT_UNFOCUS + WORKSHEET_SELECTIONCHANGE, // SC_SHEETEVENT_SELECT + WORKSHEET_BEFOREDOUBLECLICK, // SC_SHEETEVENT_DOUBLECLICK + WORKSHEET_BEFORERIGHTCLICK, // SC_SHEETEVENT_RIGHTCLICK + WORKSHEET_CHANGE, // SC_SHEETEVENT_CHANGE + WORKSHEET_CALCULATE // SC_SHEETEVENT_CALCULATE + }; + return nVbaEventIds[nEvent]; +} + +// static +sal_Int32 ScSheetEvents::GetVbaDocumentEventId(sal_Int32 nEvent) +{ + using namespace ::com::sun::star::script::vba::EventIdentifier; + sal_Int32 nSheetEventId = GetVbaSheetEventId(nEvent); + return (nSheetEventId != NO_EVENT) ? (nSheetEventId + USERDEFINED_START) : NO_EVENT; +} + // ----------------------------------------------------------------------- ScSheetEvents::ScSheetEvents() : diff --git a/sc/source/filter/excel/excimp8.cxx b/sc/source/filter/excel/excimp8.cxx index 3101922a8..46e97e4b1 100644 --- a/sc/source/filter/excel/excimp8.cxx +++ b/sc/source/filter/excel/excimp8.cxx @@ -56,7 +56,6 @@ #include <svx/xflclit.hxx> #include <filter/msfilter/svxmsbas.hxx> #include <basic/basmgr.hxx> -#include <oox/xls/excelvbaproject.hxx> #include <vcl/graph.hxx> #include <vcl/bmpacc.hxx> @@ -292,8 +291,6 @@ void ImportExcel8::PostDocLoad( void ) // read doc info (no docshell while pasting from clipboard) LoadDocumentProperties(); - // attach document events to VBA macros - AttachDocumentEvents(); // #i45843# Pivot tables are now handled outside of PostDocLoad, so they are available // when formula cells are calculated, for the GETPIVOTDATA function. @@ -318,21 +315,6 @@ void ImportExcel8::LoadDocumentProperties() } } -void ImportExcel8::AttachDocumentEvents() -{ - SfxObjectShell* pShell = GetDocShell(); - if( HasBasic() && pShell ) - { - uno::Reference< lang::XMultiServiceFactory > xGlobalFactory = ::comphelper::getProcessServiceFactory(); - uno::Reference< sheet::XSpreadsheetDocument > xDocument( pShell->GetModel(), uno::UNO_QUERY ); - if( xGlobalFactory.is() && xDocument.is() ) - { - ::oox::xls::VbaProject aVbaProject( xGlobalFactory, xDocument ); - aVbaProject.attachToEvents(); - } - } -} - //___________________________________________________________________ // autofilter diff --git a/sc/source/filter/inc/excimp8.hxx b/sc/source/filter/inc/excimp8.hxx index 35a1e81cd..d3cca163d 100644 --- a/sc/source/filter/inc/excimp8.hxx +++ b/sc/source/filter/inc/excimp8.hxx @@ -81,7 +81,6 @@ protected: private: void LoadDocumentProperties(); - void AttachDocumentEvents(); }; diff --git a/sc/source/ui/docshell/docsh.cxx b/sc/source/ui/docshell/docsh.cxx index 3049f4889..8c29cae3a 100644 --- a/sc/source/ui/docshell/docsh.cxx +++ b/sc/source/ui/docshell/docsh.cxx @@ -29,15 +29,11 @@ #include "precompiled_sc.hxx" // System - Includes ----------------------------------------------------- - - #include "scitems.hxx" #include <editeng/eeitem.hxx> #include <editeng/svxenum.hxx> #include <svx/algitem.hxx> - - #include <sot/clsids.hxx> #include <unotools/securityoptions.hxx> #include <tools/stream.hxx> @@ -68,7 +64,10 @@ #include "chgviset.hxx" #include <sfx2/request.hxx> #include <com/sun/star/document/UpdateDocMode.hpp> - +#include <com/sun/star/script/vba/EventIdentifier.hpp> +#include <com/sun/star/script/vba/XEventProcessor.hpp> +#include <basic/sbstar.hxx> +#include <basic/basmgr.hxx> #include "scabstdlg.hxx" //CHINA001 #include <sot/formats.hxx> @@ -123,8 +122,9 @@ #include <rtl/logfile.hxx> #include <comphelper/processfactory.hxx> -#include <basic/sbstar.hxx> -#include <basic/basmgr.hxx> +#include "uiitems.hxx" +#include "cellsuno.hxx" + using namespace com::sun::star; using ::rtl::OUString; using ::rtl::OUStringBuffer; @@ -272,6 +272,11 @@ void ScDocShell::BeforeXMLLoading() { aDocument.DisableIdle( TRUE ); + // suppress VBA events when loading the xml + uno::Reference< script::vba::XEventProcessor > xVbaEvents = aDocument.GetVbaEventProcessor(); + if( xVbaEvents.is() ) + xVbaEvents->setIgnoreEvents( sal_True ); + // prevent unnecessary broadcasts and updates DBG_ASSERT(pModificator == NULL, "The Modificator should not exist"); pModificator = new ScDocShellModificator( *this ); @@ -377,6 +382,12 @@ void ScDocShell::AfterXMLLoading(sal_Bool bRet) BasicManager* pAppMgr = SFX_APP()->GetBasicManager(); if ( pAppMgr ) pAppMgr->SetGlobalUNOConstant( "ThisExcelDoc", aArgs[ 0 ] ); +#if 0 // this should be controlled by a compatibility mode + // suppress VBA events when loading the xml + uno::Reference< script::vba::XEventProcessor > xVbaEvents = aDocument.GetVbaEventProcessor(); + if( xVbaEvents.is() ) + xVbaEvents->setIgnoreEvents( sal_False ); +#endif #endif aDocument.SetImportingXML( FALSE ); aDocument.EnableExecuteLink( true ); @@ -499,9 +510,70 @@ BOOL __EXPORT ScDocShell::Load( SfxMedium& rMedium ) return bRet; } - void __EXPORT ScDocShell::Notify( SfxBroadcaster&, const SfxHint& rHint ) { + uno::Reference< script::vba::XEventProcessor > xVbaEvents = aDocument.GetVbaEventProcessor(); + if ( xVbaEvents.is() ) try + { + using namespace ::com::sun::star::script::vba::EventIdentifier; + if (rHint.ISA(ScTablesHint) ) + { + const ScTablesHint& rScHint = static_cast< const ScTablesHint& >( rHint ); + if (rScHint.GetId() == SC_TAB_INSERTED) + { + uno::Sequence< uno::Any > aArgs( 1 ); + aArgs[0] <<= rScHint.GetTab1(); + xVbaEvents->processVbaEvent( WORKBOOK_NEWSHEET, aArgs ); + } + } + else if ( rHint.ISA( SfxEventHint ) ) + { + ULONG nEventId = static_cast< const SfxEventHint& >( rHint ).GetEventId(); + switch ( nEventId ) + { + case SFX_EVENT_ACTIVATEDOC: + { + uno::Sequence< uno::Any > aArgs; + xVbaEvents->processVbaEvent( WORKBOOK_ACTIVATE, aArgs ); + } + break; + case SFX_EVENT_DEACTIVATEDOC: + { + uno::Sequence< uno::Any > aArgs; + xVbaEvents->processVbaEvent( WORKBOOK_DEACTIVATE, aArgs ); + } + break; + case SFX_EVENT_OPENDOC: + { + uno::Sequence< uno::Any > aArgs; + xVbaEvents->processVbaEvent( WORKBOOK_OPEN, aArgs ); + } + break; + case SFX_EVENT_SAVEDOCDONE: + case SFX_EVENT_SAVEASDOCDONE: + case SFX_EVENT_SAVETODOCDONE: + { + uno::Sequence< uno::Any > aArgs( 1 ); + aArgs[ 0 ] <<= true; + xVbaEvents->processVbaEvent( WORKBOOK_AFTERSAVE, aArgs ); + } + break; + case SFX_EVENT_SAVEASDOCFAILED: + case SFX_EVENT_SAVEDOCFAILED: + case SFX_EVENT_SAVETODOCFAILED: + { + uno::Sequence< uno::Any > aArgs( 1 ); + aArgs[ 0 ] <<= false; + xVbaEvents->processVbaEvent( WORKBOOK_AFTERSAVE, aArgs ); + } + break; + } + } + } + catch( uno::Exception& ) + { + } + if (rHint.ISA(SfxSimpleHint)) // ohne Parameter { ULONG nSlot = ((const SfxSimpleHint&)rHint).GetId(); @@ -2197,6 +2269,26 @@ USHORT __EXPORT ScDocShell::PrepareClose( BOOL bUI, BOOL bForBrowsing ) DoEnterHandler(); + // start 'Workbook_BeforeClose' VBA event handler for possible veto + if( !IsInPrepareClose() ) + { + try + { + uno::Reference< script::vba::XEventProcessor > xVbaEvents( aDocument.GetVbaEventProcessor(), uno::UNO_SET_THROW ); + uno::Sequence< uno::Any > aArgs; + xVbaEvents->processVbaEvent( script::vba::EventIdentifier::WORKBOOK_BEFORECLOSE, aArgs ); + } + catch( util::VetoException& ) + { + // if event processor throws VetoException, macro has vetoed close + return sal_False; + } + catch( uno::Exception& ) + { + } + } + // end handler code + USHORT nRet = SfxObjectShell::PrepareClose( bUI, bForBrowsing ); if (nRet == TRUE) // TRUE = schliessen aDocument.DisableIdle(TRUE); // nicht mehr drin rumpfuschen !!! diff --git a/sc/source/ui/docshell/docsh4.cxx b/sc/source/ui/docshell/docsh4.cxx index 255b24c54..bbd2058f3 100644 --- a/sc/source/ui/docshell/docsh4.cxx +++ b/sc/source/ui/docshell/docsh4.cxx @@ -1295,7 +1295,7 @@ void ScDocShell::DoHardRecalc( BOOL /* bApi */ ) // (might check for the presence of any formulas on each sheet) SCTAB nTabCount = aDocument.GetTableCount(); SCTAB nTab; - if (aDocument.HasSheetEventScript( SC_SHEETEVENT_CALCULATE )) + if (aDocument.HasAnySheetEventScript( SC_SHEETEVENT_CALCULATE, true )) // search also for VBA hendler for (nTab=0; nTab<nTabCount; nTab++) aDocument.SetCalcNotification(nTab); diff --git a/sc/source/ui/unoobj/docuno.cxx b/sc/source/ui/unoobj/docuno.cxx index 89660806e..42704e106 100644 --- a/sc/source/ui/unoobj/docuno.cxx +++ b/sc/source/ui/unoobj/docuno.cxx @@ -28,14 +28,13 @@ // MARKER(update_precomp.py): autogen include statement, do not remove #include "precompiled_sc.hxx" - - #include "scitems.hxx" #include <svx/fmdpage.hxx> #include <svx/fmview.hxx> #include <svx/svditer.hxx> #include <svx/svdpage.hxx> #include <svx/svxids.hrc> +#include <svx/unoshape.hxx> #include <svl/numuno.hxx> #include <svl/smplhint.hxx> @@ -49,6 +48,7 @@ #include <tools/multisel.hxx> #include <tools/resary.hxx> #include <toolkit/awt/vclxdevice.hxx> + #include <ctype.h> #include <float.h> // DBL_MAX @@ -60,6 +60,8 @@ #include <com/sun/star/lang/XInitialization.hpp> #include <com/sun/star/lang/ServiceNotRegisteredException.hpp> #include <com/sun/star/document/XDocumentEventBroadcaster.hpp> +#include <com/sun/star/script/vba/EventIdentifier.hpp> +#include <com/sun/star/script/vba/XEventProcessor.hpp> #include <com/sun/star/script/XInvocation.hpp> #include <com/sun/star/reflection/XIdlClassProvider.hpp> #include <comphelper/processfactory.hxx> @@ -100,12 +102,10 @@ #include "sc.hrc" #include "scresid.hxx" -#ifndef _SVX_UNOSHAPE_HXX -#include <svx/unoshape.hxx> -#endif - using namespace com::sun::star; +#define SC_UNO_VBADOCOBJ "ThisVBADocObj" // perhaps we want to actually make this ThisWorkbook ? + //------------------------------------------------------------------------ // alles ohne Which-ID, Map nur fuer PropertySetInfo @@ -120,6 +120,7 @@ const SfxItemPropertyMapEntry* lcl_GetDocOptPropertyMap() {MAP_CHAR_LEN(SC_UNO_AUTOCONTFOC), 0, &getBooleanCppuType(), 0, 0}, {MAP_CHAR_LEN(SC_UNO_BASICLIBRARIES), 0, &getCppuType((uno::Reference< script::XLibraryContainer >*)0), beans::PropertyAttribute::READONLY, 0}, {MAP_CHAR_LEN(SC_UNO_DIALOGLIBRARIES), 0, &getCppuType((uno::Reference< script::XLibraryContainer >*)0), beans::PropertyAttribute::READONLY, 0}, + {MAP_CHAR_LEN(SC_UNO_VBADOCOBJ), 0, &getCppuType((beans::PropertyValue*)0), beans::PropertyAttribute::READONLY, 0}, {MAP_CHAR_LEN(SC_UNO_CALCASSHOWN), PROP_UNO_CALCASSHOWN, &getBooleanCppuType(), 0, 0}, {MAP_CHAR_LEN(SC_UNONAME_CLOCAL), 0, &getCppuType((lang::Locale*)0), 0, 0}, {MAP_CHAR_LEN(SC_UNO_CJK_CLOCAL), 0, &getCppuType((lang::Locale*)0), 0, 0}, @@ -468,6 +469,7 @@ uno::Any SAL_CALL ScModelObj::queryInterface( const uno::Type& rType ) SC_QUERYINTERFACE( view::XRenderable ) SC_QUERYINTERFACE( document::XLinkTargetSupplier ) SC_QUERYINTERFACE( beans::XPropertySet ) + SC_QUERYINTERFACE( script::vba::XCoreEventProcessor ) SC_QUERYINTERFACE( lang::XMultiServiceFactory ) SC_QUERYINTERFACE( lang::XServiceInfo ) SC_QUERYINTERFACE( util::XChangesNotifier ) @@ -593,8 +595,8 @@ void ScModelObj::Notify( SfxBroadcaster& rBC, const SfxHint& rHint ) DELETEZ( pPrintFuncCache ); - // handle "OnCalculate" sheet events - if ( pDocShell && pDocShell->GetDocument()->HasSheetEventScript( SC_SHEETEVENT_CALCULATE ) ) + // handle "OnCalculate" sheet events (search also for VBA event handlers) + if ( pDocShell && pDocShell->GetDocument()->HasAnySheetEventScript( SC_SHEETEVENT_CALCULATE, true ) ) HandleCalculateEvents(); } } @@ -1885,6 +1887,18 @@ uno::Any SAL_CALL ScModelObj::getPropertyValue( const rtl::OUString& aPropertyNa { aRet <<= pDocShell->GetDialogContainer(); } + else if ( aString.EqualsAscii( SC_UNO_VBADOCOBJ ) ) + { + // PropertyValue seems extreme because we store + // the model ( as the value member ) of the PropertyValue that is + // itself a property of the model ( the intention however is to + // store something like a Workbook object... but we don't do that ) + // yet + beans::PropertyValue aProp; + aProp.Name = rtl::OUString( RTL_CONSTASCII_USTRINGPARAM("ThisExcelDoc") ); + aProp.Value <<= pDocShell->GetModel(); + aRet <<= aProp; + } else if ( aString.EqualsAscii( SC_UNO_RUNTIMEUID ) ) { aRet <<= getRuntimeUID(); @@ -2058,6 +2072,38 @@ uno::Sequence<rtl::OUString> SAL_CALL ScModelObj::getAvailableServiceNames() return concatServiceNames( aMyServices, aDrawServices ); } +// XCoreEventProcessor + +void SAL_CALL ScModelObj::processCoreVbaEvent( sal_Int32 nSlotId ) + throw (lang::IllegalArgumentException, script::provider::ScriptFrameworkErrorException, util::VetoException, uno::RuntimeException) +{ + using namespace ::com::sun::star::script::vba; + + sal_Int32 nVbaEventId = EventIdentifier::NO_EVENT; + uno::Sequence< uno::Any > aArgs; + switch( nSlotId ) + { + case SID_SAVEDOC: + case SID_SAVEASDOC: + nVbaEventId = EventIdentifier::WORKBOOK_BEFORESAVE; + aArgs.realloc( 1 ); + aArgs[ 0 ] <<= (nSlotId == SID_SAVEASDOC); + break; + case SID_PRINTDOC: + case SID_PRINTDOCDIRECT: + nVbaEventId = EventIdentifier::WORKBOOK_BEFOREPRINT; + break; + default: + throw lang::IllegalArgumentException(); + } + + uno::Reference< XEventProcessor > xEventProcessor( GetDocument()->GetVbaEventProcessor(), uno::UNO_QUERY ); + if( !xEventProcessor.is() ) + throw script::provider::ScriptFrameworkErrorException(); + + xEventProcessor->processVbaEvent( nVbaEventId, aArgs ); +} + // XServiceInfo rtl::OUString SAL_CALL ScModelObj::getImplementationName() throw(uno::RuntimeException) @@ -2173,20 +2219,8 @@ bool ScModelObj::HasChangesListeners() const if ( maChangesListeners.getLength() > 0 ) return true; - if ( pDocShell ) - { - // "change" event set in any sheet? - ScDocument* pDoc = pDocShell->GetDocument(); - SCTAB nTabCount = pDoc->GetTableCount(); - for (SCTAB nTab = 0; nTab < nTabCount; nTab++) - { - const ScSheetEvents* pEvents = pDoc->GetSheetEvents(nTab); - if (pEvents && pEvents->GetScript(SC_SHEETEVENT_CHANGE)) - return true; - } - } - - return false; + // "change" event set in any sheet? + return pDocShell && pDocShell->GetDocument()->HasAnySheetEventScript(SC_SHEETEVENT_CHANGE); } void ScModelObj::NotifyChanges( const ::rtl::OUString& rOperation, const ScRangeList& rRanges, @@ -2300,17 +2334,29 @@ void ScModelObj::HandleCalculateEvents() SCTAB nTabCount = pDoc->GetTableCount(); for (SCTAB nTab = 0; nTab < nTabCount; nTab++) { - const ScSheetEvents* pEvents = pDoc->GetSheetEvents(nTab); - if (pEvents) + if (pDoc->HasCalcNotification(nTab)) { - const rtl::OUString* pScript = pEvents->GetScript(SC_SHEETEVENT_CALCULATE); - if (pScript && pDoc->HasCalcNotification(nTab)) + if (const ScSheetEvents* pEvents = pDoc->GetSheetEvents( nTab )) + { + if (const rtl::OUString* pScript = pEvents->GetScript(SC_SHEETEVENT_CALCULATE)) + { + uno::Any aRet; + uno::Sequence<uno::Any> aParams; + uno::Sequence<sal_Int16> aOutArgsIndex; + uno::Sequence<uno::Any> aOutArgs; + pDocShell->CallXScript( *pScript, aParams, aRet, aOutArgsIndex, aOutArgs ); + } + } + + try + { + uno::Reference< script::vba::XEventProcessor > xVbaEvents( pDoc->GetVbaEventProcessor(), uno::UNO_SET_THROW ); + uno::Sequence< uno::Any > aArgs( 1 ); + aArgs[ 0 ] <<= nTab; + xVbaEvents->processVbaEvent( ScSheetEvents::GetVbaSheetEventId( SC_SHEETEVENT_CALCULATE ), aArgs ); + } + catch( uno::Exception& ) { - uno::Any aRet; - uno::Sequence<uno::Any> aParams; - uno::Sequence<sal_Int16> aOutArgsIndex; - uno::Sequence<uno::Any> aOutArgs; - pDocShell->CallXScript( *pScript, aParams, aRet, aOutArgsIndex, aOutArgs ); } } } diff --git a/sc/source/ui/unoobj/viewuno.cxx b/sc/source/ui/unoobj/viewuno.cxx index 8badd44ba..6cad52f0b 100644 --- a/sc/source/ui/unoobj/viewuno.cxx +++ b/sc/source/ui/unoobj/viewuno.cxx @@ -28,6 +28,10 @@ // MARKER(update_precomp.py): autogen include statement, do not remove #include "precompiled_sc.hxx" +#include <com/sun/star/awt/MouseButton.hpp> +#include <com/sun/star/script/vba/EventIdentifier.hpp> +#include <com/sun/star/script/vba/XEventProcessor.hpp> +#include <com/sun/star/view/DocumentZoomType.hpp> #include <editeng/outliner.hxx> #include <svx/fmdpage.hxx> @@ -67,8 +71,6 @@ #include "appoptio.hxx" #include "gridwin.hxx" #include "sheetevents.hxx" -#include <com/sun/star/view/DocumentZoomType.hpp> -#include <com/sun/star/awt/MouseButton.hpp> #include "AccessibilityHints.hxx" #include <svx/sdrhittesthelper.hxx> @@ -468,7 +470,8 @@ void SAL_CALL ScViewPaneObj::release() throw() //UNUSED2008-05 aPropSet( lcl_GetViewOptPropertyMap() ), //UNUSED2008-05 aMouseClickHandlers( 0 ), //UNUSED2008-05 aActivationListeners( 0 ), -//UNUSED2008-05 bDrawSelModeSet(sal_False) +//UNUSED2008-05 bDrawSelModeSet(sal_False), +//UNUSED2008-05 bFilteredRangeSelection(sal_True) //UNUSED2008-05 { //UNUSED2008-05 } @@ -551,10 +554,22 @@ void lcl_CallActivate( ScDocShell* pDocSh, SCTAB nTab, sal_Int32 nEvent ) uno::Sequence<uno::Any> aParams; uno::Sequence<sal_Int16> aOutArgsIndex; uno::Sequence<uno::Any> aOutArgs; - /*ErrCode eRet =*/ pDocSh->CallXScript( *pScript, aParams, aRet, aOutArgsIndex, aOutArgs ); } } + + // execute VBA event handlers + try + { + uno::Reference< script::vba::XEventProcessor > xVbaEvents( pDoc->GetVbaEventProcessor(), uno::UNO_SET_THROW ); + // the parameter is the clicked object, as in the mousePressed call above + uno::Sequence< uno::Any > aArgs( 1 ); + aArgs[ 0 ] <<= nTab; + xVbaEvents->processVbaEvent( ScSheetEvents::GetVbaSheetEventId( nEvent ), aArgs ); + } + catch( uno::Exception& ) + { + } } void ScTabViewObj::SheetChanged() @@ -1242,14 +1257,12 @@ bool ScTabViewObj::IsMouseListening() const return true; // also include sheet events, because MousePressed must be called for them - ScTabViewShell* pViewSh = GetViewShell(); - ScViewData* pViewData = pViewSh->GetViewData(); - const ScSheetEvents* pEvents = pViewData->GetDocument()->GetSheetEvents(pViewData->GetTabNo()); - if ( pEvents && ( pEvents->GetScript(SC_SHEETEVENT_RIGHTCLICK) != NULL || - pEvents->GetScript(SC_SHEETEVENT_DOUBLECLICK) != NULL ) ) - return true; - - return false; + ScViewData* pViewData = GetViewShell()->GetViewData(); + ScDocument* pDoc = pViewData->GetDocument(); + SCTAB nTab = pViewData->GetTabNo(); + return + pDoc->HasSheetEventScript( nTab, SC_SHEETEVENT_RIGHTCLICK, true ) || + pDoc->HasSheetEventScript( nTab, SC_SHEETEVENT_DOUBLECLICK, true ); } sal_Bool ScTabViewObj::MousePressed( const awt::MouseEvent& e ) @@ -1257,33 +1270,29 @@ sal_Bool ScTabViewObj::MousePressed( const awt::MouseEvent& e ) { sal_Bool bReturn(sal_False); - if (aMouseClickHandlers.Count()) + uno::Reference< uno::XInterface > xTarget = GetClickedObject(Point(e.X, e.Y)); + if (aMouseClickHandlers.Count() && xTarget.is()) { - uno::Reference< uno::XInterface > xTarget = GetClickedObject(Point(e.X, e.Y)); + awt::EnhancedMouseEvent aMouseEvent; - if (xTarget.is()) - { - awt::EnhancedMouseEvent aMouseEvent; + aMouseEvent.Buttons = e.Buttons; + aMouseEvent.X = e.X; + aMouseEvent.Y = e.Y; + aMouseEvent.ClickCount = e.ClickCount; + aMouseEvent.PopupTrigger = e.PopupTrigger; + aMouseEvent.Target = xTarget; - aMouseEvent.Buttons = e.Buttons; - aMouseEvent.X = e.X; - aMouseEvent.Y = e.Y; - aMouseEvent.ClickCount = e.ClickCount; - aMouseEvent.PopupTrigger = e.PopupTrigger; - aMouseEvent.Target = xTarget; - - for ( USHORT n=0; n<aMouseClickHandlers.Count(); n++ ) + for ( USHORT n=0; n<aMouseClickHandlers.Count(); n++ ) + { + try { - try - { - if (!(*aMouseClickHandlers[n])->mousePressed( aMouseEvent )) - bReturn = sal_True; - } - catch ( uno::Exception& ) - { - aMouseClickHandlers.DeleteAndDestroy(n); - --n; // because it will be increased again in the loop - } + if (!(*aMouseClickHandlers[n])->mousePressed( aMouseEvent )) + bReturn = sal_True; + } + catch ( uno::Exception& ) + { + aMouseClickHandlers.DeleteAndDestroy(n); + --n; // because it will be increased again in the loop } } } @@ -1291,7 +1300,7 @@ sal_Bool ScTabViewObj::MousePressed( const awt::MouseEvent& e ) // handle sheet events bool bDoubleClick = ( e.Buttons == awt::MouseButton::LEFT && e.ClickCount == 2 ); bool bRightClick = ( e.Buttons == awt::MouseButton::RIGHT && e.ClickCount == 1 ); - if ( ( bDoubleClick || bRightClick ) && !bReturn ) + if ( ( bDoubleClick || bRightClick ) && !bReturn && xTarget.is()) { sal_Int32 nEvent = bDoubleClick ? SC_SHEETEVENT_DOUBLECLICK : SC_SHEETEVENT_RIGHTCLICK; @@ -1307,28 +1316,41 @@ sal_Bool ScTabViewObj::MousePressed( const awt::MouseEvent& e ) if (pScript) { // the macro parameter is the clicked object, as in the mousePressed call above - uno::Reference< uno::XInterface > xTarget = GetClickedObject(Point(e.X, e.Y)); - if (xTarget.is()) - { - uno::Sequence<uno::Any> aParams(1); - aParams[0] <<= xTarget; + uno::Sequence<uno::Any> aParams(1); + aParams[0] <<= xTarget; - uno::Any aRet; - uno::Sequence<sal_Int16> aOutArgsIndex; - uno::Sequence<uno::Any> aOutArgs; + uno::Any aRet; + uno::Sequence<sal_Int16> aOutArgsIndex; + uno::Sequence<uno::Any> aOutArgs; - /*ErrCode eRet =*/ pDocSh->CallXScript( *pScript, aParams, aRet, aOutArgsIndex, aOutArgs ); + /*ErrCode eRet =*/ pDocSh->CallXScript( *pScript, aParams, aRet, aOutArgsIndex, aOutArgs ); - // look for a boolean return value of true - sal_Bool bRetValue = sal_False; - if (aRet >>= bRetValue) - { - if (bRetValue) - bReturn = sal_True; - } + // look for a boolean return value of true + sal_Bool bRetValue = sal_False; + if (aRet >>= bRetValue) + { + if (bRetValue) + bReturn = sal_True; } } } + + // execute VBA event handler + if (!bReturn && xTarget.is()) try + { + uno::Reference< script::vba::XEventProcessor > xVbaEvents( pDoc->GetVbaEventProcessor(), uno::UNO_SET_THROW ); + // the parameter is the clicked object, as in the mousePressed call above + uno::Sequence< uno::Any > aArgs( 1 ); + aArgs[ 0 ] <<= xTarget; + xVbaEvents->processVbaEvent( ScSheetEvents::GetVbaSheetEventId( nEvent ), aArgs ); + } + catch( util::VetoException& ) + { + bReturn = sal_True; + } + catch( uno::Exception& ) + { + } } return bReturn; @@ -1820,14 +1842,24 @@ void ScTabViewObj::SelectionChanged() // the macro parameter is the selection as returned by getSelection uno::Sequence<uno::Any> aParams(1); aParams[0] = getSelection(); - uno::Any aRet; uno::Sequence<sal_Int16> aOutArgsIndex; uno::Sequence<uno::Any> aOutArgs; - /*ErrCode eRet =*/ pDocSh->CallXScript( *pScript, aParams, aRet, aOutArgsIndex, aOutArgs ); } } + // execute VBA event handler + try + { + uno::Reference< script::vba::XEventProcessor > xVbaEvents( pDoc->GetVbaEventProcessor(), uno::UNO_SET_THROW ); + // the parameter is the clicked object, as in the mousePressed call above + uno::Sequence< uno::Any > aArgs( 1 ); + aArgs[ 0 ] <<= getSelection(); + xVbaEvents->processVbaEvent( ScSheetEvents::GetVbaSheetEventId( SC_SHEETEVENT_SELECT ), aArgs ); + } + catch( uno::Exception& ) + { + } } diff --git a/sc/source/ui/vba/makefile.mk b/sc/source/ui/vba/makefile.mk index 0a84b8dd1..4cb7e3eb0 100644 --- a/sc/source/ui/vba/makefile.mk +++ b/sc/source/ui/vba/makefile.mk @@ -102,7 +102,9 @@ SLOFILES= \ $(SLO)$/vbapagesetup.obj \ $(SLO)$/vbapagebreak.obj \ $(SLO)$/vbapagebreaks.obj \ + $(SLO)$/vbaeventshelper.obj \ $(SLO)$/service.obj + .ENDIF # --- Targets ------------------------------------------------------ diff --git a/sc/source/ui/vba/service.cxx b/sc/source/ui/vba/service.cxx index ab09d2ccb..b21b55f6a 100644 --- a/sc/source/ui/vba/service.cxx +++ b/sc/source/ui/vba/service.cxx @@ -66,6 +66,10 @@ namespace application { extern sdecl::ServiceDecl const serviceDecl; } +namespace vbaeventshelper +{ +extern sdecl::ServiceDecl const serviceDecl; +} namespace textframe { extern sdecl::ServiceDecl const serviceDecl; @@ -87,7 +91,7 @@ extern "C" #if 0 // Component registration if ( component_writeInfoHelper( pServiceManager, pRegistryKey, - range::serviceDecl, workbook::serviceDecl, worksheet::serviceDecl, globals::serviceDecl, window::serviceDecl, hyperlink::serviceDecl, application::serviceDecl ) ) + range::serviceDecl, workbook::serviceDecl, worksheet::serviceDecl, globals::serviceDecl, window::serviceDecl, hyperlink::serviceDecl, application::serviceDecl ) && component_writeInfoHelper( pServiceManager, pRegistryKey, vbaeventshelper::serviceDecl ) ) { // Singleton registration try @@ -110,7 +114,7 @@ extern "C" #else // Component registration return component_writeInfoHelper( pServiceManager, pRegistryKey, - range::serviceDecl, workbook::serviceDecl, worksheet::serviceDecl, globals::serviceDecl, window::serviceDecl, hyperlink::serviceDecl, application::serviceDecl ) && component_writeInfoHelper( pServiceManager, pRegistryKey, textframe::serviceDecl ); + range::serviceDecl, workbook::serviceDecl, worksheet::serviceDecl, globals::serviceDecl, window::serviceDecl, hyperlink::serviceDecl, application::serviceDecl ) && component_writeInfoHelper( pServiceManager, pRegistryKey, vbaeventshelper::serviceDecl, textframe::serviceDecl ); #endif } @@ -122,8 +126,8 @@ extern "C" OSL_TRACE("In component_getFactory for %s", pImplName ); void* pRet = component_getFactoryHelper( pImplName, pServiceManager, pRegistryKey, range::serviceDecl, workbook::serviceDecl, worksheet::serviceDecl, globals::serviceDecl, window::serviceDecl, hyperlink::serviceDecl, application::serviceDecl ); - if( !pRet ) - pRet = component_getFactoryHelper( pImplName, pServiceManager, pRegistryKey, textframe::serviceDecl ); + if( !pRet ) + pRet = component_getFactoryHelper( pImplName, pServiceManager, pRegistryKey, vbaeventshelper::serviceDecl, textframe::serviceDecl ); OSL_TRACE("Ret is 0x%x", pRet); return pRet; } diff --git a/sc/source/ui/vba/vbaapplication.cxx b/sc/source/ui/vba/vbaapplication.cxx index b398c9e48..7af3182f4 100644 --- a/sc/source/ui/vba/vbaapplication.cxx +++ b/sc/source/ui/vba/vbaapplication.cxx @@ -117,7 +117,8 @@ public: ScVbaApplication::ScVbaApplication( const uno::Reference<uno::XComponentContext >& xContext ) : ScVbaApplication_BASE( xContext ), m_xCalculation( excel::XlCalculation::xlCalculationAutomatic ), - m_xDisplayAlerts( sal_True) + m_bDisplayAlerts( sal_True ), + m_bEnableEvents( sal_True ) { } @@ -708,14 +709,27 @@ ScVbaApplication::getName() throw (uno::RuntimeException) void SAL_CALL ScVbaApplication::setDisplayAlerts(sal_Bool displayAlerts) throw (uno::RuntimeException) { - m_xDisplayAlerts = displayAlerts; + m_bDisplayAlerts = displayAlerts; } sal_Bool SAL_CALL ScVbaApplication::getDisplayAlerts() throw (uno::RuntimeException) { - return m_xDisplayAlerts; + return m_bDisplayAlerts; } + +void SAL_CALL +ScVbaApplication::setEnableEvents(sal_Bool bEnable) throw (uno::RuntimeException) +{ + m_bEnableEvents = bEnable; +} + +sal_Bool SAL_CALL +ScVbaApplication::getEnableEvents() throw (uno::RuntimeException) +{ + return m_bEnableEvents; +} + void SAL_CALL ScVbaApplication::Calculate() throw( script::BasicErrorException , uno::RuntimeException ) { diff --git a/sc/source/ui/vba/vbaapplication.hxx b/sc/source/ui/vba/vbaapplication.hxx index 2a15a1b5e..5abb85f40 100644 --- a/sc/source/ui/vba/vbaapplication.hxx +++ b/sc/source/ui/vba/vbaapplication.hxx @@ -43,7 +43,9 @@ class ScVbaApplication : public ScVbaApplication_BASE { private: sal_Int32 m_xCalculation; - sal_Bool m_xDisplayAlerts; + sal_Bool m_bDisplayAlerts; + sal_Bool m_bEnableEvents; + rtl::OUString getOfficePath( const rtl::OUString& sPath ) throw ( css::uno::RuntimeException ); protected: @@ -99,6 +101,9 @@ public: virtual void SAL_CALL setStatusBar( const css::uno::Any& _statusbar ) throw (css::uno::RuntimeException); virtual ::sal_Int32 SAL_CALL getCursor() throw (css::uno::RuntimeException); virtual void SAL_CALL setCursor( ::sal_Int32 _cursor ) throw (css::uno::RuntimeException); + + virtual sal_Bool SAL_CALL getEnableEvents() throw (css::uno::RuntimeException); + virtual void SAL_CALL setEnableEvents( sal_Bool bEnable ) throw (css::uno::RuntimeException); virtual css::uno::Any SAL_CALL Windows( const css::uno::Any& aIndex ) throw (css::uno::RuntimeException); virtual void SAL_CALL wait( double time ) throw (css::uno::RuntimeException); diff --git a/sc/source/ui/vba/vbaeventshelper.cxx b/sc/source/ui/vba/vbaeventshelper.cxx new file mode 100755 index 000000000..5e007dca7 --- /dev/null +++ b/sc/source/ui/vba/vbaeventshelper.cxx @@ -0,0 +1,775 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#include "vbaeventshelper.hxx" + +#include <com/sun/star/awt/XWindowListener.hpp> +#include <com/sun/star/frame/XBorderResizeListener.hpp> +#include <com/sun/star/frame/XControllerBorder.hpp> +#include <com/sun/star/script/vba/EventIdentifier.hpp> +#include <com/sun/star/sheet/XCellRangeAddressable.hpp> +#include <com/sun/star/sheet/XSheetCellRangeContainer.hpp> +#include <com/sun/star/table/XCellRange.hpp> +#include <com/sun/star/util/XChangesListener.hpp> +#include <com/sun/star/util/XChangesNotifier.hpp> +#include <com/sun/star/util/XCloseListener.hpp> + +#include <ooo/vba/excel/XApplication.hpp> + +#include <cppuhelper/implbase1.hxx> +#include <cppuhelper/implbase3.hxx> +#include <toolkit/unohlp.hxx> +#include <vbahelper/helperdecl.hxx> +#include <vcl/svapp.hxx> +#include <vcl/window.hxx> + +#include "cellsuno.hxx" +#include "convuno.hxx" + +using namespace ::com::sun::star; +using namespace ::com::sun::star::script::vba::EventIdentifier; +using namespace ::ooo::vba; + +// ============================================================================ + +typedef ::cppu::WeakImplHelper1< util::XChangesListener > ScVbaChangesListener_BASE; + +class ScVbaChangesListener : public ScVbaChangesListener_BASE +{ +public: + ScVbaChangesListener( ScVbaEventsHelper* pHelper, ScDocShell* pDocShell ); + + virtual void SAL_CALL changesOccurred( const util::ChangesEvent& aEvent ) throw (uno::RuntimeException); + virtual void SAL_CALL disposing( const lang::EventObject& aSource ) throw (uno::RuntimeException); + +private: + ScVbaEventsHelper* mpVbaEvents; + ScDocShell* mpDocShell; +}; + +// ---------------------------------------------------------------------------- + +ScVbaChangesListener::ScVbaChangesListener( ScVbaEventsHelper* pHelper, ScDocShell* pDocShell ) : + mpVbaEvents( pHelper ), + mpDocShell( pDocShell ) +{ +} + +void SAL_CALL ScVbaChangesListener::changesOccurred( const util::ChangesEvent& aEvent ) throw (uno::RuntimeException) +{ + sal_Int32 nCount = aEvent.Changes.getLength(); + if( nCount == 0 ) + return; + + util::ElementChange aChange = aEvent.Changes[ 0 ]; + rtl::OUString sOperation; + aChange.Accessor >>= sOperation; + if( !sOperation.equalsIgnoreAsciiCaseAscii("cell-change") ) + return; + + if( nCount == 1 ) + { + uno::Reference< table::XCellRange > xRangeObj; + aChange.ReplacedElement >>= xRangeObj; + if( xRangeObj.is() ) + { + uno::Sequence< uno::Any > aArgs(1); + aArgs[0] <<= xRangeObj; + mpVbaEvents->processVbaEvent( WORKSHEET_CHANGE, aArgs ); + } + return; + } + + ScRangeList aRangeList; + for( sal_Int32 nIndex = 0; nIndex < nCount; ++nIndex ) + { + aChange = aEvent.Changes[ nIndex ]; + aChange.Accessor >>= sOperation; + uno::Reference< table::XCellRange > xRangeObj; + aChange.ReplacedElement >>= xRangeObj; + if( xRangeObj.is() && sOperation.equalsIgnoreAsciiCaseAscii("cell-change") ) + { + uno::Reference< sheet::XCellRangeAddressable > xCellRangeAddressable( xRangeObj, uno::UNO_QUERY ); + if( xCellRangeAddressable.is() ) + { + ScRange aRange; + ScUnoConversion::FillScRange( aRange, xCellRangeAddressable->getRangeAddress() ); + aRangeList.Append( aRange ); + } + } + } + + if( (aRangeList.Count() > 0) && mpDocShell ) + { + uno::Reference< sheet::XSheetCellRangeContainer > xRanges( new ScCellRangesObj( mpDocShell, aRangeList ) ); + uno::Sequence< uno::Any > aArgs(1); + aArgs[0] <<= xRanges; + mpVbaEvents->processVbaEvent( WORKSHEET_CHANGE, aArgs ); + } +} + +void SAL_CALL ScVbaChangesListener::disposing( const lang::EventObject& /*aSource*/ ) throw(uno::RuntimeException) +{ +} + +// ============================================================================ + +typedef ::cppu::WeakImplHelper3< + awt::XWindowListener, util::XCloseListener, frame::XBorderResizeListener > ScVbaWindowListener_BASE; + +// This class is to process Workbook window related event +class ScVbaWindowListener : public ScVbaWindowListener_BASE +{ +public : + ScVbaWindowListener( ScVbaEventsHelper* pHelper, const uno::Reference< frame::XModel >& rxModel ); + virtual ~ScVbaWindowListener(); + + void startListening(); + void stopListening(); + + // XWindowListener + virtual void SAL_CALL windowResized( const awt::WindowEvent& aEvent ) throw (uno::RuntimeException); + virtual void SAL_CALL windowMoved( const awt::WindowEvent& aEvent ) throw (uno::RuntimeException); + virtual void SAL_CALL windowShown( const lang::EventObject& aEvent ) throw (uno::RuntimeException); + virtual void SAL_CALL windowHidden( const lang::EventObject& aEvent ) throw (uno::RuntimeException); + virtual void SAL_CALL disposing( const lang::EventObject& aEvent ) throw (uno::RuntimeException); + + // XCloseListener + virtual void SAL_CALL queryClosing( const lang::EventObject& Source, ::sal_Bool GetsOwnership ) throw (util::CloseVetoException, uno::RuntimeException); + virtual void SAL_CALL notifyClosing( const lang::EventObject& Source ) throw (uno::RuntimeException); + + // XBorderResizeListener + virtual void SAL_CALL borderWidthsChanged( const uno::Reference< uno::XInterface >& aObject, const frame::BorderWidths& aNewSize ) throw (uno::RuntimeException); + +private: + uno::Reference< frame::XFrame > getFrame(); + uno::Reference< awt::XWindow > getContainerWindow(); + bool isMouseReleased(); + DECL_LINK( fireResizeMacro, void* ); + void processWindowResizeMacro(); + +private: + ::osl::Mutex maMutex; + ScVbaEventsHelper* mpVbaEvents; + uno::Reference< frame::XModel > mxModel; + bool mbWindowResized; + bool mbBorderChanged; +}; + +// ---------------------------------------------------------------------------- + +ScVbaWindowListener::ScVbaWindowListener( ScVbaEventsHelper* pHelper, const uno::Reference< frame::XModel >& rxModel ) : + mpVbaEvents( pHelper ), + mxModel( rxModel ), + mbWindowResized( sal_False ), + mbBorderChanged( sal_False ) +{ + OSL_TRACE( "ScVbaWindowListener::ScVbaWindowListener( 0x%x ) - ctor ", this ); +} + +ScVbaWindowListener::~ScVbaWindowListener() +{ + OSL_TRACE( "ScVbaWindowListener::~ScVbaWindowListener( 0x%x ) - dtor ", this ); +} + +void ScVbaWindowListener::startListening() +{ + if( mxModel.is() ) + { + // add window listener + try + { + uno::Reference< awt::XWindow > xWindow( getContainerWindow(), uno::UNO_QUERY_THROW ); + xWindow->addWindowListener( this ); + } + catch( uno::Exception& ) + { + } + // add close listener + try + { + uno::Reference< util::XCloseBroadcaster > xCloseBroadcaster( mxModel, uno::UNO_QUERY_THROW ); + xCloseBroadcaster->addCloseListener( this ); + } + catch( uno::Exception& ) + { + } + // add Border resize listener + try + { + uno::Reference< frame::XControllerBorder > xControllerBorder( mxModel->getCurrentController(), uno::UNO_QUERY_THROW ); + xControllerBorder->addBorderResizeListener( this ); + } + catch( uno::Exception& ) + { + } + } +} + +void ScVbaWindowListener::stopListening() +{ + if( mxModel.is() ) + { + try + { + uno::Reference< awt::XWindow > xWindow( getContainerWindow(), uno::UNO_QUERY_THROW ); + xWindow->removeWindowListener( this ); + } + catch( uno::Exception& ) + { + } + try + { + uno::Reference< util::XCloseBroadcaster > xCloseBroadcaster( mxModel, uno::UNO_QUERY_THROW ); + xCloseBroadcaster->removeCloseListener( this ); + } + catch( uno::Exception& ) + { + } + try + { + uno::Reference< frame::XControllerBorder > xControllerBorder( mxModel->getCurrentController(), uno::UNO_QUERY_THROW ); + xControllerBorder->removeBorderResizeListener( this ); + } + catch( uno::Exception& ) + { + } + } + mpVbaEvents = 0; +} + +void SAL_CALL ScVbaWindowListener::windowResized( const awt::WindowEvent& /*aEvent*/ ) throw ( uno::RuntimeException ) +{ + ::osl::MutexGuard aGuard( maMutex ); + // Workbook_window_resize event + mbWindowResized = true; + if( mbBorderChanged ) + { + if( Window* pWindow = VCLUnoHelper::GetWindow( getContainerWindow() ) ) + { + mbBorderChanged = mbWindowResized = false; + acquire(); // ensure we don't get deleted before the event is handled + Application::PostUserEvent( LINK( this, ScVbaWindowListener, fireResizeMacro ), 0 ); + } + } +} + +void SAL_CALL ScVbaWindowListener::windowMoved( const awt::WindowEvent& /*aEvent*/ ) throw ( uno::RuntimeException ) +{ + // not interest this time +} + +void SAL_CALL ScVbaWindowListener::windowShown( const lang::EventObject& /*aEvent*/ ) throw ( uno::RuntimeException ) +{ + // not interest this time +} + +void SAL_CALL ScVbaWindowListener::windowHidden( const lang::EventObject& /*aEvent*/ ) throw ( uno::RuntimeException ) +{ + // not interest this time +} + +void SAL_CALL ScVbaWindowListener::disposing( const lang::EventObject& /*aEvent*/ ) throw ( uno::RuntimeException ) +{ + ::osl::MutexGuard aGuard( maMutex ); + OSL_TRACE( "ScVbaWindowListener::disposing( 0x%x )", this ); + mpVbaEvents = 0; +} + +void SAL_CALL ScVbaWindowListener::queryClosing( const lang::EventObject& /*Source*/, sal_Bool /*GetsOwnership*/ ) throw (util::CloseVetoException, uno::RuntimeException) +{ + // it can cancel the close, but need to throw a CloseVetoException, and it will be transmit to caller. +} + +void SAL_CALL ScVbaWindowListener::notifyClosing( const lang::EventObject& /*Source*/ ) throw (uno::RuntimeException) +{ + ::osl::MutexGuard aGuard( maMutex ); + stopListening(); +} + +void SAL_CALL ScVbaWindowListener::borderWidthsChanged( const uno::Reference< uno::XInterface >& /*aObject*/, const frame::BorderWidths& /*aNewSize*/ ) throw (uno::RuntimeException) +{ + ::osl::MutexGuard aGuard( maMutex ); + // work with WindowResized event to guard Window Resize event. + mbBorderChanged = true; + if( mbWindowResized ) + { + if( Window* pWindow = VCLUnoHelper::GetWindow( getContainerWindow() ) ) + { + mbWindowResized = mbBorderChanged = false; + acquire(); // ensure we don't get deleted before the timer fires. + Application::PostUserEvent( LINK( this, ScVbaWindowListener, fireResizeMacro ), 0 ); + } + } +} + +// ---------------------------------------------------------------------------- + +uno::Reference< frame::XFrame > ScVbaWindowListener::getFrame() +{ + if( mpVbaEvents && mxModel.is() ) try + { + uno::Reference< frame::XController > xController( mxModel->getCurrentController(), uno::UNO_QUERY_THROW ); + return xController->getFrame(); + } + catch( uno::Exception& ) + { + } + return uno::Reference< frame::XFrame >(); +} + +uno::Reference< awt::XWindow > ScVbaWindowListener::getContainerWindow() +{ + try + { + uno::Reference< frame::XFrame > xFrame( getFrame(), uno::UNO_SET_THROW ); + return xFrame->getContainerWindow(); + } + catch( uno::Exception& ) + { + } + return uno::Reference< awt::XWindow >(); +} + +bool ScVbaWindowListener::isMouseReleased() +{ + if( Window* pWindow = VCLUnoHelper::GetWindow( getContainerWindow() ) ) + { + Window::PointerState aPointerState = pWindow->GetPointerState(); + return (aPointerState.mnState & ( MOUSE_LEFT | MOUSE_MIDDLE | MOUSE_RIGHT )) == 0; + } + return false; +} + +IMPL_LINK( ScVbaWindowListener, fireResizeMacro, void*, EMPTY_ARGS ) +{ + if( mpVbaEvents && isMouseReleased() ) + processWindowResizeMacro(); + release(); + return 0; +} + +void ScVbaWindowListener::processWindowResizeMacro() +{ + OSL_TRACE( "**** Attempt to FIRE MACRO **** " ); + if( mpVbaEvents ) + mpVbaEvents->processVbaEvent( WORKBOOK_WINDOWRESIZE, uno::Sequence< uno::Any >() ); +} + +// ============================================================================ + +ScVbaEventsHelper::ScVbaEventsHelper( const uno::Sequence< uno::Any >& rArgs, const uno::Reference< uno::XComponentContext >& xContext ) : + VbaEventsHelperBase( rArgs, xContext ), + mbOpened( false ), + mbClosed( false ) +{ + mpDocShell = dynamic_cast< ScDocShell* >( mpShell ); // mpShell from base class + mpDoc = mpDocShell ? mpDocShell->GetDocument() : 0; + + if( !mxModel.is() || !mpDocShell || !mpDoc ) + return; + + // add worksheet change listener + try + { + uno::Reference< util::XChangesNotifier > xChangesNotifier( mxModel, uno::UNO_QUERY_THROW ); + uno::Reference< util::XChangesListener > xChangesListener( new ScVbaChangesListener( this, mpDocShell ) ); + xChangesNotifier->addChangesListener( xChangesListener ); + } + catch( uno::Exception& ) + { + } + +#define REGISTER_EVENT( eventid, eventname, type, cancelindex, worksheet ) \ + registerEventHandler( eventid, eventname, type, cancelindex, uno::Any( worksheet ) ) + +#define REGISTER_WORKBOOK_EVENT( eventid, eventname, cancelindex ) \ + REGISTER_EVENT( WORKBOOK_##eventid, "Workbook_" eventname, EVENTHANDLER_DOCUMENT, cancelindex, false ) + +#define REGISTER_WORKSHEET_EVENT( eventid, eventname, cancelindex ) \ + REGISTER_EVENT( WORKSHEET_##eventid, "Worksheet_" eventname, EVENTHANDLER_DOCUMENT, cancelindex, true ); \ + REGISTER_EVENT( (USERDEFINED_START + WORKSHEET_##eventid), "Workbook_Sheet" eventname, EVENTHANDLER_DOCUMENT, (((cancelindex) >= 0) ? ((cancelindex) + 1) : -1), false ) + + // global + REGISTER_EVENT( AUTO_OPEN, "Auto_Open", EVENTHANDLER_GLOBAL, -1, false ); + REGISTER_EVENT( AUTO_CLOSE, "Auto_Close", EVENTHANDLER_GLOBAL, -1, false ); + + // Workbook + REGISTER_WORKBOOK_EVENT( ACTIVATE, "Activate", -1 ); + REGISTER_WORKBOOK_EVENT( DEACTIVATE, "Deactivate", -1 ); + REGISTER_WORKBOOK_EVENT( OPEN, "Open", -1 ); + REGISTER_WORKBOOK_EVENT( BEFORECLOSE, "BeforeClose", 0 ); + REGISTER_WORKBOOK_EVENT( BEFOREPRINT, "BeforePrint", 0 ); + REGISTER_WORKBOOK_EVENT( BEFORESAVE, "BeforeSave", 1 ); + REGISTER_WORKBOOK_EVENT( AFTERSAVE, "AfterSave", -1 ); + REGISTER_WORKBOOK_EVENT( NEWSHEET, "NewSheet", -1 ); + REGISTER_WORKBOOK_EVENT( WINDOWACTIVATE, "WindowActivate", -1 ); + REGISTER_WORKBOOK_EVENT( WINDOWDEACTIVATE, "WindowDeactivate", -1 ); + REGISTER_WORKBOOK_EVENT( WINDOWRESIZE, "WindowResize", -1 ); + + // Worksheet events. All events have a corresponding workbook event. + REGISTER_WORKSHEET_EVENT( ACTIVATE, "Activate", -1 ); + REGISTER_WORKSHEET_EVENT( DEACTIVATE, "Deactivate", -1 ); + REGISTER_WORKSHEET_EVENT( BEFOREDOUBLECLICK, "BeforeDoubleClick", 1 ); + REGISTER_WORKSHEET_EVENT( BEFORERIGHTCLICK, "BeforeRightClick", 1 ); + REGISTER_WORKSHEET_EVENT( CALCULATE, "Calculate", -1 ); + REGISTER_WORKSHEET_EVENT( CHANGE, "Change", -1 ); + REGISTER_WORKSHEET_EVENT( SELECTIONCHANGE, "SelectionChange", -1 ); + REGISTER_WORKSHEET_EVENT( FOLLOWHYPERLINK, "FollowHyperlink", -1 ); + +#undef REGISTER_EVENT +#undef REGISTER_WORKBOOK_EVENT +#undef REGISTER_WORKSHEET_EVENT +} + +ScVbaEventsHelper::~ScVbaEventsHelper() +{ +} + +// protected ------------------------------------------------------------------ + +bool ScVbaEventsHelper::implEventsEnabled() throw (uno::RuntimeException) +{ + // document and document shell are needed during event processing + if( !mpDocShell || !mpDoc ) + throw uno::RuntimeException(); + + // get Application object and check if events are enabled (this is an Excel-only attribute) + uno::Reference< excel::XApplication > xApplication( mxApplication.get(), uno::UNO_QUERY ); + if( !xApplication.is() && mpShell ) + { + uno::Any aVBAGlobals; + mpShell->GetBasicManager()->GetGlobalUNOConstant( "VBAGlobals", aVBAGlobals ); + uno::Reference< XHelperInterface > xHelperInterface( aVBAGlobals, uno::UNO_QUERY ); + if( xHelperInterface.is() ) + { + xApplication.set( xHelperInterface->Application(), uno::UNO_QUERY ); + mxApplication = xApplication; + } + } + if( !xApplication.is() ) + throw uno::RuntimeException(); + + // return whether event processing is enabled + return xApplication->getEnableEvents(); +} + +bool ScVbaEventsHelper::implPrepareEvent( EventQueue& rEventQueue, + const EventHandlerInfo& rInfo, const uno::Sequence< uno::Any >& rArgs ) throw (uno::RuntimeException) +{ + // check preconditions for some events, add more events if needed + bool bExecuteEvent = true; + switch( rInfo.mnEventId ) + { + case WORKBOOK_ACTIVATE: + // while loading, framework fires this before 'opened' event, delay it + bExecuteEvent = mbOpened; + break; + case WORKBOOK_OPEN: + bExecuteEvent = !mbOpened; + if( bExecuteEvent ) + { + // execute delayed Activate event too (see above) + rEventQueue.push_back( WORKBOOK_ACTIVATE ); + rEventQueue.push_back( WORKBOOK_WINDOWACTIVATE ); + rEventQueue.push_back( AUTO_OPEN ); + } + break; + case WORKBOOK_DEACTIVATE: + if( mbClosed ) + rEventQueue.push_back( WORKBOOK_WINDOWDEACTIVATE ); + break; + case WORKSHEET_SELECTIONCHANGE: + // if selection is not changed, then do not fire the event + bExecuteEvent = mbOpened && !mbClosed && isSelectionChanged( rArgs, 0 ); + break; + } + + // add workbook event associated to a sheet event + bool bSheetEvent = false; + rInfo.maUserData >>= bSheetEvent; + if( bSheetEvent && bExecuteEvent ) + rEventQueue.push_back( EventQueueEntry( rInfo.mnEventId + USERDEFINED_START, rArgs ) ); + + return bExecuteEvent; +} + +uno::Sequence< uno::Any > ScVbaEventsHelper::implBuildArgumentList( const EventHandlerInfo& rInfo, + const uno::Sequence< uno::Any >& rArgs ) throw (lang::IllegalArgumentException) +{ + // fill arguments for workbook events associated to sheet events according to sheet events, sheet will be added below + bool bSheetEventAsBookEvent = rInfo.mnEventId > USERDEFINED_START; + sal_Int32 nEventId = bSheetEventAsBookEvent ? (rInfo.mnEventId - USERDEFINED_START) : rInfo.mnEventId; + + uno::Sequence< uno::Any > aVbaArgs; + switch( nEventId ) + { + // *** Workbook *** + + // no arguments + case WORKBOOK_ACTIVATE: + case WORKBOOK_DEACTIVATE: + case WORKBOOK_OPEN: + break; + // 1 arg: cancel + case WORKBOOK_BEFORECLOSE: + case WORKBOOK_BEFOREPRINT: + aVbaArgs.realloc( 1 ); + // current cancel state will be inserted by caller + break; + // 2 args: saveAs, cancel + case WORKBOOK_BEFORESAVE: + aVbaArgs.realloc( 2 ); + checkArgumentType< bool >( rArgs, 0 ); + aVbaArgs[ 0 ] = rArgs[ 0 ]; + // current cancel state will be inserted by caller + break; + // 1 arg: success + case WORKBOOK_AFTERSAVE: + aVbaArgs.realloc( 1 ); + checkArgumentType< bool >( rArgs, 0 ); + aVbaArgs[ 0 ] = rArgs[ 0 ]; + break; + // 1 arg: window + case WORKBOOK_WINDOWACTIVATE: + case WORKBOOK_WINDOWDEACTIVATE: + case WORKBOOK_WINDOWRESIZE: + aVbaArgs.realloc( 1 ); + aVbaArgs[ 0 ] = createWindow(); + break; + // 1 arg: worksheet + case WORKBOOK_NEWSHEET: + aVbaArgs.realloc( 1 ); + aVbaArgs[ 0 ] = createWorksheet( rArgs, 0 ); + break; + + // *** Worksheet *** + + // no arguments + case WORKSHEET_ACTIVATE: + case WORKSHEET_CALCULATE: + case WORKSHEET_DEACTIVATE: + break; + // 1 arg: range + case WORKSHEET_CHANGE: + case WORKSHEET_SELECTIONCHANGE: + aVbaArgs.realloc( 1 ); + aVbaArgs[ 0 ] = createRange( rArgs, 0 ); + break; + // 2 args: range, cancel + case WORKSHEET_BEFOREDOUBLECLICK: + case WORKSHEET_BEFORERIGHTCLICK: + aVbaArgs.realloc( 2 ); + aVbaArgs[ 0 ] = createRange( rArgs, 0 ); + // current cancel state will be inserted by caller + break; + // 1 arg: hyperlink + case WORKSHEET_FOLLOWHYPERLINK: + aVbaArgs.realloc( 1 ); + aVbaArgs[ 0 ] = createHyperlink( rArgs, 0 ); + break; + } + + /* For workbook events associated to sheet events, the workbook event gets + the same arguments but with a Worksheet object in front of them. */ + if( bSheetEventAsBookEvent ) + { + sal_Int32 nLength = aVbaArgs.getLength(); + uno::Sequence< uno::Any > aVbaArgs2( nLength + 1 ); + aVbaArgs2[ 0 ] = createWorksheet( rArgs, 0 ); + for( sal_Int32 nIndex = 0; nIndex < nLength; ++nIndex ) + aVbaArgs2[ nIndex + 1 ] = aVbaArgs[ nIndex ]; + aVbaArgs = aVbaArgs2; + } + + return aVbaArgs; +} + +void ScVbaEventsHelper::implPostProcessEvent( EventQueue& rEventQueue, + const EventHandlerInfo& rInfo, bool /*bSuccess*/, bool bCancel ) throw (uno::RuntimeException) +{ + switch( rInfo.mnEventId ) + { + case WORKBOOK_OPEN: + mbOpened = true; + // register the window listener + if( !mxWindowListener.is() ) + { + mxWindowListener = new ScVbaWindowListener( this, mxModel ); + mxWindowListener->startListening(); + } + break; + case WORKBOOK_BEFORECLOSE: + mbClosed = !bCancel; + if( mbClosed ) + { + // execute Auto_Close if not cancelled + rEventQueue.push_back( AUTO_CLOSE ); + if( mxWindowListener.is() ) + { + mxWindowListener->stopListening(); + mxWindowListener.clear(); + } + } + break; + } +} + +::rtl::OUString ScVbaEventsHelper::implGetDocumentModuleName( const EventHandlerInfo& rInfo, + const uno::Sequence< uno::Any >& rArgs ) const throw (lang::IllegalArgumentException) +{ + bool bSheetEvent = false; + rInfo.maUserData >>= bSheetEvent; + SCTAB nTab = bSheetEvent ? getTabFromArgs( rArgs, 0 ) : -1; + if( bSheetEvent && (nTab < 0) ) + throw lang::IllegalArgumentException(); + + String aCodeName; + if( bSheetEvent ) + mpDoc->GetCodeName( nTab, aCodeName ); + else + aCodeName = mpDoc->GetCodeName(); + return aCodeName; +} + +// private -------------------------------------------------------------------- + +SCTAB ScVbaEventsHelper::getTabFromArgs( const uno::Sequence< uno::Any >& rArgs, sal_Int32 nIndex ) throw (lang::IllegalArgumentException) +{ + checkArgument( rArgs, nIndex ); + + // first try to extract a sheet index + SCTAB nTab = -1; + if( rArgs[ nIndex ] >>= nTab ) + return nTab; + + // next, try single range object + uno::Reference< sheet::XCellRangeAddressable > xCellRangeAddressable = getXSomethingFromArgs< sheet::XCellRangeAddressable >( rArgs, nIndex ); + if( xCellRangeAddressable.is() ) + return xCellRangeAddressable->getRangeAddress().Sheet; + + // at last, try range list + uno::Reference< sheet::XSheetCellRangeContainer > xRanges = getXSomethingFromArgs< sheet::XSheetCellRangeContainer >( rArgs, nIndex ); + if( xRanges.is() ) + { + uno::Sequence< table::CellRangeAddress > aRangeAddresses = xRanges->getRangeAddresses(); + if( aRangeAddresses.getLength() > 0 ) + return aRangeAddresses[ 0 ].Sheet; + } + + throw lang::IllegalArgumentException(); +} + +bool ScVbaEventsHelper::isSelectionChanged( const uno::Sequence< uno::Any >& rArgs, sal_Int32 nIndex ) throw (lang::IllegalArgumentException, uno::RuntimeException) +{ + uno::Reference< uno::XInterface > xNewSelection = getXSomethingFromArgs< uno::XInterface >( rArgs, nIndex, false ); + if( ScCellRangesBase* pNewCellRanges = ScCellRangesBase::getImplementation( xNewSelection ) ) + { + bool bChanged = maOldSelection != pNewCellRanges->GetRangeList(); + maOldSelection = pNewCellRanges->GetRangeList(); + return bChanged; + } + maOldSelection.Clear(); + return true; +} + +uno::Any ScVbaEventsHelper::createWorksheet( const uno::Sequence< uno::Any >& rArgs, sal_Int32 nIndex ) const + throw (lang::IllegalArgumentException, uno::RuntimeException) +{ + // Eventually we will be able to pull the Workbook/Worksheet objects + // directly from basic and register them as listeners + + // extract sheet index, will throw, if parameter is invalid + SCTAB nTab = getTabFromArgs( rArgs, nIndex ); + + // create Workbook + uno::Sequence< uno::Any > aArgs( 2 ); + aArgs[ 0 ] <<= uno::Reference< uno::XInterface >(); + aArgs[ 1 ] <<= mxModel; + uno::Reference< uno::XInterface > xWorkbook( createVBAUnoAPIServiceWithArgs( mpShell, "ooo.vba.excel.Workbook", aArgs ), uno::UNO_SET_THROW ); + + // create WorkSheet + String aSheetName; + mpDoc->GetName( nTab, aSheetName ); + aArgs = uno::Sequence< uno::Any >( 3 ); + aArgs[ 0 ] <<= xWorkbook; + aArgs[ 1 ] <<= mxModel; + aArgs[ 2 ] <<= ::rtl::OUString( aSheetName ); + uno::Reference< uno::XInterface > xWorksheet( createVBAUnoAPIServiceWithArgs( mpShell, "ooo.vba.excel.Worksheet", aArgs ), uno::UNO_SET_THROW ); + return uno::Any( xWorksheet ); +} + +uno::Any ScVbaEventsHelper::createRange( const uno::Sequence< uno::Any >& rArgs, sal_Int32 nIndex ) const + throw (lang::IllegalArgumentException, uno::RuntimeException) +{ + uno::Reference< sheet::XSheetCellRangeContainer > xRanges = getXSomethingFromArgs< sheet::XSheetCellRangeContainer >( rArgs, nIndex ); + uno::Reference< table::XCellRange > xRange = getXSomethingFromArgs< table::XCellRange >( rArgs, nIndex ); + if ( !xRanges.is() && !xRange.is() ) + throw lang::IllegalArgumentException(); + + uno::Sequence< uno::Any > aArgs( 2 ); + aArgs[ 0 ] <<= uno::Reference< uno::XInterface >(); // dummy parent + if ( xRanges.is() ) + aArgs[ 1 ] <<= xRanges; + else + aArgs[ 1 ] <<= xRange; + uno::Reference< uno::XInterface > xVbaRange( createVBAUnoAPIServiceWithArgs( mpShell, "ooo.vba.excel.Range", aArgs ), uno::UNO_SET_THROW ); + return uno::Any( xVbaRange ); +} + +uno::Any ScVbaEventsHelper::createHyperlink( const uno::Sequence< uno::Any >& rArgs, sal_Int32 nIndex ) const + throw (lang::IllegalArgumentException, uno::RuntimeException) +{ + uno::Sequence< uno::Any > aArgs( 2 ); + aArgs[ 0 ] <<= uno::Reference< uno::XInterface >(); // dummy parent + aArgs[ 1 ] <<= getXSomethingFromArgs< table::XCell >( rArgs, nIndex, false ); + uno::Reference< uno::XInterface > xHyperlink( createVBAUnoAPIServiceWithArgs( mpShell, "ooo.vba.excel.Hyperlink", aArgs ), uno::UNO_SET_THROW ); + return uno::Any( xHyperlink ); +} + +uno::Any ScVbaEventsHelper::createWindow() const throw (uno::RuntimeException) +{ + uno::Sequence< uno::Any > aArgs( 2 ); + aArgs[ 0 ] <<= createVBAUnoAPIService( mpShell, "ooo.vba.Application" ); + aArgs[ 1 ] <<= mxModel; + uno::Reference< uno::XInterface > xWindow( createVBAUnoAPIServiceWithArgs( mpShell, "ooo.vba.excel.Window", aArgs ), uno::UNO_SET_THROW ); + return uno::Any( xWindow ); +} + +// ============================================================================ + +namespace vbaeventshelper +{ +namespace sdecl = comphelper::service_decl; +sdecl::class_<ScVbaEventsHelper, sdecl::with_args<true> > serviceImpl; +extern sdecl::ServiceDecl const serviceDecl( + serviceImpl, + "ScVbaEventsHelper", + "com.sun.star.script.vba.SpreadsheetEventProcessor" ); +} + +// ============================================================================ diff --git a/sc/source/ui/vba/vbaeventshelper.hxx b/sc/source/ui/vba/vbaeventshelper.hxx new file mode 100755 index 000000000..39c91e31a --- /dev/null +++ b/sc/source/ui/vba/vbaeventshelper.hxx @@ -0,0 +1,86 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#ifndef SC_VBAEVENTS_HXX +#define SC_VBAEVENTS_HXX + +#include <rtl/ref.hxx> +#include <vbahelper/vbaeventshelperbase.hxx> +#include "excelvbahelper.hxx" +#include "rangelst.hxx" + +namespace ooo { namespace vba { namespace excel { class XApplication; } } } + +class ScVbaWindowListener; + +// ============================================================================ + +class ScVbaEventsHelper : public VbaEventsHelperBase +{ +public: + ScVbaEventsHelper( + const css::uno::Sequence< css::uno::Any >& rArgs, + const css::uno::Reference< css::uno::XComponentContext >& rxContext ); + virtual ~ScVbaEventsHelper(); + +protected: + virtual bool implEventsEnabled() throw (css::uno::RuntimeException); + virtual bool implPrepareEvent( EventQueue& rEventQueue, const EventHandlerInfo& rInfo, const css::uno::Sequence< css::uno::Any >& rArgs ) throw (css::uno::RuntimeException); + virtual css::uno::Sequence< css::uno::Any > implBuildArgumentList( const EventHandlerInfo& rInfo, const css::uno::Sequence< css::uno::Any >& rArgs ) throw (css::lang::IllegalArgumentException); + virtual void implPostProcessEvent( EventQueue& rEventQueue, const EventHandlerInfo& rInfo, bool bSuccess, bool bCancel ) throw (css::uno::RuntimeException); + virtual ::rtl::OUString implGetDocumentModuleName( const EventHandlerInfo& rInfo, const css::uno::Sequence< css::uno::Any >& rArgs ) const throw (css::lang::IllegalArgumentException); + +private: + /** Extracts a sheet index from the first element of the passed sequence. The + element may be an integer, or a Calc range or ranges object. */ + static SCTAB getTabFromArgs( const css::uno::Sequence< css::uno::Any >& rArgs, sal_Int32 nIndex ) throw (css::lang::IllegalArgumentException); + /** Checks if selection has been changed compared to selection of last call. + @return true, if the selection has been changed. */ + bool isSelectionChanged( const css::uno::Sequence< css::uno::Any >& rArgs, sal_Int32 nIndex ) throw (css::lang::IllegalArgumentException, css::uno::RuntimeException); + + /** Creates a VBA Worksheet object (the argument must contain a sheet index). */ + css::uno::Any createWorksheet( const css::uno::Sequence< css::uno::Any >& rArgs, sal_Int32 nIndex ) const throw (css::lang::IllegalArgumentException, css::uno::RuntimeException); + /** Creates a VBA Range object (the argument must contain a UNO range or UNO range list). */ + css::uno::Any createRange( const css::uno::Sequence< css::uno::Any >& rArgs, sal_Int32 nIndex ) const throw (css::lang::IllegalArgumentException, css::uno::RuntimeException); + /** Creates a VBA Hyperlink object (the argument must contain a UNO cell). */ + css::uno::Any createHyperlink( const css::uno::Sequence< css::uno::Any >& rArgs, sal_Int32 nIndex ) const throw (css::lang::IllegalArgumentException, css::uno::RuntimeException); + /** Creates a VBA Window object. */ + css::uno::Any createWindow() const throw (css::uno::RuntimeException); + +private: + mutable css::uno::WeakReference< ov::excel::XApplication > mxApplication; + ::rtl::Reference< ScVbaWindowListener > mxWindowListener; + ScDocShell* mpDocShell; + ScDocument* mpDoc; + ScRangeList maOldSelection; + bool mbOpened; + bool mbClosed; +}; + +// ============================================================================ + +#endif diff --git a/sc/source/ui/vba/vbaglobals.cxx b/sc/source/ui/vba/vbaglobals.cxx index 1c8c06c41..1ab234462 100644 --- a/sc/source/ui/vba/vbaglobals.cxx +++ b/sc/source/ui/vba/vbaglobals.cxx @@ -233,6 +233,7 @@ ScVbaGlobals::getAvailableServiceNames( ) throw (uno::RuntimeException) ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM ( "ooo.vba.excel.Worksheet" ) ), ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM ( "ooo.vba.excel.Application" ) ), ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM ( "ooo.vba.excel.Hyperlink" ) ), + ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM ( "com.sun.star.script.vba.SpreadsheetEventProcessor" ) ) }; sal_Int32 nExcelServices = ( sizeof( names )/ sizeof( names[0] ) ); sal_Int32 startIndex = serviceNames.getLength(); diff --git a/sc/source/ui/view/gridwin.cxx b/sc/source/ui/view/gridwin.cxx index 282a8b55b..a78f7cf16 100644 --- a/sc/source/ui/view/gridwin.cxx +++ b/sc/source/ui/view/gridwin.cxx @@ -69,6 +69,8 @@ #include <com/sun/star/sheet/MemberResultFlags.hpp> #include <com/sun/star/awt/KeyModifier.hpp> #include <com/sun/star/awt/MouseButton.hpp> +#include <com/sun/star/script/vba/EventIdentifier.hpp> +#include <com/sun/star/script/vba/XEventProcessor.hpp> #include "gridwin.hxx" #include "tabvwsh.hxx" @@ -119,6 +121,7 @@ #include "tabprotection.hxx" #include "postit.hxx" #include "dpcontrol.hxx" +#include "cellsuno.hxx" #include "drawview.hxx" #include <svx/sdrpagewindow.hxx> @@ -354,6 +357,32 @@ void lcl_UnLockComment( ScDrawView* pView, SdrPageView* pPV, SdrModel* pDrDoc, c } } +sal_Bool lcl_GetHyperlinkCell(ScDocument* pDoc, SCCOL& rPosX, SCROW& rPosY, SCTAB nTab, ScBaseCell*& rpCell ) +{ + BOOL bFound = FALSE; + do + { + pDoc->GetCell( rPosX, rPosY, nTab, rpCell ); + if ( !rpCell || rpCell->GetCellType() == CELLTYPE_NOTE ) + { + if ( rPosX <= 0 ) + return FALSE; // alles leer bis links + else + --rPosX; // weitersuchen + } + else if ( rpCell->GetCellType() == CELLTYPE_EDIT) + bFound = TRUE; + else if (rpCell->GetCellType() == CELLTYPE_FORMULA && + static_cast<ScFormulaCell*>(rpCell)->IsHyperLinkCell()) + bFound = TRUE; + else + return FALSE; // andere Zelle + } + while ( !bFound ); + + return bFound; +} + // --------------------------------------------------------------------------- // WB_DIALOGCONTROL noetig fuer UNO-Controls ScGridWindow::ScGridWindow( Window* pParent, ScViewData* pData, ScSplitPos eWhichPos ) @@ -2101,6 +2130,30 @@ void __EXPORT ScGridWindow::MouseButtonUp( const MouseEvent& rMEvt ) { nMouseStatus = SC_GM_NONE; // keinen Doppelklick anfangen ScGlobal::OpenURL( aUrl, aTarget ); + + // fire worksheet_followhyperlink event + uno::Reference< script::vba::XEventProcessor > xVbaEvents = pDoc->GetVbaEventProcessor(); + if( xVbaEvents.is() ) try + { + Point aPos = rMEvt.GetPosPixel(); + SCsCOL nPosX; + SCsROW nPosY; + SCTAB nTab = pViewData->GetTabNo(); + pViewData->GetPosFromPixel( aPos.X(), aPos.Y(), eWhich, nPosX, nPosY ); + ScBaseCell* pCell = NULL; + if( lcl_GetHyperlinkCell( pDoc, nPosX, nPosY, nTab, pCell ) ) + { + ScAddress aCellPos( nPosX, nPosY, nTab ); + uno::Reference< table::XCell > xCell( new ScCellObj( pViewData->GetDocShell(), aCellPos ) ); + uno::Sequence< uno::Any > aArgs(1); + aArgs[0] <<= xCell; + xVbaEvents->processVbaEvent( script::vba::EventIdentifier::WORKSHEET_FOLLOWHYPERLINK, aArgs ); + } + } + catch( uno::Exception& ) + { + } + return; } } @@ -4821,26 +4874,9 @@ BOOL ScGridWindow::GetEditUrlOrError( BOOL bSpellErr, const Point& rPos, ScDocument* pDoc = pDocSh->GetDocument(); ScBaseCell* pCell = NULL; - BOOL bFound = FALSE; - do - { - pDoc->GetCell( nPosX, nPosY, nTab, pCell ); - if ( !pCell || pCell->GetCellType() == CELLTYPE_NOTE ) - { - if ( nPosX <= 0 ) - return FALSE; // alles leer bis links - else - --nPosX; // weitersuchen - } - else if ( pCell->GetCellType() == CELLTYPE_EDIT) - bFound = TRUE; - else if (pCell->GetCellType() == CELLTYPE_FORMULA && - static_cast<ScFormulaCell*>(pCell)->IsHyperLinkCell()) - bFound = TRUE; - else - return FALSE; // andere Zelle - } - while ( !bFound ); + BOOL bFound = lcl_GetHyperlinkCell( pDoc, nPosX, nPosY, nTab, pCell ); + if( !bFound ) + return FALSE; ScHideTextCursor aHideCursor( pViewData, eWhich ); // before GetEditArea (MapMode is changed) diff --git a/sc/source/ui/view/makefile.mk b/sc/source/ui/view/makefile.mk index feeacc865..525f108af 100644 --- a/sc/source/ui/view/makefile.mk +++ b/sc/source/ui/view/makefile.mk @@ -154,6 +154,7 @@ EXCEPTIONSFILES= \ $(SLO)$/formatsh.obj \ $(SLO)$/gridwin2.obj \ $(SLO)$/scextopt.obj \ + $(SLO)$/tabview3.obj \ $(SLO)$/tabvwshb.obj \ $(SLO)$/viewdata.obj \ $(SLO)$/viewfunc.obj \ |