You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@poi.apache.org by ni...@apache.org on 2008/09/13 15:48:31 UTC

svn commit: r694947 [2/6] - in /poi/branches/ooxml: ./ src/documentation/content/xdocs/ src/java/org/apache/poi/hssf/extractor/ src/java/org/apache/poi/hssf/model/ src/java/org/apache/poi/hssf/record/ src/java/org/apache/poi/hssf/record/aggregates/ src...

Modified: poi/branches/ooxml/src/java/org/apache/poi/hssf/record/aggregates/ColumnInfoRecordsAggregate.java
URL: http://svn.apache.org/viewvc/poi/branches/ooxml/src/java/org/apache/poi/hssf/record/aggregates/ColumnInfoRecordsAggregate.java?rev=694947&r1=694946&r2=694947&view=diff
==============================================================================
--- poi/branches/ooxml/src/java/org/apache/poi/hssf/record/aggregates/ColumnInfoRecordsAggregate.java (original)
+++ poi/branches/ooxml/src/java/org/apache/poi/hssf/record/aggregates/ColumnInfoRecordsAggregate.java Sat Sep 13 06:48:27 2008
@@ -18,18 +18,35 @@
 package org.apache.poi.hssf.record.aggregates;
 
 import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Comparator;
 import java.util.List;
 
 import org.apache.poi.hssf.model.RecordStream;
 import org.apache.poi.hssf.record.ColumnInfoRecord;
