From 12df977d38628720ff23aaf68e856947703f6f7e Mon Sep 17 00:00:00 2001 From: PJ Fanning Date: Tue, 19 Sep 2017 21:18:09 +0000 Subject: [PATCH] Bug 61528 - Pivot Table enhancements, new example [Thanks to R Kietel]. This closes #71 git-svn-id: https://svn.apache.org/repos/asf/poi/trunk@1808945 13f79535-47bb-0310-9956-ffa450edef68 --- .../poi/xssf/usermodel/XSSFPivotTable.java | 100 +++++++++++++++++- .../usermodel/BaseTestXSSFPivotTable.java | 51 +++++++++ 2 files changed, 146 insertions(+), 5 deletions(-) diff --git a/src/ooxml/java/org/apache/poi/xssf/usermodel/XSSFPivotTable.java b/src/ooxml/java/org/apache/poi/xssf/usermodel/XSSFPivotTable.java index 9b02e5749f..c0e0fc8551 100644 --- a/src/ooxml/java/org/apache/poi/xssf/usermodel/XSSFPivotTable.java +++ b/src/ooxml/java/org/apache/poi/xssf/usermodel/XSSFPivotTable.java @@ -32,6 +32,7 @@ import org.apache.poi.ss.SpreadsheetVersion; import org.apache.poi.ss.usermodel.Cell; import org.apache.poi.ss.usermodel.CellType; import org.apache.poi.ss.usermodel.DataConsolidateFunction; +import org.apache.poi.ss.usermodel.DataFormat; import org.apache.poi.ss.usermodel.Sheet; import org.apache.poi.ss.usermodel.Workbook; import org.apache.poi.ss.util.AreaReference; @@ -291,7 +292,70 @@ public class XSSFPivotTable extends POIXMLDocumentPart { return Collections.emptyList(); } } + + /** + * Add a col label using data from the given column. + * @param columnIndex the index of the source column to be used as row label. + * {@code columnIndex} is 0-based indexed and relative to the first column in the source. + * @param valueFormat format of column value (e.g. for date: "DD.MM.YYYY") + */ + @Beta + public void addColLabel(int columnIndex, String valueFormat) { + checkColumnIndex(columnIndex); + + AreaReference pivotArea = getPivotArea(); + final int lastRowIndex = pivotArea.getLastCell().getRow() - pivotArea.getFirstCell().getRow(); + CTPivotFields pivotFields = pivotTableDefinition.getPivotFields(); + + CTPivotField pivotField = CTPivotField.Factory.newInstance(); + CTItems items = pivotField.addNewItems(); + + pivotField.setAxis(STAxis.AXIS_COL); + pivotField.setShowAll(false); + if (valueFormat != null && !"".equals(valueFormat.trim())) { + DataFormat df = parentSheet.getWorkbook().createDataFormat(); + pivotField.setNumFmtId(df.getFormat(valueFormat)); + } + for (int i = 0; i <= lastRowIndex; i++) { + items.addNewItem().setT(STItemType.DEFAULT); + } + items.setCount(items.sizeOfItemArray()); + pivotFields.setPivotFieldArray(columnIndex, pivotField); + + CTColFields colFields; + if(pivotTableDefinition.getColFields() != null) { + colFields = pivotTableDefinition.getColFields(); + } else { + colFields = pivotTableDefinition.addNewColFields(); + } + + colFields.addNewField().setX(columnIndex); + colFields.setCount(colFields.sizeOfFieldArray()); + } + + /** + * Add a col label using data from the given column. + * @param columnIndex the index of the source column to be used as row label. + * {@code columnIndex} is 0-based indexed and relative to the first column in the source. + */ + @Beta + public void addColLabel(int columnIndex) { + addColLabel(columnIndex, null); + } + @Beta + public List getColLabelColumns() { + if (pivotTableDefinition.getColFields() != null) { + List columnIndexes = new ArrayList<>(); + for (CTField f : pivotTableDefinition.getColFields().getFieldArray()) { + columnIndexes.add(f.getX()); + } + return columnIndexes; + } else { + return Collections.emptyList(); + } + } + /** * Add a column label using data from the given column and specified function * @param columnIndex the index of the source column to be used as column label. @@ -300,13 +364,14 @@ public class XSSFPivotTable extends POIXMLDocumentPart { * The following functions exists: * Sum, Count, Average, Max, Min, Product, Count numbers, StdDev, StdDevp, Var, Varp * @param valueFieldName the name of pivot table value field + * @param valueFormat format of value field (e.g. "#,##0.00") */ @Beta - public void addColumnLabel(DataConsolidateFunction function, int columnIndex, String valueFieldName) { + public void addColumnLabel(DataConsolidateFunction function, int columnIndex, String valueFieldName, String valueFormat) { checkColumnIndex(columnIndex); addDataColumn(columnIndex, true); - addDataField(function, columnIndex, valueFieldName); + addDataField(function, columnIndex, valueFieldName, valueFormat); // colfield should be added for the second one. if (pivotTableDefinition.getDataFields().getCount() == 2) { @@ -321,6 +386,20 @@ public class XSSFPivotTable extends POIXMLDocumentPart { } } + /** + * Add a column label using data from the given column and specified function + * @param columnIndex the index of the source column to be used as column label. + * {@code columnIndex} is 0-based indexed and relative to the first column in the source. + * @param function the function to be used on the data + * The following functions exists: + * Sum, Count, Average, Max, Min, Product, Count numbers, StdDev, StdDevp, Var, Varp + * @param valueFieldName the name of pivot table value field + */ + @Beta + public void addColumnLabel(DataConsolidateFunction function, int columnIndex, String valueFieldName) { + addColumnLabel(function, columnIndex, valueFieldName, null); + } + /** * Add a column label using data from the given column and specified function * @param columnIndex the index of the source column to be used as column label @@ -331,7 +410,7 @@ public class XSSFPivotTable extends POIXMLDocumentPart { */ @Beta public void addColumnLabel(DataConsolidateFunction function, int columnIndex) { - addColumnLabel(function, columnIndex, function.getName()); + addColumnLabel(function, columnIndex, function.getName(), null); } /** @@ -343,7 +422,7 @@ public class XSSFPivotTable extends POIXMLDocumentPart { * @param valueFieldName the name of pivot table value field */ @Beta - private void addDataField(DataConsolidateFunction function, int columnIndex, String valueFieldName) { + private void addDataField(DataConsolidateFunction function, int columnIndex, String valueFieldName, String valueFormat) { checkColumnIndex(columnIndex); AreaReference pivotArea = getPivotArea(); @@ -361,6 +440,10 @@ public class XSSFPivotTable extends POIXMLDocumentPart { cell.setCellType(CellType.STRING); dataField.setName(valueFieldName); dataField.setFld(columnIndex); + if (valueFormat != null && !"".equals(valueFormat.trim())) { + DataFormat df = parentSheet.getWorkbook().createDataFormat(); + dataField.setNumFmtId(df.getFormat(valueFormat)); + } dataFields.setCount(dataFields.sizeOfDataFieldArray()); } @@ -391,9 +474,16 @@ public class XSSFPivotTable extends POIXMLDocumentPart { AreaReference pivotArea = getPivotArea(); int lastRowIndex = pivotArea.getLastCell().getRow() - pivotArea.getFirstCell().getRow(); + // check and change row of location + CTLocation location = pivotTableDefinition.getLocation(); + AreaReference destination = new AreaReference(location.getRef(), SpreadsheetVersion.EXCEL2007); + if (destination.getFirstCell().getRow() < 2) { + AreaReference newDestination = new AreaReference(new CellReference(2, destination.getFirstCell().getCol()), new CellReference( + 3, destination.getFirstCell().getCol()+1), SpreadsheetVersion.EXCEL2007); + location.setRef(newDestination.formatAsString()); + } CTPivotFields pivotFields = pivotTableDefinition.getPivotFields(); - CTPivotField pivotField = CTPivotField.Factory.newInstance(); CTItems items = pivotField.addNewItems(); diff --git a/src/ooxml/testcases/org/apache/poi/xssf/usermodel/BaseTestXSSFPivotTable.java b/src/ooxml/testcases/org/apache/poi/xssf/usermodel/BaseTestXSSFPivotTable.java index c711c83e46..fb83269f4a 100644 --- a/src/ooxml/testcases/org/apache/poi/xssf/usermodel/BaseTestXSSFPivotTable.java +++ b/src/ooxml/testcases/org/apache/poi/xssf/usermodel/BaseTestXSSFPivotTable.java @@ -186,6 +186,23 @@ public abstract class BaseTestXSSFPivotTable { assertEquals(defintion.getDataFields().getDataFieldArray(0).getFld(), columnIndex); assertEquals(defintion.getDataFields().getDataFieldArray(0).getName(), customName); } + + /** + * Verify that it's possible to set the format to the data column + */ + @Test + public void testColumnLabelSetDataFormat() { + int columnIndex = 0; + + String format = "#,##0.0"; + + pivotTable.addColumnLabel(DataConsolidateFunction.SUM, columnIndex, null, format); + + CTPivotTableDefinition defintion = pivotTable.getCTPivotTableDefinition(); + + assertEquals(defintion.getDataFields().getDataFieldArray(0).getFld(), columnIndex); + assertEquals(defintion.getDataFields().getDataFieldArray(0).getNumFmtId(), wb.createDataFormat().getFormat(format)); + } /** * Verify that it's not possible to create a column label outside of the referenced area. @@ -268,4 +285,38 @@ public abstract class BaseTestXSSFPivotTable { // create a pivot table on a different sheet, case insensitive offset.createPivotTable(source, new CellReference("W1")); } + + + /** + * Verify that when creating a col label it's created on the correct column + * and the count is increased by one. + */ + @Test + public void testAddColLabelToPivotTable() { + int columnIndex = 0; + + assertEquals(0, pivotTable.getColLabelColumns().size()); + + pivotTable.addColLabel(columnIndex); + CTPivotTableDefinition defintion = pivotTable.getCTPivotTableDefinition(); + + assertEquals(defintion.getColFields().getFieldArray(0).getX(), columnIndex); + assertEquals(defintion.getColFields().getCount(), 1); + assertEquals(1, pivotTable.getColLabelColumns().size()); + + columnIndex = 1; + pivotTable.addColLabel(columnIndex); + assertEquals(2, pivotTable.getColLabelColumns().size()); + + assertEquals(0, (int)pivotTable.getColLabelColumns().get(0)); + assertEquals(1, (int)pivotTable.getColLabelColumns().get(1)); + } + + /** + * Verify that it's not possible to create a col label outside of the referenced area. + */ + @Test(expected = IndexOutOfBoundsException.class) + public void testAddColLabelOutOfRangeThrowsException() { + pivotTable.addColLabel(5); + } }