From: Josh Micich Date: Mon, 4 Aug 2008 08:00:11 +0000 (+0000) Subject: Consolidating various duplicates of CellRangeAddress X-Git-Tag: REL_3_2_FINAL~218 X-Git-Url: https://source.dussan.org/?a=commitdiff_plain;h=ba2c1e7beb4cd4bac5d676e88908a092d07ef6c6;p=poi.git Consolidating various duplicates of CellRangeAddress git-svn-id: https://svn.apache.org/repos/asf/poi/trunk@682282 13f79535-47bb-0310-9956-ffa450edef68 --- diff --git a/src/contrib/src/org/apache/poi/hssf/usermodel/contrib/HSSFRegionUtil.java b/src/contrib/src/org/apache/poi/hssf/usermodel/contrib/HSSFRegionUtil.java index 0a71600ed8..fda8759fd2 100644 --- a/src/contrib/src/org/apache/poi/hssf/usermodel/contrib/HSSFRegionUtil.java +++ b/src/contrib/src/org/apache/poi/hssf/usermodel/contrib/HSSFRegionUtil.java @@ -21,197 +21,257 @@ 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.hssf.util.CellRangeAddress; import org.apache.poi.hssf.util.Region; /** - * Various utility functions that make working with a region of cells easier. - * - *@author Eric Pugh epugh@upstate.com - *@since July 29, 2002 + * Various utility functions that make working with a region of cells easier. + * + * @author Eric Pugh epugh@upstate.com */ -public final class HSSFRegionUtil -{ - - /** Constructor for the HSSFRegionUtil object */ - private HSSFRegionUtil() { - // no instances of this class - } - - /** - * Sets the left border for a region of cells by manipulating the cell style - * of the individual cells on the left - * - *@param border The new border - *@param region The region that should have the border - *@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(); - - 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 ) ); - } - } - - /** - * Sets the leftBorderColor attribute of the HSSFRegionUtil object - * - *@param color The color of the border - *@param region The region that should have the border - *@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(); - - 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 ) ); - } - } - - /** - * Sets the borderRight attribute of the HSSFRegionUtil object - * - *@param border The new border - *@param region The region that should have the border - *@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(); - - 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 ) ); - } - } - - /** - * Sets the rightBorderColor attribute of the HSSFRegionUtil object - * - *@param color The color of the border - *@param region The region that should have the border - *@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(); - - 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 ) ); - } - } - - /** - * Sets the borderBottom attribute of the HSSFRegionUtil object - * - *@param border The new border - *@param region The region that should have the border - *@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(); - 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 ) ); - } - } - - /** - * Sets the bottomBorderColor attribute of the HSSFRegionUtil object - * - *@param color The color of the border - *@param region The region that should have the border - *@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(); - 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 ) ); - } - } - - /** - * Sets the borderBottom attribute of the HSSFRegionUtil object - * - *@param border The new border - *@param region The region that should have the border - *@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(); - 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 ) ); - } - } - - /** - * Sets the topBorderColor attribute of the HSSFRegionUtil object - * - *@param color The color of the border - *@param region The region that should have the border - *@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(); - 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 ) ); - } - } -} +public final class HSSFRegionUtil { + + 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 + * + * @param border The new border + * @param region The region that should have the border + * @param workbook The workbook that the region is on. + * @param sheet The sheet that the region is on. + */ + 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++) { + 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 + * + * @param color The color of the border + * @param region The region that should have the border + * @param workbook The workbook that the region is on. + * @param sheet The sheet that the region is on. + */ + 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++) { + 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 + * + * @param border The new border + * @param region The region that should have the border + * @param workbook The workbook that the region is on. + * @param sheet The sheet that the region is on. + */ + 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++) { + 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 + * + * @param color The color of the border + * @param region The region that should have the border + * @param workbook The workbook that the region is on. + * @param sheet The sheet that the region is on. + */ + 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++) { + 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 + * + * @param border The new border + * @param region The region that should have the border + * @param workbook The workbook that the region is on. + * @param sheet The sheet that the region is on. + */ + 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++) { + 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 + * + * @param color The color of the border + * @param region The region that should have the border + * @param workbook The workbook that the region is on. + * @param sheet The sheet that the region is on. + */ + 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++) { + 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 + * + * @param border The new border + * @param region The region that should have the border + * @param workbook The workbook that the region is on. + * @param sheet The sheet that the region is on. + */ + 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++) { + 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 + * + * @param color The color of the border + * @param region The region that should have the border + * @param workbook The workbook that the region is on. + * @param sheet The sheet that the region is on. + */ + 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++) { + cps.setProperty(row, i); + } + } +} diff --git a/src/java/org/apache/poi/hssf/dev/HSSF.java b/src/java/org/apache/poi/hssf/dev/HSSF.java index 7dddca966a..b7d4bbbca6 100644 --- a/src/java/org/apache/poi/hssf/dev/HSSF.java +++ b/src/java/org/apache/poi/hssf/dev/HSSF.java @@ -18,13 +18,20 @@ 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.hssf.usermodel.*; -import org.apache.poi.hssf.util.*; /** * File for HSSF testing/examples @@ -126,7 +133,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) @@ -148,10 +155,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 diff --git a/src/java/org/apache/poi/hssf/model/Sheet.java b/src/java/org/apache/poi/hssf/model/Sheet.java index 9959dbfb26..993dfd7b31 100644 --- a/src/java/org/apache/poi/hssf/model/Sheet.java +++ b/src/java/org/apache/poi/hssf/model/Sheet.java @@ -24,6 +24,7 @@ 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.util.CellRangeAddress; import org.apache.poi.hssf.util.PaneInformation; import org.apache.poi.util.POILogFactory; @@ -515,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 @@ -585,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) @@ -1634,13 +1635,7 @@ public final class Sheet implements Model { * Creates the Selection record and sets it to nothing selected */ private static SelectionRecord createSelection() { - SelectionRecord retval = new SelectionRecord(); - - retval.setPane(( byte ) 0x3); - retval.setActiveCellCol(( short ) 0x0); - retval.setActiveCellRow(( short ) 0x0); - retval.setNumRefs(( short ) 0x0); - return retval; + return new SelectionRecord(0, 0); } public short getTopRow() @@ -1701,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(); } /** @@ -1731,9 +1722,7 @@ public final class Sheet implements Model { } private static MergeCellsRecord createMergedCells() { - MergeCellsRecord retval = new MergeCellsRecord(); - retval.setNumAreas(( short ) 0); - return retval; + return new MergeCellsRecord(); } /** diff --git a/src/java/org/apache/poi/hssf/record/CFHeaderRecord.java b/src/java/org/apache/poi/hssf/record/CFHeaderRecord.java index d74d54ab17..70d4101fa0 100644 --- a/src/java/org/apache/poi/hssf/record/CFHeaderRecord.java +++ b/src/java/org/apache/poi/hssf/record/CFHeaderRecord.java @@ -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.hssf.util.CellRangeAddress; +import org.apache.poi.hssf.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(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; i0) + buffer.append(" .cfranges=["); + for( int i=0; i0) { sb.append(", "); diff --git a/src/java/org/apache/poi/hssf/record/MergeCellsRecord.java b/src/java/org/apache/poi/hssf/record/MergeCellsRecord.java index 41d8170dff..bf41d2fc91 100644 --- a/src/java/org/apache/poi/hssf/record/MergeCellsRecord.java +++ b/src/java/org/apache/poi/hssf/record/MergeCellsRecord.java @@ -1,4 +1,3 @@ - /* ==================================================================== Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements. See the NOTICE file distributed with @@ -15,57 +14,43 @@ See the License for the specific language governing permissions and limitations under the License. ==================================================================== */ - package org.apache.poi.hssf.record; -import java.util.ArrayList; -import java.util.Iterator; - +import org.apache.poi.hssf.util.CellRangeAddress; +import org.apache.poi.hssf.util.CellRangeAddressList; import org.apache.poi.util.LittleEndian; /** - * Title: Merged Cells Record - *
+ * Title: Merged Cells Record (0x00E5) + *
* Description: Optional record defining a square area of cells to "merged" into * one cell.
* REFERENCE: NONE (UNDOCUMENTED PRESENTLY)
* @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 MergedCellsRecord + */ + 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 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; diff --git a/src/java/org/apache/poi/hssf/record/SelectionRecord.java b/src/java/org/apache/poi/hssf/record/SelectionRecord.java index 8ad4d0cefa..2f36ea644f 100644 --- a/src/java/org/apache/poi/hssf/record/SelectionRecord.java +++ b/src/java/org/apache/poi/hssf/record/SelectionRecord.java @@ -1,4 +1,3 @@ - /* ==================================================================== Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements. See the NOTICE file distributed with @@ -15,70 +14,80 @@ See the License for the specific language governing permissions and limitations under the License. ==================================================================== */ - package org.apache.poi.hssf.record; -import java.util.*; - import org.apache.poi.util.LittleEndian; /** - * Title: Selection Record

+ * Title: Selection Record (0x001D)

* Description: shows the user's selection on the sheet * for write set num refs to 0

* - * TODO : Fully implement reference subrecords. * REFERENCE: PG 291 Microsoft Excel 97 Developer's Kit (ISBN: 1-57231-498-2)

* @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 final class SelectionRecord extends Record { + public final static short sid = 0x001D; + private byte field_1_pane; + private int field_2_row_active_cell; + private int field_3_col_active_cell; + private int field_4_active_cell_ref_index; + private Reference[] field_6_refs; -public class SelectionRecord - extends Record -{ - public final static short sid = 0x1d; - 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 - + /** + * Note - column values are 8-bit so cannot use CellRangeAddressList + */ 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; - - 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 */ static final int ENCODED_SIZE = 6; + private int _firstRow; + private int _lastRow; + private int _firstCol; + private int _lastCol; - public short getFirstRow() { - return field_1_first_row; - } - - public short getLastRow() { - return field_2_last_row; - } - - public byte getFirstColumn() { - return field_3_first_column; - } - - public byte getLastColumn() { - return field_4_last_column; - } + /* 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 int getFirstRow() { + return _firstRow; + } + public int getLastRow() { + return _lastRow; + } + public int getFirstColumn() { + return _firstCol; + } + 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-1 for full column ranges - * @param firstColumn - * @param lastColumn pass -1 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 -1. - */ - 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(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.
- * Possible return codes are: - * NO_INTERSECTION - the specified range is outside of this range;
- * OVERLAP - both ranges partially overlap;
- * INSIDE - the specified range is inside of this one
- * ENCLOSES - the specified range encloses (possibly exactly the same as) this range
- */ - 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:
- *

  • if a cell range is completely inside of another cell range, it gets removed from the list - *
  • 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; inull 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 this CellRange and all parts of range - * 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(Region[] regions) - { - CellRange[] result = new CellRange[regions.length]; - for( int i=0; itrue 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()+")"; - } - -} diff --git a/src/java/org/apache/poi/hssf/record/cf/CellRangeUtil.java b/src/java/org/apache/poi/hssf/record/cf/CellRangeUtil.java new file mode 100644 index 0000000000..4e20fbb7c4 --- /dev/null +++ b/src/java/org/apache/poi/hssf/record/cf/CellRangeUtil.java @@ -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.hssf.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.
    + * Possible return codes are: + * NO_INTERSECTION - the specified range is outside of this range;
    + * OVERLAP - both ranges partially overlap;
    + * INSIDE - the specified range is inside of this one
    + * ENCLOSES - the specified range encloses (possibly exactly the same as) this range
    + */ + 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:
    + *
  • if a cell range is completely inside of another cell range, it gets removed from the list + *
  • 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; inull 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 this CellRange and all parts of range + * 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 true 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); + } +} diff --git a/src/java/org/apache/poi/hssf/usermodel/HSSFConditionalFormatting.java b/src/java/org/apache/poi/hssf/usermodel/HSSFConditionalFormatting.java index 6c798abcf4..a08c3f0c82 100644 --- a/src/java/org/apache/poi/hssf/usermodel/HSSFConditionalFormatting.java +++ b/src/java/org/apache/poi/hssf/usermodel/HSSFConditionalFormatting.java @@ -16,10 +16,9 @@ ==================================================================== */ 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.CellRangeAddress; import org.apache.poi.hssf.util.Region; /** @@ -96,13 +95,18 @@ public final class HSSFConditionalFormatting } /** - * @return array of Regions. never null + * @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 CellRangeAddresss. never null + */ + public CellRangeAddress[] getFormattingRanges() { + return cfAggregate.getHeader().getCellRanges(); } /** diff --git a/src/java/org/apache/poi/hssf/usermodel/HSSFSheet.java b/src/java/org/apache/poi/hssf/usermodel/HSSFSheet.java index a99e48b64e..ec104ded96 100644 --- a/src/java/org/apache/poi/hssf/usermodel/HSSFSheet.java +++ b/src/java/org/apache/poi/hssf/usermodel/HSSFSheet.java @@ -38,6 +38,7 @@ import org.apache.poi.hssf.record.*; 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.CellRangeAddress; import org.apache.poi.hssf.util.PaneInformation; import org.apache.poi.hssf.util.Region; import org.apache.poi.util.POILogFactory; @@ -517,20 +518,28 @@ public final class HSSFSheet { } /** - * 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 CellRangeAddress instead of Region */ - public int addMergedRegion(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 @@ -567,7 +576,7 @@ public final class HSSFSheet { /** * 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(); @@ -632,14 +641,19 @@ public final class HSSFSheet { } /** - * 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) - { - return new Region(sheet.getMergedRegionAt(index)); + public Region getMergedRegionAt(int index) { + CellRangeAddress cra = getMergedRegion(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 sheet.getMergedRegionAt(index); } /** @@ -1072,36 +1086,43 @@ public final class HSSFSheet { 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; } /** @@ -1720,17 +1741,20 @@ public final class HSSFSheet { 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(); } } diff --git a/src/java/org/apache/poi/hssf/usermodel/HSSFSheetConditionalFormatting.java b/src/java/org/apache/poi/hssf/usermodel/HSSFSheetConditionalFormatting.java index 4df94e4b52..47cf217b26 100644 --- a/src/java/org/apache/poi/hssf/usermodel/HSSFSheetConditionalFormatting.java +++ b/src/java/org/apache/poi/hssf/usermodel/HSSFSheetConditionalFormatting.java @@ -20,6 +20,7 @@ package org.apache.poi.hssf.usermodel; 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.hssf.util.CellRangeAddress; import org.apache.poi.hssf.util.Region; /** @@ -100,7 +101,12 @@ public final class HSSFSheetConditionalFormatting { return _sheet.addConditionalFormatting(cfraClone); } - + /** + * @deprecated use CellRangeAddress instead of Region + */ + 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 * diff --git a/src/java/org/apache/poi/hssf/util/CellRangeAddress.java b/src/java/org/apache/poi/hssf/util/CellRangeAddress.java index 2f5d24aa02..d6189c368f 100644 --- a/src/java/org/apache/poi/hssf/util/CellRangeAddress.java +++ b/src/java/org/apache/poi/hssf/util/CellRangeAddress.java @@ -17,38 +17,72 @@ 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' + * See OOO documentation: excelfileformat.pdf sec 2.5.14 - 'Cell Range Address'

    * + * Note - {@link SelectionRecord} uses the BIFF5 version of this structure * @author Dragos Buleandra (dragos.buleandra@trade2b.ro) */ public final class CellRangeAddress { - private static final int ENCODED_SIZE = 8; + /* + * TODO - replace org.apache.poi.hssf.util.Region + */ + public static final int ENCODED_SIZE = 8; + /** 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 int _firstRow; private int _firstCol; private int _lastRow; private int _lastCol; - /* - * TODO - replace other incarnations of 'Cell Range Address' throughout POI: - * org.apache.poi.hssf.util.CellRange - * org.apache.poi.hssf.record.cf.CellRange - * org.apache.poi.hssf.util.HSSFCellRangeAddress.AddrStructure - * org.apache.poi.hssf.record.MergeCellsRecord.MergedRegion - * org.apache.poi.hssf.record.SelectionRecord.Reference - * - */ - 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 = lastRow; + _lastRow = convertM1ToMax(lastRow, LAST_ROW_INDEX); _firstCol = firstCol; - _lastCol = lastCol; + _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 -1. + */ + private static int convertM1ToMax(int lastIx, int maxIndex) { + if(lastIx < 0) { + return maxIndex; + } + return lastIx; } + + public CellRangeAddress(RecordInputStream in) { if (in.remaining() < ENCODED_SIZE) { // Ran out of data @@ -59,6 +93,12 @@ public final class CellRangeAddress { _firstCol = in.readUShort(); _lastCol = in.readUShort(); } + 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 @@ -116,15 +156,23 @@ public final class CellRangeAddress { _lastRow = lastRow; } - /* package */ int serialize(byte[] data, int offset) { + 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; } + + 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+"]"; + } } \ No newline at end of file diff --git a/src/java/org/apache/poi/hssf/util/CellRangeAddressList.java b/src/java/org/apache/poi/hssf/util/CellRangeAddressList.java index d52219769d..f901be4c4d 100644 --- a/src/java/org/apache/poi/hssf/util/CellRangeAddressList.java +++ b/src/java/org/apache/poi/hssf/util/CellRangeAddressList.java @@ -74,12 +74,12 @@ public final class CellRangeAddressList { * * @return number of ADDR structures */ - public int getADDRStructureNumber() { + public int countRanges() { return _list.size(); } /** - * Add an ADDR structure . + * Add a cell range structure. * * @param firstRow - the upper left hand corner's row * @param firstCol - the upper left hand corner's col @@ -89,7 +89,20 @@ public final class CellRangeAddressList { */ public void addCellRangeAddress(int firstRow, int firstCol, int lastRow, int lastCol) { CellRangeAddress region = new CellRangeAddress(firstRow, lastRow, firstCol, lastCol); - _list.add(region); + 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); } /** @@ -106,7 +119,7 @@ public final class CellRangeAddressList { LittleEndian.putUShort(data, offset, nItems); for (int k = 0; k < nItems; k++) { CellRangeAddress region = (CellRangeAddress) _list.get(k); - pos += region.serialize(data, offset + pos); + pos += region.serialize(offset + pos, data); } return getSize(); } @@ -114,4 +127,19 @@ public final class CellRangeAddressList { public int getSize() { return 2 + CellRangeAddress.getEncodedSize(_list.size()); } + 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; + } } diff --git a/src/java/org/apache/poi/hssf/util/Region.java b/src/java/org/apache/poi/hssf/util/Region.java index 67d52eb137..7047cee9f3 100644 --- a/src/java/org/apache/poi/hssf/util/Region.java +++ b/src/java/org/apache/poi/hssf/util/Region.java @@ -15,10 +15,8 @@ limitations under the License. ==================================================================== */ - 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 @@ -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 { private int rowFrom; private short colFrom; private int rowTo; @@ -52,15 +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); - } /** * get the upper left hand corner column number @@ -150,72 +137,49 @@ public class Region this.rowTo = rowTo; } - /** - * Answers: "is the row/column inside this range?" - * - * @return true if the cell is in the range and - * false if it is not - */ - - public boolean contains(int row, short col) - { - if ((this.rowFrom <= row) && (this.rowTo >= row) - && (this.colFrom <= col) && (this.colTo >= col)) - { - -// System.out.println("Region ("+rowFrom+","+colFrom+","+rowTo+","+ -// colTo+") does contain "+row+","+col); - return true; - } - return false; - } - - public boolean equals(Region r) - { - return (compareTo(r) == 0); - } - /** - * Compares that the given region is the same less than or greater than this - * region. If any regional coordiant passed in is less than this regions - * coordinants then a positive integer is returned. Otherwise a negative - * integer is returned. - * - * @param r region - * @see #compareTo(Object) - */ - - public int compareTo(Region r) - { - if ((this.getRowFrom() == r.getRowFrom()) - && (this.getColumnFrom() == r.getColumnFrom()) - && (this.getRowTo() == r.getRowTo()) - && (this.getColumnTo() == r.getColumnTo())) - { - return 0; - } - if ((this.getRowFrom() < r.getRowFrom()) - || (this.getColumnFrom() < r.getColumnFrom()) - || (this.getRowTo() < r.getRowTo()) - || (this.getColumnTo() < r.getColumnTo())) - { - return 1; - } - return -1; - } - - public int compareTo(Object o) - { - return compareTo(( Region ) o); - } - - /** - * @return the area contained by this region (number of cells) - */ - - public int getArea() - { - return ((1 + (getRowTo() - getRowFrom())) - * (1 + (getColumnTo() - getColumnFrom()))); - } + /** + * 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]; + } + + 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()); + } } diff --git a/src/testcases/org/apache/poi/hssf/record/TestCFHeaderRecord.java b/src/testcases/org/apache/poi/hssf/record/TestCFHeaderRecord.java index e883503674..fd3dd81d0c 100644 --- a/src/testcases/org/apache/poi/hssf/record/TestCFHeaderRecord.java +++ b/src/testcases/org/apache/poi/hssf/record/TestCFHeaderRecord.java @@ -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.hssf.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); @@ -168,18 +168,11 @@ public final class TestCFHeaderRecord extends TestCase assertEquals("CFHeaderRecord doesn't match", recordData[i], output[i+4]); } } - - 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); - } } diff --git a/src/testcases/org/apache/poi/hssf/record/TestMergeCellsRecord.java b/src/testcases/org/apache/poi/hssf/record/TestMergeCellsRecord.java index 31ec27b7c4..fe7d26d12a 100644 --- a/src/testcases/org/apache/poi/hssf/record/TestMergeCellsRecord.java +++ b/src/testcases/org/apache/poi/hssf/record/TestMergeCellsRecord.java @@ -1,4 +1,3 @@ - /* ==================================================================== Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements. See the NOTICE file distributed with @@ -15,19 +14,19 @@ See the License for the specific language governing permissions and limitations under the License. ==================================================================== */ - + package org.apache.poi.hssf.record; import junit.framework.TestCase; -import org.apache.poi.hssf.record.MergeCellsRecord.MergedRegion; +import org.apache.poi.hssf.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)); diff --git a/src/testcases/org/apache/poi/hssf/record/aggregates/TestCFRecordsAggregate.java b/src/testcases/org/apache/poi/hssf/record/aggregates/TestCFRecordsAggregate.java index 2ae8230d5e..2472d4d213 100644 --- a/src/testcases/org/apache/poi/hssf/record/aggregates/TestCFRecordsAggregate.java +++ b/src/testcases/org/apache/poi/hssf/record/aggregates/TestCFRecordsAggregate.java @@ -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.hssf.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); - } - } diff --git a/src/testcases/org/apache/poi/hssf/record/cf/TestCellRange.java b/src/testcases/org/apache/poi/hssf/record/cf/TestCellRange.java index 2ba196d55a..dc900d91f2 100644 --- a/src/testcases/org/apache/poi/hssf/record/cf/TestCellRange.java +++ b/src/testcases/org/apache/poi/hssf/record/cf/TestCellRange.java @@ -17,6 +17,8 @@ limitations under the License. package org.apache.poi.hssf.record.cf; +import org.apache.poi.hssf.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()); } diff --git a/src/testcases/org/apache/poi/hssf/usermodel/TestBugs.java b/src/testcases/org/apache/poi/hssf/usermodel/TestBugs.java index fe201068de..9f68e7d251 100644 --- a/src/testcases/org/apache/poi/hssf/usermodel/TestBugs.java +++ b/src/testcases/org/apache/poi/hssf/usermodel/TestBugs.java @@ -35,6 +35,7 @@ import org.apache.poi.hssf.record.FormulaRecord; import org.apache.poi.hssf.record.NameRecord; import org.apache.poi.hssf.record.aggregates.FormulaRecordAggregate; import org.apache.poi.hssf.record.formula.DeletedArea3DPtg; +import org.apache.poi.hssf.util.CellRangeAddress; import org.apache.poi.hssf.util.Region; import org.apache.poi.util.TempFile; @@ -301,15 +302,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(); @@ -317,20 +317,20 @@ public final class TestBugs extends TestCase { // remove merged regions from clone for (int i=template.getNumMergedRegions()-1; i>=0; i--) { - clone.removeMergedRegion(i); + clone.removeMergedRegion(i); } assertEquals("Original Sheet's Merged Regions were removed", originalMerged, template.getNumMergedRegions()); // check if template's merged regions are OK if (template.getNumMergedRegions()>0) { - // fetch the first merged region...EXCEPTION OCCURS HERE - template.getMergedRegionAt(0); + // fetch the first merged region...EXCEPTION OCCURS HERE + 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. */ diff --git a/src/testcases/org/apache/poi/hssf/usermodel/TestCloneSheet.java b/src/testcases/org/apache/poi/hssf/usermodel/TestCloneSheet.java index a663602ed3..54f1685bb6 100644 --- a/src/testcases/org/apache/poi/hssf/usermodel/TestCloneSheet.java +++ b/src/testcases/org/apache/poi/hssf/usermodel/TestCloneSheet.java @@ -20,6 +20,8 @@ package org.apache.poi.hssf.usermodel; import junit.framework.TestCase; + +import org.apache.poi.hssf.util.CellRangeAddress; import org.apache.poi.hssf.util.Region; /** @@ -28,23 +30,15 @@ import org.apache.poi.hssf.util.Region; * add that record to the sheet in the testCloneSheetBasic method. * @author avik */ -public class TestCloneSheet extends TestCase { +public final class TestCloneSheet extends TestCase { - public TestCloneSheet(String arg0) { - super(arg0); - } - 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)); - HSSFSheet clonedSheet = b.cloneSheet(0); - - assertEquals("One merged area", 1, clonedSheet.getNumMergedRegions()); - - } - catch(Exception e){e.printStackTrace();fail(e.getMessage());} + HSSFWorkbook b = new HSSFWorkbook(); + HSSFSheet s = b.createSheet("Test"); + s.addMergedRegion(new CellRangeAddress(0, 1, 0, 1)); + HSSFSheet clonedSheet = b.cloneSheet(0); + + assertEquals("One merged area", 1, clonedSheet.getNumMergedRegions()); } /** @@ -65,5 +59,4 @@ public class TestCloneSheet extends TestCase { assertTrue("Row 3 still should be broken", clone.isRowBroken(3)); } - } diff --git a/src/testcases/org/apache/poi/hssf/usermodel/TestDataValidation.java b/src/testcases/org/apache/poi/hssf/usermodel/TestDataValidation.java index 794d5433c3..20933819b4 100644 --- a/src/testcases/org/apache/poi/hssf/usermodel/TestDataValidation.java +++ b/src/testcases/org/apache/poi/hssf/usermodel/TestDataValidation.java @@ -32,6 +32,7 @@ import org.apache.poi.hssf.eventmodel.ERFListener; import org.apache.poi.hssf.eventmodel.EventRecordFactory; import org.apache.poi.hssf.record.DVRecord; import org.apache.poi.hssf.record.RecordFormatException; +import org.apache.poi.hssf.util.CellRangeAddress; import org.apache.poi.hssf.util.CellRangeAddressList; import org.apache.poi.hssf.util.HSSFColor; import org.apache.poi.hssf.util.Region; @@ -254,8 +255,7 @@ public final class TestDataValidation extends TestCase { HSSFSheet sheet = _currentSheet; HSSFRow row = sheet.createRow(sheet.getPhysicalNumberOfRows()); row = sheet.createRow(sheet.getPhysicalNumberOfRows()); - sheet.addMergedRegion(new Region((short) (sheet.getPhysicalNumberOfRows() - 1), - (short) 0, (short) (sheet.getPhysicalNumberOfRows() - 1), (short) 5)); + sheet.addMergedRegion(new CellRangeAddress(sheet.getPhysicalNumberOfRows()-1, sheet.getPhysicalNumberOfRows()-1, 0, 5)); HSSFCell cell = row.createCell((short) 0); setCellValue(cell, strTypeDescription); cell.setCellStyle(_style_3); @@ -297,7 +297,7 @@ public final class TestDataValidation extends TestCase { public void createDVDescriptionRow(String strTypeDescription) { HSSFSheet sheet = _currentSheet; HSSFRow row = sheet.getRow(sheet.getPhysicalNumberOfRows()-1); - sheet.addMergedRegion(new Region((short)(sheet.getPhysicalNumberOfRows()-1),(short)0,(short)(sheet.getPhysicalNumberOfRows()-1),(short)5)); + sheet.addMergedRegion(new CellRangeAddress(sheet.getPhysicalNumberOfRows()-1, sheet.getPhysicalNumberOfRows()-1, 0, 5)); HSSFCell cell = row.createCell((short)0); setCellValue(cell, strTypeDescription); cell.setCellStyle(_style_3); diff --git a/src/testcases/org/apache/poi/hssf/usermodel/TestHSSFConditionalFormatting.java b/src/testcases/org/apache/poi/hssf/usermodel/TestHSSFConditionalFormatting.java index 405f78106e..ab503737a8 100644 --- a/src/testcases/org/apache/poi/hssf/usermodel/TestHSSFConditionalFormatting.java +++ b/src/testcases/org/apache/poi/hssf/usermodel/TestHSSFConditionalFormatting.java @@ -20,8 +20,8 @@ package org.apache.poi.hssf.usermodel; import junit.framework.TestCase; import org.apache.poi.hssf.record.CFRuleRecord.ComparisonOperator; +import org.apache.poi.hssf.util.CellRangeAddress; import org.apache.poi.hssf.util.HSSFColor; -import org.apache.poi.hssf.util.Region; /** * * @author Dmitriy Kumshayev @@ -57,9 +57,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 +71,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()); diff --git a/src/testcases/org/apache/poi/hssf/usermodel/TestHSSFSheet.java b/src/testcases/org/apache/poi/hssf/usermodel/TestHSSFSheet.java index 7fa84b853a..3816c4cb64 100644 --- a/src/testcases/org/apache/poi/hssf/usermodel/TestHSSFSheet.java +++ b/src/testcases/org/apache/poi/hssf/usermodel/TestHSSFSheet.java @@ -35,7 +35,7 @@ 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.util.Region; +import org.apache.poi.hssf.util.CellRangeAddress; /** * Tests HSSFSheet. This test case is very incomplete at the moment. @@ -476,15 +476,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 +496,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 +518,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 +683,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); diff --git a/src/testcases/org/apache/poi/hssf/usermodel/TestWorkbook.java b/src/testcases/org/apache/poi/hssf/usermodel/TestWorkbook.java index c353e3f04e..3851cab56f 100644 --- a/src/testcases/org/apache/poi/hssf/usermodel/TestWorkbook.java +++ b/src/testcases/org/apache/poi/hssf/usermodel/TestWorkbook.java @@ -31,7 +31,7 @@ import org.apache.poi.hssf.record.BackupRecord; 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.hssf.util.Region; +import org.apache.poi.hssf.util.CellRangeAddress; import org.apache.poi.poifs.filesystem.POIFSFileSystem; import org.apache.poi.util.TempFile; @@ -42,7 +42,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 +260,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 +318,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 +388,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 +421,17 @@ public class TestWorkbook extends TestCase { * HSSFSheet last row or first row is incorrect.

    * */ - - 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,33 +439,27 @@ 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(); - - // 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)); + confirmRegion(new CellRangeAddress(0, 10, 0, 10), r1); + confirmRegion(new CellRangeAddress(30, 40,5, 15), 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()); + } + + /** * Test the backup field gets set as expected. */