<!-- Don't forget to update status.xml too! -->
<release version="3.0.3-beta1" date="2008-04-??">
+ <action dev="POI-DEVELOPERS" type="fix">44739 - Small fixes for conditional formatting (regions with max row/col index)</action>
<action dev="POI-DEVELOPERS" type="add">Implement Sheet.removeShape(Shape shape) in HSLF</action>
+ <action dev="RK" type="add">44694 - HPSF: Support for property sets without sections</action>
<action dev="POI-DEVELOPERS" type="add">Various fixes: Recognising var-arg built-in functions #44675, ExternalNameRecord serialisation bug #44695, PMT() bug #44691</action>
<action dev="POI-DEVELOPERS" type="add">30311 - More work on Conditional Formatting</action>
<action dev="POI-DEVELOPERS" type="add">Move the Formula Evaluator code out of scratchpad</action>
<!-- Don't forget to update changes.xml too! -->
<changes>
<release version="3.0.3-beta1" date="2008-04-??">
+ <action dev="POI-DEVELOPERS" type="fix">44739 - Small fixes for conditional formatting (regions with max row/col index)</action>
+ <action dev="RK" type="add">44694 - HPSF: Support for property sets without sections</action>
<action dev="POI-DEVELOPERS" type="add">Implement Sheet.removeShape(Shape shape) in HSLF</action>
<action dev="POI-DEVELOPERS" type="add">Various fixes: Recognising var-arg built-in functions #44675, ExternalNameRecord serialisation bug #44695, PMT() bug #44691</action>
<action dev="POI-DEVELOPERS" type="add">30311 - More work on Conditional Formatting</action>
osVersion = ps.getOSVersion();
setClassID(ps.getClassID());
clearSections();
+ if (sections == null)
+ sections = new LinkedList();
for (final Iterator i = ps.getSections().iterator(); i.hasNext();)
{
final MutableSection s = new MutableSection((Section) (i.next()));
o += ClassID.LENGTH;
final long sectionCount = LittleEndian.getUInt(src, o);
o += LittleEndian.INT_SIZE;
- if (sectionCount < 1)
+ if (sectionCount < 0)
return false;
return true;
}
o += ClassID.LENGTH;
final int sectionCount = LittleEndian.getInt(src, o);
o += LittleEndian.INT_SIZE;
- if (sectionCount <= 0)
+ if (sectionCount < 0)
throw new HPSFRuntimeException("Section count " + sectionCount +
- " must be greater than 0.");
+ " is negative.");
/*
* Read the sections, which are following the header. They
*/
public boolean isSummaryInformation()
{
+ if (sections.size() <= 0)
+ return false;
return Util.equal(((Section) sections.get(0)).getFormatID().getBytes(),
SectionIDMap.SUMMARY_INFORMATION_ID);
}
*/
public boolean isDocumentSummaryInformation()
{
+ if (sections.size() <= 0)
+ return false;
return Util.equal(((Section) sections.get(0)).getFormatID().getBytes(),
SectionIDMap.DOCUMENT_SUMMARY_INFORMATION_ID[0]);
}
}
/**
- * get the width of a given column in units of 1/20th of a point width (twips?)
+ * get the width of a given column in units of 1/256th of a character width
* @param column index
* @see org.apache.poi.hssf.record.DefaultColWidthRecord
* @see org.apache.poi.hssf.record.ColumnInfoRecord
* @see #setColumnWidth(short,short)
- * @return column width in units of 1/20th of a point (twips?)
+ * @return column width in units of 1/256th of a character width
*/
public short getColumnWidth(short column)
}
else
{
- retval = defaultcolwidth.getColWidth();
+ //default column width is measured in characters
+ //multiply
+ retval = (short)(256*defaultcolwidth.getColWidth());
}
return retval;
}
}
/**
- * set the width for a given column in 1/20th of a character width units
+ * set the width for a given column in 1/256th of a character width units
* @param column - the column number
- * @param width (in units of 1/20th of a character width)
+ * @param width (in units of 1/256th of a character width)
*/
public void setColumnWidth(short column, short width)
{
{
field_1_numcf = in.readShort();
field_2_need_recalculation = in.readShort();
- field_3_enclosing_cell_range = new CellRange(in.readShort(),in.readShort(),in.readShort(),in.readShort());
+ field_3_enclosing_cell_range = new CellRange(in.readUShort(), in.readUShort(), in.readUShort(), in.readUShort());
int numCellRanges = in.readShort();
CellRange[] crs = new CellRange[numCellRanges];
for( int i=0; i<numCellRanges; i++)
{
- crs[i] = new CellRange(in.readShort(),in.readShort(),in.readShort(),in.readShort());
+ crs[i] = new CellRange(in.readUShort(),in.readUShort(),in.readUShort(),in.readUShort());
}
field_4_cell_ranges = crs;
}
import org.apache.poi.util.StringUtil;
/**
- * Title: DV Record<P>
+ * Title: DATAVALIDATION Record (0x01BE)<p/>
* Description: This record stores data validation settings and a list of cell ranges
* which contain these settings. The data validation settings of a sheet
* are stored in a sequential list of DV records. This list is followed by
* @author Dragos Buleandra (dragos.buleandra@trade2b.ro)
* @version 2.0-pre
*/
-public class DVRecord extends Record
+public final class DVRecord extends Record
{
public final static short sid = 0x01BE;
this.field_not_used_1 = in.readShort();
//read first formula data condition
- // Not sure if this was needed or not...
-// try {
-// in.skip(this.field_size_first_formula);
-// } catch(IOException e) { throw new IllegalStateException(e); }
-
int token_pos = 0;
while (token_pos < this.field_size_first_formula)
{
this.field_not_used_2 = in.readShort();
//read sec formula data condition
- //Not sure if this was needed or not...
- try {
- in.skip(this.field_size_sec_formula);
- } catch(IOException e) {
- e.printStackTrace();
- throw new IllegalStateException(e.getMessage());
+ if (false) { // TODO - prior to bug 44710 this 'skip' was being executed. write a junit to confirm this fix
+ try {
+ in.skip(this.field_size_sec_formula);
+ } catch(IOException e) {
+ e.printStackTrace();
+ throw new IllegalStateException(e.getMessage());
+ }
}
-
token_pos = 0;
while (token_pos < this.field_size_sec_formula)
{
/**@todo DVRecord = Serializare */
- private class StringHandler
+ private static final class StringHandler
{
private int _string_length = 0x0001;
private byte _string_unicode_flag = 0x00;
*/
public final class CellRange
{
- /**
- * max index for both row and column<p/>
- *
- * Note - this value converts to <tt>-1</tt> when cast to a <tt>short</tt>
- */
- private static final int MAX_INDEX = Integer.MAX_VALUE;
+ /** max 65536 rows in BIFF8 */
+ private static final int LAST_ROW_INDEX = 0x00FFFF;
+ /** max 256 columns in BIFF8 */
+ private static final int LAST_COLUMN_INDEX = 0x00FF;
private static final Region[] EMPTY_REGION_ARRAY = { };
+ ", " + firstColumn + ", " + lastColumn + ")");
}
_firstRow = firstRow;
- _lastRow = convertM1ToMax(lastRow);
+ _lastRow = convertM1ToMax(lastRow, LAST_ROW_INDEX);
_firstColumn = firstColumn;
- _lastColumn = convertM1ToMax(lastColumn);
+ _lastColumn = convertM1ToMax(lastColumn, LAST_COLUMN_INDEX);
}
- private static int convertM1ToMax(int lastIx) {
+ /**
+ * Range arithmetic is easier when using a large positive number for 'max row or column'
+ * instead of <tt>-1</tt>.
+ */
+ private static int convertM1ToMax(int lastIx, int maxIndex) {
if(lastIx < 0) {
- return MAX_INDEX;
- }
- return lastIx;
- }
- private static int convertMaxToM1(int lastIx) {
- if(lastIx == MAX_INDEX) {
- return -1;
+ return maxIndex;
}
return lastIx;
}
public boolean isFullColumnRange() {
- return _firstColumn == 0 && _lastColumn == MAX_INDEX;
+ return _firstRow == 0 && _lastRow == LAST_ROW_INDEX;
}
public boolean isFullRowRange() {
- return _firstRow == 0 && _lastRow == MAX_INDEX;
+ return _firstColumn == 0 && _lastColumn == LAST_COLUMN_INDEX;
}
- public CellRange(Region r) {
- this(r.getRowFrom(), r.getRowTo(), r.getColumnFrom(), r.getColumnTo());
+ 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 == -1) {
- if(firstRow !=0) {
- return false;
- }
+ if(lastRow < 0 || lastRow > LAST_ROW_INDEX) {
+ return false;
}
- if(firstRow < 0 || lastRow < -1) {
+ if(firstRow < 0 || firstRow > LAST_ROW_INDEX) {
return false;
}
- if(lastColumn == -1) {
- if(firstColumn !=0) {
- return false;
- }
+ if(lastColumn < 0 || lastColumn > LAST_COLUMN_INDEX) {
+ return false;
}
- if(firstColumn < 0 || lastColumn < -1) {
+ if(firstColumn < 0 || firstColumn > LAST_COLUMN_INDEX) {
return false;
}
return true;
{
return _firstRow;
}
- /**
- * @return <tt>-1</tt> for whole column ranges
- */
public int getLastRow()
{
- return convertMaxToM1(_lastRow);
+ return _lastRow;
}
public int getFirstColumn()
{
return _firstColumn;
}
- /**
- * @return <tt>-1</tt> for whole row ranges
- */
public int getLastColumn()
{
- return convertMaxToM1(_lastColumn);
+ return _lastColumn;
}
public static final int NO_INTERSECTION = 1;
CellRange[] result = new CellRange[regions.length];
for( int i=0; i<regions.length; i++)
{
- result[i] = new CellRange(regions[i]);
+ result[i] = createFromRegion(regions[i]);
}
return result;
}
private Region convertToRegion() {
- int lastRow = convertMaxToM1(_lastRow);
- int lastColumn = convertMaxToM1(_lastColumn);
- return new Region(_firstRow, (short)_firstColumn, lastRow, (short)lastColumn);
+ return new Region(_firstRow, (short)_firstColumn, _lastRow, (short)_lastColumn);
}
169 COUNTA 0 30 V R \r
183 PRODUCT 0 30 V R \r
184 FACT 1 1 V V \r
+189 DPRODUCT 3 3 V R R R \r
190 ISNONTEXT 1 1 V V \r
-191 DPRODUCT 3 3 V R R R \r
193 STDEVP 1 30 V R \r
194 VARP 1 30 V R \r
195 DSTDEVP 3 3 V R R R \r
return paragraphStyle == null ? 0 : paragraphStyle.getReservedField();
}
+ /**
+ * Sets indentation level
+ *
+ * @param level indentation level. Must be in the range [0, 5]
+ */
+ public void setIndentLevel(int level) {
+ if(paragraphStyle != null ) paragraphStyle.setReservedField((short)level);
+ }
+
/**
* Sets whether this rich text run has bullets
*/
import org.apache.poi.hssf.record.formula.Area3DPtg;
import java.util.ArrayList;
+import java.util.Iterator;
import java.util.List;
import java.util.Stack;
*/
public class HSSFChart
{
+ private ChartRecord chartRecord;
+ private SeriesRecord seriesRecord;
+
+ private ChartTitleFormatRecord chartTitleFormat;
+ private SeriesTextRecord chartTitleText;
+
+ private HSSFChart(ChartRecord chartRecord) {
+ this.chartRecord = chartRecord;
+ }
/**
* Creates a bar chart. API needs some work. :)
sheet.insertChartRecords( records );
workbook.insertChartRecord();
}
+
+ /**
+ * Returns all the charts for the given sheet.
+ *
+ * NOTE: Does not yet work... checking it in just so others
+ * can take a look.
+ */
+ public static HSSFChart[] getSheetCharts(HSSFSheet sheet) {
+ List charts = new ArrayList();
+ HSSFChart lastChart = null;
+
+ // Find records of interest
+ List records = sheet.getSheet().getRecords();
+ for(Iterator it = records.iterator(); it.hasNext();) {
+ Record r = (Record)it.next();
+ System.err.println(r);
+
+ if(r instanceof DrawingRecord) {
+ DrawingRecord dr = (DrawingRecord)r;
+ }
+
+ if(r instanceof ChartRecord) {
+ lastChart = new HSSFChart((ChartRecord)r);
+ charts.add(lastChart);
+ }
+ if(r instanceof SeriesRecord) {
+ lastChart.seriesRecord = (SeriesRecord)r;
+ }
+ if(r instanceof ChartTitleFormatRecord) {
+ lastChart.chartTitleFormat =
+ (ChartTitleFormatRecord)r;
+ }
+ if(r instanceof SeriesTextRecord) {
+ lastChart.chartTitleText =
+ (SeriesTextRecord)r;
+ }
+ }
+
+ return (HSSFChart[])
+ charts.toArray( new HSSFChart[charts.size()] );
+ }
+
+
+ /**
+ * Returns the chart's title, if there is one,
+ * or null if not
+ */
+ public String getChartTitle() {
+ if(chartTitleText != null) {
+ return chartTitleText.getText();
+ }
+ return null;
+ }
+
+ /**
+ * Changes the chart's title, but only if there
+ * was one already.
+ * TODO - add in the records if not
+ */
+ public void setChartTitle(String title) {
+ if(chartTitleText != null) {
+ chartTitleText.setText(title);
+ } else {
+ throw new IllegalStateException("No chart title found to change");
+ }
+ }
+
+
private EOFRecord createEOFRecord()
{
--- /dev/null
+/* ====================================================================
+ Licensed to the Apache Software Foundation (ASF) under one or more
+ contributor license agreements. See the NOTICE file distributed with
+ this work for additional information regarding copyright ownership.
+ The ASF licenses this file to You under the Apache License, Version 2.0
+ (the "License"); you may not use this file except in compliance with
+ the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+==================================================================== */
+package org.apache.poi.hssf.usermodel;
+
+import java.io.File;
+import java.io.FileInputStream;
+
+import junit.framework.TestCase;
+
+public class TestHSSFChart extends TestCase {
+ private String dirName;
+
+ protected void setUp() throws Exception {
+ dirName = System.getProperty("HSSF.testdata.path");
+ }
+
+ public void testSingleChart() throws Exception {
+
+ }
+
+ public void testTwoCharts() throws Exception {
+
+ }
+
+ public void BROKENtestThreeCharts() throws Exception {
+ HSSFWorkbook wb = new HSSFWorkbook(
+ new FileInputStream(new File(dirName, "WithThreeCharts.xls"))
+ );
+
+ HSSFSheet s1 = wb.getSheetAt(0);
+ HSSFSheet s2 = wb.getSheetAt(1);
+ HSSFSheet s3 = wb.getSheetAt(2);
+
+ assertEquals(0, HSSFChart.getSheetCharts(s1).length);
+ assertEquals(2, HSSFChart.getSheetCharts(s2).length);
+ assertEquals(1, HSSFChart.getSheetCharts(s3).length);
+
+ HSSFChart[] charts;
+
+ charts = HSSFChart.getSheetCharts(s2);
+ assertNull(charts[0].getChartTitle());
+ assertEquals("Pie Chart Title Thingy", charts[1].getChartTitle());
+
+ charts = HSSFChart.getSheetCharts(s3);
+ assertEquals("Sheet 3 Chart with Title", charts[1].getChartTitle());
+ }
+}
package org.apache.poi.hssf.record;
-import org.apache.poi.hssf.record.aggregates.AllRecordAggregateTests;
-import org.apache.poi.hssf.record.formula.AllFormulaTests;
-import org.apache.poi.hssf.record.formula.functions.AllIndividualFunctionEvaluationTests;
-
import junit.framework.Test;
import junit.framework.TestSuite;
+import org.apache.poi.hssf.record.aggregates.AllRecordAggregateTests;
+import org.apache.poi.hssf.record.cf.TestCellRange;
+import org.apache.poi.hssf.record.formula.AllFormulaTests;
+
/**
* Collects all tests for package <tt>org.apache.poi.hssf.record</tt>.
*
result.addTestSuite(TestUnicodeString.class);
result.addTestSuite(TestUnitsRecord.class);
result.addTestSuite(TestValueRangeRecord.class);
+ result.addTestSuite(TestCellRange.class);
return result;
}
}
package org.apache.poi.hssf.record;
+import junit.framework.AssertionFailedError;
import junit.framework.TestCase;
import org.apache.poi.hssf.record.cf.CellRange;
{
CFHeaderRecord record = new CFHeaderRecord();
CellRange[] ranges = {
- new CellRange(0,-1,5,5),
- new CellRange(0,-1,6,6),
+ 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),
assertEquals(6,ranges.length);
CellRange enclosingCellRange = record.getEnclosingCellRange();
assertEquals(0, enclosingCellRange.getFirstRow());
- assertEquals(-1, enclosingCellRange.getLastRow());
+ assertEquals(65535, enclosingCellRange.getLastRow());
assertEquals(0, enclosingCellRange.getFirstColumn());
assertEquals(6, enclosingCellRange.getLastColumn());
record.setNeedRecalculation(true);
}
public void testSerialization() {
- byte[] recordData = new byte[]
+ byte[] recordData =
{
(byte)0x03, (byte)0x00,
(byte)0x01, (byte)0x00,
(byte)0x00, (byte)0x00,
(byte)0x03, (byte)0x00,
- (byte)0x04, (byte)0x00,
+ (byte)0x04, (byte)0x00, // nRegions
(byte)0x00, (byte)0x00,
(byte)0x01, (byte)0x00,
assertEquals("#CFRULES", 3, record.getNumberOfConditionalFormats());
assertTrue(record.getNeedRecalculation());
- CellRange enclosingCellRange = record.getEnclosingCellRange();
- assertEquals(0, enclosingCellRange.getFirstRow());
- assertEquals(3, enclosingCellRange.getLastRow());
- assertEquals(0, enclosingCellRange.getFirstColumn());
- assertEquals(3, enclosingCellRange.getLastColumn());
+ confirm(record.getEnclosingCellRange(), 0, 3, 0, 3);
CellRange[] ranges = record.getCellRanges();
- CellRange range0 = ranges[0];
- assertEquals(0, range0.getFirstRow());
- assertEquals(1, range0.getLastRow());
- assertEquals(0, range0.getFirstColumn());
- assertEquals(1, range0.getLastColumn());
- CellRange range1 = ranges[1];
- assertEquals(0, range1.getFirstRow());
- assertEquals(1, range1.getLastRow());
- assertEquals(2, range1.getFirstColumn());
- assertEquals(3, range1.getLastColumn());
- CellRange range2 = ranges[2];
- assertEquals(2, range2.getFirstRow());
- assertEquals(3, range2.getLastRow());
- assertEquals(0, range2.getFirstColumn());
- assertEquals(1, range2.getLastColumn());
- CellRange range3 = ranges[3];
- assertEquals(2, range3.getFirstRow());
- assertEquals(3, range3.getLastRow());
- assertEquals(2, range3.getFirstColumn());
- assertEquals(3, range3.getLastColumn());
+ assertEquals(4, ranges.length);
+ confirm(ranges[0], 0, 1, 0, 1);
+ confirm(ranges[1], 0, 1, 2, 3);
+ confirm(ranges[2], 2, 3, 0, 1);
+ confirm(ranges[3], 2, 3, 2, 3);
assertEquals(recordData.length+4, record.getRecordSize());
byte[] output = record.serialize();
assertEquals("Output size", recordData.length+4, output.length); //includes sid+recordlength
- for (int i = 0; i < recordData.length;i++)
+ for (int i = 0; i < recordData.length; i++)
{
assertEquals("CFHeaderRecord doesn't match", recordData[i], output[i+4]);
}
}
+ public void testExtremeRows() {
+ byte[] recordData = {
+ (byte)0x13, (byte)0x00, // nFormats
+ (byte)0x00, (byte)0x00,
+
+ (byte)0x00, (byte)0x00,
+ (byte)0xFF, (byte)0xFF,
+ (byte)0x00, (byte)0x00,
+ (byte)0xFF, (byte)0x00,
+
+ (byte)0x03, (byte)0x00, // nRegions
+
+ (byte)0x40, (byte)0x9C,
+ (byte)0x50, (byte)0xC3,
+ (byte)0x02, (byte)0x00,
+ (byte)0x02, (byte)0x00,
+
+ (byte)0x00, (byte)0x00,
+ (byte)0xFF, (byte)0xFF,
+ (byte)0x05, (byte)0x00,
+ (byte)0x05, (byte)0x00,
+
+ (byte)0x07, (byte)0x00,
+ (byte)0x07, (byte)0x00,
+ (byte)0x00, (byte)0x00,
+ (byte)0xFF, (byte)0x00,
+ };
+
+ CFHeaderRecord record;
+ try {
+ record = new CFHeaderRecord(new TestcaseRecordInputStream(CFHeaderRecord.sid, (short)recordData.length, recordData));
+ } catch (IllegalArgumentException e) {
+ if(e.getMessage().equals("invalid cell range (-25536, 2, -15536, 2)")) {
+ throw new AssertionFailedError("Identified bug 44739b");
+ }
+ throw e;
+ }
+
+ assertEquals("#CFRULES", 19, record.getNumberOfConditionalFormats());
+ assertFalse(record.getNeedRecalculation());
+ confirm(record.getEnclosingCellRange(), 0, 65535, 0, 255);
+ CellRange[] ranges = record.getCellRanges();
+ assertEquals(3, ranges.length);
+ confirm(ranges[0], 40000, 50000, 2, 2);
+ confirm(ranges[1], 0, 65535, 5, 5);
+ confirm(ranges[2], 7, 7, 0, 255);
+
+ byte[] output = record.serialize();
+
+ assertEquals("Output size", recordData.length+4, output.length); //includes sid+recordlength
+
+ for (int i = 0; i < recordData.length;i++) {
+ assertEquals("CFHeaderRecord doesn't match", recordData[i], output[i+4]);
+ }
+ }
+
+
+ private static void confirm(CellRange 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)
{
package org.apache.poi.hssf.record.cf;
+import junit.framework.AssertionFailedError;
import junit.framework.TestCase;
/**
* Tests CellRange operations.
*/
-public class TestCellRange extends TestCase
+public final class TestCellRange extends TestCase
{
- private static final CellRange biggest = new CellRange( 0, -1, 0,-1);
- private static final CellRange tenthColumn = new CellRange( 0, -1,10,10);
- private static final CellRange tenthRow = new CellRange(10, 10, 0,-1);
- private static final CellRange box10x10 = new CellRange( 0, 10, 0,10);
- private static final CellRange box9x9 = new CellRange( 0, 9, 0, 9);
- private static final CellRange box10to20c = new CellRange( 0, 10,10,20);
- private static final CellRange oneCell = new CellRange(10, 10,10,10);
+ 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);
- boolean [][] contanis = new boolean[][]
+ private static final CellRange[] sampleRanges = {
+ biggest, tenthColumn, tenthRow, box10x10, box9x9, box10to20c, oneCell,
+ };
+
+ /** cross-reference of <tt>contains()</tt> operations for sampleRanges against itself */
+ private static final boolean [][] containsExpectedResults =
{
- // biggest, tenthColumn, tenthRow, box10x10, box9x9, box10to20c, oneCell
- /*biggest */ new boolean[]{true, true , true , true , true , true , true},
- /*tenthColumn*/ new boolean[]{false, true , false, false, false, false, true},
- /*tenthRow */ new boolean[]{false, false, true , false, false, false, true},
- /*box10x10 */ new boolean[]{false, false, false, true , true , false, true},
- /*box9x9 */ new boolean[]{false, false, false, false, true , false, false},
- /*box10to20c */ new boolean[]{false, false, false, false, false, true , true},
- /*oneCell */ new boolean[]{false, false, false, false, false, false, true},
+ // biggest, tenthColumn, tenthRow, box10x10, box9x9, box10to20c, oneCell
+ /*biggest */ {true, true , true , true , true , true , true},
+ /*tenthColumn*/ {false, true , false, false, false, false, true},
+ /*tenthRow */ {false, false, true , false, false, false, true},
+ /*box10x10 */ {false, false, false, true , true , false, true},
+ /*box9x9 */ {false, false, false, false, true , false, false},
+ /*box10to20c */ {false, false, false, false, false, true , true},
+ /*oneCell */ {false, false, false, false, false, false, true},
} ;
-
-
- public void testContainsMethod()
- {
- CellRange [] ranges = new CellRange[]{biggest,tenthColumn,tenthRow,box10x10,box9x9,box10to20c,oneCell};
- testContainsMethod(contanis,ranges);
+
+ /**
+ * @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) {
+ // max row & max col limit as per BIFF8
+ return new CellRange(
+ firstRow,
+ lastRow == -1 ? 0xFFFF : lastRow,
+ firstCol,
+ lastCol == -1 ? 0x00FF : lastCol);
}
- private void testContainsMethod(boolean[][]contains,CellRange[] ranges)
+ public void testContainsMethod()
{
+ CellRange [] ranges = sampleRanges;
for(int i=0; i!=ranges.length;i++)
{
for(int j=0; j!=ranges.length;j++)
{
- assertEquals("("+i+","+j+"): ",contains[i][j],ranges[i].contains(ranges[j]));
+ boolean expectedResult = containsExpectedResults[i][j];
+ assertEquals("("+i+","+j+"): ", expectedResult, ranges[i].contains(ranges[j]));
}
}
}
- private static final CellRange col1 = new CellRange( 0, -1, 1,1);
- private static final CellRange col2 = new CellRange( 0, -1, 2,2);
- private static final CellRange row1 = new CellRange( 1, 1, 0,-1);
- private static final CellRange row2 = new CellRange( 2, 2, 0,-1);
+ 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 CellRange box0 = new CellRange( 0, 2, 0,2);
- private static final CellRange box1 = new CellRange( 0, 1, 0,1);
- private static final CellRange box2 = new CellRange( 0, 1, 2,3);
- private static final CellRange box3 = new CellRange( 2, 3, 0,1);
- private static final CellRange box4 = new CellRange( 2, 3, 2,3);
- private static final CellRange box5 = new CellRange( 1, 3, 1,3);
+ 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);
public void testHasSharedBorderMethod()
{
public void testIntersectMethod()
{
- assertEquals( CellRange.OVERLAP,box0.intersect(box5));
- assertEquals( CellRange.OVERLAP,box5.intersect(box0));
+ 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.INSIDE,tenthColumn.intersect(tenthColumn));
assertEquals(CellRange.INSIDE,tenthRow.intersect(tenthRow));
}
+
+ /**
+ * Cell ranges like the following are valid
+ * =$C:$IV,$B$1:$B$8,$B$10:$B$65536,$A:$A
+ */
+ public void testCreate() {
+ CellRange cr;
+
+ cr = createCR(0, -1, 2, 255); // $C:$IV
+ confirmRange(cr, false, true);
+ cr = createCR(0, 7, 1, 1); // $B$1:$B$8
+
+ try {
+ cr = createCR(9, -1, 1, 1); // $B$65536
+ } catch (IllegalArgumentException e) {
+ if(e.getMessage().startsWith("invalid cell range")) {
+ throw new AssertionFailedError("Identified bug 44739");
+ }
+ throw e;
+ }
+ cr = createCR(0, -1, 0, 0); // $A:$A
+ }
+
+ private static void confirmRange(CellRange cr, boolean isFullRow, boolean isFullColumn) {
+ assertEquals("isFullRowRange", isFullRow, cr.isFullRowRange());
+ assertEquals("isFullColumnRange", isFullColumn, cr.isFullColumnRange());
+ }
}
*
* @author Josh Micich
*/
-public class AllFormulaTests {
+public final class AllFormulaTests {
public static Test suite() {
TestSuite result = new TestSuite(AllFormulaTests.class.getName());
result.addTestSuite(TestReferencePtg.class);
result.addTestSuite(TestSheetNameFormatter.class);
result.addTestSuite(TestUnionPtg.class);
- result.addTest(AllFormulaFunctionTests.suite());
return result;
}
}
import org.apache.poi.hssf.record.formula.FuncVarPtg;
import org.apache.poi.hssf.record.formula.Ptg;
/**
+ * Tests parsing of some built-in functions that were not properly
+ * registered in POI as bug #44675, #44733 (March/April 2008).
+ *
* @author Josh Micich
*/
public final class TestParseMissingBuiltInFuncs extends TestCase {
Ptg[] ptgs = parse(formula);
Ptg ptgF = ptgs[ptgs.length-1]; // func is last RPN token in all these formulas
+ // Check critical things in the Ptg array encoding.
if(!(ptgF instanceof AbstractFunctionPtg)) {
throw new RuntimeException("function token missing");
}
throw new AssertionFailedError("Failed to recognise built-in function in formula '"
+ formula + "'");
}
-
assertEquals(expPtgArraySize, ptgs.length);
assertEquals(funcIx, func.getFunctionIndex());
Class expCls = isVarArgFunc ? FuncVarPtg.class : FuncPtg.class;
assertEquals(expCls, ptgF.getClass());
+
+ // check that parsed Ptg array converts back to formula text OK
+ Workbook book = Workbook.createWorkbook();
+ String reRenderedFormula = FormulaParser.toFormulaString(book, ptgs);
+ assertEquals(formula, reRenderedFormula);
}
public void testDatedif() {
public void testIsnontext() {
confirmFunc("ISNONTEXT(\"abc\")", 2, false, 190);
}
+ public void testDproduct() {
+ confirmFunc("DPRODUCT(C1:E5,\"HarvestYield\",G1:H2)", 4, false, 189);
+ }
}
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
+import java.lang.reflect.InvocationTargetException;
+import org.apache.poi.hssf.record.RecordFormatException;
import org.apache.poi.hssf.usermodel.HSSFSheet;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import junit.framework.TestCase;
/**
* Tests reading from a sample spreadsheet some built-in functions that were not properly
- * registered in POI as bug #44675 (March 2008).
+ * registered in POI as bug #44675, #44733 (March/April 2008).
*
* @author Josh Micich
*/
public final class TestReadMissingBuiltInFuncs extends TestCase {
- private HSSFSheet sht;
+ /**
+ * This spreadsheet has examples of calls to the interesting built-in functions in cells A1:A7
+ */
+ private static final String SAMPLE_SPREADSHEET_FILE_NAME = "missingFuncs44675.xls";
+ private static HSSFSheet _sheet;
- protected void setUp() {
- String cwd = System.getProperty("HSSF.testdata.path");
- HSSFWorkbook wb;
- try {
- InputStream is = new FileInputStream(new File(cwd, "missingFuncs44675.xls"));
- wb = new HSSFWorkbook(is);
- } catch (IOException e) {
- throw new RuntimeException(e);
+ private static HSSFSheet getSheet() {
+ if (_sheet == null) {
+ String cwd = System.getProperty("HSSF.testdata.path");
+ HSSFWorkbook wb;
+ try {
+ InputStream is = new FileInputStream(new File(cwd, SAMPLE_SPREADSHEET_FILE_NAME));
+ wb = new HSSFWorkbook(is);
+ } catch (IOException e) {
+ throw new RuntimeException(e);
+ }
+ _sheet = wb.getSheetAt(0);
}
- sht = wb.getSheetAt(0);
+ return _sheet;
}
public void testDatedif() {
}
assertEquals("ISNONTEXT(\"abc\")", formula);
}
+ public void testDproduct() {
+
+ String formula = getCellFormula(6);
+ assertEquals("DPRODUCT(C1:E5,\"HarvestYield\",G1:H2)", formula);
+ }
private String getCellFormula(int rowIx) {
- String result = sht.getRow(rowIx).getCell((short)0).getCellFormula();
+ HSSFSheet sheet;
+ try {
+ sheet = getSheet();
+ } catch (RecordFormatException e) {
+ if(e.getCause() instanceof InvocationTargetException) {
+ InvocationTargetException ite = (InvocationTargetException) e.getCause();
+ if(ite.getTargetException() instanceof RuntimeException) {
+ RuntimeException re = (RuntimeException) ite.getTargetException();
+ if(re.getMessage().equals("Invalid built-in function index (189)")) {
+ throw afe("DPRODUCT() registered with wrong index");
+ }
+ }
+ }
+ // some other unexpected error
+ throw e;
+ }
+ String result = sheet.getRow(rowIx).getCell((short)0).getCellFormula();
if (false) {
System.err.println(result);
}
result.addTestSuite(TestFormulas.class);
result.addTestSuite(TestHSSFCell.class);
result.addTestSuite(TestHSSFClientAnchor.class);
+ result.addTestSuite(TestHSSFConditionalFormatting.class);
result.addTestSuite(TestHSSFComment.class);
result.addTestSuite(TestHSSFDateUtil.class);
result.addTestSuite(TestHSSFHeaderFooter.class);
--- /dev/null
+/* ====================================================================
+ Licensed to the Apache Software Foundation (ASF) under one or more
+ contributor license agreements. See the NOTICE file distributed with
+ this work for additional information regarding copyright ownership.
+ The ASF licenses this file to You under the Apache License, Version 2.0
+ (the "License"); you may not use this file except in compliance with
+ the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+==================================================================== */
+
+package org.apache.poi.hssf.usermodel;
+
+import junit.framework.TestCase;
+
+import org.apache.poi.hssf.record.CFRuleRecord.ComparisonOperator;
+import org.apache.poi.hssf.util.HSSFColor;
+import org.apache.poi.hssf.util.Region;
+/**
+ *
+ * @author Dmitriy Kumshayev
+ */
+public final class TestHSSFConditionalFormatting extends TestCase
+{
+ public void testLastAndFirstColumns()
+ {
+ HSSFWorkbook workbook = new HSSFWorkbook();
+ HSSFSheet sheet = workbook.createSheet();
+ String formula = "7";
+
+ HSSFFontFormatting fontFmt = new HSSFFontFormatting();
+ fontFmt.setFontStyle(true, false);
+
+ HSSFBorderFormatting bordFmt = new HSSFBorderFormatting();
+ bordFmt.setBorderBottom(HSSFBorderFormatting.BORDER_THIN);
+ bordFmt.setBorderTop(HSSFBorderFormatting.BORDER_THICK);
+ bordFmt.setBorderLeft(HSSFBorderFormatting.BORDER_DASHED);
+ bordFmt.setBorderRight(HSSFBorderFormatting.BORDER_DOTTED);
+
+ HSSFPatternFormatting patternFmt = new HSSFPatternFormatting();
+ patternFmt.setFillBackgroundColor(HSSFColor.RED.index);
+
+ HSSFConditionalFormattingRule [] cfRules =
+ {
+ sheet.createConditionalFormattingRule(formula, fontFmt, bordFmt, patternFmt),
+ sheet.createConditionalFormattingRule(ComparisonOperator.BETWEEN, "1", "2", fontFmt, bordFmt, patternFmt)
+ };
+
+ short col = 1;
+ Region [] regions =
+ {
+ new Region(0,col,65535,col)
+ };
+
+ sheet.addConditionalFormatting(regions, cfRules);
+ sheet.addConditionalFormatting(regions, cfRules);
+
+ // Verification
+ assertEquals(2, sheet.getNumConditionalFormattings());
+ sheet.removeConditionalFormatting(1);
+ assertEquals(1, sheet.getNumConditionalFormattings());
+ HSSFConditionalFormatting cf = sheet.getConditionalFormattingAt(0);
+ assertNotNull(cf);
+
+ regions = cf.getFormattingRegions();
+ 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());
+
+ assertEquals(2, cf.getNumberOfRules());
+
+ HSSFConditionalFormattingRule rule1 = cf.getRule(0);
+ assertEquals("7",rule1.getFormula1());
+ assertNull(rule1.getFormula2());
+
+ HSSFConditionalFormattingRule rule2 = cf.getRule(1);
+ assertEquals("2",rule2.getFormula2());
+ assertEquals("1",rule2.getFormula1());
+ }
+}
+++ /dev/null
-/* ====================================================================
- Licensed to the Apache Software Foundation (ASF) under one or more
- contributor license agreements. See the NOTICE file distributed with
- this work for additional information regarding copyright ownership.
- The ASF licenses this file to You under the Apache License, Version 2.0
- (the "License"); you may not use this file except in compliance with
- the License. You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
-==================================================================== */
-
-package org.apache.poi.hssf.usermodel;
-
-import junit.framework.TestCase;
-
-import org.apache.poi.hssf.record.CFRuleRecord.ComparisonOperator;
-import org.apache.poi.hssf.util.HSSFColor;
-import org.apache.poi.hssf.util.Region;
-/**
- *
- * @author Dmitriy Kumshayev
- */
-public final class TestHSSFConfditionalFormatting extends TestCase
-{
- public void testLastAndFirstColumns()
- {
- HSSFWorkbook workbook = new HSSFWorkbook();
- HSSFSheet sheet = workbook.createSheet();
- String formula = "7";
-
- HSSFFontFormatting fontFmt = new HSSFFontFormatting();
- fontFmt.setFontStyle(true, false);
-
- HSSFBorderFormatting bordFmt = new HSSFBorderFormatting();
- bordFmt.setBorderBottom(HSSFBorderFormatting.BORDER_THIN);
- bordFmt.setBorderTop(HSSFBorderFormatting.BORDER_THICK);
- bordFmt.setBorderLeft(HSSFBorderFormatting.BORDER_DASHED);
- bordFmt.setBorderRight(HSSFBorderFormatting.BORDER_DOTTED);
-
- HSSFPatternFormatting patternFmt = new HSSFPatternFormatting();
- patternFmt.setFillBackgroundColor(HSSFColor.RED.index);
-
- HSSFConditionalFormattingRule [] cfRules =
- {
- sheet.createConditionalFormattingRule(formula, fontFmt, bordFmt, patternFmt),
- sheet.createConditionalFormattingRule(ComparisonOperator.BETWEEN, "1", "2", fontFmt, bordFmt, patternFmt)
- };
-
- short col = 1;
- Region [] regions =
- {
- new Region(0,col,-1,col)
- };
-
- sheet.addConditionalFormatting(regions, cfRules);
- sheet.addConditionalFormatting(regions, cfRules);
-
- // Verification
- assertEquals(2, sheet.getNumConditionalFormattings());
- sheet.removeConditionalFormatting(1);
- assertEquals(1, sheet.getNumConditionalFormattings());
- HSSFConditionalFormatting cf = sheet.getConditionalFormattingAt(0);
- assertNotNull(cf);
-
- regions = cf.getFormattingRegions();
- assertNotNull(regions);
- assertEquals(1, regions.length);
- Region r = regions[0];
- assertEquals(1, r.getColumnFrom());
- assertEquals(1, r.getColumnTo());
- assertEquals(0, r.getRowFrom());
- assertEquals(-1, r.getRowTo());
-
- assertEquals(2, cf.getNumberOfRules());
-
- HSSFConditionalFormattingRule rule1 = cf.getRule(0);
- assertEquals("7",rule1.getFormula1());
- assertNull(rule1.getFormula2());
-
- HSSFConditionalFormattingRule rule2 = cf.getRule(1);
- assertEquals("2",rule2.getFormula2());
- assertEquals("1",rule2.getFormula1());
- }
-}
public static void main(java.lang.String[] args) {
junit.textui.TestRunner.run(TestHSSFSheet.class);
- }
+ }
+
+ public void testColumnWidth() throws Exception {
+ //check we can correctly read column widths from a reference workbook
+ String filename = System.getProperty("HSSF.testdata.path") + "/colwidth.xls";
+ HSSFWorkbook wb = new HSSFWorkbook(new FileInputStream(filename));
+
+ //reference values
+ int[] ref = {365, 548, 731, 914, 1097, 1280, 1462, 1645, 1828, 2011, 2194, 2377, 2560, 2742, 2925, 3108, 3291, 3474, 3657};
+
+ HSSFSheet sh = wb.getSheetAt(0);
+ for (char i = 'A'; i <= 'S'; i++) {
+ int idx = i - 'A';
+ int w = sh.getColumnWidth((short)idx);
+ assertEquals(ref[idx], w);
+ }
+
+ //the second sheet doesn't have overridden column widths
+ sh = wb.getSheetAt(1);
+ int def_width = sh.getDefaultColumnWidth();
+ for (char i = 'A'; i <= 'S'; i++) {
+ int idx = i - 'A';
+ int w = sh.getColumnWidth((short)idx);
+ //getDefaultColumnWidth returns width measued in characters
+ //getColumnWidth returns width measued in 1/256th units
+ assertEquals(def_width*256, w);
+ }
+
+ //test new workbook
+ wb = new HSSFWorkbook();
+ sh = wb.createSheet();
+ sh.setDefaultColumnWidth((short)10);
+ assertEquals(10, sh.getDefaultColumnWidth());
+ assertEquals(256*10, sh.getColumnWidth((short)0));
+ assertEquals(256*10, sh.getColumnWidth((short)1));
+ assertEquals(256*10, sh.getColumnWidth((short)2));
+ for (char i = 'D'; i <= 'F'; i++) {
+ short w = (short)(256*12);
+ sh.setColumnWidth((short)i, w);
+ assertEquals(w, sh.getColumnWidth((short)i));
+ }
+
+ //serialize and read again
+ ByteArrayOutputStream out = new ByteArrayOutputStream();
+ wb.write(out);
+ out.close();
+
+ wb = new HSSFWorkbook(new ByteArrayInputStream(out.toByteArray()));
+ sh = wb.getSheetAt(0);
+ assertEquals(10, sh.getDefaultColumnWidth());
+ //columns A-C have default width
+ assertEquals(256*10, sh.getColumnWidth((short)0));
+ assertEquals(256*10, sh.getColumnWidth((short)1));
+ assertEquals(256*10, sh.getColumnWidth((short)2));
+ //columns D-F have custom wodth
+ for (char i = 'D'; i <= 'F'; i++) {
+ short w = (short)(256*12);
+ assertEquals(w, sh.getColumnWidth((short)i));
+ }
+
+ }
}