dd35dc
From b49380bd288e642352cb7ddc1c050e2fb34b5b43 Mon Sep 17 00:00:00 2001
1458e3
From: =?UTF-8?q?Caol=C3=A1n=20McNamara?= <caolanm@redhat.com>
1458e3
Date: Tue, 13 Jul 2021 12:38:07 +0100
1458e3
Subject: [PATCH] rhbz#1980800 allow --convert-to csv to write each sheet to a
1458e3
 separate file
1458e3
1458e3
Related: tdf#135762 except only currently implemented for command line use
1458e3
1458e3
sample usage:
1458e3
soffice --convert-to csv:"Text - txt - csv (StarCalc)":44,34,UTF8,1,,0,false,true,false,false,false,-1 sample.ods
1458e3
where the new (11th!) final token ("-1") enables writing each sheet to a
1458e3
new file based on the suggested target name so output in this example
1458e3
is files sample-Sheet1.csv and sample-Sheet2.csv
1458e3
1458e3
Only -1 for 'all sheets' vs 0 for existing 'current sheet only' (which
1458e3
is always sheet 0 from the command line) are currently options but the
1458e3
token could be expanded in the future to select specific sheets to
1458e3
export.
1458e3
1458e3
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/118850
1458e3
Tested-by: Jenkins
1458e3
Reviewed-by: Eike Rathke <erack@redhat.com>
1458e3
(cherry picked from commit b8903bc106dad036acb3d117e5c4fc955697fe02)
1458e3
1458e3
Related: tdf#135762 Allow --convert-to csv to specify 1-based sheet number
1458e3
1458e3
Same multifile mechanism as for -1 all sheets is used, so
1458e3
1458e3
soffice --convert-to csv:"Text - txt - csv (StarCalc)":44,34,UTF8,1,,0,false,true,false,false,false,2 sample.ods
1458e3
1458e3
writes a file sample-Sheet2.csv
1458e3
1458e3
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/118971
1458e3
Reviewed-by: Eike Rathke <erack@redhat.com>
1458e3
Tested-by: Jenkins
1458e3
(cherry picked from commit fda91f8be16ba760e360940ebafd6244c648cb8c)
1458e3
1458e3
Related: tdf#135762 Suppress cout if not command line
1458e3
1458e3
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/119294
1458e3
Reviewed-by: Eike Rathke <erack@redhat.com>
1458e3
Tested-by: Jenkins
1458e3
(cherry picked from commit 0cda081c9aa3b3dcb363f97bac60c845ce9a13e0)
1458e3
1458e3
Change-Id: Ib99a120f1a2c8d1008a7a3c59a6b39f572fb346e
1458e3
b9248c9561e4e340c88458ac5dfd159e443a4cfd
1458e3
9431221aadf97739bb197871f25fa151ef4c391c
dd35dc
dd35dc
Plus follow-up fix
dd35dc
<https://git.libreoffice.org/core/+/d768757872ad25219fa291acd623ab98924acaaa%5E%21>
dd35dc
"tdf#129829 sfx2: fix handling of password to open vs modify" (which happens to
dd35dc
also fix saving to smb shares, in addition to the Windows-specific issue it was
dd35dc
originally meant to fix), plus the relevant parts of its preceding
dd35dc
<https://git.libreoffice.org/core/+/037cd13af81f8a1169d01e95036ed942f261f9a6%5E%21>
dd35dc
"sw reqif-xhtml export: add a new RTFOLEMimeType parameter" introducing
dd35dc
SfxMedium::SetArgs.
1458e3
---
1458e3
 desktop/source/app/dispatchwatcher.cxx |  50 +++++++--
dd35dc
 include/sfx2/docfile.hxx               |   2 +
1458e3
 sc/source/ui/dbgui/imoptdlg.cxx        |  16 ++-
1458e3
 sc/source/ui/docshell/docsh.cxx        | 141 +++++++++++++++++++++----
1458e3
 sc/source/ui/inc/docsh.hxx             |   2 +-
1458e3
 sc/source/ui/inc/imoptdlg.hxx          |   6 +-
dd35dc
 sfx2/source/doc/docfile.cxx            |  13 +++
dd35dc
 7 files changed, 194 insertions(+), 36 deletions(-)
