2014-07-30 11:27:09 -04:00
/ * = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
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 ;
2015-11-21 14:37:26 -05:00
import static org.apache.poi.POIXMLTypeLoader.DEFAULT_XML_OPTIONS ;
2014-07-30 11:27:09 -04:00
import java.io.IOException ;
import java.io.InputStream ;
import java.io.OutputStream ;
2014-07-30 11:44:05 -04:00
import java.util.ArrayList ;
import java.util.Collections ;
2014-07-30 11:27:09 -04:00
import java.util.List ;
import javax.xml.namespace.QName ;
import org.apache.poi.POIXMLDocumentPart ;
import org.apache.poi.openxml4j.opc.PackagePart ;
import org.apache.poi.openxml4j.opc.PackageRelationship ;
import org.apache.poi.ss.usermodel.Cell ;
2016-07-04 06:15:18 -04:00
import org.apache.poi.ss.usermodel.CellType ;
2014-07-30 11:27:09 -04:00
import org.apache.poi.ss.usermodel.DataConsolidateFunction ;
import org.apache.poi.ss.usermodel.Sheet ;
2016-09-28 17:01:40 -04:00
import org.apache.poi.ss.usermodel.Workbook ;
2014-07-30 11:27:09 -04:00
import org.apache.poi.ss.util.AreaReference ;
import org.apache.poi.ss.util.CellReference ;
import org.apache.poi.util.Beta ;
import org.apache.poi.util.Internal ;
import org.apache.xmlbeans.XmlException ;
import org.apache.xmlbeans.XmlOptions ;
2016-07-04 06:15:18 -04:00
import org.openxmlformats.schemas.spreadsheetml.x2006.main.* ;
2014-07-30 11:27:09 -04:00
public class XSSFPivotTable extends POIXMLDocumentPart {
protected final static short CREATED_VERSION = 3 ;
protected final static short MIN_REFRESHABLE_VERSION = 3 ;
protected final static short UPDATED_VERSION = 3 ;
private CTPivotTableDefinition pivotTableDefinition ;
private XSSFPivotCacheDefinition pivotCacheDefinition ;
private XSSFPivotCache pivotCache ;
private XSSFPivotCacheRecords pivotCacheRecords ;
private Sheet parentSheet ;
private Sheet dataSheet ;
@Beta
protected XSSFPivotTable ( ) {
super ( ) ;
pivotTableDefinition = CTPivotTableDefinition . Factory . newInstance ( ) ;
pivotCache = new XSSFPivotCache ( ) ;
pivotCacheDefinition = new XSSFPivotCacheDefinition ( ) ;
pivotCacheRecords = new XSSFPivotCacheRecords ( ) ;
}
/ * *
* Creates an XSSFPivotTable representing the given package part and relationship .
* Should only be called when reading in an existing file .
*
* @param part - The package part that holds xml data representing this pivot table .
2016-01-10 15:44:17 -05:00
*
* @since POI 3 . 14 - Beta1
2014-07-30 11:27:09 -04:00
* /
@Beta
2016-01-10 15:44:17 -05:00
protected XSSFPivotTable ( PackagePart part ) throws IOException {
super ( part ) ;
2014-07-30 11:27:09 -04:00
readFrom ( part . getInputStream ( ) ) ;
}
2016-01-10 15:44:17 -05:00
/ * *
* @deprecated in POI 3 . 14 , scheduled for removal in POI 3 . 16
* /
@Deprecated
protected XSSFPivotTable ( PackagePart part , PackageRelationship rel ) throws IOException {
this ( part ) ;
}
2014-07-30 11:27:09 -04:00
@Beta
public void readFrom ( InputStream is ) throws IOException {
try {
XmlOptions options = new XmlOptions ( DEFAULT_XML_OPTIONS ) ;
//Removing root element
options . setLoadReplaceDocumentElement ( null ) ;
pivotTableDefinition = CTPivotTableDefinition . Factory . parse ( is , options ) ;
} catch ( XmlException e ) {
throw new IOException ( e . getLocalizedMessage ( ) ) ;
}
}
@Beta
public void setPivotCache ( XSSFPivotCache pivotCache ) {
this . pivotCache = pivotCache ;
}
@Beta
public XSSFPivotCache getPivotCache ( ) {
return pivotCache ;
}
@Beta
public Sheet getParentSheet ( ) {
return parentSheet ;
}
@Beta
public void setParentSheet ( XSSFSheet parentSheet ) {
this . parentSheet = parentSheet ;
}
@Beta
@Internal
public CTPivotTableDefinition getCTPivotTableDefinition ( ) {
return pivotTableDefinition ;
}
@Beta
@Internal
public void setCTPivotTableDefinition ( CTPivotTableDefinition pivotTableDefinition ) {
this . pivotTableDefinition = pivotTableDefinition ;
}
@Beta
public XSSFPivotCacheDefinition getPivotCacheDefinition ( ) {
return pivotCacheDefinition ;
}
@Beta
public void setPivotCacheDefinition ( XSSFPivotCacheDefinition pivotCacheDefinition ) {
this . pivotCacheDefinition = pivotCacheDefinition ;
}
@Beta
public XSSFPivotCacheRecords getPivotCacheRecords ( ) {
return pivotCacheRecords ;
}
@Beta
public void setPivotCacheRecords ( XSSFPivotCacheRecords pivotCacheRecords ) {
this . pivotCacheRecords = pivotCacheRecords ;
}
@Beta
public Sheet getDataSheet ( ) {
return dataSheet ;
}
@Beta
private void setDataSheet ( Sheet dataSheet ) {
this . dataSheet = dataSheet ;
}
@Beta
@Override
protected void commit ( ) throws IOException {
XmlOptions xmlOptions = new XmlOptions ( DEFAULT_XML_OPTIONS ) ;
//Sets the pivotTableDefinition tag
xmlOptions . setSaveSyntheticDocumentElement ( new QName ( CTPivotTableDefinition . type . getName ( ) .
getNamespaceURI ( ) , " pivotTableDefinition " ) ) ;
PackagePart part = getPackagePart ( ) ;
OutputStream out = part . getOutputStream ( ) ;
pivotTableDefinition . save ( out , xmlOptions ) ;
out . close ( ) ;
}
/ * *
* Set default values for the table definition .
* /
@Beta
protected void setDefaultPivotTableDefinition ( ) {
//Not more than one until more created
pivotTableDefinition . setMultipleFieldFilters ( false ) ;
//Indentation increment for compact rows
pivotTableDefinition . setIndent ( 0 ) ;
//The pivot version which created the pivot cache set to default value
pivotTableDefinition . setCreatedVersion ( CREATED_VERSION ) ;
//Minimun version required to update the pivot cache
pivotTableDefinition . setMinRefreshableVersion ( MIN_REFRESHABLE_VERSION ) ;
//Version of the application which "updated the spreadsheet last"
pivotTableDefinition . setUpdatedVersion ( UPDATED_VERSION ) ;
//Titles shown at the top of each page when printed
pivotTableDefinition . setItemPrintTitles ( true ) ;
//Set autoformat properties
pivotTableDefinition . setUseAutoFormatting ( true ) ;
pivotTableDefinition . setApplyNumberFormats ( false ) ;
pivotTableDefinition . setApplyWidthHeightFormats ( true ) ;
pivotTableDefinition . setApplyAlignmentFormats ( false ) ;
pivotTableDefinition . setApplyPatternFormats ( false ) ;
pivotTableDefinition . setApplyFontFormats ( false ) ;
pivotTableDefinition . setApplyBorderFormats ( false ) ;
pivotTableDefinition . setCacheId ( pivotCache . getCTPivotCache ( ) . getCacheId ( ) ) ;
pivotTableDefinition . setName ( " PivotTable " + pivotTableDefinition . getCacheId ( ) ) ;
pivotTableDefinition . setDataCaption ( " Values " ) ;
//Set the default style for the pivot table
CTPivotTableStyle style = pivotTableDefinition . addNewPivotTableStyleInfo ( ) ;
style . setName ( " PivotStyleLight16 " ) ;
style . setShowLastColumn ( true ) ;
style . setShowColStripes ( false ) ;
style . setShowRowStripes ( false ) ;
style . setShowColHeaders ( true ) ;
style . setShowRowHeaders ( true ) ;
}
2014-07-30 11:44:05 -04:00
protected AreaReference getPivotArea ( ) {
2016-09-28 17:01:40 -04:00
final Workbook wb = getDataSheet ( ) . getWorkbook ( ) ;
AreaReference pivotArea = getPivotCacheDefinition ( ) . getPivotArea ( wb ) ;
2014-07-30 11:44:05 -04:00
return pivotArea ;
}
2016-09-18 20:20:44 -04:00
/ * *
* Verify column index ( relative to first column in pivot area ) is within the
* pivot area
*
* @param columnIndex
* @throws IndexOutOfBoundsException
* /
private void checkColumnIndex ( int columnIndex ) throws IndexOutOfBoundsException {
AreaReference pivotArea = getPivotArea ( ) ;
int size = pivotArea . getLastCell ( ) . getCol ( ) - pivotArea . getFirstCell ( ) . getCol ( ) + 1 ;
if ( columnIndex < 0 | | columnIndex > = size ) {
throw new IndexOutOfBoundsException ( " Column Index: " + columnIndex + " , Size: " + size ) ;
}
}
2014-07-30 11:44:05 -04:00
2014-07-30 11:27:09 -04:00
/ * *
* Add a row label using data from the given column .
2016-09-18 20:20:44 -04:00
* @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 .
2014-07-30 11:27:09 -04:00
* /
@Beta
public void addRowLabel ( int columnIndex ) {
2016-09-18 20:20:44 -04:00
checkColumnIndex ( columnIndex ) ;
2014-07-30 11:44:05 -04:00
AreaReference pivotArea = getPivotArea ( ) ;
2016-09-18 20:20:44 -04:00
final int lastRowIndex = pivotArea . getLastCell ( ) . getRow ( ) - pivotArea . getFirstCell ( ) . getRow ( ) ;
2014-07-30 11:27:09 -04:00
CTPivotFields pivotFields = pivotTableDefinition . getPivotFields ( ) ;
CTPivotField pivotField = CTPivotField . Factory . newInstance ( ) ;
CTItems items = pivotField . addNewItems ( ) ;
pivotField . setAxis ( STAxis . AXIS_ROW ) ;
pivotField . setShowAll ( false ) ;
2016-09-18 20:20:44 -04:00
for ( int i = 0 ; i < = lastRowIndex ; i + + ) {
2014-07-30 11:27:09 -04:00
items . addNewItem ( ) . setT ( STItemType . DEFAULT ) ;
}
2014-08-27 20:08:41 -04:00
items . setCount ( items . sizeOfItemArray ( ) ) ;
pivotFields . setPivotFieldArray ( columnIndex , pivotField ) ;
2014-07-30 11:27:09 -04:00
CTRowFields rowFields ;
if ( pivotTableDefinition . getRowFields ( ) ! = null ) {
rowFields = pivotTableDefinition . getRowFields ( ) ;
} else {
rowFields = pivotTableDefinition . addNewRowFields ( ) ;
}
rowFields . addNewField ( ) . setX ( columnIndex ) ;
2014-08-27 20:08:41 -04:00
rowFields . setCount ( rowFields . sizeOfFieldArray ( ) ) ;
2014-07-30 11:27:09 -04:00
}
2014-07-30 11:44:05 -04:00
@Beta
public List < Integer > getRowLabelColumns ( ) {
if ( pivotTableDefinition . getRowFields ( ) ! = null ) {
List < Integer > columnIndexes = new ArrayList < Integer > ( ) ;
for ( CTField f : pivotTableDefinition . getRowFields ( ) . getFieldArray ( ) ) {
columnIndexes . add ( f . getX ( ) ) ;
}
return columnIndexes ;
} else {
return Collections . emptyList ( ) ;
}
}
2014-12-21 01:12:20 -05:00
2014-07-30 11:27:09 -04:00
/ * *
* Add a column label using data from the given column and specified function
2016-09-18 20:20:44 -04:00
* @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 .
2014-07-31 09:37:33 -04:00
* @param function the function to be used on the data
2014-07-30 11:27:09 -04:00
* The following functions exists :
* Sum , Count , Average , Max , Min , Product , Count numbers , StdDev , StdDevp , Var , Varp
2014-12-21 01:12:20 -05:00
* @param valueFieldName the name of pivot table value field
2014-07-30 11:27:09 -04:00
* /
@Beta
2014-12-21 01:12:20 -05:00
public void addColumnLabel ( DataConsolidateFunction function , int columnIndex , String valueFieldName ) {
2016-09-18 20:20:44 -04:00
checkColumnIndex ( columnIndex ) ;
2014-07-30 11:27:09 -04:00
addDataColumn ( columnIndex , true ) ;
2014-12-21 01:12:20 -05:00
addDataField ( function , columnIndex , valueFieldName ) ;
2014-07-30 11:27:09 -04:00
2014-12-21 01:20:06 -05:00
// colfield should be added for the second one.
if ( pivotTableDefinition . getDataFields ( ) . getCount ( ) = = 2 ) {
2014-07-30 11:27:09 -04:00
CTColFields colFields ;
if ( pivotTableDefinition . getColFields ( ) ! = null ) {
colFields = pivotTableDefinition . getColFields ( ) ;
} else {
colFields = pivotTableDefinition . addNewColFields ( ) ;
}
colFields . addNewField ( ) . setX ( - 2 ) ;
2014-08-27 20:08:41 -04:00
colFields . setCount ( colFields . sizeOfFieldArray ( ) ) ;
2014-07-30 11:27:09 -04:00
}
}
2014-12-21 01:12:20 -05:00
/ * *
* Add a column label using data from the given column and specified function
2016-09-18 20:20:44 -04:00
* @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 . .
2014-12-21 01:12:20 -05:00
* @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
* /
@Beta
public void addColumnLabel ( DataConsolidateFunction function , int columnIndex ) {
addColumnLabel ( function , columnIndex , function . getName ( ) ) ;
}
2014-07-30 11:27:09 -04:00
/ * *
* Add data field with data from the given column and specified function .
2014-07-31 09:37:33 -04:00
* @param function the function to be used on the data
2016-05-19 16:18:08 -04:00
* The following functions exists :
* Sum , Count , Average , Max , Min , Product , Count numbers , StdDev , StdDevp , Var , Varp
* @param columnIndex the index of the column to be used as column label .
2014-12-21 01:12:20 -05:00
* @param valueFieldName the name of pivot table value field
2014-07-30 11:27:09 -04:00
* /
@Beta
2014-12-21 01:12:20 -05:00
private void addDataField ( DataConsolidateFunction function , int columnIndex , String valueFieldName ) {
2016-09-18 20:20:44 -04:00
checkColumnIndex ( columnIndex ) ;
2014-07-30 11:44:05 -04:00
AreaReference pivotArea = getPivotArea ( ) ;
2016-09-18 20:20:44 -04:00
2014-07-30 11:27:09 -04:00
CTDataFields dataFields ;
if ( pivotTableDefinition . getDataFields ( ) ! = null ) {
dataFields = pivotTableDefinition . getDataFields ( ) ;
} else {
dataFields = pivotTableDefinition . addNewDataFields ( ) ;
}
CTDataField dataField = dataFields . addNewDataField ( ) ;
dataField . setSubtotal ( STDataConsolidateFunction . Enum . forInt ( function . getValue ( ) ) ) ;
2016-05-19 16:18:08 -04:00
Cell cell = getDataSheet ( ) . getRow ( pivotArea . getFirstCell ( ) . getRow ( ) )
. getCell ( pivotArea . getFirstCell ( ) . getCol ( ) + columnIndex ) ;
2016-07-04 06:15:18 -04:00
cell . setCellType ( CellType . STRING ) ;
2014-12-21 01:12:20 -05:00
dataField . setName ( valueFieldName ) ;
2014-07-30 11:27:09 -04:00
dataField . setFld ( columnIndex ) ;
2014-08-27 20:08:41 -04:00
dataFields . setCount ( dataFields . sizeOfDataFieldArray ( ) ) ;
2014-07-30 11:27:09 -04:00
}
/ * *
* Add column containing data from the referenced area .
2014-07-31 09:37:33 -04:00
* @param columnIndex the index of the column containing the data
* @param isDataField true if the data should be displayed in the pivot table .
2014-07-30 11:27:09 -04:00
* /
@Beta
public void addDataColumn ( int columnIndex , boolean isDataField ) {
2016-09-18 20:20:44 -04:00
checkColumnIndex ( columnIndex ) ;
2014-07-30 11:27:09 -04:00
CTPivotFields pivotFields = pivotTableDefinition . getPivotFields ( ) ;
CTPivotField pivotField = CTPivotField . Factory . newInstance ( ) ;
pivotField . setDataField ( isDataField ) ;
pivotField . setShowAll ( false ) ;
2014-08-27 20:08:41 -04:00
pivotFields . setPivotFieldArray ( columnIndex , pivotField ) ;
2014-07-30 11:27:09 -04:00
}
/ * *
* Add filter for the column with the corresponding index and cell value
2014-07-31 09:37:33 -04:00
* @param columnIndex index of column to filter on
2014-07-30 11:27:09 -04:00
* /
@Beta
public void addReportFilter ( int columnIndex ) {
2016-09-18 20:20:44 -04:00
checkColumnIndex ( columnIndex ) ;
2014-07-30 11:44:05 -04:00
AreaReference pivotArea = getPivotArea ( ) ;
2014-07-30 11:27:09 -04:00
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_PAGE ) ;
pivotField . setShowAll ( false ) ;
for ( int i = 0 ; i < = lastRowIndex ; i + + ) {
items . addNewItem ( ) . setT ( STItemType . DEFAULT ) ;
}
2014-08-27 20:08:41 -04:00
items . setCount ( items . sizeOfItemArray ( ) ) ;
pivotFields . setPivotFieldArray ( columnIndex , pivotField ) ;
2014-07-30 11:27:09 -04:00
CTPageFields pageFields ;
if ( pivotTableDefinition . getPageFields ( ) ! = null ) {
pageFields = pivotTableDefinition . getPageFields ( ) ;
//Another filter has already been created
pivotTableDefinition . setMultipleFieldFilters ( true ) ;
} else {
pageFields = pivotTableDefinition . addNewPageFields ( ) ;
}
CTPageField pageField = pageFields . addNewPageField ( ) ;
pageField . setHier ( - 1 ) ;
pageField . setFld ( columnIndex ) ;
2014-08-27 20:08:41 -04:00
pageFields . setCount ( pageFields . sizeOfPageFieldArray ( ) ) ;
2014-07-30 11:27:09 -04:00
pivotTableDefinition . getLocation ( ) . setColPageCount ( pageFields . getCount ( ) ) ;
}
/ * *
* Creates cacheSource and workSheetSource for pivot table and sets the source reference as well assets the location of the pivot table
* @param position Position for pivot table in sheet
* @param sourceSheet Sheet where the source will be collected from
2016-09-28 17:01:40 -04:00
* @param refConfig an configurator that knows how to configure pivot table references
2014-07-30 11:27:09 -04:00
* /
@Beta
2016-09-28 17:01:40 -04:00
protected void createSourceReferences ( CellReference position , Sheet sourceSheet , PivotTableReferenceConfigurator refConfig ) {
2014-07-30 11:27:09 -04:00
//Get cell one to the right and one down from position, add both to AreaReference and set pivot table location.
AreaReference destination = new AreaReference ( position , new CellReference ( position . getRow ( ) + 1 , position . getCol ( ) + 1 ) ) ;
CTLocation location ;
if ( pivotTableDefinition . getLocation ( ) = = null ) {
location = pivotTableDefinition . addNewLocation ( ) ;
location . setFirstDataCol ( 1 ) ;
location . setFirstDataRow ( 1 ) ;
location . setFirstHeaderRow ( 1 ) ;
} else {
location = pivotTableDefinition . getLocation ( ) ;
}
location . setRef ( destination . formatAsString ( ) ) ;
pivotTableDefinition . setLocation ( location ) ;
//Set source for the pivot table
CTPivotCacheDefinition cacheDef = getPivotCacheDefinition ( ) . getCTPivotCacheDefinition ( ) ;
CTCacheSource cacheSource = cacheDef . addNewCacheSource ( ) ;
cacheSource . setType ( STSourceType . WORKSHEET ) ;
CTWorksheetSource worksheetSource = cacheSource . addNewWorksheetSource ( ) ;
worksheetSource . setSheet ( sourceSheet . getSheetName ( ) ) ;
setDataSheet ( sourceSheet ) ;
2016-09-28 17:01:40 -04:00
refConfig . configureReference ( worksheetSource ) ;
if ( worksheetSource . getName ( ) = = null & & worksheetSource . getRef ( ) = = null ) throw new IllegalArgumentException ( " Pivot table source area reference or name must be specified. " ) ;
2014-07-30 11:27:09 -04:00
}
@Beta
protected void createDefaultDataColumns ( ) {
CTPivotFields pivotFields ;
if ( pivotTableDefinition . getPivotFields ( ) ! = null ) {
pivotFields = pivotTableDefinition . getPivotFields ( ) ;
} else {
pivotFields = pivotTableDefinition . addNewPivotFields ( ) ;
}
2014-07-30 11:44:05 -04:00
AreaReference sourceArea = getPivotArea ( ) ;
2014-07-30 11:27:09 -04:00
int firstColumn = sourceArea . getFirstCell ( ) . getCol ( ) ;
int lastColumn = sourceArea . getLastCell ( ) . getCol ( ) ;
CTPivotField pivotField ;
2016-09-28 17:01:40 -04:00
for ( int i = firstColumn ; i < = lastColumn ; i + + ) {
2014-07-30 11:27:09 -04:00
pivotField = pivotFields . addNewPivotField ( ) ;
pivotField . setDataField ( false ) ;
pivotField . setShowAll ( false ) ;
}
2014-08-27 20:08:41 -04:00
pivotFields . setCount ( pivotFields . sizeOfPivotFieldArray ( ) ) ;
2014-07-30 11:27:09 -04:00
}
2016-09-28 17:01:40 -04:00
protected static interface PivotTableReferenceConfigurator {
/ * *
* Configure the name or area reference for the pivot table
* @param wsSource CTWorksheetSource that needs the pivot source reference assignment
* /
public void configureReference ( CTWorksheetSource wsSource ) ;
}
2014-07-30 11:44:05 -04:00
}