From 1deea0cfa111f2f72d7d426d095ec04c71a6db72 Mon Sep 17 00:00:00 2001 From: Nick Burch Date: Fri, 11 Jun 2010 19:59:22 +0000 Subject: [PATCH 01/10] Bump the ooxml schema version up to 1.1, as 1.0 was compiled for Java 1.4 while we now compile them for Java 1.5 git-svn-id: https://svn.apache.org/repos/asf/poi/trunk@953851 13f79535-47bb-0310-9956-ffa450edef68 --- build.xml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/build.xml b/build.xml index 802ae68b9c..f0273024c6 100644 --- a/build.xml +++ b/build.xml @@ -132,9 +132,9 @@ under the License. - + + value="${repository.m2}/maven2/org/apache/poi/ooxml-schemas/1.1/ooxml-schemas-1.1.jar"/> @@ -143,8 +143,8 @@ under the License. - - + + From 9c6fdb6f53378c1d411ab302528ba8f56f041414 Mon Sep 17 00:00:00 2001 From: Yegor Kozlov Date: Sun, 13 Jun 2010 06:26:14 +0000 Subject: [PATCH 02/10] force ASCII encoding when compiling sources, fixed unmappable characters for encoding ASCII git-svn-id: https://svn.apache.org/repos/asf/poi/trunk@954172 13f79535-47bb-0310-9956-ffa450edef68 --- build.xml | 16 +++++++++++++++- .../poi/hssf/extractor/TestExcelExtractor.java | 2 +- .../hssf/usermodel/TestHSSFDataFormatter.java | 6 +++--- 3 files changed, 19 insertions(+), 5 deletions(-) diff --git a/build.xml b/build.xml index f0273024c6..6de19159dd 100644 --- a/build.xml +++ b/build.xml @@ -66,6 +66,9 @@ under the License. + + + + srcdir="${main.output.dir}" + encoding="${java.source.encoding}"> + diff --git a/src/testcases/org/apache/poi/hssf/extractor/TestExcelExtractor.java b/src/testcases/org/apache/poi/hssf/extractor/TestExcelExtractor.java index ed2da48bd4..00b3afad8f 100644 --- a/src/testcases/org/apache/poi/hssf/extractor/TestExcelExtractor.java +++ b/src/testcases/org/apache/poi/hssf/extractor/TestExcelExtractor.java @@ -251,7 +251,7 @@ public final class TestExcelExtractor extends TestCase { ); assertTrue( text.indexOf( - "£nn.nn\t£10.52\n" + "\u00a3nn.nn\t\u00a310.52\n" ) > -1 ); } diff --git a/src/testcases/org/apache/poi/hssf/usermodel/TestHSSFDataFormatter.java b/src/testcases/org/apache/poi/hssf/usermodel/TestHSSFDataFormatter.java index e5f1f8129c..4759a6c04b 100644 --- a/src/testcases/org/apache/poi/hssf/usermodel/TestHSSFDataFormatter.java +++ b/src/testcases/org/apache/poi/hssf/usermodel/TestHSSFDataFormatter.java @@ -405,9 +405,9 @@ public final class TestHSSFDataFormatter extends TestCase { assertEquals("10.5", f.formatCellValue(sheet.getRow(11).getCell(1))); // text isn't quite the format rule... - assertEquals("£nn.nn", sheet.getRow(12).getCell(0).getStringCellValue()); - assertEquals("\"£\"#,##0.00", sheet.getRow(12).getCell(1).getCellStyle().getDataFormatString()); - assertEquals("£10.52", f.formatCellValue(sheet.getRow(12).getCell(1))); + assertEquals("\u00a3nn.nn", sheet.getRow(12).getCell(0).getStringCellValue()); + assertEquals("\"\u00a3\"#,##0.00", sheet.getRow(12).getCell(1).getCellStyle().getDataFormatString()); + assertEquals("\u00a310.52", f.formatCellValue(sheet.getRow(12).getCell(1))); } private static void log(String msg) { From 36c5190f57c2dd388d22f9a2b1b5ffeeecde30c9 Mon Sep 17 00:00:00 2001 From: Nick Burch Date: Mon, 14 Jun 2010 11:45:09 +0000 Subject: [PATCH 03/10] When formatting numbers with DataFormatter, handle brackets following colours git-svn-id: https://svn.apache.org/repos/asf/poi/trunk@954416 13f79535-47bb-0310-9956-ffa450edef68 --- src/documentation/content/xdocs/status.xml | 1 + .../poi/ss/usermodel/DataFormatter.java | 4 +- .../poi/ss/usermodel/TestDataFormatter.java | 38 +++++++++++++++++++ 3 files changed, 41 insertions(+), 2 deletions(-) diff --git a/src/documentation/content/xdocs/status.xml b/src/documentation/content/xdocs/status.xml index 16ca0807fc..71f0839156 100644 --- a/src/documentation/content/xdocs/status.xml +++ b/src/documentation/content/xdocs/status.xml @@ -34,6 +34,7 @@ + When formatting numbers with DataFormatter, handle brackets following colours 48574 - further XWPF support for tables, paragraphs, including enhanced support for adding new ones diff --git a/src/java/org/apache/poi/ss/usermodel/DataFormatter.java b/src/java/org/apache/poi/ss/usermodel/DataFormatter.java index 36ba5a1b6b..de586db66a 100644 --- a/src/java/org/apache/poi/ss/usermodel/DataFormatter.java +++ b/src/java/org/apache/poi/ss/usermodel/DataFormatter.java @@ -233,14 +233,14 @@ public class DataFormatter { int at = formatStr.indexOf(colour); if(at == -1) break; String nFormatStr = formatStr.substring(0,at) + - formatStr.substring(at+colour.length()+1); + formatStr.substring(at+colour.length()); if(nFormatStr.equals(formatStr)) break; // Try again in case there's multiple formatStr = nFormatStr; colourM = colorPattern.matcher(formatStr); } - + // try to extract special characters like currency Matcher m = specialPatternGroup.matcher(formatStr); while(m.find()) { diff --git a/src/testcases/org/apache/poi/ss/usermodel/TestDataFormatter.java b/src/testcases/org/apache/poi/ss/usermodel/TestDataFormatter.java index 35be8c4ff1..06abd6c502 100644 --- a/src/testcases/org/apache/poi/ss/usermodel/TestDataFormatter.java +++ b/src/testcases/org/apache/poi/ss/usermodel/TestDataFormatter.java @@ -77,6 +77,44 @@ public class TestDataFormatter extends TestCase { assertEquals("[ab]12.34[x]", dfUS.formatRawCellContents(12.343, -1, "[ab]##.##[x]")); } + public void testColoursAndBrackets() { + DataFormatter dfUS = new DataFormatter(Locale.US); + + // Without currency symbols + String[] formats = new String[] { + "#,##0.00;[Blue](#,##0.00)", + }; + for(String format : formats) { + assertEquals( + "Wrong format for: " + format, + "12.34", + dfUS.formatRawCellContents(12.343, -1, format) + ); + assertEquals( + "Wrong format for: " + format, + "(12.34)", + dfUS.formatRawCellContents(-12.343, -1, format) + ); + } + + // With + formats = new String[] { + "$#,##0.00;[Red]($#,##0.00)" + }; + for(String format : formats) { + assertEquals( + "Wrong format for: " + format, + "$12.34", + dfUS.formatRawCellContents(12.343, -1, format) + ); + assertEquals( + "Wrong format for: " + format, + "($12.34)", + dfUS.formatRawCellContents(-12.343, -1, format) + ); + } + } + /** * Test how we handle negative and zeros. * Note - some tests are disabled as DecimalFormat From 64cfb8b39903ff0d5f5076aa02c31cb2825258b4 Mon Sep 17 00:00:00 2001 From: Nick Burch Date: Mon, 14 Jun 2010 13:47:22 +0000 Subject: [PATCH 04/10] Better handling of Outlook messages in HSMF when there's no recipient email address git-svn-id: https://svn.apache.org/repos/asf/poi/trunk@954476 13f79535-47bb-0310-9956-ffa450edef68 --- src/documentation/content/xdocs/status.xml | 1 + .../src/org/apache/poi/hsmf/MAPIMessage.java | 7 +++- .../org/apache/poi/hsmf/TestBasics.java | 37 ++++++++++++++++++ test-data/hsmf/no_recipient_address.msg | Bin 0 -> 83968 bytes 4 files changed, 44 insertions(+), 1 deletion(-) create mode 100644 test-data/hsmf/no_recipient_address.msg diff --git a/src/documentation/content/xdocs/status.xml b/src/documentation/content/xdocs/status.xml index 71f0839156..0529403be2 100644 --- a/src/documentation/content/xdocs/status.xml +++ b/src/documentation/content/xdocs/status.xml @@ -34,6 +34,7 @@ + Better handling of Outlook messages in HSMF when there's no recipient email address When formatting numbers with DataFormatter, handle brackets following colours diff --git a/src/scratchpad/src/org/apache/poi/hsmf/MAPIMessage.java b/src/scratchpad/src/org/apache/poi/hsmf/MAPIMessage.java index 8d84b1627a..e04d299b13 100644 --- a/src/scratchpad/src/org/apache/poi/hsmf/MAPIMessage.java +++ b/src/scratchpad/src/org/apache/poi/hsmf/MAPIMessage.java @@ -239,7 +239,11 @@ public class MAPIMessage extends POIDocument { if(email != null) { emails[i] = email; } else { - throw new ChunkNotFoundException("No email address holding chunks found for the " + (i+1) + "th recipient"); + if(returnNullOnMissingChunk) { + emails[i] = null; + } else { + throw new ChunkNotFoundException("No email address holding chunks found for the " + (i+1) + "th recipient"); + } } } @@ -393,6 +397,7 @@ public class MAPIMessage extends POIDocument { boolean first = true; for(String s : l) { + if(s == null) continue; if(first) { first = false; } else { diff --git a/src/scratchpad/testcases/org/apache/poi/hsmf/TestBasics.java b/src/scratchpad/testcases/org/apache/poi/hsmf/TestBasics.java index 6e958c193f..18a316491f 100644 --- a/src/scratchpad/testcases/org/apache/poi/hsmf/TestBasics.java +++ b/src/scratchpad/testcases/org/apache/poi/hsmf/TestBasics.java @@ -33,6 +33,7 @@ public final class TestBasics extends TestCase { private MAPIMessage quick; private MAPIMessage outlook30; private MAPIMessage attachments; + private MAPIMessage noRecipientAddress; /** * Initialize this test, load up the blank.msg mapi message. @@ -44,6 +45,7 @@ public final class TestBasics extends TestCase { quick = new MAPIMessage(samples.openResourceAsStream("quick.msg")); outlook30 = new MAPIMessage(samples.openResourceAsStream("outlook_30_msg.msg")); attachments = new MAPIMessage(samples.openResourceAsStream("attachment_test_msg.msg")); + noRecipientAddress = new MAPIMessage(samples.openResourceAsStream("no_recipient_address.msg")); } /** @@ -140,4 +142,39 @@ public final class TestBasics extends TestCase { // Good } } + + /** + * More missing chunk testing, this time for + * missing recipient email address + */ + public void testMissingAddressChunk() throws Exception { + assertEquals(false, noRecipientAddress.isReturnNullOnMissingChunk()); + + try { + noRecipientAddress.getRecipientEmailAddress(); + fail(); + } catch(ChunkNotFoundException e) { + // Good + } + try { + noRecipientAddress.getRecipientEmailAddressList(); + fail(); + } catch(ChunkNotFoundException e) { + // Good + } + + noRecipientAddress.setReturnNullOnMissingChunk(true); + + noRecipientAddress.getRecipientEmailAddress(); + noRecipientAddress.getRecipientEmailAddressList(); + assertEquals("", noRecipientAddress.getRecipientEmailAddress()); + assertEquals(1, noRecipientAddress.getRecipientEmailAddressList().length); + assertEquals(null, noRecipientAddress.getRecipientEmailAddressList()[0]); + + // Check a few other bits too + assertEquals("Microsoft Outlook 2003 Team", noRecipientAddress.getDisplayFrom()); + assertEquals("New Outlook User", noRecipientAddress.getDisplayTo()); + + noRecipientAddress.setReturnNullOnMissingChunk(false); + } } diff --git a/test-data/hsmf/no_recipient_address.msg b/test-data/hsmf/no_recipient_address.msg new file mode 100644 index 0000000000000000000000000000000000000000..e88d503fe8d67d26eeb83ef4ae5c1b561b78b0ec GIT binary patch literal 83968 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 )HKjol*U5(2iD&1S}YGrk;EDR%V!Rf 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 literal 0 HcmV?d00001 From 60cefff59a06c5fc3781cb591c18bd09226e63d2 Mon Sep 17 00:00:00 2001 From: Nick Burch Date: Mon, 14 Jun 2010 15:05:19 +0000 Subject: [PATCH 05/10] Have the ooxml build correctly ensure that we have the ooxml schemas to hand git-svn-id: https://svn.apache.org/repos/asf/poi/trunk@954507 13f79535-47bb-0310-9956-ffa450edef68 --- build.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.xml b/build.xml index 6de19159dd..cf73e62752 100644 --- a/build.xml +++ b/build.xml @@ -518,7 +518,7 @@ under the License. - + Date: Mon, 14 Jun 2010 15:20:19 +0000 Subject: [PATCH 06/10] Notes on ooxml-schemas 1.1 and 1.0 git-svn-id: https://svn.apache.org/repos/asf/poi/trunk@954511 13f79535-47bb-0310-9956-ffa450edef68 --- src/documentation/content/xdocs/faq.xml | 12 +++++++++--- src/documentation/content/xdocs/overview.xml | 8 +++++--- src/documentation/content/xdocs/status.xml | 1 + 3 files changed, 15 insertions(+), 6 deletions(-) diff --git a/src/documentation/content/xdocs/faq.xml b/src/documentation/content/xdocs/faq.xml index 829caa5f27..8afe510b78 100644 --- a/src/documentation/content/xdocs/faq.xml +++ b/src/documentation/content/xdocs/faq.xml @@ -63,7 +63,7 @@ System.out.println("Core POI came from " + path); org.openxmlformats.schemas namespace.

