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-674287 via svnmerge from
https://svn.apache.org/repos/asf/poi/trunk ........ r671322 | nick | 2008-06-24 20:53:53 +0100 (Tue, 24 Jun 2008) | 1 line Make a start on being able to process formulas in the eventusermodel code ........ r672230 | nick | 2008-06-27 11:12:11 +0100 (Fri, 27 Jun 2008) | 1 line Add MethodNotFound exceptions to the faq ........ r672550 | nick | 2008-06-28 18:04:09 +0100 (Sat, 28 Jun 2008) | 1 line Finish the EventWorkbookBuilder, now does sheet references in formulas properly ........ r672553 | nick | 2008-06-28 18:12:38 +0100 (Sat, 28 Jun 2008) | 1 line Update changelog about EventWorkbookBuilder, and tweak XLS2CSVmra to use it if formulas required ........ r672562 | nick | 2008-06-28 19:21:21 +0100 (Sat, 28 Jun 2008) | 1 line Avoid spurious missing lines with the MissingRecordAware event code, and odd files that contain RowRecords in the middle of the cell Records. ........ r672567 | nick | 2008-06-28 19:48:35 +0100 (Sat, 28 Jun 2008) | 1 line Patch from dnapoletano from bug #45175 - Support for variable length operands in org.apache.poi.hwpf.sprm.SprmOperation ........ r672569 | nick | 2008-06-28 19:54:02 +0100 (Sat, 28 Jun 2008) | 1 line Patch from N. Hira from bug #45001 - Further fix for HWPF Range.delete() and unicode characters ........ r672570 | nick | 2008-06-28 19:58:23 +0100 (Sat, 28 Jun 2008) | 1 line Patch from N.Hira from bug #45252 - Improvement for HWPF Range.replaceText() ........ r673050 | yegor | 2008-07-01 11:32:29 +0100 (Tue, 01 Jul 2008) | 1 line updated status of the latest release, 3.1-FINAL ........ r673853 | josh | 2008-07-03 23:20:18 +0100 (Thu, 03 Jul 2008) | 1 line Fix for bug 45334 - formula parser needs to handle dots in identifiers ........ r673863 | josh | 2008-07-04 00:09:08 +0100 (Fri, 04 Jul 2008) | 1 line Fix for bug 45334 - added impl for ERROR.TYPE() ........ r673987 | nick | 2008-07-04 10:58:21 +0100 (Fri, 04 Jul 2008) | 1 line Fix bug #45336 - Fix HSSFColor.getTripletHash() ........ r673997 | nick | 2008-07-04 11:46:59 +0100 (Fri, 04 Jul 2008) | 1 line Fix bug #45338 - Fix HSSFWorkbook to give you the same HSSFFont every time, and then fix it to find newly added fonts ........ git-svn-id: https://svn.apache.org/repos/asf/poi/branches/ooxml@674296 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
parent
695b85049d
commit
dcf1741253
@ -36,7 +36,7 @@
|
||||
</devs>
|
||||
|
||||
<!-- Don't forget to update status.xml too! -->
|
||||
<release version="3.5.1-alpha1" date="2008-04-??">
|
||||
<release version="3.5.1-beta1" date="2008-07-11">
|
||||
<action dev="POI-DEVELOPERS" type="add">45018 - Support for fetching embeded documents from within an OOXML file</action>
|
||||
<action dev="POI-DEVELOPERS" type="add">Port support for setting a policy on missing / blank cells when fetching, to XSSF too</action>
|
||||
<action dev="POI-DEVELOPERS" type="add">Common text extraction factory, which returns the correct POITextExtractor for the supplied data</action>
|
||||
@ -45,8 +45,15 @@
|
||||
<action dev="POI-DEVELOPERS" type="add">Created a common interface for handling PowerPoint files, irrespective of if they are .ppt or .pptx</action>
|
||||
<action dev="POI-DEVELOPERS" type="add">Created a common interface for handling Excel files, irrespective of if they are .xls or .xlsx</action>
|
||||
</release>
|
||||
<release version="3.2-alpha1" date="2008-??-??">
|
||||
<action dev="POI-DEVELOPERS" type="add"><!-- to keep forrest dtd quiet--></action>
|
||||
<release version="3.1.1-alpha1" date="2008-??-??">
|
||||
<action dev="POI-DEVELOPERS" type="fix">45338 - Fix HSSFWorkbook to give you the same HSSFFont every time, and then fix it to find newly added fonts</action>
|
||||
<action dev="POI-DEVELOPERS" type="fix">45336 - Fix HSSFColor.getTripletHash()</action>
|
||||
<action dev="POI-DEVELOPERS" type="fix">45334 - Fixed formula parser to handle dots in identifiers</action>
|
||||
<action dev="POI-DEVELOPERS" type="fix">45252 - Improvement for HWPF Range.replaceText()</action>
|
||||
<action dev="POI-DEVELOPERS" type="fix">45001 - Further fix for HWPF Range.delete() and unicode characters</action>
|
||||
<action dev="POI-DEVELOPERS" type="add">45175 - Support for variable length operands in org.apache.poi.hwpf.sprm.SprmOperation</action>
|
||||
<action dev="POI-DEVELOPERS" type="fix">Avoid spurious missing lines with the MissingRecordAware event code, and odd files that contain RowRecords in the middle of the cell Records.</action>
|
||||
<action dev="POI-DEVELOPERS" type="add">Support for parsing formulas during EventUserModel processing, via the new EventWorkbookBuilder</action>
|
||||
</release>
|
||||
<release version="3.1-final" date="2008-06-29">
|
||||
<action dev="POI-DEVELOPERS" type="fix">30978 - Fixed re-serialization of tRefErr3d and tAreaErr3d</action>
|
||||
|
@ -20,6 +20,36 @@
|
||||
<!DOCTYPE faqs PUBLIC "-//APACHE//DTD FAQ V1.1//EN" "./dtd/faq-v11.dtd">
|
||||
|
||||
<faqs title="Frequently Asked Questions">
|
||||
<faq>
|
||||
<question>
|
||||
My code uses some new HSSF feature, compiles fine but fails when live with a "MethodNotFoundException"
|
||||
</question>
|
||||
<answer>
|
||||
<p>You almost certainly have an older version of POI earlier
|
||||
on your classpath. Quite a few runtimes and other packages
|
||||
will ship an older version of POI, so this is an easy problem
|
||||
to hit without realising.</p>
|
||||
<p>The best way to identify the offending earlier jar file is
|
||||
with a few lines of java. These will load one of the core POI
|
||||
classes, and report where it came from.</p>
|
||||
<source>
|
||||
ClassLoader classloader = org.apache.poi.poifs.filesystem.POIFSFileSystem.class.getClassLoader();
|
||||
URL res = classloader.getResource("org/apache/poi/poifs/filesystem/POIFSFileSystem.class">
|
||||
String path = res.getPath();
|
||||
System.out.println("Core POI came from " + path);
|
||||
</source>
|
||||
</answer>
|
||||
</faq>
|
||||
<faq>
|
||||
<question>
|
||||
My code uses the scratchpad, compiles fine but fails to run with a "MethodNotFoundException"
|
||||
</question>
|
||||
<answer>
|
||||
<p>You almost certainly have an older version earlier on your
|
||||
classpath. See the answer to the similar question above for
|
||||
how to track this down.</p>
|
||||
</answer>
|
||||
</faq>
|
||||
<faq>
|
||||
<question>
|
||||
Why is reading a simple sheet taking so long?
|
||||
|
@ -31,35 +31,24 @@
|
||||
</header>
|
||||
|
||||
<body>
|
||||
<section><title>Office Open XML Support</title>
|
||||
<section><title>POI 3.5.1 beta 1, and Office Open XML Support (2008-07-11)</title>
|
||||
<p>We are currently working to support the new Office Open XML
|
||||
file formats, such as XLSX and PPTX, which were introduced in
|
||||
Office 2007.</p>
|
||||
<p>Support for these is currently only available in an svn branch,
|
||||
but we hope to have a full release including it by the summer.
|
||||
People interested should follow the
|
||||
<p>Development for this is in a svn branch, but we are please to
|
||||
announce our first preview release containing this support.
|
||||
Users interested in the OOXML support should download the
|
||||
<link href="http://www.apache.org/dyn/closer.cgi/poi/dev/">POI 3.5.1 beta 1</link>
|
||||
the source and binaries from their
|
||||
<link href="http://www.apache.org/dyn/closer.cgi/poi/dev/">local mirror</link>.
|
||||
People interested should also follow the
|
||||
<link href="mailinglists.html">dev list</link> to track progress.</p>
|
||||
</section>
|
||||
<section><title>POI 3.1-BETA2 Released (2008-05-28)</title>
|
||||
<section><title>POI 3.1-FINAL Released (2008-06-29)</title>
|
||||
<p>
|
||||
The POI team is pleased to announce the release of 3.1 BETA2 which is one of the final steps before 3.1 FINAL.
|
||||
The status of this release is a beta, meaning that we encourage users to try it out.
|
||||
If you find any bugs, please report them to the POI <link href="https://issues.apache.org/bugzilla/buglist.cgi?product=POI">bug database</link> or to
|
||||
the <link href="./mailinglists.html">POI Developer List</link>.
|
||||
</p><p> A full list of changes is available in
|
||||
<link href="./changes.html">the changelog</link>, and
|
||||
<link href="http://www.apache.org/dyn/closer.cgi/poi/dev/">download</link>
|
||||
the source and binaries from your
|
||||
<link href="http://www.apache.org/dyn/closer.cgi/poi/dev/">local mirror</link>.
|
||||
</p>
|
||||
<p>
|
||||
The release is also available from the central Maven repository
|
||||
under Group ID "org.apache.poi" and Version "3.1-beta2".
|
||||
</p>
|
||||
</section>
|
||||
<section><title>POI 3.0.2 Released</title>
|
||||
<p>The POI team is pleased to announce POI 3.0.2, the latest release of Apache POI.
|
||||
There have been many important bug fixes since the 3.0.1 release and a lot of new features. A full list of changes is available in
|
||||
The POI team is pleased to announce the release of 3.1 FINAL, the latest release of Apache POI.
|
||||
There have been many important bug fixes since the 3.0.2 release and a lot of new features.
|
||||
</p><p> A full list of changes is available in
|
||||
<link href="./changes.html">the changelog</link>, and
|
||||
<link href="http://www.apache.org/dyn/closer.cgi/poi/release/">download</link>
|
||||
the source and binaries from your
|
||||
@ -67,13 +56,8 @@
|
||||
</p>
|
||||
<p>
|
||||
The release is also available from the central Maven repository
|
||||
under Group ID "org.apache.poi" and Version "3.0.2-FINAL".
|
||||
under Group ID "org.apache.poi" and Version "3.1-FINAL".
|
||||
</p>
|
||||
<p>We would also like to confirm that verions 3.0 and 3.0.1 of Apache
|
||||
POI do
|
||||
<em>not</em> contain any viruses. Users of broken virus checkers
|
||||
which do detect a 94 byte file, sci_cec.db, as containing one are
|
||||
advised to contact their vendor for a fix.</p>
|
||||
</section>
|
||||
|
||||
<section><title>Purpose</title>
|
||||
|
@ -33,7 +33,7 @@
|
||||
|
||||
<!-- Don't forget to update changes.xml too! -->
|
||||
<changes>
|
||||
<release version="3.5.1-alpha1" date="2008-04-??">
|
||||
<release version="3.5.1-beta1" date="2008-07-11">
|
||||
<action dev="POI-DEVELOPERS" type="add">45018 - Support for fetching embeded documents from within an OOXML file</action>
|
||||
<action dev="POI-DEVELOPERS" type="add">Port support for setting a policy on missing / blank cells when fetching, to XSSF too</action>
|
||||
<action dev="POI-DEVELOPERS" type="add">Common text extraction factory, which returns the correct POITextExtractor for the supplied data</action>
|
||||
@ -42,8 +42,15 @@
|
||||
<action dev="POI-DEVELOPERS" type="add">Created a common interface for handling PowerPoint files, irrespective of if they are .ppt or .pptx</action>
|
||||
<action dev="POI-DEVELOPERS" type="add">Created a common interface for handling Excel files, irrespective of if they are .xls or .xlsx</action>
|
||||
</release>
|
||||
<release version="3.2-alpha1" date="2008-??-??">
|
||||
<action dev="POI-DEVELOPERS" type="add"><!-- to keep forrest dtd quiet--></action>
|
||||
<release version="3.1.1-alpha1" date="2008-??-??">
|
||||
<action dev="POI-DEVELOPERS" type="fix">45338 - Fix HSSFWorkbook to give you the same HSSFFont every time, and then fix it to find newly added fonts</action>
|
||||
<action dev="POI-DEVELOPERS" type="fix">45336 - Fix HSSFColor.getTripletHash()</action>
|
||||
<action dev="POI-DEVELOPERS" type="fix">45334 - Fixed formula parser to handle dots in identifiers</action>
|
||||
<action dev="POI-DEVELOPERS" type="fix">45252 - Improvement for HWPF Range.replaceText()</action>
|
||||
<action dev="POI-DEVELOPERS" type="fix">45001 - Further fix for HWPF Range.delete() and unicode characters</action>
|
||||
<action dev="POI-DEVELOPERS" type="add">45175 - Support for variable length operands in org.apache.poi.hwpf.sprm.SprmOperation</action>
|
||||
<action dev="POI-DEVELOPERS" type="fix">Avoid spurious missing lines with the MissingRecordAware event code, and odd files that contain RowRecords in the middle of the cell Records.</action>
|
||||
<action dev="POI-DEVELOPERS" type="add">Support for parsing formulas during EventUserModel processing, via the new EventWorkbookBuilder</action>
|
||||
</release>
|
||||
<release version="3.1-final" date="2008-06-29">
|
||||
<action dev="POI-DEVELOPERS" type="fix">30978 - Fixed re-serialization of tRefErr3d and tAreaErr3d</action>
|
||||
|
@ -30,9 +30,11 @@ import org.apache.poi.hssf.eventusermodel.HSSFEventFactory;
|
||||
import org.apache.poi.hssf.eventusermodel.HSSFListener;
|
||||
import org.apache.poi.hssf.eventusermodel.HSSFRequest;
|
||||
import org.apache.poi.hssf.eventusermodel.MissingRecordAwareHSSFListener;
|
||||
import org.apache.poi.hssf.eventusermodel.EventWorkbookBuilder.SheetRecordCollectingListener;
|
||||
import org.apache.poi.hssf.eventusermodel.dummyrecord.LastCellOfRowDummyRecord;
|
||||
import org.apache.poi.hssf.eventusermodel.dummyrecord.MissingCellDummyRecord;
|
||||
import org.apache.poi.hssf.model.FormulaParser;
|
||||
import org.apache.poi.hssf.record.BOFRecord;
|
||||
import org.apache.poi.hssf.record.BlankRecord;
|
||||
import org.apache.poi.hssf.record.BoolErrRecord;
|
||||
import org.apache.poi.hssf.record.CellValueRecordInterface;
|
||||
@ -46,6 +48,7 @@ import org.apache.poi.hssf.record.Record;
|
||||
import org.apache.poi.hssf.record.SSTRecord;
|
||||
import org.apache.poi.hssf.record.StringRecord;
|
||||
import org.apache.poi.hssf.usermodel.HSSFDateUtil;
|
||||
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
|
||||
import org.apache.poi.poifs.filesystem.POIFSFileSystem;
|
||||
|
||||
/**
|
||||
@ -64,6 +67,10 @@ public class XLS2CSVmra implements HSSFListener {
|
||||
/** Should we output the formula, or the value it has? */
|
||||
private boolean outputFormulaValues = true;
|
||||
|
||||
/** For parsing Formulas */
|
||||
private SheetRecordCollectingListener workbookBuildingListener;
|
||||
private HSSFWorkbook stubWorkbook;
|
||||
|
||||
// Records we pick up as we process
|
||||
private SSTRecord sstRecord;
|
||||
private FormatTrackingHSSFListener formatListener;
|
||||
@ -108,7 +115,13 @@ public class XLS2CSVmra implements HSSFListener {
|
||||
|
||||
HSSFEventFactory factory = new HSSFEventFactory();
|
||||
HSSFRequest request = new HSSFRequest();
|
||||
request.addListenerForAllRecords(formatListener);
|
||||
|
||||
if(outputFormulaValues) {
|
||||
request.addListenerForAllRecords(formatListener);
|
||||
} else {
|
||||
workbookBuildingListener = new SheetRecordCollectingListener(formatListener);
|
||||
request.addListenerForAllRecords(workbookBuildingListener);
|
||||
}
|
||||
|
||||
factory.processWorkbookEvents(request, fs);
|
||||
}
|
||||
@ -124,6 +137,16 @@ public class XLS2CSVmra implements HSSFListener {
|
||||
|
||||
switch (record.getSid())
|
||||
{
|
||||
case BOFRecord.sid:
|
||||
BOFRecord br = (BOFRecord)record;
|
||||
if(br.getType() == BOFRecord.TYPE_WORKSHEET) {
|
||||
// Create sub workbook if required
|
||||
if(workbookBuildingListener != null && stubWorkbook == null) {
|
||||
stubWorkbook = workbookBuildingListener.getStubHSSFWorkbook();
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case SSTRecord.sid:
|
||||
sstRecord = (SSTRecord) record;
|
||||
break;
|
||||
@ -161,7 +184,7 @@ public class XLS2CSVmra implements HSSFListener {
|
||||
}
|
||||
} else {
|
||||
thisStr = '"' +
|
||||
FormulaParser.toFormulaString(null, frec.getParsedExpression()) + '"';
|
||||
FormulaParser.toFormulaString(stubWorkbook, frec.getParsedExpression()) + '"';
|
||||
}
|
||||
break;
|
||||
case StringRecord.sid:
|
||||
|
@ -0,0 +1,199 @@
|
||||
/* ====================================================================
|
||||
Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
contributor license agreements. See the NOTICE file distributed with
|
||||
this work for additional information regarding copyright ownership.
|
||||
The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
(the "License"); you may not use this file except in compliance with
|
||||
the License. You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
==================================================================== */
|
||||
package org.apache.poi.hssf.eventusermodel;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import org.apache.poi.hssf.model.FormulaParser;
|
||||
import org.apache.poi.hssf.model.Workbook;
|
||||
import org.apache.poi.hssf.record.BoundSheetRecord;
|
||||
import org.apache.poi.hssf.record.EOFRecord;
|
||||
import org.apache.poi.hssf.record.ExternSheetRecord;
|
||||
import org.apache.poi.hssf.record.Record;
|
||||
import org.apache.poi.hssf.record.SSTRecord;
|
||||
import org.apache.poi.hssf.record.SupBookRecord;
|
||||
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
|
||||
|
||||
/**
|
||||
* When working with the EventUserModel, if you want to
|
||||
* process formulas, you need an instance of
|
||||
* {@link Workbook} to pass to a {@link HSSFWorkbook},
|
||||
* to finally give to {@link FormulaParser},
|
||||
* and this will build you stub ones.
|
||||
* Since you're working with the EventUserModel, you
|
||||
* wouldn't want to get a full {@link Workbook} and
|
||||
* {@link HSSFWorkbook}, as they would eat too much memory.
|
||||
* Instead, you should collect a few key records as they
|
||||
* go past, then call this once you have them to build a
|
||||
* stub {@link Workbook}, and from that a stub
|
||||
* {@link HSSFWorkbook}, to use with the {@link FormulaParser}.
|
||||
*
|
||||
* The records you should collect are:
|
||||
* * {@link ExternSheetRecord}
|
||||
* * {@link BoundSheetRecord}
|
||||
* You should probably also collect {@link SSTRecord},
|
||||
* but it's not required to pass this in.
|
||||
*
|
||||
* To help, this class includes a HSSFListener wrapper
|
||||
* that will do the collecting for you.
|
||||
*/
|
||||
public class EventWorkbookBuilder {
|
||||
/**
|
||||
* Wraps up your stub {@link Workbook} as a stub
|
||||
* {@link HSSFWorkbook}, ready for passing to
|
||||
* {@link FormulaParser}
|
||||
* @param workbook A stub {@link Workbook}
|
||||
*/
|
||||
public static HSSFWorkbook createStubHSSFWorkbook(Workbook workbook) {
|
||||
return new StubHSSFWorkbook(workbook);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a stub Workbook from the supplied records,
|
||||
* suitable for use with the {@link FormulaParser}
|
||||
* @param externs The ExternSheetRecords in your file
|
||||
* @param bounds The BoundSheetRecords in your file
|
||||
* @param sst The SSTRecord in your file.
|
||||
* @return A stub Workbook suitable for use with {@link FormulaParser}
|
||||
*/
|
||||
public static Workbook createStubWorkbook(ExternSheetRecord[] externs,
|
||||
BoundSheetRecord[] bounds, SSTRecord sst) {
|
||||
List wbRecords = new ArrayList();
|
||||
|
||||
// Core Workbook records go first
|
||||
if(bounds != null) {
|
||||
for(int i=0; i<bounds.length; i++) {
|
||||
wbRecords.add(bounds[i]);
|
||||
}
|
||||
}
|
||||
if(sst != null) {
|
||||
wbRecords.add(sst);
|
||||
}
|
||||
|
||||
// Now we can have the ExternSheetRecords,
|
||||
// preceded by a SupBookRecord
|
||||
if(externs != null) {
|
||||
wbRecords.add(SupBookRecord.createInternalReferences(
|
||||
(short)externs.length));
|
||||
for(int i=0; i<externs.length; i++) {
|
||||
wbRecords.add(externs[i]);
|
||||
}
|
||||
}
|
||||
|
||||
// Finally we need an EoF record
|
||||
wbRecords.add(new EOFRecord());
|
||||
|
||||
return Workbook.createWorkbook(wbRecords);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a stub workbook from the supplied records,
|
||||
* suitable for use with the {@link FormulaParser}
|
||||
* @param externs The ExternSheetRecords in your file
|
||||
* @param bounds The BoundSheetRecords in your file
|
||||
* @return A stub Workbook suitable for use with {@link FormulaParser}
|
||||
*/
|
||||
public static Workbook createStubWorkbook(ExternSheetRecord[] externs,
|
||||
BoundSheetRecord[] bounds) {
|
||||
return createStubWorkbook(externs, bounds, null);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* A wrapping HSSFListener which will collect
|
||||
* {@link BoundSheetRecord}s and {@link ExternSheetRecord}s as
|
||||
* they go past, so you can create a Stub {@link Workbook} from
|
||||
* them once required.
|
||||
*/
|
||||
public static class SheetRecordCollectingListener implements HSSFListener {
|
||||
private HSSFListener childListener;
|
||||
private List boundSheetRecords = new ArrayList();
|
||||
private List externSheetRecords = new ArrayList();
|
||||
private SSTRecord sstRecord = null;
|
||||
|
||||
public SheetRecordCollectingListener(HSSFListener childListener) {
|
||||
this.childListener = childListener;
|
||||
}
|
||||
|
||||
|
||||
public BoundSheetRecord[] getBoundSheetRecords() {
|
||||
return (BoundSheetRecord[])boundSheetRecords.toArray(
|
||||
new BoundSheetRecord[boundSheetRecords.size()]
|
||||
);
|
||||
}
|
||||
public ExternSheetRecord[] getExternSheetRecords() {
|
||||
return (ExternSheetRecord[])externSheetRecords.toArray(
|
||||
new ExternSheetRecord[externSheetRecords.size()]
|
||||
);
|
||||
}
|
||||
public SSTRecord getSSTRecord() {
|
||||
return sstRecord;
|
||||
}
|
||||
|
||||
public HSSFWorkbook getStubHSSFWorkbook() {
|
||||
return createStubHSSFWorkbook(
|
||||
getStubWorkbook()
|
||||
);
|
||||
}
|
||||
public Workbook getStubWorkbook() {
|
||||
return createStubWorkbook(
|
||||
getExternSheetRecords(), getBoundSheetRecords(),
|
||||
getSSTRecord()
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Process this record ourselves, and then
|
||||
* pass it on to our child listener
|
||||
*/
|
||||
public void processRecord(Record record) {
|
||||
// Handle it ourselves
|
||||
processRecordInternally(record);
|
||||
|
||||
// Now pass on to our child
|
||||
childListener.processRecord(record);
|
||||
}
|
||||
|
||||
/**
|
||||
* Process the record ourselves, but do not
|
||||
* pass it on to the child Listener.
|
||||
*/
|
||||
public void processRecordInternally(Record record) {
|
||||
if(record instanceof BoundSheetRecord) {
|
||||
boundSheetRecords.add(record);
|
||||
}
|
||||
else if(record instanceof ExternSheetRecord) {
|
||||
externSheetRecords.add(record);
|
||||
}
|
||||
else if(record instanceof SSTRecord) {
|
||||
sstRecord = (SSTRecord)record;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Let us at the {@link Workbook} constructor on
|
||||
* {@link HSSFWorkbook}
|
||||
*/
|
||||
private static class StubHSSFWorkbook extends HSSFWorkbook {
|
||||
private StubHSSFWorkbook(Workbook wb) {
|
||||
super(wb);
|
||||
}
|
||||
}
|
||||
}
|
@ -46,8 +46,14 @@ import org.apache.poi.hssf.record.RowRecord;
|
||||
*/
|
||||
public class MissingRecordAwareHSSFListener implements HSSFListener {
|
||||
private HSSFListener childListener;
|
||||
private int lastSeenRow = -1;
|
||||
private int lastSeenColumn = -1;
|
||||
|
||||
// Need to have different counters for cell rows and
|
||||
// row rows, as you sometimes get a RowRecord in the
|
||||
// middle of some cells, and that'd break everything
|
||||
private int lastRowRow = -1;
|
||||
|
||||
private int lastCellRow = -1;
|
||||
private int lastCellColumn = -1;
|
||||
|
||||
/**
|
||||
* Constructs a new MissingRecordAwareHSSFListener, which
|
||||
@ -71,14 +77,16 @@ public class MissingRecordAwareHSSFListener implements HSSFListener {
|
||||
if (bof.getType() == bof.TYPE_WORKBOOK)
|
||||
{
|
||||
// Reset the row and column counts - new workbook
|
||||
lastSeenRow = -1;
|
||||
lastSeenColumn = -1;
|
||||
lastRowRow = -1;
|
||||
lastCellRow = -1;
|
||||
lastCellColumn = -1;
|
||||
//System.out.println("Encountered workbook");
|
||||
} else if (bof.getType() == bof.TYPE_WORKSHEET)
|
||||
{
|
||||
// Reset the row and column counts - new sheet
|
||||
lastSeenRow = -1;
|
||||
lastSeenColumn = -1;
|
||||
lastRowRow = -1;
|
||||
lastCellRow = -1;
|
||||
lastCellColumn = -1;
|
||||
//System.out.println("Encountered sheet reference");
|
||||
}
|
||||
break;
|
||||
@ -92,15 +100,15 @@ public class MissingRecordAwareHSSFListener implements HSSFListener {
|
||||
// + rowrec.getFirstCol() + " last column at " + rowrec.getLastCol());
|
||||
|
||||
// If there's a jump in rows, fire off missing row records
|
||||
if(lastSeenRow+1 < rowrec.getRowNumber()) {
|
||||
for(int i=(lastSeenRow+1); i<rowrec.getRowNumber(); i++) {
|
||||
if(lastRowRow+1 < rowrec.getRowNumber()) {
|
||||
for(int i=(lastRowRow+1); i<rowrec.getRowNumber(); i++) {
|
||||
MissingRowDummyRecord dr = new MissingRowDummyRecord(i);
|
||||
childListener.processRecord(dr);
|
||||
}
|
||||
}
|
||||
|
||||
// Record this as the last row we saw
|
||||
lastSeenRow = rowrec.getRowNumber();
|
||||
lastRowRow = rowrec.getRowNumber();
|
||||
break;
|
||||
|
||||
|
||||
@ -157,45 +165,49 @@ public class MissingRecordAwareHSSFListener implements HSSFListener {
|
||||
break;
|
||||
}
|
||||
|
||||
// Do we need to fire dummy end-of-row records?
|
||||
if(thisRow != lastSeenRow) {
|
||||
for(int i=lastSeenRow; i<thisRow; i++) {
|
||||
// If we're on cells, and this cell isn't in the same
|
||||
// row as the last one, then fire the
|
||||
// dummy end-of-row records?
|
||||
if(thisRow != lastCellRow && lastCellRow > -1) {
|
||||
for(int i=lastCellRow; i<thisRow; i++) {
|
||||
int cols = -1;
|
||||
if(i == lastSeenRow) {
|
||||
cols = lastSeenColumn;
|
||||
if(i == lastCellRow) {
|
||||
cols = lastCellColumn;
|
||||
}
|
||||
LastCellOfRowDummyRecord r = new LastCellOfRowDummyRecord(i, cols);
|
||||
childListener.processRecord(r);
|
||||
}
|
||||
}
|
||||
// If we've finished with the columns, then fire the final
|
||||
// dummy end-of-row record
|
||||
if(lastSeenRow != -1 && lastSeenColumn != -1 && thisRow == -1) {
|
||||
LastCellOfRowDummyRecord r = new LastCellOfRowDummyRecord(lastSeenRow, lastSeenColumn);
|
||||
|
||||
// If we've just finished with the cells, then fire the
|
||||
// final dummy end-of-row record
|
||||
if(lastCellRow != -1 && lastCellColumn != -1 && thisRow == -1) {
|
||||
LastCellOfRowDummyRecord r = new LastCellOfRowDummyRecord(lastCellRow, lastCellColumn);
|
||||
childListener.processRecord(r);
|
||||
|
||||
lastSeenRow = -1;
|
||||
lastSeenColumn = -1;
|
||||
lastCellRow = -1;
|
||||
lastCellColumn = -1;
|
||||
}
|
||||
|
||||
// If we've moved onto a new row, the ensure we re-set
|
||||
// the column counter
|
||||
if(thisRow != lastSeenRow) {
|
||||
lastSeenColumn = -1;
|
||||
if(thisRow != lastCellRow) {
|
||||
lastCellColumn = -1;
|
||||
}
|
||||
|
||||
// Do we need to fire dummy cell records?
|
||||
if(lastSeenColumn != (thisColumn-1)) {
|
||||
for(int i=lastSeenColumn+1; i<thisColumn; i++) {
|
||||
// If there's a gap in the cells, then fire
|
||||
// the dummy cell records?
|
||||
if(lastCellColumn != (thisColumn-1)) {
|
||||
for(int i=lastCellColumn+1; i<thisColumn; i++) {
|
||||
MissingCellDummyRecord r = new MissingCellDummyRecord(thisRow, i);
|
||||
childListener.processRecord(r);
|
||||
}
|
||||
}
|
||||
|
||||
// Update cell and row counts if doing cells
|
||||
// Update cell and row counts as needed
|
||||
if(thisColumn != -1) {
|
||||
lastSeenRow = thisRow;
|
||||
lastSeenColumn = thisColumn;
|
||||
lastCellColumn = thisColumn;
|
||||
lastCellRow = thisRow;
|
||||
}
|
||||
|
||||
childListener.processRecord(record);
|
||||
|
@ -22,11 +22,13 @@ import java.util.List;
|
||||
import java.util.Stack;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
//import PTG's .. since we need everything, import *
|
||||
//import PTGs .. since we need everything, import *
|
||||
import org.apache.poi.hssf.record.formula.*;
|
||||
import org.apache.poi.hssf.record.formula.function.FunctionMetadata;
|
||||
import org.apache.poi.hssf.record.formula.function.FunctionMetadataRegistry;
|
||||
import org.apache.poi.ss.usermodel.Workbook;
|
||||
import org.apache.poi.hssf.util.AreaReference;
|
||||
import org.apache.poi.hssf.util.CellReference;
|
||||
|
||||
/**
|
||||
* This class parses a formula string into a List of tokens in RPN order.
|
||||
@ -178,8 +180,14 @@ public final class FormulaParser {
|
||||
GetChar();
|
||||
}
|
||||
|
||||
/** Get an Identifier */
|
||||
private String GetName() {
|
||||
/**
|
||||
* Parses a sheet name, named range name, or simple cell reference.<br/>
|
||||
* Note - identifiers in Excel can contain dots, so this method may return a String
|
||||
* which may need to be converted to an area reference. For example, this method
|
||||
* may return a value like "A1..B2", in which case the caller must convert it to
|
||||
* an area reference like "A1:B2"
|
||||
*/
|
||||
private String parseIdentifier() {
|
||||
StringBuffer Token = new StringBuffer();
|
||||
if (!IsAlpha(look) && look != '\'') {
|
||||
throw expected("Name");
|
||||
@ -201,7 +209,9 @@ public final class FormulaParser {
|
||||
}
|
||||
else
|
||||
{
|
||||
while (IsAlNum(look)) {
|
||||
// allow for any sequence of dots and identifier chars
|
||||
// special case of two consecutive dots is best treated in the calling code
|
||||
while (IsAlNum(look) || look == '.') {
|
||||
Token.append(look);
|
||||
GetChar();
|
||||
}
|
||||
@ -220,15 +230,22 @@ public final class FormulaParser {
|
||||
return value.length() == 0 ? null : value.toString();
|
||||
}
|
||||
|
||||
private ParseNode parseFunctionOrIdentifier() {
|
||||
String name = GetName();
|
||||
private ParseNode parseFunctionReferenceOrName() {
|
||||
String name = parseIdentifier();
|
||||
if (look == '('){
|
||||
//This is a function
|
||||
return function(name);
|
||||
}
|
||||
return new ParseNode(parseIdentifier(name));
|
||||
return new ParseNode(parseNameOrReference(name));
|
||||
}
|
||||
private Ptg parseIdentifier(String name) {
|
||||
|
||||
private Ptg parseNameOrReference(String name) {
|
||||
|
||||
AreaReference areaRef = parseArea(name);
|
||||
if (areaRef != null) {
|
||||
// will happen if dots are used instead of colon
|
||||
return new AreaPtg(areaRef.formatAsString());
|
||||
}
|
||||
|
||||
if (look == ':' || look == '.') { // this is a AreaReference
|
||||
GetChar();
|
||||
@ -238,23 +255,28 @@ public final class FormulaParser {
|
||||
}
|
||||
|
||||
String first = name;
|
||||
String second = GetName();
|
||||
String second = parseIdentifier();
|
||||
return new AreaPtg(first+":"+second);
|
||||
}
|
||||
|
||||
if (look == '!') {
|
||||
Match('!');
|
||||
String sheetName = name;
|
||||
String first = GetName();
|
||||
String first = parseIdentifier();
|
||||
short externIdx = (short)book.getExternalSheetIndex(book.getSheetIndex(sheetName));
|
||||
areaRef = parseArea(name);
|
||||
if (areaRef != null) {
|
||||
// will happen if dots are used instead of colon
|
||||
return new Area3DPtg(areaRef.formatAsString(), externIdx);
|
||||
}
|
||||
if (look == ':') {
|
||||
Match(':');
|
||||
String second=GetName();
|
||||
String second=parseIdentifier();
|
||||
if (look == '!') {
|
||||
//The sheet name was included in both of the areas. Only really
|
||||
//need it once
|
||||
Match('!');
|
||||
String third=GetName();
|
||||
String third=parseIdentifier();
|
||||
|
||||
if (!sheetName.equals(second))
|
||||
throw new RuntimeException("Unhandled double sheet reference.");
|
||||
@ -271,9 +293,7 @@ public final class FormulaParser {
|
||||
|
||||
// This can be either a cell ref or a named range
|
||||
// Try to spot which it is
|
||||
boolean cellRef = CELL_REFERENCE_PATTERN.matcher(name).matches();
|
||||
|
||||
if (cellRef) {
|
||||
if (isValidCellReference(name)) {
|
||||
return new RefPtg(name);
|
||||
}
|
||||
|
||||
@ -287,6 +307,41 @@ public final class FormulaParser {
|
||||
+ name + "\", but that named range wasn't defined!");
|
||||
}
|
||||
|
||||
/**
|
||||
* @return <code>null</code> if name cannot be split at a dot
|
||||
*/
|
||||
private AreaReference parseArea(String name) {
|
||||
int dotPos = name.indexOf('.');
|
||||
if (dotPos < 0) {
|
||||
return null;
|
||||
}
|
||||
int dotCount = 1;
|
||||
while (dotCount<name.length() && name.charAt(dotPos+dotCount) == '.') {
|
||||
dotCount++;
|
||||
if (dotCount>3) {
|
||||
// four or more consecutive dots does not convert to ':'
|
||||
return null;
|
||||
}
|
||||
}
|
||||
String partA = name.substring(0, dotPos);
|
||||
if (!isValidCellReference(partA)) {
|
||||
return null;
|
||||
}
|
||||
String partB = name.substring(dotPos+dotCount);
|
||||
if (!isValidCellReference(partB)) {
|
||||
return null;
|
||||
}
|
||||
CellReference topLeft = new CellReference(partA);
|
||||
CellReference bottomRight = new CellReference(partB);
|
||||
return new AreaReference(topLeft, bottomRight);
|
||||
}
|
||||
|
||||
private static boolean isValidCellReference(String str) {
|
||||
// TODO - exact rules for recognising cell references may be too complicated for regex
|
||||
return CELL_REFERENCE_PATTERN.matcher(str).matches();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Note - Excel function names are 'case aware but not case sensitive'. This method may end
|
||||
* up creating a defined name record in the workbook if the specified name is not an internal
|
||||
@ -465,7 +520,7 @@ public final class FormulaParser {
|
||||
return new ParseNode(parseStringLiteral());
|
||||
}
|
||||
if (IsAlpha(look) || look == '\''){
|
||||
return parseFunctionOrIdentifier();
|
||||
return parseFunctionReferenceOrName();
|
||||
}
|
||||
// else - assume number
|
||||
return new ParseNode(parseNumber());
|
||||
@ -510,7 +565,7 @@ public final class FormulaParser {
|
||||
|
||||
private ErrPtg parseErrorLiteral() {
|
||||
Match('#');
|
||||
String part1 = GetName().toUpperCase();
|
||||
String part1 = parseIdentifier().toUpperCase();
|
||||
|
||||
switch(part1.charAt(0)) {
|
||||
case 'V':
|
||||
|
@ -1,25 +1,78 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
/*
|
||||
* Created on May 15, 2005
|
||||
*
|
||||
*/
|
||||
/* ====================================================================
|
||||
Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
contributor license agreements. See the NOTICE file distributed with
|
||||
this work for additional information regarding copyright ownership.
|
||||
The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
(the "License"); you may not use this file except in compliance with
|
||||
the License. You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
==================================================================== */
|
||||
|
||||
package org.apache.poi.hssf.record.formula.functions;
|
||||
|
||||
public class Errortype extends NotImplementedFunction {
|
||||
import org.apache.poi.hssf.record.formula.eval.ErrorEval;
|
||||
import org.apache.poi.hssf.record.formula.eval.Eval;
|
||||
import org.apache.poi.hssf.record.formula.eval.EvaluationException;
|
||||
import org.apache.poi.hssf.record.formula.eval.NumberEval;
|
||||
import org.apache.poi.hssf.record.formula.eval.OperandResolver;
|
||||
import org.apache.poi.hssf.usermodel.HSSFErrorConstants;
|
||||
|
||||
/**
|
||||
* Implementation for the ERROR.TYPE() Excel function.<p/>
|
||||
*
|
||||
* <b>Syntax:</b><br/>
|
||||
* <b>ERROR.TYPE</b>(<b>errorValue</b>)<p/>
|
||||
*
|
||||
* Returns a number corresponding to the error type of the supplied argument.<p/>
|
||||
*
|
||||
* <table border="1" cellpadding="1" cellspacing="1" summary="Return values for ERROR.TYPE()">
|
||||
* <tr><td>errorValue</td><td>Return Value</td></tr>
|
||||
* <tr><td>#NULL!</td><td>1</td></tr>
|
||||
* <tr><td>#DIV/0!</td><td>2</td></tr>
|
||||
* <tr><td>#VALUE!</td><td>3</td></tr>
|
||||
* <tr><td>#REF!</td><td>4</td></tr>
|
||||
* <tr><td>#NAME?</td><td>5</td></tr>
|
||||
* <tr><td>#NUM!</td><td>6</td></tr>
|
||||
* <tr><td>#N/A!</td><td>7</td></tr>
|
||||
* <tr><td>everything else</td><td>#N/A!</td></tr>
|
||||
* </table>
|
||||
*
|
||||
* Note - the results of ERROR.TYPE() are different to the constants defined in
|
||||
* <tt>HSSFErrorConstants</tt>.
|
||||
*
|
||||
* @author Josh Micich
|
||||
*/
|
||||
public final class Errortype implements Function {
|
||||
|
||||
public Eval evaluate(Eval[] args, int srcCellRow, short srcCellCol) {
|
||||
|
||||
try {
|
||||
OperandResolver.getSingleValue(args[0], srcCellRow, srcCellCol);
|
||||
return ErrorEval.NA;
|
||||
} catch (EvaluationException e) {
|
||||
int result = translateErrorCodeToErrorTypeValue(e.getErrorEval().getErrorCode());
|
||||
return new NumberEval(result);
|
||||
}
|
||||
}
|
||||
|
||||
private int translateErrorCodeToErrorTypeValue(int errorCode) {
|
||||
switch (errorCode) {
|
||||
case HSSFErrorConstants.ERROR_NULL: return 1;
|
||||
case HSSFErrorConstants.ERROR_DIV_0: return 2;
|
||||
case HSSFErrorConstants.ERROR_VALUE: return 3;
|
||||
case HSSFErrorConstants.ERROR_REF: return 4;
|
||||
case HSSFErrorConstants.ERROR_NAME: return 5;
|
||||
case HSSFErrorConstants.ERROR_NUM: return 6;
|
||||
case HSSFErrorConstants.ERROR_NA : return 7;
|
||||
}
|
||||
throw new IllegalArgumentException("Invalid error code (" + errorCode + ")");
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -24,6 +24,7 @@ import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.io.PrintWriter;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Hashtable;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Stack;
|
||||
@ -106,6 +107,12 @@ public class HSSFWorkbook extends POIDocument implements org.apache.poi.ss.userm
|
||||
|
||||
private ArrayList names;
|
||||
|
||||
/**
|
||||
* this holds the HSSFFont objects attached to this workbook.
|
||||
* We only create these from the low level records as required.
|
||||
*/
|
||||
private Hashtable fonts;
|
||||
|
||||
/**
|
||||
* holds whether or not to preserve other nodes in the POIFS. Used
|
||||
* for macros and embedded objects.
|
||||
@ -1021,9 +1028,10 @@ public class HSSFWorkbook extends POIDocument implements org.apache.poi.ss.userm
|
||||
if(fontindex == Short.MAX_VALUE){
|
||||
throw new IllegalArgumentException("Maximum number of fonts was exceeded");
|
||||
}
|
||||
HSSFFont retval = new HSSFFont(fontindex, font);
|
||||
|
||||
return retval;
|
||||
// Ask getFontAt() to build it for us,
|
||||
// so it gets properly cached
|
||||
return getFontAt(fontindex);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -1033,15 +1041,11 @@ public class HSSFWorkbook extends POIDocument implements org.apache.poi.ss.userm
|
||||
String name, boolean italic, boolean strikeout,
|
||||
short typeOffset, byte underline)
|
||||
{
|
||||
// System.out.println( boldWeight + ", " + color + ", " + fontHeight + ", " + name + ", " + italic + ", " + strikeout + ", " + typeOffset + ", " + underline );
|
||||
for (short i = 0; i < workbook.getNumberOfFontRecords(); i++)
|
||||
{
|
||||
if (i == 4)
|
||||
continue;
|
||||
for (short i=0; i<=getNumberOfFonts(); i++) {
|
||||
// Remember - there is no 4!
|
||||
if(i == 4) continue;
|
||||
|
||||
FontRecord font = workbook.getFontRecordAt(i);
|
||||
HSSFFont hssfFont = new HSSFFont(i, font);
|
||||
// System.out.println( hssfFont.getBoldweight() + ", " + hssfFont.getColor() + ", " + hssfFont.getFontHeight() + ", " + hssfFont.getFontName() + ", " + hssfFont.getItalic() + ", " + hssfFont.getStrikeout() + ", " + hssfFont.getTypeOffset() + ", " + hssfFont.getUnderline() );
|
||||
HSSFFont hssfFont = getFontAt(i);
|
||||
if (hssfFont.getBoldweight() == boldWeight
|
||||
&& hssfFont.getColor() == color
|
||||
&& hssfFont.getFontHeight() == fontHeight
|
||||
@ -1051,12 +1055,10 @@ public class HSSFWorkbook extends POIDocument implements org.apache.poi.ss.userm
|
||||
&& hssfFont.getTypeOffset() == typeOffset
|
||||
&& hssfFont.getUnderline() == underline)
|
||||
{
|
||||
// System.out.println( "Found font" );
|
||||
return hssfFont;
|
||||
}
|
||||
}
|
||||
|
||||
// System.out.println( "No font found" );
|
||||
return null;
|
||||
}
|
||||
|
||||
@ -1071,15 +1073,26 @@ public class HSSFWorkbook extends POIDocument implements org.apache.poi.ss.userm
|
||||
}
|
||||
|
||||
/**
|
||||
* get the font at the given index number
|
||||
* Get the font at the given index number
|
||||
* @param idx index number
|
||||
* @return HSSFFont at the index
|
||||
*/
|
||||
|
||||
public HSSFFont getFontAt(short idx)
|
||||
{
|
||||
if(fonts == null) fonts = new Hashtable();
|
||||
|
||||
// So we don't confuse users, give them back
|
||||
// the same object every time, but create
|
||||
// them lazily
|
||||
Short sIdx = Short.valueOf(idx);
|
||||
if(fonts.containsKey(sIdx)) {
|
||||
return (HSSFFont)fonts.get(sIdx);
|
||||
}
|
||||
|
||||
FontRecord font = workbook.getFontRecordAt(idx);
|
||||
HSSFFont retval = new HSSFFont(idx, font);
|
||||
fonts.put(sIdx, retval);
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
@ -155,8 +155,12 @@ public class HSSFColor implements Color {
|
||||
|
||||
String hexString = color.getHexString();
|
||||
if (result.containsKey(hexString)) {
|
||||
throw new RuntimeException("Dup color hexString (" + hexString
|
||||
+ ") for color (" + color.getClass().getName() + ")");
|
||||
HSSFColor other = (HSSFColor)result.get(hexString);
|
||||
throw new RuntimeException(
|
||||
"Dup color hexString (" + hexString
|
||||
+ ") for color (" + color.getClass().getName() + ") - "
|
||||
+ " already taken by (" + other.getClass().getName() + ")"
|
||||
);
|
||||
}
|
||||
result.put(hexString, color);
|
||||
}
|
||||
@ -1511,9 +1515,9 @@ public class HSSFColor implements Color {
|
||||
public final static short index = 0x19;
|
||||
public final static short[] triplet =
|
||||
{
|
||||
153, 51, 102
|
||||
127, 0, 0
|
||||
};
|
||||
public final static String hexString = "9999:3333:6666";
|
||||
public final static String hexString = "8000:0:0";
|
||||
|
||||
public short getIndex()
|
||||
{
|
||||
|
@ -91,15 +91,18 @@ public class TextPiece extends PropertyNode implements Comparable
|
||||
public void adjustForDelete(int start, int length)
|
||||
{
|
||||
|
||||
// length is expected to be the number of code-points,
|
||||
// not the number of characters
|
||||
int numChars = length;
|
||||
if (usesUnicode()) {
|
||||
|
||||
start /= 2;
|
||||
length /= 2;
|
||||
numChars = (length / 2);
|
||||
}
|
||||
|
||||
int myStart = getStart();
|
||||
int myEnd = getEnd();
|
||||
int end = start + length;
|
||||
int end = start + numChars;
|
||||
|
||||
/* do we have to delete from this text piece? */
|
||||
if (start <= myEnd && end >= myStart) {
|
||||
@ -108,9 +111,14 @@ public class TextPiece extends PropertyNode implements Comparable
|
||||
int overlapStart = Math.max(myStart, start);
|
||||
int overlapEnd = Math.min(myEnd, end);
|
||||
((StringBuffer)_buf).delete(overlapStart, overlapEnd);
|
||||
|
||||
super.adjustForDelete(start, length);
|
||||
}
|
||||
|
||||
// We need to invoke this even if text from this piece is not being
|
||||
// deleted because the adjustment must propagate to all subsequent
|
||||
// text pieces i.e., if text from tp[n] is being deleted, then
|
||||
// tp[n + 1], tp[n + 2], etc. will need to be adjusted.
|
||||
// The superclass is expected to use a separate sentry for this.
|
||||
super.adjustForDelete(start, length);
|
||||
}
|
||||
|
||||
public int characterLength()
|
||||
|
@ -101,7 +101,14 @@ public class SprmOperation
|
||||
case 3:
|
||||
return LittleEndian.getInt(_grpprl, _gOffset);
|
||||
case 6:
|
||||
throw new UnsupportedOperationException("This SPRM contains a variable length operand");
|
||||
byte operandLength = _grpprl[_gOffset + 1]; //surely shorter than an int...
|
||||
|
||||
byte [] codeBytes = new byte[LittleEndian.INT_SIZE]; //initialized to zeros by JVM
|
||||
for(int i = 0; i < operandLength; i++)
|
||||
if(_gOffset + i < _grpprl.length)
|
||||
codeBytes[i] = _grpprl[_gOffset + 1 + i];
|
||||
|
||||
return LittleEndian.getInt(codeBytes, 0);
|
||||
case 7:
|
||||
byte threeByteInt[] = new byte[4];
|
||||
threeByteInt[0] = _grpprl[_gOffset];
|
||||
|
@ -333,7 +333,7 @@ public class Range
|
||||
_doc.getCharacterTable().adjustForInsert(_charStart, adjustedLength);
|
||||
_doc.getParagraphTable().adjustForInsert(_parStart, adjustedLength);
|
||||
_doc.getSectionTable().adjustForInsert(_sectionStart, adjustedLength);
|
||||
adjustForInsert(text.length());
|
||||
adjustForInsert(adjustedLength);
|
||||
|
||||
// update the FIB.CCPText field
|
||||
adjustFIB(text.length());
|
||||
@ -656,8 +656,15 @@ public class Range
|
||||
);
|
||||
}
|
||||
|
||||
// this Range isn't a proper parent of the subRange() so we'll have to keep
|
||||
// track of an updated endOffset on our own
|
||||
int previousEndOffset = subRange.getEndOffset();
|
||||
|
||||
subRange.insertBefore(pValue);
|
||||
|
||||
if (subRange.getEndOffset() != previousEndOffset)
|
||||
_end += (subRange.getEndOffset() - previousEndOffset);
|
||||
|
||||
// re-create the sub-range so we can delete it
|
||||
subRange = new Range(
|
||||
(absPlaceHolderIndex + pValue.length()),
|
||||
@ -671,9 +678,30 @@ public class Range
|
||||
(pValue.length() * 2)), getDocument()
|
||||
);
|
||||
|
||||
// deletes are automagically propagated
|
||||
subRange.delete();
|
||||
}
|
||||
|
||||
/**
|
||||
* Replace (all instances of) a piece of text with another...
|
||||
*
|
||||
* @param pPlaceHolder The text to be replaced (e.g., "${organization}")
|
||||
* @param pValue The replacement text (e.g., "Apache Software Foundation")
|
||||
*/
|
||||
public void replaceText(String pPlaceHolder, String pValue)
|
||||
{
|
||||
boolean keepLooking = true;
|
||||
while (keepLooking) {
|
||||
|
||||
String text = text();
|
||||
int offset = text.indexOf(pPlaceHolder);
|
||||
if (offset >= 0)
|
||||
replaceText(pPlaceHolder, pValue, offset);
|
||||
else
|
||||
keepLooking = false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the character run at index. The index is relative to this range.
|
||||
*
|
||||
@ -915,7 +943,7 @@ public class Range
|
||||
|
||||
/**
|
||||
* adjust this range after an insert happens.
|
||||
* @param length the length to adjust for
|
||||
* @param length the length to adjust for (expected to be a count of code-points, not necessarily chars)
|
||||
*/
|
||||
private void adjustForInsert(int length)
|
||||
{
|
||||
|
Binary file not shown.
@ -0,0 +1,196 @@
|
||||
|
||||
/* ====================================================================
|
||||
Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
contributor license agreements. See the NOTICE file distributed with
|
||||
this work for additional information regarding copyright ownership.
|
||||
The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
(the "License"); you may not use this file except in compliance with
|
||||
the License. You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
==================================================================== */
|
||||
|
||||
package org.apache.poi.hwpf.usermodel;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.FileInputStream;
|
||||
import java.util.List;
|
||||
|
||||
import org.apache.poi.hwpf.HWPFDocument;
|
||||
import org.apache.poi.hwpf.model.PicturesTable;
|
||||
import org.apache.poi.hwpf.usermodel.Picture;
|
||||
|
||||
import junit.framework.TestCase;
|
||||
|
||||
/**
|
||||
* Test to see if Range.delete() works even if the Range contains a
|
||||
* CharacterRun that uses Unicode characters.
|
||||
*/
|
||||
public class TestRangeDelete extends TestCase {
|
||||
|
||||
// u201c and u201d are "smart-quotes"
|
||||
private String originalText =
|
||||
"It is used to confirm that text delete works even if Unicode characters (such as \u201c\u2014\u201d (U+2014), \u201c\u2e8e\u201d (U+2E8E), or \u201c\u2714\u201d (U+2714)) are present. Everybody should be thankful to the ${organization} ${delete} and all the POI contributors for their assistance in this matter.\r";
|
||||
private String searchText = "${delete}";
|
||||
private String expectedText1 = " This is an MS-Word 97 formatted document created using NeoOffice v. 2.2.4 Patch 0 (OpenOffice.org v. 2.2.1).\r";
|
||||
private String expectedText2 =
|
||||
"It is used to confirm that text delete works even if Unicode characters (such as \u201c\u2014\u201d (U+2014), \u201c\u2e8e\u201d (U+2E8E), or \u201c\u2714\u201d (U+2714)) are present. Everybody should be thankful to the ${organization} and all the POI contributors for their assistance in this matter.\r";
|
||||
private String expectedText3 = "Thank you, ${organization} !\r";
|
||||
|
||||
private String illustrativeDocFile;
|
||||
|
||||
protected void setUp() throws Exception {
|
||||
|
||||
String dirname = System.getProperty("HWPF.testdata.path");
|
||||
|
||||
illustrativeDocFile = dirname + "/testRangeDelete.doc";
|
||||
}
|
||||
|
||||
/**
|
||||
* Test just opening the files
|
||||
*/
|
||||
public void testOpen() throws Exception {
|
||||
|
||||
HWPFDocument docA = new HWPFDocument(new FileInputStream(illustrativeDocFile));
|
||||
}
|
||||
|
||||
/**
|
||||
* Test (more "confirm" than test) that we have the general structure that we expect to have.
|
||||
*/
|
||||
public void testDocStructure() throws Exception {
|
||||
|
||||
HWPFDocument daDoc = new HWPFDocument(new FileInputStream(illustrativeDocFile));
|
||||
|
||||
Range range = daDoc.getRange();
|
||||
|
||||
assertEquals(1, range.numSections());
|
||||
Section section = range.getSection(0);
|
||||
|
||||
assertEquals(5, section.numParagraphs());
|
||||
Paragraph para = section.getParagraph(2);
|
||||
|
||||
assertEquals(5, para.numCharacterRuns());
|
||||
|
||||
assertEquals(originalText, para.text());
|
||||
}
|
||||
|
||||
/**
|
||||
* Test that we can delete text (one instance) from our Range with Unicode text.
|
||||
*/
|
||||
public void testRangeDeleteOne() throws Exception {
|
||||
|
||||
HWPFDocument daDoc = new HWPFDocument(new FileInputStream(illustrativeDocFile));
|
||||
|
||||
Range range = daDoc.getRange();
|
||||
assertEquals(1, range.numSections());
|
||||
|
||||
Section section = range.getSection(0);
|
||||
assertEquals(5, section.numParagraphs());
|
||||
|
||||
Paragraph para = section.getParagraph(2);
|
||||
|
||||
String text = para.text();
|
||||
assertEquals(originalText, text);
|
||||
|
||||
int offset = text.indexOf(searchText);
|
||||
assertEquals(192, offset);
|
||||
|
||||
int absOffset = para.getStartOffset() + offset;
|
||||
if (para.usesUnicode())
|
||||
absOffset = para.getStartOffset() + (offset * 2);
|
||||
|
||||
Range subRange = new Range(absOffset, (absOffset + searchText.length()), para.getDocument());
|
||||
if (subRange.usesUnicode())
|
||||
subRange = new Range(absOffset, (absOffset + (searchText.length() * 2)), para.getDocument());
|
||||
|
||||
assertEquals(searchText, subRange.text());
|
||||
|
||||
subRange.delete();
|
||||
|
||||
// we need to let the model re-calculate the Range before we evaluate it
|
||||
range = daDoc.getRange();
|
||||
|
||||
assertEquals(1, range.numSections());
|
||||
section = range.getSection(0);
|
||||
|
||||
assertEquals(5, section.numParagraphs());
|
||||
para = section.getParagraph(2);
|
||||
|
||||
text = para.text();
|
||||
assertEquals(expectedText2, text);
|
||||
|
||||
// this can lead to a StringBufferOutOfBoundsException, so we will add it
|
||||
// even though we don't have an assertion for it
|
||||
Range daRange = daDoc.getRange();
|
||||
daRange.text();
|
||||
}
|
||||
|
||||
/**
|
||||
* Test that we can delete text (all instances of) from our Range with Unicode text.
|
||||
*/
|
||||
public void testRangeDeleteAll() throws Exception {
|
||||
|
||||
HWPFDocument daDoc = new HWPFDocument(new FileInputStream(illustrativeDocFile));
|
||||
|
||||
Range range = daDoc.getRange();
|
||||
assertEquals(1, range.numSections());
|
||||
|
||||
Section section = range.getSection(0);
|
||||
assertEquals(5, section.numParagraphs());
|
||||
|
||||
Paragraph para = section.getParagraph(2);
|
||||
|
||||
String text = para.text();
|
||||
assertEquals(originalText, text);
|
||||
|
||||
boolean keepLooking = true;
|
||||
while (keepLooking) {
|
||||
|
||||
int offset = range.text().indexOf(searchText);
|
||||
if (offset >= 0) {
|
||||
|
||||
int absOffset = range.getStartOffset() + offset;
|
||||
if (range.usesUnicode())
|
||||
absOffset = range.getStartOffset() + (offset * 2);
|
||||
|
||||
Range subRange = new Range(
|
||||
absOffset, (absOffset + searchText.length()), range.getDocument());
|
||||
if (subRange.usesUnicode())
|
||||
subRange = new Range(
|
||||
absOffset, (absOffset + (searchText.length() * 2)), range.getDocument());
|
||||
|
||||
assertEquals(searchText, subRange.text());
|
||||
|
||||
subRange.delete();
|
||||
|
||||
} else
|
||||
keepLooking = false;
|
||||
}
|
||||
|
||||
// we need to let the model re-calculate the Range before we use it
|
||||
range = daDoc.getRange();
|
||||
|
||||
assertEquals(1, range.numSections());
|
||||
section = range.getSection(0);
|
||||
|
||||
assertEquals(5, section.numParagraphs());
|
||||
|
||||
para = section.getParagraph(1);
|
||||
text = para.text();
|
||||
assertEquals(expectedText1, text);
|
||||
|
||||
para = section.getParagraph(2);
|
||||
text = para.text();
|
||||
assertEquals(expectedText2, text);
|
||||
|
||||
para = section.getParagraph(3);
|
||||
text = para.text();
|
||||
assertEquals(expectedText3, text);
|
||||
}
|
||||
}
|
@ -39,8 +39,9 @@ public class TestRangeReplacement extends TestCase {
|
||||
"It is used to confirm that text replacement works even if Unicode characters (such as \u201c\u2014\u201d (U+2014), \u201c\u2e8e\u201d (U+2E8E), or \u201c\u2714\u201d (U+2714)) are present. Everybody should be thankful to the ${organization} and all the POI contributors for their assistance in this matter.\r";
|
||||
private String searchText = "${organization}";
|
||||
private String replacementText = "Apache Software Foundation";
|
||||
private String expectedText =
|
||||
private String expectedText2 =
|
||||
"It is used to confirm that text replacement works even if Unicode characters (such as \u201c\u2014\u201d (U+2014), \u201c\u2e8e\u201d (U+2E8E), or \u201c\u2714\u201d (U+2714)) are present. Everybody should be thankful to the Apache Software Foundation and all the POI contributors for their assistance in this matter.\r";
|
||||
private String expectedText3 = "Thank you, Apache Software Foundation!\r";
|
||||
|
||||
private String illustrativeDocFile;
|
||||
|
||||
@ -84,7 +85,7 @@ public class TestRangeReplacement extends TestCase {
|
||||
/**
|
||||
* Test that we can replace text in our Range with Unicode text.
|
||||
*/
|
||||
public void testRangeReplacement() throws Exception {
|
||||
public void testRangeReplacementOne() throws Exception {
|
||||
|
||||
HWPFDocument daDoc = new HWPFDocument(new FileInputStream(illustrativeDocFile));
|
||||
|
||||
@ -104,16 +105,46 @@ public class TestRangeReplacement extends TestCase {
|
||||
|
||||
para.replaceText(searchText, replacementText, offset);
|
||||
|
||||
// we need to let the model re-calculate the Range before we evaluate it
|
||||
range = daDoc.getRange();
|
||||
|
||||
assertEquals(1, range.numSections());
|
||||
section = range.getSection(0);
|
||||
|
||||
assertEquals(5, section.numParagraphs());
|
||||
assertEquals(4, section.numParagraphs());
|
||||
para = section.getParagraph(2);
|
||||
|
||||
text = para.text();
|
||||
assertEquals(expectedText, text);
|
||||
assertEquals(expectedText2, text);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test that we can replace text in our Range with Unicode text.
|
||||
*/
|
||||
public void testRangeReplacementAll() throws Exception {
|
||||
|
||||
HWPFDocument daDoc = new HWPFDocument(new FileInputStream(illustrativeDocFile));
|
||||
|
||||
Range range = daDoc.getRange();
|
||||
assertEquals(1, range.numSections());
|
||||
|
||||
Section section = range.getSection(0);
|
||||
assertEquals(5, section.numParagraphs());
|
||||
|
||||
Paragraph para = section.getParagraph(2);
|
||||
|
||||
String text = para.text();
|
||||
assertEquals(originalText, text);
|
||||
|
||||
range.replaceText(searchText, replacementText);
|
||||
|
||||
assertEquals(1, range.numSections());
|
||||
section = range.getSection(0);
|
||||
assertEquals(5, section.numParagraphs());
|
||||
|
||||
para = section.getParagraph(2);
|
||||
text = para.text();
|
||||
assertEquals(expectedText2, text);
|
||||
|
||||
para = section.getParagraph(3);
|
||||
text = para.text();
|
||||
assertEquals(expectedText3, text);
|
||||
}
|
||||
}
|
||||
|
BIN
src/testcases/org/apache/poi/hssf/data/3dFormulas.xls
Normal file
BIN
src/testcases/org/apache/poi/hssf/data/3dFormulas.xls
Normal file
Binary file not shown.
Binary file not shown.
BIN
src/testcases/org/apache/poi/hssf/data/MRExtraLines.xls
Normal file
BIN
src/testcases/org/apache/poi/hssf/data/MRExtraLines.xls
Normal file
Binary file not shown.
@ -0,0 +1,160 @@
|
||||
/* ====================================================================
|
||||
Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
contributor license agreements. See the NOTICE file distributed with
|
||||
this work for additional information regarding copyright ownership.
|
||||
The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
(the "License"); you may not use this file except in compliance with
|
||||
the License. You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
==================================================================== */
|
||||
|
||||
package org.apache.poi.hssf.eventusermodel;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import junit.framework.TestCase;
|
||||
|
||||
import org.apache.poi.hssf.HSSFTestDataSamples;
|
||||
import org.apache.poi.hssf.eventusermodel.EventWorkbookBuilder.SheetRecordCollectingListener;
|
||||
import org.apache.poi.hssf.model.FormulaParser;
|
||||
import org.apache.poi.hssf.model.Workbook;
|
||||
import org.apache.poi.hssf.record.FormulaRecord;
|
||||
import org.apache.poi.hssf.record.Record;
|
||||
import org.apache.poi.hssf.record.formula.Ref3DPtg;
|
||||
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
|
||||
import org.apache.poi.hssf.util.SheetReferences;
|
||||
import org.apache.poi.poifs.filesystem.POIFSFileSystem;
|
||||
/**
|
||||
* Tests for {@link EventWorkbookBuilder}
|
||||
*/
|
||||
public final class TestEventWorkbookBuilder extends TestCase {
|
||||
private MockHSSFListener mockListen;
|
||||
private SheetRecordCollectingListener listener;
|
||||
|
||||
public void setUp() {
|
||||
HSSFRequest req = new HSSFRequest();
|
||||
mockListen = new MockHSSFListener();
|
||||
listener = new SheetRecordCollectingListener(mockListen);
|
||||
req.addListenerForAllRecords(listener);
|
||||
|
||||
HSSFEventFactory factory = new HSSFEventFactory();
|
||||
try {
|
||||
InputStream is = HSSFTestDataSamples.openSampleFileStream("3dFormulas.xls");
|
||||
POIFSFileSystem fs = new POIFSFileSystem(is);
|
||||
factory.processWorkbookEvents(req, fs);
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
public void testBasics() throws Exception {
|
||||
assertNotNull(listener.getSSTRecord());
|
||||
assertNotNull(listener.getBoundSheetRecords());
|
||||
assertNotNull(listener.getExternSheetRecords());
|
||||
}
|
||||
|
||||
public void testGetStubWorkbooks() throws Exception {
|
||||
assertNotNull(listener.getStubWorkbook());
|
||||
assertNotNull(listener.getStubHSSFWorkbook());
|
||||
|
||||
assertNotNull(listener.getStubWorkbook().getSheetReferences());
|
||||
assertNotNull(listener.getStubHSSFWorkbook().getSheetReferences());
|
||||
}
|
||||
|
||||
public void testContents() throws Exception {
|
||||
assertEquals(2, listener.getSSTRecord().getNumStrings());
|
||||
assertEquals(3, listener.getBoundSheetRecords().length);
|
||||
assertEquals(1, listener.getExternSheetRecords().length);
|
||||
|
||||
assertEquals(3, listener.getStubWorkbook().getNumSheets());
|
||||
|
||||
SheetReferences ref = listener.getStubWorkbook().getSheetReferences();
|
||||
assertEquals("Sh3", ref.getSheetName(0));
|
||||
assertEquals("Sheet1", ref.getSheetName(1));
|
||||
assertEquals("S2", ref.getSheetName(2));
|
||||
}
|
||||
|
||||
public void testFormulas() throws Exception {
|
||||
FormulaRecord fr;
|
||||
|
||||
// Check our formula records
|
||||
assertEquals(6, mockListen._frecs.size());
|
||||
|
||||
Workbook stubWB = listener.getStubWorkbook();
|
||||
assertNotNull(stubWB);
|
||||
HSSFWorkbook stubHSSF = listener.getStubHSSFWorkbook();
|
||||
assertNotNull(stubHSSF);
|
||||
|
||||
// Check these stubs have the right stuff on them
|
||||
assertEquals("Sheet1", stubWB.getSheetName(0));
|
||||
assertEquals("S2", stubWB.getSheetName(1));
|
||||
assertEquals("Sh3", stubWB.getSheetName(2));
|
||||
|
||||
// Check we can get the formula without breaking
|
||||
for(int i=0; i<mockListen._frecs.size(); i++) {
|
||||
fr = (FormulaRecord)mockListen._frecs.get(i);
|
||||
FormulaParser.toFormulaString(stubHSSF, fr.getParsedExpression());
|
||||
}
|
||||
|
||||
// Peer into just one formula, and check that
|
||||
// all the ptgs give back the right things
|
||||
List ptgs = ((FormulaRecord)mockListen._frecs.get(0)).getParsedExpression();
|
||||
assertEquals(1, ptgs.size());
|
||||
assertTrue(ptgs.get(0) instanceof Ref3DPtg);
|
||||
|
||||
Ref3DPtg ptg = (Ref3DPtg)ptgs.get(0);
|
||||
assertEquals("Sheet1!A1", ptg.toFormulaString(stubHSSF));
|
||||
|
||||
|
||||
// Now check we get the right formula back for
|
||||
// a few sample ones
|
||||
|
||||
// Sheet 1 A2 is on same sheet
|
||||
fr = (FormulaRecord)mockListen._frecs.get(0);
|
||||
assertEquals(1, fr.getRow());
|
||||
assertEquals(0, fr.getColumn());
|
||||
assertEquals("Sheet1!A1", FormulaParser.toFormulaString(stubHSSF, fr.getParsedExpression()));
|
||||
|
||||
// Sheet 1 A5 is to another sheet
|
||||
fr = (FormulaRecord)mockListen._frecs.get(3);
|
||||
assertEquals(4, fr.getRow());
|
||||
assertEquals(0, fr.getColumn());
|
||||
assertEquals("'S2'!A1", FormulaParser.toFormulaString(stubHSSF, fr.getParsedExpression()));
|
||||
|
||||
// Sheet 1 A7 is to another sheet, range
|
||||
fr = (FormulaRecord)mockListen._frecs.get(5);
|
||||
assertEquals(6, fr.getRow());
|
||||
assertEquals(0, fr.getColumn());
|
||||
assertEquals("SUM('Sh3'!A1:A4)", FormulaParser.toFormulaString(stubHSSF, fr.getParsedExpression()));
|
||||
|
||||
|
||||
// Now, load via Usermodel and re-check
|
||||
InputStream is = HSSFTestDataSamples.openSampleFileStream("3dFormulas.xls");
|
||||
POIFSFileSystem fs = new POIFSFileSystem(is);
|
||||
HSSFWorkbook wb = new HSSFWorkbook(fs);
|
||||
assertEquals("Sheet1!A1", wb.getSheetAt(0).getRow(1).getCell(0).getCellFormula());
|
||||
assertEquals("SUM('Sh3'!A1:A4)", wb.getSheetAt(0).getRow(6).getCell(0).getCellFormula());
|
||||
}
|
||||
|
||||
private static final class MockHSSFListener implements HSSFListener {
|
||||
public MockHSSFListener() {}
|
||||
private final List _records = new ArrayList();
|
||||
private final List _frecs = new ArrayList();
|
||||
|
||||
public void processRecord(Record record) {
|
||||
_records.add(record);
|
||||
if(record instanceof FormulaRecord) {
|
||||
_frecs.add(record);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -16,8 +16,6 @@
|
||||
==================================================================== */
|
||||
|
||||
package org.apache.poi.hssf.eventusermodel;
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.util.ArrayList;
|
||||
@ -29,6 +27,7 @@ import org.apache.poi.hssf.HSSFTestDataSamples;
|
||||
import org.apache.poi.hssf.eventusermodel.dummyrecord.LastCellOfRowDummyRecord;
|
||||
import org.apache.poi.hssf.eventusermodel.dummyrecord.MissingCellDummyRecord;
|
||||
import org.apache.poi.hssf.eventusermodel.dummyrecord.MissingRowDummyRecord;
|
||||
import org.apache.poi.hssf.record.BOFRecord;
|
||||
import org.apache.poi.hssf.record.LabelSSTRecord;
|
||||
import org.apache.poi.hssf.record.Record;
|
||||
import org.apache.poi.hssf.record.RowRecord;
|
||||
@ -40,8 +39,7 @@ public final class TestMissingRecordAwareHSSFListener extends TestCase {
|
||||
|
||||
private Record[] r;
|
||||
|
||||
public void setUp() {
|
||||
|
||||
public void openNormal() {
|
||||
HSSFRequest req = new HSSFRequest();
|
||||
MockHSSFListener mockListen = new MockHSSFListener();
|
||||
MissingRecordAwareHSSFListener listener = new MissingRecordAwareHSSFListener(mockListen);
|
||||
@ -55,10 +53,31 @@ public final class TestMissingRecordAwareHSSFListener extends TestCase {
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
|
||||
r = mockListen.getRecords();
|
||||
assertTrue(r.length > 100);
|
||||
}
|
||||
public void openAlt() {
|
||||
HSSFRequest req = new HSSFRequest();
|
||||
MockHSSFListener mockListen = new MockHSSFListener();
|
||||
MissingRecordAwareHSSFListener listener = new MissingRecordAwareHSSFListener(mockListen);
|
||||
req.addListenerForAllRecords(listener);
|
||||
|
||||
HSSFEventFactory factory = new HSSFEventFactory();
|
||||
try {
|
||||
InputStream is = HSSFTestDataSamples.openSampleFileStream("MRExtraLines.xls");
|
||||
POIFSFileSystem fs = new POIFSFileSystem(is);
|
||||
factory.processWorkbookEvents(req, fs);
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
|
||||
r = mockListen.getRecords();
|
||||
assertTrue(r.length > 100);
|
||||
}
|
||||
|
||||
public void testMissingRowRecords() throws Exception {
|
||||
openNormal();
|
||||
|
||||
// We have rows 0, 1, 2, 20 and 21
|
||||
int row0 = -1;
|
||||
@ -108,6 +127,7 @@ public final class TestMissingRecordAwareHSSFListener extends TestCase {
|
||||
}
|
||||
|
||||
public void testEndOfRowRecords() throws Exception {
|
||||
openNormal();
|
||||
|
||||
// Find the cell at 0,0
|
||||
int cell00 = -1;
|
||||
@ -194,7 +214,7 @@ public final class TestMissingRecordAwareHSSFListener extends TestCase {
|
||||
assertTrue(r[cell00+57] instanceof LastCellOfRowDummyRecord);
|
||||
|
||||
// Check the numbers of the last seen columns
|
||||
LastCellOfRowDummyRecord[] lrs = new LastCellOfRowDummyRecord[23];
|
||||
LastCellOfRowDummyRecord[] lrs = new LastCellOfRowDummyRecord[24];
|
||||
int lrscount = 0;
|
||||
for(int i=0; i<r.length; i++) {
|
||||
if(r[i] instanceof LastCellOfRowDummyRecord) {
|
||||
@ -229,6 +249,7 @@ public final class TestMissingRecordAwareHSSFListener extends TestCase {
|
||||
|
||||
|
||||
public void testMissingCellRecords() throws Exception {
|
||||
openNormal();
|
||||
|
||||
// Find the cell at 0,0
|
||||
int cell00 = -1;
|
||||
@ -327,9 +348,37 @@ public final class TestMissingRecordAwareHSSFListener extends TestCase {
|
||||
assertEquals(10, mc.getColumn());
|
||||
}
|
||||
|
||||
// Make sure we don't put in any extra new lines
|
||||
// that aren't already there
|
||||
public void testNoExtraNewLines() throws Exception {
|
||||
// Load a different file
|
||||
openAlt();
|
||||
|
||||
|
||||
// This file has has something in lines 1-33
|
||||
List lcor = new ArrayList();
|
||||
for(int i=0; i<r.length; i++) {
|
||||
if(r[i] instanceof LastCellOfRowDummyRecord)
|
||||
lcor.add( (LastCellOfRowDummyRecord)r[i] );
|
||||
}
|
||||
|
||||
// Check we got the 33 rows
|
||||
assertEquals(33, lcor.size());
|
||||
LastCellOfRowDummyRecord[] rowEnds = (LastCellOfRowDummyRecord[])
|
||||
lcor.toArray(new LastCellOfRowDummyRecord[lcor.size()]);
|
||||
assertEquals(33, rowEnds.length);
|
||||
|
||||
// And check they have the right stuff in them,
|
||||
// no repeats
|
||||
for(int i=0; i<rowEnds.length; i++) {
|
||||
assertEquals(i, rowEnds[i].getRow());
|
||||
}
|
||||
}
|
||||
|
||||
private static final class MockHSSFListener implements HSSFListener {
|
||||
public MockHSSFListener() {}
|
||||
private final List _records = new ArrayList();
|
||||
private boolean logToStdOut = false;
|
||||
|
||||
public void processRecord(Record record) {
|
||||
_records.add(record);
|
||||
@ -346,9 +395,20 @@ public final class TestMissingRecordAwareHSSFListener extends TestCase {
|
||||
LastCellOfRowDummyRecord lc = (LastCellOfRowDummyRecord)record;
|
||||
log("Got end-of row, row was " + lc.getRow() + ", last column was " + lc.getLastColumnNumber());
|
||||
}
|
||||
|
||||
if(record instanceof BOFRecord) {
|
||||
BOFRecord r = (BOFRecord)record;
|
||||
if(r.getType() == BOFRecord.TYPE_WORKSHEET) {
|
||||
log("On new sheet");
|
||||
}
|
||||
}
|
||||
if(record instanceof RowRecord) {
|
||||
RowRecord rr = (RowRecord)record;
|
||||
log("Starting row #" + rr.getRowNumber());
|
||||
}
|
||||
}
|
||||
private static void log(String msg) {
|
||||
if(false) { // successful tests should be quiet
|
||||
private void log(String msg) {
|
||||
if(logToStdOut) {
|
||||
System.out.println(msg);
|
||||
}
|
||||
}
|
||||
|
@ -759,7 +759,7 @@ public final class TestFormulaParser extends TestCase {
|
||||
}
|
||||
}
|
||||
|
||||
public void testParseErrorExpecteMsg() {
|
||||
public void testParseErrorExpectedMsg() {
|
||||
|
||||
try {
|
||||
parseFormula("round(3.14;2)");
|
||||
@ -768,4 +768,27 @@ public final class TestFormulaParser extends TestCase {
|
||||
assertEquals("Parse error near char 10 ';' in specified formula 'round(3.14;2)'. Expected ',' or ')'", e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* this function name has a dot in it.
|
||||
*/
|
||||
public void testParseErrorTypeFunction() {
|
||||
|
||||
Ptg[] ptgs;
|
||||
try {
|
||||
ptgs = parseFormula("error.type(A1)");
|
||||
|
||||
|
||||
} catch (IllegalArgumentException e) {
|
||||
if (e.getMessage().equals("Invalid Formula cell reference: 'error'")) {
|
||||
throw new AssertionFailedError("Identified bug 45334");
|
||||
}
|
||||
throw e;
|
||||
}
|
||||
assertEquals(2, ptgs.length);
|
||||
assertEquals(FuncPtg.class, ptgs[1].getClass());
|
||||
FuncPtg funcPtg = (FuncPtg) ptgs[1];
|
||||
assertEquals("ERROR.TYPE", funcPtg.getName());
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -1052,4 +1052,88 @@ public final class TestBugs extends TestCase {
|
||||
assertTrue(nd.get(0) instanceof DeletedArea3DPtg);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Test that fonts get added properly
|
||||
*/
|
||||
public void test45338() throws Exception {
|
||||
HSSFWorkbook wb = new HSSFWorkbook();
|
||||
assertEquals(4, wb.getNumberOfFonts());
|
||||
|
||||
HSSFSheet s = wb.createSheet();
|
||||
s.createRow(0);
|
||||
s.createRow(1);
|
||||
HSSFCell c1 = s.getRow(0).createCell((short)0);
|
||||
HSSFCell c2 = s.getRow(1).createCell((short)0);
|
||||
|
||||
assertEquals(4, wb.getNumberOfFonts());
|
||||
|
||||
HSSFFont f1 = wb.getFontAt((short)0);
|
||||
assertEquals(400, f1.getBoldweight());
|
||||
|
||||
// Check that asking for the same font
|
||||
// multiple times gives you the same thing.
|
||||
// Otherwise, our tests wouldn't work!
|
||||
assertEquals(
|
||||
wb.getFontAt((short)0),
|
||||
wb.getFontAt((short)0)
|
||||
);
|
||||
assertEquals(
|
||||
wb.getFontAt((short)2),
|
||||
wb.getFontAt((short)2)
|
||||
);
|
||||
assertTrue(
|
||||
wb.getFontAt((short)0)
|
||||
!=
|
||||
wb.getFontAt((short)2)
|
||||
);
|
||||
|
||||
// Look for a new font we have
|
||||
// yet to add
|
||||
assertNull(
|
||||
wb.findFont(
|
||||
(short)11, (short)123, (short)22,
|
||||
"Thingy", false, true, (short)2, (byte)2
|
||||
)
|
||||
);
|
||||
|
||||
HSSFFont nf = wb.createFont();
|
||||
assertEquals(5, wb.getNumberOfFonts());
|
||||
|
||||
assertEquals(5, nf.getIndex());
|
||||
assertEquals(nf, wb.getFontAt((short)5));
|
||||
|
||||
nf.setBoldweight((short)11);
|
||||
nf.setColor((short)123);
|
||||
nf.setFontHeight((short)22);
|
||||
nf.setFontName("Thingy");
|
||||
nf.setItalic(false);
|
||||
nf.setStrikeout(true);
|
||||
nf.setTypeOffset((short)2);
|
||||
nf.setUnderline((byte)2);
|
||||
|
||||
assertEquals(5, wb.getNumberOfFonts());
|
||||
assertEquals(nf, wb.getFontAt((short)5));
|
||||
|
||||
// Find it now
|
||||
assertNotNull(
|
||||
wb.findFont(
|
||||
(short)11, (short)123, (short)22,
|
||||
"Thingy", false, true, (short)2, (byte)2
|
||||
)
|
||||
);
|
||||
assertEquals(
|
||||
5,
|
||||
wb.findFont(
|
||||
(short)11, (short)123, (short)22,
|
||||
"Thingy", false, true, (short)2, (byte)2
|
||||
).getIndex()
|
||||
);
|
||||
assertEquals(nf,
|
||||
wb.findFont(
|
||||
(short)11, (short)123, (short)22,
|
||||
"Thingy", false, true, (short)2, (byte)2
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
52
src/testcases/org/apache/poi/hssf/util/TestHSSFColor.java
Normal file
52
src/testcases/org/apache/poi/hssf/util/TestHSSFColor.java
Normal file
@ -0,0 +1,52 @@
|
||||
/* ====================================================================
|
||||
Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
contributor license agreements. See the NOTICE file distributed with
|
||||
this work for additional information regarding copyright ownership.
|
||||
The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
(the "License"); you may not use this file except in compliance with
|
||||
the License. You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
==================================================================== */
|
||||
|
||||
package org.apache.poi.hssf.util;
|
||||
|
||||
import java.util.Hashtable;
|
||||
|
||||
import junit.framework.TestCase;
|
||||
|
||||
public final class TestHSSFColor extends TestCase {
|
||||
public void testBasics() {
|
||||
assertNotNull(HSSFColor.YELLOW.class);
|
||||
assertTrue(HSSFColor.YELLOW.index > 0);
|
||||
assertTrue(HSSFColor.YELLOW.index2 > 0);
|
||||
}
|
||||
|
||||
public void testContents() {
|
||||
assertEquals(3, HSSFColor.YELLOW.triplet.length);
|
||||
assertEquals(255, HSSFColor.YELLOW.triplet[0]);
|
||||
assertEquals(255, HSSFColor.YELLOW.triplet[1]);
|
||||
assertEquals(0, HSSFColor.YELLOW.triplet[2]);
|
||||
|
||||
assertEquals("FFFF:FFFF:0", HSSFColor.YELLOW.hexString);
|
||||
}
|
||||
|
||||
public void testTrippletHash() {
|
||||
Hashtable tripplets = HSSFColor.getTripletHash();
|
||||
|
||||
assertEquals(
|
||||
HSSFColor.MAROON.class,
|
||||
tripplets.get(HSSFColor.MAROON.hexString).getClass()
|
||||
);
|
||||
assertEquals(
|
||||
HSSFColor.YELLOW.class,
|
||||
tripplets.get(HSSFColor.YELLOW.hexString).getClass()
|
||||
);
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user