Commits

Anonymous committed a64cabd

mib20: #i111553# correctly register current components for VBA

Comments (0)

Files changed (3)

sc/source/ui/unoobj/docuno.cxx

 
 using namespace com::sun::star;
 
+// #i111553# provides the name of the VBA constant for this document type (e.g. 'ThisExcelDoc' for Calc)
+#define SC_UNO_VBAGLOBNAME "VBAGlobalConstantName"
+
 //------------------------------------------------------------------------
 
 //	alles ohne Which-ID, Map nur fuer PropertySetInfo
         {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_VBAGLOBNAME),       0, &getCppuType(static_cast< const rtl::OUString * >(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},
         {
             aRet <<= pDocShell->GetDialogContainer();
         }
+        else if ( aString.EqualsAscii( SC_UNO_VBAGLOBNAME ) )
+        {
+            /*  #i111553# This property provides the name of the constant that
+                will be used to store this model in the global Basic manager.
+                That constant will be equivelant to 'ThisComponent' but for
+                each application, so e.g. a 'ThisExcelDoc' and a 'ThisWordDoc'
+                constant can co-exist, as required by VBA. */
+            aRet <<= rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "ThisExcelDoc" ) );
+        }
         else if ( aString.EqualsAscii( SC_UNO_RUNTIMEUID ) )
         {
             aRet <<= getRuntimeUID();

sc/source/ui/vba/vbaapplication.cxx

 
 uno::Any sbxToUnoValue( SbxVariable* pVar );
 
-class ActiveWorkbook : public ScVbaWorkbook
-{
-protected:
-	virtual uno::Reference< frame::XModel > getModel()
-	{ 	
-		return getCurrentExcelDoc(mxContext); 
-	}
-public:
-	ActiveWorkbook( const uno::Reference< XHelperInterface >& xParent, const uno::Reference< uno::XComponentContext >& xContext) : ScVbaWorkbook(  xParent, xContext ){}
-};
-
 // ============================================================================
 
 /** Global application settings shared by all open workbooks. */
 {
     uno::Reference< excel::XWorkbook > xWrkbk;
     ScDocShell* pShell = excel::getDocShell( getCurrentExcelDoc( mxContext ) );
-    if ( pShell )
-    {
-        String aName;
-        if ( pShell->GetDocument() )
-        {
-            aName = pShell->GetDocument()->GetCodeName();
-            xWrkbk.set( getUnoDocModule(  aName, pShell ), uno::UNO_QUERY );
-            // fallback ( e.g. it's possible a new document was created via the api )
-            // in that case the document will not have the appropriate Document Modules
-            // #TODO #FIXME ( needs to be fixes as part of providing support for an overall document 
-            // vba mode etc. )
-            if ( !xWrkbk.is() )
-                return new ActiveWorkbook( this, mxContext );
-        }
-    }
-    return xWrkbk; 
+    if ( !pShell )
+        throw uno::RuntimeException();
+
+    String aName = pShell->GetDocument()->GetCodeName();
+    // will throw if active document is not in VBA compatibility mode (no object for codename)
+    return uno::Reference< excel::XWorkbook >( getUnoDocModule( aName, pShell ), uno::UNO_QUERY_THROW );
 }
 
 uno::Reference< excel::XWorkbook > SAL_CALL 
 ScVbaApplication::getThisWorkbook() throw (uno::RuntimeException)
 {
-    uno::Reference< excel::XWorkbook > xWrkbk;
     ScDocShell* pShell = excel::getDocShell( getThisExcelDoc( mxContext ) );
-    if ( pShell )
-    {
-        String aName;
-        if ( pShell->GetDocument() )
-        {
-            aName = pShell->GetDocument()->GetCodeName();
-            xWrkbk.set( getUnoDocModule( aName, pShell ), uno::UNO_QUERY );
-            // fallback ( e.g. it's possible a new document was created via the api )
-            // in that case the document will not have the appropriate Document Modules
-            // #TODO #FIXME ( needs to be fixes as part of providing support for an overall document 
-            // vba mode etc. )
-            if ( !xWrkbk.is() )
-                return new ActiveWorkbook( this, mxContext );
-        }
-    }
-    return xWrkbk;
+    if ( !pShell )
+        throw uno::RuntimeException();
+
+    String aName = pShell->GetDocument()->GetCodeName();
+    // should never throw as this model is in VBA compatibility mode
+    return uno::Reference< excel::XWorkbook >( getUnoDocModule( aName, pShell ), uno::UNO_QUERY_THROW );
 }
 
 uno::Reference< XAssistant > SAL_CALL
 uno::Any SAL_CALL
 ScVbaApplication::Worksheets( const uno::Any& aIndex ) throw (uno::RuntimeException)
 {
-    uno::Reference< excel::XWorkbook > xWorkbook( getActiveWorkbook(), uno::UNO_QUERY );
-        uno::Any result;
-    if ( xWorkbook.is() )
-        result  = xWorkbook->Worksheets( aIndex );
-
-    else
-        // Fixme - check if this is reasonable/desired behavior
-        throw uno::RuntimeException( rtl::OUString::createFromAscii(
-            "No ActiveWorkBook available" ), uno::Reference< uno::XInterface >() );
-
-	return result;
+    uno::Reference< excel::XWorkbook > xWorkbook( getActiveWorkbook(), uno::UNO_SET_THROW );
+    return xWorkbook->Worksheets( aIndex );
 }
 
 uno::Any SAL_CALL

sfx2/source/doc/objxtor.cxx

 #include "precompiled_sfx2.hxx"
 
 #include "arrdecl.hxx"
+#include <map>
 
 #include <cppuhelper/implbase1.hxx>
 
 #include <com/sun/star/frame/XTitle.hpp>
 #include <vos/mutex.hxx>
 
-#ifndef _SV_RESARY_HXX
 #include <tools/resary.hxx>
-#endif
-#ifndef _MSGBOX_HXX //autogen
 #include <vcl/msgbox.hxx>
-#endif
-#ifndef _WRKWIN_HXX //autogen
 #include <vcl/wrkwin.hxx>
-#endif
 #include <vcl/svapp.hxx>
 #include <svl/eitem.hxx>
 #include <tools/rtti.hxx>
 #include <sfx2/signaturestate.hxx>
 #include <sfx2/sfxmodelfactory.hxx>
 
-#ifndef _BASIC_SBUNO_HXX
 #include <basic/sbuno.hxx>
-#endif
 #include <svtools/sfxecode.hxx>
 #include <svtools/ehdl.hxx>
 #include <unotools/printwarningoptions.hxx>
-#ifndef _UNOTOOLS_PROCESSFACTORY_HXX
 #include <comphelper/processfactory.hxx>
-#endif
 
 #include <com/sun/star/document/XStorageBasedDocument.hpp>
 #include <com/sun/star/script/DocumentDialogLibraryContainer.hpp>
 #define DocumentInfo
 #include "sfxslots.hxx"
 
+namespace {
+
 static WeakReference< XInterface > s_xCurrentComponent;
 
+// remember all registered components for VBA compatibility, to be able to remove them on disposing the model
+typedef ::std::map< XInterface*, ::rtl::OString > VBAConstantNameMap;
+static VBAConstantNameMap s_aRegisteredVBAConstants;
+
+::rtl::OString lclGetVBAGlobalConstName( const Reference< XInterface >& rxComponent )
+{
+    OSL_ENSURE( rxComponent.is(), "lclGetVBAGlobalConstName - missing component" );
+
+    VBAConstantNameMap::iterator aIt = s_aRegisteredVBAConstants.find( rxComponent.get() );
+    if( aIt != s_aRegisteredVBAConstants.end() )
+        return aIt->second;
+    
+    uno::Reference< beans::XPropertySet > xProps( rxComponent, uno::UNO_QUERY );
+    if( xProps.is() ) try
+    {
+        ::rtl::OUString aConstName;
+        xProps->getPropertyValue( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "VBAGlobalConstantName" ) ) ) >>= aConstName;
+        return ::rtl::OUStringToOString( aConstName, RTL_TEXTENCODING_ASCII_US );
+    }
+    catch( uno::Exception& ) // not supported
+    {
+    }
+    return ::rtl::OString();
+}
+
+} // namespace
+
 //=========================================================================
 
 
 
 void SAL_CALL SfxModelListener_Impl::disposing( const com::sun::star::lang::EventObject& _rEvent ) throw ( com::sun::star::uno::RuntimeException )
 {
+    ::vos::OGuard aSolarGuard( Application::GetSolarMutex() );
+
     // am I ThisComponent in AppBasic?
-    ::vos::OGuard aSolarGuard( Application::GetSolarMutex() );
     if ( SfxObjectShell::GetCurrentComponent() == _rEvent.Source )
-    {
+    { 
         // remove ThisComponent reference from AppBasic
         SfxObjectShell::SetCurrentComponent( Reference< XInterface >() );
     }
 
+    /*  Remove VBA component from AppBasic. As every application registers its
+        own current component, the disposed component may not be the "current
+        component" of the SfxObjectShell. */
+    if ( _rEvent.Source.is() )
+    {
+        VBAConstantNameMap::iterator aIt = s_aRegisteredVBAConstants.find( _rEvent.Source.get() );
+        if ( aIt != s_aRegisteredVBAConstants.end() )
+        {
+            if ( BasicManager* pAppMgr = SFX_APP()->GetBasicManager() )
+                pAppMgr->SetGlobalUNOConstant( aIt->second.getStr(), Any( Reference< XInterface >() ) );
+            s_aRegisteredVBAConstants.erase( aIt );
+        }
+    }
+
     if ( mpDoc->Get_Impl()->bHiddenLockedByAPI )
 	{
         mpDoc->Get_Impl()->bHiddenLockedByAPI = FALSE;
 
 void SfxObjectShell::SetCurrentComponent( const Reference< XInterface >& _rxComponent )
 {
-    Reference< XInterface > xTest(s_xCurrentComponent);
-    if ( _rxComponent == xTest )
+    Reference< XInterface > xOldCurrentComp(s_xCurrentComponent);
+    if ( _rxComponent == xOldCurrentComp )
         // nothing to do
         return;
     // note that "_rxComponent.get() == s_xCurrentComponent.get().get()" is /sufficient/, but not
     BasicManager* pAppMgr = SFX_APP()->GetBasicManager();
     s_xCurrentComponent = _rxComponent;
     if ( pAppMgr )
-        pAppMgr->SetGlobalUNOConstant( "ThisComponent", makeAny( _rxComponent ) );
+    {
+        // set "ThisComponent" for Basic
+        pAppMgr->SetGlobalUNOConstant( "ThisComponent", Any( _rxComponent ) );
+
+        // set new current component for VBA compatibility
+        if ( _rxComponent.is() )
+        {
+            ::rtl::OString aVBAConstName = lclGetVBAGlobalConstName( _rxComponent );
+            if ( aVBAConstName.getLength() > 0 )
+            {
+                pAppMgr->SetGlobalUNOConstant( aVBAConstName.getStr(), Any( _rxComponent ) );
+                s_aRegisteredVBAConstants[ _rxComponent.get() ] = aVBAConstName;
+            }
+        }
+        // no new component passed -> remove last registered VBA component
+        else if ( xOldCurrentComp.is() )
+        {
+            ::rtl::OString aVBAConstName = lclGetVBAGlobalConstName( xOldCurrentComp );
+            if ( aVBAConstName.getLength() > 0 )
+            {
+                pAppMgr->SetGlobalUNOConstant( aVBAConstName.getStr(), Any( Reference< XInterface >() ) );
+                s_aRegisteredVBAConstants.erase( xOldCurrentComp.get() );
+            }
+        }
+    }
 
 #if OSL_DEBUG_LEVEL > 0
     const char* pComponentImplName = _rxComponent.get() ? typeid( *_rxComponent.get() ).name() : "void";