diff -r 2eea49bf1c10 basic/inc/basic/sbmod.hxx --- a/basic/inc/basic/sbmod.hxx Tue Mar 09 15:32:19 2010 +0000 +++ b/basic/inc/basic/sbmod.hxx Wed Mar 10 19:21:46 2010 +0000 @@ -49,6 +49,7 @@ struct SbClassData; class SbModuleImpl; +class FormObjEventListenerImpl; class SbModule : public SbxObject { @@ -58,6 +59,7 @@ friend class SbiRuntime; friend class StarBASIC; friend class SbClassModuleObject; + friend class FormObjEventListenerImpl; SbModuleImpl* mpSbModuleImpl; // Impl data std::vector< String > mModuleVariableNames; diff -r 2eea49bf1c10 basic/inc/basic/sbobjmod.hxx --- a/basic/inc/basic/sbobjmod.hxx Tue Mar 09 15:32:19 2010 +0000 +++ b/basic/inc/basic/sbobjmod.hxx Wed Mar 10 19:21:46 2010 +0000 @@ -14,7 +14,7 @@ * * GNU Lesser General Public License Version 2.1 * ============================================= - * Copyright 2005 by Sun Microsystems, Inc. + * Copyright 2005, 2010 by Sun Microsystems, Inc. * 901 San Antonio Road, Palo Alto, CA 94303, USA * * This library is free software; you can redistribute it and/or @@ -59,8 +59,11 @@ void SetUnoObject( const com::sun::star::uno::Any& aObj )throw ( com::sun::star::uno::RuntimeException ) ; }; +class FormObjEventListenerImpl; class SbUserFormModule : public SbObjModule { + friend class FormObjEventListenerImpl; + css::uno::Reference m_DialogListener; css::uno::Reference m_xDialog; css::uno::Reference m_xModel; @@ -69,11 +72,13 @@ SbUserFormModule( const SbUserFormModule& ); SbUserFormModule(); + void UnloadImpl(); protected: virtual void InitObject(); public: TYPEINFO(); SbUserFormModule( const String& rName, const com::sun::star::script::ModuleInfo& mInfo, bool bIsVBACompat ); + ~SbUserFormModule(); virtual SbxVariable* Find( const XubString& rName, SbxClassType t ); void ResetApiObj(); void Unload(); diff -r 2eea49bf1c10 basic/source/classes/sbxmod.cxx --- a/basic/source/classes/sbxmod.cxx Tue Mar 09 15:32:19 2010 +0000 +++ b/basic/source/classes/sbxmod.cxx Wed Mar 10 19:21:46 2010 +0000 @@ -2,7 +2,7 @@ * * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * - * Copyright 2008 by Sun Microsystems, Inc. + * Copyright 2008, 2010 by Sun Microsystems, Inc. * * OpenOffice.org - a multi-platform office productivity suite * @@ -1713,6 +1713,9 @@ sal_Bool mbShowing; FormObjEventListenerImpl(); // not defined FormObjEventListenerImpl(const FormObjEventListenerImpl&); // not defined + + DECL_LINK( disposeDialog, void* ); + public: FormObjEventListenerImpl( SbUserFormModule* pUserForm, const uno::Reference< lang::XComponent >& xComponent ) : mpUserForm( pUserForm ), mxComponent( xComponent) , mbDisposed( false ), mbOpened( sal_False ), mbActivated( sal_False ), mbShowing( sal_False ) { @@ -1730,6 +1733,7 @@ removeListener(); } sal_Bool isShowing() { return mbShowing; } + bool isDisposed() { return mbDisposed; } void removeListener() { try @@ -1781,6 +1785,10 @@ mpUserForm->triggerMethod( rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("Userform_QueryClose") ), aParams); xVbaMethodParameter->setVbaMethodParameter( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM("Cancel")), aParams[0]); + aParams[ 0 ] >>= nCancel; + // if no veto attempt to dispose ( non-modal ) dialogs + if ( !nCancel ) + Application::PostUserEvent( LINK( this, FormObjEventListenerImpl, disposeDialog ), NULL ); return; } @@ -1824,12 +1832,65 @@ if ( mpUserForm ) mpUserForm->ResetApiObj(); } -}; +}; + +IMPL_LINK( FormObjEventListenerImpl, disposeDialog, void*, pParam ) +{ + if ( !mbDisposed && mpUserForm && mpUserForm->pDocObject ) + { + // see if this is a non modal dialog, modal dialogs normally get disposed ( when endexecute is called ) + // if this is a non-modal dialog then attempt to unload the userform + SbUnoObject* pUnoObj = PTR_CAST(SbUnoObject,(SbxVariable*)mpUserForm->pDocObject); + if ( pUnoObj ) + { + uno::Reference< script::XInvocation > xInv( pUnoObj->getUnoAny(), uno::UNO_QUERY ); + if ( xInv.is() ) + { + // Don't handle close window messages from Modal dialogs ( there are handled when endExecute is called ) + sal_Bool bIsModal = sal_True; + if ( ( xInv->getValue( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM("_IsModal") ) ) >>= bIsModal ) && !bIsModal ) + mpUserForm->UnloadImpl(); + } + } + } + return 0; +} SbUserFormModule::SbUserFormModule( const String& rName, const com::sun::star::script::ModuleInfo& mInfo, bool bIsCompat ) :SbObjModule( rName, mInfo, bIsCompat ), mbInit( false ) { m_xModel.set( mInfo.ModuleObject, uno::UNO_QUERY_THROW ); +} + +SbUserFormModule::~SbUserFormModule() +{ + bool bHasDisposed = true; + FormObjEventListenerImpl* pFormListener = dynamic_cast< FormObjEventListenerImpl* >( m_DialogListener.get() ); + if ( pFormListener ) + { + bHasDisposed = pFormListener->isDisposed(); + pFormListener->removeListener(); + } + + // Sometime, when the SbUserFormModule is destructed, but the dialog is not disposed, we need to dispose the dialog here. + // Such as: If the dialog is shown in modeless mode, we can close the document, but the dialog is not closed, so we dispose it. + if ( m_xDialog.is() && !bHasDisposed ) + { + try + { + uno::Reference< lang::XComponent > xComponent( m_xDialog, uno::UNO_QUERY ); + if ( xComponent.is() ) + { + xComponent->dispose(); + } + } + catch( const uno::Exception& ex ) + { + } + } + m_xDialog = NULL; + m_DialogListener = NULL; + pDocObject = NULL; } void SbUserFormModule::ResetApiObj() @@ -1930,27 +1991,9 @@ InitObject(); } -//liuchen 2009-7-21 change to accmordate VBA's beheavior -void SbUserFormModule::Unload() +// the unload functionality without call and handling for QueryClose +void SbUserFormModule::UnloadImpl() { - OSL_TRACE("** Unload() "); - - sal_Int8 nCancel = 0; - sal_Int8 nCloseMode = 1; - - Sequence< Any > aParams; - aParams.realloc(2); - aParams[0] <<= nCancel; - aParams[1] <<= nCloseMode; - - triggerMethod( rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("Userform_QueryClose") ), aParams); - - aParams[0] >>= nCancel; - if (nCancel == 1) - { - return; - } - if ( m_xDialog.is() ) { triggerTerminateEvent(); @@ -1969,7 +2012,11 @@ bWaitForDispose = pFormListener->isShowing(); OSL_TRACE("Showing %d", bWaitForDispose ); } + // Hold the reference of pDocObject, because call pMeth->Get( aVals) will use this reference, but pDocObject will be set to NULL in the call. + SbxObjectRef pObjectHold = pDocObject; pMeth->Get( aVals); + // Release the reference after call pMeth->Get( aVals); + pObjectHold = NULL; if ( !bWaitForDispose ) { // we've either already got a dispose or we'er never going to get one @@ -1977,6 +2024,28 @@ } // else wait for dispose OSL_TRACE("UnloadObject completed ( we hope )"); } +} + +//liuchen 2009-7-21 change to accmordate VBA's beheavior +void SbUserFormModule::Unload() +{ + OSL_TRACE("** Unload() "); + + sal_Int8 nCancel = 0; + sal_Int8 nCloseMode = 1; + + Sequence< Any > aParams; + aParams.realloc(2); + aParams[0] <<= nCancel; + aParams[1] <<= nCloseMode; + + triggerMethod( rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("Userform_QueryClose") ), aParams); + + aParams[0] >>= nCancel; + if ( nCancel ) + return; + + UnloadImpl(); } //liuchen diff -r 2eea49bf1c10 oovbaapi/ooo/vba/msforms/XUserForm.idl --- a/oovbaapi/ooo/vba/msforms/XUserForm.idl Tue Mar 09 15:32:19 2010 +0000 +++ b/oovbaapi/ooo/vba/msforms/XUserForm.idl Wed Mar 10 19:21:46 2010 +0000 @@ -14,7 +14,7 @@ * * GNU Lesser General Public License Version 2.1 * ============================================= - * Copyright 2005 by Sun Microsystems, Inc. + * Copyright 2005, 2010 by Sun Microsystems, Inc. * 901 San Antonio Road, Palo Alto, CA 94303, USA * * This library is free software; you can redistribute it and/or @@ -47,7 +47,7 @@ //interface ::ooo::vba::XHelperInterface; interface ::com::sun::star::script::XInvocation; [attribute] string Caption; - void Show(); + void Show( [in] any modal ); void Hide(); void RePaint(); void UnloadObject(); diff -r 2eea49bf1c10 vbahelper/source/msforms/vbauserform.cxx --- a/vbahelper/source/msforms/vbauserform.cxx Tue Mar 09 15:32:19 2010 +0000 +++ b/vbahelper/source/msforms/vbauserform.cxx Wed Mar 10 19:21:46 2010 +0000 @@ -14,7 +14,7 @@ * * GNU Lesser General Public License Version 2.1 * ============================================= - * Copyright 2005 by Sun Microsystems, Inc. + * Copyright 2005, 2010 by Sun Microsystems, Inc. * 901 San Antonio Road, Palo Alto, CA 94303, USA * * This library is free software; you can redistribute it and/or @@ -36,7 +36,9 @@ #include "vbauserform.hxx" #include #include +#include #include +#include #include #include #include @@ -44,6 +46,9 @@ using namespace ::ooo::vba; using namespace ::com::sun::star; + +// backdoor access keys ( note these are names not legal in OLE/IDL ) +const static rtl::OUString ISMODAL( RTL_CONSTASCII_USTRINGPARAM("_IsModal") ); // some little notes // XDialog implementation has the following interesting bits @@ -55,7 +60,7 @@ // the models in ControlModels can be accessed by name // also the XDialog is a XControl ( to access the model above -ScVbaUserForm::ScVbaUserForm( uno::Sequence< uno::Any > const& aArgs, uno::Reference< uno::XComponentContext >const& xContext ) throw ( lang::IllegalArgumentException ) : ScVbaUserForm_BASE( getXSomethingFromArgs< XHelperInterface >( aArgs, 0 ), xContext, getXSomethingFromArgs< uno::XInterface >( aArgs, 1 ), getXSomethingFromArgs< frame::XModel >( aArgs, 2 ), static_cast< ooo::vba::AbstractGeometryAttributes* >(0) ), mbDispose( true ) +ScVbaUserForm::ScVbaUserForm( uno::Sequence< uno::Any > const& aArgs, uno::Reference< uno::XComponentContext >const& xContext ) throw ( lang::IllegalArgumentException ) : ScVbaUserForm_BASE( getXSomethingFromArgs< XHelperInterface >( aArgs, 0 ), xContext, getXSomethingFromArgs< uno::XInterface >( aArgs, 1 ), getXSomethingFromArgs< frame::XModel >( aArgs, 2 ), static_cast< ooo::vba::AbstractGeometryAttributes* >(0) ), mbDispose( true ), mbModal( false ) { m_xDialog.set( m_xControl, uno::UNO_QUERY_THROW ); uno::Reference< awt::XControl > xControl( m_xDialog, uno::UNO_QUERY_THROW ); @@ -70,26 +75,57 @@ } void SAL_CALL -ScVbaUserForm::Show( ) throw (uno::RuntimeException) +ScVbaUserForm::Show( const uno::Any& modal ) throw (uno::RuntimeException) { - OSL_TRACE("ScVbaUserForm::Show( )"); - short aRet = 0; - mbDispose = true; - if ( m_xDialog.is() ) - aRet = m_xDialog->execute(); - OSL_TRACE("ScVbaUserForm::Show() execute returned %d", aRet); - if ( mbDispose ) + OSL_TRACE("***** !!!!!! *(************** ScVbaUserForm::Show( new and improved )"); + + sal_Bool isModal = sal_True; + // Convert the parameter. + uno::Reference< script::XTypeConverter > xConverter = getTypeConverter( mxContext ); + if ( modal.hasValue() && xConverter.is() ) { + uno::Any aConverted; try { - uno::Reference< lang::XComponent > xComp( m_xDialog, uno::UNO_QUERY_THROW ); - m_xDialog = NULL; - xComp->dispose(); - mbDispose = false; + aConverted = xConverter->convertTo( modal, getCppuType( (const sal_Bool*) 0 ) ); + aConverted >>= isModal; } - catch( uno::Exception& ) + catch( const uno::Exception& ex ) { } + } + + mbDispose = true; + if ( isModal ) // Show the dialog in modal mode. + { + short aRet = 0; + mbModal = true; + if ( m_xDialog.is() ) + { + aRet = m_xDialog->execute(); + } + OSL_TRACE("ScVbaUserForm::Show() execute returned %d", aRet); + if ( mbDispose ) + { + try + { + uno::Reference< lang::XComponent > xComponent( m_xDialog, uno::UNO_QUERY_THROW ); + m_xDialog = NULL; + xComponent->dispose(); + mbDispose = false; + } + catch( const uno::Exception& ex ) + { + } + } + mbModal = false; + } + else // Show the dialog in modeless mode. + { + mbModal = false; + uno::Reference< awt::XWindow > xWindow( getDialogWindow() ); + if ( xWindow.is() ) + xWindow->setVisible( sal_True ); } } @@ -111,7 +147,28 @@ { mbDispose = false; // hide not dispose if ( m_xDialog.is() ) - m_xDialog->endExecute(); + { + if ( mbModal ) // Hide the Modal Dialog. + { + m_xDialog->endExecute(); + } + else // Hide the Modeless Dialog. + { + uno::Reference< awt::XWindow > xWindow ( getDialogWindow() ); + if ( xWindow.is() ) + xWindow->setVisible( sal_False ); + } + } +} + +uno::Reference< awt::XWindow > +ScVbaUserForm::getDialogWindow() +{ + uno::Reference< awt::XWindow > xWindow; + uno::Reference< awt::XControl > xCntrl( m_xDialog, uno::UNO_QUERY ); + if ( xCntrl.is() ) + xWindow.set( xCntrl->getPeer(), uno::UNO_QUERY ); + return xWindow; } void SAL_CALL @@ -125,7 +182,27 @@ { mbDispose = true; if ( m_xDialog.is() ) - m_xDialog->endExecute(); + { + if ( mbModal ) // End the Modal Dialog. + { + m_xDialog->endExecute(); + } + else // Hide the Modeless Dialog and dispose it. + { + uno::Reference< awt::XWindow > xWindow( getDialogWindow() ); + if ( xWindow.is() ) + xWindow->setVisible( sal_False ); + try + { + uno::Reference< lang::XComponent > xComponent( m_xDialog, uno::UNO_QUERY_THROW ); + xComponent->dispose(); + } + catch( const uno::Exception& ex ) + { + } + m_xDialog = NULL; + } + } } rtl::OUString& @@ -177,6 +254,10 @@ uno::Any SAL_CALL ScVbaUserForm::getValue( const ::rtl::OUString& aPropertyName ) throw (beans::UnknownPropertyException, uno::RuntimeException) { + // Some back door access to allow basic runtime to query various states + if ( aPropertyName.equals( ISMODAL ) ) + return uno::makeAny( mbModal ); + uno::Reference< awt::XControl > xDialogControl( m_xDialog, uno::UNO_QUERY_THROW ); uno::Reference< awt::XControlContainer > xContainer( m_xDialog, uno::UNO_QUERY_THROW ); uno::Reference< awt::XControl > xControl = xContainer->getControl( aPropertyName ); diff -r 2eea49bf1c10 vbahelper/source/msforms/vbauserform.hxx --- a/vbahelper/source/msforms/vbauserform.hxx Tue Mar 09 15:32:19 2010 +0000 +++ b/vbahelper/source/msforms/vbauserform.hxx Wed Mar 10 19:21:46 2010 +0000 @@ -14,7 +14,7 @@ * * GNU Lesser General Public License Version 2.1 * ============================================= - * Copyright 2005 by Sun Microsystems, Inc. + * Copyright 2005, 2010 by Sun Microsystems, Inc. * 901 San Antonio Road, Palo Alto, CA 94303, USA * * This library is free software; you can redistribute it and/or @@ -51,14 +51,17 @@ private: css::uno::Reference< css::awt::XDialog > m_xDialog; bool mbDispose; + bool mbModal; rtl::OUString m_sLibName; + css::uno::Reference< css::awt::XWindow > getDialogWindow(); protected: public: ScVbaUserForm( css::uno::Sequence< css::uno::Any > const& aArgs, css::uno::Reference< css::uno::XComponentContext >const& xContext ) throw ( css::lang::IllegalArgumentException ); virtual ~ScVbaUserForm(); + // XUserForm virtual void SAL_CALL RePaint( ) throw (css::uno::RuntimeException); - virtual void SAL_CALL Show( ) throw (css::uno::RuntimeException); + virtual void SAL_CALL Show( const css::uno::Any& modal ) throw (css::uno::RuntimeException); // XIntrospection virtual css::uno::Reference< css::beans::XIntrospectionAccess > SAL_CALL getIntrospection( ) throw (css::uno::RuntimeException); virtual css::uno::Any SAL_CALL invoke( const ::rtl::OUString& aFunctionName, const css::uno::Sequence< css::uno::Any >& aParams, css::uno::Sequence< ::sal_Int16 >& aOutParamIndex, css::uno::Sequence< css::uno::Any >& aOutParam ) throw (css::lang::IllegalArgumentException, css::script::CannotConvertException, css::reflection::InvocationTargetException, css::uno::RuntimeException); diff -r 2eea49bf1c10 vcl/source/window/dialog.cxx --- a/vcl/source/window/dialog.cxx Tue Mar 09 15:32:19 2010 +0000 +++ b/vcl/source/window/dialog.cxx Wed Mar 10 19:21:46 2010 +0000 @@ -553,7 +553,7 @@ //liuchen 2009-7-22, support Excel VBA UserForm_QueryClose event mnCancelClose = 0; ImplCallEventListeners( VCLEVENT_WINDOW_CLOSE ); - if (mnCancelClose == 1) + if ( mnCancelClose != 0 ) { return FALSE; }