<action dev="POI-DEVELOPERS" type="add">Created a common interface for handling Excel files, irrespective of if they are .xls or .xlsx</action>
</release>
<release version="3.1.1-alpha1" date="2008-??-??">
+ <action dev="POI-DEVELOPERS" type="add">Initial support for embedded movies and controls in HSLF</action>
+ <action dev="POI-DEVELOPERS" type="fix">45358 - signed/unsigned error when parsing 3-d area refs, performance problem evaluating area refs, and ClassCastExcecption in IF()</action>
<action dev="POI-DEVELOPERS" type="add">Support for HPBF Publisher hyperlinks, including during text extraction</action>
<action dev="POI-DEVELOPERS" type="fix">26321 and 44958 - preserve position of ArrayRecords and TableRecords among cell value records</action>
<action dev="POI-DEVELOPERS" type="fix">Impove empty header or footer handling in HWPF HeaderStories</action>
think that the second 4 bytes of text describes the format
of data block at the offset. The format of the text block
is easy, but we're still trying to figure out the others.</p>
+
+ <section><title>Structure of TEXT bit</title>
+ <p>This is very simple. All the text for the document is
+ stored in a single bit of the Quill CONTENTS. The text
+ is stored as little endian 16 bit unicode strings.</p>
+ </section>
+ <section><title>Structure of PLC bit</title>
+ <p>The first four bytes seem to hold the count of the
+ entries in the bit, and the second four bytes seem to hold
+ the type. There is then some pre-data, and then data for
+ each of the entries, the exact format dependant on the type.</p>
+ <p>Type 0 has 4 2 byte unsigned ints, then a pair of 2 byte
+ unsigned ints for each entry.</p>
+ <p>Type 4 has 4 2 byte unsigned ints, then a pair of 4 byte
+ unsigned ints for each entry.</p>
+ <p>Type 8 has 7 2 byte unsigned ints, then a pair of 4 byte
+ unsigned ints for each entry.</p>
+ <p>Type 12 holds hyperlinks, and is very much more complex.
+ See <code>org.apache.poi.hpbf.model.qcbits.QCPLCBit</code>
+ for our best guess as to how the contents match up.</p>
+ </section>
</section>
</body>
</document>
lots of offsets to other parts of the file.</p>
<p>Our initial aim is to provude a text extractor for the format
(now done), and be able to extract hyperlinks from within
- the document (not yet supported). Additional low level
+ the document (partly supported). Additional low level
code to process the file format may follow, if there
is demand and developer interest warrant it.</p>
<p>At this time, there is no <em>usermodel</em> api or similar.
<action dev="POI-DEVELOPERS" type="add">Created a common interface for handling Excel files, irrespective of if they are .xls or .xlsx</action>
</release>
<release version="3.1.1-alpha1" date="2008-??-??">
+ <action dev="POI-DEVELOPERS" type="add">Initial support for embedded movies and controls in HSLF</action>
+ <action dev="POI-DEVELOPERS" type="fix">45358 - signed/unsigned error when parsing 3-d area refs, performance problem evaluating area refs, and ClassCastExcecption in IF()</action>
<action dev="POI-DEVELOPERS" type="add">Support for HPBF Publisher hyperlinks, including during text extraction</action>
<action dev="POI-DEVELOPERS" type="fix">26321 and 44958 - preserve position of ArrayRecords and TableRecords among cell value records</action>
<action dev="POI-DEVELOPERS" type="fix">Impove empty header or footer handling in HWPF HeaderStories</action>
import org.apache.poi.hssf.record.formula.Ref3DPtg;
import org.apache.poi.hssf.record.formula.UnionPtg;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
-import org.apache.poi.hssf.util.AreaReference;
import org.apache.poi.hssf.util.RangeAddress;
+import org.apache.poi.ss.util.AreaReference;
import org.apache.poi.util.HexDump;
import org.apache.poi.util.LittleEndian;
import org.apache.poi.util.StringUtil;
}
private Ptg createNewPtg(){
- Ptg ptg = new Area3DPtg();
+ Ptg ptg = new Area3DPtg("A1", 0); // TODO - change to not be partially initialised
field_13_name_definition.push(ptg);
return ptg;
// Add the area reference(s)
for(int i=0; i<refs.length; i++) {
- ptg = new Area3DPtg();
- ((Area3DPtg) ptg).setExternSheetIndex(externSheetIndex);
- ((Area3DPtg) ptg).setArea(refs[i].formatAsString());
+ ptg = new Area3DPtg(refs[i].formatAsString(), externSheetIndex);
field_13_name_definition.push(ptg);
this.setDefinitionTextLength( (short)(getDefinitionLength() + ptg.getSize()) );
}
--- /dev/null
+/* ====================================================================\r
+ Licensed to the Apache Software Foundation (ASF) under one or more\r
+ contributor license agreements. See the NOTICE file distributed with\r
+ this work for additional information regarding copyright ownership.\r
+ The ASF licenses this file to You under the Apache License, Version 2.0\r
+ (the "License"); you may not use this file except in compliance with\r
+ the License. You may obtain a copy of the License at\r
+\r
+ http://www.apache.org/licenses/LICENSE-2.0\r
+\r
+ Unless required by applicable law or agreed to in writing, software\r
+ distributed under the License is distributed on an "AS IS" BASIS,\r
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ See the License for the specific language governing permissions and\r
+ limitations under the License.\r
+==================================================================== */\r
+\r
+package org.apache.poi.hssf.record.formula;\r
+\r
+import org.apache.poi.hssf.record.RecordInputStream;\r
+import org.apache.poi.hssf.usermodel.HSSFWorkbook;\r
+import org.apache.poi.util.LittleEndian;\r
+\r
+/**\r
+ * Common superclass of 2-D area refs \r
+ */\r
+public abstract class Area2DPtgBase extends AreaPtgBase {\r
+ private final static int SIZE = 9;\r
+\r
+ protected Area2DPtgBase(int firstRow, int lastRow, int firstColumn, int lastColumn, boolean firstRowRelative, boolean lastRowRelative, boolean firstColRelative, boolean lastColRelative) {\r
+ super(firstRow, lastRow, firstColumn, lastColumn, firstRowRelative, lastRowRelative, firstColRelative, lastColRelative);\r
+ }\r
+ protected Area2DPtgBase(RecordInputStream in) {\r
+ readCoordinates(in);\r
+ }\r
+ protected abstract byte getSid();\r
+\r
+ public final void writeBytes(byte [] array, int offset) {\r
+ LittleEndian.putByte(array, offset+0, getSid() + getPtgClass());\r
+ writeCoordinates(array, offset+1); \r
+ }\r
+ public Area2DPtgBase(String arearef) {\r
+ super(arearef);\r
+ }\r
+ public final int getSize() {\r
+ return SIZE;\r
+ }\r
+ public final String toFormulaString(HSSFWorkbook book) {\r
+ return formatReferenceAsString();\r
+ }\r
+ public final String toString() {\r
+ StringBuffer sb = new StringBuffer();\r
+ sb.append(getClass().getName());\r
+ sb.append(" [");\r
+ sb.append(formatReferenceAsString());\r
+ sb.append("]");\r
+ return sb.toString();\r
+ }\r
+}\r
package org.apache.poi.hssf.record.formula;
import org.apache.poi.ss.usermodel.Workbook;
-import org.apache.poi.ss.util.CellReference;
-import org.apache.poi.hssf.util.AreaReference;
import org.apache.poi.hssf.record.RecordInputStream;
-import org.apache.poi.util.BitField;
-import org.apache.poi.util.BitFieldFactory;
+import org.apache.poi.ss.util.AreaReference;
+import org.apache.poi.ss.util.CellReference;
import org.apache.poi.util.LittleEndian;
/**
* @author Jason Height (jheight at chariot dot net dot au)
* @version 1.0-pre
*/
-public final class Area3DPtg extends OperandPtg implements AreaI {
+public final class Area3DPtg extends AreaPtgBase {
public final static byte sid = 0x3b;
private final static int SIZE = 11; // 10 + 1 for Ptg
- private static final BitField rowRelative = BitFieldFactory.getInstance(0x8000);
- private static final BitField colRelative = BitFieldFactory.getInstance(0x4000);
-
- private short field_1_index_extern_sheet;
- private int field_2_first_row;
- private int field_3_last_row;
- private int field_4_first_column;
- private int field_5_last_column;
+ private int field_1_index_extern_sheet;
- /** Creates new AreaPtg */
- public Area3DPtg()
- {
- }
-
- public Area3DPtg( String arearef, short externIdx )
- {
- setArea(arearef);
+ public Area3DPtg( String arearef, int externIdx ) {
+ super(arearef);
setExternSheetIndex( externIdx );
-
}
- public Area3DPtg(RecordInputStream in)
- {
+ public Area3DPtg(RecordInputStream in) {
field_1_index_extern_sheet = in.readShort();
- field_2_first_row = in.readUShort();
- field_3_last_row = in.readUShort();
- field_4_first_column = in.readUShort();
- field_5_last_column = in.readUShort();
+ readCoordinates(in);
}
- public Area3DPtg(short firstRow, short lastRow, short firstColumn, short lastColumn,
+ public Area3DPtg(int firstRow, int lastRow, int firstColumn, int lastColumn,
boolean firstRowRelative, boolean lastRowRelative, boolean firstColRelative, boolean lastColRelative,
- short externalSheetIndex) {
- setFirstRow(firstRow);
- setLastRow(lastRow);
- setFirstColumn(firstColumn);
- setLastColumn(lastColumn);
- setFirstRowRelative(firstRowRelative);
- setLastRowRelative(lastRowRelative);
- setFirstColRelative(firstColRelative);
- setLastColRelative(lastColRelative);
- setExternSheetIndex(externalSheetIndex);
+ int externalSheetIndex) {
+ super(firstRow, lastRow, firstColumn, lastColumn, firstRowRelative, lastRowRelative, firstColRelative, lastColRelative);
+ setExternSheetIndex(externalSheetIndex);
}
public String toString() {
StringBuffer sb = new StringBuffer();
sb.append(getClass().getName());
- sb.append(" [");
sb.append("sheetIx=").append(getExternSheetIndex());
sb.append(" ! ");
- sb.append(AreaReference.formatAsString(this));
+ sb.append(formatReferenceAsString());
sb.append("]");
return sb.toString();
}
- public void writeBytes( byte[] array, int offset )
- {
- array[0 + offset] = (byte) ( sid + getPtgClass() );
- LittleEndian.putShort( array, 1 + offset, getExternSheetIndex() );
- LittleEndian.putShort( array, 3 + offset, (short)getFirstRow() );
- LittleEndian.putShort( array, 5 + offset, (short)getLastRow() );
- LittleEndian.putShort( array, 7 + offset, (short)getFirstColumnRaw() );
- LittleEndian.putShort( array, 9 + offset, (short)getLastColumnRaw() );
+ public void writeBytes(byte[] array, int offset) {
+ LittleEndian.putByte(array, offset + 0, sid + getPtgClass());
+ LittleEndian.putUShort(array, 1 + offset, field_1_index_extern_sheet);
+ writeCoordinates(array, offset+3);
}
- public int getSize()
- {
+ public int getSize() {
return SIZE;
}
- public short getExternSheetIndex()
- {
- return field_1_index_extern_sheet;
+ public short getExternSheetIndex() {
+ return (short)field_1_index_extern_sheet;
}
- public void setExternSheetIndex( short index )
- {
+ public void setExternSheetIndex(int index) {
field_1_index_extern_sheet = index;
}
- public int getFirstRow()
- {
- return field_2_first_row;
- }
-
- public void setFirstRow( int row )
- {
- field_2_first_row = row;
- }
-
- public int getLastRow()
- {
- return field_3_last_row;
- }
-
- public void setLastRow( int row )
- {
- field_3_last_row = row;
- }
-
- public int getFirstColumn()
- {
- return field_4_first_column & 0xFF;
- }
-
- public int getFirstColumnRaw()
- {
- return field_4_first_column;
- }
-
- public boolean isFirstRowRelative()
- {
- return rowRelative.isSet( field_4_first_column );
- }
-
- public boolean isFirstColRelative()
- {
- return colRelative.isSet( field_4_first_column );
- }
-
- public void setFirstColumn( short column )
- {
- field_4_first_column &= 0xFF00;
- field_4_first_column |= column & 0xFF;
- }
-
- public void setFirstColumnRaw( short column )
- {
- field_4_first_column = column;
- }
-
- public int getLastColumn()
- {
- return field_5_last_column & 0xFF;
- }
-
- public int getLastColumnRaw()
- {
- return field_5_last_column;
- }
-
- public boolean isLastRowRelative()
- {
- return rowRelative.isSet( field_5_last_column );
- }
-
- public boolean isLastColRelative()
- {
- return colRelative.isSet( field_5_last_column );
- }
-
- public void setLastColumn( short column )
- {
- field_5_last_column &= 0xFF00;
- field_5_last_column |= column & 0xFF;
- }
-
- public void setLastColumnRaw( short column )
- {
- field_5_last_column = column;
- }
-
- /**
- * sets the first row to relative or not
- * @param rel FIXME: Document this!
- */
- public void setFirstRowRelative( boolean rel )
- {
- field_4_first_column = rowRelative.setBoolean( field_4_first_column, rel );
- }
-
- /**
- * set whether the first column is relative
- */
- public void setFirstColRelative( boolean rel )
- {
- field_4_first_column = colRelative.setBoolean( field_4_first_column, rel );
- }
-
- /**
- * set whether the last row is relative or not
- * @param rel FIXME: Document this!
- */
- public void setLastRowRelative( boolean rel )
- {
- field_5_last_column = rowRelative.setBoolean( field_5_last_column, rel );
- }
-
- /**
- * set whether the last column should be relative or not
- */
- public void setLastColRelative( boolean rel )
- {
- field_5_last_column = colRelative.setBoolean( field_5_last_column, rel );
- }
-
-
- /*public String getArea(){
- RangeAddress ra = new RangeAddress( getFirstColumn(),getFirstRow() + 1, getLastColumn(), getLastRow() + 1);
- String result = ra.getAddress();
-
- return result;
- }*/
-
- public void setArea( String ref )
- {
- AreaReference ar = new AreaReference( ref );
-
- CellReference frstCell = ar.getFirstCell();
- CellReference lastCell = ar.getLastCell();
-
- setFirstRow( (short) frstCell.getRow() );
- setFirstColumn( (short) frstCell.getCol() );
- setLastRow( (short) lastCell.getRow() );
- setLastColumn( (short) lastCell.getCol() );
- setFirstColRelative( !frstCell.isColAbsolute() );
- setLastColRelative( !lastCell.isColAbsolute() );
- setFirstRowRelative( !frstCell.isRowAbsolute() );
- setLastRowRelative( !lastCell.isRowAbsolute() );
- }
-
/**
* @return text representation of this area reference that can be used in text
* formulas. The sheet name will get properly delimited if required.
*/
- public String toFormulaString(Workbook book)
- {
+ public String toFormulaString(Workbook book) {
// First do the sheet name
StringBuffer retval = new StringBuffer();
String sheetName = Ref3DPtg.getSheetName(book, field_1_index_extern_sheet);
}
// Now the normal area bit
- retval.append(AreaReference.formatAsString(this));
+ retval.append(formatReferenceAsString());
- // All done
return retval.toString();
}
-
- public byte getDefaultOperandClass() {
- return Ptg.CLASS_REF;
- }
- // TODO - one junit relies on this. remove
- public boolean equals( Object o )
- {
- if ( this == o ) return true;
- if ( !( o instanceof Area3DPtg ) ) return false;
-
- final Area3DPtg area3DPtg = (Area3DPtg) o;
-
- if ( field_1_index_extern_sheet != area3DPtg.field_1_index_extern_sheet ) return false;
- if ( field_2_first_row != area3DPtg.field_2_first_row ) return false;
- if ( field_3_last_row != area3DPtg.field_3_last_row ) return false;
- if ( field_4_first_column != area3DPtg.field_4_first_column ) return false;
- if ( field_5_last_column != area3DPtg.field_5_last_column ) return false;
-
- return true;
- }
}
See the License for the specific language governing permissions and
limitations under the License.
==================================================================== */
+
package org.apache.poi.hssf.record.formula;
/**
- * Common interface for AreaPtg and Area3DPtg, and their
- * child classes.
+ * Common interface for AreaPtg and Area3DPtg, and their child classes.
*/
public interface AreaI {
- /**
- * @return the first row in the area
- */
- public int getFirstRow();
-
- /**
- * @return last row in the range (x2 in x1,y1-x2,y2)
- */
- public int getLastRow();
-
- /**
- * @return the first column number in the area.
- */
- public int getFirstColumn();
-
- /**
- * @return lastcolumn in the area
- */
- public int getLastColumn();
-
- /**
- * @return isrelative first column to relative or not
- */
- public boolean isFirstColRelative();
- /**
- * @return lastcol relative or not
- */
- public boolean isLastColRelative();
- /**
- * @return whether or not the first row is a relative reference or not.
- */
- public boolean isFirstRowRelative();
- /**
- * @return last row relative or not
- */
- public boolean isLastRowRelative();
+ /**
+ * @return the first row in the area
+ */
+ public int getFirstRow();
+
+ /**
+ * @return last row in the range (x2 in x1,y1-x2,y2)
+ */
+ public int getLastRow();
+
+ /**
+ * @return the first column number in the area.
+ */
+ public int getFirstColumn();
+
+ /**
+ * @return lastcolumn in the area
+ */
+ public int getLastColumn();
+
+ class OffsetArea implements AreaI {
+
+ private final int _firstColumn;
+ private final int _firstRow;
+ private final int _lastColumn;
+ private final int _lastRow;
+
+ public OffsetArea(int baseRow, int baseColumn, int relFirstRowIx, int relLastRowIx,
+ int relFirstColIx, int relLastColIx) {
+ _firstRow = baseRow + relFirstRowIx;
+ _lastRow = baseRow + relLastRowIx;
+ _firstColumn = baseColumn + relFirstColIx;
+ _lastColumn = baseColumn + relLastColIx;
+ }
+
+ public int getFirstColumn() {
+ return _firstColumn;
+ }
+
+ public int getFirstRow() {
+ return _firstRow;
+ }
+
+ public int getLastColumn() {
+ return _lastColumn;
+ }
+
+ public int getLastRow() {
+ return _lastRow;
+ }
+ }
+
}
\ No newline at end of file
* Specifies a rectangular area of cells A1:A4 for instance.
* @author Jason Height (jheight at chariot dot net dot au)
*/
-public final class AreaNPtg extends AreaPtgBase {
+public final class AreaNPtg extends Area2DPtgBase {
public final static short sid = 0x2D;
public AreaNPtg(RecordInputStream in) {
* Specifies a rectangular area of cells A1:A4 for instance.
* @author Jason Height (jheight at chariot dot net dot au)
*/
-public final class AreaPtg extends AreaPtgBase {
- public final static short sid = 0x25;
+public final class AreaPtg extends Area2DPtgBase {
+ public final static short sid = 0x25;
- public AreaPtg(int firstRow, int lastRow, int firstColumn, int lastColumn, boolean firstRowRelative, boolean lastRowRelative, boolean firstColRelative, boolean lastColRelative) {
- super(firstRow, lastRow, firstColumn, lastColumn, firstRowRelative, lastRowRelative, firstColRelative, lastColRelative);
- }
- public AreaPtg(RecordInputStream in) {
- super(in);
- }
- public AreaPtg(String arearef) {
+ public AreaPtg(int firstRow, int lastRow, int firstColumn, int lastColumn, boolean firstRowRelative, boolean lastRowRelative, boolean firstColRelative, boolean lastColRelative) {
+ super(firstRow, lastRow, firstColumn, lastColumn, firstRowRelative, lastRowRelative, firstColRelative, lastColRelative);
+ }
+ public AreaPtg(RecordInputStream in) {
+ super(in);
+ }
+ public AreaPtg(String arearef) {
super(arearef);
}
protected byte getSid() {
import org.apache.poi.ss.util.CellReference;
import org.apache.poi.ss.usermodel.Workbook;
-import org.apache.poi.hssf.util.AreaReference;
+import org.apache.poi.ss.util.AreaReference;
import org.apache.poi.hssf.record.RecordInputStream;
/**
* see similar comment in ReferencePtg
*/
protected final RuntimeException notImplemented() {
- return new RuntimeException("Coding Error: This method should never be called. This ptg should be converted");
+ return new RuntimeException("Coding Error: This method should never be called. This ptg should be converted");
}
- public final static short sid = 0x25;
- private final static int SIZE = 9;
/** zero based, unsigned 16 bit */
private int field_1_first_row;
/** zero based, unsigned 16 bit */
private final static BitField colRelative = BitFieldFactory.getInstance(0x4000);
private final static BitField columnMask = BitFieldFactory.getInstance(0x3FFF);
+ protected AreaPtgBase() {
+ // do nothing
+ }
+
protected AreaPtgBase(String arearef) {
AreaReference ar = new AreaReference(arearef);
CellReference firstCell = ar.getFirstCell();
}
}
- protected AreaPtgBase(RecordInputStream in)
- {
- field_1_first_row = in.readUShort();
- field_2_last_row = in.readUShort();
+ protected final void readCoordinates(RecordInputStream in) {
+ field_1_first_row = in.readUShort();
+ field_2_last_row = in.readUShort();
field_3_first_column = in.readUShort();
- field_4_last_column = in.readUShort();
- }
-
- public final String toString() {
- StringBuffer sb = new StringBuffer();
- sb.append(getClass().getName());
- sb.append(" [");
- sb.append(AreaReference.formatAsString(this));
- sb.append("]");
- return sb.toString();
+ field_4_last_column = in.readUShort();
}
- protected abstract byte getSid();
-
- public final void writeBytes(byte [] array, int offset) {
- array[offset] = (byte) (getSid() + getPtgClass());
- LittleEndian.putShort(array,offset+1,(short)field_1_first_row);
- LittleEndian.putShort(array,offset+3,(short)field_2_last_row);
- LittleEndian.putShort(array,offset+5,(short)field_3_first_column);
- LittleEndian.putShort(array,offset+7,(short)field_4_last_column);
- }
-
-
- public final int getSize() {
- return SIZE;
+ protected final void writeCoordinates(byte[] array, int offset) {
+ LittleEndian.putUShort(array, offset + 0, field_1_first_row);
+ LittleEndian.putUShort(array, offset + 2, field_2_last_row);
+ LittleEndian.putUShort(array, offset + 4, field_3_first_column);
+ LittleEndian.putUShort(array, offset + 6, field_4_last_column);
}
/**
*/
public final void setFirstColumn(int colIx) {
checkColumnBounds(colIx);
- field_3_first_column=columnMask.setValue(field_3_first_column, colIx);
+ field_3_first_column=columnMask.setValue(field_3_first_column, colIx);
}
/**
*/
public final void setLastColumn(int colIx) {
checkColumnBounds(colIx);
- field_4_last_column=columnMask.setValue(field_4_last_column, colIx);
+ field_4_last_column=columnMask.setValue(field_4_last_column, colIx);
}
/**
public final void setLastColumnRaw(short column) {
field_4_last_column = column;
}
+ protected final String formatReferenceAsString() {
+ CellReference topLeft = new CellReference(getFirstRow(),getFirstColumn(),!isFirstRowRelative(),!isFirstColRelative());
+ CellReference botRight = new CellReference(getLastRow(),getLastColumn(),!isLastRowRelative(),!isLastColRelative());
+
+ if(AreaReference.isWholeColumnReference(topLeft, botRight)) {
+ return (new AreaReference(topLeft, botRight)).formatAsString();
+ }
+ return topLeft.formatAsString() + ":" + botRight.formatAsString();
+ }
public String toFormulaString(Workbook book) {
- return AreaReference.formatAsString(this);
+ return formatReferenceAsString();
}
public byte getDefaultOperandClass() {
field_2_col=colRelative.setBoolean(field_2_col,rel);
}
- public final void setColumnRawX(int col) { // TODO
- field_2_col = col;
- }
-
- public int getColumnRawX() { // TODO
- return field_2_col;
- }
-
public final void setColumn(int col) {
if(col < 0 || col >= 0x100) {
throw new IllegalArgumentException("Specified colIx (" + col + ") is out of range");
+++ /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.record.formula.eval;
-
-import org.apache.poi.hssf.record.formula.AreaPtg;
-import org.apache.poi.hssf.record.formula.Ptg;
-
-/**
- * @author Amol S. Deshmukh < amolweb at ya hoo dot com >
- *
- */
-public final class Area2DEval extends AreaEvalBase {
-
- public Area2DEval(Ptg ptg, ValueEval[] values) {
- super((AreaPtg) ptg, values);
- }
-}
\ No newline at end of file
+++ /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.record.formula.eval;
-
-import org.apache.poi.hssf.record.formula.Area3DPtg;
-import org.apache.poi.hssf.record.formula.Ptg;
-
-/**
- * @author Amol S. Deshmukh < amolweb at ya hoo dot com >
- *
- */
-public final class Area3DEval extends AreaEvalBase {
-
- private final int _externSheetIndex;
-
- public Area3DEval(Ptg ptg, ValueEval[] values) {
- super((Area3DPtg) ptg, values);
- _externSheetIndex = ((Area3DPtg) ptg).getExternSheetIndex();
- }
-
- public int getExternSheetIndex() {
- return _externSheetIndex;
- }
-}
*/
boolean isColumn();
- /**
- * The array of values in this area. Although the area
- * maybe 1D (ie. isRow() or isColumn() returns true) or 2D
- * the returned array is 1D.
- */
- ValueEval[] getValues();
-
/**
* @return the ValueEval from within this area at the specified row and col index. Never
* <code>null</code> (possibly {@link BlankEval}). The specified indexes should be absolute
* specified indexes should relative to the top left corner of this area.
*/
ValueEval getRelativeValue(int relativeRowIndex, int relativeColumnIndex);
+
+ /**
+ * Creates an {@link AreaEval} offset by a relative amount from from the upper left cell
+ * of this area
+ */
+ AreaEval offset(int relFirstRowIx, int relLastRowIx, int relFirstColIx, int relLastColIx);
}
/**
* @author Josh Micich
*/
-abstract class AreaEvalBase implements AreaEval {
+public abstract class AreaEvalBase implements AreaEval {
private final int _firstColumn;
private final int _firstRow;
private final int _lastColumn;
private final int _lastRow;
- private final ValueEval[] _values;
private final int _nColumns;
private final int _nRows;
- protected AreaEvalBase(AreaI ptg, ValueEval[] values) {
- if (values == null) {
- throw new IllegalArgumentException("values must not be null");
- }
+ protected AreaEvalBase(AreaI ptg) {
_firstRow = ptg.getFirstRow();
_firstColumn = ptg.getFirstColumn();
_lastRow = ptg.getLastRow();
_nColumns = _lastColumn - _firstColumn + 1;
_nRows = _lastRow - _firstRow + 1;
-
- int expectedItemCount = _nRows * _nColumns;
- if ((values.length != expectedItemCount)) {
- // Note - this math may need alteration when POI starts to support full column or full row refs
- throw new IllegalArgumentException("Array size should be (" + expectedItemCount
- + ") but was (" + values.length + ")");
- }
-
-
-
- for (int i = values.length - 1; i >= 0; i--) {
- if (values[i] == null) {
- throw new IllegalArgumentException("value array elements must not be null");
- }
- }
- _values = values;
}
public final int getFirstColumn() {
return _lastRow;
}
- public final ValueEval[] getValues() {
- // TODO - clone() - but some junits rely on not cloning at the moment
- return _values;
- }
-
public final ValueEval getValueAt(int row, int col) {
int rowOffsetIx = row - _firstRow;
int colOffsetIx = col - _firstColumn;
return _lastRow-_firstRow+1;
}
- public ValueEval getRelativeValue(int relativeRowIndex, int relativeColumnIndex) {
- int index = relativeRowIndex * _nColumns + relativeColumnIndex;
- ValueEval result = _values[index];
- if (result == null) {
- return BlankEval.INSTANCE;
- }
- return result;
- }
+ public abstract ValueEval getRelativeValue(int relativeRowIndex, int relativeColumnIndex);
public int getWidth() {
return _lastColumn-_firstColumn+1;
static {
Map m = new HashMap();
- addMapping(m, ID.OFFSET, new Offset());
addMapping(m, ID.INDIRECT, new Indirect());
addMapping(m, ID.EXTERNAL_FUNC, new ExternalFunction());
freeRefFunctionsByIdMap = m;
retval[75] = new Areas(); // AREAS
retval[76] = new Rows(); // ROWS
retval[77] = new Columns(); // COLUMNS
- retval[ID.OFFSET] = null; // Offset.evaluate has a different signature
+ retval[ID.OFFSET] = new Offset(); // OFFSET
retval[79] = new Absref(); // ABSREF
retval[80] = new Relref(); // RELREF
retval[81] = new Argument(); // ARGUMENT
--- /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.record.formula.eval;
+
+import org.apache.poi.hssf.record.formula.AreaI;
+import org.apache.poi.hssf.record.formula.AreaI.OffsetArea;
+import org.apache.poi.ss.usermodel.Cell;
+import org.apache.poi.ss.usermodel.FormulaEvaluator;
+import org.apache.poi.ss.usermodel.Row;
+import org.apache.poi.ss.usermodel.Sheet;
+import org.apache.poi.ss.usermodel.Workbook;
+
+/**
+ * @author Amol S. Deshmukh < amolweb at ya hoo dot com >
+ *
+ */
+public final class LazyAreaEval extends AreaEvalBase {
+
+ private final Sheet _sheet;
+ private Workbook _workbook;
+
+ public LazyAreaEval(AreaI ptg, Sheet sheet, Workbook workbook) {
+ super(ptg);
+ _sheet = sheet;
+ _workbook = workbook;
+ }
+
+ public ValueEval getRelativeValue(int relativeRowIndex, int relativeColumnIndex) {
+
+ int rowIx = (relativeRowIndex + getFirstRow() ) & 0xFFFF;
+ int colIx = (relativeColumnIndex + getFirstColumn() ) & 0x00FF;
+
+ Row row = _sheet.getRow(rowIx);
+ if (row == null) {
+ return BlankEval.INSTANCE;
+ }
+ Cell cell = row.getCell(colIx);
+ if (cell == null) {
+ return BlankEval.INSTANCE;
+ }
+ return FormulaEvaluator.getEvalForCell(cell, _sheet, _workbook);
+ }
+
+ public AreaEval offset(int relFirstRowIx, int relLastRowIx, int relFirstColIx, int relLastColIx) {
+ AreaI area = new OffsetArea(getFirstRow(), getFirstColumn(),
+ relFirstRowIx, relLastRowIx, relFirstColIx, relLastColIx);
+
+ return new LazyAreaEval(area, _sheet, _workbook);
+ }
+}
--- /dev/null
+package org.apache.poi.hssf.record.formula.eval;\r
+\r
+import org.apache.poi.hssf.record.formula.AreaI;\r
+import org.apache.poi.hssf.record.formula.AreaI.OffsetArea;\r
+import org.apache.poi.hssf.record.formula.Ref3DPtg;\r
+import org.apache.poi.hssf.record.formula.RefPtg;\r
+import org.apache.poi.ss.usermodel.Cell;\r
+import org.apache.poi.ss.usermodel.FormulaEvaluator;\r
+import org.apache.poi.ss.usermodel.Row;\r
+import org.apache.poi.ss.usermodel.Sheet;\r
+import org.apache.poi.ss.usermodel.Workbook;\r
+\r
+public final class LazyRefEval extends RefEvalBase {\r
+\r
+ private final Sheet _sheet;\r
+ private final Workbook _workbook;\r
+\r
+\r
+ public LazyRefEval(RefPtg ptg, Sheet sheet, Workbook workbook) {\r
+ super(ptg.getRow(), ptg.getColumn());\r
+ _sheet = sheet;\r
+ _workbook = workbook;\r
+ }\r
+ public LazyRefEval(Ref3DPtg ptg, Sheet sheet, Workbook workbook) {\r
+ super(ptg.getRow(), ptg.getColumn());\r
+ _sheet = sheet;\r
+ _workbook = workbook;\r
+ }\r
+\r
+ public ValueEval getInnerValueEval() {\r
+ int rowIx = getRow();\r
+ int colIx = getColumn();\r
+ \r
+ Row row = _sheet.getRow(rowIx);\r
+ if (row == null) {\r
+ return BlankEval.INSTANCE;\r
+ }\r
+ Cell cell = row.getCell(colIx);\r
+ if (cell == null) {\r
+ return BlankEval.INSTANCE;\r
+ }\r
+ return FormulaEvaluator.getEvalForCell(cell, _sheet, _workbook);\r
+ }\r
+ \r
+ public AreaEval offset(int relFirstRowIx, int relLastRowIx, int relFirstColIx, int relLastColIx) {\r
+ \r
+ AreaI area = new OffsetArea(getRow(), getColumn(),\r
+ relFirstRowIx, relLastRowIx, relFirstColIx, relLastColIx);\r
+\r
+ return new LazyAreaEval(area, _sheet, _workbook);\r
+ }\r
+}\r
}
}
}
-
+ public final String toString() {
+ StringBuffer sb = new StringBuffer(64);
+ sb.append(getClass().getName()).append(" [");
+ sb.append(getStringValue());
+ sb.append("]");
+ return sb.toString();
+ }
}
public int getColumn() {
return delegate.getColumn();
}
+ public AreaEval offset(int relFirstRowIx, int relLastRowIx, int relFirstColIx, int relLastColIx) {
+ throw new RuntimeException("should not be called"); // TODO - delete this whole 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.record.formula.eval;
-
-import org.apache.poi.hssf.record.formula.Ref3DPtg;
-
-/**
- * @author Amol S. Deshmukh
- *
- */
-public final class Ref3DEval implements RefEval {
-
- private final ValueEval value;
- private final Ref3DPtg delegate;
-
- public Ref3DEval(Ref3DPtg ptg, ValueEval ve) {
- if(ve == null) {
- throw new IllegalArgumentException("ve must not be null");
- }
- if(ptg == null) {
- throw new IllegalArgumentException("ptg must not be null");
- }
- value = ve;
- delegate = ptg;
- }
- public ValueEval getInnerValueEval() {
- return value;
- }
- public int getRow() {
- return delegate.getRow();
- }
- public int getColumn() {
- return delegate.getColumn();
- }
- public int getExternSheetIndex() {
- return delegate.getExternSheetIndex();
- }
-}
-/*
-* 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.
-*/
+/* ====================================================================
+ Licensed to the Apache Software Foundation (ASF) under one or more
+ contributor license agreements. See the NOTICE file distributed with
+ this work for additional information regarding copyright ownership.
+ The ASF licenses this file to You under the Apache License, Version 2.0
+ (the "License"); you may not use this file except in compliance with
+ the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+==================================================================== */
package org.apache.poi.hssf.record.formula.eval;
public interface RefEval extends ValueEval {
/**
- * The (possibly evaluated) ValueEval contained
- * in this RefEval. eg. if cell A1 contains "test"
- * then in a formula referring to cell A1
- * the RefEval representing
- * A1 will return as the getInnerValueEval() the
- * object of concrete type StringEval
+ * @return the evaluated value of the cell referred to by this RefEval.
*/
- public ValueEval getInnerValueEval();
+ ValueEval getInnerValueEval();
/**
* returns the zero based column index.
*/
- public int getColumn();
+ int getColumn();
/**
* returns the zero based row index.
*/
- public int getRow();
+ int getRow();
+
+ /**
+ * Creates an {@link AreaEval} offset by a relative amount from this RefEval
+ */
+ AreaEval offset(int relFirstRowIx, int relLastRowIx, int relFirstColIx, int relLastColIx);
}
--- /dev/null
+package org.apache.poi.hssf.record.formula.eval;\r
+\r
+public abstract class RefEvalBase implements RefEval {\r
+\r
+ private final int _rowIndex;\r
+ private final int _columnIndex;\r
+\r
+ protected RefEvalBase(int rowIndex, int columnIndex) {\r
+ _rowIndex = rowIndex;\r
+ _columnIndex = columnIndex;\r
+ }\r
+ public final int getRow() {\r
+ return _rowIndex;\r
+ }\r
+ public final int getColumn() {\r
+ return _columnIndex;\r
+ }\r
+}\r
for (int rrIx=0; rrIx<height; rrIx++) {
for (int rcIx=0; rcIx<width; rcIx++) {
ValueEval ve = areaEval.getRelativeValue(rrIx, rcIx);
- if(criteriaPredicate.matches(ve)) {
- result++;
- }
+ if(criteriaPredicate.matches(ve)) {
+ result++;
+ }
}
}
return result;
return 0;
}
public static int countArg(Eval eval, I_MatchPredicate criteriaPredicate) {
+ if (eval == null) {
+ throw new IllegalArgumentException("eval must not be null");
+ }
if (eval instanceof AreaEval) {
return CountUtils.countMatchingCellsInArea((AreaEval) eval, criteriaPredicate);
}
-/*
-* Licensed to the Apache Software Foundation (ASF) under one or more
-* contributor license agreements. See the NOTICE file distributed with
-* this work for additional information regarding copyright ownership.
-* The ASF licenses this file to You under the Apache License, Version 2.0
-* (the "License"); you may not use this file except in compliance with
-* the License. You may obtain a copy of the License at
-*
-* http://www.apache.org/licenses/LICENSE-2.0
-*
-* Unless required by applicable law or agreed to in writing, software
-* distributed under the License is distributed on an "AS IS" BASIS,
-* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-* See the License for the specific language governing permissions and
-* limitations under the License.
-*/
-/*
- * Created on Nov 25, 2006
- *
- */
+/* ====================================================================
+ Licensed to the Apache Software Foundation (ASF) under one or more
+ contributor license agreements. See the NOTICE file distributed with
+ this work for additional information regarding copyright ownership.
+ The ASF licenses this file to You under the Apache License, Version 2.0
+ (the "License"); you may not use this file except in compliance with
+ the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+==================================================================== */
+
package org.apache.poi.hssf.record.formula.functions;
import org.apache.poi.hssf.record.formula.eval.BoolEval;
import org.apache.poi.hssf.record.formula.eval.ErrorEval;
import org.apache.poi.hssf.record.formula.eval.Eval;
+import org.apache.poi.hssf.record.formula.eval.EvaluationException;
+import org.apache.poi.hssf.record.formula.eval.OperandResolver;
+import org.apache.poi.hssf.record.formula.eval.ValueEval;
/**
* @author Amol S. Deshmukh < amolweb at ya hoo dot com >
*/
public final class If implements Function {
- public Eval evaluate(Eval[] args, int srcCellRow, short srcCellCol) {
+ public Eval evaluate(Eval[] args, int srcCellRow, short srcCellCol) {
+ Eval falseResult;
+ switch (args.length) {
+ case 3:
+ falseResult = args[2];
+ break;
+ case 2:
+ falseResult = BoolEval.FALSE;
+ break;
+ default:
+ return ErrorEval.VALUE_INVALID;
+ }
+ boolean b;
+ try {
+ b = evaluateFirstArg(args[0], srcCellRow, srcCellCol);
+ } catch (EvaluationException e) {
+ return e.getErrorEval();
+ }
+ if (b) {
+ return args[1];
+ }
+ return falseResult;
+ }
- Eval evalWhenFalse = BoolEval.FALSE;
- switch (args.length) {
- case 3:
- evalWhenFalse = args[2];
- case 2:
- BoolEval beval = (BoolEval) args[0]; // TODO - class cast exception
- if (beval.getBooleanValue()) {
- return args[1];
- }
- return evalWhenFalse;
- default:
- return ErrorEval.VALUE_INVALID;
- }
- }
+ private static boolean evaluateFirstArg(Eval arg, int srcCellRow, short srcCellCol)
+ throws EvaluationException {
+ ValueEval ve = OperandResolver.getSingleValue(arg, srcCellRow, srcCellCol);
+ Boolean b = OperandResolver.coerceValueToBoolean(ve, false);
+ if (b == null) {
+ return false;
+ }
+ return b.booleanValue();
+ }
}
-/*
-* 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.
-*/
+/* ====================================================================
+ Licensed to the Apache Software Foundation (ASF) under one or more
+ contributor license agreements. See the NOTICE file distributed with
+ this work for additional information regarding copyright ownership.
+ The ASF licenses this file to You under the Apache License, Version 2.0
+ (the "License"); you may not use this file except in compliance with
+ the License. You may obtain a copy of the License at
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+==================================================================== */
package org.apache.poi.hssf.record.formula.functions;
import org.apache.poi.hssf.record.formula.eval.AreaEval;
import org.apache.poi.hssf.record.formula.eval.ErrorEval;
import org.apache.poi.hssf.record.formula.eval.Eval;
-import org.apache.poi.hssf.record.formula.eval.NumberEval;
-import org.apache.poi.hssf.record.formula.eval.RefEval;
+import org.apache.poi.hssf.record.formula.eval.EvaluationException;
+import org.apache.poi.hssf.record.formula.eval.OperandResolver;
+import org.apache.poi.hssf.record.formula.eval.ValueEval;
/**
* Implementation for the Excel function INDEX<p/>
return ErrorEval.VALUE_INVALID;
}
Eval firstArg = args[0];
- if(firstArg instanceof AreaEval) {
- AreaEval reference = (AreaEval) firstArg;
+ if(!(firstArg instanceof AreaEval)) {
+
+ // else the other variation of this function takes an array as the first argument
+ // it seems like interface 'ArrayEval' does not even exist yet
- int rowIx = 0;
- int columnIx = 0;
- int areaIx = 0;
+ throw new RuntimeException("Incomplete code - cannot handle first arg of type ("
+ + firstArg.getClass().getName() + ")");
+ }
+ AreaEval reference = (AreaEval) firstArg;
+
+ int rowIx = 0;
+ int columnIx = 0;
+ int areaIx = 0;
+ try {
switch(nArgs) {
case 4:
- areaIx = convertIndexArgToZeroBase(args[3]);
+ areaIx = convertIndexArgToZeroBase(args[3], srcCellRow, srcCellCol);
throw new RuntimeException("Incomplete code" +
" - don't know how to support the 'area_num' parameter yet)");
// Excel expression might look like this "INDEX( (A1:B4, C3:D6, D2:E5 ), 1, 2, 3)
// The formula parser doesn't seem to support this yet. Not sure if the evaluator does either
case 3:
- columnIx = convertIndexArgToZeroBase(args[2]);
+ columnIx = convertIndexArgToZeroBase(args[2], srcCellRow, srcCellCol);
case 2:
- rowIx = convertIndexArgToZeroBase(args[1]);
+ rowIx = convertIndexArgToZeroBase(args[1], srcCellRow, srcCellCol);
break;
default:
// too many arguments
return ErrorEval.VALUE_INVALID;
}
-
- int nColumns = reference.getLastColumn()-reference.getFirstColumn()+1;
- int index = rowIx * nColumns + columnIx;
-
- return reference.getValues()[index];
+ return getValueFromArea(reference, rowIx, columnIx);
+ } catch (EvaluationException e) {
+ return e.getErrorEval();
}
-
- // else the other variation of this function takes an array as the first argument
- // it seems like interface 'ArrayEval' does not even exist yet
-
- throw new RuntimeException("Incomplete code - cannot handle first arg of type ("
- + firstArg.getClass().getName() + ")");
}
+ private static ValueEval getValueFromArea(AreaEval ae, int rowIx, int columnIx) throws EvaluationException {
+ int width = ae.getWidth();
+ int height = ae.getHeight();
+
+ // Slightly irregular logic for bounds checking errors
+ if (rowIx >= height || columnIx >= width) {
+ throw new EvaluationException(ErrorEval.REF_INVALID);
+ }
+ if (rowIx < 0 || columnIx < 0) {
+ throw new EvaluationException(ErrorEval.VALUE_INVALID);
+ }
+ return ae.getRelativeValue(rowIx, columnIx);
+ }
+
/**
* takes a NumberEval representing a 1-based index and returns the zero-based int value
*/
- private static int convertIndexArgToZeroBase(Eval ev) {
- NumberEval ne;
- if(ev instanceof RefEval) {
- // TODO - write junit to justify this
- RefEval re = (RefEval) ev;
- ne = (NumberEval) re.getInnerValueEval();
- } else {
- ne = (NumberEval)ev;
- }
+ private static int convertIndexArgToZeroBase(Eval arg, int srcCellRow, short srcCellCol) throws EvaluationException {
- return (int)ne.getNumberValue() - 1;
+ ValueEval ev = OperandResolver.getSingleValue(arg, srcCellRow, srcCellCol);
+ int oneBasedVal = OperandResolver.coerceValueToInt(ev);
+ return oneBasedVal - 1;
}
}
package org.apache.poi.hssf.record.formula.functions;
-import org.apache.poi.hssf.record.formula.AreaPtg;
-import org.apache.poi.hssf.record.formula.eval.Area2DEval;
import org.apache.poi.hssf.record.formula.eval.AreaEval;
import org.apache.poi.hssf.record.formula.eval.BlankEval;
import org.apache.poi.hssf.record.formula.eval.BoolEval;
// Make this cell ref look like a 1x1 area ref.
// It doesn't matter if eval is a 2D or 3D ref, because that detail is never asked of AreaEval.
- // This code only requires the value array item.
- // anything would be ok for rowIx and colIx, but may as well get it right.
- int rowIx = refEval.getRow();
- int colIx = refEval.getColumn();
- AreaPtg ap = new AreaPtg(rowIx, rowIx, colIx, colIx, false, false, false, false);
- ValueEval value = refEval.getInnerValueEval();
- return new Area2DEval(ap, new ValueEval[] { value, });
+ return refEval.offset(0, 0, 0, 0);
}
throw EvaluationException.invalidValue();
}
return d;
}
- /**
- * returns the sum of difference of squares of corresponding double
- * value in each subarray: ie. sigma (xarr[i]^2-yarr[i]^2)
- * <br/>
- * It is the responsibility of the caller
- * to ensure that the two subarrays are of equal length. If the
- * subarrays are not of equal length, the return value can be
- * unpredictable.
- * @param xarr
- * @param yarr
- */
- public static double sumx2my2(double[] xarr, double[] yarr) {
- double d = 0;
-
- try {
- for (int i=0, iSize=xarr.length; i<iSize; i++) {
- d += (xarr[i] + yarr[i]) * (xarr[i] - yarr[i]);
- }
- }
- catch (ArrayIndexOutOfBoundsException ae) {
- d = Double.NaN;
- }
-
- return d;
- }
-
- /**
- * returns the sum of sum of squares of corresponding double
- * value in each subarray: ie. sigma (xarr[i]^2 + yarr[i]^2)
- * <br/>
- * It is the responsibility of the caller
- * to ensure that the two subarrays are of equal length. If the
- * subarrays are not of equal length, the return value can be
- * unpredictable.
- * @param xarr
- * @param yarr
- */
- public static double sumx2py2(double[] xarr, double[] yarr) {
- double d = 0;
-
- try {
- for (int i=0, iSize=xarr.length; i<iSize; i++) {
- d += (xarr[i] * xarr[i]) + (yarr[i] * yarr[i]);
- }
- }
- catch (ArrayIndexOutOfBoundsException ae) {
- d = Double.NaN;
- }
-
- return d;
- }
-
-
- /**
- * returns the sum of squares of difference of corresponding double
- * value in each subarray: ie. sigma ( (xarr[i]-yarr[i])^2 )
- * <br/>
- * It is the responsibility of the caller
- * to ensure that the two subarrays are of equal length. If the
- * subarrays are not of equal length, the return value can be
- * unpredictable.
- * @param xarr
- * @param yarr
- */
- public static double sumxmy2(double[] xarr, double[] yarr) {
- double d = 0;
-
- try {
- for (int i=0, iSize=xarr.length; i<iSize; i++) {
- double t = (xarr[i] - yarr[i]);
- d += t * t;
- }
- }
- catch (ArrayIndexOutOfBoundsException ae) {
- d = Double.NaN;
- }
-
- return d;
- }
/**
* returns the total number of combinations possible when
if (operand instanceof AreaEval) {
AreaEval ae = (AreaEval) operand;
- ValueEval[] values = ae.getValues();
DoubleList retval = new DoubleList();
- for (int j=0, jSize=values.length; j<jSize; j++) {
- /*
- * TODO: For an AreaEval, we are constructing a RefEval
- * per element.
- * For now this is a tempfix solution since this may
- * require a more generic fix at the level of
- * HSSFFormulaEvaluator where we store an array
- * of RefEvals as the "values" array.
- */
- RefEval re = new Ref2DEval(null, values[j]);
- ValueEval ve = singleOperandEvaluate(re, srcRow, srcCol);
-
- if (ve instanceof NumericValueEval) {
- NumericValueEval nve = (NumericValueEval) ve;
- retval.add(nve.getNumberValue());
- }
- else if (ve instanceof BlankEval) {
- // note - blanks are ignored, so returned array will be smaller.
- }
- else {
- return null; // indicate to calling subclass that error occurred
- }
+ int width = ae.getWidth();
+ int height = ae.getHeight();
+ for (int rrIx=0; rrIx<height; rrIx++) {
+ for (int rcIx=0; rcIx<width; rcIx++) {
+ ValueEval ve1 = ae.getRelativeValue(rrIx, rcIx);
+ /*
+ * TODO: For an AreaEval, we are constructing a RefEval
+ * per element.
+ * For now this is a tempfix solution since this may
+ * require a more generic fix at the level of
+ * HSSFFormulaEvaluator where we store an array
+ * of RefEvals as the "values" array.
+ */
+ RefEval re = new Ref2DEval(null, ve1);
+ ValueEval ve = singleOperandEvaluate(re, srcRow, srcCol);
+
+ if (ve instanceof NumericValueEval) {
+ NumericValueEval nve = (NumericValueEval) ve;
+ retval.add(nve.getNumberValue());
+ }
+ else if (ve instanceof BlankEval) {
+ // note - blanks are ignored, so returned array will be smaller.
+ }
+ else {
+ return null; // indicate to calling subclass that error occurred
+ }
+ }
}
return retval.toArray();
}
-/*
-* 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.
-*/
+/* ====================================================================
+ Licensed to the Apache Software Foundation (ASF) under one or more
+ contributor license agreements. See the NOTICE file distributed with
+ this work for additional information regarding copyright ownership.
+ The ASF licenses this file to You under the Apache License, Version 2.0
+ (the "License"); you may not use this file except in compliance with
+ the License. You may obtain a copy of the License at
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+==================================================================== */
package org.apache.poi.hssf.record.formula.functions;
-import org.apache.poi.hssf.record.formula.Area3DPtg;
-import org.apache.poi.hssf.record.formula.AreaPtg;
-import org.apache.poi.hssf.record.formula.eval.Area3DEval;
import org.apache.poi.hssf.record.formula.eval.AreaEval;
import org.apache.poi.hssf.record.formula.eval.BoolEval;
import org.apache.poi.hssf.record.formula.eval.ErrorEval;
import org.apache.poi.hssf.record.formula.eval.EvaluationException;
import org.apache.poi.hssf.record.formula.eval.NumericValueEval;
import org.apache.poi.hssf.record.formula.eval.OperandResolver;
-import org.apache.poi.hssf.record.formula.eval.Ref3DEval;
import org.apache.poi.hssf.record.formula.eval.RefEval;
import org.apache.poi.hssf.record.formula.eval.StringEval;
import org.apache.poi.hssf.record.formula.eval.ValueEval;
-import org.apache.poi.hssf.usermodel.HSSFFormulaEvaluator;
-import org.apache.poi.ss.usermodel.Sheet;
-import org.apache.poi.ss.usermodel.Workbook;
/**
* Implementation for Excel function OFFSET()<p/>
*
*
* @author Josh Micich
*/
-public final class Offset implements FreeRefFunction {
+public final class Offset implements Function {
// These values are specific to BIFF8
private static final int LAST_VALID_ROW_INDEX = 0xFFFF;
private static final int LAST_VALID_COLUMN_INDEX = 0xFF;
* Encapsulates either an area or cell reference which may be 2d or 3d.
*/
private static final class BaseRef {
- private static final int INVALID_SHEET_INDEX = -1;
private final int _firstRowIndex;
private final int _firstColumnIndex;
private final int _width;
private final int _height;
- private final int _externalSheetIndex;
+ private final RefEval _refEval;
+ private final AreaEval _areaEval;
public BaseRef(RefEval re) {
+ _refEval = re;
+ _areaEval = null;
_firstRowIndex = re.getRow();
_firstColumnIndex = re.getColumn();
_height = 1;
_width = 1;
- if (re instanceof Ref3DEval) {
- Ref3DEval r3e = (Ref3DEval) re;
- _externalSheetIndex = r3e.getExternSheetIndex();
- } else {
- _externalSheetIndex = INVALID_SHEET_INDEX;
- }
}
public BaseRef(AreaEval ae) {
+ _refEval = null;
+ _areaEval = ae;
_firstRowIndex = ae.getFirstRow();
_firstColumnIndex = ae.getFirstColumn();
_height = ae.getLastRow() - ae.getFirstRow() + 1;
_width = ae.getLastColumn() - ae.getFirstColumn() + 1;
- if (ae instanceof Area3DEval) {
- Area3DEval a3e = (Area3DEval) ae;
- _externalSheetIndex = a3e.getExternSheetIndex();
- } else {
- _externalSheetIndex = INVALID_SHEET_INDEX;
- }
}
public int getWidth() {
public int getFirstColumnIndex() {
return _firstColumnIndex;
}
- public boolean isIs3d() {
- return _externalSheetIndex > 0;
- }
- public short getExternalSheetIndex() {
- if(_externalSheetIndex < 0) {
- throw new IllegalStateException("external sheet index only available for 3d refs");
+ public AreaEval offset(int relFirstRowIx, int relLastRowIx,
+ int relFirstColIx, int relLastColIx) {
+ if (_refEval == null) {
+ return _areaEval.offset(relFirstRowIx, relLastRowIx, relFirstColIx, relLastColIx);
}
- return (short) _externalSheetIndex;
+ return _refEval.offset(relFirstRowIx, relLastRowIx, relFirstColIx, relLastColIx);
}
}
- public ValueEval evaluate(Eval[] args, int srcCellRow, short srcCellCol, Workbook workbook, Sheet sheet) {
-
+ public Eval evaluate(Eval[] args, int srcCellRow, short srcCellCol) {
if(args.length < 3 || args.length > 5) {
return ErrorEval.VALUE_INVALID;
}
}
LinearOffsetRange rowOffsetRange = new LinearOffsetRange(rowOffset, height);
LinearOffsetRange colOffsetRange = new LinearOffsetRange(columnOffset, width);
- return createOffset(baseRef, rowOffsetRange, colOffsetRange, workbook, sheet);
+ return createOffset(baseRef, rowOffsetRange, colOffsetRange);
} catch (EvaluationException e) {
return e.getErrorEval();
}
}
private static AreaEval createOffset(BaseRef baseRef,
- LinearOffsetRange rowOffsetRange, LinearOffsetRange colOffsetRange,
- Workbook workbook, Sheet sheet) throws EvaluationException {
-
- LinearOffsetRange rows = rowOffsetRange.normaliseAndTranslate(baseRef.getFirstRowIndex());
- LinearOffsetRange cols = colOffsetRange.normaliseAndTranslate(baseRef.getFirstColumnIndex());
+ LinearOffsetRange orRow, LinearOffsetRange orCol) throws EvaluationException {
+ LinearOffsetRange absRows = orRow.normaliseAndTranslate(baseRef.getFirstRowIndex());
+ LinearOffsetRange absCols = orCol.normaliseAndTranslate(baseRef.getFirstColumnIndex());
- if(rows.isOutOfBounds(0, LAST_VALID_ROW_INDEX)) {
+ if(absRows.isOutOfBounds(0, LAST_VALID_ROW_INDEX)) {
throw new EvaluationException(ErrorEval.REF_INVALID);
}
- if(cols.isOutOfBounds(0, LAST_VALID_COLUMN_INDEX)) {
+ if(absCols.isOutOfBounds(0, LAST_VALID_COLUMN_INDEX)) {
throw new EvaluationException(ErrorEval.REF_INVALID);
}
- if(baseRef.isIs3d()) {
- Area3DPtg a3dp = new Area3DPtg(rows.getFirstIndex(), rows.getLastIndex(),
- cols.getFirstIndex(), cols.getLastIndex(),
- false, false, false, false,
- baseRef.getExternalSheetIndex());
- return HSSFFormulaEvaluator.evaluateArea3dPtg(workbook, a3dp);
- }
-
- AreaPtg ap = new AreaPtg(rows.getFirstIndex(), rows.getLastIndex(),
- cols.getFirstIndex(), cols.getLastIndex(),
- false, false, false, false);
- return HSSFFormulaEvaluator.evaluateAreaPtg(sheet, workbook, ap);
+ return baseRef.offset(orRow.getFirstIndex(), orRow.getLastIndex(), orCol.getFirstIndex(), orCol.getLastIndex());
}
private static BaseRef evaluateBaseRef(Eval eval) throws EvaluationException {
-/*
-* 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.
-*/
+/* ====================================================================
+ Licensed to the Apache Software Foundation (ASF) under one or more
+ contributor license agreements. See the NOTICE file distributed with
+ this work for additional information regarding copyright ownership.
+ The ASF licenses this file to You under the Apache License, Version 2.0
+ (the "License"); you may not use this file except in compliance with
+ the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+==================================================================== */
package org.apache.poi.hssf.record.formula.functions;
+
/**
* Implementation of Excel function SUMX2MY2()<p/>
*
*/
public final class Sumx2my2 extends XYNumericFunction {
- protected double evaluate(double[] xArray, double[] yArray) {
- return MathX.sumx2my2(xArray, yArray);
- }
+ private static final Accumulator XSquaredMinusYSquaredAccumulator = new Accumulator() {
+ public double accumulate(double x, double y) {
+ return x * x - y * y;
+ }
+ };
+
+ protected Accumulator createAccumulator() {
+ return XSquaredMinusYSquaredAccumulator;
+ }
}
-/*
-* 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.
-*/
+/* ====================================================================
+ Licensed to the Apache Software Foundation (ASF) under one or more
+ contributor license agreements. See the NOTICE file distributed with
+ this work for additional information regarding copyright ownership.
+ The ASF licenses this file to You under the Apache License, Version 2.0
+ (the "License"); you may not use this file except in compliance with
+ the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+==================================================================== */
package org.apache.poi.hssf.record.formula.functions;
+
/**
* Implementation of Excel function SUMX2PY2()<p/>
*
*/
public final class Sumx2py2 extends XYNumericFunction {
- protected double evaluate(double[] xArray, double[] yArray) {
- return MathX.sumx2py2(xArray, yArray);
- }
+ private static final Accumulator XSquaredPlusYSquaredAccumulator = new Accumulator() {
+ public double accumulate(double x, double y) {
+ return x * x + y * y;
+ }
+ };
+
+ protected Accumulator createAccumulator() {
+ return XSquaredPlusYSquaredAccumulator;
+ }
}
-/*
-* 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.
-*/
+/* ====================================================================
+ Licensed to the Apache Software Foundation (ASF) under one or more
+ contributor license agreements. See the NOTICE file distributed with
+ this work for additional information regarding copyright ownership.
+ The ASF licenses this file to You under the Apache License, Version 2.0
+ (the "License"); you may not use this file except in compliance with
+ the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+==================================================================== */
package org.apache.poi.hssf.record.formula.functions;
*/
public final class Sumxmy2 extends XYNumericFunction {
- protected double evaluate(double[] xArray, double[] yArray) {
- return MathX.sumxmy2(xArray, yArray);
- }
+ private static final Accumulator XMinusYSquaredAccumulator = new Accumulator() {
+ public double accumulate(double x, double y) {
+ double xmy = x - y;
+ return xmy * xmy;
+ }
+ };
+
+ protected Accumulator createAccumulator() {
+ return XMinusYSquaredAccumulator;
+ }
}
-/*
-* 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.
-*/
+/* ====================================================================
+ Licensed to the Apache Software Foundation (ASF) under one or more
+ contributor license agreements. See the NOTICE file distributed with
+ this work for additional information regarding copyright ownership.
+ The ASF licenses this file to You under the Apache License, Version 2.0
+ (the "License"); you may not use this file except in compliance with
+ the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+==================================================================== */
package org.apache.poi.hssf.record.formula.functions;
import org.apache.poi.hssf.record.formula.eval.NumberEval;
import org.apache.poi.hssf.record.formula.eval.RefEval;
import org.apache.poi.hssf.record.formula.eval.ValueEval;
+import org.apache.poi.hssf.record.formula.functions.LookupUtils.ValueVector;
/**
* @author Amol S. Deshmukh < amolweb at ya hoo dot com >
- *
+ *
*/
public abstract class XYNumericFunction implements Function {
- protected static final int X = 0;
- protected static final int Y = 1;
-
- protected static final class DoubleArrayPair {
- private final double[] _xArray;
- private final double[] _yArray;
+ private static abstract class ValueArray implements ValueVector {
+ private final int _size;
+ protected ValueArray(int size) {
+ _size = size;
+ }
+ public ValueEval getItem(int index) {
+ if (index < 0 || index > _size) {
+ throw new IllegalArgumentException("Specified index " + index
+ + " is outside range (0.." + (_size - 1) + ")");
+ }
+ return getItemInternal(index);
+ }
+ protected abstract ValueEval getItemInternal(int index);
+ public final int getSize() {
+ return _size;
+ }
+ }
- public DoubleArrayPair(double[] xArray, double[] yArray) {
- _xArray = xArray;
- _yArray = yArray;
+ private static final class SingleCellValueArray extends ValueArray {
+ private final ValueEval _value;
+ public SingleCellValueArray(ValueEval value) {
+ super(1);
+ _value = value;
}
- public double[] getXArray() {
- return _xArray;
+ protected ValueEval getItemInternal(int index) {
+ return _value;
+ }
+ }
+
+ private static final class RefValueArray extends ValueArray {
+ private final RefEval _ref;
+ public RefValueArray(RefEval ref) {
+ super(1);
+ _ref = ref;
}
- public double[] getYArray() {
- return _yArray;
+ protected ValueEval getItemInternal(int index) {
+ return _ref.getInnerValueEval();
}
- }
+ }
+ private static final class AreaValueArray extends ValueArray {
+ private final AreaEval _ae;
+ private final int _width;
+
+ public AreaValueArray(AreaEval ae) {
+ super(ae.getWidth() * ae.getHeight());
+ _ae = ae;
+ _width = ae.getWidth();
+ }
+ protected ValueEval getItemInternal(int index) {
+ int rowIx = index / _width;
+ int colIx = index % _width;
+ return _ae.getRelativeValue(rowIx, colIx);
+ }
+ }
+
+ protected static interface Accumulator {
+ double accumulate(double x, double y);
+ }
+
+ /**
+ * Constructs a new instance of the Accumulator used to calculated this function
+ */
+ protected abstract Accumulator createAccumulator();
+
+ public final Eval evaluate(Eval[] args, int srcCellRow, short srcCellCol) {
+ if (args.length != 2) {
+ return ErrorEval.VALUE_INVALID;
+ }
- public final Eval evaluate(Eval[] args, int srcCellRow, short srcCellCol) {
- if(args.length != 2) {
- return ErrorEval.VALUE_INVALID;
- }
-
- double[][] values;
+ double result;
try {
- values = getValues(args[0], args[1]);
+ ValueVector vvX = createValueVector(args[0]);
+ ValueVector vvY = createValueVector(args[1]);
+ int size = vvX.getSize();
+ if (size == 0 || vvY.getSize() != size) {
+ return ErrorEval.NA;
+ }
+ result = evaluateInternal(vvX, vvY, size);
} catch (EvaluationException e) {
return e.getErrorEval();
}
- if (values==null
- || values[X] == null || values[Y] == null
- || values[X].length == 0 || values[Y].length == 0
- || values[X].length != values[Y].length) {
- return ErrorEval.VALUE_INVALID;
- }
-
- double d = evaluate(values[X], values[Y]);
- if (Double.isNaN(d) || Double.isInfinite(d)) {
+ if (Double.isNaN(result) || Double.isInfinite(result)) {
return ErrorEval.NUM_ERROR;
}
- return new NumberEval(d);
- }
- protected abstract double evaluate(double[] xArray, double[] yArray);
-
- /**
- * Returns a double array that contains values for the numeric cells
- * from among the list of operands. Blanks and Blank equivalent cells
- * are ignored. Error operands or cells containing operands of type
- * that are considered invalid and would result in #VALUE! error in
- * excel cause this function to return null.
- */
- private static double[][] getNumberArray(Eval[] xops, Eval[] yops) throws EvaluationException {
-
- // check for errors first: size mismatch, value errors in x, value errors in y
-
- int nArrayItems = xops.length;
- if(nArrayItems != yops.length) {
- throw new EvaluationException(ErrorEval.NA);
- }
- for (int i = 0; i < xops.length; i++) {
- Eval eval = xops[i];
- if (eval instanceof ErrorEval) {
- throw new EvaluationException((ErrorEval) eval);
+ return new NumberEval(result);
+ }
+
+ private double evaluateInternal(ValueVector x, ValueVector y, int size)
+ throws EvaluationException {
+ Accumulator acc = createAccumulator();
+
+ // error handling is as if the x is fully evaluated before y
+ ErrorEval firstXerr = null;
+ ErrorEval firstYerr = null;
+ boolean accumlatedSome = false;
+ double result = 0.0;
+
+ for (int i = 0; i < size; i++) {
+ ValueEval vx = x.getItem(i);
+ ValueEval vy = y.getItem(i);
+ if (vx instanceof ErrorEval) {
+ if (firstXerr == null) {
+ firstXerr = (ErrorEval) vx;
+ continue;
+ }
}
- }
- for (int i = 0; i < yops.length; i++) {
- Eval eval = yops[i];
- if (eval instanceof ErrorEval) {
- throw new EvaluationException((ErrorEval) eval);
+ if (vy instanceof ErrorEval) {
+ if (firstYerr == null) {
+ firstYerr = (ErrorEval) vy;
+ continue;
+ }
+ }
+ // only count pairs if both elements are numbers
+ if (vx instanceof NumberEval && vy instanceof NumberEval) {
+ accumlatedSome = true;
+ NumberEval nx = (NumberEval) vx;
+ NumberEval ny = (NumberEval) vy;
+ result += acc.accumulate(nx.getNumberValue(), ny.getNumberValue());
+ } else {
+ // all other combinations of value types are silently ignored
}
}
-
- double[] xResult = new double[nArrayItems];
- double[] yResult = new double[nArrayItems];
-
- int count = 0;
-
- for (int i=0, iSize=nArrayItems; i<iSize; i++) {
- Eval xEval = xops[i];
- Eval yEval = yops[i];
-
- if (isNumberEval(xEval) && isNumberEval(yEval)) {
- xResult[count] = getDoubleValue(xEval);
- yResult[count] = getDoubleValue(yEval);
- if (Double.isNaN(xResult[count]) || Double.isNaN(xResult[count])) {
- throw new EvaluationException(ErrorEval.NUM_ERROR);
- }
- count++;
- }
- }
-
- return new double[][] {
- trimToSize(xResult, count),
- trimToSize(yResult, count),
- };
- }
-
- private static double[][] getValues(Eval argX, Eval argY) throws EvaluationException {
-
- if (argX instanceof ErrorEval) {
- throw new EvaluationException((ErrorEval) argX);
- }
- if (argY instanceof ErrorEval) {
- throw new EvaluationException((ErrorEval) argY);
- }
-
- Eval[] xEvals;
- Eval[] yEvals;
- if (argX instanceof AreaEval) {
- AreaEval ae = (AreaEval) argX;
- xEvals = ae.getValues();
- } else {
- xEvals = new Eval[] { argX, };
- }
-
- if (argY instanceof AreaEval) {
- AreaEval ae = (AreaEval) argY;
- yEvals = ae.getValues();
- } else {
- yEvals = new Eval[] { argY, };
- }
-
- return getNumberArray(xEvals, yEvals);
- }
-
- private static double[] trimToSize(double[] arr, int len) {
- double[] tarr = arr;
- if (arr.length > len) {
- tarr = new double[len];
- System.arraycopy(arr, 0, tarr, 0, len);
- }
- return tarr;
- }
-
- private static boolean isNumberEval(Eval eval) {
- boolean retval = false;
-
- if (eval instanceof NumberEval) {
- retval = true;
- }
- else if (eval instanceof RefEval) {
- RefEval re = (RefEval) eval;
- ValueEval ve = re.getInnerValueEval();
- retval = (ve instanceof NumberEval);
- }
-
- return retval;
- }
-
- private static double getDoubleValue(Eval eval) {
- double retval = 0;
- if (eval instanceof NumberEval) {
- NumberEval ne = (NumberEval) eval;
- retval = ne.getNumberValue();
- }
- else if (eval instanceof RefEval) {
- RefEval re = (RefEval) eval;
- ValueEval ve = re.getInnerValueEval();
- retval = (ve instanceof NumberEval)
- ? ((NumberEval) ve).getNumberValue()
- : Double.NaN;
- }
- else if (eval instanceof ErrorEval) {
- retval = Double.NaN;
- }
- return retval;
- }
+ if (firstXerr != null) {
+ throw new EvaluationException(firstXerr);
+ }
+ if (firstYerr != null) {
+ throw new EvaluationException(firstYerr);
+ }
+ if (!accumlatedSome) {
+ throw new EvaluationException(ErrorEval.DIV_ZERO);
+ }
+ return result;
+ }
+
+ private static ValueVector createValueVector(Eval arg) throws EvaluationException {
+ if (arg instanceof ErrorEval) {
+ throw new EvaluationException((ErrorEval) arg);
+ }
+ if (arg instanceof AreaEval) {
+ return new AreaValueArray((AreaEval) arg);
+ }
+ if (arg instanceof RefEval) {
+ return new RefValueArray((RefEval) arg);
+ }
+ if (arg instanceof ValueEval) {
+ return new SingleCellValueArray((ValueEval) arg);
+ }
+ throw new RuntimeException("Unexpected eval class (" + arg.getClass().getName() + ")");
+ }
}
return new FormulaParser(formula, workbook);
}
-
/**
* debug method
- *
- * @param formula
- * @param sheet
- * @param workbook
*/
void inspectPtgs(String formula) {
- HSSFWorkbook hssfWb = (HSSFWorkbook)_workbook;
- FormulaParser fp = new FormulaParser(formula, hssfWb);
- fp.parse();
- Ptg[] ptgs = fp.getRPNPtg();
+ Ptg[] ptgs = FormulaParser.parse(formula, _workbook);
System.out.println("<ptg-group>");
for (int i = 0, iSize = ptgs.length; i < iSize; i++) {
System.out.println("<ptg>");
import org.apache.poi.hssf.model.Sheet;
import org.apache.poi.hssf.model.Workbook;
import org.apache.poi.hssf.record.CellValueRecordInterface;
-import org.apache.poi.hssf.record.CFRuleRecord;
-import org.apache.poi.hssf.record.DVALRecord;
import org.apache.poi.hssf.record.DVRecord;
-import org.apache.poi.hssf.record.EOFRecord;
import org.apache.poi.hssf.record.EscherAggregate;
-import org.apache.poi.hssf.record.HCenterRecord;
-import org.apache.poi.hssf.record.PageBreakRecord;
import org.apache.poi.hssf.record.Record;
import org.apache.poi.hssf.record.RowRecord;
import org.apache.poi.hssf.record.SCLRecord;
-import org.apache.poi.hssf.record.VCenterRecord;
import org.apache.poi.hssf.record.WSBoolRecord;
import org.apache.poi.hssf.record.WindowTwoRecord;
import org.apache.poi.hssf.record.aggregates.DataValidityTable;
DVRecord dvRecord = dataValidation.createDVRecord(workbook);
dvt.addDataValidation(dvRecord);
}
+
+ /**
+ * Get the DVRecords objects that are associated to this sheet
+ * @return a list of DVRecord instances
+ */
+ public List getDVRecords() {
+ List dvRecords = new ArrayList();
+ List records = sheet.getRecords();
+
+ for(int index=0; index<records.size(); index++) {
+ if(records.get(index) instanceof DVRecord) {
+ dvRecords.add(records.get(index));
+ }
+ }
+ return dvRecords;
+ }
/**
// Since it's a formula cell, process the
// formula string, and look to see if
// it contains any references
- FormulaParser fp = new FormulaParser(c.getCellFormula(), workbook);
- fp.parse();
// Look for references, and update if needed
- Ptg[] ptgs = fp.getRPNPtg();
+ Ptg[] ptgs = FormulaParser.parse(c.getCellFormula(), workbook);
boolean changed = false;
for(int i=0; i<ptgs.length; i++) {
if(ptgs[i] instanceof RefPtg) {
// re-create the formula string
if(changed) {
c.setCellFormula(
- fp.toFormulaString(ptgs)
+ FormulaParser.toFormulaString(workbook, ptgs)
);
}
}
Stack ptgs = new Stack();
if (settingRowAndColumn) {
- final int exprsSize = 2 * 11 + 1; // Area3DPtg.SIZE + UnionPtg.SIZE
+ final int exprsSize = 2 * 11 + 1; // 2 * Area3DPtg.SIZE + UnionPtg.SIZE
ptgs.add(new MemFuncPtg(exprsSize));
}
- if (startColumn >= 0)
- {
- Area3DPtg colArea = new Area3DPtg();
- colArea.setExternSheetIndex(externSheetIndex);
- colArea.setFirstColumn((short)startColumn);
- colArea.setLastColumn((short)endColumn);
- colArea.setFirstRow(0);
- colArea.setLastRow(MAX_ROW);
- colArea.setFirstColRelative(false);
- colArea.setLastColRelative(false);
- colArea.setFirstRowRelative(false);
- colArea.setLastRowRelative(false);
+ if (startColumn >= 0) {
+ Area3DPtg colArea = new Area3DPtg(0, MAX_ROW, startColumn, endColumn,
+ false, false, false, false, externSheetIndex);
ptgs.add(colArea);
}
- if (startRow >= 0)
- {
- Area3DPtg rowArea = new Area3DPtg();
- rowArea.setExternSheetIndex(externSheetIndex);
- rowArea.setFirstColumn((short)0);
- rowArea.setLastColumn(MAX_COLUMN);
- rowArea.setFirstRow(startRow);
- rowArea.setLastRow(endRow);
- rowArea.setFirstColRelative(false);
- rowArea.setLastColRelative(false);
- rowArea.setFirstRowRelative(false);
- rowArea.setLastRowRelative(false);
+ if (startRow >= 0) {
+ Area3DPtg rowArea = new Area3DPtg(startRow, endRow, 0, MAX_COLUMN,
+ false, false, false, false, externSheetIndex);
ptgs.add(rowArea);
}
if (settingRowAndColumn)
package org.apache.poi.hssf.util;
-import java.util.ArrayList;
-import java.util.StringTokenizer;
-
-import org.apache.poi.hssf.record.formula.AreaI;
-
-public final class AreaReference {
-
- /** The character (!) that separates sheet names from cell references */
- private static final char SHEET_NAME_DELIMITER = '!';
- /** The character (:) that separates the two cell references in a multi-cell area reference */
- private static final char CELL_DELIMITER = ':';
- /** The character (') used to quote sheet names when they contain special characters */
- private static final char SPECIAL_NAME_DELIMITER = '\'';
-
- private final CellReference _firstCell;
- private final CellReference _lastCell;
- private final boolean _isSingleCell;
+public final class AreaReference extends org.apache.poi.ss.util.AreaReference {
/**
* Create an area ref from a string representation. Sheet names containing special characters should be
* delimited and escaped as per normal syntax rules for formulas.<br/>
* The area reference must be contiguous (i.e. represent a single rectangle, not a union of rectangles)
*/
public AreaReference(String reference) {
- if(! isContiguous(reference)) {
- throw new IllegalArgumentException(
- "References passed to the AreaReference must be contiguous, " +
- "use generateContiguous(ref) if you have non-contiguous references");
- }
-
- String[] parts = separateAreaRefs(reference);
-
- // Special handling for whole-column references
- if(parts.length == 2 && parts[0].length() == 1 &&
- parts[1].length() == 1 &&
- parts[0].charAt(0) >= 'A' && parts[0].charAt(0) <= 'Z' &&
- parts[1].charAt(0) >= 'A' && parts[1].charAt(0) <= 'Z') {
- // Represented internally as x$1 to x$65536
- // which is the maximum range of rows
- parts[0] = parts[0] + "$1";
- parts[1] = parts[1] + "$65536";
- }
-
- _firstCell = new CellReference(parts[0]);
-
- if(parts.length == 2) {
- _lastCell = new CellReference(parts[1]);
- _isSingleCell = false;
- } else {
- _lastCell = _firstCell;
- _isSingleCell = true;
- }
+ super(reference);
}
/**
* Creates an area ref from a pair of Cell References.
*/
public AreaReference(CellReference topLeft, CellReference botRight) {
- _firstCell = topLeft;
- _lastCell = botRight;
- _isSingleCell = false;
- }
-
- /**
- * Is the reference for a contiguous (i.e.
- * unbroken) area, or is it made up of
- * several different parts?
- * (If it is, you will need to call
- * ....
- */
- public static boolean isContiguous(String reference) {
- if(reference.indexOf(',') == -1) {
- return true;
- }
- return false;
- }
-
- /**
- * Is the reference for a whole-column reference,
- * such as C:C or D:G ?
- */
- public static boolean isWholeColumnReference(CellReference topLeft, CellReference botRight) {
- // These are represented as something like
- // C$1:C$65535 or D$1:F$0
- // i.e. absolute from 1st row to 0th one
- if(topLeft.getRow() == 0 && topLeft.isRowAbsolute() &&
- botRight.getRow() == 65535 && botRight.isRowAbsolute()) {
- return true;
- }
- return false;
- }
- public boolean isWholeColumnReference() {
- return isWholeColumnReference(_firstCell, _lastCell);
- }
-
- /**
- * Takes a non-contiguous area reference, and
- * returns an array of contiguous area references.
- */
- public static AreaReference[] generateContiguous(String reference) {
- ArrayList refs = new ArrayList();
- StringTokenizer st = new StringTokenizer(reference, ",");
- while(st.hasMoreTokens()) {
- refs.add(
- new AreaReference(st.nextToken())
- );
- }
- return (AreaReference[])refs.toArray(new AreaReference[refs.size()]);
- }
-
- /**
- * @return <code>false</code> if this area reference involves more than one cell
- */
- public boolean isSingleCell() {
- return _isSingleCell;
- }
-
- /**
- * @return the first cell reference which defines this area. Usually this cell is in the upper
- * left corner of the area (but this is not a requirement).
- */
- public CellReference getFirstCell() {
- return _firstCell;
- }
-
- /**
- * Note - if this area reference refers to a single cell, the return value of this method will
- * be identical to that of <tt>getFirstCell()</tt>
- * @return the second cell reference which defines this area. For multi-cell areas, this is
- * cell diagonally opposite the 'first cell'. Usually this cell is in the lower right corner
- * of the area (but this is not a requirement).
- */
- public CellReference getLastCell() {
- return _lastCell;
- }
- /**
- * Returns a reference to every cell covered by this area
- */
- public CellReference[] getAllReferencedCells() {
- // Special case for single cell reference
- if(_isSingleCell) {
- return new CellReference[] { _firstCell, };
- }
-
- // Interpolate between the two
- int minRow = Math.min(_firstCell.getRow(), _lastCell.getRow());
- int maxRow = Math.max(_firstCell.getRow(), _lastCell.getRow());
- int minCol = Math.min(_firstCell.getCol(), _lastCell.getCol());
- int maxCol = Math.max(_firstCell.getCol(), _lastCell.getCol());
- String sheetName = _firstCell.getSheetName();
-
- ArrayList refs = new ArrayList();
- for(int row=minRow; row<=maxRow; row++) {
- for(int col=minCol; col<=maxCol; col++) {
- CellReference ref = new CellReference(sheetName, row, col, _firstCell.isRowAbsolute(), _firstCell.isColAbsolute());
- refs.add(ref);
- }
- }
- return (CellReference[])refs.toArray(new CellReference[refs.size()]);
- }
-
- /**
- * Example return values:
- * <table border="0" cellpadding="1" cellspacing="0" summary="Example return values">
- * <tr><th align='left'>Result</th><th align='left'>Comment</th></tr>
- * <tr><td>A1:A1</td><td>Single cell area reference without sheet</td></tr>
- * <tr><td>A1:$C$1</td><td>Multi-cell area reference without sheet</td></tr>
- * <tr><td>Sheet1!A$1:B4</td><td>Standard sheet name</td></tr>
- * <tr><td>'O''Brien''s Sales'!B5:C6' </td><td>Sheet name with special characters</td></tr>
- * </table>
- * @return the text representation of this area reference as it would appear in a formula.
- */
- public String formatAsString() {
- // Special handling for whole-column references
- if(isWholeColumnReference()) {
- return
- CellReference.convertNumToColString(_firstCell.getCol())
- + ":" +
- CellReference.convertNumToColString(_lastCell.getCol());
- }
-
- StringBuffer sb = new StringBuffer(32);
- sb.append(_firstCell.formatAsString());
- if(!_isSingleCell) {
- sb.append(CELL_DELIMITER);
- if(_lastCell.getSheetName() == null) {
- sb.append(_lastCell.formatAsString());
- } else {
- // don't want to include the sheet name twice
- _lastCell.appendCellReference(sb);
- }
- }
- return sb.toString();
- }
- /**
- * Formats a 2-D area as it would appear in a formula. See formatAsString() (no-arg)
- */
- public static String formatAsString(AreaI area) {
- CellReference topLeft = new CellReference(area.getFirstRow(),area.getFirstColumn(),!area.isFirstRowRelative(),!area.isFirstColRelative());
- CellReference botRight = new CellReference(area.getLastRow(),area.getLastColumn(),!area.isLastRowRelative(),!area.isLastColRelative());
-
- if(isWholeColumnReference(topLeft, botRight)) {
- return (new AreaReference(topLeft, botRight)).formatAsString();
- }
- return topLeft.formatAsString() + ":" + botRight.formatAsString();
- }
- public String toString() {
- StringBuffer sb = new StringBuffer(64);
- sb.append(getClass().getName()).append(" [");
- sb.append(formatAsString());
- sb.append("]");
- return sb.toString();
- }
-
- /**
- * Separates Area refs in two parts and returns them as separate elements in a String array,
- * each qualified with the sheet name (if present)
- *
- * @return array with one or two elements. never <code>null</code>
- */
- private static String[] separateAreaRefs(String reference) {
- // TODO - refactor cell reference parsing logic to one place.
- // Current known incarnations:
- // FormulaParser.GetName()
- // CellReference.separateRefParts()
- // AreaReference.separateAreaRefs() (here)
- // SheetNameFormatter.format() (inverse)
-
-
- int len = reference.length();
- int delimiterPos = -1;
- boolean insideDelimitedName = false;
- for(int i=0; i<len; i++) {
- switch(reference.charAt(i)) {
- case CELL_DELIMITER:
- if(!insideDelimitedName) {
- if(delimiterPos >=0) {
- throw new IllegalArgumentException("More than one cell delimiter '"
- + CELL_DELIMITER + "' appears in area reference '" + reference + "'");
- }
- delimiterPos = i;
- }
- default:
- continue;
- case SPECIAL_NAME_DELIMITER:
- // fall through
- }
- if(!insideDelimitedName) {
- insideDelimitedName = true;
- continue;
- }
-
- if(i >= len-1) {
- // reference ends with the delimited name.
- // Assume names like: "Sheet1!'A1'" are never legal.
- throw new IllegalArgumentException("Area reference '" + reference
- + "' ends with special name delimiter '" + SPECIAL_NAME_DELIMITER + "'");
- }
- if(reference.charAt(i+1) == SPECIAL_NAME_DELIMITER) {
- // two consecutive quotes is the escape sequence for a single one
- i++; // skip this and keep parsing the special name
- } else {
- // this is the end of the delimited name
- insideDelimitedName = false;
- }
- }
- if(delimiterPos < 0) {
- return new String[] { reference, };
- }
-
- String partA = reference.substring(0, delimiterPos);
- String partB = reference.substring(delimiterPos+1);
- if(partB.indexOf(SHEET_NAME_DELIMITER) >=0) {
- // TODO - are references like "Sheet1!A1:Sheet1:B2" ever valid?
- // FormulaParser has code to handle that.
-
- throw new RuntimeException("Unexpected " + SHEET_NAME_DELIMITER
- + " in second cell reference of '" + reference + "'");
- }
-
- int plingPos = partA.lastIndexOf(SHEET_NAME_DELIMITER);
- if(plingPos < 0) {
- return new String [] { partA, partB, };
- }
-
- String sheetName = partA.substring(0, plingPos + 1); // +1 to include delimiter
-
- return new String [] { partA, sheetName + partB, };
+ super(topLeft, botRight);
}
-}
\ No newline at end of file
+}
-/*
-* 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.
-*/
+/* ====================================================================
+ 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.ss.usermodel;
-import java.lang.reflect.Constructor;
-import java.util.HashMap;
import java.util.Iterator;
-import java.util.Map;
import java.util.Stack;
import org.apache.poi.hssf.model.FormulaParser;
import org.apache.poi.hssf.record.formula.AreaPtg;
import org.apache.poi.hssf.record.formula.BoolPtg;
import org.apache.poi.hssf.record.formula.ControlPtg;
+import org.apache.poi.hssf.record.formula.ErrPtg;
import org.apache.poi.hssf.record.formula.IntPtg;
import org.apache.poi.hssf.record.formula.MemErrPtg;
import org.apache.poi.hssf.record.formula.MissingArgPtg;
import org.apache.poi.hssf.record.formula.StringPtg;
import org.apache.poi.hssf.record.formula.UnionPtg;
import org.apache.poi.hssf.record.formula.UnknownPtg;
-import org.apache.poi.hssf.record.formula.eval.Area2DEval;
-import org.apache.poi.hssf.record.formula.eval.Area3DEval;
import org.apache.poi.hssf.record.formula.eval.AreaEval;
import org.apache.poi.hssf.record.formula.eval.BlankEval;
import org.apache.poi.hssf.record.formula.eval.BoolEval;
import org.apache.poi.hssf.record.formula.eval.ErrorEval;
import org.apache.poi.hssf.record.formula.eval.Eval;
import org.apache.poi.hssf.record.formula.eval.FunctionEval;
+import org.apache.poi.hssf.record.formula.eval.LazyAreaEval;
+import org.apache.poi.hssf.record.formula.eval.LazyRefEval;
import org.apache.poi.hssf.record.formula.eval.NameEval;
import org.apache.poi.hssf.record.formula.eval.NameXEval;
import org.apache.poi.hssf.record.formula.eval.NumberEval;
import org.apache.poi.hssf.record.formula.eval.OperationEval;
-import org.apache.poi.hssf.record.formula.eval.Ref2DEval;
-import org.apache.poi.hssf.record.formula.eval.Ref3DEval;
import org.apache.poi.hssf.record.formula.eval.RefEval;
import org.apache.poi.hssf.record.formula.eval.StringEval;
import org.apache.poi.hssf.record.formula.eval.ValueEval;
-import org.apache.poi.hssf.usermodel.HSSFFormulaEvaluator;
/**
* @author Amol S. Deshmukh < amolweb at ya hoo dot com >
- *
+ *
*/
public class FormulaEvaluator {
-
- // params to lookup the right constructor using reflection
- private static final Class[] VALUE_CONTRUCTOR_CLASS_ARRAY = new Class[] { Ptg.class };
- private static final Class[] AREA3D_CONSTRUCTOR_CLASS_ARRAY = new Class[] { Ptg.class, ValueEval[].class };
-
- private static final Class[] REFERENCE_CONSTRUCTOR_CLASS_ARRAY = new Class[] { Ptg.class, ValueEval.class };
-
- private static final Class[] REF3D_CONSTRUCTOR_CLASS_ARRAY = new Class[] { Ptg.class, ValueEval.class };
-
- // Maps for mapping *Eval to *Ptg
- private static final Map VALUE_EVALS_MAP = new HashMap();
-
- /*
- * Following is the mapping between the Ptg tokens returned
- * by the FormulaParser and the *Eval classes that are used
- * by the FormulaEvaluator
- */
- static {
- VALUE_EVALS_MAP.put(BoolPtg.class, BoolEval.class);
- VALUE_EVALS_MAP.put(IntPtg.class, NumberEval.class);
- VALUE_EVALS_MAP.put(NumberPtg.class, NumberEval.class);
- VALUE_EVALS_MAP.put(StringPtg.class, StringEval.class);
-
- }
-
-
protected Sheet _sheet;
protected Workbook _workbook;
-
+
public FormulaEvaluator(Sheet sheet, Workbook workbook) {
- this._sheet = sheet;
- this._workbook = workbook;
+ _sheet = sheet;
+ _workbook = workbook;
}
-
+
/**
* Does nothing
* @deprecated (Aug 2008) - not needed, since the current row can be derived from the cell
*/
- public void setCurrentRow(Row row) {}
+ public void setCurrentRow(Row row) {
+ // do nothing
+ }
+
/**
* If cell contains a formula, the formula is evaluated and returned,
* else the CellValue simply copies the appropriate cell value from
* the cell and also its cell type. This method should be preferred over
* evaluateInCell() when the call should not modify the contents of the
- * original cell.
+ * original cell.
* @param cell
*/
public CellValue evaluate(Cell cell) {
}
return retval;
}
-
-
+
+
/**
* If cell contains formula, it evaluates the formula,
* and saves the result of the formula. The cell
* remains as a formula cell.
* Else if cell does not contain formula, this method leaves
- * the cell unchanged.
+ * the cell unchanged.
* Note that the type of the formula result is returned,
* so you know what kind of value is also stored with
- * the formula.
+ * the formula.
* <pre>
* int evaluatedCellType = evaluator.evaluateFormulaCell(cell);
* </pre>
* Be aware that your cell will hold both the formula,
* and the result. If you want the cell replaced with
- * the result of the formula, use {@link #evaluateInCell(HSSFCell)}
+ * the result of the formula, use {@link #evaluateInCell(Cell)}
* @param cell The cell to evaluate
- * @return The type of the formula result (the cell's type remains as HSSFCell.CELL_TYPE_FORMULA however)
+ * @return The type of the formula result (the cell's type remains as Cell.CELL_TYPE_FORMULA however)
*/
public int evaluateFormulaCell(Cell cell) {
if (cell != null) {
}
return -1;
}
-
+
/**
* If cell contains formula, it evaluates the formula, and
* puts the formula result back into the cell, in place
* of the old formula.
* Else if cell does not contain formula, this method leaves
- * the cell unchanged.
- * Note that the same instance of HSSFCell is returned to
+ * the cell unchanged.
+ * Note that the same instance of Cell is returned to
* allow chained calls like:
* <pre>
* int evaluatedCellType = evaluator.evaluateInCell(cell).getCellType();
* </pre>
* Be aware that your cell value will be changed to hold the
* result of the formula. If you simply want the formula
- * value computed for you, use {@link #evaluateFormulaCell(HSSFCell)}
+ * value computed for you, use {@link #evaluateFormulaCell(Cell)}
* @param cell
*/
public Cell evaluateInCell(Cell cell) {
}
return cell;
}
-
+
/**
* Loops over all cells in all sheets of the supplied
* workbook.
* remain as formula cells.
* For cells that do not contain formulas, no changes
* are made.
- * This is a helpful wrapper around looping over all
+ * This is a helpful wrapper around looping over all
* cells, and calling evaluateFormulaCell on each one.
*/
- public static void evaluateAllFormulaCells(Workbook wb) {
- for(int i=0; i<wb.getNumberOfSheets(); i++) {
- Sheet sheet = wb.getSheetAt(i);
- FormulaEvaluator evaluator = new FormulaEvaluator(sheet, wb);
-
- for (Iterator rit = sheet.rowIterator(); rit.hasNext();) {
- Row r = (Row)rit.next();
-
- for (Iterator cit = r.cellIterator(); cit.hasNext();) {
- Cell c = (Cell)cit.next();
- if (c.getCellType() == Cell.CELL_TYPE_FORMULA)
- evaluator.evaluateFormulaCell(c);
- }
- }
- }
- }
-
-
+ public static void evaluateAllFormulaCells(Workbook wb) {
+ for(int i=0; i<wb.getNumberOfSheets(); i++) {
+ Sheet sheet = wb.getSheetAt(i);
+ FormulaEvaluator evaluator = new FormulaEvaluator(sheet, wb);
+
+ for (Iterator rit = sheet.rowIterator(); rit.hasNext();) {
+ Row r = (Row)rit.next();
+
+ for (Iterator cit = r.cellIterator(); cit.hasNext();) {
+ Cell c = (Cell)cit.next();
+ if (c.getCellType() == Cell.CELL_TYPE_FORMULA)
+ evaluator.evaluateFormulaCell(c);
+ }
+ }
+ }
+ }
+
+
/**
* Returns a CellValue wrapper around the supplied ValueEval instance.
* @param eval
*/
- protected static CellValue getCellValueForEval(ValueEval eval, CreationHelper cHelper) {
+ private static CellValue getCellValueForEval(ValueEval eval, CreationHelper cHelper) {
CellValue retval = null;
if (eval != null) {
if (eval instanceof NumberEval) {
else if (eval instanceof ErrorEval) {
retval = new CellValue(Cell.CELL_TYPE_ERROR, cHelper);
retval.setErrorValue((byte)((ErrorEval)eval).getErrorCode());
-// retval.setRichTextStringValue(new HSSFRichTextString("#An error occurred. check cell.getErrorCode()"));
+// retval.setRichTextStringValue(new RichTextString("#An error occurred. check cell.getErrorCode()"));
}
else {
retval = new CellValue(Cell.CELL_TYPE_ERROR, cHelper);
}
return retval;
}
-
+
/**
- * Dev. Note: Internal evaluate must be passed only a formula cell
+ * Dev. Note: Internal evaluate must be passed only a formula cell
* else a runtime exception will be thrown somewhere inside the method.
* (Hence this is a private method.)
*/
private static ValueEval internalEvaluate(Cell srcCell, Sheet sheet, Workbook workbook) {
int srcRowNum = srcCell.getRowIndex();
short srcColNum = srcCell.getCellNum();
-
-
+
+
EvaluationCycleDetector tracker = EvaluationCycleDetectorManager.getTracker();
-
+
if(!tracker.startEvaluate(workbook, sheet, srcRowNum, srcColNum)) {
return ErrorEval.CIRCULAR_REF_ERROR;
}
tracker.endEvaluate(workbook, sheet, srcRowNum, srcColNum);
}
}
- private static ValueEval evaluateCell(Workbook workbook, Sheet sheet,
+ private static ValueEval evaluateCell(Workbook workbook, Sheet sheet,
int srcRowNum, short srcColNum, String cellFormulaText) {
+
Ptg[] ptgs = FormulaParser.parse(cellFormulaText, workbook);
Stack stack = new Stack();
// since we don't know how to handle these yet :(
Ptg ptg = ptgs[i];
if (ptg instanceof ControlPtg) {
- // skip Parentheses, Attr, etc
- continue;
- }
+ // skip Parentheses, Attr, etc
+ continue;
+ }
if (ptg instanceof MemErrPtg) { continue; }
if (ptg instanceof MissingArgPtg) { continue; }
- if (ptg instanceof NamePtg) {
+ if (ptg instanceof NamePtg) {
// named ranges, macro functions
NamePtg namePtg = (NamePtg) ptg;
stack.push(new NameEval(namePtg.getIndex()));
- continue;
+ continue;
}
if (ptg instanceof NameXPtg) {
NameXPtg nameXPtg = (NameXPtg) ptg;
continue;
}
if (ptg instanceof UnknownPtg) { continue; }
-
+ Eval opResult;
if (ptg instanceof OperationPtg) {
OperationPtg optg = (OperationPtg) ptg;
Eval p = (Eval) stack.pop();
ops[j] = p;
}
- Eval opresult = invokeOperation(operation, ops, srcRowNum, srcColNum, workbook, sheet);
- stack.push(opresult);
- }
- else if (ptg instanceof RefPtg) {
- RefPtg refPtg = (RefPtg) ptg;
- int colIx = refPtg.getColumn();
- int rowIx = refPtg.getRow();
- Row row = sheet.getRow(rowIx);
- Cell cell = (row != null) ? row.getCell(colIx) : null;
- stack.push(createRef2DEval(refPtg, cell, sheet, workbook));
- }
- else if (ptg instanceof Ref3DPtg) {
- Ref3DPtg refPtg = (Ref3DPtg) ptg;
- int colIx = refPtg.getColumn();
- int rowIx = refPtg.getRow();
- Sheet xsheet = workbook.getSheetAt(
- workbook.getSheetIndexFromExternSheetIndex(refPtg.getExternSheetIndex())
- );
- Row row = xsheet.getRow(rowIx);
- Cell cell = (row != null) ? row.getCell(colIx) : null;
- stack.push(createRef3DEval(refPtg, cell, xsheet, workbook));
- }
- else if (ptg instanceof AreaPtg) {
- AreaPtg ap = (AreaPtg) ptg;
- AreaEval ae = evaluateAreaPtg(sheet, workbook, ap);
- stack.push(ae);
- }
- else if (ptg instanceof Area3DPtg) {
- Area3DPtg a3dp = (Area3DPtg) ptg;
- AreaEval ae = evaluateArea3dPtg(workbook, a3dp);
- stack.push(ae);
- }
- else {
- Eval ptgEval = getEvalForPtg(ptg);
- stack.push(ptgEval);
+ opResult = invokeOperation(operation, ops, srcRowNum, srcColNum, workbook, sheet);
+ } else {
+ opResult = getEvalForPtg(ptg, sheet, workbook);
}
+ stack.push(opResult);
}
ValueEval value = ((ValueEval) stack.pop());
}
value = dereferenceValue(value, srcRowNum, srcColNum);
if (value instanceof BlankEval) {
- // Note Excel behaviour here. A blank final final value is converted to zero.
+ // Note Excel behaviour here. A blank final final value is converted to zero.
return NumberEval.ZERO;
- // Formulas _never_ evaluate to blank. If a formula appears to have evaluated to
+ // Formulas _never_ evaluate to blank. If a formula appears to have evaluated to
// blank, the actual value is empty string. This can be verified with ISBLANK().
}
return value;
/**
* Dereferences a single value from any AreaEval or RefEval evaluation result.
* If the supplied evaluationResult is just a plain value, it is returned as-is.
- * @return a <tt>NumberEval</tt>, <tt>StringEval</tt>, <tt>BoolEval</tt>,
- * <tt>BlankEval</tt> or <tt>ErrorEval</tt>. Never <code>null</code>.
+ * @return a <tt>NumberEval</tt>, <tt>StringEval</tt>, <tt>BoolEval</tt>,
+ * <tt>BlankEval</tt> or <tt>ErrorEval</tt>. Never <code>null</code>.
*/
private static ValueEval dereferenceValue(ValueEval evaluationResult, int srcRowNum, short srcColNum) {
if (evaluationResult instanceof RefEval) {
}
return operation.evaluate(ops, srcRowNum, srcColNum);
}
-
- public static AreaEval evaluateAreaPtg(Sheet sheet, Workbook workbook, AreaPtg ap) {
- int row0 = ap.getFirstRow();
- int col0 = ap.getFirstColumn();
- int row1 = ap.getLastRow();
- int col1 = ap.getLastColumn();
-
- // If the last row is -1, then the
- // reference is for the rest of the column
- // (eg C:C)
- // TODO: Handle whole column ranges properly
- if(row1 == -1 && row0 >= 0) {
- row1 = (short)sheet.getLastRowNum();
- }
- ValueEval[] values = evalArea(workbook, sheet, row0, col0, row1, col1);
- return new Area2DEval(ap, values);
- }
-
- public static AreaEval evaluateArea3dPtg(Workbook workbook, Area3DPtg a3dp) {
- int row0 = a3dp.getFirstRow();
- int col0 = a3dp.getFirstColumn();
- int row1 = a3dp.getLastRow();
- int col1 = a3dp.getLastColumn();
- Sheet xsheet = workbook.getSheetAt(
- workbook.getSheetIndexFromExternSheetIndex(a3dp.getExternSheetIndex())
- );
-
- // If the last row is -1, then the
- // reference is for the rest of the column
- // (eg C:C)
- // TODO: Handle whole column ranges properly
- if(row1 == -1 && row0 >= 0) {
- row1 = (short)xsheet.getLastRowNum();
- }
-
- ValueEval[] values = evalArea(workbook, xsheet, row0, col0, row1, col1);
- return new Area3DEval(a3dp, values);
- }
-
- private static ValueEval[] evalArea(Workbook workbook, Sheet sheet,
- int row0, int col0, int row1, int col1) {
- ValueEval[] values = new ValueEval[(row1 - row0 + 1) * (col1 - col0 + 1)];
- for (int x = row0; sheet != null && x < row1 + 1; x++) {
- Row row = sheet.getRow(x);
- for (int y = col0; y < col1 + 1; y++) {
- ValueEval cellEval;
- if(row == null) {
- cellEval = BlankEval.INSTANCE;
- } else {
- cellEval = getEvalForCell(row.getCell(y), row, sheet, workbook);
- }
- values[(x - row0) * (col1 - col0 + 1) + (y - col0)] = cellEval;
- }
- }
- return values;
- }
/**
* returns an appropriate Eval impl instance for the Ptg. The Ptg must be
- * one of: Area3DPtg, AreaPtg, RefPtg, Ref3DPtg, IntPtg, NumberPtg,
+ * one of: Area3DPtg, AreaPtg, ReferencePtg, Ref3DPtg, IntPtg, NumberPtg,
* StringPtg, BoolPtg <br/>special Note: OperationPtg subtypes cannot be
* passed here!
- *
- * @param ptg
*/
- protected static Eval getEvalForPtg(Ptg ptg) {
- Eval retval = null;
-
- Class clazz = (Class) VALUE_EVALS_MAP.get(ptg.getClass());
- try {
- if (ptg instanceof Area3DPtg) {
- Constructor constructor = clazz.getConstructor(AREA3D_CONSTRUCTOR_CLASS_ARRAY);
- retval = (OperationEval) constructor.newInstance(new Ptg[] { ptg });
- }
- else if (ptg instanceof AreaPtg) {
- Constructor constructor = clazz.getConstructor(AREA3D_CONSTRUCTOR_CLASS_ARRAY);
- retval = (OperationEval) constructor.newInstance(new Ptg[] { ptg });
- }
- else if (ptg instanceof RefPtg) {
- Constructor constructor = clazz.getConstructor(REFERENCE_CONSTRUCTOR_CLASS_ARRAY);
- retval = (OperationEval) constructor.newInstance(new Ptg[] { ptg });
- }
- else if (ptg instanceof Ref3DPtg) {
- Constructor constructor = clazz.getConstructor(REF3D_CONSTRUCTOR_CLASS_ARRAY);
- retval = (OperationEval) constructor.newInstance(new Ptg[] { ptg });
- }
- else {
- if (ptg instanceof IntPtg || ptg instanceof NumberPtg || ptg instanceof StringPtg
- || ptg instanceof BoolPtg) {
- Constructor constructor = clazz.getConstructor(VALUE_CONTRUCTOR_CLASS_ARRAY);
- retval = (ValueEval) constructor.newInstance(new Ptg[] { ptg });
- }
- }
+ private static Eval getEvalForPtg(Ptg ptg, Sheet sheet, Workbook workbook) {
+ if (ptg instanceof RefPtg) {
+ return new LazyRefEval(((RefPtg) ptg), sheet, workbook);
}
- catch (Exception e) {
- throw new RuntimeException("Fatal Error: ", e);
+ if (ptg instanceof Ref3DPtg) {
+ Ref3DPtg refPtg = (Ref3DPtg) ptg;
+ Sheet xsheet = workbook.getSheetAt(workbook.getSheetIndexFromExternSheetIndex(refPtg.getExternSheetIndex()));
+ return new LazyRefEval(refPtg, xsheet, workbook);
+ }
+ if (ptg instanceof AreaPtg) {
+ return new LazyAreaEval(((AreaPtg) ptg), sheet, workbook);
+ }
+ if (ptg instanceof Area3DPtg) {
+ Area3DPtg a3dp = (Area3DPtg) ptg;
+ Sheet xsheet = workbook.getSheetAt(workbook.getSheetIndexFromExternSheetIndex(a3dp.getExternSheetIndex()));
+ return new LazyAreaEval(a3dp, xsheet, workbook);
}
- return retval;
+ if (ptg instanceof IntPtg) {
+ return new NumberEval(((IntPtg)ptg).getValue());
+ }
+ if (ptg instanceof NumberPtg) {
+ return new NumberEval(((NumberPtg)ptg).getValue());
+ }
+ if (ptg instanceof StringPtg) {
+ return new StringEval(((StringPtg) ptg).getValue());
+ }
+ if (ptg instanceof BoolPtg) {
+ return BoolEval.valueOf(((BoolPtg) ptg).getValue());
+ }
+ if (ptg instanceof ErrPtg) {
+ return ErrorEval.valueOf(((ErrPtg) ptg).getErrorCode());
+ }
+ throw new RuntimeException("Unexpected ptg class (" + ptg.getClass().getName() + ")");
}
-
/**
* Given a cell, find its type and from that create an appropriate ValueEval
* impl instance and return that. Since the cell could be an external
* @param sheet
* @param workbook
*/
- protected static ValueEval getEvalForCell(Cell cell, Row row, Sheet sheet, Workbook workbook) {
+ public static ValueEval getEvalForCell(Cell cell, Sheet sheet, Workbook workbook) {
if (cell == null) {
return BlankEval.INSTANCE;
}
/**
- * Creates a Ref2DEval for RefPtg.
- * Non existent cells are treated as RefEvals containing BlankEval.
- */
- private static Ref2DEval createRef2DEval(RefPtg ptg, Cell cell,
- Sheet sheet, Workbook workbook) {
- if (cell == null) {
- return new Ref2DEval(ptg, BlankEval.INSTANCE);
- }
-
- switch (cell.getCellType()) {
- case Cell.CELL_TYPE_NUMERIC:
- return new Ref2DEval(ptg, new NumberEval(cell.getNumericCellValue()));
- case Cell.CELL_TYPE_STRING:
- return new Ref2DEval(ptg, new StringEval(cell.getRichStringCellValue().getString()));
- case Cell.CELL_TYPE_FORMULA:
- return new Ref2DEval(ptg, internalEvaluate(cell, sheet, workbook));
- case Cell.CELL_TYPE_BOOLEAN:
- return new Ref2DEval(ptg, BoolEval.valueOf(cell.getBooleanCellValue()));
- case Cell.CELL_TYPE_BLANK:
- return new Ref2DEval(ptg, BlankEval.INSTANCE);
- case Cell.CELL_TYPE_ERROR:
- return new Ref2DEval(ptg, ErrorEval.valueOf(cell.getErrorCellValue()));
- }
- throw new RuntimeException("Unexpected cell type (" + cell.getCellType() + ")");
- }
-
- /**
- * create a Ref3DEval for Ref3DPtg.
- */
- private static Ref3DEval createRef3DEval(Ref3DPtg ptg, Cell cell,
- Sheet sheet, Workbook workbook) {
- if (cell == null) {
- return new Ref3DEval(ptg, BlankEval.INSTANCE);
- }
- switch (cell.getCellType()) {
- case Cell.CELL_TYPE_NUMERIC:
- return new Ref3DEval(ptg, new NumberEval(cell.getNumericCellValue()));
- case Cell.CELL_TYPE_STRING:
- return new Ref3DEval(ptg, new StringEval(cell.getRichStringCellValue().getString()));
- case Cell.CELL_TYPE_FORMULA:
- return new Ref3DEval(ptg, internalEvaluate(cell, sheet, workbook));
- case Cell.CELL_TYPE_BOOLEAN:
- return new Ref3DEval(ptg, BoolEval.valueOf(cell.getBooleanCellValue()));
- case Cell.CELL_TYPE_BLANK:
- return new Ref3DEval(ptg, BlankEval.INSTANCE);
- case Cell.CELL_TYPE_ERROR:
- return new Ref3DEval(ptg, ErrorEval.valueOf(cell.getErrorCellValue()));
- }
- throw new RuntimeException("Unexpected cell type (" + cell.getCellType() + ")");
- }
-
- /**
- * Mimics the 'data view' of a cell. This allows formula evaluator
+ * Mimics the 'data view' of a cell. This allows formula evaluator
* to return a CellValue instead of precasting the value to String
* or Number or boolean type.
* @author Amol S. Deshmukh < amolweb at ya hoo dot com >
*/
public static class CellValue {
- private CreationHelper creationHelper;
+ private CreationHelper creationHelper;
private int cellType;
private RichTextString richTextStringValue;
private double numberValue;
private boolean booleanValue;
private byte errorValue;
-
+
/**
- * CellType should be one of the types defined in HSSFCell
+ * CellType should be one of the types defined in Cell
* @param cellType
*/
public CellValue(int cellType, CreationHelper creationHelper) {
* @deprecated
*/
public void setStringValue(String stringValue) {
- this.richTextStringValue =
- creationHelper.createRichTextString(stringValue);
+ this.richTextStringValue =
+ creationHelper.createRichTextString(stringValue);
}
/**
* @return Returns the cellType.
--- /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.ss.util;
+
+import java.util.ArrayList;
+import java.util.StringTokenizer;
+
+public class AreaReference {
+
+ /** The character (!) that separates sheet names from cell references */
+ private static final char SHEET_NAME_DELIMITER = '!';
+ /** The character (:) that separates the two cell references in a multi-cell area reference */
+ private static final char CELL_DELIMITER = ':';
+ /** The character (') used to quote sheet names when they contain special characters */
+ private static final char SPECIAL_NAME_DELIMITER = '\'';
+
+ private final CellReference _firstCell;
+ private final CellReference _lastCell;
+ private final boolean _isSingleCell;
+
+ /**
+ * Create an area ref from a string representation. Sheet names containing special characters should be
+ * delimited and escaped as per normal syntax rules for formulas.<br/>
+ * The area reference must be contiguous (i.e. represent a single rectangle, not a union of rectangles)
+ */
+ public AreaReference(String reference) {
+ if(! isContiguous(reference)) {
+ throw new IllegalArgumentException(
+ "References passed to the AreaReference must be contiguous, " +
+ "use generateContiguous(ref) if you have non-contiguous references");
+ }
+
+ String[] parts = separateAreaRefs(reference);
+
+ // Special handling for whole-column references
+ if(parts.length == 2 && parts[0].length() == 1 &&
+ parts[1].length() == 1 &&
+ parts[0].charAt(0) >= 'A' && parts[0].charAt(0) <= 'Z' &&
+ parts[1].charAt(0) >= 'A' && parts[1].charAt(0) <= 'Z') {
+ // Represented internally as x$1 to x$65536
+ // which is the maximum range of rows
+ parts[0] = parts[0] + "$1";
+ parts[1] = parts[1] + "$65536";
+ }
+
+ _firstCell = new CellReference(parts[0]);
+
+ if(parts.length == 2) {
+ _lastCell = new CellReference(parts[1]);
+ _isSingleCell = false;
+ } else {
+ _lastCell = _firstCell;
+ _isSingleCell = true;
+ }
+ }
+
+ /**
+ * Creates an area ref from a pair of Cell References.
+ */
+ public AreaReference(CellReference topLeft, CellReference botRight) {
+ _firstCell = topLeft;
+ _lastCell = botRight;
+ _isSingleCell = false;
+ }
+
+ /**
+ * Is the reference for a contiguous (i.e.
+ * unbroken) area, or is it made up of
+ * several different parts?
+ * (If it is, you will need to call
+ * ....
+ */
+ public static boolean isContiguous(String reference) {
+ if(reference.indexOf(',') == -1) {
+ return true;
+ }
+ return false;
+ }
+
+ /**
+ * Is the reference for a whole-column reference,
+ * such as C:C or D:G ?
+ */
+ public static boolean isWholeColumnReference(CellReference topLeft, CellReference botRight) {
+ // These are represented as something like
+ // C$1:C$65535 or D$1:F$0
+ // i.e. absolute from 1st row to 0th one
+ if(topLeft.getRow() == 0 && topLeft.isRowAbsolute() &&
+ botRight.getRow() == 65535 && botRight.isRowAbsolute()) {
+ return true;
+ }
+ return false;
+ }
+ public boolean isWholeColumnReference() {
+ return isWholeColumnReference(_firstCell, _lastCell);
+ }
+
+ /**
+ * Takes a non-contiguous area reference, and
+ * returns an array of contiguous area references.
+ */
+ public static AreaReference[] generateContiguous(String reference) {
+ ArrayList refs = new ArrayList();
+ StringTokenizer st = new StringTokenizer(reference, ",");
+ while(st.hasMoreTokens()) {
+ refs.add(
+ new AreaReference(st.nextToken())
+ );
+ }
+ return (AreaReference[])refs.toArray(new AreaReference[refs.size()]);
+ }
+
+ /**
+ * @return <code>false</code> if this area reference involves more than one cell
+ */
+ public boolean isSingleCell() {
+ return _isSingleCell;
+ }
+
+ /**
+ * @return the first cell reference which defines this area. Usually this cell is in the upper
+ * left corner of the area (but this is not a requirement).
+ */
+ public CellReference getFirstCell() {
+ return _firstCell;
+ }
+
+ /**
+ * Note - if this area reference refers to a single cell, the return value of this method will
+ * be identical to that of <tt>getFirstCell()</tt>
+ * @return the second cell reference which defines this area. For multi-cell areas, this is
+ * cell diagonally opposite the 'first cell'. Usually this cell is in the lower right corner
+ * of the area (but this is not a requirement).
+ */
+ public CellReference getLastCell() {
+ return _lastCell;
+ }
+ /**
+ * Returns a reference to every cell covered by this area
+ */
+ public CellReference[] getAllReferencedCells() {
+ // Special case for single cell reference
+ if(_isSingleCell) {
+ return new CellReference[] { _firstCell, };
+ }
+
+ // Interpolate between the two
+ int minRow = Math.min(_firstCell.getRow(), _lastCell.getRow());
+ int maxRow = Math.max(_firstCell.getRow(), _lastCell.getRow());
+ int minCol = Math.min(_firstCell.getCol(), _lastCell.getCol());
+ int maxCol = Math.max(_firstCell.getCol(), _lastCell.getCol());
+ String sheetName = _firstCell.getSheetName();
+
+ ArrayList refs = new ArrayList();
+ for(int row=minRow; row<=maxRow; row++) {
+ for(int col=minCol; col<=maxCol; col++) {
+ CellReference ref = new CellReference(sheetName, row, col, _firstCell.isRowAbsolute(), _firstCell.isColAbsolute());
+ refs.add(ref);
+ }
+ }
+ return (CellReference[])refs.toArray(new CellReference[refs.size()]);
+ }
+
+ /**
+ * Example return values:
+ * <table border="0" cellpadding="1" cellspacing="0" summary="Example return values">
+ * <tr><th align='left'>Result</th><th align='left'>Comment</th></tr>
+ * <tr><td>A1:A1</td><td>Single cell area reference without sheet</td></tr>
+ * <tr><td>A1:$C$1</td><td>Multi-cell area reference without sheet</td></tr>
+ * <tr><td>Sheet1!A$1:B4</td><td>Standard sheet name</td></tr>
+ * <tr><td>'O''Brien''s Sales'!B5:C6' </td><td>Sheet name with special characters</td></tr>
+ * </table>
+ * @return the text representation of this area reference as it would appear in a formula.
+ */
+ public String formatAsString() {
+ // Special handling for whole-column references
+ if(isWholeColumnReference()) {
+ return
+ CellReference.convertNumToColString(_firstCell.getCol())
+ + ":" +
+ CellReference.convertNumToColString(_lastCell.getCol());
+ }
+
+ StringBuffer sb = new StringBuffer(32);
+ sb.append(_firstCell.formatAsString());
+ if(!_isSingleCell) {
+ sb.append(CELL_DELIMITER);
+ if(_lastCell.getSheetName() == null) {
+ sb.append(_lastCell.formatAsString());
+ } else {
+ // don't want to include the sheet name twice
+ _lastCell.appendCellReference(sb);
+ }
+ }
+ return sb.toString();
+ }
+
+ public String toString() {
+ StringBuffer sb = new StringBuffer(64);
+ sb.append(getClass().getName()).append(" [");
+ sb.append(formatAsString());
+ sb.append("]");
+ return sb.toString();
+ }
+
+ /**
+ * Separates Area refs in two parts and returns them as separate elements in a String array,
+ * each qualified with the sheet name (if present)
+ *
+ * @return array with one or two elements. never <code>null</code>
+ */
+ private static String[] separateAreaRefs(String reference) {
+ // TODO - refactor cell reference parsing logic to one place.
+ // Current known incarnations:
+ // FormulaParser.GetName()
+ // CellReference.separateRefParts()
+ // AreaReference.separateAreaRefs() (here)
+ // SheetNameFormatter.format() (inverse)
+
+
+ int len = reference.length();
+ int delimiterPos = -1;
+ boolean insideDelimitedName = false;
+ for(int i=0; i<len; i++) {
+ switch(reference.charAt(i)) {
+ case CELL_DELIMITER:
+ if(!insideDelimitedName) {
+ if(delimiterPos >=0) {
+ throw new IllegalArgumentException("More than one cell delimiter '"
+ + CELL_DELIMITER + "' appears in area reference '" + reference + "'");
+ }
+ delimiterPos = i;
+ }
+ default:
+ continue;
+ case SPECIAL_NAME_DELIMITER:
+ // fall through
+ }
+ if(!insideDelimitedName) {
+ insideDelimitedName = true;
+ continue;
+ }
+
+ if(i >= len-1) {
+ // reference ends with the delimited name.
+ // Assume names like: "Sheet1!'A1'" are never legal.
+ throw new IllegalArgumentException("Area reference '" + reference
+ + "' ends with special name delimiter '" + SPECIAL_NAME_DELIMITER + "'");
+ }
+ if(reference.charAt(i+1) == SPECIAL_NAME_DELIMITER) {
+ // two consecutive quotes is the escape sequence for a single one
+ i++; // skip this and keep parsing the special name
+ } else {
+ // this is the end of the delimited name
+ insideDelimitedName = false;
+ }
+ }
+ if(delimiterPos < 0) {
+ return new String[] { reference, };
+ }
+
+ String partA = reference.substring(0, delimiterPos);
+ String partB = reference.substring(delimiterPos+1);
+ if(partB.indexOf(SHEET_NAME_DELIMITER) >=0) {
+ // TODO - are references like "Sheet1!A1:Sheet1:B2" ever valid?
+ // FormulaParser has code to handle that.
+
+ throw new RuntimeException("Unexpected " + SHEET_NAME_DELIMITER
+ + " in second cell reference of '" + reference + "'");
+ }
+
+ int plingPos = partA.lastIndexOf(SHEET_NAME_DELIMITER);
+ if(plingPos < 0) {
+ return new String [] { partA, partB, };
+ }
+
+ String sheetName = partA.substring(0, plingPos + 1); // +1 to include delimiter
+
+ return new String [] { partA, sheetName + partB, };
+ }
+}
dump(data, pos, size, padding);
} else {
//dump first 100 bytes of the atom data
- dump(out, data, pos, size, padding, true);
+ dump(out, data, pos, Math.min(size, data.length-pos), padding, true);
}
padding--;
write(out, "</"+recname + ">" + CR, padding);
* @author Yegor Kozlov\r
*/\r
public class Hyperlink {\r
-\r
+ public static final byte LINK_NEXTSLIDE = InteractiveInfoAtom.LINK_NextSlide;\r
+ public static final byte LINK_PREVIOUSSLIDE = InteractiveInfoAtom.LINK_PreviousSlide;\r
+ public static final byte LINK_FIRSTSLIDE = InteractiveInfoAtom.LINK_FirstSlide;\r
+ public static final byte LINK_LASTSLIDE = InteractiveInfoAtom.LINK_LastSlide;\r
+ public static final byte LINK_URL = InteractiveInfoAtom.LINK_Url;\r
+ public static final byte LINK_NULL = InteractiveInfoAtom.LINK_NULL;\r
+\r
+ private int id=-1;\r
private int type;\r
private String address;\r
private String title;\r
\r
/**\r
* Gets the type of the hyperlink action.\r
- * Must be a <code>ACTION_*</code> constant defined in <code>InteractiveInfoAtom</code>\r
+ * Must be a <code>LINK_*</code> constant</code>\r
*\r
* @return the hyperlink URL\r
* @see InteractiveInfoAtom\r
return type;\r
}\r
\r
+ public void setType(int val) {\r
+ type = val;\r
+ switch(type){\r
+ case LINK_NEXTSLIDE:\r
+ title = "NEXT";\r
+ address = "1,-1,NEXT";\r
+ break;\r
+ case LINK_PREVIOUSSLIDE:\r
+ title = "PREV";\r
+ address = "1,-1,PREV";\r
+ break;\r
+ case LINK_FIRSTSLIDE:\r
+ title = "FIRST";\r
+ address = "1,-1,FIRST";\r
+ break;\r
+ case LINK_LASTSLIDE:\r
+ title = "LAST";\r
+ address = "1,-1,LAST";\r
+ break;\r
+ default:\r
+ title = "";\r
+ address = "";\r
+ break;\r
+ }\r
+ }\r
+\r
/**\r
* Gets the hyperlink URL\r
*\r
return address;\r
}\r
\r
+ public void setAddress(String str) {\r
+ address = str;\r
+ }\r
+\r
+ public int getId() {\r
+ return id;\r
+ }\r
+\r
+ public void setId(int id) {\r
+ this.id = id;\r
+ }\r
+\r
/**\r
* Gets the hyperlink user-friendly title (if different from URL)\r
*\r
return title;\r
}\r
\r
+ public void setTitle(String str) {\r
+ title = str;\r
+ }\r
+\r
/**\r
* Gets the beginning character position\r
*\r
import org.apache.poi.util.LittleEndian;
import org.apache.poi.hslf.record.ColorSchemeAtom;
import org.apache.poi.hslf.record.Record;
+import org.apache.poi.hslf.record.InteractiveInfo;
+import org.apache.poi.hslf.record.InteractiveInfoAtom;
import org.apache.poi.hslf.exceptions.HSLFException;
import java.awt.*;
_clientData.setRemainingData(out.toByteArray());
}
}
+
+ public void setHyperlink(Hyperlink link){
+ if(link.getId() == -1){
+ throw new HSLFException("You must call SlideShow.addHyperlink(Hyperlink link) first");
+ }
+
+ EscherClientDataRecord cldata = new EscherClientDataRecord();
+ cldata.setOptions((short)0xF);
+ getSpContainer().getChildRecords().add(cldata);
+
+ InteractiveInfo info = new InteractiveInfo();
+ InteractiveInfoAtom infoAtom = info.getInteractiveInfoAtom();
+
+ switch(link.getType()){
+ case Hyperlink.LINK_FIRSTSLIDE:
+ infoAtom.setAction(InteractiveInfoAtom.ACTION_JUMP);
+ infoAtom.setJump(InteractiveInfoAtom.JUMP_FIRSTSLIDE);
+ infoAtom.setHyperlinkType(InteractiveInfoAtom.LINK_FirstSlide);
+ break;
+ case Hyperlink.LINK_LASTSLIDE:
+ infoAtom.setAction(InteractiveInfoAtom.ACTION_JUMP);
+ infoAtom.setJump(InteractiveInfoAtom.JUMP_LASTSLIDE);
+ infoAtom.setHyperlinkType(InteractiveInfoAtom.LINK_LastSlide);
+ break;
+ case Hyperlink.LINK_NEXTSLIDE:
+ infoAtom.setAction(InteractiveInfoAtom.ACTION_JUMP);
+ infoAtom.setJump(InteractiveInfoAtom.JUMP_NEXTSLIDE);
+ infoAtom.setHyperlinkType(InteractiveInfoAtom.LINK_NextSlide);
+ break;
+ case Hyperlink.LINK_PREVIOUSSLIDE:
+ infoAtom.setAction(InteractiveInfoAtom.ACTION_JUMP);
+ infoAtom.setJump(InteractiveInfoAtom.JUMP_PREVIOUSSLIDE);
+ infoAtom.setHyperlinkType(InteractiveInfoAtom.LINK_PreviousSlide);
+ break;
+ case Hyperlink.LINK_URL:
+ infoAtom.setAction(InteractiveInfoAtom.ACTION_HYPERLINK);
+ infoAtom.setJump(InteractiveInfoAtom.JUMP_NONE);
+ infoAtom.setHyperlinkType(InteractiveInfoAtom.LINK_Url);
+ break;
+ }
+
+ infoAtom.setHyperlinkID(link.getId());
+
+ ByteArrayOutputStream out = new ByteArrayOutputStream();
+ try {
+ info.writeOut(out);
+ } catch(Exception e){
+ throw new HSLFException(e);
+ }
+ cldata.setRemainingData(out.toByteArray());
+
+ }
+
}
public static String NAME = "char_flags";
public CharFlagsTextProp() {
super(2,0xffff, NAME, new String[] {
- "bold", // 0x0001
- "italic", // 0x0002
- "underline", // 0x0004
- "char_unknown_1",// 0x0008
- "shadow", // 0x0010
- "char_unknown_2",// 0x0020
- "char_unknown_3",// 0x0040
- "char_unknown_4",// 0x0080
- "strikethrough", // 0x0100
- "relief", // 0x0200
- "reset_numbering", // 0x0400
- "enable_numbering_1", // 0x0800
- "enable_numbering_2", // 0x1000
+ "bold", // 0x0001 A bit that specifies whether the characters are bold.
+ "italic", // 0x0002 A bit that specifies whether the characters are italicized.
+ "underline", // 0x0004 A bit that specifies whether the characters are underlined.
+ "char_unknown_1", // 0x0008 Undefined and MUST be ignored.
+ "shadow", // 0x0010 A bit that specifies whether the characters have a shadow effect.
+ "fehint", // 0x0020 A bit that specifies whether characters originated from double-byte input.
+ "char_unknown_2", // 0x0040 Undefined and MUST be ignored.
+ "kumi", // 0x0080 A bit that specifies whether Kumimoji are used for vertical text.
+ "strikethrough", // 0x0100 Undefined and MUST be ignored.
+ "emboss", // 0x0200 A bit that specifies whether the characters are embossed.
+ "char_unknown_3", // 0x0400 Undefined and MUST be ignored.
+ "char_unknown_4", // 0x0800 Undefined and MUST be ignored.
+ "char_unknown_5", // 0x1000 Undefined and MUST be ignored.
}
);
}
private int charactersCovered;
private short reservedField;
private LinkedList textPropList;
+ private int maskSpecial = 0;
/** Fetch the number of characters this styling applies to */
public int getCharactersCovered() { return charactersCovered; }
// If we do, decode that, save it, and shuffle on
for(int i=0; i<potentialProperties.length; i++) {
// Check there's still data left to read
- if(dataOffset+bytesPassed >= data.length) {
- // Out of data, can't be any more properties to go
- return bytesPassed;
- }
-
+
// Check if this property is found in the mask
if((containsField & potentialProperties[i].getMask()) != 0) {
+ if(dataOffset+bytesPassed >= data.length) {
+ // Out of data, can't be any more properties to go
+ // remember the mask and return
+ maskSpecial |= potentialProperties[i].getMask();
+ return bytesPassed;
+ }
+
// Bingo, data contains this property
TextProp prop = (TextProp)potentialProperties[i].clone();
int val = 0;
if(prop.getSize() == 2) {
val = LittleEndian.getShort(data,dataOffset+bytesPassed);
- } else {
+ } else if(prop.getSize() == 4){
val = LittleEndian.getInt(data,dataOffset+bytesPassed);
- }
+ } else if (prop.getSize() == 0){
+ //remember "special" bits.
+ maskSpecial |= potentialProperties[i].getMask();
+ continue;
+ }
prop.setValue(val);
bytesPassed += prop.getSize();
textPropList.add(prop);
}
// Then the mask field
- int mask = 0;
+ int mask = maskSpecial;
for(int i=0; i<textPropList.size(); i++) {
TextProp textProp = (TextProp)textPropList.get(i);
//sometimes header indicates that the bitmask is present but its value is 0
- if (textProp instanceof BitMaskTextProp)
- mask |= (textProp.getWriteMask() == 0 ? 1 : textProp.getWriteMask());
- else
+
+ if (textProp instanceof BitMaskTextProp) {
+ if(mask == 0) mask |= textProp.getWriteMask();
+ }
+ else {
mask |= textProp.getWriteMask();
- }
+ }
+ }
StyleTextPropAtom.writeLittleEndian(mask,o);
// Then the contents of all the properties
int val = textProp.getValue();
if(textProp.getSize() == 2) {
StyleTextPropAtom.writeLittleEndian((short)val,o);
- } else {
+ } else if(textProp.getSize() == 4){
StyleTextPropAtom.writeLittleEndian(val,o);
}
}
* TODO: Figure out if we should always set both
*/
public void setLinkURL(String url) {
- linkDetailsA.setText(url);
-
- // linkDetailsB isn't present in all PPT versions
if(linkDetailsB != null) {
linkDetailsB.setText(url);
}
}
-
+ public void setLinkTitle(String title) {
+ if(linkDetailsA != null) {
+ linkDetailsA.setText(title);
+ }
+ }
+
/**
* Get the link details (field A)
*/
/** All the different kinds of paragraph properties we might handle */
public static TextProp[] paragraphTextPropTypes = new TextProp[] {
- new ParagraphFlagsTextProp(),
+ new TextProp(0, 0x1, "hasBullet"),
+ new TextProp(0, 0x2, "hasBulletFont"),
+ new TextProp(0, 0x4, "hasBulletColor"),
+ new TextProp(0, 0x8, "hasBulletSize"),
+ new ParagraphFlagsTextProp(),
new TextProp(2, 0x80, "bullet.char"),
new TextProp(2, 0x10, "bullet.font"),
new TextProp(2, 0x40, "bullet.size"),
new TextProp(4, 0x20, "bullet.color"),
new AlignmentTextProp(),
new TextProp(2, 0x100, "text.offset"),
- new TextProp(2, 0x200, "para_unknown_2"),
new TextProp(2, 0x400, "bullet.offset"),
- new TextProp(2, 0x1000, "linespacing"),
- new TextProp(2, 0x2000, "spacebefore"),
- new TextProp(2, 0x4000, "spaceafter"),
- new TextProp(2, 0x8000, "para_unknown_4"),
- new TextProp(2, 0x10000, "para_unknown_5"),
- new TextProp(2, 0xA0000, "para_unknown_6"),
- new TextProp(2, 0x200000, "para_unknown_7")
+ new TextProp(2, 0x1000, "linespacing"),
+ new TextProp(2, 0x2000, "spacebefore"),
+ new TextProp(2, 0x4000, "spaceafter"),
+ new TextProp(2, 0x8000, "defaultTabSize"),
+ new TextProp(2, 0x100000, "tabStops"),
+ new TextProp(2, 0x10000, "fontAlign"),
+ new TextProp(2, 0xA0000, "wrapFlags"),
+ new TextProp(2, 0x200000, "textDirection")
};
/** All the different kinds of character properties we might handle */
public static TextProp[] characterTextPropTypes = new TextProp[] {
- new CharFlagsTextProp(),
+ new TextProp(0, 0x1, "bold"),
+ new TextProp(0, 0x2, "italic"),
+ new TextProp(0, 0x4, "underline"),
+ new TextProp(0, 0x8, "unused1"),
+ new TextProp(0, 0x10, "shadow"),
+ new TextProp(0, 0x20, "fehint"),
+ new TextProp(0, 0x40, "unused2"),
+ new TextProp(0, 0x80, "kumi"),
+ new TextProp(0, 0x100, "unused3"),
+ new TextProp(0, 0x200, "emboss"),
+ new CharFlagsTextProp(),
new TextProp(2, 0x10000, "font.index"),
- new TextProp(2, 0x200000, "asian_or_complex"),
- new TextProp(2, 0x400000, "char_unknown_2"),
- new TextProp(2, 0x800000, "symbol"),
+ new TextProp(0, 0x100000, "pp10ext"),
+ new TextProp(2, 0x200000, "asian.font.index"),
+ new TextProp(2, 0x400000, "ansi.font.index"),
+ new TextProp(2, 0x800000, "symbol.font.index"),
new TextProp(2, 0x20000, "font.size"),
new TextProp(4, 0x40000, "font.color"),
- new TextProp(2, 0x80000, "superscript"),
- new TextProp(2, 0x100000, "char_unknown_1"),
- new TextProp(2, 0x1000000, "char_unknown_3"),
- new TextProp(2, 0x2000000, "char_unknown_4"),
- new TextProp(2, 0x4000000, "char_unknown_5"),
- new TextProp(2, 0x8000000, "char_unknown_6"),
- new TextProp(2, 0x10000000, "char_unknown_7"),
- new TextProp(2, 0x20000000, "char_unknown_8"),
- new TextProp(2, 0x40000000, "char_unknown_9"),
- new TextProp(2, 0x80000000, "char_unknown_10"),
- };
+ new TextProp(2, 0x80000, "superscript"),
+
+ };
/* *************** record code follows ********************** */
- /**
+ /**
* For the Text Style Properties (StyleTextProp) Atom
*/
public StyleTextPropAtom(byte[] source, int start, int len) {
}
- /**
+ /**
* A new set of text style properties for some text without any.
*/
public StyleTextPropAtom(int parentTextSize) {
paragraphStyles = new LinkedList();
charStyles = new LinkedList();
- TextPropCollection defaultParagraphTextProps =
+ TextPropCollection defaultParagraphTextProps =
new TextPropCollection(parentTextSize, (short)0);
paragraphStyles.add(defaultParagraphTextProps);
- TextPropCollection defaultCharacterTextProps =
+ TextPropCollection defaultCharacterTextProps =
new TextPropCollection(parentTextSize);
charStyles.add(defaultCharacterTextProps);
textHandled += textLen;
pos += 4;
- // Fetch the 2 byte value that is safe to ignore as 0
- short paraIgn = LittleEndian.getShort(rawContents,pos);
+ short indent = LittleEndian.getShort(rawContents,pos);
pos += 2;
// Grab the 4 byte value that tells us what properties follow
pos += 4;
// Now make sense of those properties
- TextPropCollection thisCollection = new TextPropCollection(textLen, paraIgn);
+ TextPropCollection thisCollection = new TextPropCollection(textLen, indent);
int plSize = thisCollection.buildTextPropList(
paraFlags, paragraphTextPropTypes, rawContents, pos);
pos += plSize;
* @return 0-based index of the control
*/
public int addControl(String name, String progId) {
- ExObjList lst = _documentRecord.getExObjList();
+ ExObjList lst = (ExObjList)_documentRecord.findFirstOfType(RecordTypes.ExObjList.typeID);
if (lst == null) {
lst = new ExObjList();
_documentRecord.addChildAfter(lst, _documentRecord.getDocumentAtom());
return objectId;
}
+
+ /**
+ * Add a hyperlink to this presentation
+ *
+ * @return 0-based index of the hyperlink
+ */
+ public int addHyperlink(Hyperlink link) {
+ ExObjList lst = (ExObjList)_documentRecord.findFirstOfType(RecordTypes.ExObjList.typeID);
+ if (lst == null) {
+ lst = new ExObjList();
+ _documentRecord.addChildAfter(lst, _documentRecord.getDocumentAtom());
+ }
+ ExObjListAtom objAtom = lst.getExObjListAtom();
+ //increment the object ID seed
+ int objectId = (int) objAtom.getObjectIDSeed() + 1;
+ objAtom.setObjectIDSeed(objectId);
+
+ ExHyperlink ctrl = new ExHyperlink();
+ ExHyperlinkAtom obj = ctrl.getExHyperlinkAtom();
+ obj.setNumber(objectId);
+ ctrl.setLinkURL(link.getAddress());
+ ctrl.setLinkTitle(link.getTitle());
+ lst.addChildAfter(ctrl, objAtom);
+ link.setId(objectId);
+
+ return objectId;
+ }
}
r.setIndexNumberFmtRecord( (short) 0 );
LinkedDataFormulaField formula = new LinkedDataFormulaField();
Stack tokens = new Stack();
- Area3DPtg p = new Area3DPtg();
- p.setExternSheetIndex( (short) 0 );
- p.setFirstColumn( (short) 1 );
- p.setLastColumn( (short) 1 );
- p.setFirstRow( (short) 0 );
- p.setLastRow( (short) 31 );
+ Area3DPtg p = new Area3DPtg(0, 31, 1, 1,
+ false, false, false, false, 0);
tokens.add( p );
formula.setFormulaTokens( tokens );
r.setFormulaOfLink( formula );
r.setIndexNumberFmtRecord( (short) 0 );
LinkedDataFormulaField formula = new LinkedDataFormulaField();
Stack tokens = new Stack();
- Area3DPtg p = new Area3DPtg();
- p.setExternSheetIndex( (short) 0 );
- p.setFirstColumn( (short) 0 );
- p.setLastColumn( (short) 0 );
- p.setFirstRow( (short) 0 );
- p.setLastRow( (short) 31 );
+ Area3DPtg p = new Area3DPtg(0, 31, 0, 0,
+ false, false, false, false, 0);
tokens.add( p );
formula.setFormulaTokens( tokens );
r.setFormulaOfLink( formula );
import junit.framework.TestCase;
import java.io.ByteArrayOutputStream;
import java.util.LinkedList;
+import java.util.Arrays;
/**
* Tests that StyleTextPropAtom works properly
* @author Nick Burch (nick at torchbox dot com)
*/
public class TestStyleTextPropAtom extends TestCase {
- /** From a real file: a paragraph with 4 different styles */
- private byte[] data_a = new byte[] {
- 0, 0, 0xA1-256, 0x0F, 0x2A, 0, 0, 0,
+ /** From a real file: a paragraph with 4 different styles */
+ private byte[] data_a = new byte[] {
+ 0, 0, 0xA1-256, 0x0F, 0x2A, 0, 0, 0,
0x36, 00, 00, 00, // paragraph is 54 long
00, 00, // (paragraph reserved field)
00, 00, 00, 00, // it doesn't have any styles
0x10, 00, 00, 00, // third char run is 16 long
00, 00, 0x04, 00, // font.color only
0xFF-256, 0x33, 00, 0xFE-256 // red
- };
- private int data_a_text_len = 0x36-1;
-
- /**
- * From a real file: 4 paragraphs with text in 4 different styles:
- * left aligned+bold (30)
- * centre aligned+italic+blue (28)
- * right aligned+red (25)
- * left aligned+underlined+larger font size (96)
- * left aligned+underlined+larger font size+red (1)
- */
- private byte[] data_b = new byte[] {
- 0, 0, 0xA1-256, 0x0F, 0x80-256, 0, 0, 0,
- 0x1E, 00, 00, 00, // paragraph is 30 long
- 00, 00, // paragraph reserved field
- 00, 0x18, 00, 00, // mask is 0x1800
- 00, 00, // left aligned
- 0x50, 00, // line spacing 80
- 0x1C, 00, 00, 00, // paragprah is 28 long
- 00, 00, // paragraph reserved field
- 00, 0x10, 00, 00, // mask is 0x1000
- 0x50, 00, // line spacing 80
- 0x19, 00, 00, 00, // paragraph is 25 long
- 00, 00, // paragraph reserved field
- 00, 0x18, 00, 00, // mask is 0x1800
- 02, 00, // right aligned
- 0x50, 00, // line spacing 80
- 0x61, 00, 00, 00, // paragraph is 97 long
- 00, 00, // paragraph reserved field
- 00, 0x18, 00, 00, // mask is 0x1800
- 00, 00, // left aligned
- 0x50, 00, // line spacing 80
-
- 0x1E, 00, 00, 00, // character run is 30 long
- 01, 00, 02, 00, // mask is 0x020001
- 01, 00, // char flags 0x0001 = bold
- 0x14, 00, // font size 20
- 0x1C, 00, 00, 00, // character run is 28 long
- 02, 00, 06, 00, // mask is 0x060002
- 02, 00, // char flags 0x0002 = italic
- 0x14, 00, // font size 20
- 00, 00, 00, 05, // colour blue
- 0x19, 00, 00, 00, // character run is 25 long
- 00, 00, 06, 00, // char flags 0x060000
- 0x14, 00, // font size 20
- 0xFF-256, 0x33, 00, 0xFE-256, // colour red
- 0x60, 00, 00, 00, // character run is 96 long
- 04, 00, 03, 00, // mask is 0x030004
- 04, 00, // char flags 0x0004 = underlined
- 01, 00, // font index is 1
- 0x18, 00, // font size 24
-
- 01, 00, 00, 00, // character run is 1 long
- 04, 00, 07, 00, // mask is 0x070004
- 04, 00, // char flags 0x0004 = underlined
- 01, 00, // font index is 1
- 0x18, 00, // font size 24
- 0xFF-256, 0x33, 00, 0xFE-256 // colour red
- };
- private int data_b_text_len = 0xB3;
-
- /**
- * From a real file. Has a mask with more bits
- * set than it actually has data for. Shouldn't do,
- * but some real files do :(
- */
- private byte[] data_c = new byte[] {
- 0, 0, -95, 15, 62, 0, 0, 0,
- 123, 0, 0, 0, 0, 0, 48, 8,
- 10, 0, 1, 0, 0, 0, 0, 0,
- 1, 0, 2, 0, 1, 0, 0, 0,
- 0, 0, 48, 0, 10, 0, 1, 0,
- 0, 0, 0, 0, 2, 0, 123, 0,
- 0, 0, 0, 0, 3, 0, 1, 0,
- 28, 0, 1, 0, 0, 0, 0, 0,
- 3, 0, 1, 0, 24, 0
- };
- private int data_c_text_len = 123-1;
+ };
+ private int data_a_text_len = 0x36-1;
+
+ /**
+ * From a real file: 4 paragraphs with text in 4 different styles:
+ * left aligned+bold (30)
+ * centre aligned+italic+blue (28)
+ * right aligned+red (25)
+ * left aligned+underlined+larger font size (96)
+ * left aligned+underlined+larger font size+red (1)
+ */
+ private byte[] data_b = new byte[] {
+ 0, 0, 0xA1-256, 0x0F, 0x80-256, 0, 0, 0,
+ 0x1E, 00, 00, 00, // paragraph is 30 long
+ 00, 00, // paragraph reserved field
+ 00, 0x18, 00, 00, // mask is 0x1800
+ 00, 00, // left aligned
+ 0x50, 00, // line spacing 80
+ 0x1C, 00, 00, 00, // paragprah is 28 long
+ 00, 00, // paragraph reserved field
+ 00, 0x10, 00, 00, // mask is 0x1000
+ 0x50, 00, // line spacing 80
+ 0x19, 00, 00, 00, // paragraph is 25 long
+ 00, 00, // paragraph reserved field
+ 00, 0x18, 00, 00, // mask is 0x1800
+ 02, 00, // right aligned
+ 0x50, 00, // line spacing 80
+ 0x61, 00, 00, 00, // paragraph is 97 long
+ 00, 00, // paragraph reserved field
+ 00, 0x18, 00, 00, // mask is 0x1800
+ 00, 00, // left aligned
+ 0x50, 00, // line spacing 80
+
+ 0x1E, 00, 00, 00, // character run is 30 long
+ 01, 00, 02, 00, // mask is 0x020001
+ 01, 00, // char flags 0x0001 = bold
+ 0x14, 00, // font size 20
+ 0x1C, 00, 00, 00, // character run is 28 long
+ 02, 00, 06, 00, // mask is 0x060002
+ 02, 00, // char flags 0x0002 = italic
+ 0x14, 00, // font size 20
+ 00, 00, 00, 05, // colour blue
+ 0x19, 00, 00, 00, // character run is 25 long
+ 00, 00, 06, 00, // char flags 0x060000
+ 0x14, 00, // font size 20
+ 0xFF-256, 0x33, 00, 0xFE-256, // colour red
+ 0x60, 00, 00, 00, // character run is 96 long
+ 04, 00, 03, 00, // mask is 0x030004
+ 04, 00, // char flags 0x0004 = underlined
+ 01, 00, // font index is 1
+ 0x18, 00, // font size 24
+
+ 01, 00, 00, 00, // character run is 1 long
+ 04, 00, 07, 00, // mask is 0x070004
+ 04, 00, // char flags 0x0004 = underlined
+ 01, 00, // font index is 1
+ 0x18, 00, // font size 24
+ 0xFF-256, 0x33, 00, 0xFE-256 // colour red
+ };
+ private int data_b_text_len = 0xB3;
+
+ /**
+ * From a real file. Has a mask with more bits
+ * set than it actually has data for. Shouldn't do,
+ * but some real files do :(
+ */
+ private byte[] data_c = new byte[] {
+ 0, 0, -95, 15, 62, 0, 0, 0,
+ 123, 0, 0, 0, 0, 0, 48, 8,
+ 10, 0, 1, 0, 0, 0, 0, 0,
+ 1, 0, 2, 0, 1, 0, 0, 0,
+ 0, 0, 48, 0, 10, 0, 1, 0,
+ 0, 0, 0, 0, 2, 0, 123, 0,
+ 0, 0, 0, 0, 3, 0, 1, 0,
+ 28, 0, 1, 0, 0, 0, 0, 0,
+ 3, 0, 1, 0, 24, 0
+ };
+ private int data_c_text_len = 123-1;
/**
* From a real file supplied for Bug 40143 by tales@great.ufc.br
private int data_d_text_len = 0xA0-1;
public void testRecordType() throws Exception {
- StyleTextPropAtom stpa = new StyleTextPropAtom(data_a,0,data_a.length);
- StyleTextPropAtom stpb = new StyleTextPropAtom(data_b,0,data_b.length);
- StyleTextPropAtom stpc = new StyleTextPropAtom(data_c,0,data_c.length);
- assertEquals(4001l, stpa.getRecordType());
- assertEquals(4001l, stpb.getRecordType());
- assertEquals(4001l, stpc.getRecordType());
- }
-
-
- public void testCharacterStyleCounts() throws Exception {
- StyleTextPropAtom stpa = new StyleTextPropAtom(data_a,0,data_a.length);
- StyleTextPropAtom stpb = new StyleTextPropAtom(data_b,0,data_b.length);
-
- // Set for the appropriate text sizes
- stpa.setParentTextSize(data_a_text_len);
- stpb.setParentTextSize(data_b_text_len);
-
- // In case A, there is a single styling of the characters
- assertEquals(3, stpa.getCharacterStyles().size());
- // In case B, there are 5 different stylings
- assertEquals(5, stpb.getCharacterStyles().size());
- }
-
- public void testParagraphStyleCounts() throws Exception {
- StyleTextPropAtom stpa = new StyleTextPropAtom(data_a,0,data_a.length);
- StyleTextPropAtom stpb = new StyleTextPropAtom(data_b,0,data_b.length);
-
- // Set for the appropriate text sizes
- stpa.setParentTextSize(data_a_text_len);
- stpb.setParentTextSize(data_b_text_len);
-
- // In case A, all has the same spacing and alignment
- assertEquals(1, stpa.getParagraphStyles().size());
- // In case B, all 4 sets have different alignments
- assertEquals(4, stpb.getParagraphStyles().size());
- }
-
-
- public void testCharacterStyleLengths() throws Exception {
- StyleTextPropAtom stpa = new StyleTextPropAtom(data_a,0,data_a.length);
- StyleTextPropAtom stpb = new StyleTextPropAtom(data_b,0,data_b.length);
-
- // Set for the appropriate text sizes
- stpa.setParentTextSize(data_a_text_len);
- stpb.setParentTextSize(data_b_text_len);
-
- // 54 chars, 21 + 17 + 16
- LinkedList a_ch_l = stpa.getCharacterStyles();
- TextPropCollection a_ch_1 = (TextPropCollection)a_ch_l.get(0);
- TextPropCollection a_ch_2 = (TextPropCollection)a_ch_l.get(1);
- TextPropCollection a_ch_3 = (TextPropCollection)a_ch_l.get(2);
- assertEquals(21, a_ch_1.getCharactersCovered());
- assertEquals(17, a_ch_2.getCharactersCovered());
- assertEquals(16, a_ch_3.getCharactersCovered());
-
- // 179 chars, 30 + 28 + 25
- LinkedList b_ch_l = stpb.getCharacterStyles();
- TextPropCollection b_ch_1 = (TextPropCollection)b_ch_l.get(0);
- TextPropCollection b_ch_2 = (TextPropCollection)b_ch_l.get(1);
- TextPropCollection b_ch_3 = (TextPropCollection)b_ch_l.get(2);
- TextPropCollection b_ch_4 = (TextPropCollection)b_ch_l.get(3);
- assertEquals(30, b_ch_1.getCharactersCovered());
- assertEquals(28, b_ch_2.getCharactersCovered());
- assertEquals(25, b_ch_3.getCharactersCovered());
- assertEquals(96, b_ch_4.getCharactersCovered());
- }
-
-
- public void testCharacterPropOrdering() throws Exception {
- StyleTextPropAtom stpb = new StyleTextPropAtom(data_b,0,data_b.length);
- stpb.setParentTextSize(data_b_text_len);
-
- LinkedList b_ch_l = stpb.getCharacterStyles();
- TextPropCollection b_ch_1 = (TextPropCollection)b_ch_l.get(0);
- TextPropCollection b_ch_2 = (TextPropCollection)b_ch_l.get(1);
- TextPropCollection b_ch_3 = (TextPropCollection)b_ch_l.get(2);
- TextPropCollection b_ch_4 = (TextPropCollection)b_ch_l.get(3);
-
- // In first set, we get a CharFlagsTextProp and a font.size
- assertEquals(2,b_ch_1.getTextPropList().size());
- TextProp tp_1_1 = (TextProp)b_ch_1.getTextPropList().get(0);
- TextProp tp_1_2 = (TextProp)b_ch_1.getTextPropList().get(1);
- assertEquals(true, tp_1_1 instanceof CharFlagsTextProp);
- assertEquals(true, tp_1_2 instanceof TextProp);
- assertEquals("font.size", tp_1_2.getName());
- assertEquals(20, tp_1_2.getValue());
-
- // In second set, we get a CharFlagsTextProp and a font.size and a font.color
- assertEquals(3,b_ch_2.getTextPropList().size());
- TextProp tp_2_1 = (TextProp)b_ch_2.getTextPropList().get(0);
- TextProp tp_2_2 = (TextProp)b_ch_2.getTextPropList().get(1);
- TextProp tp_2_3 = (TextProp)b_ch_2.getTextPropList().get(2);
- assertEquals(true, tp_2_1 instanceof CharFlagsTextProp);
- assertEquals(true, tp_2_2 instanceof TextProp);
- assertEquals(true, tp_2_3 instanceof TextProp);
- assertEquals("font.size", tp_2_2.getName());
- assertEquals("font.color", tp_2_3.getName());
- assertEquals(20, tp_2_2.getValue());
-
- // In third set, it's just a font.size and a font.color
- assertEquals(2,b_ch_3.getTextPropList().size());
- TextProp tp_3_1 = (TextProp)b_ch_3.getTextPropList().get(0);
- TextProp tp_3_2 = (TextProp)b_ch_3.getTextPropList().get(1);
- assertEquals(true, tp_3_1 instanceof TextProp);
- assertEquals(true, tp_3_2 instanceof TextProp);
- assertEquals("font.size", tp_3_1.getName());
- assertEquals("font.color", tp_3_2.getName());
- assertEquals(20, tp_3_1.getValue());
-
- // In fourth set, we get a CharFlagsTextProp and a font.index and a font.size
- assertEquals(3,b_ch_4.getTextPropList().size());
- TextProp tp_4_1 = (TextProp)b_ch_4.getTextPropList().get(0);
- TextProp tp_4_2 = (TextProp)b_ch_4.getTextPropList().get(1);
- TextProp tp_4_3 = (TextProp)b_ch_4.getTextPropList().get(2);
- assertEquals(true, tp_4_1 instanceof CharFlagsTextProp);
- assertEquals(true, tp_4_2 instanceof TextProp);
- assertEquals(true, tp_4_3 instanceof TextProp);
- assertEquals("font.index", tp_4_2.getName());
- assertEquals("font.size", tp_4_3.getName());
- assertEquals(24, tp_4_3.getValue());
- }
-
- public void testParagraphProps() throws Exception {
- StyleTextPropAtom stpb = new StyleTextPropAtom(data_b,0,data_b.length);
- stpb.setParentTextSize(data_b_text_len);
-
- LinkedList b_p_l = stpb.getParagraphStyles();
- TextPropCollection b_p_1 = (TextPropCollection)b_p_l.get(0);
- TextPropCollection b_p_2 = (TextPropCollection)b_p_l.get(1);
- TextPropCollection b_p_3 = (TextPropCollection)b_p_l.get(2);
- TextPropCollection b_p_4 = (TextPropCollection)b_p_l.get(3);
-
- // 1st is left aligned + normal line spacing
- assertEquals(2,b_p_1.getTextPropList().size());
- TextProp tp_1_1 = (TextProp)b_p_1.getTextPropList().get(0);
- TextProp tp_1_2 = (TextProp)b_p_1.getTextPropList().get(1);
- assertEquals(true, tp_1_1 instanceof TextProp);
- assertEquals(true, tp_1_2 instanceof TextProp);
- assertEquals("alignment", tp_1_1.getName());
- assertEquals("linespacing", tp_1_2.getName());
- assertEquals(0, tp_1_1.getValue());
- assertEquals(80, tp_1_2.getValue());
-
- // 2nd is centre aligned (default) + normal line spacing
- assertEquals(1,b_p_2.getTextPropList().size());
- TextProp tp_2_1 = (TextProp)b_p_2.getTextPropList().get(0);
- assertEquals(true, tp_2_1 instanceof TextProp);
- assertEquals(true, tp_1_2 instanceof TextProp);
- assertEquals("linespacing", tp_2_1.getName());
- assertEquals(80, tp_2_1.getValue());
-
- // 3rd is right aligned + normal line spacing
- assertEquals(2,b_p_3.getTextPropList().size());
- TextProp tp_3_1 = (TextProp)b_p_3.getTextPropList().get(0);
- TextProp tp_3_2 = (TextProp)b_p_3.getTextPropList().get(1);
- assertEquals(true, tp_3_1 instanceof TextProp);
- assertEquals(true, tp_3_2 instanceof TextProp);
- assertEquals("alignment", tp_3_1.getName());
- assertEquals("linespacing", tp_3_2.getName());
- assertEquals(2, tp_3_1.getValue());
- assertEquals(80, tp_3_2.getValue());
-
- // 4st is left aligned + normal line spacing (despite differing font)
- assertEquals(2,b_p_4.getTextPropList().size());
- TextProp tp_4_1 = (TextProp)b_p_4.getTextPropList().get(0);
- TextProp tp_4_2 = (TextProp)b_p_4.getTextPropList().get(1);
- assertEquals(true, tp_4_1 instanceof TextProp);
- assertEquals(true, tp_4_2 instanceof TextProp);
- assertEquals("alignment", tp_4_1.getName());
- assertEquals("linespacing", tp_4_2.getName());
- assertEquals(0, tp_4_1.getValue());
- assertEquals(80, tp_4_2.getValue());
- }
-
- public void testCharacterProps() throws Exception {
- StyleTextPropAtom stpb = new StyleTextPropAtom(data_b,0,data_b.length);
- stpb.setParentTextSize(data_b_text_len);
-
- LinkedList b_ch_l = stpb.getCharacterStyles();
- TextPropCollection b_ch_1 = (TextPropCollection)b_ch_l.get(0);
- TextPropCollection b_ch_2 = (TextPropCollection)b_ch_l.get(1);
- TextPropCollection b_ch_3 = (TextPropCollection)b_ch_l.get(2);
- TextPropCollection b_ch_4 = (TextPropCollection)b_ch_l.get(3);
-
- // 1st is bold
- CharFlagsTextProp cf_1_1 = (CharFlagsTextProp)b_ch_1.getTextPropList().get(0);
- assertEquals(true,cf_1_1.getSubValue(CharFlagsTextProp.BOLD_IDX));
- assertEquals(false,cf_1_1.getSubValue(CharFlagsTextProp.ITALIC_IDX));
- assertEquals(false,cf_1_1.getSubValue(CharFlagsTextProp.ENABLE_NUMBERING_1_IDX));
- assertEquals(false,cf_1_1.getSubValue(CharFlagsTextProp.ENABLE_NUMBERING_2_IDX));
- assertEquals(false,cf_1_1.getSubValue(CharFlagsTextProp.RELIEF_IDX));
- assertEquals(false,cf_1_1.getSubValue(CharFlagsTextProp.RESET_NUMBERING_IDX));
- assertEquals(false,cf_1_1.getSubValue(CharFlagsTextProp.SHADOW_IDX));
- assertEquals(false,cf_1_1.getSubValue(CharFlagsTextProp.STRIKETHROUGH_IDX));
- assertEquals(false,cf_1_1.getSubValue(CharFlagsTextProp.UNDERLINE_IDX));
-
- // 2nd is italic
- CharFlagsTextProp cf_2_1 = (CharFlagsTextProp)b_ch_2.getTextPropList().get(0);
- assertEquals(false,cf_2_1.getSubValue(CharFlagsTextProp.BOLD_IDX));
- assertEquals(true,cf_2_1.getSubValue(CharFlagsTextProp.ITALIC_IDX));
- assertEquals(false,cf_2_1.getSubValue(CharFlagsTextProp.ENABLE_NUMBERING_1_IDX));
- assertEquals(false,cf_2_1.getSubValue(CharFlagsTextProp.ENABLE_NUMBERING_2_IDX));
- assertEquals(false,cf_2_1.getSubValue(CharFlagsTextProp.RELIEF_IDX));
- assertEquals(false,cf_2_1.getSubValue(CharFlagsTextProp.RESET_NUMBERING_IDX));
- assertEquals(false,cf_2_1.getSubValue(CharFlagsTextProp.SHADOW_IDX));
- assertEquals(false,cf_2_1.getSubValue(CharFlagsTextProp.STRIKETHROUGH_IDX));
- assertEquals(false,cf_2_1.getSubValue(CharFlagsTextProp.UNDERLINE_IDX));
-
- // 3rd is normal, so lacks a CharFlagsTextProp
- assertFalse(b_ch_3.getTextPropList().get(0) instanceof CharFlagsTextProp);
-
- // 4th is underlined
- CharFlagsTextProp cf_4_1 = (CharFlagsTextProp)b_ch_4.getTextPropList().get(0);
- assertEquals(false,cf_4_1.getSubValue(CharFlagsTextProp.BOLD_IDX));
- assertEquals(false,cf_4_1.getSubValue(CharFlagsTextProp.ITALIC_IDX));
- assertEquals(false,cf_4_1.getSubValue(CharFlagsTextProp.ENABLE_NUMBERING_1_IDX));
- assertEquals(false,cf_4_1.getSubValue(CharFlagsTextProp.ENABLE_NUMBERING_2_IDX));
- assertEquals(false,cf_4_1.getSubValue(CharFlagsTextProp.RELIEF_IDX));
- assertEquals(false,cf_4_1.getSubValue(CharFlagsTextProp.RESET_NUMBERING_IDX));
- assertEquals(false,cf_4_1.getSubValue(CharFlagsTextProp.SHADOW_IDX));
- assertEquals(false,cf_4_1.getSubValue(CharFlagsTextProp.STRIKETHROUGH_IDX));
- assertEquals(true,cf_4_1.getSubValue(CharFlagsTextProp.UNDERLINE_IDX));
-
- // The value for this should be 4
- assertEquals(0x0004, cf_4_1.getValue());
-
- // Now make the 4th bold, italic and not underlined
- cf_4_1.setSubValue(true, CharFlagsTextProp.BOLD_IDX);
- cf_4_1.setSubValue(true, CharFlagsTextProp.ITALIC_IDX);
- cf_4_1.setSubValue(false, CharFlagsTextProp.UNDERLINE_IDX);
-
- assertEquals(true,cf_4_1.getSubValue(CharFlagsTextProp.BOLD_IDX));
- assertEquals(true,cf_4_1.getSubValue(CharFlagsTextProp.ITALIC_IDX));
- assertEquals(false,cf_4_1.getSubValue(CharFlagsTextProp.ENABLE_NUMBERING_1_IDX));
- assertEquals(false,cf_4_1.getSubValue(CharFlagsTextProp.ENABLE_NUMBERING_2_IDX));
- assertEquals(false,cf_4_1.getSubValue(CharFlagsTextProp.RELIEF_IDX));
- assertEquals(false,cf_4_1.getSubValue(CharFlagsTextProp.RESET_NUMBERING_IDX));
- assertEquals(false,cf_4_1.getSubValue(CharFlagsTextProp.SHADOW_IDX));
- assertEquals(false,cf_4_1.getSubValue(CharFlagsTextProp.STRIKETHROUGH_IDX));
- assertEquals(false,cf_4_1.getSubValue(CharFlagsTextProp.UNDERLINE_IDX));
-
- // The value should now be 3
- assertEquals(0x0003, cf_4_1.getValue());
- }
-
- public void testFindAddTextProp() {
- StyleTextPropAtom stpb = new StyleTextPropAtom(data_b,0,data_b.length);
- stpb.setParentTextSize(data_b_text_len);
-
- LinkedList b_p_l = stpb.getParagraphStyles();
- TextPropCollection b_p_1 = (TextPropCollection)b_p_l.get(0);
- TextPropCollection b_p_2 = (TextPropCollection)b_p_l.get(1);
- TextPropCollection b_p_3 = (TextPropCollection)b_p_l.get(2);
- TextPropCollection b_p_4 = (TextPropCollection)b_p_l.get(3);
-
- LinkedList b_ch_l = stpb.getCharacterStyles();
- TextPropCollection b_ch_1 = (TextPropCollection)b_ch_l.get(0);
- TextPropCollection b_ch_2 = (TextPropCollection)b_ch_l.get(1);
- TextPropCollection b_ch_3 = (TextPropCollection)b_ch_l.get(2);
- TextPropCollection b_ch_4 = (TextPropCollection)b_ch_l.get(3);
-
- // CharFlagsTextProp: 3 doesn't have, 4 does
- assertNull(b_ch_3.findByName("char_flags"));
- assertNotNull(b_ch_4.findByName("char_flags"));
-
- // Now add in on 3, should go to front
- assertEquals(2, b_ch_3.getTextPropList().size());
- TextProp new_cftp = b_ch_3.addWithName("char_flags");
- assertEquals(3, b_ch_3.getTextPropList().size());
- assertEquals(new_cftp, b_ch_3.getTextPropList().get(0));
-
- // alignment: 1 does have, 2 doesn't
- assertNotNull(b_p_1.findByName("alignment"));
- assertNull(b_p_2.findByName("alignment"));
-
- // Now add in on 2, should go to the front
- assertEquals(1, b_p_2.getTextPropList().size());
- TextProp new_al = b_p_2.addWithName("alignment");
- assertEquals(2, b_p_2.getTextPropList().size());
- assertEquals(new_al, b_p_2.getTextPropList().get(0));
-
- // This should go at the end
- TextProp new_sa = b_p_2.addWithName("spaceafter");
- assertEquals(3, b_p_2.getTextPropList().size());
- assertEquals(new_sa, b_p_2.getTextPropList().get(2));
-
- // Check we get an error with a made up one
- try {
- b_p_2.addWithName("madeUpOne");
- fail();
- } catch(IllegalArgumentException e) {
- // Good, as expected
- }
- }
-
- /**
- * Try to recreate an existing StyleTextPropAtom (a) from the empty
- * constructor, and setting the required properties
- */
- public void testCreateAFromScatch() throws Exception {
- // Start with an empty one
- StyleTextPropAtom stpa = new StyleTextPropAtom(54);
-
- // Don't need to touch the paragraph styles
- // Add two more character styles
- LinkedList cs = stpa.getCharacterStyles();
-
- // First char style is boring, and 21 long
- TextPropCollection tpca = (TextPropCollection)cs.get(0);
- tpca.updateTextSize(21);
-
- // Second char style is coloured, 00 00 00 05, and 17 long
- TextPropCollection tpcb = stpa.addCharacterTextPropCollection(17);
- TextProp tpb = tpcb.addWithName("font.color");
- tpb.setValue(0x05000000);
-
- // Third char style is coloured, FF 33 00 FE, and 16 long
- TextPropCollection tpcc = stpa.addCharacterTextPropCollection(16);
- TextProp tpc = tpcc.addWithName("font.color");
- tpc.setValue(0xFE0033FF);
-
- // Should now be the same as data_a
- ByteArrayOutputStream baos = new ByteArrayOutputStream();
- stpa.writeOut(baos);
- byte[] b = baos.toByteArray();
-
- assertEquals(data_a.length, b.length);
- for(int i=0; i<data_a.length; i++) {
- assertEquals(data_a[i],b[i]);
- }
- }
-
- /**
- * Try to recreate an existing StyleTextPropAtom (b) from the empty
- * constructor, and setting the required properties
- */
- public void testCreateBFromScatch() throws Exception {
- // Start with an empty one
- StyleTextPropAtom stpa = new StyleTextPropAtom(data_b_text_len);
-
-
- // Need 4 paragraph styles
- LinkedList ps = stpa.getParagraphStyles();
-
- // First is 30 long, left aligned, normal spacing
- TextPropCollection tppa = (TextPropCollection)ps.get(0);
- tppa.updateTextSize(30);
-
- TextProp tp = tppa.addWithName("alignment");
- tp.setValue(0);
- tp = tppa.addWithName("linespacing");
- tp.setValue(80);
-
- // Second is 28 long, centre aligned and normal spacing
- TextPropCollection tppb = stpa.addParagraphTextPropCollection(28);
-
- tp = tppb.addWithName("linespacing");
- tp.setValue(80);
-
- // Third is 25 long, right aligned and normal spacing
- TextPropCollection tppc = stpa.addParagraphTextPropCollection(25);
-
- tp = tppc.addWithName("alignment");
- tp.setValue(2);
- tp = tppc.addWithName("linespacing");
- tp.setValue(80);
-
- // Forth is left aligned + normal line spacing (despite differing font)
- TextPropCollection tppd = stpa.addParagraphTextPropCollection(97);
-
- tp = tppd.addWithName("alignment");
- tp.setValue(0);
- tp = tppd.addWithName("linespacing");
- tp.setValue(80);
-
-
- // Now do 4 character styles
- LinkedList cs = stpa.getCharacterStyles();
-
- // First is 30 long, bold and font size
- TextPropCollection tpca = (TextPropCollection)cs.get(0);
- tpca.updateTextSize(30);
-
- tp = tpca.addWithName("font.size");
- tp.setValue(20);
- CharFlagsTextProp cftp = (CharFlagsTextProp)
- tpca.addWithName("char_flags");
- assertEquals(0, cftp.getValue());
- cftp.setSubValue(true, CharFlagsTextProp.BOLD_IDX);
- assertEquals(1, cftp.getValue());
-
- // Second is 28 long, blue and italic
- TextPropCollection tpcb = stpa.addCharacterTextPropCollection(28);
-
- tp = tpcb.addWithName("font.size");
- tp.setValue(20);
- tp = tpcb.addWithName("font.color");
- tp.setValue(0x05000000);
- cftp = (CharFlagsTextProp)tpcb.addWithName("char_flags");
- cftp.setSubValue(true, CharFlagsTextProp.ITALIC_IDX);
- assertEquals(2, cftp.getValue());
-
- // Third is 25 long and red
- TextPropCollection tpcc = stpa.addCharacterTextPropCollection(25);
-
- tp = tpcc.addWithName("font.size");
- tp.setValue(20);
- tp = tpcc.addWithName("font.color");
- tp.setValue(0xfe0033ff);
-
- // Fourth is 96 long, underlined and different+bigger font
- TextPropCollection tpcd = stpa.addCharacterTextPropCollection(96);
-
- tp = tpcd.addWithName("font.size");
- tp.setValue(24);
- tp = tpcd.addWithName("font.index");
- tp.setValue(1);
- cftp = (CharFlagsTextProp)tpcd.addWithName("char_flags");
- cftp.setSubValue(true, CharFlagsTextProp.UNDERLINE_IDX);
- assertEquals(4, cftp.getValue());
-
- // Fifth is 1 long, underlined and different+bigger font + red
- TextPropCollection tpce = stpa.addCharacterTextPropCollection(1);
-
- tp = tpce.addWithName("font.size");
- tp.setValue(24);
- tp = tpce.addWithName("font.index");
- tp.setValue(1);
- tp = tpce.addWithName("font.color");
- tp.setValue(0xfe0033ff);
- cftp = (CharFlagsTextProp)tpce.addWithName("char_flags");
- cftp.setSubValue(true, CharFlagsTextProp.UNDERLINE_IDX);
- assertEquals(4, cftp.getValue());
-
-
- // Check it's as expected
- assertEquals(4, stpa.getParagraphStyles().size());
- assertEquals(5, stpa.getCharacterStyles().size());
-
- // Compare in detail to b
- StyleTextPropAtom stpb = new StyleTextPropAtom(data_b,0,data_b.length);
- stpb.setParentTextSize(data_b_text_len);
- LinkedList psb = stpb.getParagraphStyles();
- LinkedList csb = stpb.getCharacterStyles();
-
- assertEquals(psb.size(), ps.size());
- assertEquals(csb.size(), cs.size());
-
- // Ensure Paragraph Character styles match
- for(int z=0; z<2; z++) {
- LinkedList lla = cs;
- LinkedList llb = csb;
- int upto = 5;
- if(z == 1) {
- lla = ps;
- llb = psb;
- upto = 4;
- }
-
- for(int i=0; i<upto; i++) {
- TextPropCollection ca = (TextPropCollection)lla.get(i);
- TextPropCollection cb = (TextPropCollection)llb.get(i);
-
- assertEquals(ca.getCharactersCovered(), cb.getCharactersCovered());
- assertEquals(ca.getTextPropList().size(), cb.getTextPropList().size());
-
- for(int j=0; j<ca.getTextPropList().size(); j++) {
- TextProp tpa = (TextProp)ca.getTextPropList().get(j);
- TextProp tpb = (TextProp)cb.getTextPropList().get(j);
- //System.out.println("TP " + i + " " + j + " " + tpa.getName() + "\t" + tpa.getValue() );
- assertEquals(tpa.getName(), tpb.getName());
- assertEquals(tpa.getMask(), tpb.getMask());
- assertEquals(tpa.getWriteMask(), tpb.getWriteMask());
- assertEquals(tpa.getValue(), tpb.getValue());
- }
-
- ByteArrayOutputStream ba = new ByteArrayOutputStream();
- ByteArrayOutputStream bb = new ByteArrayOutputStream();
-
- ca.writeOut(ba);
- cb.writeOut(bb);
- byte[] cab = ba.toByteArray();
- byte[] cbb = bb.toByteArray();
-
- assertEquals(cbb.length, cab.length);
- for(int j=0; j<cab.length; j++) {
- //System.out.println("On tp " + z + " " + i + " " + j + "\t" + cab[j] + "\t" + cbb[j]);
- assertEquals(cbb[j], cab[j]);
- }
- }
- }
-
-
-
- // Check byte level with b
- ByteArrayOutputStream baos = new ByteArrayOutputStream();
- stpa.writeOut(baos);
- byte[] b = baos.toByteArray();
-
- assertEquals(data_b.length, b.length);
- for(int i=0; i<data_b.length; i++) {
- System.out.println(i + "\t" + b[i] + "\t" + data_b[i] + "\t" + Integer.toHexString(b[i]) );
- assertEquals(data_b[i],b[i]);
- }
- }
-
- public void testWriteA() throws Exception {
- StyleTextPropAtom stpa = new StyleTextPropAtom(data_a,0,data_a.length);
- ByteArrayOutputStream baos = new ByteArrayOutputStream();
- stpa.writeOut(baos);
- byte[] b = baos.toByteArray();
-
- assertEquals(data_a.length, b.length);
- for(int i=0; i<data_a.length; i++) {
- assertEquals(data_a[i],b[i]);
- }
- }
-
- public void testLoadWriteA() throws Exception {
- StyleTextPropAtom stpa = new StyleTextPropAtom(data_a,0,data_a.length);
- stpa.setParentTextSize(data_a_text_len);
-
- ByteArrayOutputStream baos = new ByteArrayOutputStream();
- stpa.writeOut(baos);
- byte[] b = baos.toByteArray();
-
- assertEquals(data_a.length, b.length);
- for(int i=0; i<data_a.length; i++) {
- assertEquals(data_a[i],b[i]);
- }
- }
-
-
- public void testWriteB() throws Exception {
- StyleTextPropAtom stpb = new StyleTextPropAtom(data_b,0,data_b.length);
- ByteArrayOutputStream baos = new ByteArrayOutputStream();
- stpb.writeOut(baos);
- byte[] b = baos.toByteArray();
-
- assertEquals(data_b.length, b.length);
- for(int i=0; i<data_b.length; i++) {
- assertEquals(data_b[i],b[i]);
- }
- }
-
- public void testLoadWriteB() throws Exception {
- StyleTextPropAtom stpb = new StyleTextPropAtom(data_b,0,data_b.length);
- stpb.setParentTextSize(data_b_text_len);
-
- ByteArrayOutputStream baos = new ByteArrayOutputStream();
- stpb.writeOut(baos);
- byte[] b = baos.toByteArray();
-
- assertEquals(data_b.length, b.length);
- for(int i=0; i<data_b.length; i++) {
- //System.out.println(i + "\t" + b[i] + "\t" + data_b[i] + "\t" + Integer.toHexString(b[i]) );
- assertEquals(data_b[i],b[i]);
- }
- }
-
-
- public void testNotEnoughDataProp() throws Exception {
- // We don't have enough data in the record to cover
- // all the properties the mask says we have
- // Make sure we just do the best we can
- StyleTextPropAtom stpc = new StyleTextPropAtom(data_c,0,data_c.length);
- stpc.setParentTextSize(data_c_text_len);
-
- // If we get here, we didn't break
- }
+ StyleTextPropAtom stpa = new StyleTextPropAtom(data_a,0,data_a.length);
+ StyleTextPropAtom stpb = new StyleTextPropAtom(data_b,0,data_b.length);
+ StyleTextPropAtom stpc = new StyleTextPropAtom(data_c,0,data_c.length);
+ assertEquals(4001l, stpa.getRecordType());
+ assertEquals(4001l, stpb.getRecordType());
+ assertEquals(4001l, stpc.getRecordType());
+ }
+
+
+ public void testCharacterStyleCounts() throws Exception {
+ StyleTextPropAtom stpa = new StyleTextPropAtom(data_a,0,data_a.length);
+ StyleTextPropAtom stpb = new StyleTextPropAtom(data_b,0,data_b.length);
+
+ // Set for the appropriate text sizes
+ stpa.setParentTextSize(data_a_text_len);
+ stpb.setParentTextSize(data_b_text_len);
+
+ // In case A, there is a single styling of the characters
+ assertEquals(3, stpa.getCharacterStyles().size());
+ // In case B, there are 5 different stylings
+ assertEquals(5, stpb.getCharacterStyles().size());
+ }
+
+ public void testParagraphStyleCounts() throws Exception {
+ StyleTextPropAtom stpa = new StyleTextPropAtom(data_a,0,data_a.length);
+ StyleTextPropAtom stpb = new StyleTextPropAtom(data_b,0,data_b.length);
+
+ // Set for the appropriate text sizes
+ stpa.setParentTextSize(data_a_text_len);
+ stpb.setParentTextSize(data_b_text_len);
+
+ // In case A, all has the same spacing and alignment
+ assertEquals(1, stpa.getParagraphStyles().size());
+ // In case B, all 4 sets have different alignments
+ assertEquals(4, stpb.getParagraphStyles().size());
+ }
+
+
+ public void testCharacterStyleLengths() throws Exception {
+ StyleTextPropAtom stpa = new StyleTextPropAtom(data_a,0,data_a.length);
+ StyleTextPropAtom stpb = new StyleTextPropAtom(data_b,0,data_b.length);
+
+ // Set for the appropriate text sizes
+ stpa.setParentTextSize(data_a_text_len);
+ stpb.setParentTextSize(data_b_text_len);
+
+ // 54 chars, 21 + 17 + 16
+ LinkedList a_ch_l = stpa.getCharacterStyles();
+ TextPropCollection a_ch_1 = (TextPropCollection)a_ch_l.get(0);
+ TextPropCollection a_ch_2 = (TextPropCollection)a_ch_l.get(1);
+ TextPropCollection a_ch_3 = (TextPropCollection)a_ch_l.get(2);
+ assertEquals(21, a_ch_1.getCharactersCovered());
+ assertEquals(17, a_ch_2.getCharactersCovered());
+ assertEquals(16, a_ch_3.getCharactersCovered());
+
+ // 179 chars, 30 + 28 + 25
+ LinkedList b_ch_l = stpb.getCharacterStyles();
+ TextPropCollection b_ch_1 = (TextPropCollection)b_ch_l.get(0);
+ TextPropCollection b_ch_2 = (TextPropCollection)b_ch_l.get(1);
+ TextPropCollection b_ch_3 = (TextPropCollection)b_ch_l.get(2);
+ TextPropCollection b_ch_4 = (TextPropCollection)b_ch_l.get(3);
+ assertEquals(30, b_ch_1.getCharactersCovered());
+ assertEquals(28, b_ch_2.getCharactersCovered());
+ assertEquals(25, b_ch_3.getCharactersCovered());
+ assertEquals(96, b_ch_4.getCharactersCovered());
+ }
+
+
+ public void testCharacterPropOrdering() throws Exception {
+ StyleTextPropAtom stpb = new StyleTextPropAtom(data_b,0,data_b.length);
+ stpb.setParentTextSize(data_b_text_len);
+
+ LinkedList b_ch_l = stpb.getCharacterStyles();
+ TextPropCollection b_ch_1 = (TextPropCollection)b_ch_l.get(0);
+ TextPropCollection b_ch_2 = (TextPropCollection)b_ch_l.get(1);
+ TextPropCollection b_ch_3 = (TextPropCollection)b_ch_l.get(2);
+ TextPropCollection b_ch_4 = (TextPropCollection)b_ch_l.get(3);
+
+ // In first set, we get a CharFlagsTextProp and a font.size
+ assertEquals(2,b_ch_1.getTextPropList().size());
+ TextProp tp_1_1 = (TextProp)b_ch_1.getTextPropList().get(0);
+ TextProp tp_1_2 = (TextProp)b_ch_1.getTextPropList().get(1);
+ assertEquals(true, tp_1_1 instanceof CharFlagsTextProp);
+ assertEquals(true, tp_1_2 instanceof TextProp);
+ assertEquals("font.size", tp_1_2.getName());
+ assertEquals(20, tp_1_2.getValue());
+
+ // In second set, we get a CharFlagsTextProp and a font.size and a font.color
+ assertEquals(3,b_ch_2.getTextPropList().size());
+ TextProp tp_2_1 = (TextProp)b_ch_2.getTextPropList().get(0);
+ TextProp tp_2_2 = (TextProp)b_ch_2.getTextPropList().get(1);
+ TextProp tp_2_3 = (TextProp)b_ch_2.getTextPropList().get(2);
+ assertEquals(true, tp_2_1 instanceof CharFlagsTextProp);
+ assertEquals(true, tp_2_2 instanceof TextProp);
+ assertEquals(true, tp_2_3 instanceof TextProp);
+ assertEquals("font.size", tp_2_2.getName());
+ assertEquals("font.color", tp_2_3.getName());
+ assertEquals(20, tp_2_2.getValue());
+
+ // In third set, it's just a font.size and a font.color
+ assertEquals(2,b_ch_3.getTextPropList().size());
+ TextProp tp_3_1 = (TextProp)b_ch_3.getTextPropList().get(0);
+ TextProp tp_3_2 = (TextProp)b_ch_3.getTextPropList().get(1);
+ assertEquals(true, tp_3_1 instanceof TextProp);
+ assertEquals(true, tp_3_2 instanceof TextProp);
+ assertEquals("font.size", tp_3_1.getName());
+ assertEquals("font.color", tp_3_2.getName());
+ assertEquals(20, tp_3_1.getValue());
+
+ // In fourth set, we get a CharFlagsTextProp and a font.index and a font.size
+ assertEquals(3,b_ch_4.getTextPropList().size());
+ TextProp tp_4_1 = (TextProp)b_ch_4.getTextPropList().get(0);
+ TextProp tp_4_2 = (TextProp)b_ch_4.getTextPropList().get(1);
+ TextProp tp_4_3 = (TextProp)b_ch_4.getTextPropList().get(2);
+ assertEquals(true, tp_4_1 instanceof CharFlagsTextProp);
+ assertEquals(true, tp_4_2 instanceof TextProp);
+ assertEquals(true, tp_4_3 instanceof TextProp);
+ assertEquals("font.index", tp_4_2.getName());
+ assertEquals("font.size", tp_4_3.getName());
+ assertEquals(24, tp_4_3.getValue());
+ }
+
+ public void testParagraphProps() throws Exception {
+ StyleTextPropAtom stpb = new StyleTextPropAtom(data_b,0,data_b.length);
+ stpb.setParentTextSize(data_b_text_len);
+
+ LinkedList b_p_l = stpb.getParagraphStyles();
+ TextPropCollection b_p_1 = (TextPropCollection)b_p_l.get(0);
+ TextPropCollection b_p_2 = (TextPropCollection)b_p_l.get(1);
+ TextPropCollection b_p_3 = (TextPropCollection)b_p_l.get(2);
+ TextPropCollection b_p_4 = (TextPropCollection)b_p_l.get(3);
+
+ // 1st is left aligned + normal line spacing
+ assertEquals(2,b_p_1.getTextPropList().size());
+ TextProp tp_1_1 = (TextProp)b_p_1.getTextPropList().get(0);
+ TextProp tp_1_2 = (TextProp)b_p_1.getTextPropList().get(1);
+ assertEquals(true, tp_1_1 instanceof TextProp);
+ assertEquals(true, tp_1_2 instanceof TextProp);
+ assertEquals("alignment", tp_1_1.getName());
+ assertEquals("linespacing", tp_1_2.getName());
+ assertEquals(0, tp_1_1.getValue());
+ assertEquals(80, tp_1_2.getValue());
+
+ // 2nd is centre aligned (default) + normal line spacing
+ assertEquals(1,b_p_2.getTextPropList().size());
+ TextProp tp_2_1 = (TextProp)b_p_2.getTextPropList().get(0);
+ assertEquals(true, tp_2_1 instanceof TextProp);
+ assertEquals(true, tp_1_2 instanceof TextProp);
+ assertEquals("linespacing", tp_2_1.getName());
+ assertEquals(80, tp_2_1.getValue());
+
+ // 3rd is right aligned + normal line spacing
+ assertEquals(2,b_p_3.getTextPropList().size());
+ TextProp tp_3_1 = (TextProp)b_p_3.getTextPropList().get(0);
+ TextProp tp_3_2 = (TextProp)b_p_3.getTextPropList().get(1);
+ assertEquals(true, tp_3_1 instanceof TextProp);
+ assertEquals(true, tp_3_2 instanceof TextProp);
+ assertEquals("alignment", tp_3_1.getName());
+ assertEquals("linespacing", tp_3_2.getName());
+ assertEquals(2, tp_3_1.getValue());
+ assertEquals(80, tp_3_2.getValue());
+
+ // 4st is left aligned + normal line spacing (despite differing font)
+ assertEquals(2,b_p_4.getTextPropList().size());
+ TextProp tp_4_1 = (TextProp)b_p_4.getTextPropList().get(0);
+ TextProp tp_4_2 = (TextProp)b_p_4.getTextPropList().get(1);
+ assertEquals(true, tp_4_1 instanceof TextProp);
+ assertEquals(true, tp_4_2 instanceof TextProp);
+ assertEquals("alignment", tp_4_1.getName());
+ assertEquals("linespacing", tp_4_2.getName());
+ assertEquals(0, tp_4_1.getValue());
+ assertEquals(80, tp_4_2.getValue());
+ }
+
+ public void testCharacterProps() throws Exception {
+ StyleTextPropAtom stpb = new StyleTextPropAtom(data_b,0,data_b.length);
+ stpb.setParentTextSize(data_b_text_len);
+
+ LinkedList b_ch_l = stpb.getCharacterStyles();
+ TextPropCollection b_ch_1 = (TextPropCollection)b_ch_l.get(0);
+ TextPropCollection b_ch_2 = (TextPropCollection)b_ch_l.get(1);
+ TextPropCollection b_ch_3 = (TextPropCollection)b_ch_l.get(2);
+ TextPropCollection b_ch_4 = (TextPropCollection)b_ch_l.get(3);
+
+ // 1st is bold
+ CharFlagsTextProp cf_1_1 = (CharFlagsTextProp)b_ch_1.getTextPropList().get(0);
+ assertEquals(true,cf_1_1.getSubValue(CharFlagsTextProp.BOLD_IDX));
+ assertEquals(false,cf_1_1.getSubValue(CharFlagsTextProp.ITALIC_IDX));
+ assertEquals(false,cf_1_1.getSubValue(CharFlagsTextProp.ENABLE_NUMBERING_1_IDX));
+ assertEquals(false,cf_1_1.getSubValue(CharFlagsTextProp.ENABLE_NUMBERING_2_IDX));
+ assertEquals(false,cf_1_1.getSubValue(CharFlagsTextProp.RELIEF_IDX));
+ assertEquals(false,cf_1_1.getSubValue(CharFlagsTextProp.RESET_NUMBERING_IDX));
+ assertEquals(false,cf_1_1.getSubValue(CharFlagsTextProp.SHADOW_IDX));
+ assertEquals(false,cf_1_1.getSubValue(CharFlagsTextProp.STRIKETHROUGH_IDX));
+ assertEquals(false,cf_1_1.getSubValue(CharFlagsTextProp.UNDERLINE_IDX));
+
+ // 2nd is italic
+ CharFlagsTextProp cf_2_1 = (CharFlagsTextProp)b_ch_2.getTextPropList().get(0);
+ assertEquals(false,cf_2_1.getSubValue(CharFlagsTextProp.BOLD_IDX));
+ assertEquals(true,cf_2_1.getSubValue(CharFlagsTextProp.ITALIC_IDX));
+ assertEquals(false,cf_2_1.getSubValue(CharFlagsTextProp.ENABLE_NUMBERING_1_IDX));
+ assertEquals(false,cf_2_1.getSubValue(CharFlagsTextProp.ENABLE_NUMBERING_2_IDX));
+ assertEquals(false,cf_2_1.getSubValue(CharFlagsTextProp.RELIEF_IDX));
+ assertEquals(false,cf_2_1.getSubValue(CharFlagsTextProp.RESET_NUMBERING_IDX));
+ assertEquals(false,cf_2_1.getSubValue(CharFlagsTextProp.SHADOW_IDX));
+ assertEquals(false,cf_2_1.getSubValue(CharFlagsTextProp.STRIKETHROUGH_IDX));
+ assertEquals(false,cf_2_1.getSubValue(CharFlagsTextProp.UNDERLINE_IDX));
+
+ // 3rd is normal, so lacks a CharFlagsTextProp
+ assertFalse(b_ch_3.getTextPropList().get(0) instanceof CharFlagsTextProp);
+
+ // 4th is underlined
+ CharFlagsTextProp cf_4_1 = (CharFlagsTextProp)b_ch_4.getTextPropList().get(0);
+ assertEquals(false,cf_4_1.getSubValue(CharFlagsTextProp.BOLD_IDX));
+ assertEquals(false,cf_4_1.getSubValue(CharFlagsTextProp.ITALIC_IDX));
+ assertEquals(false,cf_4_1.getSubValue(CharFlagsTextProp.ENABLE_NUMBERING_1_IDX));
+ assertEquals(false,cf_4_1.getSubValue(CharFlagsTextProp.ENABLE_NUMBERING_2_IDX));
+ assertEquals(false,cf_4_1.getSubValue(CharFlagsTextProp.RELIEF_IDX));
+ assertEquals(false,cf_4_1.getSubValue(CharFlagsTextProp.RESET_NUMBERING_IDX));
+ assertEquals(false,cf_4_1.getSubValue(CharFlagsTextProp.SHADOW_IDX));
+ assertEquals(false,cf_4_1.getSubValue(CharFlagsTextProp.STRIKETHROUGH_IDX));
+ assertEquals(true,cf_4_1.getSubValue(CharFlagsTextProp.UNDERLINE_IDX));
+
+ // The value for this should be 4
+ assertEquals(0x0004, cf_4_1.getValue());
+
+ // Now make the 4th bold, italic and not underlined
+ cf_4_1.setSubValue(true, CharFlagsTextProp.BOLD_IDX);
+ cf_4_1.setSubValue(true, CharFlagsTextProp.ITALIC_IDX);
+ cf_4_1.setSubValue(false, CharFlagsTextProp.UNDERLINE_IDX);
+
+ assertEquals(true,cf_4_1.getSubValue(CharFlagsTextProp.BOLD_IDX));
+ assertEquals(true,cf_4_1.getSubValue(CharFlagsTextProp.ITALIC_IDX));
+ assertEquals(false,cf_4_1.getSubValue(CharFlagsTextProp.ENABLE_NUMBERING_1_IDX));
+ assertEquals(false,cf_4_1.getSubValue(CharFlagsTextProp.ENABLE_NUMBERING_2_IDX));
+ assertEquals(false,cf_4_1.getSubValue(CharFlagsTextProp.RELIEF_IDX));
+ assertEquals(false,cf_4_1.getSubValue(CharFlagsTextProp.RESET_NUMBERING_IDX));
+ assertEquals(false,cf_4_1.getSubValue(CharFlagsTextProp.SHADOW_IDX));
+ assertEquals(false,cf_4_1.getSubValue(CharFlagsTextProp.STRIKETHROUGH_IDX));
+ assertEquals(false,cf_4_1.getSubValue(CharFlagsTextProp.UNDERLINE_IDX));
+
+ // The value should now be 3
+ assertEquals(0x0003, cf_4_1.getValue());
+ }
+
+ public void testFindAddTextProp() {
+ StyleTextPropAtom stpb = new StyleTextPropAtom(data_b,0,data_b.length);
+ stpb.setParentTextSize(data_b_text_len);
+
+ LinkedList b_p_l = stpb.getParagraphStyles();
+ TextPropCollection b_p_1 = (TextPropCollection)b_p_l.get(0);
+ TextPropCollection b_p_2 = (TextPropCollection)b_p_l.get(1);
+ TextPropCollection b_p_3 = (TextPropCollection)b_p_l.get(2);
+ TextPropCollection b_p_4 = (TextPropCollection)b_p_l.get(3);
+
+ LinkedList b_ch_l = stpb.getCharacterStyles();
+ TextPropCollection b_ch_1 = (TextPropCollection)b_ch_l.get(0);
+ TextPropCollection b_ch_2 = (TextPropCollection)b_ch_l.get(1);
+ TextPropCollection b_ch_3 = (TextPropCollection)b_ch_l.get(2);
+ TextPropCollection b_ch_4 = (TextPropCollection)b_ch_l.get(3);
+
+ // CharFlagsTextProp: 3 doesn't have, 4 does
+ assertNull(b_ch_3.findByName("char_flags"));
+ assertNotNull(b_ch_4.findByName("char_flags"));
+
+ // Now add in on 3, should go to front
+ assertEquals(2, b_ch_3.getTextPropList().size());
+ TextProp new_cftp = b_ch_3.addWithName("char_flags");
+ assertEquals(3, b_ch_3.getTextPropList().size());
+ assertEquals(new_cftp, b_ch_3.getTextPropList().get(0));
+
+ // alignment: 1 does have, 2 doesn't
+ assertNotNull(b_p_1.findByName("alignment"));
+ assertNull(b_p_2.findByName("alignment"));
+
+ // Now add in on 2, should go to the front
+ assertEquals(1, b_p_2.getTextPropList().size());
+ TextProp new_al = b_p_2.addWithName("alignment");
+ assertEquals(2, b_p_2.getTextPropList().size());
+ assertEquals(new_al, b_p_2.getTextPropList().get(0));
+
+ // This should go at the end
+ TextProp new_sa = b_p_2.addWithName("spaceafter");
+ assertEquals(3, b_p_2.getTextPropList().size());
+ assertEquals(new_sa, b_p_2.getTextPropList().get(2));
+
+ // Check we get an error with a made up one
+ try {
+ b_p_2.addWithName("madeUpOne");
+ fail();
+ } catch(IllegalArgumentException e) {
+ // Good, as expected
+ }
+ }
+
+ /**
+ * Try to recreate an existing StyleTextPropAtom (a) from the empty
+ * constructor, and setting the required properties
+ */
+ public void testCreateAFromScatch() throws Exception {
+ // Start with an empty one
+ StyleTextPropAtom stpa = new StyleTextPropAtom(54);
+
+ // Don't need to touch the paragraph styles
+ // Add two more character styles
+ LinkedList cs = stpa.getCharacterStyles();
+
+ // First char style is boring, and 21 long
+ TextPropCollection tpca = (TextPropCollection)cs.get(0);
+ tpca.updateTextSize(21);
+
+ // Second char style is coloured, 00 00 00 05, and 17 long
+ TextPropCollection tpcb = stpa.addCharacterTextPropCollection(17);
+ TextProp tpb = tpcb.addWithName("font.color");
+ tpb.setValue(0x05000000);
+
+ // Third char style is coloured, FF 33 00 FE, and 16 long
+ TextPropCollection tpcc = stpa.addCharacterTextPropCollection(16);
+ TextProp tpc = tpcc.addWithName("font.color");
+ tpc.setValue(0xFE0033FF);
+
+ // Should now be the same as data_a
+ ByteArrayOutputStream baos = new ByteArrayOutputStream();
+ stpa.writeOut(baos);
+ byte[] b = baos.toByteArray();
+
+ assertEquals(data_a.length, b.length);
+ for(int i=0; i<data_a.length; i++) {
+ assertEquals(data_a[i],b[i]);
+ }
+ }
+
+ /**
+ * Try to recreate an existing StyleTextPropAtom (b) from the empty
+ * constructor, and setting the required properties
+ */
+ public void testCreateBFromScatch() throws Exception {
+ // Start with an empty one
+ StyleTextPropAtom stpa = new StyleTextPropAtom(data_b_text_len);
+
+
+ // Need 4 paragraph styles
+ LinkedList ps = stpa.getParagraphStyles();
+
+ // First is 30 long, left aligned, normal spacing
+ TextPropCollection tppa = (TextPropCollection)ps.get(0);
+ tppa.updateTextSize(30);
+
+ TextProp tp = tppa.addWithName("alignment");
+ tp.setValue(0);
+ tp = tppa.addWithName("linespacing");
+ tp.setValue(80);
+
+ // Second is 28 long, centre aligned and normal spacing
+ TextPropCollection tppb = stpa.addParagraphTextPropCollection(28);
+
+ tp = tppb.addWithName("linespacing");
+ tp.setValue(80);
+
+ // Third is 25 long, right aligned and normal spacing
+ TextPropCollection tppc = stpa.addParagraphTextPropCollection(25);
+
+ tp = tppc.addWithName("alignment");
+ tp.setValue(2);
+ tp = tppc.addWithName("linespacing");
+ tp.setValue(80);
+
+ // Forth is left aligned + normal line spacing (despite differing font)
+ TextPropCollection tppd = stpa.addParagraphTextPropCollection(97);
+
+ tp = tppd.addWithName("alignment");
+ tp.setValue(0);
+ tp = tppd.addWithName("linespacing");
+ tp.setValue(80);
+
+
+ // Now do 4 character styles
+ LinkedList cs = stpa.getCharacterStyles();
+
+ // First is 30 long, bold and font size
+ TextPropCollection tpca = (TextPropCollection)cs.get(0);
+ tpca.updateTextSize(30);
+
+ tp = tpca.addWithName("font.size");
+ tp.setValue(20);
+ CharFlagsTextProp cftp = (CharFlagsTextProp)
+ tpca.addWithName("char_flags");
+ assertEquals(0, cftp.getValue());
+ cftp.setSubValue(true, CharFlagsTextProp.BOLD_IDX);
+ assertEquals(1, cftp.getValue());
+
+ // Second is 28 long, blue and italic
+ TextPropCollection tpcb = stpa.addCharacterTextPropCollection(28);
+
+ tp = tpcb.addWithName("font.size");
+ tp.setValue(20);
+ tp = tpcb.addWithName("font.color");
+ tp.setValue(0x05000000);
+ cftp = (CharFlagsTextProp)tpcb.addWithName("char_flags");
+ cftp.setSubValue(true, CharFlagsTextProp.ITALIC_IDX);
+ assertEquals(2, cftp.getValue());
+
+ // Third is 25 long and red
+ TextPropCollection tpcc = stpa.addCharacterTextPropCollection(25);
+
+ tp = tpcc.addWithName("font.size");
+ tp.setValue(20);
+ tp = tpcc.addWithName("font.color");
+ tp.setValue(0xfe0033ff);
+
+ // Fourth is 96 long, underlined and different+bigger font
+ TextPropCollection tpcd = stpa.addCharacterTextPropCollection(96);
+
+ tp = tpcd.addWithName("font.size");
+ tp.setValue(24);
+ tp = tpcd.addWithName("font.index");
+ tp.setValue(1);
+ cftp = (CharFlagsTextProp)tpcd.addWithName("char_flags");
+ cftp.setSubValue(true, CharFlagsTextProp.UNDERLINE_IDX);
+ assertEquals(4, cftp.getValue());
+
+ // Fifth is 1 long, underlined and different+bigger font + red
+ TextPropCollection tpce = stpa.addCharacterTextPropCollection(1);
+
+ tp = tpce.addWithName("font.size");
+ tp.setValue(24);
+ tp = tpce.addWithName("font.index");
+ tp.setValue(1);
+ tp = tpce.addWithName("font.color");
+ tp.setValue(0xfe0033ff);
+ cftp = (CharFlagsTextProp)tpce.addWithName("char_flags");
+ cftp.setSubValue(true, CharFlagsTextProp.UNDERLINE_IDX);
+ assertEquals(4, cftp.getValue());
+
+
+ // Check it's as expected
+ assertEquals(4, stpa.getParagraphStyles().size());
+ assertEquals(5, stpa.getCharacterStyles().size());
+
+ // Compare in detail to b
+ StyleTextPropAtom stpb = new StyleTextPropAtom(data_b,0,data_b.length);
+ stpb.setParentTextSize(data_b_text_len);
+ LinkedList psb = stpb.getParagraphStyles();
+ LinkedList csb = stpb.getCharacterStyles();
+
+ assertEquals(psb.size(), ps.size());
+ assertEquals(csb.size(), cs.size());
+
+ // Ensure Paragraph Character styles match
+ for(int z=0; z<2; z++) {
+ LinkedList lla = cs;
+ LinkedList llb = csb;
+ int upto = 5;
+ if(z == 1) {
+ lla = ps;
+ llb = psb;
+ upto = 4;
+ }
+
+ for(int i=0; i<upto; i++) {
+ TextPropCollection ca = (TextPropCollection)lla.get(i);
+ TextPropCollection cb = (TextPropCollection)llb.get(i);
+
+ assertEquals(ca.getCharactersCovered(), cb.getCharactersCovered());
+ assertEquals(ca.getTextPropList().size(), cb.getTextPropList().size());
+
+ for(int j=0; j<ca.getTextPropList().size(); j++) {
+ TextProp tpa = (TextProp)ca.getTextPropList().get(j);
+ TextProp tpb = (TextProp)cb.getTextPropList().get(j);
+ //System.out.println("TP " + i + " " + j + " " + tpa.getName() + "\t" + tpa.getValue() );
+ assertEquals(tpa.getName(), tpb.getName());
+ assertEquals(tpa.getMask(), tpb.getMask());
+ assertEquals(tpa.getWriteMask(), tpb.getWriteMask());
+ assertEquals(tpa.getValue(), tpb.getValue());
+ }
+
+ ByteArrayOutputStream ba = new ByteArrayOutputStream();
+ ByteArrayOutputStream bb = new ByteArrayOutputStream();
+
+ ca.writeOut(ba);
+ cb.writeOut(bb);
+ byte[] cab = ba.toByteArray();
+ byte[] cbb = bb.toByteArray();
+
+ assertEquals(cbb.length, cab.length);
+ for(int j=0; j<cab.length; j++) {
+ //System.out.println("On tp " + z + " " + i + " " + j + "\t" + cab[j] + "\t" + cbb[j]);
+ assertEquals(cbb[j], cab[j]);
+ }
+ }
+ }
+
+
+
+ // Check byte level with b
+ ByteArrayOutputStream baos = new ByteArrayOutputStream();
+ stpa.writeOut(baos);
+ byte[] b = baos.toByteArray();
+
+ assertEquals(data_b.length, b.length);
+ for(int i=0; i<data_b.length; i++) {
+ //System.out.println(i + "\t" + b[i] + "\t" + data_b[i] + "\t" + Integer.toHexString(b[i]) );
+ assertEquals(data_b[i],b[i]);
+ }
+ }
+
+ public void testWriteA() throws Exception {
+ doReadWrite(data_a, -1);
+ }
+
+ public void testLoadWriteA() throws Exception {
+ doReadWrite(data_b, data_b_text_len);
+ }
+
+
+ public void testWriteB() throws Exception {
+ doReadWrite(data_b, -1);
+ }
+
+ public void testLoadWriteB() throws Exception {
+ doReadWrite(data_b, data_b_text_len);
+ }
+
+ public void testLoadWriteC() throws Exception {
+ doReadWrite(data_c, data_c_text_len);
+ }
+
+ public void testLoadWriteD() throws Exception {
+ doReadWrite(data_d, data_d_text_len);
+ }
+
+ protected void doReadWrite(byte[] data, int textlen) throws Exception {
+ StyleTextPropAtom stpb = new StyleTextPropAtom(data, 0,data.length);
+ if(textlen != -1) stpb.setParentTextSize(textlen);
+
+ ByteArrayOutputStream out = new ByteArrayOutputStream();
+ stpb.writeOut(out);
+ byte[] bytes = out.toByteArray();
+
+ assertEquals(data.length, bytes.length);
+ try {
+ assertTrue(Arrays.equals(data, bytes));
+ } catch (Throwable e){
+ //print hex dump if failed
+ assertEquals(HexDump.toHex(data), HexDump.toHex(bytes));
+ }
+ }
+
+ public void testNotEnoughDataProp() throws Exception {
+ // We don't have enough data in the record to cover
+ // all the properties the mask says we have
+ // Make sure we just do the best we can
+ StyleTextPropAtom stpc = new StyleTextPropAtom(data_c,0,data_c.length);
+ stpc.setParentTextSize(data_c_text_len);
+
+ // If we get here, we didn't break
+ }
/**
* Check the test data for Bug 40143.
assertEquals(1, chprops.findByName("char_flags").getValue());
assertEquals(1, chprops.findByName("font.index").getValue());
assertEquals(20, chprops.findByName("font.size").getValue());
- assertEquals(0, chprops.findByName("asian_or_complex").getValue());
- assertEquals(1, chprops.findByName("char_unknown_2").getValue());
+ assertEquals(0, chprops.findByName("asian.font.index").getValue());
+ assertEquals(1, chprops.findByName("ansi.font.index").getValue());
}
/**
0x00 , 0x00 , 0x13 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x63 , 0x00 ,
0x00 , 0x00 , 0x01 , 0x00 , 0x00 , 0x00 , 0x0F , 0x00
};
- StyleTextPropAtom stpa = new StyleTextPropAtom(data,0,data.length);
- stpa.setParentTextSize(length);
- ByteArrayOutputStream baos = new ByteArrayOutputStream();
- stpa.writeOut(baos);
- byte[] b = baos.toByteArray();
-
- assertEquals(data.length, b.length);
- for(int i=0; i<data.length; i++) {
- assertEquals(data[i],b[i]);
- }
+ doReadWrite(data, length);
}
}
import org.apache.poi.hssf.model.FormulaParser.FormulaParseException;
import org.apache.poi.hssf.record.formula.AbstractFunctionPtg;
import org.apache.poi.hssf.record.formula.AddPtg;
+import org.apache.poi.hssf.record.formula.AreaI;
import org.apache.poi.hssf.record.formula.AreaPtg;
import org.apache.poi.hssf.record.formula.AttrPtg;
import org.apache.poi.hssf.record.formula.BoolPtg;
}
cell.setCellFormula("count(fp1)"); // plain cell ref, col is in range
}
-}
+
+ public void testParseAreaRefHighRow_bug45358() {
+ Ptg[] ptgs;
+ AreaI aptg;
+
+ HSSFWorkbook book = new HSSFWorkbook();
+ book.createSheet("Sheet1");
+
+ ptgs = FormulaParser.parse("Sheet1!A10:A40000", book);
+ aptg = (AreaI) ptgs[0];
+ if (aptg.getLastRow() == -25537) {
+ throw new AssertionFailedError("Identified bug 45358");
+ }
+ assertEquals(39999, aptg.getLastRow());
+
+ ptgs = FormulaParser.parse("Sheet1!A10:A65536", book);
+ aptg = (AreaI) ptgs[0];
+ assertEquals(65535, aptg.getLastRow());
+
+ // plain area refs should be ok too
+ ptgs = parseFormula("A10:A65536");
+ aptg = (AreaI) ptgs[0];
+ assertEquals(65535, aptg.getLastRow());
+
+ }
+}
\ No newline at end of file
-
/* ====================================================================
Licensed to the Apache Software Foundation (ASF) under one or more
contributor license agreements. See the NOTICE file distributed with
See the License for the specific language governing permissions and
limitations under the License.
==================================================================== */
-
-
package org.apache.poi.hssf.record;
*
* @author Glen Stampoultzis (glens at apache.org)
*/
-public class TestLinkedDataRecord
- extends TestCase
-{
+public final class TestLinkedDataRecord extends TestCase {
/*
The records below are records that would appear in a simple bar chart
(byte)0x00,(byte)0x00, // index to last column and relative flags
};
- public TestLinkedDataRecord(String name)
- {
- super(name);
- }
-
- public void testLoad()
- throws Exception
- {
+ public void testLoad() {
LinkedDataRecord record = new LinkedDataRecord(new TestcaseRecordInputStream((short)0x1051, (short)data.length, data));
assertEquals( LinkedDataRecord.LINK_TYPE_VALUES, record.getLinkType());
assertEquals( false, record.isCustomNumberFormat() );
assertEquals( 0, record.getIndexNumberFmtRecord());
- Area3DPtg ptg = new Area3DPtg();
- ptg.setExternSheetIndex((short)0);
- ptg.setFirstColumn((short)0);
- ptg.setLastColumn((short)0);
- ptg.setFirstRow((short)0);
- ptg.setLastRow((short)7936);
- ptg.setFirstColRelative(false);
- ptg.setLastColRelative(false);
- ptg.setFirstRowRelative(false);
- ptg.setLastRowRelative(false);
- Stack s = new Stack();
- s.push(ptg);
- assertEquals( s, record.getFormulaOfLink().getFormulaTokens() );
+ Area3DPtg ptgExpected = new Area3DPtg(0, 7936, 0, 0,
+ false, false, false, false, 0);
+
+ Object ptgActual = record.getFormulaOfLink().getFormulaTokens().get(0);
+ assertEquals(ptgExpected.toString(), ptgActual.toString());
assertEquals( data.length + 4, record.getRecordSize() );
}
- public void testStore()
- {
+ public void testStore() {
LinkedDataRecord record = new LinkedDataRecord();
record.setLinkType( LinkedDataRecord.LINK_TYPE_VALUES );
record.setReferenceType( LinkedDataRecord.REFERENCE_TYPE_WORKSHEET );
record.setOptions( (short)0 );
record.setCustomNumberFormat( false );
record.setIndexNumberFmtRecord( (short)0 );
- Area3DPtg ptg = new Area3DPtg();
- ptg.setExternSheetIndex((short)0);
- ptg.setFirstColumn((short)0);
- ptg.setLastColumn((short)0);
- ptg.setFirstRow((short)0);
- ptg.setLastRow((short)7936);
- ptg.setFirstColRelative(false);
- ptg.setLastColRelative(false);
- ptg.setFirstRowRelative(false);
- ptg.setLastRowRelative(false);
+ Area3DPtg ptg = new Area3DPtg(0, 7936, 0, 0,
+ false, false, false, false, 0);
Stack s = new Stack();
s.push(ptg);
LinkedDataFormulaField formulaOfLink = new LinkedDataFormulaField();
import junit.framework.AssertionFailedError;
import junit.framework.TestCase;
-import org.apache.poi.hssf.record.formula.Area3DPtg;
+import org.apache.poi.hssf.record.formula.AreaPtg;
+import org.apache.poi.hssf.record.formula.functions.EvalFactory;
/**
* Tests for <tt>AreaEval</tt>
public final class TestAreaEval extends TestCase {
public void testGetValue_bug44950() {
-
- Area3DPtg ptg = new Area3DPtg("B2:D3", (short)0);
+ // TODO - this test probably isn't testing much anymore
+ AreaPtg ptg = new AreaPtg("B2:D3");
NumberEval one = new NumberEval(1);
ValueEval[] values = {
one,
new NumberEval(5),
new NumberEval(6),
};
- AreaEval ae = new Area3DEval(ptg, values);
+ AreaEval ae = EvalFactory.createAreaEval(ptg, values);
if (one == ae.getValueAt(1, 2)) {
throw new AssertionFailedError("Identified bug 44950 a");
}
package org.apache.poi.hssf.record.formula.eval;
+import junit.framework.TestCase;
+
import org.apache.poi.hssf.record.formula.AreaPtg;
import org.apache.poi.hssf.record.formula.UnaryPlusPtg;
+import org.apache.poi.hssf.record.formula.functions.EvalFactory;
import org.apache.poi.hssf.record.formula.functions.NumericFunctionInvoker;
-import junit.framework.TestCase;
-
/**
* Test for unary plus operator evaluator.
- *
+ *
* @author Josh Micich
*/
public final class TestUnaryPlusEval extends TestCase {
-
+
/**
* Test for bug observable at svn revision 618865 (5-Feb-2008)<br/>
- * The code for handling column operands had been copy-pasted from the row handling code.
+ * The code for handling column operands had been copy-pasted from the row handling code.
*/
public void testColumnOperand() {
short colNum = (short)5;
AreaPtg areaPtg = new AreaPtg(firstRow, lastRow, colNum, colNum, false, false, false, false);
ValueEval[] values = {
- new NumberEval(27),
- new NumberEval(29),
- new NumberEval(35), // value in row 10
- new NumberEval(37),
- new NumberEval(38),
+ new NumberEval(27),
+ new NumberEval(29),
+ new NumberEval(35), // value in row 10
+ new NumberEval(37),
+ new NumberEval(38),
};
- Eval areaEval = new Area2DEval(areaPtg, values);
- Eval[] args = {
- areaEval,
+ Eval[] args = {
+ EvalFactory.createAreaEval(areaPtg, values),
};
double result = NumericFunctionInvoker.invoke(new UnaryPlusEval(UnaryPlusPtg.instance), args, 10, (short)20);
See the License for the specific language governing permissions and
limitations under the License.
==================================================================== */
-
package org.apache.poi.hssf.record.formula.functions;
import org.apache.poi.hssf.record.formula.AreaPtg;
+import org.apache.poi.hssf.record.formula.Ref3DPtg;
import org.apache.poi.hssf.record.formula.RefPtg;
-import org.apache.poi.hssf.record.formula.eval.Area2DEval;
import org.apache.poi.hssf.record.formula.eval.AreaEval;
+import org.apache.poi.hssf.record.formula.eval.AreaEvalBase;
import org.apache.poi.hssf.record.formula.eval.NumberEval;
-import org.apache.poi.hssf.record.formula.eval.Ref2DEval;
import org.apache.poi.hssf.record.formula.eval.RefEval;
+import org.apache.poi.hssf.record.formula.eval.RefEvalBase;
import org.apache.poi.hssf.record.formula.eval.ValueEval;
/**
*
* @author Josh Micich
*/
-final class EvalFactory {
+public final class EvalFactory {
private EvalFactory() {
// no instances of this class
*/
public static AreaEval createAreaEval(String areaRefStr, ValueEval[] values) {
AreaPtg areaPtg = new AreaPtg(areaRefStr);
+ return createAreaEval(areaPtg, values);
+ }
+
+ /**
+ * Creates a dummy AreaEval
+ * @param values empty (<code>null</code>) entries in this array will be converted to NumberEval.ZERO
+ */
+ public static AreaEval createAreaEval(AreaPtg areaPtg, ValueEval[] values) {
int nCols = areaPtg.getLastColumn() - areaPtg.getFirstColumn() + 1;
int nRows = areaPtg.getLastRow() - areaPtg.getFirstRow() + 1;
int nExpected = nRows * nCols;
values[i] = NumberEval.ZERO;
}
}
- return new Area2DEval(areaPtg, values);
+ return new MockAreaEval(areaPtg, values);
}
/**
* Creates a single RefEval (with value zero)
*/
public static RefEval createRefEval(String refStr) {
- return new Ref2DEval(new RefPtg(refStr), NumberEval.ZERO);
+ return createRefEval(refStr, NumberEval.ZERO);
+ }
+ public static RefEval createRefEval(String refStr, ValueEval value) {
+ return new MockRefEval(new RefPtg(refStr), value);
+ }
+
+ private static final class MockAreaEval extends AreaEvalBase {
+ private final ValueEval[] _values;
+ public MockAreaEval(AreaPtg areaPtg, ValueEval[] values) {
+ super(areaPtg);
+ _values = values;
+ }
+ public ValueEval getRelativeValue(int relativeRowIndex, int relativeColumnIndex) {
+ if (relativeRowIndex < 0 || relativeRowIndex >=getHeight()) {
+ throw new IllegalArgumentException("row index out of range");
+ }
+ int width = getWidth();
+ if (relativeColumnIndex < 0 || relativeColumnIndex >=width) {
+ throw new IllegalArgumentException("column index out of range");
+ }
+ int oneDimensionalIndex = relativeRowIndex * width + relativeColumnIndex;
+ return _values[oneDimensionalIndex];
+ }
+ public AreaEval offset(int relFirstRowIx, int relLastRowIx, int relFirstColIx, int relLastColIx) {
+ throw new RuntimeException("Operation not implemented on this mock object");
+ }
+ }
+
+ private static final class MockRefEval extends RefEvalBase {
+ private final ValueEval _value;
+ public MockRefEval(RefPtg ptg, ValueEval value) {
+ super(ptg.getRow(), ptg.getColumn());
+ _value = value;
+ }
+ public MockRefEval(Ref3DPtg ptg, ValueEval value) {
+ super(ptg.getRow(), ptg.getColumn());
+ _value = value;
+ }
+ public ValueEval getInnerValueEval() {
+ return _value;
+ }
+ public AreaEval offset(int relFirstRowIx, int relLastRowIx, int relFirstColIx, int relLastColIx) {
+ throw new RuntimeException("Operation not implemented on this mock object");
+ }
}
+
}
import junit.framework.TestCase;
import org.apache.poi.hssf.HSSFTestDataSamples;
-import org.apache.poi.hssf.record.formula.AreaPtg;
import org.apache.poi.hssf.record.formula.RefPtg;
-import org.apache.poi.hssf.record.formula.eval.Area2DEval;
import org.apache.poi.hssf.record.formula.eval.AreaEval;
import org.apache.poi.hssf.record.formula.eval.BlankEval;
import org.apache.poi.hssf.record.formula.eval.BoolEval;
BoolEval.TRUE,
BlankEval.INSTANCE,
};
- range = createAreaEval("A1:B3", values);
+ range = EvalFactory.createAreaEval("A1:B3", values);
confirmCountIf(2, range, BoolEval.TRUE);
// when criteria is numeric
new NumberEval(2),
BoolEval.TRUE,
};
- range = createAreaEval("A1:B3", values);
+ range = EvalFactory.createAreaEval("A1:B3", values);
confirmCountIf(3, range, new NumberEval(2));
// note - same results when criteria is a string that parses as the number with the same value
confirmCountIf(3, range, new StringEval("2.00"));
new NumberEval(25),
new NumberEval(25),
};
- Area2DEval arg0 = new Area2DEval(new AreaPtg("C1:C6"), values);
+ AreaEval arg0 = EvalFactory.createAreaEval("C1:C6", values);
- Ref2DEval criteriaArg = new Ref2DEval(new RefPtg("A1"), new NumberEval(25));
+ ValueEval criteriaArg = EvalFactory.createRefEval("A1", new NumberEval(25));
Eval[] args= { arg0, criteriaArg, };
double actual = NumericFunctionInvoker.invoke(new Countif(), args);
assertEquals(4, actual, 0D);
}
-
- private static AreaEval createAreaEval(String areaRefStr, ValueEval[] values) {
- return new Area2DEval(new AreaPtg(areaRefStr), values);
- }
-
private static void confirmCountA(int expected, Eval[] args) {
double result = NumericFunctionInvoker.invoke(new Counta(), args);
assertEquals(expected, result, 0);
import junit.framework.TestCase;
-import org.apache.poi.hssf.record.formula.AreaPtg;
-import org.apache.poi.hssf.record.formula.eval.Area2DEval;
+import org.apache.poi.hssf.record.formula.eval.AreaEval;
import org.apache.poi.hssf.record.formula.eval.Eval;
import org.apache.poi.hssf.record.formula.eval.NumberEval;
import org.apache.poi.hssf.record.formula.eval.ValueEval;
for (int i = 0; i < values.length; i++) {
values[i] = new NumberEval(dValues[i]);
}
- Area2DEval arg0 = new Area2DEval(new AreaPtg(areaRefString), values);
+ AreaEval arg0 = EvalFactory.createAreaEval(areaRefString, values);
Eval[] args;
if (colNum > 0) {
import junit.framework.TestCase;
-import org.apache.poi.hssf.record.formula.AreaPtg;
-import org.apache.poi.hssf.record.formula.eval.Area2DEval;
import org.apache.poi.hssf.record.formula.eval.AreaEval;
import org.apache.poi.hssf.record.formula.eval.BoolEval;
import org.apache.poi.hssf.record.formula.eval.ErrorEval;
/**
* Test cases for MATCH()
- *
+ *
* @author Josh Micich
*/
public final class TestMatch extends TestCase {
private static final NumberEval MATCH_EXACT = new NumberEval(0);
/** greater than or equal to */
private static final NumberEval MATCH_SMALLEST_GTE = new NumberEval(-1);
-
-
+
+
private static Eval invokeMatch(Eval lookup_value, Eval lookup_array, Eval match_type) {
Eval[] args = { lookup_value, lookup_array, match_type, };
return new Match().evaluate(args, -1, (short)-1);
NumericValueEval nve = (NumericValueEval)actualEval;
assertEquals(expected, nve.getNumberValue(), 0);
}
- /**
- * Convenience method
- * @return <code>new Area2DEval(new AreaPtg(ref), values)</code>
- */
- private static AreaEval createAreaEval(String ref, ValueEval[] values) {
- return new Area2DEval(new AreaPtg(ref), values);
- }
-
+
public void testSimpleNumber() {
-
+
ValueEval[] values = {
- new NumberEval(4),
- new NumberEval(5),
- new NumberEval(10),
- new NumberEval(10),
- new NumberEval(25),
+ new NumberEval(4),
+ new NumberEval(5),
+ new NumberEval(10),
+ new NumberEval(10),
+ new NumberEval(25),
};
-
- AreaEval ae = createAreaEval("A1:A5", values);
-
+
+ AreaEval ae = EvalFactory.createAreaEval("A1:A5", values);
+
confirmInt(2, invokeMatch(new NumberEval(5), ae, MATCH_LARGEST_LTE));
confirmInt(2, invokeMatch(new NumberEval(5), ae, MATCH_EXACT));
confirmInt(4, invokeMatch(new NumberEval(10), ae, MATCH_LARGEST_LTE));
confirmInt(4, invokeMatch(new NumberEval(20), ae, MATCH_LARGEST_LTE));
assertEquals(ErrorEval.NA, invokeMatch(new NumberEval(20), ae, MATCH_EXACT));
}
-
+
public void testReversedNumber() {
-
+
ValueEval[] values = {
- new NumberEval(25),
- new NumberEval(10),
- new NumberEval(10),
- new NumberEval(10),
- new NumberEval(4),
+ new NumberEval(25),
+ new NumberEval(10),
+ new NumberEval(10),
+ new NumberEval(10),
+ new NumberEval(4),
};
-
- AreaEval ae = createAreaEval("A1:A5", values);
-
+
+ AreaEval ae = EvalFactory.createAreaEval("A1:A5", values);
+
confirmInt(2, invokeMatch(new NumberEval(10), ae, MATCH_SMALLEST_GTE));
confirmInt(2, invokeMatch(new NumberEval(10), ae, MATCH_EXACT));
confirmInt(4, invokeMatch(new NumberEval(9), ae, MATCH_SMALLEST_GTE));
assertEquals(ErrorEval.NA, invokeMatch(new NumberEval(20), ae, MATCH_EXACT));
assertEquals(ErrorEval.NA, invokeMatch(new NumberEval(26), ae, MATCH_SMALLEST_GTE));
}
-
+
public void testSimpleString() {
-
+
ValueEval[] values = {
- new StringEval("Albert"),
- new StringEval("Charles"),
- new StringEval("Ed"),
- new StringEval("Greg"),
- new StringEval("Ian"),
+ new StringEval("Albert"),
+ new StringEval("Charles"),
+ new StringEval("Ed"),
+ new StringEval("Greg"),
+ new StringEval("Ian"),
};
-
- AreaEval ae = createAreaEval("A1:A5", values);
-
+
+ AreaEval ae = EvalFactory.createAreaEval("A1:A5", values);
+
// Note String comparisons are case insensitive
confirmInt(3, invokeMatch(new StringEval("Ed"), ae, MATCH_LARGEST_LTE));
confirmInt(3, invokeMatch(new StringEval("eD"), ae, MATCH_LARGEST_LTE));
confirmInt(4, invokeMatch(new StringEval("Hugh"), ae, MATCH_LARGEST_LTE));
assertEquals(ErrorEval.NA, invokeMatch(new StringEval("Hugh"), ae, MATCH_EXACT));
}
-
+
public void testSimpleBoolean() {
-
+
ValueEval[] values = {
- BoolEval.FALSE,
- BoolEval.FALSE,
- BoolEval.TRUE,
- BoolEval.TRUE,
+ BoolEval.FALSE,
+ BoolEval.FALSE,
+ BoolEval.TRUE,
+ BoolEval.TRUE,
};
-
- AreaEval ae = createAreaEval("A1:A4", values);
-
+
+ AreaEval ae = EvalFactory.createAreaEval("A1:A4", values);
+
// Note String comparisons are case insensitive
confirmInt(2, invokeMatch(BoolEval.FALSE, ae, MATCH_LARGEST_LTE));
confirmInt(1, invokeMatch(BoolEval.FALSE, ae, MATCH_EXACT));
confirmInt(4, invokeMatch(BoolEval.TRUE, ae, MATCH_LARGEST_LTE));
confirmInt(3, invokeMatch(BoolEval.TRUE, ae, MATCH_EXACT));
}
-
+
public void testHeterogeneous() {
-
+
ValueEval[] values = {
- new NumberEval(4),
- BoolEval.FALSE,
+ new NumberEval(4),
+ BoolEval.FALSE,
new NumberEval(5),
- new StringEval("Albert"),
- BoolEval.FALSE,
- BoolEval.TRUE,
- new NumberEval(10),
- new StringEval("Charles"),
- new StringEval("Ed"),
- new NumberEval(10),
- new NumberEval(25),
- BoolEval.TRUE,
- new StringEval("Ed"),
+ new StringEval("Albert"),
+ BoolEval.FALSE,
+ BoolEval.TRUE,
+ new NumberEval(10),
+ new StringEval("Charles"),
+ new StringEval("Ed"),
+ new NumberEval(10),
+ new NumberEval(25),
+ BoolEval.TRUE,
+ new StringEval("Ed"),
};
-
- AreaEval ae = createAreaEval("A1:A13", values);
-
+
+ AreaEval ae = EvalFactory.createAreaEval("A1:A13", values);
+
assertEquals(ErrorEval.NA, invokeMatch(new StringEval("Aaron"), ae, MATCH_LARGEST_LTE));
-
+
confirmInt(5, invokeMatch(BoolEval.FALSE, ae, MATCH_LARGEST_LTE));
confirmInt(2, invokeMatch(BoolEval.FALSE, ae, MATCH_EXACT));
confirmInt(3, invokeMatch(new NumberEval(5), ae, MATCH_LARGEST_LTE));
confirmInt(3, invokeMatch(new NumberEval(5), ae, MATCH_EXACT));
-
+
confirmInt(8, invokeMatch(new StringEval("CHARLES"), ae, MATCH_EXACT));
-
+
confirmInt(4, invokeMatch(new StringEval("Ben"), ae, MATCH_LARGEST_LTE));
-
+
confirmInt(13, invokeMatch(new StringEval("ED"), ae, MATCH_LARGEST_LTE));
confirmInt(9, invokeMatch(new StringEval("ED"), ae, MATCH_EXACT));
-
+
confirmInt(13, invokeMatch(new StringEval("Hugh"), ae, MATCH_LARGEST_LTE));
assertEquals(ErrorEval.NA, invokeMatch(new StringEval("Hugh"), ae, MATCH_EXACT));
-
+
confirmInt(11, invokeMatch(new NumberEval(30), ae, MATCH_LARGEST_LTE));
confirmInt(12, invokeMatch(BoolEval.TRUE, ae, MATCH_LARGEST_LTE));
}
-
+
/**
* Ensures that the match_type argument can be an <tt>AreaEval</tt>.<br/>
* Bugzilla 44421
*/
public void testMatchArgTypeArea() {
-
+
ValueEval[] values = {
- new NumberEval(4),
- new NumberEval(5),
- new NumberEval(10),
- new NumberEval(10),
- new NumberEval(25),
+ new NumberEval(4),
+ new NumberEval(5),
+ new NumberEval(10),
+ new NumberEval(10),
+ new NumberEval(25),
};
-
- AreaEval ae = createAreaEval("A1:A5", values);
- AreaEval matchAE = createAreaEval("C1:C1", new ValueEval[] { MATCH_LARGEST_LTE, });
-
+ AreaEval ae = EvalFactory.createAreaEval("A1:A5", values);
+
+ AreaEval matchAE = EvalFactory.createAreaEval("C1:C1", new ValueEval[] { MATCH_LARGEST_LTE, });
+
try {
confirmInt(4, invokeMatch(new NumberEval(10), ae, matchAE));
} catch (RuntimeException e) {
if(e.getMessage().startsWith("Unexpected match_type type")) {
- // identified bug 44421
+ // identified bug 44421
fail(e.getMessage());
}
// some other error ??
*/
package org.apache.poi.hssf.record.formula.functions;
+import org.apache.poi.hssf.record.formula.functions.XYNumericFunction.Accumulator;
+
/**
* @author Amol S. Deshmukh < amolweb at ya hoo dot com >
}
public void testSumx2my2() {
- double d = 0;
double[] xarr = null;
double[] yarr = null;
xarr = new double[]{1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
yarr = new double[]{0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
- d = MathX.sumx2my2(xarr, yarr);
- assertEquals("sumx2my2 ", 100, d);
+ confirmSumx2my2(xarr, yarr, 100);
xarr = new double[]{-1, -2, -3, -4, -5, -6, -7, -8, -9, -10};
yarr = new double[]{0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
- d = MathX.sumx2my2(xarr, yarr);
- assertEquals("sumx2my2 ", 100, d);
+ confirmSumx2my2(xarr, yarr, 100);
xarr = new double[]{0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
yarr = new double[]{1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
- d = MathX.sumx2my2(xarr, yarr);
- assertEquals("sumx2my2 ", -100, d);
+ confirmSumx2my2(xarr, yarr, -100);
xarr = new double[]{10};
yarr = new double[]{9};
- d = MathX.sumx2my2(xarr, yarr);
- assertEquals("sumx2my2 ", 19, d);
+ confirmSumx2my2(xarr, yarr, 19);
xarr = new double[]{1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
yarr = new double[]{1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
- d = MathX.sumx2my2(xarr, yarr);
- assertEquals("sumx2my2 ", 0, d);
-
+ confirmSumx2my2(xarr, yarr, 0);
}
public void testSumx2py2() {
- double d = 0;
double[] xarr = null;
double[] yarr = null;
xarr = new double[]{1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
yarr = new double[]{0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
- d = MathX.sumx2py2(xarr, yarr);
- assertEquals("sumx2py2 ", 670, d);
+ confirmSumx2py2(xarr, yarr, 670);
xarr = new double[]{-1, -2, -3, -4, -5, -6, -7, -8, -9, -10};
yarr = new double[]{0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
- d = MathX.sumx2py2(xarr, yarr);
- assertEquals("sumx2py2 ", 670, d);
+ confirmSumx2py2(xarr, yarr, 670);
xarr = new double[]{0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
yarr = new double[]{1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
- d = MathX.sumx2py2(xarr, yarr);
- assertEquals("sumx2py2 ", 670, d);
+ confirmSumx2py2(xarr, yarr, 670);
xarr = new double[]{10};
yarr = new double[]{9};
- d = MathX.sumx2py2(xarr, yarr);
- assertEquals("sumx2py2 ", 181, d);
+ confirmSumx2py2(xarr, yarr, 181);
xarr = new double[]{1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
yarr = new double[]{1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
- d = MathX.sumx2py2(xarr, yarr);
- assertEquals("sumx2py2 ", 770, d);
+ confirmSumx2py2(xarr, yarr, 770);
}
public void testSumxmy2() {
- double d = 0;
double[] xarr = null;
double[] yarr = null;
xarr = new double[]{1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
yarr = new double[]{0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
- d = MathX.sumxmy2(xarr, yarr);
- assertEquals("sumxmy2 ", 10, d);
+ confirmSumxmy2(xarr, yarr, 10);
xarr = new double[]{-1, -2, -3, -4, -5, -6, -7, -8, -9, -10};
yarr = new double[]{0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
- d = MathX.sumxmy2(xarr, yarr);
- assertEquals("sumxmy2 ", 1330, d);
+ confirmSumxmy2(xarr, yarr, 1330);
xarr = new double[]{0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
yarr = new double[]{1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
- d = MathX.sumxmy2(xarr, yarr);
- assertEquals("sumxmy2 ", 10, d);
+ confirmSumxmy2(xarr, yarr, 10);
xarr = new double[]{10};
yarr = new double[]{9};
- d = MathX.sumxmy2(xarr, yarr);
- assertEquals("sumxmy2 ", 1, d);
+ confirmSumxmy2(xarr, yarr, 1);
xarr = new double[]{1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
yarr = new double[]{1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
- d = MathX.sumxmy2(xarr, yarr);
- assertEquals("sumxmy2 ", 0, d);
+ confirmSumxmy2(xarr, yarr, 0);
}
+ private static void confirmSumx2my2(double[] xarr, double[] yarr, double expectedResult) {
+ confirmXY(new Sumx2my2().createAccumulator(), xarr, yarr, expectedResult);
+ }
+ private static void confirmSumx2py2(double[] xarr, double[] yarr, double expectedResult) {
+ confirmXY(new Sumx2py2().createAccumulator(), xarr, yarr, expectedResult);
+ }
+ private static void confirmSumxmy2(double[] xarr, double[] yarr, double expectedResult) {
+ confirmXY(new Sumxmy2().createAccumulator(), xarr, yarr, expectedResult);
+ }
+
+ private static void confirmXY(Accumulator acc, double[] xarr, double[] yarr,
+ double expectedResult) {
+ double result = 0.0;
+ for (int i = 0; i < xarr.length; i++) {
+ result += acc.accumulate(xarr[i], yarr[i]);
+ }
+ assertEquals(expectedResult, result, 0.0);
+ }
+
public void testRound() {
double d = 0;
int p = 0;
package org.apache.poi.hssf.record.formula.functions;
-import org.apache.poi.hssf.record.formula.AreaPtg;
-import org.apache.poi.hssf.record.formula.RefPtg;
-import org.apache.poi.hssf.record.formula.eval.Area2DEval;
+import junit.framework.TestCase;
+
import org.apache.poi.hssf.record.formula.eval.AreaEval;
import org.apache.poi.hssf.record.formula.eval.BlankEval;
import org.apache.poi.hssf.record.formula.eval.BoolEval;
import org.apache.poi.hssf.record.formula.eval.ErrorEval;
import org.apache.poi.hssf.record.formula.eval.Eval;
import org.apache.poi.hssf.record.formula.eval.NumberEval;
-import org.apache.poi.hssf.record.formula.eval.Ref2DEval;
import org.apache.poi.hssf.record.formula.eval.RefEval;
import org.apache.poi.hssf.record.formula.eval.StringEval;
import org.apache.poi.hssf.record.formula.eval.ValueEval;
-
-import junit.framework.TestCase;
/**
* Tests for Excel function MID()
- *
+ *
* @author Josh Micich
*/
public final class TestMid extends TestCase {
-
+
private static Eval invokeMid(Eval text, Eval startPos, Eval numChars) {
Eval[] args = new Eval[] { text, startPos, numChars, };
return new Mid().evaluate(args, -1, (short)-1);
assertEquals(ErrorEval.class, result.getClass());
assertEquals(expectedError.getErrorCode(), ((ErrorEval)result).getErrorCode());
}
-
+
public void testBasic() {
-
+
confirmMid(new StringEval("galactic"), new NumberEval(3), new NumberEval(4), "lact");
}
-
+
/**
* Valid cases where args are not precisely (string, int, int) but can be resolved OK.
*/
public void testUnusualArgs() {
// startPos with fractional digits
confirmMid(new StringEval("galactic"), new NumberEval(3.1), new NumberEval(4), "lact");
-
+
// string startPos
confirmMid(new StringEval("galactic"), new StringEval("3"), new NumberEval(4), "lact");
-
- // text (first) arg type is number, other args are strings with fractional digits
+
+ // text (first) arg type is number, other args are strings with fractional digits
confirmMid(new NumberEval(123456), new StringEval("3.1"), new StringEval("2.9"), "34");
-
+
// startPos is 1x1 area ref, numChars is cell ref
- AreaEval aeStart = new Area2DEval(new AreaPtg("A1:A1"), new ValueEval[] { new NumberEval(2), } );
- RefEval reNumChars = new Ref2DEval(new RefPtg("B1"), new NumberEval(3));
+ AreaEval aeStart = EvalFactory.createAreaEval("A1:A1", new ValueEval[] { new NumberEval(2), } );
+ RefEval reNumChars = EvalFactory.createRefEval("B1", new NumberEval(3));
confirmMid(new StringEval("galactic"), aeStart, reNumChars, "ala");
confirmMid(new StringEval("galactic"), new NumberEval(3.1), BlankEval.INSTANCE, "");
confirmMid(new StringEval("galactic"), new NumberEval(3), BoolEval.FALSE, "");
confirmMid(new StringEval("galactic"), new NumberEval(3), BoolEval.TRUE, "l");
confirmMid(BlankEval.INSTANCE, new NumberEval(3), BoolEval.TRUE, "");
-
+
}
/**
*/
public void testExtremes() {
confirmMid(new StringEval("galactic"), new NumberEval(4), new NumberEval(400), "actic");
-
+
confirmMid(new StringEval("galactic"), new NumberEval(30), new NumberEval(4), "");
confirmMid(new StringEval("galactic"), new NumberEval(3), new NumberEval(0), "");
}
confirmMid(new StringEval("galactic"), ErrorEval.NAME_INVALID, new NumberEval(4), ErrorEval.NAME_INVALID);
confirmMid(new StringEval("galactic"), new NumberEval(3), ErrorEval.NAME_INVALID, ErrorEval.NAME_INVALID);
confirmMid(new StringEval("galactic"), ErrorEval.DIV_ZERO, ErrorEval.NAME_INVALID, ErrorEval.DIV_ZERO);
-
+
confirmMid(new StringEval("galactic"), BlankEval.INSTANCE, new NumberEval(3.1), ErrorEval.VALUE_INVALID);
-
+
confirmMid(new StringEval("galactic"), new NumberEval(0), new NumberEval(4), ErrorEval.VALUE_INVALID);
confirmMid(new StringEval("galactic"), new NumberEval(1), new NumberEval(-1), ErrorEval.VALUE_INVALID);
}
package org.apache.poi.hssf.record.formula.functions;
-import org.apache.poi.hssf.record.formula.RefPtg;
+import junit.framework.TestCase;
+
import org.apache.poi.hssf.record.formula.eval.AreaEval;
import org.apache.poi.hssf.record.formula.eval.ErrorEval;
import org.apache.poi.hssf.record.formula.eval.Eval;
import org.apache.poi.hssf.record.formula.eval.NumberEval;
import org.apache.poi.hssf.record.formula.eval.NumericValueEval;
-import org.apache.poi.hssf.record.formula.eval.Ref2DEval;
import org.apache.poi.hssf.record.formula.eval.RefEval;
import org.apache.poi.hssf.record.formula.eval.ValueEval;
-import junit.framework.TestCase;
-
/**
* Test cases for SUMPRODUCT()
*
public void testScalarSimple() {
- RefEval refEval = new Ref2DEval(new RefPtg("A1"), new NumberEval(3));
+ RefEval refEval = EvalFactory.createRefEval("A1", new NumberEval(3));
Eval[] args = {
refEval,
new NumberEval(2),
};
AreaEval aeA = EvalFactory.createAreaEval("A1:A2", aValues);
AreaEval aeB = EvalFactory.createAreaEval("B1:B2", new ValueEval[2]);
- aeB.getValues()[1] = ErrorEval.REF_INVALID;
Eval[] args = { aeA, aeB, };
assertEquals(ErrorEval.REF_INVALID, invokeSumproduct(args));
package org.apache.poi.hssf.record.formula.functions;
-import org.apache.poi.hssf.record.formula.RefPtg;
+import junit.framework.TestCase;
+
import org.apache.poi.hssf.record.formula.eval.BlankEval;
import org.apache.poi.hssf.record.formula.eval.BoolEval;
import org.apache.poi.hssf.record.formula.eval.ErrorEval;
import org.apache.poi.hssf.record.formula.eval.Eval;
import org.apache.poi.hssf.record.formula.eval.NumberEval;
-import org.apache.poi.hssf.record.formula.eval.Ref2DEval;
import org.apache.poi.hssf.record.formula.eval.StringEval;
import org.apache.poi.hssf.record.formula.eval.ValueEval;
-import junit.framework.TestCase;
-
/**
* Test cases for Excel function T()
*
* where cell A1 has the specified innerValue
*/
private Eval invokeTWithReference(ValueEval innerValue) {
- Eval arg = new Ref2DEval(new RefPtg((short)1, (short)1, false, false), innerValue);
+ Eval arg = EvalFactory.createRefEval("$B$2", innerValue);
return invokeT(arg);
}
import junit.framework.TestCase;
-import org.apache.poi.hssf.record.formula.AreaPtg;
-import org.apache.poi.hssf.record.formula.eval.Area2DEval;
import org.apache.poi.hssf.record.formula.eval.ErrorEval;
import org.apache.poi.hssf.record.formula.eval.Eval;
import org.apache.poi.hssf.record.formula.eval.NumberEval;
private static ValueEval createAreaEval(ValueEval[] values) {
String refStr = "A1:A" + values.length;
- return new Area2DEval(new AreaPtg(refStr), values);
+ return EvalFactory.createAreaEval(refStr, values);
}
public void testErrors() {
import junit.framework.TestCase;
import org.apache.poi.hssf.HSSFTestDataSamples;
-import org.apache.poi.hssf.util.AreaReference;
-import org.apache.poi.hssf.util.CellReference;
+import org.apache.poi.ss.util.AreaReference;
+import org.apache.poi.ss.util.CellReference;
/**
*
import org.apache.poi.hssf.usermodel.HSSFRow;
import org.apache.poi.hssf.usermodel.HSSFSheet;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
+import org.apache.poi.ss.util.AreaReference;
+import org.apache.poi.ss.util.CellReference;
/**
*
*/
import junit.framework.TestCase;
-import org.apache.poi.hssf.util.CellReference.NameType;
+import org.apache.poi.ss.util.CellReference;
+import org.apache.poi.ss.util.CellReference.NameType;
public final class TestCellReference extends TestCase {