From cdacee1de7cd8d98d79ef13bc165ce016c8b2e1a Mon Sep 17 00:00:00 2001 From: Tamas Bunth Date: Wed, 18 Dec 2019 13:08:11 +0100 Subject: tdf#123206 Store custom label as chart:data-label MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Use the chart:data-label element instead of using the loext:custom-label-field attribute. chart:data-label stores can be a child of chart:data-point and it may contain a text:o element for holding one or more paragraphs of custom label text. This commit aims to export and import chart:data-label with paragraphs put into different text:span elements. These span elements may hold a text:style-name attribute in order to achieve formatted text. This structure is already in the ODF format. Change-Id: I0bea7ce1a16af9c47b33555e18545bdaae7e95ca Reviewed-on: https://gerrit.libreoffice.org/c/core/+/85659 Tested-by: Jenkins Reviewed-by: Tamás Bunth Reviewed-on: https://gerrit.libreoffice.org/c/core/+/86122 Reviewed-by: Andras Timar --- xmloff/inc/SchXMLImport.hxx | 1 + xmloff/source/chart/SchXMLExport.cxx | 55 ++++++++------ xmloff/source/chart/SchXMLImport.cxx | 1 + xmloff/source/chart/SchXMLPlotAreaContext.cxx | 100 ++++++++++++++++++++++---- xmloff/source/chart/SchXMLPlotAreaContext.hxx | 47 +++++++++++- xmloff/source/chart/SchXMLSeries2Context.cxx | 18 +++-- xmloff/source/chart/transporttypes.hxx | 7 +- xmloff/source/core/xmltoken.cxx | 1 + xmloff/source/token/tokens.txt | 1 + 9 files changed, 185 insertions(+), 46 deletions(-) (limited to 'xmloff') diff --git a/xmloff/inc/SchXMLImport.hxx b/xmloff/inc/SchXMLImport.hxx index 5b587a4abdb1..2978ac66b5ab 100644 --- a/xmloff/inc/SchXMLImport.hxx +++ b/xmloff/inc/SchXMLImport.hxx @@ -73,6 +73,7 @@ enum SchXMLPlotAreaElemTokenMap enum SchXMLSeriesElemTokenMap { XML_TOK_SERIES_DATA_POINT, + XML_TOK_SERIES_DATA_LABEL, XML_TOK_SERIES_DOMAIN, XML_TOK_SERIES_MEAN_VALUE_LINE, XML_TOK_SERIES_REGRESSION_CURVE, diff --git a/xmloff/source/chart/SchXMLExport.cxx b/xmloff/source/chart/SchXMLExport.cxx index 4dd2bc43b6c8..e277b73758b7 100644 --- a/xmloff/source/chart/SchXMLExport.cxx +++ b/xmloff/source/chart/SchXMLExport.cxx @@ -113,11 +113,13 @@ using ::std::vector; namespace { + using CustomLabelSeq = Sequence>; + struct SchXMLDataPointStruct { OUString maStyleName; sal_Int32 mnRepeat; - OUString msCustomLabelText; + CustomLabelSeq mCustomLabelText; SchXMLDataPointStruct() : mnRepeat( 1 ) {} }; @@ -229,6 +231,8 @@ public: const css::uno::Reference< css::chart2::XDiagram > & xDiagram, bool bExportContent ); + void exportCustomLabel(const CustomLabelSeq & xCustomLabel); + void exportRegressionCurve( const css::uno::Reference& xSeries, const css::awt::Size& rPageSize, @@ -277,31 +281,26 @@ public: namespace { -OUString lcl_getCustomLabelField(sal_Int32 nDataPointIndex, +CustomLabelSeq lcl_getCustomLabelField(sal_Int32 nDataPointIndex, const uno::Reference< chart2::XDataSeries >& rSeries) { if( !rSeries.is() ) - return OUString{}; + return CustomLabelSeq(); const SvtSaveOptions::ODFDefaultVersion nCurrentODFVersion( SvtSaveOptions().GetODFDefaultVersion() ); if( nCurrentODFVersion <= SvtSaveOptions::ODFVER_012 )//do not export to ODF 1.2 or older - return OUString{}; + return CustomLabelSeq(); - // export custom label text if(Reference xLabels = rSeries->getDataPointByIndex(nDataPointIndex); xLabels.is()) { if(Any aAny = xLabels->getPropertyValue("CustomLabelFields"); aAny.hasValue()) { Sequence> aCustomLabels; aAny >>= aCustomLabels; - OUString sLabel; - // TODO export formatted string instead of simple characters - for(auto& aLabel : aCustomLabels) - sLabel += aLabel->getString(); - return sLabel; + return aCustomLabels; } } - return OUString{}; + return CustomLabelSeq(); } class lcl_MatchesRole @@ -3266,7 +3265,7 @@ void SchXMLExportHelper_Impl::exportDataPoints( SchXMLDataPointStruct aPoint; aPoint.maStyleName = maAutoStyleNameQueue.front(); if(bExportNumFmt) - aPoint.msCustomLabelText = lcl_getCustomLabelField(nElement, xSeries); + aPoint.mCustomLabelText = lcl_getCustomLabelField(nElement, xSeries); maAutoStyleNameQueue.pop(); aDataPointVector.push_back( aPoint ); } @@ -3294,7 +3293,7 @@ void SchXMLExportHelper_Impl::exportDataPoints( { SchXMLDataPointStruct aPoint; aPoint.mnRepeat = nCurrIndex - nLastIndex - 1; - aPoint.msCustomLabelText = lcl_getCustomLabelField(nCurrIndex, xSeries); + aPoint.mCustomLabelText = lcl_getCustomLabelField(nCurrIndex, xSeries); aDataPointVector.push_back( aPoint ); } @@ -3327,7 +3326,7 @@ void SchXMLExportHelper_Impl::exportDataPoints( SAL_WARN_IF( maAutoStyleNameQueue.empty(), "xmloff.chart", "Autostyle queue empty!" ); SchXMLDataPointStruct aPoint; aPoint.maStyleName = maAutoStyleNameQueue.front(); - aPoint.msCustomLabelText = lcl_getCustomLabelField(nCurrIndex, xSeries); + aPoint.mCustomLabelText = lcl_getCustomLabelField(nCurrIndex, xSeries); maAutoStyleNameQueue.pop(); aDataPointVector.push_back( aPoint ); @@ -3343,7 +3342,7 @@ void SchXMLExportHelper_Impl::exportDataPoints( // if we get here the property states are empty SchXMLDataPointStruct aPoint; - aPoint.msCustomLabelText = lcl_getCustomLabelField(nCurrIndex, xSeries); + aPoint.mCustomLabelText = lcl_getCustomLabelField(nCurrIndex, xSeries); aDataPointVector.push_back( aPoint ); nLastIndex = nCurrIndex; @@ -3373,13 +3372,10 @@ void SchXMLExportHelper_Impl::exportDataPoints( { aPoint = rPoint; - if( aPoint.maStyleName == aLastPoint.maStyleName && aPoint.msCustomLabelText.isEmpty() ) + if( aPoint.maStyleName == aLastPoint.maStyleName && aLastPoint.mCustomLabelText.getLength() < 1 ) aPoint.mnRepeat += aLastPoint.mnRepeat; else if( aLastPoint.mnRepeat > 0 ) { - // export custom label text - if(!aLastPoint.msCustomLabelText.isEmpty()) - mrExport.AddAttribute( XML_NAMESPACE_LO_EXT, XML_CUSTOM_LABEL_FIELD, aLastPoint.msCustomLabelText); // write last element if( !aLastPoint.maStyleName.isEmpty() ) mrExport.AddAttribute( XML_NAMESPACE_CHART, XML_STYLE_NAME, aLastPoint.maStyleName ); @@ -3389,16 +3385,13 @@ void SchXMLExportHelper_Impl::exportDataPoints( OUString::number( ( aLastPoint.mnRepeat ) )); SvXMLElementExport aPointElem( mrExport, XML_NAMESPACE_CHART, XML_DATA_POINT, true, true ); + exportCustomLabel(aLastPoint.mCustomLabelText); } aLastPoint = aPoint; } // write last element if it hasn't been written in last iteration if( aPoint.maStyleName == aLastPoint.maStyleName ) { - // export custom label text - if(!aLastPoint.msCustomLabelText.isEmpty()) - mrExport.AddAttribute( XML_NAMESPACE_LO_EXT, XML_CUSTOM_LABEL_FIELD, aLastPoint.msCustomLabelText); - if( !aLastPoint.maStyleName.isEmpty() ) mrExport.AddAttribute( XML_NAMESPACE_CHART, XML_STYLE_NAME, aLastPoint.maStyleName ); @@ -3407,6 +3400,22 @@ void SchXMLExportHelper_Impl::exportDataPoints( OUString::number( ( aLastPoint.mnRepeat ) )); SvXMLElementExport aPointElem( mrExport, XML_NAMESPACE_CHART, XML_DATA_POINT, true, true ); + exportCustomLabel(aLastPoint.mCustomLabelText); + } +} + +void SchXMLExportHelper_Impl::exportCustomLabel( const CustomLabelSeq & xCustomLabel ) +{ + if( xCustomLabel.getLength() < 1 ) + return; // nothing to export + + SvXMLElementExport aLabelElem( mrExport, XML_NAMESPACE_CHART, XML_DATA_LABEL, true, true); + SvXMLElementExport aPara( mrExport, XML_NAMESPACE_TEXT, XML_P, true, false ); + for( const Reference& label : xCustomLabel ) + { + // TODO add style + SvXMLElementExport aSpan( mrExport, XML_NAMESPACE_TEXT, XML_SPAN, true, false); + mrExport.GetDocHandler()->characters(label->getString()); } } diff --git a/xmloff/source/chart/SchXMLImport.cxx b/xmloff/source/chart/SchXMLImport.cxx index 322a97e4331f..d0cd1f99c33e 100644 --- a/xmloff/source/chart/SchXMLImport.cxx +++ b/xmloff/source/chart/SchXMLImport.cxx @@ -221,6 +221,7 @@ const SvXMLTokenMap& SchXMLImportHelper::GetSeriesElemTokenMap() { XML_NAMESPACE_CHART, XML_REGRESSION_CURVE, XML_TOK_SERIES_REGRESSION_CURVE }, { XML_NAMESPACE_CHART, XML_ERROR_INDICATOR, XML_TOK_SERIES_ERROR_INDICATOR }, { XML_NAMESPACE_LO_EXT, XML_PROPERTY_MAPPING, XML_TOK_SERIES_PROPERTY_MAPPING }, + { XML_NAMESPACE_CHART, XML_DATA_LABEL, XML_TOK_SERIES_DATA_LABEL }, XML_TOKEN_MAP_END }; diff --git a/xmloff/source/chart/SchXMLPlotAreaContext.cxx b/xmloff/source/chart/SchXMLPlotAreaContext.cxx index 33bb1e043893..9767efd933dc 100644 --- a/xmloff/source/chart/SchXMLPlotAreaContext.cxx +++ b/xmloff/source/chart/SchXMLPlotAreaContext.cxx @@ -587,17 +587,87 @@ void SchXMLPlotAreaContext::EndElement() SchXMLAxisContext::CorrectAxisPositions( uno::Reference< chart2::XChartDocument >( mrImportHelper.GetChartDocument(), uno::UNO_QUERY ), maChartTypeServiceName, GetImport().GetODFVersion(), m_bAxisPositionAttributeImported ); } -SchXMLDataPointContext::SchXMLDataPointContext( SvXMLImport& rImport, const OUString& rLocalName, +SchXMLDataLabelSpanContext::SchXMLDataLabelSpanContext( SvXMLImport& rImport, const OUString& rLocalName, ::std::vector& rLabels): + SvXMLImportContext( rImport, XML_NAMESPACE_TEXT, rLocalName), + mrLabels(rLabels) +{ +} + +void SchXMLDataLabelSpanContext::Characters(const OUString& sChars) +{ + mrLabels.push_back(sChars); +} + +SchXMLDataLabelParaContext::SchXMLDataLabelParaContext( SvXMLImport& rImport, const OUString& rLocalName, ::std::vector& rLabels): + SvXMLImportContext( rImport, XML_NAMESPACE_TEXT, rLocalName), + mrLabels(rLabels) +{ +} + +SvXMLImportContextRef SchXMLDataLabelParaContext::CreateChildContext( + sal_uInt16 nPrefix, + const OUString& rLocalName, + const uno::Reference< xml::sax::XAttributeList >& /*xAttrList*/ ) +{ + SvXMLImportContextRef xContext; + if ( IsXMLToken( rLocalName, XML_SPAN ) && nPrefix == XML_NAMESPACE_TEXT ) + xContext = new SchXMLDataLabelSpanContext(GetImport(), rLocalName, mrLabels); + return xContext; +} + +SchXMLDataLabelContext::SchXMLDataLabelContext( SvXMLImport& rImport, const OUString& rLocalName, ::std::vector& rLabels): + SvXMLImportContext( rImport, XML_NAMESPACE_CHART, rLocalName), + mrLabels(rLabels) +{ +} + +SvXMLImportContextRef SchXMLDataLabelContext::CreateChildContext( + sal_uInt16 nPrefix, + const OUString& rLocalName, + const uno::Reference< xml::sax::XAttributeList >& xAttrList ) +{ + SvXMLImportContextRef xContext; + if ( IsXMLToken( rLocalName, XML_P ) && nPrefix == XML_NAMESPACE_TEXT ) + xContext = new SchXMLDataLabelParaContext(GetImport(), rLocalName, mrLabels); + + if (!xContext) + xContext = SvXMLImportContext::CreateChildContext( nPrefix, rLocalName, xAttrList ); + + return xContext; +} + + +SchXMLDataPointContext::SchXMLDataPointContext( SchXMLImportHelper& rImportHelper, + SvXMLImport& rImport, const OUString& rLocalName, ::std::vector< DataRowPointStyle >& rStyleVector, const css::uno::Reference< css::chart2::XDataSeries >& xSeries, sal_Int32& rIndex, bool bSymbolSizeForSeriesIsMissingInFile ) : SvXMLImportContext( rImport, XML_NAMESPACE_CHART, rLocalName ), + mrImportHelper( rImportHelper ), mrStyleVector( rStyleVector ), - m_xSeries( xSeries ), mrIndex( rIndex ), - mbSymbolSizeForSeriesIsMissingInFile( bSymbolSizeForSeriesIsMissingInFile ) + mDataPoint(DataRowPointStyle::DATA_POINT, xSeries, rIndex, 1, OUString{}) +{ + mDataPoint.mbSymbolSizeForSeriesIsMissingInFile = bSymbolSizeForSeriesIsMissingInFile; +} + +SvXMLImportContextRef SchXMLDataPointContext::CreateChildContext( + sal_uInt16 nPrefix, + const OUString& rLocalName, + const uno::Reference< xml::sax::XAttributeList >& /*xAttrList*/ ) { + SvXMLImportContext* pContext = nullptr; + const SvXMLTokenMap& rTokenMap = mrImportHelper.GetSeriesElemTokenMap(); + + switch( rTokenMap.Get( nPrefix, rLocalName )) + { + case XML_TOK_SERIES_DATA_LABEL: + mbHasLabelParagraph = true; + pContext = new SchXMLDataLabelContext( GetImport(), rLocalName, mDataPoint.mCustomLabels); + break; + } + return pContext; } SchXMLDataPointContext::~SchXMLDataPointContext() @@ -620,29 +690,35 @@ void SchXMLDataPointContext::StartElement( const uno::Reference< xml::sax::XAttr if( nPrefix == XML_NAMESPACE_CHART ) { if( IsXMLToken( aLocalName, XML_STYLE_NAME ) ) + { sAutoStyleName = xAttrList->getValueByIndex( i ); + mDataPoint.msStyleName = sAutoStyleName; + } else if( IsXMLToken( aLocalName, XML_REPEATED ) ) + { nRepeat = xAttrList->getValueByIndex( i ).toInt32(); + mDataPoint.m_nPointRepeat = nRepeat; + } } else if( nPrefix == XML_NAMESPACE_LO_EXT) { - if( IsXMLToken( aLocalName, XML_CUSTOM_LABEL_FIELD)) + if( IsXMLToken( aLocalName, XML_CUSTOM_LABEL_FIELD) && !mbHasLabelParagraph) { sCustomLabelField = xAttrList->getValueByIndex( i ); + mDataPoint.mCustomLabels.push_back(sCustomLabelField); } } } - if( !sAutoStyleName.isEmpty()) + mrIndex += nRepeat; +} + +void SchXMLDataPointContext::EndElement() +{ + if( !mDataPoint.msStyleName.isEmpty() || mDataPoint.mCustomLabels.size() > 0) { - DataRowPointStyle aStyle( - DataRowPointStyle::DATA_POINT, - m_xSeries, mrIndex, nRepeat, sAutoStyleName ); - aStyle.mbSymbolSizeForSeriesIsMissingInFile = mbSymbolSizeForSeriesIsMissingInFile; - aStyle.msCustomLabelField = sCustomLabelField; - mrStyleVector.push_back( aStyle ); + mrStyleVector.push_back( mDataPoint ); } - mrIndex += nRepeat; } SchXMLPositionAttributesHelper::SchXMLPositionAttributesHelper( SvXMLImport& rImporter ) diff --git a/xmloff/source/chart/SchXMLPlotAreaContext.hxx b/xmloff/source/chart/SchXMLPlotAreaContext.hxx index 53fbd4986052..748aca4069e4 100644 --- a/xmloff/source/chart/SchXMLPlotAreaContext.hxx +++ b/xmloff/source/chart/SchXMLPlotAreaContext.hxx @@ -137,16 +137,51 @@ private: css::awt::Size const maChartSize; }; +class SchXMLDataLabelSpanContext: public SvXMLImportContext +{ +private: + ::std::vector& mrLabels; +public: + SchXMLDataLabelSpanContext( SvXMLImport& rImport, const OUString& rLocalName, ::std::vector& rLabels); + virtual void Characters( const OUString& rChars ) override; +}; + +class SchXMLDataLabelParaContext: public SvXMLImportContext +{ +private: + ::std::vector& mrLabels; +public: + SchXMLDataLabelParaContext( SvXMLImport& rImport, const OUString& rLocalName, ::std::vector& rLabels); + virtual SvXMLImportContextRef CreateChildContext( + sal_uInt16 nPrefix, + const OUString& rLocalName, + const css::uno::Reference< css::xml::sax::XAttributeList >& xAttrList ) override; +}; + +class SchXMLDataLabelContext: public SvXMLImportContext +{ +private: + ::std::vector& mrLabels; +public: + SchXMLDataLabelContext( SvXMLImport& rImport, const OUString& rLocalName, ::std::vector& rLabels); + virtual SvXMLImportContextRef CreateChildContext( + sal_uInt16 nPrefix, + const OUString& rLocalName, + const css::uno::Reference< css::xml::sax::XAttributeList >& xAttrList ) override; +}; + class SchXMLDataPointContext : public SvXMLImportContext { private: + SchXMLImportHelper& mrImportHelper; ::std::vector< DataRowPointStyle >& mrStyleVector; - css::uno::Reference< css::chart2::XDataSeries > m_xSeries; + bool mbHasLabelParagraph = false; sal_Int32& mrIndex; - bool const mbSymbolSizeForSeriesIsMissingInFile; + DataRowPointStyle mDataPoint; public: - SchXMLDataPointContext( SvXMLImport& rImport, const OUString& rLocalName, + SchXMLDataPointContext( SchXMLImportHelper& rImportHelper, + SvXMLImport& rImport, const OUString& rLocalName, ::std::vector< DataRowPointStyle >& rStyleVector, const css::uno::Reference< css::chart2::XDataSeries >& xSeries, sal_Int32& rIndex, @@ -154,6 +189,12 @@ public: virtual ~SchXMLDataPointContext() override; virtual void StartElement( const css::uno::Reference< css::xml::sax::XAttributeList >& xAttrList ) override; + + virtual SvXMLImportContextRef CreateChildContext( + sal_uInt16 nPrefix, + const OUString& rLocalName, + const css::uno::Reference< css::xml::sax::XAttributeList >& xAttrList ) override; + virtual void EndElement() override; }; class SchXMLCoordinateRegionContext : public SvXMLImportContext diff --git a/xmloff/source/chart/SchXMLSeries2Context.cxx b/xmloff/source/chart/SchXMLSeries2Context.cxx index 69fa587ebdeb..4e379814a859 100644 --- a/xmloff/source/chart/SchXMLSeries2Context.cxx +++ b/xmloff/source/chart/SchXMLSeries2Context.cxx @@ -684,7 +684,7 @@ SvXMLImportContextRef SchXMLSeries2Context::CreateChildContext( break; case XML_TOK_SERIES_DATA_POINT: - pContext = new SchXMLDataPointContext( GetImport(), rLocalName, + pContext = new SchXMLDataPointContext( mrImportHelper, GetImport(), rLocalName, mrStyleVector, m_xSeries, mnDataPointIndex, mbSymbolSizeIsMissingInFile ); break; case XML_TOK_SERIES_PROPERTY_MAPPING: @@ -1086,14 +1086,18 @@ void SchXMLSeries2Context::setStylesToDataPoints( SeriesDefaultsAndStyles& rSeri lcl_resetSymbolSizeForPointsIfNecessary( xPointProp, rImport, pPropStyleContext, pStylesCtxt ); } - if(!seriesStyle.msCustomLabelField.isEmpty()) + // Custom labels might be passed as property + if(auto nLabelCount = seriesStyle.mCustomLabels.size(); nLabelCount > 0) { - Sequence< Reference> xLabels(1); + Sequence< Reference> xLabels(nLabelCount); Reference< uno::XComponentContext > xContext( comphelper::getProcessComponentContext() ); - Reference< chart2::XDataPointCustomLabelField > xCustomLabel = chart2::DataPointCustomLabelField::create(xContext); - xLabels[0] = xCustomLabel; - xCustomLabel->setString(seriesStyle.msCustomLabelField); - xCustomLabel->setFieldType(chart2::DataPointCustomLabelFieldType::DataPointCustomLabelFieldType_TEXT); + for( auto j = 0; j< xLabels.getLength(); ++j ) + { + Reference< chart2::XDataPointCustomLabelField > xCustomLabel = chart2::DataPointCustomLabelField::create(xContext); + xLabels[j] = xCustomLabel; + xCustomLabel->setString(seriesStyle.mCustomLabels[j]); + xCustomLabel->setFieldType(chart2::DataPointCustomLabelFieldType::DataPointCustomLabelFieldType_TEXT); + } xPointProp->setPropertyValue("CustomLabelFields", uno::Any(xLabels)); } } diff --git a/xmloff/source/chart/transporttypes.hxx b/xmloff/source/chart/transporttypes.hxx index 6481cfb1c004..04fbe70ecdd0 100644 --- a/xmloff/source/chart/transporttypes.hxx +++ b/xmloff/source/chart/transporttypes.hxx @@ -145,6 +145,10 @@ struct RegressionStyle {} }; +struct CustomLabelField { + std::vector sRuns; +}; + struct DataRowPointStyle { enum StyleType @@ -167,8 +171,9 @@ struct DataRowPointStyle sal_Int32 m_nPointIndex; sal_Int32 m_nPointRepeat; OUString msStyleName; + ::std::vector mCustomLabels; OUString msSeriesStyleNameForDonuts; - OUString msCustomLabelField; + sal_Int32 mnAttachedAxis; bool mbSymbolSizeForSeriesIsMissingInFile; diff --git a/xmloff/source/core/xmltoken.cxx b/xmloff/source/core/xmltoken.cxx index 86344f0d05b9..e0f6e4d7a216 100644 --- a/xmloff/source/core/xmltoken.cxx +++ b/xmloff/source/core/xmltoken.cxx @@ -552,6 +552,7 @@ namespace xmloff { namespace token { TOKEN( "data-bar", XML_DATA_BAR ), TOKEN( "data-bar-entry", XML_DATA_BAR_ENTRY ), TOKEN( "data-cell-range-address", XML_DATA_CELL_RANGE_ADDRESS ), + TOKEN( "data-label", XML_DATA_LABEL ), TOKEN( "data-label-number", XML_DATA_LABEL_NUMBER ), TOKEN( "data-label-symbol", XML_DATA_LABEL_SYMBOL ), TOKEN( "data-label-text", XML_DATA_LABEL_TEXT ), diff --git a/xmloff/source/token/tokens.txt b/xmloff/source/token/tokens.txt index 539cdb53a778..921ff2b63b5a 100644 --- a/xmloff/source/token/tokens.txt +++ b/xmloff/source/token/tokens.txt @@ -475,6 +475,7 @@ data data-bar data-bar-entry data-cell-range-address +data-label data-label-number data-label-symbol data-label-text -- cgit