some changes to allow shared string table to be subclassed

git-svn-id: https://svn.apache.org/repos/asf/poi/trunk@1822404 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
PJ Fanning 2018-01-27 13:30:52 +00:00
parent 47a21a80d4
commit 42ffb63210
3 changed files with 133 additions and 102 deletions

View File

@ -20,6 +20,7 @@ package org.apache.poi.xssf.model;
import static org.apache.poi.POIXMLTypeLoader.DEFAULT_XML_OPTIONS; import static org.apache.poi.POIXMLTypeLoader.DEFAULT_XML_OPTIONS;
import static org.apache.poi.xssf.usermodel.XSSFRelation.NS_SPREADSHEETML; import static org.apache.poi.xssf.usermodel.XSSFRelation.NS_SPREADSHEETML;
import java.io.Closeable;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.io.OutputStream; import java.io.OutputStream;
@ -61,7 +62,7 @@ import org.openxmlformats.schemas.spreadsheetml.x2006.main.SstDocument;
* properties, and phonetic properties (for East Asian languages). * properties, and phonetic properties (for East Asian languages).
* </p> * </p>
*/ */
public class SharedStringsTable extends POIXMLDocumentPart { public class SharedStringsTable extends POIXMLDocumentPart implements Closeable {
/** /**
* Array of individual string items in the Shared String table. * Array of individual string items in the Shared String table.
@ -77,22 +78,22 @@ public class SharedStringsTable extends POIXMLDocumentPart {
* An integer representing the total count of strings in the workbook. This count does not * An integer representing the total count of strings in the workbook. This count does not
* include any numbers, it counts only the total of text strings in the workbook. * include any numbers, it counts only the total of text strings in the workbook.
*/ */
private int count; protected int count;
/** /**
* An integer representing the total count of unique strings in the Shared String Table. * An integer representing the total count of unique strings in the Shared String Table.
* A string is unique even if it is a copy of another string, but has different formatting applied * A string is unique even if it is a copy of another string, but has different formatting applied
* at the character level. * at the character level.
*/ */
private int uniqueCount; protected int uniqueCount;
private SstDocument _sstDoc; private SstDocument _sstDoc;
private static final XmlOptions options = new XmlOptions(); private static final XmlOptions options = new XmlOptions();
static { static {
options.put( XmlOptions.SAVE_INNER ); options.put( XmlOptions.SAVE_INNER );
options.put( XmlOptions.SAVE_AGGRESSIVE_NAMESPACES ); options.put( XmlOptions.SAVE_AGGRESSIVE_NAMESPACES );
options.put( XmlOptions.SAVE_USE_DEFAULT_NAMESPACE ); options.put( XmlOptions.SAVE_USE_DEFAULT_NAMESPACE );
options.setSaveImplicitNamespaces(Collections.singletonMap("", NS_SPREADSHEETML)); options.setSaveImplicitNamespaces(Collections.singletonMap("", NS_SPREADSHEETML));
} }
@ -108,11 +109,11 @@ public class SharedStringsTable extends POIXMLDocumentPart {
public SharedStringsTable(PackagePart part) throws IOException { public SharedStringsTable(PackagePart part) throws IOException {
super(part); super(part);
readFrom(part.getInputStream()); readFrom(part.getInputStream());
} }
/** /**
* Read this shared strings table from an XML file. * Read this shared strings table from an XML file.
* *
* @param is The input stream containing the XML document. * @param is The input stream containing the XML document.
* @throws IOException if an error occurs while reading. * @throws IOException if an error occurs while reading.
*/ */
@ -125,7 +126,7 @@ public class SharedStringsTable extends POIXMLDocumentPart {
uniqueCount = (int)sst.getUniqueCount(); uniqueCount = (int)sst.getUniqueCount();
//noinspection deprecation //noinspection deprecation
for (CTRst st : sst.getSiArray()) { for (CTRst st : sst.getSiArray()) {
stmap.put(getKey(st), cnt); stmap.put(xmlText(st), cnt);
strings.add(st); strings.add(st);
cnt++; cnt++;
} }
@ -134,7 +135,7 @@ public class SharedStringsTable extends POIXMLDocumentPart {
} }
} }
private String getKey(CTRst st) { protected String xmlText(CTRst st) {
return st.xmlText(options); return st.xmlText(options);
} }
@ -195,7 +196,7 @@ public class SharedStringsTable extends POIXMLDocumentPart {
*/ */
@Removal(version = "4.2") //make private in 4.2 @Removal(version = "4.2") //make private in 4.2
public int addEntry(CTRst st) { public int addEntry(CTRst st) {
String s = getKey(st); String s = xmlText(st);
count++; count++;
if (stmap.containsKey(s)) { if (stmap.containsKey(s)) {
return stmap.get(s); return stmap.get(s);
@ -256,7 +257,7 @@ public class SharedStringsTable extends POIXMLDocumentPart {
/** /**
* Write this table out as XML. * Write this table out as XML.
* *
* @param out The stream to write to. * @param out The stream to write to.
* @throws IOException if an error occurs while writing. * @throws IOException if an error occurs while writing.
*/ */
@ -282,4 +283,16 @@ public class SharedStringsTable extends POIXMLDocumentPart {
writeTo(out); writeTo(out);
} }
} }
/**
* Close any open resources, like temp files. This method is called by <code>XSSFWorkbook#close()</code>.
* <p>
* This implementation is empty but subclasses may need to implement some logic.
* </p>
*
* @since 4.0.0
* @throws IOException if an error occurs while closing.
*/
@Override
public void close() throws IOException {}
} }

View File

@ -27,8 +27,8 @@ import org.apache.poi.POIXMLRelation;
/** /**
* Instantiates sub-classes of POIXMLDocumentPart depending on their relationship type * Instantiates sub-classes of POIXMLDocumentPart depending on their relationship type
*/ */
public final class XSSFFactory extends POIXMLFactory { public class XSSFFactory extends POIXMLFactory {
private XSSFFactory() { protected XSSFFactory() {
} }
private static final XSSFFactory inst = new XSSFFactory(); private static final XSSFFactory inst = new XSSFFactory();
@ -50,8 +50,8 @@ public final class XSSFFactory extends POIXMLFactory {
*/ */
@Override @Override
protected POIXMLDocumentPart createDocumentPart protected POIXMLDocumentPart createDocumentPart
(Class<? extends POIXMLDocumentPart> cls, Class<?>[] classes, Object[] values) (Class<? extends POIXMLDocumentPart> cls, Class<?>[] classes, Object[] values)
throws SecurityException, NoSuchMethodException, InstantiationException, IllegalAccessException, InvocationTargetException { throws SecurityException, NoSuchMethodException, InstantiationException, IllegalAccessException, InvocationTargetException {
Constructor<? extends POIXMLDocumentPart> constructor = cls.getDeclaredConstructor(classes); Constructor<? extends POIXMLDocumentPart> constructor = cls.getDeclaredConstructor(classes);
return constructor.newInstance(values); return constructor.newInstance(values);
} }

View File

@ -127,7 +127,7 @@ public class XSSFWorkbook extends POIXMLDocument implements Workbook {
* @deprecated POI 3.17 beta 1 * @deprecated POI 3.17 beta 1
* @see Units#DEFAULT_CHARACTER_WIDTH * @see Units#DEFAULT_CHARACTER_WIDTH
*/ */
@Removal(version="3.19") @Removal(version="4.1")
public static final float DEFAULT_CHARACTER_WIDTH = Units.DEFAULT_CHARACTER_WIDTH; public static final float DEFAULT_CHARACTER_WIDTH = Units.DEFAULT_CHARACTER_WIDTH;
/** /**
@ -186,7 +186,7 @@ public class XSSFWorkbook extends POIXMLDocument implements Workbook {
* TODO * TODO
*/ */
private CalculationChain calcChain; private CalculationChain calcChain;
/** /**
* External Links, for referencing names or cells in other workbooks. * External Links, for referencing names or cells in other workbooks.
*/ */
@ -236,6 +236,7 @@ public class XSSFWorkbook extends POIXMLDocument implements Workbook {
private List<XSSFPivotTable> pivotTables; private List<XSSFPivotTable> pivotTables;
private List<CTPivotCache> pivotCaches; private List<CTPivotCache> pivotCaches;
private final XSSFFactory xssfFactory;
/** /**
* Create a new SpreadsheetML workbook. * Create a new SpreadsheetML workbook.
@ -244,23 +245,33 @@ public class XSSFWorkbook extends POIXMLDocument implements Workbook {
this(XSSFWorkbookType.XLSX); this(XSSFWorkbookType.XLSX);
} }
@Internal
public XSSFWorkbook(XSSFFactory factory) {
this(XSSFWorkbookType.XLSX, factory);
}
/** /**
* Create a new SpreadsheetML workbook. * Create a new SpreadsheetML workbook.
* @param workbookType The type of workbook to make (.xlsx or .xlsm). * @param workbookType The type of workbook to make (.xlsx or .xlsm).
*/ */
public XSSFWorkbook(XSSFWorkbookType workbookType) { public XSSFWorkbook(XSSFWorkbookType workbookType) {
this(workbookType, null);
}
private XSSFWorkbook(XSSFWorkbookType workbookType, XSSFFactory factory) {
super(newPackage(workbookType)); super(newPackage(workbookType));
this.xssfFactory = (factory == null) ? XSSFFactory.getInstance() : factory;
onWorkbookCreate(); onWorkbookCreate();
} }
/** /**
* Constructs a XSSFWorkbook object given a OpenXML4J <code>Package</code> object, * 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>. * 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 * <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 * by calling either {@link #close()} or {@link OPCPackage#close()}, to avoid
* leaving file handles open. * leaving file handles open.
* *
* <p>Creating a XSSFWorkbook from a file-backed OPC Package has a lower memory * <p>Creating a XSSFWorkbook from a file-backed OPC Package has a lower memory
* footprint than an InputStream backed one. * footprint than an InputStream backed one.
* *
@ -268,12 +279,13 @@ public class XSSFWorkbook extends POIXMLDocument implements Workbook {
*/ */
public XSSFWorkbook(OPCPackage pkg) throws IOException { public XSSFWorkbook(OPCPackage pkg) throws IOException {
super(pkg); super(pkg);
this.xssfFactory = XSSFFactory.getInstance();
beforeDocumentRead(); beforeDocumentRead();
// Build a tree of POIXMLDocumentParts, this workbook being the root // Build a tree of POIXMLDocumentParts, this workbook being the root
load(XSSFFactory.getInstance()); load(this.xssfFactory);
// some broken Workbooks miss this... // some broken Workbooks miss this...
setBookViewsIfMissing(); setBookViewsIfMissing();
} }
@ -281,7 +293,7 @@ public class XSSFWorkbook extends POIXMLDocument implements Workbook {
/** /**
* Constructs a XSSFWorkbook object, by buffering the whole stream into memory * Constructs a XSSFWorkbook object, by buffering the whole stream into memory
* and then opening an {@link OPCPackage} object for it. * and then opening an {@link OPCPackage} object for it.
* *
* <p>Using an {@link InputStream} requires more memory than using a File, so * <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 * if a {@link File} is available then you should instead do something like
* <pre><code> * <pre><code>
@ -298,29 +310,29 @@ public class XSSFWorkbook extends POIXMLDocument implements Workbook {
/** /**
* Constructs a XSSFWorkbook object from a given file. * Constructs a XSSFWorkbook object from a given file.
* *
* <p>Once you have finished working with the Workbook, you should close * <p>Once you have finished working with the Workbook, you should close
* the package by calling {@link #close()}, to avoid leaving file * the package by calling {@link #close()}, to avoid leaving file
* handles open. * handles open.
* *
* <p>Opening a XSSFWorkbook from a file has a lower memory footprint * <p>Opening a XSSFWorkbook from a file has a lower memory footprint
* than opening from an InputStream * than opening from an InputStream
* *
* @param file the file to open * @param file the file to open
*/ */
public XSSFWorkbook(File file) throws IOException, InvalidFormatException { public XSSFWorkbook(File file) throws IOException, InvalidFormatException {
this(OPCPackage.open(file)); this(OPCPackage.open(file));
} }
/** /**
* Constructs a XSSFWorkbook object given a file name. * Constructs a XSSFWorkbook object given a file name.
* *
* *
* <p>Once you have finished working with the Workbook, you should close * <p>Once you have finished working with the Workbook, you should close
* the package by calling {@link #close()}, to avoid leaving file * the package by calling {@link #close()}, to avoid leaving file
* handles open. * handles open.
* *
* <p>Opening a XSSFWorkbook from a file has a lower memory footprint * <p>Opening a XSSFWorkbook from a file has a lower memory footprint
* than opening from an InputStream * than opening from an InputStream
* *
* @param path the file name. * @param path the file name.
@ -328,7 +340,7 @@ public class XSSFWorkbook extends POIXMLDocument implements Workbook {
public XSSFWorkbook(String path) throws IOException { public XSSFWorkbook(String path) throws IOException {
this(openPackage(path)); this(openPackage(path));
} }
/** /**
* Constructs a XSSFWorkbook object using Package Part. * Constructs a XSSFWorkbook object using Package Part.
* @param part package part * @param part package part
@ -337,7 +349,7 @@ public class XSSFWorkbook extends POIXMLDocument implements Workbook {
public XSSFWorkbook(PackagePart part) throws IOException { public XSSFWorkbook(PackagePart part) throws IOException {
this(part.getInputStream()); this(part.getInputStream());
} }
protected void beforeDocumentRead() { protected void beforeDocumentRead() {
// Ensure it isn't a XLSB file, which we don't support // Ensure it isn't a XLSB file, which we don't support
if (getCorePart().getContentType().equals(XSSFRelation.XLSB_BINARY_WORKBOOK.getContentType())) { if (getCorePart().getContentType().equals(XSSFRelation.XLSB_BINARY_WORKBOOK.getContentType())) {
@ -377,13 +389,13 @@ public class XSSFWorkbook extends POIXMLDocument implements Workbook {
} }
} }
boolean packageReadOnly = (getPackage().getPackageAccess() == PackageAccess.READ); boolean packageReadOnly = (getPackage().getPackageAccess() == PackageAccess.READ);
if (stylesSource == null) { if (stylesSource == null) {
// Create Styles if it is missing // Create Styles if it is missing
if (packageReadOnly) { if (packageReadOnly) {
stylesSource = new StylesTable(); stylesSource = new StylesTable();
} else { } else {
stylesSource = (StylesTable)createRelationship(XSSFRelation.STYLES, XSSFFactory.getInstance()); stylesSource = (StylesTable)createRelationship(XSSFRelation.STYLES, this.xssfFactory);
} }
} }
stylesSource.setWorkbook(this); stylesSource.setWorkbook(this);
@ -394,10 +406,10 @@ public class XSSFWorkbook extends POIXMLDocument implements Workbook {
if (packageReadOnly) { if (packageReadOnly) {
sharedStringSource = new SharedStringsTable(); sharedStringSource = new SharedStringsTable();
} else { } else {
sharedStringSource = (SharedStringsTable)createRelationship(XSSFRelation.SHARED_STRINGS, XSSFFactory.getInstance()); sharedStringSource = (SharedStringsTable)createRelationship(XSSFRelation.SHARED_STRINGS, this.xssfFactory);
} }
} }
// Load individual sheets. The order of sheets is defined by the order // Load individual sheets. The order of sheets is defined by the order
// of CTSheet elements in the workbook // of CTSheet elements in the workbook
sheets = new ArrayList<>(shIdMap.size()); sheets = new ArrayList<>(shIdMap.size());
@ -405,8 +417,8 @@ public class XSSFWorkbook extends POIXMLDocument implements Workbook {
for (CTSheet ctSheet : this.workbook.getSheets().getSheetArray()) { for (CTSheet ctSheet : this.workbook.getSheets().getSheetArray()) {
parseSheet(shIdMap, ctSheet); parseSheet(shIdMap, ctSheet);
} }
// Load the external links tables. Their order is defined by the order // Load the external links tables. Their order is defined by the order
// of CTExternalReference elements in the workbook // of CTExternalReference elements in the workbook
externalLinks = new ArrayList<>(elIdMap.size()); externalLinks = new ArrayList<>(elIdMap.size());
if (this.workbook.isSetExternalReferences()) { if (this.workbook.isSetExternalReferences()) {
@ -419,7 +431,7 @@ public class XSSFWorkbook extends POIXMLDocument implements Workbook {
externalLinks.add(el); externalLinks.add(el);
} }
} }
// Process the named ranges // Process the named ranges
reprocessNamedRanges(); reprocessNamedRanges();
} catch (XmlException e) { } catch (XmlException e) {
@ -458,8 +470,8 @@ public class XSSFWorkbook extends POIXMLDocument implements Workbook {
POIXMLProperties.ExtendedProperties expProps = getProperties().getExtendedProperties(); POIXMLProperties.ExtendedProperties expProps = getProperties().getExtendedProperties();
expProps.getUnderlyingProperties().setApplication(DOCUMENT_CREATOR); expProps.getUnderlyingProperties().setApplication(DOCUMENT_CREATOR);
sharedStringSource = (SharedStringsTable)createRelationship(XSSFRelation.SHARED_STRINGS, XSSFFactory.getInstance()); sharedStringSource = (SharedStringsTable)createRelationship(XSSFRelation.SHARED_STRINGS, this.xssfFactory);
stylesSource = (StylesTable)createRelationship(XSSFRelation.STYLES, XSSFFactory.getInstance()); stylesSource = (StylesTable)createRelationship(XSSFRelation.STYLES, this.xssfFactory);
stylesSource.setWorkbook(this); stylesSource.setWorkbook(this);
namedRanges = new ArrayList<>(); namedRanges = new ArrayList<>();
@ -467,7 +479,7 @@ public class XSSFWorkbook extends POIXMLDocument implements Workbook {
sheets = new ArrayList<>(); sheets = new ArrayList<>();
pivotTables = new ArrayList<>(); pivotTables = new ArrayList<>();
} }
private void setBookViewsIfMissing() { private void setBookViewsIfMissing() {
if(!workbook.isSetBookViews()) { if(!workbook.isSetBookViews()) {
CTBookViews bvs = workbook.addNewBookViews(); CTBookViews bvs = workbook.addNewBookViews();
@ -525,7 +537,7 @@ public class XSSFWorkbook extends POIXMLDocument implements Workbook {
@Override @Override
public int addPicture(byte[] pictureData, int format) { public int addPicture(byte[] pictureData, int format) {
int imageNumber = getAllPictures().size() + 1; int imageNumber = getAllPictures().size() + 1;
XSSFPictureData img = createRelationship(XSSFPictureData.RELATIONS[format], XSSFFactory.getInstance(), imageNumber, true).getDocumentPart(); XSSFPictureData img = createRelationship(XSSFPictureData.RELATIONS[format], this.xssfFactory, imageNumber, true).getDocumentPart();
try (OutputStream out = img.getPackagePart().getOutputStream()) { try (OutputStream out = img.getPackagePart().getOutputStream()) {
out.write(pictureData); out.write(pictureData);
} catch (IOException e){ } catch (IOException e){
@ -552,7 +564,7 @@ public class XSSFWorkbook extends POIXMLDocument implements Workbook {
*/ */
public int addPicture(InputStream is, int format) throws IOException { public int addPicture(InputStream is, int format) throws IOException {
int imageNumber = getAllPictures().size() + 1; int imageNumber = getAllPictures().size() + 1;
XSSFPictureData img = createRelationship(XSSFPictureData.RELATIONS[format], XSSFFactory.getInstance(), imageNumber, true).getDocumentPart(); XSSFPictureData img = createRelationship(XSSFPictureData.RELATIONS[format], this.xssfFactory, imageNumber, true).getDocumentPart();
try (OutputStream out = img.getPackagePart().getOutputStream()) { try (OutputStream out = img.getPackagePart().getOutputStream()) {
IOUtils.copy(is, out); IOUtils.copy(is, out);
} }
@ -574,6 +586,12 @@ public class XSSFWorkbook extends POIXMLDocument implements Workbook {
return cloneSheet(sheetNum, null); return cloneSheet(sheetNum, null);
} }
@Override
public void close() throws IOException {
super.close();
sharedStringSource.close();
}
/** /**
* Create an XSSFSheet from an existing sheet in the XSSFWorkbook. * 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 * The cloned sheet is a deep copy of the original but with a new given
@ -618,14 +636,14 @@ public class XSSFWorkbook extends POIXMLDocument implements Workbook {
for(PackageRelationship pr : srcSheet.getPackagePart().getRelationships()) { for(PackageRelationship pr : srcSheet.getPackagePart().getRelationships()) {
if (pr.getTargetMode() == TargetMode.EXTERNAL) { if (pr.getTargetMode() == TargetMode.EXTERNAL) {
clonedSheet.getPackagePart().addExternalRelationship clonedSheet.getPackagePart().addExternalRelationship
(pr.getTargetURI().toASCIIString(), pr.getRelationshipType(), pr.getId()); (pr.getTargetURI().toASCIIString(), pr.getRelationshipType(), pr.getId());
} }
} }
} catch (InvalidFormatException e) { } catch (InvalidFormatException e) {
throw new POIXMLException("Failed to clone sheet", e); throw new POIXMLException("Failed to clone sheet", e);
} }
try (ByteArrayOutputStream out = new ByteArrayOutputStream()) { try (ByteArrayOutputStream out = new ByteArrayOutputStream()) {
srcSheet.write(out); srcSheet.write(out);
try (ByteArrayInputStream bis = new ByteArrayInputStream(out.toByteArray())) { try (ByteArrayInputStream bis = new ByteArrayInputStream(out.toByteArray())) {
@ -658,7 +676,7 @@ public class XSSFWorkbook extends POIXMLDocument implements Workbook {
clonedDg.getCTDrawing().set(dg.getCTDrawing()); clonedDg.getCTDrawing().set(dg.getCTDrawing());
clonedDg = clonedSheet.createDrawingPatriarch(); clonedDg = clonedSheet.createDrawingPatriarch();
// Clone drawing relations // Clone drawing relations
List<RelationPart> srcRels = srcSheet.createDrawingPatriarch().getRelationParts(); List<RelationPart> srcRels = srcSheet.createDrawingPatriarch().getRelationParts();
for (RelationPart rp : srcRels) { for (RelationPart rp : srcRels) {
@ -667,7 +685,7 @@ public class XSSFWorkbook extends POIXMLDocument implements Workbook {
} }
return clonedSheet; return clonedSheet;
} }
/** /**
* @since 3.14-Beta1 * @since 3.14-Beta1
*/ */
@ -675,8 +693,8 @@ public class XSSFWorkbook extends POIXMLDocument implements Workbook {
PackageRelationship rel = rp.getRelationship(); PackageRelationship rel = rp.getRelationship();
if (rel.getTargetMode() == TargetMode.EXTERNAL) { if (rel.getTargetMode() == TargetMode.EXTERNAL) {
target.getPackagePart().addRelationship( target.getPackagePart().addRelationship(
rel.getTargetURI(), rel.getTargetMode(), rel.getRelationshipType(), rel.getId()); rel.getTargetURI(), rel.getTargetMode(), rel.getRelationshipType(), rel.getId());
} else { } else {
XSSFRelation xssfRel = XSSFRelation.getInstance(rel.getRelationshipType()); XSSFRelation xssfRel = XSSFRelation.getInstance(rel.getRelationshipType());
if (xssfRel == null) { if (xssfRel == null) {
// Don't copy all relations blindly, but only the ones we know about // Don't copy all relations blindly, but only the ones we know about
@ -859,12 +877,12 @@ public class XSSFWorkbook extends POIXMLDocument implements Workbook {
for(XSSFSheet sh : sheets) { for(XSSFSheet sh : sheets) {
sheetNumber = (int)Math.max(sh.sheet.getSheetId() + 1, sheetNumber); 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 // Bug 57165: We also need to check that the resulting file name is not already taken
// this can happen when moving/cloning sheets // this can happen when moving/cloning sheets
String sheetName = XSSFRelation.WORKSHEET.getFileName(sheetNumber); String sheetName = XSSFRelation.WORKSHEET.getFileName(sheetNumber);
for(POIXMLDocumentPart relation : getRelations()) { for(POIXMLDocumentPart relation : getRelations()) {
if(relation.getPackagePart() != null && if(relation.getPackagePart() != null &&
sheetName.equals(relation.getPackagePart().getPartName().getName())) { sheetName.equals(relation.getPackagePart().getPartName().getName())) {
// name is taken => try next one // name is taken => try next one
sheetNumber++; sheetNumber++;
@ -876,7 +894,7 @@ public class XSSFWorkbook extends POIXMLDocument implements Workbook {
break; break;
} }
RelationPart rp = createRelationship(XSSFRelation.WORKSHEET, XSSFFactory.getInstance(), sheetNumber, false); RelationPart rp = createRelationship(XSSFRelation.WORKSHEET, this.xssfFactory, sheetNumber, false);
XSSFSheet wrapper = rp.getDocumentPart(); XSSFSheet wrapper = rp.getDocumentPart();
wrapper.sheet = sheet; wrapper.sheet = sheet;
sheet.setId(rp.getRelationship().getId()); sheet.setId(rp.getRelationship().getId());
@ -904,7 +922,7 @@ public class XSSFWorkbook extends POIXMLDocument implements Workbook {
sheet.setName(sheetname); sheet.setName(sheetname);
return sheet; return sheet;
} }
/** /**
* Finds a font that matches the one with the supplied attributes * Finds a font that matches the one with the supplied attributes
*/ */
@ -1194,21 +1212,21 @@ public class XSSFWorkbook extends POIXMLDocument implements Workbook {
public Iterator<Sheet> sheetIterator() { public Iterator<Sheet> sheetIterator() {
return new SheetIterator<>(); return new SheetIterator<>();
} }
/** /**
* Alias for {@link #sheetIterator()} to allow * Alias for {@link #sheetIterator()} to allow
* foreach loops * foreach loops
* *
* Note: remove() is not supported on this iterator. * Note: remove() is not supported on this iterator.
* Use {@link #removeSheetAt(int)} to remove sheets instead. * Use {@link #removeSheetAt(int)} to remove sheets instead.
* *
* @return an iterator of the sheets. * @return an iterator of the sheets.
*/ */
@Override @Override
public Iterator<Sheet> iterator() { public Iterator<Sheet> iterator() {
return sheetIterator(); return sheetIterator();
} }
private final class SheetIterator<T extends Sheet> implements Iterator<T> { private final class SheetIterator<T extends Sheet> implements Iterator<T> {
final private Iterator<T> it; final private Iterator<T> it;
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
@ -1234,7 +1252,7 @@ public class XSSFWorkbook extends POIXMLDocument implements Workbook {
"Use Sheet.removeSheetAt(int) instead."); "Use Sheet.removeSheetAt(int) instead.");
} }
} }
/** /**
* Are we a normal workbook (.xlsx), or a * Are we a normal workbook (.xlsx), or a
* macro enabled workbook (.xlsm)? * macro enabled workbook (.xlsm)?
@ -1258,11 +1276,11 @@ public class XSSFWorkbook extends POIXMLDocument implements Workbook {
/** /**
* Remove the first named range found with the given name. * Remove the first named range found with the given name.
* *
* Note: names of named ranges are not unique (name + sheet * Note: names of named ranges are not unique (name + sheet
* index is unique), so {@link #removeName(Name)} should * index is unique), so {@link #removeName(Name)} should
* be used if possible. * be used if possible.
* *
* @param name the named range name to remove * @param name the named range name to remove
* *
* @throws IllegalArgumentException if no named range could be found * @throws IllegalArgumentException if no named range could be found
@ -1373,7 +1391,7 @@ public class XSSFWorkbook extends POIXMLDocument implements Workbook {
final XSSFSheet sheet = getSheetAt(index); final XSSFSheet sheet = getSheetAt(index);
sheet.onSheetDelete(); sheet.onSheetDelete();
//delete the CTSheet reference from workbook.xml //delete the CTSheet reference from workbook.xml
workbook.getSheets().removeSheet(index); workbook.getSheets().removeSheet(index);
@ -1445,7 +1463,7 @@ public class XSSFWorkbook extends POIXMLDocument implements Workbook {
* @param index the index to validate * @param index the index to validate
* @throws IllegalArgumentException if the index is out of range (index * @throws IllegalArgumentException if the index is out of range (index
* &lt; 0 || index &gt;= getNumberOfSheets()). * &lt; 0 || index &gt;= getNumberOfSheets()).
*/ */
private void validateSheetIndex(int index) { private void validateSheetIndex(int index) {
int lastSheetIx = sheets.size() - 1; int lastSheetIx = sheets.size() - 1;
if (index < 0 || index > lastSheetIx) { if (index < 0 || index > lastSheetIx) {
@ -1592,7 +1610,7 @@ public class XSSFWorkbook extends POIXMLDocument implements Workbook {
if (sheetname == null) { if (sheetname == null) {
throw new IllegalArgumentException( "sheetName must not be null" ); throw new IllegalArgumentException( "sheetName must not be null" );
} }
validateSheetIndex(sheetIndex); validateSheetIndex(sheetIndex);
String oldSheetName = getSheetName(sheetIndex); String oldSheetName = getSheetName(sheetIndex);
@ -1606,7 +1624,7 @@ public class XSSFWorkbook extends POIXMLDocument implements Workbook {
if (sheetname.equals(oldSheetName)) { if (sheetname.equals(oldSheetName)) {
return; return;
} }
// Check it isn't already taken // Check it isn't already taken
if (containsSheet(sheetname, sheetIndex )) { if (containsSheet(sheetname, sheetIndex )) {
throw new IllegalArgumentException( "The workbook already contains a sheet of this name" ); throw new IllegalArgumentException( "The workbook already contains a sheet of this name" );
@ -1643,11 +1661,11 @@ public class XSSFWorkbook extends POIXMLDocument implements Workbook {
for(int i=0; i < sheetArray.length; i++) { for(int i=0; i < sheetArray.length; i++) {
sheets.get(i).sheet = sheetArray[i]; sheets.get(i).sheet = sheetArray[i];
} }
updateNamedRangesAfterSheetReorder(idx, pos); updateNamedRangesAfterSheetReorder(idx, pos);
updateActiveSheetAfterSheetReorder(idx, pos); updateActiveSheetAfterSheetReorder(idx, pos);
} }
/** /**
* update sheet-scoped named ranges in this workbook after changing the sheet order * update sheet-scoped named ranges in this workbook after changing the sheet order
* of a sheet at oldIndex to newIndex. * of a sheet at oldIndex to newIndex.
@ -1677,7 +1695,7 @@ public class XSSFWorkbook extends POIXMLDocument implements Workbook {
} }
} }
} }
private void updateActiveSheetAfterSheetReorder(int oldIndex, int newIndex) { private void updateActiveSheetAfterSheetReorder(int oldIndex, int newIndex) {
// adjust active sheet if necessary // adjust active sheet if necessary
int active = getActiveSheetIndex(); int active = getActiveSheetIndex();
@ -1714,7 +1732,7 @@ public class XSSFWorkbook extends POIXMLDocument implements Workbook {
workbook.unsetDefinedNames(); workbook.unsetDefinedNames();
} }
workbook.setDefinedNames(names); workbook.setDefinedNames(names);
// Re-process the named ranges // Re-process the named ranges
reprocessNamedRanges(); reprocessNamedRanges();
} else { } else {
@ -1723,7 +1741,7 @@ public class XSSFWorkbook extends POIXMLDocument implements Workbook {
} }
} }
} }
private void reprocessNamedRanges() { private void reprocessNamedRanges() {
namedRangesByName = new ArrayListValuedHashMap<>(); namedRangesByName = new ArrayListValuedHashMap<>();
namedRanges = new ArrayList<>(); namedRanges = new ArrayList<>();
@ -1757,7 +1775,7 @@ public class XSSFWorkbook extends POIXMLDocument implements Workbook {
workbook.save(out, xmlOptions); workbook.save(out, xmlOptions);
} }
} }
/** /**
* Returns SharedStringsTable - tha cache of string for this workbook * Returns SharedStringsTable - tha cache of string for this workbook
* *
@ -1855,7 +1873,7 @@ public class XSSFWorkbook extends POIXMLDocument implements Workbook {
} }
for(PackageRelationship rel : sheet.getPackagePart().getRelationshipsByType(XSSFRelation.PACKEMBEDDINGS.getRelation())) { for(PackageRelationship rel : sheet.getPackagePart().getRelationshipsByType(XSSFRelation.PACKEMBEDDINGS.getRelation())) {
embedds.add( sheet.getPackagePart().getRelatedPart(rel) ); embedds.add( sheet.getPackagePart().getRelatedPart(rel) );
} }
} }
return embedds; return embedds;
@ -1886,7 +1904,7 @@ public class XSSFWorkbook extends POIXMLDocument implements Workbook {
CTSheet ctSheet = sheets.get(sheetIx).sheet; CTSheet ctSheet = sheets.get(sheetIx).sheet;
return ctSheet.getState() == STSheetState.VERY_HIDDEN; return ctSheet.getState() == STSheetState.VERY_HIDDEN;
} }
@Override @Override
public SheetVisibility getSheetVisibility(int sheetIx) { public SheetVisibility getSheetVisibility(int sheetIx) {
validateSheetIndex(sheetIx); validateSheetIndex(sheetIx);
@ -1912,7 +1930,7 @@ public class XSSFWorkbook extends POIXMLDocument implements Workbook {
@Override @Override
public void setSheetVisibility(int sheetIx, SheetVisibility visibility) { public void setSheetVisibility(int sheetIx, SheetVisibility visibility) {
validateSheetIndex(sheetIx); validateSheetIndex(sheetIx);
final CTSheet ctSheet = sheets.get(sheetIx).sheet; final CTSheet ctSheet = sheets.get(sheetIx).sheet;
switch (visibility) { switch (visibility) {
case VISIBLE: case VISIBLE:
@ -1928,9 +1946,9 @@ public class XSSFWorkbook extends POIXMLDocument implements Workbook {
throw new IllegalArgumentException("This should never happen"); throw new IllegalArgumentException("This should never happen");
} }
} }
/** /**
* Fired when a formula is deleted from this workbook, * Fired when a formula is deleted from this workbook,
@ -1957,10 +1975,10 @@ public class XSSFWorkbook extends POIXMLDocument implements Workbook {
public CalculationChain getCalculationChain() { public CalculationChain getCalculationChain() {
return calcChain; return calcChain;
} }
/** /**
* Returns the list of {@link ExternalLinksTable} object for this workbook * Returns the list of {@link ExternalLinksTable} object for this workbook
* *
* <p>The external links table specifies details of named ranges etc * <p>The external links table specifies details of named ranges etc
* that are referenced from other workbooks, along with the last seen * that are referenced from other workbooks, along with the last seen
* values of what they point to.</p> * values of what they point to.</p>
@ -1994,9 +2012,9 @@ public class XSSFWorkbook extends POIXMLDocument implements Workbook {
} }
/** /**
* Adds the External Link Table part and relations required to allow formulas * Adds the External Link Table part and relations required to allow formulas
* referencing the specified external workbook to be added to this one. Allows * 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 * formulas such as "[MyOtherWorkbook.xlsx]Sheet3!$A$5" to be added to the
* file, for workbooks not already linked / referenced. * file, for workbooks not already linked / referenced.
* *
* Note: this is not implemented and thus currently throws an Exception stating this. * Note: this is not implemented and thus currently throws an Exception stating this.
@ -2088,8 +2106,8 @@ public class XSSFWorkbook extends POIXMLDocument implements Workbook {
} }
/** /**
* Sets the workbook password. * Sets the workbook password.
* *
* @param password if null, the password will be removed * @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) * @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) * otherwise the given algorithm is used for calculating the hash password (Excel 2013)
@ -2115,7 +2133,7 @@ public class XSSFWorkbook extends POIXMLDocument implements Workbook {
/** /**
* Sets the revisions password. * Sets the revisions password.
* *
* @param password if null, the password will be removed * @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) * @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) * otherwise the given algorithm is used for calculating the hash password (Excel 2013)
@ -2138,7 +2156,7 @@ public class XSSFWorkbook extends POIXMLDocument implements Workbook {
} }
return validatePassword(safeGetWorkbookProtection(), password, "revisions"); return validatePassword(safeGetWorkbookProtection(), password, "revisions");
} }
/** /**
* Removes the workbook protection settings * Removes the workbook protection settings
*/ */
@ -2147,7 +2165,7 @@ public class XSSFWorkbook extends POIXMLDocument implements Workbook {
workbook.unsetWorkbookProtection(); workbook.unsetWorkbookProtection();
} }
} }
private boolean workbookProtectionPresent() { private boolean workbookProtectionPresent() {
return workbook.isSetWorkbookProtection(); return workbook.isSetWorkbookProtection();
} }
@ -2158,7 +2176,7 @@ public class XSSFWorkbook extends POIXMLDocument implements Workbook {
} }
return workbook.getWorkbookProtection(); return workbook.getWorkbookProtection();
} }
/** /**
* *
* Returns the locator of user-defined functions. * Returns the locator of user-defined functions.
@ -2298,7 +2316,7 @@ public class XSSFWorkbook extends POIXMLDocument implements Workbook {
OPCPackage opc = getPackage(); OPCPackage opc = getPackage();
OutputStream outputStream; OutputStream outputStream;
if (!opc.containPart(ppName)) { if (!opc.containPart(ppName)) {
POIXMLDocumentPart relationship = createRelationship(XSSFRelation.VBA_MACROS, XSSFFactory.getInstance()); POIXMLDocumentPart relationship = createRelationship(XSSFRelation.VBA_MACROS, this.xssfFactory);
outputStream = relationship.getPackagePart().getOutputStream(); outputStream = relationship.getPackagePart().getOutputStream();
} else { } else {
PackagePart part = opc.getPart(ppName); PackagePart part = opc.getPart(ppName);
@ -2328,7 +2346,7 @@ public class XSSFWorkbook extends POIXMLDocument implements Workbook {
/** /**
* Returns the spreadsheet version (EXCLE2007) of this workbook * Returns the spreadsheet version (EXCLE2007) of this workbook
* *
* @return EXCEL2007 SpreadsheetVersion enum * @return EXCEL2007 SpreadsheetVersion enum
* @since 3.14 beta 2 * @since 3.14 beta 2
*/ */
@ -2336,10 +2354,10 @@ public class XSSFWorkbook extends POIXMLDocument implements Workbook {
public SpreadsheetVersion getSpreadsheetVersion() { public SpreadsheetVersion getSpreadsheetVersion() {
return SpreadsheetVersion.EXCEL2007; return SpreadsheetVersion.EXCEL2007;
} }
/** /**
* Returns the data table with the given name (case insensitive). * Returns the data table with the given name (case insensitive).
* *
* @param name the data table name (case-insensitive) * @param name the data table name (case-insensitive)
* @return The Data table in the workbook named <tt>name</tt>, or <tt>null</tt> if no table is named <tt>name</tt>. * @return The Data table in the workbook named <tt>name</tt>, or <tt>null</tt> if no table is named <tt>name</tt>.
* @since 3.15 beta 2 * @since 3.15 beta 2
@ -2359,7 +2377,7 @@ public class XSSFWorkbook extends POIXMLDocument implements Workbook {
@Override @Override
public int addOlePackage(byte[] oleData, String label, String fileName, String command) public int addOlePackage(byte[] oleData, String label, String fileName, String command)
throws IOException { throws IOException {
// find an unused part name // find an unused part name
OPCPackage opc = getPackage(); OPCPackage opc = getPackage();
PackagePartName pnOLE; PackagePartName pnOLE;
@ -2373,7 +2391,7 @@ public class XSSFWorkbook extends POIXMLDocument implements Workbook {
} while (opc.containPart(pnOLE)); } while (opc.containPart(pnOLE));
PackagePart pp = opc.createPart( pnOLE, "application/vnd.openxmlformats-officedocument.oleObject" ); PackagePart pp = opc.createPart( pnOLE, "application/vnd.openxmlformats-officedocument.oleObject" );
Ole10Native ole10 = new Ole10Native(label, fileName, command, oleData); Ole10Native ole10 = new Ole10Native(label, fileName, command, oleData);
try (ByteArrayOutputStream bos = new ByteArrayOutputStream(oleData.length+500)) { try (ByteArrayOutputStream bos = new ByteArrayOutputStream(oleData.length+500)) {