[bug-63902] reference cloned sheet in cloned chart data series

git-svn-id: https://svn.apache.org/repos/asf/poi/trunk@1886605 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
Alain Béarez 2021-02-16 23:39:19 +00:00
parent 0df893124a
commit bcf413f68a
11 changed files with 375 additions and 176 deletions

View File

@ -42,9 +42,4 @@ public interface XDDFCategoryDataSource extends XDDFDataSource<String> {
default boolean isReference() {
return true;
}
@Override
default String getDataRangeReference() {
return getFormula();
}
}

View File

@ -124,10 +124,6 @@ public abstract class XDDFChart extends POIXMLDocumentPart implements TextContai
*/
protected final CTChartSpace chartSpace;
/**
* Chart element in the chart space
*/
protected final CTChart chart;
/**
* Construct a chart.
@ -136,8 +132,7 @@ public abstract class XDDFChart extends POIXMLDocumentPart implements TextContai
super();
chartSpace = CTChartSpace.Factory.newInstance();
chart = chartSpace.addNewChart();
chart.addNewPlotArea();
chartSpace.addNewChart().addNewPlotArea();
}
/**
@ -153,7 +148,6 @@ public abstract class XDDFChart extends POIXMLDocumentPart implements TextContai
super(part);
chartSpace = ChartSpaceDocument.Factory.parse(part.getInputStream(), DEFAULT_XML_OPTIONS).getChartSpace();
chart = chartSpace.getChart();
}
/**
@ -174,8 +168,7 @@ public abstract class XDDFChart extends POIXMLDocumentPart implements TextContai
*/
@Internal
public CTChart getCTChart() {
return chart;
return chartSpace.getChart();
}
/**
@ -185,7 +178,7 @@ public abstract class XDDFChart extends POIXMLDocumentPart implements TextContai
*/
@Internal
protected CTPlotArea getCTPlotArea() {
return chart.getPlotArea();
return getCTChart().getPlotArea();
}
/**
@ -199,8 +192,8 @@ public abstract class XDDFChart extends POIXMLDocumentPart implements TextContai
workbook.removeSheetAt(0);
workbook.createSheet();
}
chart.set(CTChart.Factory.newInstance());
chart.addNewPlotArea();
getCTChart().set(CTChart.Factory.newInstance());
getCTChart().addNewPlotArea();
}
/**
@ -208,8 +201,8 @@ public abstract class XDDFChart extends POIXMLDocumentPart implements TextContai
* otherwise
*/
public boolean isPlotOnlyVisibleCells() {
if (chart.isSetPlotVisOnly()) {
return chart.getPlotVisOnly().getVal();
if (getCTChart().isSetPlotVisOnly()) {
return getCTChart().getPlotVisOnly().getVal();
} else {
return false;
}
@ -221,40 +214,40 @@ public abstract class XDDFChart extends POIXMLDocumentPart implements TextContai
* the chart
*/
public void setPlotOnlyVisibleCells(boolean only) {
if (!chart.isSetPlotVisOnly()) {
chart.setPlotVisOnly(CTBoolean.Factory.newInstance());
if (!getCTChart().isSetPlotVisOnly()) {
getCTChart().setPlotVisOnly(CTBoolean.Factory.newInstance());
}
chart.getPlotVisOnly().setVal(only);
getCTChart().getPlotVisOnly().setVal(only);
}
public void setFloor(int thickness) {
if (!chart.isSetFloor()) {
chart.setFloor(CTSurface.Factory.newInstance());
if (!getCTChart().isSetFloor()) {
getCTChart().setFloor(CTSurface.Factory.newInstance());
}
chart.getFloor().getThickness().setVal(thickness);
getCTChart().getFloor().getThickness().setVal(thickness);
}
public void setBackWall(int thickness) {
if (!chart.isSetBackWall()) {
chart.setBackWall(CTSurface.Factory.newInstance());
if (!getCTChart().isSetBackWall()) {
getCTChart().setBackWall(CTSurface.Factory.newInstance());
}
chart.getBackWall().getThickness().setVal(thickness);
getCTChart().getBackWall().getThickness().setVal(thickness);
}
public void setSideWall(int thickness) {
if (!chart.isSetSideWall()) {
chart.setSideWall(CTSurface.Factory.newInstance());
if (!getCTChart().isSetSideWall()) {
getCTChart().setSideWall(CTSurface.Factory.newInstance());
}
chart.getSideWall().getThickness().setVal(thickness);
getCTChart().getSideWall().getThickness().setVal(thickness);
}
public void setAutoTitleDeleted(boolean deleted) {
if (!chart.isSetAutoTitleDeleted()) {
chart.setAutoTitleDeleted(CTBoolean.Factory.newInstance());
if (!getCTChart().isSetAutoTitleDeleted()) {
getCTChart().setAutoTitleDeleted(CTBoolean.Factory.newInstance());
}
chart.getAutoTitleDeleted().setVal(deleted);
if (deleted && chart.isSetTitle()) {
chart.unsetTitle();
getCTChart().getAutoTitleDeleted().setVal(deleted);
if (deleted && getCTChart().isSetTitle()) {
getCTChart().unsetTitle();
}
}
@ -264,14 +257,14 @@ public abstract class XDDFChart extends POIXMLDocumentPart implements TextContai
*/
public void displayBlanksAs(DisplayBlanks as) {
if (as == null){
if (chart.isSetDispBlanksAs()) {
chart.unsetDispBlanksAs();
if (getCTChart().isSetDispBlanksAs()) {
getCTChart().unsetDispBlanksAs();
}
} else {
if (chart.isSetDispBlanksAs()) {
chart.getDispBlanksAs().setVal(as.underlying);
if (getCTChart().isSetDispBlanksAs()) {
getCTChart().getDispBlanksAs().setVal(as.underlying);
} else {
chart.addNewDispBlanksAs().setVal(as.underlying);
getCTChart().addNewDispBlanksAs().setVal(as.underlying);
}
}
}
@ -280,8 +273,8 @@ public abstract class XDDFChart extends POIXMLDocumentPart implements TextContai
* @since 4.0.1
*/
public Boolean getTitleOverlay() {
if (chart.isSetTitle()) {
CTTitle title = chart.getTitle();
if (getCTChart().isSetTitle()) {
CTTitle title = getCTChart().getTitle();
if (title.isSetOverlay()) {
return title.getOverlay().getVal();
}
@ -293,10 +286,10 @@ public abstract class XDDFChart extends POIXMLDocumentPart implements TextContai
* @since 4.0.1
*/
public void setTitleOverlay(boolean overlay) {
if (!chart.isSetTitle()) {
chart.addNewTitle();
if (!getCTChart().isSetTitle()) {
getCTChart().addNewTitle();
}
new XDDFTitle(this, chart.getTitle()).setOverlay(overlay);
new XDDFTitle(this, getCTChart().getTitle()).setOverlay(overlay);
}
/**
@ -307,18 +300,18 @@ public abstract class XDDFChart extends POIXMLDocumentPart implements TextContai
* @since 4.0.1
*/
public void setTitleText(String text) {
if (!chart.isSetTitle()) {
chart.addNewTitle();
if (!getCTChart().isSetTitle()) {
getCTChart().addNewTitle();
}
new XDDFTitle(this, chart.getTitle()).setText(text);
new XDDFTitle(this, getCTChart().getTitle()).setText(text);
}
/**
* @since 4.0.1
*/
public XDDFTitle getTitle() {
if (chart.isSetTitle()) {
return new XDDFTitle(this, chart.getTitle());
if (getCTChart().isSetTitle()) {
return new XDDFTitle(this, getCTChart().getTitle());
} else {
return null;
}
@ -339,10 +332,10 @@ public abstract class XDDFChart extends POIXMLDocumentPart implements TextContai
*/
public XDDFView3D getOrAddView3D() {
CTView3D view3D;
if (chart.isSetView3D()) {
view3D = chart.getView3D();
if (getCTChart().isSetView3D()) {
view3D = getCTChart().getView3D();
} else {
view3D = chart.addNewView3D();
view3D = getCTChart().addNewView3D();
}
return new XDDFView3D(view3D);
}
@ -355,10 +348,10 @@ public abstract class XDDFChart extends POIXMLDocumentPart implements TextContai
*/
@Beta
public XDDFTextBody getFormattedTitle() {
if (!chart.isSetTitle()) {
if (!getCTChart().isSetTitle()) {
return null;
}
return new XDDFTitle(this, chart.getTitle()).getBody();
return new XDDFTitle(this, getCTChart().getTitle()).getBody();
}
@Override
@ -393,12 +386,12 @@ public abstract class XDDFChart extends POIXMLDocumentPart implements TextContai
}
public XDDFChartLegend getOrAddLegend() {
return new XDDFChartLegend(chart);
return new XDDFChartLegend(getCTChart());
}
public void deleteLegend() {
if (chart.isSetLegend()) {
chart.unsetLegend();
if (getCTChart().isSetLegend()) {
getCTChart().unsetLegend();
}
}
@ -418,7 +411,8 @@ public abstract class XDDFChart extends POIXMLDocumentPart implements TextContai
series.plot();
XDDFDataSource<?> categoryDS = series.getCategoryData();
XDDFNumericalDataSource<? extends Number> valuesDS = series.getValuesData();
if (categoryDS.isCellRange() || valuesDS.isCellRange()
if (categoryDS == null || valuesDS == null
|| categoryDS.isCellRange() || valuesDS.isCellRange()
|| categoryDS.isLiteral() || valuesDS.isLiteral()) {
// let's assume the data is already in the sheet
} else {
@ -910,7 +904,7 @@ public abstract class XDDFChart extends POIXMLDocumentPart implements TextContai
* @since POI 4.0.0
*/
public void importContent(XDDFChart other) {
this.chart.set(other.chart);
getCTChartSpace().set(other.getCTChartSpace());
}
/**
@ -1074,12 +1068,51 @@ public abstract class XDDFChart extends POIXMLDocumentPart implements TextContai
}
/**
* set chart index which can be use for relation part
* Set chart index which can be used for relation part.
*
* @param chartIndex
* chart index which can be use for relation part
* chart index which can be used for relation part.
*/
public void setChartIndex(int chartIndex) {
this.chartIndex = chartIndex;
}
/**
* Replace references to the sheet name in the data supporting the chart.
*
* @param newSheet
* sheet to be used in the data references.
*
* @since POI 5.0.1
*/
public void replaceReferences(XSSFSheet newSheet) {
for (XDDFChartData data : getChartSeries()) {
for (XDDFChartData.Series series : data.series) {
XDDFDataSource newCategory = series.categoryData;
XDDFNumericalDataSource newValues = series.valuesData;
try {
if (series.categoryData != null && series.categoryData.isReference()) {
String ref = series.categoryData.getDataRangeReference();
CellRangeAddress rangeAddress = CellRangeAddress.valueOf(ref.substring(ref.indexOf('!') + 1));
newCategory = series.categoryData.isNumeric()
? XDDFDataSourcesFactory.fromNumericCellRange(newSheet, rangeAddress)
: XDDFDataSourcesFactory.fromStringCellRange(newSheet, rangeAddress);
if (newCategory.isNumeric()) {
((XDDFNumericalDataSource) newCategory).setFormatCode(series.categoryData.getFormatCode());
}
}
if (series.valuesData!= null && series.valuesData.isReference()) {
String ref = series.valuesData.getDataRangeReference();
CellRangeAddress rangeAddress = CellRangeAddress.valueOf(ref.substring(ref.indexOf('!') + 1));
newValues = XDDFDataSourcesFactory.fromNumericCellRange(newSheet, rangeAddress);
newValues.setFormatCode(series.valuesData.getFormatCode());
}
} catch (IllegalArgumentException iae) {
// keep old values when cell range cannot be parsed
}
series.replaceData(newCategory, newValues);
series.plot();
}
}
}
}

View File

@ -162,12 +162,11 @@ public abstract class XDDFChartData {
}
public void replaceData(XDDFDataSource<?> category, XDDFNumericalDataSource<? extends Number> values) {
if (category == null || values == null) {
throw new IllegalStateException("Category and values must be defined before filling chart data.");
}
int numOfPoints = category.getPointCount();
if (numOfPoints != values.getPointCount()) {
throw new IllegalStateException("Category and values must have the same point count.");
if (categoryData != null && values != null) {
int numOfPoints = category.getPointCount();
if (numOfPoints != values.getPointCount()) {
throw new IllegalStateException("Category and values must have the same point count.");
}
}
this.categoryData = category;
this.valuesData = values;
@ -209,15 +208,19 @@ public abstract class XDDFChartData {
}
public void plot() {
if (categoryData.isNumeric()) {
CTNumData cache = retrieveNumCache(getAxDS(), categoryData);
categoryData.fillNumericalCache(cache);
} else {
CTStrData cache = retrieveStrCache(getAxDS(), categoryData);
categoryData.fillStringCache(cache);
if (categoryData != null) {
if (categoryData.isNumeric()) {
CTNumData cache = retrieveNumCache(getAxDS(), categoryData);
categoryData.fillNumericalCache(cache);
} else {
CTStrData cache = retrieveStrCache(getAxDS(), categoryData);
categoryData.fillStringCache(cache);
}
}
if (valuesData != null) {
CTNumData cache = retrieveNumCache(getNumDS(), valuesData);
valuesData.fillNumericalCache(cache);
}
CTNumData cache = retrieveNumCache(getNumDS(), valuesData);
valuesData.fillNumericalCache(cache);
}
/**

View File

@ -50,7 +50,9 @@ public interface XDDFDataSource<T> {
String getDataRangeReference();
String getFormula();
default String getFormula() {
return getDataRangeReference();
}
String getFormatCode();

View File

@ -42,7 +42,10 @@ public class XDDFDataSourcesFactory {
}
public static XDDFCategoryDataSource fromDataSource(final CTAxDataSource categoryDS) {
if (categoryDS.getStrRef() == null) {
if (categoryDS == null) {
return null;
}
if (categoryDS.getNumRef() != null && categoryDS.getNumRef().getNumCache() != null) {
return new XDDFCategoryDataSource() {
private CTNumData category = (CTNumData) categoryDS.getNumRef().getNumCache().copy();
private String formatCode = category.isSetFormatCode() ? category.getFormatCode() : null;
@ -58,7 +61,7 @@ public class XDDFDataSourcesFactory {
}
@Override
public String getFormula() {
public String getDataRangeReference() {
return categoryDS.getNumRef().getF();
}
@ -75,7 +78,7 @@ public class XDDFDataSourcesFactory {
@Override
public String getFormatCode() { return formatCode; }
};
} else {
} else if (categoryDS.getStrRef() != null && categoryDS.getStrRef().getStrCache() != null) {
return new XDDFCategoryDataSource() {
private CTStrData category = (CTStrData) categoryDS.getStrRef().getStrCache().copy();
@ -85,7 +88,7 @@ public class XDDFDataSourcesFactory {
}
@Override
public String getFormula() {
public String getDataRangeReference() {
return categoryDS.getStrRef().getF();
}
@ -102,64 +105,203 @@ public class XDDFDataSourcesFactory {
@Override
public String getFormatCode() { return null; }
};
} else if (categoryDS.getNumLit() != null) {
return new XDDFCategoryDataSource() {
private CTNumData category = (CTNumData) categoryDS.getNumLit().copy();
private String formatCode = category.isSetFormatCode() ? category.getFormatCode() : null;
@Override
public boolean isCellRange() {
return false;
}
@Override
public boolean isLiteral() {
return true;
}
@Override
public boolean isNumeric() {
return true;
}
@Override
public boolean isReference() {
return false;
}
@Override
public String getDataRangeReference() {
return null;
}
@Override
public int getPointCount() {
return (int) category.getPtCount().getVal();
}
@Override
public String getPointAt(int index) {
return category.getPtArray(index).getV();
}
@Override
public String getFormatCode() { return formatCode; }
};
} else if (categoryDS.getStrLit() != null) {
return new XDDFCategoryDataSource() {
private CTStrData category = (CTStrData) categoryDS.getStrLit().copy();
@Override
public boolean isCellRange() {
return false;
}
@Override
public boolean isLiteral() {
return true;
}
@Override
public boolean isReference() {
return false;
}
@Override
public String getDataRangeReference() {
return null;
}
@Override
public int getPointCount() {
return (int) category.getPtCount().getVal();
}
@Override
public String getPointAt(int index) {
return category.getPtArray(index).getV();
}
@Override
public String getFormatCode() { return null; }
};
} else {
return null; // in some weird cases the element is empty
}
}
public static XDDFNumericalDataSource<Double> fromDataSource(final CTNumDataSource valuesDS) {
return new XDDFNumericalDataSource<Double>() {
private CTNumData values = (CTNumData) valuesDS.getNumRef().getNumCache().copy();
private String formatCode = values.isSetFormatCode() ? values.getFormatCode() : null;
if (valuesDS == null) {
return null;
}
if (valuesDS.getNumRef() != null && valuesDS.getNumRef().getNumCache() != null) {
return new XDDFNumericalDataSource<Double>() {
private CTNumData values = (CTNumData) valuesDS.getNumRef().getNumCache().copy();
private String formatCode = values.isSetFormatCode() ? values.getFormatCode() : null;
@Override
public String getFormula() {
return valuesDS.getNumRef().getF();
}
@Override
public String getFormatCode() {
return formatCode;
}
@Override
public String getFormatCode() {
return formatCode;
}
@Override
public void setFormatCode(String formatCode) {
this.formatCode = formatCode;
}
@Override
public void setFormatCode(String formatCode) {
this.formatCode = formatCode;
}
@Override
public boolean isCellRange() {
return true;
}
@Override
public boolean isCellRange() {
return true;
}
@Override
public boolean isNumeric() {
return true;
}
@Override
public boolean isNumeric() {
return true;
}
@Override
public boolean isReference() {
return true;
}
@Override
public boolean isReference() {
return true;
}
@Override
public int getPointCount() {
return (int) values.getPtCount().getVal();
}
@Override
public int getPointCount() {
return (int) values.getPtCount().getVal();
}
@Override
public Double getPointAt(int index) {
return Double.valueOf(values.getPtArray(index).getV());
}
@Override
public Double getPointAt(int index) {
return Double.valueOf(values.getPtArray(index).getV());
}
@Override
public String getDataRangeReference() {
return valuesDS.getNumRef().getF();
}
@Override
public String getDataRangeReference() {
return valuesDS.getNumRef().getF();
}
@Override
public int getColIndex() {
return 0;
}
};
} else if (valuesDS.getNumLit() != null) {
return new XDDFNumericalDataSource<Double>() {
private CTNumData values = (CTNumData) valuesDS.getNumLit().copy();
private String formatCode = values.isSetFormatCode() ? values.getFormatCode() : null;
@Override
public int getColIndex() {
return 0;
}
};
@Override
public String getFormatCode() {
return formatCode;
}
@Override
public void setFormatCode(String formatCode) {
this.formatCode = formatCode;
}
@Override
public boolean isCellRange() {
return false;
}
@Override
public boolean isLiteral() {
return true;
}
@Override
public boolean isNumeric() {
return true;
}
@Override
public boolean isReference() {
return false;
}
@Override
public int getPointCount() {
return (int) values.getPtCount().getVal();
}
@Override
public Double getPointAt(int index) {
return Double.valueOf(values.getPtArray(index).getV());
}
@Override
public String getDataRangeReference() {
return null;
}
@Override
public int getColIndex() {
return 0;
}
};
} else {
return null; // in some weird cases the element is empty
}
}
public static <T extends Number> XDDFNumericalDataSource<T> fromArray(T[] elements) {
@ -264,11 +406,6 @@ public class XDDFDataSourcesFactory {
super(elements, dataRange, col);
}
@Override
public String getFormula() {
return getDataRangeReference();
}
@Override
public String getFormatCode() {
return formatCode;
@ -290,11 +427,6 @@ public class XDDFDataSourcesFactory {
super(elements, dataRange, col);
}
@Override
public String getFormula() {
return getDataRangeReference();
}
@Override
public String getFormatCode() { return null; }
}
@ -382,11 +514,6 @@ public class XDDFDataSourcesFactory {
super(sheet, cellRangeAddress);
}
@Override
public String getFormula() {
return getDataRangeReference();
}
private String formatCode;
@Override
@ -421,11 +548,6 @@ public class XDDFDataSourcesFactory {
super(sheet, cellRangeAddress);
}
@Override
public String getFormula() {
return getDataRangeReference();
}
@Override
public String getPointAt(int index) {
CellValue cellValue = getCellValueAt(index);

View File

@ -84,10 +84,10 @@ public final class XSLFChart extends XDDFChart {
}
public XSLFTextShape getTitleShape() {
if (!chart.isSetTitle()) {
chart.addNewTitle();
if (!getCTChart().isSetTitle()) {
getCTChart().addNewTitle();
}
final CTTitle title = chart.getTitle();
final CTTitle title = getCTChart().getTitle();
if (title.getTx() != null && title.getTx().isSetRich()) {
return new XSLFTextShape(title, null) {
@Override

View File

@ -91,7 +91,7 @@ public final class XSSFChart extends XDDFChart {
CTPlotArea plotArea = getCTPlotArea();
plotArea.addNewLayout();
chart.addNewPlotVisOnly().setVal(true);
getCTChart().addNewPlotVisOnly().setVal(true);
CTPrintSettings printSettings = chartSpace.addNewPrintSettings();
printSettings.addNewHeaderFooter();
@ -154,12 +154,12 @@ public final class XSSFChart extends XDDFChart {
* if the title text is empty or the title uses a formula instead
*/
public XSSFRichTextString getTitleText() {
if (!chart.isSetTitle()) {
if (!getCTChart().isSetTitle()) {
return null;
}
// TODO Do properly
CTTitle title = chart.getTitle();
CTTitle title = getCTChart().getTitle();
StringBuilder text = new StringBuilder(64);
XmlObject[] t = title.selectPath("declare namespace a='" + XSSFDrawing.NAMESPACE_A + "' .//a:t");
@ -183,11 +183,11 @@ public final class XSSFChart extends XDDFChart {
* @return formula expression or null
*/
public String getTitleFormula() {
if (!chart.isSetTitle()) {
if (!getCTChart().isSetTitle()) {
return null;
}
CTTitle title = chart.getTitle();
CTTitle title = getCTChart().getTitle();
if (!title.isSetTx()) {
return null;
@ -209,10 +209,10 @@ public final class XSSFChart extends XDDFChart {
*/
public void setTitleFormula(String formula) {
CTTitle ctTitle;
if (chart.isSetTitle()) {
ctTitle = chart.getTitle();
if (getCTChart().isSetTitle()) {
ctTitle = getCTChart().getTitle();
} else {
ctTitle = chart.addNewTitle();
ctTitle = getCTChart().addNewTitle();
}
CTTx tx;

View File

@ -229,10 +229,7 @@ public final class XSSFDrawing extends POIXMLDocumentPart implements Drawing<XSS
* @see org.apache.poi.xssf.usermodel.XSSFDrawing#createChart(ClientAnchor)
*/
public XSSFChart createChart(XSSFClientAnchor anchor) {
int chartNumber = getPackagePart().getPackage().getPartsByContentType(XSSFRelation.CHART.getContentType())
.size() + 1;
RelationPart rp = createRelationship(XSSFRelation.CHART, XSSFFactory.getInstance(), chartNumber, false);
RelationPart rp = createChartRelationPart();
XSSFChart chart = rp.getDocumentPart();
String chartRelId = rp.getRelationship().getId();
@ -243,6 +240,13 @@ public final class XSSFDrawing extends POIXMLDocumentPart implements Drawing<XSS
return chart;
}
protected RelationPart createChartRelationPart() {
int chartNumber = getPackagePart().getPackage().getPartsByContentType(XSSFRelation.CHART.getContentType())
.size() + 1;
return createRelationship(XSSFRelation.CHART, XSSFFactory.getInstance(), chartNumber, false);
}
/**
* Creates a chart.
*
@ -271,7 +275,7 @@ public final class XSSFDrawing extends POIXMLDocumentPart implements Drawing<XSS
XSSFClientAnchor destAnchor = new XSSFClientAnchor(from, to);
destAnchor.setAnchorType(ClientAnchor.AnchorType.MOVE_AND_RESIZE);
XSSFChart destChart = createChart(destAnchor);
destChart.getCTChart().set(srcChart.getCTChartSpace().getChart().copy());
destChart.getCTChartSpace().set(srcChart.getCTChartSpace().copy());
return destChart;
}

View File

@ -671,9 +671,18 @@ public class XSSFWorkbook extends POIXMLDocument implements Workbook, Date1904Su
clonedDg.getCTDrawing().set(dg.getCTDrawing().copy());
// Clone drawing relations
List<RelationPart> srcRels = srcSheet.createDrawingPatriarch().getRelationParts();
List<RelationPart> srcRels = srcSheet.getDrawingPatriarch().getRelationParts();
for (RelationPart rp : srcRels) {
addRelation(rp, clonedDg);
POIXMLDocumentPart r = rp.getDocumentPart();
if (r instanceof XSSFChart) {
// Replace chart relation part with new relationship, cloning the chart's content
RelationPart chartPart = clonedDg.createChartRelationPart();
XSSFChart chart = chartPart.getDocumentPart();
chart.importContent((XSSFChart)r);
chart.replaceReferences(clonedSheet);
} else {
addRelation(rp, clonedDg);
}
}
}
return clonedSheet;

View File

@ -18,14 +18,16 @@
package org.apache.poi.xssf;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNotEquals;
import static org.junit.jupiter.api.Assertions.assertNotNull;
import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.junit.jupiter.api.Assertions.fail;
import org.apache.poi.hssf.HSSFITestDataProvider;
import org.apache.poi.ss.usermodel.BaseTestCloneSheet;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.ss.usermodel.Workbook;
import org.apache.poi.xddf.usermodel.chart.XDDFDataSource;
import org.apache.poi.xssf.usermodel.XSSFDrawing;
import org.apache.poi.xssf.usermodel.XSSFSheet;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.junit.jupiter.api.BeforeEach;
@ -87,4 +89,33 @@ class TestXSSFCloneSheet extends BaseTestCloneSheet {
assertNotNull(source_sh);
}
}
@Test
void testBug63902() throws IOException {
try (XSSFWorkbook workbook = XSSFTestDataSamples.openSampleWorkbook("chartTitle_withTitle.xlsx")) {
XSSFSheet sheet = workbook.getSheetAt(0);
XSSFDrawing drawing = sheet.getDrawingPatriarch();
assertEquals(1, drawing.getCharts().size());
XSSFSheet sheet2 = workbook.cloneSheet(0, "Sheet 2");
XSSFDrawing drawing2 = sheet2.getDrawingPatriarch();
assertEquals(1, drawing2.getCharts().size());
assertEquals("Sheet 2", sheet2.getSheetName());
XDDFDataSource<?> data = drawing.getCharts().get(0).getChartSeries().get(0).getSeries(0).getCategoryData();
XDDFDataSource<?> data2 = drawing2.getCharts().get(0).getChartSeries().get(0).getSeries(0).getCategoryData();
assertNotEquals(data.getFormula(), data2.getFormula());
assertEquals(sheet.getSheetName(), data.getFormula().substring(0, data.getFormula().indexOf('!')));
assertEquals("'Sheet 2'", data2.getFormula().substring(0, data2.getFormula().indexOf('!')));
assertEquals(
data.getFormula().substring(data.getFormula().indexOf('!')),
data2.getFormula().substring(data2.getFormula().indexOf('!'))
);
Workbook wbBack = XSSFTestDataSamples.writeOutAndReadBack(workbook, "poi_cloned_sheet_with_chart");
assertNotNull(wbBack);
wbBack.close();
}
}
}

View File

@ -914,19 +914,19 @@ class TestXSSFDrawing {
}
@Test
void testBug63901() {
XSSFWorkbook workbook = XSSFTestDataSamples.openSampleWorkbook("chartTitle_withTitle.xlsx");
XSSFSheet sheet = workbook.getSheet("Sheet1");
XSSFDrawing drawing = sheet.createDrawingPatriarch();
assert(drawing.getCharts().size() > 0);
void testBug63901() throws IOException {
try (XSSFWorkbook workbook = XSSFTestDataSamples.openSampleWorkbook("chartTitle_withTitle.xlsx")) {
XSSFSheet sheet = workbook.getSheetAt(0);
XSSFDrawing drawing = sheet.getDrawingPatriarch();
assertEquals(1, drawing.getCharts().size());
XSSFWorkbook workbook2 = new XSSFWorkbook();
XSSFSheet sheet2 = workbook2.createSheet();
XSSFDrawing drawing2 = sheet2.createDrawingPatriarch();
XSSFWorkbook workbook2 = new XSSFWorkbook();
XSSFSheet sheet2 = workbook2.createSheet();
XSSFDrawing drawing2 = sheet2.createDrawingPatriarch();
drawing.getCharts().forEach(drawing2::importChart);
assertEquals(drawing.getCharts().size(), drawing2.getCharts().size());
drawing.getCharts().forEach(drawing2::importChart);
assertEquals(1, drawing2.getCharts().size());
}
}
private static void checkRewrite(XSSFWorkbook wb) throws IOException {