/* ====================================================================
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;import static org.apache.poi.POIXMLTypeLoader.DEFAULT_XML_OPTIONS;import static org.apache.poi.xssf.usermodel.helpers.XSSFPasswordHelper.setPassword;import static org.apache.poi.xssf.usermodel.helpers.XSSFPasswordHelper.validatePassword;import java.io.ByteArrayInputStream;import java.io.ByteArrayOutputStream;import java.io.File;import java.io.IOException;import java.io.InputStream;import java.io.OutputStream;import java.util.ArrayList;import java.util.Collection;import java.util.Collections;import java.util.HashMap;import java.util.Iterator;import java.util.LinkedList;import java.util.List;import java.util.Locale;import java.util.Map;import java.util.NoSuchElementException;import java.util.regex.Pattern;import javax.xml.namespace.QName;import org.apache.commons.collections4.ListValuedMap;import org.apache.commons.collections4.multimap.ArrayListValuedHashMap;import org.apache.poi.POIXMLDocument;import org.apache.poi.POIXMLDocumentPart;import org.apache.poi.POIXMLException;import org.apache.poi.POIXMLProperties;import org.apache.poi.hpsf.ClassID;import org.apache.poi.openxml4j.exceptions.InvalidFormatException;import org.apache.poi.openxml4j.exceptions.OpenXML4JException;import org.apache.poi.openxml4j.opc.OPCPackage;import org.apache.poi.openxml4j.opc.PackageAccess;import org.apache.poi.openxml4j.opc.PackagePart;import org.apache.poi.openxml4j.opc.PackagePartName;import org.apache.poi.openxml4j.opc.PackageRelationship;import org.apache.poi.openxml4j.opc.PackageRelationshipTypes;import org.apache.poi.openxml4j.opc.PackagingURIHelper;import org.apache.poi.openxml4j.opc.TargetMode;import org.apache.poi.poifs.crypt.HashAlgorithm;import org.apache.poi.poifs.filesystem.DirectoryNode;import org.apache.poi.poifs.filesystem.Ole10Native;import org.apache.poi.poifs.filesystem.POIFSFileSystem;import org.apache.poi.ss.SpreadsheetVersion;import org.apache.poi.ss.formula.SheetNameFormatter;import org.apache.poi.ss.formula.udf.AggregatingUDFFinder;import org.apache.poi.ss.formula.udf.IndexedUDFFinder;import org.apache.poi.ss.formula.udf.UDFFinder;import org.apache.poi.ss.usermodel.Name;import org.apache.poi.ss.usermodel.Row;import org.apache.poi.ss.usermodel.Row.MissingCellPolicy;import org.apache.poi.ss.usermodel.Sheet;import org.apache.poi.ss.usermodel.SheetVisibility;import org.apache.poi.ss.usermodel.Workbook;import org.apache.poi.ss.util.CellReference;import org.apache.poi.ss.util.WorkbookUtil;import org.apache.poi.util.Beta;import org.apache.poi.util.IOUtils;import org.apache.poi.util.Internal;import org.apache.poi.util.NotImplemented;import org.apache.poi.util.POILogFactory;import org.apache.poi.util.POILogger;import org.apache.poi.util.PackageHelper;import org.apache.poi.util.Removal;import org.apache.poi.util.Units;import org.apache.poi.xssf.XLSBUnsupportedException;import org.apache.poi.xssf.model.CalculationChain;import org.apache.poi.xssf.model.ExternalLinksTable;import org.apache.poi.xssf.model.MapInfo;import org.apache.poi.xssf.model.SharedStringsTable;import org.apache.poi.xssf.model.StylesTable;import org.apache.poi.xssf.model.ThemesTable;import org.apache.poi.xssf.usermodel.helpers.XSSFFormulaUtils;import org.apache.xmlbeans.XmlException;import org.apache.xmlbeans.XmlObject;import org.apache.xmlbeans.XmlOptions;import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTBookView;import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTBookViews;import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTCalcPr;import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTDefinedName;import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTDefinedNames;import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTDialogsheet;import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTExternalReference;import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTPivotCache;import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTPivotCaches;import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTSheet;import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTSheets;import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTWorkbook;import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTWorkbookPr;import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTWorkbookProtection;import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTWorksheet;import org.openxmlformats.schemas.spreadsheetml.x2006.main.STCalcMode;import org.openxmlformats.schemas.spreadsheetml.x2006.main.STSheetState;import org.openxmlformats.schemas.spreadsheetml.x2006.main.WorkbookDocument;/**
* High level representation of a SpreadsheetML workbook. This is the first object most users
* will construct whether they are reading or writing a workbook. It is also the
* top level object for creating new sheets/etc.
*/public class XSSFWorkbookextends POIXMLDocumentimplements Workbook{
privatestaticfinalPatternCOMMA_PATTERN= Pattern.compile(",");/**
* Width of one character of the default font in pixels. Same for Calibry and Arial.
* @deprecated POI 3.17 beta 1
* @see Units#DEFAULT_CHARACTER_WIDTH
*/@Removal(version="3.19")publicstaticfinalfloatDEFAULT_CHARACTER_WIDTH= Units.DEFAULT_CHARACTER_WIDTH;/**
* Excel silently truncates long sheet names to 31 chars.
* This constant is used to ensure uniqueness in the first 31 chars
*/privatestaticfinalintMAX_SENSITIVE_SHEET_NAME_LEN= 31;/**
* Images formats supported by XSSF but not by HSSF
*/publicstaticfinalintPICTURE_TYPE_GIF= 8;publicstaticfinalintPICTURE_TYPE_TIFF= 9;publicstaticfinalintPICTURE_TYPE_EPS= 10;publicstaticfinalintPICTURE_TYPE_BMP= 11;publicstaticfinalintPICTURE_TYPE_WPG= 12;/**
* The underlying XML bean
*/privateCTWorkbookworkbook;/**
* this holds the XSSFSheet objects attached to this workbook
*/privateList<XSSFSheet>sheets;/**
* this holds the XSSFName objects attached to this workbook, keyed by lower-case name
*/privateListValuedMap<String, XSSFName>namedRangesByName;/**
* this holds the XSSFName objects attached to this workbook
*/privateList<XSSFName>namedRanges;/**
* shared string table - a cache of strings in this workbook
*/privateSharedStringsTablesharedStringSource;/**
* A collection of shared objects used for styling content,
* e.g. fonts, cell styles, colors, etc.
*/privateStylesTablestylesSource;/**
* The locator of user-defined functions.
* By default includes functions from the Excel Analysis Toolpack
*/privateIndexedUDFFinder_udfFinder= newIndexedUDFFinder(AggregatingUDFFinder.DEFAULT);/**
* TODO
*/privateCalculationChaincalcChain;/**
* External Links, for referencing names or cells in other workbooks.
*/privateList<ExternalLinksTable>externalLinks;/**
* A collection of custom XML mappings
*/privateMapInfomapInfo;/**
* Used to keep track of the data formatter so that all
* createDataFormatter calls return the same one for a given
* book. This ensures that updates from one places is visible
* someplace else.
*/privateXSSFDataFormatformatter;/**
* The policy to apply in the event of missing or
* blank cells when fetching from a row.
* See {@link org.apache.poi.ss.usermodel.Row.MissingCellPolicy}
*/privateMissingCellPolicy_missingCellPolicy= MissingCellPolicy.RETURN_NULL_AND_BLANK;/**
* array of pictures for this workbook
*/privateList<XSSFPictureData>pictures;privatestaticPOILoggerlogger= POILogFactory.getLogger(XSSFWorkbook.class);/**
* cached instance of XSSFCreationHelper for this workbook
* @see #getCreationHelper()
*/privateXSSFCreationHelper_creationHelper;/**
* List of all pivot tables in workbook
*/privateList<XSSFPivotTable>pivotTables;privateList<CTPivotCache>pivotCaches;/**
* Create a new SpreadsheetML workbook.
*
* XSSFWorkbook is a constructor stereotype that returns an object: XSSFWorkbook
*/publicXSSFWorkbook(){
this(XSSFWorkbookType.XLSX);
}/**
* Create a new SpreadsheetML workbook.
* @param workbookType The type of workbook to make (.xlsx or .xlsm).
*
* XSSFWorkbook is a constructor stereotype that returns an object: XSSFWorkbook
* It makes calls to the following methods: OnWorkbookCreate, and super
*/publicXSSFWorkbook(XSSFWorkbookTypeworkbookType){
super(newPackage(workbookType));onWorkbookCreate();
}/**
* Constructs a XSSFWorkbook object given a OpenXML4J <code>Package</code> object,
* see <a href="http://poi.apache.org/oxml4j/">http://poi.apache.org/oxml4j/</a>.
*
* <p>Once you have finished working with the Workbook, you should close the package
* by calling either {@link #close()} or {@link OPCPackage#close()}, to avoid
* leaving file handles open.
*
* <p>Creating a XSSFWorkbook from a file-backed OPC Package has a lower memory
* footprint than an InputStream backed one.
*
* @param pkg the OpenXML4J <code>OPC Package</code> object.
*
* XSSFWorkbook is a constructor stereotype that returns an object: XSSFWorkbook
* It makes calls to the following methods: beforeDocumentRead, load, getInstance, isSetBookViews, addNewBookViews, addNewWorkbookView, and setActiveTab
*/publicXSSFWorkbook(OPCPackagepkg)throws IOException{
super(pkg);beforeDocumentRead();// Build a tree of POIXMLDocumentParts, this workbook being the rootload(XSSFFactory.getInstance());// some broken Workbooks miss this...if(!workbook.isSetBookViews()){
CTBookViewsbvs= workbook.addNewBookViews();CTBookViewbv= bvs.addNewWorkbookView();bv.setActiveTab(0);
}
}/**
* Constructs a XSSFWorkbook object, by buffering the whole stream into memory
* and then opening an {@link OPCPackage} object for it.
*
* <p>Using an {@link InputStream} requires more memory than using a File, so
* if a {@link File} is available then you should instead do something like
* <pre><code>
* OPCPackage pkg = OPCPackage.open(path);
* XSSFWorkbook wb = new XSSFWorkbook(pkg);
* // work with the wb object
* ......
* pkg.close(); // gracefully closes the underlying zip file
* </code></pre>
*
* XSSFWorkbook is a constructor stereotype that returns an object: XSSFWorkbook
* It makes calls to the following methods: beforeDocumentRead, load, getInstance, isSetBookViews, addNewBookViews, addNewWorkbookView, and setActiveTab
*/publicXSSFWorkbook(InputStreamis)throws IOException{
super(PackageHelper.open(is));beforeDocumentRead();// Build a tree of POIXMLDocumentParts, this workbook being the rootload(XSSFFactory.getInstance());// some broken Workbooks miss this...if(!workbook.isSetBookViews()){
CTBookViewsbvs= workbook.addNewBookViews();CTBookViewbv= bvs.addNewWorkbookView();bv.setActiveTab(0);
}
}/**
* Constructs a XSSFWorkbook object from a given file.
*
* <p>Once you have finished working with the Workbook, you should close
* the package by calling {@link #close()}, to avoid leaving file
* handles open.
*
* <p>Opening a XSSFWorkbook from a file has a lower memory footprint
* than opening from an InputStream
*
* @param file the file to open
*
* XSSFWorkbook is a constructor stereotype that returns an object: XSSFWorkbook
* It makes calls to the following methods: open
*/publicXSSFWorkbook(Filefile)throws IOException, InvalidFormatException{
this(OPCPackage.open(file));
}/**
* Constructs a XSSFWorkbook object given a file name.
*
*
* <p>Once you have finished working with the Workbook, you should close
* the package by calling {@link #close()}, to avoid leaving file
* handles open.
*
* <p>Opening a XSSFWorkbook from a file has a lower memory footprint
* than opening from an InputStream
*
* @param path the file name.
*
* XSSFWorkbook is a constructor stereotype that returns an object: XSSFWorkbook
* It makes calls to the following methods: beforeDocumentRead, load, getInstance, isSetBookViews, addNewBookViews, addNewWorkbookView, and setActiveTab
*/publicXSSFWorkbook(Stringpath)throws IOException{
this(openPackage(path));
}/*
*
* beforeDocumentRead is a command stereotype.
* It modifies the following member variables: pivotCaches, and pivotTables.
* It makes calls to the following method(s): pivotCaches, and pivotTables
*/protectedvoidbeforeDocumentRead(){
// Ensure it isn't a XLSB file, which we don't supportif (getCorePart().getContentType().equals(XSSFRelation.XLSB_BINARY_WORKBOOK.getContentType())){
throw newXLSBUnsupportedException();
}// Create arrays for parts attached to the workbook itselfpivotTables=newArrayList<XSSFPivotTable>();pivotCaches=newArrayList<CTPivotCache>();
}/*
*
* onDocumentRead is a command stereotype.
* It modifies the following member variables: calcChain, externalLinks, mapInfo, sharedStringSource, sheets, and stylesSourceworkbook.
* It modifies more than 5 data members.
* It modifies member variables via the following method calls: XSSFFactory via getInstance, externalLinks via add, logger via log, stylesSource via setTheme, stylesSource via setWorkbook, this via workbook.getExternalReferences, and this via workbook.getSheets.
* It makes calls to the following method(s): externalLinks, getRelationship, parseSheet, reprocessNamedRanges, sharedStringSource, sheets, and stylesSource
*/@OverrideprotectedvoidonDocumentRead()throws IOException{
try {
WorkbookDocumentdoc= WorkbookDocument.Factory.parse(getPackagePart().getInputStream(), DEFAULT_XML_OPTIONS);this.workbook=doc.getWorkbook();ThemesTabletheme= null;Map<String, XSSFSheet>shIdMap= newHashMap<String, XSSFSheet>();Map<String, ExternalLinksTable>elIdMap= newHashMap<String, ExternalLinksTable>();for(RelationPartrp: getRelationParts()){
POIXMLDocumentPartp= rp.getDocumentPart();if(pinstanceofSharedStringsTable){
sharedStringSource=(SharedStringsTable)p;
}else if(pinstanceofStylesTable){
stylesSource=(StylesTable)p;
}else if(pinstanceofThemesTable){
theme=(ThemesTable)p;
}else if(pinstanceofCalculationChain){
calcChain=(CalculationChain)p;
}else if(pinstanceofMapInfo){
mapInfo=(MapInfo)p;
}else if (pinstanceofXSSFSheet){
shIdMap.put(rp.getRelationship().getId(), (XSSFSheet)p);
}else if (pinstanceofExternalLinksTable){
elIdMap.put(rp.getRelationship().getId(), (ExternalLinksTable)p);
}
}booleanpackageReadOnly= (getPackage().getPackageAccess()==PackageAccess.READ);if (stylesSource==null){
// Create Styles if it is missingif (packageReadOnly){
stylesSource=newStylesTable();
}else {
stylesSource=(StylesTable)createRelationship(XSSFRelation.STYLES, XSSFFactory.getInstance());
}
}stylesSource.setWorkbook(this);stylesSource.setTheme(theme);if (sharedStringSource==null){
// Create SST if it is missingif (packageReadOnly){
sharedStringSource=newSharedStringsTable();
}else {
sharedStringSource=(SharedStringsTable)createRelationship(XSSFRelation.SHARED_STRINGS, XSSFFactory.getInstance());
}
}// Load individual sheets. The order of sheets is defined by the order// of CTSheet elements in the workbooksheets=newArrayList<XSSFSheet>(shIdMap.size());//noinspection deprecationfor (CTSheetctSheet: this.workbook.getSheets().getSheetArray()){
parseSheet(shIdMap, ctSheet);
}// Load the external links tables. Their order is defined by the order // of CTExternalReference elements in the workbookexternalLinks=newArrayList<ExternalLinksTable>(elIdMap.size());if (this.workbook.isSetExternalReferences()){
for (CTExternalReferenceer: this.workbook.getExternalReferences().getExternalReferenceArray()){
ExternalLinksTableel= elIdMap.get(er.getId());if(el==null){
logger.log(POILogger.WARN, "ExternalLinksTable with r:id "+er.getId()+" was defined, but didn't exist in package, skipping");continue;
}externalLinks.add(el);
}
}// Process the named rangesreprocessNamedRanges();
}catch (XmlExceptione){
throw newPOIXMLException(e);
}
}/**
* Not normally to be called externally, but possibly to be overridden to avoid
* the DOM based parse of large sheets (see examples).
*/publicvoidparseSheet(Map<String, XSSFSheet>shIdMap, CTSheetctSheet){
XSSFSheetsh= shIdMap.get(ctSheet.getId());if(sh==null){
logger.log(POILogger.WARN, "Sheet with name "+ctSheet.getName()+" and r:id "+ctSheet.getId()+" was defined, but didn't exist in package, skipping");return;
}sh.sheet=ctSheet;sh.onDocumentRead();sheets.add(sh);
}/**
* Create a new CTWorkbook with all values set to default
*
* onWorkbookCreate is a command stereotype.
* It modifies the following member variables: namedRanges, namedRangesByName, pivotTables, sharedStringSource, sheets, stylesSource, and workbook.
* It modifies more than 5 data members.
* It modifies member variables via the following method calls: XSSFFactory via getInstance, stylesSource via setWorkbook, and workbook via addNewSheets.
* It makes calls to the following method(s): getUnderlyingProperties, namedRanges, namedRangesByName, pivotTables, sharedStringSource, sheets, and stylesSource
*/privatevoidonWorkbookCreate(){
workbook=CTWorkbook.Factory.newInstance();// don't EVER use the 1904 date systemCTWorkbookPrworkbookPr= workbook.addNewWorkbookPr();workbookPr.setDate1904(false);CTBookViewsbvs= workbook.addNewBookViews();CTBookViewbv= bvs.addNewWorkbookView();bv.setActiveTab(0);workbook.addNewSheets();POIXMLProperties.ExtendedPropertiesexpProps= getProperties().getExtendedProperties();expProps.getUnderlyingProperties().setApplication(DOCUMENT_CREATOR);sharedStringSource=(SharedStringsTable)createRelationship(XSSFRelation.SHARED_STRINGS, XSSFFactory.getInstance());stylesSource=(StylesTable)createRelationship(XSSFRelation.STYLES, XSSFFactory.getInstance());stylesSource.setWorkbook(this);namedRanges=newArrayList<XSSFName>();namedRangesByName=newArrayListValuedHashMap<String, XSSFName>();sheets=newArrayList<XSSFSheet>();pivotTables=newArrayList<XSSFPivotTable>();
}/**
* Create a new SpreadsheetML package and setup the default minimal content
*
* newPackage is a set stereotype.
*/protectedstaticOPCPackagenewPackage(XSSFWorkbookTypeworkbookType){
try {
OPCPackagepkg= OPCPackage.create(newByteArrayOutputStream());// Main partPackagePartNamecorePartName= PackagingURIHelper.createPartName(XSSFRelation.WORKBOOK.getDefaultFileName());// Create main part relationshippkg.addRelationship(corePartName, TargetMode.INTERNAL, PackageRelationshipTypes.CORE_DOCUMENT);// Create main document partpkg.createPart(corePartName, workbookType.getContentType());pkg.getPackageProperties().setCreatorProperty(DOCUMENT_CREATOR);return pkg;
}catch (Exceptione){
throw newPOIXMLException(e);
}
}/**
* Return the underlying XML bean
*
* @return the underlying CTWorkbook bean
*
* getCTWorkbook is a get stereotype.
* It returns one data member: workbook.
*/@InternalpublicCTWorkbookgetCTWorkbook(){
return this.workbook;
}/**
* Adds a picture to the workbook.
*
* @param pictureData The bytes of the picture
* @param format The format of the picture.
*
* @return the index to this picture (0 based), the added picture can be obtained from {@link #getAllPictures()} .
* @see Workbook#PICTURE_TYPE_EMF
* @see Workbook#PICTURE_TYPE_WMF
* @see Workbook#PICTURE_TYPE_PICT
* @see Workbook#PICTURE_TYPE_JPEG
* @see Workbook#PICTURE_TYPE_PNG
* @see Workbook#PICTURE_TYPE_DIB
* @see #getAllPictures()
*
* addPicture is a get stereotype.
* It returns one data member: imageNumber - 1.
* It delegates to a call: out via close, out via write, and pictures via add.
*/@OverridepublicintaddPicture(byte[]pictureData, intformat){
intimageNumber= getAllPictures().size()+1;XSSFPictureDataimg= (XSSFPictureData)createRelationship(XSSFPictureData.RELATIONS[format], XSSFFactory.getInstance(), imageNumber, true).getDocumentPart();try {
OutputStreamout= img.getPackagePart().getOutputStream();out.write(pictureData);out.close();
}catch (IOExceptione){
throw newPOIXMLException(e);
}pictures.add(img);return imageNumber-1;
}/**
* Adds a picture to the workbook.
*
* @param is The sream to read image from
* @param format The format of the picture.
*
* @return the index to this picture (0 based), the added picture can be obtained from {@link #getAllPictures()} .
* @see Workbook#PICTURE_TYPE_EMF
* @see Workbook#PICTURE_TYPE_WMF
* @see Workbook#PICTURE_TYPE_PICT
* @see Workbook#PICTURE_TYPE_JPEG
* @see Workbook#PICTURE_TYPE_PNG
* @see Workbook#PICTURE_TYPE_DIB
* @see #getAllPictures()
*
* addPicture is a get stereotype.
* It returns one data member: imageNumber - 1.
* It delegates to a call: IOUtils via copy, out via close, and pictures via add.
*/publicintaddPicture(InputStreamis, intformat)throws IOException{
intimageNumber= getAllPictures().size()+1;XSSFPictureDataimg= createRelationship(XSSFPictureData.RELATIONS[format], XSSFFactory.getInstance(), imageNumber, true).getDocumentPart();OutputStreamout= img.getPackagePart().getOutputStream();IOUtils.copy(is, out);out.close();pictures.add(img);return imageNumber-1;
}/**
* Create an XSSFSheet from an existing sheet in the XSSFWorkbook.
* The cloned sheet is a deep copy of the original.
*
* @param sheetNum The index of the sheet to clone
* @return XSSFSheet representing the cloned sheet.
* @throws IllegalArgumentException if the sheet index in invalid
* @throws POIXMLException if there were errors when cloning
*
* cloneSheet is a property stereotype.
* It has a single return, which delegates to the following call(s): cloneSheet(sheetNum, null).
* The return value depends on the following parameter(s): sheetNum.
*/@OverridepublicXSSFSheetcloneSheet(intsheetNum){
return cloneSheet(sheetNum, null);
}/**
* Create an XSSFSheet from an existing sheet in the XSSFWorkbook.
* The cloned sheet is a deep copy of the original but with a new given
* name.
*
* @param sheetNum The index of the sheet to clone
* @param newName The name to set for the newly created sheet
* @return XSSFSheet representing the cloned sheet.
* @throws IllegalArgumentException if the sheet index or the sheet
* name is invalid
* @throws POIXMLException if there were errors when cloning
*
* cloneSheet is a set stereotype.
* It modifies one member variable using the method call: logger via log.
*/publicXSSFSheetcloneSheet(intsheetNum, StringnewName){
validateSheetIndex(sheetNum);XSSFSheetsrcSheet= sheets.get(sheetNum);if (newName==null){
StringsrcName= srcSheet.getSheetName();newName=getUniqueSheetName(srcName);
}else {
validateSheetName(newName);
}XSSFSheetclonedSheet= createSheet(newName);// copy sheet's relationsList<RelationPart>rels= srcSheet.getRelationParts();// if the sheet being cloned has a drawing then remember it and re-create it tooXSSFDrawingdg= null;for(RelationPartrp: rels){
POIXMLDocumentPartr= rp.getDocumentPart();// do not copy the drawing relationship, it will be re-createdif(rinstanceofXSSFDrawing){
dg=(XSSFDrawing)r;continue;
}addRelation(rp, clonedSheet);
}try {
for(PackageRelationshippr: srcSheet.getPackagePart().getRelationships()){
if (pr.getTargetMode()==TargetMode.EXTERNAL){
clonedSheet.getPackagePart().addExternalRelationship(pr.getTargetURI().toASCIIString(), pr.getRelationshipType(), pr.getId());
}
}
}catch (InvalidFormatExceptione){
throw newPOIXMLException("Failed to clone sheet", e);
}try {
ByteArrayOutputStreamout= newByteArrayOutputStream();srcSheet.write(out);clonedSheet.read(newByteArrayInputStream(out.toByteArray()));
}catch (IOExceptione){
throw newPOIXMLException("Failed to clone sheet", e);
}CTWorksheetct= clonedSheet.getCTWorksheet();if(ct.isSetLegacyDrawing()){
logger.log(POILogger.WARN, "Cloning sheets with comments is not yet supported.");ct.unsetLegacyDrawing();
}if (ct.isSetPageSetup()){
logger.log(POILogger.WARN, "Cloning sheets with page setup is not yet supported.");ct.unsetPageSetup();
}clonedSheet.setSelected(false);// clone the sheet drawing along with its relationshipsif (dg!=null){
if(ct.isSetDrawing()){
// unset the existing reference to the drawing,// so that subsequent call of clonedSheet.createDrawingPatriarch() will create a new onect.unsetDrawing();
}XSSFDrawingclonedDg= clonedSheet.createDrawingPatriarch();// copy drawing contentsclonedDg.getCTDrawing().set(dg.getCTDrawing());clonedDg=clonedSheet.createDrawingPatriarch();// Clone drawing relationsList<RelationPart>srcRels= srcSheet.createDrawingPatriarch().getRelationParts();for (RelationPartrp: srcRels){
addRelation(rp, clonedDg);
}
}return clonedSheet;
}/**
* @since 3.14-Beta1
*/privatestaticvoidaddRelation(RelationPartrp, POIXMLDocumentParttarget){
PackageRelationshiprel= rp.getRelationship();if (rel.getTargetMode()==TargetMode.EXTERNAL){
target.getPackagePart().addRelationship(
rel.getTargetURI(), rel.getTargetMode(), rel.getRelationshipType(), rel.getId());
}else {
XSSFRelationxssfRel= XSSFRelation.getInstance(rel.getRelationshipType());if (xssfRel==null){
// Don't copy all relations blindly, but only the ones we know aboutthrow newPOIXMLException("Can't clone sheet - unknown relation type found: "+rel.getRelationshipType());
}target.addRelation(rel.getId(), xssfRel, rp.getDocumentPart());
}
}privateStringgetUniqueSheetName(StringsrcName){
intuniqueIndex= 2;StringbaseName= srcName;intbracketPos= srcName.lastIndexOf('(');if (bracketPos>0&&srcName.endsWith(")")){
Stringsuffix= srcName.substring(bracketPos+1, srcName.length()-")".length());try {
uniqueIndex=Integer.parseInt(suffix.trim());uniqueIndex++;baseName=srcName.substring(0, bracketPos).trim();
}catch (NumberFormatExceptione){
// contents of brackets not numeric
}
}while (true){
// Try and find the next sheet name that is uniqueStringindex= Integer.toString(uniqueIndex++);Stringname;if (baseName.length()+index.length()+2<31){
name=baseName+" ("+index+")";
}else {
name=baseName.substring(0, 31-index.length()-2)+"("+index+")";
}//If the sheet name is unique, then set it otherwise move on to the next number.if (getSheetIndex(name)==-1){
return name;
}
}
}/**
* Create a new XSSFCellStyle and add it to the workbook's style table
*
* @return the new XSSFCellStyle object
*/@OverridepublicXSSFCellStylecreateCellStyle(){
return stylesSource.createCellStyle();
}/**
* Returns the workbook's data format table (a factory for creating data format strings).
*
* @return the XSSFDataFormat object
* @see org.apache.poi.ss.usermodel.DataFormat
*
* createDataFormat is a get stereotype.
* It returns one data member: formatter.
*/@OverridepublicXSSFDataFormatcreateDataFormat(){
if (formatter==null){
formatter=newXSSFDataFormat(stylesSource);
}return formatter;
}/**
* Create a new Font and add it to the workbook's font table
*
* @return new font object
*
* createFont is a property stereotype.
* It returns a single value: font.
*/@OverridepublicXSSFFontcreateFont(){
XSSFFontfont= newXSSFFont();font.registerTo(stylesSource);return font;
}/*
*
* createName is a property stereotype.
* It has a single return, which delegates to the following call(s): createAndStoreName(ctName).
*/@OverridepublicXSSFNamecreateName(){
CTDefinedNamectName= CTDefinedName.Factory.newInstance();ctName.setName("");return createAndStoreName(ctName);
}/*
*
* createAndStoreName is a property stereotype.
* It returns a single value: name.
* The return value depends on the following parameter(s): ctName.
*/privateXSSFNamecreateAndStoreName(CTDefinedNamectName){
XSSFNamename= newXSSFName(ctName, this);namedRanges.add(name);namedRangesByName.put(ctName.getName().toLowerCase(Locale.ENGLISH), name);return name;
}/**
* Create an XSSFSheet for this workbook, adds it to the sheets and returns
* the high level representation. Use this to create new sheets.
*
* @return XSSFSheet representing the new sheet.
*
* createSheet is a property stereotype.
* It has a single return, which delegates to the following call(s): createSheet(sheetname).
*/@OverridepublicXSSFSheetcreateSheet(){
Stringsheetname= "Sheet"+(sheets.size());intidx= 0;while(getSheet(sheetname)!=null){
sheetname="Sheet"+idx;idx++;
}return createSheet(sheetname);
}/**
* Create a new sheet for this Workbook and return the high level representation.
* Use this to create new sheets.
*
* <p>
* Note that Excel allows sheet names up to 31 chars in length but other applications
* (such as OpenOffice) allow more. Some versions of Excel crash with names longer than 31 chars,
* others - truncate such names to 31 character.
* </p>
* <p>
* POI's SpreadsheetAPI silently truncates the input argument to 31 characters.
* Example:
*
* <pre><code>
* Sheet sheet = workbook.createSheet("My very long sheet name which is longer than 31 chars"); // will be truncated
* assert 31 == sheet.getSheetName().length();
* assert "My very long sheet name which i" == sheet.getSheetName();
* </code></pre>
* </p>
*
* Except the 31-character constraint, Excel applies some other rules:
* <p>
* Sheet name MUST be unique in the workbook and MUST NOT contain the any of the following characters:
* <ul>
* <li> 0x0000 </li>
* <li> 0x0003 </li>
* <li> colon (:) </li>
* <li> backslash (\) </li>
* <li> asterisk (*) </li>
* <li> question mark (?) </li>
* <li> forward slash (/) </li>
* <li> opening square bracket ([) </li>
* <li> closing square bracket (]) </li>
* </ul>
* The string MUST NOT begin or end with the single quote (') character.
* </p>
*
* <p>
* See {@link org.apache.poi.ss.util.WorkbookUtil#createSafeSheetName(String nameProposal)}
* for a safe way to create valid names
* </p>
* @param sheetname sheetname to set for the sheet.
* @return Sheet representing the new sheet.
* @throws IllegalArgumentException if the name is null or invalid
* or workbook already contains a sheet with this name
* @see org.apache.poi.ss.util.WorkbookUtil#createSafeSheetName(String nameProposal)
*
* createSheet is a set stereotype.
* It modifies one member variable using the method call: WorkbookUtil via validateSheetName, and sheets via add.
*/@OverridepublicXSSFSheetcreateSheet(Stringsheetname){
if (sheetname==null){
throw newIllegalArgumentException("sheetName must not be null");
}validateSheetName(sheetname);// YK: Mimic Excel and silently truncate sheet names longer than 31 charactersif(sheetname.length()>31){
sheetname=sheetname.substring(0, 31);
}WorkbookUtil.validateSheetName(sheetname);CTSheetsheet= addSheet(sheetname);intsheetNumber= 1;while(true){
for(XSSFSheetsh: sheets){
sheetNumber=(int)Math.max(sh.sheet.getSheetId()+1, sheetNumber);
}// Bug 57165: We also need to check that the resulting file name is not already taken// this can happen when moving/cloning sheetsStringsheetName= XSSFRelation.WORKSHEET.getFileName(sheetNumber);for(POIXMLDocumentPartrelation: getRelations()){
if(relation.getPackagePart()!=null&&sheetName.equals(relation.getPackagePart().getPartName().getName())){
// name is taken => try next onesheetNumber++;continue outerloop;
}
}// no duplicate found => use this onebreak;
}RelationPartrp= createRelationship(XSSFRelation.WORKSHEET, XSSFFactory.getInstance(), sheetNumber, false);XSSFSheetwrapper= rp.getDocumentPart();wrapper.sheet=sheet;sheet.setId(rp.getRelationship().getId());sheet.setSheetId(sheetNumber);if (sheets.isEmpty()){
wrapper.setSelected(true);
}sheets.add(wrapper);return wrapper;
}/*
*
* validateSheetName is a command stereotype.
*/privatevoidvalidateSheetName(finalStringsheetName)throws IllegalArgumentException{
if (containsSheet( sheetName, sheets.size() )){
throw newIllegalArgumentException("The workbook already contains a sheet named '"+sheetName+"'");
}
}/*
*
* createDialogsheet is a property stereotype.
* It has a single return, which delegates to the following call(s): new XSSFDialogsheet(sheet).
* The return value depends on the following parameter(s): dialogsheet, and sheetname.
*/protectedXSSFDialogsheetcreateDialogsheet(Stringsheetname, CTDialogsheetdialogsheet){
XSSFSheetsheet= createSheet(sheetname);return newXSSFDialogsheet(sheet);
}privateCTSheetaddSheet(Stringsheetname){
CTSheetsheet= workbook.getSheets().addNewSheet();sheet.setName(sheetname);return sheet;
}/**
* Finds a font that matches the one with the supplied attributes
*/@OverridepublicXSSFFontfindFont(booleanbold, shortcolor, shortfontHeight, Stringname, booleanitalic, booleanstrikeout, shorttypeOffset, byteunderline){
return stylesSource.findFont(bold, color, fontHeight, name, italic, strikeout, typeOffset, underline);
}/**
* Convenience method to get the active sheet. The active sheet is is the sheet
* which is currently displayed when the workbook is viewed in Excel.
* 'Selected' sheet(s) is a distinct concept.
*
* getActiveSheetIndex is a get stereotype.
* It returns one data member: (int)workbook.
*/@OverridepublicintgetActiveSheetIndex(){
//activeTab (Active Sheet Index) Specifies an unsignedInt//that contains the index to the active sheet in this book view.return (int)workbook.getBookViews().getWorkbookViewArray(0).getActiveTab();
}/**
* Gets all pictures from the Workbook.
*
* @return the list of pictures (a list of {@link XSSFPictureData} objects.)
* @see #addPicture(byte[], int)
*
* getAllPictures is a get stereotype.
* It returns one data member: pictures.
* It delegates to a call: mediaParts via size, and pictures via add.
*/@OverridepublicList<XSSFPictureData>getAllPictures(){
if(pictures==null){
List<PackagePart>mediaParts= getPackage().getPartsByName(Pattern.compile("/xl/media/.*?"));pictures=newArrayList<XSSFPictureData>(mediaParts.size());for(PackagePartpart: mediaParts){
pictures.add(newXSSFPictureData(part));
}
}return pictures;//YK: should return Collections.unmodifiableList(pictures);
}/**
* Get the cell style object at the given index
*
* @param idx index within the set of styles
* @return XSSFCellStyle object at the index
*
* getCellStyleAt is a get stereotype.
* It returns one data member: stylesSource
*/@OverridepublicXSSFCellStylegetCellStyleAt(intidx){
return stylesSource.getStyleAt(idx);
}/**
* Get the font at the given index number
*
* @param idx index number
* @return XSSFFont at the index
*/@OverridepublicXSSFFontgetFontAt(shortidx){
return stylesSource.getFontAt(idx);
}/**
* Get the first named range with the given name.
*
* Note: names of named ranges are not unique as they are scoped by sheet.
* {@link #getNames(String name)} returns all named ranges with the given name.
*
* @param name named range name
* @return XSSFName with the given name. <code>null</code> is returned no named range could be found.
*
* getName is a get stereotype.
* It has multiple return values: list, and null.
*/@OverridepublicXSSFNamegetName(Stringname){
Collection<XSSFName>list= getNames(name);if (list.isEmpty()){
return null;
}return list.iterator().next();
}/**
* Get the named ranges with the given name.
* <i>Note:</i>Excel named ranges are case-insensitive and
* this method performs a case-insensitive search.
*
* @param name named range name
* @return list of XSSFNames with the given name. An empty list if no named ranges could be found
*/@OverridepublicList<XSSFName>getNames(Stringname){
return Collections.unmodifiableList(namedRangesByName.get(name.toLowerCase(Locale.ENGLISH)));
}/**
* Get the named range at the given index.
*
* @param nameIndex the index of the named range
* @return the XSSFName at the given index
*
* @deprecated 3.16. New projects should avoid accessing named ranges by index.
*/@Override@DeprecatedpublicXSSFNamegetNameAt(intnameIndex){
intnNames= namedRanges.size();if (nNames<1){
throw newIllegalStateException("There are no defined names in this workbook");
}if (nameIndex<0||nameIndex>nNames){
throw newIllegalArgumentException("Specified name index "+nameIndex+" is outside the allowable range (0.."+(nNames-1)+").");
}return namedRanges.get(nameIndex);
}/**
* Get a list of all the named ranges in the workbook.
*
* @return list of XSSFNames in the workbook
*
* getAllNames is a property stereotype.
* It has a single return, which delegates to the following call(s): Collections.unmodifiableList(namedRanges).
*/@OverridepublicList<XSSFName>getAllNames(){
return Collections.unmodifiableList(namedRanges);
}/**
* Gets the named range index by name.
*
* @param name named range name
* @return named range index. <code>-1</code> is returned if no named ranges could be found.
*
* @deprecated 3.16. New projects should avoid accessing named ranges by index.
* Use {@link #getName(String)} instead.
*
* getNameIndex is a get stereotype.
* It has multiple return values: -1, and namedRanges.
*/@Override@DeprecatedpublicintgetNameIndex(Stringname){
XSSFNamenm= getName(name);if (nm!=null){
return namedRanges.indexOf(nm);
}return -1;
}/**
* Get the number of styles the workbook contains
*
* @return count of cell styles
*/@OverridepublicintgetNumCellStyles(){
return stylesSource.getNumCellStyles();
}/**
* Get the number of fonts in the this workbook
*
* @return number of fonts
*
* getNumberOfFonts is a property stereotype.
* It has a single return, which delegates to the following call(s): (short)stylesSource.getFonts().size().
*/@OverridepublicshortgetNumberOfFonts(){
return (short)stylesSource.getFonts().size();
}/**
* Get the number of named ranges in the this workbook
*
* @return number of named ranges
*/@OverridepublicintgetNumberOfNames(){
return namedRanges.size();
}/**
* Get the number of worksheets in the this workbook
*
* @return number of worksheets
*/@OverridepublicintgetNumberOfSheets(){
return sheets.size();
}/**
* Retrieves the reference for the printarea of the specified sheet, the sheet name is appended to the reference even if it was not specified.
* @param sheetIndex Zero-based sheet index (0 Represents the first sheet to keep consistent with java)
* @return String Null if no print area has been defined
*
* getPrintArea is a property stereotype.
* It has multiple return values: null.
* Some of which delegate to the following call(s): name.getRefersToFormula().
* The return value depends on the following parameter(s): sheetIndex.
* The return value depends on the boolean value of the following condition(s): name == null.
*/@OverridepublicStringgetPrintArea(intsheetIndex){
XSSFNamename= getBuiltInName(XSSFName.BUILTIN_PRINT_AREA, sheetIndex);if (name==null){
return null;
}//adding one here because 0 indicates a global named region; doesnt make sense for print areasreturn name.getRefersToFormula();
}/**
* Get sheet with the given name (case insensitive match)
*
* @param name of the sheet
* @return XSSFSheet with the name provided or <code>null</code> if it does not exist
*
* getSheet is a property stereotype.
* It has multiple return values: null, and sheet.
* The return value depends on the following parameter(s): name.
* The return value depends on the boolean value of the following condition(s): name.equalsIgnoreCase(sheet.getSheetName()).
*/@OverridepublicXSSFSheetgetSheet(Stringname){
for (XSSFSheetsheet: sheets){
if (name.equalsIgnoreCase(sheet.getSheetName())){
return sheet;
}
}return null;
}/**
* Get the XSSFSheet object at the given index.
*
* @param index of the sheet number (0-based physical logical)
* @return XSSFSheet at the provided index
* @throws IllegalArgumentException if the index is out of range (index
* 0 || index = getNumberOfSheets()).
*
* getSheetAt is a get stereotype.
* It returns one data member: sheets.
*/@OverridepublicXSSFSheetgetSheetAt(intindex){
validateSheetIndex(index);return sheets.get(index);
}/**
* Returns the index of the sheet by his name (case insensitive match)
*
* @param name the sheet name
* @return index of the sheet (0 based) or tt-1/tt if not found
*
* getSheetIndex is a property stereotype.
* It has multiple return values: -1, and idx.
* The return value depends on the following parameter(s): name.
* The return value depends on the boolean value of the following condition(s): name.equalsIgnoreCase(sh.getSheetName()).
*/@OverridepublicintgetSheetIndex(Stringname){
intidx= 0;for (XSSFSheetsh: sheets){
if (name.equalsIgnoreCase(sh.getSheetName())){
return idx;
}idx++;
}return -1;
}/**
* Returns the index of the given sheet
*
* @param sheet the sheet to look up
* @return index of the sheet (0 based). tt-1/tt if not found
*
* getSheetIndex is a property stereotype.
* It has multiple return values: -1, and idx.
* The return value depends on the following parameter(s): sheet.
* The return value depends on the boolean value of the following condition(s): sh == sheet.
*/@OverridepublicintgetSheetIndex(Sheetsheet){
intidx= 0;for(XSSFSheetsh: sheets){
if(sh==sheet){
return idx;
}idx++;
}return -1;
}/**
* Get the sheet name
*
* @param sheetIx Number
* @return Sheet name
*
* getSheetName is a property stereotype.
* It has a single return, which delegates to the following call(s): sheets.get(sheetIx).getSheetName().
* The return value depends on the following parameter(s): sheetIx.
*/@OverridepublicStringgetSheetName(intsheetIx){
validateSheetIndex(sheetIx);return sheets.get(sheetIx).getSheetName();
}/**
* Returns an iterator of the sheets in the workbook
* in sheet order. Includes hidden and very hidden sheets.
*
* Note: remove() is not supported on this iterator.
* Use {@link #removeSheetAt(int)} to remove sheets instead.
*
* @return an iterator of the sheets.
*/@OverridepublicIteratorSheetsheetIterator(){
return newSheetIteratorSheet();
}/**
* Alias for {@link #sheetIterator()} to allow
* foreach loops
*
* Note: remove() is not supported on this iterator.
* Use {@link #removeSheetAt(int)} to remove sheets instead.
*
* @return an iterator of the sheets.
*
* iterator is a property stereotype.
* It has a single return, which delegates to the following call(s): sheetIterator().
*/@OverridepublicIteratorSheetiterator(){
return sheetIterator();
}privatefinal class SheetIteratorTextends Sheetimplements IteratorT{
finalprivateIteratorTit;@SuppressWarnings("unchecked")publicSheetIterator(){
it=(IteratorT)sheets.iterator();
}@OverridepublicbooleanhasNext(){
return it.hasNext();
}@OverridepublicTnext()throws NoSuchElementException{
return it.next();
}/**
* Unexpected behavior may occur if sheets are reordered after iterator
* has been created. Support for the remove method may be added in the future
* if someone can figure out a reliable implementation.
*/@Overridepublicvoidremove()throws IllegalStateException{
throw newUnsupportedOperationException("remove method not supported on XSSFWorkbook.iterator(). "+"Use Sheet.removeSheetAt(int) instead.");
}
}/**
* Are we a normal workbook (.xlsx), or a
* macro enabled workbook (.xlsm)?
*
* isMacroEnabled is a predicate stereotype.
* It has a single return, which delegates to the following call(s): getPackagePart().getContentType().equals(XSSFRelation.MACROS_WORKBOOK.getContentType()).
*/publicbooleanisMacroEnabled(){
return getPackagePart().getContentType().equals(XSSFRelation.MACROS_WORKBOOK.getContentType());
}/**
* Remove the named range at the given index.
*
* @param nameIndex the index of the named range name to remove
*
* @deprecated 3.16. New projects should use {@link #removeName(Name)}.
*
* removeName is a command stereotype.
* It makes calls to the following method(s): getNameAt, and removeName
*/@Override@DeprecatedpublicvoidremoveName(intnameIndex){
removeName(getNameAt(nameIndex));
}/**
* Remove the first named range found with the given name.
*
* Note: names of named ranges are not unique (name + sheet
* index is unique), so {@link #removeName(Name)} should
* be used if possible.
*
* @param name the named range name to remove
*
* @throws IllegalArgumentException if no named range could be found
*
* @deprecated 3.16. New projects should use {@link #removeName(Name)}.
*
* removeName is a command stereotype.
* It makes calls to the following method(s): removeName
*/@Override@DeprecatedpublicvoidremoveName(Stringname){
ListXSSFNamenames= namedRangesByName.get(name.toLowerCase(Locale.ENGLISH));if (names.isEmpty()){
throw newIllegalArgumentException("Named range was not found: "+name);
}removeName(names.get(0));
}/**
* As {@link #removeName(String)} is not necessarily unique
* (name + sheet index is unique), this method is more accurate.
*
* @param name the name to remove.
*
* @throws IllegalArgumentException if the named range is not a part of this XSSFWorkbook
*/@OverridepublicvoidremoveName(Namename){
if (!namedRangesByName.removeMapping(name.getNameName().toLowerCase(Locale.ENGLISH), name)||!namedRanges.remove(name)){
throw newIllegalArgumentException("Name was not found: "+name);
}
}voidupdateName(XSSFNamename, StringoldName){
if (!namedRangesByName.removeMapping(oldName.toLowerCase(Locale.ENGLISH), name)){
throw newIllegalArgumentException("Name was not found: "+name);
}namedRangesByName.put(name.getNameName().toLowerCase(Locale.ENGLISH), name);
}/**
* Delete the printarea for the sheet specified
*
* @param sheetIndex 0-based sheet index (0 = First Sheet)
*
* removePrintArea is a command stereotype.
* It makes calls to the following method(s): removeName
*/@OverridepublicvoidremovePrintArea(intsheetIndex){
XSSFNamename= getBuiltInName(XSSFName.BUILTIN_PRINT_AREA, sheetIndex);if (name!=null){
removeName(name);
}
}/**
* Removes sheet at the given index.p
*
* Care must be taken if the removed sheet is the currently active or only selected sheet in
* the workbook. There are a few situations when Excel must have a selection and/or active
* sheet. (For example when printing - see Bug 40414).br
*
* This method makes sure that if the removed sheet was active, another sheet will become
* active in its place. Furthermore, if the removed sheet was the only selected sheet, another
* sheet will become selected. The newly active/selected sheet will have the same index, or
* one less if the removed sheet was the last in the workbook.
*
* @param index of the sheet (0-based)
*
* removeSheetAt is a command stereotype.
* It modifies member variables via the following method calls: sheets via remove.
* It makes calls to the following method(s): onSheetDelete, removeRelation, setActiveSheet, and validateSheetIndex
*/@OverridepublicvoidremoveSheetAt(intindex){
validateSheetIndex(index);onSheetDelete(index);XSSFSheetsheet= getSheetAt(index);removeRelation(sheet);sheets.remove(index);// only set new sheet if there are still some leftif(sheets.size()==0){
return;
}// the index of the closest remaining sheet to the one just deletedintnewSheetIndex= index;if (newSheetIndex=sheets.size()){
newSheetIndex=sheets.size()-1;
}// adjust active sheetintactive= getActiveSheetIndex();if(active==index){
// removed sheet was the active one, reset active sheet if there is still one left nowsetActiveSheet(newSheetIndex);
}else if (activeindex){
// removed sheet was below the active one = active is one less nowsetActiveSheet(active-1);
}
}/**
* Gracefully remove references to the sheet being deleted
*
* @param index the 0-based index of the sheet to delete
*
* onSheetDelete is a command stereotype.
* It modifies the following member variables: calcChain.
* It modifies member variables via the following method calls: workbook via getSheets.
* It makes calls to the following method(s): getSheets, removeName, and removeRelation
*/privatevoidonSheetDelete(intindex){
// remove all sheet relationsfinalXSSFSheetsheet= getSheetAt(index);sheet.onSheetDelete();//delete the CTSheet reference from workbook.xmlworkbook.getSheets().removeSheet(index);//calculation chain is auxiliary, remove it as it may contain orphan references to deleted cellsif(calcChain!=null){
removeRelation(calcChain);calcChain=null;
}//adjust indices of names rangesListXSSFNametoRemove= newArrayListXSSFName();for (XSSFNamenm: namedRanges){
CTDefinedNamect= nm.getCTName();if(!ct.isSetLocalSheetId()){
continue;
}if (ct.getLocalSheetId()==index){
toRemove.add(nm);
}else if (ct.getLocalSheetId()index){
// Bump down by one, so still points at the same sheetct.setLocalSheetId(ct.getLocalSheetId()-1);
}
}for (XSSFNamenm: toRemove){
removeName(nm);
}
}/**
* Retrieves the current policy on what to do when
* getting missing or blank cells from a row.
* The default is to return blank and null cells.
* {@link MissingCellPolicy}
*
* getMissingCellPolicy is a get stereotype.
* It returns one data member: _missingCellPolicy.
*/@OverridepublicMissingCellPolicygetMissingCellPolicy(){
return _missingCellPolicy;
}/**
* Sets the policy on what to do when
* getting missing or blank cells from a row.
* This will then apply to all calls to
* {@link Row#getCell(int)}}. See
* {@link MissingCellPolicy}
*
* setMissingCellPolicy is a command stereotype.
* It modifies the following member variables: _missingCellPolicy.
*/@OverridepublicvoidsetMissingCellPolicy(MissingCellPolicymissingCellPolicy){
_missingCellPolicy=missingCellPolicy;
}/**
* Convenience method to set the active sheet. The active sheet is is the sheet
* which is currently displayed when the workbook is viewed in Excel.
* 'Selected' sheet(s) is a distinct concept.
*
* setActiveSheet is a command stereotype.
* It modifies member variables via the following method calls: workbook via getBookViews.
* It makes calls to the following method(s): validateSheetIndex
*/@OverridepublicvoidsetActiveSheet(intindex){
validateSheetIndex(index);for (CTBookViewarrayBook: workbook.getBookViews().getWorkbookViewArray()){
arrayBook.setActiveTab(index);
}
}/**
* Validate sheet index
*
* @param index the index to validate
* @throws IllegalArgumentException if the index is out of range (index
* 0 || index = getNumberOfSheets()).
*
* validateSheetIndex is a get stereotype.
*/privatevoidvalidateSheetIndex(intindex){
intlastSheetIx= sheets.size()-1;if (index0||indexlastSheetIx){
Stringrange= "(0.."+lastSheetIx+")";if (lastSheetIx==-1){
range="(no sheets)";
}throw newIllegalArgumentException("Sheet index ("+index+") is out of range "+range);
}
}/**
* Gets the first tab that is displayed in the list of tabs in excel.
*
* @return integer that contains the index to the active sheet in this book view.
*
* getFirstVisibleTab is a property stereotype.
* It has a single return, which delegates to the following call(s): (short) bookView.getFirstSheet().
*/@OverridepublicintgetFirstVisibleTab(){
CTBookViewsbookViews= workbook.getBookViews();CTBookViewbookView= bookViews.getWorkbookViewArray(0);return (short)bookView.getFirstSheet();
}/**
* Sets the first tab that is displayed in the list of tabs in excel.
*
* @param index integer that contains the index to the active sheet in this book view.
*/@OverridepublicvoidsetFirstVisibleTab(intindex){
CTBookViewsbookViews= workbook.getBookViews();CTBookViewbookView= bookViews.getWorkbookViewArray(0);bookView.setFirstSheet(index);
}/**
* Sets the printarea for the sheet provided
* p
* i.e. Reference = $A$1:$B$2
* @param sheetIndex Zero-based sheet index (0 Represents the first sheet to keep consistent with java)
* @param reference Valid name Reference for the Print Area
*
* setPrintArea is a command stereotype.
* It modifies member variables via the following method calls: SheetNameFormatter via appendFormat.
* It makes calls to the following method(s): getSheetName
*/@OverridepublicvoidsetPrintArea(intsheetIndex, Stringreference){
XSSFNamename= getBuiltInName(XSSFName.BUILTIN_PRINT_AREA, sheetIndex);if (name==null){
name=createBuiltInName(XSSFName.BUILTIN_PRINT_AREA, sheetIndex);
}//short externSheetIndex = getWorkbook().checkExternSheet(sheetIndex);//name.setExternSheetNumber(externSheetIndex);String[]parts= COMMA_PATTERN.split(reference);StringBuffersb= newStringBuffer(32);for (inti= 0;iparts.length;i++){
if(i0){
sb.append(",");
}SheetNameFormatter.appendFormat(sb, getSheetName(sheetIndex));sb.append("!");sb.append(parts[i]);
}name.setRefersToFormula(sb.toString());
}/**
* For the Convenience of Java Programmers maintaining pointers.
* @see #setPrintArea(int, String)
* @param sheetIndex Zero-based sheet index (0 = First Sheet)
* @param startColumn Column to begin printarea
* @param endColumn Column to end the printarea
* @param startRow Row to begin the printarea
* @param endRow Row to end the printarea
*
* setPrintArea is a command stereotype.
* It makes calls to the following method(s): setPrintArea
*/@OverridepublicvoidsetPrintArea(intsheetIndex, intstartColumn, intendColumn, intstartRow, intendRow){
Stringreference=getReferencePrintArea(getSheetName(sheetIndex), startColumn, endColumn, startRow, endRow);setPrintArea(sheetIndex, reference);
}privatestaticStringgetReferencePrintArea(StringsheetName, intstartC, intendC, intstartR, intendR){
//windows excel example: Sheet1!$C$3:$E$4CellReferencecolRef= newCellReference(sheetName, startR, startC, true, true);CellReferencecolRef2= newCellReference(sheetName, endR, endC, true, true);return "$"+colRef.getCellRefParts()[2]+"$"+colRef.getCellRefParts()[1]+":$"+colRef2.getCellRefParts()[2]+"$"+colRef2.getCellRefParts()[1];
}XSSFNamegetBuiltInName(StringbuiltInCode, intsheetNumber){
for (XSSFNamename: namedRangesByName.get(builtInCode.toLowerCase(Locale.ENGLISH))){
if (name.getSheetIndex()==sheetNumber){
return name;
}
}return null;
}/**
* Generates a NameRecord to represent a built-in region
*
* @return a new NameRecord
* @throws IllegalArgumentException if sheetNumber is invalid
* @throws POIXMLException if such a name already exists in the workbook
*
* createBuiltInName is a property stereotype.
* It has a single return, which delegates to the following call(s): createAndStoreName(nameRecord).
* The return value depends on the following parameter(s): builtInName, and sheetNumber.
* The return value depends on the boolean value of the following condition(s): getBuiltInName(builtInName, sheetNumber) != null.
*/XSSFNamecreateBuiltInName(StringbuiltInName, intsheetNumber){
validateSheetIndex(sheetNumber);CTDefinedNamesnames= workbook.getDefinedNames()==null ?workbook.addNewDefinedNames(): workbook.getDefinedNames();CTDefinedNamenameRecord= names.addNewDefinedName();nameRecord.setName(builtInName);nameRecord.setLocalSheetId(sheetNumber);if (getBuiltInName(builtInName, sheetNumber)!=null){
throw newPOIXMLException("Builtin ("+builtInName+") already exists for sheet ("+sheetNumber+")");
}return createAndStoreName(nameRecord);
}/**
* We only set one sheet as selected for compatibility with HSSF.
*
* setSelectedTab is a command stereotype.
*/@OverridepublicvoidsetSelectedTab(intindex){
intidx= 0;for (XSSFSheetsh: sheets){
sh.setSelected(idx==index);idx++;
}
}/**
* Set the sheet name.
*
* @param sheetIndex sheet number (0 based)
* @param sheetname the new sheet name
* @throws IllegalArgumentException if the name is null or invalid
* or workbook already contains a sheet with this name
* @see #createSheet(String)
* @see org.apache.poi.ss.util.WorkbookUtil#createSafeSheetName(String nameProposal)
*
* setSheetName is a command stereotype.
* It modifies member variables via the following method calls: WorkbookUtil via validateSheetName, and workbook via getSheets.
* It makes calls to the following method(s): getSheets, and validateSheetIndex
*/@OverridepublicvoidsetSheetName(intsheetIndex, Stringsheetname){
if (sheetname==null){
throw newIllegalArgumentException( "sheetName must not be null" );
}validateSheetIndex(sheetIndex);StringoldSheetName= getSheetName(sheetIndex);// YK: Mimic Excel and silently truncate sheet names longer than 31 charactersif(sheetname.length()31){
sheetname=sheetname.substring(0, 31);
}WorkbookUtil.validateSheetName(sheetname);// Do nothing if no changeif (sheetname.equals(oldSheetName)){
return;
}// Check it isn't already takenif (containsSheet(sheetname, sheetIndex )){
throw newIllegalArgumentException( "The workbook already contains a sheet of this name" );
}// Update references to the nameXSSFFormulaUtilsutils= newXSSFFormulaUtils(this);utils.updateSheetName(sheetIndex, oldSheetName, sheetname);workbook.getSheets().getSheetArray(sheetIndex).setName(sheetname);
}/**
* sets the order of appearance for a given sheet.
*
* @param sheetname the name of the sheet to reorder
* @param pos the position that we want to insert the sheet into (0 based)
*
* setSheetOrder is a command stereotype.
* It modifies member variables via the following method calls: sheets via add, sheets via get, sheets via remove, and workbook via getSheets.
* It makes calls to the following method(s): getSheets, updateActiveSheetAfterSheetReorder, and updateNamedRangesAfterSheetReorder
*/@OverridepublicvoidsetSheetOrder(Stringsheetname, intpos){
intidx= getSheetIndex(sheetname);sheets.add(pos, sheets.remove(idx));// Reorder CTSheetsCTSheetsct= workbook.getSheets();XmlObjectcts= ct.getSheetArray(idx).copy();workbook.getSheets().removeSheet(idx);CTSheetnewcts= ct.insertNewSheet(pos);newcts.set(cts);//notify sheets//noinspection deprecationCTSheet[]sheetArray= ct.getSheetArray();for(inti=0;isheetArray.length;i++){
sheets.get(i).sheet=sheetArray[i];
}updateNamedRangesAfterSheetReorder(idx, pos);updateActiveSheetAfterSheetReorder(idx, pos);
}/**
* update sheet-scoped named ranges in this workbook after changing the sheet order
* of a sheet at oldIndex to newIndex.
* Sheets between these indices will move left or right by 1.
*
* @param oldIndex the original index of the re-ordered sheet
* @param newIndex the new index of the re-ordered sheet
*
* updateNamedRangesAfterSheetReorder is a command stereotype.
*/privatevoidupdateNamedRangesAfterSheetReorder(intoldIndex, intnewIndex){
// update sheet index of sheet-scoped named rangesfor (finalXSSFNamename: namedRanges){
finalinti= name.getSheetIndex();// name has sheet-level scopeif (i!=-1){
// name refers to this sheetif (i==oldIndex){
name.setSheetIndex(newIndex);
}// if oldIndex newIndex then this sheet moved left and sheets between newIndex and oldIndex moved rightelse if (newIndex=iioldIndex){
name.setSheetIndex(i+1);
}// if oldIndex newIndex then this sheet moved right and sheets between oldIndex and newIndex moved leftelse if (oldIndexii= newIndex){
name.setSheetIndex(i-1);
}
}
}
}/*
*
* updateActiveSheetAfterSheetReorder is a command stereotype.
* It makes calls to the following method(s): setActiveSheet
*/privatevoidupdateActiveSheetAfterSheetReorder(intoldIndex, intnewIndex){
// adjust active sheet if necessaryintactive= getActiveSheetIndex();if(active==oldIndex){
// moved sheet was the active onesetActiveSheet(newIndex);
}else if ((activeoldIndexactivenewIndex)||(activeoldIndexactivenewIndex)){
// not affected
}else if (newIndexoldIndex){
// moved sheet was below before and is above now = active is one lesssetActiveSheet(active-1);
}else {
// remaining case: moved sheet was higher than active before and is lower now = active is one moresetActiveSheet(active+1);
}
}/**
* marshal named ranges from the {@link #namedRanges} collection to the underlying CTWorkbook bean
*
* saveNamedRanges is a command stereotype.
* It modifies member variables via the following method calls: workbook via setDefinedNames, and workbook via unsetDefinedNames.
* It makes calls to the following method(s): reprocessNamedRanges
*/privatevoidsaveNamedRanges(){
// Named rangesif(namedRanges.size()0){
CTDefinedNamesnames= CTDefinedNames.Factory.newInstance();CTDefinedName[]nr= newCTDefinedName[namedRanges.size()];inti= 0;for(XSSFNamename: namedRanges){
nr[i]=name.getCTName();i++;
}names.setDefinedNameArray(nr);if(workbook.isSetDefinedNames()){
workbook.unsetDefinedNames();
}workbook.setDefinedNames(names);// Re-process the named rangesreprocessNamedRanges();
}else {
if(workbook.isSetDefinedNames()){
workbook.unsetDefinedNames();
}
}
}/*
*
* reprocessNamedRanges is a command stereotype.
* It modifies the following member variables: namedRanges, and namedRangesByName.
* It modifies member variables via the following method calls: workbook via getDefinedNames.
* It makes calls to the following method(s): createAndStoreName, namedRanges, and namedRangesByName
*/privatevoidreprocessNamedRanges(){
namedRangesByName=newArrayListValuedHashMapString,XSSFName();namedRanges=newArrayListXSSFName();if(workbook.isSetDefinedNames()){
for(CTDefinedNamectName: workbook.getDefinedNames().getDefinedNameArray()){
createAndStoreName(ctName);
}
}
}/*
*
* saveCalculationChain is a command stereotype.
* It modifies the following member variables: calcChain.
* It makes calls to the following method(s): removeRelation
*/privatevoidsaveCalculationChain(){
if(calcChain!=null){
intcount= calcChain.getCTCalcChain().sizeOfCArray();if(count==0){
removeRelation(calcChain);calcChain=null;
}
}
}/*
*
* commit is a command stereotype.
* It modifies member variables via the following method calls: CTWorkbook via type.getName, and workbook via save.
* It makes calls to the following method(s): new, saveCalculationChain, saveNamedRanges, and type.getName
*/@Overrideprotectedvoidcommit()throws IOException{
saveNamedRanges();saveCalculationChain();XmlOptionsxmlOptions= newXmlOptions(DEFAULT_XML_OPTIONS);xmlOptions.setSaveSyntheticDocumentElement(newQName(CTWorkbook.type.getName().getNamespaceURI(), "workbook"));PackagePartpart= getPackagePart();OutputStreamout= part.getOutputStream();workbook.save(out, xmlOptions);out.close();
}/**
* Returns SharedStringsTable - tha cache of string for this workbook
*
* @return the shared string table
*
* getSharedStringSource is a get stereotype.
* It returns one data member: sharedStringSource.
*/@InternalpublicSharedStringsTablegetSharedStringSource(){
return this.sharedStringSource;
}/**
* Return a object representing a collection of shared objects used for styling content,
* e.g. fonts, cell styles, colors, etc.
*
* getStylesSource is a get stereotype.
* It returns one data member: stylesSource.
*/publicStylesTablegetStylesSource(){
return this.stylesSource;
}/**
* Returns the Theme of current workbook.
*
* getTheme is a property stereotype.
* It has multiple return values: null.
* Some of which delegate to the following call(s): stylesSource.getTheme().
* The return value depends on the boolean value of the following condition(s): stylesSource == null.
*/publicThemesTablegetTheme(){
if (stylesSource==null){
return null;
}return stylesSource.getTheme();
}/**
* Returns an object that handles instantiating concrete
* classes of the various instances for XSSF.
*
* getCreationHelper is a get stereotype.
* It returns one data member: _creationHelper.
*/@OverridepublicXSSFCreationHelpergetCreationHelper(){
if(_creationHelper==null){
_creationHelper=newXSSFCreationHelper(this);
}return _creationHelper;
}privatebooleancontainsSheet(Stringname, intexcludeSheetIdx){
//noinspection deprecationCTSheet[]ctSheetArray= workbook.getSheets().getSheetArray();if (name.length()MAX_SENSITIVE_SHEET_NAME_LEN){
name=name.substring(0, MAX_SENSITIVE_SHEET_NAME_LEN);
}for (inti= 0;ictSheetArray.length;i++){
StringctName= ctSheetArray[i].getName();if (ctName.length()MAX_SENSITIVE_SHEET_NAME_LEN){
ctName=ctName.substring(0, MAX_SENSITIVE_SHEET_NAME_LEN);
}if (excludeSheetIdx!=iname.equalsIgnoreCase(ctName)){
return true;
}
}return false;
}/**
* Gets a boolean value that indicates whether the date systems used in the workbook starts in 1904.
* p
* The default value is false, meaning that the workbook uses the 1900 date system,
* where 1/1/1900 is the first day in the system..
* /p
* @return true if the date systems used in the workbook starts in 1904
*/@InternalpublicbooleanisDate1904(){
CTWorkbookPrworkbookPr= workbook.getWorkbookPr();return workbookPr!=nullworkbookPr.getDate1904();
}/**
* Get the document's embedded files.
*
* getAllEmbedds is a property stereotype.
* It returns a single value: embedds.
*/@OverridepublicListPackagePartgetAllEmbedds()throws OpenXML4JException{
ListPackagePartembedds= newLinkedListPackagePart();for(XSSFSheetsheet: sheets){
// Get the embeddings for the workbookfor(PackageRelationshiprel: sheet.getPackagePart().getRelationshipsByType(XSSFRelation.OLEEMBEDDINGS.getRelation())){
embedds.add( sheet.getPackagePart().getRelatedPart(rel) );
}for(PackageRelationshiprel: sheet.getPackagePart().getRelationshipsByType(XSSFRelation.PACKEMBEDDINGS.getRelation())){
embedds.add( sheet.getPackagePart().getRelatedPart(rel) );
}
}return embedds;
}@Override@NotImplementedpublicbooleanisHidden(){
throw newRuntimeException("Not implemented yet");
}@Override@NotImplementedpublicvoidsetHidden(booleanhiddenFlag){
throw newRuntimeException("Not implemented yet");
}/*
*
* isSheetHidden is a predicate stereotype.
* It has a single return, which delegates to the following call(s): ctSheet.getState() == STSheetState.HIDDEN.
* The return value depends on the following parameter(s): sheetIx.
*/@OverridepublicbooleanisSheetHidden(intsheetIx){
validateSheetIndex(sheetIx);CTSheetctSheet= sheets.get(sheetIx).sheet;return ctSheet.getState()==STSheetState.HIDDEN;
}/*
*
* isSheetVeryHidden is a predicate stereotype.
* It has a single return, which delegates to the following call(s): ctSheet.getState() == STSheetState.VERY_HIDDEN.
* The return value depends on the following parameter(s): sheetIx.
*/@OverridepublicbooleanisSheetVeryHidden(intsheetIx){
validateSheetIndex(sheetIx);CTSheetctSheet= sheets.get(sheetIx).sheet;return ctSheet.getState()==STSheetState.VERY_HIDDEN;
}/*
*
* getSheetVisibility is a get stereotype.
* It returns one data member: SheetVisibility.
*/@OverridepublicSheetVisibilitygetSheetVisibility(intsheetIx){
validateSheetIndex(sheetIx);finalCTSheetctSheet= sheets.get(sheetIx).sheet;finalSTSheetState.Enumstate= ctSheet.getState();if (state==STSheetState.VISIBLE){
return SheetVisibility.VISIBLE;
}if (state==STSheetState.HIDDEN){
return SheetVisibility.HIDDEN;
}if (state==STSheetState.VERY_HIDDEN){
return SheetVisibility.VERY_HIDDEN;
}throw newIllegalArgumentException("This should never happen");
}/*
*
* setSheetHidden is a command stereotype.
* It makes calls to the following method(s): setSheetVisibility
*/@OverridepublicvoidsetSheetHidden(intsheetIx, booleanhidden){
setSheetVisibility(sheetIx, hidden ?SheetVisibility.HIDDEN: SheetVisibility.VISIBLE);
}/*
*
* setSheetHidden is a command stereotype.
* It modifies member variables via the following method calls: SheetVisibility via values, and WorkbookUtil via validateSheetState.
* It makes calls to the following method(s): setSheetVisibility
*/@Deprecated@Removal(version="3.18")@OverridepublicvoidsetSheetHidden(intsheetIx, intstate){
WorkbookUtil.validateSheetState(state);setSheetVisibility(sheetIx, SheetVisibility.values()[state]);
}/*
*
* setSheetVisibility is a command stereotype.
* It makes calls to the following method(s): validateSheetIndex
*/@OverridepublicvoidsetSheetVisibility(intsheetIx, SheetVisibilityvisibility){
validateSheetIndex(sheetIx);finalCTSheetctSheet= sheets.get(sheetIx).sheet;switch (visibility){
case VISIBLE:ctSheet.setState(STSheetState.VISIBLE);break;case HIDDEN:ctSheet.setState(STSheetState.HIDDEN);break;case VERY_HIDDEN:ctSheet.setState(STSheetState.VERY_HIDDEN);break;default:throw newIllegalArgumentException("This should never happen");
}
}/**
* Fired when a formula is deleted from this workbook,
* for example when calling cell.setCellFormula(null)
*
* @see XSSFCell#setCellFormula(String)
*
* onDeleteFormula is a command stereotype.
* It modifies member variables via the following method calls: calcChain via removeItem.
*/protectedvoidonDeleteFormula(XSSFCellcell){
if(calcChain!=null){
intsheetId= (int)cell.getSheet().sheet.getSheetId();calcChain.removeItem(sheetId, cell.getReference());
}
}/**
* Return the {@link CalculationChain} object for this workbook
* p
* The calculation chain object specifies the order in which the cells in a workbook were last calculated
* /p
*
* @return the codeCalculationChain/code object or codenull/code if not defined
*
* getCalculationChain is a get stereotype.
* It returns one data member: calcChain.
*/@InternalpublicCalculationChaingetCalculationChain(){
return calcChain;
}/**
* Returns the list of {@link ExternalLinksTable} object for this workbook
*
* pThe external links table specifies details of named ranges etc
* that are referenced from other workbooks, along with the last seen
* values of what they point to./p
*
* pNote that Excel uses index 0 for the current workbook, so the first
* External Links in a formula would be '[1]Foo' which corresponds to
* entry 0 in this list./p
* @return the codeExternalLinksTable/code list, which may be empty
*
* getExternalLinksTable is a get stereotype.
* It returns one data member: externalLinks.
*/@InternalpublicListExternalLinksTablegetExternalLinksTable(){
return externalLinks;
}/**
*
* @return a collection of custom XML mappings defined in this workbook
*
* getCustomXMLMappings is a property stereotype.
* It has a single return, which delegates to the following call(s): mapInfo == null ? new ArrayListXSSFMap() : mapInfo.getAllXSSFMaps().
*/publicCollectionXSSFMapgetCustomXMLMappings(){
return mapInfo==null ?newArrayListXSSFMap(): mapInfo.getAllXSSFMaps();
}/**
*
* @return the helper class used to query the custom XML mapping defined in this workbook
*
* getMapInfo is a get stereotype.
* It returns one data member: mapInfo.
*/@InternalpublicMapInfogetMapInfo(){
return mapInfo;
}/**
* Adds the External Link Table part and relations required to allow formulas
* referencing the specified external workbook to be added to this one. Allows
* formulas such as "[MyOtherWorkbook.xlsx]Sheet3!$A$5" to be added to the
* file, for workbooks not already linked / referenced.
*
* Note: this is not implemented and thus currently throws an Exception stating this.
*
* @param name The name the workbook will be referenced as in formulas
* @param workbook The open workbook to fetch the link required information from
*
* @throws RuntimeException stating that this method is not implemented yet.
*/@Override@NotImplementedpublicintlinkExternalWorkbook(Stringname, Workbookworkbook){
throw newRuntimeException("Not Implemented - see bug #57184");
}publicbooleanisStructureLocked(){
return workbookProtectionPresent()workbook.getWorkbookProtection().getLockStructure();
}publicbooleanisWindowsLocked(){
return workbookProtectionPresent()workbook.getWorkbookProtection().getLockWindows();
}publicbooleanisRevisionLocked(){
return workbookProtectionPresent()workbook.getWorkbookProtection().getLockRevision();
}/**
* Locks the structure of workbook.
*
* lockStructure is a command stereotype.
* It makes calls to the following method(s): safeGetWorkbookProtection
*/publicvoidlockStructure(){
safeGetWorkbookProtection().setLockStructure(true);
}/**
* Unlocks the structure of workbook.
*
* unLockStructure is a command stereotype.
* It makes calls to the following method(s): safeGetWorkbookProtection
*/publicvoidunLockStructure(){
safeGetWorkbookProtection().setLockStructure(false);
}/**
* Locks the windows that comprise the workbook.
*
* lockWindows is a command stereotype.
* It makes calls to the following method(s): safeGetWorkbookProtection
*/publicvoidlockWindows(){
safeGetWorkbookProtection().setLockWindows(true);
}/**
* Unlocks the windows that comprise the workbook.
*
* unLockWindows is a command stereotype.
* It makes calls to the following method(s): safeGetWorkbookProtection
*/publicvoidunLockWindows(){
safeGetWorkbookProtection().setLockWindows(false);
}/**
* Locks the workbook for revisions.
*
* lockRevision is a command stereotype.
* It makes calls to the following method(s): safeGetWorkbookProtection
*/publicvoidlockRevision(){
safeGetWorkbookProtection().setLockRevision(true);
}/**
* Unlocks the workbook for revisions.
*
* unLockRevision is a command stereotype.
* It makes calls to the following method(s): safeGetWorkbookProtection
*/publicvoidunLockRevision(){
safeGetWorkbookProtection().setLockRevision(false);
}/**
* Sets the workbook password.
*
* @param password if null, the password will be removed
* @param hashAlgo if null, the password will be set as XOR password (Excel 2010 and earlier)
* otherwise the given algorithm is used for calculating the hash password (Excel 2013)
*
* setWorkbookPassword is a command stereotype.
* It makes calls to the following method(s): safeGetWorkbookProtection, and setPassword
*/publicvoidsetWorkbookPassword(Stringpassword, HashAlgorithmhashAlgo){
if (password==null!workbookProtectionPresent()){
return;
}setPassword(safeGetWorkbookProtection(), password, hashAlgo, "workbook");
}/**
* Validate the password against the stored hash, the hashing method will be determined
* by the existing password attributes
* @return true, if the hashes match (... though original password may differ ...)
*
* validateWorkbookPassword is a predicate stereotype.
* It has multiple return values. One or more delegate to a call: validatePassword(safeGetWorkbookProtection(), password, "workbook").
* And one or more do not: (password == null).
* The return value depends on the following parameter(s): password.
* The return value depends on the boolean value of the following condition(s): !workbookProtectionPresent().
*/publicbooleanvalidateWorkbookPassword(Stringpassword){
if (!workbookProtectionPresent()){
return (password==null);
}return validatePassword(safeGetWorkbookProtection(), password, "workbook");
}/**
* Sets the revisions password.
*
* @param password if null, the password will be removed
* @param hashAlgo if null, the password will be set as XOR password (Excel 2010 and earlier)
* otherwise the given algorithm is used for calculating the hash password (Excel 2013)
*
* setRevisionsPassword is a command stereotype.
* It makes calls to the following method(s): safeGetWorkbookProtection, and setPassword
*/publicvoidsetRevisionsPassword(Stringpassword, HashAlgorithmhashAlgo){
if (password==null!workbookProtectionPresent()){
return;
}setPassword(safeGetWorkbookProtection(), password, hashAlgo, "revisions");
}/**
* Validate the password against the stored hash, the hashing method will be determined
* by the existing password attributes
* @return true if the hashes match (... though original password may differ ...)
*
* validateRevisionsPassword is a predicate stereotype.
* It has multiple return values. One or more delegate to a call: validatePassword(safeGetWorkbookProtection(), password, "revisions").
* And one or more do not: (password == null).
* The return value depends on the following parameter(s): password.
* The return value depends on the boolean value of the following condition(s): !workbookProtectionPresent().
*/publicbooleanvalidateRevisionsPassword(Stringpassword){
if (!workbookProtectionPresent()){
return (password==null);
}return validatePassword(safeGetWorkbookProtection(), password, "revisions");
}/**
* Removes the workbook protection settings
*
* unLock is a command stereotype.
* It modifies member variables via the following method calls: workbook via unsetWorkbookProtection.
*/publicvoidunLock(){
if (workbookProtectionPresent()){
workbook.unsetWorkbookProtection();
}
}privatebooleanworkbookProtectionPresent(){
return workbook.isSetWorkbookProtection();
}/*
*
* safeGetWorkbookProtection is a property stereotype.
* It has multiple returns, which delegate to the following call(s): workbook.addNewWorkbookProtection(), and workbook.getWorkbookProtection().
* The return value depends on the boolean value of the following condition(s): !workbookProtectionPresent().
*/privateCTWorkbookProtectionsafeGetWorkbookProtection(){
if (!workbookProtectionPresent()){
return workbook.addNewWorkbookProtection();
}return workbook.getWorkbookProtection();
}/**
*
* Returns the locator of user-defined functions.
* p
* The default instance extends the built-in functions with the Excel Analysis Tool Pack.
* To set / evaluate custom functions you need to register them as follows:
*
*
*
* /p
* @return wrapped instance of UDFFinder that allows seeking functions both by index and name
*
* getUDFFinder is a get stereotype.
* It returns one data member: _udfFinder.
*/UDFFindergetUDFFinder(){
return _udfFinder;
}/**
* Register a new toolpack in this workbook.
*
* @param toopack the toolpack to register
*/@OverridepublicvoidaddToolPack(UDFFindertoopack){
_udfFinder.add(toopack);
}/**
* Whether the application shall perform a full recalculation when the workbook is opened.
* p
* Typically you want to force formula recalculation when you modify cell formulas or values
* of a workbook previously created by Excel. When set to true, this flag will tell Excel
* that it needs to recalculate all formulas in the workbook the next time the file is opened.
* /p
* p
* Note, that recalculation updates cached formula results and, thus, modifies the workbook.
* Depending on the version, Excel may prompt you with "Do you want to save the changes in emfilename/em?"
* on close.
* /p
*
* @param value true if the application will perform a full recalculation of
* workbook values when the workbook is opened
* @since 3.8
*
* setForceFormulaRecalculation is a command stereotype.
*/@OverridepublicvoidsetForceFormulaRecalculation(booleanvalue){
CTWorkbookctWorkbook= getCTWorkbook();CTCalcPrcalcPr= ctWorkbook.isSetCalcPr() ?ctWorkbook.getCalcPr(): ctWorkbook.addNewCalcPr();// when set to 0, will tell Excel that it needs to recalculate all formulas// in the workbook the next time the file is opened.calcPr.setCalcId(0);if(valuecalcPr.getCalcMode()==STCalcMode.MANUAL){
calcPr.setCalcMode(STCalcMode.AUTO);
}
}@OverridepublicbooleangetForceFormulaRecalculation(){
CTWorkbookctWorkbook= getCTWorkbook();CTCalcPrcalcPr= ctWorkbook.getCalcPr();return calcPr!=nullcalcPr.getCalcId()!=0;
}/**
* Add pivotCache to the workbook
*
* addPivotCache is a property stereotype.
* It returns a single value: cache.
* The return value depends on the following parameter(s): rId.
* The return value depends on the boolean value of the following condition(s): ctWorkbook.isSetPivotCaches(), and pivotCaches == null.
*/@BetaprotectedCTPivotCacheaddPivotCache(StringrId){
CTWorkbookctWorkbook= getCTWorkbook();CTPivotCachescaches;if (ctWorkbook.isSetPivotCaches()){
caches=ctWorkbook.getPivotCaches();
}else {
caches=ctWorkbook.addNewPivotCaches();
}CTPivotCachecache= caches.addNewPivotCache();inttableId= getPivotTables().size()+1;cache.setCacheId(tableId);cache.setId(rId);if(pivotCaches==null){
pivotCaches=newArrayListCTPivotCache();
}pivotCaches.add(cache);return cache;
}/*
*
* getPivotTables is a get stereotype.
* It returns one data member: pivotTables.
*/@BetapublicListXSSFPivotTablegetPivotTables(){
return pivotTables;
}@BetaprotectedvoidsetPivotTables(ListXSSFPivotTablepivotTables){
this.pivotTables=pivotTables;
}/*
*
* getWorkbookType is a property stereotype.
* It has a single return, which delegates to the following call(s): isMacroEnabled() ? XSSFWorkbookType.XLSM : XSSFWorkbookType.XLSX.
*/publicXSSFWorkbookTypegetWorkbookType(){
return isMacroEnabled() ?XSSFWorkbookType.XLSM: XSSFWorkbookType.XLSX;
}/**
* Sets whether the workbook will be an .xlsx or .xlsm (macro-enabled) file.
*
* setWorkbookType is a command stereotype.
* It makes calls to the following method(s): getPackagePart
*/publicvoidsetWorkbookType(XSSFWorkbookTypetype){
try {
getPackagePart().setContentType(type.getContentType());
}catch (InvalidFormatExceptione){
throw newPOIXMLException(e);
}
}/**
* Adds a vbaProject.bin file to the workbook. This will change the workbook
* type if necessary.
*
* @throws IOException If copying data from the stream fails.
*
* setVBAProject is a command stereotype.
* It modifies the following member variables: outputStream, and ppName.
* It modifies member variables via the following method calls: IOUtils via closeQuietly, IOUtils via copy, and XSSFRelation via VBA_MACROS.getDefaultFileName.
* It makes calls to the following method(s): outputStream, and setWorkbookType
*/publicvoidsetVBAProject(InputStreamvbaProjectStream)throws IOException{
if (!isMacroEnabled()){
setWorkbookType(XSSFWorkbookType.XLSM);
}PackagePartNameppName;try {
ppName=PackagingURIHelper.createPartName(XSSFRelation.VBA_MACROS.getDefaultFileName());
}catch (InvalidFormatExceptione){
throw newPOIXMLException(e);
}OPCPackageopc= getPackage();OutputStreamoutputStream;if (!opc.containPart(ppName)){
POIXMLDocumentPartrelationship= createRelationship(XSSFRelation.VBA_MACROS, XSSFFactory.getInstance());outputStream=relationship.getPackagePart().getOutputStream();
}else {
PackagePartpart= opc.getPart(ppName);outputStream=part.getOutputStream();
}try {
IOUtils.copy(vbaProjectStream, outputStream);
}finally {
IOUtils.closeQuietly(outputStream);
}
}/**
* Adds a vbaProject.bin file taken from another, given workbook to this one.
* @throws IOException If copying the VBAProject stream fails.
* @throws InvalidFormatException If an error occurs while handling parts of the XSSF format
*
* setVBAProject is a command stereotype.
* It makes calls to the following method(s): setVBAProject
*/publicvoidsetVBAProject(XSSFWorkbookmacroWorkbook)throws IOException, InvalidFormatException{
if (!macroWorkbook.isMacroEnabled()){
return;
}InputStreamvbaProjectStream= XSSFRelation.VBA_MACROS.getContents(macroWorkbook.getCorePart());if (vbaProjectStream!=null){
setVBAProject(vbaProjectStream);
}
}/**
* Returns the spreadsheet version (EXCLE2007) of this workbook
*
* @return EXCEL2007 SpreadsheetVersion enum
* @since 3.14 beta 2
*
* getSpreadsheetVersion is a get stereotype.
* It returns one data member: SpreadsheetVersion.
*/@OverridepublicSpreadsheetVersiongetSpreadsheetVersion(){
return SpreadsheetVersion.EXCEL2007;
}publicXSSFTablegetTable(Stringname){
if (name!=nullsheets!=null){
for (XSSFSheetsheet: sheets){
for (XSSFTabletbl: sheet.getTables()){
if (name.equalsIgnoreCase(tbl.getName())){
return tbl;
}
}
}
}return null;
}/*
*
* addOlePackage is a property stereotype.
* It returns a single value: oleId.
* The return value depends on the following parameter(s): command, e, fileName, label, and oleData.
*/@OverridepublicintaddOlePackage(byte[]oleData, Stringlabel, StringfileName, Stringcommand)throws IOException{
// find an unused part nameOPCPackageopc= getPackage();PackagePartNamepnOLE;intoleId=0;do {
try {
pnOLE=PackagingURIHelper.createPartName( "/xl/embeddings/oleObject"+(++oleId)+".bin" );
}catch (InvalidFormatExceptione){
throw newIOException("ole object name not recognized", e);
}
} while (opc.containPart(pnOLE));PackagePartpp= opc.createPart( pnOLE, "application/vnd.openxmlformats-officedocument.oleObject" );Ole10Nativeole10= newOle10Native(label, fileName, command, oleData);ByteArrayOutputStreambos= newByteArrayOutputStream(oleData.length+500);ole10.writeOut(bos);POIFSFileSystempoifs= newPOIFSFileSystem();DirectoryNoderoot= poifs.getRoot();root.createDocument(Ole10Native.OLE10_NATIVE, newByteArrayInputStream(bos.toByteArray()));root.setStorageClsid(ClassID.OLE10_PACKAGE);// TODO: generate CombObj streamOutputStreamos= pp.getOutputStream();poifs.writeFilesystem(os);os.close();poifs.close();return oleId;
}
}