There are two jar files available, as described in the components overview section. - The full jar of all of the schemas is ooxml-schemas-1.0.jar, + The full jar of all of the schemas is ooxml-schemas-1.1.jar, and it is currently around 15mb. The smaller poi-ooxml-schemas jar is only about 4mb. This latter jar file only contains the typically used parts though.

@@ -72,11 +72,11 @@ System.out.println("Core POI came from " + path); classes that are typically used, as identified by the unit tests. Every so often, you may try to use part of the file format which isn't included in the minimal poi-ooxml-schemas jar. In this case, - you should switch to the full ooxml-schemas-1.0.jar. Longer term, + you should switch to the full ooxml-schemas-1.1.jar. Longer term, you may also wish to submit a new unit test which uses the extra parts of the XSDs, so that a future poi-ooxml-schemas jar will include them.

-

There are a number of ways to get the full ooxml-schemas-1.0.jar. +

There are a number of ways to get the full ooxml-schemas-1.1.jar. If you are a maven user, see the the components overview section for the artifact details to have maven download it for you. @@ -88,6 +88,12 @@ System.out.println("Core POI came from " + path); look at this). Finally, you can download the jar by hand from the POI Maven Repository.

+

Note that for POI 3.5 and 3.6, the full ooxml schemas jar was + named ooxml-schemas-1.0.jar. For POI 3.7, the filename was bumped + to ooxml-schemas-1.1.jar when generics support was added. You can + use ooxml-schemas-1.1.jar with POI 3.5 and 3.6 if you wish, but + POI 3.7 won't wokr with ooxml-schemas-1.0.jar (it needs thew newer + one).

