From: PJ Fanning Date: Tue, 27 Feb 2018 23:12:53 +0000 (+0000) Subject: [github-98] write data in respective Column in case of XDDFChart. Thanks to Sandeep... X-Git-Tag: REL_4_0_0_FINAL~230 X-Git-Url: https://source.dussan.org/?a=commitdiff_plain;h=24fee0c0d58d29584a26827113ae80bc692a60b8;p=poi.git [github-98] write data in respective Column in case of XDDFChart. Thanks to Sandeep Tiwari. This closes #98 git-svn-id: https://svn.apache.org/repos/asf/poi/trunk@1825521 13f79535-47bb-0310-9956-ffa450edef68 --- diff --git a/src/examples/src/org/apache/poi/xwpf/usermodel/examples/BarChartExampleDOCX.java b/src/examples/src/org/apache/poi/xwpf/usermodel/examples/BarChartExampleDOCX.java new file mode 100644 index 0000000000..efc5a70f87 --- /dev/null +++ b/src/examples/src/org/apache/poi/xwpf/usermodel/examples/BarChartExampleDOCX.java @@ -0,0 +1,129 @@ + +/* + * ==================================================================== + * 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.xwpf.usermodel.examples; + +import java.io.BufferedReader; +import java.io.FileInputStream; +import java.io.FileOutputStream; +import java.io.FileReader; +import java.io.OutputStream; +import java.util.ArrayList; +import java.util.List; + +import org.apache.poi.POIXMLDocumentPart; +import org.apache.poi.ss.util.CellRangeAddress; +import org.apache.poi.xddf.usermodel.chart.AxisOrientation; +import org.apache.poi.xddf.usermodel.chart.AxisPosition; +import org.apache.poi.xddf.usermodel.chart.BarDirection; +import org.apache.poi.xddf.usermodel.chart.XDDFBarChartData; +import org.apache.poi.xddf.usermodel.chart.XDDFChartData; +import org.apache.poi.xddf.usermodel.chart.XDDFDataSource; +import org.apache.poi.xddf.usermodel.chart.XDDFDataSourcesFactory; +import org.apache.poi.xddf.usermodel.chart.XDDFNumericalDataSource; +import org.apache.poi.xwpf.usermodel.XWPFChart; +import org.apache.poi.xwpf.usermodel.XWPFDocument; + +/** + * Build a bar chart from a template docx + */ +public class BarChartExampleDOCX { + private static void usage(){ + System.out.println("Usage: BarChartDemo "); + System.out.println(" bar-chart-template.docx template with a bar chart"); + System.out.println(" bar-chart-data.txt the model to set. First line is chart title, " + + "then go pairs {axis-label value}"); + } + + public static void main(String[] args) throws Exception { + if(args.length < 2) { + usage(); + return; + } + + try (FileInputStream argIS = new FileInputStream(args[0]); + BufferedReader modelReader = new BufferedReader(new FileReader(args[1]))) { + + String chartTitle = modelReader.readLine(); // first line is chart title + + // Category Axis Data + List listCategories = new ArrayList(3); + + // Values + List listValues = new ArrayList(3); + + // set model + String ln; + while((ln = modelReader.readLine()) != null){ + String[] vals = ln.split("\\s+"); + listCategories.add(vals[0]); + listValues.add(Double.valueOf(vals[1])); + } + String[] categories = listCategories.toArray(new String[listCategories.size()]); + Double[] values = listValues.toArray(new Double[listValues.size()]); + + try (XWPFDocument doc = new XWPFDocument(argIS)) { + XWPFChart chart = doc.getCharts().get(0); + setBarData(chart, chartTitle, categories, values); + chart = doc.getCharts().get(1); + setColumnData(chart, "Column variant"); + + // save the result + try (OutputStream out = new FileOutputStream("bar-chart-demo-output.docx")) { + doc.write(out); + } + } + } + System.out.println("Done"); + } + + private static void setBarData(XWPFChart chart, String chartTitle, String[] categories, Double[] values) { + final List series = chart.getChartSeries(); + final XDDFBarChartData bar = (XDDFBarChartData) series.get(0); + + final int numOfPoints = categories.length; + final String categoryDataRange = chart.formatRange(new CellRangeAddress(1, numOfPoints, 0, 0)); + final String valuesDataRange = chart.formatRange(new CellRangeAddress(1, numOfPoints, 1, 1)); + final String valuesDataRange2 = chart.formatRange(new CellRangeAddress(1, numOfPoints, 2, 2)); + final XDDFDataSource categoriesData = XDDFDataSourcesFactory.fromArray(categories, categoryDataRange, 0); + final XDDFNumericalDataSource valuesData = XDDFDataSourcesFactory.fromArray(values, valuesDataRange, 1); + values[2] = 10.0; + final XDDFNumericalDataSource valuesData2 = XDDFDataSourcesFactory.fromArray(values, valuesDataRange2, 2); + bar.getSeries().get(0).replaceData(categoriesData, valuesData); + bar.addSeries(categoriesData, valuesData2); + bar.getSeries().get(0).setTitle(chartTitle, chart.setSheetTitle(chartTitle)); + chart.plot(bar); + } + + private static void setColumnData(XWPFChart chart, String chartTitle) { + // Series Text + List series = chart.getChartSeries(); + XDDFBarChartData bar = (XDDFBarChartData) series.get(0); + bar.getSeries().get(0).setTitle(chartTitle, chart.setSheetTitle(chartTitle)); + + // in order to transform a bar chart into a column chart, you just need to change the bar direction + bar.setBarDirection(BarDirection.COL); + + // additionally, you can adjust the axes + bar.getCategoryAxis().setOrientation(AxisOrientation.MAX_MIN); + bar.getValueAxes().get(0).setPosition(AxisPosition.TOP); + } +} + diff --git a/src/examples/src/org/apache/poi/xwpf/usermodel/examples/bar-chart-data.txt b/src/examples/src/org/apache/poi/xwpf/usermodel/examples/bar-chart-data.txt new file mode 100644 index 0000000000..7f9c271036 --- /dev/null +++ b/src/examples/src/org/apache/poi/xwpf/usermodel/examples/bar-chart-data.txt @@ -0,0 +1,4 @@ +My Bar or Column Chart +First 1.0 +Second 3.0 +Third 4.0 \ No newline at end of file diff --git a/src/examples/src/org/apache/poi/xwpf/usermodel/examples/bar-chart-template.docx b/src/examples/src/org/apache/poi/xwpf/usermodel/examples/bar-chart-template.docx new file mode 100644 index 0000000000..ddd57ef0a3 Binary files /dev/null and b/src/examples/src/org/apache/poi/xwpf/usermodel/examples/bar-chart-template.docx differ diff --git a/src/ooxml/java/org/apache/poi/xddf/usermodel/chart/XDDFChart.java b/src/ooxml/java/org/apache/poi/xddf/usermodel/chart/XDDFChart.java index 99a117fd36..b39419bfca 100644 --- a/src/ooxml/java/org/apache/poi/xddf/usermodel/chart/XDDFChart.java +++ b/src/ooxml/java/org/apache/poi/xddf/usermodel/chart/XDDFChart.java @@ -21,6 +21,8 @@ package org.apache.poi.xddf.usermodel.chart; import static org.apache.poi.POIXMLTypeLoader.DEFAULT_XML_OPTIONS; +import java.io.File; +import java.io.FileOutputStream; import java.io.IOException; import java.io.OutputStream; import java.util.ArrayList; @@ -41,11 +43,14 @@ import org.apache.poi.openxml4j.exceptions.InvalidFormatException; import org.apache.poi.openxml4j.exceptions.NotOfficeXmlFileException; import org.apache.poi.openxml4j.opc.PackagePart; import org.apache.poi.openxml4j.opc.PackageRelationship; +import org.apache.poi.poifs.filesystem.POIFSFileSystem; import org.apache.poi.ss.util.CellRangeAddress; import org.apache.poi.ss.util.CellReference; import org.apache.poi.util.Beta; import org.apache.poi.util.Internal; +import org.apache.poi.util.TempFile; import org.apache.poi.xddf.usermodel.XDDFShapeProperties; +import org.apache.poi.xssf.usermodel.XSSFCell; import org.apache.poi.xssf.usermodel.XSSFRow; import org.apache.poi.xssf.usermodel.XSSFSheet; import org.apache.poi.xssf.usermodel.XSSFWorkbook; @@ -67,6 +72,9 @@ import org.openxmlformats.schemas.drawingml.x2006.chart.CTSurface; import org.openxmlformats.schemas.drawingml.x2006.chart.CTValAx; import org.openxmlformats.schemas.drawingml.x2006.chart.ChartSpaceDocument; import org.openxmlformats.schemas.drawingml.x2006.main.CTShapeProperties; +import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTTable; +import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTTableColumn; +import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTTableColumns; @Beta public abstract class XDDFChart extends POIXMLDocumentPart { @@ -78,6 +86,8 @@ public abstract class XDDFChart extends POIXMLDocumentPart { private int chartIndex = 0; + private POIXMLDocumentPart documentPart = null; + protected List axes = new ArrayList<>(); /** @@ -412,8 +422,7 @@ public abstract class XDDFChart extends POIXMLDocumentPart { * @since POI 4.0.0 */ public PackageRelationship createRelationshipInChart(POIXMLRelation chartRelation, POIXMLFactory chartFactory, int chartIndex) { - POIXMLDocumentPart documentPart = createRelationship(chartRelation, chartFactory, chartIndex, true).getDocumentPart(); - documentPart.setCommited(true); + documentPart = createRelationship(chartRelation, chartFactory, chartIndex, true).getDocumentPart(); return this.addRelation(null, chartRelation, documentPart).getRelationship(); } @@ -442,7 +451,7 @@ public abstract class XDDFChart extends POIXMLDocumentPart { * @since POI 4.0.0 */ public void saveWorkbook(XSSFWorkbook workbook) throws IOException, InvalidFormatException { - PackagePart worksheetPart = getWorksheetPart(true); + PackagePart worksheetPart = getWorksheetPart(); if (worksheetPart == null) { POIXMLRelation chartRelation = getChartRelation(); POIXMLRelation chartWorkbookRelation = getChartWorkbookRelation(); @@ -454,6 +463,7 @@ public abstract class XDDFChart extends POIXMLDocumentPart { } } try (OutputStream xlsOut = worksheetPart.getOutputStream()) { + setWorksheetPartCommitted(); workbook.write(xlsOut); } } @@ -490,9 +500,43 @@ public abstract class XDDFChart extends POIXMLDocumentPart { protected void fillSheet(XSSFSheet sheet, XDDFDataSource categoryData, XDDFNumericalDataSource valuesData) { int numOfPoints = categoryData.getPointCount(); for (int i = 0; i < numOfPoints; i++) { - XSSFRow row = sheet.createRow(i + 1); // first row is for title - row.createCell(0).setCellValue(categoryData.getPointAt(i).toString()); - row.createCell(1).setCellValue(valuesData.getPointAt(i).doubleValue()); + XSSFRow row = this.getRow(sheet, i + 1); // first row is for title + this.getCell(row, categoryData.getColIndex()).setCellValue(categoryData.getPointAt(i).toString()); + this.getCell(row, valuesData.getColIndex()).setCellValue(valuesData.getPointAt(i).doubleValue()); + } + } + + /** + * this method return row on given index + * if row is null then create new row + * + * @param sheet current sheet object + * @param index index of current row + * @return this method return sheet row on given index + * @since POI 4.0.0 + */ + private XSSFRow getRow(XSSFSheet sheet,int index){ + if (sheet.getRow(index) != null) { + return sheet.getRow(index); + } else { + return sheet.createRow(index); + } + } + + /** + * this method return cell on given index + * if cell is null then create new cell + * + * @param row current row object + * @param index index of current cell + * @return this method return sheet cell on given index + * @since POI 4.0.0 + */ + private XSSFCell getCell(XSSFRow row,int index){ + if (row.getCell(index) != null) { + return row.getCell(index); + } else { + return row.createCell(index); } } @@ -537,10 +581,33 @@ public abstract class XDDFChart extends POIXMLDocumentPart { */ public CellReference setSheetTitle(String title) { XSSFSheet sheet = getSheet(); - sheet.createRow(0).createCell(1).setCellValue(title); + XSSFRow row = this.getRow(sheet, 0); + XSSFCell cell = this.getCell(row, 1); + cell.setCellValue(title); + this.updateSheetTable(sheet.getTables().get(0).getCTTable(), title, 1); return new CellReference(sheet.getSheetName(), 0, 1, true, true); } + /** + * this method update column header of sheet into table + * + * @param ctTable xssf table object + * @param title title of column + * @param index index of column + */ + private void updateSheetTable(CTTable ctTable, String title, int index) { + CTTableColumns tableColumnList = ctTable.getTableColumns(); + CTTableColumn column = null; + if(tableColumnList.getCount() >= index) { + column = tableColumnList.getTableColumnArray(index); + } + else { + column = tableColumnList.addNewTableColumn(); + column.setId(index); + } + column.setName(title); + } + /** * @param range * @return @@ -566,17 +633,6 @@ public abstract class XDDFChart extends POIXMLDocumentPart { return sheet; } - /** - * default method for worksheet part - * - * @return return embedded worksheet part - * @throws InvalidFormatException - * @since POI 4.0.0 - */ - private PackagePart getWorksheetPart() throws InvalidFormatException { - return getWorksheetPart(false); - } - /** * this method is used to get worksheet part * if call is from saveworkbook method then check isCommitted @@ -587,18 +643,24 @@ public abstract class XDDFChart extends POIXMLDocumentPart { * @throws InvalidFormatException * @since POI 4.0.0 */ - private PackagePart getWorksheetPart(boolean isCommitted) throws InvalidFormatException { + private PackagePart getWorksheetPart() throws InvalidFormatException { for (RelationPart part : getRelationParts()) { if (POIXMLDocument.PACK_OBJECT_REL_TYPE.equals(part.getRelationship().getRelationshipType())) { - if (isCommitted) { - part.getDocumentPart().setCommited(true); - } return getTargetPart(part.getRelationship()); } } return null; } + private void setWorksheetPartCommitted() throws InvalidFormatException { + for (RelationPart part : getRelationParts()) { + if (POIXMLDocument.PACK_OBJECT_REL_TYPE.equals(part.getRelationship().getRelationshipType())) { + part.getDocumentPart().setCommited(true); + break; + } + } + } + /** * @return returns the workbook object of embedded excel file * @throws IOException @@ -631,7 +693,19 @@ public abstract class XDDFChart extends POIXMLDocumentPart { * @since POI 4.0.0 */ public void setWorkbook(XSSFWorkbook workbook) { - this.workbook = workbook; + File file; + FileOutputStream fos; + try { + file = TempFile.createTempFile("TempEmbedded",".xlsx"); + fos = new FileOutputStream(file); + workbook.write(fos); + fos.close(); + this.workbook = new XSSFWorkbook(file); + } catch (IOException e) { + + } catch (InvalidFormatException e) { + + } } /** diff --git a/src/ooxml/java/org/apache/poi/xddf/usermodel/chart/XDDFDataSource.java b/src/ooxml/java/org/apache/poi/xddf/usermodel/chart/XDDFDataSource.java index f6c19a1d1d..1ab617571d 100644 --- a/src/ooxml/java/org/apache/poi/xddf/usermodel/chart/XDDFDataSource.java +++ b/src/ooxml/java/org/apache/poi/xddf/usermodel/chart/XDDFDataSource.java @@ -31,5 +31,7 @@ public interface XDDFDataSource { boolean isNumeric(); + int getColIndex(); + String getDataRangeReference(); } diff --git a/src/ooxml/java/org/apache/poi/xddf/usermodel/chart/XDDFDataSourcesFactory.java b/src/ooxml/java/org/apache/poi/xddf/usermodel/chart/XDDFDataSourcesFactory.java index a740d92f4f..be8a34ad23 100644 --- a/src/ooxml/java/org/apache/poi/xddf/usermodel/chart/XDDFDataSourcesFactory.java +++ b/src/ooxml/java/org/apache/poi/xddf/usermodel/chart/XDDFDataSourcesFactory.java @@ -68,6 +68,11 @@ public class XDDFDataSourcesFactory { public String getDataRangeReference() { return categoryDS.getStrRef().getF(); } + + @Override + public int getColIndex() { + return 0; + } }; } @@ -110,6 +115,11 @@ public class XDDFDataSourcesFactory { public String getDataRangeReference() { return valuesDS.getNumRef().getF(); } + + @Override + public int getColIndex() { + return 0; + } }; } @@ -121,6 +131,14 @@ public class XDDFDataSourcesFactory { return new StringArrayDataSource(elements, dataRange); } + public static XDDFNumericalDataSource fromArray(T[] elements, String dataRange, int col) { + return new NumericalArrayDataSource(elements, dataRange, col); + } + + public static XDDFCategoryDataSource fromArray(String[] elements, String dataRange, int col) { + return new StringArrayDataSource(elements, dataRange, col); + } + public static XDDFNumericalDataSource fromNumericCellRange(XSSFSheet sheet, CellRangeAddress cellRangeAddress) { return new NumericalCellRangeDataSource(sheet, cellRangeAddress); @@ -133,12 +151,19 @@ public class XDDFDataSourcesFactory { private abstract static class AbstractArrayDataSource implements XDDFDataSource { private final T[] elements; private final String dataRange; + private int col = 0; public AbstractArrayDataSource(T[] elements, String dataRange) { this.elements = elements.clone(); this.dataRange = dataRange; } + public AbstractArrayDataSource(T[] elements, String dataRange, int col) { + this.elements = elements.clone(); + this.dataRange = dataRange; + this.col = col; + } + @Override public int getPointCount() { return elements.length; @@ -168,6 +193,11 @@ public class XDDFDataSourcesFactory { return dataRange; } } + + @Override + public int getColIndex() { + return col; + } } private static class NumericalArrayDataSource extends AbstractArrayDataSource @@ -178,6 +208,10 @@ public class XDDFDataSourcesFactory { super(elements, dataRange); } + public NumericalArrayDataSource(T[] elements, String dataRange, int col) { + super(elements, dataRange, col); + } + @Override public String getFormatCode() { return formatCode; @@ -194,6 +228,10 @@ public class XDDFDataSourcesFactory { public StringArrayDataSource(String[] elements, String dataRange) { super(elements, dataRange); } + + public StringArrayDataSource(String[] elements, String dataRange, int col) { + super(elements, dataRange, col); + } } private abstract static class AbstractCellRangeDataSource implements XDDFDataSource { @@ -220,6 +258,11 @@ public class XDDFDataSourcesFactory { return true; } + @Override + public int getColIndex() { + return cellRangeAddress.getFirstColumn(); + } + @Override public String getDataRangeReference() { return cellRangeAddress.formatAsString(sheet.getSheetName(), true); @@ -262,7 +305,7 @@ public class XDDFDataSourcesFactory { @Override public Double getPointAt(int index) { CellValue cellValue = getCellValueAt(index); - if (cellValue != null && cellValue.getCellTypeEnum() == CellType.NUMERIC) { + if (cellValue != null && cellValue.getCellType() == CellType.NUMERIC) { return Double.valueOf(cellValue.getNumberValue()); } else { return null; @@ -284,7 +327,7 @@ public class XDDFDataSourcesFactory { @Override public String getPointAt(int index) { CellValue cellValue = getCellValueAt(index); - if (cellValue != null && cellValue.getCellTypeEnum() == CellType.STRING) { + if (cellValue != null && cellValue.getCellType() == CellType.STRING) { return cellValue.getStringValue(); } else { return null; diff --git a/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFGraphicFrame.java b/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFGraphicFrame.java index b2cf29e43b..35da6bf558 100644 --- a/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFGraphicFrame.java +++ b/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFGraphicFrame.java @@ -189,7 +189,7 @@ public class XSLFGraphicFrame extends XSLFShape implements GraphicalFrame