mirror of https://github.com/apache/poi.git
[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:
parent
0df893124a
commit
bcf413f68a
|
@ -42,9 +42,4 @@ public interface XDDFCategoryDataSource extends XDDFDataSource<String> {
|
|||
default boolean isReference() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
default String getDataRangeReference() {
|
||||
return getFormula();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -50,7 +50,9 @@ public interface XDDFDataSource<T> {
|
|||
|
||||
String getDataRangeReference();
|
||||
|
||||
String getFormula();
|
||||
default String getFormula() {
|
||||
return getDataRangeReference();
|
||||
}
|
||||
|
||||
String getFormatCode();
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -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 {
|
||||
|
|
Loading…
Reference in New Issue