diff --git a/src/documentation/content/xdocs/overview.xml b/src/documentation/content/xdocs/overview.xml index bb8e0d2aee..35ae35f380 100644 --- a/src/documentation/content/xdocs/overview.xml +++ b/src/documentation/content/xdocs/overview.xml @@ -247,15 +247,17 @@ ooxml-schemas xmlbeans - ooxml-schemas-1.0.jar + ooxml-schemas-1.1.jar

(*) starting with 3.6-beta1-20091124.

- poi-ooxml requires poi-ooxml-schemas. This is a substantially smaller version of the ooxml-schemas-1.0.jar. - The larger ooxml-schemas jar is only required for development. + poi-ooxml requires poi-ooxml-schemas. This is a substantially smaller + version of the ooxml-schemas jar (ooxml-schemas-1.1.jar for POI 3.7 or later, ooxml-scheams-1.0.jar for POI 3.5 and 3.6). + The larger ooxml-schemas jar is normally + only required for development

Examples diff --git a/src/documentation/content/xdocs/status.xml b/src/documentation/content/xdocs/status.xml index 0529403be2..99c896ee87 100644 --- a/src/documentation/content/xdocs/status.xml +++ b/src/documentation/content/xdocs/status.xml @@ -118,6 +118,7 @@ 48339 - fixed ExternalNameRecord to properly distinguish DDE data from OLE data items 47920 - allow editing workbooks embedded into PowerPoint files 48343 - added implementation of SUBTOTAL function + Switch to compiling the OOXML Schemas for Java 1.5 48332 - fixed XSSFSheet autoSizeColumn() to tolerate empty RichTextString From 741f499c4ad6dd68e1ef5abe54ea4444e4cabc95 Mon Sep 17 00:00:00 2001 From: Nick Burch Date: Mon, 14 Jun 2010 15:43:47 +0000 Subject: [PATCH 07/10] Fix bug #49432 - Lazy caching of XSSFComment CTComment objects by reference, to make repeated comment searching faster git-svn-id: https://svn.apache.org/repos/asf/poi/trunk@954521 13f79535-47bb-0310-9956-ffa450edef68 --- src/documentation/content/xdocs/status.xml | 1 + .../apache/poi/xssf/model/CommentsTable.java | 48 +++++++++++++++---- .../poi/xssf/usermodel/XSSFComment.java | 10 +++- .../apache/poi/xssf/usermodel/XSSFSheet.java | 7 ++- 4 files changed, 55 insertions(+), 11 deletions(-) diff --git a/src/documentation/content/xdocs/status.xml b/src/documentation/content/xdocs/status.xml index 99c896ee87..4f07ad331a 100644 --- a/src/documentation/content/xdocs/status.xml +++ b/src/documentation/content/xdocs/status.xml @@ -34,6 +34,7 @@ + 49432 - Lazy caching of XSSFComment CTComment objects by reference, to make repeated comment searching faster Better handling of Outlook messages in HSMF when there's no recipient email address When formatting numbers with DataFormatter, handle brackets following colours diff --git a/src/ooxml/java/org/apache/poi/xssf/model/CommentsTable.java b/src/ooxml/java/org/apache/poi/xssf/model/CommentsTable.java index da47d90a2c..f443be4837 100644 --- a/src/ooxml/java/org/apache/poi/xssf/model/CommentsTable.java +++ b/src/ooxml/java/org/apache/poi/xssf/model/CommentsTable.java @@ -19,20 +19,27 @@ package org.apache.poi.xssf.model; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; +import java.util.HashMap; +import java.util.Map; -import org.apache.poi.ss.util.CellReference; -import org.apache.poi.xssf.usermodel.XSSFComment; import org.apache.poi.POIXMLDocumentPart; +import org.apache.poi.openxml4j.opc.PackagePart; +import org.apache.poi.openxml4j.opc.PackageRelationship; +import org.apache.poi.xssf.usermodel.XSSFComment; import org.apache.xmlbeans.XmlException; import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTComment; import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTCommentList; import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTComments; import org.openxmlformats.schemas.spreadsheetml.x2006.main.CommentsDocument; -import org.apache.poi.openxml4j.opc.PackagePart; -import org.apache.poi.openxml4j.opc.PackageRelationship; public class CommentsTable extends POIXMLDocumentPart { private CTComments comments; + /** + * XML Beans uses a list, which is very slow + * to search, so we wrap things with our own + * map for fast lookup. + */ + private Map commentRefs; public CommentsTable() { super(); @@ -67,6 +74,17 @@ public class CommentsTable extends POIXMLDocumentPart { writeTo(out); out.close(); } + + /** + * Called after the reference is updated, so that + * we can reflect that in our cache + */ + public void referenceUpdated(String oldReference, CTComment comment) { + if(commentRefs != null) { + commentRefs.remove(oldReference); + commentRefs.put(comment.getRef(), comment); + } + } public int getNumberOfComments() { return comments.getCommentList().sizeOfCommentArray(); @@ -95,18 +113,26 @@ public class CommentsTable extends POIXMLDocumentPart { } public CTComment getCTComment(String cellRef) { - for (CTComment comment : comments.getCommentList().getCommentArray()) { - if (cellRef.equals(comment.getRef())) { - return comment; - } + // Create the cache if needed + if(commentRefs == null) { + commentRefs = new HashMap(); + for (CTComment comment : comments.getCommentList().getCommentList()) { + commentRefs.put(comment.getRef(), comment); + } } - return null; + + // Return the comment, or null if not known + return commentRefs.get(cellRef); } public CTComment newComment() { CTComment ct = comments.getCommentList().addNewComment(); ct.setRef("A1"); ct.setAuthorId(0); + + if(commentRefs != null) { + commentRefs.put(ct.getRef(), ct); + } return ct; } @@ -116,6 +142,10 @@ public class CommentsTable extends POIXMLDocumentPart { CTComment comment = lst.getCommentArray(i); if (cellRef.equals(comment.getRef())) { lst.removeComment(i); + + if(commentRefs != null) { + commentRefs.remove(cellRef); + } return true; } } diff --git a/src/ooxml/java/org/apache/poi/xssf/usermodel/XSSFComment.java b/src/ooxml/java/org/apache/poi/xssf/usermodel/XSSFComment.java index a7e577d190..9d6c34cd47 100644 --- a/src/ooxml/java/org/apache/poi/xssf/usermodel/XSSFComment.java +++ b/src/ooxml/java/org/apache/poi/xssf/usermodel/XSSFComment.java @@ -110,8 +110,12 @@ public class XSSFComment implements Comment { * @param col the 0-based column of the cell that contains the comment */ public void setColumn(int col) { + String oldRef = _comment.getRef(); + CellReference ref = new CellReference(getRow(), col); - _comment.setRef(ref.formatAsString()); + _comment.setRef(ref.formatAsString()); + _comments.referenceUpdated(oldRef, _comment); + if(_vmlShape != null) _vmlShape.getClientDataArray(0).setColumnArray(0, new BigInteger(String.valueOf(col))); } @@ -121,9 +125,13 @@ public class XSSFComment implements Comment { * @param row the 0-based row of the cell that contains the comment */ public void setRow(int row) { + String oldRef = _comment.getRef(); + String newRef = (new CellReference(row, getColumn())).formatAsString(); _comment.setRef(newRef); + _comments.referenceUpdated(oldRef, _comment); + if(_vmlShape != null) _vmlShape.getClientDataArray(0).setRowArray(0, new BigInteger(String.valueOf(row))); } diff --git a/src/ooxml/java/org/apache/poi/xssf/usermodel/XSSFSheet.java b/src/ooxml/java/org/apache/poi/xssf/usermodel/XSSFSheet.java index 34db7c403e..6c13857f9c 100644 --- a/src/ooxml/java/org/apache/poi/xssf/usermodel/XSSFSheet.java +++ b/src/ooxml/java/org/apache/poi/xssf/usermodel/XSSFSheet.java @@ -175,9 +175,14 @@ public class XSSFSheet extends POIXMLDocumentPart implements Sheet { initRows(worksheet); columnHelper = new ColumnHelper(worksheet); + // Look for bits we're interested in for(POIXMLDocumentPart p : getRelations()){ - if(p instanceof CommentsTable) sheetComments = (CommentsTable)p; + if(p instanceof CommentsTable) { + sheetComments = (CommentsTable)p; + break; + } } + // Process external hyperlinks for the sheet, if there are any initHyperlinks(); } From de6f455d6d156868eb9f131c5330c83a1234b2c3 Mon Sep 17 00:00:00 2001 From: Nick Burch Date: Tue, 15 Jun 2010 11:40:00 +0000 Subject: [PATCH 08/10] Add main method git-svn-id: https://svn.apache.org/repos/asf/poi/trunk@954834 13f79535-47bb-0310-9956-ffa450edef68 --- .../poi/hpsf/extractor/HPSFPropertiesExtractor.java | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/src/java/org/apache/poi/hpsf/extractor/HPSFPropertiesExtractor.java b/src/java/org/apache/poi/hpsf/extractor/HPSFPropertiesExtractor.java index 14bb16887d..1ba9b6441c 100644 --- a/src/java/org/apache/poi/hpsf/extractor/HPSFPropertiesExtractor.java +++ b/src/java/org/apache/poi/hpsf/extractor/HPSFPropertiesExtractor.java @@ -17,6 +17,8 @@ package org.apache.poi.hpsf.extractor; +import java.io.FileInputStream; +import java.io.IOException; import java.io.OutputStream; import java.util.Iterator; @@ -150,4 +152,13 @@ public class HPSFPropertiesExtractor extends POITextExtractor { throw new IllegalStateException("Unable to write, only for properties!"); } } + + public static void main(String[] args) throws IOException { + for(String file : args) { + HPSFPropertiesExtractor ext = new HPSFPropertiesExtractor( + new POIFSFileSystem(new FileInputStream(file)) + ); + System.out.println(ext.getText()); + } + } } From 2b5d3fcbfd55b8ddd276dd41516af07d8100542e Mon Sep 17 00:00:00 2001 From: Nick Burch Date: Tue, 15 Jun 2010 11:41:06 +0000 Subject: [PATCH 09/10] Temporary switch back to using only ooxml-schemas-1.0 (no lists). Revert this commit once 3.7 beta1 is out, so we can continue testing the new ooxml-schemas-1.1 (java 1.5) stuff git-svn-id: https://svn.apache.org/repos/asf/poi/trunk@954835 13f79535-47bb-0310-9956-ffa450edef68 --- build.xml | 10 +++++----- .../apache/poi/xssf/model/CommentsTable.java | 2 +- .../poi/xwpf/usermodel/XWPFParagraph.java | 20 +++++++++---------- 3 files changed, 16 insertions(+), 16 deletions(-) diff --git a/build.xml b/build.xml index cf73e62752..18984f8cab 100644 --- a/build.xml +++ b/build.xml @@ -135,9 +135,9 @@ under the License. - + + value="${repository.m2}/maven2/org/apache/poi/ooxml-schemas/1.0/ooxml-schemas-1.0.jar"/> @@ -146,8 +146,8 @@ under the License. - - + + @@ -397,7 +397,7 @@ under the License. srcgendir="${ooxml.xsds.src.dir}" optimize="yes" destfile="${ooxml.xsds.jar}" - javasource="1.5" + javasource="1.4" failonerror="true" fork="true" memoryMaximumSize="512m" diff --git a/src/ooxml/java/org/apache/poi/xssf/model/CommentsTable.java b/src/ooxml/java/org/apache/poi/xssf/model/CommentsTable.java index f443be4837..3e35db871e 100644 --- a/src/ooxml/java/org/apache/poi/xssf/model/CommentsTable.java +++ b/src/ooxml/java/org/apache/poi/xssf/model/CommentsTable.java @@ -116,7 +116,7 @@ public class CommentsTable extends POIXMLDocumentPart { // Create the cache if needed if(commentRefs == null) { commentRefs = new HashMap(); - for (CTComment comment : comments.getCommentList().getCommentList()) { + for (CTComment comment : comments.getCommentList().getCommentArray()) { commentRefs.put(comment.getRef(), comment); } } diff --git a/src/ooxml/java/org/apache/poi/xwpf/usermodel/XWPFParagraph.java b/src/ooxml/java/org/apache/poi/xwpf/usermodel/XWPFParagraph.java index 6aabadef95..e771424170 100644 --- a/src/ooxml/java/org/apache/poi/xwpf/usermodel/XWPFParagraph.java +++ b/src/ooxml/java/org/apache/poi/xwpf/usermodel/XWPFParagraph.java @@ -93,8 +93,8 @@ public class XWPFParagraph implements IBodyElement{ } runs = new ArrayList(); - if (prgrph.getRList().size() > 0) { - for(CTR ctRun : prgrph.getRList()) { + if (prgrph.getRArray().length > 0) { + for(CTR ctRun : prgrph.getRArray()) { runs.add(new XWPFRun(ctRun, this)); } } @@ -111,17 +111,17 @@ public class XWPFParagraph implements IBodyElement{ // TODO - replace this with some sort of XPath expression // to directly find all the CTRs, in the right order ArrayList rs = new ArrayList(); - rs.addAll( paragraph.getRList() ); + rs.addAll( Arrays.asList(paragraph.getRArray()) ); - for (CTSdtRun sdt : paragraph.getSdtList()) { + for (CTSdtRun sdt : paragraph.getSdtArray()) { CTSdtContentRun run = sdt.getSdtContent(); - rs.addAll( run.getRList() ); + rs.addAll( Arrays.asList(run.getRArray()) ); } - for (CTRunTrackChange c : paragraph.getDelList()) { - rs.addAll( c.getRList() ); + for (CTRunTrackChange c : paragraph.getDelArray()) { + rs.addAll( Arrays.asList(c.getRArray()) ); } - for (CTRunTrackChange c : paragraph.getInsList()) { - rs.addAll( c.getRList() ); + for (CTRunTrackChange c : paragraph.getInsArray()) { + rs.addAll( Arrays.asList(c.getRArray()) ); } // Get text of the paragraph @@ -179,7 +179,7 @@ public class XWPFParagraph implements IBodyElement{ // Loop over pictures inside our // paragraph, looking for text in them - for(CTPicture pict : rs.get(j).getPictList()) { + for(CTPicture pict : rs.get(j).getPictArray()) { XmlObject[] t = pict .selectPath("declare namespace w='http://schemas.openxmlformats.org/wordprocessingml/2006/main' .//w:t"); for (int m = 0; m < t.length; m++) { From 3525bb93a6a54fcf6021d0945a41f985e641f080 Mon Sep 17 00:00:00 2001 From: Nick Burch Date: Tue, 15 Jun 2010 11:42:09 +0000 Subject: [PATCH 10/10] New expected release date for 3.7 beta 1 git-svn-id: https://svn.apache.org/repos/asf/poi/trunk@954837 13f79535-47bb-0310-9956-ffa450edef68 --- src/documentation/content/xdocs/status.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/documentation/content/xdocs/status.xml b/src/documentation/content/xdocs/status.xml index 4f07ad331a..d7096d8cdc 100644 --- a/src/documentation/content/xdocs/status.xml +++ b/src/documentation/content/xdocs/status.xml @@ -34,11 +34,11 @@ + + 49432 - Lazy caching of XSSFComment CTComment objects by reference, to make repeated comment searching faster Better handling of Outlook messages in HSMF when there's no recipient email address When formatting numbers with DataFormatter, handle brackets following colours - - 48574 - further XWPF support for tables, paragraphs, including enhanced support for adding new ones 48245 - tweak HWPF table cell detection to work across more files 48996 - initial support for External Name References in HSSF formula evaluation