<!-- 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>
<!-- 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>
* @author Josh Micich
*/
final class LinkTable {
+
+
// TODO make this class into a record aggregate
private static final class CRNBlock {
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();
}
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)
*/
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)
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;
}
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;
/**
*
// 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();
+ }
}