-import org.apache.poi.hssf.record.Record;
 
 /**
  * @author Glen Stampoultzis
- * @version $Id$
  */
 public final class ColumnInfoRecordsAggregate extends RecordAggregate {
+	/**
+	 * List of {@link ColumnInfoRecord}s assumed to be in order 
+	 */
 	private final List records;
+	
+	
+	private static final class CIRComparator implements Comparator {
+		public static final Comparator instance = new CIRComparator();
+		private CIRComparator() {
+			// enforce singleton
+		}
+		public int compare(Object a, Object b) {
+			return compareColInfos((ColumnInfoRecord)a, (ColumnInfoRecord)b);
+		}
+		public static int compareColInfos(ColumnInfoRecord a, ColumnInfoRecord b) {
+			return a.getFirstColumn()-b.getFirstColumn();
+		}
+	}
 
 	/**
 	 * Creates an empty aggregate
@@ -37,486 +54,470 @@
 	public ColumnInfoRecordsAggregate() {
 		records = new ArrayList();
 	}
-    public ColumnInfoRecordsAggregate(RecordStream rs) {
-        this();
-        
-        while(rs.peekNextClass() == ColumnInfoRecord.class) {
-        	records.add(rs.getNext());
-        }
-        if (records.size() < 1) {
-        	throw new RuntimeException("No column info records found");
-        }
-   }
-
-    /**
-     * Performs a deep clone of the record
-     */
-    public Object clone()
-    {
-        ColumnInfoRecordsAggregate rec = new ColumnInfoRecordsAggregate();
-        for (int k = 0; k < records.size(); k++)
-        {
-            ColumnInfoRecord ci = ( ColumnInfoRecord ) records.get(k);
-            ci=(ColumnInfoRecord) ci.clone();
-            rec.insertColumn( ci );
-        }
-        return rec;
-    }
-
-    /**
-     * Inserts a column into the aggregate (at the end of the list).
-     */
-    public void insertColumn( ColumnInfoRecord col )
-    {
-        records.add( col );
-    }
-
-    /**
-     * Inserts a column into the aggregate (at the position specified
-     * by <code>idx</code>.
-     */
-    public void insertColumn( int idx, ColumnInfoRecord col )
-    {
-        records.add( idx, col );
-    }
-
-    public int getNumColumns( )
-    {
-        return records.size();
-    }
-
-    public void visitContainedRecords(RecordVisitor rv) {
-    	int nItems = records.size();
-    	if (nItems < 1) {
-    		return;
-    	}
-    	for(int i=0; i<nItems; i++) {
-    		rv.visitRecord((Record)records.get(i));
-    	}
-    }
-
-    public int findStartOfColumnOutlineGroup(int idx)
-    {
-        // Find the start of the group.
-        ColumnInfoRecord columnInfo = (ColumnInfoRecord) records.get( idx );
-        int level = columnInfo.getOutlineLevel();
-        while (idx != 0)
-        {
-            ColumnInfoRecord prevColumnInfo = (ColumnInfoRecord) records.get( idx - 1 );
-            if (columnInfo.getFirstColumn() - 1 == prevColumnInfo.getLastColumn())
-            {
-                if (prevColumnInfo.getOutlineLevel() < level)
-                {
-                    break;
-                }
-                idx--;
-                columnInfo = prevColumnInfo;
-            }
-            else
-            {
-                break;
-            }
-        }
-
-        return idx;
-    }
-
-    public int findEndOfColumnOutlineGroup(int idx)
-    {
-        // Find the end of the group.
-        ColumnInfoRecord columnInfo = (ColumnInfoRecord) records.get( idx );
-        int level = columnInfo.getOutlineLevel();
-        while (idx < records.size() - 1)
-        {
-            ColumnInfoRecord nextColumnInfo = (ColumnInfoRecord) records.get( idx + 1 );
-            if (columnInfo.getLastColumn() + 1 == nextColumnInfo.getFirstColumn())
-            {
-                if (nextColumnInfo.getOutlineLevel() < level)
-                {
-                    break;
-                }
-                idx++;
-                columnInfo = nextColumnInfo;
-            }
-            else
-            {
-                break;
-            }
-        }
-
-        return idx;
-    }
-
-    private ColumnInfoRecord getColInfo(int idx) {
-        return (ColumnInfoRecord) records.get( idx );
-    }
-
-    public ColumnInfoRecord writeHidden( ColumnInfoRecord columnInfo, int idx, boolean hidden )
-    {
-        int level = columnInfo.getOutlineLevel();
-        while (idx < records.size())
-        {
-            columnInfo.setHidden( hidden );
-            if (idx + 1 < records.size())
-            {
-                ColumnInfoRecord nextColumnInfo = getColInfo(idx + 1);
-                if (columnInfo.getLastColumn() + 1 == nextColumnInfo.getFirstColumn())
-                {
-                    if (nextColumnInfo.getOutlineLevel() < level)
-                        break;
-                    columnInfo = nextColumnInfo;
-                }
-                else
-                {
-                    break;
-                }
-            }
-            idx++;
-        }
-        return columnInfo;
-    }
-
-    public boolean isColumnGroupCollapsed( int idx )
-    {
-        int endOfOutlineGroupIdx = findEndOfColumnOutlineGroup( idx );
-        if (endOfOutlineGroupIdx >= records.size())
-            return false;
-        if (getColInfo(endOfOutlineGroupIdx).getLastColumn() + 1 != getColInfo(endOfOutlineGroupIdx + 1).getFirstColumn())
-            return false;
-        else
-            return getColInfo(endOfOutlineGroupIdx+1).getCollapsed();
-    }
-
-
-    public boolean isColumnGroupHiddenByParent( int idx )
-    {
-        // Look out outline details of end
-        int endLevel;
-        boolean endHidden;
-        int endOfOutlineGroupIdx = findEndOfColumnOutlineGroup( idx );
-        if (endOfOutlineGroupIdx >= records.size())
-        {
-            endLevel = 0;
-            endHidden = false;
-        }
-        else if (getColInfo(endOfOutlineGroupIdx).getLastColumn() + 1 != getColInfo(endOfOutlineGroupIdx + 1).getFirstColumn())
-        {
-            endLevel = 0;
-            endHidden = false;
-        }
-        else
-        {
-            endLevel = getColInfo( endOfOutlineGroupIdx + 1).getOutlineLevel();
-            endHidden = getColInfo( endOfOutlineGroupIdx + 1).getHidden();
-        }
-
-        // Look out outline details of start
-        int startLevel;
-        boolean startHidden;
-        int startOfOutlineGroupIdx = findStartOfColumnOutlineGroup( idx );
-        if (startOfOutlineGroupIdx <= 0)
-        {
-            startLevel = 0;
-            startHidden = false;
-        }
-        else if (getColInfo(startOfOutlineGroupIdx).getFirstColumn() - 1 != getColInfo(startOfOutlineGroupIdx - 1).getLastColumn())
-        {
-            startLevel = 0;
-            startHidden = false;
-        }
-        else
-        {
-            startLevel = getColInfo( startOfOutlineGroupIdx - 1).getOutlineLevel();
-            startHidden = getColInfo( startOfOutlineGroupIdx - 1 ).getHidden();
-        }
-
-        if (endLevel > startLevel)
-        {
-            return endHidden;
-        }
-        else
-        {
-            return startHidden;
-        }
-    }
-
-    public void collapseColumn( short columnNumber )
-    {
-        int idx = findColumnIdx( columnNumber, 0 );
-        if (idx == -1)
-            return;
-
-        // Find the start of the group.
-        ColumnInfoRecord columnInfo = getColInfo( findStartOfColumnOutlineGroup( idx ) );
-
-        // Hide all the columns until the end of the group
-        columnInfo = writeHidden( columnInfo, idx, true );
-
-        // Write collapse field
-        setColumn( (short) ( columnInfo.getLastColumn() + 1 ), null, null, null, null, Boolean.TRUE);
-    }
-
-    public void expandColumn( short columnNumber )
-    {
-        int idx = findColumnIdx( columnNumber, 0 );
-        if (idx == -1)
-            return;
-
-        // If it is already exapanded do nothing.
-        if (!isColumnGroupCollapsed(idx))
-            return;
-
-        // Find the start of the group.
-        int startIdx = findStartOfColumnOutlineGroup( idx );
-        ColumnInfoRecord columnInfo = getColInfo( startIdx );
-
-        // Find the end of the group.
-        int endIdx = findEndOfColumnOutlineGroup( idx );
-        ColumnInfoRecord endColumnInfo = getColInfo( endIdx );
-
-        // expand:
-        // colapsed bit must be unset
-        // hidden bit gets unset _if_ surrounding groups are expanded you can determine
-        //   this by looking at the hidden bit of the enclosing group.  You will have
-        //   to look at the start and the end of the current group to determine which
-        //   is the enclosing group
-        // hidden bit only is altered for this outline level.  ie.  don't uncollapse contained groups
-        if (!isColumnGroupHiddenByParent( idx ))
-        {
-            for (int i = startIdx; i <= endIdx; i++)
-            {
-                if (columnInfo.getOutlineLevel() == getColInfo(i).getOutlineLevel())
-                    getColInfo(i).setHidden( false );
-            }
-        }
-
-        // Write collapse field
-        setColumn( (short) ( columnInfo.getLastColumn() + 1 ), null, null, null, null, Boolean.FALSE);
-    }
-
-    /**
-     * creates the ColumnInfo Record and sets it to a default column/width
-     * @see org.apache.poi.hssf.record.ColumnInfoRecord
-     * @return record containing a ColumnInfoRecord
-     */
-    public static ColumnInfoRecord createColInfo()
-    {
-        ColumnInfoRecord retval = new ColumnInfoRecord();
-
-        retval.setColumnWidth(( short ) 2275);
-        // was:       retval.setOptions(( short ) 6);
-        retval.setOptions(( short ) 2);
-        retval.setXFIndex(( short ) 0x0f);
-        return retval;
-    }
-
-
-    public void setColumn(short column, Short xfIndex, Short width, Integer level, Boolean hidden, Boolean collapsed)
-    {
-        ColumnInfoRecord ci = null;
-        int              k  = 0;
-
-        for (k = 0; k < records.size(); k++)
-        {
-            ci = ( ColumnInfoRecord ) records.get(k);
-            if ((ci.getFirstColumn() <= column)
-                    && (column <= ci.getLastColumn()))
-            {
-                break;
-            }
-            ci = null;
-        }
-
-        if (ci != null)
-        {
-	    boolean styleChanged = xfIndex != null && ci.getXFIndex() != xfIndex.shortValue();
-            boolean widthChanged = width != null && ci.getColumnWidth() != width.shortValue();
-            boolean levelChanged = level != null && ci.getOutlineLevel() != level.intValue();
-            boolean hiddenChanged = hidden != null && ci.getHidden() != hidden.booleanValue();
-            boolean collapsedChanged = collapsed != null && ci.getCollapsed() != collapsed.booleanValue();
-            boolean columnChanged = styleChanged || widthChanged || levelChanged || hiddenChanged || collapsedChanged;
-            if (!columnChanged)
-            {
-                // do nothing...nothing changed.
-            }
-            else if ((ci.getFirstColumn() == column)
-                     && (ci.getLastColumn() == column))
-            {                               // if its only for this cell then
-                setColumnInfoFields( ci, xfIndex, width, level, hidden, collapsed );
-            }
-            else if ((ci.getFirstColumn() == column)
-                     || (ci.getLastColumn() == column))
-            {
-                // okay so the width is different but the first or last column == the column we'return setting
-                // we'll just divide the info and create a new one
-                if (ci.getFirstColumn() == column)
-                {
-                    ci.setFirstColumn(( short ) (column + 1));
-                }
-                else
-                {
-                    ci.setLastColumn(( short ) (column - 1));
-                }
-                ColumnInfoRecord nci = ( ColumnInfoRecord ) createColInfo();
-
-                nci.setFirstColumn(column);
-                nci.setLastColumn(column);
-                nci.setOptions(ci.getOptions());
-                nci.setXFIndex(ci.getXFIndex());
-                setColumnInfoFields( nci, xfIndex, width, level, hidden, collapsed );
-
-                insertColumn(k, nci);
-            }
-            else
-            {
-                //split to 3 records
-                short lastcolumn = ci.getLastColumn();
-                ci.setLastColumn(( short ) (column - 1));
-
-                ColumnInfoRecord nci = ( ColumnInfoRecord ) createColInfo();
-                nci.setFirstColumn(column);
-                nci.setLastColumn(column);
-                nci.setOptions(ci.getOptions());
-                nci.setXFIndex(ci.getXFIndex());
-                setColumnInfoFields( nci, xfIndex, width, level, hidden, collapsed );
-                insertColumn(++k, nci);
-
-                nci = ( ColumnInfoRecord ) createColInfo();
-                nci.setFirstColumn((short)(column+1));
-                nci.setLastColumn(lastcolumn);
-                nci.setOptions(ci.getOptions());
-                nci.setXFIndex(ci.getXFIndex());
-                nci.setColumnWidth(ci.getColumnWidth());
-                insertColumn(++k, nci);
-            }
-        }
-        else
-        {
-
-            // okay so there ISN'T a column info record that cover's this column so lets create one!
-            ColumnInfoRecord nci = ( ColumnInfoRecord ) createColInfo();
-
-            nci.setFirstColumn(column);
-            nci.setLastColumn(column);
-            setColumnInfoFields( nci, xfIndex, width, level, hidden, collapsed );
-            insertColumn(k, nci);
-        }
-    }
-
-    /**
-     * Sets all non null fields into the <code>ci</code> parameter.
-     */
-    private void setColumnInfoFields( ColumnInfoRecord ci, Short xfStyle, Short width, Integer level, Boolean hidden, Boolean collapsed )
-    {
-	if (xfStyle != null)
-	    ci.setXFIndex(xfStyle.shortValue());
-        if (width != null)
-            ci.setColumnWidth(width.shortValue());
-        if (level != null)
-            ci.setOutlineLevel( level.shortValue() );
-        if (hidden != null)
-            ci.setHidden( hidden.booleanValue() );
-        if (collapsed != null)
-            ci.setCollapsed( collapsed.booleanValue() );
-    }
-
-    private int findColumnIdx(int column, int fromIdx)
-    {
-        if (column < 0)
-            throw new IllegalArgumentException( "column parameter out of range: " + column );
-        if (fromIdx < 0)
-            throw new IllegalArgumentException( "fromIdx parameter out of range: " + fromIdx );
-
-        ColumnInfoRecord ci;
-        for (int k = fromIdx; k < records.size(); k++)
-        {
-            ci = getColInfo(k);
-            if ((ci.getFirstColumn() <= column)
-                    && (column <= ci.getLastColumn()))
-            {
-                return k;
-            }
-            ci = null;
-        }
-        return -1;
-    }
-
-    public void collapseColInfoRecords( int columnIdx )
-    {
-        if (columnIdx == 0)
-            return;
-        ColumnInfoRecord previousCol = getColInfo( columnIdx - 1);
-        ColumnInfoRecord currentCol = getColInfo( columnIdx );
-        boolean adjacentColumns = previousCol.getLastColumn() == currentCol.getFirstColumn() - 1;
-        if (!adjacentColumns)
-            return;
-
-        boolean columnsMatch =
-                previousCol.getXFIndex() == currentCol.getXFIndex() &&
-                previousCol.getOptions() == currentCol.getOptions() &&
-                previousCol.getColumnWidth() == currentCol.getColumnWidth();
-
-        if (columnsMatch)
-        {
-            previousCol.setLastColumn( currentCol.getLastColumn() );
-            records.remove( columnIdx );
-        }
-    }
-
-    /**
-     * Creates an outline group for the specified columns.
-     * @param fromColumn    group from this column (inclusive)
-     * @param toColumn      group to this column (inclusive)
-     * @param indent        if true the group will be indented by one level,
-     *                      if false indenting will be removed by one level.
-     */
-    public void groupColumnRange(short fromColumn, short toColumn, boolean indent)
-    {
-
-        // Set the level for each column
-        int fromIdx = 0;
-        for (int i = fromColumn; i <= toColumn; i++)
-        {
-            int level = 1;
-            int columnIdx = findColumnIdx( i, Math.max(0,fromIdx) );
-            if (columnIdx != -1)
-            {
-                level = getColInfo(columnIdx).getOutlineLevel();
-                if (indent) level++; else level--;
-                level = Math.max(0, level);
-                level = Math.min(7, level);
-                fromIdx = columnIdx - 1; // subtract 1 just in case this column is collapsed later.
-            }
-            setColumn((short)i, null, null, new Integer(level), null, null);
-            columnIdx = findColumnIdx( i, Math.max(0, fromIdx ) );
-            collapseColInfoRecords( columnIdx );
-        }
-
-    }
-    /**
-     * Finds the <tt>ColumnInfoRecord</tt> which contains the specified columnIndex
-     * @param columnIndex index of the column (not the index of the ColumnInfoRecord)
-     * @return <code>null</code> if no column info found for the specified column
-     */
+	public ColumnInfoRecordsAggregate(RecordStream rs) {
+		this();
+
+		boolean isInOrder = true;
+		ColumnInfoRecord cirPrev = null;
+		while(rs.peekNextClass() == ColumnInfoRecord.class) {
+			ColumnInfoRecord cir = (ColumnInfoRecord) rs.getNext();
+			records.add(cir);
+			if (cirPrev != null && CIRComparator.compareColInfos(cirPrev, cir) > 0) {
+				isInOrder = false;
+			}
+			cirPrev = cir;
+		}
+		if (records.size() < 1) {
+			throw new RuntimeException("No column info records found");
+		}
+		if (!isInOrder) {
+			Collections.sort(records, CIRComparator.instance);
+		}
+	}
+
+	/**
+	 * Performs a deep clone of the record
+	 */
+	public Object clone() {
+		ColumnInfoRecordsAggregate rec = new ColumnInfoRecordsAggregate();
+		for (int k = 0; k < records.size(); k++) {
+			ColumnInfoRecord ci = ( ColumnInfoRecord ) records.get(k);
+			rec.records.add(ci.clone());
+		}
+		return rec;
+	}
+
+	/**
+	 * Inserts a column into the aggregate (at the end of the list).
+	 */
+	public void insertColumn(ColumnInfoRecord col) {
+		records.add(col);
+		Collections.sort(records, CIRComparator.instance);
+	}
+
+	/**
+	 * Inserts a column into the aggregate (at the position specified by
+	 * <code>idx</code>.
+	 */
+	private void insertColumn(int idx, ColumnInfoRecord col) {
+		records.add(idx, col);
+	}
+
+	/* package */ int getNumColumns() {
+		return records.size();
+	}
+
+	public void visitContainedRecords(RecordVisitor rv) {
+		int nItems = records.size();
+		if (nItems < 1) {
+			return;
+		}
+		ColumnInfoRecord cirPrev = null;
+		for(int i=0; i<nItems; i++) {
+			ColumnInfoRecord cir = (ColumnInfoRecord)records.get(i);
+			rv.visitRecord(cir);
+			if (cirPrev != null && CIRComparator.compareColInfos(cirPrev, cir) > 0) {
+				// Excel probably wouldn't mind, but there is much logic in this class
+				// that assumes the column info records are kept in order
+				throw new RuntimeException("Column info records are out of order");
+			}
+			cirPrev = cir;
+		}
+	}
+
+	private int findStartOfColumnOutlineGroup(int pIdx) {
+		// Find the start of the group.
+		ColumnInfoRecord columnInfo = (ColumnInfoRecord) records.get(pIdx);
+		int level = columnInfo.getOutlineLevel();
+		int idx = pIdx;
+		while (idx != 0) {
+			ColumnInfoRecord prevColumnInfo = (ColumnInfoRecord) records.get(idx - 1);
+			if (!prevColumnInfo.isAdjacentBefore(columnInfo)) {
+				break;
+			}
+			if (prevColumnInfo.getOutlineLevel() < level) {
+				break;
+			}
+			idx--;
+			columnInfo = prevColumnInfo;
+		}
+
+		return idx;
+	}
+
+	private int findEndOfColumnOutlineGroup(int colInfoIndex) {
+		// Find the end of the group.
+		ColumnInfoRecord columnInfo = (ColumnInfoRecord) records.get(colInfoIndex);
+		int level = columnInfo.getOutlineLevel();
+		int idx = colInfoIndex;
+		while (idx < records.size() - 1) {
+			ColumnInfoRecord nextColumnInfo = (ColumnInfoRecord) records.get(idx + 1);
+			if (!columnInfo.isAdjacentBefore(nextColumnInfo)) {
+				break;
+			}
+			if (nextColumnInfo.getOutlineLevel() < level) {
+				break;
+			}
+			idx++;
+			columnInfo = nextColumnInfo;
+		}
+		return idx;
+	}
+
+	private ColumnInfoRecord getColInfo(int idx) {
+		return (ColumnInfoRecord) records.get( idx );
+	}
+
+	/**
+	 * 'Collapsed' state is stored in a single column col info record immediately after the outline group
+	 * @param idx
+	 * @return
+	 */
+	private boolean isColumnGroupCollapsed(int idx) {
+		int endOfOutlineGroupIdx = findEndOfColumnOutlineGroup(idx);
+		int nextColInfoIx = endOfOutlineGroupIdx+1;
+		if (nextColInfoIx >= records.size()) {
+			return false;
+		}
+		ColumnInfoRecord nextColInfo = getColInfo(nextColInfoIx);
+		if (!getColInfo(endOfOutlineGroupIdx).isAdjacentBefore(nextColInfo)) {
+			return false;
+		}
+		return nextColInfo.getCollapsed();
+	}
+
+
+	private boolean isColumnGroupHiddenByParent(int idx) {
+		// Look out outline details of end
+		int endLevel = 0;
+		boolean endHidden = false;
+		int endOfOutlineGroupIdx = findEndOfColumnOutlineGroup( idx );
+		if (endOfOutlineGroupIdx < records.size()) {
+			ColumnInfoRecord nextInfo = getColInfo(endOfOutlineGroupIdx + 1);
+			if (getColInfo(endOfOutlineGroupIdx).isAdjacentBefore(nextInfo)) {
+				endLevel = nextInfo.getOutlineLevel();
+				endHidden = nextInfo.getHidden();
+			}
+		}
+		// Look out outline details of start
+		int startLevel = 0;
+		boolean startHidden = false;
+		int startOfOutlineGroupIdx = findStartOfColumnOutlineGroup( idx );
+		if (startOfOutlineGroupIdx > 0) {
+			ColumnInfoRecord prevInfo = getColInfo(startOfOutlineGroupIdx - 1);
+			if (prevInfo.isAdjacentBefore(getColInfo(startOfOutlineGroupIdx))) {
+				startLevel = prevInfo.getOutlineLevel();
+				startHidden = prevInfo.getHidden();
+			}
+		}
+		if (endLevel > startLevel) {
+			return endHidden;
+		}
+		return startHidden;
+	}
+
+	public void collapseColumn(int columnIndex) {
+		int colInfoIx = findColInfoIdx(columnIndex, 0);
+		if (colInfoIx == -1) {
+			return;
+		}
+
+		// Find the start of the group.
+		int groupStartColInfoIx = findStartOfColumnOutlineGroup(colInfoIx);
+		ColumnInfoRecord columnInfo = getColInfo(groupStartColInfoIx);
+
+		// Hide all the columns until the end of the group
+		int lastColIx = setGroupHidden(groupStartColInfoIx, columnInfo.getOutlineLevel(), true);
+
+		// Write collapse field
+		setColumn(lastColIx + 1, null, null, null, null, Boolean.TRUE);
+	}
+	/**
+	 * Sets all adjacent columns of the same outline level to the specified hidden status.
+	 * @param pIdx the col info index of the start of the outline group
+	 * @return the column index of the last column in the outline group
+	 */
+	private int setGroupHidden(int pIdx, int level, boolean hidden) {
+		int idx = pIdx;
+		ColumnInfoRecord columnInfo = getColInfo(idx);
+		while (idx < records.size()) {
+			columnInfo.setHidden(hidden);
+			if (idx + 1 < records.size()) {
+				ColumnInfoRecord nextColumnInfo = getColInfo(idx + 1);
+				if (!columnInfo.isAdjacentBefore(nextColumnInfo)) {
+					break;
+				}
+				if (nextColumnInfo.getOutlineLevel() < level) {
+					break;
+				}
+				columnInfo = nextColumnInfo;
+			}
+			idx++;
+		}
+		return columnInfo.getLastColumn();
+	}
+
+
+	public void expandColumn(int columnIndex) {
+		int idx = findColInfoIdx(columnIndex, 0);
+		if (idx == -1) {
+			return;
+		}
+
+		// If it is already expanded do nothing.
+		if (!isColumnGroupCollapsed(idx)) {
+			return;
+		}
+
+		// Find the start/end of the group.
+		int startIdx = findStartOfColumnOutlineGroup(idx);
+		int endIdx = findEndOfColumnOutlineGroup(idx);
+
+		// expand:
+		// colapsed bit must be unset
+		// hidden bit gets unset _if_ surrounding groups are expanded you can determine
+		//   this by looking at the hidden bit of the enclosing group.  You will have
+		//   to look at the start and the end of the current group to determine which
+		//   is the enclosing group
+		// hidden bit only is altered for this outline level.  ie.  don't uncollapse contained groups
+		ColumnInfoRecord columnInfo = getColInfo(endIdx);
+		if (!isColumnGroupHiddenByParent(idx)) {
+			int outlineLevel = columnInfo.getOutlineLevel();
+			for (int i = startIdx; i <= endIdx; i++) {
+				ColumnInfoRecord ci = getColInfo(i);
+				if (outlineLevel == ci.getOutlineLevel())
+					ci.setHidden(false);
+			}
+		}
+
+		// Write collapse flag (stored in a single col info record after this outline group)
+		setColumn(columnInfo.getLastColumn() + 1, null, null, null, null, Boolean.FALSE);
+	}
+
+	private static ColumnInfoRecord copyColInfo(ColumnInfoRecord ci) {
+		return (ColumnInfoRecord) ci.clone();
+	}
+
+
+	public void setColumn(int targetColumnIx, Short xfIndex, Short width, 
+					Integer level, Boolean hidden, Boolean collapsed) {
+		ColumnInfoRecord ci = null;
+		int k  = 0;
+
+		for (k = 0; k < records.size(); k++) {
+			ColumnInfoRecord tci = (ColumnInfoRecord) records.get(k);
+			if (tci.containsColumn(targetColumnIx)) {
+				ci = tci;
+				break;
+			}
+			if (tci.getFirstColumn() > targetColumnIx) {
+				// call column infos after k are for later columns
+				break; // exit now so k will be the correct insert pos
+			}
+		}
+
+		if (ci == null) {
+			// okay so there ISN'T a column info record that covers this column so lets create one!
+			ColumnInfoRecord nci = new ColumnInfoRecord();
+
+			nci.setFirstColumn(targetColumnIx);
+			nci.setLastColumn(targetColumnIx);
+			setColumnInfoFields( nci, xfIndex, width, level, hidden, collapsed );
+			insertColumn(k, nci);
+			attemptMergeColInfoRecords(k);
+			return;
+		}
+
+		boolean styleChanged = xfIndex != null && ci.getXFIndex() != xfIndex.shortValue();
+		boolean widthChanged = width != null && ci.getColumnWidth() != width.shortValue();
+		boolean levelChanged = level != null && ci.getOutlineLevel() != level.intValue();
+		boolean hiddenChanged = hidden != null && ci.getHidden() != hidden.booleanValue();
+		boolean collapsedChanged = collapsed != null && ci.getCollapsed() != collapsed.booleanValue();
+
+		boolean columnChanged = styleChanged || widthChanged || levelChanged || hiddenChanged || collapsedChanged;
+		if (!columnChanged) {
+			// do nothing...nothing changed.
+			return;
+		}
+
+		if (ci.getFirstColumn() == targetColumnIx && ci.getLastColumn() == targetColumnIx) {
+			// ColumnInfo ci for a single column, the target column
+			setColumnInfoFields(ci, xfIndex, width, level, hidden, collapsed);
+			attemptMergeColInfoRecords(k);
+			return;
+		}
+
+		if (ci.getFirstColumn() == targetColumnIx || ci.getLastColumn() == targetColumnIx) {
+			// The target column is at either end of the multi-column ColumnInfo ci
+			// we'll just divide the info and create a new one
+			if (ci.getFirstColumn() == targetColumnIx) {
+				ci.setFirstColumn(targetColumnIx + 1);
+			} else {
+				ci.setLastColumn(targetColumnIx - 1);
+				k++; // adjust insert pos to insert after
+			}
+			ColumnInfoRecord nci = copyColInfo(ci);
+
+			nci.setFirstColumn(targetColumnIx);
+			nci.setLastColumn(targetColumnIx);
+			setColumnInfoFields( nci, xfIndex, width, level, hidden, collapsed );
+
+			insertColumn(k, nci);
+			attemptMergeColInfoRecords(k);
+		} else {
+			//split to 3 records
+			ColumnInfoRecord ciStart = ci;
+			ColumnInfoRecord ciMid = copyColInfo(ci);
+			ColumnInfoRecord ciEnd = copyColInfo(ci);
+			int lastcolumn = ci.getLastColumn();
+			
+			ciStart.setLastColumn(targetColumnIx - 1);
+
+			ciMid.setFirstColumn(targetColumnIx);
+			ciMid.setLastColumn(targetColumnIx);
+			setColumnInfoFields(ciMid, xfIndex, width, level, hidden, collapsed);
+			insertColumn(++k, ciMid);
+			
+			ciEnd.setFirstColumn(targetColumnIx+1);
+			ciEnd.setLastColumn(lastcolumn);
+			insertColumn(++k, ciEnd);
+			// no need to attemptMergeColInfoRecords because we 
+			// know both on each side are different
+		}
+	}
+
+	/**
+	 * Sets all non null fields into the <code>ci</code> parameter.
+	 */
+	private static void setColumnInfoFields( ColumnInfoRecord ci, Short xfStyle, Short width, 
+				Integer level, Boolean hidden, Boolean collapsed ) {
+		if (xfStyle != null) {
+			ci.setXFIndex(xfStyle.shortValue());
+		}
+		if (width != null) {
+			ci.setColumnWidth(width.shortValue());
+		}
+		if (level != null) {
+			ci.setOutlineLevel( level.shortValue() );
+		}
+		if (hidden != null) {
+			ci.setHidden( hidden.booleanValue() );
+		}
+		if (collapsed != null) {
+			ci.setCollapsed( collapsed.booleanValue() );
+		}
+	}
+
+	private int findColInfoIdx(int columnIx, int fromColInfoIdx) {
+		if (columnIx < 0) {
+			throw new IllegalArgumentException( "column parameter out of range: " + columnIx );
+		}
+		if (fromColInfoIdx < 0) {
+			throw new IllegalArgumentException( "fromIdx parameter out of range: " + fromColInfoIdx );
+		}
+
+		for (int k = fromColInfoIdx; k < records.size(); k++) {
+			ColumnInfoRecord ci = getColInfo(k);
+			if (ci.containsColumn(columnIx)) {
+				return k;
+			}
+			if (ci.getFirstColumn() > columnIx) {
+				break;
+			}
+		}
+		return -1;
+	}
+
+	/**
+	 * Attempts to merge the col info record at the specified index 
+	 * with either or both of its neighbours
+	 */
+	private void attemptMergeColInfoRecords(int colInfoIx) {
+		int nRecords = records.size();
+		if (colInfoIx < 0 || colInfoIx >= nRecords) {
+			throw new IllegalArgumentException("colInfoIx " + colInfoIx 
+					+ " is out of range (0.." + (nRecords-1) + ")");
+		}
+		ColumnInfoRecord currentCol = getColInfo(colInfoIx);
+		int nextIx = colInfoIx+1;
+		if (nextIx < nRecords) {
+			if (mergeColInfoRecords(currentCol, getColInfo(nextIx))) {
+    			records.remove(nextIx);
+			}
+		}
+		if (colInfoIx > 0) {
+			if (mergeColInfoRecords(getColInfo(colInfoIx - 1), currentCol)) {
+    			records.remove(colInfoIx);
+    		}
+		}
+	}
+	/**
+	 * merges two column info records (if they are adjacent and have the same formatting, etc)
+	 * @return <code>false</code> if the two column records could not be merged
+	 */
+	private static boolean mergeColInfoRecords(ColumnInfoRecord ciA, ColumnInfoRecord ciB) {
+		if (ciA.isAdjacentBefore(ciB) && ciA.formatMatches(ciB)) {
+			ciA.setLastColumn(ciB.getLastColumn());
+			return true;
+		}
+		return false;
+	}
+	/**
+	 * Creates an outline group for the specified columns, by setting the level
+	 * field for each col info record in the range. {@link ColumnInfoRecord}s
+	 * may be created, split or merged as a result of this operation.
+	 * 
+	 * @param fromColumnIx
+	 *            group from this column (inclusive)
+	 * @param toColumnIx
+	 *            group to this column (inclusive)
+	 * @param indent
+	 *            if <code>true</code> the group will be indented by one
+	 *            level, if <code>false</code> indenting will be decreased by
+	 *            one level.
+	 */
+	public void groupColumnRange(int fromColumnIx, int toColumnIx, boolean indent) {
+
+		int colInfoSearchStartIdx = 0; // optimization to speed up the search for col infos
+		for (int i = fromColumnIx; i <= toColumnIx; i++) {
+			int level = 1;
+			int colInfoIdx = findColInfoIdx(i, colInfoSearchStartIdx);
+			if (colInfoIdx != -1) {
+				level = getColInfo(colInfoIdx).getOutlineLevel();
+				if (indent) {
+					level++;
+				} else {
+					level--;
+				}
+				level = Math.max(0, level);
+				level = Math.min(7, level);
+				colInfoSearchStartIdx = Math.max(0, colInfoIdx - 1); // -1 just in case this column is collapsed later.
+			}
+			setColumn(i, null, null, new Integer(level), null, null);
+		}
+	}
+	/**
+	 * Finds the <tt>ColumnInfoRecord</tt> which contains the specified columnIndex
+	 * @param columnIndex index of the column (not the index of the ColumnInfoRecord)
+	 * @return <code>null</code> if no column info found for the specified column
+	 */
 	public ColumnInfoRecord findColumnInfo(int columnIndex) {
 		int nInfos = records.size();
 		for(int i=0; i< nInfos; i++) {
 			ColumnInfoRecord ci = getColInfo(i);
-			if (ci.getFirstColumn() <= columnIndex && columnIndex <= ci.getLastColumn()) {
+			if (ci.containsColumn(columnIndex)) {
 				return ci;
 			}
 		}
 		return null;
 	}
 	public int getMaxOutlineLevel() {
-        int result = 0;
-        int count=records.size();
-        for (int i=0; i<count; i++) {
-            ColumnInfoRecord columnInfoRecord = getColInfo(i);
-            result = Math.max(columnInfoRecord.getOutlineLevel(), result);
-        }
-        return result;
+		int result = 0;
+		int count=records.size();
+		for (int i=0; i<count; i++) {
+			ColumnInfoRecord columnInfoRecord = getColInfo(i);
+			result = Math.max(columnInfoRecord.getOutlineLevel(), result);
+		}
+		return result;
 	}
-
-
 }

Modified: poi/branches/ooxml/src/java/org/apache/poi/hssf/record/aggregates/FormulaRecordAggregate.java
URL: http://svn.apache.org/viewvc/poi/branches/ooxml/src/java/org/apache/poi/hssf/record/aggregates/FormulaRecordAggregate.java?rev=694947&r1=694946&r2=694947&view=diff
==============================================================================
--- poi/branches/ooxml/src/java/org/apache/poi/hssf/record/aggregates/FormulaRecordAggregate.java (original)
+++ poi/branches/ooxml/src/java/org/apache/poi/hssf/record/aggregates/FormulaRecordAggregate.java Sat Sep 13 06:48:27 2008
@@ -20,6 +20,7 @@
 import org.apache.poi.hssf.record.CellValueRecordInterface;
 import org.apache.poi.hssf.record.FormulaRecord;
 import org.apache.poi.hssf.record.Record;
+import org.apache.poi.hssf.record.RecordFormatException;
 import org.apache.poi.hssf.record.StringRecord;
 
 /**
@@ -34,9 +35,9 @@
     private SharedValueManager _sharedValueManager;
     /** caches the calculated result of the formula */
     private StringRecord _stringRecord;
-    
+
     /**
-     * @param stringRec may be <code>null</code> if this formula does not have a cached text 
+     * @param stringRec may be <code>null</code> if this formula does not have a cached text
      * value.
      * @param svm the {@link SharedValueManager} for the current sheet
      */
@@ -44,6 +45,14 @@
         if (svm == null) {
             throw new IllegalArgumentException("sfm must not be null");
         }
+        boolean hasStringRec = stringRec != null;
+        boolean hasCachedStringFlag = formulaRec.hasCachedResultString();
+		if (hasStringRec != hasCachedStringFlag) {
+			throw new RecordFormatException("String record was "
+					+ (hasStringRec ? "": "not ") + " supplied but formula record flag is "
+					+ (hasCachedStringFlag ? "" : "not ") + " set");
+		}
+        	
         if (formulaRec.isSharedFormula()) {
             svm.convertSharedFormulaRecord(formulaRec);
         }
@@ -52,18 +61,18 @@
         _stringRecord = stringRec;
     }
 
