From 03c86080660c39d386f4409907b5ed36c76dbcac Mon Sep 17 00:00:00 2001 From: Nick Burch Date: Thu, 10 Jul 2008 22:27:38 +0000 Subject: [PATCH] Merged revisions 638786-638802,638805-638811,638813-638814,638816-639230,639233-639241,639243-639253,639255-639486,639488-639601,639603-639835,639837-639917,639919-640056,640058-640710,640712-641156,641158-641184,641186-641795,641797-641798,641800-641933,641935-641963,641965-641966,641968-641995,641997-642230,642232-642562,642564-642565,642568-642570,642572-642573,642576-642736,642739-642877,642879,642881-642890,642892-642903,642905-642945,642947-643624,643626-643653,643655-643669,643671,643673-643830,643832-643833,643835-644342,644344-644472,644474-644508,644510-645347,645349-645351,645353-645559,645561-645565,645568-645951,645953-646193,646195-646311,646313-646404,646406-646665,646667-646853,646855-646869,646871-647151,647153-647185,647187-647277,647279-647566,647568-647573,647575,647578-647711,647714-647737,647739-647823,647825-648155,648157-648202,648204-648273,648275,648277-648302,648304-648333,648335-648588,648590-648622,648625-648673,648675-649141,649144,649146-649556,649558-649795,649799,649801-649910,649912-649913,649915-650128,650131-650132,650134-650137,650140-650914,650916-651991,651993-652284,652286-652287,652289,652291,652293-652297,652299-652328,652330-652425,652427-652445,652447-652560,652562-652933,652935,652937-652993,652995-653116,653118-653124,653126-653483,653487-653519,653522-653550,653552-653607,653609-653667,653669-653674,653676-653814,653817-653830,653832-653891,653893-653944,653946-654055,654057-654355,654357-654365,654367-654648,654651-655215,655217-655277,655279-655281,655283-655911,655913-656212,656214,656216-656251,656253-656698,656700-656756,656758-656892,656894-657135,657137-657165,657168-657179,657181-657354,657356-657357,657359-657701,657703-657874,657876-658032,658034-658284,658286,658288-658301,658303-658307,658309-658321,658323-658335,658337-658348,658351,658353-658832,658834-658983,658985,658987-659066,659068-659402,659404-659428,659430-659451,659453-659454,659456-659461,659463-659477,659479-659524,659526-659571,659574,659576-660255,660257-660262,660264-660279,660281-660343,660345-660473,660475-660827,660829-660833,660835-660888,660890-663321,663323-663435,663437-663764,663766-663854,663856-664219,664221-664489,664494-664514,664516-668013,668015-668142,668144-668152,668154,668156-668256,668258,668260-669139,669141-669455,669457-669657,669659-669808,669810-670189,670191-671321,671323-672229,672231-672549,672551-672552,672554-672561,672563-672566,672568,672571-673049,673051-673852,673854-673862,673864-673986,673988-673996,673998-674347,674349-674890,674892-674910,674912-674936,674938-674952,674954-675078,675080-675085,675087-675217,675219-675660,675662-675670,675672-675716,675718-675776 via svnmerge from https://svn.apache.org:443/repos/asf/poi/trunk ........ r675727 | nick | 2008-07-10 21:54:42 +0100 (Thu, 10 Jul 2008) | 1 line Fix cell.getRichStringCellValue() for formula cells with string results ........ r675734 | nick | 2008-07-10 22:03:52 +0100 (Thu, 10 Jul 2008) | 1 line Add test for bug #43623, currently disabled as it makes FormulaParser unhappy ........ r675776 | nick | 2008-07-10 22:49:37 +0100 (Thu, 10 Jul 2008) | 1 line Fix bug #45126 - Avoid generating multiple NamedRanges with the same name, which Excel dislikes ........ git-svn-id: https://svn.apache.org/repos/asf/poi/branches/ooxml@675787 13f79535-47bb-0310-9956-ffa450edef68 --- src/documentation/content/xdocs/changes.xml | 2 + src/documentation/content/xdocs/status.xml | 2 + .../org/apache/poi/hssf/model/LinkTable.java | 30 ++++++- .../org/apache/poi/hssf/model/Workbook.java | 33 ++++++-- .../apache/poi/hssf/usermodel/HSSFCell.java | 23 +++++- .../org/apache/poi/hssf/data/43623.xls | Bin 0 -> 13824 bytes .../apache/poi/hssf/usermodel/TestBugs.java | 75 +++++++++++++++--- .../poi/hssf/usermodel/TestNamedRange.java | 59 ++++++++++++++ 8 files changed, 204 insertions(+), 20 deletions(-) create mode 100644 src/testcases/org/apache/poi/hssf/data/43623.xls diff --git a/src/documentation/content/xdocs/changes.xml b/src/documentation/content/xdocs/changes.xml index f0c5d67ac..d0c00a646 100644 --- a/src/documentation/content/xdocs/changes.xml +++ b/src/documentation/content/xdocs/changes.xml @@ -50,6 +50,8 @@ Created a common interface for handling Excel files, irrespective of if they are .xls or .xlsx + 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 45367 - Fixed bug when last row removed from sheet is row zero diff --git a/src/documentation/content/xdocs/status.xml b/src/documentation/content/xdocs/status.xml index 693fc42e2..78937b325 100644 --- a/src/documentation/content/xdocs/status.xml +++ b/src/documentation/content/xdocs/status.xml @@ -47,6 +47,8 @@ Created a common interface for handling Excel files, irrespective of if they are .xls or .xlsx + 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 45367 - Fixed bug when last row removed from sheet is row zero diff --git a/src/java/org/apache/poi/hssf/model/LinkTable.java b/src/java/org/apache/poi/hssf/model/LinkTable.java index a19971b7d..1d8781d97 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 fa22cfb68..329e217a8 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/java/org/apache/poi/hssf/usermodel/HSSFCell.java b/src/java/org/apache/poi/hssf/usermodel/HSSFCell.java index 2c8234894..a5279993e 100644 --- a/src/java/org/apache/poi/hssf/usermodel/HSSFCell.java +++ b/src/java/org/apache/poi/hssf/usermodel/HSSFCell.java @@ -610,13 +610,28 @@ public class HSSFCell implements Cell // Set the 'pre-evaluated result' for the formula // note - formulas do not preserve text formatting. FormulaRecordAggregate fr = (FormulaRecordAggregate) record; - // must make new sr because fr.getStringRecord() may be null - StringRecord sr = new StringRecord(); - sr.setString(hvalue.getString()); // looses format - fr.setStringRecord(sr); + + // Save the string into a String Record, creating + // one if required + StringRecord sr = fr.getStringRecord(); + if(sr == null) { + // Wasn't a string before, need a new one + sr = new StringRecord(); + fr.setStringRecord(sr); + } + + // Save, loosing the formatting + sr.setString(hvalue.getString()); + // Update our local cache to the un-formatted version + stringValue = new HSSFRichTextString(sr.getString()); + + // All done return; } + // If we get here, we're not dealing with a formula, + // so handle things as a normal rich text cell + if (cellType != CELL_TYPE_STRING) { setCellType(CELL_TYPE_STRING, false, row, col, styleIndex); } diff --git a/src/testcases/org/apache/poi/hssf/data/43623.xls b/src/testcases/org/apache/poi/hssf/data/43623.xls new file mode 100644 index 0000000000000000000000000000000000000000..401cb2a88747c288c52eea61b6c5c95b3d3b9d8d GIT binary patch literal 13824 zcmeHOYiv|S6#nkr-F9nBpMX5o?VgfR=IWu$5 z%sF%Bn=^Co%)R^7sj~ikhsK;kPMD1lE~g5R7vMY0kM^%i!SYl}mwq~md9rM{i4Z7= zav<{}I6dw}{+CH+L%=z>I2b<482FyF5*ttsEbMIUXjvD3xTSSVS7+NZovmBr|6Q1C zY-n+0Lz0d+i#Z2-$StN1id$~t3KM^5>K!rhES6kA33fJZnmmK`K)DreqpA0riK|Rp z%-F#vM&>)inToq{jP+C7cFEO&$I6^0^k5_U(1|C}#(W&pFrD!N!|7njjV~1ok3s|$ zK-K=L>bmOcDKl5r``K8yl5?Ch*JsRpd~w^_Rly1|>4>* zOttB#!4#lbjn~ADCC&AoEt$)7X;pm{%bM#Oo9koYI!wd_31+IT4CKYnsy_>L;Lryf zq5(N=d7Mmh4GozFr=b>;0}cAp>Gpk5(`-hrAH$8?{GN)N)QggF@#Rp4|C?WQeZD;W zTJ;CxOY61j|DX8|=V2!Jc-DG2{Nb1Q{E36`>jvT148kwCioe?pqcjmpDJ@InnY26+ zHfcp7-=s*uq{9=D)M~TlZ0AaLDk3ZMu%x4{t#9g1gy|=BIO;@6oKK%QxX7vHhZI+- zC|aWV#*DX|mu4;Jg|6q8s#ieT!F&1uD-SaZU=icBTrRa3mN5oO*~rEB zemT8x&7y{8!>=*?S`)u$IEjE+ce2|+rSk$yj)v8iOnS-Ge%ZwPP-SX3Y{OwEGoio1 z%PU>Vx=}m_S>$4GVF`f=o9i%B{~B(w5m8UThZG>{@)l?c{xx_SuVB6BU5yrqyF#8;Pa@-885WM0CoV-Xj~B@~%bYxn zWzNm2;lNErC`I;ocMOZ8aMeG!my0l8mrl}2&Jm1bRm~SpG&Qm&Z*vqD`$)Kg#m1we z1z5mmx@4>#Ax}z1jjEsb=%3@yH>ir^Nja1%H&Rp)jq-Mgly4{PqR{b~+uGmS`y
<)Lil8q2iu{?$~@aSSRCQC$g6 zkH2Tzvu9m{LY8tWWATYAmWQ*I%PD-z+bK+?WU~MmK+bi1UllrVOT0L_@s7eV{3b*G;PaQW^&WI#jj^N4XAe2$zd)|EFFS@Tr~@j72$t~w z9qajPF@1lCD6|`!#L@pgy2%+l+{N}ahcthN+P==Y%mEpb2tV=dMys)*&5Xc5vuDP? L=)dWDy8nLx-hqa< literal 0 HcmV?d00001 diff --git a/src/testcases/org/apache/poi/hssf/usermodel/TestBugs.java b/src/testcases/org/apache/poi/hssf/usermodel/TestBugs.java index 523d42ec9..bfd359318 100644 --- a/src/testcases/org/apache/poi/hssf/usermodel/TestBugs.java +++ b/src/testcases/org/apache/poi/hssf/usermodel/TestBugs.java @@ -33,9 +33,7 @@ import org.apache.poi.hssf.HSSFTestDataSamples; import org.apache.poi.hssf.model.Workbook; import org.apache.poi.hssf.record.CellValueRecordInterface; import org.apache.poi.hssf.record.EmbeddedObjectRefSubRecord; -import org.apache.poi.hssf.record.FormulaRecord; import org.apache.poi.hssf.record.NameRecord; -import org.apache.poi.hssf.record.Record; import org.apache.poi.hssf.record.aggregates.FormulaRecordAggregate; import org.apache.poi.hssf.record.formula.DeletedArea3DPtg; import org.apache.poi.util.TempFile; @@ -1152,10 +1150,12 @@ public final class TestBugs extends TestCase { s.createRow(0); HSSFCell c1 = s.getRow(0).createCell((short)0); HSSFCell c2 = s.getRow(0).createCell((short)1); + HSSFCell c3 = s.getRow(0).createCell((short)2); // As number and string c1.setCellFormula("70164"); c2.setCellFormula("\"70164\""); + c3.setCellFormula("\"90210\""); // Check the formulas assertEquals("70164.0", c1.getCellFormula()); @@ -1166,20 +1166,31 @@ public final class TestBugs extends TestCase { assertEquals("", c1.getRichStringCellValue().getString()); assertEquals(0.0, c2.getNumericCellValue(), 0.00001); assertEquals("", c2.getRichStringCellValue().getString()); + assertEquals(0.0, c3.getNumericCellValue(), 0.00001); + assertEquals("", c3.getRichStringCellValue().getString()); - // Now evaluate + // Try changing the cached value on one of the string + // formula cells, so we can see it updates properly + c3.setCellValue(new HSSFRichTextString("test")); + assertEquals(0.0, c3.getNumericCellValue(), 0.00001); + assertEquals("test", c3.getRichStringCellValue().getString()); + + + // Now evaluate, they should all be changed HSSFFormulaEvaluator eval = new HSSFFormulaEvaluator(s, wb); eval.setCurrentRow(s.getRow(0)); eval.evaluateFormulaCell(c1); eval.evaluateFormulaCell(c2); + eval.evaluateFormulaCell(c3); - // Check + // Check that the cells now contain + // the correct values assertEquals(70164.0, c1.getNumericCellValue(), 0.00001); assertEquals("", c1.getRichStringCellValue().getString()); assertEquals(0.0, c2.getNumericCellValue(), 0.00001); - - // TODO - why isn't this working? -// assertEquals("70164", c2.getRichStringCellValue().getString()); + assertEquals("70164", c2.getRichStringCellValue().getString()); + assertEquals(0.0, c3.getNumericCellValue(), 0.00001); + assertEquals("90210", c3.getRichStringCellValue().getString()); // Write and read @@ -1187,12 +1198,15 @@ public final class TestBugs extends TestCase { HSSFSheet ns = nwb.getSheetAt(0); HSSFCell nc1 = ns.getRow(0).getCell((short)0); HSSFCell nc2 = ns.getRow(0).getCell((short)1); + HSSFCell nc3 = ns.getRow(0).getCell((short)2); // Re-check assertEquals(70164.0, nc1.getNumericCellValue(), 0.00001); assertEquals("", nc1.getRichStringCellValue().getString()); assertEquals(0.0, nc2.getNumericCellValue(), 0.00001); assertEquals("70164", nc2.getRichStringCellValue().getString()); + assertEquals(0.0, nc3.getNumericCellValue(), 0.00001); + assertEquals("90210", nc3.getRichStringCellValue().getString()); // Now check record level stuff too ns.getSheet().setLoc(0); @@ -1205,15 +1219,58 @@ public final class TestBugs extends TestCase { if(fn == 0) { assertEquals(70164.0, fr.getFormulaRecord().getValue(), 0.0001); assertNull(fr.getStringRecord()); - } else { + } else if (fn == 1) { assertEquals(0.0, fr.getFormulaRecord().getValue(), 0.0001); assertNotNull(fr.getStringRecord()); assertEquals("70164", fr.getStringRecord().getString()); + } else { + assertEquals(0.0, fr.getFormulaRecord().getValue(), 0.0001); + assertNotNull(fr.getStringRecord()); + assertEquals("90210", fr.getStringRecord().getString()); } fn++; } } - assertEquals(2, fn); + assertEquals(3, fn); + } + + /** + * Problem with "Vector Rows", eg a whole + * column which is set to the result of + * {=sin(B1:B9)}(9,1), so that each cell is + * shown to have the contents + * {=sin(B1:B9){9,1)[rownum][0] + * In this sample file, the vector column + * is C, and the data column is B. + * + * For now, blows up with an exception from ExtPtg + * Expected ExpPtg to be converted from Shared to Non-Shared... + */ + public void DISABLEDtest43623() throws Exception { + HSSFWorkbook wb = openSample("43623.xls"); + assertEquals(1, wb.getNumberOfSheets()); + + HSSFSheet s1 = wb.getSheetAt(0); + + HSSFCell c1 = s1.getRow(0).getCell(2); + HSSFCell c2 = s1.getRow(1).getCell(2); + HSSFCell c3 = s1.getRow(2).getCell(2); + + // These formula contents are a guess... + assertEquals("{=sin(B1:B9){9,1)[0][0]", c1.getCellFormula()); + assertEquals("{=sin(B1:B9){9,1)[1][0]", c2.getCellFormula()); + assertEquals("{=sin(B1:B9){9,1)[2][0]", c3.getCellFormula()); + + // Save and re-open, ensure it still works + HSSFWorkbook nwb = writeOutAndReadBack(wb); + HSSFSheet ns1 = nwb.getSheetAt(0); + HSSFCell nc1 = ns1.getRow(0).getCell(2); + HSSFCell nc2 = ns1.getRow(1).getCell(2); + HSSFCell nc3 = ns1.getRow(2).getCell(2); + + assertEquals("{=sin(B1:B9){9,1)[0][0]", nc1.getCellFormula()); + assertEquals("{=sin(B1:B9){9,1)[1][0]", nc2.getCellFormula()); + assertEquals("{=sin(B1:B9){9,1)[2][0]", nc3.getCellFormula()); } } diff --git a/src/testcases/org/apache/poi/hssf/usermodel/TestNamedRange.java b/src/testcases/org/apache/poi/hssf/usermodel/TestNamedRange.java index 591a7ba24..0a508805d 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(); + } }