1458e3
1458e3
diff --git a/desktop/source/app/dispatchwatcher.cxx b/desktop/source/app/dispatchwatcher.cxx
1458e3
index 04140173c6d1..a5365da618e8 100644
1458e3
--- a/desktop/source/app/dispatchwatcher.cxx
1458e3
+++ b/desktop/source/app/dispatchwatcher.cxx
1458e3
@@ -30,6 +30,7 @@
1458e3
 #include "dispatchwatcher.hxx"
1458e3
 #include <rtl/ustring.hxx>
1458e3
 #include <comphelper/processfactory.hxx>
1458e3
+#include <comphelper/string.hxx>
1458e3
 #include <comphelper/synchronousdispatch.hxx>
1458e3
 #include <com/sun/star/io/IOException.hpp>
1458e3
 #include <com/sun/star/util/XCloseable.hpp>
1458e3
@@ -604,6 +605,8 @@ bool DispatchWatcher::executeDispatchRequests( const std::vector
1458e3
                                 aFilter = impl_GuessFilter( aOutFile, aDocService );
1458e3
                             }
1458e3
 
1458e3
+                            bool bMultiFileTarget = false;
1458e3
+
1458e3
                             if (aFilter.isEmpty())
1458e3
                             {
1458e3
                                 std::cerr << "Error: no export filter" << std::endl;
1458e3
@@ -611,29 +614,54 @@ bool DispatchWatcher::executeDispatchRequests( const std::vector
1458e3
                             else
1458e3
                             {
1458e3
                                 sal_Int32 nFilterOptionsIndex = aFilter.indexOf(':');
1458e3
-                                sal_Int32 nProps = ( 0 < nFilterOptionsIndex ) ? 3 : 2;
1458e3
+                                sal_Int32 nProps = ( 0 < nFilterOptionsIndex ) ? 4 : 3;
1458e3
 
1458e3
                                 if ( !aImgOut.isEmpty() )
1458e3
                                     nProps +=1;
1458e3
                                 Sequence<PropertyValue> conversionProperties( nProps );
1458e3
-                                conversionProperties[0].Name = "Overwrite";
1458e3
-                                conversionProperties[0].Value <<= true;
1458e3
+                                conversionProperties[0].Name = "ConversionRequestOrigin";
1458e3
+                                conversionProperties[0].Value <<= OUString("CommandLine");
1458e3
+                                conversionProperties[1].Name = "Overwrite";
1458e3
+                                conversionProperties[1].Value <<= true;
1458e3
 
1458e3
-                                conversionProperties[1].Name = "FilterName";
1458e3
+                                conversionProperties[2].Name = "FilterName";
1458e3
                                 if( 0 < nFilterOptionsIndex )
1458e3
                                 {
1458e3
-                                    conversionProperties[1].Value <<= aFilter.copy(0, nFilterOptionsIndex);
1458e3
+                                    OUString sFilterName = aFilter.copy(0, nFilterOptionsIndex);
1458e3
+                                    OUString sFilterOptions = aFilter.copy(nFilterOptionsIndex + 1);
1458e3
+
1458e3
+                                    if (sFilterName == "Text - txt - csv (StarCalc)")
1458e3
+                                    {
1458e3
+                                        sal_Int32 nIdx(0);
1458e3
+                                        // If the 11th token is '-1' then we export a file
1458e3
+                                        // per sheet where the file name is based on the suggested
1458e3
+                                        // output filename concatenated with the sheet name, so adjust
1458e3
+                                        // the output and overwrite messages
1458e3
+                                        // If the 11th token is not present or numeric 0 then the
1458e3
+                                        // default sheet is exported with the output filename. If it
1458e3
+                                        // is numeric >0 then that sheet (1-based) with the output
1458e3
+                                        // filename concatenated with the sheet name. So even if
1458e3
+                                        // that is a single file, the multi file target mechanism is
1458e3
+                                        // used.
1458e3
+                                        const OUString aTok(sFilterOptions.getToken(11, ',', nIdx));
1458e3
+                                        // Actual validity is checked in Calc, here just check for
1458e3
+                                        // presence of numeric value at start.
1458e3
+                                        bMultiFileTarget = (!aTok.isEmpty() && aTok.toInt32() != 0);
1458e3
+                                    }
1458e3
+
1458e3
+                                    conversionProperties[2].Value <<= sFilterName;
1458e3
 
1458e3
-                                    conversionProperties[2].Name = "FilterOptions";
1458e3
-                                    conversionProperties[2].Value <<= aFilter.copy(nFilterOptionsIndex + 1);
1458e3
+                                    conversionProperties[3].Name = "FilterOptions";
1458e3
+                                    conversionProperties[3].Value <<= sFilterOptions;
1458e3
                                 }
1458e3
                                 else
1458e3
                                 {
1458e3
-                                    conversionProperties[1].Value <<= aFilter;
1458e3
+                                    conversionProperties[2].Value <<= aFilter;
1458e3
                                 }
1458e3
 
1458e3
                                 if ( !aImgOut.isEmpty() )
1458e3
                                 {
1458e3
+                                    assert(conversionProperties[nProps-1].Name.isEmpty());
1458e3
                                     conversionProperties[nProps-1].Name = "ImageFilter";
1458e3
                                     conversionProperties[nProps-1].Value <<= aImgOut;
1458e3
                                 }
1458e3
@@ -645,9 +673,11 @@ bool DispatchWatcher::executeDispatchRequests( const std::vector
1458e3
                                 OString aTargetURL8 = OUStringToOString(aTempName, osl_getThreadTextEncoding());
1458e3
                                 if (aDispatchRequest.aRequestType != REQUEST_CAT)
1458e3
                                 {
1458e3
-                                    std::cout << "convert " << aSource8 << " -> " << aTargetURL8;
1458e3
+                                    std::cout << "convert " << aSource8;
1458e3
+                                    if (!bMultiFileTarget)
1458e3
+                                        std::cout << " -> " << aTargetURL8;
1458e3
                                     std::cout << " using filter : " << OUStringToOString(aFilter, osl_getThreadTextEncoding()) << std::endl;
1458e3
-                                    if (FStatHelper::IsDocument(aOutFile))
1458e3
+                                    if (!bMultiFileTarget && FStatHelper::IsDocument(aOutFile))
1458e3
                                         std::cout << "Overwriting: " << OUStringToOString(aTempName, osl_getThreadTextEncoding()) << std::endl ;
1458e3
                                 }
1458e3
                                 try
1458e3
diff --git a/include/sfx2/docfile.hxx b/include/sfx2/docfile.hxx
dd35dc
index 2019b5738c01..2886348 100644
1458e3
--- a/include/sfx2/docfile.hxx
1458e3
+++ b/include/sfx2/docfile.hxx
dd35dc
@@ -108,6 +108,8 @@ public:
1458e3
     const OUString&     GetOrigURL() const;
1458e3
 
1458e3
     SfxItemSet  *       GetItemSet() const;
dd35dc
+    void SetArgs(const css::uno::Sequence<css::beans::PropertyValue>& rArgs);
1458e3
+    css::uno::Sequence<css::beans::PropertyValue> GetArgs() const;
1458e3
     void                Close(bool bInDestruction = false);
1458e3
     void                CloseAndRelease();
1458e3
     void                ReOpen();
1458e3
diff --git a/sc/source/ui/dbgui/imoptdlg.cxx b/sc/source/ui/dbgui/imoptdlg.cxx
1458e3
index 26781924baac..7aa8c8acb061 100644
1458e3
--- a/sc/source/ui/dbgui/imoptdlg.cxx
1458e3
+++ b/sc/source/ui/dbgui/imoptdlg.cxx
1458e3
@@ -20,6 +20,7 @@
1458e3
 #include <imoptdlg.hxx>
1458e3
 #include <asciiopt.hxx>
1458e3
 #include <comphelper/string.hxx>
1458e3
+#include <unotools/charclass.hxx>
1458e3
 #include <osl/thread.h>
1458e3
 #include <global.hxx>
1458e3
 
1458e3
@@ -43,6 +44,7 @@ ScImportOptions::ScImportOptions( const OUString& rStr )
1458e3
     bSaveNumberAsSuch = true;
1458e3
     bSaveFormulas = false;
1458e3
     bRemoveSpace = false;
1458e3
+    nSheetToExport = 0;
1458e3
     sal_Int32 nTokenCount = comphelper::string::getTokenCount(rStr, ',');
1458e3
     if ( nTokenCount >= 3 )
1458e3
     {
1458e3
@@ -76,6 +78,16 @@ ScImportOptions::ScImportOptions( const OUString& rStr )
1458e3
                 bSaveFormulas = rStr.getToken(0, ',', nIdx) == "true";
1458e3
             if ( nTokenCount >= 11 )
1458e3
                 bRemoveSpace = rStr.getToken(0, ',', nIdx) == "true";
1458e3
+            if ( nTokenCount >= 12 )
1458e3
+            {
1458e3
+                const OUString aTok(rStr.getToken(0, ',', nIdx));
1458e3
+                if (aTok == "-1")
1458e3
+                    nSheetToExport = -1;    // all
1458e3
+                else if (aTok.isEmpty() || CharClass::isAsciiNumeric(aTok))
1458e3
+                    nSheetToExport = aTok.toInt32();
1458e3
+                else
1458e3
+                    nSheetToExport = -23;   // invalid, force error
1458e3
+            }
1458e3
         }
1458e3
     }
1458e3
 }
1458e3
@@ -99,7 +111,9 @@ OUString ScImportOptions::BuildString() const
1458e3
             "," +
1458e3
             OUString::boolean( bSaveFormulas ) +  // "save formulas": not in ScAsciiOptions
1458e3
             "," +
1458e3
-            OUString::boolean( bRemoveSpace );    // same as "Remove space" in ScAsciiOptions
1458e3
+            OUString::boolean( bRemoveSpace ) +  // same as "Remove space" in ScAsciiOptions
1458e3
+            "," +
1458e3
+            OUString::number(nSheetToExport) ;  // Only available for command line --convert-to
1458e3
 
1458e3
     return aResult;
1458e3
 }
1458e3
diff --git a/sc/source/ui/docshell/docsh.cxx b/sc/source/ui/docshell/docsh.cxx
1458e3
index bd7402231333..1c544fb6fa1a 100644
1458e3
--- a/sc/source/ui/docshell/docsh.cxx
1458e3
+++ b/sc/source/ui/docshell/docsh.cxx
1458e3
@@ -45,6 +45,7 @@
1458e3
 #include <sfx2/objface.hxx>
1458e3
 #include <sfx2/viewfrm.hxx>
1458e3
 #include <svl/documentlockfile.hxx>
1458e3
+#include <svl/fstathelper.hxx>
1458e3
 #include <svl/sharecontrolfile.hxx>
1458e3
 #include <svl/urihelper.hxx>
1458e3
 #include <osl/file.hxx>
1458e3
@@ -120,6 +121,7 @@
1458e3
 #include <comphelper/processfactory.hxx>
1458e3
 #include <comphelper/string.hxx>
1458e3
 #include <unotools/configmgr.hxx>
1458e3
+#include <unotools/ucbstreamhelper.hxx>
1458e3
 #include <uiitems.hxx>
1458e3
 #include <dpobject.hxx>
1458e3
 #include <markdata.hxx>
1458e3
@@ -1920,7 +1922,7 @@ void escapeTextSep(sal_Int32 nPos, const StrT& rStrDelim, StrT& rStr)
1458e3
 
1458e3
 }
