officecfg/registry/data/org/openoffice/Office/UI/GenericCommands.xcu | 11 sfx2/sdi/sfx.sdi | 6 sfx2/source/appl/appdata.cxx | 1 sfx2/source/appl/appserv.cxx | 113 +++++++--- sfx2/source/doc/objserv.cxx | 8 sfx2/source/inc/appdata.hxx | 1 6 files changed, 114 insertions(+), 26 deletions(-)
New commits: commit 9d9cd7804919c518ed12875a81f520bee878d737 Author: AungKhantOo <[email protected]> AuthorDate: Fri Apr 12 21:01:41 2024 +0000 Commit: Andreas Heinisch <[email protected]> CommitDate: Thu Jun 27 08:05:15 2024 +0200 tdf#159380 Add an UNO command to close all documents Add an UNO command which closes the documents and also prompts the user to save while closing unsaved documents. This command also open the start center after all the documents are successfully closed. Change-Id: I9c502cfa2e550c6f60fa8867fb42e36aded65999 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/166041 Tested-by: Heiko Tietze <[email protected]> Reviewed-by: Andreas Heinisch <[email protected]> Tested-by: Jenkins Reviewed-by: Heiko Tietze <[email protected]> diff --git a/officecfg/registry/data/org/openoffice/Office/UI/GenericCommands.xcu b/officecfg/registry/data/org/openoffice/Office/UI/GenericCommands.xcu index 7880deebb46c..71f3b3ab17a4 100644 --- a/officecfg/registry/data/org/openoffice/Office/UI/GenericCommands.xcu +++ b/officecfg/registry/data/org/openoffice/Office/UI/GenericCommands.xcu @@ -2451,6 +2451,17 @@ bit 3 (0x8): #define UICOMMANDDESCRIPTION_PROPERTIES_TOGGLEBUTTON 8 <value>1</value> </prop> </node> + <node oor:name=".uno:CloseDocs" oor:op="replace"> + <prop oor:name="Label" oor:type="xs:string"> + <value xml:lang="en-US">Close All Documents</value> + </prop> + <prop oor:name="TooltipLabel" oor:type="xs:string"> + <value xml:lang="en-US">Close All Documents</value> + </prop> + <prop oor:name="Properties" oor:type="xs:int"> + <value>1</value> + </prop> + </node> <node oor:name=".uno:Print" oor:op="replace"> <prop oor:name="Label" oor:type="xs:string"> <value xml:lang="en-US">~Print...</value> diff --git a/sfx2/sdi/sfx.sdi b/sfx2/sdi/sfx.sdi index 8d3298b541b4..9993519b3ebe 100644 --- a/sfx2/sdi/sfx.sdi +++ b/sfx2/sdi/sfx.sdi @@ -631,9 +631,9 @@ SfxVoidItem CloseDocs SID_CLOSEDOCS RecordPerSet; Asynchron; - AccelConfig = FALSE, - MenuConfig = FALSE, - ToolBoxConfig = FALSE, + AccelConfig = TRUE, + MenuConfig = TRUE, + ToolBoxConfig = TRUE, GroupId = SfxGroupId::Application; ] diff --git a/sfx2/source/appl/appdata.cxx b/sfx2/source/appl/appdata.cxx index 06d524c9330b..70be13869689 100644 --- a/sfx2/source/appl/appdata.cxx +++ b/sfx2/source/appl/appdata.cxx @@ -79,6 +79,7 @@ SfxAppData_Impl::SfxAppData_Impl() , pViewFrame( nullptr ) , bDowning( true ) , bInQuit( false ) + , bClosingDocs( false ) { pBasic = new BasicDLL; diff --git a/sfx2/source/appl/appserv.cxx b/sfx2/source/appl/appserv.cxx index a53cbd7ff9e1..737635ddf2c0 100644 --- a/sfx2/source/appl/appserv.cxx +++ b/sfx2/source/appl/appserv.cxx @@ -374,8 +374,8 @@ void SfxApplication::MiscExec_Impl( SfxRequest& rReq ) case SID_QUITAPP: case SID_LOGOUT: { - // protect against reentrant calls - if ( pImpl->bInQuit ) + // protect against reentrant calls and avoid closing the same files in parallel + if (pImpl->bInQuit || pImpl->bClosingDocs) return; if ( rReq.GetSlot() == SID_LOGOUT ) @@ -484,34 +484,94 @@ void SfxApplication::MiscExec_Impl( SfxRequest& rReq ) case SID_CLOSEDOCS: { + // protect against reentrant calls and avoid closing the same files in parallel + if (pImpl->bInQuit || pImpl->bClosingDocs) + return; - Reference < XDesktop2 > xDesktop = Desktop::create( ::comphelper::getProcessComponentContext() ); - Reference< XIndexAccess > xTasks = xDesktop->getFrames(); - if ( !xTasks.is() ) - break; + pImpl->bClosingDocs = true; + // closed all status for all visible frames + bool bClosedAll = true; - sal_Int32 n=0; - do + // Iterate over all documents and close them + for (SfxObjectShell *pObjSh = SfxObjectShell::GetFirst(); pObjSh;) { - if ( xTasks->getCount() <= n ) - break; - - Any aAny = xTasks->getByIndex(n); - Reference < XCloseable > xTask; - aAny >>= xTask; - try + SfxObjectShell* pNxtObjSh = SfxObjectShell::GetNext(*pObjSh); + // can close immediately + if (!pObjSh->IsModified() || pObjSh->isSaveLocked()) { - xTask->close(true); - n++; + // don't close the last remaining frame for close dispatch + if (pNxtObjSh || !bClosedAll) + pObjSh->DoClose(); } - catch( CloseVetoException& ) + else { + // skip invisible frames when asking user to close + SfxViewFrame* pFrame = SfxViewFrame::GetFirst(pObjSh); + if (pFrame && pFrame->GetWindow().IsReallyVisible()) + { + // asks user to close + if (pObjSh->PrepareClose()) + { + pObjSh->SetModified(false); + // get next pointer again after asking user since it can become invalid pointer from being manually closed by user + // don't close the last remaining frame for close dispatch + if ((pNxtObjSh = SfxObjectShell::GetNext(*pObjSh)) || !bClosedAll) + pObjSh->DoClose(); + } + // user disagrees to close + else + { + bClosedAll = false; + // get next pointer again after asking user since it can become invalid pointer from being manually closed by user + pNxtObjSh = SfxObjectShell::GetNext(*pObjSh); + } + } } + pObjSh = pNxtObjSh; } - while( true ); - bool bOk = ( n == 0); - rReq.SetReturnValue( SfxBoolItem( 0, bOk ) ); + pImpl->bClosingDocs = false; + + // close dispatch status + bool bDispatchOk = true; + // open backing window + if (bClosedAll) + { + // don't use pViewFrame = SfxViewFrame::Current() as dispatch won't load sometimes + SfxObjectShell* pObjSh = SfxObjectShell::GetFirst(); + SfxViewFrame* pViewFrame = SfxViewFrame::GetFirst(pObjSh); + if (pViewFrame) + { + Reference<XFrame> xCurrentFrame = pViewFrame->GetFrame().GetFrameInterface(); + if (xCurrentFrame.is()) + { + uno::Reference<frame::XDispatchProvider> xProvider(xCurrentFrame, uno::UNO_QUERY); + if (xProvider.is()) + { + uno::Reference<frame::XDispatchHelper> xDispatcher + = frame::DispatchHelper::create(::comphelper::getProcessComponentContext()); + // use .uno:CloseDoc to be able to close windows of the same document + css::uno::Any aResult = + xDispatcher->executeDispatch(xProvider, + u".uno:CloseDoc"_ustr, + u"_self"_ustr, + 0, + uno::Sequence<beans::PropertyValue>()); + css::frame::DispatchResultEvent aEvent; + bDispatchOk = (aResult >>= aEvent) && (aEvent.State == frame::DispatchResultState::SUCCESS); + } + } + } + } + // terminate the application if the dispatch fails or + // if there is no visible frame left after the command is run (e.g user manually closes the document again that was already cancelled for closing) + if (!bDispatchOk || (!bClosedAll && !SfxObjectShell::GetFirst())) + { + SfxRequest aReq(SID_QUITAPP, SfxCallMode::SLOT, GetPool()); + MiscExec_Impl(aReq); + } + + rReq.SetReturnValue(SfxBoolItem(0, bDispatchOk)); bDone = true; break; } @@ -524,7 +584,7 @@ void SfxApplication::MiscExec_Impl( SfxRequest& rReq ) pObjSh = SfxObjectShell::GetNext( *pObjSh ) ) { SfxRequest aReq( SID_SAVEDOC, SfxCallMode::SLOT, pObjSh->GetPool() ); - if ( pObjSh->IsModified() && !pObjSh->isSaveLocked()) + if ( pObjSh->IsModified() && !pObjSh->isSaveLocked() ) { pObjSh->ExecuteSlot( aReq ); const SfxBoolItem* pItem(dynamic_cast<const SfxBoolItem*>(aReq.GetReturnValue().getItem())); @@ -1235,7 +1295,7 @@ void SfxApplication::MiscState_Impl(SfxItemSet &rSet) break; case SID_QUITAPP: { - if ( pImpl->nDocModalMode ) + if (pImpl->nDocModalMode || pImpl->bClosingDocs) rSet.DisableItem(nWhich); else rSet.Put(SfxStringItem(nWhich, SfxResId(STR_QUITAPP))); @@ -1287,8 +1347,15 @@ void SfxApplication::MiscState_Impl(SfxItemSet &rSet) case SID_CLOSEDOCS: { + if ( pImpl->nDocModalMode || pImpl->bInQuit ) + { + rSet.DisableItem(nWhich); + return; + } + Reference < XDesktop2 > xDesktop = Desktop::create( ::comphelper::getProcessComponentContext() ); Reference< XIndexAccess > xTasks = xDesktop->getFrames(); + if ( !xTasks.is() || !xTasks->getCount() ) rSet.DisableItem(nWhich); break; diff --git a/sfx2/source/doc/objserv.cxx b/sfx2/source/doc/objserv.cxx index a7863609e617..f4bcbd1b0496 100644 --- a/sfx2/source/doc/objserv.cxx +++ b/sfx2/source/doc/objserv.cxx @@ -49,6 +49,7 @@ #include <svtools/ehdl.hxx> #include <sal/log.hxx> #include <sfx2/app.hxx> +#include <appdata.hxx> #include <comphelper/string.hxx> #include <basic/sbxcore.hxx> @@ -1293,6 +1294,13 @@ void SfxObjectShell::ExecFile_Impl(SfxRequest &rReq) case SID_CLOSEDOC: { + // cancel requests during SfxApplication is closing or quiting. + SfxAppData_Impl* pAppData = SfxGetpApp()->Get_Impl(); + if (pAppData && (pAppData->bInQuit || pAppData->bClosingDocs)) + { + return; + } + // Evaluate Parameter const SfxBoolItem* pSaveItem = rReq.GetArg<SfxBoolItem>(SID_CLOSEDOC_SAVE); const SfxStringItem* pNameItem = rReq.GetArg<SfxStringItem>(SID_CLOSEDOC_FILENAME); diff --git a/sfx2/source/inc/appdata.hxx b/sfx2/source/inc/appdata.hxx index 6362d05d093d..400dcae776d6 100644 --- a/sfx2/source/inc/appdata.hxx +++ b/sfx2/source/inc/appdata.hxx @@ -114,6 +114,7 @@ public: bool bDowning:1; // sal_True on Exit and afterwards bool bInQuit : 1; + bool bClosingDocs : 1; SfxAppData_Impl(); ~SfxAppData_Impl();
