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
This commit is contained in:
Nick Burch 2008-07-10 21:49:37 +00:00
parent ae7c94b6cb
commit 21d6638529
5 changed files with 117 additions and 7 deletions

View File

@ -37,6 +37,7 @@
<!-- Don't forget to update status.xml too! -->
<release version="3.1.1-alpha1" date="2008-??-??">
<action dev="POI-DEVELOPERS" type="fix">45126 - Avoid generating multiple NamedRanges with the same name, which Excel dislikes</action>
<action dev="POI-DEVELOPERS" type="fix">Fix cell.getRichStringCellValue() for formula cells with string results</action>
<action dev="POI-DEVELOPERS" type="fix">45365 - Handle more excel number formatting rules in FormatTrackingHSSFListener / XLS2CSVmra</action>
<action dev="POI-DEVELOPERS" type="fix">45373 - Improve the performance of HSSFSheet.shiftRows</action>

View File

@ -34,6 +34,7 @@
<!-- Don't forget to update changes.xml too! -->
<changes>
<release version="3.1.1-alpha1" date="2008-??-??">
<action dev="POI-DEVELOPERS" type="fix">45126 - Avoid generating multiple NamedRanges with the same name, which Excel dislikes</action>
<action dev="POI-DEVELOPERS" type="fix">Fix cell.getRichStringCellValue() for formula cells with string results</action>
<action dev="POI-DEVELOPERS" type="fix">45365 - Handle more excel number formatting rules in FormatTrackingHSSFListener / XLS2CSVmra</action>
<action dev="POI-DEVELOPERS" type="fix">45373 - Improve the performance of HSSFSheet.shiftRows</action>

View File

@ -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();
}

View File

@ -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;
}

View File

@ -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();
}
}