merge BETA3 with trunk r615229. OOXML is excluded
git-svn-id: https://svn.apache.org/repos/asf/poi/tags/REL_3_0_2_BETA3@615249 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
parent
63f92098a3
commit
7cd05f9a2a
16
build.xml
16
build.xml
|
@ -137,7 +137,7 @@ under the License.
|
|||
<property name="ooxml.jar4.dir" location="${ooxml.lib}/jsr173_1.0_api.jar"/>
|
||||
<property name="ooxml.jar4.url" value="${repository}/xmlbeans/jars/jsr173_1.0_api.jar"/>
|
||||
<!-- No official release of openxml4j yet -->
|
||||
<property name="ooxml.jar5.dir" location="${ooxml.lib}/openxml4j-bin-prealpha-071224.jar"/>
|
||||
<property name="ooxml.jar5.dir" location="${ooxml.lib}/openxml4j-bin-alpha-080124.jar"/>
|
||||
<property name="ooxml.jar5.url" value="http://people.apache.org/~nick/openxml4j-bin-prealpha-071224.jar"/>
|
||||
|
||||
<!-- See http://www.ecma-international.org/publications/standards/Ecma-376.htm -->
|
||||
|
@ -159,7 +159,7 @@ under the License.
|
|||
<property name="mavendist.poi.dir" location="build/maven-dist/poi"/>
|
||||
<property name="mavendist.oap.dir" location="build/maven-dist/org.apache.poi"/>
|
||||
<property name="jar.name" value="poi"/>
|
||||
<property name="version.id" value="3.0.2-beta2"/>
|
||||
<property name="version.id" value="3.0.2-FINAL"/>
|
||||
<property name="halt.on.test.failure" value="true"/>
|
||||
<property name="jdk.version.source" value="1.3"
|
||||
description="JDK version of source code"/>
|
||||
|
@ -368,6 +368,8 @@ under the License.
|
|||
destfile="${ooxml.xsds.jar}"
|
||||
javasource="1.4"
|
||||
failonerror="false"
|
||||
fork="true"
|
||||
memoryMaximumSize="512m"
|
||||
>
|
||||
<classpath refid="ooxml.classpath"/>
|
||||
</xmlbean>
|
||||
|
@ -461,6 +463,16 @@ under the License.
|
|||
destdir="${ooxml.output.dir}" debug="on" srcdir="${ooxml.src}">
|
||||
<classpath refid="ooxml.classpath"/>
|
||||
</javac>
|
||||
|
||||
<javac target="1.5" source="1.5"
|
||||
failonerror="true" destdir="${ooxml.output.test.dir}" debug="on"
|
||||
fork="yes" srcdir="${ooxml.src.test}">
|
||||
<classpath>
|
||||
<path refid="ooxml.classpath"/>
|
||||
<pathelement location="${ooxml.output.dir}"/>
|
||||
<pathelement location="${junit.jar1.dir}"/>
|
||||
</classpath>
|
||||
</javac>
|
||||
</target>
|
||||
|
||||
<target name="test" depends="test-main,test-scratchpad,test-contrib"
|
||||
|
|
|
@ -36,6 +36,27 @@
|
|||
|
||||
<!-- Don't forget to update status.xml too! -->
|
||||
<release version="3.0.2-FINAL" date="2008-??-??">
|
||||
<action dev="POI-DEVELOPERS" type="fix">44292 - Correctly process the last paragraph in a word file</action>
|
||||
<action dev="POI-DEVELOPERS" type="fix">44254 - Avoid some unread byte warnings, and properly understand DVALRecord</action>
|
||||
<action dev="POI-DEVELOPERS" type="add">Add another formula evaluation method, evaluateFormulaCell(cell), which will re-calculate the value for a formula, without affecting the formula itself.</action>
|
||||
<action dev="POI-DEVELOPERS" type="fix">41726 - Fix how we handle signed cell offsets in relative areas and references</action>
|
||||
<action dev="POI-DEVELOPERS" type="add">44233 - Support for getting and setting a flag on the sheet, which tells excel to re-calculate all formulas on it at next reload</action>
|
||||
<action dev="POI-DEVELOPERS" type="fix">44201 - Enable cloning of sheets with data validation rules</action>
|
||||
<action dev="POI-DEVELOPERS" type="fix">44200 - Enable cloning of sheets with notes</action>
|
||||
<action dev="POI-DEVELOPERS" type="add">43008 - Add a moveCell method to HSSFRow, and deprecate setCellNum(), which didn't update things properly</action>
|
||||
<action dev="POI-DEVELOPERS" type="fix">43058 - Support setting row grouping on files from CR IX, which lack GutsRecords</action>
|
||||
<action dev="POI-DEVELOPERS" type="fix">31795 - Support cloning of sheets with certain drawing objects on them</action>
|
||||
<action dev="POI-DEVELOPERS" type="fix">43902 - Don't consider merged regions when auto-sizing columns</action>
|
||||
<action dev="POI-DEVELOPERS" type="fix">42464 - Avoid "Expected ExpPtg to be converted from Shared to Non-Shared Formula" on large, formula heavy worksheets</action>
|
||||
<action dev="POI-DEVELOPERS" type="add">42033 - Add support for named ranges with unicode names</action>
|
||||
<action dev="POI-DEVELOPERS" type="add">34023 - When shifting rows, update formulas on that sheet to point to the new location of those rows</action>
|
||||
<action dev="POI-DEVELOPERS" type="add">Support getting all the cells referenced by an AreaReference, not just the corner ones</action>
|
||||
<action dev="POI-DEVELOPERS" type="add">43510 - Add support for named ranges in formulas, including non-contiguous named ranges</action>
|
||||
<action dev="POI-DEVELOPERS" type="add">43937 - Add support for hiding and un-hiding sheets, and checking their current hidden status</action>
|
||||
<action dev="POI-DEVELOPERS" type="fix">44167 - Fix for non-contiguous named ranges</action>
|
||||
<action dev="POI-DEVELOPERS" type="fix">44070 - Fix for shifting comments when shifting rows</action>
|
||||
</release>
|
||||
<release version="3.0.2-BETA2" date="2008-01-12">
|
||||
<action dev="POI-DEVELOPERS" type="add">Support for tables in HSLF</action>
|
||||
<action dev="POI-DEVELOPERS" type="fix">43781 - Fix for extracting text from TextBoxes HSLF in</action>
|
||||
<action dev="POI-DEVELOPERS" type="fix">Improve JavaDocs relating to hssf font and fill colourings</action>
|
||||
|
@ -45,7 +66,6 @@
|
|||
<action dev="POI-DEVELOPERS" type="add">41064 - [PATCH] Support for String continue records</action>
|
||||
<action dev="POI-DEVELOPERS" type="add">27511 - [PATCH] Support for data validation, via DVRecord and DVALRecord</action>
|
||||
</release>
|
||||
|
||||
<release version="3.0.2-BETA1" date="2007-12-04">
|
||||
<action dev="POI-DEVELOPERS" type="fix">43877 and 39512 - Fix for handling mixed OBJ and CONTINUE records.</action>
|
||||
<action dev="POI-DEVELOPERS" type="fix">43807 - Throw an IllegalArgumentException if asked to create a merged region with invalid columns or rows, rather than writing out a corrupt file</action>
|
||||
|
|
|
@ -32,14 +32,18 @@
|
|||
formulas in Excels sheets read-in, or created in POI. This document explains
|
||||
how to use the API to evaluate your formulas.
|
||||
</p>
|
||||
<note> This code currently lives the scratchpad area of the POI CVS repository.
|
||||
<note> This code currently lives the scratchpad area of the POI SVN repository.
|
||||
Ensure that you have the scratchpad jar or the scratchpad build area in your
|
||||
classpath before experimenting with this code.
|
||||
classpath before experimenting with this code. You are advised
|
||||
to make use of a recent SVN checkout, as new functions are
|
||||
being supported fairly frequently.
|
||||
</note>
|
||||
</section>
|
||||
|
||||
<anchor id="Status"/>
|
||||
<section><title>Status</title>
|
||||
<p> The code currently provides implementations for all the arithmatic operators.
|
||||
It also provides implementations for approx. 20 built in
|
||||
It also provides implementations for approx. 100 built in
|
||||
functions in Excel. The framework however makes is easy to add
|
||||
implementation of new functions. See the <link href="eval-devguide.html"> Formula
|
||||
evaluation development guide</link> for details. </p>
|
||||
|
@ -51,8 +55,12 @@
|
|||
<p>The following code demonstrates how to use the HSSFFormulaEvaluator
|
||||
in the context of other POI excel reading code.
|
||||
</p>
|
||||
<p>There are two ways in which you can use the HSSFFormulaEvalutator API.</p>
|
||||
<p>There are several ways in which you can use the HSSFFormulaEvalutator API.</p>
|
||||
|
||||
<anchor id="Evaluate"/>
|
||||
<section><title>Using HSSFFormulaEvaluator.<strong>evaluate</strong>(HSSFCell cell)</title>
|
||||
<p>This evaluates a given cell, and returns the new value,
|
||||
without affecting the cell</p>
|
||||
<source>
|
||||
FileInputStream fis = new FileInputStream("c:/temp/test.xls");
|
||||
HSSFWorkbook wb = new HSSFWorkbook(fis);
|
||||
|
@ -94,10 +102,62 @@ switch (cellValue.getCellType()) {
|
|||
a simple value object and does not maintain reference
|
||||
to the original cell.
|
||||
</p>
|
||||
|
||||
</section>
|
||||
<section><title>Using HSSFFormulaEvaluator.<strong>evaluateInCell</strong>(HSSFCell cell)
|
||||
</title>
|
||||
|
||||
<anchor id="EvaluateFormulaCell"/>
|
||||
<section><title>Using HSSFFormulaEvaluator.<strong>evaluateFormulaCell</strong>(HSSFCell cell)</title>
|
||||
<p><strong>evaluateFormulaCell</strong>(HSSFCell cell)
|
||||
will check to see if the supplied cell is a formula cell.
|
||||
If it isn't, then no changes will be made to it. If it is,
|
||||
then the formula is evaluated. The value for the formula
|
||||
is saved alongside it, to be displayed in excel. The
|
||||
formula remains in the cell, just with a new value</p>
|
||||
<p>The return of the function is the type of the
|
||||
formula result, such as HSSFCell.CELL_TYPE_BOOLEAN</p>
|
||||
<source>
|
||||
FileInputStream fis = new FileInputStream("/somepath/test.xls");
|
||||
HSSFWorkbook wb = new HSSFWorkbook(fis);
|
||||
HSSFSheet sheet = wb.getSheetAt(0);
|
||||
HSSFFormulaEvaluator evaluator = new HSSFFormulaEvaluator(sheet, wb);
|
||||
|
||||
// suppose your formula is in B3
|
||||
CellReference cellReference = new CellReference("B3");
|
||||
HSSFRow row = sheet.getRow(cellReference.getRow());
|
||||
HSSFCell cell = row.getCell(cellReference.getCol());
|
||||
evaluator.setCurrentRow(row);
|
||||
|
||||
if (cell!=null) {
|
||||
switch (<strong>evaluator.evaluateFormulaCell</strong>(cell)) {
|
||||
case HSSFCell.CELL_TYPE_BOOLEAN:
|
||||
System.out.println(cell.getBooleanCellValue());
|
||||
break;
|
||||
case HSSFCell.CELL_TYPE_NUMERIC:
|
||||
System.out.println(cell.getNumberCellValue());
|
||||
break;
|
||||
case HSSFCell.CELL_TYPE_STRING:
|
||||
System.out.println(cell.getStringCellValue());
|
||||
break;
|
||||
case HSSFCell.CELL_TYPE_BLANK:
|
||||
break;
|
||||
case HSSFCell.CELL_TYPE_ERROR:
|
||||
System.out.println(cell.getErrorCellValue());
|
||||
break;
|
||||
|
||||
// CELL_TYPE_FORMULA will never occur
|
||||
case HSSFCell.CELL_TYPE_FORMULA:
|
||||
break;
|
||||
}
|
||||
}
|
||||
</source>
|
||||
</section>
|
||||
|
||||
<anchor id="EvaluateInCell"/>
|
||||
<section><title>Using HSSFFormulaEvaluator.<strong>evaluateInCell</strong>(HSSFCell cell)</title>
|
||||
<p><strong>evaluateInCell</strong>(HSSFCell cell) will check to
|
||||
see if the supplied cell is a formula cell. If it isn't,
|
||||
then no changes will be made to it. If it is, then the
|
||||
formula is evaluated, and the new value saved into the cell,
|
||||
in place of the old formula.</p>
|
||||
<source>
|
||||
FileInputStream fis = new FileInputStream("/somepath/test.xls");
|
||||
HSSFWorkbook wb = new HSSFWorkbook(fis);
|
||||
|
@ -132,11 +192,36 @@ if (cell!=null) {
|
|||
break;
|
||||
}
|
||||
}
|
||||
</source>
|
||||
</source>
|
||||
</section>
|
||||
|
||||
</section>
|
||||
<anchor id="EvaluateAll"/>
|
||||
<section><title>Re-calculating all formulas in a Workbook</title>
|
||||
<source>
|
||||
FileInputStream fis = new FileInputStream("/somepath/test.xls");
|
||||
HSSFWorkbook wb = new HSSFWorkbook(fis);
|
||||
for(int sheetNum = 0; sheetNum < wb.getNumberOfSheets(); sheetNum++) {
|
||||
HSSFSheet sheet = wb.getSheetAt(sheetNum);
|
||||
HSSFFormulaEvaluator evaluator = new HSSFFormulaEvaluator(sheet, wb);
|
||||
|
||||
for(Iterator rit = sheet.rowIterator(); rit.hasNext();) {
|
||||
HSSFRow r = (HSSFRow)rit.next();
|
||||
evaluator.setCurrentRow(r);
|
||||
|
||||
for(Iterator cit = r.cellIterator(); cit.hasNext();) {
|
||||
HSSFCell c = (HSSFCell)cit.next();
|
||||
if(c.getCellType() == HSSFCell.CELL_TYPE_FORMULA) {
|
||||
evaluator.evaluateFormulaCell(c);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
wb.write(new FileOutputStream("/somepath/changed.xls"));
|
||||
</source>
|
||||
</section>
|
||||
</section>
|
||||
|
||||
<anchor id="Performance"/>
|
||||
<section><title>Performance Notes</title>
|
||||
<ul>
|
||||
<li>Generally you should have to create only one HSSFFormulaEvaluator
|
||||
|
|
|
@ -1151,7 +1151,7 @@ Examples:
|
|||
|
||||
// retrieve the cell at the named range and test its contents
|
||||
AreaReference aref = new AreaReference(aNamedCell.getReference());
|
||||
CellReference[] crefs = aref.getCells();
|
||||
CellReference[] crefs = aref.getAllReferencedCells();
|
||||
for (int i=0; i<crefs.length; i++) {
|
||||
HSSFSheet s = wb.getSheet(crefs[i].getSheetName());
|
||||
HSSFRow r = sheet.getRow(crefs[i].getRow());
|
||||
|
@ -1159,7 +1159,36 @@ Examples:
|
|||
// extract the cell contents based on cell type etc.
|
||||
}
|
||||
</source>
|
||||
<p>
|
||||
Reading from non-contiguous Named Ranges
|
||||
</p>
|
||||
<source>
|
||||
// Setup code
|
||||
String cname = "TestName";
|
||||
HSSFWorkbook wb = getMyWorkbook(); // retrieve workbook
|
||||
|
||||
// Retrieve the named range
|
||||
// Will be something like "$C$10,$D$12:$D$14";
|
||||
int namedCellIdx = wb.getNameIndex(cellName);
|
||||
HSSFName aNamedCell = wb.getNameAt(namedCellIdx);
|
||||
|
||||
// Retrieve the cell at the named range and test its contents
|
||||
// Will get back one AreaReference for C10, and
|
||||
// another for D12 to D14
|
||||
AreaReference[] arefs = AreaReference.generateContiguous(aNamedCell.getReference());
|
||||
for (int i=0; i<arefs.length; i++) {
|
||||
// Only get the corners of the Area
|
||||
// (use arefs[i].getAllReferencedCells() to get all cells)
|
||||
CellReference[] crefs = arefs[i].getCells();
|
||||
for (int j=0; j<crefs.length; j++) {
|
||||
// Check it turns into real stuff
|
||||
HSSFSheet s = wb.getSheet(crefs[j].getSheetName());
|
||||
HSSFRow r = s.getRow(crefs[j].getRow());
|
||||
HSSFCell c = r.getCell(crefs[j].getCol());
|
||||
// Do something with this corner cell
|
||||
}
|
||||
}
|
||||
</source>
|
||||
</section>
|
||||
<anchor id="CellComments"/>
|
||||
<section><title>Cell Comments</title>
|
||||
|
|
|
@ -31,14 +31,14 @@
|
|||
</header>
|
||||
|
||||
<body>
|
||||
<section><title>POI 3.0.2 BETA1 Release</title>
|
||||
<p>The latest release of Apache POI is 3.0.2 BETA1 which was promoted to "Beta" on 04 December 2007. It contains a mixture of
|
||||
<section><title>POI 3.0.2 BETA2 Release</title>
|
||||
<p>The latest release of Apache POI is 3.0.2 BETA2 which was promoted to "Beta" on 12 January 2008. It contains a mixture of
|
||||
new features and bug fixes, compared to 3.0.1. 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>
|
||||
<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/release/">local mirror</link>.
|
||||
<link href="http://www.apache.org/dyn/closer.cgi/poi/dev/">local mirror</link>.
|
||||
The release is also available from the central Maven repository under Group ID "org.apache.poi".
|
||||
</p>
|
||||
</section>
|
||||
|
|
|
@ -33,6 +33,27 @@
|
|||
<!-- Don't forget to update changes.xml too! -->
|
||||
<changes>
|
||||
<release version="3.0.2-FINAL" date="2008-??-??">
|
||||
<action dev="POI-DEVELOPERS" type="fix">44292 - Correctly process the last paragraph in a word file</action>
|
||||
<action dev="POI-DEVELOPERS" type="fix">44254 - Avoid some unread byte warnings, and properly understand DVALRecord</action>
|
||||
<action dev="POI-DEVELOPERS" type="add">Add another formula evaluation method, evaluateFormulaCell(cell), which will re-calculate the value for a formula, without affecting the formula itself.</action>
|
||||
<action dev="POI-DEVELOPERS" type="fix">41726 - Fix how we handle signed cell offsets in relative areas and references</action>
|
||||
<action dev="POI-DEVELOPERS" type="add">44233 - Support for getting and setting a flag on the sheet, which tells excel to re-calculate all formulas on it at next reload</action>
|
||||
<action dev="POI-DEVELOPERS" type="fix">44201 - Enable cloning of sheets with data validation rules</action>
|
||||
<action dev="POI-DEVELOPERS" type="fix">44200 - Enable cloning of sheets with notes</action>
|
||||
<action dev="POI-DEVELOPERS" type="add">43008 - Add a moveCell method to HSSFRow, and deprecate setCellNum(), which didn't update things properly</action>
|
||||
<action dev="POI-DEVELOPERS" type="fix">43058 - Support setting row grouping on files from CR IX, which lack GutsRecords</action>
|
||||
<action dev="POI-DEVELOPERS" type="fix">31795 - Support cloning of sheets with certain drawing objects on them</action>
|
||||
<action dev="POI-DEVELOPERS" type="fix">43902 - Don't consider merged regions when auto-sizing columns</action>
|
||||
<action dev="POI-DEVELOPERS" type="fix">42464 - Avoid "Expected ExpPtg to be converted from Shared to Non-Shared Formula" on large, formula heavy worksheets</action>
|
||||
<action dev="POI-DEVELOPERS" type="add">42033 - Add support for named ranges with unicode names</action>
|
||||
<action dev="POI-DEVELOPERS" type="add">34023 - When shifting rows, update formulas on that sheet to point to the new location of those rows</action>
|
||||
<action dev="POI-DEVELOPERS" type="add">Support getting all the cells referenced by an AreaReference, not just the corner ones</action>
|
||||
<action dev="POI-DEVELOPERS" type="add">43510 - Add support for named ranges in formulas, including non-contiguous named ranges</action>
|
||||
<action dev="POI-DEVELOPERS" type="add">43937 - Add support for hiding and un-hiding sheets, and checking their current hidden status</action>
|
||||
<action dev="POI-DEVELOPERS" type="fix">44167 - Fix for non-contiguous named ranges</action>
|
||||
<action dev="POI-DEVELOPERS" type="fix">44070 - Fix for shifting comments when shifting rows</action>
|
||||
</release>
|
||||
<release version="3.0.2-BETA2" date="2008-01-12">
|
||||
<action dev="POI-DEVELOPERS" type="add">Support for tables in HSLF</action>
|
||||
<action dev="POI-DEVELOPERS" type="fix">43781 - Fix for extracting text from TextBoxes HSLF in</action>
|
||||
<action dev="POI-DEVELOPERS" type="fix">Improve JavaDocs relating to hssf font and fill colourings</action>
|
||||
|
|
|
@ -101,11 +101,47 @@ public class EscherContainerRecord extends EscherRecord
|
|||
return 8 + childRecordsSize;
|
||||
}
|
||||
|
||||
/**
|
||||
* Do any of our (top level) children have the
|
||||
* given recordId?
|
||||
*/
|
||||
public boolean hasChildOfType(short recordId) {
|
||||
for ( Iterator iterator = getChildRecords().iterator(); iterator.hasNext(); )
|
||||
{
|
||||
EscherRecord r = (EscherRecord) iterator.next();
|
||||
if(r.getRecordId() == recordId) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a list of all the child (escher) records
|
||||
* of the container.
|
||||
*/
|
||||
public List getChildRecords()
|
||||
{
|
||||
return childRecords;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns all of our children which are also
|
||||
* EscherContainers (may be 0, 1, or vary rarely
|
||||
* 2 or 3)
|
||||
*/
|
||||
public List getChildContainers() {
|
||||
List containers = new ArrayList();
|
||||
for ( Iterator iterator = getChildRecords().iterator(); iterator.hasNext(); )
|
||||
{
|
||||
EscherRecord r = (EscherRecord) iterator.next();
|
||||
if(r instanceof EscherContainerRecord) {
|
||||
containers.add(r);
|
||||
}
|
||||
}
|
||||
return containers;
|
||||
}
|
||||
|
||||
public void setChildRecords( List childRecords )
|
||||
{
|
||||
this.childRecords = childRecords;
|
||||
|
@ -148,6 +184,10 @@ public class EscherContainerRecord extends EscherRecord
|
|||
}
|
||||
|
||||
public String toString()
|
||||
{
|
||||
return toString("");
|
||||
}
|
||||
public String toString(String indent)
|
||||
{
|
||||
String nl = System.getProperty( "line.separator" );
|
||||
|
||||
|
@ -155,20 +195,32 @@ public class EscherContainerRecord extends EscherRecord
|
|||
if ( getChildRecords().size() > 0 )
|
||||
{
|
||||
children.append( " children: " + nl );
|
||||
|
||||
int count = 0;
|
||||
for ( Iterator iterator = getChildRecords().iterator(); iterator.hasNext(); )
|
||||
{
|
||||
String newIndent = indent + " ";
|
||||
|
||||
EscherRecord record = (EscherRecord) iterator.next();
|
||||
children.append( record.toString() );
|
||||
// children.append( nl );
|
||||
children.append(newIndent + "Child " + count + ":" + nl);
|
||||
|
||||
if(record instanceof EscherContainerRecord) {
|
||||
EscherContainerRecord ecr = (EscherContainerRecord)record;
|
||||
children.append( ecr.toString(newIndent));
|
||||
} else {
|
||||
children.append( record.toString() );
|
||||
}
|
||||
count++;
|
||||
}
|
||||
}
|
||||
|
||||
return getClass().getName() + " (" + getRecordName() + "):" + nl +
|
||||
" isContainer: " + isContainerRecord() + nl +
|
||||
" options: 0x" + HexDump.toHex( getOptions() ) + nl +
|
||||
" recordId: 0x" + HexDump.toHex( getRecordId() ) + nl +
|
||||
" numchildren: " + getChildRecords().size() + nl +
|
||||
children.toString();
|
||||
return
|
||||
indent + getClass().getName() + " (" + getRecordName() + "):" + nl +
|
||||
indent + " isContainer: " + isContainerRecord() + nl +
|
||||
indent + " options: 0x" + HexDump.toHex( getOptions() ) + nl +
|
||||
indent + " recordId: 0x" + HexDump.toHex( getRecordId() ) + nl +
|
||||
indent + " numchildren: " + getChildRecords().size() + nl +
|
||||
indent + children.toString();
|
||||
|
||||
}
|
||||
|
||||
|
|
|
@ -18,11 +18,14 @@
|
|||
|
||||
package org.apache.poi.ddf;
|
||||
|
||||
import org.apache.poi.util.LittleEndian;
|
||||
import org.apache.poi.util.HexDump;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.Comparator;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
|
||||
import java.util.*;
|
||||
import java.io.IOException;
|
||||
import org.apache.poi.util.HexDump;
|
||||
import org.apache.poi.util.LittleEndian;
|
||||
|
||||
/**
|
||||
* The opt record is used to store property values for a shape. It is the key to determining
|
||||
|
|
|
@ -40,6 +40,13 @@ public class DrawingManager2
|
|||
this.dgg = dgg;
|
||||
}
|
||||
|
||||
/**
|
||||
* Clears the cached list of drawing groups
|
||||
*/
|
||||
public void clearDrawingGroups() {
|
||||
drawingGroups.clear();
|
||||
}
|
||||
|
||||
public EscherDgRecord createDgRecord()
|
||||
{
|
||||
EscherDgRecord dg = new EscherDgRecord();
|
||||
|
@ -93,6 +100,10 @@ public class DrawingManager2
|
|||
}
|
||||
|
||||
//////////// Non-public methods /////////////
|
||||
|
||||
/**
|
||||
* Finds the next available (1 based) drawing group id
|
||||
*/
|
||||
short findNewDrawingGroupId()
|
||||
{
|
||||
short dgId = 1;
|
||||
|
|
|
@ -24,6 +24,7 @@ import java.util.ArrayList;
|
|||
import java.util.Iterator;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
//import PTG's .. since we need everything, import *
|
||||
import org.apache.poi.hssf.record.formula.*;
|
||||
|
@ -66,6 +67,12 @@ public class FormulaParser {
|
|||
*/
|
||||
private List functionTokens = new LinkedList();
|
||||
|
||||
/**
|
||||
* Used for spotting if we have a cell reference,
|
||||
* or a named range
|
||||
*/
|
||||
private final static Pattern CELL_REFERENCE_PATTERN = Pattern.compile("(?:('?)[^:\\\\/\\?\\*\\[\\]]+\\1!)?\\$?[A-Za-z]+\\$?[\\d]+");
|
||||
|
||||
private static char TAB = '\t';
|
||||
private static char CR = '\n';
|
||||
|
||||
|
@ -306,15 +313,27 @@ public class FormulaParser {
|
|||
tokens.add(new Ref3DPtg(first,externIdx));
|
||||
}
|
||||
} else {
|
||||
//this can be either a cell ref or a named range !!
|
||||
boolean cellRef = true ; //we should probably do it with reg exp??
|
||||
// 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();
|
||||
boolean boolLit = (name.equals("TRUE") || name.equals("FALSE"));
|
||||
|
||||
if (boolLit) {
|
||||
tokens.add(new BoolPtg(name));
|
||||
} else if (cellRef) {
|
||||
tokens.add(new ReferencePtg(name));
|
||||
}else {
|
||||
//handle after named range is integrated!!
|
||||
} else {
|
||||
boolean nameRecordExists = false;
|
||||
for(int i = 0; i < book.getNumNames(); i++) {
|
||||
// Our formula will by now contain an upper-cased
|
||||
// version of any named range names
|
||||
if(book.getNameRecord(i).getNameText().toUpperCase().equals(name)) {
|
||||
nameRecordExists = true;
|
||||
}
|
||||
}
|
||||
if(!nameRecordExists)
|
||||
Abort("Found reference to named range \"" + name + "\", but that named range wasn't defined!");
|
||||
tokens.add(new NamePtg(name, book));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -97,6 +97,8 @@ public class Sheet implements Model
|
|||
protected ScenarioProtectRecord scenprotect = null;
|
||||
protected PasswordRecord password = null;
|
||||
|
||||
/** Add an UncalcedRecord if not true indicating formulas have not been calculated */
|
||||
protected boolean uncalced = false;
|
||||
|
||||
public static final byte PANE_LOWER_RIGHT = (byte)0;
|
||||
public static final byte PANE_UPPER_RIGHT = (byte)1;
|
||||
|
@ -161,6 +163,9 @@ public class Sheet implements Model
|
|||
break;
|
||||
}
|
||||
}
|
||||
else if (rec.getSid() == UncalcedRecord.sid) {
|
||||
retval.uncalced = true;
|
||||
}
|
||||
else if (rec.getSid() == DimensionsRecord.sid)
|
||||
{
|
||||
// Make a columns aggregate if one hasn't ready been created.
|
||||
|
@ -736,8 +741,14 @@ public class Sheet implements Model
|
|||
{
|
||||
Record record = (( Record ) records.get(k));
|
||||
|
||||
//Once the rows have been found in the list of records, start
|
||||
//writing out the blocked row information. This includes the DBCell references
|
||||
// Don't write out UncalcedRecord entries, as
|
||||
// we handle those specially just below
|
||||
if (record instanceof UncalcedRecord) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Once the rows have been found in the list of records, start
|
||||
// writing out the blocked row information. This includes the DBCell references
|
||||
if (record instanceof RowRecordsAggregate) {
|
||||
pos += ((RowRecordsAggregate)record).serialize(pos, data, cells); // rec.length;
|
||||
} else if (record instanceof ValueRecordsAggregate) {
|
||||
|
@ -745,8 +756,14 @@ public class Sheet implements Model
|
|||
} else {
|
||||
pos += record.serialize(pos, data ); // rec.length;
|
||||
}
|
||||
//If the BOF record was just serialized then add the IndexRecord
|
||||
|
||||
// If the BOF record was just serialized then add the IndexRecord
|
||||
if (record.getSid() == BOFRecord.sid) {
|
||||
// Add an optional UncalcedRecord
|
||||
if (uncalced) {
|
||||
UncalcedRecord rec = new UncalcedRecord();
|
||||
pos += rec.serialize(pos, data);
|
||||
}
|
||||
//Can there be more than one BOF for a sheet? If not then we can
|
||||
//remove this guard. So be safe it is left here.
|
||||
if (rows != null && !haveSerializedIndex) {
|
||||
|
@ -2184,6 +2201,11 @@ public class Sheet implements Model
|
|||
retval += 2;
|
||||
}
|
||||
}
|
||||
// Add space for UncalcedRecord
|
||||
if (uncalced) {
|
||||
retval += UncalcedRecord.getStaticRecordSize();
|
||||
}
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
|
@ -2652,7 +2674,21 @@ public class Sheet implements Model
|
|||
return windowTwo.getDisplayRowColHeadings();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return whether an uncalced record must be inserted or not at generation
|
||||
*/
|
||||
public boolean getUncalced() {
|
||||
return uncalced;
|
||||
}
|
||||
/**
|
||||
* @param uncalced whether an uncalced record must be inserted or not at generation
|
||||
*/
|
||||
public void setUncalced(boolean uncalced) {
|
||||
this.uncalced = uncalced;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the array of margins. If not created, will create.
|
||||
*
|
||||
* @return the array of marings.
|
||||
|
@ -2663,12 +2699,26 @@ public class Sheet implements Model
|
|||
return margins;
|
||||
}
|
||||
|
||||
public int aggregateDrawingRecords(DrawingManager2 drawingManager)
|
||||
/**
|
||||
* Finds the DrawingRecord for our sheet, and
|
||||
* attaches it to the DrawingManager (which knows about
|
||||
* the overall DrawingGroup for our workbook).
|
||||
* If requested, will create a new DrawRecord
|
||||
* if none currently exist
|
||||
* @param drawingManager The DrawingManager2 for our workbook
|
||||
* @param createIfMissing Should one be created if missing?
|
||||
*/
|
||||
public int aggregateDrawingRecords(DrawingManager2 drawingManager, boolean createIfMissing)
|
||||
{
|
||||
int loc = findFirstRecordLocBySid(DrawingRecord.sid);
|
||||
boolean noDrawingRecordsFound = loc == -1;
|
||||
boolean noDrawingRecordsFound = (loc == -1);
|
||||
if (noDrawingRecordsFound)
|
||||
{
|
||||
if(!createIfMissing) {
|
||||
// None found, and not allowed to add in
|
||||
return -1;
|
||||
}
|
||||
|
||||
EscherAggregate aggregate = new EscherAggregate( drawingManager );
|
||||
loc = findFirstRecordLocBySid(EscherAggregate.sid);
|
||||
if (loc == -1)
|
||||
|
@ -3144,7 +3194,13 @@ public class Sheet implements Model
|
|||
maxLevel = Math.max(rowRecord.getOutlineLevel(), maxLevel);
|
||||
}
|
||||
|
||||
// Grab the guts record, adding if needed
|
||||
GutsRecord guts = (GutsRecord) findFirstRecordBySid( GutsRecord.sid );
|
||||
if(guts == null) {
|
||||
guts = new GutsRecord();
|
||||
records.add(guts);
|
||||
}
|
||||
// Set the levels onto it
|
||||
guts.setRowLevelMax( (short) ( maxLevel + 1 ) );
|
||||
guts.setLeftRowGutter( (short) ( 29 + (12 * (maxLevel)) ) );
|
||||
}
|
||||
|
|
|
@ -542,6 +542,29 @@ public class Workbook implements Model
|
|||
.getSheetname();
|
||||
}
|
||||
|
||||
/**
|
||||
* gets the hidden flag for a given sheet.
|
||||
*
|
||||
* @param sheetnum the sheet number (0 based)
|
||||
* @return True if sheet is hidden
|
||||
*/
|
||||
|
||||
public boolean isSheetHidden(int sheetnum) {
|
||||
BoundSheetRecord bsr = ( BoundSheetRecord ) boundsheets.get(sheetnum);
|
||||
return bsr.isHidden();
|
||||
}
|
||||
|
||||
/**
|
||||
* Hide or unhide a sheet
|
||||
*
|
||||
* @param sheetnum The sheet number
|
||||
* @param hidden True to mark the sheet as hidden, false otherwise
|
||||
*/
|
||||
|
||||
public void setSheetHidden(int sheetnum, boolean hidden) {
|
||||
BoundSheetRecord bsr = ( BoundSheetRecord ) boundsheets.get(sheetnum);
|
||||
bsr.setHidden(hidden);
|
||||
}
|
||||
/**
|
||||
* get the sheet's index
|
||||
* @param name sheet name
|
||||
|
@ -2144,11 +2167,66 @@ public class Workbook implements Model
|
|||
}
|
||||
|
||||
/**
|
||||
* Creates a drawing group record. If it already exists then it's modified.
|
||||
* Finds the primary drawing group, if one already exists
|
||||
*/
|
||||
public void findDrawingGroup() {
|
||||
// Need to find a DrawingGroupRecord that
|
||||
// contains a EscherDggRecord
|
||||
for(Iterator rit = records.iterator(); rit.hasNext();) {
|
||||
Record r = (Record)rit.next();
|
||||
|
||||
if(r instanceof DrawingGroupRecord) {
|
||||
DrawingGroupRecord dg = (DrawingGroupRecord)r;
|
||||
dg.processChildRecords();
|
||||
|
||||
EscherContainerRecord cr =
|
||||
dg.getEscherContainer();
|
||||
if(cr == null) {
|
||||
continue;
|
||||
}
|
||||
|
||||
EscherDggRecord dgg = null;
|
||||
for(Iterator it = cr.getChildRecords().iterator(); it.hasNext();) {
|
||||
Object er = it.next();
|
||||
if(er instanceof EscherDggRecord) {
|
||||
dgg = (EscherDggRecord)er;
|
||||
}
|
||||
}
|
||||
|
||||
if(dgg != null) {
|
||||
drawingManager = new DrawingManager2(dgg);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Look for the DrawingGroup record
|
||||
int dgLoc = findFirstRecordLocBySid(DrawingGroupRecord.sid);
|
||||
|
||||
// If there is one, does it have a EscherDggRecord?
|
||||
if(dgLoc != -1) {
|
||||
DrawingGroupRecord dg =
|
||||
(DrawingGroupRecord)records.get(dgLoc);
|
||||
EscherDggRecord dgg = null;
|
||||
for(Iterator it = dg.getEscherRecords().iterator(); it.hasNext();) {
|
||||
Object er = it.next();
|
||||
if(er instanceof EscherDggRecord) {
|
||||
dgg = (EscherDggRecord)er;
|
||||
}
|
||||
}
|
||||
|
||||
if(dgg != null) {
|
||||
drawingManager = new DrawingManager2(dgg);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a primary drawing group record. If it already
|
||||
* exists then it's modified.
|
||||
*/
|
||||
public void createDrawingGroup()
|
||||
{
|
||||
|
||||
if (drawingManager == null)
|
||||
{
|
||||
EscherContainerRecord dggContainer = new EscherContainerRecord();
|
||||
|
@ -2212,7 +2290,6 @@ public class Workbook implements Model
|
|||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public WindowOneRecord getWindowOne() {
|
||||
|
|
|
@ -18,16 +18,17 @@
|
|||
|
||||
package org.apache.poi.hssf.record;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
|
||||
import org.apache.poi.ddf.DefaultEscherRecordFactory;
|
||||
import org.apache.poi.ddf.EscherContainerRecord;
|
||||
import org.apache.poi.ddf.EscherRecord;
|
||||
import org.apache.poi.ddf.EscherRecordFactory;
|
||||
import org.apache.poi.ddf.NullEscherSerializationListener;
|
||||
import org.apache.poi.util.LittleEndian;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* The escher container record is used to hold escher records. It is abstract and
|
||||
* must be subclassed for maximum benefit.
|
||||
|
@ -76,7 +77,7 @@ public abstract class AbstractEscherHolderRecord
|
|||
{
|
||||
if (id != getSid())
|
||||
{
|
||||
throw new RecordFormatException("Not an escher record");
|
||||
throw new RecordFormatException("Not an escher record! (sid was " + id + ", expecting " + getSid() + ")");
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -94,6 +95,9 @@ public abstract class AbstractEscherHolderRecord
|
|||
}
|
||||
}
|
||||
|
||||
protected void convertRawBytesToEscherRecords() {
|
||||
convertToEscherRecords(0, rawData.length, rawData);
|
||||
}
|
||||
private void convertToEscherRecords( int offset, int size, byte[] data )
|
||||
{
|
||||
EscherRecordFactory recordFactory = new DefaultEscherRecordFactory();
|
||||
|
@ -227,7 +231,7 @@ public abstract class AbstractEscherHolderRecord
|
|||
|
||||
public Object clone()
|
||||
{
|
||||
throw new IllegalStateException("Not implemented yet.");
|
||||
return cloneViaReserialise();
|
||||
}
|
||||
|
||||
public void addEscherRecord(int index, EscherRecord element)
|
||||
|
@ -250,6 +254,54 @@ public abstract class AbstractEscherHolderRecord
|
|||
escherRecords.clear();
|
||||
}
|
||||
|
||||
/**
|
||||
* If we have a EscherContainerRecord as one of our
|
||||
* children (and most top level escher holders do),
|
||||
* then return that.
|
||||
*/
|
||||
public EscherContainerRecord getEscherContainer() {
|
||||
for(Iterator it = escherRecords.iterator(); it.hasNext();) {
|
||||
Object er = it.next();
|
||||
if(er instanceof EscherContainerRecord) {
|
||||
return (EscherContainerRecord)er;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Descends into all our children, returning the
|
||||
* first EscherRecord with the given id, or null
|
||||
* if none found
|
||||
*/
|
||||
public EscherRecord findFirstWithId(short id) {
|
||||
return findFirstWithId(id, getEscherRecords());
|
||||
}
|
||||
private EscherRecord findFirstWithId(short id, List records) {
|
||||
// Check at our level
|
||||
for(Iterator it = records.iterator(); it.hasNext();) {
|
||||
EscherRecord r = (EscherRecord)it.next();
|
||||
if(r.getRecordId() == id) {
|
||||
return r;
|
||||
}
|
||||
}
|
||||
|
||||
// Then check our children in turn
|
||||
for(Iterator it = records.iterator(); it.hasNext();) {
|
||||
EscherRecord r = (EscherRecord)it.next();
|
||||
if(r.isContainerRecord()) {
|
||||
EscherRecord found =
|
||||
findFirstWithId(id, r.getChildRecords());
|
||||
if(found != null) {
|
||||
return found;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Not found in this lot
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
public EscherRecord getEscherRecord(int index)
|
||||
{
|
||||
|
|
|
@ -19,6 +19,7 @@
|
|||
|
||||
package org.apache.poi.hssf.record;
|
||||
|
||||
import org.apache.poi.util.BitFieldFactory;
|
||||
import org.apache.poi.util.LittleEndian;
|
||||
import org.apache.poi.util.StringUtil;
|
||||
|
||||
|
@ -36,6 +37,7 @@ import org.apache.poi.util.StringUtil;
|
|||
public class BoundSheetRecord
|
||||
extends Record
|
||||
{
|
||||
private static final short HIDDEN_FLAG_MASK = 0x01;
|
||||
public final static short sid = 0x85;
|
||||
private int field_1_position_of_BOF;
|
||||
private short field_2_option_flags;
|
||||
|
@ -301,4 +303,12 @@ public class BoundSheetRecord
|
|||
{
|
||||
return sid;
|
||||
}
|
||||
|
||||
public boolean isHidden() {
|
||||
return BitFieldFactory.getInstance(HIDDEN_FLAG_MASK).isSet(field_2_option_flags);
|
||||
}
|
||||
|
||||
public void setHidden(boolean hidden) {
|
||||
field_2_option_flags = BitFieldFactory.getInstance(HIDDEN_FLAG_MASK).setShortBoolean(field_2_option_flags, hidden);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -29,19 +29,22 @@ import org.apache.poi.util.LittleEndian;
|
|||
|
||||
public class DVALRecord extends Record
|
||||
{
|
||||
public final static short sid = 0x01B2;
|
||||
public final static short sid = 0x01B2;
|
||||
|
||||
//unknown field ; it's size should be 10
|
||||
private short field_unknown = 0x0000;
|
||||
/** Options of the DVAL */
|
||||
private short field_1_options;
|
||||
/** Horizontal position of the dialog */
|
||||
private int field_2_horiz_pos;
|
||||
/** Vertical position of the dialog */
|
||||
private int field_3_vert_pos;
|
||||
|
||||
//Object ID of the drop down arrow object for list boxes ;
|
||||
//in our case this will be always FFFF , until
|
||||
//MSODrawingGroup and MSODrawing records are implemented
|
||||
private int field_cbo_id = 0xFFFFFFFF;
|
||||
/** Object ID of the drop down arrow object for list boxes ;
|
||||
* in our case this will be always FFFF , until
|
||||
* MSODrawingGroup and MSODrawing records are implemented */
|
||||
private int field_cbo_id = 0xFFFFFFFF;
|
||||
|
||||
//Number of following DV records
|
||||
//Default value is 1
|
||||
private int field_3_dv_no = 0x00000000;
|
||||
/** Number of following DV Records */
|
||||
private int field_5_dv_no = 0x00000000;
|
||||
|
||||
public DVALRecord()
|
||||
{
|
||||
|
@ -66,17 +69,38 @@ public class DVALRecord extends Record
|
|||
}
|
||||
}
|
||||
|
||||
protected void fillFields(RecordInputStream in)
|
||||
{
|
||||
for ( int i=0; i<5; i++)
|
||||
{
|
||||
this.field_unknown = in.readShort();
|
||||
}
|
||||
protected void fillFields(RecordInputStream in)
|
||||
{
|
||||
this.field_1_options = in.readShort();
|
||||
this.field_2_horiz_pos = in.readInt();
|
||||
this.field_3_vert_pos = in.readInt();
|
||||
this.field_cbo_id = in.readInt();
|
||||
this.field_3_dv_no = in.readInt();
|
||||
}
|
||||
this.field_5_dv_no = in.readInt();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param field_1_options the options of the dialog
|
||||
*/
|
||||
public void setOptions(short field_1_options) {
|
||||
this.field_1_options = field_1_options;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param field_2_horiz_pos the Horizontal position of the dialog
|
||||
*/
|
||||
public void setHorizontalPos(int field_2_horiz_pos) {
|
||||
this.field_2_horiz_pos = field_2_horiz_pos;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param field_3_vert_pos the Vertical position of the dialog
|
||||
*/
|
||||
public void setVerticalPos(int field_3_vert_pos) {
|
||||
this.field_3_vert_pos = field_3_vert_pos;
|
||||
}
|
||||
|
||||
/**
|
||||
* set the object ID of the drop down arrow object for list boxes
|
||||
* @param cboID - Object ID
|
||||
*/
|
||||
|
@ -91,10 +115,33 @@ public class DVALRecord extends Record
|
|||
*/
|
||||
public void setDVRecNo(int dvNo)
|
||||
{
|
||||
this.field_3_dv_no = dvNo;
|
||||
this.field_5_dv_no = dvNo;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @return the field_1_options
|
||||
*/
|
||||
public short getOptions() {
|
||||
return field_1_options;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the Horizontal position of the dialog
|
||||
*/
|
||||
public int getHorizontalPos() {
|
||||
return field_2_horiz_pos;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the the Vertical position of the dialog
|
||||
*/
|
||||
public int getVerticalPos() {
|
||||
return field_3_vert_pos;
|
||||
}
|
||||
|
||||
/**
|
||||
* get Object ID of the drop down arrow object for list boxes
|
||||
*/
|
||||
public int getObjectID( )
|
||||
|
@ -107,29 +154,32 @@ public class DVALRecord extends Record
|
|||
*/
|
||||
public int getDVRecNo( )
|
||||
{
|
||||
return this.field_3_dv_no;
|
||||
return this.field_5_dv_no;
|
||||
}
|
||||
|
||||
|
||||
public String toString()
|
||||
{
|
||||
StringBuffer buffer = new StringBuffer();
|
||||
public String toString()
|
||||
{
|
||||
StringBuffer buffer = new StringBuffer();
|
||||
|
||||
buffer.append("[DVAL]\n");
|
||||
buffer.append(" .comboObjectID = ").append(Integer.toHexString(this.getObjectID())).append("\n");
|
||||
buffer.append(" .DVRecordsNumber = ").append(Integer.toHexString(this.getDVRecNo())).append("\n");
|
||||
buffer.append("[/DVAL]\n");
|
||||
return buffer.toString();
|
||||
}
|
||||
buffer.append("[DVAL]\n");
|
||||
buffer.append(" .options = ").append(this.getOptions()).append('\n');
|
||||
buffer.append(" .horizPos = ").append(this.getHorizontalPos()).append('\n');
|
||||
buffer.append(" .vertPos = ").append(this.getVerticalPos()).append('\n');
|
||||
buffer.append(" .comboObjectID = ").append(Integer.toHexString(this.getObjectID())).append("\n");
|
||||
buffer.append(" .DVRecordsNumber = ").append(Integer.toHexString(this.getDVRecNo())).append("\n");
|
||||
buffer.append("[/DVAL]\n");
|
||||
return buffer.toString();
|
||||
}
|
||||
|
||||
public int serialize(int offset, byte [] data)
|
||||
{
|
||||
LittleEndian.putShort(data, 0 + offset, this.sid);
|
||||
LittleEndian.putShort(data, 2 + offset, ( short)(this.getRecordSize()-4));
|
||||
for ( int i=0; i<5; i++)
|
||||
{
|
||||
LittleEndian.putShort(data, 4 + i*2 + offset, (short)this.field_unknown);
|
||||
}
|
||||
|
||||
LittleEndian.putShort(data, 4 + offset, this.getOptions());
|
||||
LittleEndian.putInt(data, 6 + offset, this.getHorizontalPos());
|
||||
LittleEndian.putInt(data, 10 + offset, this.getVerticalPos());
|
||||
LittleEndian.putInt(data, 14 + offset, this.getObjectID());
|
||||
LittleEndian.putInt(data, 18 + offset, this.getDVRecNo());
|
||||
return getRecordSize();
|
||||
|
@ -149,9 +199,11 @@ public class DVALRecord extends Record
|
|||
public Object clone()
|
||||
{
|
||||
DVALRecord rec = new DVALRecord();
|
||||
rec.field_unknown = this.field_unknown;
|
||||
rec.field_1_options = field_1_options;
|
||||
rec.field_2_horiz_pos = field_2_horiz_pos;
|
||||
rec.field_3_vert_pos = field_3_vert_pos;
|
||||
rec.field_cbo_id = this.field_cbo_id;
|
||||
rec.field_3_dv_no = this.field_3_dv_no;
|
||||
rec.field_5_dv_no = this.field_5_dv_no;
|
||||
return rec;
|
||||
}
|
||||
}
|
|
@ -16,16 +16,16 @@
|
|||
|
||||
package org.apache.poi.hssf.record;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Enumeration;
|
||||
import java.util.Hashtable;
|
||||
import java.util.Stack;
|
||||
|
||||
import org.apache.poi.hssf.record.formula.Ptg;
|
||||
import org.apache.poi.hssf.util.HSSFCellRangeAddress;
|
||||
import org.apache.poi.util.BitField;
|
||||
import org.apache.poi.util.LittleEndian;
|
||||
import org.apache.poi.util.StringUtil;
|
||||
import org.apache.poi.hssf.util.HSSFCellRangeAddress;
|
||||
import org.apache.poi.hssf.record.formula.Ptg;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Stack;
|
||||
import java.util.Hashtable;
|
||||
import java.util.Enumeration;
|
||||
|
||||
/**
|
||||
* Title: DV Record<P>
|
||||
|
@ -187,10 +187,13 @@ public class DVRecord extends Record
|
|||
this.field_not_used_2 = in.readShort();
|
||||
|
||||
//read sec formula data condition
|
||||
// Not sure if this was needed or not...
|
||||
//Not sure if this was needed or not...
|
||||
try {
|
||||
in.skip(this.field_size_sec_formula);
|
||||
} catch(IOException e) { throw new IllegalStateException(e); }
|
||||
} catch(IOException e) {
|
||||
e.printStackTrace();
|
||||
throw new IllegalStateException(e.getMessage());
|
||||
}
|
||||
|
||||
token_pos = 0;
|
||||
while (token_pos < this.field_size_sec_formula)
|
||||
|
@ -503,6 +506,14 @@ public class DVRecord extends Record
|
|||
return this.sid;
|
||||
}
|
||||
|
||||
/**
|
||||
* Clones the object. Uses serialisation, as the
|
||||
* contents are somewhat complex
|
||||
*/
|
||||
public Object clone() {
|
||||
return cloneViaReserialise();
|
||||
}
|
||||
|
||||
/**@todo DVRecord = Serializare */
|
||||
|
||||
private class StringHandler
|
||||
|
|
|
@ -73,6 +73,16 @@ public class DrawingGroupRecord extends AbstractEscherHolderRecord
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Process the bytes into escher records.
|
||||
* (Not done by default in case we break things,
|
||||
* unless you set the "poi.deserialize.escher"
|
||||
* system property)
|
||||
*/
|
||||
public void processChildRecords() {
|
||||
convertRawBytesToEscherRecords();
|
||||
}
|
||||
|
||||
/**
|
||||
* Size of record (including 4 byte headers for all sections)
|
||||
*/
|
||||
|
|
|
@ -106,4 +106,18 @@ public class DrawingRecord extends Record
|
|||
this.recordData = thedata;
|
||||
}
|
||||
|
||||
public Object clone() {
|
||||
DrawingRecord rec = new DrawingRecord();
|
||||
|
||||
if (recordData != null) {
|
||||
rec.recordData = new byte[ recordData.length ];
|
||||
System.arraycopy(recordData, 0, rec.recordData, 0, recordData.length);
|
||||
}
|
||||
if (contd != null) {
|
||||
System.arraycopy(contd, 0, rec.contd, 0, contd.length);
|
||||
rec.contd = new byte[ contd.length ];
|
||||
}
|
||||
|
||||
return rec;
|
||||
}
|
||||
}
|
|
@ -24,6 +24,8 @@ import org.apache.poi.hssf.model.TextboxShape;
|
|||
import org.apache.poi.hssf.model.DrawingManager2;
|
||||
import org.apache.poi.hssf.model.ConvertAnchor;
|
||||
import org.apache.poi.hssf.model.CommentShape;
|
||||
import org.apache.poi.util.POILogFactory;
|
||||
import org.apache.poi.util.POILogger;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
|
@ -47,6 +49,7 @@ import java.util.*;
|
|||
public class EscherAggregate extends AbstractEscherHolderRecord
|
||||
{
|
||||
public static final short sid = 9876;
|
||||
private static POILogger log = POILogFactory.getLogger(EscherAggregate.class);
|
||||
|
||||
public static final short ST_MIN = (short) 0;
|
||||
public static final short ST_NOT_PRIMATIVE = ST_MIN;
|
||||
|
@ -524,6 +527,145 @@ public class EscherAggregate extends AbstractEscherHolderRecord
|
|||
this.patriarch = patriarch;
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts the Records into UserModel
|
||||
* objects on the bound HSSFPatriarch
|
||||
*/
|
||||
public void convertRecordsToUserModel() {
|
||||
if(patriarch == null) {
|
||||
throw new IllegalStateException("Must call setPatriarch() first");
|
||||
}
|
||||
|
||||
// The top level container ought to have
|
||||
// the DgRecord and the container of one container
|
||||
// per shape group (patriach overall first)
|
||||
EscherContainerRecord topContainer =
|
||||
(EscherContainerRecord)getEscherContainer();
|
||||
if(topContainer == null) {
|
||||
return;
|
||||
}
|
||||
topContainer = (EscherContainerRecord)
|
||||
topContainer.getChildContainers().get(0);
|
||||
|
||||
List tcc = topContainer.getChildContainers();
|
||||
if(tcc.size() == 0) {
|
||||
throw new IllegalStateException("No child escher containers at the point that should hold the patriach data, and one container per top level shape!");
|
||||
}
|
||||
|
||||
// First up, get the patriach position
|
||||
// This is in the first EscherSpgrRecord, in
|
||||
// the first container, with a EscherSRecord too
|
||||
EscherContainerRecord patriachContainer =
|
||||
(EscherContainerRecord)tcc.get(0);
|
||||
EscherSpgrRecord spgr = null;
|
||||
for(Iterator it = patriachContainer.getChildRecords().iterator(); it.hasNext();) {
|
||||
EscherRecord r = (EscherRecord)it.next();
|
||||
if(r instanceof EscherSpgrRecord) {
|
||||
spgr = (EscherSpgrRecord)r;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if(spgr != null) {
|
||||
patriarch.setCoordinates(
|
||||
spgr.getRectX1(), spgr.getRectY1(),
|
||||
spgr.getRectX2(), spgr.getRectY2()
|
||||
);
|
||||
}
|
||||
|
||||
// Now process the containers for each group
|
||||
// and objects
|
||||
for(int i=1; i<tcc.size(); i++) {
|
||||
EscherContainerRecord shapeContainer =
|
||||
(EscherContainerRecord)tcc.get(i);
|
||||
//System.err.println("\n\n*****\n\n");
|
||||
//System.err.println(shapeContainer);
|
||||
|
||||
// Could be a group, or a base object
|
||||
if(shapeContainer.getChildRecords().size() == 1 &&
|
||||
shapeContainer.getChildContainers().size() == 1) {
|
||||
// Group
|
||||
HSSFShapeGroup group =
|
||||
new HSSFShapeGroup(null, new HSSFClientAnchor());
|
||||
patriarch.getChildren().add(group);
|
||||
|
||||
EscherContainerRecord groupContainer =
|
||||
(EscherContainerRecord)shapeContainer.getChild(0);
|
||||
convertRecordsToUserModel(groupContainer, group);
|
||||
} else if(shapeContainer.hasChildOfType((short)0xF00D)) {
|
||||
// TextBox
|
||||
HSSFTextbox box =
|
||||
new HSSFTextbox(null, new HSSFClientAnchor());
|
||||
patriarch.getChildren().add(box);
|
||||
|
||||
convertRecordsToUserModel(shapeContainer, box);
|
||||
} else if(shapeContainer.hasChildOfType((short)0xF011)) {
|
||||
// Not yet supporting EscherClientDataRecord stuff
|
||||
} else {
|
||||
// Base level
|
||||
convertRecordsToUserModel(shapeContainer, patriarch);
|
||||
}
|
||||
}
|
||||
|
||||
// Now, clear any trace of what records make up
|
||||
// the patriarch
|
||||
// Otherwise, everything will go horribly wrong
|
||||
// when we try to write out again....
|
||||
// clearEscherRecords();
|
||||
drawingManager.getDgg().setFileIdClusters(new EscherDggRecord.FileIdCluster[0]);
|
||||
|
||||
// TODO: Support converting our records
|
||||
// back into shapes
|
||||
log.log(POILogger.WARN, "Not processing objects into Patriarch!");
|
||||
}
|
||||
|
||||
private void convertRecordsToUserModel(EscherContainerRecord shapeContainer, Object model) {
|
||||
for(Iterator it = shapeContainer.getChildRecords().iterator(); it.hasNext();) {
|
||||
EscherRecord r = (EscherRecord)it.next();
|
||||
if(r instanceof EscherSpgrRecord) {
|
||||
// This may be overriden by a later EscherClientAnchorRecord
|
||||
EscherSpgrRecord spgr = (EscherSpgrRecord)r;
|
||||
|
||||
if(model instanceof HSSFShapeGroup) {
|
||||
HSSFShapeGroup g = (HSSFShapeGroup)model;
|
||||
g.setCoordinates(
|
||||
spgr.getRectX1(), spgr.getRectY1(),
|
||||
spgr.getRectX2(), spgr.getRectY2()
|
||||
);
|
||||
} else {
|
||||
throw new IllegalStateException("Got top level anchor but not processing a group");
|
||||
}
|
||||
}
|
||||
else if(r instanceof EscherClientAnchorRecord) {
|
||||
EscherClientAnchorRecord car = (EscherClientAnchorRecord)r;
|
||||
|
||||
if(model instanceof HSSFShape) {
|
||||
HSSFShape g = (HSSFShape)model;
|
||||
g.getAnchor().setDx1(car.getDx1());
|
||||
g.getAnchor().setDx2(car.getDx2());
|
||||
g.getAnchor().setDy1(car.getDy1());
|
||||
g.getAnchor().setDy2(car.getDy2());
|
||||
} else {
|
||||
throw new IllegalStateException("Got top level anchor but not processing a group or shape");
|
||||
}
|
||||
}
|
||||
else if(r instanceof EscherTextboxRecord) {
|
||||
EscherTextboxRecord tbr = (EscherTextboxRecord)r;
|
||||
|
||||
// Also need to find the TextObjectRecord too
|
||||
// TODO
|
||||
}
|
||||
else if(r instanceof EscherSpRecord) {
|
||||
// Use flags if needed
|
||||
}
|
||||
else if(r instanceof EscherOptRecord) {
|
||||
// Use properties if needed
|
||||
}
|
||||
else {
|
||||
//System.err.println(r);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void clear()
|
||||
{
|
||||
clearEscherRecords();
|
||||
|
|
|
@ -179,7 +179,6 @@ public class FormulaRecord
|
|||
*
|
||||
* @return calculated value
|
||||
*/
|
||||
|
||||
public double getValue()
|
||||
{
|
||||
return field_4_value;
|
||||
|
@ -190,7 +189,6 @@ public class FormulaRecord
|
|||
*
|
||||
* @return bitmask
|
||||
*/
|
||||
|
||||
public short getOptions()
|
||||
{
|
||||
return field_5_options;
|
||||
|
@ -199,9 +197,25 @@ public class FormulaRecord
|
|||
public boolean isSharedFormula() {
|
||||
return sharedFormula.isSet(field_5_options);
|
||||
}
|
||||
|
||||
public void setSharedFormula(boolean flag) {
|
||||
sharedFormula.setBoolean(field_5_options, flag);
|
||||
field_5_options =
|
||||
sharedFormula.setShortBoolean(field_5_options, flag);
|
||||
}
|
||||
|
||||
public boolean isAlwaysCalc() {
|
||||
return alwaysCalc.isSet(field_5_options);
|
||||
}
|
||||
public void setAlwaysCalc(boolean flag) {
|
||||
field_5_options =
|
||||
alwaysCalc.setShortBoolean(field_5_options, flag);
|
||||
}
|
||||
|
||||
public boolean isCalcOnLoad() {
|
||||
return calcOnLoad.isSet(field_5_options);
|
||||
}
|
||||
public void setCalcOnLoad(boolean flag) {
|
||||
field_5_options =
|
||||
calcOnLoad.setShortBoolean(field_5_options, flag);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -20,13 +20,11 @@ package org.apache.poi.hssf.record;
|
|||
|
||||
import java.util.List;
|
||||
import java.util.Stack;
|
||||
import java.util.Iterator;
|
||||
|
||||
import org.apache.poi.hssf.model.Workbook;
|
||||
import org.apache.poi.hssf.record.formula.Area3DPtg;
|
||||
import org.apache.poi.hssf.record.formula.DeletedArea3DPtg;
|
||||
import org.apache.poi.hssf.record.formula.DeletedRef3DPtg;
|
||||
import org.apache.poi.hssf.record.formula.Ptg;
|
||||
import org.apache.poi.hssf.record.formula.Ref3DPtg;
|
||||
import org.apache.poi.hssf.record.formula.*;
|
||||
import org.apache.poi.hssf.util.AreaReference;
|
||||
import org.apache.poi.hssf.util.RangeAddress;
|
||||
import org.apache.poi.util.HexDump;
|
||||
import org.apache.poi.util.LittleEndian;
|
||||
|
@ -272,6 +270,9 @@ public class NameRecord extends Record {
|
|||
*/
|
||||
public void setNameText(String name){
|
||||
field_12_name_text = name;
|
||||
setCompressedUnicodeFlag(
|
||||
StringUtil.hasMultibyte(name) ? (byte)1 : (byte)0
|
||||
);
|
||||
}
|
||||
|
||||
// public void setNameDefintion(String definition){
|
||||
|
@ -320,13 +321,25 @@ public class NameRecord extends Record {
|
|||
return field_2_keyboard_shortcut ;
|
||||
}
|
||||
|
||||
/** gets the name length
|
||||
/**
|
||||
* gets the name length, in characters
|
||||
* @return name length
|
||||
*/
|
||||
public byte getNameTextLength(){
|
||||
return field_3_length_name_text;
|
||||
}
|
||||
|
||||
/**
|
||||
* gets the name length, in bytes
|
||||
* @return raw name length
|
||||
*/
|
||||
public byte getRawNameTextLength(){
|
||||
if( (field_11_compressed_unicode_flag & 0x01) == 1 ) {
|
||||
return (byte)(2 * field_3_length_name_text);
|
||||
}
|
||||
return field_3_length_name_text;
|
||||
}
|
||||
|
||||
/** get the definition length
|
||||
* @return definition length
|
||||
*/
|
||||
|
@ -513,27 +526,16 @@ public class NameRecord extends Record {
|
|||
data[17 + offset] = getStatusBarLength();
|
||||
data[18 + offset] = getCompressedUnicodeFlag();
|
||||
|
||||
/* temp: gjs
|
||||
if (isBuiltInName())
|
||||
{
|
||||
LittleEndian.putShort( data, 2 + offset, (short) ( 16 + field_13_raw_name_definition.length ) );
|
||||
|
||||
data[19 + offset] = field_12_builtIn_name;
|
||||
System.arraycopy( field_13_raw_name_definition, 0, data, 20 + offset, field_13_raw_name_definition.length );
|
||||
|
||||
return 20 + field_13_raw_name_definition.length;
|
||||
}
|
||||
else
|
||||
{ */
|
||||
|
||||
int start_of_name_definition = 19 + field_3_length_name_text;
|
||||
|
||||
if (this.isBuiltInName()) {
|
||||
//can send the builtin name directly in
|
||||
data [19 + offset] = this.getBuiltInName();
|
||||
} else if ((this.getCompressedUnicodeFlag() & 0x01) == 1) {
|
||||
StringUtil.putUnicodeLE( getNameText(), data, 19 + offset );
|
||||
start_of_name_definition = 19 + (2 * field_3_length_name_text);
|
||||
} else {
|
||||
StringUtil.putCompressedUnicode( getNameText(), data, 19 + offset );
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
@ -556,15 +558,15 @@ public class NameRecord extends Record {
|
|||
/* } */
|
||||
}
|
||||
|
||||
/** gets the length of all texts
|
||||
/**
|
||||
* Gets the length of all texts, in bytes
|
||||
* @return total length
|
||||
*/
|
||||
public int getTextsLength(){
|
||||
int result;
|
||||
|
||||
result = getNameTextLength() + getDescriptionTextLength() +
|
||||
getHelpTopicLength() + getStatusBarLength();
|
||||
|
||||
result = getRawNameTextLength() + getDescriptionTextLength() +
|
||||
getHelpTopicLength() + getStatusBarLength();
|
||||
|
||||
return result;
|
||||
}
|
||||
|
@ -648,17 +650,46 @@ public class NameRecord extends Record {
|
|||
Ptg ptg = (Ptg) field_13_name_definition.peek();
|
||||
String result = "";
|
||||
|
||||
if (ptg.getClass() == Area3DPtg.class){
|
||||
result = ptg.toFormulaString(book);
|
||||
// If it's a union, descend in and process
|
||||
if (ptg.getClass() == UnionPtg.class) {
|
||||
Iterator it =field_13_name_definition.iterator();
|
||||
while( it.hasNext() ) {
|
||||
Ptg p = (Ptg)it.next();
|
||||
|
||||
} else if (ptg.getClass() == Ref3DPtg.class){
|
||||
result = ptg.toFormulaString(book);
|
||||
} else if (ptg.getClass() == DeletedArea3DPtg.class || ptg.getClass() == DeletedRef3DPtg.class) {
|
||||
result = "#REF!" ; }
|
||||
String thisRes = getAreaRefString(p, book);
|
||||
if(thisRes.length() > 0) {
|
||||
// Add a comma to the end if needed
|
||||
if(result.length() > 0 && !result.endsWith(",")) {
|
||||
result += ",";
|
||||
}
|
||||
// And add the string it corresponds to
|
||||
result += thisRes;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// Otherwise just get the string
|
||||
result = getAreaRefString(ptg, book);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Turn the given ptg into a string, or
|
||||
* return an empty string if nothing is possible
|
||||
* for it.
|
||||
*/
|
||||
private String getAreaRefString(Ptg ptg,Workbook book) {
|
||||
if (ptg.getClass() == Area3DPtg.class){
|
||||
return ptg.toFormulaString(book);
|
||||
} else if (ptg.getClass() == Ref3DPtg.class){
|
||||
return ptg.toFormulaString(book);
|
||||
} else if (ptg.getClass() == DeletedArea3DPtg.class || ptg.getClass() == DeletedRef3DPtg.class) {
|
||||
return "#REF!";
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
/** sets the reference , the area only (range)
|
||||
* @param ref area reference
|
||||
*/
|
||||
|
@ -686,19 +717,32 @@ public class NameRecord extends Record {
|
|||
}
|
||||
|
||||
if (ra.hasRange()) {
|
||||
ptg = new Area3DPtg();
|
||||
((Area3DPtg) ptg).setExternSheetIndex(externSheetIndex);
|
||||
((Area3DPtg) ptg).setArea(ref);
|
||||
this.setDefinitionTextLength((short)ptg.getSize());
|
||||
// Is it contiguous or not?
|
||||
AreaReference[] refs =
|
||||
AreaReference.generateContiguous(ref);
|
||||
this.setDefinitionTextLength((short)0);
|
||||
|
||||
// Add the area reference(s)
|
||||
for(int i=0; i<refs.length; i++) {
|
||||
ptg = new Area3DPtg();
|
||||
((Area3DPtg) ptg).setExternSheetIndex(externSheetIndex);
|
||||
((Area3DPtg) ptg).setArea(refs[i].toString());
|
||||
field_13_name_definition.push(ptg);
|
||||
this.setDefinitionTextLength( (short)(getDefinitionLength() + ptg.getSize()) );
|
||||
}
|
||||
// And then a union if we had more than one area
|
||||
if(refs.length > 1) {
|
||||
ptg = new UnionPtg();
|
||||
field_13_name_definition.push(ptg);
|
||||
this.setDefinitionTextLength( (short)(getDefinitionLength() + ptg.getSize()) );
|
||||
}
|
||||
} else {
|
||||
ptg = new Ref3DPtg();
|
||||
((Ref3DPtg) ptg).setExternSheetIndex(externSheetIndex);
|
||||
((Ref3DPtg) ptg).setArea(ref);
|
||||
field_13_name_definition.push(ptg);
|
||||
this.setDefinitionTextLength((short)ptg.getSize());
|
||||
}
|
||||
|
||||
field_13_name_definition.push(ptg);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -832,6 +876,15 @@ public class NameRecord extends Record {
|
|||
.append("\n");
|
||||
buffer.append(" .Name (Unicode text) = ").append( getNameText() )
|
||||
.append("\n");
|
||||
|
||||
buffer.append(" .Parts (" + field_13_name_definition.size() +"):")
|
||||
.append("\n");
|
||||
Iterator it = field_13_name_definition.iterator();
|
||||
while(it.hasNext()) {
|
||||
Ptg ptg = (Ptg)it.next();
|
||||
buffer.append(" " + ptg.toString()).append("\n");
|
||||
}
|
||||
|
||||
buffer.append(" .Menu text (Unicode string without length field) = ").append( field_14_custom_menu_text )
|
||||
.append("\n");
|
||||
buffer.append(" .Description text (Unicode string without length field) = ").append( field_15_description_text )
|
||||
|
|
|
@ -243,4 +243,15 @@ public class NoteRecord extends Record {
|
|||
public void setAuthor(String author){
|
||||
field_5_author = author;
|
||||
}
|
||||
|
||||
public Object clone() {
|
||||
NoteRecord rec = new NoteRecord();
|
||||
rec.field_1_row = field_1_row;
|
||||
rec.field_2_col = field_2_col;
|
||||
rec.field_3_flags = field_3_flags;
|
||||
rec.field_4_shapeid = field_4_shapeid;
|
||||
rec.field_5_author = field_5_author;
|
||||
return rec;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -125,6 +125,15 @@ public class NoteStructureSubRecord
|
|||
{
|
||||
return sid;
|
||||
}
|
||||
|
||||
public Object clone() {
|
||||
NoteStructureSubRecord rec = new NoteStructureSubRecord();
|
||||
byte[] recdata = new byte[reserved.length];
|
||||
System.arraycopy(reserved, 0, recdata, 0, recdata.length);
|
||||
rec.reserved = recdata;
|
||||
return rec;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -19,6 +19,8 @@
|
|||
|
||||
package org.apache.poi.hssf.record;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
|
||||
/**
|
||||
* Title: Record
|
||||
* Description: All HSSF Records inherit from this class. It
|
||||
|
@ -147,4 +149,30 @@ public abstract class Record
|
|||
public Object clone() {
|
||||
throw new RuntimeException("The class "+getClass().getName()+" needs to define a clone method");
|
||||
}
|
||||
|
||||
/**
|
||||
* Clone the current record, via a call to serialise
|
||||
* it, and another to create a new record from the
|
||||
* bytes.
|
||||
* May only be used for classes which don't have
|
||||
* internal counts / ids in them. For those which
|
||||
* do, a full record-aware serialise is needed, which
|
||||
* allocates new ids / counts as needed.
|
||||
*/
|
||||
public Record cloneViaReserialise()
|
||||
{
|
||||
// Do it via a re-serialise
|
||||
// It's a cheat, but it works...
|
||||
byte[] b = serialize();
|
||||
RecordInputStream rinp = new RecordInputStream(
|
||||
new ByteArrayInputStream(b)
|
||||
);
|
||||
rinp.nextRecord();
|
||||
|
||||
Record[] r = RecordFactory.createRecord(rinp);
|
||||
if(r.length != 1) {
|
||||
throw new IllegalStateException("Re-serialised a record to clone it, but got " + r.length + " records back!");
|
||||
}
|
||||
return r[0];
|
||||
}
|
||||
}
|
||||
|
|
|
@ -76,7 +76,7 @@ public class RecordFactory
|
|||
WriteProtectRecord.class, FilePassRecord.class, PaneRecord.class,
|
||||
NoteRecord.class, ObjectProtectRecord.class, ScenarioProtectRecord.class,
|
||||
FileSharingRecord.class, ChartTitleFormatRecord.class,
|
||||
DVRecord.class, DVALRecord.class
|
||||
DVRecord.class, DVALRecord.class, UncalcedRecord.class
|
||||
};
|
||||
}
|
||||
private static Map recordsMap = recordsToMap(records);
|
||||
|
|
|
@ -133,6 +133,9 @@ public class RecordInputStream extends InputStream
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads an 8 bit, signed value
|
||||
*/
|
||||
public byte readByte() {
|
||||
checkRecordPosition();
|
||||
|
||||
|
@ -142,6 +145,9 @@ public class RecordInputStream extends InputStream
|
|||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads a 16 bit, signed value
|
||||
*/
|
||||
public short readShort() {
|
||||
checkRecordPosition();
|
||||
|
||||
|
@ -169,6 +175,21 @@ public class RecordInputStream extends InputStream
|
|||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads an 8 bit, unsigned value
|
||||
*/
|
||||
public short readUByte() {
|
||||
short s = readByte();
|
||||
if(s < 0) {
|
||||
s += 256;
|
||||
}
|
||||
return s;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads a 16 bit,un- signed value.
|
||||
* @return
|
||||
*/
|
||||
public int readUShort() {
|
||||
checkRecordPosition();
|
||||
|
||||
|
|
|
@ -20,10 +20,8 @@
|
|||
package org.apache.poi.hssf.record;
|
||||
|
||||
import java.util.Stack;
|
||||
import java.util.List;
|
||||
|
||||
import org.apache.poi.hssf.record.formula.*;
|
||||
import org.apache.poi.util.LittleEndian;
|
||||
|
||||
/**
|
||||
* Title: SharedFormulaRecord
|
||||
|
@ -156,15 +154,12 @@ public class SharedFormulaRecord
|
|||
return sid;
|
||||
}
|
||||
|
||||
/**
|
||||
* Shared formulas are to treated like unknown records, and as a result d
|
||||
*/
|
||||
protected void fillFields(RecordInputStream in)
|
||||
{
|
||||
field_1_first_row = in.readShort();
|
||||
field_2_last_row = in.readShort();
|
||||
field_3_first_column = in.readByte();
|
||||
field_4_last_column = in.readByte();
|
||||
field_1_first_row = in.readUShort();
|
||||
field_2_last_row = in.readUShort();
|
||||
field_3_first_column = in.readUByte();
|
||||
field_4_last_column = in.readUByte();
|
||||
field_5_reserved = in.readShort();
|
||||
field_6_expression_len = in.readShort();
|
||||
field_7_parsed_expr = getParsedExpressionTokens(in);
|
||||
|
@ -181,6 +176,9 @@ public class SharedFormulaRecord
|
|||
return stack;
|
||||
}
|
||||
|
||||
/**
|
||||
* Are we shared by the supplied formula record?
|
||||
*/
|
||||
public boolean isFormulaInShared(FormulaRecord formula) {
|
||||
final int formulaRow = formula.getRow();
|
||||
final int formulaColumn = formula.getColumn();
|
||||
|
@ -202,48 +200,48 @@ public class SharedFormulaRecord
|
|||
Ptg ptg = (Ptg) field_7_parsed_expr.get(k);
|
||||
if (ptg instanceof RefNPtg) {
|
||||
RefNPtg refNPtg = (RefNPtg)ptg;
|
||||
ptg = new ReferencePtg( (short)(formulaRow + refNPtg.getRow()),
|
||||
(byte)(formulaColumn + refNPtg.getColumn()),
|
||||
ptg = new ReferencePtg(fixupRelativeRow(formulaRow,refNPtg.getRow(),refNPtg.isRowRelative()),
|
||||
fixupRelativeColumn(formulaColumn,refNPtg.getColumn(),refNPtg.isColRelative()),
|
||||
refNPtg.isRowRelative(),
|
||||
refNPtg.isColRelative());
|
||||
} else if (ptg instanceof RefNVPtg) {
|
||||
RefNVPtg refNVPtg = (RefNVPtg)ptg;
|
||||
ptg = new RefVPtg( (short)(formulaRow + refNVPtg.getRow()),
|
||||
(byte)(formulaColumn + refNVPtg.getColumn()),
|
||||
refNVPtg.isRowRelative(),
|
||||
refNVPtg.isColRelative());
|
||||
ptg = new RefVPtg(fixupRelativeRow(formulaRow,refNVPtg.getRow(),refNVPtg.isRowRelative()),
|
||||
fixupRelativeColumn(formulaColumn,refNVPtg.getColumn(),refNVPtg.isColRelative()),
|
||||
refNVPtg.isRowRelative(),
|
||||
refNVPtg.isColRelative());
|
||||
} else if (ptg instanceof RefNAPtg) {
|
||||
RefNAPtg refNAPtg = (RefNAPtg)ptg;
|
||||
ptg = new RefAPtg( (short)(formulaRow + refNAPtg.getRow()),
|
||||
(byte)(formulaColumn + refNAPtg.getColumn()),
|
||||
ptg = new RefAPtg( fixupRelativeRow(formulaRow,refNAPtg.getRow(),refNAPtg.isRowRelative()),
|
||||
fixupRelativeColumn(formulaColumn,refNAPtg.getColumn(),refNAPtg.isColRelative()),
|
||||
refNAPtg.isRowRelative(),
|
||||
refNAPtg.isColRelative());
|
||||
} else if (ptg instanceof AreaNPtg) {
|
||||
AreaNPtg areaNPtg = (AreaNPtg)ptg;
|
||||
ptg = new AreaPtg((short)(formulaRow + areaNPtg.getFirstRow()),
|
||||
(short)(formulaRow + areaNPtg.getLastRow()),
|
||||
(short)(formulaColumn + areaNPtg.getFirstColumn()),
|
||||
(short)(formulaColumn + areaNPtg.getLastColumn()),
|
||||
ptg = new AreaPtg(fixupRelativeRow(formulaRow,areaNPtg.getFirstRow(),areaNPtg.isFirstRowRelative()),
|
||||
fixupRelativeRow(formulaRow,areaNPtg.getLastRow(),areaNPtg.isLastRowRelative()),
|
||||
fixupRelativeColumn(formulaColumn,areaNPtg.getFirstColumn(),areaNPtg.isFirstColRelative()),
|
||||
fixupRelativeColumn(formulaColumn,areaNPtg.getLastColumn(),areaNPtg.isLastColRelative()),
|
||||
areaNPtg.isFirstRowRelative(),
|
||||
areaNPtg.isLastRowRelative(),
|
||||
areaNPtg.isFirstColRelative(),
|
||||
areaNPtg.isLastColRelative());
|
||||
} else if (ptg instanceof AreaNVPtg) {
|
||||
AreaNVPtg areaNVPtg = (AreaNVPtg)ptg;
|
||||
ptg = new AreaVPtg((short)(formulaRow + areaNVPtg.getFirstRow()),
|
||||
(short)(formulaRow + areaNVPtg.getLastRow()),
|
||||
(short)(formulaColumn + areaNVPtg.getFirstColumn()),
|
||||
(short)(formulaColumn + areaNVPtg.getLastColumn()),
|
||||
ptg = new AreaVPtg(fixupRelativeRow(formulaRow,areaNVPtg.getFirstRow(),areaNVPtg.isFirstRowRelative()),
|
||||
fixupRelativeRow(formulaRow,areaNVPtg.getLastRow(),areaNVPtg.isLastRowRelative()),
|
||||
fixupRelativeColumn(formulaColumn,areaNVPtg.getFirstColumn(),areaNVPtg.isFirstColRelative()),
|
||||
fixupRelativeColumn(formulaColumn,areaNVPtg.getLastColumn(),areaNVPtg.isLastColRelative()),
|
||||
areaNVPtg.isFirstRowRelative(),
|
||||
areaNVPtg.isLastRowRelative(),
|
||||
areaNVPtg.isFirstColRelative(),
|
||||
areaNVPtg.isLastColRelative());
|
||||
} else if (ptg instanceof AreaNAPtg) {
|
||||
AreaNAPtg areaNAPtg = (AreaNAPtg)ptg;
|
||||
ptg = new AreaAPtg((short)(formulaRow + areaNAPtg.getFirstRow()),
|
||||
(short)(formulaRow + areaNAPtg.getLastRow()),
|
||||
(short)(formulaColumn + areaNAPtg.getFirstColumn()),
|
||||
(short)(formulaColumn + areaNAPtg.getLastColumn()),
|
||||
ptg = new AreaAPtg(fixupRelativeRow(formulaRow,areaNAPtg.getFirstRow(),areaNAPtg.isFirstRowRelative()),
|
||||
fixupRelativeRow(formulaRow,areaNAPtg.getLastRow(),areaNAPtg.isLastRowRelative()),
|
||||
fixupRelativeColumn(formulaColumn,areaNAPtg.getFirstColumn(),areaNAPtg.isFirstColRelative()),
|
||||
fixupRelativeColumn(formulaColumn,areaNAPtg.getLastColumn(),areaNAPtg.isLastColRelative()),
|
||||
areaNAPtg.isFirstRowRelative(),
|
||||
areaNAPtg.isLastRowRelative(),
|
||||
areaNAPtg.isFirstColRelative(),
|
||||
|
@ -259,6 +257,21 @@ public class SharedFormulaRecord
|
|||
}
|
||||
}
|
||||
|
||||
private short fixupRelativeColumn(int currentcolumn, short column, boolean relative) {
|
||||
if(relative) {
|
||||
if((column&128)!=0) column=(short)(column-256);
|
||||
column+=currentcolumn;
|
||||
}
|
||||
return column;
|
||||
}
|
||||
|
||||
private short fixupRelativeRow(int currentrow, short row, boolean relative) {
|
||||
if(relative) {
|
||||
row+=currentrow;
|
||||
}
|
||||
return row;
|
||||
}
|
||||
|
||||
/**
|
||||
* Mirroring formula records so it is registered in the ValueRecordsAggregate
|
||||
*/
|
||||
|
|
|
@ -251,4 +251,21 @@ public class TextObjectRecord
|
|||
buffer.append( "[/TXO]\n" );
|
||||
return buffer.toString();
|
||||
}
|
||||
|
||||
public Object clone() {
|
||||
|
||||
TextObjectRecord rec = new TextObjectRecord();
|
||||
rec.str = str;
|
||||
|
||||
rec.setOptions(getOptions());
|
||||
rec.setTextOrientation(getTextOrientation());
|
||||
rec.setReserved4(getReserved4());
|
||||
rec.setReserved5(getReserved5());
|
||||
rec.setReserved6(getReserved6());
|
||||
rec.setTextLength(getTextLength());
|
||||
rec.setFormattingRunLength(getFormattingRunLength());
|
||||
rec.setReserved7(getReserved7());
|
||||
return rec;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -0,0 +1,82 @@
|
|||
/* ====================================================================
|
||||
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;
|
||||
|
||||
import org.apache.poi.util.LittleEndian;
|
||||
|
||||
/**
|
||||
* Title: Uncalced Record
|
||||
* <P>
|
||||
* If this record occurs in the Worksheet Substream, it indicates that the formulas have not
|
||||
* been recalculated before the document was saved.
|
||||
*
|
||||
* @author Olivier Leprince
|
||||
*/
|
||||
|
||||
public class UncalcedRecord extends Record
|
||||
{
|
||||
public final static short sid = 0x5E;
|
||||
|
||||
/**
|
||||
* Default constructor
|
||||
*/
|
||||
public UncalcedRecord() {
|
||||
}
|
||||
/**
|
||||
* read constructor
|
||||
*/
|
||||
public UncalcedRecord(RecordInputStream in) {
|
||||
super(in);
|
||||
}
|
||||
|
||||
public short getSid() {
|
||||
return sid;
|
||||
}
|
||||
|
||||
protected void validateSid(short id) {
|
||||
if (id != sid) {
|
||||
throw new RecordFormatException("NOT AN UNCALCED RECORD");
|
||||
}
|
||||
}
|
||||
|
||||
protected void fillFields(RecordInputStream in) {
|
||||
short unused = in.readShort();
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
StringBuffer buffer = new StringBuffer();
|
||||
buffer.append("[UNCALCED]\n");
|
||||
buffer.append("[/UNCALCED]\n");
|
||||
return buffer.toString();
|
||||
}
|
||||
|
||||
public int serialize(int offset, byte[] data) {
|
||||
LittleEndian.putShort(data, 0 + offset, sid);
|
||||
LittleEndian.putShort(data, 2 + offset, (short) 2);
|
||||
LittleEndian.putShort(data, 4 + offset, (short) 0); // unused
|
||||
return getRecordSize();
|
||||
}
|
||||
|
||||
public int getRecordSize() {
|
||||
return UncalcedRecord.getStaticRecordSize();
|
||||
}
|
||||
|
||||
public static int getStaticRecordSize() {
|
||||
return 6;
|
||||
}
|
||||
}
|
|
@ -127,8 +127,17 @@ public class ValueRecordsAggregate
|
|||
|
||||
FormulaRecordAggregate lastFormulaAggregate = null;
|
||||
|
||||
// First up, locate all the shared formulas
|
||||
List sharedFormulas = new java.util.ArrayList();
|
||||
for (k = offset; k < records.size(); k++)
|
||||
{
|
||||
Record rec = ( Record ) records.get(k);
|
||||
if (rec instanceof SharedFormulaRecord) {
|
||||
sharedFormulas.add(rec);
|
||||
}
|
||||
}
|
||||
|
||||
// Now do the main processing sweep
|
||||
for (k = offset; k < records.size(); k++)
|
||||
{
|
||||
Record rec = ( Record ) records.get(k);
|
||||
|
@ -137,18 +146,14 @@ public class ValueRecordsAggregate
|
|||
{
|
||||
break;
|
||||
} else if (rec instanceof SharedFormulaRecord) {
|
||||
sharedFormulas.add(rec);
|
||||
// Already handled, not to worry
|
||||
} else if (rec instanceof FormulaRecord)
|
||||
{
|
||||
FormulaRecord formula = (FormulaRecord)rec;
|
||||
if (formula.isSharedFormula()) {
|
||||
Record nextRecord = (Record) records.get(k + 1);
|
||||
if (nextRecord instanceof SharedFormulaRecord) {
|
||||
sharedFormulas.add(nextRecord);
|
||||
k++;
|
||||
}
|
||||
//traverse the list of shared formulas in reverse order, and try to find the correct one
|
||||
//for us
|
||||
// Traverse the list of shared formulas in
|
||||
// reverse order, and try to find the correct one
|
||||
// for us
|
||||
boolean found = false;
|
||||
for (int i=sharedFormulas.size()-1;i>=0;i--) {
|
||||
SharedFormulaRecord shrd = (SharedFormulaRecord)sharedFormulas.get(i);
|
||||
|
|
|
@ -243,16 +243,22 @@ public class Area3DPtg extends Ptg
|
|||
public void setArea( String ref )
|
||||
{
|
||||
AreaReference ar = new AreaReference( ref );
|
||||
CellReference[] crs = ar.getCells();
|
||||
|
||||
setFirstRow( (short) ar.getCells()[0].getRow() );
|
||||
setFirstColumn( (short) ar.getCells()[0].getCol() );
|
||||
setLastRow( (short) ar.getCells()[1].getRow() );
|
||||
setLastColumn( (short) ar.getCells()[1].getCol() );
|
||||
setFirstColRelative( !ar.getCells()[0].isColAbsolute() );
|
||||
setLastColRelative( !ar.getCells()[1].isColAbsolute() );
|
||||
setFirstRowRelative( !ar.getCells()[0].isRowAbsolute() );
|
||||
setLastRowRelative( !ar.getCells()[1].isRowAbsolute() );
|
||||
CellReference firstCell = crs[0];
|
||||
CellReference lastCell = firstCell;
|
||||
if(crs.length > 1) {
|
||||
lastCell = crs[1];
|
||||
}
|
||||
|
||||
setFirstRow( (short) firstCell.getRow() );
|
||||
setFirstColumn( (short) firstCell.getCol() );
|
||||
setLastRow( (short) lastCell.getRow() );
|
||||
setLastColumn( (short) lastCell.getCol() );
|
||||
setFirstColRelative( !firstCell.isColAbsolute() );
|
||||
setLastColRelative( !lastCell.isColAbsolute() );
|
||||
setFirstRowRelative( !firstCell.isRowAbsolute() );
|
||||
setLastRowRelative( !lastCell.isRowAbsolute() );
|
||||
}
|
||||
|
||||
public String toFormulaString(Workbook book)
|
||||
|
|
|
@ -29,7 +29,7 @@ import org.apache.poi.hssf.usermodel.HSSFErrorConstants;
|
|||
public class ErrPtg extends Ptg
|
||||
{
|
||||
public static final short sid = 0x1c;
|
||||
private static final int SIZE = 7;
|
||||
private static final int SIZE = 2;
|
||||
private byte field_1_error_code;
|
||||
|
||||
/** Creates new ErrPtg */
|
||||
|
|
|
@ -75,7 +75,7 @@ public class ExpPtg
|
|||
|
||||
public String toFormulaString(Workbook book)
|
||||
{
|
||||
throw new RecordFormatException("Coding Error: Expected ExpPtg to be converted from Shared to Non-Shared Formula");
|
||||
throw new RecordFormatException("Coding Error: Expected ExpPtg to be converted from Shared to Non-Shared Formula by ValueRecordsAggregate, but it wasn't");
|
||||
}
|
||||
|
||||
public String toString()
|
||||
|
|
|
@ -24,17 +24,33 @@
|
|||
*/
|
||||
package org.apache.poi.hssf.usermodel;
|
||||
|
||||
import java.text.DateFormat;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.Calendar;
|
||||
import java.util.Date;
|
||||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
|
||||
import org.apache.poi.hssf.model.FormulaParser;
|
||||
import org.apache.poi.hssf.model.Sheet;
|
||||
import org.apache.poi.hssf.model.Workbook;
|
||||
import org.apache.poi.hssf.record.*;
|
||||
import org.apache.poi.hssf.record.BlankRecord;
|
||||
import org.apache.poi.hssf.record.BoolErrRecord;
|
||||
import org.apache.poi.hssf.record.CellValueRecordInterface;
|
||||
import org.apache.poi.hssf.record.CommonObjectDataSubRecord;
|
||||
import org.apache.poi.hssf.record.ExtendedFormatRecord;
|
||||
import org.apache.poi.hssf.record.FormulaRecord;
|
||||
import org.apache.poi.hssf.record.LabelSSTRecord;
|
||||
import org.apache.poi.hssf.record.NoteRecord;
|
||||
import org.apache.poi.hssf.record.NumberRecord;
|
||||
import org.apache.poi.hssf.record.ObjRecord;
|
||||
import org.apache.poi.hssf.record.Record;
|
||||
import org.apache.poi.hssf.record.SubRecord;
|
||||
import org.apache.poi.hssf.record.TextObjectRecord;
|
||||
import org.apache.poi.hssf.record.UnicodeString;
|
||||
import org.apache.poi.hssf.record.aggregates.FormulaRecordAggregate;
|
||||
import org.apache.poi.hssf.record.formula.Ptg;
|
||||
|
||||
import java.text.DateFormat;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* High level representation of a cell in a row of a spreadsheet.
|
||||
* Cells can be numeric, formula-based or string-based (text). The cell type
|
||||
|
@ -266,15 +282,25 @@ public class HSSFCell
|
|||
}
|
||||
|
||||
/**
|
||||
* set the cell's number within the row (0 based)
|
||||
* Set the cell's number within the row (0 based).
|
||||
* @param num short the cell number
|
||||
* @deprecated Doesn't update the row's idea of what cell this is, use {@link HSSFRow#moveCell(HSSFCell, short)} instead
|
||||
*/
|
||||
|
||||
public void setCellNum(short num)
|
||||
{
|
||||
record.setColumn(num);
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the cell record's idea of what
|
||||
* column it belongs in (0 based)
|
||||
* @param num the new cell number
|
||||
*/
|
||||
protected void updateCellNum(short num)
|
||||
{
|
||||
record.setColumn(num);
|
||||
}
|
||||
|
||||
/**
|
||||
* get the cell's number within the row
|
||||
* @return short reperesenting the column number (logical!)
|
||||
|
@ -508,7 +534,13 @@ public class HSSFCell
|
|||
{
|
||||
setCellType(CELL_TYPE_NUMERIC, false, row, col, styleIndex);
|
||||
}
|
||||
(( NumberRecord ) record).setValue(value);
|
||||
|
||||
// Save into the apropriate record
|
||||
if(record instanceof FormulaRecordAggregate) {
|
||||
(( FormulaRecordAggregate ) record).getFormulaRecord().setValue(value);
|
||||
} else {
|
||||
(( NumberRecord ) record).setValue(value);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -21,6 +21,13 @@ import java.util.ArrayList;
|
|||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
|
||||
import org.apache.poi.ddf.EscherComplexProperty;
|
||||
import org.apache.poi.ddf.EscherOptRecord;
|
||||
import org.apache.poi.ddf.EscherProperty;
|
||||
import org.apache.poi.hssf.record.EscherAggregate;
|
||||
import org.apache.poi.util.LittleEndian;
|
||||
import org.apache.poi.util.StringUtil;
|
||||
|
||||
/**
|
||||
* The patriarch is the toplevel container for shapes in a sheet. It does
|
||||
* little other than act as a container for other shapes and groups.
|
||||
|
@ -37,13 +44,21 @@ public class HSSFPatriarch
|
|||
int x2 = 1023;
|
||||
int y2 = 255;
|
||||
|
||||
/**
|
||||
* The EscherAggregate we have been bound to.
|
||||
* (This will handle writing us out into records,
|
||||
* and building up our shapes from the records)
|
||||
*/
|
||||
private EscherAggregate boundAggregate;
|
||||
|
||||
/**
|
||||
* Creates the patriarch.
|
||||
*
|
||||
* @param sheet the sheet this patriarch is stored in.
|
||||
* @param sheet the sheet this patriarch is stored in.
|
||||
*/
|
||||
HSSFPatriarch(HSSFSheet sheet)
|
||||
HSSFPatriarch(HSSFSheet sheet, EscherAggregate boundAggregate)
|
||||
{
|
||||
this.boundAggregate = boundAggregate;
|
||||
this.sheet = sheet;
|
||||
}
|
||||
|
||||
|
@ -174,6 +189,39 @@ public class HSSFPatriarch
|
|||
this.y2 = y2;
|
||||
}
|
||||
|
||||
/**
|
||||
* Does this HSSFPatriarch contain a chart?
|
||||
* (Technically a reference to a chart, since they
|
||||
* get stored in a different block of records)
|
||||
* FIXME - detect chart in all cases (only seems
|
||||
* to work on some charts so far)
|
||||
*/
|
||||
public boolean containsChart() {
|
||||
// TODO - support charts properly in usermodel
|
||||
|
||||
// We're looking for a EscherOptRecord
|
||||
EscherOptRecord optRecord = (EscherOptRecord)
|
||||
boundAggregate.findFirstWithId(EscherOptRecord.RECORD_ID);
|
||||
if(optRecord == null) {
|
||||
// No opt record, can't have chart
|
||||
return false;
|
||||
}
|
||||
|
||||
for(Iterator it = optRecord.getEscherProperties().iterator(); it.hasNext();) {
|
||||
EscherProperty prop = (EscherProperty)it.next();
|
||||
if(prop.getPropertyNumber() == 896 && prop.isComplex()) {
|
||||
EscherComplexProperty cp = (EscherComplexProperty)prop;
|
||||
String str = StringUtil.getFromUnicodeLE(cp.getComplexData());
|
||||
System.err.println(str);
|
||||
if(str.equals("Chart 1\0")) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* The top left x coordinate of this group.
|
||||
*/
|
||||
|
@ -206,4 +254,10 @@ public class HSSFPatriarch
|
|||
return y2;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the aggregate escher record we're bound to
|
||||
*/
|
||||
protected EscherAggregate _getBoundAggregate() {
|
||||
return boundAggregate;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -22,15 +22,14 @@
|
|||
*/
|
||||
package org.apache.poi.hssf.usermodel;
|
||||
|
||||
import java.util.Iterator;
|
||||
import java.util.NoSuchElementException;
|
||||
|
||||
import org.apache.poi.hssf.model.Sheet;
|
||||
import org.apache.poi.hssf.model.Workbook;
|
||||
import org.apache.poi.hssf.record.CellValueRecordInterface;
|
||||
import org.apache.poi.hssf.record.RowRecord;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
import java.util.NoSuchElementException;
|
||||
|
||||
/**
|
||||
* High level representation of a row of a spreadsheet.
|
||||
*
|
||||
|
@ -157,11 +156,15 @@ public class HSSFRow
|
|||
* remove the HSSFCell from this row.
|
||||
* @param cell to remove
|
||||
*/
|
||||
public void removeCell(HSSFCell cell)
|
||||
{
|
||||
CellValueRecordInterface cval = cell.getCellValueRecord();
|
||||
public void removeCell(HSSFCell cell) {
|
||||
removeCell(cell, true);
|
||||
}
|
||||
private void removeCell(HSSFCell cell, boolean alsoRemoveRecords) {
|
||||
if(alsoRemoveRecords) {
|
||||
CellValueRecordInterface cval = cell.getCellValueRecord();
|
||||
sheet.removeValueRecord(getRowNum(), cval);
|
||||
}
|
||||
|
||||
sheet.removeValueRecord(getRowNum(), cval);
|
||||
short column=cell.getCellNum();
|
||||
if(cell!=null && column<cells.length)
|
||||
{
|
||||
|
@ -224,10 +227,43 @@ public class HSSFRow
|
|||
return rowNum;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the rows outline level. Increased as you
|
||||
* put it into more groups (outlines), reduced as
|
||||
* you take it out of them.
|
||||
* TODO - Should this really be public?
|
||||
*/
|
||||
protected int getOutlineLevel() {
|
||||
return row.getOutlineLevel();
|
||||
}
|
||||
|
||||
/**
|
||||
* Moves the supplied cell to a new column, which
|
||||
* must not already have a cell there!
|
||||
* @param cell The cell to move
|
||||
* @param newColumn The new column number (0 based)
|
||||
*/
|
||||
public void moveCell(HSSFCell cell, short newColumn) {
|
||||
// Ensure the destination is free
|
||||
if(cells.length > newColumn && cells[newColumn] != null) {
|
||||
throw new IllegalArgumentException("Asked to move cell to column " + newColumn + " but there's already a cell there");
|
||||
}
|
||||
|
||||
// Check it's one of ours
|
||||
if(! cells[cell.getCellNum()].equals(cell)) {
|
||||
throw new IllegalArgumentException("Asked to move a cell, but it didn't belong to our row");
|
||||
}
|
||||
|
||||
// Move the cell to the new position
|
||||
// (Don't remove the records though)
|
||||
removeCell(cell, false);
|
||||
cell.updateCellNum(newColumn);
|
||||
addCell(cell);
|
||||
}
|
||||
|
||||
/**
|
||||
* used internally to add a cell.
|
||||
*/
|
||||
|
||||
private void addCell(HSSFCell cell)
|
||||
{
|
||||
short column=cell.getCellNum();
|
||||
|
|
|
@ -121,7 +121,7 @@ public class HSSFShapeGroup
|
|||
}
|
||||
|
||||
/**
|
||||
* Sets the coordinate space of this group. All children are contrained
|
||||
* Sets the coordinate space of this group. All children are constrained
|
||||
* to these coordinates.
|
||||
*/
|
||||
public void setCoordinates( int x1, int y1, int x2, int y2 )
|
||||
|
@ -177,5 +177,4 @@ public class HSSFShapeGroup
|
|||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
}
|
|
@ -28,6 +28,7 @@ import org.apache.poi.hssf.model.Sheet;
|
|||
import org.apache.poi.hssf.model.Workbook;
|
||||
import org.apache.poi.hssf.record.*;
|
||||
import org.apache.poi.hssf.record.formula.Ptg;
|
||||
import org.apache.poi.hssf.record.formula.ReferencePtg;
|
||||
import org.apache.poi.hssf.util.HSSFCellRangeAddress;
|
||||
import org.apache.poi.hssf.util.HSSFDataValidation;
|
||||
import org.apache.poi.hssf.util.Region;
|
||||
|
@ -593,6 +594,26 @@ public class HSSFSheet
|
|||
region.getColumnTo());
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether a record must be inserted or not at generation to indicate that
|
||||
* formula must be recalculated when workbook is opened.
|
||||
* @param value true if an uncalced record must be inserted or not at generation
|
||||
*/
|
||||
public void setForceFormulaRecalculation(boolean value)
|
||||
{
|
||||
sheet.setUncalced(value);
|
||||
}
|
||||
/**
|
||||
* Whether a record must be inserted or not at generation to indicate that
|
||||
* formula must be recalculated when workbook is opened.
|
||||
* @return true if an uncalced record must be inserted or not at generation
|
||||
*/
|
||||
public boolean getForceFormulaRecalculation()
|
||||
{
|
||||
return sheet.getUncalced();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* determines whether the output is vertically centered on the page.
|
||||
* @param value true to vertically center, false otherwise.
|
||||
|
@ -1202,10 +1223,66 @@ public class HSSFSheet
|
|||
row2Replace.createCellFromRecord( cellRecord );
|
||||
sheet.addValueRecord( rowNum + n, cellRecord );
|
||||
}
|
||||
|
||||
// move comments if exist (can exist even if cell is null)
|
||||
HSSFComment comment = getCellComment(rowNum, col);
|
||||
if (comment != null) {
|
||||
comment.setRow(rowNum + n);
|
||||
}
|
||||
}
|
||||
}
|
||||
if ( endRow == lastrow || endRow + n > lastrow ) lastrow = Math.min( endRow + n, 65535 );
|
||||
if ( startRow == firstrow || startRow + n < firstrow ) firstrow = Math.max( startRow + n, 0 );
|
||||
|
||||
// Update any formulas on this sheet that point to
|
||||
// rows which have been moved
|
||||
updateFormulasAfterShift(startRow, endRow, n);
|
||||
}
|
||||
|
||||
/**
|
||||
* Called by shiftRows to update formulas on this sheet
|
||||
* to point to the new location of moved rows
|
||||
*/
|
||||
private void updateFormulasAfterShift(int startRow, int endRow, int n) {
|
||||
// Need to look at every cell on the sheet
|
||||
// Not just those that were moved
|
||||
Iterator ri = rowIterator();
|
||||
while(ri.hasNext()) {
|
||||
HSSFRow r = (HSSFRow)ri.next();
|
||||
Iterator ci = r.cellIterator();
|
||||
while(ci.hasNext()) {
|
||||
HSSFCell c = (HSSFCell)ci.next();
|
||||
if(c.getCellType() == HSSFCell.CELL_TYPE_FORMULA) {
|
||||
// Since it's a formula cell, process the
|
||||
// formula string, and look to see if
|
||||
// it contains any references
|
||||
FormulaParser fp = new FormulaParser(c.getCellFormula(), workbook.getWorkbook());
|
||||
fp.parse();
|
||||
|
||||
// Look for references, and update if needed
|
||||
Ptg[] ptgs = fp.getRPNPtg();
|
||||
boolean changed = false;
|
||||
for(int i=0; i<ptgs.length; i++) {
|
||||
if(ptgs[i] instanceof ReferencePtg) {
|
||||
ReferencePtg rptg = (ReferencePtg)ptgs[i];
|
||||
if(startRow <= rptg.getRowAsInt() &&
|
||||
rptg.getRowAsInt() <= endRow) {
|
||||
// References a row that moved
|
||||
rptg.setRow(rptg.getRowAsInt() + n);
|
||||
changed = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
// If any references were changed, then
|
||||
// re-create the formula string
|
||||
if(changed) {
|
||||
c.setCellFormula(
|
||||
fp.toFormulaString(ptgs)
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected void insertChartRecords( List records )
|
||||
|
@ -1431,7 +1508,7 @@ public class HSSFSheet
|
|||
*/
|
||||
public void dumpDrawingRecords(boolean fat)
|
||||
{
|
||||
sheet.aggregateDrawingRecords(book.getDrawingManager());
|
||||
sheet.aggregateDrawingRecords(book.getDrawingManager(), false);
|
||||
|
||||
EscherAggregate r = (EscherAggregate) getSheet().findFirstRecordBySid(EscherAggregate.sid);
|
||||
List escherRecords = r.getEscherRecords();
|
||||
|
@ -1448,9 +1525,10 @@ public class HSSFSheet
|
|||
}
|
||||
|
||||
/**
|
||||
* Creates the toplevel drawing patriarch. This will have the effect of
|
||||
* removing any existing drawings on this sheet.
|
||||
*
|
||||
* Creates the top-level drawing patriarch. This will have
|
||||
* the effect of removing any existing drawings on this
|
||||
* sheet.
|
||||
* This may then be used to add graphics or charts
|
||||
* @return The new patriarch.
|
||||
*/
|
||||
public HSSFPatriarch createDrawingPatriarch()
|
||||
|
@ -1458,15 +1536,58 @@ public class HSSFSheet
|
|||
// Create the drawing group if it doesn't already exist.
|
||||
book.createDrawingGroup();
|
||||
|
||||
sheet.aggregateDrawingRecords(book.getDrawingManager());
|
||||
sheet.aggregateDrawingRecords(book.getDrawingManager(), true);
|
||||
EscherAggregate agg = (EscherAggregate) sheet.findFirstRecordBySid(EscherAggregate.sid);
|
||||
HSSFPatriarch patriarch = new HSSFPatriarch(this);
|
||||
HSSFPatriarch patriarch = new HSSFPatriarch(this, agg);
|
||||
agg.clear(); // Initially the behaviour will be to clear out any existing shapes in the sheet when
|
||||
// creating a new patriarch.
|
||||
agg.setPatriarch(patriarch);
|
||||
return patriarch;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the top-level drawing patriach, if there is
|
||||
* one.
|
||||
* This will hold any graphics or charts for the sheet.
|
||||
* WARNING - calling this will trigger a parsing of the
|
||||
* associated escher records. Any that aren't supported
|
||||
* (such as charts and complex drawing types) will almost
|
||||
* certainly be lost or corrupted when written out. Only
|
||||
* use this with simple drawings, otherwise call
|
||||
* {@link HSSFSheet#createDrawingPatriarch()} and
|
||||
* start from scratch!
|
||||
*/
|
||||
public HSSFPatriarch getDrawingPatriarch() {
|
||||
book.findDrawingGroup();
|
||||
|
||||
// If there's now no drawing manager, then there's
|
||||
// no drawing escher records on the workbook
|
||||
if(book.getDrawingManager() == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
int found = sheet.aggregateDrawingRecords(
|
||||
book.getDrawingManager(), false
|
||||
);
|
||||
if(found == -1) {
|
||||
// Workbook has drawing stuff, but this sheet doesn't
|
||||
return null;
|
||||
}
|
||||
|
||||
// Grab our aggregate record, and wire it up
|
||||
EscherAggregate agg = (EscherAggregate) sheet.findFirstRecordBySid(EscherAggregate.sid);
|
||||
HSSFPatriarch patriarch = new HSSFPatriarch(this, agg);
|
||||
agg.setPatriarch(patriarch);
|
||||
|
||||
// Have it process the records into high level objects
|
||||
// as best it can do (this step may eat anything
|
||||
// that isn't supported, you were warned...)
|
||||
agg.convertRecordsToUserModel();
|
||||
|
||||
// Return what we could cope with
|
||||
return patriarch;
|
||||
}
|
||||
|
||||
/**
|
||||
* Expands or collapses a column group.
|
||||
*
|
||||
|
@ -1558,7 +1679,13 @@ public class HSSFSheet
|
|||
for (Iterator it = rowIterator(); it.hasNext();) {
|
||||
HSSFRow row = (HSSFRow) it.next();
|
||||
HSSFCell cell = row.getCell(column);
|
||||
if (cell == null) continue;
|
||||
|
||||
boolean isCellInMergedRegion = false;
|
||||
for (int i = 0 ; i < getNumMergedRegions() && ! isCellInMergedRegion; i++) {
|
||||
isCellInMergedRegion = getMergedRegionAt(i).contains(row.getRowNum(), column);
|
||||
}
|
||||
|
||||
if (cell == null | isCellInMergedRegion) continue;
|
||||
|
||||
HSSFCellStyle style = cell.getCellStyle();
|
||||
HSSFFont font = wb.getFontAt(style.getFontIndex());
|
||||
|
@ -1621,27 +1748,28 @@ public class HSSFSheet
|
|||
} else if (cell.getCellType() == HSSFCell.CELL_TYPE_BOOLEAN) {
|
||||
sval = String.valueOf(cell.getBooleanCellValue());
|
||||
}
|
||||
if(sval != null) {
|
||||
String txt = sval + defaultChar;
|
||||
str = new AttributedString(txt);
|
||||
copyAttributes(font, str, 0, txt.length());
|
||||
|
||||
String txt = sval + defaultChar;
|
||||
str = new AttributedString(txt);
|
||||
copyAttributes(font, str, 0, txt.length());
|
||||
|
||||
layout = new TextLayout(str.getIterator(), frc);
|
||||
if(style.getRotation() != 0){
|
||||
/*
|
||||
* Transform the text using a scale so that it's height is increased by a multiple of the leading,
|
||||
* and then rotate the text before computing the bounds. The scale results in some whitespace around
|
||||
* the unrotated top and bottom of the text that normally wouldn't be present if unscaled, but
|
||||
* is added by the standard Excel autosize.
|
||||
*/
|
||||
AffineTransform trans = new AffineTransform();
|
||||
trans.concatenate(AffineTransform.getRotateInstance(style.getRotation()*2.0*Math.PI/360.0));
|
||||
trans.concatenate(
|
||||
AffineTransform.getScaleInstance(1, fontHeightMultiple)
|
||||
);
|
||||
width = Math.max(width, layout.getOutline(trans).getBounds().getWidth() / defaultCharWidth);
|
||||
} else {
|
||||
width = Math.max(width, layout.getBounds().getWidth() / defaultCharWidth);
|
||||
layout = new TextLayout(str.getIterator(), frc);
|
||||
if(style.getRotation() != 0){
|
||||
/*
|
||||
* Transform the text using a scale so that it's height is increased by a multiple of the leading,
|
||||
* and then rotate the text before computing the bounds. The scale results in some whitespace around
|
||||
* the unrotated top and bottom of the text that normally wouldn't be present if unscaled, but
|
||||
* is added by the standard Excel autosize.
|
||||
*/
|
||||
AffineTransform trans = new AffineTransform();
|
||||
trans.concatenate(AffineTransform.getRotateInstance(style.getRotation()*2.0*Math.PI/360.0));
|
||||
trans.concatenate(
|
||||
AffineTransform.getScaleInstance(1, fontHeightMultiple)
|
||||
);
|
||||
width = Math.max(width, layout.getOutline(trans).getBounds().getWidth() / defaultCharWidth);
|
||||
} else {
|
||||
width = Math.max(width, layout.getBounds().getWidth() / defaultCharWidth);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1671,7 +1799,21 @@ public class HSSFSheet
|
|||
* @return cell comment or <code>null</code> if not found
|
||||
*/
|
||||
public HSSFComment getCellComment(int row, int column){
|
||||
return HSSFCell.findCellComment(sheet, row, column);
|
||||
// Don't call findCellComment directly, otherwise
|
||||
// two calls to this method will result in two
|
||||
// new HSSFComment instances, which is bad
|
||||
HSSFRow r = getRow(row);
|
||||
if(r != null) {
|
||||
HSSFCell c = r.getCell((short)column);
|
||||
if(c != null) {
|
||||
return c.getCellComment();
|
||||
} else {
|
||||
// No cell, so you will get new
|
||||
// objects every time, sorry...
|
||||
return HSSFCell.findCellComment(sheet, row, column);
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -445,6 +445,35 @@ public class HSSFWorkbook extends POIDocument
|
|||
return workbook.getSheetName(sheet);
|
||||
}
|
||||
|
||||
/**
|
||||
* check whether a sheet is hidden
|
||||
* @param sheet Number
|
||||
* @return True if sheet is hidden
|
||||
*/
|
||||
|
||||
public boolean isSheetHidden(int sheet) {
|
||||
if (sheet > (sheets.size() - 1))
|
||||
{
|
||||
throw new RuntimeException("Sheet out of bounds");
|
||||
}
|
||||
return workbook.isSheetHidden(sheet);
|
||||
}
|
||||
|
||||
/**
|
||||
* Hide or unhide a sheet
|
||||
*
|
||||
* @param sheetnum The sheet number
|
||||
* @param hidden True to mark the sheet as hidden, false otherwise
|
||||
*/
|
||||
|
||||
public void setSheetHidden(int sheet, boolean hidden) {
|
||||
if (sheet > (sheets.size() - 1))
|
||||
{
|
||||
throw new RuntimeException("Sheet out of bounds");
|
||||
}
|
||||
workbook.setSheetHidden(sheet,hidden);
|
||||
}
|
||||
|
||||
/*
|
||||
* get the sheet's index
|
||||
* @param name sheet name
|
||||
|
|
|
@ -18,15 +18,24 @@
|
|||
|
||||
package org.apache.poi.hssf.util;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.StringTokenizer;
|
||||
|
||||
public class AreaReference {
|
||||
|
||||
|
||||
private CellReference [] cells;
|
||||
private int dim;
|
||||
|
||||
/** Create an area ref from a string representation
|
||||
/**
|
||||
* Create an area ref from a string representation.
|
||||
* The area reference must be contiguous
|
||||
*/
|
||||
public AreaReference(String reference) {
|
||||
if(! isContiguous(reference)) {
|
||||
throw new IllegalArgumentException("References passed to the AreaReference must be contiguous, use generateContiguous(ref) if you have non-contiguous references");
|
||||
}
|
||||
|
||||
String[] refs = seperateAreaRefs(reference);
|
||||
dim = refs.length;
|
||||
cells = new CellReference[dim];
|
||||
|
@ -34,16 +43,73 @@ private int dim;
|
|||
cells[i]=new CellReference(refs[i]);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Is the reference for a contiguous (i.e.
|
||||
* unbroken) area, or is it made up of
|
||||
* several different parts?
|
||||
* (If it is, you will need to call
|
||||
* ....
|
||||
*/
|
||||
public static boolean isContiguous(String reference) {
|
||||
if(reference.indexOf(',') == -1) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Takes a non-contiguous area reference, and
|
||||
* returns an array of contiguous area references.
|
||||
*/
|
||||
public static AreaReference[] generateContiguous(String reference) {
|
||||
ArrayList refs = new ArrayList();
|
||||
StringTokenizer st = new StringTokenizer(reference, ",");
|
||||
while(st.hasMoreTokens()) {
|
||||
refs.add(
|
||||
new AreaReference(st.nextToken())
|
||||
);
|
||||
}
|
||||
return (AreaReference[])refs.toArray(new AreaReference[refs.size()]);
|
||||
}
|
||||
|
||||
//not sure if we need to be flexible here!
|
||||
/** return the dimensions of this area
|
||||
**/
|
||||
public int getDim() {
|
||||
return dim;
|
||||
}
|
||||
/** return the cell references that define this area */
|
||||
/**
|
||||
* Return the cell references that define this area
|
||||
* (i.e. the two corners)
|
||||
*/
|
||||
public CellReference[] getCells() {
|
||||
return cells;
|
||||
}
|
||||
/**
|
||||
* Returns a reference to every cell covered by this area
|
||||
*/
|
||||
public CellReference[] getAllReferencedCells() {
|
||||
// Special case for single cell reference
|
||||
if(cells.length == 1) {
|
||||
return cells;
|
||||
}
|
||||
// Interpolate between the two
|
||||
int minRow = Math.min(cells[0].getRow(), cells[1].getRow());
|
||||
int maxRow = Math.max(cells[0].getRow(), cells[1].getRow());
|
||||
int minCol = Math.min(cells[0].getCol(), cells[1].getCol());
|
||||
int maxCol = Math.max(cells[0].getCol(), cells[1].getCol());
|
||||
|
||||
ArrayList refs = new ArrayList();
|
||||
for(int row=minRow; row<=maxRow; row++) {
|
||||
for(int col=minCol; col<=maxCol; col++) {
|
||||
CellReference ref = new CellReference(row, col, cells[0].isRowAbsolute(), cells[0].isColAbsolute());
|
||||
ref.setSheetName(cells[0].getSheetName());
|
||||
refs.add(ref);
|
||||
}
|
||||
}
|
||||
return (CellReference[])refs.toArray(new CellReference[refs.size()]);
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
StringBuffer retval = new StringBuffer();
|
||||
|
|
|
@ -70,6 +70,10 @@ public class CellReference {
|
|||
public boolean isColAbsolute(){return colAbs;}
|
||||
public String getSheetName(){return sheetName;}
|
||||
|
||||
protected void setSheetName(String sheetName) {
|
||||
this.sheetName = sheetName;
|
||||
}
|
||||
|
||||
/**
|
||||
* takes in a column reference portion of a CellRef and converts it from
|
||||
* ALPHA-26 number format to 0-based base 10.
|
||||
|
|
|
@ -31,4 +31,7 @@ public interface POIFSConstants
|
|||
public static final int END_OF_CHAIN = -2;
|
||||
public static final int PROPERTY_SIZE = 0x0080;
|
||||
public static final int UNUSED_BLOCK = -1;
|
||||
|
||||
public static final byte[] OOXML_FILE_HEADER =
|
||||
new byte[] { 0x50, 0x4b, 0x03, 0x04 };
|
||||
} // end public interface POIFSConstants;
|
||||
|
|
|
@ -19,14 +19,19 @@
|
|||
|
||||
package org.apache.poi.poifs.filesystem;
|
||||
|
||||
import java.io.*;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.io.PushbackInputStream;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
import org.apache.poi.poifs.common.POIFSConstants;
|
||||
import org.apache.poi.poifs.dev.POIFSViewable;
|
||||
import org.apache.poi.poifs.property.DirectoryProperty;
|
||||
import org.apache.poi.poifs.property.DocumentProperty;
|
||||
import org.apache.poi.poifs.property.Property;
|
||||
import org.apache.poi.poifs.property.PropertyTable;
|
||||
import org.apache.poi.poifs.storage.BATBlock;
|
||||
|
@ -34,13 +39,14 @@ import org.apache.poi.poifs.storage.BlockAllocationTableReader;
|
|||
import org.apache.poi.poifs.storage.BlockAllocationTableWriter;
|
||||
import org.apache.poi.poifs.storage.BlockList;
|
||||
import org.apache.poi.poifs.storage.BlockWritable;
|
||||
import org.apache.poi.poifs.storage.HeaderBlockConstants;
|
||||
import org.apache.poi.poifs.storage.HeaderBlockReader;
|
||||
import org.apache.poi.poifs.storage.HeaderBlockWriter;
|
||||
import org.apache.poi.poifs.storage.RawDataBlock;
|
||||
import org.apache.poi.poifs.storage.RawDataBlockList;
|
||||
import org.apache.poi.poifs.storage.SmallBlockTableReader;
|
||||
import org.apache.poi.poifs.storage.SmallBlockTableWriter;
|
||||
import org.apache.poi.poifs.storage.SmallDocumentBlock;
|
||||
import org.apache.poi.util.IOUtils;
|
||||
import org.apache.poi.util.LongField;
|
||||
|
||||
/**
|
||||
* This is the main class of the POIFS system; it manages the entire
|
||||
|
@ -107,6 +113,35 @@ public class POIFSFileSystem
|
|||
.getChildren(), null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks that the supplied InputStream (which MUST
|
||||
* support mark and reset, or be a PushbackInputStream)
|
||||
* has a POIFS (OLE2) header at the start of it.
|
||||
* If your InputStream does not support mark / reset,
|
||||
* then wrap it in a PushBackInputStream, then be
|
||||
* sure to always use that, and not the original!
|
||||
* @param inp An InputStream which supports either mark/reset, or is a PushbackInputStream
|
||||
*/
|
||||
public static boolean hasPOIFSHeader(InputStream inp) throws IOException {
|
||||
// We want to peek at the first 8 bytes
|
||||
inp.mark(8);
|
||||
|
||||
byte[] header = new byte[8];
|
||||
IOUtils.readFully(inp, header);
|
||||
LongField signature = new LongField(HeaderBlockConstants._signature_offset, header);
|
||||
|
||||
// Wind back those 8 bytes
|
||||
if(inp instanceof PushbackInputStream) {
|
||||
PushbackInputStream pin = (PushbackInputStream)inp;
|
||||
pin.unread(header);
|
||||
} else {
|
||||
inp.reset();
|
||||
}
|
||||
|
||||
// Did it match the signature?
|
||||
return (signature.get() == HeaderBlockConstants._signature);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new document to be added to the root directory
|
||||
*
|
||||
|
|
|
@ -91,8 +91,11 @@ public class HeaderBlockReader
|
|||
if (signature.get() != _signature)
|
||||
{
|
||||
// Is it one of the usual suspects?
|
||||
if(_data[0] == 0x50 && _data[1] == 0x4b && _data[2] == 0x03 &&
|
||||
_data[3] == 0x04) {
|
||||
byte[] OOXML_FILE_HEADER = POIFSConstants.OOXML_FILE_HEADER;
|
||||
if(_data[0] == OOXML_FILE_HEADER[0] &&
|
||||
_data[1] == OOXML_FILE_HEADER[1] &&
|
||||
_data[2] == OOXML_FILE_HEADER[2] &&
|
||||
_data[3] == OOXML_FILE_HEADER[3]) {
|
||||
throw new OfficeXmlFileException("The supplied data appears to be in the Office 2007+ XML. POI only supports OLE2 Office documents");
|
||||
}
|
||||
|
||||
|
|
|
@ -42,34 +42,44 @@ public class RawDataBlock
|
|||
* @param stream the InputStream from which the data will be read
|
||||
*
|
||||
* @exception IOException on I/O errors, and if an insufficient
|
||||
* amount of data is read
|
||||
* amount of data is read (the InputStream must
|
||||
* be an exact multiple of the block size)
|
||||
*/
|
||||
|
||||
public RawDataBlock(final InputStream stream)
|
||||
throws IOException
|
||||
{
|
||||
_data = new byte[ POIFSConstants.BIG_BLOCK_SIZE ];
|
||||
throws IOException {
|
||||
this(stream, POIFSConstants.BIG_BLOCK_SIZE);
|
||||
}
|
||||
/**
|
||||
* Constructor RawDataBlock
|
||||
*
|
||||
* @param stream the InputStream from which the data will be read
|
||||
* @param blockSize the size of the POIFS blocks, normally 512 bytes {@link POIFSConstants#BIG_BLOCK_SIZE}
|
||||
*
|
||||
* @exception IOException on I/O errors, and if an insufficient
|
||||
* amount of data is read (the InputStream must
|
||||
* be an exact multiple of the block size)
|
||||
*/
|
||||
public RawDataBlock(final InputStream stream, int blockSize)
|
||||
throws IOException {
|
||||
_data = new byte[ blockSize ];
|
||||
int count = IOUtils.readFully(stream, _data);
|
||||
|
||||
if (count == -1)
|
||||
{
|
||||
if (count == -1) {
|
||||
_eof = true;
|
||||
}
|
||||
else if (count != POIFSConstants.BIG_BLOCK_SIZE)
|
||||
{
|
||||
if (count == -1)
|
||||
//Cant have -1 bytes read in the error message!
|
||||
count = 0;
|
||||
|
||||
else if (count != blockSize) {
|
||||
// IOUtils.readFully will always read the
|
||||
// requested number of bytes, unless it hits
|
||||
// an EOF
|
||||
_eof = true;
|
||||
String type = " byte" + ((count == 1) ? ("")
|
||||
: ("s"));
|
||||
|
||||
throw new IOException("Unable to read entire block; " + count
|
||||
+ type + " read; expected "
|
||||
+ POIFSConstants.BIG_BLOCK_SIZE + " bytes");
|
||||
+ type + " read before EOF; expected "
|
||||
+ blockSize + " bytes");
|
||||
}
|
||||
else
|
||||
{
|
||||
else {
|
||||
_eof = false;
|
||||
}
|
||||
}
|
||||
|
@ -82,7 +92,6 @@ public class RawDataBlock
|
|||
*
|
||||
* @exception IOException
|
||||
*/
|
||||
|
||||
public boolean eof()
|
||||
throws IOException
|
||||
{
|
||||
|
@ -98,7 +107,6 @@ public class RawDataBlock
|
|||
*
|
||||
* @exception IOException if there is no data
|
||||
*/
|
||||
|
||||
public byte [] getData()
|
||||
throws IOException
|
||||
{
|
||||
|
|
|
@ -58,11 +58,16 @@ public class IOUtils
|
|||
}
|
||||
|
||||
/**
|
||||
* Same as the normal <tt>in.read(b, off, len)</tt>, but tries to ensure that
|
||||
* the entire len number of bytes is read.
|
||||
* Same as the normal <tt>in.read(b, off, len)</tt>, but
|
||||
* tries to ensure that the entire len number of bytes
|
||||
* is read.
|
||||
* <p>
|
||||
* If the end of file is reached before any bytes are read, returns -1.
|
||||
* Otherwise, returns the number of bytes read.
|
||||
* If the end of file is reached before any bytes
|
||||
* are read, returns -1.
|
||||
* If the end of the file is reached after some bytes are
|
||||
* read, returns the number of bytes read.
|
||||
* If the end of the file isn't reached before len
|
||||
* bytes have been read, will return len bytes.
|
||||
*/
|
||||
public static int readFully(InputStream in, byte[] b, int off, int len)
|
||||
throws IOException
|
||||
|
@ -80,4 +85,3 @@ public class IOUtils
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -41,7 +41,9 @@ public class PowerPointExtractor extends POITextExtractor
|
|||
private HSLFSlideShow _hslfshow;
|
||||
private SlideShow _show;
|
||||
private Slide[] _slides;
|
||||
private Notes[] _notes;
|
||||
|
||||
private boolean slidesByDefault = true;
|
||||
private boolean notesByDefault = false;
|
||||
|
||||
/**
|
||||
* Basic extractor. Returns all the text, and optionally all the notes
|
||||
|
@ -99,7 +101,6 @@ public class PowerPointExtractor extends POITextExtractor
|
|||
_hslfshow = ss;
|
||||
_show = new SlideShow(_hslfshow);
|
||||
_slides = _show.getSlides();
|
||||
_notes = _show.getNotes();
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -110,23 +111,39 @@ public class PowerPointExtractor extends POITextExtractor
|
|||
_hslfshow = null;
|
||||
_show = null;
|
||||
_slides = null;
|
||||
_notes = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Should a call to getText() return slide text?
|
||||
* Default is yes
|
||||
*/
|
||||
public void setSlidesByDefault(boolean slidesByDefault) {
|
||||
this.slidesByDefault = slidesByDefault;
|
||||
}
|
||||
/**
|
||||
* Should a call to getText() return notes text?
|
||||
* Default is no
|
||||
*/
|
||||
public void setNotesByDefault(boolean notesByDefault) {
|
||||
this.notesByDefault = notesByDefault;
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetches all the slide text from the slideshow, but not the notes
|
||||
*/
|
||||
public String getText() {
|
||||
return getText(true,false);
|
||||
}
|
||||
/**
|
||||
* Fetches all the slide text from the slideshow,
|
||||
* but not the notes, unless you've called
|
||||
* setSlidesByDefault() and setNotesByDefault()
|
||||
* to change this
|
||||
*/
|
||||
public String getText() {
|
||||
return getText(slidesByDefault,notesByDefault);
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetches all the notes text from the slideshow, but not the slide text
|
||||
*/
|
||||
public String getNotes() {
|
||||
return getText(false,true);
|
||||
}
|
||||
/**
|
||||
* Fetches all the notes text from the slideshow, but not the slide text
|
||||
*/
|
||||
public String getNotes() {
|
||||
return getText(false,true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetches text from the slideshow, be it slide text or note text.
|
||||
|
@ -154,7 +171,7 @@ public class PowerPointExtractor extends POITextExtractor
|
|||
}
|
||||
}
|
||||
if(getNoteText) {
|
||||
ret.append(" ");
|
||||
ret.append("\n");
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -24,7 +24,12 @@ import java.util.LinkedList;
|
|||
import java.util.Vector;
|
||||
|
||||
import org.apache.poi.hslf.model.textproperties.TextPropCollection;
|
||||
import org.apache.poi.hslf.record.*;
|
||||
import org.apache.poi.hslf.record.Record;
|
||||
import org.apache.poi.hslf.record.RecordContainer;
|
||||
import org.apache.poi.hslf.record.StyleTextPropAtom;
|
||||
import org.apache.poi.hslf.record.TextBytesAtom;
|
||||
import org.apache.poi.hslf.record.TextCharsAtom;
|
||||
import org.apache.poi.hslf.record.TextHeaderAtom;
|
||||
import org.apache.poi.hslf.usermodel.RichTextRun;
|
||||
import org.apache.poi.hslf.usermodel.SlideShow;
|
||||
import org.apache.poi.util.StringUtil;
|
||||
|
@ -254,7 +259,68 @@ public class TextRun
|
|||
// Update methods follow
|
||||
|
||||
/**
|
||||
* Saves the given string to the records. Doesn't touch the stylings.
|
||||
* Adds the supplied text onto the end of the TextRun,
|
||||
* creating a new RichTextRun (returned) for it to
|
||||
* sit in.
|
||||
* In many cases, before calling this, you'll want to add
|
||||
* a newline onto the end of your last RichTextRun
|
||||
*/
|
||||
public RichTextRun appendText(String s) {
|
||||
// We will need a StyleTextProp atom
|
||||
ensureStyleAtomPresent();
|
||||
|
||||
// First up, append the text to the
|
||||
// underlying text atom
|
||||
int oldSize = getRawText().length();
|
||||
storeText(
|
||||
getRawText() + s
|
||||
);
|
||||
|
||||
// If either of the previous styles overran
|
||||
// the text by one, we need to shuffle that
|
||||
// extra character onto the new ones
|
||||
int pOverRun = _styleAtom.getParagraphTextLengthCovered() - oldSize;
|
||||
int cOverRun = _styleAtom.getCharacterTextLengthCovered() - oldSize;
|
||||
if(pOverRun > 0) {
|
||||
TextPropCollection tpc = (TextPropCollection)
|
||||
_styleAtom.getParagraphStyles().getLast();
|
||||
tpc.updateTextSize(
|
||||
tpc.getCharactersCovered() - pOverRun
|
||||
);
|
||||
}
|
||||
if(cOverRun > 0) {
|
||||
TextPropCollection tpc = (TextPropCollection)
|
||||
_styleAtom.getCharacterStyles().getLast();
|
||||
tpc.updateTextSize(
|
||||
tpc.getCharactersCovered() - cOverRun
|
||||
);
|
||||
}
|
||||
|
||||
// Next, add the styles for its paragraph and characters
|
||||
TextPropCollection newPTP =
|
||||
_styleAtom.addParagraphTextPropCollection(s.length()+pOverRun);
|
||||
TextPropCollection newCTP =
|
||||
_styleAtom.addCharacterTextPropCollection(s.length()+cOverRun);
|
||||
|
||||
// Now, create the new RichTextRun
|
||||
RichTextRun nr = new RichTextRun(
|
||||
this, oldSize, s.length(),
|
||||
newPTP, newCTP, false, false
|
||||
);
|
||||
|
||||
// Add the new RichTextRun onto our list
|
||||
RichTextRun[] newRuns = new RichTextRun[_rtRuns.length+1];
|
||||
System.arraycopy(_rtRuns, 0, newRuns, 0, _rtRuns.length);
|
||||
newRuns[newRuns.length-1] = nr;
|
||||
_rtRuns = newRuns;
|
||||
|
||||
// And return the new run to the caller
|
||||
return nr;
|
||||
}
|
||||
|
||||
/**
|
||||
* Saves the given string to the records. Doesn't
|
||||
* touch the stylings.
|
||||
*/
|
||||
private void storeText(String s) {
|
||||
// Remove a single trailing \n, as there is an implicit one at the
|
||||
|
|
|
@ -19,17 +19,19 @@
|
|||
|
||||
package org.apache.poi.hslf.record;
|
||||
|
||||
import org.apache.poi.hslf.model.textproperties.*;
|
||||
import org.apache.poi.util.LittleEndian;
|
||||
import org.apache.poi.util.POILogger;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.util.LinkedList;
|
||||
import java.util.Vector;
|
||||
import java.util.List;
|
||||
import java.util.Iterator;
|
||||
import java.util.LinkedList;
|
||||
|
||||
import org.apache.poi.hslf.model.textproperties.AlignmentTextProp;
|
||||
import org.apache.poi.hslf.model.textproperties.CharFlagsTextProp;
|
||||
import org.apache.poi.hslf.model.textproperties.ParagraphFlagsTextProp;
|
||||
import org.apache.poi.hslf.model.textproperties.TextProp;
|
||||
import org.apache.poi.hslf.model.textproperties.TextPropCollection;
|
||||
import org.apache.poi.util.LittleEndian;
|
||||
import org.apache.poi.util.POILogger;
|
||||
|
||||
/**
|
||||
* A StyleTextPropAtom (type 4001). Holds basic character properties
|
||||
|
@ -89,6 +91,37 @@ public class StyleTextPropAtom extends RecordAtom
|
|||
*/
|
||||
public void setCharacterStyles(LinkedList cs) { charStyles = cs; }
|
||||
|
||||
/**
|
||||
* Returns how many characters the paragraph's
|
||||
* TextPropCollections cover.
|
||||
* (May be one or two more than the underlying text does,
|
||||
* due to having extra characters meaning something
|
||||
* special to powerpoint)
|
||||
*/
|
||||
public int getParagraphTextLengthCovered() {
|
||||
return getCharactersCovered(paragraphStyles);
|
||||
}
|
||||
/**
|
||||
* Returns how many characters the character's
|
||||
* TextPropCollections cover.
|
||||
* (May be one or two more than the underlying text does,
|
||||
* due to having extra characters meaning something
|
||||
* special to powerpoint)
|
||||
*/
|
||||
public int getCharacterTextLengthCovered() {
|
||||
return getCharactersCovered(charStyles);
|
||||
}
|
||||
private int getCharactersCovered(LinkedList styles) {
|
||||
int length = 0;
|
||||
Iterator it = styles.iterator();
|
||||
while(it.hasNext()) {
|
||||
TextPropCollection tpc =
|
||||
(TextPropCollection)it.next();
|
||||
length += tpc.getCharactersCovered();
|
||||
}
|
||||
return length;
|
||||
}
|
||||
|
||||
/** All the different kinds of paragraph properties we might handle */
|
||||
public static TextProp[] paragraphTextPropTypes = new TextProp[] {
|
||||
new ParagraphFlagsTextProp(),
|
||||
|
@ -356,7 +389,6 @@ public class StyleTextPropAtom extends RecordAtom
|
|||
return tpc;
|
||||
}
|
||||
|
||||
|
||||
/* ************************************************************************ */
|
||||
|
||||
|
||||
|
|
|
@ -20,25 +20,28 @@
|
|||
|
||||
package org.apache.poi.hslf.usermodel;
|
||||
|
||||
import org.apache.poi.hslf.model.*;
|
||||
import org.apache.poi.hslf.model.Shape;
|
||||
import org.apache.poi.hslf.model.textproperties.*;
|
||||
import org.apache.poi.hslf.record.ColorSchemeAtom;
|
||||
import org.apache.poi.hslf.exceptions.HSLFException;
|
||||
import java.awt.Color;
|
||||
|
||||
import java.awt.*;
|
||||
import org.apache.poi.hslf.model.MasterSheet;
|
||||
import org.apache.poi.hslf.model.Shape;
|
||||
import org.apache.poi.hslf.model.Sheet;
|
||||
import org.apache.poi.hslf.model.TextRun;
|
||||
import org.apache.poi.hslf.model.textproperties.BitMaskTextProp;
|
||||
import org.apache.poi.hslf.model.textproperties.CharFlagsTextProp;
|
||||
import org.apache.poi.hslf.model.textproperties.ParagraphFlagsTextProp;
|
||||
import org.apache.poi.hslf.model.textproperties.TextProp;
|
||||
import org.apache.poi.hslf.model.textproperties.TextPropCollection;
|
||||
import org.apache.poi.hslf.record.ColorSchemeAtom;
|
||||
|
||||
|
||||
/**
|
||||
* Represents a run of text, all with the same style
|
||||
*
|
||||
* TODO: get access to the font/character properties
|
||||
*
|
||||
* @author Nick Burch
|
||||
* TODO: finish all the getters and setters to the
|
||||
* font/character/paragraph properties (currently only
|
||||
* has some of them)
|
||||
*/
|
||||
|
||||
public class RichTextRun
|
||||
{
|
||||
public class RichTextRun {
|
||||
/** The TextRun we belong to */
|
||||
private TextRun parentRun;
|
||||
/** The SlideShow we belong to */
|
||||
|
|
|
@ -217,14 +217,66 @@ public class HSSFFormulaEvaluator {
|
|||
|
||||
|
||||
/**
|
||||
* If cell contains formula, it evaluates the formula, and puts the
|
||||
* formula result back into the cell.
|
||||
* Else if cell does not contain formula, this method leaves the cell
|
||||
* unchanged. Note that the same instance of HSSFCell is returned to
|
||||
* If cell contains formula, it evaluates the formula,
|
||||
* and saves the result of the formula. The cell
|
||||
* remains as a formula cell.
|
||||
* Else if cell does not contain formula, this method leaves
|
||||
* the cell unchanged.
|
||||
* Note that the type of the formula result is returned,
|
||||
* so you know what kind of value is also stored with
|
||||
* the formula.
|
||||
* <pre>
|
||||
* int evaluatedCellType = evaluator.evaluateFormulaCell(cell);
|
||||
* </pre>
|
||||
* Be aware that your cell will hold both the formula,
|
||||
* and the result. If you want the cell replaced with
|
||||
* the result of the formula, use {@link #evaluateInCell(HSSFCell)}
|
||||
* @param cell The cell to evaluate
|
||||
* @return The type of the formula result (the cell's type remains as HSSFCell.CELL_TYPE_FORMULA however)
|
||||
*/
|
||||
public int evaluateFormulaCell(HSSFCell cell) {
|
||||
if (cell != null) {
|
||||
switch (cell.getCellType()) {
|
||||
case HSSFCell.CELL_TYPE_FORMULA:
|
||||
CellValue cv = getCellValueForEval(internalEvaluate(cell, row, sheet, workbook));
|
||||
switch (cv.getCellType()) {
|
||||
case HSSFCell.CELL_TYPE_BOOLEAN:
|
||||
cell.setCellValue(cv.getBooleanValue());
|
||||
break;
|
||||
case HSSFCell.CELL_TYPE_ERROR:
|
||||
cell.setCellValue(cv.getErrorValue());
|
||||
break;
|
||||
case HSSFCell.CELL_TYPE_NUMERIC:
|
||||
cell.setCellValue(cv.getNumberValue());
|
||||
break;
|
||||
case HSSFCell.CELL_TYPE_STRING:
|
||||
cell.setCellValue(cv.getRichTextStringValue());
|
||||
break;
|
||||
case HSSFCell.CELL_TYPE_BLANK:
|
||||
break;
|
||||
case HSSFCell.CELL_TYPE_FORMULA: // this will never happen, we have already evaluated the formula
|
||||
break;
|
||||
}
|
||||
return cv.getCellType();
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
/**
|
||||
* If cell contains formula, it evaluates the formula, and
|
||||
* puts the formula result back into the cell, in place
|
||||
* of the old formula.
|
||||
* Else if cell does not contain formula, this method leaves
|
||||
* the cell unchanged.
|
||||
* Note that the same instance of HSSFCell is returned to
|
||||
* allow chained calls like:
|
||||
* <pre>
|
||||
* int evaluatedCellType = evaluator.evaluateInCell(cell).getCellType();
|
||||
* </pre>
|
||||
* Be aware that your cell value will be changed to hold the
|
||||
* result of the formula. If you simply want the formula
|
||||
* value computed for you, use {@link #evaluateFormulaCell(HSSFCell)}
|
||||
* @param cell
|
||||
*/
|
||||
public HSSFCell evaluateInCell(HSSFCell cell) {
|
||||
|
|
|
@ -58,7 +58,7 @@ public class TableRow
|
|||
p = getParagraph(end);
|
||||
s = p.text();
|
||||
}
|
||||
_cells[cellIndex] = new TableCell(start, end, this, levelNum,
|
||||
_cells[cellIndex] = new TableCell(start, end+1, this, levelNum,
|
||||
_tprops.getRgtc()[cellIndex],
|
||||
_tprops.getRgdxaCenter()[cellIndex],
|
||||
_tprops.getRgdxaCenter()[cellIndex+1]-_tprops.getRgdxaCenter()[cellIndex]);
|
||||
|
|
Binary file not shown.
Binary file not shown.
|
@ -0,0 +1,26 @@
|
|||
Author = Nick Burch
|
||||
Title = SlideShow Sample
|
||||
Subject = A sample slideshow
|
||||
Keywords = Sample Testing
|
||||
Comments = This is a sample slideshow, for use with testing etc
|
||||
|
||||
(Slide 1)
|
||||
Title of the first slide
|
||||
|
||||
Subtitle of the first slide
|
||||
|
||||
This bit is in italic green
|
||||
|
||||
(Notes 1)
|
||||
I am the notes of the first slide
|
||||
|
||||
(Slide 2)
|
||||
This is the second slide
|
||||
|
||||
* It has bullet points on it
|
||||
* They’re fun, aren’t they?
|
||||
* Especially in a different font like Arial Black at 16 point!
|
||||
|
||||
(Notes 2)
|
||||
These are the notes of the 2nd slide
|
||||
THIS LINE IS BOLD
|
|
@ -73,6 +73,29 @@ public class TextExtractor extends TestCase {
|
|||
ensureTwoStringsTheSame(expectText, notesText);
|
||||
}
|
||||
|
||||
public void testReadBoth() throws Exception {
|
||||
String[] slText = new String[] {
|
||||
"This is a test title\nThis is a test subtitle\nThis is on page 1\n",
|
||||
"This is the title on page 2\nThis is page two\nIt has several blocks of text\nNone of them have formatting\n"
|
||||
};
|
||||
String[] ntText = new String[] {
|
||||
"These are the notes for page 1\n",
|
||||
"These are the notes on page two, again lacking formatting\n"
|
||||
};
|
||||
|
||||
ppe.setSlidesByDefault(true);
|
||||
ppe.setNotesByDefault(false);
|
||||
assertEquals(slText[0]+slText[1], ppe.getText());
|
||||
|
||||
ppe.setSlidesByDefault(false);
|
||||
ppe.setNotesByDefault(true);
|
||||
assertEquals(ntText[0]+ntText[1], ppe.getText());
|
||||
|
||||
ppe.setSlidesByDefault(true);
|
||||
ppe.setNotesByDefault(true);
|
||||
assertEquals(slText[0]+slText[1]+"\n"+ntText[0]+ntText[1], ppe.getText());
|
||||
}
|
||||
|
||||
/**
|
||||
* Test that when presented with a PPT file missing the odd
|
||||
* core record, we can still get the rest of the text out
|
||||
|
|
|
@ -16,16 +16,22 @@
|
|||
*/
|
||||
package org.apache.poi.hslf.usermodel;
|
||||
|
||||
import java.io.*;
|
||||
import java.awt.*;
|
||||
|
||||
import org.apache.poi.hslf.HSLFSlideShow;
|
||||
import org.apache.poi.hslf.model.*;
|
||||
import org.apache.poi.hslf.record.Record;
|
||||
import org.apache.poi.hslf.record.SlideListWithText;
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileOutputStream;
|
||||
|
||||
import junit.framework.TestCase;
|
||||
|
||||
import org.apache.poi.hslf.HSLFSlideShow;
|
||||
import org.apache.poi.hslf.model.Slide;
|
||||
import org.apache.poi.hslf.model.SlideMaster;
|
||||
import org.apache.poi.hslf.model.TextBox;
|
||||
import org.apache.poi.hslf.model.TextRun;
|
||||
import org.apache.poi.hslf.record.Record;
|
||||
import org.apache.poi.hslf.record.SlideListWithText;
|
||||
|
||||
/**
|
||||
* Test that the friendly getters and setters on RichTextRun
|
||||
* behave as expected.
|
||||
|
@ -549,4 +555,75 @@ if(false) {
|
|||
assertEquals(0, rt.getBulletOffset());
|
||||
assertEquals('\u263A', rt.getBulletChar());
|
||||
}
|
||||
|
||||
public void testAddText() throws Exception {
|
||||
FileInputStream is = new FileInputStream(new File(System.getProperty("HSLF.testdata.path"), "bullets.ppt"));
|
||||
SlideShow ppt = new SlideShow(is);
|
||||
is.close();
|
||||
assertTrue("No Exceptions while reading file", true);
|
||||
|
||||
RichTextRun rt;
|
||||
TextRun[] txt;
|
||||
Slide[] slides = ppt.getSlides();
|
||||
|
||||
assertEquals(2, slides.length);
|
||||
txt = slides[0].getTextRuns();
|
||||
assertEquals(2, txt.length);
|
||||
|
||||
assertEquals("Title text", txt[0].getRawText());
|
||||
assertEquals(1, txt[0].getRichTextRuns().length);
|
||||
rt = txt[0].getRichTextRuns()[0];
|
||||
assertFalse(rt.isBullet());
|
||||
|
||||
// Add some new text
|
||||
txt[0].appendText("Foo! I'm new!");
|
||||
assertEquals(2, txt[0].getRichTextRuns().length);
|
||||
|
||||
rt = txt[0].getRichTextRuns()[0];
|
||||
assertFalse(rt.isBold());
|
||||
assertEquals("Title text", rt.getText());
|
||||
rt = txt[0].getRichTextRuns()[1];
|
||||
assertFalse(rt.isBold());
|
||||
assertEquals("Foo! I'm new!", rt.getText());
|
||||
rt.setBold(true);
|
||||
|
||||
// And some more
|
||||
txt[0].appendText("Me too!");
|
||||
assertEquals(3, txt[0].getRichTextRuns().length);
|
||||
rt = txt[0].getRichTextRuns()[0];
|
||||
assertFalse(rt.isBold());
|
||||
assertEquals("Title text", rt.getText());
|
||||
rt = txt[0].getRichTextRuns()[1];
|
||||
assertTrue(rt.isBold());
|
||||
assertEquals("Foo! I'm new!", rt.getText());
|
||||
rt = txt[0].getRichTextRuns()[2];
|
||||
assertFalse(rt.isBold());
|
||||
assertEquals("Me too!", rt.getText());
|
||||
|
||||
// Save and re-open
|
||||
ByteArrayOutputStream out = new ByteArrayOutputStream();
|
||||
ppt.write(out);
|
||||
out.close();
|
||||
|
||||
ppt = new SlideShow(new ByteArrayInputStream(out.toByteArray()));
|
||||
slides = ppt.getSlides();
|
||||
|
||||
assertEquals(2, slides.length);
|
||||
|
||||
txt = slides[0].getTextRuns();
|
||||
assertEquals(2, txt.length);
|
||||
assertEquals(3, txt[0].getRichTextRuns().length);
|
||||
rt = txt[0].getRichTextRuns()[0];
|
||||
assertFalse(rt.isBold());
|
||||
assertEquals("Title text", rt.getText());
|
||||
rt = txt[0].getRichTextRuns()[1];
|
||||
assertTrue(rt.isBold());
|
||||
assertEquals("Foo! I'm new!", rt.getText());
|
||||
rt = txt[0].getRichTextRuns()[2];
|
||||
assertFalse(rt.isBold());
|
||||
assertEquals("Me too!", rt.getText());
|
||||
|
||||
// FileOutputStream fout = new FileOutputStream("/tmp/foo.ppt");
|
||||
// ppt.write(fout);
|
||||
}
|
||||
}
|
||||
|
|
Binary file not shown.
Binary file not shown.
|
@ -0,0 +1,83 @@
|
|||
|
||||
/* ====================================================================
|
||||
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.model;
|
||||
|
||||
import junit.framework.TestCase;
|
||||
|
||||
import org.apache.poi.hssf.record.formula.FuncVarPtg;
|
||||
import org.apache.poi.hssf.record.formula.NamePtg;
|
||||
import org.apache.poi.hssf.record.formula.Ptg;
|
||||
import org.apache.poi.hssf.usermodel.HSSFFormulaEvaluator;
|
||||
import org.apache.poi.hssf.usermodel.HSSFName;
|
||||
import org.apache.poi.hssf.usermodel.HSSFSheet;
|
||||
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
|
||||
|
||||
/**
|
||||
* Test the low level formula parser functionality,
|
||||
* but using parts which need to use the
|
||||
* HSSFFormulaEvaluator, which is in scratchpad
|
||||
*/
|
||||
public class TestFormulaParserSP extends TestCase {
|
||||
|
||||
public TestFormulaParserSP(String name) {
|
||||
super(name);
|
||||
}
|
||||
|
||||
public void testWithNamedRange() throws Exception {
|
||||
HSSFWorkbook workbook = new HSSFWorkbook();
|
||||
FormulaParser fp;
|
||||
Ptg[] ptgs;
|
||||
|
||||
HSSFSheet s = workbook.createSheet("Foo");
|
||||
s.createRow(0).createCell((short)0).setCellValue(1.1);
|
||||
s.createRow(1).createCell((short)0).setCellValue(2.3);
|
||||
s.createRow(2).createCell((short)2).setCellValue(3.1);
|
||||
|
||||
HSSFName name = workbook.createName();
|
||||
name.setNameName("testName");
|
||||
name.setReference("A1:A2");
|
||||
|
||||
fp = HSSFFormulaEvaluator.getUnderlyingParser(workbook, "SUM(testName)");
|
||||
fp.parse();
|
||||
ptgs = fp.getRPNPtg();
|
||||
assertTrue("two tokens expected, got "+ptgs.length,ptgs.length == 2);
|
||||
assertEquals(NamePtg.class, ptgs[0].getClass());
|
||||
assertEquals(FuncVarPtg.class, ptgs[1].getClass());
|
||||
|
||||
// Now make it a single cell
|
||||
name.setReference("C3");
|
||||
|
||||
fp = HSSFFormulaEvaluator.getUnderlyingParser(workbook, "SUM(testName)");
|
||||
fp.parse();
|
||||
ptgs = fp.getRPNPtg();
|
||||
assertTrue("two tokens expected, got "+ptgs.length,ptgs.length == 2);
|
||||
assertEquals(NamePtg.class, ptgs[0].getClass());
|
||||
assertEquals(FuncVarPtg.class, ptgs[1].getClass());
|
||||
|
||||
// And make it non-contiguous
|
||||
name.setReference("A1:A2,C3");
|
||||
fp = HSSFFormulaEvaluator.getUnderlyingParser(workbook, "SUM(testName)");
|
||||
fp.parse();
|
||||
ptgs = fp.getRPNPtg();
|
||||
assertTrue("two tokens expected, got "+ptgs.length,ptgs.length == 2);
|
||||
assertEquals(NamePtg.class, ptgs[0].getClass());
|
||||
assertEquals(FuncVarPtg.class, ptgs[1].getClass());
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,93 @@
|
|||
/* ====================================================================
|
||||
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.usermodel;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
|
||||
import org.apache.poi.hssf.record.FormulaRecord;
|
||||
import org.apache.poi.hssf.record.aggregates.FormulaRecordAggregate;
|
||||
import org.apache.poi.hssf.record.formula.ExpPtg;
|
||||
import org.apache.poi.hssf.util.CellReference;
|
||||
|
||||
import junit.framework.TestCase;
|
||||
|
||||
public class TestBug42464 extends TestCase {
|
||||
String dirname;
|
||||
|
||||
protected void setUp() throws Exception {
|
||||
super.setUp();
|
||||
dirname = System.getProperty("HSSF.testdata.path");
|
||||
}
|
||||
|
||||
public void testOKFile() throws Exception {
|
||||
HSSFWorkbook wb = new HSSFWorkbook(
|
||||
new FileInputStream(new File(dirname,"42464-ExpPtg-ok.xls"))
|
||||
);
|
||||
process(wb);
|
||||
}
|
||||
public void testExpSharedBadFile() throws Exception {
|
||||
HSSFWorkbook wb = new HSSFWorkbook(
|
||||
new FileInputStream(new File(dirname,"42464-ExpPtg-bad.xls"))
|
||||
);
|
||||
process(wb);
|
||||
}
|
||||
|
||||
protected void process(HSSFWorkbook wb) {
|
||||
for(int i=0; i<wb.getNumberOfSheets(); i++) {
|
||||
HSSFSheet s = wb.getSheetAt(i);
|
||||
HSSFFormulaEvaluator eval =
|
||||
new HSSFFormulaEvaluator(s, wb);
|
||||
|
||||
Iterator it = s.rowIterator();
|
||||
while(it.hasNext()) {
|
||||
HSSFRow r = (HSSFRow)it.next();
|
||||
eval.setCurrentRow(r);
|
||||
process(r, eval);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected void process(HSSFRow row, HSSFFormulaEvaluator eval) {
|
||||
Iterator it = row.cellIterator();
|
||||
while(it.hasNext()) {
|
||||
HSSFCell cell = (HSSFCell)it.next();
|
||||
if(cell.getCellType() == HSSFCell.CELL_TYPE_FORMULA) {
|
||||
FormulaRecordAggregate record = (FormulaRecordAggregate)
|
||||
cell.getCellValueRecord();
|
||||
FormulaRecord r = record.getFormulaRecord();
|
||||
List ptgs = r.getParsedExpression();
|
||||
|
||||
String cellRef = (new CellReference(row.getRowNum(), cell.getCellNum())).toString();
|
||||
if(cellRef.equals("BP24")) {
|
||||
System.out.print(cellRef);
|
||||
System.out.println(" - has " + r.getNumberOfExpressionTokens() + " ptgs over " + r.getExpressionLength() + " tokens:");
|
||||
for(int i=0; i<ptgs.size(); i++) {
|
||||
String c = ptgs.get(i).getClass().toString();
|
||||
System.out.println("\t" + c.substring(c.lastIndexOf('.')+1) );
|
||||
}
|
||||
System.out.println("-> " + cell.getCellFormula());
|
||||
}
|
||||
|
||||
eval.evaluate(cell);
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,117 @@
|
|||
package org.apache.poi.hssf.usermodel;
|
||||
|
||||
import java.util.Iterator;
|
||||
|
||||
import junit.framework.TestCase;
|
||||
|
||||
/**
|
||||
* Tests to show that our documentation at
|
||||
* http://poi.apache.org/hssf/eval.html
|
||||
* all actually works as we'd expect them to
|
||||
*/
|
||||
public class TestFormulaEvaluatorDocs extends TestCase {
|
||||
protected void setUp() throws Exception {
|
||||
super.setUp();
|
||||
}
|
||||
|
||||
/**
|
||||
* http://poi.apache.org/hssf/eval.html#EvaluateAll
|
||||
*/
|
||||
public void testEvaluateAll() throws Exception {
|
||||
HSSFWorkbook wb = new HSSFWorkbook();
|
||||
HSSFSheet s1 = wb.createSheet();
|
||||
HSSFSheet s2 = wb.createSheet();
|
||||
wb.setSheetName(0, "S1");
|
||||
wb.setSheetName(1, "S2");
|
||||
|
||||
HSSFRow s1r1 = s1.createRow(0);
|
||||
HSSFRow s1r2 = s1.createRow(1);
|
||||
HSSFRow s2r1 = s2.createRow(0);
|
||||
|
||||
HSSFCell s1r1c1 = s1r1.createCell((short)0);
|
||||
HSSFCell s1r1c2 = s1r1.createCell((short)1);
|
||||
HSSFCell s1r1c3 = s1r1.createCell((short)2);
|
||||
s1r1c1.setCellValue(22.3);
|
||||
s1r1c2.setCellValue(33.4);
|
||||
s1r1c3.setCellFormula("SUM(A1:B1)");
|
||||
|
||||
HSSFCell s1r2c1 = s1r2.createCell((short)0);
|
||||
HSSFCell s1r2c2 = s1r2.createCell((short)1);
|
||||
HSSFCell s1r2c3 = s1r2.createCell((short)2);
|
||||
s1r2c1.setCellValue(-1.2);
|
||||
s1r2c2.setCellValue(-3.4);
|
||||
s1r2c3.setCellFormula("SUM(A2:B2)");
|
||||
|
||||
HSSFCell s2r1c1 = s2r1.createCell((short)0);
|
||||
s2r1c1.setCellFormula("S1!A1");
|
||||
|
||||
// Not evaluated yet
|
||||
assertEquals(0.0, s1r1c3.getNumericCellValue(), 0);
|
||||
assertEquals(0.0, s1r2c3.getNumericCellValue(), 0);
|
||||
assertEquals(0.0, s2r1c1.getNumericCellValue(), 0);
|
||||
|
||||
// Do a full evaluate, as per our docs
|
||||
// uses evaluateFormulaCell()
|
||||
for(int sheetNum = 0; sheetNum < wb.getNumberOfSheets(); sheetNum++) {
|
||||
HSSFSheet sheet = wb.getSheetAt(sheetNum);
|
||||
HSSFFormulaEvaluator evaluator = new HSSFFormulaEvaluator(sheet, wb);
|
||||
|
||||
for(Iterator rit = sheet.rowIterator(); rit.hasNext();) {
|
||||
HSSFRow r = (HSSFRow)rit.next();
|
||||
evaluator.setCurrentRow(r);
|
||||
|
||||
for(Iterator cit = r.cellIterator(); cit.hasNext();) {
|
||||
HSSFCell c = (HSSFCell)cit.next();
|
||||
if(c.getCellType() == HSSFCell.CELL_TYPE_FORMULA) {
|
||||
evaluator.evaluateFormulaCell(c);
|
||||
|
||||
// For testing - all should be numeric
|
||||
assertEquals(HSSFCell.CELL_TYPE_NUMERIC, evaluator.evaluateFormulaCell(c));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Check now as expected
|
||||
assertEquals(55.7, wb.getSheetAt(0).getRow(0).getCell((short)2).getNumericCellValue(), 0);
|
||||
assertEquals("SUM(A1:B1)", wb.getSheetAt(0).getRow(0).getCell((short)2).getCellFormula());
|
||||
assertEquals(HSSFCell.CELL_TYPE_FORMULA, wb.getSheetAt(0).getRow(0).getCell((short)2).getCellType());
|
||||
|
||||
assertEquals(-4.6, wb.getSheetAt(0).getRow(1).getCell((short)2).getNumericCellValue(), 0);
|
||||
assertEquals("SUM(A2:B2)", wb.getSheetAt(0).getRow(1).getCell((short)2).getCellFormula());
|
||||
assertEquals(HSSFCell.CELL_TYPE_FORMULA, wb.getSheetAt(0).getRow(1).getCell((short)2).getCellType());
|
||||
|
||||
assertEquals(22.3, wb.getSheetAt(1).getRow(0).getCell((short)0).getNumericCellValue(), 0);
|
||||
assertEquals("S1!A1", wb.getSheetAt(1).getRow(0).getCell((short)0).getCellFormula());
|
||||
assertEquals(HSSFCell.CELL_TYPE_FORMULA, wb.getSheetAt(1).getRow(0).getCell((short)0).getCellType());
|
||||
|
||||
|
||||
// Now do the alternate call, which zaps the formulas
|
||||
// uses evaluateInCell()
|
||||
for(int sheetNum = 0; sheetNum < wb.getNumberOfSheets(); sheetNum++) {
|
||||
HSSFSheet sheet = wb.getSheetAt(sheetNum);
|
||||
HSSFFormulaEvaluator evaluator = new HSSFFormulaEvaluator(sheet, wb);
|
||||
|
||||
for(Iterator rit = sheet.rowIterator(); rit.hasNext();) {
|
||||
HSSFRow r = (HSSFRow)rit.next();
|
||||
evaluator.setCurrentRow(r);
|
||||
|
||||
for(Iterator cit = r.cellIterator(); cit.hasNext();) {
|
||||
HSSFCell c = (HSSFCell)cit.next();
|
||||
if(c.getCellType() == HSSFCell.CELL_TYPE_FORMULA) {
|
||||
evaluator.evaluateInCell(c);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
assertEquals(55.7, wb.getSheetAt(0).getRow(0).getCell((short)2).getNumericCellValue(), 0);
|
||||
assertEquals(HSSFCell.CELL_TYPE_NUMERIC, wb.getSheetAt(0).getRow(0).getCell((short)2).getCellType());
|
||||
|
||||
assertEquals(-4.6, wb.getSheetAt(0).getRow(1).getCell((short)2).getNumericCellValue(), 0);
|
||||
assertEquals(HSSFCell.CELL_TYPE_NUMERIC, wb.getSheetAt(0).getRow(1).getCell((short)2).getCellType());
|
||||
|
||||
assertEquals(22.3, wb.getSheetAt(1).getRow(0).getCell((short)0).getNumericCellValue(), 0);
|
||||
assertEquals(HSSFCell.CELL_TYPE_NUMERIC, wb.getSheetAt(1).getRow(0).getCell((short)0).getCellType());
|
||||
}
|
||||
}
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
@ -0,0 +1,14 @@
|
|||
Author = Nick Burch
|
||||
Title = Test Document
|
||||
Subject = This is a sample document
|
||||
Keywords = Testing Sample
|
||||
Comments = This document is used for testing text and metadata extraction
|
||||
|
||||
|
||||
I am a test document
|
||||
This is page 1
|
||||
I am Calibri (Body) in font size 11
|
||||
|
||||
This is page two
|
||||
It’s Arial Black in 16 point
|
||||
It’s also in blue
|
|
@ -74,4 +74,34 @@ public class TestProblems extends TestCase {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Test for TableCell not skipping the last paragraph
|
||||
*/
|
||||
public void testTableCellLastParagraph() throws Exception {
|
||||
HWPFDocument doc = new HWPFDocument(new FileInputStream(dirname + "/Bug44292.doc"));
|
||||
Range r = doc.getRange();
|
||||
|
||||
//get the table
|
||||
Paragraph p = r.getParagraph(0);
|
||||
Table t = r.getTable(p);
|
||||
|
||||
//get the only row
|
||||
TableRow row = t.getRow(0);
|
||||
|
||||
//get the first cell
|
||||
TableCell cell = row.getCell(0);
|
||||
// First cell should have one paragraph
|
||||
assertEquals(1, cell.numParagraphs());
|
||||
|
||||
//get the second
|
||||
cell = row.getCell(1);
|
||||
// Second cell should be detected as having two paragraphs
|
||||
assertEquals(2, cell.numParagraphs());
|
||||
|
||||
//get the last cell
|
||||
cell = row.getCell(2);
|
||||
// Last cell should have one paragraph
|
||||
assertEquals(1, cell.numParagraphs());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -82,21 +82,45 @@ public class TestEscherContainerRecord extends TestCase
|
|||
r2.setOptions( (short) 0x9876 );
|
||||
r2.setRecordId( EscherOptRecord.RECORD_ID );
|
||||
|
||||
String expected;
|
||||
r.addChildRecord( r2 );
|
||||
String expected = "org.apache.poi.ddf.EscherContainerRecord (SpContainer):" + nl +
|
||||
" isContainer: true" + nl +
|
||||
" options: 0x000F" + nl +
|
||||
" recordId: 0xF004" + nl +
|
||||
" numchildren: 1" + nl +
|
||||
" children: " + nl +
|
||||
"org.apache.poi.ddf.EscherOptRecord:" + nl +
|
||||
" isContainer: false" + nl +
|
||||
" options: 0x0003" + nl +
|
||||
" recordId: 0xF00B" + nl +
|
||||
" numchildren: 0" + nl +
|
||||
" properties:" + nl;
|
||||
expected = "org.apache.poi.ddf.EscherContainerRecord (SpContainer):" + nl +
|
||||
" isContainer: true" + nl +
|
||||
" options: 0x000F" + nl +
|
||||
" recordId: 0xF004" + nl +
|
||||
" numchildren: 1" + nl +
|
||||
" children: " + nl +
|
||||
" Child 0:" + nl +
|
||||
"org.apache.poi.ddf.EscherOptRecord:" + nl +
|
||||
" isContainer: false" + nl +
|
||||
" options: 0x0003" + nl +
|
||||
" recordId: 0xF00B" + nl +
|
||||
" numchildren: 0" + nl +
|
||||
" properties:" + nl;
|
||||
assertEquals( expected, r.toString() );
|
||||
|
||||
r.addChildRecord( r2 );
|
||||
expected = "org.apache.poi.ddf.EscherContainerRecord (SpContainer):" + nl +
|
||||
" isContainer: true" + nl +
|
||||
" options: 0x000F" + nl +
|
||||
" recordId: 0xF004" + nl +
|
||||
" numchildren: 2" + nl +
|
||||
" children: " + nl +
|
||||
" Child 0:" + nl +
|
||||
"org.apache.poi.ddf.EscherOptRecord:" + nl +
|
||||
" isContainer: false" + nl +
|
||||
" options: 0x0003" + nl +
|
||||
" recordId: 0xF00B" + nl +
|
||||
" numchildren: 0" + nl +
|
||||
" properties:" + nl +
|
||||
" Child 1:" + nl +
|
||||
"org.apache.poi.ddf.EscherOptRecord:" + nl +
|
||||
" isContainer: false" + nl +
|
||||
" options: 0x0003" + nl +
|
||||
" recordId: 0xF00B" + nl +
|
||||
" numchildren: 0" + nl +
|
||||
" properties:" + nl;
|
||||
assertEquals( expected, r.toString() );
|
||||
}
|
||||
|
||||
public void testGetRecordSize() throws Exception
|
||||
|
|
|
@ -23,8 +23,8 @@ import junit.framework.TestSuite;
|
|||
|
||||
import org.apache.poi.hssf.eventmodel.TestEventRecordFactory;
|
||||
import org.apache.poi.hssf.eventmodel.TestModelFactory;
|
||||
import org.apache.poi.hssf.model.TestFormulaParser;
|
||||
import org.apache.poi.hssf.model.TestDrawingManager;
|
||||
import org.apache.poi.hssf.model.TestFormulaParser;
|
||||
import org.apache.poi.hssf.model.TestSheet;
|
||||
import org.apache.poi.hssf.record.TestAreaFormatRecord;
|
||||
import org.apache.poi.hssf.record.TestAreaRecord;
|
||||
|
@ -91,6 +91,7 @@ import org.apache.poi.hssf.usermodel.TestFontDetails;
|
|||
import org.apache.poi.hssf.usermodel.TestFormulas;
|
||||
import org.apache.poi.hssf.usermodel.TestHSSFCell;
|
||||
import org.apache.poi.hssf.usermodel.TestHSSFClientAnchor;
|
||||
import org.apache.poi.hssf.usermodel.TestHSSFComment;
|
||||
import org.apache.poi.hssf.usermodel.TestHSSFDateUtil;
|
||||
import org.apache.poi.hssf.usermodel.TestHSSFHeaderFooter;
|
||||
import org.apache.poi.hssf.usermodel.TestHSSFPalette;
|
||||
|
@ -110,7 +111,6 @@ import org.apache.poi.hssf.util.TestCellReference;
|
|||
import org.apache.poi.hssf.util.TestRKUtil;
|
||||
import org.apache.poi.hssf.util.TestRangeAddress;
|
||||
import org.apache.poi.hssf.util.TestSheetReferences;
|
||||
import org.apache.poi.hssf.usermodel.TestHSSFComment;
|
||||
|
||||
/**
|
||||
* Test Suite for running just HSSF tests. Mostly
|
||||
|
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
@ -0,0 +1,21 @@
|
|||
Author = Nick Burch
|
||||
Title = Sample Spreadsheet
|
||||
Subject = Spreadsheet for testing
|
||||
Keywords = Testing Sample Formulas
|
||||
Comments = This is a sample spreadsheet, for use when testing things
|
||||
|
||||
(First Sheet)
|
||||
Test spreadsheet
|
||||
2nd row 2nd row 2nd column
|
||||
|
||||
This one is red
|
||||
|
||||
(Sheet Number 2)
|
||||
Start of 2nd sheet
|
||||
Sheet 2 row 2
|
||||
|
||||
I'm in bold blue, on a yellow background
|
||||
|
||||
cb=1 cb=10 cb=2 cb=sum
|
||||
1 10 2 =SUM(A7:C7)
|
||||
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
@ -45,7 +45,9 @@ import org.apache.poi.hssf.usermodel.HSSFWorkbook;
|
|||
|
||||
/**
|
||||
* Test the low level formula parser functionality. High level tests are to
|
||||
* be done via usermodel/HSSFCell.setFormulaValue() .
|
||||
* be done via usermodel/HSSFCell.setFormulaValue() .
|
||||
* Some tests are also done in scratchpad, if they need
|
||||
* HSSFFormulaEvaluator, which is there
|
||||
*/
|
||||
public class TestFormulaParser extends TestCase {
|
||||
|
||||
|
|
|
@ -79,4 +79,27 @@ public class TestNoteRecord
|
|||
System.arraycopy(ser, 4, recdata, 0, recdata.length);
|
||||
assertTrue(Arrays.equals(data, recdata));
|
||||
}
|
||||
|
||||
public void testClone()
|
||||
{
|
||||
NoteRecord record = new NoteRecord();
|
||||
|
||||
record.setRow((short)1);
|
||||
record.setColumn((short)2);
|
||||
record.setFlags(NoteRecord.NOTE_VISIBLE);
|
||||
record.setShapeId((short)1026);
|
||||
record.setAuthor("Apache Software Foundation");
|
||||
|
||||
NoteRecord cloned = (NoteRecord)record.clone();
|
||||
assertEquals(record.getRow(), cloned.getRow());
|
||||
assertEquals(record.getColumn(), cloned.getColumn());
|
||||
assertEquals(record.getFlags(), cloned.getFlags());
|
||||
assertEquals(record.getShapeId(), cloned.getShapeId());
|
||||
assertEquals(record.getAuthor(), cloned.getAuthor());
|
||||
|
||||
//finally check that the serialized data is the same
|
||||
byte[] src = record.serialize();
|
||||
byte[] cln = cloned.serialize();
|
||||
assertTrue(Arrays.equals(src, cln));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -65,4 +65,16 @@ public class TestNoteStructureSubRecord
|
|||
assertEquals(ser.length - 4, data.length);
|
||||
|
||||
}
|
||||
|
||||
public void testClone()
|
||||
{
|
||||
NoteStructureSubRecord record = new NoteStructureSubRecord();
|
||||
byte[] src = record.serialize();
|
||||
|
||||
NoteStructureSubRecord cloned = (NoteStructureSubRecord)record.clone();
|
||||
byte[] cln = cloned.serialize();
|
||||
|
||||
assertEquals(record.getRecordSize(), cloned.getRecordSize());
|
||||
assertTrue(Arrays.equals(src, cln));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -117,4 +117,44 @@ public class TestTextObjectRecord extends TestCase {
|
|||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Test cloning
|
||||
*/
|
||||
public void testClone() {
|
||||
String text = "Hello, World";
|
||||
HSSFRichTextString str = new HSSFRichTextString(text);
|
||||
|
||||
TextObjectRecord obj = new TextObjectRecord();
|
||||
int frLength = ( str.numFormattingRuns() + 1 ) * 8;
|
||||
obj.setFormattingRunLength( (short) frLength );
|
||||
obj.setTextLength( (short) str.length() );
|
||||
obj.setReserved1(true);
|
||||
obj.setReserved2((short)2);
|
||||
obj.setReserved3((short)3);
|
||||
obj.setReserved4((short)4);
|
||||
obj.setReserved5((short)5);
|
||||
obj.setReserved6((short)6);
|
||||
obj.setReserved7((short)7);
|
||||
obj.setStr( str );
|
||||
|
||||
|
||||
TextObjectRecord cloned = (TextObjectRecord)obj.clone();
|
||||
assertEquals(obj.getReserved2(), cloned.getReserved2());
|
||||
assertEquals(obj.getReserved3(), cloned.getReserved3());
|
||||
assertEquals(obj.getReserved4(), cloned.getReserved4());
|
||||
assertEquals(obj.getReserved5(), cloned.getReserved5());
|
||||
assertEquals(obj.getReserved6(), cloned.getReserved6());
|
||||
assertEquals(obj.getReserved7(), cloned.getReserved7());
|
||||
assertEquals(obj.getRecordSize(), cloned.getRecordSize());
|
||||
assertEquals(obj.getOptions(), cloned.getOptions());
|
||||
assertEquals(obj.getHorizontalTextAlignment(), cloned.getHorizontalTextAlignment());
|
||||
assertEquals(obj.getFormattingRunLength(), cloned.getFormattingRunLength());
|
||||
assertEquals(obj.getStr().getString(), cloned.getStr().getString());
|
||||
|
||||
//finally check that the serialized data is the same
|
||||
byte[] src = obj.serialize();
|
||||
byte[] cln = cloned.serialize();
|
||||
assertTrue(Arrays.equals(src, cln));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -913,6 +913,103 @@ extends TestCase {
|
|||
|
||||
}
|
||||
|
||||
/**
|
||||
* Bug 44200: Sheet not cloneable when Note added to excel cell
|
||||
*/
|
||||
public void test44200() throws Exception {
|
||||
FileInputStream in = new FileInputStream(new File(cwd, "44200.xls"));
|
||||
HSSFWorkbook wb = new HSSFWorkbook(in);
|
||||
in.close();
|
||||
|
||||
wb.cloneSheet(0);
|
||||
assertTrue("No Exceptions while cloning sheet", true);
|
||||
|
||||
//serialize and read again
|
||||
ByteArrayOutputStream out = new ByteArrayOutputStream();
|
||||
wb.write(out);
|
||||
out.close();
|
||||
|
||||
wb = new HSSFWorkbook(new ByteArrayInputStream(out.toByteArray()));
|
||||
assertTrue("No Exceptions while reading file", true);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Bug 44201: Sheet not cloneable when validation added to excel cell
|
||||
*/
|
||||
public void test44201() throws Exception {
|
||||
FileInputStream in = new FileInputStream(new File(cwd, "44201.xls"));
|
||||
HSSFWorkbook wb = new HSSFWorkbook(in);
|
||||
in.close();
|
||||
|
||||
wb.cloneSheet(0);
|
||||
assertTrue("No Exceptions while cloning sheet", true);
|
||||
|
||||
//serialize and read again
|
||||
ByteArrayOutputStream out = new ByteArrayOutputStream();
|
||||
wb.write(out);
|
||||
out.close();
|
||||
|
||||
wb = new HSSFWorkbook(new ByteArrayInputStream(out.toByteArray()));
|
||||
assertTrue("No Exceptions while reading file", true);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Bug 37684 : Unhandled Continue Record Error
|
||||
*/
|
||||
public void test37684 () throws Exception {
|
||||
FileInputStream in = new FileInputStream(new File(cwd, "37684-1.xls"));
|
||||
HSSFWorkbook wb = new HSSFWorkbook(in);
|
||||
in.close();
|
||||
|
||||
assertTrue("No exceptions while reading workbook", true);
|
||||
|
||||
//serialize and read again
|
||||
ByteArrayOutputStream out = new ByteArrayOutputStream();
|
||||
wb.write(out);
|
||||
out.close();
|
||||
assertTrue("No exceptions while saving workbook", true);
|
||||
|
||||
wb = new HSSFWorkbook(new ByteArrayInputStream(out.toByteArray()));
|
||||
assertTrue("No exceptions while reading saved stream", true);
|
||||
|
||||
|
||||
in = new FileInputStream(new File(cwd, "37684-2.xls"));
|
||||
wb = new HSSFWorkbook(in);
|
||||
in.close();
|
||||
|
||||
assertTrue("No exceptions while reading workbook", true);
|
||||
|
||||
//serialize and read again
|
||||
out = new ByteArrayOutputStream();
|
||||
wb.write(out);
|
||||
out.close();
|
||||
assertTrue("No exceptions while saving workbook", true);
|
||||
|
||||
wb = new HSSFWorkbook(new ByteArrayInputStream(out.toByteArray()));
|
||||
assertTrue("No exceptions while reading saved stream", true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Bug 41139: Constructing HSSFWorkbook is failed,threw threw ArrayIndexOutOfBoundsException for creating UnknownRecord
|
||||
*/
|
||||
public void test41139() throws Exception {
|
||||
FileInputStream in = new FileInputStream(new File(cwd, "41139.xls"));
|
||||
HSSFWorkbook wb = new HSSFWorkbook(in);
|
||||
in.close();
|
||||
|
||||
assertTrue("No Exceptions while reading file", true);
|
||||
|
||||
//serialize and read again
|
||||
ByteArrayOutputStream out = new ByteArrayOutputStream();
|
||||
wb.write(out);
|
||||
out.close();
|
||||
|
||||
wb = new HSSFWorkbook(new ByteArrayInputStream(out.toByteArray()));
|
||||
assertTrue("No Exceptions while reading file", true);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
|
|
@ -20,24 +20,36 @@ package org.apache.poi.hssf.usermodel;
|
|||
import junit.framework.TestCase;
|
||||
|
||||
import java.awt.*;
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
|
||||
/**
|
||||
* Tests the capabilities of the EscherGraphics class.
|
||||
*
|
||||
* All tests have two escher groups available to them,
|
||||
* one anchored at 0,0,1022,255 and another anchored
|
||||
* at 20,30,500,200
|
||||
*
|
||||
* @author Glen Stampoultzis (glens at apache.org)
|
||||
*/
|
||||
public class TestEscherGraphics extends TestCase
|
||||
{
|
||||
private HSSFShapeGroup escherGroup;
|
||||
private HSSFWorkbook workbook;
|
||||
private HSSFPatriarch patriarch;
|
||||
private HSSFShapeGroup escherGroupA;
|
||||
private HSSFShapeGroup escherGroupB;
|
||||
private EscherGraphics graphics;
|
||||
|
||||
protected void setUp() throws Exception
|
||||
{
|
||||
HSSFWorkbook workbook = new HSSFWorkbook();
|
||||
workbook = new HSSFWorkbook();
|
||||
|
||||
HSSFSheet sheet = workbook.createSheet("test");
|
||||
escherGroup = sheet.createDrawingPatriarch().createGroup(new HSSFClientAnchor(0,0,1023,255,(short)0,0,(short) 0,0));
|
||||
escherGroup = new HSSFShapeGroup(null, new HSSFChildAnchor());
|
||||
graphics = new EscherGraphics(this.escherGroup, workbook, Color.black, 1.0f);
|
||||
patriarch = sheet.createDrawingPatriarch();
|
||||
escherGroupA = patriarch.createGroup(new HSSFClientAnchor(0,0,1022,255,(short)0,0,(short) 0,0));
|
||||
escherGroupB = patriarch.createGroup(new HSSFClientAnchor(20,30,500,200,(short)0,0,(short) 0,0));
|
||||
// escherGroup = new HSSFShapeGroup(null, new HSSFChildAnchor());
|
||||
graphics = new EscherGraphics(this.escherGroupA, workbook, Color.black, 1.0f);
|
||||
super.setUp();
|
||||
}
|
||||
|
||||
|
@ -74,7 +86,7 @@ public class TestEscherGraphics extends TestCase
|
|||
public void testFillRect() throws Exception
|
||||
{
|
||||
graphics.fillRect( 10, 10, 20, 20 );
|
||||
HSSFSimpleShape s = (HSSFSimpleShape) escherGroup.getChildren().get(0);
|
||||
HSSFSimpleShape s = (HSSFSimpleShape) escherGroupA.getChildren().get(0);
|
||||
assertEquals(HSSFSimpleShape.OBJECT_TYPE_RECTANGLE, s.getShapeType());
|
||||
assertEquals(10, s.getAnchor().getDx1());
|
||||
assertEquals(10, s.getAnchor().getDy1());
|
||||
|
@ -85,8 +97,198 @@ public class TestEscherGraphics extends TestCase
|
|||
public void testDrawString() throws Exception
|
||||
{
|
||||
graphics.drawString("This is a test", 10, 10);
|
||||
HSSFTextbox t = (HSSFTextbox) escherGroup.getChildren().get(0);
|
||||
HSSFTextbox t = (HSSFTextbox) escherGroupA.getChildren().get(0);
|
||||
assertEquals("This is a test", t.getString().getString().toString());
|
||||
}
|
||||
|
||||
public void testGetDataBackAgain() throws Exception {
|
||||
HSSFSheet s;
|
||||
HSSFShapeGroup s1;
|
||||
HSSFShapeGroup s2;
|
||||
|
||||
patriarch.setCoordinates(10, 20, 30, 40);
|
||||
|
||||
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
||||
workbook.write(baos);
|
||||
workbook = new HSSFWorkbook(new ByteArrayInputStream(baos.toByteArray()));
|
||||
s = workbook.getSheetAt(0);
|
||||
|
||||
patriarch = s.getDrawingPatriarch();
|
||||
|
||||
assertNotNull(patriarch);
|
||||
assertEquals(10, patriarch.getX1());
|
||||
assertEquals(20, patriarch.getY1());
|
||||
assertEquals(30, patriarch.getX2());
|
||||
assertEquals(40, patriarch.getY2());
|
||||
|
||||
// Check the two groups too
|
||||
assertEquals(2, patriarch.countOfAllChildren());
|
||||
assertTrue(patriarch.getChildren().get(0) instanceof HSSFShapeGroup);
|
||||
assertTrue(patriarch.getChildren().get(1) instanceof HSSFShapeGroup);
|
||||
|
||||
s1 = (HSSFShapeGroup)patriarch.getChildren().get(0);
|
||||
s2 = (HSSFShapeGroup)patriarch.getChildren().get(1);
|
||||
|
||||
assertEquals(0, s1.getX1());
|
||||
assertEquals(0, s1.getY1());
|
||||
assertEquals(1023, s1.getX2());
|
||||
assertEquals(255, s1.getY2());
|
||||
assertEquals(0, s2.getX1());
|
||||
assertEquals(0, s2.getY1());
|
||||
assertEquals(1023, s2.getX2());
|
||||
assertEquals(255, s2.getY2());
|
||||
|
||||
assertEquals(0, s1.getAnchor().getDx1());
|
||||
assertEquals(0, s1.getAnchor().getDy1());
|
||||
assertEquals(1022, s1.getAnchor().getDx2());
|
||||
assertEquals(255, s1.getAnchor().getDy2());
|
||||
assertEquals(20, s2.getAnchor().getDx1());
|
||||
assertEquals(30, s2.getAnchor().getDy1());
|
||||
assertEquals(500, s2.getAnchor().getDx2());
|
||||
assertEquals(200, s2.getAnchor().getDy2());
|
||||
|
||||
|
||||
// Write and re-load once more, to check that's ok
|
||||
baos = new ByteArrayOutputStream();
|
||||
workbook.write(baos);
|
||||
workbook = new HSSFWorkbook(new ByteArrayInputStream(baos.toByteArray()));
|
||||
s = workbook.getSheetAt(0);
|
||||
patriarch = s.getDrawingPatriarch();
|
||||
|
||||
assertNotNull(patriarch);
|
||||
assertEquals(10, patriarch.getX1());
|
||||
assertEquals(20, patriarch.getY1());
|
||||
assertEquals(30, patriarch.getX2());
|
||||
assertEquals(40, patriarch.getY2());
|
||||
|
||||
// Check the two groups too
|
||||
assertEquals(2, patriarch.countOfAllChildren());
|
||||
assertTrue(patriarch.getChildren().get(0) instanceof HSSFShapeGroup);
|
||||
assertTrue(patriarch.getChildren().get(1) instanceof HSSFShapeGroup);
|
||||
|
||||
s1 = (HSSFShapeGroup)patriarch.getChildren().get(0);
|
||||
s2 = (HSSFShapeGroup)patriarch.getChildren().get(1);
|
||||
|
||||
assertEquals(0, s1.getX1());
|
||||
assertEquals(0, s1.getY1());
|
||||
assertEquals(1023, s1.getX2());
|
||||
assertEquals(255, s1.getY2());
|
||||
assertEquals(0, s2.getX1());
|
||||
assertEquals(0, s2.getY1());
|
||||
assertEquals(1023, s2.getX2());
|
||||
assertEquals(255, s2.getY2());
|
||||
|
||||
assertEquals(0, s1.getAnchor().getDx1());
|
||||
assertEquals(0, s1.getAnchor().getDy1());
|
||||
assertEquals(1022, s1.getAnchor().getDx2());
|
||||
assertEquals(255, s1.getAnchor().getDy2());
|
||||
assertEquals(20, s2.getAnchor().getDx1());
|
||||
assertEquals(30, s2.getAnchor().getDy1());
|
||||
assertEquals(500, s2.getAnchor().getDx2());
|
||||
assertEquals(200, s2.getAnchor().getDy2());
|
||||
|
||||
// Change the positions of the first groups,
|
||||
// but not of their anchors
|
||||
s1.setCoordinates(2, 3, 1021, 242);
|
||||
|
||||
baos = new ByteArrayOutputStream();
|
||||
workbook.write(baos);
|
||||
workbook = new HSSFWorkbook(new ByteArrayInputStream(baos.toByteArray()));
|
||||
s = workbook.getSheetAt(0);
|
||||
patriarch = s.getDrawingPatriarch();
|
||||
|
||||
assertNotNull(patriarch);
|
||||
assertEquals(10, patriarch.getX1());
|
||||
assertEquals(20, patriarch.getY1());
|
||||
assertEquals(30, patriarch.getX2());
|
||||
assertEquals(40, patriarch.getY2());
|
||||
|
||||
// Check the two groups too
|
||||
assertEquals(2, patriarch.countOfAllChildren());
|
||||
assertEquals(2, patriarch.getChildren().size());
|
||||
assertTrue(patriarch.getChildren().get(0) instanceof HSSFShapeGroup);
|
||||
assertTrue(patriarch.getChildren().get(1) instanceof HSSFShapeGroup);
|
||||
|
||||
s1 = (HSSFShapeGroup)patriarch.getChildren().get(0);
|
||||
s2 = (HSSFShapeGroup)patriarch.getChildren().get(1);
|
||||
|
||||
assertEquals(2, s1.getX1());
|
||||
assertEquals(3, s1.getY1());
|
||||
assertEquals(1021, s1.getX2());
|
||||
assertEquals(242, s1.getY2());
|
||||
assertEquals(0, s2.getX1());
|
||||
assertEquals(0, s2.getY1());
|
||||
assertEquals(1023, s2.getX2());
|
||||
assertEquals(255, s2.getY2());
|
||||
|
||||
assertEquals(0, s1.getAnchor().getDx1());
|
||||
assertEquals(0, s1.getAnchor().getDy1());
|
||||
assertEquals(1022, s1.getAnchor().getDx2());
|
||||
assertEquals(255, s1.getAnchor().getDy2());
|
||||
assertEquals(20, s2.getAnchor().getDx1());
|
||||
assertEquals(30, s2.getAnchor().getDy1());
|
||||
assertEquals(500, s2.getAnchor().getDx2());
|
||||
assertEquals(200, s2.getAnchor().getDy2());
|
||||
|
||||
|
||||
// Now add some text to one group, and some more
|
||||
// to the base, and check we can get it back again
|
||||
HSSFTextbox tbox1 =
|
||||
patriarch.createTextbox(new HSSFClientAnchor(1,2,3,4, (short)0,0,(short)0,0));
|
||||
tbox1.setString(new HSSFRichTextString("I am text box 1"));
|
||||
HSSFTextbox tbox2 =
|
||||
s2.createTextbox(new HSSFChildAnchor(41,42,43,44));
|
||||
tbox2.setString(new HSSFRichTextString("This is text box 2"));
|
||||
|
||||
assertEquals(3, patriarch.getChildren().size());
|
||||
|
||||
|
||||
baos = new ByteArrayOutputStream();
|
||||
workbook.write(baos);
|
||||
workbook = new HSSFWorkbook(new ByteArrayInputStream(baos.toByteArray()));
|
||||
s = workbook.getSheetAt(0);
|
||||
|
||||
patriarch = s.getDrawingPatriarch();
|
||||
|
||||
assertNotNull(patriarch);
|
||||
assertEquals(10, patriarch.getX1());
|
||||
assertEquals(20, patriarch.getY1());
|
||||
assertEquals(30, patriarch.getX2());
|
||||
assertEquals(40, patriarch.getY2());
|
||||
|
||||
// Check the two groups and the text
|
||||
assertEquals(3, patriarch.countOfAllChildren());
|
||||
assertEquals(2, patriarch.getChildren().size());
|
||||
|
||||
// Should be two groups and a text
|
||||
assertTrue(patriarch.getChildren().get(0) instanceof HSSFShapeGroup);
|
||||
assertTrue(patriarch.getChildren().get(1) instanceof HSSFTextbox);
|
||||
// assertTrue(patriarch.getChildren().get(2) instanceof HSSFShapeGroup);
|
||||
|
||||
s1 = (HSSFShapeGroup)patriarch.getChildren().get(0);
|
||||
tbox1 = (HSSFTextbox)patriarch.getChildren().get(1);
|
||||
|
||||
// s2 = (HSSFShapeGroup)patriarch.getChildren().get(1);
|
||||
|
||||
assertEquals(2, s1.getX1());
|
||||
assertEquals(3, s1.getY1());
|
||||
assertEquals(1021, s1.getX2());
|
||||
assertEquals(242, s1.getY2());
|
||||
assertEquals(0, s2.getX1());
|
||||
assertEquals(0, s2.getY1());
|
||||
assertEquals(1023, s2.getX2());
|
||||
assertEquals(255, s2.getY2());
|
||||
|
||||
assertEquals(0, s1.getAnchor().getDx1());
|
||||
assertEquals(0, s1.getAnchor().getDy1());
|
||||
assertEquals(1022, s1.getAnchor().getDx2());
|
||||
assertEquals(255, s1.getAnchor().getDy2());
|
||||
assertEquals(20, s2.getAnchor().getDx1());
|
||||
assertEquals(30, s2.getAnchor().getDy1());
|
||||
assertEquals(500, s2.getAnchor().getDx2());
|
||||
assertEquals(200, s2.getAnchor().getDy2());
|
||||
|
||||
// Not working just yet
|
||||
//assertEquals("I am text box 1", tbox1.getString().getString());
|
||||
}
|
||||
}
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue