ASF Bugzilla – Attachment 27445 Details for
Bug 51196
[PATCH] Patch to simplify XSSFChart creation
Home
|
New
|
Browse
|
Search
|
[?]
|
Reports
|
Help
|
New Account
|
Log In
Remember
[x]
|
Forgot Password
Login:
[x]
[patch]
patch with ChartDataSource strategy implementation
dataSources.patch (text/plain), 66.96 KB, created by
Roman Kashitsyn
on 2011-08-29 06:23:52 UTC
(
hide
)
Description:
patch with ChartDataSource strategy implementation
Filename:
MIME Type:
Creator:
Roman Kashitsyn
Created:
2011-08-29 06:23:52 UTC
Size:
66.96 KB
patch
obsolete
>Index: src/testcases/org/apache/poi/ss/util/TestSheetBuilder.java >=================================================================== >--- src/testcases/org/apache/poi/ss/util/TestSheetBuilder.java (revision 1148642) >+++ src/testcases/org/apache/poi/ss/util/TestSheetBuilder.java (revision ) >@@ -29,49 +29,56 @@ > > /** > * Tests SheetBuilder. >+ * > * @see org.apache.poi.ss.util.SheetBuilder > */ > public final class TestSheetBuilder extends TestCase { >- >+ >- private static Object[][] testData = new Object[][] { >+ private static Object[][] testData = new Object[][]{ >- { 1, 2, 3}, >+ {1, 2, 3}, >- {new Date(), null, null}, >+ {new Date(), null, null}, >- { "one", "two", "=A1+B2"} >+ {"one", "two", "=A1+B2"} > }; > > public void testNotCreateEmptyCells() { >- Workbook wb = new HSSFWorkbook(); >- Sheet sheet = new SheetBuilder(wb, testData).build(); >- >- assertEquals(sheet.getPhysicalNumberOfRows(), 3); >+ Workbook wb = new HSSFWorkbook(); >+ Sheet sheet = new SheetBuilder(wb, testData).build(); >+ >+ assertEquals(sheet.getPhysicalNumberOfRows(), 3); > >- Row firstRow = sheet.getRow(0); >- Cell firstCell = firstRow.getCell(0); >+ Row firstRow = sheet.getRow(0); >+ Cell firstCell = firstRow.getCell(0); > >- assertEquals(firstCell.getCellType(), Cell.CELL_TYPE_NUMERIC); >- assertEquals(1.0, firstCell.getNumericCellValue(), 0.00001); >- >+ assertEquals(firstCell.getCellType(), Cell.CELL_TYPE_NUMERIC); >+ assertEquals(1.0, firstCell.getNumericCellValue(), 0.00001); >+ > >- Row secondRow = sheet.getRow(1); >- assertNotNull(secondRow.getCell(0)); >- assertNull(secondRow.getCell(2)); >+ Row secondRow = sheet.getRow(1); >+ assertNotNull(secondRow.getCell(0)); >+ assertNull(secondRow.getCell(2)); > >- Row thirdRow = sheet.getRow(2); >- assertEquals(Cell.CELL_TYPE_STRING, thirdRow.getCell(0).getCellType()); >- String cellValue = thirdRow.getCell(0).getStringCellValue(); >- assertEquals(testData[2][0].toString(), cellValue); >- >- assertEquals(Cell.CELL_TYPE_FORMULA, thirdRow.getCell(2).getCellType()); >- assertEquals("A1+B2", thirdRow.getCell(2).getCellFormula()); >+ Row thirdRow = sheet.getRow(2); >+ assertEquals(Cell.CELL_TYPE_STRING, thirdRow.getCell(0).getCellType()); >+ String cellValue = thirdRow.getCell(0).getStringCellValue(); >+ assertEquals(testData[2][0].toString(), cellValue); >+ >+ assertEquals(Cell.CELL_TYPE_FORMULA, thirdRow.getCell(2).getCellType()); >+ assertEquals("A1+B2", thirdRow.getCell(2).getCellFormula()); > } > > public void testEmptyCells() { >- Workbook wb = new HSSFWorkbook(); >- Sheet sheet = new SheetBuilder(wb, testData).setCreateEmptyCells(true).build(); >- >- Cell emptyCell = sheet.getRow(1).getCell(1); >- assertNotNull(emptyCell); >- assertEquals(Cell.CELL_TYPE_BLANK, emptyCell.getCellType()); >+ Workbook wb = new HSSFWorkbook(); >+ Sheet sheet = new SheetBuilder(wb, testData).setCreateEmptyCells(true).build(); >+ >+ Cell emptyCell = sheet.getRow(1).getCell(1); >+ assertNotNull(emptyCell); >+ assertEquals(Cell.CELL_TYPE_BLANK, emptyCell.getCellType()); > } > >+ public void testSheetName() { >+ final String sheetName = "TEST SHEET NAME"; >+ Workbook wb = new HSSFWorkbook(); >+ Sheet sheet = new SheetBuilder(wb, testData).setSheetName(sheetName).build(); >+ assertEquals(sheetName, sheet.getSheetName()); >-} >\ No newline at end of file >+ } >+} >\ No newline at end of file >Index: src/ooxml/java/org/apache/poi/xssf/usermodel/charts/XSSFNumberCache.java >=================================================================== >--- src/ooxml/java/org/apache/poi/xssf/usermodel/charts/XSSFNumberCache.java (revision 1148642) >+++ src/ooxml/java/org/apache/poi/xssf/usermodel/charts/XSSFNumberCache.java (revision 1148642) >@@ -1,150 +0,0 @@ >-/* ==================================================================== >- 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.ss.usermodel.Cell; >-import org.apache.poi.ss.usermodel.Row; >-import org.apache.poi.ss.usermodel.Sheet; >-import org.apache.poi.ss.usermodel.FormulaEvaluator; >-import org.apache.poi.ss.usermodel.CellValue; >-import org.apache.poi.ss.usermodel.Workbook; >-import org.apache.poi.ss.util.CellRangeAddress; >-import org.apache.poi.ss.util.NumberToTextConverter; >-import org.apache.poi.ss.util.DataMarker; >-import org.apache.poi.ss.util.cellwalk.CellWalk; >-import org.apache.poi.ss.util.cellwalk.CellHandler; >-import org.apache.poi.ss.util.cellwalk.CellWalkContext; >-import org.openxmlformats.schemas.drawingml.x2006.chart.CTNumRef; >-import org.openxmlformats.schemas.drawingml.x2006.chart.CTNumData; >-import org.openxmlformats.schemas.drawingml.x2006.chart.CTNumVal; >-import org.openxmlformats.schemas.drawingml.x2006.chart.CTUnsignedInt; >- >-/** >- * Package private class to fill chart's number reference with cached >- * numeric values. If a formula-typed cell referenced by data marker, >- * cell's value will be calculated and placed to cache. Numeric cells >- * will be placed to cache as is. Non-numeric cells will be ignored. >- * >- * @author Roman Kashitsyn >- */ >-class XSSFNumberCache { >- >- private CTNumData ctNumData; >- >- XSSFNumberCache(CTNumData ctNumData) { >- this.ctNumData = ctNumData; >- } >- >- /** >- * Builds new numeric cache container. >- * @param marker data marker to use for cache evaluation >- * @param ctNumRef parent number reference >- * @return numeric cache instance >- */ >- static XSSFNumberCache buildCache(DataMarker marker, CTNumRef ctNumRef) { >- CellRangeAddress range = marker.getRange(); >- int numOfPoints = range.getNumberOfCells(); >- >- if (numOfPoints == 0) { >- // Nothing to do. >- return null; >- } >- >- XSSFNumberCache cache = new XSSFNumberCache(ctNumRef.addNewNumCache()); >- cache.setPointCount(numOfPoints); >- >- Workbook wb = marker.getSheet().getWorkbook(); >- FormulaEvaluator evaluator = wb.getCreationHelper().createFormulaEvaluator(); >- >- CellWalk cellWalk = new CellWalk(marker); >- NumCacheCellHandler numCacheHandler = cache.new NumCacheCellHandler(evaluator); >- cellWalk.traverse(numCacheHandler); >- return cache; >- } >- >- /** >- * Returns total count of points in cache. Some (or even all) of >- * them might be empty. >- * @return total count of points in cache >- */ >- long getPointCount() { >- CTUnsignedInt pointCount = ctNumData.getPtCount(); >- if (pointCount != null) { >- return pointCount.getVal(); >- } else { >- return 0L; >- } >- } >- >- /** >- * Returns cache value at specified index. >- * @param index index of the point in cache >- * @return point value >- */ >- double getValueAt(int index) { >- /* TODO: consider more effective algorithm. Left as is since >- * this method should be invoked mostly in tests. */ >- for (CTNumVal pt : ctNumData.getPtList()) { >- if (pt.getIdx() == index) { >- return Double.valueOf(pt.getV()).doubleValue(); >- } >- } >- return 0.0; >- } >- >- private void setPointCount(int numOfPoints) { >- ctNumData.addNewPtCount().setVal(numOfPoints); >- } >- >- private class NumCacheCellHandler implements CellHandler { >- >- private FormulaEvaluator evaluator; >- >- public NumCacheCellHandler(FormulaEvaluator evaluator) { >- this.evaluator = evaluator; >- } >- >- public void onCell(Cell cell, CellWalkContext ctx) { >- double pointValue = getOrEvalCellValue(cell); >- /* Silently ignore non-numeric values. >- * This is Office default behaviour. */ >- if (Double.isNaN(pointValue)) { >- return; >- } >- >- CTNumVal point = ctNumData.addNewPt(); >- point.setIdx(ctx.getOrdinalNumber()); >- point.setV(NumberToTextConverter.toText(pointValue)); >- } >- >- private double getOrEvalCellValue(Cell cell) { >- int cellType = cell.getCellType(); >- >- if (cellType == Cell.CELL_TYPE_NUMERIC) { >- return cell.getNumericCellValue(); >- } else if (cellType == Cell.CELL_TYPE_FORMULA) { >- CellValue value = evaluator.evaluate(cell); >- if (value.getCellType() == Cell.CELL_TYPE_NUMERIC) { >- return value.getNumberValue(); >- } >- } >- return Double.NaN; >- } >- >- } >-} >Index: src/testcases/org/apache/poi/ss/usermodel/charts/TestDataSources.java >=================================================================== >--- src/testcases/org/apache/poi/ss/usermodel/charts/TestDataSources.java (revision ) >+++ src/testcases/org/apache/poi/ss/usermodel/charts/TestDataSources.java (revision ) >@@ -0,0 +1,136 @@ >+/* ==================================================================== >+ 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; >+ >+import junit.framework.TestCase; >+import org.apache.poi.hssf.usermodel.HSSFWorkbook; >+import org.apache.poi.ss.usermodel.Sheet; >+import org.apache.poi.ss.usermodel.Workbook; >+import org.apache.poi.ss.util.CellRangeAddress; >+import org.apache.poi.ss.util.SheetBuilder; >+ >+/** >+ * Tests for {@link org.apache.poi.ss.usermodel.charts.DataSources}. >+ * >+ * @author Roman Kashitsyn >+ */ >+public class TestDataSources extends TestCase { >+ >+ private static final Object[][] numericCells = { >+ {0.0, 1.0, 2.0, 3.0, 4.0}, >+ {0.0, "=B1*2", "=C1*2", "=D1*2", "=E1*2"} >+ }; >+ >+ private static final Object[][] stringCells = { >+ { 1, 2, 3, 4, 5}, >+ {"A", "B", "C", "D", "E"} >+ }; >+ >+ private static final Object[][] mixedCells = { >+ {1.0, "2.0", 3.0, "4.0", 5.0, "6.0"} >+ }; >+ >+ public void testNumericArrayDataSource() { >+ Double[] doubles = new Double[]{1.0, 2.0, 3.0, 4.0, 5.0}; >+ ChartDataSource<Double> doubleDataSource = DataSources.fromArray(doubles); >+ assertTrue(doubleDataSource.isNumeric()); >+ assertFalse(doubleDataSource.isReference()); >+ assertDataSourceIsEqualToArray(doubleDataSource, doubles); >+ } >+ >+ public void testStringArrayDataSource() { >+ String[] strings = new String[]{"one", "two", "three", "four", "five"}; >+ ChartDataSource<String> stringDataSource = DataSources.fromArray(strings); >+ assertFalse(stringDataSource.isNumeric()); >+ assertFalse(stringDataSource.isReference()); >+ assertDataSourceIsEqualToArray(stringDataSource, strings); >+ } >+ >+ public void testNumericCellDataSource() { >+ Workbook wb = new HSSFWorkbook(); >+ Sheet sheet = new SheetBuilder(wb, numericCells).build(); >+ CellRangeAddress numCellRange = CellRangeAddress.valueOf("A2:E2"); >+ ChartDataSource<Number> numDataSource = DataSources.fromNumericCellRange(sheet, numCellRange); >+ assertTrue(numDataSource.isReference()); >+ assertTrue(numDataSource.isNumeric()); >+ assertEquals(numericCells[0].length, numDataSource.getPointCount()); >+ for (int i = 0; i < numericCells[0].length; ++i) { >+ assertEquals(((Number) numericCells[0][i]).doubleValue() * 2, >+ numDataSource.getPointAt(i).doubleValue(), 0.00001); >+ } >+ } >+ >+ public void testStringCellDataSource() { >+ Workbook wb = new HSSFWorkbook(); >+ Sheet sheet = new SheetBuilder(wb, stringCells).build(); >+ CellRangeAddress numCellRange = CellRangeAddress.valueOf("A2:E2"); >+ ChartDataSource<String> numDataSource = DataSources.fromStringCellRange(sheet, numCellRange); >+ assertTrue(numDataSource.isReference()); >+ assertFalse(numDataSource.isNumeric()); >+ assertEquals(numericCells[0].length, numDataSource.getPointCount()); >+ for (int i = 0; i < stringCells[1].length; ++i) { >+ assertEquals(stringCells[1][i], numDataSource.getPointAt(i)); >+ } >+ } >+ >+ public void testMixedCellDataSource() { >+ Workbook wb = new HSSFWorkbook(); >+ Sheet sheet = new SheetBuilder(wb, mixedCells).build(); >+ CellRangeAddress mixedCellRange = CellRangeAddress.valueOf("A1:F1"); >+ ChartDataSource<String> strDataSource = DataSources.fromStringCellRange(sheet, mixedCellRange); >+ ChartDataSource<Number> numDataSource = DataSources.fromNumericCellRange(sheet, mixedCellRange); >+ for (int i = 0; i < mixedCells[0].length; ++i) { >+ if (i % 2 == 0) { >+ assertNull(strDataSource.getPointAt(i)); >+ assertEquals(((Number) mixedCells[0][i]).doubleValue(), >+ numDataSource.getPointAt(i).doubleValue(), 0.00001); >+ } else { >+ assertNull(numDataSource.getPointAt(i)); >+ assertEquals(mixedCells[0][i], strDataSource.getPointAt(i)); >+ } >+ } >+ } >+ >+ public void testIOBExceptionOnInvalidIndex() { >+ Workbook wb = new HSSFWorkbook(); >+ Sheet sheet = new SheetBuilder(wb, numericCells).build(); >+ CellRangeAddress rangeAddress = CellRangeAddress.valueOf("A2:E2"); >+ ChartDataSource<Number> numDataSource = DataSources.fromNumericCellRange(sheet, rangeAddress); >+ IndexOutOfBoundsException exception = null; >+ try { >+ numDataSource.getPointAt(-1); >+ } catch (IndexOutOfBoundsException e) { >+ exception = e; >+ } >+ assertNotNull(exception); >+ >+ exception = null; >+ try { >+ numDataSource.getPointAt(numDataSource.getPointCount()); >+ } catch (IndexOutOfBoundsException e) { >+ exception = e; >+ } >+ assertNotNull(exception); >+ } >+ >+ private <T> void assertDataSourceIsEqualToArray(ChartDataSource<T> ds, T[] array) { >+ assertEquals(ds.getPointCount(), array.length); >+ for (int i = 0; i < array.length; ++i) { >+ assertEquals(ds.getPointAt(i), array[i]); >+ } >+ } >+} >Index: src/java/org/apache/poi/ss/usermodel/charts/ChartData.java >=================================================================== >--- src/java/org/apache/poi/ss/usermodel/charts/ChartData.java (revision 1125275) >+++ src/java/org/apache/poi/ss/usermodel/charts/ChartData.java (revision ) >@@ -20,17 +20,17 @@ > import org.apache.poi.ss.usermodel.Chart; > > /** >- * A base for all chart data types. >+ * A base for all charts data types. > * > * @author Roman Kashitsyn > */ > public interface ChartData { > > /** >- * Fills a chart with data specified by implementation. >+ * Fills a charts with data specified by implementation. > * >- * @param chart a chart to fill in >- * @param axis chart axis to use >+ * @param chart a charts to fill in >+ * @param axis charts axis to use > */ > void fillChart(Chart chart, ChartAxis... axis); > } >Index: src/ooxml/java/org/apache/poi/xssf/usermodel/charts/XSSFChartDataFactory.java >=================================================================== >--- src/ooxml/java/org/apache/poi/xssf/usermodel/charts/XSSFChartDataFactory.java (revision 1125275) >+++ src/ooxml/java/org/apache/poi/xssf/usermodel/charts/XSSFChartDataFactory.java (revision ) >@@ -31,7 +31,7 @@ > } > > /** >- * @return new scatter chart data instance >+ * @return new scatter charts data instance > */ > public XSSFScatterChartData createScatterChartData() { > return new XSSFScatterChartData(); >Index: src/java/org/apache/poi/ss/util/SheetBuilder.java >=================================================================== >--- src/java/org/apache/poi/ss/util/SheetBuilder.java (revision 1148642) >+++ src/java/org/apache/poi/ss/util/SheetBuilder.java (revision ) >@@ -25,115 +25,134 @@ > import org.apache.poi.ss.usermodel.Cell; > > /** >- * Class that provides useful sheet build capabilities. It can be used >- * in test cases to improve readability or in Swing applications with >- * tables. >+ * Class {@code SheetBuilder} provides an easy way of building workbook sheets >+ * from 2D array of Objects. It can be used in test cases to improve code >+ * readability or in Swing applications with tables. > * > * @author Roman Kashitsyn > */ > public class SheetBuilder { > >- private Workbook workbook; >- private Object[][] cells; >+ private final Workbook workbook; >+ private final Object[][] cells; > private boolean shouldCreateEmptyCells = false; >+ private String sheetName = null; > > public SheetBuilder(Workbook workbook, Object[][] cells) { >- this.workbook = workbook; >- this.cells = cells; >+ this.workbook = workbook; >+ this.cells = cells; > } > > /** >- * @return true if null objects should be trated as empty cells >- * false otherwise >+ * Returns {@code true} if null array elements should be treated as empty >+ * cells. >+ * >+ * @return {@code true} if null objects should be treated as empty cells >+ * and {@code false} otherwise > */ > public boolean getCreateEmptyCells() { >- return shouldCreateEmptyCells; >+ return shouldCreateEmptyCells; > } > > /** >- * @param shouldCreateEmptyCells true if null array elements should be >- * trated as empty cells >- * @return this >+ * Specifies if null array elements should be treated as empty cells. >+ * >+ * @param shouldCreateEmptyCells {@code true} if null array elements should be >+ * treated as empty cells >+ * @return {@code this} > */ > public SheetBuilder setCreateEmptyCells(boolean shouldCreateEmptyCells) { >- this.shouldCreateEmptyCells = shouldCreateEmptyCells; >- return this; >+ this.shouldCreateEmptyCells = shouldCreateEmptyCells; >+ return this; > } > > /** >+ * Specifies name of the sheet to build. If not specified, default name (provided by >+ * workbook) will be used instead. >+ * @param sheetName sheet name to use >+ * @return {@code this} >+ */ >+ public SheetBuilder setSheetName(String sheetName) { >+ this.sheetName = sheetName; >+ return this; >+ } >+ >+ /** > * Builds sheet from parent workbook and 2D array with cell > * values. Creates rows anyway (even if row contains only null >- * cells), creates cells only if corresponding property is true. >+ * cells), creates cells if either corresponding array value is not >+ * null or createEmptyCells property is true. > * The conversion is performed in the following way: >- * >+ * <p/> > * <ul> > * <li>Numbers become numeric cells.</li> > * <li><code>java.util.Date</code> or <code>java.util.Calendar</code> >- * instances become date cells.</li> >+ * instances become date cells.</li> > * <li>String with leading '=' char become formulas (leading '=' >- * trancated).</li> >+ * will be truncated).</li> > * <li>Other objects become strings via <code>Object.toString()</code> >- * method.</li> >+ * method call.</li> > * </ul> > * > * @return newly created sheet > */ > public Sheet build() { >- Sheet sheet = workbook.createSheet(); >+ Sheet sheet = (sheetName == null) ? workbook.createSheet() : workbook.createSheet(sheetName); >- Row currentRow = null; >- Cell currentCell = null; >+ Row currentRow = null; >+ Cell currentCell = null; > >- for (int rowIndex = 0; rowIndex < cells.length; ++rowIndex) { >- Object[] rowArray = cells[rowIndex]; >- currentRow = sheet.createRow(rowIndex); >+ for (int rowIndex = 0; rowIndex < cells.length; ++rowIndex) { >+ Object[] rowArray = cells[rowIndex]; >+ currentRow = sheet.createRow(rowIndex); > >- for (int cellIndex = 0; cellIndex < rowArray.length; ++cellIndex) { >- Object cellValue = rowArray[cellIndex]; >- if (cellValue != null || shouldCreateEmptyCells) { >- currentCell = currentRow.createCell(cellIndex); >- setCellValue(currentCell, cellValue); >- } >- } >- } >- return sheet; >+ for (int cellIndex = 0; cellIndex < rowArray.length; ++cellIndex) { >+ Object cellValue = rowArray[cellIndex]; >+ if (cellValue != null || shouldCreateEmptyCells) { >+ currentCell = currentRow.createCell(cellIndex); >+ setCellValue(currentCell, cellValue); >+ } >+ } >+ } >+ return sheet; > } > > /** > * Sets the cell value using object type information. >+ * >- * @param cell cell to change >+ * @param cell cell to change > * @param value value to set > */ >- public void setCellValue(Cell cell, Object value) { >+ private void setCellValue(Cell cell, Object value) { >- if (value == null || cell == null) { >- return; >- } else if (value instanceof Number) { >- double doubleValue = ((Number) value).doubleValue(); >- cell.setCellValue(doubleValue); >- } else if (value instanceof Date) { >- cell.setCellValue((Date) value); >- } else if (value instanceof Calendar) { >- cell.setCellValue((Calendar) value); >- } else if (isFormulaDefinition(value)) { >- cell.setCellFormula(getFormula(value)); >- } else { >- cell.setCellValue(value.toString()); >- } >+ if (value == null || cell == null) { >+ return; >+ } else if (value instanceof Number) { >+ double doubleValue = ((Number) value).doubleValue(); >+ cell.setCellValue(doubleValue); >+ } else if (value instanceof Date) { >+ cell.setCellValue((Date) value); >+ } else if (value instanceof Calendar) { >+ cell.setCellValue((Calendar) value); >+ } else if (isFormulaDefinition(value)) { >+ cell.setCellFormula(getFormula(value)); >+ } else { >+ cell.setCellValue(value.toString()); >+ } > } > > private boolean isFormulaDefinition(Object obj) { >- if (obj instanceof String) { >- String str = (String) obj; >- if (str.length() < 2) { >- return false; >- } else { >- return ((String) obj).charAt(0) == '='; >- } >- } else { >- return false; >- } >+ if (obj instanceof String) { >+ String str = (String) obj; >+ if (str.length() < 2) { >+ return false; >+ } else { >+ return ((String) obj).charAt(0) == '='; >+ } >+ } else { >+ return false; >+ } > } > > private String getFormula(Object obj) { >- return ((String) obj).substring(1); >+ return ((String) obj).substring(1); > } > } >\ No newline at end of file >Index: src/ooxml/java/org/apache/poi/xssf/usermodel/charts/XSSFScatterChartData.java >=================================================================== >--- src/ooxml/java/org/apache/poi/xssf/usermodel/charts/XSSFScatterChartData.java (revision 1148642) >+++ src/ooxml/java/org/apache/poi/xssf/usermodel/charts/XSSFScatterChartData.java (revision ) >@@ -17,37 +17,20 @@ > > package org.apache.poi.xssf.usermodel.charts; > >-import java.util.List; >-import java.util.ArrayList; >- > import org.apache.poi.ss.usermodel.Chart; >-import org.apache.poi.ss.usermodel.Sheet; >-import org.apache.poi.ss.util.DataMarker; >+import org.apache.poi.ss.usermodel.charts.ChartAxis; >+import org.apache.poi.ss.usermodel.charts.ChartDataSource; > import org.apache.poi.ss.usermodel.charts.ScatterChartData; > import org.apache.poi.ss.usermodel.charts.ScatterChartSerie; >-import org.apache.poi.ss.usermodel.charts.ChartDataFactory; >-import org.apache.poi.ss.usermodel.charts.ChartAxis; >+import org.apache.poi.xssf.usermodel.XSSFChart; >+import org.openxmlformats.schemas.drawingml.x2006.chart.*; > >-import org.openxmlformats.schemas.drawingml.x2006.chart.CTPlotArea; >-import org.openxmlformats.schemas.drawingml.x2006.chart.CTScatterChart; >-import org.openxmlformats.schemas.drawingml.x2006.chart.CTScatterStyle; >-import org.openxmlformats.schemas.drawingml.x2006.chart.CTScatterSer; >-import org.openxmlformats.schemas.drawingml.x2006.chart.CTAxDataSource; >-import org.openxmlformats.schemas.drawingml.x2006.chart.CTNumRef; >-import org.openxmlformats.schemas.drawingml.x2006.chart.CTNumDataSource; >-import org.openxmlformats.schemas.drawingml.x2006.chart.CTNumFmt; >-import org.openxmlformats.schemas.drawingml.x2006.chart.CTValAx; >-import org.openxmlformats.schemas.drawingml.x2006.chart.STScatterStyle; >-import org.openxmlformats.schemas.drawingml.x2006.chart.STCrosses; >-import org.openxmlformats.schemas.drawingml.x2006.chart.STCrossBetween; >-import org.openxmlformats.schemas.drawingml.x2006.chart.STOrientation; >-import org.openxmlformats.schemas.drawingml.x2006.chart.STTickLblPos; >-import org.openxmlformats.schemas.drawingml.x2006.chart.STAxPos; >+import java.util.ArrayList; >+import java.util.List; > >-import org.apache.poi.xssf.usermodel.XSSFChart; > > /** >- * Represents DrawingML scatter chart. >+ * Represents DrawingML scatter charts. > * > * @author Roman Kashitsyn > */ >@@ -59,118 +42,93 @@ > private List<Serie> series; > > public XSSFScatterChartData() { >- series = new ArrayList<Serie>(); >+ series = new ArrayList<Serie>(); > } > > /** > * Package private ScatterChartSerie implementation. > */ > static class Serie implements ScatterChartSerie { >- private int id; >- private int order; >+ private int id; >+ private int order; >- private boolean useCache; >- private DataMarker xMarker; >- private DataMarker yMarker; >- private XSSFNumberCache lastCaclulatedXCache; >- private XSSFNumberCache lastCalculatedYCache; >+ private ChartDataSource<?> xs; >+ private ChartDataSource<? extends Number> ys; > >- protected Serie(int id, int order) { >+ protected Serie(int id, int order, >+ ChartDataSource<?> xs, >+ ChartDataSource<? extends Number> ys) { >- super(); >- this.id = id; >- this.order = order; >+ super(); >+ this.id = id; >+ this.order = order; >- this.useCache = true; >+ this.xs = xs; >+ this.ys = ys; >- } >+ } > >- public void setXValues(DataMarker marker) { >- xMarker = marker; >- } >- >- public void setYValues(DataMarker marker) { >- yMarker = marker; >- } >- >- /** >+ /** >- * @param useCache if true, cached results will be added on plot >+ * Returns data source used for X axis values. >+ * @return data source used for X axis values >- */ >+ */ >- public void setUseCache(boolean useCache) { >- this.useCache = useCache; >+ public ChartDataSource<?> getXValues() { >+ return xs; >- } >+ } > >- /** >+ /** >- * Returns last calculated number cache for X axis. >- * @return last calculated number cache for X axis. >+ * Returns data source used for Y axis values. >+ * @return data source used for Y axis values >- */ >+ */ >- XSSFNumberCache getLastCaculatedXCache() { >- return lastCaclulatedXCache; >+ public ChartDataSource<? extends Number> getYValues() { >+ return ys; >- } >+ } > >- /** >- * Returns last calculated number cache for Y axis. >- * @return last calculated number cache for Y axis. >- */ >- XSSFNumberCache getLastCalculatedYCache() { >- return lastCalculatedYCache; >- } >- >- protected void addToChart(CTScatterChart ctScatterChart) { >- CTScatterSer scatterSer = ctScatterChart.addNewSer(); >- scatterSer.addNewIdx().setVal(this.id); >- scatterSer.addNewOrder().setVal(this.order); >+ protected void addToChart(CTScatterChart ctScatterChart) { >+ CTScatterSer scatterSer = ctScatterChart.addNewSer(); >+ scatterSer.addNewIdx().setVal(this.id); >+ scatterSer.addNewOrder().setVal(this.order); > >- /* TODO: add some logic to automatically recognize cell >- * types and choose appropriate data representation for >- * X axis. >- */ >- CTAxDataSource xVal = scatterSer.addNewXVal(); >+ CTAxDataSource xVal = scatterSer.addNewXVal(); >- CTNumRef xNumRef = xVal.addNewNumRef(); >- xNumRef.setF(xMarker.formatAsString()); >+ XSSFChartUtil.buildAxDataSource(xVal, xs); > >- CTNumDataSource yVal = scatterSer.addNewYVal(); >+ CTNumDataSource yVal = scatterSer.addNewYVal(); >- CTNumRef yNumRef = yVal.addNewNumRef(); >- yNumRef.setF(yMarker.formatAsString()); >- >- if (useCache) { >- /* We can not store cache since markers are not immutable */ >- XSSFNumberCache.buildCache(xMarker, xNumRef); >- lastCalculatedYCache = XSSFNumberCache.buildCache(yMarker, yNumRef); >+ XSSFChartUtil.buildNumDataSource(yVal, ys); >- } >- } >+ } >+ } >- } > >- public ScatterChartSerie addSerie(DataMarker xMarker, DataMarker yMarker) { >+ public ScatterChartSerie addSerie(ChartDataSource<?> xs, >+ ChartDataSource<? extends Number> ys) { >+ if (!ys.isNumeric()) { >+ throw new IllegalArgumentException("Y axis data source must be numeric."); >+ } >- int numOfSeries = series.size(); >+ int numOfSeries = series.size(); >- Serie newSerie = new Serie(numOfSeries, numOfSeries); >- newSerie.setXValues(xMarker); >- newSerie.setYValues(yMarker); >+ Serie newSerie = new Serie(numOfSeries, numOfSeries, xs, ys); >- series.add(newSerie); >- return newSerie; >+ series.add(newSerie); >+ return newSerie; > } > > public void fillChart(Chart chart, ChartAxis... axis) { >- if (!(chart instanceof XSSFChart)) { >- throw new IllegalArgumentException("Chart must be instance of XSSFChart"); >- } >+ if (!(chart instanceof XSSFChart)) { >+ throw new IllegalArgumentException("Chart must be instance of XSSFChart"); >+ } > >- XSSFChart xssfChart = (XSSFChart) chart; >- CTPlotArea plotArea = xssfChart.getCTChart().getPlotArea(); >- CTScatterChart scatterChart = plotArea.addNewScatterChart(); >- addStyle(scatterChart); >+ XSSFChart xssfChart = (XSSFChart) chart; >+ CTPlotArea plotArea = xssfChart.getCTChart().getPlotArea(); >+ CTScatterChart scatterChart = plotArea.addNewScatterChart(); >+ addStyle(scatterChart); > >- for (Serie s : series) { >- s.addToChart(scatterChart); >- } >+ for (Serie s : series) { >+ s.addToChart(scatterChart); >+ } > >- for (ChartAxis ax : axis) { >- scatterChart.addNewAxId().setVal(ax.getId()); >- } >+ for (ChartAxis ax : axis) { >+ scatterChart.addNewAxId().setVal(ax.getId()); >+ } > } > > public List<? extends Serie> getSeries() { >- return series; >+ return series; > } > > private void addStyle(CTScatterChart ctScatterChart) { >- CTScatterStyle scatterStyle = ctScatterChart.addNewScatterStyle(); >- scatterStyle.setVal(STScatterStyle.LINE_MARKER); >+ CTScatterStyle scatterStyle = ctScatterChart.addNewScatterStyle(); >+ scatterStyle.setVal(STScatterStyle.LINE_MARKER); > } > } >Index: src/java/org/apache/poi/ss/usermodel/charts/DataSources.java >=================================================================== >--- src/java/org/apache/poi/ss/usermodel/charts/DataSources.java (revision ) >+++ src/java/org/apache/poi/ss/usermodel/charts/DataSources.java (revision ) >@@ -0,0 +1,142 @@ >+/* ==================================================================== >+ 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; >+ >+import org.apache.poi.ss.usermodel.*; >+import org.apache.poi.ss.util.CellRangeAddress; >+ >+/** >+ * Class {@code DataSources} is a factory for {@link ChartDataSource} instances. >+ * >+ * @author Roman Kashitsyn >+ */ >+public class DataSources { >+ >+ private DataSources() { >+ } >+ >+ public static <T> ChartDataSource<T> fromArray(T[] elements) { >+ return new ArrayDataSource<T>(elements); >+ } >+ >+ public static ChartDataSource<Number> fromNumericCellRange(Sheet sheet, CellRangeAddress cellRangeAddress) { >+ return new AbstractCellRangeDataSource<Number>(sheet, cellRangeAddress) { >+ public Number getPointAt(int index) { >+ CellValue cellValue = getCellValueAt(index); >+ if (cellValue != null && cellValue.getCellType() == Cell.CELL_TYPE_NUMERIC) { >+ return Double.valueOf(cellValue.getNumberValue()); >+ } else { >+ return null; >+ } >+ } >+ >+ public boolean isNumeric() { >+ return true; >+ } >+ }; >+ } >+ >+ public static ChartDataSource<String> fromStringCellRange(Sheet sheet, CellRangeAddress cellRangeAddress) { >+ return new AbstractCellRangeDataSource<String>(sheet, cellRangeAddress) { >+ public String getPointAt(int index) { >+ CellValue cellValue = getCellValueAt(index); >+ if (cellValue != null && cellValue.getCellType() == Cell.CELL_TYPE_STRING) { >+ return cellValue.getStringValue(); >+ } else { >+ return null; >+ } >+ } >+ >+ public boolean isNumeric() { >+ return false; >+ } >+ }; >+ } >+ >+ private static class ArrayDataSource<T> implements ChartDataSource<T> { >+ >+ private final T[] elements; >+ >+ public ArrayDataSource(T[] elements) { >+ this.elements = elements; >+ } >+ >+ public int getPointCount() { >+ return elements.length; >+ } >+ >+ public T getPointAt(int index) { >+ return elements[index]; >+ } >+ >+ public boolean isReference() { >+ return false; >+ } >+ >+ public boolean isNumeric() { >+ Class<?> arrayComponentType = elements.getClass().getComponentType(); >+ return (Number.class.isAssignableFrom(arrayComponentType)); >+ } >+ >+ public String getFormulaString() { >+ throw new UnsupportedOperationException("Literal data source can not be expressed by reference."); >+ } >+ } >+ >+ private abstract static class AbstractCellRangeDataSource<T> implements ChartDataSource<T> { >+ private final Sheet sheet; >+ private final CellRangeAddress cellRangeAddress; >+ private final int numOfCells; >+ private FormulaEvaluator evaluator; >+ >+ protected AbstractCellRangeDataSource(Sheet sheet, CellRangeAddress cellRangeAddress) { >+ this.sheet = sheet; >+ // Make copy since CellRangeAddress is mutable. >+ this.cellRangeAddress = cellRangeAddress.copy(); >+ this.numOfCells = this.cellRangeAddress.getNumberOfCells(); >+ this.evaluator = sheet.getWorkbook().getCreationHelper().createFormulaEvaluator(); >+ } >+ >+ public int getPointCount() { >+ return numOfCells; >+ } >+ >+ public boolean isReference() { >+ return true; >+ } >+ >+ public String getFormulaString() { >+ return cellRangeAddress.formatAsString(sheet.getSheetName(), true); >+ } >+ >+ protected CellValue getCellValueAt(int index) { >+ if (index < 0 || index >= numOfCells) { >+ throw new IndexOutOfBoundsException("Index must be between 0 and " + >+ (numOfCells - 1) + " (inclusive), given: " + index); >+ } >+ int firstRow = cellRangeAddress.getFirstRow(); >+ int firstCol = cellRangeAddress.getFirstColumn(); >+ int lastCol = cellRangeAddress.getLastColumn(); >+ int width = lastCol - firstCol + 1; >+ int rowIndex = firstRow + index / width; >+ int cellIndex = firstCol + index % width; >+ Row row = sheet.getRow(rowIndex); >+ return (row == null) ? null : evaluator.evaluate(row.getCell(cellIndex)); >+ } >+ } >+} >Index: src/java/org/apache/poi/ss/usermodel/charts/ChartDataSource.java >=================================================================== >--- src/java/org/apache/poi/ss/usermodel/charts/ChartDataSource.java (revision ) >+++ src/java/org/apache/poi/ss/usermodel/charts/ChartDataSource.java (revision ) >@@ -0,0 +1,67 @@ >+/* ==================================================================== >+ 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; >+ >+/** >+ * Represents data model of the charts. >+ * >+ * @param <T> type of points the data source contents >+ * @author Roman Kashitsyn >+ */ >+public interface ChartDataSource<T> { >+ >+ /** >+ * Return number of points contained by data source. >+ * >+ * @return number of points contained by data source >+ */ >+ int getPointCount(); >+ >+ /** >+ * Returns point value at specified index. >+ * >+ * @param index index to value from >+ * @return point value at specified index. >+ * @throws {@code IndexOutOfBoundsException} if index >+ * parameter not in range {@code 0 <= index <= pointCount} >+ */ >+ T getPointAt(int index); >+ >+ /** >+ * Returns {@code true} if charts data source is valid cell range. >+ * >+ * @return {@code true} if charts data source is valid cell range >+ */ >+ boolean isReference(); >+ >+ /** >+ * Returns {@code true} if data source points should be treated as numbers. >+ * >+ * @return {@code true} if data source points should be treated as numbers >+ */ >+ boolean isNumeric(); >+ >+ /** >+ * Returns formula representation of the data source. It is only applicable >+ * for data source that is valid cell range. >+ * >+ * @return formula representation of the data source >+ * @throws {@code UnsupportedOperationException} if the data source is not a >+ * reference. >+ */ >+ String getFormulaString(); >+} >Index: src/ooxml/testcases/org/apache/poi/xssf/usermodel/TestXSSFWorkbook.java >=================================================================== >--- src/ooxml/testcases/org/apache/poi/xssf/usermodel/TestXSSFWorkbook.java (revision 1148673) >+++ src/ooxml/testcases/org/apache/poi/xssf/usermodel/TestXSSFWorkbook.java (revision ) >@@ -332,7 +332,7 @@ > } > > /** >- * Problems with XSSFWorkbook.removeSheetAt when workbook contains chart >+ * Problems with XSSFWorkbook.removeSheetAt when workbook contains charts > */ > public void testBug47813() { > XSSFWorkbook wb = XSSFTestDataSamples.openSampleWorkbook("47813.xlsx"); >Index: src/java/org/apache/poi/ss/usermodel/charts/ScatterChartSerie.java >=================================================================== >--- src/java/org/apache/poi/ss/usermodel/charts/ScatterChartSerie.java (revision 1132553) >+++ src/java/org/apache/poi/ss/usermodel/charts/ScatterChartSerie.java (revision ) >@@ -17,23 +17,21 @@ > > package org.apache.poi.ss.usermodel.charts; > >-import org.apache.poi.ss.usermodel.Sheet; >-import org.apache.poi.ss.util.DataMarker; >-import org.apache.poi.ss.usermodel.charts.ChartDataFactory; >- > /** >+ * Represents scatter charts serie. >+ * > * @author Roman Kashitsyn > */ > public interface ScatterChartSerie { > >- /** >+ /** >- * @param xMarker data marker to use for X values. >+ * @return data source used for X axis values >- */ >+ */ >- void setXValues(DataMarker xMarker); >+ ChartDataSource<?> getXValues(); > >- /**' >- * @param yMarker data marker to use for Y values. >+ /** >+ * @return data source used for Y axis values >- */ >+ */ >- void setYValues(DataMarker yMarker); >+ ChartDataSource<? extends Number> getYValues(); > > } >Index: src/java/org/apache/poi/ss/usermodel/charts/ChartDataFactory.java >=================================================================== >--- src/java/org/apache/poi/ss/usermodel/charts/ChartDataFactory.java (revision 1125275) >+++ src/java/org/apache/poi/ss/usermodel/charts/ChartDataFactory.java (revision ) >@@ -18,7 +18,7 @@ > package org.apache.poi.ss.usermodel.charts; > > /** >- * A factory for different chart data types. >+ * A factory for different charts data types. > * > * @author Roman Kashitsyn > */ >Index: src/java/org/apache/poi/ss/util/DataMarker.java >=================================================================== >--- src/java/org/apache/poi/ss/util/DataMarker.java (revision 1132553) >+++ src/java/org/apache/poi/ss/util/DataMarker.java (revision 1132553) >@@ -1,87 +0,0 @@ >-/* >- * ==================================================================== >- * 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); >- } >- } >-} >Index: src/java/org/apache/poi/ss/util/cellwalk/CellWalk.java >=================================================================== >--- src/java/org/apache/poi/ss/util/cellwalk/CellWalk.java (revision 1148642) >+++ src/java/org/apache/poi/ss/util/cellwalk/CellWalk.java (revision ) >@@ -17,12 +17,10 @@ > > package org.apache.poi.ss.util.cellwalk; > >- > import org.apache.poi.ss.usermodel.Cell; > import org.apache.poi.ss.usermodel.Row; > import org.apache.poi.ss.usermodel.Sheet; > import org.apache.poi.ss.util.CellRangeAddress; >-import org.apache.poi.ss.util.DataMarker; > > /** > * Traverse cell range. >@@ -35,95 +33,96 @@ > private CellRangeAddress range; > private boolean traverseEmptyCells; > >- public CellWalk(DataMarker dm) { >- this(dm.getSheet(), dm.getRange()); >- } > > public CellWalk(Sheet sheet, CellRangeAddress range) { >- this.sheet = sheet; >- this.range = range; >- this.traverseEmptyCells = false; >+ this.sheet = sheet; >+ this.range = range; >+ this.traverseEmptyCells = false; > } > > /** > * Should we call handler on empty (blank) cells. Default is > * false. >+ * > * @return true if handler should be called on empty (blank) >- * cells, false otherwise. >+ * cells, false otherwise. > */ > public boolean isTraverseEmptyCells() { >- return traverseEmptyCells; >+ return traverseEmptyCells; > } > > /** > * Sets the traverseEmptyCells property. >+ * > * @param traverseEmptyCells new property value > */ > public void setTraverseEmptyCells(boolean traverseEmptyCells) { >- this.traverseEmptyCells = traverseEmptyCells; >+ this.traverseEmptyCells = traverseEmptyCells; > } > > /** > * Traverse cell range from top left to bottom right cell. >+ * > * @param handler handler to call on each appropriate cell > */ > public void traverse(CellHandler handler) { >- int firstRow = range.getFirstRow(); >- int lastRow = range.getLastRow(); >- int firstColumn = range.getFirstColumn(); >- int lastColumn = range.getLastColumn(); >- final int width = lastColumn - firstColumn + 1; >- SimpleCellWalkContext ctx = new SimpleCellWalkContext(); >- Row currentRow = null; >- Cell currentCell = null; >+ int firstRow = range.getFirstRow(); >+ int lastRow = range.getLastRow(); >+ int firstColumn = range.getFirstColumn(); >+ int lastColumn = range.getLastColumn(); >+ final int width = lastColumn - firstColumn + 1; >+ SimpleCellWalkContext ctx = new SimpleCellWalkContext(); >+ Row currentRow = null; >+ Cell currentCell = null; > >- for (ctx.rowNumber = firstRow; ctx.rowNumber <= lastRow; ++ctx.rowNumber) { >- currentRow = sheet.getRow(ctx.rowNumber); >- if (currentRow == null) { >- continue; >- } >- for (ctx.colNumber = firstColumn; ctx.colNumber <= lastColumn; ++ctx.colNumber) { >- currentCell = currentRow.getCell(ctx.colNumber); >+ for (ctx.rowNumber = firstRow; ctx.rowNumber <= lastRow; ++ctx.rowNumber) { >+ currentRow = sheet.getRow(ctx.rowNumber); >+ if (currentRow == null) { >+ continue; >+ } >+ for (ctx.colNumber = firstColumn; ctx.colNumber <= lastColumn; ++ctx.colNumber) { >+ currentCell = currentRow.getCell(ctx.colNumber); > >- if (currentCell == null) { >- continue; >- } >- if (isEmpty(currentCell) && !traverseEmptyCells) { >- continue; >- } >+ if (currentCell == null) { >+ continue; >+ } >+ if (isEmpty(currentCell) && !traverseEmptyCells) { >+ continue; >+ } > >- ctx.ordinalNumber = >- (ctx.rowNumber - firstRow) * width + >- (ctx.colNumber - firstColumn + 1); >+ ctx.ordinalNumber = >+ (ctx.rowNumber - firstRow) * width + >+ (ctx.colNumber - firstColumn + 1); > >- handler.onCell(currentCell, ctx); >- } >- } >+ handler.onCell(currentCell, ctx); >+ } >+ } > } > > private boolean isEmpty(Cell cell) { >- return (cell.getCellType() == Cell.CELL_TYPE_BLANK); >+ return (cell.getCellType() == Cell.CELL_TYPE_BLANK); > } > > /** > * Inner class to hold walk context. >+ * > * @author Roman Kashitsyn > */ > private class SimpleCellWalkContext implements CellWalkContext { >- public long ordinalNumber = 0; >- public int rowNumber = 0; >- public int colNumber = 0; >+ public long ordinalNumber = 0; >+ public int rowNumber = 0; >+ public int colNumber = 0; > >- public long getOrdinalNumber() { >- return ordinalNumber; >- } >+ public long getOrdinalNumber() { >+ return ordinalNumber; >+ } > >- public int getRowNumber() { >- return rowNumber; >- } >+ public int getRowNumber() { >+ return rowNumber; >+ } > >- public int getColumnNumber() { >- return colNumber; >- } >+ public int getColumnNumber() { >+ return colNumber; >+ } > } > } >Index: src/ooxml/testcases/org/apache/poi/xssf/usermodel/charts/TestXSSFScatterChartData.java >=================================================================== >--- src/ooxml/testcases/org/apache/poi/xssf/usermodel/charts/TestXSSFScatterChartData.java (revision 1148642) >+++ src/ooxml/testcases/org/apache/poi/xssf/usermodel/charts/TestXSSFScatterChartData.java (revision ) >@@ -21,42 +21,43 @@ > > import org.apache.poi.ss.usermodel.*; > import org.apache.poi.ss.util.CellRangeAddress; >-import org.apache.poi.ss.util.DataMarker; > import org.apache.poi.ss.util.SheetBuilder; > import org.apache.poi.ss.usermodel.charts.*; > import org.apache.poi.xssf.usermodel.XSSFWorkbook; > > /** > * Tests for XSSFScatterChartData. >+ * > * @author Roman Kashitsyn > */ >-public final class TestXSSFScatterChartData extends TestCase { >+public final class TestXSSFScatterChartData extends TestCase { > >- private static Object[][] plotData = new Object[][] { >- {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}, >+ private static final Object[][] plotData = { >+ {"A", "B", "C", "D", "E", "F", "G", "H", "I", "J"}, >- {1, 2, 3, 4, 5, 6, 7, 8, 9, 10} >+ { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10} > }; >- >+ > public void testOneSeriePlot() throws Exception { >- Workbook wb = new XSSFWorkbook(); >- Sheet sheet = new SheetBuilder(wb, plotData).build(); >- Drawing drawing = sheet.createDrawingPatriarch(); >- ClientAnchor anchor = drawing.createAnchor(0, 0, 0, 0, 1, 1, 10, 30); >- Chart chart = drawing.createChart(anchor); >+ Workbook wb = new XSSFWorkbook(); >+ Sheet sheet = new SheetBuilder(wb, plotData).build(); >+ Drawing drawing = sheet.createDrawingPatriarch(); >+ ClientAnchor anchor = drawing.createAnchor(0, 0, 0, 0, 1, 1, 10, 30); >+ Chart chart = drawing.createChart(anchor); > >- ChartAxis bottomAxis = chart.getChartAxisFactory().createValueAxis(AxisPosition.BOTTOM); >- ChartAxis leftAxis = chart.getChartAxisFactory().createValueAxis(AxisPosition.LEFT); >+ ChartAxis bottomAxis = chart.getChartAxisFactory().createValueAxis(AxisPosition.BOTTOM); >+ ChartAxis leftAxis = chart.getChartAxisFactory().createValueAxis(AxisPosition.LEFT); > >- ScatterChartData scatterChartData = >- chart.getChartDataFactory().createScatterChartData(); >+ ScatterChartData scatterChartData = >+ chart.getChartDataFactory().createScatterChartData(); > >- DataMarker xMarker = new DataMarker(sheet, CellRangeAddress.valueOf("A1:A10")); >- DataMarker yMarker = new DataMarker(sheet, CellRangeAddress.valueOf("B1:B10")); >- ScatterChartSerie serie = scatterChartData.addSerie(xMarker, yMarker); >+ ChartDataSource<String> xs = DataSources.fromStringCellRange(sheet, CellRangeAddress.valueOf("A1:J1")); >+ ChartDataSource<Number> ys = DataSources.fromNumericCellRange(sheet, CellRangeAddress.valueOf("A2:J2")); >+ ScatterChartSerie serie = scatterChartData.addSerie(xs, ys); > >+ assertNotNull(serie); >- assertEquals(1, scatterChartData.getSeries().size()); >+ assertEquals(1, scatterChartData.getSeries().size()); >+ assertTrue(scatterChartData.getSeries().contains(serie)); > >- chart.plot(scatterChartData, bottomAxis, leftAxis); >+ chart.plot(scatterChartData, bottomAxis, leftAxis); > } >- > } >Index: src/ooxml/testcases/org/apache/poi/xssf/usermodel/charts/TestXSSFNumberCache.java >=================================================================== >--- src/ooxml/testcases/org/apache/poi/xssf/usermodel/charts/TestXSSFNumberCache.java (revision 1148642) >+++ src/ooxml/testcases/org/apache/poi/xssf/usermodel/charts/TestXSSFNumberCache.java (revision 1148642) >@@ -1,64 +0,0 @@ >-/* ==================================================================== >- 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.ss.usermodel.*; >-import org.apache.poi.ss.util.CellRangeAddress; >-import org.apache.poi.ss.util.DataMarker; >-import org.apache.poi.ss.util.SheetBuilder; >-import org.apache.poi.ss.usermodel.charts.*; >-import org.apache.poi.xssf.usermodel.XSSFWorkbook; >- >- >-import junit.framework.TestCase; >- >-public class TestXSSFNumberCache extends TestCase { >- private static Object[][] plotData = { >- {0, 1, 2, 3, 4}, >- {0, "=B1*2", "=C1*2", "=D1*2", "=E1*4"} >- }; >- >- public void testFormulaCache() { >- Workbook wb = new XSSFWorkbook(); >- Sheet sheet = new SheetBuilder(wb, plotData).build(); >- Drawing drawing = sheet.createDrawingPatriarch(); >- ClientAnchor anchor = drawing.createAnchor(0, 0, 0, 0, 1, 1, 10, 30); >- Chart chart = drawing.createChart(anchor); >- >- ChartAxis bottomAxis = chart.getChartAxisFactory().createValueAxis(AxisPosition.BOTTOM); >- ChartAxis leftAxis = chart.getChartAxisFactory().createValueAxis(AxisPosition.LEFT); >- >- ScatterChartData scatterChartData = >- chart.getChartDataFactory().createScatterChartData(); >- >- DataMarker xMarker = new DataMarker(sheet, CellRangeAddress.valueOf("A1:E1")); >- DataMarker yMarker = new DataMarker(sheet, CellRangeAddress.valueOf("A2:E2")); >- ScatterChartSerie serie = scatterChartData.addSerie(xMarker, yMarker); >- >- chart.plot(scatterChartData, bottomAxis, leftAxis); >- >- XSSFScatterChartData.Serie xssfScatterSerie = >- (XSSFScatterChartData.Serie) serie; >- XSSFNumberCache yCache = xssfScatterSerie.getLastCalculatedYCache(); >- >- assertEquals(5, yCache.getPointCount()); >- assertEquals(4.0, yCache.getValueAt(3), 0.00001); >- assertEquals(16.0, yCache.getValueAt(5), 0.00001); >- } >- >- >-} >\ No newline at end of file >Index: src/examples/src/org/apache/poi/xssf/usermodel/examples/ScatterChart.java >=================================================================== >--- src/examples/src/org/apache/poi/xssf/usermodel/examples/ScatterChart.java (revision 1132553) >+++ src/examples/src/org/apache/poi/xssf/usermodel/examples/ScatterChart.java (revision ) >@@ -20,63 +20,60 @@ > package org.apache.poi.xssf.usermodel.examples; > > import java.io.FileOutputStream; >-import java.util.Date; >- > import org.apache.poi.ss.usermodel.*; > import org.apache.poi.ss.util.*; > import org.apache.poi.ss.usermodel.charts.*; >-import org.apache.poi.xssf.usermodel.*; >-import org.apache.poi.xssf.usermodel.charts.*; >-import org.apache.poi.xssf.usermodel.XSSFWorkbook; >+import org.apache.poi.xssf.usermodel.XSSFWorkbook; > > /** > * Illustrates how to create a simple scatter chart. >+ * >+ * @author Roman Kashitsyn > */ > public class ScatterChart { > >- public static void main(String[]args) throws Exception { >+ public static void main(String[] args) throws Exception { >- Workbook wb = new XSSFWorkbook(); >+ Workbook wb = new XSSFWorkbook(); >- CreationHelper creationHelper = wb.getCreationHelper(); >- Sheet sheet = wb.createSheet("Sheet 1"); >- final int NUM_OF_ROWS = 3; >- final int NUM_OF_COLUMNS = 10; >+ Sheet sheet = wb.createSheet("Sheet 1"); >+ final int NUM_OF_ROWS = 3; >+ final int NUM_OF_COLUMNS = 10; > >- // Create a row and put some cells in it. Rows are 0 based. >- Row row; >- Cell cell; >- for (int rowIndex = 0; rowIndex < NUM_OF_ROWS; rowIndex++) { >+ // Create a row and put some cells in it. Rows are 0 based. >+ Row row; >+ Cell cell; >+ for (int rowIndex = 0; rowIndex < NUM_OF_ROWS; rowIndex++) { >- row = sheet.createRow((short)rowIndex); >+ row = sheet.createRow((short) rowIndex); >- for (int colIndex = 0; colIndex < NUM_OF_COLUMNS; colIndex++) { >+ for (int colIndex = 0; colIndex < NUM_OF_COLUMNS; colIndex++) { >- cell = row.createCell((short)colIndex); >+ cell = row.createCell((short) colIndex); >- cell.setCellValue(colIndex * (rowIndex + 1)); >- } >- } >+ cell.setCellValue(colIndex * (rowIndex + 1)); >+ } >+ } > >- Drawing drawing = sheet.createDrawingPatriarch(); >- ClientAnchor anchor = drawing.createAnchor(0, 0, 0, 0, 0, 5, 10, 15); >+ Drawing drawing = sheet.createDrawingPatriarch(); >+ ClientAnchor anchor = drawing.createAnchor(0, 0, 0, 0, 0, 5, 10, 15); > >- Chart chart = drawing.createChart(anchor); >- ChartLegend legend = chart.getOrCreateLegend(); >- legend.setPosition(LegendPosition.TOP_RIGHT); >+ Chart chart = drawing.createChart(anchor); >+ ChartLegend legend = chart.getOrCreateLegend(); >+ legend.setPosition(LegendPosition.TOP_RIGHT); > >- ScatterChartData data = chart.getChartDataFactory().createScatterChartData(); >+ ScatterChartData data = chart.getChartDataFactory().createScatterChartData(); > >- ValueAxis bottomAxis = chart.getChartAxisFactory().createValueAxis(AxisPosition.BOTTOM); >- ValueAxis leftAxis = chart.getChartAxisFactory().createValueAxis(AxisPosition.LEFT); >+ ValueAxis bottomAxis = chart.getChartAxisFactory().createValueAxis(AxisPosition.BOTTOM); >+ ValueAxis leftAxis = chart.getChartAxisFactory().createValueAxis(AxisPosition.LEFT); > >- 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)); >+ ChartDataSource<Number> xs = DataSources.fromNumericCellRange(sheet, new CellRangeAddress(0, 0, 0, NUM_OF_COLUMNS - 1)); >+ ChartDataSource<Number> ys1 = DataSources.fromNumericCellRange(sheet, new CellRangeAddress(1, 1, 0, NUM_OF_COLUMNS - 1)); >+ ChartDataSource<Number> ys2 = DataSources.fromNumericCellRange(sheet, new CellRangeAddress(2, 2, 0, NUM_OF_COLUMNS - 1)); > >- >+ >- data.addSerie(xMarker, y1Marker); >- data.addSerie(xMarker, y2Marker); >+ data.addSerie(xs, ys1); >+ data.addSerie(xs, ys2); > >- chart.plot(data, bottomAxis, leftAxis); >+ chart.plot(data, bottomAxis, leftAxis); > >- // Write the output to a file >- FileOutputStream fileOut = new FileOutputStream("ooxml-scatter-chart.xlsx"); >- wb.write(fileOut); >- fileOut.close(); >- } >+ // Write the output to a file >+ FileOutputStream fileOut = new FileOutputStream("ooxml-scatter-chart.xlsx"); >+ wb.write(fileOut); >+ fileOut.close(); >+ } > } >Index: src/ooxml/testcases/org/apache/poi/xssf/usermodel/TestXSSFChartSheet.java >=================================================================== >--- src/ooxml/testcases/org/apache/poi/xssf/usermodel/TestXSSFChartSheet.java (revision 1090442) >+++ src/ooxml/testcases/org/apache/poi/xssf/usermodel/TestXSSFChartSheet.java (revision ) >@@ -40,7 +40,7 @@ > XSSFChartSheet sheet = (XSSFChartSheet)wb.getSheetAt(2); > > for(Row row : sheet) { >- fail("Row iterator for chart sheets should return zero rows"); >+ fail("Row iterator for charts sheets should return zero rows"); > } > //access to a arbitrary row > assertEquals(null, sheet.getRow(1)); >Index: src/java/org/apache/poi/ss/usermodel/charts/ScatterChartData.java >=================================================================== >--- src/java/org/apache/poi/ss/usermodel/charts/ScatterChartData.java (revision 1132553) >+++ src/java/org/apache/poi/ss/usermodel/charts/ScatterChartData.java (revision ) >@@ -18,20 +18,17 @@ > 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 >+ * @param xs data source to be used for X axis values >+ * @param ys data source to be used for Y axis values >+ * @return a new scatter charts serie > */ >- ScatterChartSerie addSerie(DataMarker xMarker, DataMarker yMarker); >+ ScatterChartSerie addSerie(ChartDataSource<?> xs, ChartDataSource<? extends Number> ys); > > /** > * @return list of all series >Index: src/ooxml/java/org/apache/poi/xssf/usermodel/charts/XSSFChartUtil.java >=================================================================== >--- src/ooxml/java/org/apache/poi/xssf/usermodel/charts/XSSFChartUtil.java (revision ) >+++ src/ooxml/java/org/apache/poi/xssf/usermodel/charts/XSSFChartUtil.java (revision ) >@@ -0,0 +1,113 @@ >+/* ==================================================================== >+ 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.ss.usermodel.charts.ChartDataSource; >+import org.openxmlformats.schemas.drawingml.x2006.chart.*; >+ >+/** >+ * Package private class with utility methods. >+ * >+ * @author Roman Kashitsyn >+ */ >+class XSSFChartUtil { >+ >+ private XSSFChartUtil() {} >+ >+ /** >+ * Builds CTAxDataSource object content from POI ChartDataSource. >+ * @param ctAxDataSource OOXML data source to build >+ * @param dataSource POI data source to use >+ */ >+ public static void buildAxDataSource(CTAxDataSource ctAxDataSource, ChartDataSource<?> dataSource) { >+ if (dataSource.isNumeric()) { >+ if (dataSource.isReference()) { >+ buildNumRef(ctAxDataSource.addNewNumRef(), dataSource); >+ } else { >+ buildNumLit(ctAxDataSource.addNewNumLit(), dataSource); >+ } >+ } else { >+ if (dataSource.isReference()) { >+ buildStrRef(ctAxDataSource.addNewStrRef(), dataSource); >+ } else { >+ buildStrLit(ctAxDataSource.addNewStrLit(), dataSource); >+ } >+ } >+ } >+ >+ /** >+ * Builds CTNumDataSource object content from POI ChartDataSource >+ * @param ctNumDataSource OOXML data source to build >+ * @param dataSource POI data source to use >+ */ >+ public static void buildNumDataSource(CTNumDataSource ctNumDataSource, >+ ChartDataSource<? extends Number> dataSource) { >+ if (dataSource.isReference()) { >+ buildNumRef(ctNumDataSource.addNewNumRef(), dataSource); >+ } else { >+ buildNumLit(ctNumDataSource.addNewNumLit(), dataSource); >+ } >+ } >+ >+ private static void buildNumRef(CTNumRef ctNumRef, ChartDataSource<?> dataSource) { >+ ctNumRef.setF(dataSource.getFormulaString()); >+ CTNumData cache = ctNumRef.addNewNumCache(); >+ fillNumCache(cache, dataSource); >+ } >+ >+ private static void buildNumLit(CTNumData ctNumData, ChartDataSource<?> dataSource) { >+ fillNumCache(ctNumData, dataSource); >+ } >+ >+ private static void buildStrRef(CTStrRef ctStrRef, ChartDataSource<?> dataSource) { >+ ctStrRef.setF(dataSource.getFormulaString()); >+ CTStrData cache = ctStrRef.addNewStrCache(); >+ fillStringCache(cache, dataSource); >+ } >+ >+ private static void buildStrLit(CTStrData ctStrData, ChartDataSource<?> dataSource) { >+ fillStringCache(ctStrData, dataSource); >+ } >+ >+ private static void fillStringCache(CTStrData cache, ChartDataSource<?> dataSource) { >+ int numOfPoints = dataSource.getPointCount(); >+ cache.addNewPtCount().setVal(numOfPoints); >+ for (int i = 0; i < numOfPoints; ++i) { >+ Object value = dataSource.getPointAt(i); >+ if (value != null) { >+ CTStrVal ctStrVal = cache.addNewPt(); >+ ctStrVal.setIdx(i); >+ ctStrVal.setV(value.toString()); >+ } >+ } >+ >+ } >+ >+ private static void fillNumCache(CTNumData cache, ChartDataSource<?> dataSource) { >+ int numOfPoints = dataSource.getPointCount(); >+ cache.addNewPtCount().setVal(numOfPoints); >+ for (int i = 0; i < numOfPoints; ++i) { >+ Number value = (Number) dataSource.getPointAt(i); >+ if (value != null) { >+ CTNumVal ctNumVal = cache.addNewPt(); >+ ctNumVal.setIdx(i); >+ ctNumVal.setV(value.toString()); >+ } >+ } >+ } >+}
You cannot view the attachment while viewing its details because your browser does not support IFRAMEs.
View the attachment on a separate page
.
View Attachment As Diff
View Attachment As Raw
Actions:
View
|
Diff
Attachments on
bug 51196
:
26995
|
26996
|
27004
|
27021
|
27033
|
27039
|
27077
|
27294
| 27445