Merged revisions 638786-638802,638805-638811,638813-638814,638816-639230,639233-639241,639243-639253,639255-639486,639488-639601,639603-639835,639837-639917,639919-640056,640058-640710,640712-641156,641158-641184,641186-641795,641797-641798,641800-641933,641935-641963,641965-641966,641968-641995,641997-642230,642232-642562,642564-642565,642568-642570,642572-642573,642576-642736,642739-642877,642879,642881-642890,642892-642903,642905-642945,642947-643624,643626-643653,643655-643669,643671,643673-643830,643832-643833,643835-644342,644344-644472,644474-644508,644510-645347,645349-645351,645353-645559,645561-645565,645568-645951,645953-646193,646195-646311,646313-646404,646406-646665,646667-646853,646855-646869,646871-647151,647153-647185,647187-647277,647279-647566,647568-647573,647575,647578-647711,647714-647737,647739-647823,647825-648155,648157-648202,648204-648273,648275,648277-648302,648304-648333,648335-648588,648590-648622,648625-648673,648675-649141,649144,649146-649556,649558-649795,649799,649801-649910,649912-649913,649915-650128,650131-650132,650134-650137,650140-650914,650916-651991,651993-652284,652286-652287,652289,652291,652293-652297,652299-652328,652330-652425,652427-652445,652447-652560,652562-652933,652935,652937-652993,652995-653116,653118-653124,653126-653483,653487-653519,653522-653550,653552-653607,653609-653667,653669-653674,653676-653814,653817-653830,653832-653891,653893-653944,653946-654055,654057-654355,654357-654365,654367-654648,654651-655215,655217-655277,655279-655281,655283-655911,655913-656212,656214,656216-656251,656253-656698,656700-656756,656758-656892,656894-657135,657137-657165,657168-657179,657181-657354,657356-657357,657359-657701,657703-657874,657876-658032,658034-658284,658286,658288-658301,658303-658307,658309-658321,658323-658335,658337-658348,658351,658353-658832,658834-658983,658985,658987-659066,659068-659402,659404-659428,659430-659451,659453-659454,659456-659461,659463-659477,659479-659524,659526-659571,659574,659576-660255,660257-660262,660264-660279,660281-660343,660345-660473,660475-660827,660829-660833,660835-660888,660890-663321,663323-663435,663437-663764,663766-663854,663856-664219,664221-664489,664494-664514,664516-668013,668015-668142,668144-668152,668154,668156-668256,668258,668260-669139,669141-669455,669457-669657,669659-669808,669810-670189,670191-671321,671323-672229,672231-672549,672551-672552,672554-672561,672563-672566,672568,672571-673049,673051-673852,673854-673862,673864-673986,673988-673996,673998-674347,674349-674890,674892-674910,674912-674936,674938-674952,674954-675078,675080-675085,675087-675217,675219-675660,675662-675670,675672-675716,675718-675726,675728-675733,675735-675775,675777-675782,675784,675786-675791,675794-675852,675854-676200,676202,676204,676206-676220,676222-676309,676311-676456,676458-676994,676996-677027,677030-677040,677042-677056,677058-677375,677377-677968,677970-677971,677973,677975-677994,677996-678286,678288-678538,678540-680393,680395-680469,680471-682349 via svnmerge from
https://svn.apache.org/repos/asf/poi/trunk ........ r680530 | nick | 2008-07-28 23:10:07 +0100 (Mon, 28 Jul 2008) | 1 line Some work on bug #45466 - Partial support for removing excel comments (won't work for all excel versions yet) ........ r680853 | nick | 2008-07-29 22:40:47 +0100 (Tue, 29 Jul 2008) | 1 line Support for creating new HSLF CurrentUserAtoms ........ r681530 | josh | 2008-07-31 23:44:48 +0100 (Thu, 31 Jul 2008) | 1 line Fix for bug 45519 - keep data validation records together ........ r681572 | josh | 2008-08-01 02:04:28 +0100 (Fri, 01 Aug 2008) | 1 line Small update for c681530 bug 45519 ........ r682225 | josh | 2008-08-03 23:11:26 +0100 (Sun, 03 Aug 2008) | 1 line Extensive fixes for data validation (bug 44953) ........ r682227 | josh | 2008-08-03 23:15:46 +0100 (Sun, 03 Aug 2008) | 1 line should have been submitted with c682225 - Extensive fixes for data validation (bug 44953) ........ r682229 | josh | 2008-08-03 23:49:58 +0100 (Sun, 03 Aug 2008) | 1 line fixed BiffViewer to add some missing record types. Formatted switch/case for readability ........ r682230 | josh | 2008-08-04 00:13:17 +0100 (Mon, 04 Aug 2008) | 1 line Small tweaks for data validation (bug 44953) ........ r682282 | josh | 2008-08-04 09:00:11 +0100 (Mon, 04 Aug 2008) | 1 line Consolidating various duplicates of CellRangeAddress ........ r682336 | yegor | 2008-08-04 12:40:25 +0100 (Mon, 04 Aug 2008) | 1 line support for headers / footers in HSLF ........ git-svn-id: https://svn.apache.org/repos/asf/poi/branches/ooxml@682485 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
parent
155d2b939e
commit
cfdf265975
@ -21,23 +21,50 @@ import org.apache.poi.hssf.usermodel.HSSFCell;
|
||||
import org.apache.poi.hssf.usermodel.HSSFRow;
|
||||
import org.apache.poi.hssf.usermodel.HSSFSheet;
|
||||
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
|
||||
|
||||
import org.apache.poi.ss.util.CellRangeAddress;
|
||||
import org.apache.poi.ss.util.Region;
|
||||
|
||||
/**
|
||||
* Various utility functions that make working with a region of cells easier.
|
||||
*
|
||||
* @author Eric Pugh epugh@upstate.com
|
||||
*@since July 29, 2002
|
||||
*/
|
||||
public final class HSSFRegionUtil
|
||||
{
|
||||
public final class HSSFRegionUtil {
|
||||
|
||||
/** Constructor for the HSSFRegionUtil object */
|
||||
private HSSFRegionUtil() {
|
||||
// no instances of this class
|
||||
}
|
||||
/**
|
||||
* For setting the same property on many cells to the same value
|
||||
*/
|
||||
private static final class CellPropertySetter {
|
||||
|
||||
private final HSSFWorkbook _workbook;
|
||||
private final String _propertyName;
|
||||
private final Short _propertyValue;
|
||||
|
||||
public CellPropertySetter(HSSFWorkbook workbook, String propertyName, int value) {
|
||||
_workbook = workbook;
|
||||
_propertyName = propertyName;
|
||||
_propertyValue = new Short((short)value);
|
||||
}
|
||||
public void setProperty(HSSFRow row, int column) {
|
||||
HSSFCell cell = HSSFCellUtil.getCell(row, column);
|
||||
HSSFCellUtil.setCellStyleProperty(cell, _workbook, _propertyName, _propertyValue);
|
||||
}
|
||||
}
|
||||
|
||||
private static CellRangeAddress toCRA(Region region) {
|
||||
return Region.convertToCellRangeAddress(region);
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated (Aug 2008) use {@link CellRangeAddress} instead of {@link Region}
|
||||
*/
|
||||
public static void setBorderLeft(short border, Region region, HSSFSheet sheet,
|
||||
HSSFWorkbook workbook) {
|
||||
setBorderLeft(border, toCRA(region), sheet, workbook);
|
||||
}
|
||||
/**
|
||||
* Sets the left border for a region of cells by manipulating the cell style
|
||||
* of the individual cells on the left
|
||||
@ -47,20 +74,25 @@ public final class HSSFRegionUtil
|
||||
* @param workbook The workbook that the region is on.
|
||||
* @param sheet The sheet that the region is on.
|
||||
*/
|
||||
public static void setBorderLeft( short border, Region region, HSSFSheet sheet, HSSFWorkbook workbook )
|
||||
{
|
||||
int rowStart = region.getRowFrom();
|
||||
int rowEnd = region.getRowTo();
|
||||
int column = region.getColumnFrom();
|
||||
public static void setBorderLeft(int border, CellRangeAddress region, HSSFSheet sheet,
|
||||
HSSFWorkbook workbook) {
|
||||
int rowStart = region.getFirstRow();
|
||||
int rowEnd = region.getLastRow();
|
||||
int column = region.getFirstColumn();
|
||||
|
||||
CellPropertySetter cps = new CellPropertySetter(workbook, HSSFCellUtil.BORDER_LEFT, border);
|
||||
for (int i = rowStart; i <= rowEnd; i++) {
|
||||
HSSFRow row = HSSFCellUtil.getRow( i, sheet );
|
||||
HSSFCell cell = HSSFCellUtil.getCell( row, column );
|
||||
HSSFCellUtil.setCellStyleProperty(
|
||||
cell, workbook, HSSFCellUtil.BORDER_LEFT, new Short( border ) );
|
||||
cps.setProperty(HSSFCellUtil.getRow(i, sheet), column);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated (Aug 2008) use {@link CellRangeAddress} instead of {@link Region}
|
||||
*/
|
||||
public static void setLeftBorderColor(short color, Region region, HSSFSheet sheet,
|
||||
HSSFWorkbook workbook) {
|
||||
setLeftBorderColor(color, toCRA(region), sheet, workbook);
|
||||
}
|
||||
/**
|
||||
* Sets the leftBorderColor attribute of the HSSFRegionUtil object
|
||||
*
|
||||
@ -69,20 +101,25 @@ public final class HSSFRegionUtil
|
||||
* @param workbook The workbook that the region is on.
|
||||
* @param sheet The sheet that the region is on.
|
||||
*/
|
||||
public static void setLeftBorderColor( short color, Region region, HSSFSheet sheet, HSSFWorkbook workbook )
|
||||
{
|
||||
int rowStart = region.getRowFrom();
|
||||
int rowEnd = region.getRowTo();
|
||||
int column = region.getColumnFrom();
|
||||
public static void setLeftBorderColor(int color, CellRangeAddress region, HSSFSheet sheet,
|
||||
HSSFWorkbook workbook) {
|
||||
int rowStart = region.getFirstRow();
|
||||
int rowEnd = region.getLastRow();
|
||||
int column = region.getFirstColumn();
|
||||
|
||||
CellPropertySetter cps = new CellPropertySetter(workbook, HSSFCellUtil.LEFT_BORDER_COLOR, color);
|
||||
for (int i = rowStart; i <= rowEnd; i++) {
|
||||
HSSFRow row = HSSFCellUtil.getRow( i, sheet );
|
||||
HSSFCell cell = HSSFCellUtil.getCell( row, column );
|
||||
HSSFCellUtil.setCellStyleProperty(
|
||||
cell, workbook, HSSFCellUtil.LEFT_BORDER_COLOR, new Short( color ) );
|
||||
cps.setProperty(HSSFCellUtil.getRow(i, sheet), column);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated (Aug 2008) use {@link CellRangeAddress} instead of {@link Region}
|
||||
*/
|
||||
public static void setBorderRight(short border, Region region, HSSFSheet sheet,
|
||||
HSSFWorkbook workbook) {
|
||||
setBorderRight(border, toCRA(region), sheet, workbook);
|
||||
}
|
||||
/**
|
||||
* Sets the borderRight attribute of the HSSFRegionUtil object
|
||||
*
|
||||
@ -91,21 +128,25 @@ public final class HSSFRegionUtil
|
||||
* @param workbook The workbook that the region is on.
|
||||
* @param sheet The sheet that the region is on.
|
||||
*/
|
||||
public static void setBorderRight( short border, Region region, HSSFSheet sheet, HSSFWorkbook workbook )
|
||||
{
|
||||
int rowStart = region.getRowFrom();
|
||||
int rowEnd = region.getRowTo();
|
||||
int column = region.getColumnTo();
|
||||
public static void setBorderRight(int border, CellRangeAddress region, HSSFSheet sheet,
|
||||
HSSFWorkbook workbook) {
|
||||
int rowStart = region.getFirstRow();
|
||||
int rowEnd = region.getLastRow();
|
||||
int column = region.getLastColumn();
|
||||
|
||||
CellPropertySetter cps = new CellPropertySetter(workbook, HSSFCellUtil.BORDER_RIGHT, border);
|
||||
for (int i = rowStart; i <= rowEnd; i++) {
|
||||
HSSFRow row = HSSFCellUtil.getRow( i, sheet );
|
||||
HSSFCell cell = HSSFCellUtil.getCell( row, column );
|
||||
|
||||
HSSFCellUtil.setCellStyleProperty(
|
||||
cell, workbook, HSSFCellUtil.BORDER_RIGHT, new Short( border ) );
|
||||
cps.setProperty(HSSFCellUtil.getRow(i, sheet), column);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated (Aug 2008) use {@link CellRangeAddress} instead of {@link Region}
|
||||
*/
|
||||
public static void setRightBorderColor(short color, Region region, HSSFSheet sheet,
|
||||
HSSFWorkbook workbook) {
|
||||
setRightBorderColor(color, toCRA(region), sheet, workbook);
|
||||
}
|
||||
/**
|
||||
* Sets the rightBorderColor attribute of the HSSFRegionUtil object
|
||||
*
|
||||
@ -114,20 +155,25 @@ public final class HSSFRegionUtil
|
||||
* @param workbook The workbook that the region is on.
|
||||
* @param sheet The sheet that the region is on.
|
||||
*/
|
||||
public static void setRightBorderColor( short color, Region region, HSSFSheet sheet, HSSFWorkbook workbook )
|
||||
{
|
||||
int rowStart = region.getRowFrom();
|
||||
int rowEnd = region.getRowTo();
|
||||
int column = region.getColumnTo();
|
||||
public static void setRightBorderColor(int color, CellRangeAddress region, HSSFSheet sheet,
|
||||
HSSFWorkbook workbook) {
|
||||
int rowStart = region.getFirstRow();
|
||||
int rowEnd = region.getLastRow();
|
||||
int column = region.getLastColumn();
|
||||
|
||||
CellPropertySetter cps = new CellPropertySetter(workbook, HSSFCellUtil.RIGHT_BORDER_COLOR, color);
|
||||
for (int i = rowStart; i <= rowEnd; i++) {
|
||||
HSSFRow row = HSSFCellUtil.getRow( i, sheet );
|
||||
HSSFCell cell = HSSFCellUtil.getCell( row, column );
|
||||
HSSFCellUtil.setCellStyleProperty(
|
||||
cell, workbook, HSSFCellUtil.RIGHT_BORDER_COLOR, new Short( color ) );
|
||||
cps.setProperty(HSSFCellUtil.getRow(i, sheet), column);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated (Aug 2008) use {@link CellRangeAddress} instead of {@link Region}
|
||||
*/
|
||||
public static void setBorderBottom(short border, Region region, HSSFSheet sheet,
|
||||
HSSFWorkbook workbook) {
|
||||
setBorderBottom(border, toCRA(region), sheet, workbook);
|
||||
}
|
||||
/**
|
||||
* Sets the borderBottom attribute of the HSSFRegionUtil object
|
||||
*
|
||||
@ -136,20 +182,25 @@ public final class HSSFRegionUtil
|
||||
* @param workbook The workbook that the region is on.
|
||||
* @param sheet The sheet that the region is on.
|
||||
*/
|
||||
public static void setBorderBottom( short border, Region region, HSSFSheet sheet, HSSFWorkbook workbook )
|
||||
{
|
||||
int colStart = region.getColumnFrom();
|
||||
int colEnd = region.getColumnTo();
|
||||
int rowIndex = region.getRowTo();
|
||||
public static void setBorderBottom(int border, CellRangeAddress region, HSSFSheet sheet,
|
||||
HSSFWorkbook workbook) {
|
||||
int colStart = region.getFirstColumn();
|
||||
int colEnd = region.getLastColumn();
|
||||
int rowIndex = region.getLastRow();
|
||||
CellPropertySetter cps = new CellPropertySetter(workbook, HSSFCellUtil.BORDER_BOTTOM, border);
|
||||
HSSFRow row = HSSFCellUtil.getRow(rowIndex, sheet);
|
||||
for (int i = colStart; i <= colEnd; i++) {
|
||||
|
||||
HSSFCell cell = HSSFCellUtil.getCell( row, i );
|
||||
HSSFCellUtil.setCellStyleProperty(
|
||||
cell, workbook, HSSFCellUtil.BORDER_BOTTOM, new Short( border ) );
|
||||
cps.setProperty(row, i);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated (Aug 2008) use {@link CellRangeAddress} instead of {@link Region}
|
||||
*/
|
||||
public static void setBottomBorderColor(short color, Region region, HSSFSheet sheet,
|
||||
HSSFWorkbook workbook) {
|
||||
setBottomBorderColor(color, toCRA(region), sheet, workbook);
|
||||
}
|
||||
/**
|
||||
* Sets the bottomBorderColor attribute of the HSSFRegionUtil object
|
||||
*
|
||||
@ -158,19 +209,25 @@ public final class HSSFRegionUtil
|
||||
* @param workbook The workbook that the region is on.
|
||||
* @param sheet The sheet that the region is on.
|
||||
*/
|
||||
public static void setBottomBorderColor( short color, Region region, HSSFSheet sheet, HSSFWorkbook workbook )
|
||||
{
|
||||
int colStart = region.getColumnFrom();
|
||||
int colEnd = region.getColumnTo();
|
||||
int rowIndex = region.getRowTo();
|
||||
public static void setBottomBorderColor(int color, CellRangeAddress region, HSSFSheet sheet,
|
||||
HSSFWorkbook workbook) {
|
||||
int colStart = region.getFirstColumn();
|
||||
int colEnd = region.getLastColumn();
|
||||
int rowIndex = region.getLastRow();
|
||||
CellPropertySetter cps = new CellPropertySetter(workbook, HSSFCellUtil.BOTTOM_BORDER_COLOR, color);
|
||||
HSSFRow row = HSSFCellUtil.getRow(rowIndex, sheet);
|
||||
for (int i = colStart; i <= colEnd; i++) {
|
||||
HSSFCell cell = HSSFCellUtil.getCell( row, i );
|
||||
HSSFCellUtil.setCellStyleProperty(
|
||||
cell, workbook, HSSFCellUtil.BOTTOM_BORDER_COLOR, new Short( color ) );
|
||||
cps.setProperty(row, i);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated (Aug 2008) use {@link CellRangeAddress} instead of {@link Region}
|
||||
*/
|
||||
public static void setBorderTop(short border, Region region, HSSFSheet sheet,
|
||||
HSSFWorkbook workbook) {
|
||||
setBorderTop(border, toCRA(region), sheet, workbook);
|
||||
}
|
||||
/**
|
||||
* Sets the borderBottom attribute of the HSSFRegionUtil object
|
||||
*
|
||||
@ -179,20 +236,25 @@ public final class HSSFRegionUtil
|
||||
* @param workbook The workbook that the region is on.
|
||||
* @param sheet The sheet that the region is on.
|
||||
*/
|
||||
public static void setBorderTop( short border, Region region, HSSFSheet sheet, HSSFWorkbook workbook )
|
||||
{
|
||||
int colStart = region.getColumnFrom();
|
||||
int colEnd = region.getColumnTo();
|
||||
int rowIndex = region.getRowFrom();
|
||||
public static void setBorderTop(int border, CellRangeAddress region, HSSFSheet sheet,
|
||||
HSSFWorkbook workbook) {
|
||||
int colStart = region.getFirstColumn();
|
||||
int colEnd = region.getLastColumn();
|
||||
int rowIndex = region.getFirstRow();
|
||||
CellPropertySetter cps = new CellPropertySetter(workbook, HSSFCellUtil.BORDER_TOP, border);
|
||||
HSSFRow row = HSSFCellUtil.getRow(rowIndex, sheet);
|
||||
for (int i = colStart; i <= colEnd; i++) {
|
||||
|
||||
HSSFCell cell = HSSFCellUtil.getCell( row, i );
|
||||
HSSFCellUtil.setCellStyleProperty(
|
||||
cell, workbook, HSSFCellUtil.BORDER_TOP, new Short( border ) );
|
||||
cps.setProperty(row, i);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated (Aug 2008) use {@link CellRangeAddress} instead of {@link Region}
|
||||
*/
|
||||
public static void setTopBorderColor(short color, Region region, HSSFSheet sheet,
|
||||
HSSFWorkbook workbook) {
|
||||
setTopBorderColor(color, toCRA(region), sheet, workbook);
|
||||
}
|
||||
/**
|
||||
* Sets the topBorderColor attribute of the HSSFRegionUtil object
|
||||
*
|
||||
@ -201,17 +263,15 @@ public final class HSSFRegionUtil
|
||||
* @param workbook The workbook that the region is on.
|
||||
* @param sheet The sheet that the region is on.
|
||||
*/
|
||||
public static void setTopBorderColor( short color, Region region, HSSFSheet sheet, HSSFWorkbook workbook )
|
||||
{
|
||||
int colStart = region.getColumnFrom();
|
||||
int colEnd = region.getColumnTo();
|
||||
int rowIndex = region.getRowFrom();
|
||||
public static void setTopBorderColor(int color, CellRangeAddress region, HSSFSheet sheet,
|
||||
HSSFWorkbook workbook) {
|
||||
int colStart = region.getFirstColumn();
|
||||
int colEnd = region.getLastColumn();
|
||||
int rowIndex = region.getFirstRow();
|
||||
CellPropertySetter cps = new CellPropertySetter(workbook, HSSFCellUtil.TOP_BORDER_COLOR, color);
|
||||
HSSFRow row = HSSFCellUtil.getRow(rowIndex, sheet);
|
||||
for (int i = colStart; i <= colEnd; i++) {
|
||||
HSSFCell cell = HSSFCellUtil.getCell( row, i );
|
||||
HSSFCellUtil.setCellStyleProperty(
|
||||
cell, workbook, HSSFCellUtil.TOP_BORDER_COLOR, new Short( color ) );
|
||||
cps.setProperty(row, i);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -52,6 +52,11 @@
|
||||
<action dev="POI-DEVELOPERS" type="add">Created a common interface for handling Excel files, irrespective of if they are .xls or .xlsx</action>
|
||||
</release>
|
||||
<release version="3.1.1-alpha1" date="2008-??-??">
|
||||
<action dev="POI-DEVELOPERS" type="add">Support for Headers / Footers in HSLF</action>
|
||||
<action dev="POI-DEVELOPERS" type="fix">44953 - Extensive fixes for data validation</action>
|
||||
<action dev="POI-DEVELOPERS" type="fix">45519 - Fixed to keep datavalidation records together</action>
|
||||
<action dev="POI-DEVELOPERS" type="add">Support for creating new HSLF CurrentUserAtoms</action>
|
||||
<action dev="POI-DEVELOPERS" type="add">45466 - Partial support for removing excel comments (won't work for all excel versions yet)</action>
|
||||
<action dev="POI-DEVELOPERS" type="fix">45437 - Detect encrypted word documents, and throw an EncryptedDocumentException instead of a OOM</action>
|
||||
<action dev="POI-DEVELOPERS" type="add">45404 - New class, hssf.usermodel.HSSFDataFormatter, for formatting numbers and dates in the same way that Excel does</action>
|
||||
<action dev="POI-DEVELOPERS" type="fix">45414 - Don't add too many UncalcedRecords to sheets with charts in them</action>
|
||||
|
@ -49,6 +49,11 @@
|
||||
<action dev="POI-DEVELOPERS" type="add">Created a common interface for handling Excel files, irrespective of if they are .xls or .xlsx</action>
|
||||
</release>
|
||||
<release version="3.1.1-alpha1" date="2008-??-??">
|
||||
<action dev="POI-DEVELOPERS" type="add">Support for Headers / Footers in HSLF</action>
|
||||
<action dev="POI-DEVELOPERS" type="fix">44953 - Extensive fixes for data validation</action>
|
||||
<action dev="POI-DEVELOPERS" type="fix">45519 - Fixed to keep datavalidation records together</action>
|
||||
<action dev="POI-DEVELOPERS" type="add">Support for creating new HSLF CurrentUserAtoms</action>
|
||||
<action dev="POI-DEVELOPERS" type="add">45466 - Partial support for removing excel comments (won't work for all excel versions yet)</action>
|
||||
<action dev="POI-DEVELOPERS" type="fix">45437 - Detect encrypted word documents, and throw an EncryptedDocumentException instead of a OOM</action>
|
||||
<action dev="POI-DEVELOPERS" type="add">45404 - New class, hssf.usermodel.HSSFDataFormatter, for formatting numbers and dates in the same way that Excel does</action>
|
||||
<action dev="POI-DEVELOPERS" type="fix">45414 - Don't add too many UncalcedRecords to sheets with charts in them</action>
|
||||
|
@ -113,260 +113,136 @@ public final class BiffViewer {
|
||||
{
|
||||
switch ( in.getSid() )
|
||||
{
|
||||
case ChartRecord.sid:
|
||||
return new ChartRecord( in );
|
||||
case ChartFormatRecord.sid:
|
||||
return new ChartFormatRecord( in );
|
||||
case SeriesRecord.sid:
|
||||
return new SeriesRecord( in );
|
||||
case BeginRecord.sid:
|
||||
return new BeginRecord( in );
|
||||
case EndRecord.sid:
|
||||
return new EndRecord( in );
|
||||
case BOFRecord.sid:
|
||||
return new BOFRecord( in );
|
||||
case InterfaceHdrRecord.sid:
|
||||
return new InterfaceHdrRecord( in );
|
||||
case MMSRecord.sid:
|
||||
return new MMSRecord( in );
|
||||
case InterfaceEndRecord.sid:
|
||||
return new InterfaceEndRecord( in );
|
||||
case WriteAccessRecord.sid:
|
||||
return new WriteAccessRecord( in );
|
||||
case CodepageRecord.sid:
|
||||
return new CodepageRecord( in );
|
||||
case DSFRecord.sid:
|
||||
return new DSFRecord( in );
|
||||
case TabIdRecord.sid:
|
||||
return new TabIdRecord( in );
|
||||
case FnGroupCountRecord.sid:
|
||||
return new FnGroupCountRecord( in );
|
||||
case WindowProtectRecord.sid:
|
||||
return new WindowProtectRecord( in );
|
||||
case ProtectRecord.sid:
|
||||
return new ProtectRecord( in );
|
||||
case PasswordRecord.sid:
|
||||
return new PasswordRecord( in );
|
||||
case ProtectionRev4Record.sid:
|
||||
return new ProtectionRev4Record( in );
|
||||
case PasswordRev4Record.sid:
|
||||
return new PasswordRev4Record( in );
|
||||
case WindowOneRecord.sid:
|
||||
return new WindowOneRecord( in );
|
||||
case BackupRecord.sid:
|
||||
return new BackupRecord( in );
|
||||
case HideObjRecord.sid:
|
||||
return new HideObjRecord( in );
|
||||
case DateWindow1904Record.sid:
|
||||
return new DateWindow1904Record( in );
|
||||
case PrecisionRecord.sid:
|
||||
return new PrecisionRecord( in );
|
||||
case RefreshAllRecord.sid:
|
||||
return new RefreshAllRecord( in );
|
||||
case BookBoolRecord.sid:
|
||||
return new BookBoolRecord( in );
|
||||
case FontRecord.sid:
|
||||
return new FontRecord( in );
|
||||
case FormatRecord.sid:
|
||||
return new FormatRecord( in );
|
||||
case ExtendedFormatRecord.sid:
|
||||
return new ExtendedFormatRecord( in );
|
||||
case StyleRecord.sid:
|
||||
return new StyleRecord( in );
|
||||
case UseSelFSRecord.sid:
|
||||
return new UseSelFSRecord( in );
|
||||
case BoundSheetRecord.sid:
|
||||
return new BoundSheetRecord( in );
|
||||
case CountryRecord.sid:
|
||||
return new CountryRecord( in );
|
||||
case SSTRecord.sid:
|
||||
return new SSTRecord( in );
|
||||
case ExtSSTRecord.sid:
|
||||
return new ExtSSTRecord( in );
|
||||
case EOFRecord.sid:
|
||||
return new EOFRecord( in );
|
||||
case IndexRecord.sid:
|
||||
return new IndexRecord( in );
|
||||
case CalcModeRecord.sid:
|
||||
return new CalcModeRecord( in );
|
||||
case CalcCountRecord.sid:
|
||||
return new CalcCountRecord( in );
|
||||
case RefModeRecord.sid:
|
||||
return new RefModeRecord( in );
|
||||
case IterationRecord.sid:
|
||||
return new IterationRecord( in );
|
||||
case DeltaRecord.sid:
|
||||
return new DeltaRecord( in );
|
||||
case SaveRecalcRecord.sid:
|
||||
return new SaveRecalcRecord( in );
|
||||
case PrintHeadersRecord.sid:
|
||||
return new PrintHeadersRecord( in );
|
||||
case PrintGridlinesRecord.sid:
|
||||
return new PrintGridlinesRecord( in );
|
||||
case GridsetRecord.sid:
|
||||
return new GridsetRecord( in );
|
||||
case DrawingGroupRecord.sid:
|
||||
return new DrawingGroupRecord( in );
|
||||
case DrawingRecordForBiffViewer.sid:
|
||||
return new DrawingRecordForBiffViewer( in );
|
||||
case DrawingSelectionRecord.sid:
|
||||
return new DrawingSelectionRecord( in );
|
||||
case GutsRecord.sid:
|
||||
return new GutsRecord( in );
|
||||
case DefaultRowHeightRecord.sid:
|
||||
return new DefaultRowHeightRecord( in );
|
||||
case WSBoolRecord.sid:
|
||||
return new WSBoolRecord( in );
|
||||
case HeaderRecord.sid:
|
||||
return new HeaderRecord( in );
|
||||
case FooterRecord.sid:
|
||||
return new FooterRecord( in );
|
||||
case HCenterRecord.sid:
|
||||
return new HCenterRecord( in );
|
||||
case VCenterRecord.sid:
|
||||
return new VCenterRecord( in );
|
||||
case PrintSetupRecord.sid:
|
||||
return new PrintSetupRecord( in );
|
||||
case DefaultColWidthRecord.sid:
|
||||
return new DefaultColWidthRecord( in );
|
||||
case DimensionsRecord.sid:
|
||||
return new DimensionsRecord( in );
|
||||
case RowRecord.sid:
|
||||
return new RowRecord( in );
|
||||
case LabelSSTRecord.sid:
|
||||
return new LabelSSTRecord( in );
|
||||
case RKRecord.sid:
|
||||
return new RKRecord( in );
|
||||
case NumberRecord.sid:
|
||||
return new NumberRecord( in );
|
||||
case DBCellRecord.sid:
|
||||
return new DBCellRecord( in );
|
||||
case WindowTwoRecord.sid:
|
||||
return new WindowTwoRecord( in );
|
||||
case SelectionRecord.sid:
|
||||
return new SelectionRecord( in );
|
||||
case ContinueRecord.sid:
|
||||
return new ContinueRecord( in );
|
||||
case LabelRecord.sid:
|
||||
return new LabelRecord( in );
|
||||
case MulRKRecord.sid:
|
||||
return new MulRKRecord( in );
|
||||
case MulBlankRecord.sid:
|
||||
return new MulBlankRecord( in );
|
||||
case BlankRecord.sid:
|
||||
return new BlankRecord( in );
|
||||
case BoolErrRecord.sid:
|
||||
return new BoolErrRecord( in );
|
||||
case ColumnInfoRecord.sid:
|
||||
return new ColumnInfoRecord( in );
|
||||
case MergeCellsRecord.sid:
|
||||
return new MergeCellsRecord( in );
|
||||
case AreaRecord.sid:
|
||||
return new AreaRecord( in );
|
||||
case DataFormatRecord.sid:
|
||||
return new DataFormatRecord( in );
|
||||
case BarRecord.sid:
|
||||
return new BarRecord( in );
|
||||
case DatRecord.sid:
|
||||
return new DatRecord( in );
|
||||
case PlotGrowthRecord.sid:
|
||||
return new PlotGrowthRecord( in );
|
||||
case UnitsRecord.sid:
|
||||
return new UnitsRecord( in );
|
||||
case FrameRecord.sid:
|
||||
return new FrameRecord( in );
|
||||
case ValueRangeRecord.sid:
|
||||
return new ValueRangeRecord( in );
|
||||
case SeriesListRecord.sid:
|
||||
return new SeriesListRecord( in );
|
||||
case FontBasisRecord.sid:
|
||||
return new FontBasisRecord( in );
|
||||
case FontIndexRecord.sid:
|
||||
return new FontIndexRecord( in );
|
||||
case LineFormatRecord.sid:
|
||||
return new LineFormatRecord( in );
|
||||
case AreaFormatRecord.sid:
|
||||
return new AreaFormatRecord( in );
|
||||
case LinkedDataRecord.sid:
|
||||
return new LinkedDataRecord( in );
|
||||
case FormulaRecord.sid:
|
||||
return new FormulaRecord( in );
|
||||
case SheetPropertiesRecord.sid:
|
||||
return new SheetPropertiesRecord( in );
|
||||
case DefaultDataLabelTextPropertiesRecord.sid:
|
||||
return new DefaultDataLabelTextPropertiesRecord( in );
|
||||
case TextRecord.sid:
|
||||
return new TextRecord( in );
|
||||
case AxisParentRecord.sid:
|
||||
return new AxisParentRecord( in );
|
||||
case AxisLineFormatRecord.sid:
|
||||
return new AxisLineFormatRecord( in );
|
||||
case SupBookRecord.sid:
|
||||
return new SupBookRecord( in );
|
||||
case ExternSheetRecord.sid:
|
||||
return new ExternSheetRecord( in );
|
||||
case SCLRecord.sid:
|
||||
return new SCLRecord( in );
|
||||
case SeriesToChartGroupRecord.sid:
|
||||
return new SeriesToChartGroupRecord( in );
|
||||
case AxisUsedRecord.sid:
|
||||
return new AxisUsedRecord( in );
|
||||
case AxisRecord.sid:
|
||||
return new AxisRecord( in );
|
||||
case CategorySeriesAxisRecord.sid:
|
||||
return new CategorySeriesAxisRecord( in );
|
||||
case AxisOptionsRecord.sid:
|
||||
return new AxisOptionsRecord( in );
|
||||
case TickRecord.sid:
|
||||
return new TickRecord( in );
|
||||
case SeriesTextRecord.sid:
|
||||
return new SeriesTextRecord( in );
|
||||
case ObjectLinkRecord.sid:
|
||||
return new ObjectLinkRecord( in );
|
||||
case PlotAreaRecord.sid:
|
||||
return new PlotAreaRecord( in );
|
||||
case SeriesIndexRecord.sid:
|
||||
return new SeriesIndexRecord( in );
|
||||
case LegendRecord.sid:
|
||||
return new LegendRecord( in );
|
||||
case LeftMarginRecord.sid:
|
||||
return new LeftMarginRecord( in );
|
||||
case RightMarginRecord.sid:
|
||||
return new RightMarginRecord( in );
|
||||
case TopMarginRecord.sid:
|
||||
return new TopMarginRecord( in );
|
||||
case BottomMarginRecord.sid:
|
||||
return new BottomMarginRecord( in );
|
||||
case PaletteRecord.sid:
|
||||
return new PaletteRecord( in );
|
||||
case StringRecord.sid:
|
||||
return new StringRecord( in );
|
||||
case NameRecord.sid:
|
||||
return new NameRecord( in );
|
||||
case PaneRecord.sid:
|
||||
return new PaneRecord( in );
|
||||
case SharedFormulaRecord.sid:
|
||||
return new SharedFormulaRecord( in);
|
||||
case ObjRecord.sid:
|
||||
return new ObjRecord( in);
|
||||
case TextObjectRecord.sid:
|
||||
return new TextObjectRecord( in);
|
||||
case HorizontalPageBreakRecord.sid:
|
||||
return new HorizontalPageBreakRecord( in);
|
||||
case VerticalPageBreakRecord.sid:
|
||||
return new VerticalPageBreakRecord( in);
|
||||
case WriteProtectRecord.sid:
|
||||
return new WriteProtectRecord( in);
|
||||
case FilePassRecord.sid:
|
||||
return new FilePassRecord(in);
|
||||
case NoteRecord.sid:
|
||||
return new NoteRecord( in );
|
||||
case FileSharingRecord.sid:
|
||||
return new FileSharingRecord( in );
|
||||
case HyperlinkRecord.sid:
|
||||
return new HyperlinkRecord( in );
|
||||
case TableRecord.sid:
|
||||
return new TableRecord( in );
|
||||
case AreaFormatRecord.sid: return new AreaFormatRecord(in);
|
||||
case AreaRecord.sid: return new AreaRecord(in);
|
||||
case AxisLineFormatRecord.sid: return new AxisLineFormatRecord(in);
|
||||
case AxisOptionsRecord.sid: return new AxisOptionsRecord(in);
|
||||
case AxisParentRecord.sid: return new AxisParentRecord(in);
|
||||
case AxisRecord.sid: return new AxisRecord(in);
|
||||
case AxisUsedRecord.sid: return new AxisUsedRecord(in);
|
||||
case BOFRecord.sid: return new BOFRecord(in);
|
||||
case BackupRecord.sid: return new BackupRecord(in);
|
||||
case BarRecord.sid: return new BarRecord(in);
|
||||
case BeginRecord.sid: return new BeginRecord(in);
|
||||
case BlankRecord.sid: return new BlankRecord(in);
|
||||
case BookBoolRecord.sid: return new BookBoolRecord(in);
|
||||
case BoolErrRecord.sid: return new BoolErrRecord(in);
|
||||
case BottomMarginRecord.sid: return new BottomMarginRecord(in);
|
||||
case BoundSheetRecord.sid: return new BoundSheetRecord(in);
|
||||
case CalcCountRecord.sid: return new CalcCountRecord(in);
|
||||
case CalcModeRecord.sid: return new CalcModeRecord(in);
|
||||
case CategorySeriesAxisRecord.sid: return new CategorySeriesAxisRecord(in);
|
||||
case ChartFormatRecord.sid: return new ChartFormatRecord(in);
|
||||
case ChartRecord.sid: return new ChartRecord(in);
|
||||
case CodepageRecord.sid: return new CodepageRecord(in);
|
||||
case ColumnInfoRecord.sid: return new ColumnInfoRecord(in);
|
||||
case ContinueRecord.sid: return new ContinueRecord(in);
|
||||
case CountryRecord.sid: return new CountryRecord(in);
|
||||
case DBCellRecord.sid: return new DBCellRecord(in);
|
||||
case DSFRecord.sid: return new DSFRecord(in);
|
||||
case DatRecord.sid: return new DatRecord(in);
|
||||
case DataFormatRecord.sid: return new DataFormatRecord(in);
|
||||
case DateWindow1904Record.sid: return new DateWindow1904Record(in);
|
||||
case DefaultColWidthRecord.sid:return new DefaultColWidthRecord(in);
|
||||
case DefaultDataLabelTextPropertiesRecord.sid: return new DefaultDataLabelTextPropertiesRecord(in);
|
||||
case DefaultRowHeightRecord.sid: return new DefaultRowHeightRecord(in);
|
||||
case DeltaRecord.sid: return new DeltaRecord(in);
|
||||
case DimensionsRecord.sid: return new DimensionsRecord(in);
|
||||
case DrawingGroupRecord.sid: return new DrawingGroupRecord(in);
|
||||
case DrawingRecordForBiffViewer.sid: return new DrawingRecordForBiffViewer(in);
|
||||
case DrawingSelectionRecord.sid: return new DrawingSelectionRecord(in);
|
||||
case DVRecord.sid: return new DVRecord(in);
|
||||
case DVALRecord.sid: return new DVALRecord(in);
|
||||
case EOFRecord.sid: return new EOFRecord(in);
|
||||
case EndRecord.sid: return new EndRecord(in);
|
||||
case ExtSSTRecord.sid: return new ExtSSTRecord(in);
|
||||
case ExtendedFormatRecord.sid: return new ExtendedFormatRecord(in);
|
||||
case ExternSheetRecord.sid: return new ExternSheetRecord(in);
|
||||
case FilePassRecord.sid: return new FilePassRecord(in);
|
||||
case FileSharingRecord.sid: return new FileSharingRecord(in);
|
||||
case FnGroupCountRecord.sid: return new FnGroupCountRecord(in);
|
||||
case FontBasisRecord.sid: return new FontBasisRecord(in);
|
||||
case FontIndexRecord.sid: return new FontIndexRecord(in);
|
||||
case FontRecord.sid: return new FontRecord(in);
|
||||
case FooterRecord.sid: return new FooterRecord(in);
|
||||
case FormatRecord.sid: return new FormatRecord(in);
|
||||
case FormulaRecord.sid: return new FormulaRecord(in);
|
||||
case FrameRecord.sid: return new FrameRecord(in);
|
||||
case GridsetRecord.sid: return new GridsetRecord(in);
|
||||
case GutsRecord.sid: return new GutsRecord(in);
|
||||
case HCenterRecord.sid: return new HCenterRecord(in);
|
||||
case HeaderRecord.sid: return new HeaderRecord(in);
|
||||
case HideObjRecord.sid: return new HideObjRecord(in);
|
||||
case HorizontalPageBreakRecord.sid: return new HorizontalPageBreakRecord(in);
|
||||
case HyperlinkRecord.sid: return new HyperlinkRecord(in);
|
||||
case IndexRecord.sid: return new IndexRecord(in);
|
||||
case InterfaceEndRecord.sid: return new InterfaceEndRecord(in);
|
||||
case InterfaceHdrRecord.sid: return new InterfaceHdrRecord(in);
|
||||
case IterationRecord.sid: return new IterationRecord(in);
|
||||
case LabelRecord.sid: return new LabelRecord(in);
|
||||
case LabelSSTRecord.sid: return new LabelSSTRecord(in);
|
||||
case LeftMarginRecord.sid: return new LeftMarginRecord(in);
|
||||
case LegendRecord.sid: return new LegendRecord(in);
|
||||
case LineFormatRecord.sid: return new LineFormatRecord(in);
|
||||
case LinkedDataRecord.sid: return new LinkedDataRecord(in);
|
||||
case MMSRecord.sid: return new MMSRecord(in);
|
||||
case MergeCellsRecord.sid: return new MergeCellsRecord(in);
|
||||
case MulBlankRecord.sid: return new MulBlankRecord(in);
|
||||
case MulRKRecord.sid: return new MulRKRecord(in);
|
||||
case NameRecord.sid: return new NameRecord(in);
|
||||
case NoteRecord.sid: return new NoteRecord(in);
|
||||
case NumberRecord.sid: return new NumberRecord(in);
|
||||
case ObjRecord.sid: return new ObjRecord(in);
|
||||
case ObjectLinkRecord.sid: return new ObjectLinkRecord(in);
|
||||
case PaletteRecord.sid: return new PaletteRecord(in);
|
||||
case PaneRecord.sid: return new PaneRecord(in);
|
||||
case PasswordRecord.sid: return new PasswordRecord(in);
|
||||
case PasswordRev4Record.sid: return new PasswordRev4Record(in);
|
||||
case PlotAreaRecord.sid: return new PlotAreaRecord(in);
|
||||
case PlotGrowthRecord.sid: return new PlotGrowthRecord(in);
|
||||
case PrecisionRecord.sid: return new PrecisionRecord(in);
|
||||
case PrintGridlinesRecord.sid: return new PrintGridlinesRecord(in);
|
||||
case PrintHeadersRecord.sid: return new PrintHeadersRecord(in);
|
||||
case PrintSetupRecord.sid: return new PrintSetupRecord(in);
|
||||
case ProtectRecord.sid: return new ProtectRecord(in);
|
||||
case ProtectionRev4Record.sid: return new ProtectionRev4Record(in);
|
||||
case RKRecord.sid: return new RKRecord(in);
|
||||
case RefModeRecord.sid: return new RefModeRecord(in);
|
||||
case RefreshAllRecord.sid: return new RefreshAllRecord(in);
|
||||
case RightMarginRecord.sid: return new RightMarginRecord(in);
|
||||
case RowRecord.sid: return new RowRecord(in);
|
||||
case SCLRecord.sid: return new SCLRecord(in);
|
||||
case SSTRecord.sid: return new SSTRecord(in);
|
||||
case SaveRecalcRecord.sid: return new SaveRecalcRecord(in);
|
||||
case SelectionRecord.sid: return new SelectionRecord(in);
|
||||
case SeriesIndexRecord.sid: return new SeriesIndexRecord(in);
|
||||
case SeriesListRecord.sid: return new SeriesListRecord(in);
|
||||
case SeriesRecord.sid: return new SeriesRecord(in);
|
||||
case SeriesTextRecord.sid: return new SeriesTextRecord(in);
|
||||
case SeriesToChartGroupRecord.sid: return new SeriesToChartGroupRecord(in);
|
||||
case SharedFormulaRecord.sid: return new SharedFormulaRecord(in);
|
||||
case SheetPropertiesRecord.sid:return new SheetPropertiesRecord(in);
|
||||
case StringRecord.sid: return new StringRecord(in);
|
||||
case StyleRecord.sid: return new StyleRecord(in);
|
||||
case SupBookRecord.sid: return new SupBookRecord(in);
|
||||
case TabIdRecord.sid: return new TabIdRecord(in);
|
||||
case TableRecord.sid: return new TableRecord(in);
|
||||
case TextObjectRecord.sid: return new TextObjectRecord(in);
|
||||
case TextRecord.sid: return new TextRecord(in);
|
||||
case TickRecord.sid: return new TickRecord(in);
|
||||
case TopMarginRecord.sid: return new TopMarginRecord(in);
|
||||
case UnitsRecord.sid: return new UnitsRecord(in);
|
||||
case UseSelFSRecord.sid: return new UseSelFSRecord(in);
|
||||
case VCenterRecord.sid: return new VCenterRecord(in);
|
||||
case ValueRangeRecord.sid: return new ValueRangeRecord(in);
|
||||
case VerticalPageBreakRecord.sid: return new VerticalPageBreakRecord(in);
|
||||
case WSBoolRecord.sid: return new WSBoolRecord(in);
|
||||
case WindowOneRecord.sid: return new WindowOneRecord(in);
|
||||
case WindowProtectRecord.sid: return new WindowProtectRecord(in);
|
||||
case WindowTwoRecord.sid: return new WindowTwoRecord(in);
|
||||
case WriteAccessRecord.sid: return new WriteAccessRecord(in);
|
||||
case WriteProtectRecord.sid: return new WriteProtectRecord(in);
|
||||
|
||||
}
|
||||
return new UnknownRecord(in);
|
||||
}
|
||||
|
@ -18,14 +18,21 @@
|
||||
|
||||
package org.apache.poi.hssf.dev;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
|
||||
import org.apache.poi.hssf.usermodel.HSSFCell;
|
||||
import org.apache.poi.hssf.usermodel.HSSFCellStyle;
|
||||
import org.apache.poi.hssf.usermodel.HSSFDataFormat;
|
||||
import org.apache.poi.hssf.usermodel.HSSFFont;
|
||||
import org.apache.poi.hssf.usermodel.HSSFRichTextString;
|
||||
import org.apache.poi.hssf.usermodel.HSSFRow;
|
||||
import org.apache.poi.hssf.usermodel.HSSFSheet;
|
||||
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
|
||||
import org.apache.poi.hssf.util.CellRangeAddress;
|
||||
import org.apache.poi.poifs.filesystem.POIFSFileSystem;
|
||||
import org.apache.poi.ss.util.Region;
|
||||
import org.apache.poi.hssf.usermodel.*;
|
||||
import org.apache.poi.hssf.util.*;
|
||||
|
||||
/**
|
||||
* File for HSSF testing/examples
|
||||
@ -127,7 +134,7 @@ public class HSSF
|
||||
}
|
||||
c = r.createCell(( short ) (cellnum + 1),
|
||||
HSSFCell.CELL_TYPE_STRING);
|
||||
c.setCellValue("TEST");
|
||||
c.setCellValue(new HSSFRichTextString("TEST"));
|
||||
s.setColumnWidth(( short ) (cellnum + 1),
|
||||
( short ) ((50 * 8) / (( double ) 1 / 20)));
|
||||
if ((rownum % 2) == 0)
|
||||
@ -149,10 +156,8 @@ public class HSSF
|
||||
// c.setCellValue(0);
|
||||
c.setCellStyle(cs3);
|
||||
}
|
||||
s.addMergedRegion(new Region(( short ) 0, ( short ) 0, ( short ) 3,
|
||||
( short ) 3));
|
||||
s.addMergedRegion(new Region(( short ) 100, ( short ) 100,
|
||||
( short ) 110, ( short ) 110));
|
||||
s.addMergedRegion(new CellRangeAddress(0, 3, 0, 3));
|
||||
s.addMergedRegion(new CellRangeAddress(100, 110, 100, 110));
|
||||
|
||||
// end draw thick black border
|
||||
// create a sheet, set its title then delete it
|
||||
|
@ -27,6 +27,7 @@ import org.apache.poi.hssf.record.formula.*;
|
||||
import org.apache.poi.hssf.record.formula.function.FunctionMetadata;
|
||||
import org.apache.poi.hssf.record.formula.function.FunctionMetadataRegistry;
|
||||
import org.apache.poi.ss.usermodel.Workbook;
|
||||
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
|
||||
import org.apache.poi.hssf.util.AreaReference;
|
||||
import org.apache.poi.hssf.util.CellReference;
|
||||
import org.apache.poi.hssf.util.CellReference.NameType;
|
||||
@ -66,8 +67,11 @@ public final class FormulaParser {
|
||||
public static final int FORMULA_TYPE_CELL = 0;
|
||||
public static final int FORMULA_TYPE_SHARED = 1;
|
||||
public static final int FORMULA_TYPE_ARRAY =2;
|
||||
public static final int FORMULA_TYPE_CONDFOMRAT = 3;
|
||||
public static final int FORMULA_TYPE_CONDFORMAT = 3;
|
||||
public static final int FORMULA_TYPE_NAMEDRANGE = 4;
|
||||
// this constant is currently very specific. The exact differences from general data
|
||||
// validation formulas or conditional format formulas is not known yet
|
||||
public static final int FORMULA_TYPE_DATAVALIDATION_LIST = 5;
|
||||
|
||||
private final String formulaString;
|
||||
private final int formulaLength;
|
||||
@ -75,12 +79,6 @@ public final class FormulaParser {
|
||||
|
||||
private ParseNode _rootNode;
|
||||
|
||||
/**
|
||||
* 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';
|
||||
|
||||
/**
|
||||
@ -112,9 +110,13 @@ public final class FormulaParser {
|
||||
}
|
||||
|
||||
public static Ptg[] parse(String formula, Workbook book) {
|
||||
FormulaParser fp = new FormulaParser(formula, book);
|
||||
return parse(formula, book, FORMULA_TYPE_CELL);
|
||||
}
|
||||
|
||||
public static Ptg[] parse(String formula, Workbook workbook, int formulaType) {
|
||||
FormulaParser fp = new FormulaParser(formula, workbook);
|
||||
fp.parse();
|
||||
return fp.getRPNPtg();
|
||||
return fp.getRPNPtg(formulaType);
|
||||
}
|
||||
|
||||
/** Read New Character From Input Stream */
|
||||
|
@ -66,6 +66,9 @@ final class OperandClassTransformer {
|
||||
case FormulaParser.FORMULA_TYPE_CELL:
|
||||
rootNodeOperandClass = Ptg.CLASS_VALUE;
|
||||
break;
|
||||
case FormulaParser.FORMULA_TYPE_DATAVALIDATION_LIST:
|
||||
rootNodeOperandClass = Ptg.CLASS_REF;
|
||||
break;
|
||||
default:
|
||||
throw new RuntimeException("Incomplete code - formula type ("
|
||||
+ _formulaType + ") not supported yet");
|
||||
|
@ -25,7 +25,7 @@ import org.apache.poi.hssf.record.Record;
|
||||
*
|
||||
* @author Josh Micich
|
||||
*/
|
||||
final class RecordStream {
|
||||
public final class RecordStream {
|
||||
|
||||
private final List _list;
|
||||
private int _nextIndex;
|
||||
|
@ -17,13 +17,14 @@
|
||||
|
||||
package org.apache.poi.hssf.model;
|
||||
|
||||
import org.apache.poi.hssf.record.*;
|
||||
import org.apache.poi.hssf.record.*; // normally I don't do this, buy we literally mean ALL
|
||||
import org.apache.poi.hssf.record.aggregates.ColumnInfoRecordsAggregate;
|
||||
import org.apache.poi.hssf.record.aggregates.DataValidityTable;
|
||||
import org.apache.poi.hssf.record.aggregates.FormulaRecordAggregate;
|
||||
import org.apache.poi.hssf.record.aggregates.RowRecordsAggregate;
|
||||
import org.apache.poi.hssf.record.aggregates.ValueRecordsAggregate;
|
||||
import org.apache.poi.hssf.record.aggregates.CFRecordsAggregate;
|
||||
import org.apache.poi.hssf.record.formula.Ptg;
|
||||
import org.apache.poi.ss.util.CellRangeAddress;
|
||||
import org.apache.poi.hssf.util.PaneInformation;
|
||||
|
||||
import org.apache.poi.util.POILogFactory;
|
||||
@ -31,7 +32,7 @@ import org.apache.poi.util.POILogger;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Iterator;
|
||||
import java.util.List; // normally I don't do this, buy we literally mean ALL
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Low level model implementation of a Sheet (one workbook contains many sheets)
|
||||
@ -90,6 +91,7 @@ public final class Sheet implements Model {
|
||||
protected ProtectRecord protect = null;
|
||||
protected PageBreakRecord rowBreaks = null;
|
||||
protected PageBreakRecord colBreaks = null;
|
||||
private DataValidityTable _dataValidityTable= null;
|
||||
protected ObjectProtectRecord objprotect = null;
|
||||
protected ScenarioProtectRecord scenprotect = null;
|
||||
protected PasswordRecord password = null;
|
||||
@ -299,7 +301,12 @@ public final class Sheet implements Model {
|
||||
// and POI always re-calculates its contents
|
||||
rec = null;
|
||||
}
|
||||
|
||||
else if ( rec.getSid() == DVALRecord.sid) {
|
||||
RecordStream rs = new RecordStream(recs, k);
|
||||
retval._dataValidityTable = new DataValidityTable(rs);
|
||||
k += rs.getCountRead() - 1; // TODO - convert this method result to be zero based
|
||||
rec = retval._dataValidityTable;
|
||||
}
|
||||
else if ( rec.getSid() == ProtectRecord.sid )
|
||||
{
|
||||
retval.protect = (ProtectRecord) rec;
|
||||
@ -425,56 +432,56 @@ public final class Sheet implements Model {
|
||||
Sheet retval = new Sheet();
|
||||
ArrayList records = new ArrayList(30);
|
||||
|
||||
records.add(retval.createBOF());
|
||||
records.add(createBOF());
|
||||
|
||||
// records.add(retval.createIndex());
|
||||
records.add(retval.createCalcMode());
|
||||
records.add(retval.createCalcCount() );
|
||||
records.add( retval.createRefMode() );
|
||||
records.add( retval.createIteration() );
|
||||
records.add( retval.createDelta() );
|
||||
records.add( retval.createSaveRecalc() );
|
||||
records.add( retval.createPrintHeaders() );
|
||||
retval.printGridlines = (PrintGridlinesRecord) retval.createPrintGridlines();
|
||||
records.add(createCalcMode());
|
||||
records.add(createCalcCount() );
|
||||
records.add(createRefMode() );
|
||||
records.add(createIteration() );
|
||||
records.add(createDelta() );
|
||||
records.add(createSaveRecalc() );
|
||||
records.add(createPrintHeaders() );
|
||||
retval.printGridlines = createPrintGridlines();
|
||||
records.add( retval.printGridlines );
|
||||
retval.gridset = (GridsetRecord) retval.createGridset();
|
||||
retval.gridset = createGridset();
|
||||
records.add( retval.gridset );
|
||||
records.add( retval.createGuts() );
|
||||
retval.defaultrowheight =
|
||||
(DefaultRowHeightRecord) retval.createDefaultRowHeight();
|
||||
retval.defaultrowheight = createDefaultRowHeight();
|
||||
records.add( retval.defaultrowheight );
|
||||
records.add( retval.createWSBool() );
|
||||
|
||||
// 'Page Settings Block'
|
||||
retval.rowBreaks = new PageBreakRecord(PageBreakRecord.HORIZONTAL_SID);
|
||||
records.add(retval.rowBreaks);
|
||||
retval.colBreaks = new PageBreakRecord(PageBreakRecord.VERTICAL_SID);
|
||||
records.add(retval.colBreaks);
|
||||
|
||||
retval.header = (HeaderRecord) retval.createHeader();
|
||||
retval.header = createHeader();
|
||||
records.add( retval.header );
|
||||
retval.footer = (FooterRecord) retval.createFooter();
|
||||
retval.footer = createFooter();
|
||||
records.add( retval.footer );
|
||||
records.add( retval.createHCenter() );
|
||||
records.add( retval.createVCenter() );
|
||||
retval.printSetup = (PrintSetupRecord) retval.createPrintSetup();
|
||||
records.add(createHCenter() );
|
||||
records.add(createVCenter() );
|
||||
retval.printSetup = createPrintSetup();
|
||||
records.add( retval.printSetup );
|
||||
retval.defaultcolwidth =
|
||||
(DefaultColWidthRecord) retval.createDefaultColWidth();
|
||||
|
||||
// 'Worksheet Protection Block' (after 'Page Settings Block' and before DEFCOLWIDTH)
|
||||
// PROTECT record normally goes here, don't add yet since the flag is initially false
|
||||
|
||||
retval.defaultcolwidth = createDefaultColWidth();
|
||||
records.add( retval.defaultcolwidth);
|
||||
ColumnInfoRecordsAggregate columns = new ColumnInfoRecordsAggregate();
|
||||
records.add( columns );
|
||||
retval.columns = columns;
|
||||
retval.dims = ( DimensionsRecord ) retval.createDimensions();
|
||||
retval.dims = createDimensions();
|
||||
records.add(retval.dims);
|
||||
retval.dimsloc = records.size()-1;
|
||||
records.add(retval.windowTwo = retval.createWindowTwo());
|
||||
retval.setLoc(records.size() - 1);
|
||||
retval.selection =
|
||||
(SelectionRecord) retval.createSelection();
|
||||
retval.selection = createSelection();
|
||||
records.add(retval.selection);
|
||||
retval.protect = (ProtectRecord) retval.createProtect();
|
||||
records.add(retval.protect);
|
||||
records.add(retval.createEOF());
|
||||
records.add(new EOFRecord());
|
||||
|
||||
|
||||
retval.records = records;
|
||||
@ -509,7 +516,7 @@ public final class Sheet implements Model {
|
||||
}
|
||||
}
|
||||
|
||||
public int addMergedRegion(int rowFrom, short colFrom, int rowTo, short colTo) {
|
||||
public int addMergedRegion(int rowFrom, int colFrom, int rowTo, int colTo) {
|
||||
// Validate input
|
||||
if (rowTo < rowFrom) {
|
||||
throw new IllegalArgumentException("The 'to' row (" + rowTo
|
||||
@ -522,7 +529,7 @@ public final class Sheet implements Model {
|
||||
|
||||
if (merged == null || merged.getNumAreas() == 1027)
|
||||
{
|
||||
merged = ( MergeCellsRecord ) createMergedCells();
|
||||
merged = createMergedCells();
|
||||
mergedRecords.add(merged);
|
||||
records.add(records.size() - 1, merged);
|
||||
}
|
||||
@ -579,7 +586,7 @@ public final class Sheet implements Model {
|
||||
}
|
||||
}
|
||||
|
||||
public MergeCellsRecord.MergedRegion getMergedRegionAt(int index)
|
||||
public CellRangeAddress getMergedRegionAt(int index)
|
||||
{
|
||||
//safety checks
|
||||
if (index >= numMergedRegions || mergedRecords.size() == 0)
|
||||
@ -911,124 +918,11 @@ public final class Sheet implements Model {
|
||||
|
||||
/**
|
||||
* Create a row record. (does not add it to the records contained in this sheet)
|
||||
*
|
||||
* @param row number
|
||||
* @return RowRecord created for the passed in row number
|
||||
* @see org.apache.poi.hssf.record.RowRecord
|
||||
*/
|
||||
|
||||
public RowRecord createRow(int row)
|
||||
{
|
||||
private static RowRecord createRow(int row) {
|
||||
return RowRecordsAggregate.createRow( row );
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a LABELSST Record (does not add it to the records contained in this sheet)
|
||||
*
|
||||
* @param row the row the LabelSST is a member of
|
||||
* @param col the column the LabelSST defines
|
||||
* @param index the index of the string within the SST (use workbook addSSTString method)
|
||||
* @return LabelSSTRecord newly created containing your SST Index, row,col.
|
||||
* @see org.apache.poi.hssf.record.SSTRecord
|
||||
*/
|
||||
public LabelSSTRecord createLabelSST(int row, short col, int index)
|
||||
{
|
||||
log.logFormatted(POILogger.DEBUG, "create labelsst row,col,index %,%,%",
|
||||
new int[]
|
||||
{
|
||||
row, col, index
|
||||
});
|
||||
LabelSSTRecord rec = new LabelSSTRecord();
|
||||
|
||||
rec.setRow(row);
|
||||
rec.setColumn(col);
|
||||
rec.setSSTIndex(index);
|
||||
rec.setXFIndex(( short ) 0x0f);
|
||||
return rec;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a NUMBER Record (does not add it to the records contained in this sheet)
|
||||
*
|
||||
* @param row the row the NumberRecord is a member of
|
||||
* @param col the column the NumberRecord defines
|
||||
* @param value for the number record
|
||||
*
|
||||
* @return NumberRecord for that row, col containing that value as added to the sheet
|
||||
*/
|
||||
public NumberRecord createNumber(int row, short col, double value)
|
||||
{
|
||||
log.logFormatted(POILogger.DEBUG, "create number row,col,value %,%,%",
|
||||
new double[]
|
||||
{
|
||||
row, col, value
|
||||
});
|
||||
NumberRecord rec = new NumberRecord();
|
||||
|
||||
rec.setRow(row);
|
||||
rec.setColumn(col);
|
||||
rec.setValue(value);
|
||||
rec.setXFIndex(( short ) 0x0f);
|
||||
return rec;
|
||||
}
|
||||
|
||||
/**
|
||||
* create a BLANK record (does not add it to the records contained in this sheet)
|
||||
*
|
||||
* @param row - the row the BlankRecord is a member of
|
||||
* @param col - the column the BlankRecord is a member of
|
||||
*/
|
||||
public BlankRecord createBlank(int row, short col)
|
||||
{
|
||||
log.logFormatted(POILogger.DEBUG, "create blank row,col %,%", new int[]
|
||||
{
|
||||
row, col
|
||||
});
|
||||
BlankRecord rec = new BlankRecord();
|
||||
|
||||
rec.setRow(row);
|
||||
rec.setColumn(col);
|
||||
rec.setXFIndex(( short ) 0x0f);
|
||||
return rec;
|
||||
}
|
||||
|
||||
/**
|
||||
* Attempts to parse the formula into PTGs and create a formula record
|
||||
* DOES NOT WORK YET
|
||||
*
|
||||
* @param row - the row for the formula record
|
||||
* @param col - the column of the formula record
|
||||
* @param formula - a String representing the formula. To be parsed to PTGs
|
||||
* @return bogus/useless formula record
|
||||
*/
|
||||
public FormulaRecord createFormula(int row, short col, String formula)
|
||||
{
|
||||
log.logFormatted(POILogger.DEBUG, "create formula row,col,formula %,%,%",
|
||||
new int[]
|
||||
{
|
||||
row, col
|
||||
}, formula);
|
||||
FormulaRecord rec = new FormulaRecord();
|
||||
|
||||
rec.setRow(row);
|
||||
rec.setColumn(col);
|
||||
rec.setOptions(( short ) 2);
|
||||
rec.setValue(0);
|
||||
rec.setXFIndex(( short ) 0x0f);
|
||||
FormulaParser fp = new FormulaParser(formula,null); //fix - do we need this method?
|
||||
fp.parse();
|
||||
Ptg[] ptg = fp.getRPNPtg();
|
||||
int size = 0;
|
||||
|
||||
for (int k = 0; k < ptg.length; k++)
|
||||
{
|
||||
size += ptg[ k ].getSize();
|
||||
rec.pushExpressionToken(ptg[ k ]);
|
||||
}
|
||||
rec.setExpressionLength(( short ) size);
|
||||
return rec;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a value record to the sheet's contained binary records
|
||||
* (i.e. LabelSSTRecord or NumberRecord).
|
||||
@ -1247,13 +1141,8 @@ public final class Sheet implements Model {
|
||||
|
||||
/**
|
||||
* creates the BOF record
|
||||
* @see org.apache.poi.hssf.record.BOFRecord
|
||||
* @see org.apache.poi.hssf.record.Record
|
||||
* @return record containing a BOFRecord
|
||||
*/
|
||||
|
||||
protected Record createBOF()
|
||||
{
|
||||
private static BOFRecord createBOF() {
|
||||
BOFRecord retval = new BOFRecord();
|
||||
|
||||
retval.setVersion(( short ) 0x600);
|
||||
@ -1266,31 +1155,10 @@ public final class Sheet implements Model {
|
||||
return retval;
|
||||
}
|
||||
|
||||
/**
|
||||
* creates the Index record - not currently used
|
||||
* @see org.apache.poi.hssf.record.IndexRecord
|
||||
* @see org.apache.poi.hssf.record.Record
|
||||
* @return record containing a IndexRecord
|
||||
*/
|
||||
|
||||
protected Record createIndex()
|
||||
{
|
||||
IndexRecord retval = new IndexRecord();
|
||||
|
||||
retval.setFirstRow(0); // must be set explicitly
|
||||
retval.setLastRowAdd1(0);
|
||||
return retval;
|
||||
}
|
||||
|
||||
/**
|
||||
* creates the CalcMode record and sets it to 1 (automatic formula caculation)
|
||||
* @see org.apache.poi.hssf.record.CalcModeRecord
|
||||
* @see org.apache.poi.hssf.record.Record
|
||||
* @return record containing a CalcModeRecord
|
||||
*/
|
||||
|
||||
protected Record createCalcMode()
|
||||
{
|
||||
private static CalcModeRecord createCalcMode() {
|
||||
CalcModeRecord retval = new CalcModeRecord();
|
||||
|
||||
retval.setCalcMode(( short ) 1);
|
||||
@ -1298,29 +1166,19 @@ public final class Sheet implements Model {
|
||||
}
|
||||
|
||||
/**
|
||||
* creates the CalcCount record and sets it to 0x64 (default number of iterations)
|
||||
* @see org.apache.poi.hssf.record.CalcCountRecord
|
||||
* @see org.apache.poi.hssf.record.Record
|
||||
* @return record containing a CalcCountRecord
|
||||
* creates the CalcCount record and sets it to 100 (default number of iterations)
|
||||
*/
|
||||
|
||||
protected Record createCalcCount()
|
||||
{
|
||||
private static CalcCountRecord createCalcCount() {
|
||||
CalcCountRecord retval = new CalcCountRecord();
|
||||
|
||||
retval.setIterations(( short ) 0x64); // default 64 iterations
|
||||
retval.setIterations(( short ) 100); // default 100 iterations
|
||||
return retval;
|
||||
}
|
||||
|
||||
/**
|
||||
* creates the RefMode record and sets it to A1 Mode (default reference mode)
|
||||
* @see org.apache.poi.hssf.record.RefModeRecord
|
||||
* @see org.apache.poi.hssf.record.Record
|
||||
* @return record containing a RefModeRecord
|
||||
*/
|
||||
|
||||
protected Record createRefMode()
|
||||
{
|
||||
private static RefModeRecord createRefMode() {
|
||||
RefModeRecord retval = new RefModeRecord();
|
||||
|
||||
retval.setMode(RefModeRecord.USE_A1_MODE);
|
||||
@ -1329,13 +1187,8 @@ public final class Sheet implements Model {
|
||||
|
||||
/**
|
||||
* creates the Iteration record and sets it to false (don't iteratively calculate formulas)
|
||||
* @see org.apache.poi.hssf.record.IterationRecord
|
||||
* @see org.apache.poi.hssf.record.Record
|
||||
* @return record containing a IterationRecord
|
||||
*/
|
||||
|
||||
protected Record createIteration()
|
||||
{
|
||||
private static IterationRecord createIteration() {
|
||||
IterationRecord retval = new IterationRecord();
|
||||
|
||||
retval.setIteration(false);
|
||||
@ -1344,13 +1197,8 @@ public final class Sheet implements Model {
|
||||
|
||||
/**
|
||||
* creates the Delta record and sets it to 0.0010 (default accuracy)
|
||||
* @see org.apache.poi.hssf.record.DeltaRecord
|
||||
* @see org.apache.poi.hssf.record.Record
|
||||
* @return record containing a DeltaRecord
|
||||
*/
|
||||
|
||||
protected Record createDelta()
|
||||
{
|
||||
private static DeltaRecord createDelta() {
|
||||
DeltaRecord retval = new DeltaRecord();
|
||||
|
||||
retval.setMaxChange(0.0010);
|
||||
@ -1359,13 +1207,8 @@ public final class Sheet implements Model {
|
||||
|
||||
/**
|
||||
* creates the SaveRecalc record and sets it to true (recalculate before saving)
|
||||
* @see org.apache.poi.hssf.record.SaveRecalcRecord
|
||||
* @see org.apache.poi.hssf.record.Record
|
||||
* @return record containing a SaveRecalcRecord
|
||||
*/
|
||||
|
||||
protected Record createSaveRecalc()
|
||||
{
|
||||
private static SaveRecalcRecord createSaveRecalc() {
|
||||
SaveRecalcRecord retval = new SaveRecalcRecord();
|
||||
|
||||
retval.setRecalc(true);
|
||||
@ -1374,13 +1217,8 @@ public final class Sheet implements Model {
|
||||
|
||||
/**
|
||||
* creates the PrintHeaders record and sets it to false (we don't create headers yet so why print them)
|
||||
* @see org.apache.poi.hssf.record.PrintHeadersRecord
|
||||
* @see org.apache.poi.hssf.record.Record
|
||||
* @return record containing a PrintHeadersRecord
|
||||
*/
|
||||
|
||||
protected Record createPrintHeaders()
|
||||
{
|
||||
private static PrintHeadersRecord createPrintHeaders() {
|
||||
PrintHeadersRecord retval = new PrintHeadersRecord();
|
||||
|
||||
retval.setPrintHeaders(false);
|
||||
@ -1390,14 +1228,8 @@ public final class Sheet implements Model {
|
||||
/**
|
||||
* creates the PrintGridlines record and sets it to false (that makes for ugly sheets). As far as I can
|
||||
* tell this does the same thing as the GridsetRecord
|
||||
*
|
||||
* @see org.apache.poi.hssf.record.PrintGridlinesRecord
|
||||
* @see org.apache.poi.hssf.record.Record
|
||||
* @return record containing a PrintGridlinesRecord
|
||||
*/
|
||||
|
||||
protected Record createPrintGridlines()
|
||||
{
|
||||
private static PrintGridlinesRecord createPrintGridlines() {
|
||||
PrintGridlinesRecord retval = new PrintGridlinesRecord();
|
||||
|
||||
retval.setPrintGridlines(false);
|
||||
@ -1406,13 +1238,8 @@ public final class Sheet implements Model {
|
||||
|
||||
/**
|
||||
* creates the Gridset record and sets it to true (user has mucked with the gridlines)
|
||||
* @see org.apache.poi.hssf.record.GridsetRecord
|
||||
* @see org.apache.poi.hssf.record.Record
|
||||
* @return record containing a GridsetRecord
|
||||
*/
|
||||
|
||||
protected Record createGridset()
|
||||
{
|
||||
private static GridsetRecord createGridset() {
|
||||
GridsetRecord retval = new GridsetRecord();
|
||||
|
||||
retval.setGridset(true);
|
||||
@ -1421,13 +1248,8 @@ public final class Sheet implements Model {
|
||||
|
||||
/**
|
||||
* creates the Guts record and sets leftrow/topcol guttter and rowlevelmax/collevelmax to 0
|
||||
* @see org.apache.poi.hssf.record.GutsRecord
|
||||
* @see org.apache.poi.hssf.record.Record
|
||||
* @return record containing a GutsRecordRecord
|
||||
*/
|
||||
|
||||
protected Record createGuts()
|
||||
{
|
||||
private static GutsRecord createGuts() {
|
||||
GutsRecord retval = new GutsRecord();
|
||||
|
||||
retval.setLeftRowGutter(( short ) 0);
|
||||
@ -1439,13 +1261,8 @@ public final class Sheet implements Model {
|
||||
|
||||
/**
|
||||
* creates the DefaultRowHeight Record and sets its options to 0 and rowheight to 0xff
|
||||
* @see org.apache.poi.hssf.record.DefaultRowHeightRecord
|
||||
* @see org.apache.poi.hssf.record.Record
|
||||
* @return record containing a DefaultRowHeightRecord
|
||||
*/
|
||||
|
||||
protected Record createDefaultRowHeight()
|
||||
{
|
||||
private static DefaultRowHeightRecord createDefaultRowHeight() {
|
||||
DefaultRowHeightRecord retval = new DefaultRowHeightRecord();
|
||||
|
||||
retval.setOptionFlags(( short ) 0);
|
||||
@ -1455,13 +1272,8 @@ public final class Sheet implements Model {
|
||||
|
||||
/**
|
||||
* creates the WSBoolRecord and sets its values to defaults
|
||||
* @see org.apache.poi.hssf.record.WSBoolRecord
|
||||
* @see org.apache.poi.hssf.record.Record
|
||||
* @return record containing a WSBoolRecord
|
||||
*/
|
||||
|
||||
protected Record createWSBool()
|
||||
{
|
||||
private static WSBoolRecord createWSBool() {
|
||||
WSBoolRecord retval = new WSBoolRecord();
|
||||
|
||||
retval.setWSBool1(( byte ) 0x4);
|
||||
@ -1471,13 +1283,8 @@ public final class Sheet implements Model {
|
||||
|
||||
/**
|
||||
* creates the Header Record and sets it to nothing/0 length
|
||||
* @see org.apache.poi.hssf.record.HeaderRecord
|
||||
* @see org.apache.poi.hssf.record.Record
|
||||
* @return record containing a HeaderRecord
|
||||
*/
|
||||
|
||||
protected Record createHeader()
|
||||
{
|
||||
private static HeaderRecord createHeader() {
|
||||
HeaderRecord retval = new HeaderRecord();
|
||||
|
||||
retval.setHeaderLength(( byte ) 0);
|
||||
@ -1487,13 +1294,8 @@ public final class Sheet implements Model {
|
||||
|
||||
/**
|
||||
* creates the Footer Record and sets it to nothing/0 length
|
||||
* @see org.apache.poi.hssf.record.FooterRecord
|
||||
* @see org.apache.poi.hssf.record.Record
|
||||
* @return record containing a FooterRecord
|
||||
*/
|
||||
|
||||
protected Record createFooter()
|
||||
{
|
||||
private static FooterRecord createFooter() {
|
||||
FooterRecord retval = new FooterRecord();
|
||||
|
||||
retval.setFooterLength(( byte ) 0);
|
||||
@ -1503,13 +1305,8 @@ public final class Sheet implements Model {
|
||||
|
||||
/**
|
||||
* creates the HCenter Record and sets it to false (don't horizontally center)
|
||||
* @see org.apache.poi.hssf.record.HCenterRecord
|
||||
* @see org.apache.poi.hssf.record.Record
|
||||
* @return record containing a HCenterRecord
|
||||
*/
|
||||
|
||||
protected Record createHCenter()
|
||||
{
|
||||
private static HCenterRecord createHCenter() {
|
||||
HCenterRecord retval = new HCenterRecord();
|
||||
|
||||
retval.setHCenter(false);
|
||||
@ -1518,13 +1315,8 @@ public final class Sheet implements Model {
|
||||
|
||||
/**
|
||||
* creates the VCenter Record and sets it to false (don't horizontally center)
|
||||
* @see org.apache.poi.hssf.record.VCenterRecord
|
||||
* @see org.apache.poi.hssf.record.Record
|
||||
* @return record containing a VCenterRecord
|
||||
*/
|
||||
|
||||
protected Record createVCenter()
|
||||
{
|
||||
private static VCenterRecord createVCenter() {
|
||||
VCenterRecord retval = new VCenterRecord();
|
||||
|
||||
retval.setVCenter(false);
|
||||
@ -1537,9 +1329,7 @@ public final class Sheet implements Model {
|
||||
* @see org.apache.poi.hssf.record.Record
|
||||
* @return record containing a PrintSetupRecord
|
||||
*/
|
||||
|
||||
protected Record createPrintSetup()
|
||||
{
|
||||
private static PrintSetupRecord createPrintSetup() {
|
||||
PrintSetupRecord retval = new PrintSetupRecord();
|
||||
|
||||
retval.setPaperSize(( short ) 1);
|
||||
@ -1558,30 +1348,13 @@ public final class Sheet implements Model {
|
||||
|
||||
/**
|
||||
* creates the DefaultColWidth Record and sets it to 8
|
||||
* @see org.apache.poi.hssf.record.DefaultColWidthRecord
|
||||
* @see org.apache.poi.hssf.record.Record
|
||||
* @return record containing a DefaultColWidthRecord
|
||||
*/
|
||||
|
||||
protected Record createDefaultColWidth()
|
||||
{
|
||||
private static DefaultColWidthRecord createDefaultColWidth() {
|
||||
DefaultColWidthRecord retval = new DefaultColWidthRecord();
|
||||
|
||||
retval.setColWidth(( short ) 8);
|
||||
return retval;
|
||||
}
|
||||
|
||||
/**
|
||||
* creates the ColumnInfo Record and sets it to a default column/width
|
||||
* @see org.apache.poi.hssf.record.ColumnInfoRecord
|
||||
* @return record containing a ColumnInfoRecord
|
||||
*/
|
||||
// TODO change return type to ColumnInfoRecord
|
||||
protected Record createColInfo()
|
||||
{
|
||||
return ColumnInfoRecordsAggregate.createColInfo();
|
||||
}
|
||||
|
||||
/**
|
||||
* get the default column width for the sheet (if the columns do not define their own width)
|
||||
* @return default column width
|
||||
@ -1600,7 +1373,7 @@ public final class Sheet implements Model {
|
||||
public boolean isGridsPrinted()
|
||||
{
|
||||
if (gridset == null) {
|
||||
gridset = (GridsetRecord)createGridset();
|
||||
gridset = createGridset();
|
||||
//Insert the newlycreated Gridset record at the end of the record (just before the EOF)
|
||||
int loc = findFirstRecordLocBySid(EOFRecord.sid);
|
||||
records.add(loc, gridset);
|
||||
@ -1816,22 +1589,18 @@ public final class Sheet implements Model {
|
||||
|
||||
GutsRecord guts = (GutsRecord) findFirstRecordBySid( GutsRecord.sid );
|
||||
guts.setColLevelMax( (short) ( maxLevel+1 ) );
|
||||
if (maxLevel == 0)
|
||||
if (maxLevel == 0) {
|
||||
guts.setTopColGutter( (short)0 );
|
||||
else
|
||||
} else {
|
||||
guts.setTopColGutter( (short) ( 29 + (12 * (maxLevel-1)) ) );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* creates the Dimensions Record and sets it to bogus values (you should set this yourself
|
||||
* or let the high level API do it for you)
|
||||
* @see org.apache.poi.hssf.record.DimensionsRecord
|
||||
* @see org.apache.poi.hssf.record.Record
|
||||
* @return record containing a DimensionsRecord
|
||||
*/
|
||||
|
||||
protected Record createDimensions()
|
||||
{
|
||||
private static DimensionsRecord createDimensions() {
|
||||
DimensionsRecord retval = new DimensionsRecord();
|
||||
|
||||
retval.setFirstCol(( short ) 0);
|
||||
@ -1849,13 +1618,8 @@ public final class Sheet implements Model {
|
||||
* headercolor = 0x40 <P>
|
||||
* pagebreakzoom = 0x0 <P>
|
||||
* normalzoom = 0x0 <p>
|
||||
* @see org.apache.poi.hssf.record.WindowTwoRecord
|
||||
* @see org.apache.poi.hssf.record.Record
|
||||
* @return record containing a WindowTwoRecord
|
||||
*/
|
||||
|
||||
protected WindowTwoRecord createWindowTwo()
|
||||
{
|
||||
private static WindowTwoRecord createWindowTwo() {
|
||||
WindowTwoRecord retval = new WindowTwoRecord();
|
||||
|
||||
retval.setOptions(( short ) 0x6b6);
|
||||
@ -1869,21 +1633,9 @@ public final class Sheet implements Model {
|
||||
|
||||
/**
|
||||
* Creates the Selection record and sets it to nothing selected
|
||||
*
|
||||
* @see org.apache.poi.hssf.record.SelectionRecord
|
||||
* @see org.apache.poi.hssf.record.Record
|
||||
* @return record containing a SelectionRecord
|
||||
*/
|
||||
|
||||
protected Record createSelection()
|
||||
{
|
||||
SelectionRecord retval = new SelectionRecord();
|
||||
|
||||
retval.setPane(( byte ) 0x3);
|
||||
retval.setActiveCellCol(( short ) 0x0);
|
||||
retval.setActiveCellRow(( short ) 0x0);
|
||||
retval.setNumRefs(( short ) 0x0);
|
||||
return retval;
|
||||
private static SelectionRecord createSelection() {
|
||||
return new SelectionRecord(0, 0);
|
||||
}
|
||||
|
||||
public short getTopRow()
|
||||
@ -1904,19 +1656,15 @@ public final class Sheet implements Model {
|
||||
* @param leftCol the left column to show in desktop window pane
|
||||
*/
|
||||
public void setLeftCol(short leftCol){
|
||||
if (windowTwo!=null)
|
||||
{
|
||||
if (windowTwo!=null) {
|
||||
windowTwo.setLeftCol(leftCol);
|
||||
}
|
||||
}
|
||||
|
||||
public short getLeftCol()
|
||||
{
|
||||
public short getLeftCol() {
|
||||
return (windowTwo==null) ? (short) 0 : windowTwo.getLeftCol();
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Returns the active row
|
||||
*
|
||||
@ -1948,18 +1696,14 @@ public final class Sheet implements Model {
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the active column
|
||||
*
|
||||
* @see org.apache.poi.hssf.record.SelectionRecord
|
||||
* @return row the active column index
|
||||
* @return column of the active cell
|
||||
*/
|
||||
public short getActiveCellCol()
|
||||
{
|
||||
if (selection == null)
|
||||
{
|
||||
return (short) 0;
|
||||
public short getActiveCellCol() {
|
||||
if (selection == null) {
|
||||
return 0;
|
||||
}
|
||||
return selection.getActiveCellCol();
|
||||
return (short)selection.getActiveCellCol();
|
||||
}
|
||||
|
||||
/**
|
||||
@ -1977,23 +1721,8 @@ public final class Sheet implements Model {
|
||||
}
|
||||
}
|
||||
|
||||
protected Record createMergedCells()
|
||||
{
|
||||
MergeCellsRecord retval = new MergeCellsRecord();
|
||||
retval.setNumAreas(( short ) 0);
|
||||
return retval;
|
||||
}
|
||||
|
||||
/**
|
||||
* creates the EOF record
|
||||
* @see org.apache.poi.hssf.record.EOFRecord
|
||||
* @see org.apache.poi.hssf.record.Record
|
||||
* @return record containing a EOFRecord
|
||||
*/
|
||||
|
||||
protected Record createEOF()
|
||||
{
|
||||
return new EOFRecord();
|
||||
private static MergeCellsRecord createMergedCells() {
|
||||
return new MergeCellsRecord();
|
||||
}
|
||||
|
||||
/**
|
||||
@ -2383,28 +2112,20 @@ public final class Sheet implements Model {
|
||||
|
||||
/**
|
||||
* creates a Protect record with protect set to false.
|
||||
* @see org.apache.poi.hssf.record.ProtectRecord
|
||||
* @see org.apache.poi.hssf.record.Record
|
||||
* @return a ProtectRecord
|
||||
*/
|
||||
protected Record createProtect()
|
||||
{
|
||||
if (log.check( POILogger.DEBUG ))
|
||||
private static ProtectRecord createProtect() {
|
||||
if (log.check( POILogger.DEBUG )) {
|
||||
log.log(POILogger.DEBUG, "create protect record with protection disabled");
|
||||
}
|
||||
ProtectRecord retval = new ProtectRecord();
|
||||
|
||||
retval.setProtect(false);
|
||||
retval.setProtect(false); // TODO - supply param to constructor
|
||||
return retval;
|
||||
}
|
||||
|
||||
/**
|
||||
* creates an ObjectProtect record with protect set to false.
|
||||
* @see org.apache.poi.hssf.record.ObjectProtectRecord
|
||||
* @see org.apache.poi.hssf.record.Record
|
||||
* @return an ObjectProtectRecord
|
||||
*/
|
||||
protected ObjectProtectRecord createObjectProtect()
|
||||
{
|
||||
private static ObjectProtectRecord createObjectProtect() {
|
||||
if (log.check( POILogger.DEBUG ))
|
||||
log.log(POILogger.DEBUG, "create protect record with protection disabled");
|
||||
ObjectProtectRecord retval = new ObjectProtectRecord();
|
||||
@ -2415,12 +2136,8 @@ public final class Sheet implements Model {
|
||||
|
||||
/**
|
||||
* creates a ScenarioProtect record with protect set to false.
|
||||
* @see org.apache.poi.hssf.record.ScenarioProtectRecord
|
||||
* @see org.apache.poi.hssf.record.Record
|
||||
* @return a ScenarioProtectRecord
|
||||
*/
|
||||
protected ScenarioProtectRecord createScenarioProtect()
|
||||
{
|
||||
private static ScenarioProtectRecord createScenarioProtect() {
|
||||
if (log.check( POILogger.DEBUG ))
|
||||
log.log(POILogger.DEBUG, "create protect record with protection disabled");
|
||||
ScenarioProtectRecord retval = new ScenarioProtectRecord();
|
||||
@ -2435,9 +2152,9 @@ public final class Sheet implements Model {
|
||||
public ProtectRecord getProtect()
|
||||
{
|
||||
if (protect == null) {
|
||||
protect = (ProtectRecord)createProtect();
|
||||
//Insert the newlycreated protect record at the end of the record (just before the EOF)
|
||||
int loc = findFirstRecordLocBySid(EOFRecord.sid);
|
||||
protect = createProtect();
|
||||
// Insert the newly created protect record just before DefaultColWidthRecord
|
||||
int loc = findFirstRecordLocBySid(DefaultColWidthRecord.sid);
|
||||
records.add(loc, protect);
|
||||
}
|
||||
return protect;
|
||||
@ -2459,14 +2176,11 @@ public final class Sheet implements Model {
|
||||
|
||||
/**
|
||||
* creates a Password record with password set to 00.
|
||||
* @see org.apache.poi.hssf.record.PasswordRecord
|
||||
* @see org.apache.poi.hssf.record.Record
|
||||
* @return a PasswordRecord
|
||||
*/
|
||||
protected PasswordRecord createPassword()
|
||||
{
|
||||
if (log.check( POILogger.DEBUG ))
|
||||
private static PasswordRecord createPassword() {
|
||||
if (log.check( POILogger.DEBUG )) {
|
||||
log.log(POILogger.DEBUG, "create password record with 00 password");
|
||||
}
|
||||
PasswordRecord retval = new PasswordRecord();
|
||||
|
||||
retval.setPassword((short)00);
|
||||
@ -2892,4 +2606,10 @@ public final class Sheet implements Model {
|
||||
rows.expandRow( row );
|
||||
}
|
||||
}
|
||||
public DataValidityTable getOrCreateDataValidityTable() {
|
||||
if (_dataValidityTable == null) {
|
||||
_dataValidityTable = DataValidityTable.createForSheet(records);
|
||||
}
|
||||
return _dataValidityTable;
|
||||
}
|
||||
}
|
||||
|
@ -17,35 +17,33 @@
|
||||
|
||||
package org.apache.poi.hssf.record;
|
||||
|
||||
import org.apache.poi.hssf.record.cf.CellRange;
|
||||
import org.apache.poi.hssf.util.Region;
|
||||
import org.apache.poi.hssf.record.cf.CellRangeUtil;
|
||||
import org.apache.poi.ss.util.CellRangeAddress;
|
||||
import org.apache.poi.ss.util.CellRangeAddressList;
|
||||
import org.apache.poi.util.LittleEndian;
|
||||
|
||||
/**
|
||||
* Conditional Formatting Header record (CFHEADER)
|
||||
* Conditional Formatting Header record CFHEADER (0x1B0)
|
||||
*
|
||||
* @author Dmitriy Kumshayev
|
||||
*/
|
||||
public final class CFHeaderRecord extends Record
|
||||
{
|
||||
public final class CFHeaderRecord extends Record {
|
||||
public static final short sid = 0x1B0;
|
||||
|
||||
private static final CellRange[] EMPTY_CELL_RANGE_ARRAY = { };
|
||||
|
||||
private int field_1_numcf;
|
||||
private int field_2_need_recalculation;
|
||||
private CellRange field_3_enclosing_cell_range;
|
||||
private CellRange[] field_4_cell_ranges;
|
||||
private CellRangeAddress field_3_enclosing_cell_range;
|
||||
private CellRangeAddressList field_4_cell_ranges;
|
||||
|
||||
/** Creates new CFHeaderRecord */
|
||||
public CFHeaderRecord()
|
||||
{
|
||||
field_4_cell_ranges = EMPTY_CELL_RANGE_ARRAY;
|
||||
field_4_cell_ranges = new CellRangeAddressList();
|
||||
}
|
||||
public CFHeaderRecord(org.apache.poi.ss.util.Region[] regions)
|
||||
public CFHeaderRecord(CellRangeAddress[] regions)
|
||||
{
|
||||
CellRange[] unmergedRanges = CellRange.convertRegionsToCellRanges(regions);
|
||||
CellRange[] mergeCellRanges = CellRange.mergeCellRanges(unmergedRanges);
|
||||
CellRangeAddress[] unmergedRanges = regions;
|
||||
CellRangeAddress[] mergeCellRanges = CellRangeUtil.mergeCellRanges(unmergedRanges);
|
||||
setCellRanges(mergeCellRanges);
|
||||
}
|
||||
|
||||
@ -58,14 +56,8 @@ public final class CFHeaderRecord extends Record
|
||||
{
|
||||
field_1_numcf = in.readShort();
|
||||
field_2_need_recalculation = in.readShort();
|
||||
field_3_enclosing_cell_range = new CellRange(in.readUShort(), in.readUShort(), in.readUShort(), in.readUShort());
|
||||
int numCellRanges = in.readShort();
|
||||
CellRange[] crs = new CellRange[numCellRanges];
|
||||
for( int i=0; i<numCellRanges; i++)
|
||||
{
|
||||
crs[i] = new CellRange(in.readUShort(),in.readUShort(),in.readUShort(),in.readUShort());
|
||||
}
|
||||
field_4_cell_ranges = crs;
|
||||
field_3_enclosing_cell_range = new org.apache.poi.hssf.util.CellRangeAddress(in);
|
||||
field_4_cell_ranges = new org.apache.poi.hssf.util.CellRangeAddressList(in);
|
||||
}
|
||||
|
||||
public int getNumberOfConditionalFormats()
|
||||
@ -87,14 +79,14 @@ public final class CFHeaderRecord extends Record
|
||||
field_2_need_recalculation=b?1:0;
|
||||
}
|
||||
|
||||
public CellRange getEnclosingCellRange()
|
||||
public CellRangeAddress getEnclosingCellRange()
|
||||
{
|
||||
return field_3_enclosing_cell_range;
|
||||
}
|
||||
|
||||
public void setEnclosingCellRange( CellRange cr)
|
||||
public void setEnclosingCellRange(CellRangeAddress cr)
|
||||
{
|
||||
field_3_enclosing_cell_range = cr.cloneCellRange();
|
||||
field_3_enclosing_cell_range = cr;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -102,24 +94,26 @@ public final class CFHeaderRecord extends Record
|
||||
* modify the enclosing cell range accordingly.
|
||||
* @param List cellRanges - list of CellRange objects
|
||||
*/
|
||||
public void setCellRanges(CellRange[] cellRanges)
|
||||
public void setCellRanges(CellRangeAddress[] cellRanges)
|
||||
{
|
||||
if(cellRanges == null)
|
||||
{
|
||||
throw new IllegalArgumentException("cellRanges must not be null");
|
||||
}
|
||||
field_4_cell_ranges = (CellRange[]) cellRanges.clone();
|
||||
CellRange enclosingRange = null;
|
||||
CellRangeAddressList cral = new CellRangeAddressList();
|
||||
CellRangeAddress enclosingRange = null;
|
||||
for (int i = 0; i < cellRanges.length; i++)
|
||||
{
|
||||
enclosingRange = cellRanges[i].createEnclosingCellRange(enclosingRange);
|
||||
CellRangeAddress cr = cellRanges[i];
|
||||
enclosingRange = CellRangeUtil.createEnclosingCellRange(cr, enclosingRange);
|
||||
cral.addCellRangeAddress(cr);
|
||||
}
|
||||
field_3_enclosing_cell_range = enclosingRange;
|
||||
field_4_cell_ranges = cral;
|
||||
}
|
||||
|
||||
public CellRange[] getCellRanges()
|
||||
{
|
||||
return (CellRange[]) field_4_cell_ranges.clone();
|
||||
public CellRangeAddress[] getCellRanges() {
|
||||
return field_4_cell_ranges.getCellRangeAddresses();
|
||||
}
|
||||
|
||||
public String toString()
|
||||
@ -131,50 +125,39 @@ public final class CFHeaderRecord extends Record
|
||||
buffer.append(" .numCF = ").append(getNumberOfConditionalFormats()).append("\n");
|
||||
buffer.append(" .needRecalc = ").append(getNeedRecalculation()).append("\n");
|
||||
buffer.append(" .enclosingCellRange= ").append(getEnclosingCellRange()).append("\n");
|
||||
if( field_4_cell_ranges.length>0)
|
||||
{
|
||||
buffer.append(" .cfranges=[");
|
||||
for( int i=0; i<field_4_cell_ranges.length; i++)
|
||||
for( int i=0; i<field_4_cell_ranges.countRanges(); i++)
|
||||
{
|
||||
buffer.append(i==0?"":",").append(field_4_cell_ranges[i].toString());
|
||||
buffer.append(i==0?"":",").append(field_4_cell_ranges.getCellRangeAddress(i).toString());
|
||||
}
|
||||
buffer.append("]\n");
|
||||
}
|
||||
buffer.append("[/CFHEADER]\n");
|
||||
return buffer.toString();
|
||||
}
|
||||
|
||||
private int getDataSize() {
|
||||
return 4 // 2 short fields
|
||||
+ CellRangeAddress.ENCODED_SIZE
|
||||
+ field_4_cell_ranges.getSize();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return byte array containing instance data
|
||||
*/
|
||||
public int serialize(int offset, byte[] data) {
|
||||
int dataSize = getDataSize();
|
||||
|
||||
public int serialize(int offset, byte[] data)
|
||||
{
|
||||
int recordsize = getRecordSize();
|
||||
|
||||
LittleEndian.putShort(data, 0 + offset, sid);
|
||||
LittleEndian.putShort(data, 2 + offset, (short) (recordsize-4));
|
||||
LittleEndian.putShort(data, 4 + offset, (short) field_1_numcf);
|
||||
LittleEndian.putShort(data, 6 + offset, (short) field_2_need_recalculation);
|
||||
LittleEndian.putShort(data, 8 + offset, (short) field_3_enclosing_cell_range.getFirstRow());
|
||||
LittleEndian.putShort(data, 10 + offset, (short) field_3_enclosing_cell_range.getLastRow());
|
||||
LittleEndian.putShort(data, 12 + offset, (short) field_3_enclosing_cell_range.getFirstColumn());
|
||||
LittleEndian.putShort(data, 14 + offset, (short) field_3_enclosing_cell_range.getLastColumn());
|
||||
LittleEndian.putShort(data, 16 + offset, (short) field_4_cell_ranges.length);
|
||||
for( int i=0 ; i!=field_4_cell_ranges.length; i++)
|
||||
{
|
||||
CellRange cr = field_4_cell_ranges[i];
|
||||
LittleEndian.putShort(data, 18 + 0 + 8 * i + offset, (short) cr.getFirstRow());
|
||||
LittleEndian.putShort(data, 18 + 2 + 8 * i + offset, (short) cr.getLastRow());
|
||||
LittleEndian.putShort(data, 18 + 4 + 8 * i + offset, (short) cr.getFirstColumn());
|
||||
LittleEndian.putShort(data, 18 + 6 + 8 * i + offset, (short) cr.getLastColumn());
|
||||
}
|
||||
return getRecordSize();
|
||||
LittleEndian.putUShort(data, 0 + offset, sid);
|
||||
LittleEndian.putUShort(data, 2 + offset, dataSize);
|
||||
LittleEndian.putUShort(data, 4 + offset, field_1_numcf);
|
||||
LittleEndian.putUShort(data, 6 + offset, field_2_need_recalculation);
|
||||
field_3_enclosing_cell_range.serialize(8 + offset, data);
|
||||
field_4_cell_ranges.serialize(16 + offset, data);
|
||||
return 4 + dataSize;
|
||||
}
|
||||
|
||||
public int getRecordSize()
|
||||
{
|
||||
return 18+8*field_4_cell_ranges.length;
|
||||
public int getRecordSize() {
|
||||
return 4 + getDataSize();
|
||||
}
|
||||
|
||||
/**
|
||||
@ -204,11 +187,7 @@ public final class CFHeaderRecord extends Record
|
||||
result.field_1_numcf = field_1_numcf;
|
||||
result.field_2_need_recalculation = field_2_need_recalculation;
|
||||
result.field_3_enclosing_cell_range = field_3_enclosing_cell_range;
|
||||
CellRange[] crs = new CellRange[field_4_cell_ranges.length];
|
||||
for (int i = 0; i < crs.length; i++) {
|
||||
crs[i] = field_4_cell_ranges[i].cloneCellRange();
|
||||
}
|
||||
result.field_4_cell_ranges = crs;
|
||||
result.field_4_cell_ranges = field_4_cell_ranges.copy();
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
@ -16,16 +16,14 @@
|
||||
|
||||
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.UnicodeString.UnicodeRecordStats;
|
||||
import org.apache.poi.hssf.record.formula.Ptg;
|
||||
import org.apache.poi.hssf.util.HSSFCellRangeAddress;
|
||||
import org.apache.poi.hssf.usermodel.DVConstraint;
|
||||
import org.apache.poi.hssf.usermodel.HSSFDataValidation;
|
||||
import org.apache.poi.ss.util.CellRangeAddress;
|
||||
import org.apache.poi.ss.util.CellRangeAddressList;
|
||||
import org.apache.poi.util.BitField;
|
||||
import org.apache.poi.util.LittleEndian;
|
||||
import org.apache.poi.util.StringUtil;
|
||||
|
||||
/**
|
||||
* Title: DATAVALIDATION Record (0x01BE)<p/>
|
||||
@ -34,324 +32,169 @@ import org.apache.poi.util.StringUtil;
|
||||
* are stored in a sequential list of DV records. This list is followed by
|
||||
* DVAL record(s)
|
||||
* @author Dragos Buleandra (dragos.buleandra@trade2b.ro)
|
||||
* @version 2.0-pre
|
||||
* @author Josh Micich
|
||||
*/
|
||||
public final class DVRecord extends Record
|
||||
{
|
||||
public final class DVRecord extends Record {
|
||||
public final static short sid = 0x01BE;
|
||||
|
||||
/**
|
||||
* Option flags
|
||||
*/
|
||||
private int field_option_flags;
|
||||
/** the unicode string used for error/prompt title/text when not present */
|
||||
private static final UnicodeString NULL_TEXT_STRING = new UnicodeString("\0");
|
||||
|
||||
/**
|
||||
* Title of the prompt box
|
||||
*/
|
||||
private String field_title_prompt;
|
||||
|
||||
/**
|
||||
* Title of the error box
|
||||
*/
|
||||
private String field_title_error;
|
||||
|
||||
/**
|
||||
* Text of the prompt box
|
||||
*/
|
||||
private String field_text_prompt;
|
||||
|
||||
/**
|
||||
* Text of the error box
|
||||
*/
|
||||
private String field_text_error;
|
||||
|
||||
/**
|
||||
* Size of the formula data for first condition
|
||||
*/
|
||||
private short field_size_first_formula;
|
||||
|
||||
/**
|
||||
* Not used
|
||||
*/
|
||||
private short field_not_used_1 = 0x3FE0;
|
||||
|
||||
/**
|
||||
* Formula data for first condition (RPN token array without size field)
|
||||
*/
|
||||
private Stack field_rpn_token_1 ;
|
||||
|
||||
/**
|
||||
* Size of the formula data for second condition
|
||||
*/
|
||||
private short field_size_sec_formula;
|
||||
|
||||
/**
|
||||
* Not used
|
||||
*/
|
||||
private short field_not_used_2 = 0x0000;
|
||||
|
||||
/**
|
||||
* Formula data for second condition (RPN token array without size field)
|
||||
*/
|
||||
private Stack field_rpn_token_2 ;
|
||||
|
||||
/**
|
||||
* Cell range address list with all affected ranges
|
||||
*/
|
||||
private HSSFCellRangeAddress field_regions;
|
||||
|
||||
public static final Integer STRING_PROMPT_TITLE = new Integer(0);
|
||||
public static final Integer STRING_ERROR_TITLE = new Integer(1);
|
||||
public static final Integer STRING_PROMPT_TEXT = new Integer(2);
|
||||
public static final Integer STRING_ERROR_TEXT = new Integer(3);
|
||||
private Hashtable _hash_strings ;
|
||||
/** Option flags */
|
||||
private int _option_flags;
|
||||
/** Title of the prompt box */
|
||||
private UnicodeString _promptTitle;
|
||||
/** Title of the error box */
|
||||
private UnicodeString _errorTitle;
|
||||
/** Text of the prompt box */
|
||||
private UnicodeString _promptText;
|
||||
/** Text of the error box */
|
||||
private UnicodeString _errorText;
|
||||
/** Not used - Excel seems to always write 0x3FE0 */
|
||||
private short _not_used_1 = 0x3FE0;
|
||||
/** Formula data for first condition (RPN token array without size field) */
|
||||
private Ptg[] _formula1;
|
||||
/** Not used - Excel seems to always write 0x0000 */
|
||||
private short _not_used_2 = 0x0000;
|
||||
/** Formula data for second condition (RPN token array without size field) */
|
||||
private Ptg[] _formula2;
|
||||
/** Cell range address list with all affected ranges */
|
||||
private CellRangeAddressList _regions;
|
||||
|
||||
/**
|
||||
* Option flags field
|
||||
*
|
||||
* @see org.apache.poi.hssf.util.HSSFDataValidation utility class
|
||||
*/
|
||||
private BitField opt_data_type = new BitField(0x0000000F);
|
||||
private BitField opt_error_style = new BitField(0x00000070);
|
||||
private BitField opt_string_list_formula = new BitField(0x00000080);
|
||||
private BitField opt_empty_cell_allowed = new BitField(0x00000100);
|
||||
private BitField opt_surppres_dropdown_arrow = new BitField(0x00000200);
|
||||
private BitField opt_show_prompt_on_cell_selected = new BitField(0x00040000);
|
||||
private BitField opt_show_error_on_invalid_value = new BitField(0x00080000);
|
||||
private BitField opt_condition_operator = new BitField(0x00F00000);
|
||||
|
||||
public DVRecord()
|
||||
{
|
||||
}
|
||||
private static final BitField opt_data_type = new BitField(0x0000000F);
|
||||
private static final BitField opt_error_style = new BitField(0x00000070);
|
||||
private static final BitField opt_string_list_formula = new BitField(0x00000080);
|
||||
private static final BitField opt_empty_cell_allowed = new BitField(0x00000100);
|
||||
private static final BitField opt_suppress_dropdown_arrow = new BitField(0x00000200);
|
||||
private static final BitField opt_show_prompt_on_cell_selected = new BitField(0x00040000);
|
||||
private static final BitField opt_show_error_on_invalid_value = new BitField(0x00080000);
|
||||
private static final BitField opt_condition_operator = new BitField(0x00700000);
|
||||
|
||||
/**
|
||||
* Constructs a DV record and sets its fields appropriately.
|
||||
*
|
||||
* @param in the RecordInputstream to read the record from
|
||||
*/
|
||||
|
||||
public DVRecord(RecordInputStream in)
|
||||
{
|
||||
public DVRecord(RecordInputStream in) {
|
||||
super(in);
|
||||
}
|
||||
|
||||
protected void validateSid(short id)
|
||||
{
|
||||
if (id != sid)
|
||||
{
|
||||
public DVRecord(int validationType, int operator, int errorStyle, boolean emptyCellAllowed,
|
||||
boolean suppressDropDownArrow, boolean isExplicitList,
|
||||
boolean showPromptBox, String promptTitle, String promptText,
|
||||
boolean showErrorBox, String errorTitle, String errorText,
|
||||
Ptg[] formula1, Ptg[] formula2,
|
||||
CellRangeAddressList regions) {
|
||||
|
||||
int flags = 0;
|
||||
flags = opt_data_type.setValue(flags, validationType);
|
||||
flags = opt_condition_operator.setValue(flags, operator);
|
||||
flags = opt_error_style.setValue(flags, errorStyle);
|
||||
flags = opt_empty_cell_allowed.setBoolean(flags, emptyCellAllowed);
|
||||
flags = opt_suppress_dropdown_arrow.setBoolean(flags, suppressDropDownArrow);
|
||||
flags = opt_string_list_formula.setBoolean(flags, isExplicitList);
|
||||
flags = opt_show_prompt_on_cell_selected.setBoolean(flags, showPromptBox);
|
||||
flags = opt_show_error_on_invalid_value.setBoolean(flags, showErrorBox);
|
||||
_option_flags = flags;
|
||||
_promptTitle = resolveTitleText(promptTitle);
|
||||
_promptText = resolveTitleText(promptText);
|
||||
_errorTitle = resolveTitleText(errorTitle);
|
||||
_errorText = resolveTitleText(errorText);
|
||||
_formula1 = formula1;
|
||||
_formula2 = formula2;
|
||||
_regions = regions;
|
||||
}
|
||||
|
||||
protected void validateSid(short id) {
|
||||
if (id != sid) {
|
||||
throw new RecordFormatException("NOT a valid DV RECORD");
|
||||
}
|
||||
}
|
||||
|
||||
protected void fillFields(RecordInputStream in)
|
||||
{
|
||||
field_rpn_token_1 = new Stack();
|
||||
field_rpn_token_2 = new Stack();
|
||||
protected void fillFields(RecordInputStream in) {
|
||||
|
||||
this.field_option_flags = in.readInt();
|
||||
this._hash_strings = new Hashtable(4);
|
||||
_option_flags = in.readInt();
|
||||
|
||||
StringHandler strHandler_prompt_title = new StringHandler( in );
|
||||
this.field_title_prompt = strHandler_prompt_title.getStringData();
|
||||
this._hash_strings.put(DVRecord.STRING_PROMPT_TITLE, strHandler_prompt_title);
|
||||
_promptTitle = readUnicodeString(in);
|
||||
_errorTitle = readUnicodeString(in);
|
||||
_promptText = readUnicodeString(in);
|
||||
_errorText = readUnicodeString(in);
|
||||
|
||||
StringHandler strHandler_error_title = new StringHandler( in );
|
||||
this.field_title_error = strHandler_error_title.getStringData();
|
||||
this._hash_strings.put(DVRecord.STRING_ERROR_TITLE, strHandler_error_title);
|
||||
|
||||
StringHandler strHandler_prompt_text = new StringHandler( in );
|
||||
this.field_text_prompt = strHandler_prompt_text.getStringData();
|
||||
this._hash_strings.put(DVRecord.STRING_PROMPT_TEXT, strHandler_prompt_text);
|
||||
|
||||
StringHandler strHandler_error_text = new StringHandler( in );
|
||||
this.field_text_error = strHandler_error_text.getStringData();
|
||||
this._hash_strings.put(DVRecord.STRING_ERROR_TEXT, strHandler_error_text);
|
||||
|
||||
this.field_size_first_formula = in.readShort();
|
||||
this.field_not_used_1 = in.readShort();
|
||||
int field_size_first_formula = in.readUShort();
|
||||
_not_used_1 = in.readShort();
|
||||
|
||||
//read first formula data condition
|
||||
int token_pos = 0;
|
||||
while (token_pos < this.field_size_first_formula)
|
||||
{
|
||||
Ptg ptg = Ptg.createPtg(in);
|
||||
token_pos += ptg.getSize();
|
||||
field_rpn_token_1.push(ptg);
|
||||
}
|
||||
_formula1 = Ptg.readTokens(field_size_first_formula, in);
|
||||
|
||||
this.field_size_sec_formula = in.readShort();
|
||||
this.field_not_used_2 = in.readShort();
|
||||
int field_size_sec_formula = in.readUShort();
|
||||
_not_used_2 = in.readShort();
|
||||
|
||||
//read sec formula data condition
|
||||
if (false) { // TODO - prior to bug 44710 this 'skip' was being executed. write a junit to confirm this fix
|
||||
try {
|
||||
in.skip(this.field_size_sec_formula);
|
||||
} catch(IOException e) {
|
||||
e.printStackTrace();
|
||||
throw new IllegalStateException(e.getMessage());
|
||||
}
|
||||
}
|
||||
token_pos = 0;
|
||||
while (token_pos < this.field_size_sec_formula)
|
||||
{
|
||||
Ptg ptg = Ptg.createPtg(in);
|
||||
token_pos += ptg.getSize();
|
||||
field_rpn_token_2.push(ptg);
|
||||
}
|
||||
_formula2 = Ptg.readTokens(field_size_sec_formula, in);
|
||||
|
||||
//read cell range address list with all affected ranges
|
||||
this.field_regions = new HSSFCellRangeAddress(in);
|
||||
_regions = new org.apache.poi.hssf.util.CellRangeAddressList(in);
|
||||
}
|
||||
|
||||
|
||||
// --> start option flags
|
||||
/**
|
||||
* set the condition data type
|
||||
* @param type - condition data type
|
||||
* @see org.apache.poi.hssf.util.HSSFDataValidation utility class
|
||||
*/
|
||||
public void setDataType(int type)
|
||||
{
|
||||
this.field_option_flags = this.opt_data_type.setValue(this.field_option_flags, type);
|
||||
}
|
||||
|
||||
/**
|
||||
* get the condition data type
|
||||
* @return the condition data type
|
||||
* @see org.apache.poi.hssf.util.HSSFDataValidation utility class
|
||||
* @see DVConstraint.ValidationType
|
||||
*/
|
||||
public int getDataType()
|
||||
{
|
||||
return this.opt_data_type.getValue(this.field_option_flags);
|
||||
public int getDataType() {
|
||||
return opt_data_type.getValue(_option_flags);
|
||||
}
|
||||
|
||||
/**
|
||||
* set the condition error style
|
||||
* @param type - condition error style
|
||||
* @see org.apache.poi.hssf.util.HSSFDataValidation utility class
|
||||
*/
|
||||
public void setErrorStyle(int style)
|
||||
{
|
||||
this.field_option_flags = this.opt_error_style.setValue(this.field_option_flags, style);
|
||||
}
|
||||
|
||||
/**
|
||||
* get the condition error style
|
||||
* @return the condition error style
|
||||
* @see org.apache.poi.hssf.util.HSSFDataValidation utility class
|
||||
* @see HSSFDataValidation.ErrorStyle
|
||||
*/
|
||||
public int getErrorStyle()
|
||||
{
|
||||
return this.opt_error_style.getValue(this.field_option_flags);
|
||||
public int getErrorStyle() {
|
||||
return opt_error_style.getValue(_option_flags);
|
||||
}
|
||||
|
||||
/**
|
||||
* set if in list validations the string list is explicitly given in the formula
|
||||
* @param type - true if in list validations the string list is explicitly given in the formula; false otherwise
|
||||
* @see org.apache.poi.hssf.util.HSSFDataValidation utility class
|
||||
* @return <code>true</code> if in list validations the string list is explicitly given in the
|
||||
* formula, <code>false</code> otherwise
|
||||
*/
|
||||
public void setListExplicitFormula(boolean explicit)
|
||||
{
|
||||
this.field_option_flags = this.opt_string_list_formula.setBoolean(this.field_option_flags, explicit);
|
||||
public boolean getListExplicitFormula() {
|
||||
return (opt_string_list_formula.isSet(_option_flags));
|
||||
}
|
||||
|
||||
/**
|
||||
* return true if in list validations the string list is explicitly given in the formula, false otherwise
|
||||
* @return true if in list validations the string list is explicitly given in the formula, false otherwise
|
||||
* @see org.apache.poi.hssf.util.HSSFDataValidation utility class
|
||||
* @return <code>true</code> if empty values are allowed in cells, <code>false</code> otherwise
|
||||
*/
|
||||
public boolean getListExplicitFormula()
|
||||
{
|
||||
return (this.opt_string_list_formula.isSet(this.field_option_flags));
|
||||
public boolean getEmptyCellAllowed() {
|
||||
return (opt_empty_cell_allowed.isSet(_option_flags));
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return <code>true</code> if drop down arrow should be suppressed when list validation is
|
||||
* used, <code>false</code> otherwise
|
||||
*/
|
||||
public boolean getSuppressDropdownArrow() {
|
||||
return (opt_suppress_dropdown_arrow.isSet(_option_flags));
|
||||
}
|
||||
|
||||
/**
|
||||
* set if empty values are allowed in cells
|
||||
* @param type - true if empty values are allowed in cells, false otherwise
|
||||
* @see org.apache.poi.hssf.util.HSSFDataValidation utility class
|
||||
* @return <code>true</code> if a prompt window should appear when cell is selected, <code>false</code> otherwise
|
||||
*/
|
||||
public void setEmptyCellAllowed(boolean allowed)
|
||||
{
|
||||
this.field_option_flags = this.opt_empty_cell_allowed.setBoolean(this.field_option_flags, allowed);
|
||||
public boolean getShowPromptOnCellSelected() {
|
||||
return (opt_show_prompt_on_cell_selected.isSet(_option_flags));
|
||||
}
|
||||
|
||||
/**
|
||||
* return true if empty values are allowed in cells, false otherwise
|
||||
* @return if empty values are allowed in cells, false otherwise
|
||||
* @see org.apache.poi.hssf.util.HSSFDataValidation utility class
|
||||
* @return <code>true</code> if an error window should appear when an invalid value is entered
|
||||
* in the cell, <code>false</code> otherwise
|
||||
*/
|
||||
public boolean getEmptyCellAllowed()
|
||||
{
|
||||
return (this.opt_empty_cell_allowed.isSet(this.field_option_flags));
|
||||
}
|
||||
|
||||
/**
|
||||
* set if drop down arrow should be surppressed when list validation is used
|
||||
* @param type - true if drop down arrow should be surppressed when list validation is used, false otherwise
|
||||
* @see org.apache.poi.hssf.util.HSSFDataValidation utility class
|
||||
*/
|
||||
public void setSurppresDropdownArrow(boolean surppress)
|
||||
{
|
||||
this.field_option_flags = this.opt_surppres_dropdown_arrow.setBoolean(this.field_option_flags, surppress);
|
||||
}
|
||||
|
||||
/**
|
||||
* return true if drop down arrow should be surppressed when list validation is used, false otherwise
|
||||
* @return if drop down arrow should be surppressed when list validation is used, false otherwise
|
||||
* @see org.apache.poi.hssf.util.HSSFDataValidation utility class
|
||||
*/
|
||||
public boolean getSurppresDropdownArrow()
|
||||
{
|
||||
return (this.opt_surppres_dropdown_arrow.isSet(this.field_option_flags));
|
||||
}
|
||||
|
||||
/**
|
||||
* set if a prompt window should appear when cell is selected
|
||||
* @param type - true if a prompt window should appear when cell is selected, false otherwise
|
||||
* @see org.apache.poi.hssf.util.HSSFDataValidation utility class
|
||||
*/
|
||||
public void setShowPromptOnCellSelected(boolean show)
|
||||
{
|
||||
this.field_option_flags = this.opt_show_prompt_on_cell_selected.setBoolean(this.field_option_flags, show);
|
||||
}
|
||||
|
||||
/**
|
||||
* return true if a prompt window should appear when cell is selected, false otherwise
|
||||
* @return if a prompt window should appear when cell is selected, false otherwise
|
||||
* @see org.apache.poi.hssf.util.HSSFDataValidation utility class
|
||||
*/
|
||||
public boolean getShowPromptOnCellSelected()
|
||||
{
|
||||
return (this.opt_show_prompt_on_cell_selected.isSet(this.field_option_flags));
|
||||
}
|
||||
|
||||
/**
|
||||
* set if an error window should appear when an invalid value is entered in the cell
|
||||
* @param type - true if an error window should appear when an invalid value is entered in the cell, false otherwise
|
||||
* @see org.apache.poi.hssf.util.HSSFDataValidation utility class
|
||||
*/
|
||||
public void setShowErrorOnInvalidValue(boolean show)
|
||||
{
|
||||
this.field_option_flags = this.opt_show_error_on_invalid_value.setBoolean(this.field_option_flags, show);
|
||||
}
|
||||
|
||||
/**
|
||||
* return true if an error window should appear when an invalid value is entered in the cell, false otherwise
|
||||
* @return if an error window should appear when an invalid value is entered in the cell, false otherwise
|
||||
* @see org.apache.poi.hssf.util.HSSFDataValidation utility class
|
||||
*/
|
||||
public boolean getShowErrorOnInvalidValue()
|
||||
{
|
||||
return (this.opt_show_error_on_invalid_value.isSet(this.field_option_flags));
|
||||
}
|
||||
|
||||
/**
|
||||
* set the condition operator
|
||||
* @param type - condition operator
|
||||
* @see org.apache.poi.hssf.util.HSSFDataValidation utility class
|
||||
*/
|
||||
public void setConditionOperator(int operator)
|
||||
{
|
||||
this.field_option_flags = this.opt_condition_operator.setValue(this.field_option_flags, operator);
|
||||
public boolean getShowErrorOnInvalidValue() {
|
||||
return (opt_show_error_on_invalid_value.isSet(_option_flags));
|
||||
}
|
||||
|
||||
/**
|
||||
@ -359,146 +202,135 @@ public final class DVRecord extends Record
|
||||
* @return the condition operator
|
||||
* @see org.apache.poi.hssf.util.HSSFDataValidation utility class
|
||||
*/
|
||||
public int getConditionOperator()
|
||||
{
|
||||
return this.opt_condition_operator.getValue(this.field_option_flags);
|
||||
public int getConditionOperator() {
|
||||
return opt_condition_operator.getValue(_option_flags);
|
||||
}
|
||||
// <-- end option flags
|
||||
|
||||
public void setFirstFormulaRPN( Stack rpn )
|
||||
{
|
||||
this.field_rpn_token_1 = rpn;
|
||||
|
||||
|
||||
|
||||
public CellRangeAddressList getCellRangeAddress() {
|
||||
return this._regions;
|
||||
}
|
||||
|
||||
public void setFirstFormulaSize( short size )
|
||||
{
|
||||
this.field_size_first_formula = size;
|
||||
|
||||
public String toString() {
|
||||
StringBuffer sb = new StringBuffer();
|
||||
sb.append("[DV]\n");
|
||||
sb.append(" options=").append(Integer.toHexString(_option_flags));
|
||||
sb.append(" title-prompt=").append(formatTextTitle(_promptTitle));
|
||||
sb.append(" title-error=").append(formatTextTitle(_errorTitle));
|
||||
sb.append(" text-prompt=").append(formatTextTitle(_promptText));
|
||||
sb.append(" text-error=").append(formatTextTitle(_errorText));
|
||||
sb.append("\n");
|
||||
appendFormula(sb, "Formula 1:", _formula1);
|
||||
appendFormula(sb, "Formula 2:", _formula2);
|
||||
sb.append("Regions: ");
|
||||
int nRegions = _regions.countRanges();
|
||||
for(int i=0; i<nRegions; i++) {
|
||||
if (i>0) {
|
||||
sb.append(", ");
|
||||
}
|
||||
CellRangeAddress addr = _regions.getCellRangeAddress(i);
|
||||
sb.append('(').append(addr.getFirstRow()).append(',').append(addr.getLastRow());
|
||||
sb.append(',').append(addr.getFirstColumn()).append(',').append(addr.getLastColumn()).append(')');
|
||||
}
|
||||
sb.append("\n");
|
||||
sb.append("[/DV]");
|
||||
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
public void setSecFormulaRPN( Stack rpn )
|
||||
{
|
||||
this.field_rpn_token_2 = rpn;
|
||||
private static String formatTextTitle(UnicodeString us) {
|
||||
String str = us.getString();
|
||||
if (str.length() == 1 && str.charAt(0) == '\0') {
|
||||
return "'\\0'";
|
||||
}
|
||||
return str;
|
||||
}
|
||||
|
||||
public void setSecFormulaSize( short size )
|
||||
{
|
||||
this.field_size_sec_formula = size;
|
||||
private void appendFormula(StringBuffer sb, String label, Ptg[] ptgs) {
|
||||
sb.append(label);
|
||||
if (ptgs.length < 1) {
|
||||
sb.append("<empty>\n");
|
||||
return;
|
||||
}
|
||||
sb.append("\n");
|
||||
for (int i = 0; i < ptgs.length; i++) {
|
||||
sb.append('\t').append(ptgs[i].toString()).append('\n');
|
||||
}
|
||||
}
|
||||
|
||||
public void setStringField( Integer type, String str_data )
|
||||
{
|
||||
if ( this._hash_strings == null )
|
||||
{
|
||||
this._hash_strings = new Hashtable();
|
||||
}
|
||||
StringHandler strHandler = new StringHandler();
|
||||
if ( str_data == null )
|
||||
{
|
||||
str_data = "";
|
||||
}
|
||||
else
|
||||
{
|
||||
strHandler.setStringLength(str_data.length());
|
||||
}
|
||||
strHandler.setStringData(str_data);
|
||||
|
||||
strHandler.setUnicodeFlag((byte)0x00);
|
||||
this._hash_strings.put( type, strHandler);
|
||||
}
|
||||
|
||||
public String getStringField( Integer type )
|
||||
{
|
||||
return ((StringHandler)this._hash_strings.get(type)).getStringData();
|
||||
}
|
||||
|
||||
public void setCellRangeAddress( HSSFCellRangeAddress range )
|
||||
{
|
||||
this.field_regions = range;
|
||||
}
|
||||
|
||||
public HSSFCellRangeAddress getCellRangeAddress( )
|
||||
{
|
||||
return this.field_regions;
|
||||
}
|
||||
|
||||
/**
|
||||
* gets the option flags field.
|
||||
* @return options - the option flags field
|
||||
*/
|
||||
public int getOptionFlags()
|
||||
{
|
||||
return this.field_option_flags;
|
||||
}
|
||||
|
||||
public String toString()
|
||||
{
|
||||
/** @todo DVRecord string representation */
|
||||
StringBuffer buffer = new StringBuffer();
|
||||
|
||||
return buffer.toString();
|
||||
}
|
||||
|
||||
public int serialize(int offset, byte [] data)
|
||||
{
|
||||
public int serialize(int offset, byte [] data) {
|
||||
int size = this.getRecordSize();
|
||||
LittleEndian.putShort(data, 0 + offset, sid);
|
||||
LittleEndian.putShort(data, 2 + offset, ( short ) (size-4));
|
||||
|
||||
int pos = 4;
|
||||
LittleEndian.putInt(data, pos + offset, this.getOptionFlags());
|
||||
LittleEndian.putInt(data, pos + offset, _option_flags);
|
||||
pos += 4;
|
||||
pos += ((StringHandler)this._hash_strings.get( DVRecord.STRING_PROMPT_TITLE )).serialize(pos+offset, data);
|
||||
pos += ((StringHandler)this._hash_strings.get( DVRecord.STRING_ERROR_TITLE )).serialize(pos+offset, data);
|
||||
pos += ((StringHandler)this._hash_strings.get( DVRecord.STRING_PROMPT_TEXT )).serialize(pos+offset, data);
|
||||
pos += ((StringHandler)this._hash_strings.get( DVRecord.STRING_ERROR_TEXT )).serialize(pos+offset, data);
|
||||
LittleEndian.putShort(data, offset+pos, this.field_size_first_formula);
|
||||
|
||||
pos += serializeUnicodeString(_promptTitle, pos+offset, data);
|
||||
pos += serializeUnicodeString(_errorTitle, pos+offset, data);
|
||||
pos += serializeUnicodeString(_promptText, pos+offset, data);
|
||||
pos += serializeUnicodeString(_errorText, pos+offset, data);
|
||||
LittleEndian.putUShort(data, offset+pos, Ptg.getEncodedSize(_formula1));
|
||||
pos += 2;
|
||||
LittleEndian.putShort(data, offset+pos, this.field_not_used_1);
|
||||
LittleEndian.putUShort(data, offset+pos, _not_used_1);
|
||||
pos += 2;
|
||||
|
||||
for (int k = 0; k < this.field_rpn_token_1.size(); k++)
|
||||
{
|
||||
Ptg ptg = ( Ptg ) this.field_rpn_token_1.get(k);
|
||||
ptg.writeBytes(data, pos+offset);
|
||||
pos += ptg.getSize();
|
||||
}
|
||||
pos += Ptg.serializePtgs(_formula1, data, pos+offset);
|
||||
|
||||
LittleEndian.putShort(data, offset+pos, this.field_size_sec_formula);
|
||||
LittleEndian.putUShort(data, offset+pos, Ptg.getEncodedSize(_formula2));
|
||||
pos += 2;
|
||||
LittleEndian.putShort(data, offset+pos, this.field_not_used_2);
|
||||
LittleEndian.putShort(data, offset+pos, _not_used_2);
|
||||
pos += 2;
|
||||
if ( this.field_size_sec_formula > 0 )
|
||||
{
|
||||
for (int k = 0; k < this.field_rpn_token_2.size(); k++)
|
||||
{
|
||||
Ptg ptg = ( Ptg ) this.field_rpn_token_2.get(k);
|
||||
ptg.writeBytes(data, pos+offset);
|
||||
pos += ptg.getSize();
|
||||
}
|
||||
}
|
||||
this.field_regions.serialize(pos+offset, data);
|
||||
pos += Ptg.serializePtgs(_formula2, data, pos+offset);
|
||||
_regions.serialize(pos+offset, data);
|
||||
return size;
|
||||
}
|
||||
|
||||
public int getRecordSize()
|
||||
{
|
||||
/**
|
||||
* When entered via the UI, Excel translates empty string into "\0"
|
||||
* While it is possible to encode the title/text as empty string (Excel doesn't exactly crash),
|
||||
* the resulting tool-tip text / message box looks wrong. It is best to do the same as the
|
||||
* Excel UI and encode 'not present' as "\0".
|
||||
*/
|
||||
private static UnicodeString resolveTitleText(String str) {
|
||||
if (str == null || str.length() < 1) {
|
||||
return NULL_TEXT_STRING;
|
||||
}
|
||||
return new UnicodeString(str);
|
||||
}
|
||||
|
||||
private static UnicodeString readUnicodeString(RecordInputStream in) {
|
||||
return new UnicodeString(in);
|
||||
}
|
||||
|
||||
private static int serializeUnicodeString(UnicodeString us, int offset, byte[] data) {
|
||||
UnicodeRecordStats urs = new UnicodeRecordStats();
|
||||
us.serialize(urs, offset, data);
|
||||
return urs.recordSize;
|
||||
}
|
||||
private static int getUnicodeStringSize(UnicodeString str) {
|
||||
return 3 + str.getString().length();
|
||||
}
|
||||
|
||||
public int getRecordSize() {
|
||||
int size = 4+4+2+2+2+2;//header+options_field+first_formula_size+first_unused+sec_formula_size+sec+unused;
|
||||
if ( this._hash_strings != null )
|
||||
{
|
||||
Enumeration enum_keys = this._hash_strings.keys();
|
||||
while ( enum_keys.hasMoreElements() )
|
||||
{
|
||||
size += ((StringHandler)this._hash_strings.get( (Integer)enum_keys.nextElement() )).getSize();
|
||||
}
|
||||
}
|
||||
size += this.field_size_first_formula+ this.field_size_sec_formula;
|
||||
size += this.field_regions.getSize();
|
||||
size += getUnicodeStringSize(_promptTitle);
|
||||
size += getUnicodeStringSize(_errorTitle);
|
||||
size += getUnicodeStringSize(_promptText);
|
||||
size += getUnicodeStringSize(_errorText);
|
||||
size += Ptg.getEncodedSize(_formula1);
|
||||
size += Ptg.getEncodedSize(_formula2);
|
||||
size += _regions.getSize();
|
||||
return size;
|
||||
}
|
||||
|
||||
public short getSid()
|
||||
{
|
||||
return this.sid;
|
||||
public short getSid() {
|
||||
return sid;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -508,89 +340,4 @@ public final class DVRecord extends Record
|
||||
public Object clone() {
|
||||
return cloneViaReserialise();
|
||||
}
|
||||
|
||||
/**@todo DVRecord = Serializare */
|
||||
|
||||
private static final class StringHandler
|
||||
{
|
||||
private int _string_length = 0x0001;
|
||||
private byte _string_unicode_flag = 0x00;
|
||||
private String _string_data = "0x00";
|
||||
private int _start_offset;
|
||||
private int _end_offset;
|
||||
|
||||
StringHandler()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
StringHandler(RecordInputStream in)
|
||||
{
|
||||
this.fillFields(in);
|
||||
}
|
||||
|
||||
protected void fillFields(RecordInputStream in)
|
||||
{
|
||||
this._string_length = in.readUShort();
|
||||
this._string_unicode_flag = in.readByte();
|
||||
if (this._string_unicode_flag == 1)
|
||||
{
|
||||
this._string_data = in.readUnicodeLEString(this._string_length);
|
||||
}
|
||||
else
|
||||
{
|
||||
this._string_data = in.readCompressedUnicode(this._string_length);
|
||||
}
|
||||
}
|
||||
|
||||
private void setStringData( String string_data )
|
||||
{
|
||||
this._string_data = string_data;
|
||||
}
|
||||
|
||||
private String getStringData()
|
||||
{
|
||||
return this._string_data;
|
||||
}
|
||||
|
||||
private int getEndOffset()
|
||||
{
|
||||
return this._end_offset;
|
||||
}
|
||||
|
||||
public int serialize( int offset, byte[] data )
|
||||
{
|
||||
LittleEndian.putUShort(data, offset, this._string_length );
|
||||
data[2 + offset] = this._string_unicode_flag;
|
||||
if (this._string_unicode_flag == 1)
|
||||
{
|
||||
StringUtil.putUnicodeLE(this._string_data, data, 3 + offset);
|
||||
}
|
||||
else
|
||||
{
|
||||
StringUtil.putCompressedUnicode(this._string_data, data, 3 + offset);
|
||||
}
|
||||
return getSize();
|
||||
}
|
||||
|
||||
private void setUnicodeFlag( byte flag )
|
||||
{
|
||||
this._string_unicode_flag = flag;
|
||||
}
|
||||
|
||||
private void setStringLength( int len )
|
||||
{
|
||||
this._string_length = len;
|
||||
}
|
||||
|
||||
private int getStringByteLength()
|
||||
{
|
||||
return (this._string_unicode_flag == 1) ? this._string_length * 2 : this._string_length;
|
||||
}
|
||||
|
||||
public int getSize()
|
||||
{
|
||||
return 2 + 1 + getStringByteLength();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,4 +1,3 @@
|
||||
|
||||
/* ====================================================================
|
||||
Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
contributor license agreements. See the NOTICE file distributed with
|
||||
@ -16,56 +15,42 @@
|
||||
limitations under the License.
|
||||
==================================================================== */
|
||||
|
||||
|
||||
package org.apache.poi.hssf.record;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Iterator;
|
||||
|
||||
import org.apache.poi.ss.util.CellRangeAddress;
|
||||
import org.apache.poi.ss.util.CellRangeAddressList;
|
||||
import org.apache.poi.util.LittleEndian;
|
||||
|
||||
/**
|
||||
* Title: Merged Cells Record
|
||||
* <br>
|
||||
* Title: Merged Cells Record (0x00E5)
|
||||
* <br/>
|
||||
* Description: Optional record defining a square area of cells to "merged" into
|
||||
* one cell. <br>
|
||||
* REFERENCE: NONE (UNDOCUMENTED PRESENTLY) <br>
|
||||
* @author Andrew C. Oliver (acoliver at apache dot org)
|
||||
* @version 2.0-pre
|
||||
*/
|
||||
public class MergeCellsRecord
|
||||
extends Record
|
||||
{
|
||||
public final static short sid = 0xe5;
|
||||
private ArrayList field_2_regions;
|
||||
public final class MergeCellsRecord extends Record {
|
||||
public final static short sid = 0x00E5;
|
||||
private CellRangeAddressList _regions;
|
||||
|
||||
public MergeCellsRecord()
|
||||
{
|
||||
/**
|
||||
* Creates an empty <tt>MergedCellsRecord</tt>
|
||||
*/
|
||||
public MergeCellsRecord() {
|
||||
_regions = new CellRangeAddressList();
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a MergedCellsRecord and sets its fields appropriately
|
||||
* @param in the RecordInputstream to read the record from
|
||||
*/
|
||||
|
||||
public MergeCellsRecord(RecordInputStream in)
|
||||
{
|
||||
public MergeCellsRecord(RecordInputStream in) {
|
||||
super(in);
|
||||
}
|
||||
|
||||
protected void fillFields(RecordInputStream in)
|
||||
{
|
||||
short numAreas = in.readShort();
|
||||
field_2_regions = new ArrayList(numAreas + 10);
|
||||
|
||||
for (int k = 0; k < numAreas; k++)
|
||||
{
|
||||
MergedRegion region =
|
||||
new MergedRegion(in.readShort(), in.readShort(),
|
||||
in.readShort(), in.readShort());
|
||||
|
||||
field_2_regions.add(region);
|
||||
}
|
||||
protected void fillFields(RecordInputStream in) {
|
||||
_regions = new org.apache.poi.hssf.util.CellRangeAddressList(in);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -73,27 +58,8 @@ public class MergeCellsRecord
|
||||
* ahead and delete the record.
|
||||
* @return number of areas
|
||||
*/
|
||||
|
||||
public short getNumAreas()
|
||||
{
|
||||
//if the array size is larger than a short (65536), the record can't hold that many merges anyway
|
||||
if (field_2_regions == null) return 0;
|
||||
return (short)field_2_regions.size();
|
||||
}
|
||||
|
||||
/**
|
||||
* set the number of merged areas. You do not need to call this if you use addArea,
|
||||
* it will be incremented automatically or decremented when an area is removed. If
|
||||
* you are setting this to 0 then you are a terrible person. Just remove the record.
|
||||
* (just kidding about you being a terrible person..hehe)
|
||||
* @deprecated We now link the size to the actual array of merged regions
|
||||
* @see #getNumAreas()
|
||||
* @param numareas number of areas
|
||||
*/
|
||||
|
||||
public void setNumAreas(short numareas)
|
||||
{
|
||||
|
||||
public short getNumAreas() {
|
||||
return (short)_regions.countRanges();
|
||||
}
|
||||
|
||||
/**
|
||||
@ -101,178 +67,84 @@ public class MergeCellsRecord
|
||||
* be correct provided you do not add ahead of or remove ahead of it (in which case
|
||||
* you should increment or decrement appropriately....in other words its an arrayList)
|
||||
*
|
||||
* @param rowfrom - the upper left hand corner's row
|
||||
* @param colfrom - the upper left hand corner's col
|
||||
* @param rowto - the lower right hand corner's row
|
||||
* @param colto - the lower right hand corner's col
|
||||
* @param firstRow - the upper left hand corner's row
|
||||
* @param firstCol - the upper left hand corner's col
|
||||
* @param lastRow - the lower right hand corner's row
|
||||
* @param lastCol - the lower right hand corner's col
|
||||
* @return new index of said area (don't depend on it if you add/remove)
|
||||
*/
|
||||
|
||||
//public int addArea(short rowfrom, short colfrom, short rowto, short colto)
|
||||
public int addArea(int rowfrom, short colfrom, int rowto, short colto)
|
||||
{
|
||||
if (field_2_regions == null)
|
||||
{
|
||||
field_2_regions = new ArrayList(10);
|
||||
}
|
||||
MergedRegion region = new MergedRegion(rowfrom, rowto, colfrom,
|
||||
colto);
|
||||
|
||||
field_2_regions.add(region);
|
||||
return field_2_regions.size() - 1;
|
||||
public void addArea(int firstRow, int firstCol, int lastRow, int lastCol) {
|
||||
_regions.addCellRangeAddress(firstRow, firstCol, lastRow, lastCol);
|
||||
}
|
||||
|
||||
/**
|
||||
* essentially unmerge the cells in the "area" stored at the passed in index
|
||||
* @param area index
|
||||
* @param areaIndex
|
||||
*/
|
||||
|
||||
public void removeAreaAt(int area)
|
||||
{
|
||||
field_2_regions.remove(area);
|
||||
public void removeAreaAt(int areaIndex) {
|
||||
_regions.remove(areaIndex);
|
||||
}
|
||||
|
||||
/**
|
||||
* return the MergedRegion at the given index.
|
||||
*
|
||||
* @return MergedRegion representing the area that is Merged (r1,c1 - r2,c2)
|
||||
* @return MergedRegion at the given index representing the area that is Merged (r1,c1 - r2,c2)
|
||||
*/
|
||||
|
||||
public MergedRegion getAreaAt(int index)
|
||||
{
|
||||
return ( MergedRegion ) field_2_regions.get(index);
|
||||
public CellRangeAddress getAreaAt(int index) {
|
||||
return _regions.getCellRangeAddress(index);
|
||||
}
|
||||
|
||||
public int getRecordSize()
|
||||
{
|
||||
int retValue;
|
||||
|
||||
retValue = 6 + (8 * field_2_regions.size());
|
||||
return retValue;
|
||||
public int getRecordSize() {
|
||||
return 4 + _regions.getSize();
|
||||
}
|
||||
|
||||
public short getSid()
|
||||
{
|
||||
public short getSid() {
|
||||
return sid;
|
||||
}
|
||||
|
||||
public int serialize(int offset, byte [] data)
|
||||
{
|
||||
int recordsize = getRecordSize();
|
||||
int pos = 6;
|
||||
public int serialize(int offset, byte [] data) {
|
||||
int dataSize = _regions.getSize();
|
||||
|
||||
LittleEndian.putShort(data, offset + 0, sid);
|
||||
LittleEndian.putShort(data, offset + 2, ( short ) (recordsize - 4));
|
||||
LittleEndian.putShort(data, offset + 4, getNumAreas());
|
||||
for (int k = 0; k < getNumAreas(); k++)
|
||||
{
|
||||
MergedRegion region = getAreaAt(k);
|
||||
|
||||
//LittleEndian.putShort(data, offset + pos, region.row_from);
|
||||
LittleEndian.putShort(data, offset + pos, ( short ) region.row_from);
|
||||
pos += 2;
|
||||
//LittleEndian.putShort(data, offset + pos, region.row_to);
|
||||
LittleEndian.putShort(data, offset + pos, ( short ) region.row_to);
|
||||
pos += 2;
|
||||
LittleEndian.putShort(data, offset + pos, region.col_from);
|
||||
pos += 2;
|
||||
LittleEndian.putShort(data, offset + pos, region.col_to);
|
||||
pos += 2;
|
||||
}
|
||||
return recordsize;
|
||||
LittleEndian.putUShort(data, offset + 2, dataSize);
|
||||
_regions.serialize(offset + 4, data);
|
||||
return 4 + dataSize;
|
||||
}
|
||||
|
||||
public String toString()
|
||||
{
|
||||
public String toString() {
|
||||
StringBuffer retval = new StringBuffer();
|
||||
|
||||
retval.append("[MERGEDCELLS]").append("\n");
|
||||
retval.append(" .sid =").append(sid).append("\n");
|
||||
retval.append(" .numregions =").append(getNumAreas())
|
||||
.append("\n");
|
||||
for (int k = 0; k < getNumAreas(); k++)
|
||||
{
|
||||
MergedRegion region = ( MergedRegion ) field_2_regions.get(k);
|
||||
for (int k = 0; k < _regions.countRanges(); k++) {
|
||||
CellRangeAddress region = _regions.getCellRangeAddress(k);
|
||||
|
||||
retval.append(" .rowfrom =").append(region.row_from)
|
||||
retval.append(" .rowfrom =").append(region.getFirstRow())
|
||||
.append("\n");
|
||||
retval.append(" .colfrom =").append(region.col_from)
|
||||
retval.append(" .colfrom =").append(region.getFirstColumn())
|
||||
.append("\n");
|
||||
retval.append(" .rowto =").append(region.row_to)
|
||||
retval.append(" .rowto =").append(region.getLastRow())
|
||||
.append("\n");
|
||||
retval.append(" .colto =").append(region.col_to)
|
||||
retval.append(" .colto =").append(region.getLastColumn())
|
||||
.append("\n");
|
||||
}
|
||||
retval.append("[MERGEDCELLS]").append("\n");
|
||||
return retval.toString();
|
||||
}
|
||||
|
||||
protected void validateSid(short id)
|
||||
{
|
||||
if (id != sid)
|
||||
{
|
||||
protected void validateSid(short id) {
|
||||
if (id != sid) {
|
||||
throw new RecordFormatException("NOT A MERGEDCELLS RECORD!! "
|
||||
+ id);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* this is a low level representation of a MergedRegion of cells. It is an
|
||||
* inner class because we do not want it used without reference to this class.
|
||||
*
|
||||
*/
|
||||
|
||||
public class MergedRegion
|
||||
{
|
||||
|
||||
/**
|
||||
* create a merged region all in one stroke.
|
||||
*/
|
||||
|
||||
//public MergedRegion(short row_from, short row_to, short col_from,
|
||||
public MergedRegion(int row_from, int row_to, short col_from,
|
||||
short col_to)
|
||||
{
|
||||
this.row_from = row_from;
|
||||
this.row_to = row_to;
|
||||
this.col_from = col_from;
|
||||
this.col_to = col_to;
|
||||
}
|
||||
|
||||
/**
|
||||
* upper lefthand corner row
|
||||
*/
|
||||
|
||||
//public short row_from;
|
||||
public int row_from;
|
||||
|
||||
/**
|
||||
* lower right hand corner row
|
||||
*/
|
||||
|
||||
//public short row_to;
|
||||
public int row_to;
|
||||
|
||||
/**
|
||||
* upper right hand corner col
|
||||
*/
|
||||
|
||||
public short col_from;
|
||||
|
||||
/**
|
||||
* lower right hand corner col
|
||||
*/
|
||||
|
||||
public short col_to;
|
||||
}
|
||||
|
||||
public Object clone() {
|
||||
MergeCellsRecord rec = new MergeCellsRecord();
|
||||
rec.field_2_regions = new ArrayList();
|
||||
Iterator iterator = field_2_regions.iterator();
|
||||
while (iterator.hasNext()) {
|
||||
MergedRegion oldRegion = (MergedRegion)iterator.next();
|
||||
rec.addArea(oldRegion.row_from, oldRegion.col_from, oldRegion.row_to, oldRegion.col_to);
|
||||
for (int k = 0; k < _regions.countRanges(); k++) {
|
||||
CellRangeAddress oldRegion = _regions.getCellRangeAddress(k);
|
||||
rec.addArea(oldRegion.getFirstRow(), oldRegion.getFirstColumn(),
|
||||
oldRegion.getLastRow(), oldRegion.getLastColumn());
|
||||
}
|
||||
|
||||
return rec;
|
||||
|
@ -1,4 +1,3 @@
|
||||
|
||||
/* ====================================================================
|
||||
Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
contributor license agreements. See the NOTICE file distributed with
|
||||
@ -16,69 +15,79 @@
|
||||
limitations under the License.
|
||||
==================================================================== */
|
||||
|
||||
|
||||
package org.apache.poi.hssf.record;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
import org.apache.poi.util.LittleEndian;
|
||||
|
||||
/**
|
||||
* Title: Selection Record<P>
|
||||
* Title: Selection Record (0x001D)<P>
|
||||
* Description: shows the user's selection on the sheet
|
||||
* for write set num refs to 0<P>
|
||||
*
|
||||
* TODO : Fully implement reference subrecords.
|
||||
* REFERENCE: PG 291 Microsoft Excel 97 Developer's Kit (ISBN: 1-57231-498-2)<P>
|
||||
* @author Andrew C. Oliver (acoliver at apache dot org)
|
||||
* @author Jason Height (jheight at chariot dot net dot au)
|
||||
* @author Glen Stampoultzis (glens at apache.org)
|
||||
*/
|
||||
|
||||
public class SelectionRecord
|
||||
extends Record
|
||||
{
|
||||
public final static short sid = 0x1d;
|
||||
public final class SelectionRecord extends Record {
|
||||
public final static short sid = 0x001D;
|
||||
private byte field_1_pane;
|
||||
//private short field_2_row_active_cell;
|
||||
private int field_2_row_active_cell;
|
||||
private short field_3_col_active_cell;
|
||||
private short field_4_ref_active_cell;
|
||||
private short field_5_num_refs;
|
||||
private ArrayList field_6_refs; // not used yet
|
||||
private int field_3_col_active_cell;
|
||||
private int field_4_active_cell_ref_index;
|
||||
private Reference[] field_6_refs;
|
||||
|
||||
/**
|
||||
* Note - column values are 8-bit so cannot use <tt>CellRangeAddressList</tt>
|
||||
*/
|
||||
public class Reference {
|
||||
private short field_1_first_row;
|
||||
private short field_2_last_row;
|
||||
private byte field_3_first_column;
|
||||
private byte field_4_last_column;
|
||||
/* package */ static final int ENCODED_SIZE = 6;
|
||||
private int _firstRow;
|
||||
private int _lastRow;
|
||||
private int _firstCol;
|
||||
private int _lastCol;
|
||||
|
||||
Reference(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();
|
||||
/* package */ Reference(int firstRow, int lastRow, int firstColumn, int lastColumn) {
|
||||
_firstRow = firstRow;
|
||||
_lastRow = lastRow;
|
||||
_firstCol = firstColumn;
|
||||
_lastCol = lastColumn;
|
||||
}
|
||||
/* package */ Reference(RecordInputStream in) {
|
||||
this(in.readUShort(), in.readUShort(), in.readUByte(), in.readUByte());
|
||||
}
|
||||
public void serialize(int offset, byte[] data) {
|
||||
LittleEndian.putUShort(data, offset + 0, _firstRow);
|
||||
LittleEndian.putUShort(data, offset + 2, _lastRow);
|
||||
LittleEndian.putByte(data, offset + 4, _firstCol);
|
||||
LittleEndian.putByte(data, offset + 6, _lastCol);
|
||||
}
|
||||
|
||||
public short getFirstRow() {
|
||||
return field_1_first_row;
|
||||
public int getFirstRow() {
|
||||
return _firstRow;
|
||||
}
|
||||
|
||||
public short getLastRow() {
|
||||
return field_2_last_row;
|
||||
public int getLastRow() {
|
||||
return _lastRow;
|
||||
}
|
||||
|
||||
public byte getFirstColumn() {
|
||||
return field_3_first_column;
|
||||
public int getFirstColumn() {
|
||||
return _firstCol;
|
||||
}
|
||||
|
||||
public byte getLastColumn() {
|
||||
return field_4_last_column;
|
||||
public int getLastColumn() {
|
||||
return _lastCol;
|
||||
}
|
||||
}
|
||||
|
||||
public SelectionRecord()
|
||||
{
|
||||
/**
|
||||
* Creates a default selection record (cell A1, in pane ID 3)
|
||||
*/
|
||||
public SelectionRecord(int activeCellRow, int activeCellCol) {
|
||||
field_1_pane = 3; // pane id 3 is always present. see OOO sec 5.75 'PANE'
|
||||
field_2_row_active_cell = activeCellRow;
|
||||
field_3_col_active_cell = activeCellCol;
|
||||
field_4_active_cell_ref_index = 0;
|
||||
field_6_refs = new Reference[] {
|
||||
new Reference(activeCellRow, activeCellRow, activeCellCol, activeCellCol),
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
@ -86,41 +95,33 @@ public class SelectionRecord
|
||||
* @param in the RecordInputstream to read the record from
|
||||
*/
|
||||
|
||||
public SelectionRecord(RecordInputStream in)
|
||||
{
|
||||
public SelectionRecord(RecordInputStream in) {
|
||||
super(in);
|
||||
}
|
||||
|
||||
protected void validateSid(short id)
|
||||
{
|
||||
if (id != sid)
|
||||
{
|
||||
protected void validateSid(short id) {
|
||||
if (id != sid) {
|
||||
throw new RecordFormatException("NOT A valid Selection RECORD");
|
||||
}
|
||||
}
|
||||
|
||||
protected void fillFields(RecordInputStream in)
|
||||
{
|
||||
protected void fillFields(RecordInputStream in) {
|
||||
field_1_pane = in.readByte();
|
||||
//field_2_row_active_cell = LittleEndian.getShort(data, 1 + offset);
|
||||
field_2_row_active_cell = in.readUShort();
|
||||
field_3_col_active_cell = in.readShort();
|
||||
field_4_ref_active_cell = in.readShort();
|
||||
field_5_num_refs = in.readShort();
|
||||
field_4_active_cell_ref_index = in.readShort();
|
||||
int field_5_num_refs = in.readUShort();
|
||||
|
||||
field_6_refs = new ArrayList(field_5_num_refs);
|
||||
for (int i=0; i<field_5_num_refs; i++) {
|
||||
field_6_refs.add(new Reference(in));
|
||||
field_6_refs = new Reference[field_5_num_refs];
|
||||
for (int i = 0; i < field_6_refs.length; i++) {
|
||||
field_6_refs[i] = new Reference(in);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* set which window pane this is for
|
||||
* @param pane
|
||||
*/
|
||||
|
||||
public void setPane(byte pane)
|
||||
{
|
||||
public void setPane(byte pane) {
|
||||
field_1_pane = pane;
|
||||
}
|
||||
|
||||
@ -128,10 +129,7 @@ public class SelectionRecord
|
||||
* set the active cell's row
|
||||
* @param row number of active cell
|
||||
*/
|
||||
|
||||
//public void setActiveCellRow(short row)
|
||||
public void setActiveCellRow(int row)
|
||||
{
|
||||
public void setActiveCellRow(int row) {
|
||||
field_2_row_active_cell = row;
|
||||
}
|
||||
|
||||
@ -139,9 +137,7 @@ public class SelectionRecord
|
||||
* set the active cell's col
|
||||
* @param col number of active cell
|
||||
*/
|
||||
|
||||
public void setActiveCellCol(short col)
|
||||
{
|
||||
public void setActiveCellCol(short col) {
|
||||
field_3_col_active_cell = col;
|
||||
}
|
||||
|
||||
@ -149,29 +145,14 @@ public class SelectionRecord
|
||||
* set the active cell's reference number
|
||||
* @param ref number of active cell
|
||||
*/
|
||||
|
||||
public void setActiveCellRef(short ref)
|
||||
{
|
||||
field_4_ref_active_cell = ref;
|
||||
public void setActiveCellRef(short ref) {
|
||||
field_4_active_cell_ref_index = ref;
|
||||
}
|
||||
|
||||
/**
|
||||
* set the number of cell refs (we don't support selection so set to 0
|
||||
* @param refs - number of references
|
||||
* @return the pane ID which window pane this is for
|
||||
*/
|
||||
|
||||
public void setNumRefs(short refs)
|
||||
{
|
||||
field_5_num_refs = refs;
|
||||
}
|
||||
|
||||
/**
|
||||
* get which window pane this is for
|
||||
* @return pane
|
||||
*/
|
||||
|
||||
public byte getPane()
|
||||
{
|
||||
public byte getPane() {
|
||||
return field_1_pane;
|
||||
}
|
||||
|
||||
@ -179,10 +160,7 @@ public class SelectionRecord
|
||||
* get the active cell's row
|
||||
* @return row number of active cell
|
||||
*/
|
||||
|
||||
//public short getActiveCellRow()
|
||||
public int getActiveCellRow()
|
||||
{
|
||||
public int getActiveCellRow() {
|
||||
return field_2_row_active_cell;
|
||||
}
|
||||
|
||||
@ -190,9 +168,7 @@ public class SelectionRecord
|
||||
* get the active cell's col
|
||||
* @return col number of active cell
|
||||
*/
|
||||
|
||||
public short getActiveCellCol()
|
||||
{
|
||||
public int getActiveCellCol() {
|
||||
return field_3_col_active_cell;
|
||||
}
|
||||
|
||||
@ -200,20 +176,8 @@ public class SelectionRecord
|
||||
* get the active cell's reference number
|
||||
* @return ref number of active cell
|
||||
*/
|
||||
|
||||
public short getActiveCellRef()
|
||||
{
|
||||
return field_4_ref_active_cell;
|
||||
}
|
||||
|
||||
/**
|
||||
* get the number of cell refs (we don't support selection so set to 0
|
||||
* @return refs - number of references
|
||||
*/
|
||||
|
||||
public short getNumRefs()
|
||||
{
|
||||
return field_5_num_refs;
|
||||
public int getActiveCellRef() {
|
||||
return (short)field_4_active_cell_ref_index;
|
||||
}
|
||||
|
||||
public String toString()
|
||||
@ -230,46 +194,43 @@ public class SelectionRecord
|
||||
buffer.append(" .activecellref = ")
|
||||
.append(Integer.toHexString(getActiveCellRef())).append("\n");
|
||||
buffer.append(" .numrefs = ")
|
||||
.append(Integer.toHexString(getNumRefs())).append("\n");
|
||||
.append(Integer.toHexString(field_6_refs.length)).append("\n");
|
||||
buffer.append("[/SELECTION]\n");
|
||||
return buffer.toString();
|
||||
}
|
||||
|
||||
//hacked to provide one cell reference to 0,0 - 0,0
|
||||
public int serialize(int offset, byte [] data)
|
||||
{
|
||||
LittleEndian.putShort(data, 0 + offset, sid);
|
||||
LittleEndian.putShort(data, 2 + offset, ( short ) 15);
|
||||
data[ 4 + offset ] = getPane();
|
||||
//LittleEndian.putShort(data, 5 + offset, getActiveCellRow());
|
||||
LittleEndian.putShort(data, 5 + offset, ( short ) getActiveCellRow());
|
||||
LittleEndian.putShort(data, 7 + offset, getActiveCellCol());
|
||||
LittleEndian.putShort(data, 9 + offset, getActiveCellRef());
|
||||
LittleEndian.putShort(data, 11 + offset, ( short ) 1);
|
||||
LittleEndian.putShort(data, 13 + offset, ( short ) getActiveCellRow());
|
||||
LittleEndian.putShort(data, 15 + offset, ( short ) getActiveCellRow());
|
||||
data[ 17 + offset ] = (byte)getActiveCellCol();
|
||||
data[ 18 + offset ] = (byte)getActiveCellCol();
|
||||
return getRecordSize();
|
||||
private int getDataSize() {
|
||||
return 9 // 1 byte + 4 shorts
|
||||
+ field_6_refs.length * Reference.ENCODED_SIZE;
|
||||
}
|
||||
public int serialize(int offset, byte [] data) {
|
||||
int dataSize = getDataSize();
|
||||
LittleEndian.putUShort(data, 0 + offset, sid);
|
||||
LittleEndian.putUShort(data, 2 + offset, dataSize);
|
||||
LittleEndian.putByte(data, 4 + offset, getPane());
|
||||
LittleEndian.putUShort(data, 5 + offset, getActiveCellRow());
|
||||
LittleEndian.putUShort(data, 7 + offset, getActiveCellCol());
|
||||
LittleEndian.putUShort(data, 9 + offset, getActiveCellRef());
|
||||
int nRefs = field_6_refs.length;
|
||||
LittleEndian.putUShort(data, 11 + offset, nRefs);
|
||||
for (int i = 0; i < field_6_refs.length; i++) {
|
||||
Reference r = field_6_refs[i];
|
||||
r.serialize(offset + 13 + i * Reference.ENCODED_SIZE, data);
|
||||
}
|
||||
return 4 + dataSize;
|
||||
}
|
||||
|
||||
public int getRecordSize()
|
||||
{
|
||||
return 19;
|
||||
public int getRecordSize() {
|
||||
return 4 + getDataSize();
|
||||
}
|
||||
|
||||
public short getSid()
|
||||
{
|
||||
public short getSid() {
|
||||
return sid;
|
||||
}
|
||||
|
||||
public Object clone() {
|
||||
SelectionRecord rec = new SelectionRecord();
|
||||
SelectionRecord rec = new SelectionRecord(field_2_row_active_cell, field_3_col_active_cell);
|
||||
rec.field_1_pane = field_1_pane;
|
||||
rec.field_2_row_active_cell = field_2_row_active_cell;
|
||||
rec.field_3_col_active_cell = field_3_col_active_cell;
|
||||
rec.field_4_ref_active_cell = field_4_ref_active_cell;
|
||||
rec.field_5_num_refs = field_5_num_refs;
|
||||
rec.field_4_active_cell_ref_index = field_4_active_cell_ref_index;
|
||||
rec.field_6_refs = field_6_refs;
|
||||
return rec;
|
||||
}
|
||||
|
@ -25,6 +25,7 @@ import org.apache.poi.hssf.record.CFRuleRecord;
|
||||
import org.apache.poi.hssf.record.Record;
|
||||
import org.apache.poi.hssf.record.RecordInputStream;
|
||||
import org.apache.poi.ss.util.Region;
|
||||
import org.apache.poi.ss.util.CellRangeAddress;
|
||||
import org.apache.poi.util.POILogFactory;
|
||||
import org.apache.poi.util.POILogger;
|
||||
|
||||
@ -68,7 +69,7 @@ public final class CFRecordsAggregate extends Record
|
||||
}
|
||||
}
|
||||
|
||||
public CFRecordsAggregate(Region[] regions, CFRuleRecord[] rules) {
|
||||
public CFRecordsAggregate(CellRangeAddress[] regions, CFRuleRecord[] rules) {
|
||||
this(new CFHeaderRecord(regions), rules);
|
||||
}
|
||||
|
||||
|
@ -0,0 +1,178 @@
|
||||
/* ====================================================================
|
||||
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.aggregates;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import org.apache.poi.hssf.model.RecordStream;
|
||||
import org.apache.poi.hssf.record.CFHeaderRecord;
|
||||
import org.apache.poi.hssf.record.CFRuleRecord;
|
||||
import org.apache.poi.hssf.record.DVALRecord;
|
||||
import org.apache.poi.hssf.record.DVRecord;
|
||||
import org.apache.poi.hssf.record.EOFRecord;
|
||||
import org.apache.poi.hssf.record.HyperlinkRecord;
|
||||
import org.apache.poi.hssf.record.MergeCellsRecord;
|
||||
import org.apache.poi.hssf.record.PaneRecord;
|
||||
import org.apache.poi.hssf.record.Record;
|
||||
import org.apache.poi.hssf.record.SelectionRecord;
|
||||
import org.apache.poi.hssf.record.WindowTwoRecord;
|
||||
|
||||
/**
|
||||
* Manages the DVALRecord and DVRecords for a single sheet<br/>
|
||||
* See OOO excelfileformat.pdf section 4.14
|
||||
* @author Josh Micich
|
||||
*/
|
||||
public final class DataValidityTable extends RecordAggregate {
|
||||
|
||||
private static final short sid = -0x01B2; // not a real record
|
||||
private final DVALRecord _headerRec;
|
||||
/**
|
||||
* The list of data validations for the current sheet.
|
||||
* Note - this may be empty (contrary to OOO documentation)
|
||||
*/
|
||||
private final List _validationList;
|
||||
|
||||
public DataValidityTable(RecordStream rs) {
|
||||
_headerRec = (DVALRecord) rs.getNext();
|
||||
List temp = new ArrayList();
|
||||
while (rs.peekNextClass() == DVRecord.class) {
|
||||
temp.add(rs.getNext());
|
||||
}
|
||||
_validationList = temp;
|
||||
}
|
||||
|
||||
private DataValidityTable() {
|
||||
_headerRec = new DVALRecord();
|
||||
_validationList = new ArrayList();
|
||||
}
|
||||
|
||||
public short getSid() {
|
||||
return sid;
|
||||
}
|
||||
|
||||
public int serialize(int offset, byte[] data) {
|
||||
int result = _headerRec.serialize(offset, data);
|
||||
for (int i = 0; i < _validationList.size(); i++) {
|
||||
result += ((Record) _validationList.get(i)).serialize(offset + result, data);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
public int getRecordSize() {
|
||||
int result = _headerRec.getRecordSize();
|
||||
for (int i = _validationList.size() - 1; i >= 0; i--) {
|
||||
result += ((Record) _validationList.get(i)).getRecordSize();
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new <tt>DataValidityTable</tt> and inserts it in the right
|
||||
* place in the sheetRecords list.
|
||||
*/
|
||||
public static DataValidityTable createForSheet(List sheetRecords) {
|
||||
int index = findDVTableInsertPos(sheetRecords);
|
||||
|
||||
DataValidityTable result = new DataValidityTable();
|
||||
sheetRecords.add(index, result);
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Finds the index where the sheet validations header record should be inserted
|
||||
* @param records the records for this sheet
|
||||
*
|
||||
* + WINDOW2
|
||||
* o SCL
|
||||
* o PANE
|
||||
* oo SELECTION
|
||||
* o STANDARDWIDTH
|
||||
* oo MERGEDCELLS
|
||||
* o LABELRANGES
|
||||
* o PHONETICPR
|
||||
* o Conditional Formatting Table
|
||||
* o Hyperlink Table
|
||||
* o Data Validity Table
|
||||
* o SHEETLAYOUT
|
||||
* o SHEETPROTECTION
|
||||
* o RANGEPROTECTION
|
||||
* + EOF
|
||||
*/
|
||||
private static int findDVTableInsertPos(List records) {
|
||||
int i = records.size() - 1;
|
||||
if (!(records.get(i) instanceof EOFRecord)) {
|
||||
throw new IllegalStateException("Last sheet record should be EOFRecord");
|
||||
}
|
||||
while (i > 0) {
|
||||
i--;
|
||||
Record rec = (Record) records.get(i);
|
||||
if (isPriorRecord(rec.getSid())) {
|
||||
Record nextRec = (Record) records.get(i + 1);
|
||||
if (!isSubsequentRecord(nextRec.getSid())) {
|
||||
throw new IllegalStateException("Unexpected (" + nextRec.getClass().getName()
|
||||
+ ") found after (" + rec.getClass().getName() + ")");
|
||||
}
|
||||
return i;
|
||||
}
|
||||
if (!isSubsequentRecord(rec.getSid())) {
|
||||
throw new IllegalStateException("Unexpected (" + rec.getClass().getName()
|
||||
+ ") while looking for DV Table insert pos");
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
// TODO - add UninterpretedRecord as base class for many of these
|
||||
// unimplemented sids
|
||||
|
||||
private static boolean isPriorRecord(short sid) {
|
||||
switch(sid) {
|
||||
case WindowTwoRecord.sid:
|
||||
case 0x00A0: // SCL
|
||||
case PaneRecord.sid:
|
||||
case SelectionRecord.sid:
|
||||
case 0x0099: // STANDARDWIDTH
|
||||
case MergeCellsRecord.sid:
|
||||
case 0x015F: // LABELRANGES
|
||||
case 0x00EF: // PHONETICPR
|
||||
case CFHeaderRecord.sid:
|
||||
case CFRuleRecord.sid:
|
||||
case HyperlinkRecord.sid:
|
||||
case 0x0800: // QUICKTIP
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private static boolean isSubsequentRecord(short sid) {
|
||||
switch(sid) {
|
||||
case 0x0862: // SHEETLAYOUT
|
||||
case 0x0867: // SHEETPROTECTION
|
||||
case 0x0868: // RANGEPROTECTION
|
||||
case EOFRecord.sid:
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public void addDataValidation(DVRecord dvRecord) {
|
||||
_validationList.add(dvRecord);
|
||||
_headerRec.setDVRecNo(_validationList.size());
|
||||
}
|
||||
}
|
@ -0,0 +1,41 @@
|
||||
/* ====================================================================
|
||||
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.aggregates;
|
||||
|
||||
import org.apache.poi.hssf.record.Record;
|
||||
import org.apache.poi.hssf.record.RecordInputStream;
|
||||
|
||||
/**
|
||||
* <tt>RecordAggregate</tt>s are groups of of BIFF <tt>Record</tt>s that are typically stored
|
||||
* together and/or updated together. Workbook / Sheet records are typically stored in a sequential
|
||||
* list, which does not provide much structure to coordinate updates.
|
||||
*
|
||||
* @author Josh Micich
|
||||
*/
|
||||
public abstract class RecordAggregate extends Record {
|
||||
// TODO - convert existing aggregate classes to proper subclasses of this one
|
||||
protected final void validateSid(short id) {
|
||||
// TODO - break class hierarchy and make separate from Record
|
||||
throw new RuntimeException("Should not be called");
|
||||
}
|
||||
protected final void fillFields(RecordInputStream in) {
|
||||
throw new RuntimeException("Should not be called");
|
||||
}
|
||||
// force subclassses to provide better implementation than default
|
||||
public abstract int getRecordSize();
|
||||
}
|
@ -1,513 +0,0 @@
|
||||
/* ====================================================================
|
||||
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.cf;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
import org.apache.poi.hssf.util.Region;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Dmitriy Kumshayev
|
||||
*/
|
||||
public final class CellRange
|
||||
{
|
||||
/** max 65536 rows in BIFF8 */
|
||||
private static final int LAST_ROW_INDEX = 0x00FFFF;
|
||||
/** max 256 columns in BIFF8 */
|
||||
private static final int LAST_COLUMN_INDEX = 0x00FF;
|
||||
|
||||
private static final Region[] EMPTY_REGION_ARRAY = { };
|
||||
|
||||
private int _firstRow;
|
||||
private int _lastRow;
|
||||
private int _firstColumn;
|
||||
private int _lastColumn;
|
||||
|
||||
/**
|
||||
*
|
||||
* @param firstRow
|
||||
* @param lastRow pass <tt>-1</tt> for full column ranges
|
||||
* @param firstColumn
|
||||
* @param lastColumn pass <tt>-1</tt> for full row ranges
|
||||
*/
|
||||
public CellRange(int firstRow, int lastRow, int firstColumn, int lastColumn)
|
||||
{
|
||||
if(!isValid(firstRow, lastRow, firstColumn, lastColumn)) {
|
||||
throw new IllegalArgumentException("invalid cell range (" + firstRow + ", " + lastRow
|
||||
+ ", " + firstColumn + ", " + lastColumn + ")");
|
||||
}
|
||||
_firstRow = firstRow;
|
||||
_lastRow = convertM1ToMax(lastRow, LAST_ROW_INDEX);
|
||||
_firstColumn = firstColumn;
|
||||
_lastColumn = convertM1ToMax(lastColumn, LAST_COLUMN_INDEX);
|
||||
}
|
||||
|
||||
/**
|
||||
* Range arithmetic is easier when using a large positive number for 'max row or column'
|
||||
* instead of <tt>-1</tt>.
|
||||
*/
|
||||
private static int convertM1ToMax(int lastIx, int maxIndex) {
|
||||
if(lastIx < 0) {
|
||||
return maxIndex;
|
||||
}
|
||||
return lastIx;
|
||||
}
|
||||
|
||||
public boolean isFullColumnRange() {
|
||||
return _firstRow == 0 && _lastRow == LAST_ROW_INDEX;
|
||||
}
|
||||
public boolean isFullRowRange() {
|
||||
return _firstColumn == 0 && _lastColumn == LAST_COLUMN_INDEX;
|
||||
}
|
||||
|
||||
private static CellRange createFromRegion(org.apache.poi.ss.util.Region r) {
|
||||
return new CellRange(r.getRowFrom(), r.getRowTo(), r.getColumnFrom(), r.getColumnTo());
|
||||
}
|
||||
|
||||
private static boolean isValid(int firstRow, int lastRow, int firstColumn, int lastColumn)
|
||||
{
|
||||
if(lastRow < 0 || lastRow > LAST_ROW_INDEX) {
|
||||
return false;
|
||||
}
|
||||
if(firstRow < 0 || firstRow > LAST_ROW_INDEX) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if(lastColumn < 0 || lastColumn > LAST_COLUMN_INDEX) {
|
||||
return false;
|
||||
}
|
||||
if(firstColumn < 0 || firstColumn > LAST_COLUMN_INDEX) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public int getFirstRow()
|
||||
{
|
||||
return _firstRow;
|
||||
}
|
||||
public int getLastRow()
|
||||
{
|
||||
return _lastRow;
|
||||
}
|
||||
public int getFirstColumn()
|
||||
{
|
||||
return _firstColumn;
|
||||
}
|
||||
public int getLastColumn()
|
||||
{
|
||||
return _lastColumn;
|
||||
}
|
||||
|
||||
public static final int NO_INTERSECTION = 1;
|
||||
public static final int OVERLAP = 2;
|
||||
/** first range is within the second range */
|
||||
public static final int INSIDE = 3;
|
||||
/** first range encloses or is equal to the second */
|
||||
public static final int ENCLOSES = 4;
|
||||
|
||||
/**
|
||||
* Intersect this range with the specified range.
|
||||
*
|
||||
* @param another - the specified range
|
||||
* @return code which reflects how the specified range is related to this range.<br/>
|
||||
* Possible return codes are:
|
||||
* NO_INTERSECTION - the specified range is outside of this range;<br/>
|
||||
* OVERLAP - both ranges partially overlap;<br/>
|
||||
* INSIDE - the specified range is inside of this one<br/>
|
||||
* ENCLOSES - the specified range encloses (possibly exactly the same as) this range<br/>
|
||||
*/
|
||||
public int intersect(CellRange another )
|
||||
{
|
||||
|
||||
int firstRow = another.getFirstRow();
|
||||
int lastRow = another.getLastRow();
|
||||
int firstCol = another.getFirstColumn();
|
||||
int lastCol = another.getLastColumn();
|
||||
|
||||
if
|
||||
(
|
||||
gt(getFirstRow(),lastRow) ||
|
||||
lt(getLastRow(),firstRow) ||
|
||||
gt(getFirstColumn(),lastCol) ||
|
||||
lt(getLastColumn(),firstCol)
|
||||
)
|
||||
{
|
||||
return NO_INTERSECTION;
|
||||
}
|
||||
else if( contains(another) )
|
||||
{
|
||||
return INSIDE;
|
||||
}
|
||||
else if( another.contains(this))
|
||||
{
|
||||
return ENCLOSES;
|
||||
}
|
||||
else
|
||||
{
|
||||
return OVERLAP;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Do all possible cell merges between cells of the list so that:<br>
|
||||
* <li>if a cell range is completely inside of another cell range, it gets removed from the list
|
||||
* <li>if two cells have a shared border, merge them into one bigger cell range
|
||||
* @param cellRangeList
|
||||
* @return updated List of cell ranges
|
||||
*/
|
||||
public static CellRange[] mergeCellRanges(CellRange[] cellRanges) {
|
||||
if(cellRanges.length < 1) {
|
||||
return cellRanges;
|
||||
}
|
||||
List temp = mergeCellRanges(Arrays.asList(cellRanges));
|
||||
return toArray(temp);
|
||||
}
|
||||
private static List mergeCellRanges(List cellRangeList)
|
||||
{
|
||||
|
||||
while(cellRangeList.size() > 1)
|
||||
{
|
||||
boolean somethingGotMerged = false;
|
||||
|
||||
for( int i=0; i<cellRangeList.size(); i++)
|
||||
{
|
||||
CellRange range1 = (CellRange)cellRangeList.get(i);
|
||||
for( int j=i+1; j<cellRangeList.size(); j++)
|
||||
{
|
||||
CellRange range2 = (CellRange)cellRangeList.get(j);
|
||||
|
||||
CellRange[] mergeResult = mergeRanges(range1, range2);
|
||||
if(mergeResult == null) {
|
||||
continue;
|
||||
}
|
||||
somethingGotMerged = true;
|
||||
// overwrite range1 with first result
|
||||
cellRangeList.set(i, mergeResult[0]);
|
||||
// remove range2
|
||||
cellRangeList.remove(j--);
|
||||
// add any extra results beyond the first
|
||||
for(int k=1; k<mergeResult.length; k++) {
|
||||
j++;
|
||||
cellRangeList.add(j, mergeResult[k]);
|
||||
}
|
||||
}
|
||||
}
|
||||
if(!somethingGotMerged) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return cellRangeList;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the new range(s) to replace the supplied ones. <code>null</code> if no merge is possible
|
||||
*/
|
||||
private static CellRange[] mergeRanges(CellRange range1, CellRange range2) {
|
||||
|
||||
int x = range1.intersect(range2);
|
||||
switch(x)
|
||||
{
|
||||
case CellRange.NO_INTERSECTION:
|
||||
if( range1.hasExactSharedBorder(range2))
|
||||
{
|
||||
return new CellRange[] { range1.createEnclosingCellRange(range2), };
|
||||
}
|
||||
// else - No intersection and no shared border: do nothing
|
||||
return null;
|
||||
case CellRange.OVERLAP:
|
||||
return resolveRangeOverlap(range1, range2);
|
||||
case CellRange.INSIDE:
|
||||
// Remove range2, since it is completely inside of range1
|
||||
return new CellRange[] { range1, };
|
||||
case CellRange.ENCLOSES:
|
||||
// range2 encloses range1, so replace it with the enclosing one
|
||||
return new CellRange[] { range2, };
|
||||
}
|
||||
throw new RuntimeException("unexpected intersection result (" + x + ")");
|
||||
}
|
||||
|
||||
// TODO - write junit test for this
|
||||
static CellRange[] resolveRangeOverlap(CellRange rangeA, CellRange rangeB) {
|
||||
|
||||
if(rangeA.isFullColumnRange()) {
|
||||
if(rangeB.isFullRowRange()) {
|
||||
// Excel seems to leave these unresolved
|
||||
return null;
|
||||
}
|
||||
return rangeA.sliceUp(rangeB);
|
||||
}
|
||||
if(rangeA.isFullRowRange()) {
|
||||
if(rangeB.isFullColumnRange()) {
|
||||
// Excel seems to leave these unresolved
|
||||
return null;
|
||||
}
|
||||
return rangeA.sliceUp(rangeB);
|
||||
}
|
||||
if(rangeB.isFullColumnRange()) {
|
||||
return rangeB.sliceUp(rangeA);
|
||||
}
|
||||
if(rangeB.isFullRowRange()) {
|
||||
return rangeB.sliceUp(rangeA);
|
||||
}
|
||||
return rangeA.sliceUp(rangeB);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param range never a full row or full column range
|
||||
* @return an array including <b>this</b> <tt>CellRange</tt> and all parts of <tt>range</tt>
|
||||
* outside of this range
|
||||
*/
|
||||
private CellRange[] sliceUp(CellRange range) {
|
||||
|
||||
List temp = new ArrayList();
|
||||
|
||||
// Chop up range horizontally and vertically
|
||||
temp.add(range);
|
||||
if(!isFullColumnRange()) {
|
||||
temp = cutHorizontally(_firstRow, temp);
|
||||
temp = cutHorizontally(_lastRow+1, temp);
|
||||
}
|
||||
if(!isFullRowRange()) {
|
||||
temp = cutVertically(_firstColumn, temp);
|
||||
temp = cutVertically(_lastColumn+1, temp);
|
||||
}
|
||||
CellRange[] crParts = toArray(temp);
|
||||
|
||||
// form result array
|
||||
temp.clear();
|
||||
temp.add(this);
|
||||
|
||||
for (int i = 0; i < crParts.length; i++) {
|
||||
CellRange crPart = crParts[i];
|
||||
// only include parts that are not enclosed by this
|
||||
if(intersect(crPart) != ENCLOSES) {
|
||||
temp.add(crPart);
|
||||
}
|
||||
}
|
||||
return toArray(temp);
|
||||
}
|
||||
|
||||
private static List cutHorizontally(int cutRow, List input) {
|
||||
|
||||
List result = new ArrayList();
|
||||
CellRange[] crs = toArray(input);
|
||||
for (int i = 0; i < crs.length; i++) {
|
||||
CellRange cr = crs[i];
|
||||
if(cr._firstRow < cutRow && cutRow < cr._lastRow) {
|
||||
result.add(new CellRange(cr._firstRow, cutRow, cr._firstColumn, cr._lastColumn));
|
||||
result.add(new CellRange(cutRow+1, cr._lastRow, cr._firstColumn, cr._lastColumn));
|
||||
} else {
|
||||
result.add(cr);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
private static List cutVertically(int cutColumn, List input) {
|
||||
|
||||
List result = new ArrayList();
|
||||
CellRange[] crs = toArray(input);
|
||||
for (int i = 0; i < crs.length; i++) {
|
||||
CellRange cr = crs[i];
|
||||
if(cr._firstColumn < cutColumn && cutColumn < cr._lastColumn) {
|
||||
result.add(new CellRange(cr._firstRow, cr._lastRow, cr._firstColumn, cutColumn));
|
||||
result.add(new CellRange(cr._firstRow, cr._lastRow, cutColumn+1, cr._lastColumn));
|
||||
} else {
|
||||
result.add(cr);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
private static CellRange[] toArray(List temp) {
|
||||
CellRange[] result = new CellRange[temp.size()];
|
||||
temp.toArray(result);
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert array of regions to a List of CellRange objects
|
||||
*
|
||||
* @param regions
|
||||
* @return List of CellRange objects
|
||||
*/
|
||||
public static CellRange[] convertRegionsToCellRanges(org.apache.poi.ss.util.Region[] regions)
|
||||
{
|
||||
CellRange[] result = new CellRange[regions.length];
|
||||
for( int i=0; i<regions.length; i++)
|
||||
{
|
||||
result[i] = createFromRegion(regions[i]);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert a List of CellRange objects to an array of regions
|
||||
*
|
||||
* @param List of CellRange objects
|
||||
* @return regions
|
||||
*/
|
||||
public static Region[] convertCellRangesToRegions(CellRange[] cellRanges)
|
||||
{
|
||||
int size = cellRanges.length;
|
||||
if(size < 1) {
|
||||
return EMPTY_REGION_ARRAY;
|
||||
}
|
||||
|
||||
Region[] result = new Region[size];
|
||||
|
||||
for (int i = 0; i != size; i++)
|
||||
{
|
||||
result[i] = cellRanges[i].convertToRegion();
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
|
||||
private Region convertToRegion() {
|
||||
|
||||
return new Region(_firstRow, (short)_firstColumn, _lastRow, (short)_lastColumn);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Check if the specified range is located inside of this cell range.
|
||||
*
|
||||
* @param range
|
||||
* @return true if this cell range contains the argument range inside if it's area
|
||||
*/
|
||||
public boolean contains(CellRange range)
|
||||
{
|
||||
int firstRow = range.getFirstRow();
|
||||
int lastRow = range.getLastRow();
|
||||
int firstCol = range.getFirstColumn();
|
||||
int lastCol = range.getLastColumn();
|
||||
return le(getFirstRow(), firstRow) && ge(getLastRow(), lastRow)
|
||||
&& le(getFirstColumn(), firstCol) && ge(getLastColumn(), lastCol);
|
||||
}
|
||||
|
||||
public boolean contains(int row, short column)
|
||||
{
|
||||
return le(getFirstRow(), row) && ge(getLastRow(), row)
|
||||
&& le(getFirstColumn(), column) && ge(getLastColumn(), column);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the specified cell range has a shared border with the current range.
|
||||
*
|
||||
* @return <code>true</code> if the ranges have a complete shared border (i.e.
|
||||
* the two ranges together make a simple rectangular region.
|
||||
*/
|
||||
public boolean hasExactSharedBorder(CellRange range)
|
||||
{
|
||||
int oFirstRow = range._firstRow;
|
||||
int oLastRow = range._lastRow;
|
||||
int oFirstCol = range._firstColumn;
|
||||
int oLastCol = range._lastColumn;
|
||||
|
||||
if (_firstRow > 0 && _firstRow-1 == oLastRow ||
|
||||
oFirstRow > 0 && oFirstRow-1 == _lastRow) {
|
||||
// ranges have a horizontal border in common
|
||||
// make sure columns are identical:
|
||||
return _firstColumn == oFirstCol && _lastColumn == oLastCol;
|
||||
}
|
||||
|
||||
if (_firstColumn>0 && _firstColumn - 1 == oLastCol ||
|
||||
oFirstCol>0 && _lastColumn == oFirstCol -1) {
|
||||
// ranges have a vertical border in common
|
||||
// make sure rows are identical:
|
||||
return _firstRow == oFirstRow && _lastRow == oLastRow;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create an enclosing CellRange for the two cell ranges.
|
||||
*
|
||||
* @return enclosing CellRange
|
||||
*/
|
||||
public CellRange createEnclosingCellRange(CellRange range)
|
||||
{
|
||||
if( range == null)
|
||||
{
|
||||
return cloneCellRange();
|
||||
}
|
||||
else
|
||||
{
|
||||
CellRange cellRange =
|
||||
new CellRange(
|
||||
lt(range.getFirstRow(),getFirstRow())?range.getFirstRow():getFirstRow(),
|
||||
gt(range.getLastRow(),getLastRow())?range.getLastRow():getLastRow(),
|
||||
lt(range.getFirstColumn(),getFirstColumn())?range.getFirstColumn():getFirstColumn(),
|
||||
gt(range.getLastColumn(),getLastColumn())?range.getLastColumn():getLastColumn()
|
||||
);
|
||||
return cellRange;
|
||||
}
|
||||
}
|
||||
|
||||
public CellRange cloneCellRange()
|
||||
{
|
||||
return new CellRange(getFirstRow(),getLastRow(),getFirstColumn(),getLastColumn());
|
||||
}
|
||||
|
||||
/**
|
||||
* @return true if a < b
|
||||
*/
|
||||
private static boolean lt(int a, int b)
|
||||
{
|
||||
return a == -1 ? false : (b == -1 ? true : a < b);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return true if a <= b
|
||||
*/
|
||||
private static boolean le(int a, int b)
|
||||
{
|
||||
return a == b || lt(a,b);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return true if a > b
|
||||
*/
|
||||
private static boolean gt(int a, int b)
|
||||
{
|
||||
return lt(b,a);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return true if a >= b
|
||||
*/
|
||||
private static boolean ge(int a, int b)
|
||||
{
|
||||
return !lt(a,b);
|
||||
}
|
||||
|
||||
public String toString()
|
||||
{
|
||||
return "("+getFirstRow()+","+getLastRow()+","+getFirstColumn()+","+getLastColumn()+")";
|
||||
}
|
||||
|
||||
}
|
363
src/java/org/apache/poi/hssf/record/cf/CellRangeUtil.java
Normal file
363
src/java/org/apache/poi/hssf/record/cf/CellRangeUtil.java
Normal file
@ -0,0 +1,363 @@
|
||||
/* ====================================================================
|
||||
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.cf;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
import org.apache.poi.ss.util.CellRangeAddress;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Dmitriy Kumshayev
|
||||
*/
|
||||
public final class CellRangeUtil
|
||||
{
|
||||
|
||||
private CellRangeUtil() {
|
||||
// no instance of this class
|
||||
}
|
||||
|
||||
public static final int NO_INTERSECTION = 1;
|
||||
public static final int OVERLAP = 2;
|
||||
/** first range is within the second range */
|
||||
public static final int INSIDE = 3;
|
||||
/** first range encloses or is equal to the second */
|
||||
public static final int ENCLOSES = 4;
|
||||
|
||||
/**
|
||||
* Intersect this range with the specified range.
|
||||
*
|
||||
* @param crB - the specified range
|
||||
* @return code which reflects how the specified range is related to this range.<br/>
|
||||
* Possible return codes are:
|
||||
* NO_INTERSECTION - the specified range is outside of this range;<br/>
|
||||
* OVERLAP - both ranges partially overlap;<br/>
|
||||
* INSIDE - the specified range is inside of this one<br/>
|
||||
* ENCLOSES - the specified range encloses (possibly exactly the same as) this range<br/>
|
||||
*/
|
||||
public static int intersect(CellRangeAddress crA, CellRangeAddress crB )
|
||||
{
|
||||
|
||||
int firstRow = crB.getFirstRow();
|
||||
int lastRow = crB.getLastRow();
|
||||
int firstCol = crB.getFirstColumn();
|
||||
int lastCol = crB.getLastColumn();
|
||||
|
||||
if
|
||||
(
|
||||
gt(crA.getFirstRow(),lastRow) ||
|
||||
lt(crA.getLastRow(),firstRow) ||
|
||||
gt(crA.getFirstColumn(),lastCol) ||
|
||||
lt(crA.getLastColumn(),firstCol)
|
||||
)
|
||||
{
|
||||
return NO_INTERSECTION;
|
||||
}
|
||||
else if( contains(crA, crB) )
|
||||
{
|
||||
return INSIDE;
|
||||
}
|
||||
else if( contains(crB, crA))
|
||||
{
|
||||
return ENCLOSES;
|
||||
}
|
||||
else
|
||||
{
|
||||
return OVERLAP;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Do all possible cell merges between cells of the list so that:<br>
|
||||
* <li>if a cell range is completely inside of another cell range, it gets removed from the list
|
||||
* <li>if two cells have a shared border, merge them into one bigger cell range
|
||||
* @param cellRangeList
|
||||
* @return updated List of cell ranges
|
||||
*/
|
||||
public static CellRangeAddress[] mergeCellRanges(CellRangeAddress[] cellRanges) {
|
||||
if(cellRanges.length < 1) {
|
||||
return cellRanges;
|
||||
}
|
||||
List temp = mergeCellRanges(Arrays.asList(cellRanges));
|
||||
return toArray(temp);
|
||||
}
|
||||
private static List mergeCellRanges(List cellRangeList)
|
||||
{
|
||||
|
||||
while(cellRangeList.size() > 1)
|
||||
{
|
||||
boolean somethingGotMerged = false;
|
||||
|
||||
for( int i=0; i<cellRangeList.size(); i++)
|
||||
{
|
||||
CellRangeAddress range1 = (CellRangeAddress)cellRangeList.get(i);
|
||||
for( int j=i+1; j<cellRangeList.size(); j++)
|
||||
{
|
||||
CellRangeAddress range2 = (CellRangeAddress)cellRangeList.get(j);
|
||||
|
||||
CellRangeAddress[] mergeResult = mergeRanges(range1, range2);
|
||||
if(mergeResult == null) {
|
||||
continue;
|
||||
}
|
||||
somethingGotMerged = true;
|
||||
// overwrite range1 with first result
|
||||
cellRangeList.set(i, mergeResult[0]);
|
||||
// remove range2
|
||||
cellRangeList.remove(j--);
|
||||
// add any extra results beyond the first
|
||||
for(int k=1; k<mergeResult.length; k++) {
|
||||
j++;
|
||||
cellRangeList.add(j, mergeResult[k]);
|
||||
}
|
||||
}
|
||||
}
|
||||
if(!somethingGotMerged) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return cellRangeList;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the new range(s) to replace the supplied ones. <code>null</code> if no merge is possible
|
||||
*/
|
||||
private static CellRangeAddress[] mergeRanges(CellRangeAddress range1, CellRangeAddress range2) {
|
||||
|
||||
int x = intersect(range1, range2);
|
||||
switch(x)
|
||||
{
|
||||
case CellRangeUtil.NO_INTERSECTION:
|
||||
if(hasExactSharedBorder(range1, range2)) {
|
||||
return new CellRangeAddress[] { createEnclosingCellRange(range1, range2), };
|
||||
}
|
||||
// else - No intersection and no shared border: do nothing
|
||||
return null;
|
||||
case CellRangeUtil.OVERLAP:
|
||||
return resolveRangeOverlap(range1, range2);
|
||||
case CellRangeUtil.INSIDE:
|
||||
// Remove range2, since it is completely inside of range1
|
||||
return new CellRangeAddress[] { range1, };
|
||||
case CellRangeUtil.ENCLOSES:
|
||||
// range2 encloses range1, so replace it with the enclosing one
|
||||
return new CellRangeAddress[] { range2, };
|
||||
}
|
||||
throw new RuntimeException("unexpected intersection result (" + x + ")");
|
||||
}
|
||||
|
||||
// TODO - write junit test for this
|
||||
static CellRangeAddress[] resolveRangeOverlap(CellRangeAddress rangeA, CellRangeAddress rangeB) {
|
||||
|
||||
if(rangeA.isFullColumnRange()) {
|
||||
if(rangeA.isFullRowRange()) {
|
||||
// Excel seems to leave these unresolved
|
||||
return null;
|
||||
}
|
||||
return sliceUp(rangeA, rangeB);
|
||||
}
|
||||
if(rangeA.isFullRowRange()) {
|
||||
if(rangeB.isFullColumnRange()) {
|
||||
// Excel seems to leave these unresolved
|
||||
return null;
|
||||
}
|
||||
return sliceUp(rangeA, rangeB);
|
||||
}
|
||||
if(rangeB.isFullColumnRange()) {
|
||||
return sliceUp(rangeB, rangeA);
|
||||
}
|
||||
if(rangeB.isFullRowRange()) {
|
||||
return sliceUp(rangeB, rangeA);
|
||||
}
|
||||
return sliceUp(rangeA, rangeB);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param crB never a full row or full column range
|
||||
* @return an array including <b>this</b> <tt>CellRange</tt> and all parts of <tt>range</tt>
|
||||
* outside of this range
|
||||
*/
|
||||
private static CellRangeAddress[] sliceUp(CellRangeAddress crA, CellRangeAddress crB) {
|
||||
|
||||
List temp = new ArrayList();
|
||||
|
||||
// Chop up range horizontally and vertically
|
||||
temp.add(crB);
|
||||
if(!crA.isFullColumnRange()) {
|
||||
temp = cutHorizontally(crA.getFirstRow(), temp);
|
||||
temp = cutHorizontally(crA.getLastRow()+1, temp);
|
||||
}
|
||||
if(!crA.isFullRowRange()) {
|
||||
temp = cutVertically(crA.getFirstColumn(), temp);
|
||||
temp = cutVertically(crA.getLastColumn()+1, temp);
|
||||
}
|
||||
CellRangeAddress[] crParts = toArray(temp);
|
||||
|
||||
// form result array
|
||||
temp.clear();
|
||||
temp.add(crA);
|
||||
|
||||
for (int i = 0; i < crParts.length; i++) {
|
||||
CellRangeAddress crPart = crParts[i];
|
||||
// only include parts that are not enclosed by this
|
||||
if(intersect(crA, crPart) != ENCLOSES) {
|
||||
temp.add(crPart);
|
||||
}
|
||||
}
|
||||
return toArray(temp);
|
||||
}
|
||||
|
||||
private static List cutHorizontally(int cutRow, List input) {
|
||||
|
||||
List result = new ArrayList();
|
||||
CellRangeAddress[] crs = toArray(input);
|
||||
for (int i = 0; i < crs.length; i++) {
|
||||
CellRangeAddress cr = crs[i];
|
||||
if(cr.getFirstRow() < cutRow && cutRow < cr.getLastRow()) {
|
||||
result.add(new CellRangeAddress(cr.getFirstRow(), cutRow, cr.getFirstColumn(), cr.getLastColumn()));
|
||||
result.add(new CellRangeAddress(cutRow+1, cr.getLastRow(), cr.getFirstColumn(), cr.getLastColumn()));
|
||||
} else {
|
||||
result.add(cr);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
private static List cutVertically(int cutColumn, List input) {
|
||||
|
||||
List result = new ArrayList();
|
||||
CellRangeAddress[] crs = toArray(input);
|
||||
for (int i = 0; i < crs.length; i++) {
|
||||
CellRangeAddress cr = crs[i];
|
||||
if(cr.getFirstColumn() < cutColumn && cutColumn < cr.getLastColumn()) {
|
||||
result.add(new CellRangeAddress(cr.getFirstRow(), cr.getLastRow(), cr.getFirstColumn(), cutColumn));
|
||||
result.add(new CellRangeAddress(cr.getFirstRow(), cr.getLastRow(), cutColumn+1, cr.getLastColumn()));
|
||||
} else {
|
||||
result.add(cr);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
private static CellRangeAddress[] toArray(List temp) {
|
||||
CellRangeAddress[] result = new CellRangeAddress[temp.size()];
|
||||
temp.toArray(result);
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Check if the specified range is located inside of this cell range.
|
||||
*
|
||||
* @param crB
|
||||
* @return true if this cell range contains the argument range inside if it's area
|
||||
*/
|
||||
public static boolean contains(CellRangeAddress crA, CellRangeAddress crB)
|
||||
{
|
||||
int firstRow = crB.getFirstRow();
|
||||
int lastRow = crB.getLastRow();
|
||||
int firstCol = crB.getFirstColumn();
|
||||
int lastCol = crB.getLastColumn();
|
||||
return le(crA.getFirstRow(), firstRow) && ge(crA.getLastRow(), lastRow)
|
||||
&& le(crA.getFirstColumn(), firstCol) && ge(crA.getLastColumn(), lastCol);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the specified cell range has a shared border with the current range.
|
||||
*
|
||||
* @return <code>true</code> if the ranges have a complete shared border (i.e.
|
||||
* the two ranges together make a simple rectangular region.
|
||||
*/
|
||||
public static boolean hasExactSharedBorder(CellRangeAddress crA, CellRangeAddress crB) {
|
||||
int oFirstRow = crB.getFirstRow();
|
||||
int oLastRow = crB.getLastRow();
|
||||
int oFirstCol = crB.getFirstColumn();
|
||||
int oLastCol = crB.getLastColumn();
|
||||
|
||||
if (crA.getFirstRow() > 0 && crA.getFirstRow()-1 == oLastRow ||
|
||||
oFirstRow > 0 && oFirstRow-1 == crA.getLastRow()) {
|
||||
// ranges have a horizontal border in common
|
||||
// make sure columns are identical:
|
||||
return crA.getFirstColumn() == oFirstCol && crA.getLastColumn() == oLastCol;
|
||||
}
|
||||
|
||||
if (crA.getFirstColumn()>0 && crA.getFirstColumn() - 1 == oLastCol ||
|
||||
oFirstCol>0 && crA.getLastColumn() == oFirstCol -1) {
|
||||
// ranges have a vertical border in common
|
||||
// make sure rows are identical:
|
||||
return crA.getFirstRow() == oFirstRow && crA.getLastRow() == oLastRow;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create an enclosing CellRange for the two cell ranges.
|
||||
*
|
||||
* @return enclosing CellRange
|
||||
*/
|
||||
public static CellRangeAddress createEnclosingCellRange(CellRangeAddress crA, CellRangeAddress crB) {
|
||||
if( crB == null) {
|
||||
return crA.copy();
|
||||
}
|
||||
|
||||
return
|
||||
new CellRangeAddress(
|
||||
lt(crB.getFirstRow(), crA.getFirstRow()) ?crB.getFirstRow() :crA.getFirstRow(),
|
||||
gt(crB.getLastRow(), crA.getLastRow()) ?crB.getLastRow() :crA.getLastRow(),
|
||||
lt(crB.getFirstColumn(),crA.getFirstColumn())?crB.getFirstColumn():crA.getFirstColumn(),
|
||||
gt(crB.getLastColumn(), crA.getLastColumn()) ?crB.getLastColumn() :crA.getLastColumn()
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @return true if a < b
|
||||
*/
|
||||
private static boolean lt(int a, int b)
|
||||
{
|
||||
return a == -1 ? false : (b == -1 ? true : a < b);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return true if a <= b
|
||||
*/
|
||||
private static boolean le(int a, int b)
|
||||
{
|
||||
return a == b || lt(a,b);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return true if a > b
|
||||
*/
|
||||
private static boolean gt(int a, int b)
|
||||
{
|
||||
return lt(b,a);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return true if a >= b
|
||||
*/
|
||||
private static boolean ge(int a, int b)
|
||||
{
|
||||
return !lt(a,b);
|
||||
}
|
||||
}
|
@ -36,7 +36,7 @@ public final class NumberPtg extends ScalarConstantPtg {
|
||||
/** Create a NumberPtg from a byte array read from disk */
|
||||
public NumberPtg(RecordInputStream in)
|
||||
{
|
||||
field_1_value = in.readDouble();
|
||||
this(in.readDouble());
|
||||
}
|
||||
|
||||
/** Create a NumberPtg from a string representation of the number
|
||||
@ -45,9 +45,12 @@ public final class NumberPtg extends ScalarConstantPtg {
|
||||
* @param value : String representation of a floating point number
|
||||
*/
|
||||
public NumberPtg(String value) {
|
||||
field_1_value = Double.parseDouble(value);
|
||||
this(Double.parseDouble(value));
|
||||
}
|
||||
|
||||
public NumberPtg(double value) {
|
||||
field_1_value = value;
|
||||
}
|
||||
|
||||
public double getValue()
|
||||
{
|
||||
@ -67,6 +70,15 @@ public final class NumberPtg extends ScalarConstantPtg {
|
||||
|
||||
public String toFormulaString(Workbook book)
|
||||
{
|
||||
return "" + getValue();
|
||||
// TODO - java's rendering of double values is not quite same as excel's
|
||||
return String.valueOf(field_1_value);
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
StringBuffer sb = new StringBuffer(64);
|
||||
sb.append(getClass().getName()).append(" [");
|
||||
sb.append(field_1_value);
|
||||
sb.append("]");
|
||||
return sb.toString();
|
||||
}
|
||||
}
|
||||
|
@ -41,6 +41,7 @@ import org.apache.poi.ss.usermodel.Workbook;
|
||||
* @author Jason Height (jheight at chariot dot net dot au)
|
||||
*/
|
||||
public abstract class Ptg implements Cloneable {
|
||||
public static final Ptg[] EMPTY_PTG_ARRAY = { };
|
||||
|
||||
/* convert infix order ptg list to rpn order ptg list
|
||||
* @return List ptgs in RPN order
|
||||
@ -250,6 +251,9 @@ public abstract class Ptg implements Cloneable {
|
||||
}
|
||||
}
|
||||
private static Ptg[] toPtgArray(List l) {
|
||||
if (l.isEmpty()) {
|
||||
return EMPTY_PTG_ARRAY;
|
||||
}
|
||||
Ptg[] result = new Ptg[l.size()];
|
||||
l.toArray(result);
|
||||
return result;
|
||||
|
479
src/java/org/apache/poi/hssf/usermodel/DVConstraint.java
Normal file
479
src/java/org/apache/poi/hssf/usermodel/DVConstraint.java
Normal file
@ -0,0 +1,479 @@
|
||||
/* ====================================================================
|
||||
Copyright 2002-2004 Apache Software Foundation
|
||||
|
||||
Licensed 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.text.ParseException;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.Date;
|
||||
|
||||
import org.apache.poi.hssf.model.FormulaParser;
|
||||
import org.apache.poi.hssf.record.formula.NumberPtg;
|
||||
import org.apache.poi.hssf.record.formula.Ptg;
|
||||
import org.apache.poi.hssf.record.formula.StringPtg;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Josh Micich
|
||||
*/
|
||||
public class DVConstraint {
|
||||
/**
|
||||
* ValidationType enum
|
||||
*/
|
||||
public static final class ValidationType {
|
||||
private ValidationType() {
|
||||
// no instances of this class
|
||||
}
|
||||
/** 'Any value' type - value not restricted */
|
||||
public static final int ANY = 0x00;
|
||||
/** Integer ('Whole number') type */
|
||||
public static final int INTEGER = 0x01;
|
||||
/** Decimal type */
|
||||
public static final int DECIMAL = 0x02;
|
||||
/** List type ( combo box type ) */
|
||||
public static final int LIST = 0x03;
|
||||
/** Date type */
|
||||
public static final int DATE = 0x04;
|
||||
/** Time type */
|
||||
public static final int TIME = 0x05;
|
||||
/** String length type */
|
||||
public static final int TEXT_LENGTH = 0x06;
|
||||
/** Formula ( 'Custom' ) type */
|
||||
public static final int FORMULA = 0x07;
|
||||
}
|
||||
/**
|
||||
* Condition operator enum
|
||||
*/
|
||||
public static final class OperatorType {
|
||||
private OperatorType() {
|
||||
// no instances of this class
|
||||
}
|
||||
|
||||
public static final int BETWEEN = 0x00;
|
||||
public static final int NOT_BETWEEN = 0x01;
|
||||
public static final int EQUAL = 0x02;
|
||||
public static final int NOT_EQUAL = 0x03;
|
||||
public static final int GREATER_THAN = 0x04;
|
||||
public static final int LESS_THAN = 0x05;
|
||||
public static final int GREATER_OR_EQUAL = 0x06;
|
||||
public static final int LESS_OR_EQUAL = 0x07;
|
||||
/** default value to supply when the operator type is not used */
|
||||
public static final int IGNORED = BETWEEN;
|
||||
|
||||
/* package */ static void validateSecondArg(int comparisonOperator, String paramValue) {
|
||||
switch (comparisonOperator) {
|
||||
case BETWEEN:
|
||||
case NOT_BETWEEN:
|
||||
if (paramValue == null) {
|
||||
throw new IllegalArgumentException("expr2 must be supplied for 'between' comparisons");
|
||||
}
|
||||
// all other operators don't need second arg
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* package */ static final class FormulaPair {
|
||||
|
||||
private final Ptg[] _formula1;
|
||||
private final Ptg[] _formula2;
|
||||
|
||||
public FormulaPair(Ptg[] formula1, Ptg[] formula2) {
|
||||
_formula1 = formula1;
|
||||
_formula2 = formula2;
|
||||
}
|
||||
public Ptg[] getFormula1() {
|
||||
return _formula1;
|
||||
}
|
||||
public Ptg[] getFormula2() {
|
||||
return _formula2;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// convenient access to ValidationType namespace
|
||||
private static final ValidationType VT = null;
|
||||
|
||||
|
||||
private final int _validationType;
|
||||
private int _operator;
|
||||
private String[] _explicitListValues;
|
||||
|
||||
private String _formula1;
|
||||
private String _formula2;
|
||||
private Double _value1;
|
||||
private Double _value2;
|
||||
|
||||
|
||||
private DVConstraint(int validationType, int comparisonOperator, String formulaA,
|
||||
String formulaB, Double value1, Double value2, String[] excplicitListValues) {
|
||||
_validationType = validationType;
|
||||
_operator = comparisonOperator;
|
||||
_formula1 = formulaA;
|
||||
_formula2 = formulaB;
|
||||
_value1 = value1;
|
||||
_value2 = value2;
|
||||
_explicitListValues = excplicitListValues;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Creates a list constraint
|
||||
*/
|
||||
private DVConstraint(String listFormula, String[] excplicitListValues) {
|
||||
this(ValidationType.LIST, OperatorType.IGNORED,
|
||||
listFormula, null, null, null, excplicitListValues);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a number based data validation constraint. The text values entered for expr1 and expr2
|
||||
* can be either standard Excel formulas or formatted number values. If the expression starts
|
||||
* with '=' it is parsed as a formula, otherwise it is parsed as a formatted number.
|
||||
*
|
||||
* @param validationType one of {@link ValidationType#ANY}, {@link ValidationType#DECIMAL},
|
||||
* {@link ValidationType#INTEGER}, {@link ValidationType#TEXT_LENGTH}
|
||||
* @param comparisonOperator any constant from {@link OperatorType} enum
|
||||
* @param expr1 date formula (when first char is '=') or formatted number value
|
||||
* @param expr2 date formula (when first char is '=') or formatted number value
|
||||
*/
|
||||
public static DVConstraint createNumericConstraint(int validationType, int comparisonOperator,
|
||||
String expr1, String expr2) {
|
||||
switch (validationType) {
|
||||
case ValidationType.ANY:
|
||||
if (expr1 != null || expr2 != null) {
|
||||
throw new IllegalArgumentException("expr1 and expr2 must be null for validation type 'any'");
|
||||
}
|
||||
break;
|
||||
case ValidationType.DECIMAL:
|
||||
case ValidationType.INTEGER:
|
||||
case ValidationType.TEXT_LENGTH:
|
||||
if (expr1 == null) {
|
||||
throw new IllegalArgumentException("expr1 must be supplied");
|
||||
}
|
||||
OperatorType.validateSecondArg(comparisonOperator, expr2);
|
||||
break;
|
||||
default:
|
||||
throw new IllegalArgumentException("Validation Type ("
|
||||
+ validationType + ") not supported with this method");
|
||||
}
|
||||
// formula1 and value1 are mutually exclusive
|
||||
String formula1 = getFormulaFromTextExpression(expr1);
|
||||
Double value1 = formula1 == null ? convertNumber(expr1) : null;
|
||||
// formula2 and value2 are mutually exclusive
|
||||
String formula2 = getFormulaFromTextExpression(expr2);
|
||||
Double value2 = formula2 == null ? convertNumber(expr2) : null;
|
||||
return new DVConstraint(validationType, comparisonOperator, formula1, formula2, value1, value2, null);
|
||||
}
|
||||
|
||||
public static DVConstraint createFormulaListConstraint(String listFormula) {
|
||||
return new DVConstraint(listFormula, null);
|
||||
}
|
||||
public static DVConstraint createExplicitListConstraint(String[] explicitListValues) {
|
||||
return new DVConstraint(null, explicitListValues);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Creates a time based data validation constraint. The text values entered for expr1 and expr2
|
||||
* can be either standard Excel formulas or formatted time values. If the expression starts
|
||||
* with '=' it is parsed as a formula, otherwise it is parsed as a formatted time. To parse
|
||||
* formatted times, two formats are supported: "HH:MM" or "HH:MM:SS". This is contrary to
|
||||
* Excel which uses the default time format from the OS.
|
||||
*
|
||||
* @param comparisonOperator constant from {@link OperatorType} enum
|
||||
* @param expr1 date formula (when first char is '=') or formatted time value
|
||||
* @param expr2 date formula (when first char is '=') or formatted time value
|
||||
*/
|
||||
public static DVConstraint createTimeConstraint(int comparisonOperator, String expr1, String expr2) {
|
||||
if (expr1 == null) {
|
||||
throw new IllegalArgumentException("expr1 must be supplied");
|
||||
}
|
||||
OperatorType.validateSecondArg(comparisonOperator, expr1);
|
||||
|
||||
// formula1 and value1 are mutually exclusive
|
||||
String formula1 = getFormulaFromTextExpression(expr1);
|
||||
Double value1 = formula1 == null ? convertTime(expr1) : null;
|
||||
// formula2 and value2 are mutually exclusive
|
||||
String formula2 = getFormulaFromTextExpression(expr2);
|
||||
Double value2 = formula2 == null ? convertTime(expr2) : null;
|
||||
return new DVConstraint(VT.TIME, comparisonOperator, formula1, formula2, value1, value2, null);
|
||||
|
||||
}
|
||||
/**
|
||||
* Creates a date based data validation constraint. The text values entered for expr1 and expr2
|
||||
* can be either standard Excel formulas or formatted date values. If the expression starts
|
||||
* with '=' it is parsed as a formula, otherwise it is parsed as a formatted date (Excel uses
|
||||
* the same convention). To parse formatted dates, a date format needs to be specified. This
|
||||
* is contrary to Excel which uses the default short date format from the OS.
|
||||
*
|
||||
* @param comparisonOperator constant from {@link OperatorType} enum
|
||||
* @param expr1 date formula (when first char is '=') or formatted date value
|
||||
* @param expr2 date formula (when first char is '=') or formatted date value
|
||||
* @param dateFormat ignored if both expr1 and expr2 are formulas. Default value is "YYYY/MM/DD"
|
||||
* otherwise any other valid argument for <tt>SimpleDateFormat</tt> can be used
|
||||
* @see <a href='http://java.sun.com/j2se/1.5.0/docs/api/java/text/DateFormat.html'>SimpleDateFormat</a>
|
||||
*/
|
||||
public static DVConstraint createDateConstraint(int comparisonOperator, String expr1, String expr2, String dateFormat) {
|
||||
if (expr1 == null) {
|
||||
throw new IllegalArgumentException("expr1 must be supplied");
|
||||
}
|
||||
OperatorType.validateSecondArg(comparisonOperator, expr2);
|
||||
SimpleDateFormat df = dateFormat == null ? null : new SimpleDateFormat(dateFormat);
|
||||
|
||||
// formula1 and value1 are mutually exclusive
|
||||
String formula1 = getFormulaFromTextExpression(expr1);
|
||||
Double value1 = formula1 == null ? convertDate(expr1, df) : null;
|
||||
// formula2 and value2 are mutually exclusive
|
||||
String formula2 = getFormulaFromTextExpression(expr2);
|
||||
Double value2 = formula2 == null ? convertDate(expr2, df) : null;
|
||||
return new DVConstraint(VT.DATE, comparisonOperator, formula1, formula2, value1, value2, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Distinguishes formula expressions from simple value expressions. This logic is only
|
||||
* required by a few factory methods in this class that create data validation constraints
|
||||
* from more or less the same parameters that would have been entered in the Excel UI. The
|
||||
* data validation dialog box uses the convention that formulas begin with '='. Other methods
|
||||
* in this class follow the POI convention (formulas and values are distinct), so the '='
|
||||
* convention is not used there.
|
||||
*
|
||||
* @param textExpr a formula or value expression
|
||||
* @return all text after '=' if textExpr begins with '='. Otherwise <code>null</code> if textExpr does not begin with '='
|
||||
*/
|
||||
private static String getFormulaFromTextExpression(String textExpr) {
|
||||
if (textExpr == null) {
|
||||
return null;
|
||||
}
|
||||
if (textExpr.length() < 1) {
|
||||
throw new IllegalArgumentException("Empty string is not a valid formula/value expression");
|
||||
}
|
||||
if (textExpr.charAt(0) == '=') {
|
||||
return textExpr.substring(1);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return <code>null</code> if numberStr is <code>null</code>
|
||||
*/
|
||||
private static Double convertNumber(String numberStr) {
|
||||
if (numberStr == null) {
|
||||
return null;
|
||||
}
|
||||
try {
|
||||
return new Double(numberStr);
|
||||
} catch (NumberFormatException e) {
|
||||
throw new RuntimeException("The supplied text '" + numberStr
|
||||
+ "' could not be parsed as a number");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return <code>null</code> if timeStr is <code>null</code>
|
||||
*/
|
||||
private static Double convertTime(String timeStr) {
|
||||
if (timeStr == null) {
|
||||
return null;
|
||||
}
|
||||
return new Double(HSSFDateUtil.convertTime(timeStr));
|
||||
}
|
||||
/**
|
||||
* @param dateFormat pass <code>null</code> for default YYYYMMDD
|
||||
* @return <code>null</code> if timeStr is <code>null</code>
|
||||
*/
|
||||
private static Double convertDate(String dateStr, SimpleDateFormat dateFormat) {
|
||||
if (dateStr == null) {
|
||||
return null;
|
||||
}
|
||||
Date dateVal;
|
||||
if (dateFormat == null) {
|
||||
dateVal = HSSFDateUtil.parseYYYYMMDDDate(dateStr);
|
||||
} else {
|
||||
try {
|
||||
dateVal = dateFormat.parse(dateStr);
|
||||
} catch (ParseException e) {
|
||||
throw new RuntimeException("Failed to parse date '" + dateStr
|
||||
+ "' using specified format '" + dateFormat + "'", e);
|
||||
}
|
||||
}
|
||||
return new Double(HSSFDateUtil.getExcelDate(dateVal));
|
||||
}
|
||||
|
||||
public static DVConstraint createCustomFormulaConstraint(String formula) {
|
||||
if (formula == null) {
|
||||
throw new IllegalArgumentException("formula must be supplied");
|
||||
}
|
||||
return new DVConstraint(VT.FORMULA, OperatorType.IGNORED, formula, null, null, null, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return both parsed formulas (for expression 1 and 2).
|
||||
*/
|
||||
/* package */ FormulaPair createFormulas(HSSFWorkbook workbook) {
|
||||
Ptg[] formula1;
|
||||
Ptg[] formula2;
|
||||
if (isListValidationType()) {
|
||||
formula1 = createListFormula(workbook);
|
||||
formula2 = Ptg.EMPTY_PTG_ARRAY;
|
||||
} else {
|
||||
formula1 = convertDoubleFormula(_formula1, _value1, workbook);
|
||||
formula2 = convertDoubleFormula(_formula2, _value2, workbook);
|
||||
}
|
||||
return new FormulaPair(formula1, formula2);
|
||||
}
|
||||
|
||||
private Ptg[] createListFormula(HSSFWorkbook workbook) {
|
||||
|
||||
if (_explicitListValues == null) {
|
||||
// formula is parsed with slightly different RVA rules: (root node type must be 'reference')
|
||||
return FormulaParser.parse(_formula1, workbook, FormulaParser.FORMULA_TYPE_DATAVALIDATION_LIST);
|
||||
// To do: Excel places restrictions on the available operations within a list formula.
|
||||
// Some things like union and intersection are not allowed.
|
||||
}
|
||||
// explicit list was provided
|
||||
StringBuffer sb = new StringBuffer(_explicitListValues.length * 16);
|
||||
for (int i = 0; i < _explicitListValues.length; i++) {
|
||||
if (i > 0) {
|
||||
sb.append('\0'); // list delimiter is the nul char
|
||||
}
|
||||
sb.append(_explicitListValues[i]);
|
||||
|
||||
}
|
||||
return new Ptg[] { new StringPtg(sb.toString()), };
|
||||
}
|
||||
|
||||
/**
|
||||
* @return The parsed token array representing the formula or value specified.
|
||||
* Empty array if both formula and value are <code>null</code>
|
||||
*/
|
||||
private static Ptg[] convertDoubleFormula(String formula, Double value, HSSFWorkbook workbook) {
|
||||
if (formula == null) {
|
||||
if (value == null) {
|
||||
return Ptg.EMPTY_PTG_ARRAY;
|
||||
}
|
||||
return new Ptg[] { new NumberPtg(value.doubleValue()), };
|
||||
}
|
||||
if (value != null) {
|
||||
throw new IllegalStateException("Both formula and value cannot be present");
|
||||
}
|
||||
return FormulaParser.parse(formula, workbook);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return data validation type of this constraint
|
||||
* @see ValidationType
|
||||
*/
|
||||
public int getValidationType() {
|
||||
return _validationType;
|
||||
}
|
||||
/**
|
||||
* Convenience method
|
||||
* @return <code>true</code> if this constraint is a 'list' validation
|
||||
*/
|
||||
public boolean isListValidationType() {
|
||||
return _validationType == VT.LIST;
|
||||
}
|
||||
/**
|
||||
* Convenience method
|
||||
* @return <code>true</code> if this constraint is a 'list' validation with explicit values
|
||||
*/
|
||||
public boolean isExplicitList() {
|
||||
return _validationType == VT.LIST && _explicitListValues != null;
|
||||
}
|
||||
/**
|
||||
* @return the operator used for this constraint
|
||||
* @see OperatorType
|
||||
*/
|
||||
public int getOperator() {
|
||||
return _operator;
|
||||
}
|
||||
/**
|
||||
* Sets the comparison operator for this constraint
|
||||
* @see OperatorType
|
||||
*/
|
||||
public void setOperator(int operator) {
|
||||
_operator = operator;
|
||||
}
|
||||
|
||||
public String[] getExplicitListValues() {
|
||||
return _explicitListValues;
|
||||
}
|
||||
public void setExplicitListValues(String[] explicitListValues) {
|
||||
if (_validationType != VT.LIST) {
|
||||
throw new RuntimeException("Cannot setExplicitListValues on non-list constraint");
|
||||
}
|
||||
_formula1 = null;
|
||||
_explicitListValues = explicitListValues;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the formula for expression 1. May be <code>null</code>
|
||||
*/
|
||||
public String getFormula1() {
|
||||
return _formula1;
|
||||
}
|
||||
/**
|
||||
* Sets a formula for expression 1.
|
||||
*/
|
||||
public void setFormula1(String formula1) {
|
||||
_value1 = null;
|
||||
_explicitListValues = null;
|
||||
_formula1 = formula1;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the formula for expression 2. May be <code>null</code>
|
||||
*/
|
||||
public String getFormula2() {
|
||||
return _formula2;
|
||||
}
|
||||
/**
|
||||
* Sets a formula for expression 2.
|
||||
*/
|
||||
public void setFormula2(String formula2) {
|
||||
_value2 = null;
|
||||
_formula2 = formula2;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the numeric value for expression 1. May be <code>null</code>
|
||||
*/
|
||||
public Double getValue1() {
|
||||
return _value1;
|
||||
}
|
||||
/**
|
||||
* Sets a numeric value for expression 1.
|
||||
*/
|
||||
public void setValue1(double value1) {
|
||||
_formula1 = null;
|
||||
_value1 = new Double(value1);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the numeric value for expression 2. May be <code>null</code>
|
||||
*/
|
||||
public Double getValue2() {
|
||||
return _value2;
|
||||
}
|
||||
/**
|
||||
* Sets a numeric value for expression 2.
|
||||
*/
|
||||
public void setValue2(double value2) {
|
||||
_formula2 = null;
|
||||
_value2 = new Double(value2);
|
||||
}
|
||||
}
|
@ -34,7 +34,24 @@ 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.DrawingRecord;
|
||||
import org.apache.poi.hssf.record.EOFRecord;
|
||||
import org.apache.poi.hssf.record.ExtendedFormatRecord;
|
||||
import org.apache.poi.hssf.record.FormulaRecord;
|
||||
import org.apache.poi.hssf.record.HyperlinkRecord;
|
||||
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.StringRecord;
|
||||
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 org.apache.poi.ss.usermodel.Cell;
|
||||
@ -1055,11 +1072,18 @@ public class HSSFCell implements Cell
|
||||
}
|
||||
|
||||
/**
|
||||
* Assign a comment to this cell
|
||||
* Assign a comment to this cell. If the supplied
|
||||
* comment is null, the comment for this cell
|
||||
* will be removed.
|
||||
*
|
||||
* @param comment comment associated with this cell
|
||||
*/
|
||||
public void setCellComment(Comment comment){
|
||||
if(comment == null) {
|
||||
removeCellComment();
|
||||
return;
|
||||
}
|
||||
|
||||
this.comment = (HSSFComment) comment;
|
||||
this.comment.setRow((short)record.getRow());
|
||||
this.comment.setColumn(record.getColumn());
|
||||
@ -1077,6 +1101,49 @@ public class HSSFCell implements Cell
|
||||
return comment;
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes the comment for this cell, if
|
||||
* there is one.
|
||||
* WARNING - some versions of excel will loose
|
||||
* all comments after performing this action!
|
||||
*/
|
||||
public void removeCellComment() {
|
||||
HSSFComment comment = findCellComment(sheet, record.getRow(), record.getColumn());
|
||||
this.comment = null;
|
||||
|
||||
if(comment == null) {
|
||||
// Nothing to do
|
||||
return;
|
||||
}
|
||||
|
||||
// Zap the underlying NoteRecord
|
||||
sheet.getRecords().remove(comment.getNoteRecord());
|
||||
|
||||
// If we have a TextObjectRecord, is should
|
||||
// be proceeed by:
|
||||
// MSODRAWING with container
|
||||
// OBJ
|
||||
// MSODRAWING with EscherTextboxRecord
|
||||
if(comment.getTextObjectRecord() != null) {
|
||||
TextObjectRecord txo = comment.getTextObjectRecord();
|
||||
int txoAt = sheet.getRecords().indexOf(txo);
|
||||
|
||||
if(sheet.getRecords().get(txoAt-3) instanceof DrawingRecord &&
|
||||
sheet.getRecords().get(txoAt-2) instanceof ObjRecord &&
|
||||
sheet.getRecords().get(txoAt-1) instanceof DrawingRecord) {
|
||||
// Zap these, in reverse order
|
||||
sheet.getRecords().remove(txoAt-1);
|
||||
sheet.getRecords().remove(txoAt-2);
|
||||
sheet.getRecords().remove(txoAt-3);
|
||||
} else {
|
||||
throw new IllegalStateException("Found the wrong records before the TextObjectRecord, can't remove comment");
|
||||
}
|
||||
|
||||
// Now remove the text record
|
||||
sheet.getRecords().remove(txo);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Cell comment finder.
|
||||
* Returns cell comment for the specified sheet, row and column.
|
||||
|
@ -156,4 +156,13 @@ public class HSSFComment extends HSSFTextbox implements Comment {
|
||||
}
|
||||
super.setString(string);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the underlying Note record
|
||||
*/
|
||||
protected NoteRecord getNoteRecord() { return note; }
|
||||
/**
|
||||
* Returns the underlying Text record
|
||||
*/
|
||||
protected TextObjectRecord getTextObjectRecord() { return txo; }
|
||||
}
|
||||
|
@ -16,11 +16,10 @@
|
||||
==================================================================== */
|
||||
package org.apache.poi.hssf.usermodel;
|
||||
|
||||
import org.apache.poi.hssf.record.CFHeaderRecord;
|
||||
import org.apache.poi.hssf.record.CFRuleRecord;
|
||||
import org.apache.poi.hssf.record.aggregates.CFRecordsAggregate;
|
||||
import org.apache.poi.hssf.record.cf.CellRange;
|
||||
import org.apache.poi.hssf.util.Region;
|
||||
import org.apache.poi.ss.util.CellRangeAddress;
|
||||
import org.apache.poi.ss.util.Region;
|
||||
|
||||
/**
|
||||
* HSSFConditionalFormatting class encapsulates all settings of Conditional Formatting.
|
||||
@ -96,13 +95,18 @@ public final class HSSFConditionalFormatting
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array of <tt>Region</tt>s. never <code>null</code>
|
||||
* @deprecated (Aug-2008) use {@link HSSFConditionalFormatting#getFormattingRanges()}
|
||||
*/
|
||||
public Region[] getFormattingRegions()
|
||||
{
|
||||
CFHeaderRecord cfh = cfAggregate.getHeader();
|
||||
CellRange[] cellRanges = cfh.getCellRanges();
|
||||
return CellRange.convertCellRangesToRegions(cellRanges);
|
||||
CellRangeAddress[] cellRanges = getFormattingRanges();
|
||||
return Region.convertCellRangesToRegions(cellRanges);
|
||||
}
|
||||
/**
|
||||
* @return array of <tt>CellRangeAddress</tt>s. never <code>null</code>
|
||||
*/
|
||||
public CellRangeAddress[] getFormattingRanges() {
|
||||
return cfAggregate.getHeader().getCellRanges();
|
||||
}
|
||||
|
||||
/**
|
||||
|
235
src/java/org/apache/poi/hssf/usermodel/HSSFDataValidation.java
Normal file
235
src/java/org/apache/poi/hssf/usermodel/HSSFDataValidation.java
Normal file
@ -0,0 +1,235 @@
|
||||
/* ====================================================================
|
||||
Copyright 2002-2004 Apache Software Foundation
|
||||
|
||||
Licensed 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 org.apache.poi.hssf.record.DVRecord;
|
||||
import org.apache.poi.hssf.usermodel.DVConstraint.FormulaPair;
|
||||
import org.apache.poi.ss.util.CellRangeAddressList;
|
||||
|
||||
/**
|
||||
*Utility class for creating data validation cells
|
||||
*
|
||||
* @author Dragos Buleandra (dragos.buleandra@trade2b.ro)
|
||||
*/
|
||||
public final class HSSFDataValidation {
|
||||
/**
|
||||
* Error style constants for error box
|
||||
*/
|
||||
public static final class ErrorStyle {
|
||||
/** STOP style */
|
||||
public static final int STOP = 0x00;
|
||||
/** WARNING style */
|
||||
public static final int WARNING = 0x01;
|
||||
/** INFO style */
|
||||
public static final int INFO = 0x02;
|
||||
}
|
||||
|
||||
private String _prompt_title;
|
||||
private String _prompt_text;
|
||||
private String _error_title;
|
||||
private String _error_text;
|
||||
|
||||
private int _errorStyle = ErrorStyle.STOP;
|
||||
private boolean _emptyCellAllowed = true;
|
||||
private boolean _suppress_dropdown_arrow = false;
|
||||
private boolean _showPromptBox = true;
|
||||
private boolean _showErrorBox = true;
|
||||
private final CellRangeAddressList _regions;
|
||||
private DVConstraint _constraint;
|
||||
|
||||
/**
|
||||
* Constructor which initializes the cell range on which this object will be
|
||||
* applied
|
||||
* @param constraint
|
||||
*/
|
||||
public HSSFDataValidation(CellRangeAddressList regions, DVConstraint constraint) {
|
||||
_regions = regions;
|
||||
_constraint = constraint;
|
||||
}
|
||||
|
||||
|
||||
public DVConstraint getConstraint() {
|
||||
return _constraint;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the error style for error box
|
||||
* @see ErrorStyle
|
||||
*/
|
||||
public void setErrorStyle(int error_style) {
|
||||
_errorStyle = error_style;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the error style of error box
|
||||
* @see ErrorStyle
|
||||
*/
|
||||
public int getErrorStyle() {
|
||||
return _errorStyle;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets if this object allows empty as a valid value
|
||||
*
|
||||
* @param allowed <code>true</code> if this object should treats empty as valid value , <code>false</code>
|
||||
* otherwise
|
||||
*/
|
||||
public void setEmptyCellAllowed(boolean allowed) {
|
||||
_emptyCellAllowed = allowed;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve the settings for empty cells allowed
|
||||
*
|
||||
* @return True if this object should treats empty as valid value , false
|
||||
* otherwise
|
||||
*/
|
||||
public boolean getEmptyCellAllowed() {
|
||||
return _emptyCellAllowed;
|
||||
}
|
||||
|
||||
/**
|
||||
* Useful for list validation objects .
|
||||
*
|
||||
* @param suppress
|
||||
* True if a list should display the values into a drop down list ,
|
||||
* false otherwise . In other words , if a list should display
|
||||
* the arrow sign on its right side
|
||||
*/
|
||||
public void setSuppressDropDownArrow(boolean suppress) {
|
||||
_suppress_dropdown_arrow = suppress;
|
||||
}
|
||||
|
||||
/**
|
||||
* Useful only list validation objects . This method always returns false if
|
||||
* the object isn't a list validation object
|
||||
*
|
||||
* @return <code>true</code> if a list should display the values into a drop down list ,
|
||||
* <code>false</code> otherwise .
|
||||
*/
|
||||
public boolean getSuppressDropDownArrow() {
|
||||
if (_constraint.isListValidationType()) {
|
||||
return _suppress_dropdown_arrow;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the behaviour when a cell which belongs to this object is selected
|
||||
*
|
||||
* @param show <code>true</code> if an prompt box should be displayed , <code>false</code> otherwise
|
||||
*/
|
||||
public void setShowPromptBox(boolean show) {
|
||||
_showPromptBox = show;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param show <code>true</code> if an prompt box should be displayed , <code>false</code> otherwise
|
||||
*/
|
||||
public boolean getShowPromptBox() {
|
||||
return _showPromptBox;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the behaviour when an invalid value is entered
|
||||
*
|
||||
* @param show <code>true</code> if an error box should be displayed , <code>false</code> otherwise
|
||||
*/
|
||||
public void setShowErrorBox(boolean show) {
|
||||
_showErrorBox = show;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return <code>true</code> if an error box should be displayed , <code>false</code> otherwise
|
||||
*/
|
||||
public boolean getShowErrorBox() {
|
||||
return _showErrorBox;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Sets the title and text for the prompt box . Prompt box is displayed when
|
||||
* the user selects a cell which belongs to this validation object . In
|
||||
* order for a prompt box to be displayed you should also use method
|
||||
* setShowPromptBox( boolean show )
|
||||
*
|
||||
* @param title The prompt box's title
|
||||
* @param text The prompt box's text
|
||||
*/
|
||||
public void createPromptBox(String title, String text) {
|
||||
_prompt_title = title;
|
||||
_prompt_text = text;
|
||||
this.setShowPromptBox(true);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Prompt box's title or <code>null</code>
|
||||
*/
|
||||
public String getPromptBoxTitle() {
|
||||
return _prompt_title;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Prompt box's text or <code>null</code>
|
||||
*/
|
||||
public String getPromptBoxText() {
|
||||
return _prompt_text;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the title and text for the error box . Error box is displayed when
|
||||
* the user enters an invalid value int o a cell which belongs to this
|
||||
* validation object . In order for an error box to be displayed you should
|
||||
* also use method setShowErrorBox( boolean show )
|
||||
*
|
||||
* @param title The error box's title
|
||||
* @param text The error box's text
|
||||
*/
|
||||
public void createErrorBox(String title, String text) {
|
||||
_error_title = title;
|
||||
_error_text = text;
|
||||
this.setShowErrorBox(true);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Error box's title or <code>null</code>
|
||||
*/
|
||||
public String getErrorBoxTitle() {
|
||||
return _error_title;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Error box's text or <code>null</code>
|
||||
*/
|
||||
public String getErrorBoxText() {
|
||||
return _error_text;
|
||||
}
|
||||
|
||||
public DVRecord createDVRecord(HSSFWorkbook workbook) {
|
||||
|
||||
FormulaPair fp = _constraint.createFormulas(workbook);
|
||||
|
||||
return new DVRecord(_constraint.getValidationType(),
|
||||
_constraint.getOperator(),
|
||||
_errorStyle, _emptyCellAllowed, getSuppressDropDownArrow(),
|
||||
_constraint.isExplicitList(),
|
||||
_showPromptBox, _prompt_title, _prompt_text,
|
||||
_showErrorBox, _error_title, _error_text,
|
||||
fp.getFormula1(), fp.getFormula2(),
|
||||
_regions);
|
||||
}
|
||||
}
|
@ -28,7 +28,6 @@ import java.text.NumberFormat;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Stack;
|
||||
import java.util.TreeMap;
|
||||
|
||||
import org.apache.poi.ddf.EscherRecord;
|
||||
@ -49,13 +48,13 @@ import org.apache.poi.hssf.record.SCLRecord;
|
||||
import org.apache.poi.hssf.record.VCenterRecord;
|
||||
import org.apache.poi.hssf.record.WSBoolRecord;
|
||||
import org.apache.poi.hssf.record.WindowTwoRecord;
|
||||
import org.apache.poi.hssf.record.aggregates.DataValidityTable;
|
||||
import org.apache.poi.hssf.record.formula.Ptg;
|
||||
import org.apache.poi.hssf.record.formula.RefPtg;
|
||||
import org.apache.poi.hssf.util.HSSFCellRangeAddress;
|
||||
import org.apache.poi.hssf.util.HSSFDataValidation;
|
||||
import org.apache.poi.hssf.util.PaneInformation;
|
||||
import org.apache.poi.ss.usermodel.CellStyle;
|
||||
import org.apache.poi.ss.usermodel.Row;
|
||||
import org.apache.poi.ss.util.CellRangeAddress;
|
||||
import org.apache.poi.hssf.util.Region;
|
||||
import org.apache.poi.util.POILogFactory;
|
||||
import org.apache.poi.util.POILogger;
|
||||
@ -393,91 +392,18 @@ public class HSSFSheet implements org.apache.poi.ss.usermodel.Sheet
|
||||
|
||||
/**
|
||||
* Creates a data validation object
|
||||
* @param obj_validation The Data validation object settings
|
||||
* @param dataValidation The Data validation object settings
|
||||
*/
|
||||
public void addValidationData(HSSFDataValidation obj_validation)
|
||||
{
|
||||
if ( obj_validation == null )
|
||||
{
|
||||
return;
|
||||
public void addValidationData(HSSFDataValidation dataValidation) {
|
||||
if (dataValidation == null) {
|
||||
throw new IllegalArgumentException("objValidation must not be null");
|
||||
}
|
||||
DVALRecord dvalRec = (DVALRecord)sheet.findFirstRecordBySid( DVALRecord.sid );
|
||||
int eofLoc = sheet.findFirstRecordLocBySid( EOFRecord.sid );
|
||||
if ( dvalRec == null )
|
||||
{
|
||||
dvalRec = new DVALRecord();
|
||||
sheet.getRecords().add( eofLoc, dvalRec );
|
||||
}
|
||||
int curr_dvRecNo = dvalRec.getDVRecNo();
|
||||
dvalRec.setDVRecNo(curr_dvRecNo+1);
|
||||
DataValidityTable dvt = sheet.getOrCreateDataValidityTable();
|
||||
|
||||
//create dv record
|
||||
DVRecord dvRecord = new DVRecord();
|
||||
|
||||
//dv record's option flags
|
||||
dvRecord.setDataType( obj_validation.getDataValidationType() );
|
||||
dvRecord.setErrorStyle(obj_validation.getErrorStyle());
|
||||
dvRecord.setEmptyCellAllowed(obj_validation.getEmptyCellAllowed());
|
||||
dvRecord.setSurppresDropdownArrow(obj_validation.getSurppressDropDownArrow());
|
||||
dvRecord.setShowPromptOnCellSelected(obj_validation.getShowPromptBox());
|
||||
dvRecord.setShowErrorOnInvalidValue(obj_validation.getShowErrorBox());
|
||||
dvRecord.setConditionOperator(obj_validation.getOperator());
|
||||
|
||||
//string fields
|
||||
dvRecord.setStringField( DVRecord.STRING_PROMPT_TITLE,obj_validation.getPromptBoxTitle());
|
||||
dvRecord.setStringField( DVRecord.STRING_PROMPT_TEXT, obj_validation.getPromptBoxText());
|
||||
dvRecord.setStringField( DVRecord.STRING_ERROR_TITLE, obj_validation.getErrorBoxTitle());
|
||||
dvRecord.setStringField( DVRecord.STRING_ERROR_TEXT, obj_validation.getErrorBoxText());
|
||||
|
||||
//formula fields ( size and data )
|
||||
String str_formula = obj_validation.getFirstFormula();
|
||||
FormulaParser fp = new FormulaParser(str_formula, workbook);
|
||||
fp.parse();
|
||||
Stack ptg_arr = new Stack();
|
||||
Ptg[] ptg = fp.getRPNPtg();
|
||||
int size = 0;
|
||||
for (int k = 0; k < ptg.length; k++)
|
||||
{
|
||||
if ( ptg[k] instanceof org.apache.poi.hssf.record.formula.AreaPtg )
|
||||
{
|
||||
//we should set ptgClass to Ptg.CLASS_REF and explicit formula string to false
|
||||
ptg[k].setClass(Ptg.CLASS_REF);
|
||||
obj_validation.setExplicitListFormula(false);
|
||||
}
|
||||
size += ptg[k].getSize();
|
||||
ptg_arr.push(ptg[k]);
|
||||
}
|
||||
dvRecord.setFirstFormulaRPN(ptg_arr);
|
||||
dvRecord.setFirstFormulaSize((short)size);
|
||||
|
||||
dvRecord.setListExplicitFormula(obj_validation.getExplicitListFormula());
|
||||
|
||||
if ( obj_validation.getSecondFormula() != null )
|
||||
{
|
||||
str_formula = obj_validation.getSecondFormula();
|
||||
fp = new FormulaParser(str_formula, workbook);
|
||||
fp.parse();
|
||||
ptg_arr = new Stack();
|
||||
ptg = fp.getRPNPtg();
|
||||
size = 0;
|
||||
for (int k = 0; k < ptg.length; k++)
|
||||
{
|
||||
size += ptg[k].getSize();
|
||||
ptg_arr.push(ptg[k]);
|
||||
}
|
||||
dvRecord.setSecFormulaRPN(ptg_arr);
|
||||
dvRecord.setSecFormulaSize((short)size);
|
||||
DVRecord dvRecord = dataValidation.createDVRecord(workbook);
|
||||
dvt.addDataValidation(dvRecord);
|
||||
}
|
||||
|
||||
//dv records cell range field
|
||||
HSSFCellRangeAddress cell_range = new HSSFCellRangeAddress();
|
||||
cell_range.addADDRStructure(obj_validation.getFirstRow(), obj_validation.getFirstColumn(), obj_validation.getLastRow(), obj_validation.getLastColumn());
|
||||
dvRecord.setCellRangeAddress(cell_range);
|
||||
|
||||
//add dv record
|
||||
eofLoc = sheet.findFirstRecordLocBySid( EOFRecord.sid );
|
||||
sheet.getRecords().add( eofLoc, dvRecord );
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the visibility state for a given column.
|
||||
@ -610,19 +536,28 @@ public class HSSFSheet implements org.apache.poi.ss.usermodel.Sheet
|
||||
}
|
||||
|
||||
/**
|
||||
* adds a merged region of cells (hence those cells form one)
|
||||
* @param region (rowfrom/colfrom-rowto/colto) to merge
|
||||
* @return index of this region
|
||||
* @deprecated (Aug-2008) use <tt>CellRangeAddress</tt> instead of <tt>Region</tt>
|
||||
*/
|
||||
public int addMergedRegion(org.apache.poi.ss.util.Region region)
|
||||
{
|
||||
//return sheet.addMergedRegion((short) region.getRowFrom(),
|
||||
return sheet.addMergedRegion( region.getRowFrom(),
|
||||
region.getColumnFrom(),
|
||||
//(short) region.getRowTo(),
|
||||
region.getRowTo(),
|
||||
region.getColumnTo());
|
||||
}
|
||||
/**
|
||||
* adds a merged region of cells (hence those cells form one)
|
||||
* @param region (rowfrom/colfrom-rowto/colto) to merge
|
||||
* @return index of this region
|
||||
*/
|
||||
public int addMergedRegion(CellRangeAddress region)
|
||||
{
|
||||
return sheet.addMergedRegion( region.getFirstRow(),
|
||||
region.getFirstColumn(),
|
||||
region.getLastRow(),
|
||||
region.getLastColumn());
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether a record must be inserted or not at generation to indicate that
|
||||
@ -659,7 +594,7 @@ public class HSSFSheet implements org.apache.poi.ss.usermodel.Sheet
|
||||
|
||||
/**
|
||||
* TODO: Boolean not needed, remove after next release
|
||||
* @deprecated use getVerticallyCenter() instead
|
||||
* @deprecated (Mar-2008) use getVerticallyCenter() instead
|
||||
*/
|
||||
public boolean getVerticallyCenter(boolean value) {
|
||||
return getVerticallyCenter();
|
||||
@ -724,14 +659,19 @@ public class HSSFSheet implements org.apache.poi.ss.usermodel.Sheet
|
||||
}
|
||||
|
||||
/**
|
||||
* gets the region at a particular index
|
||||
* @param index of the region to fetch
|
||||
* @return the merged region (simple eh?)
|
||||
* @deprecated (Aug-2008) use {@link HSSFSheet#getMergedRegion(int)}
|
||||
*/
|
||||
public Region getMergedRegionAt(int index) {
|
||||
CellRangeAddress cra = getMergedRegion(index);
|
||||
|
||||
public Region getMergedRegionAt(int index)
|
||||
{
|
||||
return new Region(sheet.getMergedRegionAt(index));
|
||||
return new Region(cra.getFirstRow(), (short)cra.getFirstColumn(),
|
||||
cra.getLastRow(), (short)cra.getLastColumn());
|
||||
}
|
||||
/**
|
||||
* @return the merged region at the specified index
|
||||
*/
|
||||
public CellRangeAddress getMergedRegion(int index) {
|
||||
return (CellRangeAddress)sheet.getMergedRegionAt(index);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -1164,36 +1104,43 @@ public class HSSFSheet implements org.apache.poi.ss.usermodel.Sheet
|
||||
protected void shiftMerged(int startRow, int endRow, int n, boolean isRow) {
|
||||
List shiftedRegions = new ArrayList();
|
||||
//move merged regions completely if they fall within the new region boundaries when they are shifted
|
||||
for (int i = 0; i < this.getNumMergedRegions(); i++) {
|
||||
Region merged = this.getMergedRegionAt(i);
|
||||
for (int i = 0; i < getNumMergedRegions(); i++) {
|
||||
CellRangeAddress merged = getMergedRegion(i);
|
||||
|
||||
boolean inStart = (merged.getRowFrom() >= startRow || merged.getRowTo() >= startRow);
|
||||
boolean inEnd = (merged.getRowTo() <= endRow || merged.getRowFrom() <= endRow);
|
||||
boolean inStart= (merged.getFirstRow() >= startRow || merged.getLastRow() >= startRow);
|
||||
boolean inEnd = (merged.getFirstRow() <= endRow || merged.getLastRow() <= endRow);
|
||||
|
||||
//dont check if it's not within the shifted area
|
||||
if (! (inStart && inEnd)) continue;
|
||||
//don't check if it's not within the shifted area
|
||||
if (!inStart || !inEnd) {
|
||||
continue;
|
||||
}
|
||||
|
||||
//only shift if the region outside the shifted rows is not merged too
|
||||
if (!merged.contains(startRow-1, (short)0) && !merged.contains(endRow+1, (short)0)){
|
||||
merged.setRowFrom(merged.getRowFrom()+n);
|
||||
merged.setRowTo(merged.getRowTo()+n);
|
||||
if (!containsCell(merged, startRow-1, 0) && !containsCell(merged, endRow+1, 0)){
|
||||
merged.setFirstRow(merged.getFirstRow()+n);
|
||||
merged.setLastRow(merged.getLastRow()+n);
|
||||
//have to remove/add it back
|
||||
shiftedRegions.add(merged);
|
||||
this.removeMergedRegion(i);
|
||||
removeMergedRegion(i);
|
||||
i = i -1; // we have to back up now since we removed one
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
//readd so it doesn't get shifted again
|
||||
//read so it doesn't get shifted again
|
||||
Iterator iterator = shiftedRegions.iterator();
|
||||
while (iterator.hasNext()) {
|
||||
Region region = (Region)iterator.next();
|
||||
CellRangeAddress region = (CellRangeAddress)iterator.next();
|
||||
|
||||
this.addMergedRegion(region);
|
||||
}
|
||||
|
||||
}
|
||||
private static boolean containsCell(CellRangeAddress cr, int rowIx, int colIx) {
|
||||
if (cr.getFirstRow() <= rowIx && cr.getLastRow() >= rowIx
|
||||
&& cr.getFirstColumn() <= colIx && cr.getLastColumn() >= colIx)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -1812,17 +1759,20 @@ public class HSSFSheet implements org.apache.poi.ss.usermodel.Sheet
|
||||
HSSFRow row = (HSSFRow) it.next();
|
||||
HSSFCell cell = row.getCell(column);
|
||||
|
||||
if (cell == null) continue;
|
||||
if (cell == null) {
|
||||
continue;
|
||||
}
|
||||
|
||||
int colspan = 1;
|
||||
for (int i = 0 ; i < getNumMergedRegions(); i++) {
|
||||
if (getMergedRegionAt(i).contains(row.getRowNum(), column)) {
|
||||
CellRangeAddress region = getMergedRegion(i);
|
||||
if (containsCell(region, row.getRowNum(), column)) {
|
||||
if (!useMergedCells) {
|
||||
// If we're not using merged cells, skip this one and move on to the next.
|
||||
continue rows;
|
||||
}
|
||||
cell = row.getCell(getMergedRegionAt(i).getColumnFrom());
|
||||
colspan = 1+ getMergedRegionAt(i).getColumnTo() - getMergedRegionAt(i).getColumnFrom();
|
||||
cell = row.getCell(region.getFirstColumn());
|
||||
colspan = 1 + region.getLastColumn() - region.getFirstColumn();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -21,6 +21,7 @@ import org.apache.poi.hssf.model.Sheet;
|
||||
import org.apache.poi.hssf.record.CFRuleRecord;
|
||||
import org.apache.poi.hssf.record.aggregates.CFRecordsAggregate;
|
||||
import org.apache.poi.ss.util.Region;
|
||||
import org.apache.poi.ss.util.CellRangeAddress;
|
||||
|
||||
/**
|
||||
* The 'Conditional Formatting' facet of <tt>HSSFSheet</tt>
|
||||
@ -100,7 +101,12 @@ public final class HSSFSheetConditionalFormatting {
|
||||
|
||||
return _sheet.addConditionalFormatting(cfraClone);
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated use <tt>CellRangeAddress</tt> instead of <tt>Region</tt>
|
||||
*/
|
||||
public int addConditionalFormatting(Region[] regions, HSSFConditionalFormattingRule[] cfRules) {
|
||||
return addConditionalFormatting(Region.convertRegionsToCellRanges(regions), cfRules);
|
||||
}
|
||||
/**
|
||||
* Allows to add a new Conditional Formatting set to the sheet.
|
||||
*
|
||||
@ -109,8 +115,7 @@ public final class HSSFSheetConditionalFormatting {
|
||||
*
|
||||
* @return index of the newly created Conditional Formatting object
|
||||
*/
|
||||
|
||||
public int addConditionalFormatting(Region[] regions, HSSFConditionalFormattingRule[] cfRules) {
|
||||
public int addConditionalFormatting(CellRangeAddress[] regions, HSSFConditionalFormattingRule[] cfRules) {
|
||||
if (regions == null) {
|
||||
throw new IllegalArgumentException("regions must not be null");
|
||||
}
|
||||
@ -132,7 +137,7 @@ public final class HSSFSheetConditionalFormatting {
|
||||
return _sheet.addConditionalFormatting(cfra);
|
||||
}
|
||||
|
||||
public int addConditionalFormatting(Region[] regions,
|
||||
public int addConditionalFormatting(CellRangeAddress[] regions,
|
||||
HSSFConditionalFormattingRule rule1)
|
||||
{
|
||||
return addConditionalFormatting(regions,
|
||||
@ -142,7 +147,7 @@ public final class HSSFSheetConditionalFormatting {
|
||||
});
|
||||
}
|
||||
|
||||
public int addConditionalFormatting(Region[] regions,
|
||||
public int addConditionalFormatting(CellRangeAddress[] regions,
|
||||
HSSFConditionalFormattingRule rule1,
|
||||
HSSFConditionalFormattingRule rule2)
|
||||
{
|
||||
@ -153,18 +158,6 @@ public final class HSSFSheetConditionalFormatting {
|
||||
});
|
||||
}
|
||||
|
||||
public int addConditionalFormatting(Region[] regions,
|
||||
HSSFConditionalFormattingRule rule1,
|
||||
HSSFConditionalFormattingRule rule2,
|
||||
HSSFConditionalFormattingRule rule3)
|
||||
{
|
||||
return addConditionalFormatting(regions,
|
||||
new HSSFConditionalFormattingRule[]
|
||||
{
|
||||
rule1, rule2, rule3
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* gets Conditional Formatting object at a particular index
|
||||
*
|
||||
|
46
src/java/org/apache/poi/hssf/util/CellRangeAddress.java
Normal file
46
src/java/org/apache/poi/hssf/util/CellRangeAddress.java
Normal file
@ -0,0 +1,46 @@
|
||||
/* ====================================================================
|
||||
Copyright 2002-2004 Apache Software Foundation
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
==================================================================== */
|
||||
|
||||
package org.apache.poi.hssf.util;
|
||||
|
||||
import org.apache.poi.hssf.record.RecordInputStream;
|
||||
import org.apache.poi.hssf.record.SelectionRecord;
|
||||
import org.apache.poi.util.LittleEndian;
|
||||
|
||||
/**
|
||||
* See OOO documentation: excelfileformat.pdf sec 2.5.14 - 'Cell Range Address'<p/>
|
||||
*
|
||||
* Note - {@link SelectionRecord} uses the BIFF5 version of this structure
|
||||
* @author Dragos Buleandra (dragos.buleandra@trade2b.ro)
|
||||
*/
|
||||
public class CellRangeAddress extends org.apache.poi.ss.util.CellRangeAddress {
|
||||
public CellRangeAddress(int firstRow, int lastRow, int firstCol, int lastCol) {
|
||||
super(firstRow, lastRow, firstCol, lastCol);
|
||||
}
|
||||
public CellRangeAddress() {
|
||||
super();
|
||||
}
|
||||
public CellRangeAddress(RecordInputStream in) {
|
||||
if (in.remaining() < ENCODED_SIZE) {
|
||||
// Ran out of data
|
||||
throw new RuntimeException("Ran out of data reading CellRangeAddress");
|
||||
}
|
||||
_firstRow = in.readUShort();
|
||||
_lastRow = in.readUShort();
|
||||
_firstCol = in.readUShort();
|
||||
_lastCol = in.readUShort();
|
||||
}
|
||||
}
|
57
src/java/org/apache/poi/hssf/util/CellRangeAddressList.java
Normal file
57
src/java/org/apache/poi/hssf/util/CellRangeAddressList.java
Normal file
@ -0,0 +1,57 @@
|
||||
/* ====================================================================
|
||||
Copyright 2002-2004 Apache Software Foundation
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
==================================================================== */
|
||||
|
||||
package org.apache.poi.hssf.util;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import org.apache.poi.hssf.record.RecordInputStream;
|
||||
import org.apache.poi.util.LittleEndian;
|
||||
|
||||
/**
|
||||
* Implementation of the cell range address lists,like is described
|
||||
* in OpenOffice.org's Excel Documentation: excelfileformat.pdf sec 2.5.14 -
|
||||
* 'Cell Range Address List'
|
||||
*
|
||||
* In BIFF8 there is a common way to store absolute cell range address lists in
|
||||
* several records (not formulas). A cell range address list consists of a field
|
||||
* with the number of ranges and the list of the range addresses. Each cell
|
||||
* range address (called an ADDR structure) contains 4 16-bit-values.
|
||||
* </p>
|
||||
*
|
||||
* @author Dragos Buleandra (dragos.buleandra@trade2b.ro)
|
||||
*/
|
||||
public class CellRangeAddressList extends org.apache.poi.ss.util.CellRangeAddressList {
|
||||
public CellRangeAddressList(int firstRow, int lastRow, int firstCol, int lastCol) {
|
||||
super(firstRow,lastRow,firstCol,lastCol);
|
||||
}
|
||||
public CellRangeAddressList() {
|
||||
super();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param in the RecordInputstream to read the record from
|
||||
*/
|
||||
public CellRangeAddressList(RecordInputStream in) {
|
||||
super();
|
||||
int nItems = in.readUShort();
|
||||
|
||||
for (int k = 0; k < nItems; k++) {
|
||||
_list.add(new CellRangeAddress(in));
|
||||
}
|
||||
}
|
||||
}
|
@ -1,269 +0,0 @@
|
||||
/* ====================================================================
|
||||
Copyright 2002-2004 Apache Software Foundation
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
==================================================================== */
|
||||
|
||||
package org.apache.poi.hssf.util;
|
||||
|
||||
import org.apache.poi.hssf.record.RecordInputStream;
|
||||
import org.apache.poi.util.LittleEndian;
|
||||
import org.apache.poi.util.POILogFactory;
|
||||
import org.apache.poi.util.POILogger;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
/**
|
||||
* <p>Title: HSSFCellRangeAddress</p>
|
||||
* <p>Description:
|
||||
* Implementation of the cell range address lists,like is described in
|
||||
* OpenOffice.org's Excel Documentation .
|
||||
* In BIFF8 there is a common way to store absolute cell range address
|
||||
* lists in several records (not formulas). A cell range address list
|
||||
* consists of a field with the number of ranges and the list of the range
|
||||
* addresses. Each cell range address (called an ADDR structure) contains
|
||||
* 4 16-bit-values.</p>
|
||||
* <p>Copyright: Copyright (c) 2004</p>
|
||||
* <p>Company: </p>
|
||||
* @author Dragos Buleandra (dragos.buleandra@trade2b.ro)
|
||||
* @version 2.0-pre
|
||||
*/
|
||||
|
||||
public class HSSFCellRangeAddress
|
||||
{
|
||||
private static POILogger logger = POILogFactory.getLogger(HSSFCellRangeAddress.class);
|
||||
|
||||
/**
|
||||
* Number of following ADDR structures
|
||||
*/
|
||||
private short field_addr_number;
|
||||
|
||||
/**
|
||||
* List of ADDR structures. Each structure represents a cell range
|
||||
*/
|
||||
private ArrayList field_regions_list;
|
||||
|
||||
public HSSFCellRangeAddress()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct a new HSSFCellRangeAddress object and sets its fields appropriately .
|
||||
* Even this isn't an Excel record , I kept the same behavior for reading/writing
|
||||
* the object's data as for a regular record .
|
||||
*
|
||||
* @param in the RecordInputstream to read the record from
|
||||
*/
|
||||
public HSSFCellRangeAddress(RecordInputStream in)
|
||||
{
|
||||
this.fillFields(in);
|
||||
}
|
||||
|
||||
public void fillFields(RecordInputStream in)
|
||||
{
|
||||
this.field_addr_number = in.readShort();
|
||||
this.field_regions_list = new ArrayList(this.field_addr_number);
|
||||
|
||||
for (int k = 0; k < this.field_addr_number; k++)
|
||||
{
|
||||
short first_row = in.readShort();
|
||||
short first_col = in.readShort();
|
||||
|
||||
short last_row = first_row;
|
||||
short last_col = first_col;
|
||||
if(in.remaining() >= 4) {
|
||||
last_row = in.readShort();
|
||||
last_col = in.readShort();
|
||||
} else {
|
||||
// Ran out of data
|
||||
// For now, issue a warning, finish, and
|
||||
// hope for the best....
|
||||
logger.log(POILogger.WARN, "Ran out of data reading cell references for DVRecord");
|
||||
k = this.field_addr_number;
|
||||
}
|
||||
|
||||
AddrStructure region = new AddrStructure(first_row, first_col, last_row, last_col);
|
||||
this.field_regions_list.add(region);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the number of following ADDR structures.
|
||||
* The number of this structures is automatically set when reading an Excel file
|
||||
* and/or increased when you manually add a new ADDR structure .
|
||||
* This is the reason there isn't a set method for this field .
|
||||
* @return number of ADDR structures
|
||||
*/
|
||||
public short getADDRStructureNumber()
|
||||
{
|
||||
return this.field_addr_number;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add an ADDR structure .
|
||||
* @param first_row - the upper left hand corner's row
|
||||
* @param first_col - the upper left hand corner's col
|
||||
* @param last_row - the lower right hand corner's row
|
||||
* @param last_col - the lower right hand corner's col
|
||||
* @return the index of this ADDR structure
|
||||
*/
|
||||
public int addADDRStructure(short first_row, short first_col, short last_row, short last_col)
|
||||
{
|
||||
if (this.field_regions_list == null)
|
||||
{
|
||||
//just to be sure :-)
|
||||
this.field_addr_number= 0;
|
||||
this.field_regions_list = new ArrayList(10);
|
||||
}
|
||||
AddrStructure region = new AddrStructure(first_row, last_row, first_col, last_col);
|
||||
|
||||
this.field_regions_list.add(region);
|
||||
this.field_addr_number++;
|
||||
return this.field_addr_number;
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove the ADDR structure stored at the passed in index
|
||||
* @param index The ADDR structure's index
|
||||
*/
|
||||
public void removeADDRStructureAt(int index)
|
||||
{
|
||||
this.field_regions_list.remove(index);
|
||||
this.field_addr_number--;
|
||||
}
|
||||
|
||||
/**
|
||||
* return the ADDR structure at the given index.
|
||||
* @return AddrStructure representing
|
||||
*/
|
||||
public AddrStructure getADDRStructureAt(int index)
|
||||
{
|
||||
return ( AddrStructure ) this.field_regions_list.get(index);
|
||||
}
|
||||
|
||||
public int serialize(int offset, byte [] data)
|
||||
{
|
||||
int pos = 2;
|
||||
|
||||
LittleEndian.putShort(data, offset, this.getADDRStructureNumber());
|
||||
for (int k = 0; k < this.getADDRStructureNumber(); k++)
|
||||
{
|
||||
AddrStructure region = this.getADDRStructureAt(k);
|
||||
LittleEndian.putShort(data, offset + pos, region.getFirstRow());
|
||||
pos += 2;
|
||||
LittleEndian.putShort(data, offset + pos, region.getLastRow());
|
||||
pos += 2;
|
||||
LittleEndian.putShort(data, offset + pos, region.getFirstColumn());
|
||||
pos += 2;
|
||||
LittleEndian.putShort(data, offset + pos, region.getLastColumn());
|
||||
pos += 2;
|
||||
}
|
||||
return this.getSize();
|
||||
}
|
||||
|
||||
public int getSize()
|
||||
{
|
||||
return 2 + this.field_addr_number*8;
|
||||
}
|
||||
|
||||
public class AddrStructure
|
||||
{
|
||||
private short _first_row;
|
||||
private short _first_col;
|
||||
private short _last_row;
|
||||
private short _last_col;
|
||||
|
||||
public AddrStructure(short first_row, short last_row, short first_col, short last_col)
|
||||
{
|
||||
this._first_row = first_row;
|
||||
this._last_row = last_row;
|
||||
this._first_col = first_col;
|
||||
this._last_col = last_col;
|
||||
}
|
||||
|
||||
/**
|
||||
* get the upper left hand corner column number
|
||||
* @return column number for the upper left hand corner
|
||||
*/
|
||||
public short getFirstColumn()
|
||||
{
|
||||
return this._first_col;
|
||||
}
|
||||
|
||||
/**
|
||||
* get the upper left hand corner row number
|
||||
* @return row number for the upper left hand corner
|
||||
*/
|
||||
public short getFirstRow()
|
||||
{
|
||||
return this._first_row;
|
||||
}
|
||||
|
||||
/**
|
||||
* get the lower right hand corner column number
|
||||
* @return column number for the lower right hand corner
|
||||
*/
|
||||
public short getLastColumn()
|
||||
{
|
||||
return this._last_col;
|
||||
}
|
||||
|
||||
/**
|
||||
* get the lower right hand corner row number
|
||||
* @return row number for the lower right hand corner
|
||||
*/
|
||||
public short getLastRow()
|
||||
{
|
||||
return this._last_row;
|
||||
}
|
||||
|
||||
/**
|
||||
* set the upper left hand corner column number
|
||||
* @param this._first_col column number for the upper left hand corner
|
||||
*/
|
||||
public void setFirstColumn(short first_col)
|
||||
{
|
||||
this._first_col = first_col;
|
||||
}
|
||||
|
||||
/**
|
||||
* set the upper left hand corner row number
|
||||
* @param rowFrom row number for the upper left hand corner
|
||||
*/
|
||||
public void setFirstRow(short first_row)
|
||||
{
|
||||
this._first_row = first_row;
|
||||
}
|
||||
|
||||
/**
|
||||
* set the lower right hand corner column number
|
||||
* @param colTo column number for the lower right hand corner
|
||||
*/
|
||||
public void setLastColumn(short last_col)
|
||||
{
|
||||
this._last_col = last_col;
|
||||
}
|
||||
|
||||
/**
|
||||
* get the lower right hand corner row number
|
||||
* @param rowTo row number for the lower right hand corner
|
||||
*/
|
||||
public void setLastRow(short last_row)
|
||||
{
|
||||
this._last_row = last_row;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,471 +0,0 @@
|
||||
/* ====================================================================
|
||||
Copyright 2002-2004 Apache Software Foundation
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
==================================================================== */
|
||||
|
||||
package org.apache.poi.hssf.util;
|
||||
|
||||
/**
|
||||
* <p>Title: HSSFDataValidation</p>
|
||||
* <p>Description: Utilty class for creating data validation cells</p>
|
||||
* <p>Copyright: Copyright (c) 2004</p>
|
||||
* <p>Company: </p>
|
||||
* @author Dragos Buleandra (dragos.buleandra@trade2b.ro)
|
||||
* @version 2.0-pre
|
||||
*/
|
||||
|
||||
public class HSSFDataValidation
|
||||
{
|
||||
/**
|
||||
* Validation data type constants
|
||||
*/
|
||||
/**
|
||||
* Any type
|
||||
*/
|
||||
public static final int DATA_TYPE_ANY = 0x00;
|
||||
/**
|
||||
* Integer type
|
||||
*/
|
||||
public static final int DATA_TYPE_INTEGER = 0x01;
|
||||
/**
|
||||
* Decimal type
|
||||
*/
|
||||
public static final int DATA_TYPE_DECIMAL = 0x02;
|
||||
/**
|
||||
* List type ( combo box type )
|
||||
*/
|
||||
public static final int DATA_TYPE_LIST = 0x03;
|
||||
/**
|
||||
* Date type
|
||||
*/
|
||||
public static final int DATA_TYPE_DATE = 0x04;
|
||||
/**
|
||||
* Time type
|
||||
*/
|
||||
public static final int DATA_TYPE_TIME = 0x05;
|
||||
/**
|
||||
* String length type
|
||||
*/
|
||||
public static final int DATA_TYPE_TEXT_LENGTH = 0x06;
|
||||
/**
|
||||
* Formula ( custom ) type
|
||||
*/
|
||||
public static final int DATA_TYPE_FORMULA = 0x07;
|
||||
|
||||
/**
|
||||
* Error style constants for error box
|
||||
*/
|
||||
/**
|
||||
* STOP style like
|
||||
*/
|
||||
public static final int ERROR_STYLE_STOP = 0x00;
|
||||
/**
|
||||
* WARNING style like
|
||||
*/
|
||||
public static final int ERROR_STYLE_WARNING = 0x01;
|
||||
/**
|
||||
* INFO style like
|
||||
*/
|
||||
public static final int ERROR_STYLE_INFO = 0x02;
|
||||
|
||||
/**
|
||||
* Condition operator
|
||||
*/
|
||||
public static final int OPERATOR_BETWEEN = 0x00;
|
||||
public static final int OPERATOR_NOT_BETWEEN = 0x01;
|
||||
public static final int OPERATOR_EQUAL = 0x02;
|
||||
public static final int OPERATOR_NOT_EQUAL = 0x03;
|
||||
public static final int OPERATOR_GREATER_THAN = 0x04;
|
||||
public static final int OPERATOR_LESS_THAN = 0x05;
|
||||
public static final int OPERATOR_GREATER_OR_EQUAL = 0x06;
|
||||
public static final int OPERATOR_LESS_OR_EQUAL = 0x07;
|
||||
|
||||
private short _first_row = 0;
|
||||
private short _first_col = 0;
|
||||
private short _last_row = 0;
|
||||
private short _last_col = 0;
|
||||
|
||||
private String _prompt_title = null;
|
||||
private String _prompt_text = null;
|
||||
private String _error_title = null;
|
||||
private String _error_text = null;
|
||||
private String _string_first_formula = null;
|
||||
private String _string_sec_formula = null;
|
||||
|
||||
private int _data_type = HSSFDataValidation.DATA_TYPE_ANY;
|
||||
private int _error_style = HSSFDataValidation.ERROR_STYLE_STOP;
|
||||
private boolean _list_explicit_formula = true;
|
||||
private boolean _empty_cell_allowed = true;
|
||||
private boolean _surpress_dropdown_arrow = false;
|
||||
private boolean _show_prompt_box = true;
|
||||
private boolean _show_error_box = true;
|
||||
private int _operator = HSSFDataValidation.OPERATOR_BETWEEN;
|
||||
|
||||
|
||||
/**
|
||||
* Empty constructor
|
||||
*/
|
||||
public HSSFDataValidation( )
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor wich initializes the cell range on wich this object will be applied
|
||||
* @param first_row First row
|
||||
* @param first_col First column
|
||||
* @param last_row Last row
|
||||
* @param last_col Last column
|
||||
*/
|
||||
public HSSFDataValidation( short first_row, short first_col, short last_row, short last_col )
|
||||
{
|
||||
this._first_row = first_row;
|
||||
this._first_col = first_col;
|
||||
this._last_row = last_row;
|
||||
this._last_col = last_col;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the type of this object
|
||||
* @param data_type The type
|
||||
* @see DATA_TYPE_ANY, DATA_TYPE_INTEGER, DATA_TYPE_DECIMNAL, DATA_TYPE_LIST, DATA_TYPE_DATE,
|
||||
* DATA_TYPE_TIME, DATA_TYPE_TEXT_LENTGH, DATA_TYPE_FORMULA
|
||||
*/
|
||||
public void setDataValidationType( int data_type )
|
||||
{
|
||||
this._data_type = data_type;
|
||||
}
|
||||
|
||||
/**
|
||||
* The data type of this object
|
||||
* @return The type
|
||||
* @see DATA_TYPE_ANY, DATA_TYPE_INTEGER, DATA_TYPE_DECIMNAL, DATA_TYPE_LIST, DATA_TYPE_DATE,
|
||||
* DATA_TYPE_TIME, DATA_TYPE_TEXT_LENTGH, DATA_TYPE_FORMULA
|
||||
*/
|
||||
public int getDataValidationType()
|
||||
{
|
||||
return this._data_type;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the error style for error box
|
||||
* @param error_style Error style constant
|
||||
* @see ERROR_STYLE_STOP, ERROR_STYLE_WARNING, ERROR_STYLE_INFO
|
||||
*/
|
||||
public void setErrorStyle( int error_style )
|
||||
{
|
||||
this._error_style = error_style;
|
||||
}
|
||||
|
||||
/**
|
||||
* returns the error style of errror box
|
||||
* @return the style constant
|
||||
* @see ERROR_STYLE_STOP, ERROR_STYLE_WARNING, ERROR_STYLE_INFO
|
||||
*/
|
||||
public int getErrorStyle( )
|
||||
{
|
||||
return this._error_style;
|
||||
}
|
||||
|
||||
/**
|
||||
* If this object has an explicit formula . This is useful only for list data validation object
|
||||
* @param explicit True if use an explicit formula
|
||||
*/
|
||||
public void setExplicitListFormula( boolean explicit )
|
||||
{
|
||||
this._list_explicit_formula = explicit;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the settings for explicit formula . This is useful only for list data validation objects.
|
||||
* This method always returns false if the object isn't a list validation object
|
||||
* @see setDataValidationType( int data_type )
|
||||
* @return
|
||||
*/
|
||||
public boolean getExplicitListFormula( )
|
||||
{
|
||||
if ( this._data_type != HSSFDataValidation.DATA_TYPE_LIST )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
return this._list_explicit_formula ;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets if this object allows empty as a valid value
|
||||
* @param allowed True if this object should treats empty as valid value , false otherwise
|
||||
*/
|
||||
public void setEmptyCellAllowed( boolean allowed )
|
||||
{
|
||||
this._empty_cell_allowed = allowed;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve the settings for empty cells allowed
|
||||
* @return True if this object should treats empty as valid value , false otherwise
|
||||
*/
|
||||
public boolean getEmptyCellAllowed( )
|
||||
{
|
||||
return this._empty_cell_allowed ;
|
||||
}
|
||||
|
||||
/**
|
||||
* Useful for list validation objects .
|
||||
* @param surppres True if a list should display the values into a drop down list , false otherwise .
|
||||
* In other words , if a list should display the arrow sign on its right side
|
||||
*/
|
||||
public void setSurppressDropDownArrow( boolean surppres )
|
||||
{
|
||||
this._surpress_dropdown_arrow = surppres;
|
||||
}
|
||||
|
||||
/**
|
||||
* Useful only list validation objects .
|
||||
* This method always returns false if the object isn't a list validation object
|
||||
* @return True if a list should display the values into a drop down list , false otherwise .
|
||||
* @see setDataValidationType( int data_type )
|
||||
*/
|
||||
public boolean getSurppressDropDownArrow( )
|
||||
{
|
||||
if ( this._data_type != HSSFDataValidation.DATA_TYPE_LIST )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
return this._surpress_dropdown_arrow ;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the behaviour when a cell which belongs to this object is selected
|
||||
* @param show True if an prompt box should be displayed , false otherwise
|
||||
*/
|
||||
public void setShowPromptBox( boolean show )
|
||||
{
|
||||
this._show_prompt_box = show;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param show True if an prompt box should be displayed , false otherwise
|
||||
*/
|
||||
public boolean getShowPromptBox( )
|
||||
{
|
||||
if ( (this.getPromptBoxText() == null) && (this.getPromptBoxTitle() == null) )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
return this._show_prompt_box ;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the behaviour when an invalid value is entered
|
||||
* @param show True if an error box should be displayed , false otherwise
|
||||
*/
|
||||
public void setShowErrorBox( boolean show )
|
||||
{
|
||||
this._show_error_box = show;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return True if an error box should be displayed , false otherwise
|
||||
*/
|
||||
public boolean getShowErrorBox( )
|
||||
{
|
||||
if ( (this.getErrorBoxText() == null) && (this.getErrorBoxTitle() == null) )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
return this._show_error_box ;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the operator involved in the formula whic governs this object
|
||||
* Example : if you wants that a cell to accept only values between 1 and 5 , which
|
||||
* mathematically means 1 <= value <= 5 , then the operator should be OPERATOR_BETWEEN
|
||||
* @param operator A constant for operator
|
||||
* @see OPERATOR_BETWEEN, OPERATOR_NOT_BETWEEN, OPERATOR_EQUAL, OPERATOR_NOT_EQUAL
|
||||
* OPERATOR_GREATER_THAN, OPERATOR_LESS_THAN, OPERATOR_GREATER_OR_EQUAL,
|
||||
* OPERATOR_LESS_OR_EQUAL
|
||||
*/
|
||||
public void setOperator( int operator )
|
||||
{
|
||||
this._operator = operator;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the operator used for this object's formula
|
||||
* @return
|
||||
* @see OPERATOR_BETWEEN, OPERATOR_NOT_BETWEEN, OPERATOR_EQUAL, OPERATOR_NOT_EQUAL
|
||||
* OPERATOR_GREATER_THAN, OPERATOR_LESS_THAN, OPERATOR_GREATER_OR_EQUAL,
|
||||
* OPERATOR_LESS_OR_EQUAL
|
||||
*/
|
||||
public int getOperator()
|
||||
{
|
||||
return this._operator;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the title and text for the prompt box . Prompt box is displayed when the user
|
||||
* selects a cell which belongs to this validation object . In order for a prompt box
|
||||
* to be displayed you should also use method setShowPromptBox( boolean show )
|
||||
* @param title The prompt box's title
|
||||
* @param text The prompt box's text
|
||||
* @see setShowPromptBox( boolean show )
|
||||
*/
|
||||
public void createPromptBox( String title, String text )
|
||||
{
|
||||
this._prompt_title = title;
|
||||
this._prompt_text = text;
|
||||
this.setShowPromptBox(true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the prompt box's title
|
||||
* @return Prompt box's title or null
|
||||
*/
|
||||
public String getPromptBoxTitle( )
|
||||
{
|
||||
return this._prompt_title;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the prompt box's text
|
||||
* @return Prompt box's text or null
|
||||
*/
|
||||
public String getPromptBoxText( )
|
||||
{
|
||||
return this._prompt_text;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the title and text for the error box . Error box is displayed when the user
|
||||
* enters an invalid value int o a cell which belongs to this validation object .
|
||||
* In order for an error box to be displayed you should also use method
|
||||
* setShowErrorBox( boolean show )
|
||||
* @param title The error box's title
|
||||
* @param text The error box's text
|
||||
* @see setShowErrorBox( boolean show )
|
||||
*/
|
||||
public void createErrorBox( String title, String text )
|
||||
{
|
||||
this._error_title = title;
|
||||
this._error_text = text;
|
||||
this.setShowErrorBox(true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the error box's title
|
||||
* @return Error box's title or null
|
||||
*/
|
||||
public String getErrorBoxTitle( )
|
||||
{
|
||||
return this._error_title;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the error box's text
|
||||
* @return Error box's text or null
|
||||
*/
|
||||
public String getErrorBoxText( )
|
||||
{
|
||||
return this._error_text;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the first formula for this object .
|
||||
* A formula is divided into three parts : first formula , operator and second formula .
|
||||
* In other words , a formula contains a left oprand , an operator and a right operand.
|
||||
* This is the general rule . An example is 1<= value <= 5 . In this case ,
|
||||
* the left operand ( or the first formula ) is the number 1 . The operator is
|
||||
* OPERATOR_BETWEEN and the right operand ( or the second formula ) is 5 .
|
||||
* @param formula
|
||||
*/
|
||||
public void setFirstFormula( String formula )
|
||||
{
|
||||
this._string_first_formula = formula;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the first formula
|
||||
* @return
|
||||
*/
|
||||
public String getFirstFormula( )
|
||||
{
|
||||
return this._string_first_formula;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the first formula for this object .
|
||||
* A formula is divided into three parts : first formula , operator and second formula .
|
||||
* In other words , a formula contains a left oprand , an operator and a right operand.
|
||||
* This is the general rule . An example is 1<= value <=5 . In this case ,
|
||||
* the left operand ( or the first formula ) is the number 1 . The operator is
|
||||
* OPERATOR_BETWEEN and the right operand ( or the second formula ) is 5 .
|
||||
* But there are cases when a second formula isn't needed :
|
||||
* You want somethink like : all values less than 5 . In this case , there's only a first
|
||||
* formula ( in our case 5 ) and the operator OPERATOR_LESS_THAN
|
||||
* @param formula
|
||||
*/
|
||||
public void setSecondFormula( String formula )
|
||||
{
|
||||
this._string_sec_formula = formula;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the second formula
|
||||
* @return
|
||||
*/
|
||||
public String getSecondFormula( )
|
||||
{
|
||||
return this._string_sec_formula;
|
||||
}
|
||||
|
||||
public void setFirstRow( short first_row )
|
||||
{
|
||||
this._first_row = first_row;
|
||||
}
|
||||
|
||||
public void setFirstColumn( short first_column )
|
||||
{
|
||||
this._first_col = first_column;
|
||||
}
|
||||
|
||||
public void setLastRow( short last_row )
|
||||
{
|
||||
this._last_row = last_row;
|
||||
}
|
||||
|
||||
public void setLastColumn( short last_column )
|
||||
{
|
||||
this._last_col = last_column;
|
||||
}
|
||||
|
||||
public short getFirstRow()
|
||||
{
|
||||
return this._first_row;
|
||||
}
|
||||
|
||||
public short getFirstColumn()
|
||||
{
|
||||
return this._first_col;
|
||||
}
|
||||
|
||||
public short getLastRow()
|
||||
{
|
||||
return this._last_row;
|
||||
}
|
||||
|
||||
public short getLastColumn()
|
||||
{
|
||||
return this._last_col;
|
||||
}
|
||||
|
||||
}
|
@ -18,8 +18,6 @@
|
||||
|
||||
package org.apache.poi.hssf.util;
|
||||
|
||||
import org.apache.poi.hssf.record.MergeCellsRecord.MergedRegion;
|
||||
|
||||
/**
|
||||
* Represents a from/to row/col square. This is a object primitive
|
||||
* that can be used to represent row,col - row,col just as one would use String
|
||||
@ -43,16 +41,6 @@ public class Region extends org.apache.poi.ss.util.Region
|
||||
super(rowFrom, colFrom, rowTo, colTo);
|
||||
}
|
||||
|
||||
/**
|
||||
* special constructor (I know this is bad but it is so wrong that its right
|
||||
* okay) that makes a region from a mergedcells's region subrecord.
|
||||
*/
|
||||
|
||||
public Region(MergedRegion region)
|
||||
{
|
||||
super(region);
|
||||
}
|
||||
|
||||
public Region(String ref) {
|
||||
super(ref);
|
||||
}
|
||||
|
@ -16,17 +16,12 @@
|
||||
==================================================================== */
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* DateUtil.java
|
||||
*
|
||||
* Created on January 19, 2002, 9:30 AM
|
||||
*/
|
||||
package org.apache.poi.ss.usermodel;
|
||||
|
||||
import java.util.Calendar;
|
||||
import java.util.Date;
|
||||
import java.util.GregorianCalendar;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
/**
|
||||
* Contains methods for dealing with Excel dates.
|
||||
@ -38,16 +33,19 @@ import java.util.GregorianCalendar;
|
||||
* @author Alex Jacoby (ajacoby at gmail.com)
|
||||
* @author Pavel Krupets (pkrupets at palmtreebusiness dot com)
|
||||
*/
|
||||
|
||||
public class DateUtil
|
||||
{
|
||||
protected DateUtil()
|
||||
{
|
||||
public class DateUtil {
|
||||
protected DateUtil() {
|
||||
// no instances of this class
|
||||
}
|
||||
private static final int SECONDS_PER_MINUTE = 60;
|
||||
private static final int MINUTES_PER_HOUR = 60;
|
||||
private static final int HOURS_PER_DAY = 24;
|
||||
private static final int SECONDS_PER_DAY = (HOURS_PER_DAY * MINUTES_PER_HOUR * SECONDS_PER_MINUTE);
|
||||
|
||||
private static final int BAD_DATE =
|
||||
-1; // used to specify that date is invalid
|
||||
private static final long DAY_MILLISECONDS = 24 * 60 * 60 * 1000;
|
||||
private static final int BAD_DATE = -1; // used to specify that date is invalid
|
||||
private static final long DAY_MILLISECONDS = SECONDS_PER_DAY * 1000L;
|
||||
|
||||
private static final Pattern TIME_SEPARATOR_PATTERN = Pattern.compile(":");
|
||||
|
||||
/**
|
||||
* Given a Date, converts it into a double representing its internal Excel representation,
|
||||
@ -91,7 +89,7 @@ public class DateUtil
|
||||
(use1904windowing && date.get(Calendar.YEAR) < 1904))
|
||||
{
|
||||
return BAD_DATE;
|
||||
} else {
|
||||
}
|
||||
// Because of daylight time saving we cannot use
|
||||
// date.getTime() - calStart.getTimeInMillis()
|
||||
// as the difference in milliseconds between 00:00 and 04:00
|
||||
@ -116,7 +114,6 @@ public class DateUtil
|
||||
|
||||
return value;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Given an Excel date with using 1900 date windowing, and
|
||||
@ -158,7 +155,9 @@ public class DateUtil
|
||||
* @see java.util.TimeZone
|
||||
*/
|
||||
public static Date getJavaDate(double date, boolean use1904windowing) {
|
||||
if (isValidExcelDate(date)) {
|
||||
if (!isValidExcelDate(date)) {
|
||||
return null;
|
||||
}
|
||||
int startYear = 1900;
|
||||
int dayAdjust = -1; // Excel thinks 2/29/1900 is a valid date, which it isn't
|
||||
int wholeDays = (int)Math.floor(date);
|
||||
@ -178,10 +177,6 @@ public class DateUtil
|
||||
calendar.set(GregorianCalendar.MILLISECOND, millisecondsInDay);
|
||||
return calendar.getTime();
|
||||
}
|
||||
else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Given a format ID and its format String, will check to see if the
|
||||
@ -231,7 +226,6 @@ public class DateUtil
|
||||
// Otherwise, check it's only made up, in any case, of:
|
||||
// y m d h s - / , . :
|
||||
// optionally followed by AM/PM
|
||||
// optionally followed by AM/PM
|
||||
if(fs.matches("^[yYmMdDhHsS\\-/,. :]+[ampAMP/]*$")) {
|
||||
return true;
|
||||
}
|
||||
@ -245,8 +239,6 @@ public class DateUtil
|
||||
* @see #isADateFormat(int, java.lang.String)
|
||||
*/
|
||||
public static boolean isInternalDateFormat(int format) {
|
||||
boolean retval =false;
|
||||
|
||||
switch(format) {
|
||||
// Internal Date Formats as described on page 427 in
|
||||
// Microsoft Excel Dev's Kit...
|
||||
@ -262,14 +254,9 @@ public class DateUtil
|
||||
case 0x2d:
|
||||
case 0x2e:
|
||||
case 0x2f:
|
||||
retval = true;
|
||||
break;
|
||||
|
||||
default:
|
||||
retval = false;
|
||||
break;
|
||||
return true;
|
||||
}
|
||||
return retval;
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -286,8 +273,6 @@ public class DateUtil
|
||||
double d = cell.getNumericCellValue();
|
||||
if ( DateUtil.isValidExcelDate(d) ) {
|
||||
CellStyle style = cell.getCellStyle();
|
||||
if(style == null) return false;
|
||||
|
||||
int i = style.getDataFormat();
|
||||
String f = style.getDataFormatString();
|
||||
bDate = isADateFormat(i, f);
|
||||
@ -335,7 +320,6 @@ public class DateUtil
|
||||
* @param cal the Calendar
|
||||
* @exception IllegalArgumentException if date is invalid
|
||||
*/
|
||||
|
||||
protected static int absoluteDay(Calendar cal, boolean use1904windowing)
|
||||
{
|
||||
return cal.get(Calendar.DAY_OF_YEAR)
|
||||
@ -380,5 +364,95 @@ public class DateUtil
|
||||
return cal;
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------------------------------------
|
||||
|
||||
private static final class FormatException extends Exception {
|
||||
public FormatException(String msg) {
|
||||
super(msg);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts a string of format "HH:MM" or "HH:MM:SS" to its (Excel) numeric equivalent
|
||||
*
|
||||
* @return a double between 0 and 1 representing the fraction of the day
|
||||
*/
|
||||
public static double convertTime(String timeStr) {
|
||||
try {
|
||||
return convertTimeInternal(timeStr);
|
||||
} catch (FormatException e) {
|
||||
String msg = "Bad time format '" + timeStr
|
||||
+ "' expected 'HH:MM' or 'HH:MM:SS' - " + e.getMessage();
|
||||
throw new IllegalArgumentException(msg);
|
||||
}
|
||||
}
|
||||
private static double convertTimeInternal(String timeStr) throws FormatException {
|
||||
int len = timeStr.length();
|
||||
if (len < 4 || len > 8) {
|
||||
throw new FormatException("Bad length");
|
||||
}
|
||||
String[] parts = TIME_SEPARATOR_PATTERN.split(timeStr);
|
||||
|
||||
String secStr;
|
||||
switch (parts.length) {
|
||||
case 2: secStr = "00"; break;
|
||||
case 3: secStr = parts[2]; break;
|
||||
default:
|
||||
throw new FormatException("Expected 2 or 3 fields but got (" + parts.length + ")");
|
||||
}
|
||||
String hourStr = parts[0];
|
||||
String minStr = parts[1];
|
||||
int hours = parseInt(hourStr, "hour", HOURS_PER_DAY);
|
||||
int minutes = parseInt(minStr, "minute", MINUTES_PER_HOUR);
|
||||
int seconds = parseInt(secStr, "second", SECONDS_PER_MINUTE);
|
||||
|
||||
double totalSeconds = seconds + (minutes + (hours) * 60) * 60;
|
||||
return totalSeconds / (SECONDS_PER_DAY);
|
||||
}
|
||||
/**
|
||||
* Converts a string of format "YYYY/MM/DD" to its (Excel) numeric equivalent
|
||||
*
|
||||
* @return a double representing the (integer) number of days since the start of the Excel epoch
|
||||
*/
|
||||
public static Date parseYYYYMMDDDate(String dateStr) {
|
||||
try {
|
||||
return parseYYYYMMDDDateInternal(dateStr);
|
||||
} catch (FormatException e) {
|
||||
String msg = "Bad time format " + dateStr
|
||||
+ " expected 'YYYY/MM/DD' - " + e.getMessage();
|
||||
throw new IllegalArgumentException(msg);
|
||||
}
|
||||
}
|
||||
private static Date parseYYYYMMDDDateInternal(String timeStr) throws FormatException {
|
||||
if(timeStr.length() != 10) {
|
||||
throw new FormatException("Bad length");
|
||||
}
|
||||
|
||||
String yearStr = timeStr.substring(0, 4);
|
||||
String monthStr = timeStr.substring(5, 7);
|
||||
String dayStr = timeStr.substring(8, 10);
|
||||
int year = parseInt(yearStr, "year", Short.MIN_VALUE, Short.MAX_VALUE);
|
||||
int month = parseInt(monthStr, "month", 1, 12);
|
||||
int day = parseInt(dayStr, "day", 1, 31);
|
||||
|
||||
Calendar cal = new GregorianCalendar(year, month-1, day, 0, 0, 0);
|
||||
cal.set(Calendar.MILLISECOND, 0);
|
||||
return cal.getTime();
|
||||
}
|
||||
private static int parseInt(String strVal, String fieldName, int rangeMax) throws FormatException {
|
||||
return parseInt(strVal, fieldName, 0, rangeMax-1);
|
||||
}
|
||||
|
||||
private static int parseInt(String strVal, String fieldName, int lowerLimit, int upperLimit) throws FormatException {
|
||||
int result;
|
||||
try {
|
||||
result = Integer.parseInt(strVal);
|
||||
} catch (NumberFormatException e) {
|
||||
throw new FormatException("Bad int format '" + strVal + "' for " + fieldName + " field");
|
||||
}
|
||||
if (result < lowerLimit || result > upperLimit) {
|
||||
throw new FormatException(fieldName + " value (" + result
|
||||
+ ") is outside the allowable range(0.." + upperLimit + ")");
|
||||
}
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
167
src/java/org/apache/poi/ss/util/CellRangeAddress.java
Normal file
167
src/java/org/apache/poi/ss/util/CellRangeAddress.java
Normal file
@ -0,0 +1,167 @@
|
||||
/* ====================================================================
|
||||
Copyright 2002-2004 Apache Software Foundation
|
||||
|
||||
Licensed 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.ss.util;
|
||||
|
||||
import org.apache.poi.hssf.record.SelectionRecord;
|
||||
import org.apache.poi.util.LittleEndian;
|
||||
|
||||
/**
|
||||
* See OOO documentation: excelfileformat.pdf sec 2.5.14 - 'Cell Range Address'<p/>
|
||||
*
|
||||
* Note - {@link SelectionRecord} uses the BIFF5 version of this structure
|
||||
* @author Dragos Buleandra (dragos.buleandra@trade2b.ro)
|
||||
*/
|
||||
public class CellRangeAddress {
|
||||
/*
|
||||
* TODO - replace org.apache.poi.hssf.util.Region
|
||||
*/
|
||||
public static final int ENCODED_SIZE = 8;
|
||||
|
||||
/** max 65536 rows in BIFF8 */
|
||||
public static final int LAST_ROW_INDEX = 0x00FFFF;
|
||||
/** max 256 columns in BIFF8 */
|
||||
public static final int LAST_COLUMN_INDEX = 0x00FF;
|
||||
|
||||
|
||||
protected int _firstRow;
|
||||
protected int _firstCol;
|
||||
protected int _lastRow;
|
||||
protected int _lastCol;
|
||||
|
||||
protected CellRangeAddress() {}
|
||||
public CellRangeAddress(int firstRow, int lastRow, int firstCol, int lastCol) {
|
||||
if(!isValid(firstRow, lastRow, firstCol, lastCol)) {
|
||||
throw new IllegalArgumentException("invalid cell range (" + firstRow + ", " + lastRow
|
||||
+ ", " + firstCol + ", " + lastCol + ")");
|
||||
}
|
||||
_firstRow = firstRow;
|
||||
_lastRow = convertM1ToMax(lastRow, LAST_ROW_INDEX);
|
||||
_firstCol = firstCol;
|
||||
_lastCol = convertM1ToMax(lastCol, LAST_COLUMN_INDEX);
|
||||
}
|
||||
|
||||
private static boolean isValid(int firstRow, int lastRow, int firstColumn, int lastColumn)
|
||||
{
|
||||
if(lastRow < 0 || lastRow > LAST_ROW_INDEX) {
|
||||
return false;
|
||||
}
|
||||
if(firstRow < 0 || firstRow > LAST_ROW_INDEX) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if(lastColumn < 0 || lastColumn > LAST_COLUMN_INDEX) {
|
||||
return false;
|
||||
}
|
||||
if(firstColumn < 0 || firstColumn > LAST_COLUMN_INDEX) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
/**
|
||||
* Range arithmetic is easier when using a large positive number for 'max row or column'
|
||||
* instead of <tt>-1</tt>.
|
||||
*/
|
||||
private static int convertM1ToMax(int lastIx, int maxIndex) {
|
||||
if(lastIx < 0) {
|
||||
return maxIndex;
|
||||
}
|
||||
return lastIx;
|
||||
}
|
||||
|
||||
public boolean isFullColumnRange() {
|
||||
return _firstRow == 0 && _lastRow == LAST_ROW_INDEX;
|
||||
}
|
||||
public boolean isFullRowRange() {
|
||||
return _firstCol == 0 && _lastCol == LAST_COLUMN_INDEX;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return column number for the upper left hand corner
|
||||
*/
|
||||
public int getFirstColumn() {
|
||||
return _firstCol;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return row number for the upper left hand corner
|
||||
*/
|
||||
public int getFirstRow() {
|
||||
return _firstRow;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return column number for the lower right hand corner
|
||||
*/
|
||||
public int getLastColumn() {
|
||||
return _lastCol;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return row number for the lower right hand corner
|
||||
*/
|
||||
public int getLastRow() {
|
||||
return _lastRow;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param _firstCol column number for the upper left hand corner
|
||||
*/
|
||||
public void setFirstColumn(int firstCol) {
|
||||
_firstCol = firstCol;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param rowFrom row number for the upper left hand corner
|
||||
*/
|
||||
public void setFirstRow(int firstRow) {
|
||||
_firstRow = firstRow;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param colTo column number for the lower right hand corner
|
||||
*/
|
||||
public void setLastColumn(int lastCol) {
|
||||
_lastCol = lastCol;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param rowTo row number for the lower right hand corner
|
||||
*/
|
||||
public void setLastRow(int lastRow) {
|
||||
_lastRow = lastRow;
|
||||
}
|
||||
|
||||
public CellRangeAddress copy() {
|
||||
return new CellRangeAddress(_firstRow, _lastRow, _firstCol, _lastCol);
|
||||
}
|
||||
|
||||
public static int getEncodedSize(int numberOfItems) {
|
||||
return numberOfItems * ENCODED_SIZE;
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
return getClass().getName() + " ["+_firstRow+", "+_lastRow+", "+_firstCol+", "+_lastCol+"]";
|
||||
}
|
||||
|
||||
public int serialize(int offset, byte[] data) {
|
||||
LittleEndian.putUShort(data, offset + 0, _firstRow);
|
||||
LittleEndian.putUShort(data, offset + 2, _lastRow);
|
||||
LittleEndian.putUShort(data, offset + 4, _firstCol);
|
||||
LittleEndian.putUShort(data, offset + 6, _lastCol);
|
||||
return ENCODED_SIZE;
|
||||
}
|
||||
}
|
132
src/java/org/apache/poi/ss/util/CellRangeAddressList.java
Normal file
132
src/java/org/apache/poi/ss/util/CellRangeAddressList.java
Normal file
@ -0,0 +1,132 @@
|
||||
/* ====================================================================
|
||||
Copyright 2002-2004 Apache Software Foundation
|
||||
|
||||
Licensed 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.ss.util;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import org.apache.poi.util.LittleEndian;
|
||||
|
||||
/**
|
||||
* Implementation of the cell range address lists,like is described
|
||||
* in OpenOffice.org's Excel Documentation: excelfileformat.pdf sec 2.5.14 -
|
||||
* 'Cell Range Address List'
|
||||
*
|
||||
* In BIFF8 there is a common way to store absolute cell range address lists in
|
||||
* several records (not formulas). A cell range address list consists of a field
|
||||
* with the number of ranges and the list of the range addresses. Each cell
|
||||
* range address (called an ADDR structure) contains 4 16-bit-values.
|
||||
* </p>
|
||||
*
|
||||
* @author Dragos Buleandra (dragos.buleandra@trade2b.ro)
|
||||
*/
|
||||
public class CellRangeAddressList {
|
||||
|
||||
/**
|
||||
* List of <tt>CellRangeAddress</tt>es. Each structure represents a cell range
|
||||
*/
|
||||
protected final List _list;
|
||||
|
||||
public CellRangeAddressList() {
|
||||
_list = new ArrayList();
|
||||
}
|
||||
/**
|
||||
* Convenience constructor for creating a <tt>CellRangeAddressList</tt> with a single
|
||||
* <tt>CellRangeAddress</tt>. Other <tt>CellRangeAddress</tt>es may be added later.
|
||||
*/
|
||||
public CellRangeAddressList(int firstRow, int lastRow, int firstCol, int lastCol) {
|
||||
this();
|
||||
addCellRangeAddress(firstRow, firstCol, lastRow, lastCol);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the number of following ADDR structures. The number of this
|
||||
* structures is automatically set when reading an Excel file and/or
|
||||
* increased when you manually add a new ADDR structure . This is the reason
|
||||
* there isn't a set method for this field .
|
||||
*
|
||||
* @return number of ADDR structures
|
||||
*/
|
||||
public int countRanges() {
|
||||
return _list.size();
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a cell range structure.
|
||||
*
|
||||
* @param firstRow - the upper left hand corner's row
|
||||
* @param firstCol - the upper left hand corner's col
|
||||
* @param lastRow - the lower right hand corner's row
|
||||
* @param lastCol - the lower right hand corner's col
|
||||
* @return the index of this ADDR structure
|
||||
*/
|
||||
public void addCellRangeAddress(int firstRow, int firstCol, int lastRow, int lastCol) {
|
||||
CellRangeAddress region = new CellRangeAddress(firstRow, lastRow, firstCol, lastCol);
|
||||
addCellRangeAddress(region);
|
||||
}
|
||||
public void addCellRangeAddress(CellRangeAddress cra) {
|
||||
_list.add(cra);
|
||||
}
|
||||
public CellRangeAddress remove(int rangeIndex) {
|
||||
if (_list.isEmpty()) {
|
||||
throw new RuntimeException("List is empty");
|
||||
}
|
||||
if (rangeIndex < 0 || rangeIndex >= _list.size()) {
|
||||
throw new RuntimeException("Range index (" + rangeIndex
|
||||
+ ") is outside allowable range (0.." + (_list.size()-1) + ")");
|
||||
}
|
||||
return (CellRangeAddress) _list.remove(rangeIndex);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return <tt>CellRangeAddress</tt> at the given index
|
||||
*/
|
||||
public CellRangeAddress getCellRangeAddress(int index) {
|
||||
return (CellRangeAddress) _list.get(index);
|
||||
}
|
||||
|
||||
public int getSize() {
|
||||
return 2 + CellRangeAddress.getEncodedSize(_list.size());
|
||||
}
|
||||
|
||||
public int serialize(int offset, byte[] data) {
|
||||
int pos = 2;
|
||||
|
||||
int nItems = _list.size();
|
||||
LittleEndian.putUShort(data, offset, nItems);
|
||||
for (int k = 0; k < nItems; k++) {
|
||||
CellRangeAddress region = (CellRangeAddress) _list.get(k);
|
||||
pos += region.serialize(offset + pos, data);
|
||||
}
|
||||
return getSize();
|
||||
}
|
||||
|
||||
public CellRangeAddressList copy() {
|
||||
CellRangeAddressList result = new CellRangeAddressList();
|
||||
|
||||
int nItems = _list.size();
|
||||
for (int k = 0; k < nItems; k++) {
|
||||
CellRangeAddress region = (CellRangeAddress) _list.get(k);
|
||||
result.addCellRangeAddress(region.copy());
|
||||
}
|
||||
return result;
|
||||
}
|
||||
public CellRangeAddress[] getCellRangeAddresses() {
|
||||
CellRangeAddress[] result = new CellRangeAddress[_list.size()];
|
||||
_list.toArray(result);
|
||||
return result;
|
||||
}
|
||||
}
|
@ -15,10 +15,8 @@
|
||||
limitations under the License.
|
||||
==================================================================== */
|
||||
|
||||
|
||||
package org.apache.poi.ss.util;
|
||||
|
||||
import org.apache.poi.hssf.record.MergeCellsRecord.MergedRegion;
|
||||
|
||||
/**
|
||||
* Represents a from/to row/col square. This is a object primitive
|
||||
@ -26,11 +24,9 @@ import org.apache.poi.hssf.record.MergeCellsRecord.MergedRegion;
|
||||
* to represent a string of characters. Its really only useful for HSSF though.
|
||||
*
|
||||
* @author Andrew C. Oliver acoliver at apache dot org
|
||||
* @deprecated (Aug-2008) use {@link CellRangeAddress}
|
||||
*/
|
||||
|
||||
public class Region
|
||||
implements Comparable
|
||||
{
|
||||
public class Region implements Comparable {
|
||||
private int rowFrom;
|
||||
private short colFrom;
|
||||
private int rowTo;
|
||||
@ -52,16 +48,6 @@ public class Region
|
||||
this.colTo = colTo;
|
||||
}
|
||||
|
||||
/**
|
||||
* special constructor (I know this is bad but it is so wrong that its right
|
||||
* okay) that makes a region from a mergedcells's region subrecord.
|
||||
*/
|
||||
|
||||
public Region(MergedRegion region)
|
||||
{
|
||||
this(region.row_from, region.col_from, region.row_to, region.col_to);
|
||||
}
|
||||
|
||||
public Region(String ref) {
|
||||
CellReference cellReferenceFrom = new CellReference(ref.substring(0, ref.indexOf(":")));
|
||||
CellReference cellReferenceTo = new CellReference(ref.substring(ref.indexOf(":") + 1));
|
||||
@ -71,6 +57,7 @@ public class Region
|
||||
this.colTo = (short) cellReferenceTo.getCol();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* get the upper left hand corner column number
|
||||
*
|
||||
@ -159,6 +146,7 @@ public class Region
|
||||
this.rowTo = rowTo;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Answers: "is the row/column inside this range?"
|
||||
*
|
||||
@ -219,13 +207,48 @@ public class Region
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the area contained by this region (number of cells)
|
||||
* Convert a List of CellRange objects to an array of regions
|
||||
*
|
||||
* @param List of CellRange objects
|
||||
* @return regions
|
||||
*/
|
||||
public static Region[] convertCellRangesToRegions(CellRangeAddress[] cellRanges) {
|
||||
int size = cellRanges.length;
|
||||
if(size < 1) {
|
||||
return new Region[0];
|
||||
}
|
||||
|
||||
public int getArea()
|
||||
{
|
||||
return ((1 + (getRowTo() - getRowFrom()))
|
||||
* (1 + (getColumnTo() - getColumnFrom())));
|
||||
Region[] result = new Region[size];
|
||||
|
||||
for (int i = 0; i != size; i++) {
|
||||
result[i] = convertToRegion(cellRanges[i]);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
|
||||
private static Region convertToRegion(CellRangeAddress cr) {
|
||||
|
||||
return new Region(cr.getFirstRow(), (short)cr.getFirstColumn(), cr.getLastRow(), (short)cr.getLastColumn());
|
||||
}
|
||||
|
||||
public static CellRangeAddress[] convertRegionsToCellRanges(Region[] regions) {
|
||||
int size = regions.length;
|
||||
if(size < 1) {
|
||||
return new CellRangeAddress[0];
|
||||
}
|
||||
|
||||
CellRangeAddress[] result = new CellRangeAddress[size];
|
||||
|
||||
for (int i = 0; i != size; i++) {
|
||||
result[i] = convertToCellRangeAddress(regions[i]);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
public static CellRangeAddress convertToCellRangeAddress(Region r) {
|
||||
return new CellRangeAddress(r.getRowFrom(), r.getRowTo(), r.getColumnFrom(), r.getColumnTo());
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -0,0 +1,51 @@
|
||||
/* ====================================================================
|
||||
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.hslf.examples;
|
||||
|
||||
import org.apache.poi.hslf.usermodel.SlideShow;
|
||||
import org.apache.poi.hslf.model.HeadersFooters;
|
||||
import org.apache.poi.hslf.model.Slide;
|
||||
|
||||
import java.io.FileOutputStream;
|
||||
|
||||
/**
|
||||
* Demonstrates how to set headers / footers
|
||||
*
|
||||
* @author Yegor Kozlov
|
||||
*/
|
||||
public class HeadersFootersDemo {
|
||||
public static void main(String[] args) throws Exception {
|
||||
SlideShow ppt = new SlideShow();
|
||||
|
||||
HeadersFooters slideHeaders = ppt.getSlideHeadersFooters();
|
||||
slideHeaders.setFootersText("Created by POI-HSLF");
|
||||
slideHeaders.setSlideNumberVisible(true);
|
||||
slideHeaders.setDateTimeText("custom date time");
|
||||
|
||||
HeadersFooters notesHeaders = ppt.getNotesHeadersFooters();
|
||||
notesHeaders.setFootersText("My notes footers");
|
||||
notesHeaders.setHeaderText("My notes header");
|
||||
|
||||
Slide slide = ppt.createSlide();
|
||||
|
||||
FileOutputStream out = new FileOutputStream("headers_footers.ppt");
|
||||
ppt.write(out);
|
||||
out.close();
|
||||
|
||||
}
|
||||
|
||||
}
|
226
src/scratchpad/src/org/apache/poi/hslf/model/HeadersFooters.java
Normal file
226
src/scratchpad/src/org/apache/poi/hslf/model/HeadersFooters.java
Normal file
@ -0,0 +1,226 @@
|
||||
|
||||
/* ====================================================================
|
||||
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.hslf.model;
|
||||
|
||||
import org.apache.poi.hslf.record.*;
|
||||
import org.apache.poi.hslf.usermodel.SlideShow;
|
||||
|
||||
/**
|
||||
* Header / Footer settings.
|
||||
*
|
||||
* @author Yegor Kozlov
|
||||
*/
|
||||
public class HeadersFooters {
|
||||
|
||||
private HeadersFootersContainer _container;
|
||||
private boolean _newRecord;
|
||||
private SlideShow _ppt;
|
||||
|
||||
public HeadersFooters(HeadersFootersContainer rec, SlideShow ppt, boolean newRecord){
|
||||
_container = rec;
|
||||
_newRecord = newRecord;
|
||||
_ppt = ppt;
|
||||
}
|
||||
|
||||
/**
|
||||
* Headers's text
|
||||
*
|
||||
* @return Headers's text
|
||||
*/
|
||||
public String getHeaderText(){
|
||||
CString cs = _container.getHeaderAtom();
|
||||
return cs == null ? null : cs.getText();
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets headers's text
|
||||
*
|
||||
* @param text headers's text
|
||||
*/
|
||||
public void setHeaderText(String text){
|
||||
if(_newRecord) attach();
|
||||
|
||||
setHeaderVisible(true);
|
||||
CString cs = _container.getHeaderAtom();
|
||||
if(cs == null) cs = _container.addHeaderAtom();
|
||||
|
||||
cs.setText(text);
|
||||
}
|
||||
|
||||
/**
|
||||
* Footer's text
|
||||
*
|
||||
* @return Footer's text
|
||||
*/
|
||||
public String getFooterText(){
|
||||
CString cs = _container.getFooterAtom();
|
||||
return cs == null ? null : cs.getText();
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets footers's text
|
||||
*
|
||||
* @param text footers's text
|
||||
*/
|
||||
public void setFootersText(String text){
|
||||
if(_newRecord) attach();
|
||||
|
||||
setFooterVisible(true);
|
||||
CString cs = _container.getFooterAtom();
|
||||
if(cs == null) cs = _container.addFooterAtom();
|
||||
|
||||
cs.setText(text);
|
||||
}
|
||||
|
||||
/**
|
||||
* This is the date that the user wants in the footers, instead of today's date.
|
||||
*
|
||||
* @return custom user date
|
||||
*/
|
||||
public String getDateTimeText(){
|
||||
CString cs = _container.getUserDateAtom();
|
||||
return cs == null ? null : cs.getText();
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets custom user date to be displayed instead of today's date.
|
||||
*
|
||||
* @param text custom user date
|
||||
*/
|
||||
public void setDateTimeText(String text){
|
||||
if(_newRecord) attach();
|
||||
|
||||
setUserDateVisible(true);
|
||||
setDateTimeVisible(true);
|
||||
CString cs = _container.getUserDateAtom();
|
||||
if(cs == null) cs = _container.addUserDateAtom();
|
||||
|
||||
cs.setText(text);
|
||||
}
|
||||
|
||||
/**
|
||||
* whether the footer text is displayed.
|
||||
*/
|
||||
public boolean isFooterVisible(){
|
||||
return _container.getHeadersFootersAtom().getFlag(HeadersFootersAtom.fHasFooter);
|
||||
}
|
||||
|
||||
/**
|
||||
* whether the footer text is displayed.
|
||||
*/
|
||||
public void setFooterVisible(boolean flag){
|
||||
if(_newRecord) attach();
|
||||
_container.getHeadersFootersAtom().setFlag(HeadersFootersAtom.fHasFooter, flag);
|
||||
}
|
||||
|
||||
/**
|
||||
* whether the header text is displayed.
|
||||
*/
|
||||
public boolean isHeaderVisible(){
|
||||
return _container.getHeadersFootersAtom().getFlag(HeadersFootersAtom.fHasHeader);
|
||||
}
|
||||
|
||||
/**
|
||||
* whether the header text is displayed.
|
||||
*/
|
||||
public void setHeaderVisible(boolean flag){
|
||||
if(_newRecord) attach();
|
||||
_container.getHeadersFootersAtom().setFlag(HeadersFootersAtom.fHasHeader, flag);
|
||||
}
|
||||
|
||||
/**
|
||||
* whether the date is displayed in the footer.
|
||||
*/
|
||||
public boolean isDateTimeVisible(){
|
||||
return _container.getHeadersFootersAtom().getFlag(HeadersFootersAtom.fHasDate);
|
||||
}
|
||||
|
||||
/**
|
||||
* whether the date is displayed in the footer.
|
||||
*/
|
||||
public void setDateTimeVisible(boolean flag){
|
||||
if(_newRecord) attach();
|
||||
_container.getHeadersFootersAtom().setFlag(HeadersFootersAtom.fHasDate, flag);
|
||||
}
|
||||
|
||||
/**
|
||||
* whether the custom user date is used instead of today's date.
|
||||
*/
|
||||
public boolean isUserDateVisible(){
|
||||
return _container.getHeadersFootersAtom().getFlag(HeadersFootersAtom.fHasUserDate);
|
||||
}
|
||||
|
||||
/**
|
||||
* whether the date is displayed in the footer.
|
||||
*/
|
||||
public void setUserDateVisible(boolean flag){
|
||||
if(_newRecord) attach();
|
||||
_container.getHeadersFootersAtom().setFlag(HeadersFootersAtom.fHasUserDate, flag);
|
||||
}
|
||||
|
||||
/**
|
||||
* whether the slide number is displayed in the footer.
|
||||
*/
|
||||
public boolean isSlideNumberVisible(){
|
||||
return _container.getHeadersFootersAtom().getFlag(HeadersFootersAtom.fHasSlideNumber);
|
||||
}
|
||||
|
||||
/**
|
||||
* whether the slide number is displayed in the footer.
|
||||
*/
|
||||
public void setSlideNumberVisible(boolean flag){
|
||||
if(_newRecord) attach();
|
||||
_container.getHeadersFootersAtom().setFlag(HeadersFootersAtom.fHasSlideNumber, flag);
|
||||
}
|
||||
|
||||
/**
|
||||
* An integer that specifies the format ID to be used to style the datetime.
|
||||
*
|
||||
* @return an integer that specifies the format ID to be used to style the datetime.
|
||||
*/
|
||||
public int getDateTimeFormat(){
|
||||
return _container.getHeadersFootersAtom().getFormatId();
|
||||
}
|
||||
|
||||
/**
|
||||
* An integer that specifies the format ID to be used to style the datetime.
|
||||
*
|
||||
* @param formatId an integer that specifies the format ID to be used to style the datetime.
|
||||
*/
|
||||
public void setDateTimeFormat(int formatId){
|
||||
if(_newRecord) attach();
|
||||
_container.getHeadersFootersAtom().setFormatId(formatId);
|
||||
}
|
||||
|
||||
/**
|
||||
* Attach this HeadersFootersContainer to the parent Document record
|
||||
*/
|
||||
private void attach(){
|
||||
Document doc = _ppt.getDocumentRecord();
|
||||
Record[] ch = doc.getChildRecords();
|
||||
Record lst = null;
|
||||
for (int i=0; i < ch.length; i++){
|
||||
if(ch[i].getRecordType() == RecordTypes.List.typeID){
|
||||
lst = ch[i];
|
||||
break;
|
||||
}
|
||||
}
|
||||
doc.addChildAfter(_container, lst);
|
||||
_newRecord = false;
|
||||
}
|
||||
}
|
@ -24,9 +24,7 @@ import java.util.Vector;
|
||||
import java.util.Iterator;
|
||||
import java.awt.*;
|
||||
|
||||
import org.apache.poi.hslf.record.SlideAtom;
|
||||
import org.apache.poi.hslf.record.TextHeaderAtom;
|
||||
import org.apache.poi.hslf.record.ColorSchemeAtom;
|
||||
import org.apache.poi.hslf.record.*;
|
||||
import org.apache.poi.hslf.record.SlideListWithText.SlideAtomsSet;
|
||||
import org.apache.poi.ddf.EscherDggRecord;
|
||||
import org.apache.poi.ddf.EscherContainerRecord;
|
||||
@ -381,4 +379,22 @@ public class Slide extends Sheet
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Header / Footer settings for this slide.
|
||||
*
|
||||
* @return Header / Footer settings for this slide
|
||||
*/
|
||||
public HeadersFooters getHeadersFooters(){
|
||||
HeadersFootersContainer hdd = null;
|
||||
Record[] ch = getSheetContainer().getChildRecords();
|
||||
for (int i = 0; i < ch.length; i++) {
|
||||
if(ch[i] instanceof HeadersFootersContainer){
|
||||
hdd = (HeadersFootersContainer)ch[i];
|
||||
break;
|
||||
}
|
||||
}
|
||||
boolean newRecord = false;
|
||||
if(hdd == null) return getSlideShow().getSlideHeadersFooters();
|
||||
else return new HeadersFooters(hdd, getSlideShow(), newRecord);
|
||||
}
|
||||
}
|
||||
|
@ -56,7 +56,7 @@ public class CString extends RecordAtom {
|
||||
* Grabs the count, from the first two bytes of the header.
|
||||
* The meaning of the count is specific to the type of the parent record
|
||||
*/
|
||||
public int getCount() {
|
||||
public int getOptions() {
|
||||
return (int)LittleEndian.getShort(_header);
|
||||
}
|
||||
|
||||
@ -64,7 +64,7 @@ public class CString extends RecordAtom {
|
||||
* Sets the count
|
||||
* The meaning of the count is specific to the type of the parent record
|
||||
*/
|
||||
public void setCount(int count) {
|
||||
public void setOptions(int count) {
|
||||
LittleEndian.putShort(_header, (short)count);
|
||||
}
|
||||
|
||||
|
@ -140,9 +140,9 @@ public class Comment2000 extends RecordContainer {
|
||||
CString csa = new CString();
|
||||
CString csb = new CString();
|
||||
CString csc = new CString();
|
||||
csa.setCount(0x00);
|
||||
csb.setCount(0x10);
|
||||
csc.setCount(0x20);
|
||||
csa.setOptions(0x00);
|
||||
csb.setOptions(0x10);
|
||||
csc.setOptions(0x20);
|
||||
_children[0] = csa;
|
||||
_children[1] = csb;
|
||||
_children[2] = csc;
|
||||
|
@ -25,6 +25,7 @@ import org.apache.poi.poifs.filesystem.*;
|
||||
import org.apache.poi.util.LittleEndian;
|
||||
import org.apache.poi.util.StringUtil;
|
||||
import org.apache.poi.hslf.exceptions.CorruptPowerPointFileException;
|
||||
import org.apache.poi.hslf.exceptions.EncryptedPowerPointFileException;
|
||||
|
||||
|
||||
/**
|
||||
@ -39,14 +40,15 @@ public class CurrentUserAtom
|
||||
{
|
||||
/** Standard Atom header */
|
||||
public static final byte[] atomHeader = new byte[] { 0, 0, -10, 15 };
|
||||
/** The Powerpoint magic numer */
|
||||
public static final byte[] magicNumber = new byte[] { 95, -64, -111, -29 };
|
||||
/** The PowerPoint magic number for a non-encrypted file */
|
||||
public static final byte[] headerToken = new byte[] { 95, -64, -111, -29 };
|
||||
/** The PowerPoint magic number for an encrytpted file */
|
||||
public static final byte[] encHeaderToken = new byte[] { -33, -60, -47, -13 };
|
||||
/** The Powerpoint 97 version, major and minor numbers */
|
||||
public static final byte[] ppt97FileVer = new byte[] { 8, 00, -13, 03, 03, 00 };
|
||||
|
||||
/** The version, major and minor numbers */
|
||||
private int docFinalVersionA;
|
||||
private int docFinalVersionB;
|
||||
private int docFinalVersion;
|
||||
private byte docMajorNo;
|
||||
private byte docMinorNo;
|
||||
|
||||
@ -54,7 +56,7 @@ public class CurrentUserAtom
|
||||
private long currentEditOffset;
|
||||
/** The Username of the last person to edit the file */
|
||||
private String lastEditUser;
|
||||
/** The document release version */
|
||||
/** The document release version. Almost always 8 */
|
||||
private long releaseVersion;
|
||||
|
||||
/** Only correct after reading in or writing out */
|
||||
@ -63,8 +65,7 @@ public class CurrentUserAtom
|
||||
|
||||
/* ********************* getter/setter follows *********************** */
|
||||
|
||||
public int getDocFinalVersionA() { return docFinalVersionA; }
|
||||
public int getDocFinalVersionB() { return docFinalVersionB; }
|
||||
public int getDocFinalVersion() { return docFinalVersion; }
|
||||
public byte getDocMajorNo() { return docMajorNo; }
|
||||
public byte getDocMinorNo() { return docMinorNo; }
|
||||
|
||||
@ -86,7 +87,14 @@ public class CurrentUserAtom
|
||||
*/
|
||||
public CurrentUserAtom() {
|
||||
_contents = new byte[0];
|
||||
throw new RuntimeException("Creation support for Current User Atom not complete");
|
||||
|
||||
// Initialise to empty
|
||||
docFinalVersion = 0x03f4;
|
||||
docMajorNo = 3;
|
||||
docMinorNo = 0;
|
||||
releaseVersion = 8;
|
||||
currentEditOffset = 0;
|
||||
lastEditUser = "Apache POI";
|
||||
}
|
||||
|
||||
/**
|
||||
@ -130,12 +138,20 @@ public class CurrentUserAtom
|
||||
* Actually do the creation from a block of bytes
|
||||
*/
|
||||
private void init() {
|
||||
// First up is the size, in 4 bytes, which is fixed
|
||||
// Then is the header - check for encrypted
|
||||
if(_contents[12] == encHeaderToken[0] &&
|
||||
_contents[13] == encHeaderToken[1] &&
|
||||
_contents[14] == encHeaderToken[2] &&
|
||||
_contents[15] == encHeaderToken[3]) {
|
||||
throw new EncryptedPowerPointFileException("The CurrentUserAtom specifies that the document is encrypted");
|
||||
}
|
||||
|
||||
// Grab the edit offset
|
||||
currentEditOffset = LittleEndian.getUInt(_contents,16);
|
||||
|
||||
// Grab the versions
|
||||
docFinalVersionA = LittleEndian.getUShort(_contents,20);
|
||||
docFinalVersionB = LittleEndian.getUShort(_contents,22);
|
||||
docFinalVersion = LittleEndian.getUShort(_contents,22);
|
||||
docMajorNo = _contents[24];
|
||||
docMinorNo = _contents[25];
|
||||
|
||||
@ -194,15 +210,22 @@ public class CurrentUserAtom
|
||||
// Now we have the size of the details, which is 20
|
||||
LittleEndian.putInt(_contents,8,20);
|
||||
|
||||
// Now the ppt magic number (4 bytes)
|
||||
System.arraycopy(magicNumber,0,_contents,12,4);
|
||||
// Now the ppt un-encrypted header token (4 bytes)
|
||||
System.arraycopy(headerToken,0,_contents,12,4);
|
||||
|
||||
// Now the current edit offset
|
||||
LittleEndian.putInt(_contents,16,(int)currentEditOffset);
|
||||
|
||||
// Now the file versions, 2+2+1+1
|
||||
LittleEndian.putShort(_contents,20,(short)docFinalVersionA);
|
||||
LittleEndian.putShort(_contents,22,(short)docFinalVersionB);
|
||||
// The username gets stored twice, once as US
|
||||
// ascii, and again as unicode laster on
|
||||
byte[] asciiUN = new byte[lastEditUser.length()];
|
||||
StringUtil.putCompressedUnicode(lastEditUser,asciiUN,0);
|
||||
|
||||
// Now we're able to do the length of the last edited user
|
||||
LittleEndian.putShort(_contents,20,(short)asciiUN.length);
|
||||
|
||||
// Now the file versions, 2+1+1
|
||||
LittleEndian.putShort(_contents,22,(short)docFinalVersion);
|
||||
_contents[24] = docMajorNo;
|
||||
_contents[25] = docMinorNo;
|
||||
|
||||
@ -210,9 +233,7 @@ public class CurrentUserAtom
|
||||
_contents[26] = 0;
|
||||
_contents[27] = 0;
|
||||
|
||||
// username in bytes in us ascii
|
||||
byte[] asciiUN = new byte[lastEditUser.length()];
|
||||
StringUtil.putCompressedUnicode(lastEditUser,asciiUN,0);
|
||||
// At this point we have the username as us ascii
|
||||
System.arraycopy(asciiUN,0,_contents,28,asciiUN.length);
|
||||
|
||||
// 4 byte release version
|
||||
|
@ -74,8 +74,8 @@ public class ExEmbed extends RecordContainer {
|
||||
CString cs1 = new CString();
|
||||
CString cs2 = new CString();
|
||||
CString cs3 = new CString();
|
||||
// cs1.setCount(0x00);
|
||||
// cs2.setCount(0x10);
|
||||
// cs1.setOptions(0x00);
|
||||
// cs2.setOptions(0x10);
|
||||
_children[0] = new ExEmbedAtom();
|
||||
_children[1] = new ExOleObjAtom();
|
||||
_children[2] = cs1;
|
||||
|
@ -136,8 +136,8 @@ public class ExHyperlink extends RecordContainer {
|
||||
// Setup our child records
|
||||
CString csa = new CString();
|
||||
CString csb = new CString();
|
||||
csa.setCount(0x00);
|
||||
csb.setCount(0x10);
|
||||
csa.setOptions(0x00);
|
||||
csb.setOptions(0x10);
|
||||
_children[0] = new ExHyperlinkAtom();
|
||||
_children[1] = csa;
|
||||
_children[2] = csb;
|
||||
|
@ -0,0 +1,207 @@
|
||||
|
||||
/* ====================================================================
|
||||
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.hslf.record;
|
||||
|
||||
import org.apache.poi.util.LittleEndian;
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
|
||||
/**
|
||||
* An atom record that specifies options for displaying headers and footers
|
||||
* on a presentation slide or notes slide.
|
||||
*
|
||||
* @author Yegor Kozlov
|
||||
*/
|
||||
|
||||
public class HeadersFootersAtom extends RecordAtom {
|
||||
|
||||
/**
|
||||
* A bit that specifies whether the date is displayed in the footer.
|
||||
* @see {@link #getMask()}, {@link #setMask(int)}},
|
||||
*/
|
||||
public static final int fHasDate = 1;
|
||||
|
||||
/**
|
||||
* A bit that specifies whether the current datetime is used for displaying the datetime.
|
||||
* @see {@link #getMask()}, {@link #setMask(int)}},
|
||||
*/
|
||||
public static final int fHasTodayDate = 2;
|
||||
|
||||
/**
|
||||
* A bit that specifies whether the date specified in UserDateAtom record
|
||||
* is used for displaying the datetime.
|
||||
*
|
||||
* @see {@link #getMask()}, {@link #setMask(int)}},
|
||||
*/
|
||||
public static final int fHasUserDate = 4;
|
||||
|
||||
/**
|
||||
* A bit that specifies whether the slide number is displayed in the footer.
|
||||
*
|
||||
* @see {@link #getMask()}, {@link #setMask(int)}},
|
||||
*/
|
||||
public static final int fHasSlideNumber = 8;
|
||||
|
||||
/**
|
||||
* bit that specifies whether the header text is displayed.
|
||||
*
|
||||
* @see {@link #getMask()}, {@link #setMask(int)}},
|
||||
*/
|
||||
public static final int fHasHeader = 16;
|
||||
|
||||
/**
|
||||
* bit that specifies whether the footer text is displayed.
|
||||
*
|
||||
* @see {@link #getMask()}, {@link #setMask(int)}},
|
||||
*/
|
||||
public static final int fHasFooter = 32;
|
||||
|
||||
/**
|
||||
* record header
|
||||
*/
|
||||
private byte[] _header;
|
||||
|
||||
/**
|
||||
* record data
|
||||
*/
|
||||
private byte[] _recdata;
|
||||
|
||||
/**
|
||||
* Build an instance of <code>HeadersFootersAtom</code> from on-disk data
|
||||
*/
|
||||
protected HeadersFootersAtom(byte[] source, int start, int len) {
|
||||
// Get the header
|
||||
_header = new byte[8];
|
||||
System.arraycopy(source,start,_header,0,8);
|
||||
|
||||
// Grab the record data
|
||||
_recdata = new byte[len-8];
|
||||
System.arraycopy(source,start+8,_recdata,0,len-8);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new instance of <code>HeadersFootersAtom</code>
|
||||
*/
|
||||
public HeadersFootersAtom() {
|
||||
_recdata = new byte[4];
|
||||
|
||||
_header = new byte[8];
|
||||
LittleEndian.putShort(_header, 2, (short)getRecordType());
|
||||
LittleEndian.putInt(_header, 4, _recdata.length);
|
||||
}
|
||||
|
||||
public long getRecordType() {
|
||||
return RecordTypes.HeadersFootersAtom.typeID;
|
||||
}
|
||||
|
||||
/**
|
||||
* Write the contents of the record back, so it can be written to disk
|
||||
*/
|
||||
public void writeOut(OutputStream out) throws IOException {
|
||||
out.write(_header);
|
||||
out.write(_recdata);
|
||||
}
|
||||
|
||||
/**
|
||||
* A signed integer that specifies the format ID to be used to style the datetime.
|
||||
* <p>
|
||||
* It MUST be in the range [0, 12]. </br>
|
||||
* This value is converted into a string as specified by the index field of the DateTimeMCAtom record.
|
||||
* It MUST be ignored unless fHasTodayDate is TRUE.
|
||||
* </b>
|
||||
*
|
||||
* @return A signed integer that specifies the format ID to be used to style the datetime.
|
||||
*/
|
||||
public int getFormatId(){
|
||||
return LittleEndian.getShort(_recdata, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* A signed integer that specifies the format ID to be used to style the datetime.
|
||||
*
|
||||
* @param formatId A signed integer that specifies the format ID to be used to style the datetime.
|
||||
*/
|
||||
public void setFormatId(int formatId){
|
||||
LittleEndian.putUShort(_recdata, 0, formatId);
|
||||
}
|
||||
|
||||
/**
|
||||
* A bit mask specifying options for displaying headers and footers
|
||||
*
|
||||
* <li> A - {@link #fHasDate} (1 bit): A bit that specifies whether the date is displayed in the footer.
|
||||
* <li> B - {@link #fHasTodayDate} (1 bit): A bit that specifies whether the current datetime is used for
|
||||
* displaying the datetime.
|
||||
* <li> C - {@link #fHasUserDate} (1 bit): A bit that specifies whether the date specified in UserDateAtom record
|
||||
* is used for displaying the datetime.
|
||||
* <li> D - {@link #fHasSlideNumber} (1 bit): A bit that specifies whether the slide number is displayed in the footer.
|
||||
* <li> E - {@link #fHasHeader} (1 bit): A bit that specifies whether the header text specified by HeaderAtom
|
||||
* record is displayed.
|
||||
* <li> F - {@link #fHasFooter} (1 bit): A bit that specifies whether the footer text specified by FooterAtom
|
||||
* record is displayed.
|
||||
* <li> reserved (10 bits): MUST be zero and MUST be ignored.
|
||||
*
|
||||
* @return A bit mask specifying options for displaying headers and footers
|
||||
*/
|
||||
public int getMask(){
|
||||
return LittleEndian.getShort(_recdata, 2);
|
||||
}
|
||||
|
||||
/**
|
||||
* A bit mask specifying options for displaying headers and footers
|
||||
*
|
||||
* @param mask A bit mask specifying options for displaying headers and footers
|
||||
*/
|
||||
public void setMask(int mask){
|
||||
LittleEndian.putUShort(_recdata, 2, mask);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param bit the bit to check
|
||||
* @return whether the specified flag is set
|
||||
*/
|
||||
public boolean getFlag(int bit){
|
||||
return (getMask() & bit) != 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param bit the bit to set
|
||||
* @param value whether the specified bit is set
|
||||
*/
|
||||
public void setFlag(int bit, boolean value){
|
||||
int mask = getMask();
|
||||
if(value) mask |= bit;
|
||||
else mask &= ~bit;
|
||||
setMask(mask);
|
||||
}
|
||||
|
||||
public String toString(){
|
||||
StringBuffer buf = new StringBuffer();
|
||||
buf.append("HeadersFootersAtom\n");
|
||||
buf.append("\tFormatId: " + getFormatId() + "\n");
|
||||
buf.append("\tMask : " + getMask() + "\n");
|
||||
buf.append("\t fHasDate : " + getFlag(fHasDate) + "\n");
|
||||
buf.append("\t fHasTodayDate : " + getFlag(fHasTodayDate) + "\n");
|
||||
buf.append("\t fHasUserDate : " + getFlag(fHasUserDate) + "\n");
|
||||
buf.append("\t fHasSlideNumber : " + getFlag(fHasSlideNumber) + "\n");
|
||||
buf.append("\t fHasHeader : " + getFlag(fHasHeader) + "\n");
|
||||
buf.append("\t fHasFooter : " + getFlag(fHasFooter) + "\n");
|
||||
return buf.toString();
|
||||
}
|
||||
}
|
@ -0,0 +1,212 @@
|
||||
|
||||
/* ====================================================================
|
||||
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.hslf.record;
|
||||
|
||||
import org.apache.poi.util.LittleEndian;
|
||||
import org.apache.poi.util.POILogger;
|
||||
|
||||
import java.io.OutputStream;
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* A container record that specifies information about the footers on a presentation slide.
|
||||
* <p>
|
||||
* It contains:<br>
|
||||
* <li> 1. {@link HeadersFootersAtom}
|
||||
* <li> 2. {@link CString }, Instance UserDate (0), optional: Stores the user's date.
|
||||
* This is the date that the user wants in the footers, instead of today's date.
|
||||
* <li> 3. {@link CString }, Instance Header (1), optional: Stores the Header's contents.
|
||||
* <li> 4. {@link CString }, Instance Footer (2), optional: Stores the Footer's contents.
|
||||
* </p>
|
||||
*
|
||||
* @author Yegor Kozlov
|
||||
*/
|
||||
public class HeadersFootersContainer extends RecordContainer {
|
||||
|
||||
/**
|
||||
* "instance" field in the record header indicating that this HeadersFootersContaine
|
||||
* is applied for slides
|
||||
*/
|
||||
public static final short SlideHeadersFootersContainer = 0x3F;
|
||||
/**
|
||||
* "instance" field in the record header indicating that this HeadersFootersContaine
|
||||
* is applied for notes and handouts
|
||||
*/
|
||||
public static final short NotesHeadersFootersContainer = 0x4F;
|
||||
|
||||
public static final int USERDATEATOM = 0;
|
||||
public static final int HEADERATOM = 1;
|
||||
public static final int FOOTERATOM = 2;
|
||||
|
||||
private byte[] _header;
|
||||
private HeadersFootersAtom hdAtom;
|
||||
private CString csDate, csHeader, csFooter;
|
||||
|
||||
protected HeadersFootersContainer(byte[] source, int start, int len) {
|
||||
// Grab the header
|
||||
_header = new byte[8];
|
||||
System.arraycopy(source,start,_header,0,8);
|
||||
|
||||
_children = Record.findChildRecords(source,start+8,len-8);
|
||||
for(int i=0; i < _children.length; i++){
|
||||
if(_children[i] instanceof HeadersFootersAtom) hdAtom = (HeadersFootersAtom)_children[i];
|
||||
else if(_children[i] instanceof CString) {
|
||||
CString cs = (CString)_children[i];
|
||||
int opts = cs.getOptions() >> 4;
|
||||
switch(opts){
|
||||
case USERDATEATOM: csDate = cs; break;
|
||||
case HEADERATOM: csHeader = cs; break;
|
||||
case FOOTERATOM: csFooter = cs; break;
|
||||
default:
|
||||
logger.log(POILogger.WARN, "Unexpected CString.Options in HeadersFootersContainer: " + opts);
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
logger.log(POILogger.WARN, "Unexpected record in HeadersFootersContainer: " + _children[i]);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public HeadersFootersContainer(short options) {
|
||||
_header = new byte[8];
|
||||
LittleEndian.putShort(_header, 0, options);
|
||||
LittleEndian.putShort(_header, 2, (short)getRecordType());
|
||||
|
||||
hdAtom = new HeadersFootersAtom();
|
||||
_children = new Record[]{
|
||||
hdAtom
|
||||
};
|
||||
csDate = csHeader = csFooter = null;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the type, which is <code>{@link RecordTypes#HeadersFooters}</code>
|
||||
*/
|
||||
public long getRecordType() {
|
||||
return RecordTypes.HeadersFooters.typeID;
|
||||
}
|
||||
|
||||
/**
|
||||
* Must be either {@link #SlideHeadersFootersContainer} or {@link #NotesHeadersFootersContainer}
|
||||
*
|
||||
* @return "instance" field in the record header
|
||||
*/
|
||||
public int getOptions(){
|
||||
return LittleEndian.getShort(_header, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Write the contents of the record back, so it can be written to disk
|
||||
*/
|
||||
public void writeOut(OutputStream out) throws IOException {
|
||||
writeOut(_header[0],_header[1],getRecordType(),_children,out);
|
||||
}
|
||||
|
||||
/**
|
||||
* HeadersFootersAtom stores the basic information of the header and footer structure.
|
||||
*
|
||||
* @return <code>HeadersFootersAtom</code>
|
||||
*/
|
||||
public HeadersFootersAtom getHeadersFootersAtom(){
|
||||
return hdAtom;
|
||||
}
|
||||
|
||||
/**
|
||||
* A {@link CString} record that stores the user's date.
|
||||
* <p>This is the date that the user wants in the footers, instead of today's date.</p>
|
||||
*
|
||||
* @return A {@link CString} record that stores the user's date or <code>null</code>
|
||||
*/
|
||||
public CString getUserDateAtom(){
|
||||
return csDate;
|
||||
}
|
||||
|
||||
/**
|
||||
* A {@link CString} record that stores the Header's contents.
|
||||
*
|
||||
* @return A {@link CString} record that stores the Header's contents or <code>null</code>
|
||||
*/
|
||||
public CString getHeaderAtom(){
|
||||
return csHeader;
|
||||
}
|
||||
|
||||
/**
|
||||
* A {@link CString} record that stores the Footers's contents.
|
||||
*
|
||||
* @return A {@link CString} record that stores the Footers's contents or <code>null</code>
|
||||
*/
|
||||
public CString getFooterAtom(){
|
||||
return csFooter;
|
||||
}
|
||||
|
||||
/**
|
||||
* Insert a {@link CString} record that stores the user's date.
|
||||
*
|
||||
* @return the created {@link CString} record that stores the user's date.
|
||||
*/
|
||||
public CString addUserDateAtom(){
|
||||
if(csDate != null) return csDate;
|
||||
|
||||
csDate = new CString();
|
||||
csDate.setOptions(USERDATEATOM << 4);
|
||||
|
||||
addChildAfter(csDate, hdAtom);
|
||||
|
||||
return csDate;
|
||||
}
|
||||
|
||||
/**
|
||||
* Insert a {@link CString} record that stores the user's date.
|
||||
*
|
||||
* @return the created {@link CString} record that stores the user's date.
|
||||
*/
|
||||
public CString addHeaderAtom(){
|
||||
if(csHeader != null) return csHeader;
|
||||
|
||||
csHeader = new CString();
|
||||
csHeader.setOptions(HEADERATOM << 4);
|
||||
|
||||
Record r = hdAtom;
|
||||
if(csDate != null) r = hdAtom;
|
||||
addChildAfter(csHeader, r);
|
||||
|
||||
return csHeader;
|
||||
}
|
||||
|
||||
/**
|
||||
* Insert a {@link CString} record that stores the user's date.
|
||||
*
|
||||
* @return the created {@link CString} record that stores the user's date.
|
||||
*/
|
||||
public CString addFooterAtom(){
|
||||
if(csFooter != null) return csFooter;
|
||||
|
||||
csFooter = new CString();
|
||||
csFooter.setOptions(FOOTERATOM << 4);
|
||||
|
||||
Record r = hdAtom;
|
||||
if(csHeader != null) r = csHeader;
|
||||
else if(csDate != null) r = csDate;
|
||||
addChildAfter(csFooter, r);
|
||||
|
||||
return csFooter;
|
||||
}
|
||||
}
|
@ -111,8 +111,8 @@ public class RecordTypes {
|
||||
public static final Type ExHyperlinkAtom = new Type(4051,ExHyperlinkAtom.class);
|
||||
public static final Type ExHyperlink = new Type(4055,ExHyperlink.class);
|
||||
public static final Type SlideNumberMCAtom = new Type(4056,null);
|
||||
public static final Type HeadersFooters = new Type(4057,null);
|
||||
public static final Type HeadersFootersAtom = new Type(4058,null);
|
||||
public static final Type HeadersFooters = new Type(4057,HeadersFootersContainer.class);
|
||||
public static final Type HeadersFootersAtom = new Type(4058,HeadersFootersAtom.class);
|
||||
public static final Type TxInteractiveInfoAtom = new Type(4063,TxInteractiveInfoAtom.class);
|
||||
public static final Type CharFormatAtom = new Type(4066,null);
|
||||
public static final Type ParaFormatAtom = new Type(4067,null);
|
||||
|
@ -811,4 +811,50 @@ public class SlideShow
|
||||
public int getNumberOfFonts() {
|
||||
return getDocumentRecord().getEnvironment().getFontCollection().getNumberOfFonts();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return Header / Footer settings for slides
|
||||
*
|
||||
* @return Header / Footer settings for slides
|
||||
*/
|
||||
public HeadersFooters getSlideHeadersFooters(){
|
||||
HeadersFootersContainer hdd = null;
|
||||
Record[] ch = _documentRecord.getChildRecords();
|
||||
for (int i = 0; i < ch.length; i++) {
|
||||
if(ch[i] instanceof HeadersFootersContainer &&
|
||||
((HeadersFootersContainer)ch[i]).getOptions() == HeadersFootersContainer.SlideHeadersFootersContainer){
|
||||
hdd = (HeadersFootersContainer)ch[i];
|
||||
break;
|
||||
}
|
||||
}
|
||||
boolean newRecord = false;
|
||||
if(hdd == null) {
|
||||
hdd = new HeadersFootersContainer(HeadersFootersContainer.SlideHeadersFootersContainer);
|
||||
newRecord = true;
|
||||
}
|
||||
return new HeadersFooters(hdd, this, newRecord);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return Header / Footer settings for notes
|
||||
*
|
||||
* @return Header / Footer settings for notes
|
||||
*/
|
||||
public HeadersFooters getNotesHeadersFooters(){
|
||||
HeadersFootersContainer hdd = null;
|
||||
Record[] ch = _documentRecord.getChildRecords();
|
||||
for (int i = 0; i < ch.length; i++) {
|
||||
if(ch[i] instanceof HeadersFootersContainer &&
|
||||
((HeadersFootersContainer)ch[i]).getOptions() == HeadersFootersContainer.NotesHeadersFootersContainer){
|
||||
hdd = (HeadersFootersContainer)ch[i];
|
||||
break;
|
||||
}
|
||||
}
|
||||
boolean newRecord = false;
|
||||
if(hdd == null) {
|
||||
hdd = new HeadersFootersContainer(HeadersFootersContainer.NotesHeadersFootersContainer);
|
||||
newRecord = true;
|
||||
}
|
||||
return new HeadersFooters(hdd, this, newRecord);
|
||||
}
|
||||
}
|
||||
|
Binary file not shown.
@ -0,0 +1,118 @@
|
||||
|
||||
/* ====================================================================
|
||||
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.hslf.model;
|
||||
|
||||
import java.io.*;
|
||||
import org.apache.poi.hslf.usermodel.SlideShow;
|
||||
|
||||
import junit.framework.TestCase;
|
||||
|
||||
/**
|
||||
* Test {@link org.apache.poi.hslf.model.HeadersFooters} object
|
||||
*/
|
||||
public class TestHeadersFooters extends TestCase
|
||||
{
|
||||
|
||||
public static final String cwd = System.getProperty("HSLF.testdata.path");
|
||||
|
||||
public void testRead() throws Exception
|
||||
{
|
||||
File file = new File(cwd, "headers_footers.ppt");
|
||||
FileInputStream is = new FileInputStream(file);
|
||||
SlideShow ppt = new SlideShow(is);
|
||||
is.close();
|
||||
|
||||
HeadersFooters slideHdd = ppt.getSlideHeadersFooters();
|
||||
assertTrue(slideHdd.isFooterVisible());
|
||||
assertEquals("Global Slide Footer", slideHdd.getFooterText());
|
||||
assertTrue(slideHdd.isSlideNumberVisible());
|
||||
assertFalse(slideHdd.isHeaderVisible());
|
||||
assertNull(slideHdd.getHeaderText());
|
||||
assertFalse(slideHdd.isUserDateVisible());
|
||||
assertNull(slideHdd.getDateTimeText());
|
||||
|
||||
|
||||
HeadersFooters notesHdd = ppt.getNotesHeadersFooters();
|
||||
assertTrue(notesHdd.isFooterVisible());
|
||||
assertEquals("Notes Footer", notesHdd.getFooterText());
|
||||
assertTrue(notesHdd.isHeaderVisible());
|
||||
assertEquals("Notes Header", notesHdd.getHeaderText());
|
||||
assertTrue(notesHdd.isUserDateVisible());
|
||||
assertNull(notesHdd.getDateTimeText());
|
||||
|
||||
Slide[] slide = ppt.getSlides();
|
||||
//the first slide uses presentation-scope headers / footers
|
||||
HeadersFooters hd1 = slide[0].getHeadersFooters();
|
||||
assertEquals(slideHdd.isFooterVisible(), hd1.isFooterVisible());
|
||||
assertEquals(slideHdd.getFooterText(), hd1.getFooterText());
|
||||
assertEquals(slideHdd.isSlideNumberVisible(), hd1.isSlideNumberVisible());
|
||||
assertEquals(slideHdd.isHeaderVisible(), hd1.isHeaderVisible());
|
||||
assertEquals(slideHdd.getHeaderText(), hd1.getHeaderText());
|
||||
assertEquals(slideHdd.isUserDateVisible(), hd1.isUserDateVisible());
|
||||
assertEquals(slideHdd.getDateTimeText(), hd1.getDateTimeText());
|
||||
|
||||
//the first slide uses per-slide headers / footers
|
||||
HeadersFooters hd2 = slide[1].getHeadersFooters();
|
||||
assertEquals(true, hd2.isFooterVisible());
|
||||
assertEquals("per-slide footer", hd2.getFooterText());
|
||||
assertEquals(true, hd2.isUserDateVisible());
|
||||
assertEquals("custom date format", hd2.getDateTimeText());
|
||||
}
|
||||
|
||||
public void testCreateSlideFooters() throws Exception
|
||||
{
|
||||
SlideShow ppt = new SlideShow();
|
||||
HeadersFooters hdd = ppt.getSlideHeadersFooters();
|
||||
hdd.setFootersText("My slide footer");
|
||||
hdd.setSlideNumberVisible(true);
|
||||
|
||||
ByteArrayOutputStream out = new ByteArrayOutputStream();
|
||||
ppt.write(out);
|
||||
byte[] b = out.toByteArray();
|
||||
|
||||
SlideShow ppt2 = new SlideShow(new ByteArrayInputStream(b));
|
||||
HeadersFooters hdd2 = ppt2.getSlideHeadersFooters();
|
||||
assertTrue(hdd2.isSlideNumberVisible());
|
||||
assertTrue(hdd2.isFooterVisible());
|
||||
assertEquals("My slide footer", hdd2.getFooterText());
|
||||
}
|
||||
|
||||
public void testCreateNotesFooters() throws Exception
|
||||
{
|
||||
SlideShow ppt = new SlideShow();
|
||||
HeadersFooters hdd = ppt.getNotesHeadersFooters();
|
||||
hdd.setFootersText("My notes footer");
|
||||
hdd.setHeaderText("My notes header");
|
||||
hdd.setSlideNumberVisible(true);
|
||||
|
||||
ByteArrayOutputStream out = new ByteArrayOutputStream();
|
||||
ppt.write(out);
|
||||
byte[] b = out.toByteArray();
|
||||
|
||||
SlideShow ppt2 = new SlideShow(new ByteArrayInputStream(b));
|
||||
HeadersFooters hdd2 = ppt2.getNotesHeadersFooters();
|
||||
assertTrue(hdd2.isSlideNumberVisible());
|
||||
assertTrue(hdd2.isFooterVisible());
|
||||
assertEquals("My notes footer", hdd2.getFooterText());
|
||||
assertTrue(hdd2.isHeaderVisible());
|
||||
assertEquals("My notes header", hdd2.getHeaderText());
|
||||
}
|
||||
}
|
@ -46,12 +46,12 @@ public class TestCString extends TestCase {
|
||||
}
|
||||
public void testCount() throws Exception {
|
||||
CString ca = new CString(data_a, 0, data_a.length);
|
||||
assertEquals(0, ca.getCount());
|
||||
assertEquals(0, ca.getOptions());
|
||||
CString cb = new CString(data_b, 0, data_a.length);
|
||||
assertEquals(0x10, cb.getCount());
|
||||
assertEquals(0x10, cb.getOptions());
|
||||
|
||||
ca.setCount(28);
|
||||
assertEquals(28, ca.getCount());
|
||||
ca.setOptions(28);
|
||||
assertEquals(28, ca.getOptions());
|
||||
}
|
||||
|
||||
public void testText() throws Exception {
|
||||
@ -90,7 +90,7 @@ public class TestCString extends TestCase {
|
||||
public void testChange() throws Exception {
|
||||
CString ca = new CString(data_a, 0, data_a.length);
|
||||
ca.setText("Comments");
|
||||
ca.setCount(0x10);
|
||||
ca.setOptions(0x10);
|
||||
|
||||
try {
|
||||
for(int i=0; i<data_a.length; i++) {
|
||||
|
@ -0,0 +1,115 @@
|
||||
|
||||
/* ====================================================================
|
||||
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.hslf.record;
|
||||
|
||||
|
||||
import junit.framework.TestCase;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.InputStream;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.Date;
|
||||
|
||||
import javax.imageio.stream.FileImageInputStream;
|
||||
|
||||
import org.apache.poi.hslf.exceptions.CorruptPowerPointFileException;
|
||||
import org.apache.poi.hslf.exceptions.EncryptedPowerPointFileException;
|
||||
import org.apache.poi.poifs.filesystem.DocumentEntry;
|
||||
import org.apache.poi.poifs.filesystem.POIFSFileSystem;
|
||||
|
||||
/**
|
||||
* Tests that CurrentUserAtom works properly.
|
||||
*
|
||||
* @author Nick Burch (nick at torchbox dot com)
|
||||
*/
|
||||
public class TestCurrentUserAtom extends TestCase {
|
||||
/** Not encrypted */
|
||||
private String normalFile;
|
||||
/** Encrypted */
|
||||
private String encFile;
|
||||
|
||||
protected void setUp() throws Exception {
|
||||
super.setUp();
|
||||
|
||||
String dirname = System.getProperty("HSLF.testdata.path");
|
||||
normalFile = dirname + "/basic_test_ppt_file.ppt";
|
||||
encFile = dirname + "/Password_Protected-hello.ppt";
|
||||
}
|
||||
|
||||
public void testReadNormal() throws Exception {
|
||||
POIFSFileSystem fs = new POIFSFileSystem(
|
||||
new FileInputStream(normalFile)
|
||||
);
|
||||
|
||||
CurrentUserAtom cu = new CurrentUserAtom(fs);
|
||||
|
||||
// Check the contents
|
||||
assertEquals("Hogwarts", cu.getLastEditUsername());
|
||||
assertEquals(0x2942, cu.getCurrentEditOffset());
|
||||
|
||||
// Round trip
|
||||
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
||||
cu.writeOut(baos);
|
||||
|
||||
CurrentUserAtom cu2 = new CurrentUserAtom(baos.toByteArray());
|
||||
assertEquals("Hogwarts", cu2.getLastEditUsername());
|
||||
assertEquals(0x2942, cu2.getCurrentEditOffset());
|
||||
}
|
||||
|
||||
public void testReadEnc() throws Exception {
|
||||
POIFSFileSystem fs = new POIFSFileSystem(
|
||||
new FileInputStream(encFile)
|
||||
);
|
||||
|
||||
try {
|
||||
new CurrentUserAtom(fs);
|
||||
fail();
|
||||
} catch(EncryptedPowerPointFileException e) {
|
||||
// Good
|
||||
}
|
||||
}
|
||||
|
||||
public void testWriteNormal() throws Exception {
|
||||
// Get raw contents from a known file
|
||||
POIFSFileSystem fs = new POIFSFileSystem(
|
||||
new FileInputStream(normalFile)
|
||||
);
|
||||
DocumentEntry docProps = (DocumentEntry)fs.getRoot().getEntry("Current User");
|
||||
byte[] contents = new byte[docProps.getSize()];
|
||||
InputStream in = fs.getRoot().createDocumentInputStream("Current User");
|
||||
in.read(contents);
|
||||
|
||||
// Now build up a new one
|
||||
CurrentUserAtom cu = new CurrentUserAtom();
|
||||
cu.setLastEditUsername("Hogwarts");
|
||||
cu.setCurrentEditOffset(0x2942);
|
||||
|
||||
// Check it matches
|
||||
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
||||
cu.writeOut(baos);
|
||||
byte[] out = baos.toByteArray();
|
||||
|
||||
assertEquals(contents.length, out.length);
|
||||
for(int i=0; i<contents.length; i++) {
|
||||
assertEquals("Byte " + i, contents[i], out[i]);
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,95 @@
|
||||
|
||||
/* ====================================================================
|
||||
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.hslf.record;
|
||||
|
||||
|
||||
import junit.framework.TestCase;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.util.Arrays;
|
||||
|
||||
/**
|
||||
* Tests that {@link HeadersFootersAtom} works properly
|
||||
*
|
||||
* @author Yegor Kozlov
|
||||
*/
|
||||
public class TestHeadersFootersAtom extends TestCase {
|
||||
// From a real file
|
||||
private byte[] data = new byte[] {
|
||||
0x00, 0x00, (byte)0xDA, 0x0F, 0x04, 0x00, 0x00, 00,
|
||||
0x00, 0x00, 0x23, 0x00 };
|
||||
|
||||
public void testRead() throws Exception {
|
||||
HeadersFootersAtom record = new HeadersFootersAtom(data, 0, data.length);
|
||||
assertEquals(RecordTypes.HeadersFootersAtom.typeID, record.getRecordType());
|
||||
|
||||
assertEquals(0, record.getFormatId());
|
||||
assertEquals(0x23, record.getMask());
|
||||
|
||||
assertTrue(record.getFlag(HeadersFootersAtom.fHasDate));
|
||||
assertTrue(record.getFlag(HeadersFootersAtom.fHasTodayDate));
|
||||
assertFalse(record.getFlag(HeadersFootersAtom.fHasUserDate));
|
||||
assertFalse(record.getFlag(HeadersFootersAtom.fHasSlideNumber));
|
||||
assertFalse(record.getFlag(HeadersFootersAtom.fHasHeader));
|
||||
assertTrue(record.getFlag(HeadersFootersAtom.fHasFooter));
|
||||
}
|
||||
|
||||
public void testWrite() throws Exception {
|
||||
HeadersFootersAtom record = new HeadersFootersAtom(data, 0, data.length);
|
||||
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
||||
record.writeOut(baos);
|
||||
byte[] b = baos.toByteArray();
|
||||
|
||||
assertTrue(Arrays.equals(data, b));
|
||||
}
|
||||
|
||||
public void testNewRecord() throws Exception {
|
||||
HeadersFootersAtom record = new HeadersFootersAtom();
|
||||
record.setFlag(HeadersFootersAtom.fHasDate, true);
|
||||
record.setFlag(HeadersFootersAtom.fHasTodayDate, true);
|
||||
record.setFlag(HeadersFootersAtom.fHasFooter, true);
|
||||
|
||||
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
||||
record.writeOut(baos);
|
||||
byte[] b = baos.toByteArray();
|
||||
|
||||
assertTrue(Arrays.equals(data, b));
|
||||
}
|
||||
|
||||
public void testFlags() throws Exception {
|
||||
HeadersFootersAtom record = new HeadersFootersAtom();
|
||||
|
||||
//in a new record all the bits are 0
|
||||
for(int i = 0; i < 6; i++) assertFalse(record.getFlag(1 << i));
|
||||
|
||||
record.setFlag(HeadersFootersAtom.fHasTodayDate, true);
|
||||
assertTrue(record.getFlag(HeadersFootersAtom.fHasTodayDate));
|
||||
|
||||
record.setFlag(HeadersFootersAtom.fHasTodayDate, true);
|
||||
assertTrue(record.getFlag(HeadersFootersAtom.fHasTodayDate));
|
||||
|
||||
record.setFlag(HeadersFootersAtom.fHasTodayDate, false);
|
||||
assertFalse(record.getFlag(HeadersFootersAtom.fHasTodayDate));
|
||||
|
||||
record.setFlag(HeadersFootersAtom.fHasTodayDate, false);
|
||||
assertFalse(record.getFlag(HeadersFootersAtom.fHasTodayDate));
|
||||
|
||||
}
|
||||
}
|
@ -0,0 +1,171 @@
|
||||
|
||||
/* ====================================================================
|
||||
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.hslf.record;
|
||||
|
||||
|
||||
import junit.framework.TestCase;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.util.Arrays;
|
||||
|
||||
/**
|
||||
* Tests that {@link HeadersFootersContainer} works properly
|
||||
*
|
||||
* @author Yegor Kozlov
|
||||
*/
|
||||
public class TestHeadersFootersContainer extends TestCase {
|
||||
// SlideHeadersFootersContainer
|
||||
private byte[] slideData = new byte[] {
|
||||
0x3F, 0x00, (byte)0xD9, 0x0F, 0x2E, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, (byte)0xDA, 0x0F, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x23, 0x00,
|
||||
0x20, 0x00, (byte)0xBA, 0x0F, 0x1A, 0x00, 0x00, 0x00,
|
||||
0x4D, 0x00, 0x79, 0x00, 0x20, 0x00, 0x46, 0x00, 0x6F, 0x00, 0x6F, 0x00, 0x74,
|
||||
0x00, 0x65, 0x00, 0x72, 0x00, 0x20, 0x00, 0x2D, 0x00, 0x20, 0x00, 0x31, 0x00
|
||||
|
||||
};
|
||||
|
||||
// NotesHeadersFootersContainer
|
||||
private byte[] notesData = new byte[] {
|
||||
0x4F, 0x00, (byte)0xD9, 0x0F, 0x48, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, (byte)0xDA, 0x0F, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3D, 0x00,
|
||||
0x10, 0x00, (byte)0xBA, 0x0F, 0x16, 0x00, 0x00, 0x00,
|
||||
0x4E, 0x00, 0x6F, 0x00, 0x74, 0x00, 0x65, 0x00, 0x20, 0x00, 0x48, 0x00,
|
||||
0x65, 0x00, 0x61, 0x00, 0x64, 0x00, 0x65, 0x00, 0x72, 0x00,
|
||||
0x20, 0x00, (byte)0xBA, 0x0F, 0x16, 0x00, 0x00, 0x00,
|
||||
0x4E, 0x00, 0x6F, 0x00, 0x74, 0x00, 0x65, 0x00, 0x20, 0x00, 0x46, 0x00,
|
||||
0x6F, 0x00, 0x6F, 0x00, 0x74, 0x00, 0x65, 0x00, 0x72, 0x00
|
||||
};
|
||||
|
||||
public void testReadSlideHeadersFootersContainer() throws Exception {
|
||||
HeadersFootersContainer record = new HeadersFootersContainer(slideData, 0, slideData.length);
|
||||
assertEquals(RecordTypes.HeadersFooters.typeID, record.getRecordType());
|
||||
assertEquals(HeadersFootersContainer.SlideHeadersFootersContainer, record.getOptions());
|
||||
assertEquals(2, record.getChildRecords().length);
|
||||
|
||||
HeadersFootersAtom hdd = record.getHeadersFootersAtom();
|
||||
assertNotNull(hdd);
|
||||
|
||||
CString csFooter = record.getFooterAtom();
|
||||
assertNotNull(csFooter);
|
||||
assertEquals(HeadersFootersContainer.FOOTERATOM, csFooter.getOptions() >> 4);
|
||||
|
||||
assertEquals("My Footer - 1", csFooter.getText());
|
||||
|
||||
assertNull(record.getUserDateAtom());
|
||||
assertNull(record.getHeaderAtom());
|
||||
}
|
||||
|
||||
public void testWriteSlideHeadersFootersContainer() throws Exception {
|
||||
HeadersFootersContainer record = new HeadersFootersContainer(slideData, 0, slideData.length);
|
||||
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
||||
record.writeOut(baos);
|
||||
byte[] b = baos.toByteArray();
|
||||
|
||||
assertTrue(Arrays.equals(slideData, b));
|
||||
}
|
||||
|
||||
public void testNewSlideHeadersFootersContainer() throws Exception {
|
||||
HeadersFootersContainer record = new HeadersFootersContainer(HeadersFootersContainer.SlideHeadersFootersContainer);
|
||||
|
||||
assertNotNull(record.getHeadersFootersAtom());
|
||||
assertNull(record.getUserDateAtom());
|
||||
assertNull(record.getHeaderAtom());
|
||||
assertNull(record.getFooterAtom());
|
||||
|
||||
HeadersFootersAtom hd = record.getHeadersFootersAtom();
|
||||
hd.setFlag(HeadersFootersAtom.fHasDate, true);
|
||||
hd.setFlag(HeadersFootersAtom.fHasTodayDate, true);
|
||||
hd.setFlag(HeadersFootersAtom.fHasFooter, true);
|
||||
|
||||
CString csFooter = record.addFooterAtom();
|
||||
assertNotNull(csFooter);
|
||||
assertEquals(HeadersFootersContainer.FOOTERATOM, csFooter.getOptions() >> 4);
|
||||
csFooter.setText("My Footer - 1");
|
||||
|
||||
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
||||
record.writeOut(baos);
|
||||
byte[] b = baos.toByteArray();
|
||||
|
||||
assertTrue(Arrays.equals(slideData, b));
|
||||
}
|
||||
|
||||
public void testReadNotesHeadersFootersContainer() throws Exception {
|
||||
HeadersFootersContainer record = new HeadersFootersContainer(notesData, 0, notesData.length);
|
||||
assertEquals(RecordTypes.HeadersFooters.typeID, record.getRecordType());
|
||||
assertEquals(HeadersFootersContainer.NotesHeadersFootersContainer, record.getOptions());
|
||||
assertEquals(3, record.getChildRecords().length);
|
||||
|
||||
HeadersFootersAtom hdd = record.getHeadersFootersAtom();
|
||||
assertNotNull(hdd);
|
||||
|
||||
CString csHeader = record.getHeaderAtom();
|
||||
assertNotNull(csHeader);
|
||||
assertEquals(HeadersFootersContainer.HEADERATOM, csHeader.getOptions() >> 4);
|
||||
assertEquals("Note Header", csHeader.getText());
|
||||
|
||||
CString csFooter = record.getFooterAtom();
|
||||
assertNotNull(csFooter);
|
||||
assertEquals(HeadersFootersContainer.FOOTERATOM, csFooter.getOptions() >> 4);
|
||||
assertEquals("Note Footer", csFooter.getText());
|
||||
}
|
||||
|
||||
public void testWriteNotesHeadersFootersContainer() throws Exception {
|
||||
HeadersFootersContainer record = new HeadersFootersContainer(notesData, 0, notesData.length);
|
||||
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
||||
record.writeOut(baos);
|
||||
byte[] b = baos.toByteArray();
|
||||
|
||||
assertTrue(Arrays.equals(notesData, b));
|
||||
}
|
||||
|
||||
public void testNewNotesHeadersFootersContainer() throws Exception {
|
||||
HeadersFootersContainer record = new HeadersFootersContainer(HeadersFootersContainer.NotesHeadersFootersContainer);
|
||||
|
||||
assertNotNull(record.getHeadersFootersAtom());
|
||||
assertNull(record.getUserDateAtom());
|
||||
assertNull(record.getHeaderAtom());
|
||||
assertNull(record.getFooterAtom());
|
||||
|
||||
HeadersFootersAtom hd = record.getHeadersFootersAtom();
|
||||
hd.setFlag(HeadersFootersAtom.fHasDate, true);
|
||||
hd.setFlag(HeadersFootersAtom.fHasTodayDate, false);
|
||||
hd.setFlag(HeadersFootersAtom.fHasUserDate, true);
|
||||
hd.setFlag(HeadersFootersAtom.fHasSlideNumber, true);
|
||||
hd.setFlag(HeadersFootersAtom.fHasHeader, true);
|
||||
hd.setFlag(HeadersFootersAtom.fHasFooter, true);
|
||||
|
||||
CString csHeader = record.addHeaderAtom();
|
||||
assertNotNull(csHeader);
|
||||
assertEquals(HeadersFootersContainer.HEADERATOM, csHeader.getOptions() >> 4);
|
||||
csHeader.setText("Note Header");
|
||||
|
||||
CString csFooter = record.addFooterAtom();
|
||||
assertNotNull(csFooter);
|
||||
assertEquals(HeadersFootersContainer.FOOTERATOM, csFooter.getOptions() >> 4);
|
||||
csFooter.setText("Note Footer");
|
||||
|
||||
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
||||
record.writeOut(baos);
|
||||
byte[] b = baos.toByteArray();
|
||||
|
||||
assertTrue(Arrays.equals(notesData, b));
|
||||
}
|
||||
|
||||
}
|
BIN
src/testcases/org/apache/poi/hssf/data/dvEmpty.xls
Normal file
BIN
src/testcases/org/apache/poi/hssf/data/dvEmpty.xls
Normal file
Binary file not shown.
@ -297,7 +297,8 @@ public final class TestSheet extends TestCase {
|
||||
xfindex = sheet.getXFIndexForColAt((short) 1);
|
||||
assertEquals(DEFAULT_IDX, xfindex);
|
||||
|
||||
ColumnInfoRecord nci = ( ColumnInfoRecord ) sheet.createColInfo();
|
||||
// TODO change return type to ColumnInfoRecord
|
||||
ColumnInfoRecord nci = (ColumnInfoRecord)ColumnInfoRecordsAggregate.createColInfo();
|
||||
sheet.columns.insertColumn(nci);
|
||||
|
||||
// single column ColumnInfoRecord
|
||||
|
@ -17,13 +17,10 @@
|
||||
|
||||
package org.apache.poi.hssf.model;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import junit.framework.TestCase;
|
||||
|
||||
import org.apache.poi.hssf.record.ColumnInfoRecord;
|
||||
import org.apache.poi.hssf.record.aggregates.ColumnInfoRecordsAggregate;
|
||||
|
||||
/**
|
||||
* @author Tony Poppleton
|
||||
@ -32,7 +29,8 @@ public final class TestSheetAdditional extends TestCase {
|
||||
|
||||
public void testGetCellWidth() {
|
||||
Sheet sheet = Sheet.createSheet();
|
||||
ColumnInfoRecord nci = ( ColumnInfoRecord ) sheet.createColInfo();
|
||||
// TODO change return type to ColumnInfoRecord
|
||||
ColumnInfoRecord nci = (ColumnInfoRecord)ColumnInfoRecordsAggregate.createColInfo();
|
||||
|
||||
// Prepare test model
|
||||
nci.setFirstColumn((short)5);
|
||||
|
@ -20,7 +20,7 @@ package org.apache.poi.hssf.record;
|
||||
import junit.framework.AssertionFailedError;
|
||||
import junit.framework.TestCase;
|
||||
|
||||
import org.apache.poi.hssf.record.cf.CellRange;
|
||||
import org.apache.poi.ss.util.CellRangeAddress;
|
||||
|
||||
/**
|
||||
* Tests the serialization and deserialization of the TestCFHeaderRecord
|
||||
@ -34,18 +34,18 @@ public final class TestCFHeaderRecord extends TestCase
|
||||
public void testCreateCFHeaderRecord ()
|
||||
{
|
||||
CFHeaderRecord record = new CFHeaderRecord();
|
||||
CellRange[] ranges = {
|
||||
new CellRange(0,0xFFFF,5,5),
|
||||
new CellRange(0,0xFFFF,6,6),
|
||||
new CellRange(0,1,0,1),
|
||||
new CellRange(0,1,2,3),
|
||||
new CellRange(2,3,0,1),
|
||||
new CellRange(2,3,2,3),
|
||||
CellRangeAddress[] ranges = {
|
||||
new CellRangeAddress(0,0xFFFF,5,5),
|
||||
new CellRangeAddress(0,0xFFFF,6,6),
|
||||
new CellRangeAddress(0,1,0,1),
|
||||
new CellRangeAddress(0,1,2,3),
|
||||
new CellRangeAddress(2,3,0,1),
|
||||
new CellRangeAddress(2,3,2,3),
|
||||
};
|
||||
record.setCellRanges(ranges);
|
||||
ranges = record.getCellRanges();
|
||||
assertEquals(6,ranges.length);
|
||||
CellRange enclosingCellRange = record.getEnclosingCellRange();
|
||||
CellRangeAddress enclosingCellRange = record.getEnclosingCellRange();
|
||||
assertEquals(0, enclosingCellRange.getFirstRow());
|
||||
assertEquals(65535, enclosingCellRange.getLastRow());
|
||||
assertEquals(0, enclosingCellRange.getFirstColumn());
|
||||
@ -95,7 +95,7 @@ public final class TestCFHeaderRecord extends TestCase
|
||||
assertEquals("#CFRULES", 3, record.getNumberOfConditionalFormats());
|
||||
assertTrue(record.getNeedRecalculation());
|
||||
confirm(record.getEnclosingCellRange(), 0, 3, 0, 3);
|
||||
CellRange[] ranges = record.getCellRanges();
|
||||
CellRangeAddress[] ranges = record.getCellRanges();
|
||||
assertEquals(4, ranges.length);
|
||||
confirm(ranges[0], 0, 1, 0, 1);
|
||||
confirm(ranges[1], 0, 1, 2, 3);
|
||||
@ -154,7 +154,7 @@ public final class TestCFHeaderRecord extends TestCase
|
||||
assertEquals("#CFRULES", 19, record.getNumberOfConditionalFormats());
|
||||
assertFalse(record.getNeedRecalculation());
|
||||
confirm(record.getEnclosingCellRange(), 0, 65535, 0, 255);
|
||||
CellRange[] ranges = record.getCellRanges();
|
||||
CellRangeAddress[] ranges = record.getCellRanges();
|
||||
assertEquals(3, ranges.length);
|
||||
confirm(ranges[0], 40000, 50000, 2, 2);
|
||||
confirm(ranges[1], 0, 65535, 5, 5);
|
||||
@ -169,17 +169,10 @@ public final class TestCFHeaderRecord extends TestCase
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private static void confirm(CellRange cr, int expFirstRow, int expLastRow, int expFirstCol, int expLastColumn) {
|
||||
private static void confirm(CellRangeAddress cr, int expFirstRow, int expLastRow, int expFirstCol, int expLastColumn) {
|
||||
assertEquals("first row", expFirstRow, cr.getFirstRow());
|
||||
assertEquals("last row", expLastRow, cr.getLastRow());
|
||||
assertEquals("first column", expFirstCol, cr.getFirstColumn());
|
||||
assertEquals("last column", expLastColumn, cr.getLastColumn());
|
||||
}
|
||||
|
||||
public static void main(String[] ignored_args)
|
||||
{
|
||||
System.out.println("Testing org.apache.poi.hssf.record.CFHeaderRecord");
|
||||
junit.textui.TestRunner.run(TestCFHeaderRecord.class);
|
||||
}
|
||||
}
|
||||
|
@ -1,4 +1,3 @@
|
||||
|
||||
/* ====================================================================
|
||||
Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
contributor license agreements. See the NOTICE file distributed with
|
||||
@ -20,14 +19,14 @@ package org.apache.poi.hssf.record;
|
||||
|
||||
import junit.framework.TestCase;
|
||||
|
||||
import org.apache.poi.hssf.record.MergeCellsRecord.MergedRegion;
|
||||
import org.apache.poi.ss.util.CellRangeAddress;
|
||||
|
||||
/**
|
||||
* Make sure the merge cells record behaves
|
||||
* @author Danny Mui (dmui at apache dot org)
|
||||
*
|
||||
*/
|
||||
public class TestMergeCellsRecord extends TestCase {
|
||||
public final class TestMergeCellsRecord extends TestCase {
|
||||
|
||||
/**
|
||||
* Make sure when a clone is called, we actually clone it.
|
||||
@ -40,13 +39,13 @@ public class TestMergeCellsRecord extends TestCase {
|
||||
|
||||
assertNotSame("Merged and cloned objects are the same", merge, clone);
|
||||
|
||||
MergedRegion mergeRegion = merge.getAreaAt(0);
|
||||
MergedRegion cloneRegion = clone.getAreaAt(0);
|
||||
CellRangeAddress mergeRegion = merge.getAreaAt(0);
|
||||
CellRangeAddress cloneRegion = clone.getAreaAt(0);
|
||||
assertNotSame("Should not point to same objects when cloning", mergeRegion, cloneRegion);
|
||||
assertEquals("New Clone Row From doesnt match", mergeRegion.row_from, cloneRegion.row_from);
|
||||
assertEquals("New Clone Row To doesnt match", mergeRegion.row_to, cloneRegion.row_to);
|
||||
assertEquals("New Clone Col From doesnt match", mergeRegion.col_from, cloneRegion.col_from);
|
||||
assertEquals("New Clone Col To doesnt match", mergeRegion.col_to, cloneRegion.col_to);
|
||||
assertEquals("New Clone Row From doesnt match", mergeRegion.getFirstRow(), cloneRegion.getFirstRow());
|
||||
assertEquals("New Clone Row To doesnt match", mergeRegion.getLastRow(), cloneRegion.getLastRow());
|
||||
assertEquals("New Clone Col From doesnt match", mergeRegion.getFirstColumn(), cloneRegion.getFirstColumn());
|
||||
assertEquals("New Clone Col To doesnt match", mergeRegion.getLastColumn(), cloneRegion.getLastColumn());
|
||||
|
||||
merge.removeAreaAt(0);
|
||||
assertNotNull("Clone's item not removed", clone.getAreaAt(0));
|
||||
|
@ -28,8 +28,8 @@ import org.apache.poi.hssf.record.CFHeaderRecord;
|
||||
import org.apache.poi.hssf.record.CFRuleRecord;
|
||||
import org.apache.poi.hssf.record.RecordFactory;
|
||||
import org.apache.poi.hssf.record.CFRuleRecord.ComparisonOperator;
|
||||
import org.apache.poi.hssf.record.cf.CellRange;
|
||||
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
|
||||
import org.apache.poi.ss.util.CellRangeAddress;
|
||||
|
||||
/**
|
||||
* Tests the serialization and deserialization of the CFRecordsAggregate
|
||||
@ -49,9 +49,9 @@ public final class TestCFRecordsAggregate extends TestCase
|
||||
CFRuleRecord rule2 = CFRuleRecord.create(workbook, ComparisonOperator.BETWEEN, "2", "5");
|
||||
CFRuleRecord rule3 = CFRuleRecord.create(workbook, ComparisonOperator.GE, "100", null);
|
||||
header.setNumberOfConditionalFormats(3);
|
||||
CellRange[] cellRanges = {
|
||||
new CellRange(0,1,0,0),
|
||||
new CellRange(0,1,2,2),
|
||||
CellRangeAddress[] cellRanges = {
|
||||
new CellRangeAddress(0,1,0,0),
|
||||
new CellRangeAddress(0,1,2,2),
|
||||
};
|
||||
header.setCellRanges(cellRanges);
|
||||
recs.add(header);
|
||||
@ -97,11 +97,4 @@ public final class TestCFRecordsAggregate extends TestCase
|
||||
assertEquals(2, cellRanges.length);
|
||||
assertEquals(3, header.getNumberOfConditionalFormats());
|
||||
}
|
||||
|
||||
public static void main(String[] ignored_args)
|
||||
{
|
||||
System.out.println("Testing org.apache.poi.hssf.record.aggregates.CFRecordsAggregate");
|
||||
junit.textui.TestRunner.run(TestCFRecordsAggregate.class);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -17,6 +17,8 @@ limitations under the License.
|
||||
|
||||
package org.apache.poi.hssf.record.cf;
|
||||
|
||||
import org.apache.poi.ss.util.CellRangeAddress;
|
||||
|
||||
import junit.framework.AssertionFailedError;
|
||||
import junit.framework.TestCase;
|
||||
|
||||
@ -25,15 +27,15 @@ import junit.framework.TestCase;
|
||||
*/
|
||||
public final class TestCellRange extends TestCase
|
||||
{
|
||||
private static final CellRange biggest = createCR( 0, -1, 0,-1);
|
||||
private static final CellRange tenthColumn = createCR( 0, -1,10,10);
|
||||
private static final CellRange tenthRow = createCR(10, 10, 0,-1);
|
||||
private static final CellRange box10x10 = createCR( 0, 10, 0,10);
|
||||
private static final CellRange box9x9 = createCR( 0, 9, 0, 9);
|
||||
private static final CellRange box10to20c = createCR( 0, 10,10,20);
|
||||
private static final CellRange oneCell = createCR(10, 10,10,10);
|
||||
private static final CellRangeAddress biggest = createCR( 0, -1, 0,-1);
|
||||
private static final CellRangeAddress tenthColumn = createCR( 0, -1,10,10);
|
||||
private static final CellRangeAddress tenthRow = createCR(10, 10, 0,-1);
|
||||
private static final CellRangeAddress box10x10 = createCR( 0, 10, 0,10);
|
||||
private static final CellRangeAddress box9x9 = createCR( 0, 9, 0, 9);
|
||||
private static final CellRangeAddress box10to20c = createCR( 0, 10,10,20);
|
||||
private static final CellRangeAddress oneCell = createCR(10, 10,10,10);
|
||||
|
||||
private static final CellRange[] sampleRanges = {
|
||||
private static final CellRangeAddress[] sampleRanges = {
|
||||
biggest, tenthColumn, tenthRow, box10x10, box9x9, box10to20c, oneCell,
|
||||
};
|
||||
|
||||
@ -54,9 +56,9 @@ public final class TestCellRange extends TestCase
|
||||
* @param lastRow pass -1 for max row index
|
||||
* @param lastCol pass -1 for max col index
|
||||
*/
|
||||
private static CellRange createCR(int firstRow, int lastRow, int firstCol, int lastCol) {
|
||||
private static CellRangeAddress createCR(int firstRow, int lastRow, int firstCol, int lastCol) {
|
||||
// max row & max col limit as per BIFF8
|
||||
return new CellRange(
|
||||
return new CellRangeAddress(
|
||||
firstRow,
|
||||
lastRow == -1 ? 0xFFFF : lastRow,
|
||||
firstCol,
|
||||
@ -65,89 +67,89 @@ public final class TestCellRange extends TestCase
|
||||
|
||||
public void testContainsMethod()
|
||||
{
|
||||
CellRange [] ranges = sampleRanges;
|
||||
CellRangeAddress [] ranges = sampleRanges;
|
||||
for(int i=0; i!=ranges.length;i++)
|
||||
{
|
||||
for(int j=0; j!=ranges.length;j++)
|
||||
{
|
||||
boolean expectedResult = containsExpectedResults[i][j];
|
||||
assertEquals("("+i+","+j+"): ", expectedResult, ranges[i].contains(ranges[j]));
|
||||
assertEquals("("+i+","+j+"): ", expectedResult, CellRangeUtil.contains(ranges[i], ranges[j]));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static final CellRange col1 = createCR( 0, -1, 1,1);
|
||||
private static final CellRange col2 = createCR( 0, -1, 2,2);
|
||||
private static final CellRange row1 = createCR( 1, 1, 0,-1);
|
||||
private static final CellRange row2 = createCR( 2, 2, 0,-1);
|
||||
private static final CellRangeAddress col1 = createCR( 0, -1, 1,1);
|
||||
private static final CellRangeAddress col2 = createCR( 0, -1, 2,2);
|
||||
private static final CellRangeAddress row1 = createCR( 1, 1, 0,-1);
|
||||
private static final CellRangeAddress row2 = createCR( 2, 2, 0,-1);
|
||||
|
||||
private static final CellRange box0 = createCR( 0, 2, 0,2);
|
||||
private static final CellRange box1 = createCR( 0, 1, 0,1);
|
||||
private static final CellRange box2 = createCR( 0, 1, 2,3);
|
||||
private static final CellRange box3 = createCR( 2, 3, 0,1);
|
||||
private static final CellRange box4 = createCR( 2, 3, 2,3);
|
||||
private static final CellRange box5 = createCR( 1, 3, 1,3);
|
||||
private static final CellRangeAddress box0 = createCR( 0, 2, 0,2);
|
||||
private static final CellRangeAddress box1 = createCR( 0, 1, 0,1);
|
||||
private static final CellRangeAddress box2 = createCR( 0, 1, 2,3);
|
||||
private static final CellRangeAddress box3 = createCR( 2, 3, 0,1);
|
||||
private static final CellRangeAddress box4 = createCR( 2, 3, 2,3);
|
||||
private static final CellRangeAddress box5 = createCR( 1, 3, 1,3);
|
||||
|
||||
public void testHasSharedBorderMethod()
|
||||
{
|
||||
assertFalse(col1.hasExactSharedBorder(col1));
|
||||
assertFalse(col2.hasExactSharedBorder(col2));
|
||||
assertTrue(col1.hasExactSharedBorder(col2));
|
||||
assertTrue(col2.hasExactSharedBorder(col1));
|
||||
assertFalse(CellRangeUtil.hasExactSharedBorder(col1, col1));
|
||||
assertFalse(CellRangeUtil.hasExactSharedBorder(col2, col2));
|
||||
assertTrue(CellRangeUtil.hasExactSharedBorder(col1, col2));
|
||||
assertTrue(CellRangeUtil.hasExactSharedBorder(col2, col1));
|
||||
|
||||
assertFalse(row1.hasExactSharedBorder(row1));
|
||||
assertFalse(row2.hasExactSharedBorder(row2));
|
||||
assertTrue(row1.hasExactSharedBorder(row2));
|
||||
assertTrue(row2.hasExactSharedBorder(row1));
|
||||
assertFalse(CellRangeUtil.hasExactSharedBorder(row1, row1));
|
||||
assertFalse(CellRangeUtil.hasExactSharedBorder(row2, row2));
|
||||
assertTrue(CellRangeUtil.hasExactSharedBorder(row1, row2));
|
||||
assertTrue(CellRangeUtil.hasExactSharedBorder(row2, row1));
|
||||
|
||||
assertFalse(row1.hasExactSharedBorder(col1));
|
||||
assertFalse(row1.hasExactSharedBorder(col2));
|
||||
assertFalse(col1.hasExactSharedBorder(row1));
|
||||
assertFalse(col2.hasExactSharedBorder(row1));
|
||||
assertFalse(row2.hasExactSharedBorder(col1));
|
||||
assertFalse(row2.hasExactSharedBorder(col2));
|
||||
assertFalse(col1.hasExactSharedBorder(row2));
|
||||
assertFalse(col2.hasExactSharedBorder(row2));
|
||||
assertTrue(col2.hasExactSharedBorder(col1));
|
||||
assertFalse(CellRangeUtil.hasExactSharedBorder(row1, col1));
|
||||
assertFalse(CellRangeUtil.hasExactSharedBorder(row1, col2));
|
||||
assertFalse(CellRangeUtil.hasExactSharedBorder(col1, row1));
|
||||
assertFalse(CellRangeUtil.hasExactSharedBorder(col2, row1));
|
||||
assertFalse(CellRangeUtil.hasExactSharedBorder(row2, col1));
|
||||
assertFalse(CellRangeUtil.hasExactSharedBorder(row2, col2));
|
||||
assertFalse(CellRangeUtil.hasExactSharedBorder(col1, row2));
|
||||
assertFalse(CellRangeUtil.hasExactSharedBorder(col2, row2));
|
||||
assertTrue(CellRangeUtil.hasExactSharedBorder(col2, col1));
|
||||
|
||||
assertFalse(box1.hasExactSharedBorder(box1));
|
||||
assertTrue(box1.hasExactSharedBorder(box2));
|
||||
assertTrue(box1.hasExactSharedBorder(box3));
|
||||
assertFalse(box1.hasExactSharedBorder(box4));
|
||||
assertFalse(CellRangeUtil.hasExactSharedBorder(box1, box1));
|
||||
assertTrue(CellRangeUtil.hasExactSharedBorder(box1, box2));
|
||||
assertTrue(CellRangeUtil.hasExactSharedBorder(box1, box3));
|
||||
assertFalse(CellRangeUtil.hasExactSharedBorder(box1, box4));
|
||||
|
||||
assertTrue(box2.hasExactSharedBorder(box1));
|
||||
assertFalse(box2.hasExactSharedBorder(box2));
|
||||
assertFalse(box2.hasExactSharedBorder(box3));
|
||||
assertTrue(box2.hasExactSharedBorder(box4));
|
||||
assertTrue(CellRangeUtil.hasExactSharedBorder(box2, box1));
|
||||
assertFalse(CellRangeUtil.hasExactSharedBorder(box2, box2));
|
||||
assertFalse(CellRangeUtil.hasExactSharedBorder(box2, box3));
|
||||
assertTrue(CellRangeUtil.hasExactSharedBorder(box2, box4));
|
||||
|
||||
assertTrue(box3.hasExactSharedBorder(box1));
|
||||
assertFalse(box3.hasExactSharedBorder(box2));
|
||||
assertFalse(box3.hasExactSharedBorder(box3));
|
||||
assertTrue(box3.hasExactSharedBorder(box4));
|
||||
assertTrue(CellRangeUtil.hasExactSharedBorder(box3, box1));
|
||||
assertFalse(CellRangeUtil.hasExactSharedBorder(box3, box2));
|
||||
assertFalse(CellRangeUtil.hasExactSharedBorder(box3, box3));
|
||||
assertTrue(CellRangeUtil.hasExactSharedBorder(box3, box4));
|
||||
|
||||
assertFalse(box4.hasExactSharedBorder(box1));
|
||||
assertTrue(box4.hasExactSharedBorder(box2));
|
||||
assertTrue(box4.hasExactSharedBorder(box3));
|
||||
assertFalse(box4.hasExactSharedBorder(box4));
|
||||
assertFalse(CellRangeUtil.hasExactSharedBorder(box4, box1));
|
||||
assertTrue(CellRangeUtil.hasExactSharedBorder(box4, box2));
|
||||
assertTrue(CellRangeUtil.hasExactSharedBorder(box4, box3));
|
||||
assertFalse(CellRangeUtil.hasExactSharedBorder(box4, box4));
|
||||
}
|
||||
|
||||
public void testIntersectMethod()
|
||||
{
|
||||
assertEquals(CellRange.OVERLAP,box0.intersect(box5));
|
||||
assertEquals(CellRange.OVERLAP,box5.intersect(box0));
|
||||
assertEquals(CellRange.NO_INTERSECTION,box1.intersect(box4));
|
||||
assertEquals(CellRange.NO_INTERSECTION,box4.intersect(box1));
|
||||
assertEquals(CellRange.NO_INTERSECTION,box2.intersect(box3));
|
||||
assertEquals(CellRange.NO_INTERSECTION,box3.intersect(box2));
|
||||
assertEquals(CellRange.INSIDE,box0.intersect(box1));
|
||||
assertEquals(CellRange.INSIDE,box0.intersect(box0));
|
||||
assertEquals(CellRange.ENCLOSES,box1.intersect(box0));
|
||||
assertEquals(CellRange.INSIDE,tenthColumn.intersect(oneCell));
|
||||
assertEquals(CellRange.ENCLOSES,oneCell.intersect(tenthColumn));
|
||||
assertEquals(CellRange.OVERLAP,tenthColumn.intersect(tenthRow));
|
||||
assertEquals(CellRange.OVERLAP,tenthRow.intersect(tenthColumn));
|
||||
assertEquals(CellRange.INSIDE,tenthColumn.intersect(tenthColumn));
|
||||
assertEquals(CellRange.INSIDE,tenthRow.intersect(tenthRow));
|
||||
assertEquals(CellRangeUtil.OVERLAP, CellRangeUtil.intersect(box0, box5));
|
||||
assertEquals(CellRangeUtil.OVERLAP, CellRangeUtil.intersect(box5, box0));
|
||||
assertEquals(CellRangeUtil.NO_INTERSECTION, CellRangeUtil.intersect(box1, box4));
|
||||
assertEquals(CellRangeUtil.NO_INTERSECTION, CellRangeUtil.intersect(box4, box1));
|
||||
assertEquals(CellRangeUtil.NO_INTERSECTION, CellRangeUtil.intersect(box2, box3));
|
||||
assertEquals(CellRangeUtil.NO_INTERSECTION, CellRangeUtil.intersect(box3, box2));
|
||||
assertEquals(CellRangeUtil.INSIDE, CellRangeUtil.intersect(box0, box1));
|
||||
assertEquals(CellRangeUtil.INSIDE, CellRangeUtil.intersect(box0, box0));
|
||||
assertEquals(CellRangeUtil.ENCLOSES, CellRangeUtil.intersect(box1, box0));
|
||||
assertEquals(CellRangeUtil.INSIDE, CellRangeUtil.intersect(tenthColumn, oneCell));
|
||||
assertEquals(CellRangeUtil.ENCLOSES, CellRangeUtil.intersect(oneCell, tenthColumn));
|
||||
assertEquals(CellRangeUtil.OVERLAP, CellRangeUtil.intersect(tenthColumn, tenthRow));
|
||||
assertEquals(CellRangeUtil.OVERLAP, CellRangeUtil.intersect(tenthRow, tenthColumn));
|
||||
assertEquals(CellRangeUtil.INSIDE, CellRangeUtil.intersect(tenthColumn, tenthColumn));
|
||||
assertEquals(CellRangeUtil.INSIDE, CellRangeUtil.intersect(tenthRow, tenthRow));
|
||||
}
|
||||
|
||||
/**
|
||||
@ -155,7 +157,7 @@ public final class TestCellRange extends TestCase
|
||||
* =$C:$IV,$B$1:$B$8,$B$10:$B$65536,$A:$A
|
||||
*/
|
||||
public void testCreate() {
|
||||
CellRange cr;
|
||||
CellRangeAddress cr;
|
||||
|
||||
cr = createCR(0, -1, 2, 255); // $C:$IV
|
||||
confirmRange(cr, false, true);
|
||||
@ -172,7 +174,7 @@ public final class TestCellRange extends TestCase
|
||||
cr = createCR(0, -1, 0, 0); // $A:$A
|
||||
}
|
||||
|
||||
private static void confirmRange(CellRange cr, boolean isFullRow, boolean isFullColumn) {
|
||||
private static void confirmRange(CellRangeAddress cr, boolean isFullRow, boolean isFullColumn) {
|
||||
assertEquals("isFullRowRange", isFullRow, cr.isFullRowRange());
|
||||
assertEquals("isFullColumnRange", isFullColumn, cr.isFullColumnRange());
|
||||
}
|
||||
|
131
src/testcases/org/apache/poi/hssf/usermodel/StreamUtility.java
Normal file
131
src/testcases/org/apache/poi/hssf/usermodel/StreamUtility.java
Normal file
@ -0,0 +1,131 @@
|
||||
/* ====================================================================
|
||||
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.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Utility class to help test code verify that generated files do not differ from proof copies in
|
||||
* any significant detail. Normally this task would be simple except for the presence of artifacts
|
||||
* in the file that change every time it is generated. Usually these volatile artifacts are
|
||||
* time-stamps, user names, or other machine dependent parameters.
|
||||
*
|
||||
* @author Josh Micich
|
||||
*/
|
||||
public final class StreamUtility {
|
||||
|
||||
/**
|
||||
* Compares two streams with expected differences in specified regions. The streams are
|
||||
* expected to be of equal length and comparison is always byte for byte. That is -
|
||||
* differences can only involve exchanging each individual byte for another single byte.<br>
|
||||
* Both input streams are closed.
|
||||
*
|
||||
* @param allowableDifferenceRegions array of integer pairs: (offset, length).
|
||||
* Any differences encountered in these regions of the streams will be ignored
|
||||
* @return <code>null</code> if streams are identical, else the
|
||||
* byte indexes of differing data. If streams were different lengths,
|
||||
* the returned indexes will be -1 and the length of the shorter stream
|
||||
*/
|
||||
public static int[] diffStreams(InputStream isA, InputStream isB, int[] allowableDifferenceRegions) {
|
||||
|
||||
if((allowableDifferenceRegions.length % 2) != 0) {
|
||||
throw new RuntimeException("allowableDifferenceRegions length is odd");
|
||||
}
|
||||
boolean success = false;
|
||||
int[] result;
|
||||
try {
|
||||
result = diffInternal(isA, isB, allowableDifferenceRegions);
|
||||
success = true;
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
} finally {
|
||||
close(isA, success);
|
||||
close(isB, success);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param success <code>false</code> if the outer method is throwing an exception.
|
||||
*/
|
||||
private static void close(InputStream is, boolean success) {
|
||||
try {
|
||||
is.close();
|
||||
} catch (IOException e) {
|
||||
if(success) {
|
||||
// this is a new error. ok to throw
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
// else don't subvert original exception. just print stack trace for this one
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
private static int[] diffInternal(InputStream isA, InputStream isB, int[] allowableDifferenceRegions)
|
||||
throws IOException {
|
||||
int offset = 0;
|
||||
List temp = new ArrayList();
|
||||
while (true) {
|
||||
int b = isA.read();
|
||||
int b2 = isB.read();
|
||||
if (b == -1) {
|
||||
// EOF
|
||||
if (b2 == -1) {
|
||||
return toPrimitiveIntArray(temp);
|
||||
}
|
||||
return new int[] { -1, offset, };
|
||||
}
|
||||
if (b2 == -1) {
|
||||
return new int[] { -1, offset, };
|
||||
}
|
||||
if (b != b2 && !isIgnoredRegion(allowableDifferenceRegions, offset)) {
|
||||
temp.add(new Integer(offset));
|
||||
}
|
||||
offset++;
|
||||
}
|
||||
}
|
||||
|
||||
private static boolean isIgnoredRegion(int[] allowableDifferenceRegions, int offset) {
|
||||
for (int i = 0; i < allowableDifferenceRegions.length; i+=2) {
|
||||
int start = allowableDifferenceRegions[i];
|
||||
int end = start + allowableDifferenceRegions[i+1];
|
||||
if(start <= offset && offset < end) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private static int[] toPrimitiveIntArray(List temp) {
|
||||
int nItems = temp.size();
|
||||
if(nItems < 1) {
|
||||
return null;
|
||||
}
|
||||
Integer[] boxInts = new Integer[nItems];
|
||||
temp.toArray(boxInts);
|
||||
|
||||
int[] result = new int[nItems];
|
||||
for (int i = 0; i < result.length; i++) {
|
||||
result[i] = boxInts[i].intValue();
|
||||
}
|
||||
return result;
|
||||
}
|
||||
}
|
@ -28,6 +28,7 @@ import junit.framework.AssertionFailedError;
|
||||
import junit.framework.TestCase;
|
||||
|
||||
import org.apache.poi.ss.util.Region;
|
||||
import org.apache.poi.ss.util.CellRangeAddress;
|
||||
|
||||
import org.apache.poi.hssf.HSSFTestDataSamples;
|
||||
import org.apache.poi.hssf.model.Workbook;
|
||||
@ -302,15 +303,14 @@ public final class TestBugs extends TestCase {
|
||||
|
||||
/**
|
||||
* Merged regions were being removed from the parent in cloned sheets
|
||||
* @throws Exception
|
||||
*/
|
||||
public void test22720() {
|
||||
HSSFWorkbook workBook = new HSSFWorkbook();
|
||||
workBook.createSheet("TEST");
|
||||
HSSFSheet template = workBook.getSheetAt(0);
|
||||
|
||||
template.addMergedRegion(new Region(0, (short)0, 1, (short)2));
|
||||
template.addMergedRegion(new Region(1, (short)0, 2, (short)2));
|
||||
template.addMergedRegion(new CellRangeAddress(0, 1, 0, 2));
|
||||
template.addMergedRegion(new CellRangeAddress(1, 2, 0, 2));
|
||||
|
||||
HSSFSheet clone = workBook.cloneSheet(0);
|
||||
int originalMerged = template.getNumMergedRegions();
|
||||
@ -325,13 +325,13 @@ public final class TestBugs extends TestCase {
|
||||
// check if template's merged regions are OK
|
||||
if (template.getNumMergedRegions()>0) {
|
||||
// fetch the first merged region...EXCEPTION OCCURS HERE
|
||||
template.getMergedRegionAt(0);
|
||||
template.getMergedRegion(0);
|
||||
}
|
||||
//make sure we dont exception
|
||||
|
||||
}
|
||||
|
||||
/*Tests read and write of Unicode strings in formula results
|
||||
/**Tests read and write of Unicode strings in formula results
|
||||
* bug and testcase submitted by Sompop Kumnoonsate
|
||||
* The file contains THAI unicode characters.
|
||||
*/
|
||||
|
@ -21,6 +21,7 @@ package org.apache.poi.hssf.usermodel;
|
||||
|
||||
import junit.framework.TestCase;
|
||||
|
||||
import org.apache.poi.ss.util.CellRangeAddress;
|
||||
import org.apache.poi.ss.util.Region;
|
||||
|
||||
/**
|
||||
@ -29,23 +30,15 @@ import org.apache.poi.ss.util.Region;
|
||||
* add that record to the sheet in the testCloneSheetBasic method.
|
||||
* @author avik
|
||||
*/
|
||||
public class TestCloneSheet extends TestCase {
|
||||
|
||||
public TestCloneSheet(String arg0) {
|
||||
super(arg0);
|
||||
}
|
||||
public final class TestCloneSheet extends TestCase {
|
||||
|
||||
public void testCloneSheetBasic(){
|
||||
try{
|
||||
HSSFWorkbook b = new HSSFWorkbook();
|
||||
HSSFSheet s = b.createSheet("Test");
|
||||
s.addMergedRegion(new Region((short)0,(short)0,(short)1,(short)1));
|
||||
s.addMergedRegion(new CellRangeAddress(0, 1, 0, 1));
|
||||
HSSFSheet clonedSheet = b.cloneSheet(0);
|
||||
|
||||
assertEquals("One merged area", 1, clonedSheet.getNumMergedRegions());
|
||||
|
||||
}
|
||||
catch(Exception e){e.printStackTrace();fail(e.getMessage());}
|
||||
}
|
||||
|
||||
/**
|
||||
@ -66,5 +59,4 @@ public class TestCloneSheet extends TestCase {
|
||||
|
||||
assertTrue("Row 3 still should be broken", clone.isRowBroken(3));
|
||||
}
|
||||
|
||||
}
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -176,4 +176,37 @@ public final class TestHSSFComment extends TestCase {
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public void testDeleteComments() throws Exception {
|
||||
HSSFWorkbook wb = HSSFTestDataSamples.openSampleWorkbook("SimpleWithComments.xls");
|
||||
HSSFSheet sheet = wb.getSheetAt(0);
|
||||
|
||||
// Zap from rows 1 and 3
|
||||
assertNotNull(sheet.getRow(0).getCell(1).getCellComment());
|
||||
assertNotNull(sheet.getRow(1).getCell(1).getCellComment());
|
||||
assertNotNull(sheet.getRow(2).getCell(1).getCellComment());
|
||||
|
||||
sheet.getRow(0).getCell(1).removeCellComment();
|
||||
sheet.getRow(2).getCell(1).setCellComment(null);
|
||||
|
||||
// Check gone so far
|
||||
assertNull(sheet.getRow(0).getCell(1).getCellComment());
|
||||
assertNotNull(sheet.getRow(1).getCell(1).getCellComment());
|
||||
assertNull(sheet.getRow(2).getCell(1).getCellComment());
|
||||
|
||||
// Save and re-load
|
||||
ByteArrayOutputStream out = new ByteArrayOutputStream();
|
||||
wb.write(out);
|
||||
out.close();
|
||||
wb = new HSSFWorkbook(new ByteArrayInputStream(out.toByteArray()));
|
||||
|
||||
// Check
|
||||
assertNull(sheet.getRow(0).getCell(1).getCellComment());
|
||||
assertNotNull(sheet.getRow(1).getCell(1).getCellComment());
|
||||
assertNull(sheet.getRow(2).getCell(1).getCellComment());
|
||||
|
||||
// FileOutputStream fout = new FileOutputStream("/tmp/c.xls");
|
||||
// wb.write(fout);
|
||||
// fout.close();
|
||||
}
|
||||
}
|
||||
|
@ -21,7 +21,9 @@ import junit.framework.TestCase;
|
||||
|
||||
import org.apache.poi.hssf.record.CFRuleRecord.ComparisonOperator;
|
||||
import org.apache.poi.hssf.util.HSSFColor;
|
||||
import org.apache.poi.ss.util.CellRangeAddress;
|
||||
import org.apache.poi.ss.util.Region;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Dmitriy Kumshayev
|
||||
@ -57,9 +59,8 @@ public final class TestHSSFConditionalFormatting extends TestCase
|
||||
};
|
||||
|
||||
short col = 1;
|
||||
Region [] regions =
|
||||
{
|
||||
new Region(0,col,65535,col)
|
||||
CellRangeAddress [] regions = {
|
||||
new CellRangeAddress(0, 65535, col, col)
|
||||
};
|
||||
|
||||
sheetCF.addConditionalFormatting(regions, cfRules);
|
||||
@ -72,14 +73,14 @@ public final class TestHSSFConditionalFormatting extends TestCase
|
||||
HSSFConditionalFormatting cf = sheetCF.getConditionalFormattingAt(0);
|
||||
assertNotNull(cf);
|
||||
|
||||
regions = cf.getFormattingRegions();
|
||||
regions = cf.getFormattingRanges();
|
||||
assertNotNull(regions);
|
||||
assertEquals(1, regions.length);
|
||||
Region r = regions[0];
|
||||
assertEquals(1, r.getColumnFrom());
|
||||
assertEquals(1, r.getColumnTo());
|
||||
assertEquals(0, r.getRowFrom());
|
||||
assertEquals(65535, r.getRowTo());
|
||||
CellRangeAddress r = regions[0];
|
||||
assertEquals(1, r.getFirstColumn());
|
||||
assertEquals(1, r.getLastColumn());
|
||||
assertEquals(0, r.getFirstRow());
|
||||
assertEquals(65535, r.getLastRow());
|
||||
|
||||
assertEquals(2, cf.getNumberOfRules());
|
||||
|
||||
|
@ -19,6 +19,7 @@ package org.apache.poi.hssf.usermodel;
|
||||
|
||||
import java.text.DecimalFormat;
|
||||
import java.text.Format;
|
||||
import java.util.Date;
|
||||
import java.util.Iterator;
|
||||
|
||||
import junit.framework.TestCase;
|
||||
|
@ -39,7 +39,7 @@ import org.apache.poi.hssf.model.Workbook;
|
||||
* @author Alex Jacoby (ajacoby at gmail.com)
|
||||
* @version %I%, %G%
|
||||
*/
|
||||
public class TestHSSFDateUtil extends TestCase {
|
||||
public final class TestHSSFDateUtil extends TestCase {
|
||||
|
||||
public static final int CALENDAR_JANUARY = 0;
|
||||
public static final int CALENDAR_FEBRUARY = 1;
|
||||
@ -48,11 +48,6 @@ public class TestHSSFDateUtil extends TestCase {
|
||||
public static final int CALENDAR_JULY = 6;
|
||||
public static final int CALENDAR_OCTOBER = 9;
|
||||
|
||||
public TestHSSFDateUtil(String s)
|
||||
{
|
||||
super(s);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks the date conversion functions in the HSSFDateUtil class.
|
||||
*/
|
||||
@ -193,14 +188,13 @@ public class TestHSSFDateUtil extends TestCase {
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests that we deal with timezones properly
|
||||
* Tests that we deal with time-zones properly
|
||||
*/
|
||||
public void testCalendarConversion() {
|
||||
GregorianCalendar date = new GregorianCalendar(2002, 0, 1, 12, 1, 1);
|
||||
Date expected = date.getTime();
|
||||
double expectedExcel = HSSFDateUtil.getExcelDate(expected);
|
||||
|
||||
// Iteratating over the hours exposes any rounding issues.
|
||||
// Iterating over the hours exposes any rounding issues.
|
||||
for (int hour = -12; hour <= 12; hour++)
|
||||
{
|
||||
String id = "GMT" + (hour < 0 ? "" : "+") + hour + ":00";
|
||||
@ -209,7 +203,7 @@ public class TestHSSFDateUtil extends TestCase {
|
||||
double excelDate = HSSFDateUtil.getExcelDate(date, false);
|
||||
Date javaDate = HSSFDateUtil.getJavaDate(excelDate);
|
||||
|
||||
// Should match despite timezone
|
||||
// Should match despite time-zone
|
||||
assertEquals("Checking timezone " + id, expected.getTime(), javaDate.getTime());
|
||||
}
|
||||
}
|
||||
@ -402,7 +396,11 @@ public class TestHSSFDateUtil extends TestCase {
|
||||
assertEquals(34519.0, HSSFDateUtil.getExcelDate(createDate(1998, CALENDAR_JULY, 5), true), 0.00001);
|
||||
}
|
||||
|
||||
private Date createDate(int year, int month, int day) {
|
||||
/**
|
||||
* @param month zero based
|
||||
* @param day one based
|
||||
*/
|
||||
private static Date createDate(int year, int month, int day) {
|
||||
Calendar c = new GregorianCalendar();
|
||||
c.set(year, month, day, 0, 0, 0);
|
||||
c.set(Calendar.MILLISECOND, 0);
|
||||
@ -421,9 +419,17 @@ public class TestHSSFDateUtil extends TestCase {
|
||||
assertEquals("Checking absolute day (1 Jan 1901)", 366, HSSFDateUtil.absoluteDay(calendar, false));
|
||||
}
|
||||
|
||||
public static void main(String [] args) {
|
||||
System.out
|
||||
.println("Testing org.apache.poi.hssf.usermodel.TestHSSFDateUtil");
|
||||
junit.textui.TestRunner.run(TestHSSFDateUtil.class);
|
||||
public void testConvertTime() {
|
||||
|
||||
final double delta = 1E-7; // a couple of digits more accuracy than strictly required
|
||||
assertEquals(0.5, HSSFDateUtil.convertTime("12:00"), delta);
|
||||
assertEquals(2.0/3, HSSFDateUtil.convertTime("16:00"), delta);
|
||||
assertEquals(0.0000116, HSSFDateUtil.convertTime("0:00:01"), delta);
|
||||
assertEquals(0.7330440, HSSFDateUtil.convertTime("17:35:35"), delta);
|
||||
}
|
||||
|
||||
public void testParseDate() {
|
||||
assertEquals(createDate(2008, Calendar.AUGUST, 3), HSSFDateUtil.parseYYYYMMDDDate("2008/08/03"));
|
||||
assertEquals(createDate(1994, Calendar.MAY, 1), HSSFDateUtil.parseYYYYMMDDDate("1994/05/01"));
|
||||
}
|
||||
}
|
||||
|
@ -36,6 +36,7 @@ import org.apache.poi.hssf.record.VCenterRecord;
|
||||
import org.apache.poi.hssf.record.WSBoolRecord;
|
||||
import org.apache.poi.hssf.record.WindowTwoRecord;
|
||||
import org.apache.poi.ss.util.Region;
|
||||
import org.apache.poi.ss.util.CellRangeAddress;
|
||||
|
||||
/**
|
||||
* Tests HSSFSheet. This test case is very incomplete at the moment.
|
||||
@ -476,15 +477,15 @@ public final class TestHSSFSheet extends TestCase {
|
||||
public void testRemoveMerged() {
|
||||
HSSFWorkbook wb = new HSSFWorkbook();
|
||||
HSSFSheet sheet = wb.createSheet();
|
||||
Region region = new Region(0, (short)0, 1, (short)1);
|
||||
CellRangeAddress region = new CellRangeAddress(0, 1, 0, 1);
|
||||
sheet.addMergedRegion(region);
|
||||
region = new Region(1, (short)0, 2, (short)1);
|
||||
region = new CellRangeAddress(1, 2, 0, 1);
|
||||
sheet.addMergedRegion(region);
|
||||
|
||||
sheet.removeMergedRegion(0);
|
||||
|
||||
region = sheet.getMergedRegionAt(0);
|
||||
assertEquals("Left over region should be starting at row 1", 1, region.getRowFrom());
|
||||
region = sheet.getMergedRegion(0);
|
||||
assertEquals("Left over region should be starting at row 1", 1, region.getFirstRow());
|
||||
|
||||
sheet.removeMergedRegion(0);
|
||||
|
||||
@ -496,15 +497,15 @@ public final class TestHSSFSheet extends TestCase {
|
||||
sheet.removeMergedRegion(0);
|
||||
assertEquals("there should now be zero merged regions!", 0, sheet.getNumMergedRegions());
|
||||
//add it again!
|
||||
region.setRowTo(4);
|
||||
region.setLastRow(4);
|
||||
|
||||
sheet.addMergedRegion(region);
|
||||
assertEquals("there should now be one merged region!", 1, sheet.getNumMergedRegions());
|
||||
|
||||
//should exist now!
|
||||
assertTrue("there isn't more than one merged region in there", 1 <= sheet.getNumMergedRegions());
|
||||
region = sheet.getMergedRegionAt(0);
|
||||
assertEquals("the merged row to doesnt match the one we put in ", 4, region.getRowTo());
|
||||
region = sheet.getMergedRegion(0);
|
||||
assertEquals("the merged row to doesnt match the one we put in ", 4, region.getLastRow());
|
||||
}
|
||||
|
||||
public void testShiftMerged() {
|
||||
@ -518,13 +519,13 @@ public final class TestHSSFSheet extends TestCase {
|
||||
cell = row.createCell((short)1);
|
||||
cell.setCellValue(new HSSFRichTextString("second row, second cell"));
|
||||
|
||||
Region region = new Region(1, (short)0, 1, (short)1);
|
||||
CellRangeAddress region = new CellRangeAddress(1, 1, 0, 1);
|
||||
sheet.addMergedRegion(region);
|
||||
|
||||
sheet.shiftRows(1, 1, 1);
|
||||
|
||||
region = sheet.getMergedRegionAt(0);
|
||||
assertEquals("Merged region not moved over to row 2", 2, region.getRowFrom());
|
||||
region = sheet.getMergedRegion(0);
|
||||
assertEquals("Merged region not moved over to row 2", 2, region.getFirstRow());
|
||||
}
|
||||
|
||||
/**
|
||||
@ -683,7 +684,7 @@ public final class TestHSSFSheet extends TestCase {
|
||||
assertTrue("Column autosized with only one row: wrong width", sheet.getColumnWidth((short)0) <= maxWithRow1And2);
|
||||
|
||||
//create a region over the 2nd row and auto size the first column
|
||||
sheet.addMergedRegion(new Region(1,(short)0,1,(short)1));
|
||||
sheet.addMergedRegion(new CellRangeAddress(1,1,0,1));
|
||||
sheet.autoSizeColumn((short)0);
|
||||
HSSFWorkbook wb2 = HSSFTestDataSamples.writeOutAndReadBack(wb);
|
||||
|
||||
|
@ -32,6 +32,7 @@ import org.apache.poi.hssf.record.LabelSSTRecord;
|
||||
import org.apache.poi.hssf.record.Record;
|
||||
import org.apache.poi.hssf.record.aggregates.ValueRecordsAggregate;
|
||||
import org.apache.poi.poifs.filesystem.POIFSFileSystem;
|
||||
import org.apache.poi.ss.util.CellRangeAddress;
|
||||
import org.apache.poi.ss.util.Region;
|
||||
import org.apache.poi.util.TempFile;
|
||||
|
||||
@ -42,7 +43,7 @@ import org.apache.poi.util.TempFile;
|
||||
* @author Greg Merrill
|
||||
* @author Siggi Cherem
|
||||
*/
|
||||
public class TestWorkbook extends TestCase {
|
||||
public final class TestWorkbook extends TestCase {
|
||||
private static final String LAST_NAME_KEY = "lastName";
|
||||
private static final String FIRST_NAME_KEY = "firstName";
|
||||
private static final String SSN_KEY = "ssn";
|
||||
@ -260,10 +261,10 @@ public class TestWorkbook extends TestCase {
|
||||
HSSFWorkbook workbook = openSample("Employee.xls");
|
||||
HSSFSheet sheet = workbook.getSheetAt(0);
|
||||
|
||||
assertEquals(EMPLOYEE_INFORMATION, sheet.getRow(1).getCell(1).getStringCellValue());
|
||||
assertEquals(LAST_NAME_KEY, sheet.getRow(3).getCell(2).getStringCellValue());
|
||||
assertEquals(FIRST_NAME_KEY, sheet.getRow(4).getCell(2).getStringCellValue());
|
||||
assertEquals(SSN_KEY, sheet.getRow(5).getCell(2).getStringCellValue());
|
||||
assertEquals(EMPLOYEE_INFORMATION, sheet.getRow(1).getCell(1).getRichStringCellValue().getString());
|
||||
assertEquals(LAST_NAME_KEY, sheet.getRow(3).getCell(2).getRichStringCellValue().getString());
|
||||
assertEquals(FIRST_NAME_KEY, sheet.getRow(4).getCell(2).getRichStringCellValue().getString());
|
||||
assertEquals(SSN_KEY, sheet.getRow(5).getCell(2).getRichStringCellValue().getString());
|
||||
}
|
||||
|
||||
/**
|
||||
@ -318,13 +319,13 @@ public class TestWorkbook extends TestCase {
|
||||
|
||||
sheet = workbook.getSheetAt(0);
|
||||
cell = sheet.getRow(0).getCell(1);
|
||||
assertEquals(REPLACED, cell.getStringCellValue());
|
||||
assertEquals(REPLACED, cell.getRichStringCellValue().getString());
|
||||
cell = sheet.getRow(0).getCell(0);
|
||||
assertEquals(DO_NOT_REPLACE, cell.getStringCellValue());
|
||||
assertEquals(DO_NOT_REPLACE, cell.getRichStringCellValue().getString());
|
||||
cell = sheet.getRow(1).getCell(0);
|
||||
assertEquals(REPLACED, cell.getStringCellValue());
|
||||
assertEquals(REPLACED, cell.getRichStringCellValue().getString());
|
||||
cell = sheet.getRow(1).getCell(1);
|
||||
assertEquals(DO_NOT_REPLACE, cell.getStringCellValue());
|
||||
assertEquals(DO_NOT_REPLACE, cell.getRichStringCellValue().getString());
|
||||
}
|
||||
|
||||
/**
|
||||
@ -388,10 +389,10 @@ public class TestWorkbook extends TestCase {
|
||||
|
||||
workbook = HSSFTestDataSamples.writeOutAndReadBack(workbook);
|
||||
sheet = workbook.getSheetAt(0);
|
||||
assertEquals(EMPLOYEE_INFORMATION, sheet.getRow(1).getCell(1).getStringCellValue());
|
||||
assertEquals(LAST_NAME_VALUE, sheet.getRow(3).getCell(2).getStringCellValue());
|
||||
assertEquals(FIRST_NAME_VALUE, sheet.getRow(4).getCell(2).getStringCellValue());
|
||||
assertEquals(SSN_VALUE, sheet.getRow(5).getCell(2).getStringCellValue());
|
||||
assertEquals(EMPLOYEE_INFORMATION, sheet.getRow(1).getCell(1).getRichStringCellValue().getString());
|
||||
assertEquals(LAST_NAME_VALUE, sheet.getRow(3).getCell(2).getRichStringCellValue().getString());
|
||||
assertEquals(FIRST_NAME_VALUE, sheet.getRow(4).getCell(2).getRichStringCellValue().getString());
|
||||
assertEquals(SSN_VALUE, sheet.getRow(5).getCell(2).getRichStringCellValue().getString());
|
||||
}
|
||||
|
||||
/**
|
||||
@ -421,26 +422,17 @@ public class TestWorkbook extends TestCase {
|
||||
* HSSFSheet last row or first row is incorrect. <P>
|
||||
*
|
||||
*/
|
||||
|
||||
public void testWriteModifySheetMerged()
|
||||
throws IOException
|
||||
{
|
||||
File file = TempFile.createTempFile("testWriteSheetMerged",
|
||||
".xls");
|
||||
FileOutputStream out = new FileOutputStream(file);
|
||||
FileInputStream in = null;
|
||||
public void testWriteModifySheetMerged() {
|
||||
HSSFWorkbook wb = new HSSFWorkbook();
|
||||
HSSFSheet s = wb.createSheet();
|
||||
HSSFRow r = null;
|
||||
HSSFCell c = null;
|
||||
|
||||
for (short rownum = ( short ) 0; rownum < 100; rownum++)
|
||||
{
|
||||
r = s.createRow(rownum);
|
||||
HSSFRow r = s.createRow(rownum);
|
||||
|
||||
for (short cellnum = ( short ) 0; cellnum < 50; cellnum += 2)
|
||||
{
|
||||
c = r.createCell(cellnum);
|
||||
HSSFCell c = r.createCell(cellnum);
|
||||
c.setCellValue(rownum * 10000 + cellnum
|
||||
+ ((( double ) rownum / 1000)
|
||||
+ (( double ) cellnum / 10000)));
|
||||
@ -448,30 +440,24 @@ public class TestWorkbook extends TestCase {
|
||||
c.setCellValue(new HSSFRichTextString("TEST"));
|
||||
}
|
||||
}
|
||||
s.addMergedRegion(new Region(( short ) 0, ( short ) 0, ( short ) 10,
|
||||
( short ) 10));
|
||||
s.addMergedRegion(new Region(( short ) 30, ( short ) 5, ( short ) 40,
|
||||
( short ) 15));
|
||||
wb.write(out);
|
||||
out.close();
|
||||
s.addMergedRegion(new CellRangeAddress(0, 10, 0, 10));
|
||||
s.addMergedRegion(new CellRangeAddress(30, 40, 5, 15));
|
||||
sanityChecker.checkHSSFWorkbook(wb);
|
||||
in = new FileInputStream(file);
|
||||
wb = new HSSFWorkbook(new POIFSFileSystem(in));
|
||||
wb = HSSFTestDataSamples.writeOutAndReadBack(wb);
|
||||
|
||||
s = wb.getSheetAt(0);
|
||||
Region r1 = s.getMergedRegionAt(0);
|
||||
Region r2 = s.getMergedRegionAt(1);
|
||||
CellRangeAddress r1 = s.getMergedRegion(0);
|
||||
CellRangeAddress r2 = s.getMergedRegion(1);
|
||||
|
||||
in.close();
|
||||
confirmRegion(new CellRangeAddress(0, 10, 0, 10), r1);
|
||||
confirmRegion(new CellRangeAddress(30, 40,5, 15), r2);
|
||||
}
|
||||
|
||||
// System.out.println(file.length());
|
||||
// assertEquals("FILE LENGTH == 87552",file.length(), 87552);
|
||||
// System.out.println(s.getLastRowNum());
|
||||
assertEquals("REGION1 = 0,0,10,10", 0,
|
||||
new Region(( short ) 0, ( short ) 0, ( short ) 10,
|
||||
( short ) 10).compareTo(r1));
|
||||
assertEquals("REGION2 == 30,5,40,15", 0,
|
||||
new Region(( short ) 30, ( short ) 5, ( short ) 40,
|
||||
( short ) 15).compareTo(r2));
|
||||
private static void confirmRegion(CellRangeAddress ra, CellRangeAddress rb) {
|
||||
assertEquals(ra.getFirstRow(), rb.getFirstRow());
|
||||
assertEquals(ra.getLastRow(), rb.getLastRow());
|
||||
assertEquals(ra.getFirstColumn(), rb.getFirstColumn());
|
||||
assertEquals(ra.getLastColumn(), rb.getLastColumn());
|
||||
}
|
||||
|
||||
/**
|
||||
|
Loading…
Reference in New Issue
Block a user