-    public void setStringRecord(StringRecord stringRecord) {
-        _stringRecord = stringRecord;
-    }
-    
     public FormulaRecord getFormulaRecord() {
         return _formulaRecord;
     }
 
+    /**
+     * debug only
+     * TODO - encapsulate
+     */
     public StringRecord getStringRecord() {
         return _stringRecord;
     }
-    
+
     public short getXFIndex() {
         return _formulaRecord.getXFIndex();
     }
@@ -91,7 +100,7 @@
     public String toString() {
         return _formulaRecord.toString();
     }
-   
+
     public void visitContainedRecords(RecordVisitor rv) {
          rv.visitRecord(_formulaRecord);
          Record sharedFormulaRecord = _sharedValueManager.getRecordForFirstCell(_formulaRecord);
@@ -102,11 +111,33 @@
              rv.visitRecord(_stringRecord);
          }
     }
-   
+
     public String getStringValue() {
         if(_stringRecord==null) {
             return null;
         }
         return _stringRecord.getString();
     }
+
+    public void setCachedStringResult(String value) {
+
+        // Save the string into a String Record, creating one if required
+        if(_stringRecord == null) {
+            _stringRecord = new StringRecord();
+        }
+        _stringRecord.setString(value);
+        if (value.length() < 1) {
+            _formulaRecord.setCachedResultTypeEmptyString();
+        } else {
+            _formulaRecord.setCachedResultTypeString();
+        }
+    }
+    public void setCachedBooleanResult(boolean value) {
+        _stringRecord = null;
+        _formulaRecord.setCachedResultBoolean(value);
+    }
+    public void setCachedErrorResult(int errorCode) {
+        _stringRecord = null;
+        _formulaRecord.setCachedResultErrorCode(errorCode);
+    }
 }

