Blob Blame History Raw
From a4a480f7119c0e3d10acec2c779eb0367196d05d Mon Sep 17 00:00:00 2001
Message-Id: <a4a480f7119c0e3d10acec2c779eb0367196d05d.1477576374.git.erack@redhat.com>
From: Eike Rathke <erack@redhat.com>
Date: Thu, 27 Oct 2016 12:06:46 +0200
Subject: [PATCH] Resolves: tdf#103530 tdf#103531 OOXML: external references
MIME-Version: 1.0
Content-Type: multipart/mixed; boundary="------------erAck-patch-parts"

This is a multi-part message in MIME format.
--------------erAck-patch-parts
Content-Type: text/plain; charset=UTF-8; format=fixed
Content-Transfer-Encoding: 8bit


This is a combination of 3 commits.

Resolves: tdf#103530 OOXML: pass ExternalLinkInfo compiling named expressions

(cherry picked from commit e641c1740f36ce11c9f178193f74a53ac7af8465)

Resolves: tdf#103531 OOXML: write external file ID within quoted sheet names

Excel expects '[1]Sheet Name' instead of [1]'Sheet Name' and complains if it
encounters the latter.

Fortunately Calc handles both.

(cherry picked from commit 02af87fdd76bc94fb51aeb160c74d6f719c42c63)

sc: OOXML: actually write both sheet names in external 3D references

... instead of twice the same name. Even if not handled yet in Calc, external
3D references may get imported and have to be written again.
Copy&Paste error since 2f373570c51e13baf0530605ef59808462e6ca71

(cherry picked from commit a6628078a929a39a95ae8b2f51348996dc41afbc)

f1129e58725b522ca4755c05e313c03fca065f28
6cb982793e1072d619053c02860a8046e78bc99e

Change-Id: If15aa520b93f30b889e5f950185068ef3bdb9235
---
 sc/source/core/tool/compiler.cxx        | 40 ++++++++++++++++++++++++++++-----
 sc/source/filter/inc/defnamesbuffer.hxx |  4 ++--
 sc/source/filter/oox/defnamesbuffer.cxx | 10 +++++----
 3 files changed, 42 insertions(+), 12 deletions(-)


--------------erAck-patch-parts
Content-Type: text/x-patch; name="0001-Resolves-tdf-103530-tdf-103531-OOXML-external-refere.patch"
Content-Transfer-Encoding: 8bit
Content-Disposition: attachment; filename="0001-Resolves-tdf-103530-tdf-103531-OOXML-external-refere.patch"

diff --git a/sc/source/core/tool/compiler.cxx b/sc/source/core/tool/compiler.cxx
index 5d0af7e..2299200 100644
--- a/sc/source/core/tool/compiler.cxx
+++ b/sc/source/core/tool/compiler.cxx
@@ -1184,7 +1184,7 @@ struct ConventionXL
         if (rTabName != aLastTabName)
         {
             rBuf.append(':');
-            ScRangeStringConverter::AppendTableName(rBuf, rTabName);
+            ScRangeStringConverter::AppendTableName(rBuf, aLastTabName);
         }
     }
 