1458e3
 
1458e3
-void ScDocShell::AsciiSave( SvStream& rStream, const ScImportOptions& rAsciiOpt )
1458e3
+void ScDocShell::AsciiSave( SvStream& rStream, const ScImportOptions& rAsciiOpt, SCTAB nTab )
1458e3
 {
1458e3
     sal_Unicode cDelim    = rAsciiOpt.nFieldSepCode;
1458e3
     sal_Unicode cStrDelim = rAsciiOpt.nTextSepCode;
1458e3
@@ -1966,7 +1968,6 @@ void ScDocShell::AsciiSave( SvStream& rStream, const ScImportOptions& rAsciiOpt
1458e3
 
1458e3
     SCCOL nStartCol = 0;
1458e3
     SCROW nStartRow = 0;
1458e3
-    SCTAB nTab = GetSaveTab();
1458e3
     SCCOL nEndCol;
1458e3
     SCROW nEndRow;
1458e3
     m_aDocument.GetCellArea( nTab, nEndCol, nEndRow );
1458e3
@@ -2384,35 +2385,129 @@ bool ScDocShell::ConvertTo( SfxMedium &rMed )
1458e3
     }
1458e3
     else if (aFltName == pFilterAscii)
1458e3
     {
1458e3
-        SvStream* pStream = rMed.GetOutStream();
1458e3
-        if (pStream)
1458e3
+        OUString sItStr;
1458e3
+        SfxItemSet*  pSet = rMed.GetItemSet();
1458e3
+        const SfxPoolItem* pItem;
1458e3
+        if ( pSet && SfxItemState::SET ==
1458e3
+             pSet->GetItemState( SID_FILE_FILTEROPTIONS, true, &pItem ) )
1458e3
         {
1458e3
-            OUString sItStr;
1458e3
-            SfxItemSet*  pSet = rMed.GetItemSet();
1458e3
-            const SfxPoolItem* pItem;
1458e3
-            if ( pSet && SfxItemState::SET ==
1458e3
-                 pSet->GetItemState( SID_FILE_FILTEROPTIONS, true, &pItem ) )
1458e3
+            sItStr = static_cast<const SfxStringItem*>(pItem)->GetValue();
1458e3
+        }
1458e3
+
1458e3
+        if ( sItStr.isEmpty() )
1458e3
+        {
1458e3
+            //  default for ascii export (from API without options):
1458e3
+            //  ISO8859-1/MS_1252 encoding, comma, double quotes
1458e3
+
1458e3
+            ScImportOptions aDefOptions( ',', '"', RTL_TEXTENCODING_MS_1252 );
1458e3
+            sItStr = aDefOptions.BuildString();
1458e3
+        }
1458e3
+
1458e3
+        weld::WaitObject aWait( GetActiveDialogParent() );
1458e3
+        ScImportOptions aOptions( sItStr );
1458e3
+
1458e3
+        if (aOptions.nSheetToExport)
1458e3
+        {
1458e3
+            // Only from command line --convert-to
1458e3
+            bRet = true;
1458e3
+
1458e3
+            // Verbose only from command line, not UI (in case we actually
1458e3
+            // implement that) nor macro filter options.
1458e3
+            bool bVerbose = false;
1458e3
+            const css::uno::Sequence<css::beans::PropertyValue> & rArgs = rMed.GetArgs();
1458e3
+            const auto pProp = std::find_if( rArgs.begin(), rArgs.end(),
1458e3
+                    [](const css::beans::PropertyValue& rProp) { return rProp.Name == "ConversionRequestOrigin"; });
1458e3
+            if (pProp != rArgs.end())
1458e3
             {
1458e3
-                sItStr = static_cast<const SfxStringItem*>(pItem)->GetValue();
1458e3
+                OUString aOrigin;
1458e3
+                pProp->Value >>= aOrigin;
1458e3
+                bVerbose = (aOrigin == "CommandLine");
1458e3
             }
1458e3
 
1458e3
-            if ( sItStr.isEmpty() )
1458e3
+            SCTAB nStartTab;
1458e3
+            SCTAB nCount = m_aDocument.GetTableCount();
1458e3
+            if (aOptions.nSheetToExport == -1)
1458e3
             {
1458e3
-                //  default for ascii export (from API without options):
1458e3
-                //  ISO8859-1/MS_1252 encoding, comma, double quotes
1458e3
-
1458e3
-                ScImportOptions aDefOptions( ',', '"', RTL_TEXTENCODING_MS_1252 );
1458e3
-                sItStr = aDefOptions.BuildString();
1458e3
+                // All sheets.
1458e3
+                nStartTab = 0;
1458e3
+            }
1458e3
+            else if (0 < aOptions.nSheetToExport && aOptions.nSheetToExport <= nCount)
1458e3
+            {
1458e3
+                // One sheet, 1-based.
1458e3
+                nCount = aOptions.nSheetToExport;
1458e3
+                nStartTab = nCount - 1;
1458e3
+            }
1458e3
+            else
1458e3
+            {
1458e3
+                // Usage error, no export but log.
1458e3
+                if (bVerbose)
1458e3
+                {
1458e3
+                    if (aOptions.nSheetToExport < 0)
1458e3
+                        std::cout << "Bad sheet number string given." << std::endl;
1458e3
+                    else
1458e3
+                        std::cout << "No sheet number " << aOptions.nSheetToExport
1458e3
+                            << ", number of sheets is " << nCount << std::endl;
1458e3
+                }
1458e3
+                nStartTab = 0;
1458e3
+                nCount = 0;
1458e3
+                SetError(SCERR_EXPORT_DATA);
1458e3
+                bRet = false;
1458e3
             }
1458e3
 
1458e3
-            weld::WaitObject aWait( GetActiveDialogParent() );
1458e3
-            ScImportOptions aOptions( sItStr );
1458e3
-            AsciiSave( *pStream, aOptions );
1458e3
-            bRet = true;
1458e3
+            INetURLObject aURLObject(rMed.GetURLObject());
1458e3
+            OUString sExt = aURLObject.CutExtension();
1458e3
+            OUString sBaseName = aURLObject.GetLastName();
1458e3
+            aURLObject.CutLastName();
1458e3
 
1458e3
-            if (m_aDocument.GetTableCount() > 1)
1458e3
-                if (!rMed.GetError())
1458e3
-                    rMed.SetError(SCWARN_EXPORT_ASCII);
1458e3
+            for (SCTAB i = nStartTab; i < nCount; ++i)
1458e3
+            {
1458e3
+                OUString sTabName;
1458e3
+                if (!m_aDocument.GetName(i, sTabName))
1458e3
+                    sTabName = OUString::number(i);
1458e3
+                INetURLObject aSheetURLObject(aURLObject);
1458e3
+                OUString sFileName = sBaseName + "-" + sTabName;
1458e3
+                if (!sExt.isEmpty())
1458e3
+                    sFileName = sFileName + "." + sExt;
1458e3
+                aSheetURLObject.Append(sFileName);
1458e3
+
1458e3
+                // log similar to DispatchWatcher::executeDispatchRequests
1458e3
+                OUString aOutFile = aSheetURLObject.GetMainURL(INetURLObject::DecodeMechanism::NONE);
1458e3
+                if (bVerbose)
1458e3
+                {
1458e3
+                    OUString aDisplayedName;
1458e3
+                    if (osl::FileBase::E_None != osl::FileBase::getSystemPathFromFileURL(aOutFile, aDisplayedName))
1458e3
+                        aDisplayedName = aOutFile;
1458e3
+                    std::cout << "Writing sheet " << OUStringToOString(sTabName, osl_getThreadTextEncoding()) << " -> "
1458e3
+                                                  << OUStringToOString(aDisplayedName, osl_getThreadTextEncoding())
1458e3
+                                                  << std::endl;
1458e3
+
1458e3
+                    if (FStatHelper::IsDocument(aOutFile))
1458e3
+                        std::cout << "Overwriting: " << OUStringToOString(aDisplayedName, osl_getThreadTextEncoding())
1458e3
+                                                     << std::endl ;
1458e3
+                }
1458e3
+
1458e3
+                std::unique_ptr<SvStream> xStm = ::utl::UcbStreamHelper::CreateStream(aOutFile, StreamMode::TRUNC | StreamMode::WRITE);
1458e3
+                if (!xStm)
1458e3
+                {
1458e3
+                    SetError(ERRCODE_IO_CANTCREATE);
1458e3
+                    bRet = false;
1458e3
+                    break;
1458e3
+                }
1458e3
+                AsciiSave(*xStm, aOptions, i);
1458e3
+            }
1458e3
+        }
1458e3
+        else
1458e3
+        {
1458e3
+            SvStream* pStream = rMed.GetOutStream();
1458e3
+            if (pStream)
1458e3
+            {
1458e3
+                AsciiSave(*pStream, aOptions, GetSaveTab());
1458e3
+                bRet = true;
1458e3
+
1458e3
+                if (m_aDocument.GetTableCount() > 1)
1458e3
+                    if (!rMed.GetError())
1458e3
+                        rMed.SetError(SCWARN_EXPORT_ASCII);
1458e3
+            }
1458e3
         }
1458e3
     }
1458e3
     else if (aFltName == pFilterDBase)
1458e3
diff --git a/sc/source/ui/inc/docsh.hxx b/sc/source/ui/inc/docsh.hxx
1458e3
index a519f4c87d04..6a075ff6dade 100644
1458e3
--- a/sc/source/ui/inc/docsh.hxx
1458e3
+++ b/sc/source/ui/inc/docsh.hxx
1458e3
@@ -230,7 +230,7 @@ public:
1458e3
 
1458e3
     ScDrawLayer*    MakeDrawLayer();
1458e3
 
1458e3
-    void            AsciiSave( SvStream& rStream, const ScImportOptions& rOpt );
1458e3
+    void            AsciiSave( SvStream& rStream, const ScImportOptions& rOpt, SCTAB nTab );
1458e3
 
1458e3
     void            Execute( SfxRequest& rReq );
1458e3
     void            GetState( SfxItemSet &rSet );
1458e3
diff --git a/sc/source/ui/inc/imoptdlg.hxx b/sc/source/ui/inc/imoptdlg.hxx
1458e3
index bac941c2a377..382067d67813 100644
1458e3
--- a/sc/source/ui/inc/imoptdlg.hxx
1458e3
+++ b/sc/source/ui/inc/imoptdlg.hxx
1458e3
@@ -32,7 +32,8 @@ public:
1458e3
         ScImportOptions( sal_Unicode nFieldSep, sal_Unicode nTextSep, rtl_TextEncoding nEnc )
1458e3
             : nFieldSepCode(nFieldSep), nTextSepCode(nTextSep),
1458e3
             bFixedWidth(false), bSaveAsShown(false), bQuoteAllText(false),
1458e3
-            bSaveNumberAsSuch(true), bSaveFormulas(false), bRemoveSpace(false)
1458e3
+            bSaveNumberAsSuch(true), bSaveFormulas(false), bRemoveSpace(false),
1458e3
+            nSheetToExport(0)
1458e3
         { SetTextEncoding( nEnc ); }
1458e3
 
1458e3
     ScImportOptions& operator=( const ScImportOptions& rCpy ) = default;
1458e3
@@ -51,6 +52,9 @@ public:
1458e3
     bool        bSaveNumberAsSuch;
1458e3
     bool        bSaveFormulas;
1458e3
     bool        bRemoveSpace;
1458e3
+    // "0" for 'current sheet', "-1" for all sheets (each to a separate file),
1458e3
+    // or 1-based specific sheet number (to a separate file).
1458e3
+    sal_Int32   nSheetToExport;
1458e3
 };