Propchange: poi/branches/ooxml/src/java/org/apache/poi/hssf/record/aggregates/PageSettingsBlock.java
            ('svn:mergeinfo' removed)

Propchange: poi/branches/ooxml/src/java/org/apache/poi/hssf/record/aggregates/SharedValueManager.java
            ('svn:mergeinfo' removed)

Propchange: poi/branches/ooxml/src/java/org/apache/poi/hssf/record/cf/CellRangeUtil.java
            ('svn:mergeinfo' removed)

Modified: poi/branches/ooxml/src/java/org/apache/poi/hssf/record/formula/Area2DPtgBase.java
URL: http://svn.apache.org/viewvc/poi/branches/ooxml/src/java/org/apache/poi/hssf/record/formula/Area2DPtgBase.java?rev=694947&r1=694946&r2=694947&view=diff
==============================================================================
--- poi/branches/ooxml/src/java/org/apache/poi/hssf/record/formula/Area2DPtgBase.java (original)
+++ poi/branches/ooxml/src/java/org/apache/poi/hssf/record/formula/Area2DPtgBase.java Sat Sep 13 06:48:27 2008
@@ -18,7 +18,7 @@
 package org.apache.poi.hssf.record.formula;
 
 import org.apache.poi.hssf.record.RecordInputStream;
-import org.apache.poi.hssf.usermodel.HSSFWorkbook;
+import org.apache.poi.ss.usermodel.Workbook;
 import org.apache.poi.util.LittleEndian;
 
 /**
@@ -45,7 +45,7 @@
 	public final int getSize() {
 		return SIZE;
 	}
-	public final String toFormulaString(HSSFWorkbook book) {
+	public final String toFormulaString(Workbook book) {
     	return formatReferenceAsString();
 	}
     public final String toString() {

Modified: poi/branches/ooxml/src/java/org/apache/poi/hssf/record/formula/ArrayPtg.java
URL: http://svn.apache.org/viewvc/poi/branches/ooxml/src/java/org/apache/poi/hssf/record/formula/ArrayPtg.java?rev=694947&r1=694946&r2=694947&view=diff
==============================================================================
--- poi/branches/ooxml/src/java/org/apache/poi/hssf/record/formula/ArrayPtg.java (original)
+++ poi/branches/ooxml/src/java/org/apache/poi/hssf/record/formula/ArrayPtg.java Sat Sep 13 06:48:27 2008
@@ -44,8 +44,11 @@
 	 * (not including the data which comes after all formula tokens)
 	 */
 	public static final int PLAIN_TOKEN_SIZE = 1+RESERVED_FIELD_LEN;
+
+	private static final byte[] DEFAULT_RESERVED_DATA = new byte[RESERVED_FIELD_LEN];
+
 	// TODO - fix up field visibility and subclasses
-	private byte[] field_1_reserved;
+	private final byte[] field_1_reserved;
 	
 	// data from these fields comes after the Ptg data of all tokens in current formula
 	private short  token_1_columns;
@@ -59,8 +62,42 @@
 			field_1_reserved[i] = in.readByte();
 		}
 	}
