framework/source/dispatch/closedispatcher.cxx | 9 +++ framework/source/loadenv/loadenv.cxx | 4 + include/vcl/dialog.hxx | 17 ++++++ include/vcl/msgbox.hxx | 3 - include/vcl/svapp.hxx | 6 ++ uui/source/iahndl.cxx | 30 ++++++++++- vcl/inc/svdata.hxx | 1 vcl/source/app/svapp.cxx | 16 ++++++ vcl/source/window/dialog.cxx | 67 ++++++++++++++++---------- vcl/source/window/msgbox.cxx | 4 - 10 files changed, 124 insertions(+), 33 deletions(-)
New commits: commit 4a6755c688fb69f8ce47cc89fe49f89860e02e07 Author: Armin Le Grand <armin.le.gr...@cib.de> Date: Thu Aug 24 18:32:38 2017 +0200 Allow non-modal Dialogs during FileImport/Load When opening a file that triggers Dialogs (e.g. cannot read/repair/FileType) the Frame from which it was initialized gets blocked. This irritates quite some people. Changed this to a non-modal Dialog so that the user can continue to work with all opened docs, open new ones, close and print/PDF/export these. Change-Id: I048d3de3369527cec20d26396b87439254764b8a Reviewed-on: https://gerrit.libreoffice.org/41534 Tested-by: Jenkins <c...@libreoffice.org> Reviewed-by: Armin Le Grand <armin.le.gr...@cib.de> diff --git a/framework/source/dispatch/closedispatcher.cxx b/framework/source/dispatch/closedispatcher.cxx index aa15c28009a1..9aa25190a544 100644 --- a/framework/source/dispatch/closedispatcher.cxx +++ b/framework/source/dispatch/closedispatcher.cxx @@ -37,6 +37,7 @@ #include <vcl/svapp.hxx> #include <vcl/syswin.hxx> #include <osl/mutex.hxx> +#include <vcl/dialog.hxx> #include <unotools/moduleoptions.hxx> #include <comphelper/processfactory.hxx> @@ -362,6 +363,14 @@ IMPL_LINK_NOARG_TYPED(CloseDispatcher, impl_asyncCallback, LinkParamNone*, void) } } + // if we still have dialogs open, temporary suppress termination + if (bTerminateApp && Dialog::AreDialogsOpen()) + { + Application::SetShutdownDelayed(); + bCloseFrame = true; + bTerminateApp = false; + } + // Do it now ... bool bSuccess = false; if (bCloseFrame) diff --git a/framework/source/loadenv/loadenv.cxx b/framework/source/loadenv/loadenv.cxx index b6f6f4c92178..c789f4d6e957 100644 --- a/framework/source/loadenv/loadenv.cxx +++ b/framework/source/loadenv/loadenv.cxx @@ -378,6 +378,10 @@ void LoadEnv::startLoading() if (!bStarted) bStarted = impl_loadContent(); + // This may have triggered Dialogs (error cases) that may have + // delayed the shutdown, so give delayed shutdown a chance + Application::TriggerShutdownDelayed(); + // not started => general error // We can't say - what was the reason for. if (!bStarted) diff --git a/include/vcl/dialog.hxx b/include/vcl/dialog.hxx index 3aa38f543802..87588d50c85d 100644 --- a/include/vcl/dialog.hxx +++ b/include/vcl/dialog.hxx @@ -33,7 +33,17 @@ class VclButtonBox; class VCL_DLLPUBLIC Dialog : public SystemWindow { public: - enum class InitFlag { Default, NoParent }; + enum class InitFlag + { + /** Use given parent or get a default one using GetDefaultParent(...) */ + Default, + + /** Suppress Parent so that Parent is not blocked (kind of modal mode) */ + NoParent, + + /** Suppress Parent (no modal, see above) and additionally center on default parent */ + NoParentCentered + }; private: VclPtr<Dialog> mpPrevExecuteDlg; @@ -83,6 +93,10 @@ public: virtual void dispose() override; virtual bool Notify( NotifyEvent& rNEvt ) override; + + // get the default parent for a dialog as is done in standard initialization + static vcl::Window* GetDefaultParent(WinBits nStyle); + virtual void StateChanged( StateChangedType nStateChange ) override; virtual void DataChanged( const DataChangedEvent& rDCEvt ) override; @@ -111,6 +125,7 @@ public: void EndDialog( long nResult = 0 ); static void EndAllDialogs( vcl::Window* pParent=nullptr ); + static bool AreDialogsOpen(); void GetDrawWindowBorder( sal_Int32& rLeftBorder, sal_Int32& rTopBorder, sal_Int32& rRightBorder, sal_Int32& rBottomBorder ) const; diff --git a/include/vcl/msgbox.hxx b/include/vcl/msgbox.hxx index 5ac566f435d9..0f526f618fe6 100644 --- a/include/vcl/msgbox.hxx +++ b/include/vcl/msgbox.hxx @@ -47,7 +47,8 @@ protected: public: MessBox( vcl::Window* pParent, WinBits nStyle, - const OUString& rTitle, const OUString& rMessage ); + const OUString& rTitle, const OUString& rMessage, + Dialog::InitFlag eInitFlag = Dialog::InitFlag::NoParentCentered); virtual ~MessBox(); virtual void dispose() override; diff --git a/include/vcl/svapp.hxx b/include/vcl/svapp.hxx index 34b659fa7f33..2be63c268198 100644 --- a/include/vcl/svapp.hxx +++ b/include/vcl/svapp.hxx @@ -1451,6 +1451,12 @@ public: // For vclbootstrapprotector: static void setDeInitHook(Link<LinkParamNone*,void> const & hook); + // for delayed shutdown: set using SetShutdownDelayed, then + // trigger using TriggerShutdownDelayed which may actually shutdown + // when SetShutdownDelayed is set + static void SetShutdownDelayed(); + static void TriggerShutdownDelayed(); + private: DECL_STATIC_LINK_TYPED( Application, PostEventHandler, void*, void ); }; diff --git a/uui/source/iahndl.cxx b/uui/source/iahndl.cxx index 2321bdf19361..b53f5b474323 100644 --- a/uui/source/iahndl.cxx +++ b/uui/source/iahndl.cxx @@ -998,11 +998,33 @@ executeMessageBox( vcl::Window * pParent, OUString const & rTitle, OUString const & rMessage, - WinBits nButtonMask ) + WinBits nButtonMask, + Dialog::InitFlag eInitFlag) { SolarMutexGuard aGuard; + ScopedVclPtrInstance< MessBox > xBox(pParent, nButtonMask, rTitle, rMessage, eInitFlag); - ScopedVclPtrInstance< MessBox > xBox(pParent, nButtonMask, rTitle, rMessage); + if (Dialog::InitFlag::NoParentCentered == eInitFlag) + { + vcl::Window* pDefaultParent = Dialog::GetDefaultParent(nButtonMask); + + if (pDefaultParent) + { + // need to 'Show' to have the following tasks do someting, does + // not work without and may even stumble on nullptrs/errors + xBox->Show(); + + // center on parent window + const Point aP(pDefaultParent->GetPosPixel()); + const Size aS(pDefaultParent->GetSizePixel()); + const Size aMySize(xBox->GetSizePixel()); + + xBox->SetPosPixel( + Point( + aP.X() + ((aS.Width() - aMySize.Width()) >> 1), + aP.Y() + ((aS.Height() - aMySize.Height()) >> 1))); + } + } sal_uInt16 aResult = xBox->Execute(); switch( aResult ) @@ -1154,7 +1176,7 @@ UUIInteractionHelper::handleGenericErrorRequest( aTitle += aErrTitle; executeMessageBox( - getParentProperty(), aTitle, aErrorString, WB_OK ); + getParentProperty(), aTitle, aErrorString, WB_OK, Dialog::InitFlag::NoParentCentered); } else ErrorHandler::HandleError(nErrorCode); @@ -1278,7 +1300,7 @@ UUIInteractionHelper::handleBrokenPackageRequest( utl::ConfigManager::getProductVersion() ); switch ( - executeMessageBox( getParentProperty(), title, aMessage, nButtonMask ) ) + executeMessageBox( getParentProperty(), title, aMessage, nButtonMask, Dialog::InitFlag::NoParentCentered) ) { case ERRCODE_BUTTON_OK: OSL_ENSURE( xAbort.is(), "unexpected situation" ); diff --git a/vcl/inc/svdata.hxx b/vcl/inc/svdata.hxx index 4b1c1d7b3fa1..fb6c71281eeb 100644 --- a/vcl/inc/svdata.hxx +++ b/vcl/inc/svdata.hxx @@ -147,6 +147,7 @@ struct ImplSVAppData bool mbInAppMain = false; // is Application::Main() on stack bool mbInAppExecute = false; // is Application::Execute() on stack bool mbAppQuit = false; // is Application::Quit() called + bool mbShutdownDelayed = false; bool mbSettingsInit = false; // true: Settings are initialized Application::DialogCancelMode meDialogCancel; // true: All Dialog::Execute() calls will be terminated immediately with return false diff --git a/vcl/source/app/svapp.cxx b/vcl/source/app/svapp.cxx index 6af3c7c1c7cf..fc6fefc7d958 100644 --- a/vcl/source/app/svapp.cxx +++ b/vcl/source/app/svapp.cxx @@ -1816,4 +1816,20 @@ void Application::setDeInitHook(Link<LinkParamNone*,void> const & hook) { pSVData->maAppData.mbInAppMain = true; } +void Application::SetShutdownDelayed() +{ + ImplSVData * pSVData = ImplGetSVData(); + pSVData->maAppData.mbShutdownDelayed = true; +} + +void Application::TriggerShutdownDelayed() +{ + ImplSVData * pSVData = ImplGetSVData(); + + if (pSVData->maAppData.mbShutdownDelayed && !Dialog::AreDialogsOpen()) + { + Application::PostUserEvent(LINK(nullptr, ImplSVAppData, ImplPrepareExitMsg)); + } +} + /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/source/window/dialog.cxx b/vcl/source/window/dialog.cxx index 2cebcb16fe0e..95fed10ab0a6 100644 --- a/vcl/source/window/dialog.cxx +++ b/vcl/source/window/dialog.cxx @@ -365,6 +365,36 @@ void Dialog::ImplInitDialogData() mpDialogImpl = new DialogImpl; } +vcl::Window* Dialog::GetDefaultParent(WinBits nStyle) +{ + vcl::Window* pParent = Application::GetDefDialogParent(); + if (!pParent && !(nStyle & WB_SYSTEMWINDOW)) + pParent = ImplGetSVData()->maWinData.mpAppWin; + + // If Parent is disabled, then we search for a modal dialog + // in this frame + if (pParent && (!pParent->IsInputEnabled() || pParent->IsInModalMode())) + { + ImplSVData* pSVData = ImplGetSVData(); + Dialog* pExeDlg = pSVData->maWinData.mpLastExecuteDlg; + while (pExeDlg) + { + // only if visible and enabled + if (pParent->ImplGetFirstOverlapWindow()->IsWindowOrChild(pExeDlg, true) && + pExeDlg->IsReallyVisible() && + pExeDlg->IsEnabled() && pExeDlg->IsInputEnabled() && !pExeDlg->IsInModalMode()) + { + pParent = pExeDlg; + break; + } + + pExeDlg = pExeDlg->mpPrevExecuteDlg; + } + } + + return pParent; +} + void Dialog::ImplInit( vcl::Window* pParent, WinBits nStyle, InitFlag eFlag ) { SystemWindowFlags nSysWinMode = Application::GetSystemWindowMode(); @@ -376,34 +406,13 @@ void Dialog::ImplInit( vcl::Window* pParent, WinBits nStyle, InitFlag eFlag ) // Now, all Dialogs are per default system windows !!! nStyle |= WB_SYSTEMWINDOW; - if (eFlag == InitFlag::NoParent) + if (InitFlag::NoParent == eFlag || InitFlag::NoParentCentered == eFlag) + { pParent = nullptr; + } else if (!pParent) // parent is NULL: get the default Dialog parent { - pParent = Application::GetDefDialogParent(); - if ( !pParent && !(nStyle & WB_SYSTEMWINDOW) ) - pParent = ImplGetSVData()->maWinData.mpAppWin; - - // If Parent is disabled, then we search for a modal dialog - // in this frame - if ( pParent && (!pParent->IsInputEnabled() || pParent->IsInModalMode()) ) - { - ImplSVData* pSVData = ImplGetSVData(); - Dialog* pExeDlg = pSVData->maWinData.mpLastExecuteDlg; - while ( pExeDlg ) - { - // only if visible and enabled - if ( pParent->ImplGetFirstOverlapWindow()->IsWindowOrChild( pExeDlg, true ) && - pExeDlg->IsReallyVisible() && - pExeDlg->IsEnabled() && pExeDlg->IsInputEnabled() && !pExeDlg->IsInModalMode() ) - { - pParent = pExeDlg; - break; - } - - pExeDlg = pExeDlg->mpPrevExecuteDlg; - } - } + pParent = Dialog::GetDefaultParent(nStyle); } if ( !pParent || (nStyle & WB_SYSTEMWINDOW) || @@ -1000,6 +1009,14 @@ void Dialog::EndAllDialogs( vcl::Window* pParent ) } } +bool Dialog::AreDialogsOpen() +{ + ImplSVData* pSVData = ImplGetSVData(); + Dialog* pModDialog = pSVData->maWinData.mpLastExecuteDlg; + + return (nullptr != pModDialog); +} + void Dialog::SetModalInputMode( bool bModal ) { if ( bModal == mbModalMode ) diff --git a/vcl/source/window/msgbox.cxx b/vcl/source/window/msgbox.cxx index 7fb7f28dd12b..f6fd26773624 100644 --- a/vcl/source/window/msgbox.cxx +++ b/vcl/source/window/msgbox.cxx @@ -138,12 +138,12 @@ void MessBox::ImplInitButtons() } MessBox::MessBox( vcl::Window* pParent, WinBits nStyle, - const OUString& rTitle, const OUString& rMessage ) : + const OUString& rTitle, const OUString& rMessage, Dialog::InitFlag eInitFlag) : ButtonDialog( WINDOW_MESSBOX ), maMessText( rMessage ) { ImplInitMessBoxData(); - ImplInit( pParent, nStyle | WB_MOVEABLE | WB_HORZ | WB_CENTER ); + ImplInit( pParent, nStyle | WB_MOVEABLE | WB_HORZ | WB_CENTER, eInitFlag); ImplInitButtons(); if ( !rTitle.isEmpty() ) _______________________________________________ Libreoffice-commits mailing list libreoffice-comm...@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/libreoffice-commits