1458e3
 
1458e3
 #endif // INCLUDED_SC_SOURCE_UI_INC_IMOPTDLG_HXX
1458e3
diff --git a/sfx2/source/doc/docfile.cxx b/sfx2/source/doc/docfile.cxx
dd35dc
index 5d00d39bd837..4e4e74a 100644
1458e3
--- a/sfx2/source/doc/docfile.cxx
1458e3
+++ b/sfx2/source/doc/docfile.cxx
1458e3
@@ -328,6 +328,8 @@ public:
1458e3
 
1458e3
     util::DateTime m_aDateTime;
1458e3
 
1458e3
+    uno::Sequence<beans::PropertyValue> m_aArgs;
1458e3
+
1458e3
     explicit SfxMedium_Impl();
1458e3
     ~SfxMedium_Impl();
1458e3
     SfxMedium_Impl(const SfxMedium_Impl&) = delete;
1458e3
@@ -3240,6 +3242,7 @@ SfxMedium::SfxMedium( const uno::Sequence<beans::PropertyValue>& aArgs ) :
1458e3
     SfxAllItemSet *pParams = new SfxAllItemSet( SfxGetpApp()->GetPool() );
1458e3
     pImpl->m_pSet.reset( pParams );
1458e3
     TransformParameters( SID_OPENDOC, aArgs, *pParams );
