diff --git a/chart2/qa/extras/chart2export2.cxx b/chart2/qa/extras/chart2export2.cxx
index e05d984f75cf..adde208d620c 100644
--- a/chart2/qa/extras/chart2export2.cxx
+++ b/chart2/qa/extras/chart2export2.cxx
@@ -97,6 +97,7 @@ public:
void testTdf138181();
void testCustomShapeText();
void testuserShapesXLSX();
+ void testNameRangeXLSX();
CPPUNIT_TEST_SUITE(Chart2ExportTest2);
CPPUNIT_TEST(testSetSeriesToSecondaryAxisXLSX);
@@ -157,6 +158,7 @@ public:
CPPUNIT_TEST(testTdf138181);
CPPUNIT_TEST(testCustomShapeText);
CPPUNIT_TEST(testuserShapesXLSX);
+ CPPUNIT_TEST(testNameRangeXLSX);
CPPUNIT_TEST_SUITE_END();
};
@@ -1420,6 +1422,21 @@ void Chart2ExportTest2::testuserShapesXLSX()
CPPUNIT_ASSERT(!xRange->getString().isEmpty());
}
+void Chart2ExportTest2::testNameRangeXLSX()
+{
+ load(u"/chart2/qa/extras/data/xlsx/", "chart_with_name_range.xlsx");
+ xmlDocUniquePtr pXmlDoc = parseExport("xl/charts/chart", "Calc Office Open XML");
+ CPPUNIT_ASSERT(pXmlDoc);
+ // test the syntax of local range name on the the local sheet.
+ assertXPathContent(pXmlDoc,
+ "/c:chartSpace/c:chart/c:plotArea/c:barChart/c:ser/c:cat/c:strRef/c:f",
+ "Sheet1!local_name_range");
+ // test the syntax of a global range name.
+ assertXPathContent(pXmlDoc,
+ "/c:chartSpace/c:chart/c:plotArea/c:barChart/c:ser/c:val/c:numRef/c:f",
+ "[0]!series1");
+}
+
CPPUNIT_TEST_SUITE_REGISTRATION(Chart2ExportTest2);
CPPUNIT_PLUGIN_IMPLEMENT();
diff --git a/chart2/qa/extras/data/xlsx/chart_with_name_range.xlsx b/chart2/qa/extras/data/xlsx/chart_with_name_range.xlsx
new file mode 100644
index 000000000000..2f2b814011ff
Binary files /dev/null and b/chart2/qa/extras/data/xlsx/chart_with_name_range.xlsx differ
diff --git a/offapi/com/sun/star/sheet/FormulaParser.idl b/offapi/com/sun/star/sheet/FormulaParser.idl
index 2c1145ec1369..fb9085130341 100644
--- a/offapi/com/sun/star/sheet/FormulaParser.idl
+++ b/offapi/com/sun/star/sheet/FormulaParser.idl
@@ -81,6 +81,16 @@ service FormulaParser
*/
[property] sequence< ExternalLinkInfo > ExternalLinks;
+
+ /** specifies that use special ooxml chart syntax in case of OOXML reference
+ convention, when parsing a formula string.
+
+
Special syntax like: [0]!GlobalNamedRange, LocalSheet!LocalNamedRange
+
+ @since LibreOffice 7.3
+ */
+ [property] boolean RefConventionChartOOXML;
+
};
diff --git a/oox/source/export/chartexport.cxx b/oox/source/export/chartexport.cxx
index 2a0d335ca86b..dfebc8bf061a 100644
--- a/oox/source/export/chartexport.cxx
+++ b/oox/source/export/chartexport.cxx
@@ -710,6 +710,8 @@ OUString ChartExport::parseFormula( const OUString& rRange )
if( xParserProps.is() )
{
xParserProps->setPropertyValue("FormulaConvention", uno::makeAny(css::sheet::AddressConvention::XL_OOX) );
+ // For referencing named ranges correctly with special excel chart syntax.
+ xParserProps->setPropertyValue("RefConventionChartOOXML", uno::makeAny(true) );
}
aResult = xParser->printFormula( aTokens, CellAddress( 0, 0, 0 ) );
}
diff --git a/oox/source/token/properties.txt b/oox/source/token/properties.txt
index b35a5bc3cd4a..808df85533ff 100644
--- a/oox/source/token/properties.txt
+++ b/oox/source/token/properties.txt
@@ -411,6 +411,7 @@ RangeYMaximum
RangeYMinimum
ReadOnly
RefAngle
+RefConventionChartOOXML
RefR
RefX
RefY
diff --git a/sc/inc/compiler.hxx b/sc/inc/compiler.hxx
index 17e258dc3805..8ae65a4eb8b3 100644
--- a/sc/inc/compiler.hxx
+++ b/sc/inc/compiler.hxx
@@ -297,6 +297,8 @@ private:
ExtendedErrorDetection meExtendedErrorDetection;
bool mbCloseBrackets; // whether to close open brackets automatically, default TRUE
bool mbRewind; // whether symbol is to be rewound to some step during lexical analysis
+ bool mbRefConventionChartOOXML; // whether to use special ooxml chart syntax in case of OOXML reference convention,
+ // when parsing a formula string. [0]!GlobalNamedRange, LocalSheet!LocalNamedRange
std::vector maExternalFiles;
std::vector maTabNames; /// sheet names mangled for the current grammar for output
@@ -426,6 +428,7 @@ public:
*/
void SetAutoCorrection( bool bVal );
void SetCloseBrackets( bool bVal ) { mbCloseBrackets = bVal; }
+ void SetRefConventionChartOOXML( bool bVal ) { mbRefConventionChartOOXML = bVal; }
void SetRefConvention( const Convention *pConvP );
void SetRefConvention( const formula::FormulaGrammar::AddressConvention eConv );
diff --git a/sc/inc/tokenuno.hxx b/sc/inc/tokenuno.hxx
index cded5065f6b2..d025ba0cf44d 100644
--- a/sc/inc/tokenuno.hxx
+++ b/sc/inc/tokenuno.hxx
@@ -62,6 +62,7 @@ private:
bool mbEnglish;
bool mbIgnoreSpaces;
bool mbCompileFAP;
+ bool mbRefConventionChartOOXML;
void SetCompilerFlags( ScCompiler& rCompiler ) const;
diff --git a/sc/inc/unonames.hxx b/sc/inc/unonames.hxx
index c4e7a234f1a3..56936063f74c 100644
--- a/sc/inc/unonames.hxx
+++ b/sc/inc/unonames.hxx
@@ -674,6 +674,7 @@
#define SC_UNO_OPCODEMAP "OpCodeMap"
#define SC_UNO_EXTERNALLINKS "ExternalLinks"
#define SC_UNO_COMPILEFAP "CompileFAP"
+#define SC_UNO_REF_CONV_CHARTOOXML "RefConventionChartOOXML"
// Chart2
#define SC_UNONAME_ROLE "Role"
diff --git a/sc/qa/uitest/chart/tdf64086.py b/sc/qa/uitest/chart/tdf64086.py
new file mode 100644
index 000000000000..238a936a9caa
--- /dev/null
+++ b/sc/qa/uitest/chart/tdf64086.py
@@ -0,0 +1,31 @@
+# -*- tab-width: 4; indent-tabs-mode: nil; py-indent-offset: 4 -*-
+#
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+#
+
+from uitest.framework import UITestCase
+from uitest.uihelper.common import get_url_for_data_file
+
+class NamedRangesChart(UITestCase):
+
+ def test_chart_series_ranges_with_named_ranges_as_datasource(self):
+ with self.ui_test.load_file(get_url_for_data_file("tdf64086.xlsx")) as calc_doc:
+
+ xChart = calc_doc.Sheets[0].Charts[0]
+ xDataSeries = xChart.getEmbeddedObject().getFirstDiagram().CoordinateSystems[0].ChartTypes[0].DataSeries
+
+ self.assertEqual(3, len(xDataSeries))
+
+ test_range1 = calc_doc.Sheets[0].NamedRanges.getByName("Local_sheet_name")
+ self.assertEqual(xDataSeries[0].DataSequences[0].Values.SourceRangeRepresentation, test_range1.Name)
+
+ test_range2 = calc_doc.NamedRanges.getByName("global_name")
+ self.assertEqual(xDataSeries[1].DataSequences[0].Values.SourceRangeRepresentation, test_range2.Name)
+
+ test_range3 = calc_doc.Sheets[1].NamedRanges.getByName("other_sheet_name")
+ test_range3_Name = calc_doc.Sheets[1].Name + '.' + test_range3.Name
+ self.assertEqual(xDataSeries[2].DataSequences[0].Values.SourceRangeRepresentation, test_range3_Name)
+
+# vim: set shiftwidth=4 softtabstop=4 expandtab:
diff --git a/sc/qa/uitest/data/tdf64086.xlsx b/sc/qa/uitest/data/tdf64086.xlsx
new file mode 100644
index 000000000000..4cbd5ce8dbd1
Binary files /dev/null and b/sc/qa/uitest/data/tdf64086.xlsx differ
diff --git a/sc/source/core/tool/compiler.cxx b/sc/source/core/tool/compiler.cxx
index 83eb2f4ab7db..d6ae770e5c91 100644
--- a/sc/source/core/tool/compiler.cxx
+++ b/sc/source/core/tool/compiler.cxx
@@ -1842,6 +1842,7 @@ ScCompiler::ScCompiler( sc::CompileFormulaContext& rCxt, const ScAddress& rPos,
meExtendedErrorDetection(EXTENDED_ERROR_DETECTION_NONE),
mbCloseBrackets(true),
mbRewind(false),
+ mbRefConventionChartOOXML(false),
maTabNames(rCxt.getTabNames())
{
SetGrammar(rCxt.getGrammar());
@@ -1865,7 +1866,8 @@ ScCompiler::ScCompiler( ScDocument& rDocument, const ScAddress& rPos, ScTokenArr
pConv( GetRefConvention( FormulaGrammar::CONV_OOO ) ),
meExtendedErrorDetection( EXTENDED_ERROR_DETECTION_NONE ),
mbCloseBrackets( true ),
- mbRewind( false )
+ mbRewind( false ),
+ mbRefConventionChartOOXML( false )
{
SetGrammar( (eGrammar == formula::FormulaGrammar::GRAM_UNSPECIFIED) ?
rDocument.GetGrammar() :
@@ -1889,6 +1891,7 @@ ScCompiler::ScCompiler( sc::CompileFormulaContext& rCxt, const ScAddress& rPos,
meExtendedErrorDetection(EXTENDED_ERROR_DETECTION_NONE),
mbCloseBrackets(true),
mbRewind(false),
+ mbRefConventionChartOOXML(false),
maTabNames(rCxt.getTabNames())
{
SetGrammar(rCxt.getGrammar());
@@ -1912,7 +1915,8 @@ ScCompiler::ScCompiler( ScDocument& rDocument, const ScAddress& rPos,
pConv( GetRefConvention( FormulaGrammar::CONV_OOO ) ),
meExtendedErrorDetection( EXTENDED_ERROR_DETECTION_NONE ),
mbCloseBrackets( true ),
- mbRewind( false )
+ mbRewind( false ),
+ mbRefConventionChartOOXML( false )
{
SetGrammar( (eGrammar == formula::FormulaGrammar::GRAM_UNSPECIFIED) ?
rDocument.GetGrammar() :
@@ -2244,6 +2248,18 @@ Label_MaskStateMachine:
if (c == '[' && FormulaGrammar::isExcelSyntax( meGrammar)
&& eLastOp != ocDBArea && maTableRefs.empty())
{
+ // [0]!Global_Range_Name, is a special case in OOXML
+ // syntax, where the '0' is referencing to self and we
+ // do not need it, so we should skip it, in order to
+ // later it will be more recognisable for IsNamedRange.
+ if (FormulaGrammar::isRefConventionOOXML(meGrammar) &&
+ pSrc[0] == '0' && pSrc[1] == ']' && pSrc[2] == '!')
+ {
+ pSrc += 3;
+ c = *pSrc;
+ continue;
+ }
+
nMask &= ~ScCharFlags::Char;
goto Label_MaskStateMachine;
}
@@ -5313,7 +5329,7 @@ void ScCompiler::CreateStringFromIndex( OUStringBuffer& rBuffer, const FormulaTo
if (pData)
{
SCTAB nTab = _pTokenP->GetSheet();
- if (nTab >= 0 && nTab != aPos.Tab())
+ if (nTab >= 0 && (nTab != aPos.Tab() || mbRefConventionChartOOXML))
{
// Sheet-local on other sheet.
OUString aName;
@@ -5326,6 +5342,11 @@ void ScCompiler::CreateStringFromIndex( OUStringBuffer& rBuffer, const FormulaTo
aBuffer.append(ScCompiler::GetNativeSymbol(ocErrName));
aBuffer.append( pConv->getSpecialSymbol( ScCompiler::Convention::SHEET_SEPARATOR));
}
+ else if (mbRefConventionChartOOXML)
+ {
+ aBuffer.append("[0]");
+ aBuffer.append(pConv->getSpecialSymbol(ScCompiler::Convention::SHEET_SEPARATOR));
+ }
aBuffer.append(pData->GetName());
}
}
diff --git a/sc/source/core/tool/reftokenhelper.cxx b/sc/source/core/tool/reftokenhelper.cxx
index 58d9353222dc..7d49a60f3e97 100644
--- a/sc/source/core/tool/reftokenhelper.cxx
+++ b/sc/source/core/tool/reftokenhelper.cxx
@@ -108,6 +108,16 @@ void ScRefTokenHelper::compileRangeRepresentation(
if (p->GetString().isEmpty())
bFailure = true;
break;
+ case svIndex:
+ {
+ if (p->GetOpCode() == ocName)
+ {
+ ScRangeData* pNameRange = rDoc.FindRangeNameBySheetAndIndex(p->GetSheet(), p->GetIndex());
+ if (!pNameRange->HasReferences())
+ bFailure = true;
+ }
+ }
+ break;
default:
bFailure = true;
break;
@@ -150,6 +160,16 @@ bool ScRefTokenHelper::getRangeFromToken(
rRange = rRefData.toAbs(*pDoc, rPos);
return true;
}
+ case svIndex:
+ {
+ if (pToken->GetOpCode() == ocName)
+ {
+ ScRangeData* pNameRange = pDoc->FindRangeNameBySheetAndIndex(pToken->GetSheet(), pToken->GetIndex());
+ if (pNameRange->IsReference(rRange, rPos))
+ return true;
+ }
+ return false;
+ }
default:
; // do nothing
}
diff --git a/sc/source/ui/unoobj/chart2uno.cxx b/sc/source/ui/unoobj/chart2uno.cxx
index 2f0461b39a5d..3d1b05256578 100644
--- a/sc/source/ui/unoobj/chart2uno.cxx
+++ b/sc/source/ui/unoobj/chart2uno.cxx
@@ -874,9 +874,21 @@ public:
ScTokenRef aStart, aEnd;
bool bValidToken = splitRangeToken(*mpDoc, rToken, aStart, aEnd);
+ // Check there is a valid reference in named range
+ if (!bValidToken && rToken->GetType() == svIndex && rToken->GetOpCode() == ocName)
+ {
+ ScRangeData* pNameRange = mpDoc->FindRangeNameBySheetAndIndex(rToken->GetSheet(), rToken->GetIndex());
+ if (pNameRange->HasReferences())
+ {
+ const ScTokenRef aTempToken = pNameRange->GetCode()->FirstToken();
+ bValidToken = splitRangeToken(*mpDoc, aTempToken, aStart, aEnd);
+ }
+ }
+
OSL_ENSURE(bValidToken, "invalid token");
if (!bValidToken)
return;
+
ScCompiler aCompiler(*mpDoc, ScAddress(0,0,0), FormulaGrammar::GRAM_ENGLISH);
{
OUString aStr;
@@ -1593,7 +1605,7 @@ class RangeAnalyzer
{
public:
RangeAnalyzer();
- void initRangeAnalyzer( const vector& rTokens );
+ void initRangeAnalyzer( const ScDocument* pDoc, const vector& rTokens );
void analyzeRange( sal_Int32& rnDataInRows, sal_Int32& rnDataInCols,
bool& rbRowSourceAmbiguous ) const;
bool inSameSingleRow( const RangeAnalyzer& rOther );
@@ -1621,7 +1633,7 @@ RangeAnalyzer::RangeAnalyzer()
{
}
-void RangeAnalyzer::initRangeAnalyzer( const vector& rTokens )
+void RangeAnalyzer::initRangeAnalyzer( const ScDocument* pDoc, const vector& rTokens )
{
mnRowCount=0;
mnColumnCount=0;
@@ -1675,6 +1687,28 @@ void RangeAnalyzer::initRangeAnalyzer( const vector& rTokens )
mbAmbiguous=true;
}
}
+ else if (eVar == svIndex && aRefToken->GetOpCode() == ocName)
+ {
+ ScRangeData* pNameRange = pDoc->FindRangeNameBySheetAndIndex(aRefToken->GetSheet(), aRefToken->GetIndex());
+ ScRange aRange;
+ if (pNameRange->IsReference(aRange))
+ {
+ mnColumnCount = std::max(mnColumnCount, static_cast(abs(aRange.aEnd.Col() - aRange.aStart.Col()) + 1));
+ mnRowCount = std::max(mnRowCount, static_cast(abs(aRange.aEnd.Row() - aRange.aStart.Row()) + 1));
+ if (mnStartColumn == -1)
+ {
+ mnStartColumn = aRange.aStart.Col();
+ mnStartRow = aRange.aStart.Row();
+ }
+ else
+ {
+ if (mnStartColumn != aRange.aStart.Col() && mnStartRow != aRange.aStart.Row())
+ mbAmbiguous = true;
+ }
+ }
+ else
+ mbAmbiguous = true;
+ }
else
mbAmbiguous=true;
}
@@ -1777,10 +1811,22 @@ uno::Sequence< beans::PropertyValue > SAL_CALL ScChart2DataProvider::detectArgum
const sal_Unicode cSep = ScCompiler::GetNativeSymbolChar(ocSep);
ScRefTokenHelper::compileRangeRepresentation(
aTokens, xLabel->getSourceRangeRepresentation(), *m_pDocument, cSep, m_pDocument->GetGrammar(), true);
- aLabel.initRangeAnalyzer(aTokens);
+ aLabel.initRangeAnalyzer(m_pDocument, aTokens);
for (const auto& rxToken : aTokens)
{
- ScRefTokenHelper::join(m_pDocument, aAllTokens, rxToken, ScAddress());
+ if (rxToken->GetType() == svIndex && rxToken->GetOpCode() == ocName)
+ {
+ ScRangeData* pNameRange = m_pDocument->FindRangeNameBySheetAndIndex(rxToken->GetSheet(), rxToken->GetIndex());
+ if (pNameRange->HasReferences())
+ {
+ const ScTokenRef aTempToken = pNameRange->GetCode()->FirstToken();
+ ScRefTokenHelper::join(m_pDocument, aAllTokens, aTempToken, ScAddress());
+ }
+ else
+ ScRefTokenHelper::join(m_pDocument, aAllTokens, rxToken, ScAddress());
+ }
+ else
+ ScRefTokenHelper::join(m_pDocument, aAllTokens, rxToken, ScAddress());
if(!bThisIsCategories)
ScRefTokenHelper::join(m_pDocument, aAllSeriesLabelTokens, rxToken, ScAddress());
}
@@ -1795,10 +1841,22 @@ uno::Sequence< beans::PropertyValue > SAL_CALL ScChart2DataProvider::detectArgum
const sal_Unicode cSep = ScCompiler::GetNativeSymbolChar(ocSep);
ScRefTokenHelper::compileRangeRepresentation(
aTokens, xValues->getSourceRangeRepresentation(), *m_pDocument, cSep, m_pDocument->GetGrammar(), true);
- aValues.initRangeAnalyzer(aTokens);
+ aValues.initRangeAnalyzer(m_pDocument, aTokens);
for (const auto& rxToken : aTokens)
{
- ScRefTokenHelper::join(m_pDocument, aAllTokens, rxToken, ScAddress());
+ if (rxToken->GetType() == svIndex && rxToken->GetOpCode() == ocName)
+ {
+ ScRangeData* pNameRange = m_pDocument->FindRangeNameBySheetAndIndex(rxToken->GetSheet(), rxToken->GetIndex());
+ if (pNameRange->HasReferences())
+ {
+ const ScTokenRef aTempToken = pNameRange->GetCode()->FirstToken();
+ ScRefTokenHelper::join(m_pDocument, aAllTokens, aTempToken, ScAddress());
+ }
+ else
+ ScRefTokenHelper::join(m_pDocument, aAllTokens, rxToken, ScAddress());
+ }
+ else
+ ScRefTokenHelper::join(m_pDocument, aAllTokens, rxToken, ScAddress());
if(bThisIsCategories)
ScRefTokenHelper::join(m_pDocument, aAllCategoriesValuesTokens, rxToken, ScAddress());
}
@@ -1885,13 +1943,13 @@ uno::Sequence< beans::PropertyValue > SAL_CALL ScChart2DataProvider::detectArgum
RangeAnalyzer aTop,aLeft;
if( eRowSource==chart::ChartDataRowSource_COLUMNS )
{
- aTop.initRangeAnalyzer(aAllSeriesLabelTokens);
- aLeft.initRangeAnalyzer(aAllCategoriesValuesTokens);
+ aTop.initRangeAnalyzer(m_pDocument, aAllSeriesLabelTokens);
+ aLeft.initRangeAnalyzer(m_pDocument, aAllCategoriesValuesTokens);
}
else
{
- aTop.initRangeAnalyzer(aAllCategoriesValuesTokens);
- aLeft.initRangeAnalyzer(aAllSeriesLabelTokens);
+ aTop.initRangeAnalyzer(m_pDocument, aAllCategoriesValuesTokens);
+ aLeft.initRangeAnalyzer(m_pDocument, aAllSeriesLabelTokens);
}
lcl_addUpperLeftCornerIfMissing(m_pDocument, aAllTokens, aTop.getRowCount(), aLeft.getColumnCount());//e.g. #i91212#
}
@@ -2127,6 +2185,7 @@ ScChart2DataProvider::createDataSequenceByFormulaTokens(
}
}
break;
+ case svIndex:
case svString:
case svSingleRef:
case svDoubleRef:
diff --git a/sc/source/ui/unoobj/tokenuno.cxx b/sc/source/ui/unoobj/tokenuno.cxx
index b07a04e12b04..96f882d282ea 100644
--- a/sc/source/ui/unoobj/tokenuno.cxx
+++ b/sc/source/ui/unoobj/tokenuno.cxx
@@ -78,7 +78,8 @@ ScFormulaParserObj::ScFormulaParserObj(ScDocShell* pDocSh) :
mnConv( sheet::AddressConvention::UNSPECIFIED ),
mbEnglish( false ),
mbIgnoreSpaces( true ),
- mbCompileFAP( false )
+ mbCompileFAP( false ),
+ mbRefConventionChartOOXML( false )
{
mpDocShell->GetDocument().AddUnoObject(*this);
}
@@ -122,7 +123,8 @@ void ScFormulaParserObj::SetCompilerFlags( ScCompiler& rCompiler ) const
rCompiler.EnableJumpCommandReorder(!mbCompileFAP);
rCompiler.EnableStopOnError(!mbCompileFAP);
- rCompiler.SetExternalLinks( maExternalLinks);
+ rCompiler.SetExternalLinks(maExternalLinks);
+ rCompiler.SetRefConventionChartOOXML(mbRefConventionChartOOXML);
}
uno::Sequence SAL_CALL ScFormulaParserObj::parseFormula(
@@ -243,6 +245,11 @@ void SAL_CALL ScFormulaParserObj::setPropertyValue(
if (!(aValue >>= maExternalLinks))
throw lang::IllegalArgumentException();
}
+ else if ( aPropertyName == SC_UNO_REF_CONV_CHARTOOXML )
+ {
+ if (!(aValue >>= mbRefConventionChartOOXML))
+ throw lang::IllegalArgumentException();
+ }
else
throw beans::UnknownPropertyException(aPropertyName);
}
@@ -275,6 +282,10 @@ uno::Any SAL_CALL ScFormulaParserObj::getPropertyValue( const OUString& aPropert
{
aRet <<= maExternalLinks;
}
+ else if ( aPropertyName == SC_UNO_REF_CONV_CHARTOOXML )
+ {
+ aRet <<= mbRefConventionChartOOXML;
+ }
else
throw beans::UnknownPropertyException(aPropertyName);
return aRet;