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.stahl@allotropia.de>
Tested-by: Jenkins
Reviewed-by: Balazs Varga <balazs.varga.extern@allotropia.de>
This commit is contained in:
Balazs Varga
2024-04-15 13:39:03 +02:00
parent 176406a07e
commit d7214aba95
14 changed files with 491 additions and 125 deletions

View File

@ -10,6 +10,9 @@
#include "charttest.hxx"
#include <com/sun/star/chart2/DataPointLabel.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;
@ -432,11 +435,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");
}
@ -447,13 +456,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");
}
@ -600,8 +615,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");
@ -812,6 +827,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\n", "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: */

Binary file not shown.

View File

@ -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 );
}

View File

@ -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 );

View File

@ -1155,13 +1155,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
@ -1452,7 +1448,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

View File

@ -552,26 +552,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(
@ -583,7 +575,7 @@ css::uno::Reference< css::xml::sax::XFastContextHandler > SchXMLAxisContext::cre
case XML_ELEMENT(CHART, XML_TITLE):
{
return new SchXMLTitleContext( m_rImportHelper, GetImport(),
m_aCurrentAxis.aTitle,
m_aCurrentAxis.maTitle,
getTitleShape() );
}
break;

View File

@ -729,37 +729,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);
}
}
@ -1181,7 +1160,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 ),
@ -1247,7 +1226,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);

View File

@ -91,7 +91,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;
@ -130,14 +130,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;

View File

@ -208,6 +208,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 );
@ -276,6 +278,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;
@ -1322,15 +1325,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 );
@ -1341,19 +1343,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();
@ -1363,16 +1358,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 );
@ -1383,19 +1377,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();
@ -2266,11 +2253,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 );
@ -2279,11 +2261,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();
}
@ -3827,6 +3810,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() )
@ -3843,6 +3847,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)

View File

@ -101,4 +101,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: */

View File

@ -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: */

View File

@ -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>
@ -605,6 +608,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

View File

@ -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 );

View File

@ -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 ) {}