dd35dc
+    SetArgs(aArgs);
1458e3
 
1458e3
     OUString aFilterProvider, aFilterName;
1458e3
     {
dd35dc
@@ -3301,6 +3304,16 @@ SfxMedium::SfxMedium( const uno::Sequence<beans::PropertyValue>& aArgs ) :
1458e3
     Init_Impl();
1458e3
 }
1458e3
 
dd35dc
+void SfxMedium::SetArgs(const uno::Sequence<beans::PropertyValue>& rArgs)
dd35dc
+{
dd35dc
+    pImpl->m_aArgs = rArgs;
dd35dc
+    comphelper::SequenceAsHashMap aArgsMap(rArgs);
dd35dc
+    aArgsMap.erase("Stream");
dd35dc
+    aArgsMap.erase("InputStream");
dd35dc
+    pImpl->m_aArgs = aArgsMap.getAsConstPropertyValueList();
dd35dc
+}
dd35dc
+
1458e3
+uno::Sequence<beans::PropertyValue> SfxMedium::GetArgs() const { return pImpl->m_aArgs; }
1458e3
 
1458e3
 SfxMedium::SfxMedium( const uno::Reference < embed::XStorage >& rStor, const OUString& rBaseURL, const std::shared_ptr<SfxItemSet>& p ) :
1458e3
     pImpl(new SfxMedium_Impl)
1458e3
-- 
1458e3
2.31.1
1458e3