tdf#50934: Add a pie-with-remainder-as-another-pie chart type
Implement ODF import/export for bar-of-pie and pie-of-pie types,
and add simple tests for this capability. The associated ODF tags
are implemented in the loext namespace. This also required changing
the schema.
Change-Id: Ib55ae1c5818ad810f7b962d807a9163a3d02ba17
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/164436
Tested-by: Jenkins
Reviewed-by: Noel Grandin <noel.grandin@collabora.co.uk>
diff --git a/chart2/qa/extras/chart2export.cxx b/chart2/qa/extras/chart2export.cxx
index b46bc77..86f2dee 100644
--- a/chart2/qa/extras/chart2export.cxx
+++ b/chart2/qa/extras/chart2export.cxx
@@ -18,6 +18,7 @@
#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/chart2/PieChartSubType.hpp>
using uno::Reference;
using beans::XPropertySet;
@@ -1132,6 +1133,58 @@ CPPUNIT_TEST_FIXTURE(Chart2ExportTest, testErrorBarDataRangeODS)
CPPUNIT_ASSERT_EQUAL(OUString("$Sheet1.$C$1:$C$3"), aNegRange);
}
CPPUNIT_TEST_FIXTURE(Chart2ExportTest, tdf50934_barOfPie)
{
loadFromFile(u"ods/tdf50934_barOfPie.ods");
saveAndReload("calc8");
uno::Reference< chart2::XChartDocument > xChartDoc = getChartDocFromSheet( 0, mxComponent );
CPPUNIT_ASSERT(xChartDoc.is());
Reference< chart2::XChartType > xChartType = getChartTypeFromDoc( xChartDoc, 0 );
CPPUNIT_ASSERT(xChartType.is());
CPPUNIT_ASSERT_EQUAL(u"com.sun.star.chart2.PieChartType"_ustr,
xChartType->getChartType());
// Verify that it saves and loads as bar-of-pie
Reference< chart2::XDiagram> xDia(xChartDoc->getFirstDiagram());
CPPUNIT_ASSERT(xDia.is());
uno::Reference< beans::XPropertySet > xDiaProp( xDia, uno::UNO_QUERY );
CPPUNIT_ASSERT(xDiaProp.is());
uno::Any aAny = xDiaProp->getPropertyValue("SubPieType");
CPPUNIT_ASSERT(aAny.hasValue());
chart2::PieChartSubType subPieType;
aAny >>= subPieType;
CPPUNIT_ASSERT_EQUAL(chart2::PieChartSubType_BAR, subPieType);
}
CPPUNIT_TEST_FIXTURE(Chart2ExportTest, tdf50934_pieOfPie)
{
loadFromFile(u"ods/tdf50934_pieOfPie.ods");
saveAndReload("calc8");
uno::Reference< chart2::XChartDocument > xChartDoc = getChartDocFromSheet( 0, mxComponent );
CPPUNIT_ASSERT(xChartDoc.is());
Reference< chart2::XChartType > xChartType = getChartTypeFromDoc( xChartDoc, 0 );
CPPUNIT_ASSERT(xChartType.is());
CPPUNIT_ASSERT_EQUAL(u"com.sun.star.chart2.PieChartType"_ustr,
xChartType->getChartType());
// Verify that it saves and loads as pie-of-pie
Reference< chart2::XDiagram> xDia(xChartDoc->getFirstDiagram());
CPPUNIT_ASSERT(xDia.is());
uno::Reference< beans::XPropertySet > xDiaProp( xDia, uno::UNO_QUERY );
CPPUNIT_ASSERT(xDiaProp.is());
uno::Any aAny = xDiaProp->getPropertyValue("SubPieType");
CPPUNIT_ASSERT(aAny.hasValue());
chart2::PieChartSubType subPieType;
aAny >>= subPieType;
CPPUNIT_ASSERT_EQUAL(chart2::PieChartSubType_PIE, subPieType);
}
CPPUNIT_TEST_FIXTURE(Chart2ExportTest, testChartCrash)
{
loadFromFile(u"docx/FDO75975.docx");
diff --git a/chart2/qa/extras/data/ods/tdf50934_barOfPie.ods b/chart2/qa/extras/data/ods/tdf50934_barOfPie.ods
new file mode 100644
index 0000000..d9b577a
--- /dev/null
+++ b/chart2/qa/extras/data/ods/tdf50934_barOfPie.ods
Binary files differ
diff --git a/chart2/qa/extras/data/ods/tdf50934_pieOfPie.ods b/chart2/qa/extras/data/ods/tdf50934_pieOfPie.ods
new file mode 100644
index 0000000..74a9f85
--- /dev/null
+++ b/chart2/qa/extras/data/ods/tdf50934_pieOfPie.ods
Binary files differ
diff --git a/chart2/source/controller/chartapiwrapper/DiagramWrapper.cxx b/chart2/source/controller/chartapiwrapper/DiagramWrapper.cxx
index 949aaa9..2917b98 100644
--- a/chart2/source/controller/chartapiwrapper/DiagramWrapper.cxx
+++ b/chart2/source/controller/chartapiwrapper/DiagramWrapper.cxx
@@ -465,6 +465,15 @@ OUString lcl_getDiagramType( std::u16string_view rTemplateServiceName )
if( aName.find( u"Area" ) != std::u16string_view::npos )
return "com.sun.star.chart.AreaDiagram";
// Handle bar-of-pie and pie-of-pie before simple pie
// "BarOfPie"
if( aName.find( u"BarOfPie" ) != std::u16string_view::npos )
return "com.sun.star.chart.BarOfPieDiagram";
// "PieOfPie"
if( aName.find( u"PieOfPie" ) != std::u16string_view::npos )
return "com.sun.star.chart.PieOfPieDiagram";
// "Pie" "PieAllExploded" "ThreeDPie" "ThreeDPieAllExploded"
if( aName.find( u"Pie" ) != std::u16string_view::npos )
return "com.sun.star.chart.PieDiagram";
diff --git a/chart2/source/inc/ChartType.hxx b/chart2/source/inc/ChartType.hxx
index fccafdb..fa55cf0 100644
--- a/chart2/source/inc/ChartType.hxx
+++ b/chart2/source/inc/ChartType.hxx
@@ -75,12 +75,6 @@ public:
// ____ XChartType ____
// still abstract ! implement !
virtual OUString SAL_CALL getChartType() override = 0;
#if 0
virtual ::com::sun::star::chart2::PieChartSubType SAL_CALL getPieChartSubType() override
{
return ::com::sun::star::chart2::PieChartSubType_NONE;
}
#endif
virtual css::uno::Reference< css::chart2::XCoordinateSystem > SAL_CALL
createCoordinateSystem( ::sal_Int32 DimensionCount ) final override;
virtual css::uno::Sequence< OUString > SAL_CALL
diff --git a/include/xmloff/xmltoken.hxx b/include/xmloff/xmltoken.hxx
index b6fa0dc..ce732e3 100644
--- a/include/xmloff/xmltoken.hxx
+++ b/include/xmloff/xmltoken.hxx
@@ -1909,7 +1909,10 @@ namespace xmloff::token {
XML_STYLES,
XML_STYLESHEET,
XML_SUB_TABLE,
XML_SUB_BAR,
XML_SUB_NONE,
XML_SUBJECT,
XML_SUB_PIE,
XML_SUBSET,
XML_SUBTITLE,
XML_SUBTOTAL_FIELD,
diff --git a/schema/libreoffice/OpenDocument-v1.3+libreoffice-schema.rng b/schema/libreoffice/OpenDocument-v1.3+libreoffice-schema.rng
index a68033d..b14c02b 100644
--- a/schema/libreoffice/OpenDocument-v1.3+libreoffice-schema.rng
+++ b/schema/libreoffice/OpenDocument-v1.3+libreoffice-schema.rng
@@ -2717,6 +2717,20 @@ xmlns:loext="urn:org:documentfoundation:names:experimental:office:xmlns:loext:1.
</rng:optional>
</rng:define>
<!-- TODO no proposal -->
<rng:define name="chart-chart-attlist" combine="interleave">
<rng:optional>
<rng:attribute name="loext:sub-bar">
<rng:ref name="boolean"/>
</rng:attribute>
</rng:optional>
<rng:optional>
<rng:attribute name="loext:sub-pie">
<rng:ref name="boolean"/>
</rng:attribute>
</rng:optional>
</rng:define>
<!-- OFFICE-2112, TODO half of this missing in proposal -->
<rng:define name="table-table-protection">
<rng:element name="loext:table-protection">
diff --git a/xmloff/source/chart/PropertyMap.hxx b/xmloff/source/chart/PropertyMap.hxx
index cd6370e..ec59875 100644
--- a/xmloff/source/chart/PropertyMap.hxx
+++ b/xmloff/source/chart/PropertyMap.hxx
@@ -42,6 +42,7 @@
#define XML_SCH_TYPE_LABEL_BORDER_STYLE ( XML_SCH_TYPES_START + 17 )
#define XML_SCH_TYPE_LABEL_BORDER_OPACITY ( XML_SCH_TYPES_START + 18 )
#define XML_SCH_TYPE_LABEL_FILL_STYLE ( XML_SCH_TYPES_START + 19 )
#define XML_SCH_TYPE_OF_PIE_TYPE ( XML_SCH_TYPES_START + 20 )
// context ids
#define XML_SCH_CONTEXT_USER_SYMBOL ( XML_SCH_CTF_START + 0 )
diff --git a/xmloff/source/chart/SchXMLChartContext.cxx b/xmloff/source/chart/SchXMLChartContext.cxx
index b2def8e3..9d5522f 100644
--- a/xmloff/source/chart/SchXMLChartContext.cxx
+++ b/xmloff/source/chart/SchXMLChartContext.cxx
@@ -231,7 +231,8 @@ SchXMLChartContext::SchXMLChartContext( SchXMLImportHelper& rImpHelper,
mbColHasLabels( false ),
mbRowHasLabels( false ),
meDataRowSource( chart::ChartDataRowSource_COLUMNS ),
mbIsStockChart( false )
mbIsStockChart( false ),
mPieSubType(com::sun::star::chart2::PieChartSubType_NONE)
{
}
@@ -317,6 +318,7 @@ void SchXMLChartContext::startFastElement( sal_Int32 /*nElement*/,
OUString sAutoStyleName;
OUString aOldChartTypeName;
bool bHasAddin = false;
mPieSubType = com::sun::star::chart2::PieChartSubType_NONE;
for( auto& aIter : sax_fastparser::castToFastAttributeList(xAttrList) )
{
@@ -385,6 +387,16 @@ void SchXMLChartContext::startFastElement( sal_Int32 /*nElement*/,
case XML_ELEMENT(CHART, XML_ROW_MAPPING):
msRowTrans = aIter.toString();
break;
case XML_ELEMENT(LO_EXT, XML_SUB_BAR):
if (aIter.toString().toBoolean()) {
mPieSubType = com::sun::star::chart2::PieChartSubType_BAR;
}
break;
case XML_ELEMENT(LO_EXT, XML_SUB_PIE):
if (aIter.toString().toBoolean()) {
mPieSubType = com::sun::star::chart2::PieChartSubType_PIE;
}
break;
default:
XMLOFF_WARN_UNKNOWN("xmloff", aIter);
}
@@ -752,6 +764,15 @@ void SchXMLChartContext::endFastElement(sal_Int32 )
// cleanup: remove empty chart type groups
lcl_removeEmptyChartTypeGroups( xNewDoc );
// Handle sub-pie type. Is this the right place to do this?
if (maChartTypeServiceName == "com.sun.star.chart2.PieChartType") {
Reference< chart2::XDiagram> xDia(xNewDoc->getFirstDiagram());
uno::Reference< beans::XPropertySet > xDiaProp( xDia, uno::UNO_QUERY );
if( xDiaProp.is()) {
xDiaProp->setPropertyValue("SubPieType", uno::Any(mPieSubType));
}
}
// set stack mode before a potential chart type detection (in case we have a rectangular range)
uno::Reference< chart::XDiagram > xDiagram( xDoc->getDiagram() );
uno::Reference< beans::XPropertySet > xDiaProp( xDiagram, uno::UNO_QUERY );
diff --git a/xmloff/source/chart/SchXMLChartContext.hxx b/xmloff/source/chart/SchXMLChartContext.hxx
index 40ba13e0..f79be55 100644
--- a/xmloff/source/chart/SchXMLChartContext.hxx
+++ b/xmloff/source/chart/SchXMLChartContext.hxx
@@ -23,6 +23,8 @@
#include <com/sun/star/chart/ChartDataRowSource.hpp>
#include <com/sun/star/awt/Size.hpp>
#include <com/sun/star/chart2/PieChartSubType.hpp>
#include "transporttypes.hxx"
#include <vector>
@@ -98,6 +100,7 @@ private:
bool mbRowHasLabels;
css::chart::ChartDataRowSource meDataRowSource;
bool mbIsStockChart;
com::sun::star::chart2::PieChartSubType mPieSubType;
OUString msCategoriesAddress;
OUString msChartAddress;
diff --git a/xmloff/source/chart/SchXMLExport.cxx b/xmloff/source/chart/SchXMLExport.cxx
index 4fb0227a..79238a5 100644
--- a/xmloff/source/chart/SchXMLExport.cxx
+++ b/xmloff/source/chart/SchXMLExport.cxx
@@ -1284,6 +1284,13 @@ void SchXMLExportHelper_Impl::parseDocument( Reference< chart::XChartDocument >
XML_NAMESPACE_CHART, GetXMLToken(eXMLChartType )) );
}
// Handle subtype for of-pie charts
if (sChartType == u"com.sun.star.chart.BarOfPieDiagram") {
mrExport.AddAttribute(XML_NAMESPACE_LO_EXT, XML_SUB_BAR, OUString::boolean(true));
} else if (sChartType == u"com.sun.star.chart.PieOfPieDiagram") {
mrExport.AddAttribute(XML_NAMESPACE_LO_EXT, XML_SUB_PIE, OUString::boolean(true));
}
//column-mapping or row-mapping
if( maSequenceMapping.hasElements() )
{
diff --git a/xmloff/source/chart/SchXMLTools.cxx b/xmloff/source/chart/SchXMLTools.cxx
index 120e361..4287b73 100644
--- a/xmloff/source/chart/SchXMLTools.cxx
+++ b/xmloff/source/chart/SchXMLTools.cxx
@@ -167,6 +167,10 @@ static const tMakeStringStringMap& lcl_getChartTypeNameMap()
"com.sun.star.chart2.ColumnChartType"},
{"com.sun.star.chart.PieDiagram",
"com.sun.star.chart2.PieChartType"},
{"com.sun.star.chart.BarOfPieDiagram",
"com.sun.star.chart2.BarOfPieChartType"},
{"com.sun.star.chart.PieOfPieDiagram",
"com.sun.star.chart2.PieOfPieChartType"},
{"com.sun.star.chart.DonutDiagram",
"com.sun.star.chart2.DonutChartType"},
{"com.sun.star.chart.XYDiagram",
@@ -304,7 +308,8 @@ XMLTokenEnum getTokenByChartType(
else if( aServiceName == u"Bar" ||
(!bUseOldNames && aServiceName == u"Column"))
eResult = XML_BAR;
else if ( aServiceName == u"Pie" )
else if ( aServiceName == u"Pie" || aServiceName == u"BarOfPie" ||
aServiceName == u"PieOfPie" )
eResult = XML_CIRCLE;
else if ( aServiceName == u"Donut" )
eResult = XML_RING;
diff --git a/xmloff/source/core/xmltoken.cxx b/xmloff/source/core/xmltoken.cxx
index 78ac150..3fb5874 100644
--- a/xmloff/source/core/xmltoken.cxx
+++ b/xmloff/source/core/xmltoken.cxx
@@ -1922,7 +1922,10 @@ namespace xmloff::token {
TOKEN( "styles", XML_STYLES ),
TOKEN( "stylesheet", XML_STYLESHEET ),
TOKEN( "sub-table", XML_SUB_TABLE ),
TOKEN( "sub-bar", XML_SUB_BAR ),
TOKEN( "sub-none", XML_SUB_NONE ),
TOKEN( "subject", XML_SUBJECT ),
TOKEN( "sub-pie", XML_SUB_PIE ),
TOKEN( "subset", XML_SUBSET ),
TOKEN( "subtitle", XML_SUBTITLE ),
TOKEN( "subtotal-field", XML_SUBTOTAL_FIELD ),
diff --git a/xmloff/source/token/tokens.txt b/xmloff/source/token/tokens.txt
index 882ad0e..5045d86 100644
--- a/xmloff/source/token/tokens.txt
+++ b/xmloff/source/token/tokens.txt
@@ -1822,7 +1822,10 @@ style-ref
styles
stylesheet
sub-table
sub-bar
sub-none
subject
sub-pie
subset
subtitle
subtotal-field