summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDaniel Rentz <dr@openoffice.org>2010-07-06 19:34:53 +0200
committerDaniel Rentz <dr@openoffice.org>2010-07-06 19:34:53 +0200
commitd5bbb90b33416ad70987ab6725e41c1ce673ab93 (patch)
treeef4ed55c797fd6ba98c5ef29c36c6ff64dc7ad60
parentbee21111f8c0d5974031722236ae52bdb0d65b97 (diff)
mib17: #i112634# add VBA sheet event handling, based on a patch from Noel Power
-rw-r--r--sc/inc/document.hxx13
-rw-r--r--sc/inc/docuno.hxx9
-rwxr-xr-xsc/inc/sheetevents.hxx2
-rw-r--r--[-rwxr-xr-x]sc/source/core/data/documen2.cxx30
-rw-r--r--sc/source/core/data/documen3.cxx38
-rw-r--r--sc/source/core/data/documen7.cxx2
-rwxr-xr-xsc/source/core/data/sheetevents.cxx35
-rw-r--r--sc/source/filter/excel/excimp8.cxx18
-rw-r--r--sc/source/filter/inc/excimp8.hxx1
-rw-r--r--sc/source/ui/docshell/docsh.cxx108
-rw-r--r--sc/source/ui/docshell/docsh4.cxx2
-rw-r--r--sc/source/ui/unoobj/docuno.cxx108
-rw-r--r--sc/source/ui/unoobj/viewuno.cxx140
-rw-r--r--sc/source/ui/vba/makefile.mk2
-rw-r--r--sc/source/ui/vba/service.cxx12
-rw-r--r--sc/source/ui/vba/vbaapplication.cxx20
-rw-r--r--sc/source/ui/vba/vbaapplication.hxx7
-rwxr-xr-xsc/source/ui/vba/vbaeventshelper.cxx775
-rwxr-xr-xsc/source/ui/vba/vbaeventshelper.hxx86
-rw-r--r--sc/source/ui/vba/vbaglobals.cxx1
-rw-r--r--sc/source/ui/view/gridwin.cxx76
-rw-r--r--sc/source/ui/view/makefile.mk1
22 files changed, 1330 insertions, 156 deletions
diff --git a/sc/inc/document.hxx b/sc/inc/document.hxx
index 0f22b40eef1d..a829787aac2f 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 );
@@ -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 2c3ecee39e32..fd2d9a706556 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 8f52efb990f7..bb27f5cf2068 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 c5922aa88dcc..4cd23ca66353 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 8fb9e764259d..a27e5b0a13d5 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 97aae44f1a7b..d77dc1041d9c 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 e9e430ef85d9..6086eb84dcbb 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 9608804da9f9..378df4704faa 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 5b2bbe2e7b5d..7e4cca15dfe1 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 135bbcdace49..9dd754bbc555 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 f7bcb3ea9f44..a9c92a4b8dbd 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 df283e58c739..e3572f0bf598 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 d10d3ba54f86..025e699552e1 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 0a84b8dd12a5..4cb7e3eb064b 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 8be0f6d9f726..2b1f14cf154a 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 1ed63ff39125..8006292331b6 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 96638651bcd1..ff391b9187b8 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:
@@ -100,6 +102,9 @@ public:
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);
virtual css::uno::Any SAL_CALL Range( const css::uno::Any& Cell1, const css::uno::Any& Cell2 ) 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 000000000000..c9e92a218877
--- /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 000000000000..b859d9db6d23
--- /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 0cddacafd194..178ee85ef068 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 ff40bdeb7390..2d7f883ea852 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 feeacc865fba..525f108aff5f 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 \