Kaydet (Commit) b7a30d4b authored tarafından Justin Luth's avatar Justin Luth Kaydeden (comit) Eike Rathke

tdf#113991 xls/xlsx export: no relative sheet in named ranges

MSO apparently requires absolute sheet references
in named ranges.

XLS and XLSX compose the range in entirely different ways.
XLS doesn't use the sSymbol result at all, while XLSX is
entirely dependent upon it.

XLS doesn't require the range to be 3D in order to be absolute,
but XLSX and ODS do require that, so it only makes sense to ensure
that 3D is always enabled when the range changes to absolute
in order to enhance inter-operability.

GLOBAL names will be handled in a followup commit.

Change-Id: Idd2bd841264fdbb30e861da8956da3d28158dfa3
Reviewed-on: https://gerrit.libreoffice.org/54739Tested-by: 's avatarJenkins <ci@libreoffice.org>
Reviewed-by: 's avatarEike Rathke <erack@redhat.com>
üst cd4f4e65
......@@ -179,6 +179,7 @@ public:
#endif
void testAbsNamedRangeHTML();
void testSheetLocalRangeNameXLS();
void testRelativeNamedExpressionsXLS();
void testSheetTextBoxHyperlinkXLSX();
void testFontSizeXLSX();
void testSheetCharacterKerningSpaceXLSX();
......@@ -286,6 +287,7 @@ public:
CPPUNIT_TEST(testPreserveTextWhitespace2XLSX);
CPPUNIT_TEST(testAbsNamedRangeHTML);
CPPUNIT_TEST(testSheetLocalRangeNameXLS);
CPPUNIT_TEST(testRelativeNamedExpressionsXLS);
CPPUNIT_TEST(testSheetTextBoxHyperlinkXLSX);
CPPUNIT_TEST(testFontSizeXLSX);
CPPUNIT_TEST(testSheetCharacterKerningSpaceXLSX);
......@@ -3364,6 +3366,26 @@ void ScExportTest::testSheetLocalRangeNameXLS()
xDocSh2->DoClose();
}
void ScExportTest::testRelativeNamedExpressionsXLS()
{
ScDocShellRef xDocSh = loadDoc("tdf113991_relativeNamedRanges.", FORMAT_ODS);
xDocSh->DoHardRecalc();
ScDocShellRef xDocSh2 = saveAndReload(xDocSh.get(), FORMAT_XLS);
xDocSh->DoClose();
xDocSh2->DoHardRecalc();
ScDocument& rDoc = xDocSh2->GetDocument();
// Sheet1:G3
ScAddress aPos(6,2,0);
CPPUNIT_ASSERT_EQUAL(1.0, rDoc.GetValue(aPos));
ASSERT_FORMULA_EQUAL(rDoc, aPos, "single_cell_A3", nullptr);
// Sheet2:F6
aPos = ScAddress(5,5,1);
CPPUNIT_ASSERT_EQUAL(18.0, rDoc.GetValue(aPos));
ASSERT_FORMULA_EQUAL(rDoc, aPos, "SUM(test_conflict)", nullptr);
xDocSh2->DoClose();
}
void ScExportTest::testSheetTextBoxHyperlinkXLSX()
{
ScDocShellRef xShell = loadDoc("textbox-hyperlink.", FORMAT_XLSX);
......
......@@ -23,6 +23,7 @@
#include <document.hxx>
#include <rangenam.hxx>
#include <tokenarray.hxx>
#include <dbdata.hxx>
#include <xehelper.hxx>
#include <xelink.hxx>
......@@ -334,6 +335,41 @@ void XclExpName::WriteBody( XclExpStream& rStrm )
mxTokArr->WriteArray( rStrm ); // token array without size
}
void lcl_EnsureAbs3DToken( const SCTAB nTab, formula::FormulaToken* pTok )
{
if ( !pTok || ( pTok->GetType() != formula::svSingleRef && pTok->GetType() != formula::svDoubleRef ) )
return;
ScSingleRefData* pRef1 = pTok->GetSingleRef();
if ( !pRef1 )
return;
ScSingleRefData* pRef2 = nullptr;
if ( pTok->GetType() == formula::svDoubleRef )
pRef2 = pTok->GetSingleRef2();
if ( pRef1->IsTabRel() || !pRef1->IsFlag3D() )
{
if ( pRef1->IsTabRel() && nTab != SCTAB_GLOBAL )
pRef1->SetAbsTab( nTab + pRef1->Tab() ); //XLS requirement
if ( !pRef1->IsTabRel() )
{
pRef1->SetFlag3D( true ); //XLSX requirement
if ( pRef2 && !pRef2->IsTabRel() )
pRef2->SetFlag3D( pRef2->Tab() != pRef1->Tab() );
}
}
if ( pRef2 && pRef2->IsTabRel() && !pRef1->IsTabRel() )
{
if ( nTab != SCTAB_GLOBAL )
{
pRef2->SetAbsTab( nTab + pRef2->Tab() );
pRef2->SetFlag3D( pRef2->Tab() != pRef1->Tab() );
}
}
}
XclExpNameManagerImpl::XclExpNameManagerImpl( const XclExpRoot& rRoot ) :
XclExpRoot( rRoot ),
mnFirstUserIdx( 0 )
......@@ -543,12 +579,29 @@ sal_uInt16 XclExpNameManagerImpl::CreateName( SCTAB nTab, const ScRangeData& rRa
This may cause recursive creation of other defined names. */
if( const ScTokenArray* pScTokArr = const_cast< ScRangeData& >( rRangeData ).GetCode() )
{
XclTokenArrayRef xTokArr = GetFormulaCompiler().CreateFormula( EXC_FMLATYPE_NAME, *pScTokArr );
xName->SetTokenArray( xTokArr );
XclTokenArrayRef xTokArr;
OUString sSymbol;
rRangeData.GetSymbol( sSymbol, ((GetOutput() == EXC_OUTPUT_BINARY) ?
formula::FormulaGrammar::GRAM_ENGLISH_XL_A1 : formula::FormulaGrammar::GRAM_OOXML));
// MSO requires named ranges to have absolute sheet references
if ( rRangeData.HasType( ScRangeData::Type::AbsPos ) || rRangeData.HasType( ScRangeData::Type::AbsArea ) )
{
// Don't modify the actual document; use a temporary copy to create the export formulas.
std::unique_ptr<ScTokenArray> pTokenCopy( pScTokArr->Clone() );
lcl_EnsureAbs3DToken( nTab, pTokenCopy.get()->FirstToken() );
xTokArr = GetFormulaCompiler().CreateFormula( EXC_FMLATYPE_NAME, *pTokenCopy.get() );
if ( GetOutput() != EXC_OUTPUT_BINARY )
{
ScCompiler aComp( &GetDocRef(), rRangeData.GetPos(), *pTokenCopy.get(), formula::FormulaGrammar::GRAM_OOXML );
aComp.CreateStringFromTokenArray( sSymbol );
}
}
else
{
xTokArr = GetFormulaCompiler().CreateFormula( EXC_FMLATYPE_NAME, *pScTokArr );
rRangeData.GetSymbol( sSymbol, ((GetOutput() == EXC_OUTPUT_BINARY) ?
formula::FormulaGrammar::GRAM_ENGLISH_XL_A1 : formula::FormulaGrammar::GRAM_OOXML));
}
xName->SetTokenArray( xTokArr );
xName->SetSymbol( sSymbol );
/* Try to replace by existing built-in name - complete token array is
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment