diff --git a/src/examples/src/org/apache/poi/xssf/usermodel/examples/ScatterChart.java b/src/examples/src/org/apache/poi/xssf/usermodel/examples/ScatterChart.java index 1747a7782..3df1d90ac 100644 --- a/src/examples/src/org/apache/poi/xssf/usermodel/examples/ScatterChart.java +++ b/src/examples/src/org/apache/poi/xssf/usermodel/examples/ScatterChart.java @@ -64,13 +64,13 @@ public class ScatterChart { ValueAxis bottomAxis = chart.getChartAxisFactory().createValueAxis(AxisPosition.BOTTOM); ValueAxis leftAxis = chart.getChartAxisFactory().createValueAxis(AxisPosition.LEFT); - ScatterChartSerie firstSerie = data.addSerie(); - firstSerie.setXValues(sheet, new CellRangeAddress(0, 0, 0, NUM_OF_COLUMNS - 1)); - firstSerie.setYValues(sheet, new CellRangeAddress(1, 1, 0, NUM_OF_COLUMNS - 1)); + DataMarker xMarker = new DataMarker(sheet, new CellRangeAddress(0, 0, 0, NUM_OF_COLUMNS - 1)); + DataMarker y1Marker = new DataMarker(sheet, new CellRangeAddress(1, 1, 0, NUM_OF_COLUMNS - 1)); + DataMarker y2Marker = new DataMarker(sheet, new CellRangeAddress(2, 2, 0, NUM_OF_COLUMNS - 1)); - ScatterChartSerie secondSerie = data.addSerie(); - secondSerie.setXValues(sheet, new CellRangeAddress(0, 0, 0, NUM_OF_COLUMNS - 1)); - secondSerie.setYValues(sheet, new CellRangeAddress(2, 2, 0, NUM_OF_COLUMNS - 1)); + + data.addSerie(xMarker, y1Marker); + data.addSerie(xMarker, y2Marker); chart.plot(data, bottomAxis, leftAxis); diff --git a/src/java/org/apache/poi/ss/usermodel/Chart.java b/src/java/org/apache/poi/ss/usermodel/Chart.java index 8c4198ef7..b14d95d10 100644 --- a/src/java/org/apache/poi/ss/usermodel/Chart.java +++ b/src/java/org/apache/poi/ss/usermodel/Chart.java @@ -22,6 +22,8 @@ import java.util.List; import org.apache.poi.ss.usermodel.charts.ChartData; import org.apache.poi.ss.usermodel.charts.ChartAxis; import org.apache.poi.ss.usermodel.charts.ChartLegend; +import org.apache.poi.ss.usermodel.charts.ManualLayout; +import org.apache.poi.ss.usermodel.charts.ManuallyPositionable; import org.apache.poi.ss.usermodel.charts.ChartDataFactory; import org.apache.poi.ss.usermodel.charts.ChartAxisFactory; @@ -30,7 +32,7 @@ import org.apache.poi.ss.usermodel.charts.ChartAxisFactory; * * @author Roman Kashitsyn */ -public interface Chart { +public interface Chart extends ManuallyPositionable { /** * @return an appropriate ChartDataFactory implementation diff --git a/src/java/org/apache/poi/ss/usermodel/charts/ChartAxis.java b/src/java/org/apache/poi/ss/usermodel/charts/ChartAxis.java index 034f4500d..6542f991b 100644 --- a/src/java/org/apache/poi/ss/usermodel/charts/ChartAxis.java +++ b/src/java/org/apache/poi/ss/usermodel/charts/ChartAxis.java @@ -101,7 +101,7 @@ public interface ChartAxis { AxisOrientation getOrientation(); /** - * @param axis orientation + * @param orientation axis orientation */ void setOrientation(AxisOrientation orientation); diff --git a/src/java/org/apache/poi/ss/usermodel/charts/ChartLegend.java b/src/java/org/apache/poi/ss/usermodel/charts/ChartLegend.java index 0975caf43..b870a773e 100644 --- a/src/java/org/apache/poi/ss/usermodel/charts/ChartLegend.java +++ b/src/java/org/apache/poi/ss/usermodel/charts/ChartLegend.java @@ -22,7 +22,7 @@ package org.apache.poi.ss.usermodel.charts; * * @author Roman Kashitsyn */ -public interface ChartLegend { +public interface ChartLegend extends ManuallyPositionable { /** * @return legend position @@ -33,5 +33,4 @@ public interface ChartLegend { * @param position new legend position */ void setPosition(LegendPosition position); - } diff --git a/src/java/org/apache/poi/ss/usermodel/charts/LayoutMode.java b/src/java/org/apache/poi/ss/usermodel/charts/LayoutMode.java new file mode 100644 index 000000000..87769701b --- /dev/null +++ b/src/java/org/apache/poi/ss/usermodel/charts/LayoutMode.java @@ -0,0 +1,35 @@ +/* ==================================================================== + Licensed to the Apache Software Foundation (ASF) under one or more + contributor license agreements. See the NOTICE file distributed with + this work for additional information regarding copyright ownership. + The ASF licenses this file to You under the Apache License, Version 2.0 + (the "License"); you may not use this file except in compliance with + the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +==================================================================== */ + +package org.apache.poi.ss.usermodel.charts; + +/** + * Specifies the possible ways to store a chart element's position. + * @author Roman Kashitsyn + */ +public enum LayoutMode { + /** + * Specifies that the Width or Height shall be interpreted as the + * Right or Bottom of the chart element. + */ + EDGE, + /** + * Specifies that the Width or Height shall be interpreted as the + * Width or Height of the chart element. + */ + FACTOR +} diff --git a/src/java/org/apache/poi/ss/usermodel/charts/LayoutTarget.java b/src/java/org/apache/poi/ss/usermodel/charts/LayoutTarget.java new file mode 100644 index 000000000..f95c5370f --- /dev/null +++ b/src/java/org/apache/poi/ss/usermodel/charts/LayoutTarget.java @@ -0,0 +1,39 @@ +/* ==================================================================== + Licensed to the Apache Software Foundation (ASF) under one or more + contributor license agreements. See the NOTICE file distributed with + this work for additional information regarding copyright ownership. + The ASF licenses this file to You under the Apache License, Version 2.0 + (the "License"); you may not use this file except in compliance with + the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +==================================================================== */ + +package org.apache.poi.ss.usermodel.charts; + +/** + * Specifies whether to layout the plot area by its inside (not including axis + * and axis labels) or outside (including axis and axis labels). + * + * @author Roman Kashitsyn + */ +public enum LayoutTarget { + /** + * Specifies that the plot area size shall determine the + * size of the plot area, not including the tick marks and + * axis labels. + */ + INNER, + /** + * Specifies that the plot area size shall determine the + * size of the plot area, the tick marks, and the axis + * labels. + */ + OUTER +} diff --git a/src/java/org/apache/poi/ss/usermodel/charts/ManualLayout.java b/src/java/org/apache/poi/ss/usermodel/charts/ManualLayout.java new file mode 100644 index 000000000..993ab3daf --- /dev/null +++ b/src/java/org/apache/poi/ss/usermodel/charts/ManualLayout.java @@ -0,0 +1,150 @@ +/* ==================================================================== + Licensed to the Apache Software Foundation (ASF) under one or more + contributor license agreements. See the NOTICE file distributed with + this work for additional information regarding copyright ownership. + The ASF licenses this file to You under the Apache License, Version 2.0 + (the "License"); you may not use this file except in compliance with + the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +==================================================================== */ + +package org.apache.poi.ss.usermodel.charts; + +/** + * High level representation of chart element manual layout. + * + * @author Roman Kashitsyn + */ +public interface ManualLayout { + + /** + * Sets the layout target. + * @param target new layout target. + */ + public void setTarget(LayoutTarget target); + + /** + * Returns current layout target. + * @return current layout target + */ + public LayoutTarget getTarget(); + + /** + * Sets the x-coordinate layout mode. + * @param mode new x-coordinate layout mode. + */ + public void setXMode(LayoutMode mode); + + /** + * Returns current x-coordinnate layout mode. + * @return current x-coordinate layout mode. + */ + public LayoutMode getXMode(); + + /** + * Sets the y-coordinate layout mode. + * @param mode new y-coordinate layout mode. + */ + public void setYMode(LayoutMode mode); + + /** + * Returns current y-coordinate layout mode. + * @return current y-coordinate layout mode. + */ + public LayoutMode getYMode(); + + /** + * Returns the x location of the chart element. + * @return the x location (left) of the chart element or 0.0 if + * not set. + */ + public double getX(); + + /** + * Specifies the x location (left) of the chart element as a + * fraction of the width of the chart. If Left Mode is Factor, + * then the position is relative to the default position for the + * chart element. + */ + public void setX(double x); + + + /** + * Returns current y location of the chart element. + * @return the y location (top) of the chart element or 0.0 if not + * set. + */ + public double getY(); + + /** + * Specifies the y location (top) of the chart element as a + * fraction of the height of the chart. If Top Mode is Factor, + * then the position is relative to the default position for the + * chart element. + */ + public void setY(double y); + + + /** + * Specifies how to interpret the Width element for this manual + * layout. + * @param mode new width layout mode of this manual layout. + */ + public void setWidthMode(LayoutMode mode); + + + /** + * Returns current width mode of this manual layout. + * @return width mode of this manual layout. + */ + public LayoutMode getWidthMode(); + + /** + * Specifies how to interpret the Height element for this manual + * layout. + * @param mode new height mode of this manual layout. + */ + public void setHeightMode(LayoutMode mode); + + /** + * Returns current height mode of this + * @return height mode of this manual layout. + */ + public LayoutMode getHeightMode(); + + /** + * Specifies the width (if Width Mode is Factor) or right (if + * Width Mode is Edge) of the chart element as a fraction of the + * width of the chart. + * @param ratio a fraction of the width of the chart. + */ + public void setWidthRatio(double ratio); + + /** + * Returns current fraction of the width of the chart. + * @return fraction of the width of the chart or 0.0 if not set. + */ + public double getWidthRatio(); + + /** + * Specifies the height (if Height Mode is Factor) or bottom (if + * Height Mode is edge) of the chart element as a fraction of the + * height of the chart. + * @param ratio a fraction of the height of the chart. + */ + public void setHeightRatio(double ratio); + + /** + * Returns current fraction of the height of the chart. + * @return fraction of the height of the chart or 0.0 if not set. + */ + public double getHeightRatio(); + +} diff --git a/src/java/org/apache/poi/ss/usermodel/charts/ManuallyPositionable.java b/src/java/org/apache/poi/ss/usermodel/charts/ManuallyPositionable.java new file mode 100644 index 000000000..03a85a4bc --- /dev/null +++ b/src/java/org/apache/poi/ss/usermodel/charts/ManuallyPositionable.java @@ -0,0 +1,33 @@ +/* ==================================================================== + Licensed to the Apache Software Foundation (ASF) under one or more + contributor license agreements. See the NOTICE file distributed with + this work for additional information regarding copyright ownership. + The ASF licenses this file to You under the Apache License, Version 2.0 + (the "License"); you may not use this file except in compliance with + the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +==================================================================== */ + +package org.apache.poi.ss.usermodel.charts; + +/** + * Abstraction of chart element that can be positioned with manual + * layout. + * + * @author Roman Kashitsyn + */ +public interface ManuallyPositionable { + + /** + * Returns manual layout for the chart element. + * @return manual layout for the chart element. + */ + public ManualLayout getManualLayout(); +} diff --git a/src/java/org/apache/poi/ss/usermodel/charts/ScatterChartData.java b/src/java/org/apache/poi/ss/usermodel/charts/ScatterChartData.java index 7f828d766..09e10048e 100644 --- a/src/java/org/apache/poi/ss/usermodel/charts/ScatterChartData.java +++ b/src/java/org/apache/poi/ss/usermodel/charts/ScatterChartData.java @@ -18,15 +18,20 @@ package org.apache.poi.ss.usermodel.charts; import java.util.List; +import org.apache.poi.ss.usermodel.Sheet; +import org.apache.poi.ss.util.DataMarker; + /** * @author Roman Kashitsyn */ public interface ScatterChartData extends ChartData { /** + * @param xMarker data marker to be used for X value range + * @param yMarker data marker to be used for Y value range * @return a new scatter chart serie */ - ScatterChartSerie addSerie(); + ScatterChartSerie addSerie(DataMarker xMarker, DataMarker yMarker); /** * @return list of all series diff --git a/src/java/org/apache/poi/ss/usermodel/charts/ScatterChartSerie.java b/src/java/org/apache/poi/ss/usermodel/charts/ScatterChartSerie.java index 274113b2d..16cef9c5f 100644 --- a/src/java/org/apache/poi/ss/usermodel/charts/ScatterChartSerie.java +++ b/src/java/org/apache/poi/ss/usermodel/charts/ScatterChartSerie.java @@ -18,7 +18,7 @@ package org.apache.poi.ss.usermodel.charts; import org.apache.poi.ss.usermodel.Sheet; -import org.apache.poi.ss.util.CellRangeAddress; +import org.apache.poi.ss.util.DataMarker; import org.apache.poi.ss.usermodel.charts.ChartDataFactory; /** @@ -27,15 +27,13 @@ import org.apache.poi.ss.usermodel.charts.ChartDataFactory; public interface ScatterChartSerie { /** - * @param sheet a sheet to take range from - * @param address a column or a row with values + * @param xMarker data marker to use for X values. */ - void setXValues(Sheet sheet, CellRangeAddress address); - + void setXValues(DataMarker xMarker); + /**' - * @param sheet a sheet to take range from - * @param address a column or a row with values + * @param yMarker data marker to use for Y values. */ - void setYValues(Sheet sheet, CellRangeAddress address); + void setYValues(DataMarker yMarker); } diff --git a/src/java/org/apache/poi/ss/util/DataMarker.java b/src/java/org/apache/poi/ss/util/DataMarker.java new file mode 100644 index 000000000..628a975aa --- /dev/null +++ b/src/java/org/apache/poi/ss/util/DataMarker.java @@ -0,0 +1,87 @@ +/* + * ==================================================================== + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ==================================================================== + */ + +package org.apache.poi.ss.util; + +import org.apache.poi.ss.usermodel.Sheet; + +/** + * Represents data marker used in charts. + * @author Roman Kashitsyn + */ +public class DataMarker { + + private Sheet sheet; + private CellRangeAddress range; + + /** + * @param sheet the sheet where data located. + * @param range the range within that sheet. + */ + public DataMarker(Sheet sheet, CellRangeAddress range) { + this.sheet = sheet; + this.range = range; + } + + /** + * Returns the sheet marker points to. + * @return sheet marker points to. + */ + public Sheet getSheet() { + return sheet; + } + + /** + * Sets sheet marker points to. + * @param sheet new sheet for the marker. + */ + public void setSheet(Sheet sheet) { + this.sheet = sheet; + } + + /** + * Returns range of the marker. + * @return range of cells marker points to. + */ + public CellRangeAddress getRange() { + return range; + } + + /** + * Sets range of the marker. + * @param range new range for the marker. + */ + public void setRange(CellRangeAddress range) { + this.range = range; + } + + /** + * Formats data marker using canonical format, for example + * `SheetName!$A$1:$A$5'. + * @return formatted data marker. + */ + public String formatAsString() { + String sheetName = (sheet == null) ? (null) : (sheet.getSheetName()); + if (range == null) { + return null; + } else { + return range.formatAsString(sheetName, true); + } + } +} diff --git a/src/ooxml/java/org/apache/poi/xssf/usermodel/XSSFChart.java b/src/ooxml/java/org/apache/poi/xssf/usermodel/XSSFChart.java index 2ecb018e7..eddf983b2 100644 --- a/src/ooxml/java/org/apache/poi/xssf/usermodel/XSSFChart.java +++ b/src/ooxml/java/org/apache/poi/xssf/usermodel/XSSFChart.java @@ -36,6 +36,7 @@ import org.apache.poi.ss.usermodel.charts.ChartAxisFactory; import org.apache.poi.xssf.usermodel.charts.XSSFChartDataFactory; import org.apache.poi.xssf.usermodel.charts.XSSFChartAxis; import org.apache.poi.xssf.usermodel.charts.XSSFValueAxis; +import org.apache.poi.xssf.usermodel.charts.XSSFManualLayout; import org.apache.poi.xssf.usermodel.charts.XSSFChartLegend; import org.apache.poi.ss.usermodel.charts.ChartData; import org.apache.poi.ss.usermodel.charts.AxisPosition; @@ -49,6 +50,7 @@ import org.openxmlformats.schemas.drawingml.x2006.chart.ChartSpaceDocument; import org.openxmlformats.schemas.drawingml.x2006.chart.CTLayout; import org.openxmlformats.schemas.drawingml.x2006.chart.CTManualLayout; import org.openxmlformats.schemas.drawingml.x2006.chart.CTPlotArea; +import org.openxmlformats.schemas.drawingml.x2006.chart.CTValAx; import org.openxmlformats.schemas.drawingml.x2006.chart.CTPrintSettings; import org.openxmlformats.schemas.drawingml.x2006.chart.CTPageMargins; import org.openxmlformats.schemas.drawingml.x2006.chart.STLayoutTarget; @@ -90,7 +92,7 @@ public final class XSSFChart extends POIXMLDocumentPart implements Chart, ChartA } /** - * Construct a SpreadsheetML chart from a package part + * Construct a SpreadsheetML chart from a package part. * * @param part the package part holding the chart data, * the content type must be application/vnd.openxmlformats-officedocument.drawingml.chart+xml @@ -105,7 +107,8 @@ public final class XSSFChart extends POIXMLDocumentPart implements Chart, ChartA } /** - * Construct a new CTChartSpace bean. By default, it's just an empty placeholder for chart objects + * Construct a new CTChartSpace bean. + * By default, it's just an empty placeholder for chart objects. * * @return a new CTChartSpace bean */ @@ -113,16 +116,10 @@ public final class XSSFChart extends POIXMLDocumentPart implements Chart, ChartA chartSpace = CTChartSpace.Factory.newInstance(); chart = chartSpace.addNewChart(); CTPlotArea plotArea = chart.addNewPlotArea(); - CTLayout layout = plotArea.addNewLayout(); - CTManualLayout manualLayout = layout.addNewManualLayout(); - manualLayout.addNewLayoutTarget().setVal(STLayoutTarget.INNER); - manualLayout.addNewXMode().setVal(STLayoutMode.EDGE); - manualLayout.addNewYMode().setVal(STLayoutMode.EDGE); - manualLayout.addNewX().setVal(0); - manualLayout.addNewY().setVal(0); - manualLayout.addNewW().setVal(0.65); - manualLayout.addNewH().setVal(0.8); + + plotArea.addNewLayout(); chart.addNewPlotVisOnly().setVal(true); + CTPrintSettings printSettings = chartSpace.addNewPrintSettings(); printSettings.addNewHeaderFooter(); @@ -220,39 +217,14 @@ public final class XSSFChart extends POIXMLDocumentPart implements Chart, ChartA } public List getAxis() { + if (axis.isEmpty() && hasAxis()) { + parseAxis(); + } return axis; } - /** - * Sets the width ratio of the chart. - * Chart width is ratio multiplied by parent frame width. - * @param ratio a number between 0 and 1. - */ - public void setWidthRatio(double ratio) { - chart.getPlotArea().getLayout().getManualLayout().getW().setVal(ratio); - } - - /** - * @return relative chart width - */ - public double getWidthRatio() { - return chart.getPlotArea().getLayout().getManualLayout().getW().getVal(); - } - - /** - * Sets the height ratio of the chart. - * Chart height is ratio multiplied by parent frame height. - * @param ratio a number between 0 and 1. - */ - public void setHeightRatio(double ratio) { - chart.getPlotArea().getLayout().getManualLayout().getH().setVal(ratio); - } - - /** - * @return relative chart height - */ - public double getHeightRatio() { - return chart.getPlotArea().getLayout().getManualLayout().getH().getVal(); + public XSSFManualLayout getManualLayout() { + return new XSSFManualLayout(this); } /** @@ -307,4 +279,25 @@ public final class XSSFChart extends POIXMLDocumentPart implements Chart, ChartA } } + private boolean hasAxis() { + CTPlotArea ctPlotArea = chart.getPlotArea(); + int totalAxisCount = + ctPlotArea.sizeOfValAxArray() + + ctPlotArea.sizeOfCatAxArray() + + ctPlotArea.sizeOfDateAxArray() + + ctPlotArea.sizeOfSerAxArray(); + return totalAxisCount > 0; + } + + private void parseAxis() { + // TODO: add other axis types + parseValueAxis(); + } + + private void parseValueAxis() { + for (CTValAx valAx : chart.getPlotArea().getValAxArray()) { + axis.add(new XSSFValueAxis(this, valAx)); + } + } + } diff --git a/src/ooxml/java/org/apache/poi/xssf/usermodel/charts/XSSFChartLegend.java b/src/ooxml/java/org/apache/poi/xssf/usermodel/charts/XSSFChartLegend.java index de4b415b2..112357349 100644 --- a/src/ooxml/java/org/apache/poi/xssf/usermodel/charts/XSSFChartLegend.java +++ b/src/ooxml/java/org/apache/poi/xssf/usermodel/charts/XSSFChartLegend.java @@ -75,6 +75,13 @@ public final class XSSFChartLegend implements ChartLegend { } } + public XSSFManualLayout getManualLayout() { + if (!legend.isSetLayout()) { + legend.addNewLayout(); + } + return new XSSFManualLayout(legend.getLayout()); + } + private STLegendPos.Enum fromLegendPosition(LegendPosition position) { switch (position) { case BOTTOM: return STLegendPos.B; diff --git a/src/ooxml/java/org/apache/poi/xssf/usermodel/charts/XSSFManualLayout.java b/src/ooxml/java/org/apache/poi/xssf/usermodel/charts/XSSFManualLayout.java new file mode 100644 index 000000000..81bf55a06 --- /dev/null +++ b/src/ooxml/java/org/apache/poi/xssf/usermodel/charts/XSSFManualLayout.java @@ -0,0 +1,246 @@ +/* ==================================================================== + Licensed to the Apache Software Foundation (ASF) under one or more + contributor license agreements. See the NOTICE file distributed with + this work for additional information regarding copyright ownership. + The ASF licenses this file to You under the Apache License, Version 2.0 + (the "License"); you may not use this file except in compliance with + the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + ==================================================================== */ + +package org.apache.poi.xssf.usermodel.charts; + +import org.apache.poi.util.Internal; +import org.apache.poi.ss.usermodel.charts.ManualLayout; +import org.apache.poi.ss.usermodel.charts.LayoutMode; +import org.apache.poi.ss.usermodel.charts.LayoutTarget; +import org.apache.poi.xssf.usermodel.XSSFChart; +import org.openxmlformats.schemas.drawingml.x2006.chart.STLayoutTarget; +import org.openxmlformats.schemas.drawingml.x2006.chart.CTLayout; +import org.openxmlformats.schemas.drawingml.x2006.chart.CTManualLayout; +import org.openxmlformats.schemas.drawingml.x2006.chart.CTPlotArea; +import org.openxmlformats.schemas.drawingml.x2006.chart.CTLayoutMode; +import org.openxmlformats.schemas.drawingml.x2006.chart.CTLayoutTarget; +import org.openxmlformats.schemas.drawingml.x2006.chart.STLayoutMode; +import org.openxmlformats.schemas.drawingml.x2006.chart.STLayoutTarget; + +/** + * Represents a SpreadsheetML manual layout. + * @author Roman Kashitsyn + */ +public final class XSSFManualLayout implements ManualLayout { + + /** + * Underlaying CTManualLayout bean. + */ + private CTManualLayout layout; + + private static final LayoutMode defaultLayoutMode = LayoutMode.EDGE; + private static final LayoutTarget defaultLayoutTarget = LayoutTarget.INNER; + + /** + * Create a new SpreadsheetML manual layout. + * @param layout a Spreadsheet ML layout that should be used as base. + */ + public XSSFManualLayout(CTLayout ctLayout) { + initLayout(ctLayout); + } + + /** + * Create a new SpreadsheetML manual layout for chart. + * @param chart a chart to create layout for. + */ + public XSSFManualLayout(XSSFChart chart) { + CTPlotArea ctPlotArea = chart.getCTChart().getPlotArea(); + CTLayout ctLayout = ctPlotArea.isSetLayout() ? + ctPlotArea.getLayout() : ctPlotArea.addNewLayout(); + + initLayout(ctLayout); + } + + /** + * Return the underlying CTManualLayout bean. + * + * @return the underlying CTManualLayout bean. + */ + @Internal public CTManualLayout getCTManualLayout(){ + return layout; + } + + public void setWidthRatio(double ratio) { + if (!layout.isSetW()) { + layout.addNewW(); + } + layout.getW().setVal(ratio); + } + + public double getWidthRatio() { + if (!layout.isSetW()) { + return 0.0; + } + return layout.getW().getVal(); + } + + public void setHeightRatio(double ratio) { + if (!layout.isSetH()) { + layout.addNewH(); + } + layout.getH().setVal(ratio); + } + + public double getHeightRatio() { + if (!layout.isSetH()) { + return 0.0; + } + return layout.getH().getVal(); + } + + public LayoutTarget getTarget() { + if (!layout.isSetLayoutTarget()) { + return defaultLayoutTarget; + } + return toLayoutTarget(layout.getLayoutTarget()); + } + + public void setTarget(LayoutTarget target) { + if (!layout.isSetLayoutTarget()) { + layout.addNewLayoutTarget(); + } + layout.getLayoutTarget().setVal(fromLayoutTarget(target)); + } + + public LayoutMode getXMode() { + if (!layout.isSetXMode()) { + return defaultLayoutMode; + } + return toLayoutMode(layout.getXMode()); + } + + public void setXMode(LayoutMode mode) { + if (!layout.isSetXMode()) { + layout.addNewXMode(); + } + layout.getXMode().setVal(fromLayoutMode(mode)); + } + + public LayoutMode getYMode() { + if (!layout.isSetYMode()) { + return defaultLayoutMode; + } + return toLayoutMode(layout.getYMode()); + } + + public void setYMode(LayoutMode mode) { + if (!layout.isSetYMode()) { + layout.addNewYMode(); + } + layout.getYMode().setVal(fromLayoutMode(mode)); + } + + public double getX() { + if (!layout.isSetX()) { + return 0.0; + } + return layout.getX().getVal(); + } + + public void setX(double x) { + if (!layout.isSetX()) { + layout.addNewX(); + } + layout.getX().setVal(x); + } + + public double getY() { + if (!layout.isSetY()) { + return 0.0; + } + return layout.getY().getVal(); + } + + public void setY(double y) { + if (!layout.isSetY()) { + layout.addNewY(); + } + layout.getY().setVal(y); + } + + public LayoutMode getWidthMode() { + if (!layout.isSetWMode()) { + return defaultLayoutMode; + } + return toLayoutMode(layout.getWMode()); + } + + public void setWidthMode(LayoutMode mode) { + if (!layout.isSetWMode()) { + layout.addNewWMode(); + } + layout.getWMode().setVal(fromLayoutMode(mode)); + } + + public LayoutMode getHeightMode() { + if (!layout.isSetHMode()) { + return defaultLayoutMode; + } + return toLayoutMode(layout.getHMode()); + } + + public void setHeightMode(LayoutMode mode) { + if (!layout.isSetHMode()) { + layout.addNewHMode(); + } + layout.getHMode().setVal(fromLayoutMode(mode)); + } + + private void initLayout(CTLayout ctLayout) { + if (ctLayout.isSetManualLayout()) { + this.layout = ctLayout.getManualLayout(); + } else { + this.layout = ctLayout.addNewManualLayout(); + } + } + + private STLayoutMode.Enum fromLayoutMode(LayoutMode mode) { + switch (mode) { + case EDGE: return STLayoutMode.EDGE; + case FACTOR: return STLayoutMode.FACTOR; + default: + throw new IllegalArgumentException(); + } + } + + private LayoutMode toLayoutMode(CTLayoutMode ctLayoutMode) { + switch (ctLayoutMode.getVal().intValue()) { + case STLayoutMode.INT_EDGE: return LayoutMode.EDGE; + case STLayoutMode.INT_FACTOR: return LayoutMode.FACTOR; + default: + throw new IllegalArgumentException(); + } + } + + private STLayoutTarget.Enum fromLayoutTarget(LayoutTarget target) { + switch (target) { + case INNER: return STLayoutTarget.INNER; + case OUTER: return STLayoutTarget.OUTER; + default: + throw new IllegalArgumentException(); + } + } + + private LayoutTarget toLayoutTarget(CTLayoutTarget ctLayoutTarget) { + switch (ctLayoutTarget.getVal().intValue()) { + case STLayoutTarget.INT_INNER: return LayoutTarget.INNER; + case STLayoutTarget.INT_OUTER: return LayoutTarget.OUTER; + default: + throw new IllegalArgumentException(); + } + } +} diff --git a/src/ooxml/java/org/apache/poi/xssf/usermodel/charts/XSSFScatterChartData.java b/src/ooxml/java/org/apache/poi/xssf/usermodel/charts/XSSFScatterChartData.java index d3f6b9626..42b2775f2 100644 --- a/src/ooxml/java/org/apache/poi/xssf/usermodel/charts/XSSFScatterChartData.java +++ b/src/ooxml/java/org/apache/poi/xssf/usermodel/charts/XSSFScatterChartData.java @@ -22,7 +22,7 @@ import java.util.ArrayList; import org.apache.poi.ss.usermodel.Chart; import org.apache.poi.ss.usermodel.Sheet; -import org.apache.poi.ss.util.CellRangeAddress; +import org.apache.poi.ss.util.DataMarker; import org.apache.poi.ss.usermodel.charts.ScatterChartData; import org.apache.poi.ss.usermodel.charts.ScatterChartSerie; import org.apache.poi.ss.usermodel.charts.ChartDataFactory; @@ -66,10 +66,8 @@ public class XSSFScatterChartData implements ScatterChartData { private int id; private int order; private boolean useCache; - private Sheet xSheet; - private Sheet ySheet; - private CellRangeAddress xAddress; - private CellRangeAddress yAddress; + private DataMarker xMarker; + private DataMarker yMarker; public Serie(int id, int order) { super(); @@ -78,14 +76,12 @@ public class XSSFScatterChartData implements ScatterChartData { this.useCache = false; } - public void setXValues(Sheet sheet, CellRangeAddress address) { - this.xSheet = sheet; - this.xAddress = address; + public void setXValues(DataMarker marker) { + xMarker = marker; } - public void setYValues(Sheet sheet, CellRangeAddress address) { - this.ySheet = sheet; - this.yAddress = address; + public void setYValues(DataMarker marker) { + yMarker = marker; } /** @@ -102,17 +98,19 @@ public class XSSFScatterChartData implements ScatterChartData { CTAxDataSource xVal = scatterSer.addNewXVal(); CTNumRef numRef = xVal.addNewNumRef(); - numRef.setF(xAddress.formatAsString(xSheet.getSheetName(), true)); + numRef.setF(xMarker.formatAsString()); CTNumDataSource yVal = scatterSer.addNewYVal(); numRef = yVal.addNewNumRef(); - numRef.setF(yAddress.formatAsString(ySheet.getSheetName(), true)); + numRef.setF(yMarker.formatAsString()); } } - public XSSFScatterChartData.Serie addSerie() { + public XSSFScatterChartData.Serie addSerie(DataMarker xMarker, DataMarker yMarker) { int numOfSeries = series.size(); Serie newSerie = new Serie(numOfSeries, numOfSeries); + newSerie.setXValues(xMarker); + newSerie.setYValues(yMarker); series.add(newSerie); return newSerie; } diff --git a/src/ooxml/java/org/apache/poi/xssf/usermodel/charts/XSSFValueAxis.java b/src/ooxml/java/org/apache/poi/xssf/usermodel/charts/XSSFValueAxis.java index 4ed5df2b9..1646db593 100644 --- a/src/ooxml/java/org/apache/poi/xssf/usermodel/charts/XSSFValueAxis.java +++ b/src/ooxml/java/org/apache/poi/xssf/usermodel/charts/XSSFValueAxis.java @@ -48,6 +48,11 @@ public class XSSFValueAxis extends XSSFChartAxis implements ValueAxis { createAxis(id, pos); } + public XSSFValueAxis(XSSFChart chart, CTValAx ctValAx) { + super(chart); + this.ctValAx = ctValAx; + } + public long getId() { return ctValAx.getAxId().getVal(); } diff --git a/src/ooxml/testcases/org/apache/poi/xssf/usermodel/charts/TestXSSFManualLayout.java b/src/ooxml/testcases/org/apache/poi/xssf/usermodel/charts/TestXSSFManualLayout.java new file mode 100644 index 000000000..cceceddff --- /dev/null +++ b/src/ooxml/testcases/org/apache/poi/xssf/usermodel/charts/TestXSSFManualLayout.java @@ -0,0 +1,104 @@ +/* ==================================================================== + Licensed to the Apache Software Foundation (ASF) under one or more + contributor license agreements. See the NOTICE file distributed with + this work for additional information regarding copyright ownership. + The ASF licenses this file to You under the Apache License, Version 2.0 + (the "License"); you may not use this file except in compliance with + the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +==================================================================== */ + +package org.apache.poi.xssf.usermodel.charts; + +import junit.framework.TestCase; + +import org.apache.poi.ss.usermodel.*; +import org.apache.poi.ss.usermodel.charts.ChartLegend; +import org.apache.poi.ss.usermodel.charts.LegendPosition; +import org.apache.poi.ss.usermodel.charts.ManualLayout; +import org.apache.poi.ss.usermodel.charts.LayoutMode; +import org.apache.poi.ss.usermodel.charts.LayoutTarget; +import org.apache.poi.xssf.usermodel.*; + +public final class TestXSSFManualLayout extends TestCase { + + /* + * Accessor methods are not trivial. They use lazy underlying bean + * initialization so there can be some errors (NPE, for example). + */ + public void testAccessorMethods() throws Exception { + final double newRatio = 1.1; + final double newCoordinate = 0.3; + final LayoutMode nonDefaultMode = LayoutMode.FACTOR; + final LayoutTarget nonDefaultTarget = LayoutTarget.OUTER; + + ManualLayout layout = getEmptyLayout(); + + layout.setWidthRatio(newRatio); + assertTrue(layout.getWidthRatio() == newRatio); + + layout.setHeightRatio(newRatio); + assertTrue(layout.getHeightRatio() == newRatio); + + layout.setX(newCoordinate); + assertTrue(layout.getX() == newCoordinate); + + layout.setY(newCoordinate); + assertTrue(layout.getY() == newCoordinate); + + layout.setXMode(nonDefaultMode); + assertTrue(layout.getXMode() == nonDefaultMode); + + layout.setYMode(nonDefaultMode); + assertTrue(layout.getYMode() == nonDefaultMode); + + layout.setWidthMode(nonDefaultMode); + assertTrue(layout.getWidthMode() == nonDefaultMode); + + layout.setHeightMode(nonDefaultMode); + assertTrue(layout.getHeightMode() == nonDefaultMode); + + layout.setTarget(nonDefaultTarget); + assertTrue(layout.getTarget() == nonDefaultTarget); + + } + + /* + * Layout must have reasonable default values and must not throw + * any exceptions. + */ + public void testDefaultValues() throws Exception { + ManualLayout layout = getEmptyLayout(); + + assertNotNull(layout.getTarget()); + assertNotNull(layout.getXMode()); + assertNotNull(layout.getYMode()); + assertNotNull(layout.getHeightMode()); + assertNotNull(layout.getWidthMode()); + /* + * According to interface, 0.0 should be returned for + * uninitialized double properties. + */ + assertTrue(layout.getX() == 0.0); + assertTrue(layout.getY() == 0.0); + assertTrue(layout.getWidthRatio() == 0.0); + assertTrue(layout.getHeightRatio() == 0.0); + } + + private ManualLayout getEmptyLayout() { + Workbook wb = new XSSFWorkbook(); + Sheet sheet = wb.createSheet(); + Drawing drawing = sheet.createDrawingPatriarch(); + ClientAnchor anchor = drawing.createAnchor(0, 0, 0, 0, 1, 1, 10, 30); + Chart chart = drawing.createChart(anchor); + ChartLegend legend = chart.getOrCreateLegend(); + return legend.getManualLayout(); + } +} diff --git a/src/ooxml/testcases/org/apache/poi/xssf/usermodel/charts/TestXSSFScatterChartData.java b/src/ooxml/testcases/org/apache/poi/xssf/usermodel/charts/TestXSSFScatterChartData.java index cd39a6917..852af700f 100644 --- a/src/ooxml/testcases/org/apache/poi/xssf/usermodel/charts/TestXSSFScatterChartData.java +++ b/src/ooxml/testcases/org/apache/poi/xssf/usermodel/charts/TestXSSFScatterChartData.java @@ -21,6 +21,7 @@ import junit.framework.TestCase; import org.apache.poi.xssf.usermodel.*; import org.apache.poi.ss.util.CellRangeAddress; +import org.apache.poi.ss.util.DataMarker; import org.apache.poi.ss.usermodel.charts.*; import org.apache.poi.xssf.usermodel.charts.XSSFChartDataFactory; @@ -39,9 +40,9 @@ public final class TestXSSFScatterChartData extends TestCase { ScatterChartData scatterChartData = XSSFChartDataFactory.getInstance().createScatterChartData(); - ScatterChartSerie serie = scatterChartData.addSerie(); - serie.setXValues(sheet, new CellRangeAddress(0,0,1,10)); - serie.setYValues(sheet, new CellRangeAddress(1,1,1,10)); + DataMarker xMarker = new DataMarker(sheet, new CellRangeAddress(0,0,1,10)); + DataMarker yMarker = new DataMarker(sheet, new CellRangeAddress(1,1,1,10)); + ScatterChartSerie serie = scatterChartData.addSerie(xMarker, yMarker); assertEquals(scatterChartData.getSeries().size(), 1);