diff --git a/poi-3.13.pwc/src/java/org/apache/poi/hssf/model/InternalWorkbook.java b/poi-3.13.pwc/src/java/org/apache/poi/hssf/model/InternalWorkbook.java index c5fc7a9..0bfd6ac 100644 --- a/poi-3.13.pwc/src/java/org/apache/poi/hssf/model/InternalWorkbook.java +++ b/poi-3.13.pwc/src/java/org/apache/poi/hssf/model/InternalWorkbook.java @@ -1915,6 +1915,10 @@ } return linkTable.getNumNames(); } + + public boolean nameExists(NameRecord nr) { + return linkTable.nameAlreadyExists(nr); + } /** gets the name record * @param index name index @@ -1924,6 +1928,25 @@ return linkTable.getNameRecord(index); } + public NameRecord getNameRecord(String name, int sheetNumber) { + if (name != null && name.length() > 0) { + return linkTable.getNameRecord(name, sheetNumber); + } + return null; + } + + public void replaceNameRecord(String existingName, NameRecord nameRecord) { + linkTable.replaceNameRecord(existingName, nameRecord); + } + + public void replaceNameSheet(NameRecord nameRecord, int newSheetNumber) { + linkTable.replaceNameSheet(newSheetNumber, nameRecord); + } + + public int getNameRecordIndex(NameRecord nr) { + return linkTable.getNameRecordIndex(nr); + } + /** gets the name comment record * @param nameRecord name record who's comment is required. * @return name comment record or null if there isn't one for the given name. @@ -1950,6 +1973,10 @@ linkTable.addName(name); return name; + } + + public void addToNamesMap(NameRecord nr) { + linkTable.addToNamesMap(nr); } /** @@ -1983,7 +2010,7 @@ linkTable.removeName(nameIndex); } } - + /** * If a {@link NameCommentRecord} is added or the name it references * is renamed, then this will update the lookup cache for it. diff --git a/poi-3.13.pwc/src/java/org/apache/poi/hssf/model/LinkTable.java b/poi-3.13.pwc/src/java/org/apache/poi/hssf/model/LinkTable.java index 76a288c..af3684b 100644 --- a/poi-3.13.pwc/src/java/org/apache/poi/hssf/model/LinkTable.java +++ b/poi-3.13.pwc/src/java/org/apache/poi/hssf/model/LinkTable.java @@ -18,6 +18,7 @@ package org.apache.poi.hssf.model; import java.util.ArrayList; +import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Map; @@ -185,6 +186,7 @@ private final List _definedNames; private final int _recordCount; private final WorkbookRecordList _workbookRecordList; // TODO - would be nice to remove this + private final Map> _nameRecordMap; public LinkTable(List inputList, int startIndex, WorkbookRecordList workbookRecordList, Map commentRecords) { @@ -213,6 +215,7 @@ } _definedNames = new ArrayList(); + _nameRecordMap = new HashMap>(); // collect zero or more DEFINEDNAMEs id=0x18, // with their comments if present while(true) { @@ -220,6 +223,7 @@ if (nextClass == NameRecord.class) { NameRecord nr = (NameRecord)rs.getNext(); _definedNames.add(nr); + addToNamesMap(nr); } else if (nextClass == NameCommentRecord.class) { NameCommentRecord ncr = (NameCommentRecord)rs.getNext(); @@ -259,6 +263,7 @@ public LinkTable(int numberOfSheets, WorkbookRecordList workbookRecordList) { _workbookRecordList = workbookRecordList; _definedNames = new ArrayList(); + _nameRecordMap = new HashMap>(); _externalBookBlocks = new ExternalBookBlock[] { new ExternalBookBlock(numberOfSheets), }; @@ -309,6 +314,7 @@ NameRecord record = getSpecificBuiltinRecord(name, sheetIndex); if (record != null) { _definedNames.remove(record); + removeFromNameRecordMap(record); } // TODO - do we need "Workbook.records.remove(...);" similar to that in Workbook.removeName(int namenum) {}? } @@ -320,9 +326,59 @@ public NameRecord getNameRecord(int index) { return _definedNames.get(index); } + + public NameRecord getNameRecord(String name, int sheetNumber) { + if (name != null && name.length() > 0) { + Map entity = _nameRecordMap.get(sheetNumber); + if (entity != null) { + return entity.get(name.toLowerCase()); + } + return null; + } + return null; + } + + public int getNameRecordIndex(NameRecord nr) { + return _definedNames.indexOf(nr); + } + + public void replaceNameRecord(String name, NameRecord nameRecord) { + if (name != null && name.length() > 0) { + Map record = _nameRecordMap.get(nameRecord.getSheetNumber()); + if (record != null) { + record.remove(name); + } + } + if (nameRecord.getNameText() != null && nameRecord.getNameText().length() > 0) { + Map record = _nameRecordMap.get(nameRecord.getSheetNumber()); + if (record != null) { + record.put(nameRecord.getNameText().toLowerCase(), nameRecord); + } + } + } + + public void replaceNameSheet(int newSheetNumber, NameRecord nameRecord) { + String name = nameRecord.getNameText(); + if (name != null && name.length() > 0) { + Map record = _nameRecordMap.get(nameRecord.getSheetNumber()); + if (record != null) { + record.remove(name); + } + nameRecord.setSheetNumber(newSheetNumber); + record = _nameRecordMap.get(newSheetNumber); + if (record != null) { + record.put(nameRecord.getNameText().toLowerCase(), nameRecord); + } else { + record = new HashMap(); + record.put(nameRecord.getNameText().toLowerCase(), nameRecord); + _nameRecordMap.put(newSheetNumber, record); + } + } + } public void addName(NameRecord name) { _definedNames.add(name); + addToNamesMap(name); // TODO - this is messy // Not the most efficient way but the other way was causing too many bugs @@ -333,32 +389,52 @@ _workbookRecordList.add(idx+countNames, name); } + public void addToNamesMap(NameRecord name) { + if (name != null + && name.getNameText() != null + && name.getNameText().length() > 0) { + if (_nameRecordMap.containsKey(name.getSheetNumber())) { + Map entity = _nameRecordMap.get(name.getSheetNumber()); + entity.put(name.getNameText().toLowerCase(), name); + } else { + Map entity = new HashMap(); + entity.put(name.getNameText().toLowerCase(), name); + _nameRecordMap.put(name.getSheetNumber(), entity); + } + } + } + public void removeName(int namenum) { - _definedNames.remove(namenum); + NameRecord toRemove = _definedNames.get(namenum); + if (toRemove != null + && toRemove.getNameText() != null + && toRemove.getNameText().length() > 0) { + removeFromNameRecordMap(toRemove); + _definedNames.remove(namenum); + } } + public void removeFromNameRecordMap(NameRecord toRemove) { + if (toRemove != null) { + Map entity = _nameRecordMap.get(toRemove.getSheetNumber()); + if (entity != null) { + entity.remove(toRemove.getNameText().toLowerCase()); + } + } + } + /** * checks if the given name is already included in the linkTable */ public boolean nameAlreadyExists(NameRecord name) { - // Check to ensure no other names have the same case-insensitive name - for ( int i = getNumNames()-1; i >=0; i-- ) { - NameRecord rec = getNameRecord(i); - if (rec != name) { - if (isDuplicatedNames(name, rec)) - return true; - } - } - return false; - } - - private static boolean isDuplicatedNames(NameRecord firstName, NameRecord lastName) { - return lastName.getNameText().equalsIgnoreCase(firstName.getNameText()) - && isSameSheetNames(firstName, lastName); - } - private static boolean isSameSheetNames(NameRecord firstName, NameRecord lastName) { - return lastName.getSheetNumber() == firstName.getSheetNumber(); + if (_nameRecordMap.get(name.getSheetNumber()) != null) { + Map entity = _nameRecordMap.get(name.getSheetNumber()); + if (entity.containsKey(name.getNameText().toLowerCase())) { + return true; + } + } + return false; } public String[] getExternalBookAndSheetName(int extRefIndex) { diff --git a/poi-3.13.pwc/src/java/org/apache/poi/hssf/usermodel/HSSFEvaluationWorkbook.java b/poi-3.13.pwc/src/java/org/apache/poi/hssf/usermodel/HSSFEvaluationWorkbook.java index 79a5962..4f7c51e 100644 --- a/poi-3.13.pwc/src/java/org/apache/poi/hssf/usermodel/HSSFEvaluationWorkbook.java +++ b/poi-3.13.pwc/src/java/org/apache/poi/hssf/usermodel/HSSFEvaluationWorkbook.java @@ -92,13 +92,12 @@ * The sheet index is required to resolve sheet-level names. -1 means workbook-global names */ public EvaluationName getName(String name, int sheetIndex) { - for(int i=0; i < _iBook.getNumNames(); i++) { - NameRecord nr = _iBook.getNameRecord(i); - if (nr.getSheetNumber() == sheetIndex+1 && name.equalsIgnoreCase(nr.getNameText())) { - return new Name(nr, i); - } + NameRecord found = _iBook.getNameRecord(name, sheetIndex+1); + if (found == null) { + return sheetIndex == -1 ? null : getName(name, -1); + } else { + return new Name(found, _iBook.getNameRecordIndex(found)); } - return sheetIndex == -1 ? null : getName(name, -1); } public int getSheetIndex(EvaluationSheet evalSheet) { diff --git a/poi-3.13.pwc/src/java/org/apache/poi/hssf/usermodel/HSSFName.java b/poi-3.13.pwc/src/java/org/apache/poi/hssf/usermodel/HSSFName.java index 6b6ae38..602c747 100644 --- a/poi-3.13.pwc/src/java/org/apache/poi/hssf/usermodel/HSSFName.java +++ b/poi-3.13.pwc/src/java/org/apache/poi/hssf/usermodel/HSSFName.java @@ -129,23 +129,27 @@ validateName(nameName); InternalWorkbook wb = _book.getWorkbook(); + String existingName = _definedNameRec.getNameText(); _definedNameRec.setNameText(nameName); - int sheetNumber = _definedNameRec.getSheetNumber(); - //Check to ensure no other names have the same case-insensitive name - for ( int i = wb.getNumNames()-1; i >=0; i-- ) - { - NameRecord rec = wb.getNameRecord(i); - if (rec != _definedNameRec) { - if (rec.getNameText().equalsIgnoreCase(nameName) && sheetNumber == rec.getSheetNumber()){ - String msg = "The "+(sheetNumber == 0 ? "workbook" : "sheet")+" already contains this name: " + nameName; - _definedNameRec.setNameText(nameName + "(2)"); - throw new IllegalArgumentException(msg); - } + if (wb.nameExists(_definedNameRec)) { + String msg = "The "+(sheetNumber == 0 ? "workbook" : "sheet")+" already contains this name: " + nameName; + _definedNameRec.setNameText(nameName + "(2)"); + throw new IllegalArgumentException(msg); + } + if (_definedNameRec.getNameText() != null && _definedNameRec.getNameText().length() > 0) { + NameRecord nr = wb.getNameRecord(existingName, _definedNameRec.getSheetNumber()); + if (nr != null) { + HSSFName newName = new HSSFName(_book, _definedNameRec, wb.getNameCommentRecord(_definedNameRec)); + _book.replaceNameRecord(existingName, newName); + wb.replaceNameRecord(existingName, _definedNameRec); + } else { + HSSFName newName = new HSSFName(_book, _definedNameRec, wb.getNameCommentRecord(_definedNameRec)); + _book.addToNamesMap(newName); + wb.addToNamesMap(_definedNameRec); } } - // Update our comment, if there is one if(_commentRec != null) { _commentRec.setNameText(nameName); @@ -245,7 +249,15 @@ (lastSheetIx == -1 ? "" : (" (0.." + lastSheetIx + ")"))); } - _definedNameRec.setSheetNumber(index + 1); + if (_definedNameRec.getNameText() != null && + _definedNameRec.getNameText().length() > 0) { + InternalWorkbook wb = _book.getWorkbook(); + HSSFName newName = new HSSFName(_book, _definedNameRec, wb.getNameCommentRecord(_definedNameRec)); + _book.replaceNameSheet(newName, index + 1); + wb.replaceNameSheet(_definedNameRec, index + 1); + } else { + _definedNameRec.setSheetNumber(index + 1); + } } /** diff --git a/poi-3.13.pwc/src/java/org/apache/poi/hssf/usermodel/HSSFWorkbook.java b/poi-3.13.pwc/src/java/org/apache/poi/hssf/usermodel/HSSFWorkbook.java index 8475ec7..e7bb2fb 100644 --- a/poi-3.13.pwc/src/java/org/apache/poi/hssf/usermodel/HSSFWorkbook.java +++ b/poi-3.13.pwc/src/java/org/apache/poi/hssf/usermodel/HSSFWorkbook.java @@ -143,6 +143,11 @@ */ private ArrayList names; + + /** + * this holds the HSSFName in a map for fast look-up. + */ + private Map> namesMap; /** * this holds the HSSFFont objects attached to this workbook. @@ -195,6 +200,7 @@ workbook = book; _sheets = new ArrayList(INITIAL_CAPACITY); names = new ArrayList(INITIAL_CAPACITY); + namesMap = new HashMap>(); } /** @@ -335,6 +341,7 @@ _sheets = new ArrayList(INITIAL_CAPACITY); names = new ArrayList(INITIAL_CAPACITY); + namesMap = new HashMap>(); // Grab the data from the workbook stream, however // it happens to be spelled. @@ -363,6 +370,60 @@ NameRecord nameRecord = workbook.getNameRecord(i); HSSFName name = new HSSFName(this, nameRecord, workbook.getNameCommentRecord(nameRecord)); names.add(name); + addToNamesMap(name); + } + } + + /** + * This adds the HSSFName to the map. + */ + public void addToNamesMap(HSSFName name) { + if (name.getNameName() != null && name.getNameName().length() > 0) { + Map entity = namesMap.get(name.getSheetIndex()); + if (entity == null) { + entity = new HashMap(); + entity.put(name.getNameName(), name); + namesMap.put(name.getSheetIndex(), entity); + } else { + entity.put(name.getNameName(), name); + } + } + } + + /** + * Replace existing HSSFName with new name value. + */ + public void replaceNameRecord(String existingName, HSSFName nameRecord) { + if (nameRecord != null) { + if (existingName != null && existingName.length() > 0) { + Map record = namesMap.get(nameRecord.getSheetIndex()); + if (record != null) { + record.remove(existingName); + } + } + Map record = new HashMap(); + record.put(nameRecord.getNameName(), nameRecord); + namesMap.put(nameRecord.getSheetIndex(), record); + } + } + + /** + * Move the HHSFName to a new sheet in the map of names. + * Note: this sets the nameRecord to the new sheet index. + */ + public void replaceNameSheet(HSSFName nameRecord, int newSheetNumber) { + if (nameRecord != null) { + String name = nameRecord.getNameName(); + if (name != null && name.length() > 0) { + Map record = namesMap.get(nameRecord.getSheetIndex()); + if (record != null) { + record.remove(name); + } + nameRecord.setSheetIndex(newSheetNumber - 1); + record = new HashMap(); + record.put(nameRecord.getNameName(), nameRecord); + namesMap.put(nameRecord.getSheetIndex(), record); + } } } @@ -815,6 +876,7 @@ NameRecord newNameRecord = workbook.cloneFilter(filterDbNameIndex, newSheetIndex); HSSFName newName = new HSSFName(this, newNameRecord); names.add(newName); + addToNamesMap(newName); } // TODO - maybe same logic required for other/all built-in name records // workbook.cloneDrawings(clonedSheet.getSheet()); @@ -1522,13 +1584,33 @@ return result; } - @Override public HSSFName getName(String name) { int nameIndex = getNameIndex(name); if (nameIndex < 0) { return null; } return names.get(nameIndex); + } + + /** + * This is zero based, i.e. sheetNumber not sheetIndex + * + * @param name + * @param sheetNumber + * @return + */ + public HSSFName getName(String name, int sheetNumber) { + HSSFName found = null; + if (name != null && name.length() > 0) { + Map record = namesMap.get(sheetNumber); + found = record.get(name); + } + //FIXME: this is a failsafe move. + if (found == null) { + return getName(name); + } else { + return found; + } } @Override @@ -1647,6 +1729,7 @@ HSSFName newName = new HSSFName(this, nameRecord); names.add(newName); + addToNamesMap(newName); return newName; } @@ -1686,9 +1769,18 @@ @Override public void removeName(int index){ + HSSFName name = names.get(index); + removeFromNamesMap(name); names.remove(index); workbook.removeName(index); } + + private void removeFromNamesMap(HSSFName name) { + Map record = namesMap.get(name.getSheetIndex()); + if (record != null) { + record.remove(name.getNameName()); + } + } /** * Returns the instance of HSSFDataFormat for this workbook.