From: Nick Burch Date: Thu, 10 Jul 2008 21:49:37 +0000 (+0000) Subject: Fix bug #45126 - Avoid generating multiple NamedRanges with the same name, which... X-Git-Tag: REL_3_2_FINAL~252 X-Git-Url: https://source.dussan.org/?a=commitdiff_plain;h=21d6638529dd259c98e0535c9a5b6e7eafe3c374;p=poi.git Fix bug #45126 - Avoid generating multiple NamedRanges with the same name, which Excel dislikes git-svn-id: https://svn.apache.org/repos/asf/poi/trunk@675776 13f79535-47bb-0310-9956-ffa450edef68 --- diff --git a/src/documentation/content/xdocs/changes.xml b/src/documentation/content/xdocs/changes.xml index f6f0bce1a1..e484ebbf1a 100644 --- a/src/documentation/content/xdocs/changes.xml +++ b/src/documentation/content/xdocs/changes.xml @@ -37,6 +37,7 @@ + 45126 - Avoid generating multiple NamedRanges with the same name, which Excel dislikes Fix cell.getRichStringCellValue() for formula cells with string results 45365 - Handle more excel number formatting rules in FormatTrackingHSSFListener / XLS2CSVmra 45373 - Improve the performance of HSSFSheet.shiftRows diff --git a/src/documentation/content/xdocs/status.xml b/src/documentation/content/xdocs/status.xml index 4e95db3230..767b33521b 100644 --- a/src/documentation/content/xdocs/status.xml +++ b/src/documentation/content/xdocs/status.xml @@ -34,6 +34,7 @@ + 45126 - Avoid generating multiple NamedRanges with the same name, which Excel dislikes Fix cell.getRichStringCellValue() for formula cells with string results 45365 - Handle more excel number formatting rules in FormatTrackingHSSFListener / XLS2CSVmra 45373 - Improve the performance of HSSFSheet.shiftRows diff --git a/src/java/org/apache/poi/hssf/model/LinkTable.java b/src/java/org/apache/poi/hssf/model/LinkTable.java index a19971b7d5..1d8781d971 100755 --- a/src/java/org/apache/poi/hssf/model/LinkTable.java +++ b/src/java/org/apache/poi/hssf/model/LinkTable.java @@ -63,6 +63,8 @@ import org.apache.poi.hssf.record.SupBookRecord; * @author Josh Micich */ final class LinkTable { + + // TODO make this class into a record aggregate private static final class CRNBlock { @@ -233,13 +235,39 @@ final class LinkTable { if (idx == -1) idx = findFirstRecordLocBySid(CountryRecord.sid); int countNames = _definedNames.size(); _workbookRecordList.add(idx+countNames, name); - } public void removeName(int namenum) { _definedNames.remove(namenum); } + /** + * 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 boolean isDuplicatedNames(NameRecord firstName, NameRecord lastName) + { + return lastName.getNameText().equalsIgnoreCase(firstName.getNameText()) + && isSameSheetNames(firstName, lastName); + } + private boolean isSameSheetNames(NameRecord firstName, NameRecord lastName) + { + return lastName.getEqualsToIndexToSheet() == firstName.getEqualsToIndexToSheet(); + } + + public short getIndexToSheet(short num) { return _externSheetRecord.getREFRecordAt(num).getIndexToFirstSupBook(); } diff --git a/src/java/org/apache/poi/hssf/model/Workbook.java b/src/java/org/apache/poi/hssf/model/Workbook.java index fa22cfb688..329e217a81 100644 --- a/src/java/org/apache/poi/hssf/model/Workbook.java +++ b/src/java/org/apache/poi/hssf/model/Workbook.java @@ -105,6 +105,8 @@ public class Workbook implements Model private static POILogger log = POILogFactory.getLogger(Workbook.class); + protected static final String EXCEL_REPEATING_NAME_PREFIX_ = "Excel_Name_Record_Titles_"; + /** * Creates new Workbook with no intitialization --useless right now * @see #createWorkbook(List) @@ -1918,13 +1920,20 @@ public class Workbook implements Model */ public NameRecord addName(NameRecord name) { - - getOrCreateLinkTable().addName(name); + + LinkTable linkTable = getOrCreateLinkTable(); + if(linkTable.nameAlreadyExists(name)) { + throw new IllegalArgumentException( + "You are trying to assign a duplicated name record: " + + name.getNameText()); + } + linkTable.addName(name); return name; } - - /**Generates a NameRecord to represent a built-in region + + /** + * Generates a NameRecord to represent a built-in region * @return a new NameRecord unless the index is invalid */ public NameRecord createBuiltInName(byte builtInName, int index) @@ -1933,9 +1942,21 @@ public class Workbook implements Model throw new IllegalArgumentException("Index is not valid ["+index+"]"); NameRecord name = new NameRecord(builtInName, (short)(index)); - - addName(name); + String prefix = EXCEL_REPEATING_NAME_PREFIX_ + index + "_"; + int cont = 0; + while(linkTable.nameAlreadyExists(name)) { + cont++; + String altNameName = prefix + cont; + + // It would be better to set a different builtInName here. + // It does not seem possible, so we create it as a + // non built-in name from this point on + name = new NameRecord(); + name.setNameText(altNameName); + name.setNameTextLength((byte)altNameName.length()); + } + addName(name); return name; } diff --git a/src/testcases/org/apache/poi/hssf/usermodel/TestNamedRange.java b/src/testcases/org/apache/poi/hssf/usermodel/TestNamedRange.java index 591a7ba24f..0a508805db 100644 --- a/src/testcases/org/apache/poi/hssf/usermodel/TestNamedRange.java +++ b/src/testcases/org/apache/poi/hssf/usermodel/TestNamedRange.java @@ -17,11 +17,17 @@ package org.apache.poi.hssf.usermodel; +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.File; +import java.io.FileOutputStream; + import junit.framework.TestCase; import org.apache.poi.hssf.HSSFTestDataSamples; import org.apache.poi.hssf.util.AreaReference; import org.apache.poi.hssf.util.CellReference; +import org.apache.poi.poifs.filesystem.POIFSFileSystem; /** * @@ -485,4 +491,57 @@ public final class TestNamedRange extends TestCase { // expected during successful test } } + + public void testRepeatingRowsAndColumsNames() throws Exception { + HSSFWorkbook wb = new HSSFWorkbook(); + HSSFSheet sheet = wb.createSheet(); + + for (int rowItem = 0; rowItem < 10; rowItem++) { + HSSFRow r = sheet.createRow(rowItem); + for (int column = 0; column < 2; column++) { + HSSFCell cellItem = r.createCell((short) column); + cellItem.setCellType(HSSFCell.CELL_TYPE_STRING); + cellItem.setCellValue(new HSSFRichTextString("Some value here")); + if (rowItem == 2) { + wb.setRepeatingRowsAndColumns(0, 0, 0, 0, 3 - 1); + sheet.createFreezePane(0, 3); + } + } + } + + assertEquals(2, wb.getNumberOfNames()); + HSSFName nr1 = wb.getNameAt(0); + HSSFName nr2 = wb.getNameAt(1); + + assertEquals("Print_Titles", nr1.getNameName()); + assertEquals("Sheet0!$A$1:$A$0,Sheet0!$A$1:$IV$3", nr1.getReference()); + + assertEquals("Excel_Name_Record_Titles_1_1", nr2.getNameName()); + assertEquals("Sheet0!$A$1:$A$0,Sheet0!$A$1:$IV$3", nr2.getReference()); + + // Save and re-open + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + wb.write(baos); + ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray()); + HSSFWorkbook nwb = new HSSFWorkbook(new POIFSFileSystem(bais)); + + assertEquals(2, nwb.getNumberOfNames()); + nr1 = nwb.getNameAt(0); + nr2 = nwb.getNameAt(1); + + // TODO - + // should these references really have been corrected? + // and if so, why not also above? + assertEquals("Print_Titles", nr1.getNameName()); + assertEquals("Sheet0!A:A,Sheet0!$A$1:$IV$3", nr1.getReference()); + + assertEquals("Excel_Name_Record_Titles_1_1", nr2.getNameName()); + assertEquals("Sheet0!A:A,Sheet0!$A$1:$IV$3", nr2.getReference()); + + // In case you fancy checking in excel, to ensure it + // won't complain about the file now + FileOutputStream fout = new FileOutputStream(File.createTempFile("POI-45126-", ".xls")); + wb.write(fout); + fout.close(); + } }