-	public Object[] getTokenArrayValues() {
-		return (Object[]) token_3_arrayValues.clone();
+	/**
+	 * @param values2d array values arranged in rows
+	 */
+	public ArrayPtg(Object[][] values2d) {
+		int nColumns = values2d[0].length;
+		int nRows = values2d.length;
+		// convert 2-d to 1-d array (row by row according to getValueIndex())
+		token_1_columns = (short) nColumns;
+		token_2_rows = (short) nRows;
+
+		Object[] vv = new Object[token_1_columns * token_2_rows];
+		for (int r=0; r<nRows; r++) {
+			Object[] rowData = values2d[r];
+			for (int c=0; c<nColumns; c++) {
+				vv[getValueIndex(c, r)] = rowData[c];
+			}
+		}
+		
+		token_3_arrayValues = vv;
+		field_1_reserved = DEFAULT_RESERVED_DATA;
+	}
+	/**
+	 * @return 2-d array (inner index is rowIx, outer index is colIx)
+	 */
+	public Object[][] getTokenArrayValues() {
+		if (token_3_arrayValues == null) {
+			throw new IllegalStateException("array values not read yet");
+		}
+		Object[][] result = new Object[token_2_rows][token_1_columns];
+		for (int r = 0; r < token_2_rows; r++) {
+			Object[] rowData = result[r];
+			for (int c = 0; c < token_1_columns; c++) {
+				rowData[c] = token_3_arrayValues[getValueIndex(c, r)];
+			}
+		}
+		return result;
 	}
 	
 	public boolean isBaseToken() {
@@ -88,27 +125,21 @@
 		token_3_arrayValues = ConstantValueParser.parse(in, totalCount);
 	}
 
-	public String toString()
-	{
-		StringBuffer buffer = new StringBuffer("[ArrayPtg]\n");
+	public String toString() {
+		StringBuffer sb = new StringBuffer("[ArrayPtg]\n");
 
-		buffer.append("columns = ").append(getColumnCount()).append("\n");
-		buffer.append("rows = ").append(getRowCount()).append("\n");
+		sb.append("nRows = ").append(getRowCount()).append("\n");
+		sb.append("nCols = ").append(getColumnCount()).append("\n");
 		if (token_3_arrayValues == null) {
-			buffer.append("  #values#uninitialised#\n");
+			sb.append("  #values#uninitialised#\n");
 		} else {
-			for (int x=0;x<getColumnCount();x++) {
-				for (int y=0;y<getRowCount();y++) {
-					Object o = token_3_arrayValues[getValueIndex(x, y)];
-					buffer.append("[").append(x).append("][").append(y).append("] = ").append(o).append("\n"); 
-				}
-			}
+			sb.append("  ").append(formatAsString());
 		}
-		return buffer.toString();
+		return sb.toString();
 	}
 
 	/**
-	 * Note - (2D) array elements are stored column by column 
+	 * Note - (2D) array elements are stored row by row
 	 * @return the index into the internal 1D array for the specified column and row
 	 */
 	/* package */ int getValueIndex(int colIx, int rowIx) {
@@ -120,7 +151,7 @@
 			throw new IllegalArgumentException("Specified rowIx (" + rowIx 
 					+ ") is outside the allowed range (0.." + (token_2_rows-1) + ")");
 		}
-		return rowIx + token_2_rows * colIx;
+		return rowIx * token_1_columns + colIx;
 	}
 
 	public void writeBytes(byte[] data, int offset) {
@@ -153,16 +184,15 @@
 			+ ConstantValueParser.getEncodedSize(token_3_arrayValues);
 	}
 
-	public String toFormulaString(Workbook book)
-	{
+	public String formatAsString() {
 		StringBuffer b = new StringBuffer();
 		b.append("{");
-		for (int x=0;x<getColumnCount();x++) {
-		  	if (x > 0) {
+	  	for (int y=0;y<getRowCount();y++) {
+			if (y > 0) {
 				b.append(";");
 			}
-		  	for (int y=0;y<getRowCount();y++) {
-				if (y > 0) {
+			for (int x=0;x<getColumnCount();x++) {
+			  	if (x > 0) {
 					b.append(",");
 				}
 		  		Object o = token_3_arrayValues[getValueIndex(x, y)];
@@ -172,11 +202,14 @@
 		b.append("}");
 		return b.toString();
 	}
+	public String toFormulaString(Workbook book) {
+		return formatAsString();
+	}
 	
 	private static String getConstantText(Object o) {
 
 		if (o == null) {
-			return ""; // TODO - how is 'empty value' represented in formulas?
+			throw new RuntimeException("Array item cannot be null");
 		}
 		if (o instanceof UnicodeString) {
 			return "\"" + ((UnicodeString)o).getString() + "\"";
@@ -196,11 +229,4 @@
 	public byte getDefaultOperandClass() {
 		return Ptg.CLASS_ARRAY;
 	}
-	
-	public Object clone() {
-	  ArrayPtg ptg = (ArrayPtg) super.clone();
-	  ptg.field_1_reserved = (byte[]) field_1_reserved.clone();
-	  ptg.token_3_arrayValues = (Object[]) token_3_arrayValues.clone();
-	  return ptg;
-	}
 }

Modified: poi/branches/ooxml/src/java/org/apache/poi/hssf/record/formula/ErrPtg.java
URL: http://svn.apache.org/viewvc/poi/branches/ooxml/src/java/org/apache/poi/hssf/record/formula/ErrPtg.java?rev=694947&r1=694946&r2=694947&view=diff
==============================================================================
--- poi/branches/ooxml/src/java/org/apache/poi/hssf/record/formula/ErrPtg.java (original)
+++ poi/branches/ooxml/src/java/org/apache/poi/hssf/record/formula/ErrPtg.java Sat Sep 13 06:48:27 2008
@@ -24,12 +24,12 @@
  * @author Daniel Noll (daniel at nuix dot com dot au)
  */
 public final class ErrPtg extends ScalarConstantPtg {
-    
+
     // convenient access to namespace
     private static final HSSFErrorConstants EC = null;
-    
+
     /** <b>#NULL!</b>  - Intersection of two cell ranges is empty */
-    public static final ErrPtg NULL_INTERSECTION = new ErrPtg(EC.ERROR_NULL); 
+    public static final ErrPtg NULL_INTERSECTION = new ErrPtg(EC.ERROR_NULL);
     /** <b>#DIV/0!</b> - Division by zero */
     public static final ErrPtg DIV_ZERO = new ErrPtg(EC.ERROR_DIV_0);
     /** <b>#VALUE!</b> - Wrong type of operand */
@@ -37,28 +37,28 @@
     /** <b>#REF!</b> - Illegal or deleted cell reference */
     public static final ErrPtg REF_INVALID = new ErrPtg(EC.ERROR_REF);
     /** <b>#NAME?</b> - Wrong function or range name */
-    public static final ErrPtg NAME_INVALID = new ErrPtg(EC.ERROR_NAME); 
+    public static final ErrPtg NAME_INVALID = new ErrPtg(EC.ERROR_NAME);
     /** <b>#NUM!</b> - Value range overflow */
     public static final ErrPtg NUM_ERROR = new ErrPtg(EC.ERROR_NUM);
     /** <b>#N/A</b> - Argument or function not available */
     public static final ErrPtg N_A = new ErrPtg(EC.ERROR_NA);
-    
-    
+
+
     public static final short sid  = 0x1c;
     private static final int  SIZE = 2;
     private final int field_1_error_code;
 
     /** Creates new ErrPtg */
 
-    public ErrPtg(int errorCode) {
+    private ErrPtg(int errorCode) {
         if(!HSSFErrorConstants.isValidCode(errorCode)) {
             throw new IllegalArgumentException("Invalid error code (" + errorCode + ")");
         }
         field_1_error_code = errorCode;
     }
- 
-    public ErrPtg(RecordInputStream in) {
-        this(in.readByte());
+
+    public static ErrPtg read(RecordInputStream in) {
+        return valueOf(in.readByte());
     }
 
     public void writeBytes(byte [] array, int offset)
@@ -78,4 +78,17 @@
     public int getErrorCode() {
         return field_1_error_code;
     }
+
+    public static ErrPtg valueOf(int code) {
+        switch(code) {
+            case HSSFErrorConstants.ERROR_DIV_0: return DIV_ZERO;
+            case HSSFErrorConstants.ERROR_NA: return N_A;
+            case HSSFErrorConstants.ERROR_NAME: return NAME_INVALID;
+            case HSSFErrorConstants.ERROR_NULL: return NULL_INTERSECTION;
+            case HSSFErrorConstants.ERROR_NUM: return NUM_ERROR;
+            case HSSFErrorConstants.ERROR_REF: return REF_INVALID;
+            case HSSFErrorConstants.ERROR_VALUE: return VALUE_INVALID;
+        }
+        throw new RuntimeException("Unexpected error code (" + code + ")");
+    }
 }

Modified: poi/branches/ooxml/src/java/org/apache/poi/hssf/record/formula/Ptg.java
URL: http://svn.apache.org/viewvc/poi/branches/ooxml/src/java/org/apache/poi/hssf/record/formula/Ptg.java?rev=694947&r1=694946&r2=694947&view=diff
==============================================================================
--- poi/branches/ooxml/src/java/org/apache/poi/hssf/record/formula/Ptg.java (original)
+++ poi/branches/ooxml/src/java/org/apache/poi/hssf/record/formula/Ptg.java Sat Sep 13 06:48:27 2008
@@ -56,20 +56,21 @@
 	/**
 	 * @deprecated - use readTokens()
 	 */
-	public static Stack createParsedExpressionTokens(short size, RecordInputStream in)
-	{
+	public static Stack createParsedExpressionTokens(short size, RecordInputStream in) {
 		Stack stack = new Stack();
 		int pos = 0;
 		List arrayPtgs = null;
-		while ( pos < size )
-		{
+		while (pos < size) {
 			Ptg ptg = Ptg.createPtg( in );
 			if (ptg instanceof ArrayPtg) {
-				if (arrayPtgs == null)
+				if (arrayPtgs == null) {
 					arrayPtgs = new ArrayList(5);
+				}
 				arrayPtgs.add(ptg);
-				pos += 8;
-			} else pos += ptg.getSize();
+				pos += ArrayPtg.PLAIN_TOKEN_SIZE;
+			} else {
+				pos += ptg.getSize();
+			}
 			stack.push( ptg );
 		}
 		if(pos != size) {
@@ -109,25 +110,25 @@
 		int baseId = id & 0x1F | 0x20;
 		
 		switch (baseId) {
-			case ArrayPtg.sid:     return new ArrayPtg(in);    // 0x20, 0x40, 0x60
-			 case FuncPtg.sid:     return new FuncPtg(in);     // 0x21, 0x41, 0x61
-			 case FuncVarPtg.sid:  return new FuncVarPtg(in);  // 0x22, 0x42, 0x62
-			 case NamePtg.sid:     return new NamePtg(in);     // 0x23, 0x43, 0x63
-			 case RefPtg.sid:      return new RefPtg(in);      // 0x24, 0x44, 0x64
-			 case AreaPtg.sid:     return new AreaPtg(in);     // 0x25, 0x45, 0x65
-			 case MemAreaPtg.sid:  return new MemAreaPtg(in);  // 0x26, 0x46, 0x66
-			 case MemErrPtg.sid:   return new MemErrPtg(in);   // 0x27, 0x47, 0x67
-			 case MemFuncPtg.sid:  return new MemFuncPtg(in);  // 0x29, 0x49, 0x69
-			 case RefErrorPtg.sid: return  new RefErrorPtg(in);// 0x2a, 0x4a, 0x6a
-			 case AreaErrPtg.sid:  return new AreaErrPtg(in);  // 0x2b, 0x4b, 0x6b
-			 case RefNPtg.sid:     return new RefNPtg(in);     // 0x2c, 0x4c, 0x6c
-			 case AreaNPtg.sid:    return new AreaNPtg(in);    // 0x2d, 0x4d, 0x6d
-
-			 case NameXPtg.sid:    return new NameXPtg(in);    // 0x39, 0x49, 0x79
-			 case Ref3DPtg.sid:    return  new Ref3DPtg(in);   // 0x3a, 0x5a, 0x7a
-			 case Area3DPtg.sid:   return new Area3DPtg(in);   // 0x3b, 0x5b, 0x7b
-			 case DeletedRef3DPtg.sid:  return new DeletedRef3DPtg(in);   // 0x3c, 0x5c, 0x7c
-			 case DeletedArea3DPtg.sid: return  new DeletedArea3DPtg(in); // 0x3d, 0x5d, 0x7d
+			case ArrayPtg.sid:    return new ArrayPtg(in);    // 0x20, 0x40, 0x60
+			case FuncPtg.sid:     return new FuncPtg(in);     // 0x21, 0x41, 0x61
+			case FuncVarPtg.sid:  return new FuncVarPtg(in);  // 0x22, 0x42, 0x62
+			case NamePtg.sid:     return new NamePtg(in);     // 0x23, 0x43, 0x63
+			case RefPtg.sid:      return new RefPtg(in);      // 0x24, 0x44, 0x64
+			case AreaPtg.sid:     return new AreaPtg(in);     // 0x25, 0x45, 0x65
+			case MemAreaPtg.sid:  return new MemAreaPtg(in);  // 0x26, 0x46, 0x66
+			case MemErrPtg.sid:   return new MemErrPtg(in);   // 0x27, 0x47, 0x67
+			case MemFuncPtg.sid:  return new MemFuncPtg(in);  // 0x29, 0x49, 0x69
+			case RefErrorPtg.sid: return new RefErrorPtg(in); // 0x2a, 0x4a, 0x6a
+			case AreaErrPtg.sid:  return new AreaErrPtg(in);  // 0x2b, 0x4b, 0x6b
+			case RefNPtg.sid:     return new RefNPtg(in);     // 0x2c, 0x4c, 0x6c
+			case AreaNPtg.sid:    return new AreaNPtg(in);    // 0x2d, 0x4d, 0x6d
+
+			case NameXPtg.sid:    return new NameXPtg(in);    // 0x39, 0x49, 0x79
+			case Ref3DPtg.sid:    return new Ref3DPtg(in);    // 0x3a, 0x5a, 0x7a
+			case Area3DPtg.sid:   return new Area3DPtg(in);   // 0x3b, 0x5b, 0x7b
+			case DeletedRef3DPtg.sid:  return new DeletedRef3DPtg(in);   // 0x3c, 0x5c, 0x7c
+			case DeletedArea3DPtg.sid: return  new DeletedArea3DPtg(in); // 0x3d, 0x5d, 0x7d
 		}
 		throw new UnsupportedOperationException(" Unknown Ptg in Formula: 0x"+
 				   Integer.toHexString(id) + " (" + ( int ) id + ")");
@@ -162,7 +163,7 @@
 			case StringPtg.sid:       return new StringPtg(in);       // 0x17
 			case AttrPtg.sid:                
 			case 0x1a:        return new AttrPtg(in); // 0x19
-			case ErrPtg.sid:          return new ErrPtg(in);          // 0x1c
+			case ErrPtg.sid:          return ErrPtg.read(in);         // 0x1c
 			case BoolPtg.sid:         return new BoolPtg(in);         // 0x1d
 			case IntPtg.sid:          return new IntPtg(in);          // 0x1e
 			case NumberPtg.sid:       return new NumberPtg(in);       // 0x1f
@@ -262,11 +263,14 @@
 
 			ptg.writeBytes(array, pos + offset);
 			if (ptg instanceof ArrayPtg) {
-			  if (arrayPtgs == null)
-				  arrayPtgs = new ArrayList(5);
-			  arrayPtgs.add(ptg);
-			  pos += 8;
-			} else pos += ptg.getSize();
+				if (arrayPtgs == null) {
+					arrayPtgs = new ArrayList(5);
+				}
+				arrayPtgs.add(ptg);
+				pos += ArrayPtg.PLAIN_TOKEN_SIZE;
+			} else {
+				pos += ptg.getSize();
+			}
 		}
 		if (arrayPtgs != null) {
 			for (int i=0;i<arrayPtgs.size();i++) {

Modified: poi/branches/ooxml/src/java/org/apache/poi/hssf/record/formula/atp/AnalysisToolPak.java
URL: http://svn.apache.org/viewvc/poi/branches/ooxml/src/java/org/apache/poi/hssf/record/formula/atp/AnalysisToolPak.java?rev=694947&r1=694946&r2=694947&view=diff
==============================================================================
--- poi/branches/ooxml/src/java/org/apache/poi/hssf/record/formula/atp/AnalysisToolPak.java (original)
+++ poi/branches/ooxml/src/java/org/apache/poi/hssf/record/formula/atp/AnalysisToolPak.java Sat Sep 13 06:48:27 2008
@@ -24,15 +24,14 @@
 import org.apache.poi.hssf.record.formula.eval.Eval;
 import org.apache.poi.hssf.record.formula.eval.ValueEval;
 import org.apache.poi.hssf.record.formula.functions.FreeRefFunction;
-import org.apache.poi.ss.usermodel.Sheet;
 import org.apache.poi.ss.usermodel.Workbook;
 
 public final class AnalysisToolPak {
 
 	private static final FreeRefFunction NotImplemented = new FreeRefFunction() {
 
-		public ValueEval evaluate(Eval[] args, int srcCellRow, short srcCellCol,
-				Workbook workbook, Sheet sheet) {
+		public ValueEval evaluate(Eval[] args, Workbook workbook, int srcCellSheet,
+				int srcCellRow, int srcCellCol) {
 			return ErrorEval.FUNCTION_NOT_IMPLEMENTED;
 		}
 	};

Modified: poi/branches/ooxml/src/java/org/apache/poi/hssf/record/formula/atp/ParityFunction.java
URL: http://svn.apache.org/viewvc/poi/branches/ooxml/src/java/org/apache/poi/hssf/record/formula/atp/ParityFunction.java?rev=694947&r1=694946&r2=694947&view=diff
==============================================================================
--- poi/branches/ooxml/src/java/org/apache/poi/hssf/record/formula/atp/ParityFunction.java (original)
+++ poi/branches/ooxml/src/java/org/apache/poi/hssf/record/formula/atp/ParityFunction.java Sat Sep 13 06:48:27 2008
@@ -42,8 +42,8 @@
 		_desiredParity = desiredParity;
 	}
 
-	public ValueEval evaluate(Eval[] args, int srcCellRow, short srcCellCol, Workbook workbook,
-			Sheet sheet) {
+	public ValueEval evaluate(Eval[] args, Workbook workbook, int srcCellSheet, int srcCellRow,
+			int srcCellCol) {
 		if (args.length != 1) {
 			return ErrorEval.VALUE_INVALID;  
 		}
@@ -58,8 +58,8 @@
 		return BoolEval.valueOf(val == _desiredParity);
 	}
 
-	private static int evaluateArgParity(Eval arg, int srcCellRow, short srcCellCol) throws EvaluationException {
-		ValueEval ve = OperandResolver.getSingleValue(arg, srcCellRow, srcCellCol);
+	private static int evaluateArgParity(Eval arg, int srcCellRow, int srcCellCol) throws EvaluationException {
+		ValueEval ve = OperandResolver.getSingleValue(arg, srcCellRow, (short)srcCellCol);
 		
 		double d = OperandResolver.coerceValueToDouble(ve);
 		if (d < 0) {

Modified: poi/branches/ooxml/src/java/org/apache/poi/hssf/record/formula/atp/YearFrac.java
URL: http://svn.apache.org/viewvc/poi/branches/ooxml/src/java/org/apache/poi/hssf/record/formula/atp/YearFrac.java?rev=694947&r1=694946&r2=694947&view=diff
==============================================================================
--- poi/branches/ooxml/src/java/org/apache/poi/hssf/record/formula/atp/YearFrac.java (original)
+++ poi/branches/ooxml/src/java/org/apache/poi/hssf/record/formula/atp/YearFrac.java Sat Sep 13 06:48:27 2008
@@ -61,8 +61,8 @@
 		// enforce singleton
 	}
 
-	public ValueEval evaluate(Eval[] args, int srcCellRow, short srcCellCol, Workbook workbook,
-			Sheet sheet) {
+	public ValueEval evaluate(Eval[] args, Workbook workbook, int srcCellSheet, int srcCellRow,
+			int srcCellCol) {
 
 		double result;
 		try {
@@ -85,8 +85,8 @@
 		return new NumberEval(result);
 	}
 
-	private static double evaluateDateArg(Eval arg, int srcCellRow, short srcCellCol) throws EvaluationException {
-		ValueEval ve = OperandResolver.getSingleValue(arg, srcCellRow, srcCellCol);
+	private static double evaluateDateArg(Eval arg, int srcCellRow, int srcCellCol) throws EvaluationException {
+		ValueEval ve = OperandResolver.getSingleValue(arg, srcCellRow, (short) srcCellCol);
 
 		if (ve instanceof StringEval) {
 			String strVal = ((StringEval) ve).getStringValue();
@@ -155,8 +155,8 @@
 		return cal;
 	}
 
-	private static int evaluateIntArg(Eval arg, int srcCellRow, short srcCellCol) throws EvaluationException {
-		ValueEval ve = OperandResolver.getSingleValue(arg, srcCellRow, srcCellCol);
+	private static int evaluateIntArg(Eval arg, int srcCellRow, int srcCellCol) throws EvaluationException {
+		ValueEval ve = OperandResolver.getSingleValue(arg, srcCellRow, (short) srcCellCol);
 		return OperandResolver.coerceValueToInt(ve);
 	}
 }

Modified: poi/branches/ooxml/src/java/org/apache/poi/hssf/record/formula/eval/ConcatEval.java
URL: http://svn.apache.org/viewvc/poi/branches/ooxml/src/java/org/apache/poi/hssf/record/formula/eval/ConcatEval.java?rev=694947&r1=694946&r2=694947&view=diff
==============================================================================
--- poi/branches/ooxml/src/java/org/apache/poi/hssf/record/formula/eval/ConcatEval.java (original)
+++ poi/branches/ooxml/src/java/org/apache/poi/hssf/record/formula/eval/ConcatEval.java Sat Sep 13 06:48:27 2008
@@ -1,19 +1,19 @@
-/*
-* 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;
 
@@ -24,7 +24,7 @@
  * @author Amol S. Deshmukh &lt; amolweb at ya hoo dot com &gt;
  *  
  */
-public final class ConcatEval extends StringOperationEval {
+public final class ConcatEval implements OperationEval {
 
     private ConcatPtg delegate;
 
@@ -37,20 +37,23 @@
     		return ErrorEval.VALUE_INVALID;
     	}
         StringBuffer sb = new StringBuffer();
-        for (int i = 0; i < 2; i++) { 
-            
-            ValueEval ve = singleOperandEvaluate(args[i], srcRow, srcCol);
-            if (ve instanceof StringValueEval) {
-                StringValueEval sve = (StringValueEval) ve;
-                sb.append(sve.getStringValue());
-            }
-            else if (ve instanceof BlankEval) {
-                // do nothing
-            }
-            else { // must be an error eval
-                return ve;
-            }
-        }
+        try {
+			for (int i = 0; i < 2; i++) { 
+			    
+			    ValueEval ve = OperandResolver.getSingleValue(args[i], srcRow, srcCol);
+			    if (ve instanceof StringValueEval) {
+			        StringValueEval sve = (StringValueEval) ve;
+			        sb.append(sve.getStringValue());
+			    } else if (ve == BlankEval.INSTANCE) {
+			        // do nothing
+			    } else { // must be an error eval
+			        throw new RuntimeException("Unexpected value type (" 
+			        		+ ve.getClass().getName() + ")");
+			    }
+			}
+		} catch (EvaluationException e) {
+			return e.getErrorEval();
+		}
         
         return new StringEval(sb.toString());
     }

Modified: poi/branches/ooxml/src/java/org/apache/poi/hssf/record/formula/eval/ExternalFunction.java
URL: http://svn.apache.org/viewvc/poi/branches/ooxml/src/java/org/apache/poi/hssf/record/formula/eval/ExternalFunction.java?rev=694947&r1=694946&r2=694947&view=diff
==============================================================================
--- poi/branches/ooxml/src/java/org/apache/poi/hssf/record/formula/eval/ExternalFunction.java (original)
+++ poi/branches/ooxml/src/java/org/apache/poi/hssf/record/formula/eval/ExternalFunction.java Sat Sep 13 06:48:27 2008
@@ -19,7 +19,6 @@
 
 import org.apache.poi.hssf.record.formula.atp.AnalysisToolPak;
 import org.apache.poi.hssf.record.formula.functions.FreeRefFunction;
-import org.apache.poi.ss.usermodel.Sheet;
 import org.apache.poi.ss.usermodel.Workbook;
 /**
  * 
@@ -31,7 +30,8 @@
  */
 final class ExternalFunction implements FreeRefFunction {
 
-	public ValueEval evaluate(Eval[] args, int srcCellRow, short srcCellCol, Workbook workbook, Sheet sheet) {
+	public ValueEval evaluate(Eval[] args, Workbook workbook, 
+			int srcCellSheet, int srcCellRow,int srcCellCol) {
 		
 		int nIncomingArgs = args.length;
 		if(nIncomingArgs < 1) {
@@ -55,7 +55,7 @@
 		int nOutGoingArgs = nIncomingArgs -1;
 		Eval[] outGoingArgs = new Eval[nOutGoingArgs];
 		System.arraycopy(args, 1, outGoingArgs, 0, nOutGoingArgs);
-		return targetFunc.evaluate(outGoingArgs, srcCellRow, srcCellCol, workbook, sheet);
+		return targetFunc.evaluate(outGoingArgs, workbook, srcCellSheet, srcCellRow, srcCellCol);
 	}
 
 	private FreeRefFunction findExternalUserDefinedFunction(Workbook workbook,

Modified: poi/branches/ooxml/src/java/org/apache/poi/hssf/record/formula/eval/FunctionEval.java
URL: http://svn.apache.org/viewvc/poi/branches/ooxml/src/java/org/apache/poi/hssf/record/formula/eval/FunctionEval.java?rev=694947&r1=694946&r2=694947&view=diff
==============================================================================
--- poi/branches/ooxml/src/java/org/apache/poi/hssf/record/formula/eval/FunctionEval.java (original)
+++ poi/branches/ooxml/src/java/org/apache/poi/hssf/record/formula/eval/FunctionEval.java Sat Sep 13 06:48:27 2008
@@ -1,23 +1,20 @@
-/*
-* 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 May 8, 2005
- *
- */
+/* ====================================================================
+   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 java.util.HashMap;
@@ -81,42 +78,42 @@
         retval[1] = new If(); // IF
         retval[2] = new IsNa(); // ISNA
         retval[3] = new IsError(); // ISERROR
-        retval[4] = new Sum(); // SUM
-        retval[5] = new Average(); // AVERAGE
-        retval[6] = new Min(); // MIN
-        retval[7] = new Max(); // MAX
+        retval[4] = AggregateFunction.SUM;
+        retval[5] = AggregateFunction.AVERAGE;
+        retval[6] = AggregateFunction.MIN;
+        retval[7] = AggregateFunction.MAX;
         retval[8] = new Row(); // ROW
         retval[9] = new Column(); // COLUMN
         retval[10] = new Na(); // NA
         retval[11] = new Npv(); // NPV
-        retval[12] = new Stdev(); // STDEV
-        retval[13] = NumericFunctionOneArg.DOLLAR;
+        retval[12] = AggregateFunction.STDEV;
+        retval[13] = NumericFunction.DOLLAR;
         retval[14] = new Fixed(); // FIXED
-        retval[15] = NumericFunctionOneArg.SIN;
-        retval[16] = NumericFunctionOneArg.COS;
-        retval[17] = NumericFunctionOneArg.TAN;
-        retval[18] = NumericFunctionOneArg.ATAN;
+        retval[15] = NumericFunction.SIN;
+        retval[16] = NumericFunction.COS;
+        retval[17] = NumericFunction.TAN;
+        retval[18] = NumericFunction.ATAN;
         retval[19] = new Pi(); // PI
-        retval[20] = NumericFunctionOneArg.SQRT;
-        retval[21] = NumericFunctionOneArg.EXP;
-        retval[22] = NumericFunctionOneArg.LN;
-        retval[23] = NumericFunctionOneArg.LOG10;
-        retval[24] = NumericFunctionOneArg.ABS;
-        retval[25] = NumericFunctionOneArg.INT;
-        retval[26] = NumericFunctionOneArg.SIGN;
-        retval[27] = new Round(); // ROUND
+        retval[20] = NumericFunction.SQRT;
+        retval[21] = NumericFunction.EXP;
+        retval[22] = NumericFunction.LN;
+        retval[23] = NumericFunction.LOG10;
+        retval[24] = NumericFunction.ABS;
+        retval[25] = NumericFunction.INT;
+        retval[26] = NumericFunction.SIGN;
+        retval[27] = NumericFunction.ROUND;
         retval[28] = new Lookup(); // LOOKUP
         retval[29] = new Index(); // INDEX
         retval[30] = new Rept(); // REPT
-        retval[31] = new Mid(); // MID
-        retval[32] = new Len(); // LEN
+        retval[31] = TextFunction.MID;
+        retval[32] = TextFunction.LEN;
         retval[33] = new Value(); // VALUE
         retval[34] = new True(); // TRUE
         retval[35] = new False(); // FALSE
         retval[36] = new And(); // AND
         retval[37] = new Or(); // OR
         retval[38] = new Not(); // NOT
-        retval[39] = new Mod(); // MOD
+        retval[39] = NumericFunction.MOD;
         retval[40] = new Dcount(); // DCOUNT
         retval[41] = new Dsum(); // DSUM
         retval[42] = new Daverage(); // DAVERAGE
@@ -132,16 +129,16 @@
         retval[52] = new Growth(); // GROWTH
         retval[53] = new Goto(); // GOTO
         retval[54] = new Halt(); // HALT
-        retval[56] = new Pv(); // PV
-        retval[57] = new Fv(); // FV
-        retval[58] = new Nper(); // NPER
-        retval[59] = new Pmt(); // PMT
+        retval[56] = FinanceFunction.PV;
+        retval[57] = FinanceFunction.FV;
+        retval[58] = FinanceFunction.NPER;
+        retval[59] = FinanceFunction.PMT;
         retval[60] = new Rate(); // RATE
         retval[61] = new Mirr(); // MIRR
         retval[62] = new Irr(); // IRR
         retval[63] = new Rand(); // RAND
         retval[64] = new Match(); // MATCH
-        retval[65] = new Date(); // DATE
+        retval[65] = DateFunc.instance; // DATE
         retval[66] = new Time(); // TIME
         retval[67] = CalendarFieldFunction.DAY; // DAY
         retval[68] = CalendarFieldFunction.MONTH; // MONTH
@@ -173,9 +170,9 @@
         retval[94] = new Activecell(); // ACTIVECELL
         retval[95] = new NotImplementedFunction(); // SELECTION
         retval[96] = new Result(); // RESULT
-        retval[97] = new Atan2(); // ATAN2
-        retval[98] = NumericFunctionOneArg.ASIN;
-        retval[99] = NumericFunctionOneArg.ACOS;
+        retval[97] = NumericFunction.ATAN2;
+        retval[98] = NumericFunction.ASIN;
+        retval[99] = NumericFunction.ACOS;
         retval[100] = new Choose(); // CHOOSE
         retval[101] = new Hlookup(); // HLOOKUP
         retval[102] = new Vlookup(); // VLOOKUP
@@ -185,16 +182,16 @@
         retval[106] = new NotImplementedFunction(); // GETFORMULA
         retval[107] = new NotImplementedFunction(); // GETNAME
         retval[108] = new Setvalue(); // SETVALUE
-        retval[109] = new Log(); // LOG
+        retval[109] = NumericFunction.LOG;
         retval[110] = new Exec(); // EXEC
         retval[111] = new Char(); // CHAR
-        retval[112] = new Lower(); // LOWER
-        retval[113] = new Upper(); // UPPER
+        retval[112] = TextFunction.LOWER;
+        retval[113] = TextFunction.UPPER;
         retval[114] = new Proper(); // PROPER
-        retval[115] = new Left(); // LEFT
-        retval[116] = new Right(); // RIGHT
-        retval[117] = new Exact(); // EXACT
-        retval[118] = new Trim(); // TRIM
+        retval[115] = TextFunction.LEFT;
+        retval[116] = TextFunction.RIGHT;
+        retval[117] = TextFunction.EXACT;
+        retval[118] = TextFunction.TRIM;
         retval[119] = new Replace(); // REPLACE
         retval[120] = new Substitute(); // SUBSTITUTE
         retval[121] = new Code(); // CODE
@@ -255,8 +252,8 @@
         retval[180] = new NotImplementedFunction(); // RESTART
         retval[181] = new Help(); // HELP
         retval[182] = new NotImplementedFunction(); // GETBAR
-        retval[183] = new Product(); // PRODUCT
-        retval[184] = NumericFunctionOneArg.FACT;
+        retval[183] = AggregateFunction.PRODUCT;
+        retval[184] = NumericFunction.FACT;
         retval[185] = new NotImplementedFunction(); // GETCELL
         retval[186] = new NotImplementedFunction(); // GETWORKSPACE
         retval[187] = new NotImplementedFunction(); // GETWINDOW
@@ -282,8 +279,8 @@
         retval[209] = new Rightb(); // RIGHTB
         retval[210] = new Midb(); // MIDB
         retval[211] = new Lenb(); // LENB
-        retval[212] = new Roundup(); // ROUNDUP
-        retval[213] = new Rounddown(); // ROUNDDOWN
+        retval[212] = NumericFunction.ROUNDUP;
+        retval[213] = NumericFunction.ROUNDDOWN;
         retval[214] = new Asc(); // ASC
         retval[215] = new Dbcs(); // DBCS
         retval[216] = new Rank(); // RANK
@@ -291,14 +288,14 @@
         retval[220] = new Days360(); // DAYS360
         retval[221] = new Today(); // TODAY
         retval[222] = new Vdb(); // VDB
-        retval[227] = new Median(); // MEDIAN
+        retval[227] = AggregateFunction.MEDIAN;
         retval[228] = new Sumproduct(); // SUMPRODUCT
-        retval[229] = NumericFunctionOneArg.SINH;
-        retval[230] = NumericFunctionOneArg.COSH;
-        retval[231] = NumericFunctionOneArg.TANH;
-        retval[232] = NumericFunctionOneArg.ASINH;
-        retval[233] = NumericFunctionOneArg.ACOSH;
-        retval[234] = NumericFunctionOneArg.ATANH;
+        retval[229] = NumericFunction.SINH;
+        retval[230] = NumericFunction.COSH;
+        retval[231] = NumericFunction.TANH;
+        retval[232] = NumericFunction.ASINH;
+        retval[233] = NumericFunction.ACOSH;
+        retval[234] = NumericFunction.ATANH;
         retval[235] = new Dget(); // DGET
         retval[236] = new NotImplementedFunction(); // CREATEOBJECT
         retval[237] = new Volatile(); // VOLATILE
@@ -331,14 +328,14 @@
         retval[266] = new NotImplementedFunction(); // PRESSTOOL
         retval[267] = new NotImplementedFunction(); // REGISTERID
         retval[268] = new NotImplementedFunction(); // GETWORKBOOK
-        retval[269] = new Avedev(); // AVEDEV
+        retval[269] = AggregateFunction.AVEDEV;
         retval[270] = new Betadist(); // BETADIST
         retval[271] = new Gammaln(); // GAMMALN
         retval[272] = new Betainv(); // BETAINV
         retval[273] = new Binomdist(); // BINOMDIST
         retval[274] = new Chidist(); // CHIDIST
         retval[275] = new Chiinv(); // CHIINV
-        retval[276] = new Combin(); // COMBIN
+        retval[276] = NumericFunction.COMBIN;
         retval[277] = new Confidence(); // CONFIDENCE
         retval[278] = new Critbinom(); // CRITBINOM
         retval[279] = new Even(); // EVEN
@@ -347,10 +344,10 @@
         retval[282] = new Finv(); // FINV
         retval[283] = new Fisher(); // FISHER
         retval[284] = new Fisherinv(); // FISHERINV
-        retval[285] = new Floor(); // FLOOR
+        retval[285] = NumericFunction.FLOOR;
         retval[286] = new Gammadist(); // GAMMADIST
         retval[287] = new Gammainv(); // GAMMAINV
-        retval[288] = new Ceiling(); // CEILING
+        retval[288] = NumericFunction.CEILING;
         retval[289] = new Hypgeomdist(); // HYPGEOMDIST
         retval[290] = new Lognormdist(); // LOGNORMDIST
         retval[291] = new Loginv(); // LOGINV
@@ -380,15 +377,15 @@
         retval[315] = new Slope(); // SLOPE
         retval[316] = new Ttest(); // TTEST
         retval[317] = new Prob(); // PROB
-        retval[318] = new Devsq(); // DEVSQ
+        retval[318] = AggregateFunction.DEVSQ;
         retval[319] = new Geomean(); // GEOMEAN
         retval[320] = new Harmean(); // HARMEAN
-        retval[321] = new Sumsq(); // SUMSQ
+        retval[321] = AggregateFunction.SUMSQ;
         retval[322] = new Kurt(); // KURT
         retval[323] = new Skew(); // SKEW
         retval[324] = new Ztest(); // ZTEST
-        retval[325] = new Large(); // LARGE
-        retval[326] = new Small(); // SMALL
+        retval[325] = AggregateFunction.LARGE;
+        retval[326] = AggregateFunction.SMALL;
         retval[327] = new Quartile(); // QUARTILE
         retval[328] = new Percentile(); // PERCENTILE
         retval[329] = new Percentrank(); // PERCENTRANK
@@ -397,14 +394,14 @@
         retval[332] = new Tinv(); // TINV
         retval[334] = new NotImplementedFunction(); // MOVIECOMMAND
         retval[335] = new NotImplementedFunction(); // GETMOVIE
-        retval[336] = new Concatenate(); // CONCATENATE
-        retval[337] = new Power(); // POWER
+        retval[336] = TextFunction.CONCATENATE;
+        retval[337] = NumericFunction.POWER;
         retval[338] = new NotImplementedFunction(); // PIVOTADDDATA
         retval[339] = new NotImplementedFunction(); // GETPIVOTTABLE
         retval[340] = new NotImplementedFunction(); // GETPIVOTFIELD
         retval[341] = new NotImplementedFunction(); // GETPIVOTITEM
-        retval[342] = NumericFunctionOneArg.RADIANS;
-        retval[343] = NumericFunctionOneArg.DEGREES;
+        retval[342] = NumericFunction.RADIANS;
+        retval[343] = NumericFunction.DEGREES;
         retval[344] = new Subtotal(); // SUBTOTAL
         retval[345] = new Sumif(); // SUMIF
         retval[346] = new Countif(); // COUNTIF
@@ -423,8 +420,8 @@
         retval[359] = new Hyperlink(); // HYPERLINK
         retval[360] = new NotImplementedFunction(); // PHONETIC
         retval[361] = new Averagea(); // AVERAGEA
-        retval[362] = new Maxa(); // MAXA
-        retval[363] = new Mina(); // MINA
+        retval[362] = MinaMaxa.MAXA;
+        retval[363] = MinaMaxa.MINA;
         retval[364] = new Stdevpa(); // STDEVPA
         retval[365] = new Varpa(); // VARPA
         retval[366] = new Stdeva(); // STDEVA

Modified: poi/branches/ooxml/src/java/org/apache/poi/hssf/record/formula/eval/OperandResolver.java
URL: http://svn.apache.org/viewvc/poi/branches/ooxml/src/java/org/apache/poi/hssf/record/formula/eval/OperandResolver.java?rev=694947&r1=694946&r2=694947&view=diff
==============================================================================
--- poi/branches/ooxml/src/java/org/apache/poi/hssf/record/formula/eval/OperandResolver.java (original)
+++ poi/branches/ooxml/src/java/org/apache/poi/hssf/record/formula/eval/OperandResolver.java Sat Sep 13 06:48:27 2008
@@ -272,12 +272,7 @@
 			StringValueEval sve = (StringValueEval) ve;
 			return sve.getStringValue();
 		}
-		if (ve instanceof NumberEval) {
-			NumberEval neval = (NumberEval) ve;
-			return neval.getStringValue();
-		} 
-
-		if (ve instanceof BlankEval) {
+		if (ve == BlankEval.INSTANCE) {
 			return "";
 		}
 		throw new IllegalArgumentException("Unexpected eval class (" + ve.getClass().getName() + ")");
@@ -289,7 +284,7 @@
 	 */
 	public static Boolean coerceValueToBoolean(ValueEval ve, boolean stringsAreBlanks) throws EvaluationException {
 
-		if (ve == null || ve instanceof BlankEval) {
+		if (ve == null || ve == BlankEval.INSTANCE) {
 			// TODO - remove 've == null' condition once AreaEval is fixed
 			return null;
 		}
@@ -297,7 +292,7 @@
 			return Boolean.valueOf(((BoolEval) ve).getBooleanValue());
 		}
 
-		if (ve instanceof BlankEval) {
+		if (ve == BlankEval.INSTANCE) {
 			return null;
 		}
 

Modified: poi/branches/ooxml/src/java/org/apache/poi/hssf/record/formula/functions/Even.java
URL: http://svn.apache.org/viewvc/poi/branches/ooxml/src/java/org/apache/poi/hssf/record/formula/functions/Even.java?rev=694947&r1=694946&r2=694947&view=diff
==============================================================================
--- poi/branches/ooxml/src/java/org/apache/poi/hssf/record/formula/functions/Even.java (original)
+++ poi/branches/ooxml/src/java/org/apache/poi/hssf/record/formula/functions/Even.java Sat Sep 13 06:48:27 2008
@@ -22,7 +22,7 @@
  * @author Amol S. Deshmukh &lt; amolweb at ya hoo dot com &gt;
  *  
  */
-public final class Even extends NumericFunctionOneArg {
+public final class Even extends NumericFunction.OneArg {
 
 	private static final long PARITY_MASK = 0xFFFFFFFFFFFFFFFEL;
 

Modified: poi/branches/ooxml/src/java/org/apache/poi/hssf/record/formula/functions/FinanceFunction.java
URL: http://svn.apache.org/viewvc/poi/branches/ooxml/src/java/org/apache/poi/hssf/record/formula/functions/FinanceFunction.java?rev=694947&r1=694946&r2=694947&view=diff
==============================================================================
--- poi/branches/ooxml/src/java/org/apache/poi/hssf/record/formula/functions/FinanceFunction.java (original)
+++ poi/branches/ooxml/src/java/org/apache/poi/hssf/record/formula/functions/FinanceFunction.java Sat Sep 13 06:48:27 2008
@@ -1,71 +1,77 @@
-/*
-* 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
 
-package org.apache.poi.hssf.record.formula.functions;
+       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.
+==================================================================== */
 
-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.NumericValueEval;
-import org.apache.poi.hssf.record.formula.eval.ValueEval;
-import org.apache.poi.hssf.record.formula.eval.ValueEvalToNumericXlator;
+package org.apache.poi.hssf.record.formula.functions;
 
+import org.apache.poi.hssf.record.formula.eval.EvaluationException;
 
 /**
  * @author Amol S. Deshmukh &lt; amolweb at ya hoo dot com &gt;
  * Super class for all Evals for financial function evaluation.
- * 
+ *
  */
-public abstract class FinanceFunction extends NumericFunction {
-    private static final ValueEvalToNumericXlator DEFAULT_NUM_XLATOR =
-        new ValueEvalToNumericXlator((short) (0
-                | ValueEvalToNumericXlator.BOOL_IS_PARSED  
-                | ValueEvalToNumericXlator.REF_BOOL_IS_PARSED  
-                | ValueEvalToNumericXlator.STRING_IS_PARSED  
-                | ValueEvalToNumericXlator.REF_STRING_IS_PARSED  
-                | ValueEvalToNumericXlator.BLANK_IS_PARSED  
-                | ValueEvalToNumericXlator.REF_BLANK_IS_PARSED  
-              //| ValueEvalToNumericXlator.REF_STRING_TO_BOOL_IS_PARSED  
-              //| ValueEvalToNumericXlator.STRING_IS_INVALID_VALUE  
-              //| ValueEvalToNumericXlator.REF_STRING_IS_INVALID_VALUE
-                ));
-    
-    /**
-     * this is the default impl of the factory(ish) method getXlator.
-     * Subclasses can override this method
-     * if they desire to return a different ValueEvalToNumericXlator instance
-     * than the default.
-     */
-    protected final ValueEvalToNumericXlator getXlator() {
-        return DEFAULT_NUM_XLATOR;
-    }
-    
-    protected final ValueEval singleOperandNumericAsBoolean(Eval eval, int srcRow, short srcCol) {
-        ValueEval retval = null;
-        retval = singleOperandEvaluate(eval, srcRow, srcCol);
-        if (retval instanceof NumericValueEval) {
-            NumericValueEval nve = (NumericValueEval) retval;
-            retval = (nve.getNumberValue() == 0)
-                    ? BoolEval.FALSE
-                    : BoolEval.TRUE;
-        }
-        else {
-            retval = ErrorEval.VALUE_INVALID;
-        }
-        return retval;
-    }
+public abstract class FinanceFunction extends NumericFunction.MultiArg {
+
+	protected FinanceFunction() {
+		super (3, 5);
+	}
+
+	protected double evaluate(double[] ds) throws EvaluationException {
+		// All finance functions have 3 to 5 args, first 4 are numbers, last is boolean
+		// default for last 2 args are 0.0 and false
+		// Text boolean literals are not valid for the last arg
+		
+		double arg3 = 0.0;
+		double arg4 = 0.0;
+
+		switch(ds.length) {
+			case 5:
+				arg4 = ds[4];
+			case 4:
+				arg3 = ds[3];
+			case 3:
+				break;
+			default:
+				throw new IllegalStateException("Wrong number of arguments");
+		}
+		return evaluate(ds[0], ds[1], ds[2], arg3, arg4!=0.0);
+	}
+
+	protected abstract double evaluate(double rate, double arg1, double arg2, double arg3, boolean type) throws EvaluationException ;
+
+
+	public static final Function FV = new FinanceFunction() {
+		protected double evaluate(double rate, double arg1, double arg2, double arg3, boolean type) {
+			return FinanceLib.fv(rate, arg1, arg2, arg3, type);
+		}
+	};
+	public static final Function NPER = new FinanceFunction() {
+		protected double evaluate(double rate, double arg1, double arg2, double arg3, boolean type) {
+			return FinanceLib.nper(rate, arg1, arg2, arg3, type);
+		}
+	};
+	public static final Function PMT = new FinanceFunction() {
+		protected double evaluate(double rate, double arg1, double arg2, double arg3, boolean type) {
+			return FinanceLib.pmt(rate, arg1, arg2, arg3, type);
+		}
+	};
+	public static final Function PV = new FinanceFunction() {
+		protected double evaluate(double rate, double arg1, double arg2, double arg3, boolean type) {
+			return FinanceLib.pv(rate, arg1, arg2, arg3, type);
+		}
+	};
 }

Modified: poi/branches/ooxml/src/java/org/apache/poi/hssf/record/formula/functions/FreeRefFunction.java
URL: http://svn.apache.org/viewvc/poi/branches/ooxml/src/java/org/apache/poi/hssf/record/formula/functions/FreeRefFunction.java?rev=694947&r1=694946&r2=694947&view=diff
==============================================================================
--- poi/branches/ooxml/src/java/org/apache/poi/hssf/record/formula/functions/FreeRefFunction.java (original)
+++ poi/branches/ooxml/src/java/org/apache/poi/hssf/record/formula/functions/FreeRefFunction.java Sat Sep 13 06:48:27 2008
@@ -45,13 +45,13 @@
 	 * 
 	 * @param args the pre-evaluated arguments for this function. args is never <code>null</code>,
 	 * 		  nor are any of its elements.
+	 * @param srcCellSheet zero based sheet index of the cell containing the currently evaluating formula
 	 * @param srcCellRow zero based row index of the cell containing the currently evaluating formula 
 	 * @param srcCellCol zero based column index of the cell containing the currently evaluating formula 
 	 * @param workbook is the workbook containing the formula/cell being evaluated
-	 * @param sheet is the sheet containing the formula/cell being evaluated
 	 * @return never <code>null</code>. Possibly an instance of <tt>ErrorEval</tt> in the case of 
 	 * a specified Excel error (Exceptions are never thrown to represent Excel errors).
 	 * 
 	 */
-	ValueEval evaluate(Eval[] args, int srcCellRow, short srcCellCol, Workbook workbook, Sheet sheet);
+	ValueEval evaluate(Eval[] args, Workbook workbook, int srcCellSheet, int srcCellRow, int srcCellCol);
 }



---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@poi.apache.org
For additional commands, e-mail: commits-help@poi.apache.org