chart2/qa/extras/chart2export3.cxx | 138 +++++++++++- chart2/qa/extras/data/ods/tdf39052.ods |binary chart2/source/controller/chartapiwrapper/TitleWrapper.cxx | 46 +--- chart2/source/controller/main/ChartController_Tools.cxx | 6 chart2/source/controller/main/ControllerCommandDispatch.cxx | 3 chart2/source/model/main/Title.cxx | 3 oox/source/export/chartexport.cxx | 12 - xmloff/source/chart/SchXMLAxisContext.cxx | 22 - xmloff/source/chart/SchXMLChartContext.cxx | 39 --- xmloff/source/chart/SchXMLChartContext.hxx | 6 xmloff/source/chart/SchXMLExport.cxx | 77 +++--- xmloff/source/chart/SchXMLParagraphContext.cxx | 131 +++++++++++ xmloff/source/chart/SchXMLParagraphContext.hxx | 44 +++ xmloff/source/chart/SchXMLTools.cxx | 92 ++++++++ xmloff/source/chart/SchXMLTools.hxx | 4 xmloff/source/chart/transporttypes.hxx | 2 16 files changed, 496 insertions(+), 129 deletions(-)
New commits: commit 0ddf1d301e8e6e8a406ad170417e12d2af84ed43 Author: Balazs Varga <balazs.varga.ext...@allotropia.de> AuthorDate: Wed May 8 17:22:24 2024 +0200 Commit: Thorsten Behrens <thorsten.behr...@allotropia.de> CommitDate: Thu May 9 21:47:42 2024 +0200 tdf#58038 - chart: make available format characters toolbar for text boxes or shapes *inside* charts (as created with the Drawing toolbar). follow-up commit: 4f994cec388377cc5c2bddb804bd92eb4cd7dc8d (tdf#39052 - Chart: make characters formatable in editable chart textshapes) Change-Id: Iccc5ee350ea0a37d8bda9652e09d3d61339f1d71 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/167366 Tested-by: Jenkins Reviewed-by: Balazs Varga <balazs.varga.ext...@allotropia.de> diff --git a/chart2/source/controller/main/ChartController_Tools.cxx b/chart2/source/controller/main/ChartController_Tools.cxx index 67ceaa1764c7..6363970553db 100644 --- a/chart2/source/controller/main/ChartController_Tools.cxx +++ b/chart2/source/controller/main/ChartController_Tools.cxx @@ -591,9 +591,9 @@ bool ChartController::isShapeContext() const bool ChartController::IsTextEdit() const { - // only Title objects are editable textshapes - return m_aSelection.isTitleObjectSelected() && - m_pDrawViewWrapper && m_pDrawViewWrapper->IsTextEdit(); + // only Title objects and additional shapes are editable textshapes in chart + return m_pDrawViewWrapper && m_pDrawViewWrapper->IsTextEdit() && + (m_aSelection.isTitleObjectSelected() || m_aSelection.isAdditionalShapeSelected()); } void ChartController::impl_ClearSelection() diff --git a/chart2/source/controller/main/ControllerCommandDispatch.cxx b/chart2/source/controller/main/ControllerCommandDispatch.cxx index cf305ea66d64..95cf433f3e04 100644 --- a/chart2/source/controller/main/ControllerCommandDispatch.cxx +++ b/chart2/source/controller/main/ControllerCommandDispatch.cxx @@ -601,7 +601,8 @@ void ControllerCommandDispatch::updateCommandAvailability() // format objects bool bFormatObjectAvailable = bIsWritable && bControllerStateIsValid && m_apControllerState->bIsFormateableObjectSelected; m_aCommandAvailability[ ".uno:FormatSelection" ] = bFormatObjectAvailable && !bIsTextEdit; - m_aCommandAvailability[ ".uno:FontDialog" ] = bFormatObjectAvailable && bIsTextEdit; + m_aCommandAvailability[ ".uno:FontDialog" ] = (bShapeContext ? isShapeControllerCommandAvailable(".uno:FontDialog") : + bFormatObjectAvailable) && bIsTextEdit; m_aCommandAvailability[ ".uno:FormatAxis" ] = bFormatObjectAvailable; m_aCommandAvailability[ ".uno:FormatTitle" ] = bFormatObjectAvailable && !bIsTextEdit; m_aCommandAvailability[ ".uno:FormatDataSeries" ] = bFormatObjectAvailable; commit bb16f920b5e16ca7d2601190a7e2b534a2dfa1a5 Author: Balazs Varga <balazs.varga.ext...@allotropia.de> AuthorDate: Mon Apr 15 13:39:03 2024 +0200 Commit: Thorsten Behrens <thorsten.behr...@allotropia.de> CommitDate: Thu May 9 21:41:41 2024 +0200 tdf#160517 - chart odf: import/export formatted chart titles (main, sub, axis titles) texts properly to/from odf format. Fix odf export of formatted chart titles. The exported data structure will look like: <chart:title svg:x="3.304cm" svg:y="0.285cm" chart:style-name="ch2"> <text:p> <text:span text:style-name="T1">This</text:span> <text:span text:style-name="T2"> is</text:span> . . . <text:span text:style-name="T3">3</text:span> <text:span text:style-name="T2"> a </text:span> </text:p> </chart:title> Fix import of formatted chart titles. Put the properties and related texts into the chart2::XFormattedString2 uno objects. Follow-up commit of: 55e9a27afd2d6a13cf76b39641bf121c3ec4b45c Related: tdf#39052 - chart ooxml: export formatted chart titles 4f994cec388377cc5c2bddb804bd92eb4cd7dc8d tdf#39052 - Chart: make characters formatable in editable chart textshapes -- TODO: chart data point / dataseries labels are handled differently since those are not editable objects, but that is a completily different issue. -- Change-Id: I1842f2c69c132bdf578bb2d354f451cc9d49c63c Reviewed-on: https://gerrit.libreoffice.org/c/core/+/166122 Reviewed-by: Michael Stahl <michael.st...@allotropia.de> Tested-by: Jenkins Reviewed-by: Balazs Varga <balazs.varga.ext...@allotropia.de> diff --git a/chart2/qa/extras/chart2export3.cxx b/chart2/qa/extras/chart2export3.cxx index 13f41f56198f..fcc9a80954cc 100644 --- a/chart2/qa/extras/chart2export3.cxx +++ b/chart2/qa/extras/chart2export3.cxx @@ -18,6 +18,9 @@ #include <com/sun/star/drawing/FillStyle.hpp> #include <com/sun/star/chart2/DataPointLabel.hpp> #include <com/sun/star/chart/DataLabelPlacement.hpp> +#include <com/sun/star/awt/FontWeight.hpp> +#include <com/sun/star/awt/FontSlant.hpp> +#include <com/sun/star/awt/FontUnderline.hpp> using uno::Reference; using beans::XPropertySet; @@ -440,11 +443,17 @@ CPPUNIT_TEST_FIXTURE(Chart2ExportTest3, testChartSubTitle) xmlDocUniquePtr pXmlDoc = parseExport("xl/charts/chart1.xml"); CPPUNIT_ASSERT(pXmlDoc); // test properties of subtitle + // paragraph props assertXPath(pXmlDoc, "/c:chartSpace/c:chart/c:title/c:tx/c:rich/a:p/a:pPr/a:defRPr"_ostr, "sz"_ostr, "1100"); assertXPath(pXmlDoc, "/c:chartSpace/c:chart/c:title/c:tx/c:rich/a:p/a:pPr/a:defRPr"_ostr, "b"_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, "00a933"); + // run props + assertXPath(pXmlDoc, "/c:chartSpace/c:chart/c:title/c:tx/c:rich/a:p/a:r/a:rPr"_ostr, "sz"_ostr, "1100"); + assertXPath(pXmlDoc, "/c:chartSpace/c:chart/c:title/c:tx/c:rich/a:p/a:r/a:rPr"_ostr, "b"_ostr, "1"); + assertXPath(pXmlDoc, "/c:chartSpace/c:chart/c:title/c:tx/c:rich/a:p/a:r/a:rPr/a:solidFill/a:srgbClr"_ostr, "val"_ostr, "00a933"); assertXPath(pXmlDoc, "/c:chartSpace/c:chart/c:title/c:tx/c:rich/a:p/a:r/a:rPr/a:latin"_ostr, "typeface"_ostr, "Times New Roman"); + // text assertXPathContent(pXmlDoc, "/c:chartSpace/c:chart/c:title/c:tx/c:rich/a:p/a:r/a:t"_ostr, "It is a Subtitle"); + // shape props assertXPath(pXmlDoc, "/c:chartSpace/c:chart/c:title/c:spPr/a:solidFill/a:srgbClr"_ostr, "val"_ostr, "b2b2b2"); } @@ -455,13 +464,19 @@ CPPUNIT_TEST_FIXTURE(Chart2ExportTest3, testChartMainWithSubTitle) xmlDocUniquePtr pXmlDoc = parseExport("xl/charts/chart1.xml"); CPPUNIT_ASSERT(pXmlDoc); // test properties of title + // paragraph props 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"); + // run props + assertXPath(pXmlDoc, "/c:chartSpace/c:chart/c:title/c:tx/c:rich/a:p[1]/a:r/a:rPr"_ostr, "sz"_ostr, "1300"); + assertXPath(pXmlDoc, "/c:chartSpace/c:chart/c:title/c:tx/c:rich/a:p[1]/a:r/a:rPr"_ostr, "b"_ostr, "0"); + assertXPath(pXmlDoc, "/c:chartSpace/c:chart/c:title/c:tx/c:rich/a:p[1]/a:r/a:rPr"_ostr, "i"_ostr, "1"); + assertXPath(pXmlDoc, "/c:chartSpace/c:chart/c:title/c:tx/c:rich/a:p[1]/a:r/a:rPr/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"); + // text 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"); + // shape props assertXPath(pXmlDoc, "/c:chartSpace/c:chart/c:title/c:spPr/a:solidFill/a:srgbClr"_ostr, "val"_ostr, "81d41a"); } @@ -608,8 +623,8 @@ CPPUNIT_TEST_FIXTURE(Chart2ExportTest3, testTitleCharacterPropertiesXLSX) xmlDocUniquePtr pXmlDoc = parseExport("xl/charts/chart1.xml"); CPPUNIT_ASSERT(pXmlDoc); - assertXPath(pXmlDoc, "/c:chartSpace/c:chart/c:title/c:tx/c:rich/a:p/a:pPr/a:defRPr"_ostr, "sz"_ostr, "2400"); - assertXPath(pXmlDoc, "/c:chartSpace/c:chart/c:title/c:tx/c:rich/a:p/a:pPr/a:defRPr"_ostr, "b"_ostr, "1"); + 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:r/a:rPr"_ostr, "sz"_ostr, "2400"); assertXPath(pXmlDoc, "/c:chartSpace/c:chart/c:title/c:tx/c:rich/a:p/a:r/a:rPr"_ostr, "b"_ostr, "1"); @@ -820,6 +835,119 @@ CPPUNIT_TEST_FIXTURE(Chart2ExportTest3, testFormattedChartTitles) assertXPathContent(pXmlDoc, "/c:chartSpace/c:chart/c:title/c:tx/c:rich/a:p[2]/a:r[4]/a:t"_ostr, "title"); } +namespace { + +void checkCharacterProps(Reference<beans::XPropertySet> const & xTitleProp) +{ + Sequence< uno::Reference< chart2::XFormattedString > > xFormattedSubTitle; + CPPUNIT_ASSERT(xTitleProp->getPropertyValue("FormattedStrings") >>= xFormattedSubTitle); + CPPUNIT_ASSERT_EQUAL(sal_Int32(10), xFormattedSubTitle.getLength()); + // check texts + std::vector<OUString> aValues = { "This", " is", "3", " a ", "custom", " erte1 ", "2dfgd ch", "ar", "t ", "title" }; + for (sal_Int32 i = 0; i < xFormattedSubTitle.getLength(); i++) + { + const OUString aText = xFormattedSubTitle.getConstArray()[i]->getString(); + CPPUNIT_ASSERT_EQUAL(aValues[i], aText); + Reference< beans::XPropertySet > xRunPropSet(xFormattedSubTitle.getConstArray()[i], uno::UNO_QUERY); + // common props + uno::Any aAny = xRunPropSet->getPropertyValue("CharFontName"); + CPPUNIT_ASSERT_EQUAL(uno::Any(OUString("Aptos Narrow")), aAny); + // unique props + if (aText == aValues[0]) + { + aAny = xRunPropSet->getPropertyValue("CharWeight"); + CPPUNIT_ASSERT_EQUAL(uno::Any(awt::FontWeight::BOLD), aAny); + aAny = xRunPropSet->getPropertyValue("CharHeight"); + CPPUNIT_ASSERT_EQUAL(uno::Any(14.0f), aAny); + aAny = xRunPropSet->getPropertyValue("CharColor"); + CPPUNIT_ASSERT_EQUAL(uno::Any(Color(0xff0000)), aAny); + aAny = xRunPropSet->getPropertyValue("CharEscapement"); + CPPUNIT_ASSERT_EQUAL(uno::Any(short(0)), aAny); + aAny = xRunPropSet->getPropertyValue("CharEscapementHeight"); + CPPUNIT_ASSERT_EQUAL(uno::Any(short(100)), aAny); + } + else if (aText == aValues[1] || aText == aValues[3] || aText == aValues[5] || + aText == aValues[6] || aText == aValues[8]) + { + aAny = xRunPropSet->getPropertyValue("CharWeight"); + CPPUNIT_ASSERT_EQUAL(uno::Any(awt::FontWeight::NORMAL), aAny); + aAny = xRunPropSet->getPropertyValue("CharHeight"); + CPPUNIT_ASSERT_EQUAL(uno::Any(14.0f), aAny); + aAny = xRunPropSet->getPropertyValue("CharColor"); + CPPUNIT_ASSERT_EQUAL(uno::Any(Color(0x595959)), aAny); + } + else if (aText == aValues[2]) + { + aAny = xRunPropSet->getPropertyValue("CharWeight"); + CPPUNIT_ASSERT_EQUAL(uno::Any(awt::FontWeight::NORMAL), aAny); + aAny = xRunPropSet->getPropertyValue("CharHeight"); + CPPUNIT_ASSERT_EQUAL(uno::Any(14.0f), aAny); + aAny = xRunPropSet->getPropertyValue("CharColor"); + CPPUNIT_ASSERT_EQUAL(uno::Any(Color(0x595959)), aAny); + aAny = xRunPropSet->getPropertyValue("CharEscapement"); + CPPUNIT_ASSERT_EQUAL(uno::Any(short(30)), aAny); + aAny = xRunPropSet->getPropertyValue("CharEscapementHeight"); + CPPUNIT_ASSERT_EQUAL(uno::Any(short(58)), aAny); + } + else if (aText == aValues[4]) + { + aAny = xRunPropSet->getPropertyValue("CharWeight"); + CPPUNIT_ASSERT_EQUAL(uno::Any(awt::FontWeight::NORMAL), aAny); + aAny = xRunPropSet->getPropertyValue("CharHeight"); + CPPUNIT_ASSERT_EQUAL(uno::Any(20.0f), aAny); + aAny = xRunPropSet->getPropertyValue("CharColor"); + CPPUNIT_ASSERT_EQUAL(uno::Any(Color(0x4ea72e)), aAny); + aAny = xRunPropSet->getPropertyValue("CharPosture"); + CPPUNIT_ASSERT_EQUAL(uno::Any(awt::FontSlant_ITALIC), aAny); + aAny = xRunPropSet->getPropertyValue("CharUnderline"); + CPPUNIT_ASSERT_EQUAL(uno::Any(awt::FontUnderline::SINGLE), aAny); + } + else if (aText == aValues[7]) + { + aAny = xRunPropSet->getPropertyValue("CharWeight"); + CPPUNIT_ASSERT_EQUAL(uno::Any(awt::FontWeight::BOLD), aAny); + aAny = xRunPropSet->getPropertyValue("CharHeight"); + CPPUNIT_ASSERT_EQUAL(uno::Any(14.0f), aAny); + aAny = xRunPropSet->getPropertyValue("CharColor"); + CPPUNIT_ASSERT_EQUAL(uno::Any(Color(0x595959)), aAny); + aAny = xRunPropSet->getPropertyValue("CharPosture"); + CPPUNIT_ASSERT_EQUAL(uno::Any(awt::FontSlant_NONE), aAny); + } + else // aText == aValues[9] + { + aAny = xRunPropSet->getPropertyValue("CharWeight"); + CPPUNIT_ASSERT_EQUAL(uno::Any(awt::FontWeight::NORMAL), aAny); + aAny = xRunPropSet->getPropertyValue("CharHeight"); + CPPUNIT_ASSERT_EQUAL(uno::Any(14.0f), aAny); + aAny = xRunPropSet->getPropertyValue("CharColor"); + CPPUNIT_ASSERT_EQUAL(uno::Any(Color(0x595959)), aAny); + aAny = xRunPropSet->getPropertyValue("CharPosture"); + CPPUNIT_ASSERT_EQUAL(uno::Any(awt::FontSlant_ITALIC), aAny); + aAny = xRunPropSet->getPropertyValue("CharOverline"); + CPPUNIT_ASSERT_EQUAL(uno::Any(awt::FontUnderline::NONE), aAny); + } + } +} + +} + +CPPUNIT_TEST_FIXTURE(Chart2ExportTest3, testODSFormattedChartTitles) +{ + // The document contains a line chart with "Between tick marks" X axis position. + loadFromFile(u"ods/tdf39052.ods"); + // Check formatted strings after export. + saveAndReload("calc8"); + + Reference<chart2::XChartDocument> xChart2Doc = getChartDocFromSheet(0, mxComponent); + CPPUNIT_ASSERT(xChart2Doc.is()); + Reference< chart::XChartDocument > xChartDoc(xChart2Doc, uno::UNO_QUERY); + CPPUNIT_ASSERT(xChartDoc.is()); + uno::Reference< beans::XPropertySet > xTitleProp(xChartDoc->getTitle(), uno::UNO_QUERY); + CPPUNIT_ASSERT(xTitleProp.is()); + + checkCharacterProps(xTitleProp); +} + CPPUNIT_PLUGIN_IMPLEMENT(); /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/qa/extras/data/ods/tdf39052.ods b/chart2/qa/extras/data/ods/tdf39052.ods new file mode 100644 index 000000000000..68089195507e Binary files /dev/null and b/chart2/qa/extras/data/ods/tdf39052.ods differ diff --git a/chart2/source/controller/chartapiwrapper/TitleWrapper.cxx b/chart2/source/controller/chartapiwrapper/TitleWrapper.cxx index b0367cb0f478..fb94a5d74c8a 100644 --- a/chart2/source/controller/chartapiwrapper/TitleWrapper.cxx +++ b/chart2/source/controller/chartapiwrapper/TitleWrapper.cxx @@ -143,16 +143,7 @@ Any WrappedTitleFormStringsProperty::getPropertyValue( const Reference< beans::X 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; - } + aRet <<= aStrings; } return aRet; } @@ -325,27 +316,12 @@ void SAL_CALL TitleWrapper::removeEventListener( m_aEventListenerContainer.removeInterface( g, aListener ); } -Reference< beans::XPropertySet > TitleWrapper::getFirstCharacterPropertySet() -{ - Reference< beans::XPropertySet > xProp; - - Reference< chart2::XTitle > xTitle( getTitleObject() ); - if( xTitle.is()) - { - Sequence< Reference< chart2::XFormattedString > > aStrings( xTitle->getText()); - if( aStrings.hasElements() ) - xProp.set( aStrings[0], uno::UNO_QUERY ); - } - - return xProp; -} - void TitleWrapper::getFastCharacterPropertyValue( sal_Int32 nHandle, Any& rValue ) { OSL_ASSERT( FAST_PROPERTY_ID_START_CHAR_PROP <= nHandle && nHandle < CharacterProperties::FAST_PROPERTY_ID_END_CHAR_PROP ); - Reference< beans::XPropertySet > xProp = getFirstCharacterPropertySet(); + Reference< beans::XPropertySet > xProp = getInnerPropertySet(); Reference< beans::XFastPropertySet > xFastProp( xProp, uno::UNO_QUERY ); if(xProp.is()) { @@ -385,6 +361,16 @@ void TitleWrapper::setFastCharacterPropertyValue( else if( xFastPropertySet.is() ) xFastPropertySet->setFastPropertyValue( nHandle, rValue ); } + + Reference< beans::XPropertySet > xInnerProp = getInnerPropertySet(); + Reference< beans::XFastPropertySet > xFastInnerProp( xInnerProp, uno::UNO_QUERY ); + if (xInnerProp.is()) + { + if (pWrappedProperty) + pWrappedProperty->setPropertyValue(rValue, xInnerProp); + else if (xFastInnerProp.is()) + xFastInnerProp->setFastPropertyValue(nHandle, rValue); + } } // WrappedPropertySet @@ -418,7 +404,7 @@ beans::PropertyState SAL_CALL TitleWrapper::getPropertyState( const OUString& rP sal_Int32 nHandle = getInfoHelper().getHandleByName( rPropertyName ); if( CharacterProperties::IsCharacterPropertyHandle( nHandle ) ) { - Reference< beans::XPropertyState > xPropState( getFirstCharacterPropertySet(), uno::UNO_QUERY ); + Reference< beans::XPropertyState > xPropState( getInnerPropertySet(), uno::UNO_QUERY); if( xPropState.is() ) { const WrappedProperty* pWrappedProperty = getWrappedProperty( rPropertyName ); @@ -451,7 +437,7 @@ Any SAL_CALL TitleWrapper::getPropertyDefault( const OUString& rPropertyName ) sal_Int32 nHandle = getInfoHelper().getHandleByName( rPropertyName ); if( CharacterProperties::IsCharacterPropertyHandle( nHandle ) ) { - Reference< beans::XPropertyState > xPropState( getFirstCharacterPropertySet(), uno::UNO_QUERY ); + Reference< beans::XPropertyState > xPropState( getInnerPropertySet(), uno::UNO_QUERY ); if( xPropState.is() ) { const WrappedProperty* pWrappedProperty = getWrappedProperty( rPropertyName ); @@ -472,7 +458,7 @@ void SAL_CALL TitleWrapper::addPropertyChangeListener( const OUString& rProperty sal_Int32 nHandle = getInfoHelper().getHandleByName( rPropertyName ); if( CharacterProperties::IsCharacterPropertyHandle( nHandle ) ) { - Reference< beans::XPropertySet > xPropSet = getFirstCharacterPropertySet(); + Reference< beans::XPropertySet > xPropSet = getInnerPropertySet(); if( xPropSet.is() ) xPropSet->addPropertyChangeListener( rPropertyName, xListener ); } @@ -484,7 +470,7 @@ void SAL_CALL TitleWrapper::removePropertyChangeListener( const OUString& rPrope sal_Int32 nHandle = getInfoHelper().getHandleByName( rPropertyName ); if( CharacterProperties::IsCharacterPropertyHandle( nHandle ) ) { - Reference< beans::XPropertySet > xPropSet = getFirstCharacterPropertySet(); + Reference< beans::XPropertySet > xPropSet = getInnerPropertySet(); if( xPropSet.is() ) xPropSet->removePropertyChangeListener( rPropertyName, xListener ); } diff --git a/chart2/source/model/main/Title.cxx b/chart2/source/model/main/Title.cxx index 6833684e9bf2..10551ce6e318 100644 --- a/chart2/source/model/main/Title.cxx +++ b/chart2/source/model/main/Title.cxx @@ -18,6 +18,7 @@ */ #include <Title.hxx> +#include <CharacterProperties.hxx> #include <LinePropertiesHelper.hxx> #include <FillProperties.hxx> #include <CloneHelper.hxx> @@ -145,6 +146,7 @@ const ::chart::tPropertyValueMap& StaticTitleDefaults() { ::chart::tPropertyValueMap aTmp; + ::chart::CharacterProperties::AddDefaultsToMap( aTmp ); ::chart::LinePropertiesHelper::AddDefaultsToMap( aTmp ); ::chart::FillProperties::AddDefaultsToMap( aTmp ); @@ -178,6 +180,7 @@ const ::chart::tPropertyValueMap& StaticTitleDefaults() { std::vector< css::beans::Property > aProperties; lcl_AddPropertiesToVector( aProperties ); + ::chart::CharacterProperties::AddPropertiesToVector( aProperties ); ::chart::LinePropertiesHelper::AddPropertiesToVector( aProperties ); ::chart::FillProperties::AddPropertiesToVector( aProperties ); diff --git a/oox/source/export/chartexport.cxx b/oox/source/export/chartexport.cxx index 00161cde7e4a..6fb1ae804ee7 100644 --- a/oox/source/export/chartexport.cxx +++ b/oox/source/export/chartexport.cxx @@ -1154,13 +1154,9 @@ void ChartExport::exportChart( const Reference< css::chart::XChartDocument >& xC Reference< beans::XPropertySet > xPropSubTitle( xChartDoc->getSubTitle(), UNO_QUERY ); if( xPropSubTitle.is()) { - try - { + OUString aSubTitle; + if ((xPropSubTitle->getPropertyValue("String") >>= aSubTitle) && !aSubTitle.isEmpty()) xPropSubTitle->getPropertyValue("FormattedStrings") >>= xFormattedSubTitle; - } - catch( beans::UnknownPropertyException & ) - { - } } // chart element @@ -1451,7 +1447,9 @@ void ChartExport::exportTitle( const Reference< XShape >& xShape, Reference< beans::XPropertySet > xPropSet( xShape, uno::UNO_QUERY ); if( xPropSet.is()) { - xPropSet->getPropertyValue("FormattedStrings") >>= xFormattedTitle; + OUString aTitle; + if ((xPropSet->getPropertyValue("String") >>= aTitle) && !aTitle.isEmpty()) + xPropSet->getPropertyValue("FormattedStrings") >>= xFormattedTitle; } // tdf#101322: add subtitle to title diff --git a/xmloff/source/chart/SchXMLAxisContext.cxx b/xmloff/source/chart/SchXMLAxisContext.cxx index fd106f72fa69..c39d13f69100 100644 --- a/xmloff/source/chart/SchXMLAxisContext.cxx +++ b/xmloff/source/chart/SchXMLAxisContext.cxx @@ -553,26 +553,18 @@ void SchXMLAxisContext::CreateAxis() void SchXMLAxisContext::SetAxisTitle() { - if( m_aCurrentAxis.aTitle.isEmpty() ) + if( m_aCurrentAxis.maTitle.empty() ) return; Reference< chart::XAxis > xAxis( lcl_getChartAxis( m_aCurrentAxis, m_xDiagram ) ); if( !xAxis.is() ) return; - Reference< beans::XPropertySet > xTitleProp( xAxis->getAxisTitle() ); - if( xTitleProp.is() ) - { - try - { - // TODO: ODF import for formatted chart titles - xTitleProp->setPropertyValue("String", uno::Any(m_aCurrentAxis.aTitle) ); - } - catch( beans::UnknownPropertyException & ) - { - SAL_INFO("xmloff.chart", "Property String for Title not available" ); - } - } + if (m_aCurrentAxis.maTitle.back().first.isEmpty() && + m_aCurrentAxis.maTitle.back().second == OUStringChar(u'\x0D')) + m_aCurrentAxis.maTitle.pop_back(); // remove last end of paragraph break + + SchXMLTools::importFormattedText(GetImport(), m_aCurrentAxis.maTitle, xAxis->getAxisTitle()); } css::uno::Reference< css::xml::sax::XFastContextHandler > SchXMLAxisContext::createFastChildContext( @@ -585,7 +577,7 @@ css::uno::Reference< css::xml::sax::XFastContextHandler > SchXMLAxisContext::cre { Reference< drawing::XShape > xTitleShape = getTitleShape(); return new SchXMLTitleContext( m_rImportHelper, GetImport(), - m_aCurrentAxis.aTitle, + m_aCurrentAxis.maTitle, xTitleShape ); } break; diff --git a/xmloff/source/chart/SchXMLChartContext.cxx b/xmloff/source/chart/SchXMLChartContext.cxx index 6d1350add627..ab800c5f5199 100644 --- a/xmloff/source/chart/SchXMLChartContext.cxx +++ b/xmloff/source/chart/SchXMLChartContext.cxx @@ -720,37 +720,16 @@ void SchXMLChartContext::endFastElement(sal_Int32 ) if( xProp.is()) { - if( !maMainTitle.isEmpty()) + if( !maMainTitle.empty()) { - uno::Reference< beans::XPropertySet > xTitleProp( xDoc->getTitle(), uno::UNO_QUERY ); - if( xTitleProp.is()) - { - try - { - // TODO: ODF import for formatted chart titles - xTitleProp->setPropertyValue("String", uno::Any(maMainTitle) ); - } - catch(const beans::UnknownPropertyException&) - { - SAL_WARN("xmloff.chart", "Property String for Title not available" ); - } - } + uno::Reference< beans::XPropertySet > xTitleProp(xDoc->getTitle(), uno::UNO_QUERY); + SchXMLTools::importFormattedText(GetImport(), maMainTitle, xTitleProp); } - if( !maSubTitle.isEmpty()) + + if( !maSubTitle.empty()) { - uno::Reference< beans::XPropertySet > xTitleProp( xDoc->getSubTitle(), uno::UNO_QUERY ); - if( xTitleProp.is()) - { - try - { - // TODO: ODF import for formatted chart titles - xTitleProp->setPropertyValue("String", uno::Any(maSubTitle) ); - } - catch(const beans::UnknownPropertyException&) - { - SAL_WARN("xmloff.chart", "Property String for Title not available" ); - } - } + uno::Reference< beans::XPropertySet > xTitleProp(xDoc->getSubTitle(), uno::UNO_QUERY); + SchXMLTools::importFormattedText(GetImport(), maSubTitle, xTitleProp); } } @@ -1165,7 +1144,7 @@ void SchXMLChartContext::InitChart( } SchXMLTitleContext::SchXMLTitleContext( SchXMLImportHelper& rImpHelper, SvXMLImport& rImport, - OUString& rTitle, + std::vector<std::pair<OUString, OUString>>& rTitle, uno::Reference< drawing::XShape > xTitleShape ) : SvXMLImportContext( rImport ), mrImportHelper( rImpHelper ), @@ -1231,7 +1210,7 @@ css::uno::Reference< css::xml::sax::XFastContextHandler > SchXMLTitleContext::cr if( nElement == XML_ELEMENT(TEXT, XML_P) || nElement == XML_ELEMENT(LO_EXT, XML_P) ) { - pContext = new SchXMLParagraphContext( GetImport(), mrTitle ); + pContext = new SchXMLTitleParaContext(GetImport(), mrTitle); } else XMLOFF_WARN_UNKNOWN_ELEMENT("xmloff", nElement); diff --git a/xmloff/source/chart/SchXMLChartContext.hxx b/xmloff/source/chart/SchXMLChartContext.hxx index 40ba13e0177c..6b52b61b6d7c 100644 --- a/xmloff/source/chart/SchXMLChartContext.hxx +++ b/xmloff/source/chart/SchXMLChartContext.hxx @@ -89,7 +89,7 @@ private: SchXMLTable maTable; SchXMLImportHelper& mrImportHelper; - OUString maMainTitle, maSubTitle; + std::vector<std::pair<OUString, OUString>> maMainTitle, maSubTitle; OUString m_aXLinkHRefAttributeToIndicateDataProvider; bool m_bHasRangeAtPlotArea; bool m_bHasTableElement; @@ -127,14 +127,14 @@ class SchXMLTitleContext : public SvXMLImportContext { private: SchXMLImportHelper& mrImportHelper; - OUString& mrTitle; + std::vector<std::pair<OUString, OUString>>& mrTitle; css::uno::Reference< css::drawing::XShape > mxTitleShape; OUString msAutoStyleName; public: SchXMLTitleContext( SchXMLImportHelper& rImpHelper, SvXMLImport& rImport, - OUString& rTitle, + std::vector<std::pair<OUString, OUString>>& rTitle, css::uno::Reference< css::drawing::XShape > xTitleShape ); virtual ~SchXMLTitleContext() override; diff --git a/xmloff/source/chart/SchXMLExport.cxx b/xmloff/source/chart/SchXMLExport.cxx index 804891006faa..e3b1c3ebb1ef 100644 --- a/xmloff/source/chart/SchXMLExport.cxx +++ b/xmloff/source/chart/SchXMLExport.cxx @@ -207,6 +207,8 @@ public: ::std::queue< OUString > maAutoStyleNameQueue; void CollectAutoStyle( std::vector< XMLPropertyState >&& aStates ); + void CollectAutoTextStyle( + const css::uno::Reference< css::beans::XPropertySet >& xTitlePropSet ); void AddAutoStyleAttribute( const std::vector< XMLPropertyState >& aStates ); @@ -275,6 +277,7 @@ public: void addSize( const css::uno::Reference< css::drawing::XShape >& xShape ); /// exports a string as a paragraph element void exportText( const OUString& rText ); + void exportFormattedText( const css::uno::Reference< beans::XPropertySet >& xTitleProps ); public: SvXMLExport& mrExport; @@ -1314,15 +1317,14 @@ void SchXMLExportHelper_Impl::parseDocument( Reference< chart::XChartDocument > if( bHasMainTitle ) { // get property states for autostyles - if( mxExpPropMapper.is()) + Reference< drawing::XShape > xShape = rChartDoc->getTitle(); + Reference< beans::XPropertySet > xPropSet(xShape, uno::UNO_QUERY); + if( mxExpPropMapper.is() && xPropSet.is()) { - Reference< beans::XPropertySet > xPropSet( rChartDoc->getTitle(), uno::UNO_QUERY ); - if( xPropSet.is()) - aPropertyStates = mxExpPropMapper->Filter(mrExport, xPropSet); + aPropertyStates = mxExpPropMapper->Filter(mrExport, xPropSet); } if( bExportContent ) { - Reference< drawing::XShape > xShape = rChartDoc->getTitle(); if( xShape.is()) // && "hasTitleBeenMoved" addPosition( xShape ); @@ -1333,19 +1335,12 @@ void SchXMLExportHelper_Impl::parseDocument( Reference< chart::XChartDocument > SvXMLElementExport aElTitle( mrExport, XML_NAMESPACE_CHART, XML_TITLE, true, true ); // content (text:p) - 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; - exportText( aText ); - } + exportFormattedText(xPropSet); } else // autostyles { CollectAutoStyle( std::move(aPropertyStates) ); + CollectAutoTextStyle( xPropSet ); } // remove property states for autostyles aPropertyStates.clear(); @@ -1355,16 +1350,15 @@ void SchXMLExportHelper_Impl::parseDocument( Reference< chart::XChartDocument > if( bHasSubTitle ) { // get property states for autostyles - if( mxExpPropMapper.is()) + Reference< drawing::XShape > xShape = rChartDoc->getSubTitle(); + Reference< beans::XPropertySet > xPropSet(xShape, uno::UNO_QUERY); + if( mxExpPropMapper.is() && xPropSet.is()) { - Reference< beans::XPropertySet > xPropSet( rChartDoc->getSubTitle(), uno::UNO_QUERY ); - if( xPropSet.is()) - aPropertyStates = mxExpPropMapper->Filter(mrExport, xPropSet); + aPropertyStates = mxExpPropMapper->Filter(mrExport, xPropSet); } if( bExportContent ) { - Reference< drawing::XShape > xShape = rChartDoc->getSubTitle(); if( xShape.is()) addPosition( xShape ); @@ -1375,19 +1369,12 @@ void SchXMLExportHelper_Impl::parseDocument( Reference< chart::XChartDocument > SvXMLElementExport aElSubTitle( mrExport, XML_NAMESPACE_CHART, XML_SUBTITLE, true, true ); // content (text:p) - 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; - exportText( aText ); - } + exportFormattedText(xPropSet); } else // autostyles { CollectAutoStyle( std::move(aPropertyStates) ); + CollectAutoTextStyle(xPropSet); } // remove property states for autostyles aPropertyStates.clear(); @@ -2258,11 +2245,6 @@ void SchXMLExportHelper_Impl::exportAxisTitle( const Reference< beans::XProperty std::vector<XMLPropertyState> aPropertyStates = mxExpPropMapper->Filter(mrExport, rTitleProps); if( bExportContent ) { - // TODO: ODF import for formatted chart titles - OUString aText; - Any aAny( rTitleProps->getPropertyValue( "String" )); - aAny >>= aText; - Reference< drawing::XShape > xShape( rTitleProps, uno::UNO_QUERY ); if( xShape.is()) addPosition( xShape ); @@ -2271,11 +2253,12 @@ void SchXMLExportHelper_Impl::exportAxisTitle( const Reference< beans::XProperty SvXMLElementExport aTitle( mrExport, XML_NAMESPACE_CHART, XML_TITLE, true, true ); // paragraph containing title - exportText( aText ); + exportFormattedText( rTitleProps ); } else { CollectAutoStyle( std::move(aPropertyStates) ); + CollectAutoTextStyle( rTitleProps ); } aPropertyStates.clear(); } @@ -3819,6 +3802,27 @@ void SchXMLExportHelper_Impl::CollectAutoStyle( std::vector< XMLPropertyState >& maAutoStyleNameQueue.push( mrAutoStylePool.Add( XmlStyleFamily::SCH_CHART_ID, std::move(aStates) )); } +void SchXMLExportHelper_Impl::CollectAutoTextStyle( const css::uno::Reference< beans::XPropertySet >& xTitlePropSet ) +{ + if (xTitlePropSet.is()) + { + Sequence< uno::Reference< chart2::XFormattedString > > xFormattedTitle; + + OUString aTitle; + if ((xTitlePropSet->getPropertyValue("String") >>= aTitle) && !aTitle.isEmpty()) + xTitlePropSet->getPropertyValue("FormattedStrings") >>= xFormattedTitle; + + if (xFormattedTitle.hasElements()) + { + for (const uno::Reference<chart2::XFormattedString>& rxFS : xFormattedTitle) + { + Reference< beans::XPropertySet > xRunPropSet(rxFS, uno::UNO_QUERY); + mrExport.GetTextParagraphExport()->Add(XmlStyleFamily::TEXT_TEXT, xRunPropSet); + } + } + } +} + void SchXMLExportHelper_Impl::AddAutoStyleAttribute( const std::vector< XMLPropertyState >& aStates ) { if( !aStates.empty() ) @@ -3835,6 +3839,11 @@ void SchXMLExportHelper_Impl::exportText( const OUString& rText ) SchXMLTools::exportText( mrExport, rText, false/*bConvertTabsLFs*/ ); } +void SchXMLExportHelper_Impl::exportFormattedText( const css::uno::Reference< beans::XPropertySet >& xTitleProps ) +{ + SchXMLTools::exportFormattedText( mrExport, xTitleProps ); +} + SchXMLExport::SchXMLExport(const Reference<uno::XComponentContext>& xContext, OUString const& implementationName, SvXMLExportFlags nExportFlags) diff --git a/xmloff/source/chart/SchXMLParagraphContext.cxx b/xmloff/source/chart/SchXMLParagraphContext.cxx index 84e22c5a5c71..32e2a9899789 100644 --- a/xmloff/source/chart/SchXMLParagraphContext.cxx +++ b/xmloff/source/chart/SchXMLParagraphContext.cxx @@ -104,4 +104,135 @@ void SchXMLParagraphContext::characters( const OUString& rChars ) maBuffer.append( rChars ); } +SchXMLTitleParaContext::SchXMLTitleParaContext( SvXMLImport& rImport, + std::vector<std::pair<OUString, OUString>>& rParaText, + OUString * pOutId /* = 0 */ ) : + SvXMLImportContext( rImport ), + mrParaText( rParaText ), + mpId( pOutId ) +{ +} + +SchXMLTitleParaContext::~SchXMLTitleParaContext() +{} + +void SchXMLTitleParaContext::startFastElement( + sal_Int32 /*nElement*/, + const uno::Reference< xml::sax::XFastAttributeList >& xAttrList ) +{ + // remember the id. It is used for storing the original cell range string in + // a local table (cached data) + if( !mpId ) + return; + + bool bHaveXmlId( false ); + + for( auto& aIter : sax_fastparser::castToFastAttributeList(xAttrList) ) + { + switch(aIter.getToken()) + { + case XML_ELEMENT(TEXT, XML_STYLE_NAME): + maStyleName = aIter.toString(); + break; + case XML_ELEMENT(XML, XML_ID): + (*mpId) = aIter.toString(); + bHaveXmlId = true; + break; + case XML_ELEMENT(TEXT, XML_ID): + { // text:id shall be ignored if xml:id exists + if (!bHaveXmlId) + { + (*mpId) = aIter.toString(); + } + break; + } + default: + XMLOFF_WARN_UNKNOWN("xmloff", aIter); + } + } +} + +void SchXMLTitleParaContext::endFastElement(sal_Int32 ) +{ + if (!maBuffer.isEmpty()) + mrParaText.push_back(std::make_pair(maStyleName, maBuffer.makeStringAndClear())); +} + +void SchXMLTitleParaContext::characters(const OUString& rChars) +{ + maBuffer.append(rChars); +} + +css::uno::Reference< css::xml::sax::XFastContextHandler > SchXMLTitleParaContext::createFastChildContext( + sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList) +{ + if( nElement == XML_ELEMENT(TEXT, XML_SPAN) ) + { + if (!maBuffer.isEmpty()) + mrParaText.push_back(std::make_pair(maStyleName, maBuffer.makeStringAndClear())); + + return new SchXMLTitleSpanContext(GetImport(), mrParaText, xAttrList); + } + else if( nElement == XML_ELEMENT(TEXT, XML_TAB_STOP) ) + { + maBuffer.append( u'\x0009'); // tabulator + } + else if( nElement == XML_ELEMENT(TEXT, XML_LINE_BREAK) ) + { + maBuffer.append( u'\x000A'); // linefeed + } + else + XMLOFF_WARN_UNKNOWN_ELEMENT("xmloff", nElement); + + return nullptr; +} + +SchXMLTitleSpanContext::SchXMLTitleSpanContext(SvXMLImport& rImport, std::vector<std::pair<OUString, OUString>>& rSpanTexts, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList) : + SvXMLImportContext(rImport), + mrSpanTexts(rSpanTexts) +{ + for( auto& aIter : sax_fastparser::castToFastAttributeList(xAttrList) ) + { + if( aIter.getToken() == XML_ELEMENT(TEXT, XML_STYLE_NAME) ) + { + maStyleName = aIter.toString(); + break; + } + } +} + +SchXMLTitleSpanContext::~SchXMLTitleSpanContext() +{} + +void SchXMLTitleSpanContext::characters(const OUString& rChars) +{ + maCharBuffer.append(rChars); +} + +css::uno::Reference< css::xml::sax::XFastContextHandler > SchXMLTitleSpanContext::createFastChildContext( + sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& /*xAttrList*/) +{ + if( nElement == XML_ELEMENT(TEXT, XML_TAB_STOP) ) + { + maCharBuffer.append( u'\x0009'); // tabulator + } + else if( nElement == XML_ELEMENT(TEXT, XML_LINE_BREAK) ) + { + maCharBuffer.append( u'\x000A'); // linefeed + } + else + XMLOFF_WARN_UNKNOWN_ELEMENT("xmloff", nElement); + + return nullptr; +} + +void SchXMLTitleSpanContext::endFastElement(sal_Int32) +{ + if (!maCharBuffer.isEmpty()) + mrSpanTexts.push_back(std::make_pair(maStyleName, maCharBuffer.makeStringAndClear())); +} + /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/chart/SchXMLParagraphContext.hxx b/xmloff/source/chart/SchXMLParagraphContext.hxx index 65e90522e860..ba2231bd5d24 100644 --- a/xmloff/source/chart/SchXMLParagraphContext.hxx +++ b/xmloff/source/chart/SchXMLParagraphContext.hxx @@ -50,4 +50,48 @@ public: const css::uno::Reference< css::xml::sax::XFastAttributeList >& AttrList ) override; }; +class SchXMLTitleParaContext : public SvXMLImportContext +{ +private: + std::vector<std::pair<OUString, OUString>>& mrParaText; + OUString* mpId; + OUStringBuffer maBuffer; + OUString maStyleName; + +public: + SchXMLTitleParaContext( SvXMLImport& rImport, + std::vector<std::pair<OUString, OUString>>& rParaText, + OUString * pOutId = nullptr ); + virtual ~SchXMLTitleParaContext() override; + + virtual void SAL_CALL startFastElement( + sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList ) override; + virtual void SAL_CALL endFastElement(sal_Int32 nElement) override; + virtual void SAL_CALL characters( const OUString& rChars ) override; + + virtual css::uno::Reference< css::xml::sax::XFastContextHandler > SAL_CALL createFastChildContext( + sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& AttrList ) override; +}; + +class SchXMLTitleSpanContext : public SvXMLImportContext +{ +private: + std::vector<std::pair<OUString, OUString>>& mrSpanTexts; + OUStringBuffer maCharBuffer; + OUString maStyleName; +public: + SchXMLTitleSpanContext( SvXMLImport& rImport, std::vector<std::pair<OUString, OUString>>& rSpanTexts, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList); + virtual ~SchXMLTitleSpanContext() override; + + virtual void SAL_CALL characters( const OUString& rChars ) override; + virtual void SAL_CALL endFastElement( sal_Int32 nElement ) override; + + virtual css::uno::Reference< css::xml::sax::XFastContextHandler > SAL_CALL createFastChildContext( + sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& /*AttrList*/) override; +}; + /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/chart/SchXMLTools.cxx b/xmloff/source/chart/SchXMLTools.cxx index 120e361f84f0..ad012dc9cffe 100644 --- a/xmloff/source/chart/SchXMLTools.cxx +++ b/xmloff/source/chart/SchXMLTools.cxx @@ -26,6 +26,7 @@ #include <xmloff/prstylei.hxx> #include <xmloff/xmlprmap.hxx> #include <xmloff/xmlexp.hxx> +#include <xmloff/xmlimp.hxx> #include <xmloff/xmlnamespace.hxx> #include <xmloff/xmlmetai.hxx> #include <xmloff/maptype.hxx> @@ -37,6 +38,7 @@ #include <com/sun/star/chart2/data/XDataReceiver.hpp> #include <com/sun/star/chart2/data/XRangeXMLConversion.hpp> #include <com/sun/star/chart2/data/XPivotTableDataProvider.hpp> +#include <com/sun/star/chart2/FormattedString.hpp> #include <com/sun/star/chart2/XChartDocument.hpp> #include <com/sun/star/chart2/XCoordinateSystemContainer.hpp> #include <com/sun/star/container/XChild.hpp> @@ -47,6 +49,7 @@ #include <comphelper/processfactory.hxx> #include <comphelper/diagnose_ex.hxx> +#include <comphelper/sequence.hxx> #include <sal/log.hxx> #include <o3tl/string_view.hxx> #include <algorithm> @@ -600,6 +603,95 @@ void exportText( SvXMLExport& rExport, const OUString& rText, bool bConvertTabsL } } +void exportFormattedText( SvXMLExport& rExport, const uno::Reference< beans::XPropertySet >& xTitleProps ) +{ + Sequence< uno::Reference< chart2::XFormattedString > > xFormattedTitle; + if (xTitleProps.is()) + { + OUString aTitle; + if ((xTitleProps->getPropertyValue("String") >>= aTitle) && !aTitle.isEmpty()) + xTitleProps->getPropertyValue("FormattedStrings") >>= xFormattedTitle; + } + + if (xFormattedTitle.hasElements()) + { + SvXMLElementExport aElemP(rExport, XML_NAMESPACE_TEXT, XML_P, true, false); + for (const uno::Reference<chart2::XFormattedString>& rxFS : xFormattedTitle) + { + Reference< beans::XPropertySet > xRunPropSet(rxFS, uno::UNO_QUERY); + bool bIsUICharStyle, bHasAutoStyle = false; + OUString sStyle = rExport.GetTextParagraphExport()->FindTextStyle(xRunPropSet, bIsUICharStyle, bHasAutoStyle); + if (!sStyle.isEmpty()) + { + rExport.AddAttribute(XML_NAMESPACE_TEXT, XML_STYLE_NAME, + rExport.EncodeStyleName(sStyle)); + } + + SvXMLElementExport aSpan(rExport, !sStyle.isEmpty(), XML_NAMESPACE_TEXT, XML_SPAN, true, false); + rExport.GetDocHandler()->characters(rxFS->getString()); + } + } +} + +void importFormattedText( SvXMLImport& rImport, const std::vector<std::pair<OUString, OUString>>& rTitle, + const uno::Reference< beans::XPropertySet >& xTitleProp ) +{ + if (!xTitleProp.is()) + return; + + std::vector< Reference< chart2::XFormattedString > > aStringVec; + Sequence< uno::Reference< chart2::XFormattedString > > xFullTextTitle; + Reference < beans::XPropertySet > xFullTextTitleProps; + + try + { + if ((xTitleProp->getPropertyValue("FormattedStrings") >>= xFullTextTitle) && + xFullTextTitle.hasElements()) + { + // these are the properies from the textshape object - needs to apply them + // to all the string parts firstly - (necessarry for backward compatibility) + xFullTextTitleProps.set(xFullTextTitle.getArray()[0], uno::UNO_QUERY); + } + + for (auto aRIt = std::begin(rTitle); aRIt != std::end(rTitle); ++aRIt) + { + Reference< chart2::XFormattedString2 > xNewFmtStr; + xNewFmtStr = chart2::FormattedString::create(rImport.GetComponentContext()); + + if (xFullTextTitleProps.is()) + { + // these are the properies from the textshape object - needs to apply them + // to all the string parts firstly + uno::Reference< beans::XPropertySetInfo > xInfo = xNewFmtStr->getPropertySetInfo(); + for (const beans::Property& rProp : xFullTextTitleProps->getPropertySetInfo()->getProperties()) + { + if (xInfo.is() && xInfo->hasPropertyByName(rProp.Name)) + { + const uno::Any aValue = xFullTextTitleProps->getPropertyValue(rProp.Name); + xNewFmtStr->setPropertyValue(rProp.Name, aValue); + } + } + } + + if (auto pStyle = rImport.GetTextImport()->FindAutoCharStyle(aRIt->first)) + { + pStyle->FillPropertySet(xNewFmtStr); + } + + xNewFmtStr->setString(aRIt->second); + aStringVec.emplace_back(xNewFmtStr); + } + + uno::Sequence< Reference< chart2::XFormattedString > > aStringSeq = + comphelper::containerToSequence(aStringVec); + xTitleProp->setPropertyValue("FormattedStrings", uno::Any(aStringSeq)); + } + catch (const beans::UnknownPropertyException&) + { + SAL_WARN("xmloff.chart", "Property FormattedStrings for Title not available"); + } +} + void exportRangeToSomewhere( SvXMLExport& rExport, const OUString& rValue ) { //with issue #i366# and CWS chart20 ranges for error bars were introduced diff --git a/xmloff/source/chart/SchXMLTools.hxx b/xmloff/source/chart/SchXMLTools.hxx index 994308a19bc3..364c894c5634 100644 --- a/xmloff/source/chart/SchXMLTools.hxx +++ b/xmloff/source/chart/SchXMLTools.hxx @@ -38,6 +38,7 @@ namespace com::sun::star { class XMLPropStyleContext; class SvXMLStylesContext; class SvXMLExport; +class SvXMLImport; namespace SchXMLTools { @@ -98,6 +99,9 @@ namespace SchXMLTools css::uno::Any getPropertyFromContext( std::u16string_view rPropertyName, const XMLPropStyleContext * pPropStyleContext, const SvXMLStylesContext* pStylesCtxt ); void exportText( SvXMLExport& rExport, const OUString& rText, bool bConvertTabsLFs ); + void exportFormattedText( SvXMLExport& rExport, const css::uno::Reference< css::beans::XPropertySet >& xTitleProps ); + void importFormattedText( SvXMLImport& rImport, const std::vector<std::pair<OUString, OUString>>& rTitle, + const css::uno::Reference< css::beans::XPropertySet >& xTitleProp); void exportRangeToSomewhere( SvXMLExport& rExport, const OUString& rValue ); diff --git a/xmloff/source/chart/transporttypes.hxx b/xmloff/source/chart/transporttypes.hxx index 81d5de8cdb8a..b312af71cf38 100644 --- a/xmloff/source/chart/transporttypes.hxx +++ b/xmloff/source/chart/transporttypes.hxx @@ -103,7 +103,7 @@ struct SchXMLAxis enum SchXMLAxisDimension eDimension; sal_Int8 nAxisIndex;//0->primary axis; 1->secondary axis OUString aName; - OUString aTitle; + std::vector<std::pair<OUString, OUString>> maTitle; bool bHasCategories; SchXMLAxis() : eDimension( SCH_XML_AXIS_UNDEF ), nAxisIndex( 0 ), bHasCategories( false ) {}