@@ -1470,12 +1470,23 @@ struct ConventionXL_OOX : public ConventionXL_A1
         OUStringBuffer& rBuffer, const ScAddress& rPos, sal_uInt16 nFileId, const OUString& /*rFileName*/,
         const OUString& rTabName, const ScSingleRefData& rRef ) const override
     {
-        // [N]'Sheet Name'!$A$1
+        // '[N]Sheet Name'!$A$1 or [N]SheetName!$A$1
         // Where N is a 1-based positive integer number of a file name in OOXML
         // xl/externalLinks/externalLinkN.xml
 
-        ConventionXL_OOX::makeExternalDocStr(rBuffer, nFileId);
-        ScRangeStringConverter::AppendTableName(rBuffer, rTabName);
+        OUString aQuotedTab( rTabName);
+        ScCompiler::CheckTabQuotes( aQuotedTab);
+        if (!aQuotedTab.isEmpty() && aQuotedTab[0] == '\'')
+        {
+            rBuffer.append('\'');
+            ConventionXL_OOX::makeExternalDocStr( rBuffer, nFileId);
+            rBuffer.append( aQuotedTab.copy(1));
+        }
+        else
+        {
+            ConventionXL_OOX::makeExternalDocStr( rBuffer, nFileId);
+            rBuffer.append( aQuotedTab);
+        }
         rBuffer.append('!');
 
         makeSingleCellStr(rBuffer, rRef, rRef.toAbs(rPos));
@@ -1486,10 +1497,27 @@ struct ConventionXL_OOX : public ConventionXL_A1
         const std::vector<OUString>& rTabNames, const OUString& rTabName,
         const ScComplexRefData& rRef ) const override
     {
+        // '[N]Sheet One':'Sheet Two'!A1:B2 or [N]SheetOne!A1:B2
+        // Actually Excel writes '[N]Sheet One:Sheet Two'!A1:B2 but reads the
+        // simpler to produce and more logical form with independently quoted
+        // sheet names as well. The [N] having to be within the quoted sheet
+        // name is ugly enough..
+
         ScRange aAbsRef = rRef.toAbs(rPos);
 
-        ConventionXL_OOX::makeExternalDocStr(rBuffer, nFileId);
-        ConventionXL::makeExternalTabNameRange(rBuffer, rTabName, rTabNames, aAbsRef);
+        OUStringBuffer aBuf;
+        ConventionXL::makeExternalTabNameRange( aBuf, rTabName, rTabNames, aAbsRef);
+        if (!aBuf.isEmpty() && aBuf[0] == '\'')
+        {
+            rBuffer.append('\'');
+            ConventionXL_OOX::makeExternalDocStr( rBuffer, nFileId);
+            rBuffer.append( aBuf.copy(1));
+        }
+        else
+        {
+            ConventionXL_OOX::makeExternalDocStr( rBuffer, nFileId);
+            rBuffer.append( aBuf);
+        }
         rBuffer.append('!');
 
         makeSingleCellStr(rBuffer, rRef.Ref1, aAbsRef.aStart);
diff --git a/sc/source/filter/inc/defnamesbuffer.hxx b/sc/source/filter/inc/defnamesbuffer.hxx
index 5b0c36e..c4b1d04 100644
--- a/sc/source/filter/inc/defnamesbuffer.hxx
+++ b/sc/source/filter/inc/defnamesbuffer.hxx
@@ -105,8 +105,8 @@ public:
     /** Creates a defined name in the Calc document. */
     void                createNameObject( sal_Int32 nIndex );
     /** Converts the formula string or BIFF token array for this defined name. */
-    void                convertFormula();
-    std::unique_ptr<ScTokenArray> getScTokens();
+    void                convertFormula( const css::uno::Sequence<css::sheet::ExternalLinkInfo>& rExternalLinks );
+    std::unique_ptr<ScTokenArray> getScTokens( const css::uno::Sequence<css::sheet::ExternalLinkInfo>& rExternalLinks );
     /** Returns true, if this defined name is global in the document. */
     inline bool         isGlobalName() const { return mnCalcSheet < 0; }
     /** Returns true, if this defined name is a special builtin name. */
diff --git a/sc/source/filter/oox/defnamesbuffer.cxx b/sc/source/filter/oox/defnamesbuffer.cxx
index 99ed9b7..0bf3d48 100644
--- a/sc/source/filter/oox/defnamesbuffer.cxx
+++ b/sc/source/filter/oox/defnamesbuffer.cxx
@@ -325,11 +325,13 @@ void DefinedName::createNameObject( sal_Int32 nIndex )
     mnTokenIndex = nIndex;
 }
 
-std::unique_ptr<ScTokenArray> DefinedName::getScTokens()
+std::unique_ptr<ScTokenArray> DefinedName::getScTokens(
+        const css::uno::Sequence<css::sheet::ExternalLinkInfo>& rExternalLinks )
 {
     ScTokenArray aTokenArray;
     ScCompiler aCompiler(&getScDocument(), ScAddress(0, 0, mnCalcSheet));
     aCompiler.SetGrammar(formula::FormulaGrammar::GRAM_OOXML);
+    aCompiler.SetExternalLinks( rExternalLinks);
     std::unique_ptr<ScTokenArray> pArray(aCompiler.CompileString(maModel.maFormula));
     // Compile the tokens into RPN once to populate information into tokens
     // where necessary, e.g. for TableRef inner reference. RPN can be discarded
@@ -342,7 +344,7 @@ std::unique_ptr<ScTokenArray> DefinedName::getScTokens()
     return pArray;
 }
 
-void DefinedName::convertFormula()
+void DefinedName::convertFormula( const css::uno::Sequence<css::sheet::ExternalLinkInfo>& rExternalLinks )
 {
     // macro function or vba procedure
     if(!mpScRangeData)
@@ -351,7 +353,7 @@ void DefinedName::convertFormula()
     // convert and set formula of the defined name
     if ( getFilterType() == FILTER_OOXML )
     {
-        std::unique_ptr<ScTokenArray> pTokenArray = getScTokens();
+        std::unique_ptr<ScTokenArray> pTokenArray = getScTokens( rExternalLinks);
         mpScRangeData->SetCode( *pTokenArray );
     }
 
@@ -449,7 +451,7 @@ void DefinedNamesBuffer::finalizeImport()
 
     /*  Now convert all name formulas, so that the formula parser can find all
         names in case of circular dependencies. */
-    maDefNames.forEachMem( &DefinedName::convertFormula );
+    maDefNames.forEachMem( &DefinedName::convertFormula, getExternalLinks().getLinkInfos());
 }
 
 DefinedNameRef DefinedNamesBuffer::getByIndex( sal_Int32 nIndex ) const

--------------erAck-patch-parts--