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();

Reply via email to