From 55e9a27afd2d6a13cf76b39641bf121c3ec4b45c Mon Sep 17 00:00:00 2001 From: Balazs Varga Date: Fri, 29 Mar 2024 23:00:50 +0100 Subject: Related: tdf#39052 - chart ooxml: export formatted chart titles texts properly to ooxml. Also adding "FormattedStrings" property for title objects to simplify the working of character formattings in editable chart shapes. TODO: odf import/export Change-Id: Ie27b4dee72c24fa6a2a4e2a7db8da7fa50eb8937 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/165583 Tested-by: Jenkins Tested-by: Gabor Kelemen Reviewed-by: Balazs Varga --- chart2/qa/extras/chart2export3.cxx | 70 ++++++++++++++++-- chart2/qa/extras/data/xlsx/tdf39052.xlsx | Bin 0 -> 9210 bytes .../controller/chartapiwrapper/TitleWrapper.cxx | 65 +++++++++++++++++ .../controller/main/ChartController_TextEdit.cxx | 30 +------- chart2/source/inc/TitleHelper.hxx | 2 + chart2/source/tools/TitleHelper.cxx | 31 ++++++-- include/oox/export/chartexport.hxx | 4 +- oox/source/export/chartexport.cxx | 81 ++++++++++++++++----- oox/source/export/drawingml.cxx | 3 + xmloff/source/chart/SchXMLAxisContext.cxx | 1 + xmloff/source/chart/SchXMLChartContext.cxx | 2 + xmloff/source/chart/SchXMLExport.cxx | 3 + 12 files changed, 230 insertions(+), 62 deletions(-) create mode 100644 chart2/qa/extras/data/xlsx/tdf39052.xlsx diff --git a/chart2/qa/extras/chart2export3.cxx b/chart2/qa/extras/chart2export3.cxx index e1229b07720c..3d05495eff40 100644 --- a/chart2/qa/extras/chart2export3.cxx +++ b/chart2/qa/extras/chart2export3.cxx @@ -447,12 +447,13 @@ CPPUNIT_TEST_FIXTURE(Chart2ExportTest3, testChartMainWithSubTitle) xmlDocUniquePtr pXmlDoc = parseExport("xl/charts/chart1.xml"); CPPUNIT_ASSERT(pXmlDoc); // test properties of title - assertXPath(pXmlDoc, "/c:chartSpace/c:chart/c:title/c:tx/c:rich/a:p/a:pPr/a:defRPr"_ostr, "sz"_ostr, "1300"); - assertXPath(pXmlDoc, "/c:chartSpace/c:chart/c:title/c:tx/c:rich/a:p/a:pPr/a:defRPr"_ostr, "b"_ostr, "0"); - assertXPath(pXmlDoc, "/c:chartSpace/c:chart/c:title/c:tx/c:rich/a:p/a:pPr/a:defRPr"_ostr, "i"_ostr, "1"); - assertXPath(pXmlDoc, "/c:chartSpace/c:chart/c:title/c:tx/c:rich/a:p/a:pPr/a:defRPr/a:solidFill/a:srgbClr"_ostr, "val"_ostr, "f10d0c"); - assertXPath(pXmlDoc, "/c:chartSpace/c:chart/c:title/c:tx/c:rich/a:p/a:r/a:rPr/a:latin"_ostr, "typeface"_ostr, "Arial"); - assertXPathContent(pXmlDoc, "/c:chartSpace/c:chart/c:title/c:tx/c:rich/a:p/a:r/a:t"_ostr, "It is a Maintitle\nIt is a Subtitle"); + assertXPath(pXmlDoc, "/c:chartSpace/c:chart/c:title/c:tx/c:rich/a:p[1]/a:pPr/a:defRPr"_ostr, "sz"_ostr, "1300"); + assertXPath(pXmlDoc, "/c:chartSpace/c:chart/c:title/c:tx/c:rich/a:p[1]/a:pPr/a:defRPr"_ostr, "b"_ostr, "0"); + assertXPath(pXmlDoc, "/c:chartSpace/c:chart/c:title/c:tx/c:rich/a:p[1]/a:pPr/a:defRPr"_ostr, "i"_ostr, "1"); + assertXPath(pXmlDoc, "/c:chartSpace/c:chart/c:title/c:tx/c:rich/a:p[1]/a:pPr/a:defRPr/a:solidFill/a:srgbClr"_ostr, "val"_ostr, "f10d0c"); + assertXPath(pXmlDoc, "/c:chartSpace/c:chart/c:title/c:tx/c:rich/a:p[1]/a:r/a:rPr/a:latin"_ostr, "typeface"_ostr, "Arial"); + assertXPathContent(pXmlDoc, "/c:chartSpace/c:chart/c:title/c:tx/c:rich/a:p[1]/a:r/a:t"_ostr, "It is a Maintitle"); + assertXPathContent(pXmlDoc, "/c:chartSpace/c:chart/c:title/c:tx/c:rich/a:p[2]/a:r/a:t"_ostr, "It is a Subtitle"); assertXPath(pXmlDoc, "/c:chartSpace/c:chart/c:title/c:spPr/a:solidFill/a:srgbClr"_ostr, "val"_ostr, "81d41a"); } @@ -754,6 +755,63 @@ CPPUNIT_TEST_FIXTURE(Chart2ExportTest3, testTdf148142) CPPUNIT_ASSERT(!aScaleData2.ShiftedCategoryPosition); } +CPPUNIT_TEST_FIXTURE(Chart2ExportTest3, testFormattedChartTitles) +{ + loadFromFile(u"xlsx/tdf39052.xlsx"); + save("Calc Office Open XML"); + xmlDocUniquePtr pXmlDoc = parseExport("xl/charts/chart1.xml"); + CPPUNIT_ASSERT(pXmlDoc); + + // Check run level properties [1] - first paragraph + assertXPath(pXmlDoc, "/c:chartSpace/c:chart/c:title/c:tx/c:rich/a:p[1]/a:r[1]/a:rPr"_ostr, "b"_ostr, "1"); + assertXPath(pXmlDoc, "/c:chartSpace/c:chart/c:title/c:tx/c:rich/a:p[1]/a:r[1]/a:rPr"_ostr, "sz"_ostr, "1400"); + assertXPath(pXmlDoc, "/c:chartSpace/c:chart/c:title/c:tx/c:rich/a:p[1]/a:r[1]/a:rPr/a:solidFill/a:srgbClr"_ostr, "val"_ostr, "ff0000"); + assertXPath(pXmlDoc, "/c:chartSpace/c:chart/c:title/c:tx/c:rich/a:p[1]/a:r[1]/a:rPr/a:latin"_ostr, "typeface"_ostr, "Aptos Narrow"); + assertXPathContent(pXmlDoc, "/c:chartSpace/c:chart/c:title/c:tx/c:rich/a:p[1]/a:r[1]/a:t"_ostr, "This"); + // Check run level properties [2] + assertXPath(pXmlDoc, "/c:chartSpace/c:chart/c:title/c:tx/c:rich/a:p[1]/a:r[2]/a:rPr"_ostr, "b"_ostr, "0"); + assertXPath(pXmlDoc, "/c:chartSpace/c:chart/c:title/c:tx/c:rich/a:p[1]/a:r[2]/a:rPr"_ostr, "sz"_ostr, "1400"); + assertXPath(pXmlDoc, "/c:chartSpace/c:chart/c:title/c:tx/c:rich/a:p[1]/a:r[2]/a:rPr/a:solidFill/a:srgbClr"_ostr, "val"_ostr, "595959"); + assertXPathContent(pXmlDoc, "/c:chartSpace/c:chart/c:title/c:tx/c:rich/a:p[1]/a:r[2]/a:t"_ostr, " is"); + // Check run level properties [3] + assertXPath(pXmlDoc, "/c:chartSpace/c:chart/c:title/c:tx/c:rich/a:p[1]/a:r[3]/a:rPr"_ostr, "b"_ostr, "0"); + assertXPath(pXmlDoc, "/c:chartSpace/c:chart/c:title/c:tx/c:rich/a:p[1]/a:r[3]/a:rPr"_ostr, "sz"_ostr, "1400"); + assertXPath(pXmlDoc, "/c:chartSpace/c:chart/c:title/c:tx/c:rich/a:p[1]/a:r[3]/a:rPr"_ostr, "baseline"_ostr, "30000"); + assertXPathContent(pXmlDoc, "/c:chartSpace/c:chart/c:title/c:tx/c:rich/a:p[1]/a:r[3]/a:t"_ostr, "3"); + // Check run level properties [4] + assertXPath(pXmlDoc, "/c:chartSpace/c:chart/c:title/c:tx/c:rich/a:p[1]/a:r[4]/a:rPr"_ostr, "b"_ostr, "0"); + assertXPath(pXmlDoc, "/c:chartSpace/c:chart/c:title/c:tx/c:rich/a:p[1]/a:r[4]/a:rPr"_ostr, "sz"_ostr, "1400"); + assertXPathContent(pXmlDoc, "/c:chartSpace/c:chart/c:title/c:tx/c:rich/a:p[1]/a:r[4]/a:t"_ostr, " a "); + // Check run level properties [5] + assertXPath(pXmlDoc, "/c:chartSpace/c:chart/c:title/c:tx/c:rich/a:p[1]/a:r[5]/a:rPr"_ostr, "b"_ostr, "0"); + assertXPath(pXmlDoc, "/c:chartSpace/c:chart/c:title/c:tx/c:rich/a:p[1]/a:r[5]/a:rPr"_ostr, "i"_ostr, "1"); + assertXPath(pXmlDoc, "/c:chartSpace/c:chart/c:title/c:tx/c:rich/a:p[1]/a:r[5]/a:rPr"_ostr, "sz"_ostr, "2000"); + assertXPath(pXmlDoc, "/c:chartSpace/c:chart/c:title/c:tx/c:rich/a:p[1]/a:r[5]/a:rPr"_ostr, "u"_ostr, "sng"); + assertXPath(pXmlDoc, "/c:chartSpace/c:chart/c:title/c:tx/c:rich/a:p[1]/a:r[5]/a:rPr/a:solidFill/a:srgbClr"_ostr, "val"_ostr, "4ea72e"); + assertXPath(pXmlDoc, "/c:chartSpace/c:chart/c:title/c:tx/c:rich/a:p[1]/a:r[5]/a:rPr/a:uFillTx"_ostr, 1); + assertXPathContent(pXmlDoc, "/c:chartSpace/c:chart/c:title/c:tx/c:rich/a:p[1]/a:r[5]/a:t"_ostr, "custom"); + // Check run level properties [6] + assertXPath(pXmlDoc, "/c:chartSpace/c:chart/c:title/c:tx/c:rich/a:p[1]/a:r[6]/a:rPr"_ostr, "b"_ostr, "0"); + assertXPath(pXmlDoc, "/c:chartSpace/c:chart/c:title/c:tx/c:rich/a:p[1]/a:r[6]/a:rPr"_ostr, "sz"_ostr, "1400"); + assertXPathContent(pXmlDoc, "/c:chartSpace/c:chart/c:title/c:tx/c:rich/a:p[1]/a:r[6]/a:t"_ostr, " erte1"); + // Check run level properties [1] - second paragraph + assertXPath(pXmlDoc, "/c:chartSpace/c:chart/c:title/c:tx/c:rich/a:p[2]/a:r[1]/a:rPr"_ostr, "b"_ostr, "0"); + assertXPath(pXmlDoc, "/c:chartSpace/c:chart/c:title/c:tx/c:rich/a:p[2]/a:r[1]/a:rPr"_ostr, "sz"_ostr, "1400"); + assertXPath(pXmlDoc, "/c:chartSpace/c:chart/c:title/c:tx/c:rich/a:p[2]/a:r[1]/a:rPr/a:solidFill/a:srgbClr"_ostr, "val"_ostr, "595959"); + assertXPath(pXmlDoc, "/c:chartSpace/c:chart/c:title/c:tx/c:rich/a:p[2]/a:r[1]/a:rPr/a:latin"_ostr, "typeface"_ostr, "Aptos Narrow"); + assertXPathContent(pXmlDoc, "/c:chartSpace/c:chart/c:title/c:tx/c:rich/a:p[2]/a:r[1]/a:t"_ostr, "2dfgd ch"); + // Check run level properties [2] + assertXPath(pXmlDoc, "/c:chartSpace/c:chart/c:title/c:tx/c:rich/a:p[2]/a:r[2]/a:rPr"_ostr, "b"_ostr, "1"); + assertXPathContent(pXmlDoc, "/c:chartSpace/c:chart/c:title/c:tx/c:rich/a:p[2]/a:r[2]/a:t"_ostr, "ar"); + // Check run level properties [3] + assertXPath(pXmlDoc, "/c:chartSpace/c:chart/c:title/c:tx/c:rich/a:p[2]/a:r[3]/a:rPr"_ostr, "b"_ostr, "0");; + assertXPathContent(pXmlDoc, "/c:chartSpace/c:chart/c:title/c:tx/c:rich/a:p[2]/a:r[3]/a:t"_ostr, "t "); + // Check run level properties [4] + assertXPath(pXmlDoc, "/c:chartSpace/c:chart/c:title/c:tx/c:rich/a:p[2]/a:r[4]/a:rPr"_ostr, "b"_ostr, "0"); + assertXPath(pXmlDoc, "/c:chartSpace/c:chart/c:title/c:tx/c:rich/a:p[2]/a:r[4]/a:rPr"_ostr, "strike"_ostr, "sngStrike"); + assertXPathContent(pXmlDoc, "/c:chartSpace/c:chart/c:title/c:tx/c:rich/a:p[2]/a:r[4]/a:t"_ostr, "title"); +} + CPPUNIT_PLUGIN_IMPLEMENT(); /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/qa/extras/data/xlsx/tdf39052.xlsx b/chart2/qa/extras/data/xlsx/tdf39052.xlsx new file mode 100644 index 000000000000..5b0285bab292 Binary files /dev/null and b/chart2/qa/extras/data/xlsx/tdf39052.xlsx differ diff --git a/chart2/source/controller/chartapiwrapper/TitleWrapper.cxx b/chart2/source/controller/chartapiwrapper/TitleWrapper.cxx index 9c802462ff09..b0367cb0f478 100644 --- a/chart2/source/controller/chartapiwrapper/TitleWrapper.cxx +++ b/chart2/source/controller/chartapiwrapper/TitleWrapper.cxx @@ -104,6 +104,63 @@ Any WrappedTitleStringProperty::getPropertyDefault( const Reference< beans::XPro return uno::Any( OUString() );//default title is an empty String } +namespace { + + class WrappedTitleFormStringsProperty : public WrappedProperty + { + public: + explicit WrappedTitleFormStringsProperty(); + + virtual void setPropertyValue( const Any& rOuterValue, const Reference< beans::XPropertySet >& xInnerPropertySet ) const override; + virtual Any getPropertyValue( const Reference< beans::XPropertySet >& xInnerPropertySet ) const override; + virtual Any getPropertyDefault( const Reference< beans::XPropertyState >& xInnerPropertyState ) const override; + + protected: + Reference< uno::XComponentContext > m_xContext; + }; + +} + +WrappedTitleFormStringsProperty::WrappedTitleFormStringsProperty() + : ::chart::WrappedProperty( "FormattedStrings", OUString() ) +{ +} + +void WrappedTitleFormStringsProperty::setPropertyValue( const Any& rOuterValue, const Reference< beans::XPropertySet >& xInnerPropertySet ) const +{ + Title* pTitle = dynamic_cast(xInnerPropertySet.get()); + if (pTitle) + { + Sequence< Reference< chart2::XFormattedString >> xFormattedStrings; + rOuterValue >>= xFormattedStrings; + TitleHelper::setFormattedString(pTitle, xFormattedStrings); + } +} +Any WrappedTitleFormStringsProperty::getPropertyValue( const Reference< beans::XPropertySet >& xInnerPropertySet ) const +{ + Any aRet(getPropertyDefault(Reference< beans::XPropertyState >(xInnerPropertySet, uno::UNO_QUERY))); + Reference< chart2::XTitle > xTitle(xInnerPropertySet, uno::UNO_QUERY); + if (xTitle.is()) + { + const Sequence< Reference< chart2::XFormattedString > > aStrings(xTitle->getText()); + + OUStringBuffer aBuf; + for (Reference< chart2::XFormattedString > const& formattedStr : aStrings) + { + aBuf.append(formattedStr->getString()); + } + if (!aBuf.makeStringAndClear().isEmpty()) + { + aRet <<= aStrings; + } + } + return aRet; +} +Any WrappedTitleFormStringsProperty::getPropertyDefault( const Reference< beans::XPropertyState >& /*xInnerPropertyState*/ ) const +{ + return uno::Any(Sequence< Reference< chart2::XFormattedString > >()); //default title is an empty Sequence of XFormattedStrings +} + namespace { class WrappedStackedTextProperty : public WrappedProperty @@ -127,6 +184,7 @@ namespace enum { PROP_TITLE_STRING, + PROP_TITLE_FORMATTED_STRINGS, PROP_TITLE_VISIBLE, PROP_TITLE_TEXT_ROTATION, PROP_TITLE_TEXT_STACKED @@ -141,6 +199,12 @@ void lcl_AddPropertiesToVector( beans::PropertyAttribute::BOUND | beans::PropertyAttribute::MAYBEVOID ); + rOutProperties.emplace_back( "FormattedStrings", + PROP_TITLE_FORMATTED_STRINGS, + cppu::UnoType< Sequence< Reference< chart2::XFormattedString >>>::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEVOID ); + rOutProperties.emplace_back( "Visible", PROP_TITLE_VISIBLE, cppu::UnoType::get(), @@ -475,6 +539,7 @@ std::vector< std::unique_ptr > TitleWrapper::createWrappedPrope std::vector< std::unique_ptr > aWrappedProperties; aWrappedProperties.emplace_back( new WrappedTitleStringProperty( m_spChart2ModelContact->m_xContext ) ); + aWrappedProperties.emplace_back( new WrappedTitleFormStringsProperty() ); aWrappedProperties.emplace_back( new WrappedTextRotationProperty( true ) ); aWrappedProperties.emplace_back( new WrappedStackedTextProperty() ); WrappedCharacterHeightProperty::addWrappedProperties( aWrappedProperties, this ); diff --git a/chart2/source/controller/main/ChartController_TextEdit.cxx b/chart2/source/controller/main/ChartController_TextEdit.cxx index c88f06a66e45..600d46b434d0 100644 --- a/chart2/source/controller/main/ChartController_TextEdit.cxx +++ b/chart2/source/controller/main/ChartController_TextEdit.cxx @@ -128,17 +128,10 @@ bool ChartController::EndTextEdit() if(!pTextObject) return false; - SdrOutliner* pOutliner = m_pDrawViewWrapper->getOutliner(); OutlinerParaObject* pParaObj = pTextObject->GetOutlinerParaObject(); - if( !pParaObj || !pOutliner ) + if( !pParaObj ) return true; - pOutliner->SetText( *pParaObj ); - - OUString aString = pOutliner->GetText( - pOutliner->GetParagraph( 0 ), - pOutliner->GetParagraphCount() ); - OUString aObjectCID = m_aSelection.getSelectedCID(); if ( !aObjectCID.isEmpty() ) { @@ -152,26 +145,7 @@ bool ChartController::EndTextEdit() GetFormattedTitle(pParaObj->GetTextObject(), pTextObject->getUnoShape()); Title* pTitle = dynamic_cast(xPropSet.get()); - if (pTitle && aNewFormattedTitle.hasElements()) - { - bool bStacked = false; - if (xPropSet.is()) - xPropSet->getPropertyValue("StackCharacters") >>= bStacked; - - if (bStacked) - { - for (uno::Reference< chart2::XFormattedString >const& formattedStr : aNewFormattedTitle) - { - formattedStr->setString(TitleHelper::getUnstackedStr(formattedStr->getString())); - } - } - - pTitle->setText(aNewFormattedTitle); - } - else - { - TitleHelper::setCompleteString(aString, pTitle, m_xCC); - } + TitleHelper::setFormattedString(pTitle, aNewFormattedTitle); OSL_ENSURE(m_pTextActionUndoGuard, "ChartController::EndTextEdit: no TextUndoGuard!"); if (m_pTextActionUndoGuard) diff --git a/chart2/source/inc/TitleHelper.hxx b/chart2/source/inc/TitleHelper.hxx index f2a8a0830b21..f4ea2204d7d5 100644 --- a/chart2/source/inc/TitleHelper.hxx +++ b/chart2/source/inc/TitleHelper.hxx @@ -78,6 +78,8 @@ public: static OUString getCompleteString( const rtl::Reference< ::chart::Title >& xTitle ); static OUString getUnstackedStr( const OUString& rNewText ); + static void setFormattedString( const rtl::Reference< ::chart::Title >& xTitle, + const css::uno::Sequence< css::uno::Reference< css::chart2::XFormattedString > >& aNewFormattedTitle ); static void setCompleteString( const OUString& rNewText , const rtl::Reference< ::chart::Title >& xTitle , const css::uno::Reference< css::uno::XComponentContext > & xContext diff --git a/chart2/source/tools/TitleHelper.cxx b/chart2/source/tools/TitleHelper.cxx index ca137cb6e072..6fdb4f5adef3 100644 --- a/chart2/source/tools/TitleHelper.cxx +++ b/chart2/source/tools/TitleHelper.cxx @@ -327,32 +327,47 @@ OUString TitleHelper::getUnstackedStr(const OUString& rNewText) return aUnstackedStr.makeStringAndClear(); } +void TitleHelper::setFormattedString( const rtl::Reference< Title >& xTitle, + const css::uno::Sequence< css::uno::Reference< css::chart2::XFormattedString > >& aNewFormattedTitle ) +{ + if (!xTitle.is() || !aNewFormattedTitle.hasElements()) + return; + + bool bStacked = false; + xTitle->getPropertyValue("StackCharacters") >>= bStacked; + + if (bStacked) + { + for (uno::Reference< chart2::XFormattedString >const& formattedStr : aNewFormattedTitle) + { + formattedStr->setString(TitleHelper::getUnstackedStr(formattedStr->getString())); + } + } + + xTitle->setText(aNewFormattedTitle); +} + void TitleHelper::setCompleteString( const OUString& rNewText , const rtl::Reference< Title >& xTitle , const uno::Reference< uno::XComponentContext > & xContext , const float * pDefaultCharHeight /* = 0 */ , bool bDialogTitle /*= false*/ ) { - if(!xTitle.is()) + if (!xTitle.is()) return; - OUString aNewText = rNewText; - bool bStacked = false; if( xTitle.is() ) xTitle->getPropertyValue( "StackCharacters" ) >>= bStacked; - uno::Sequence< uno::Reference< XFormattedString > > aOldStringList = xTitle->getText(); + OUString aNewText = rNewText; if( bStacked ) { aNewText = getUnstackedStr(rNewText); - for (uno::Reference< XFormattedString >const & formattedStr : aOldStringList) - { - formattedStr->setString(getUnstackedStr(formattedStr->getString())); - } } uno::Sequence< uno::Reference< XFormattedString > > aNewStringList; + uno::Sequence< uno::Reference< XFormattedString > > aOldStringList = xTitle->getText(); if( aOldStringList.hasElements()) { const OUString aFullString = getCompleteString(xTitle); diff --git a/include/oox/export/chartexport.hxx b/include/oox/export/chartexport.hxx index 640415003d15..1b708b83d479 100644 --- a/include/oox/export/chartexport.hxx +++ b/include/oox/export/chartexport.hxx @@ -25,6 +25,7 @@ #include #include +#include #include #include #include @@ -176,7 +177,8 @@ private: void exportLegend( const css::uno::Reference< css::chart::XChartDocument >& rChartDoc ); void exportTitle( const css::uno::Reference< css::drawing::XShape >& xShape, - const OUString* pSubText = nullptr ); + const css::uno::Sequence< css::uno::Reference< css::chart2::XFormattedString > >& xFormattedSubTitle = + css::uno::Sequence< css::uno::Reference< css::chart2::XFormattedString > >() ); void exportPlotArea( const css::uno::Reference< css::chart::XChartDocument >& rChartDoc ); void exportAdditionalShapes( const css::uno::Reference& rChartDoc ); diff --git a/oox/source/export/chartexport.cxx b/oox/source/export/chartexport.cxx index f9c4c12d066d..75283815a831 100644 --- a/oox/source/export/chartexport.cxx +++ b/oox/source/export/chartexport.cxx @@ -1134,7 +1134,6 @@ void ChartExport::exportChart( const Reference< css::chart::XChartDocument >& xC // get Properties of ChartDocument bool bHasMainTitle = false; - OUString aSubTitle; bool bHasLegend = false; Reference< beans::XPropertySet > xDocPropSet( xChartDoc, uno::UNO_QUERY ); if( xDocPropSet.is()) @@ -1152,12 +1151,13 @@ void ChartExport::exportChart( const Reference< css::chart::XChartDocument >& xC } } // if( xDocPropSet.is()) + Sequence< uno::Reference< chart2::XFormattedString > > xFormattedSubTitle; Reference< beans::XPropertySet > xPropSubTitle( xChartDoc->getSubTitle(), UNO_QUERY ); if( xPropSubTitle.is()) { try { - xPropSubTitle->getPropertyValue("String") >>= aSubTitle; + xPropSubTitle->getPropertyValue("FormattedStrings") >>= xFormattedSubTitle; } catch( beans::UnknownPropertyException & ) { @@ -1171,12 +1171,12 @@ void ChartExport::exportChart( const Reference< css::chart::XChartDocument >& xC // titles if( bHasMainTitle ) { - exportTitle( xChartDoc->getTitle(), !aSubTitle.isEmpty() ? &aSubTitle : nullptr ); + exportTitle( xChartDoc->getTitle(), xFormattedSubTitle); pFS->singleElement(FSNS(XML_c, XML_autoTitleDeleted), XML_val, "0"); } - else if( !aSubTitle.isEmpty() ) + else if( xFormattedSubTitle.hasElements() ) { - exportTitle( xChartDoc->getSubTitle(), nullptr ); + exportTitle( xChartDoc->getSubTitle() ); pFS->singleElement(FSNS(XML_c, XML_autoTitleDeleted), XML_val, "0"); } else @@ -1445,20 +1445,40 @@ void ChartExport::exportLegend( const Reference< css::chart::XChartDocument >& x pFS->endElement( FSNS( XML_c, XML_legend ) ); } -void ChartExport::exportTitle( const Reference< XShape >& xShape, const OUString* pSubText) +void ChartExport::exportTitle( const Reference< XShape >& xShape, + const css::uno::Sequence< uno::Reference< css::chart2::XFormattedString > >& xFormattedSubTitle ) { - OUString sText; + Sequence< uno::Reference< chart2::XFormattedString > > xFormattedTitle; Reference< beans::XPropertySet > xPropSet( xShape, uno::UNO_QUERY ); if( xPropSet.is()) { - xPropSet->getPropertyValue("String") >>= sText; + xPropSet->getPropertyValue("FormattedStrings") >>= xFormattedTitle; } // tdf#101322: add subtitle to title - if( pSubText ) - sText = sText.isEmpty() ? *pSubText : sText + "\n" + *pSubText; + if (xFormattedSubTitle.hasElements()) + { + if (!xFormattedTitle.hasElements()) + { + xFormattedTitle = xFormattedSubTitle; + } + else + { + sal_uInt32 nLength = xFormattedTitle.size(); + const OUString aLastString = xFormattedTitle.getArray()[nLength - 1]->getString(); + xFormattedTitle.getArray()[nLength - 1]->setString(aLastString + OUStringChar('\n')); + for (const uno::Reference& rxFS : xFormattedSubTitle) + { + if (!rxFS->getString().isEmpty()) + { + xFormattedTitle.realloc(nLength + 1); + xFormattedTitle.getArray()[nLength++] = rxFS; + } + } + } + } - if( sText.isEmpty() ) + if (!xFormattedTitle.hasElements()) return; FSHelperPtr pFS = GetFS(); @@ -1482,7 +1502,6 @@ void ChartExport::exportTitle( const Reference< XShape >& xShape, const OUString XML_rot, oox::drawingml::calcRotationValue(nRotation) ); // TODO: lstStyle pFS->singleElement(FSNS(XML_a, XML_lstStyle)); - // FIXME: handle multiple paragraphs to parse aText pFS->startElement(FSNS(XML_a, XML_p)); pFS->startElement(FSNS(XML_a, XML_pPr)); @@ -1493,13 +1512,37 @@ void ChartExport::exportTitle( const Reference< XShape >& xShape, const OUString pFS->endElement( FSNS( XML_a, XML_pPr ) ); - pFS->startElement(FSNS(XML_a, XML_r)); - bDummy = false; - WriteRunProperties( xPropSet, false, XML_rPr, true, bDummy, nDummy ); - pFS->startElement(FSNS(XML_a, XML_t)); - pFS->writeEscaped( sText ); - pFS->endElement( FSNS( XML_a, XML_t ) ); - pFS->endElement( FSNS( XML_a, XML_r ) ); + for (const uno::Reference& rxFS : xFormattedTitle) + { + pFS->startElement(FSNS(XML_a, XML_r)); + bDummy = false; + Reference< beans::XPropertySet > xRunPropSet(rxFS, uno::UNO_QUERY); + WriteRunProperties(xRunPropSet, false, XML_rPr, true, bDummy, nDummy); + pFS->startElement(FSNS(XML_a, XML_t)); + + // the linebreak should always be at the end of the XFormattedString text + bool bNextPara = rxFS->getString().endsWith(u"\n"); + if (!bNextPara) + pFS->writeEscaped(rxFS->getString()); + else + { + sal_Int32 nEnd = rxFS->getString().lastIndexOf('\n'); + pFS->writeEscaped(rxFS->getString().replaceAt(nEnd, 1, u"")); + } + pFS->endElement(FSNS(XML_a, XML_t)); + pFS->endElement(FSNS(XML_a, XML_r)); + + if (bNextPara) + { + pFS->endElement(FSNS(XML_a, XML_p)); + + pFS->startElement(FSNS(XML_a, XML_p)); + pFS->startElement(FSNS(XML_a, XML_pPr)); + bDummy = false; + WriteRunProperties(xPropSet, false, XML_defRPr, true, bDummy, nDummy); + pFS->endElement(FSNS(XML_a, XML_pPr)); + } + } pFS->endElement( FSNS( XML_a, XML_p ) ); diff --git a/oox/source/export/drawingml.cxx b/oox/source/export/drawingml.cxx index 59b32eb2df4e..450d374b3b89 100644 --- a/oox/source/export/drawingml.cxx +++ b/oox/source/export/drawingml.cxx @@ -2518,6 +2518,9 @@ void DrawingML::WriteRunProperties( const Reference< XPropertySet >& rRun, bool { switch ( *o3tl::doAccess(mAny) ) { + case awt::FontUnderline::NONE : + underline = "none"; + break; case awt::FontUnderline::SINGLE : underline = "sng"; break; diff --git a/xmloff/source/chart/SchXMLAxisContext.cxx b/xmloff/source/chart/SchXMLAxisContext.cxx index 39d93cb26662..b54808790845 100644 --- a/xmloff/source/chart/SchXMLAxisContext.cxx +++ b/xmloff/source/chart/SchXMLAxisContext.cxx @@ -564,6 +564,7 @@ void SchXMLAxisContext::SetAxisTitle() { try { + // TODO: ODF import for formatted chart titles xTitleProp->setPropertyValue("String", uno::Any(m_aCurrentAxis.aTitle) ); } catch( beans::UnknownPropertyException & ) diff --git a/xmloff/source/chart/SchXMLChartContext.cxx b/xmloff/source/chart/SchXMLChartContext.cxx index 9d5522feaceb..6072a1a09622 100644 --- a/xmloff/source/chart/SchXMLChartContext.cxx +++ b/xmloff/source/chart/SchXMLChartContext.cxx @@ -736,6 +736,7 @@ void SchXMLChartContext::endFastElement(sal_Int32 ) { try { + // TODO: ODF import for formatted chart titles xTitleProp->setPropertyValue("String", uno::Any(maMainTitle) ); } catch(const beans::UnknownPropertyException&) @@ -751,6 +752,7 @@ void SchXMLChartContext::endFastElement(sal_Int32 ) { try { + // TODO: ODF import for formatted chart titles xTitleProp->setPropertyValue("String", uno::Any(maSubTitle) ); } catch(const beans::UnknownPropertyException&) diff --git a/xmloff/source/chart/SchXMLExport.cxx b/xmloff/source/chart/SchXMLExport.cxx index 79238a5b34be..56cdca7bdefa 100644 --- a/xmloff/source/chart/SchXMLExport.cxx +++ b/xmloff/source/chart/SchXMLExport.cxx @@ -1344,6 +1344,7 @@ void SchXMLExportHelper_Impl::parseDocument( Reference< chart::XChartDocument > Reference< beans::XPropertySet > xPropSet( xShape, uno::UNO_QUERY ); if( xPropSet.is()) { + // TODO: ODF export for formatted chart titles Any aAny( xPropSet->getPropertyValue( "String" )); OUString aText; aAny >>= aText; @@ -1385,6 +1386,7 @@ void SchXMLExportHelper_Impl::parseDocument( Reference< chart::XChartDocument > Reference< beans::XPropertySet > xPropSet( xShape, uno::UNO_QUERY ); if( xPropSet.is()) { + // TODO: ODF import for formatted chart titles Any aAny( xPropSet->getPropertyValue( "String" )); OUString aText; aAny >>= aText; @@ -2264,6 +2266,7 @@ void SchXMLExportHelper_Impl::exportAxisTitle( const Reference< beans::XProperty std::vector aPropertyStates = mxExpPropMapper->Filter(mrExport, rTitleProps); if( bExportContent ) { + // TODO: ODF import for formatted chart titles OUString aText; Any aAny( rTitleProps->getPropertyValue( "String" )); aAny >>= aText; -- cgit