]> source.dussan.org Git - poi.git/commitdiff
Fix from Josh from bug #44417 - Improved handling of references for the need to quote...
authorNick Burch <nick@apache.org>
Fri, 15 Feb 2008 12:04:42 +0000 (12:04 +0000)
committerNick Burch <nick@apache.org>
Fri, 15 Feb 2008 12:04:42 +0000 (12:04 +0000)
git-svn-id: https://svn.apache.org/repos/asf/poi/trunk@628033 13f79535-47bb-0310-9956-ffa450edef68

18 files changed:
src/documentation/content/xdocs/changes.xml
src/documentation/content/xdocs/status.xml
src/java/org/apache/poi/hssf/record/NameRecord.java
src/java/org/apache/poi/hssf/record/formula/Area3DPtg.java
src/java/org/apache/poi/hssf/record/formula/AreaPtg.java
src/java/org/apache/poi/hssf/record/formula/Ref3DPtg.java
src/java/org/apache/poi/hssf/record/formula/ReferencePtg.java
src/java/org/apache/poi/hssf/record/formula/SheetNameFormatter.java
src/java/org/apache/poi/hssf/usermodel/HSSFWorkbook.java
src/java/org/apache/poi/hssf/util/AreaReference.java
src/java/org/apache/poi/hssf/util/CellReference.java
src/scratchpad/testcases/org/apache/poi/hssf/usermodel/TestBug42464.java
src/testcases/org/apache/poi/hssf/HSSFTests.java
src/testcases/org/apache/poi/hssf/usermodel/TestFormulas.java
src/testcases/org/apache/poi/hssf/usermodel/TestNamedRange.java
src/testcases/org/apache/poi/hssf/util/AllHSSFUtilTests.java [new file with mode: 0755]
src/testcases/org/apache/poi/hssf/util/TestAreaReference.java
src/testcases/org/apache/poi/hssf/util/TestCellReference.java

index 1c91e62f85b328e9a472546f57b25773c35b888c..f7e9714e5bd944de715a7b952debaf34d88032fd 100644 (file)
@@ -36,6 +36,7 @@
 
                <!-- Don't forget to update status.xml too! -->
         <release version="3.1-beta1" date="2008-??-??">
+           <action dev="POI-DEVELOPERS" type="fix">44417 - Improved handling of references for the need to quote the sheet name for some formulas, but not when fetching a sheet by name</action>
            <action dev="POI-DEVELOPERS" type="fix">44413 - Fix for circular references in INDEX, OFFSET, VLOOKUP formulas, where a cell is actually allowed to reference itself</action>
            <action dev="POI-DEVELOPERS" type="fix">44403 - Fix for Mid function handling its arguments wrong</action>
            <action dev="POI-DEVELOPERS" type="add">44364 - Support for Match, NA and SumProduct functions, as well as initial function error support</action>
index 67d1ddd4ce3b94ee5bef14552f121f7f0e9b8101..22eca6da818cf023e18e60843ace1e554c224b41 100644 (file)
@@ -33,6 +33,7 @@
        <!-- Don't forget to update changes.xml too! -->
     <changes>
         <release version="3.1-beta1" date="2008-??-??">
+           <action dev="POI-DEVELOPERS" type="fix">44417 - Improved handling of references for the need to quote the sheet name for some formulas, but not when fetching a sheet by name</action>
            <action dev="POI-DEVELOPERS" type="fix">44413 - Fix for circular references in INDEX, OFFSET, VLOOKUP formulas, where a cell is actually allowed to reference itself</action>
            <action dev="POI-DEVELOPERS" type="fix">44403 - Fix for Mid function handling its arguments wrong</action>
            <action dev="POI-DEVELOPERS" type="add">44364 - Support for Match, NA and SumProduct functions, as well as initial function error support</action>
index 3b1c413d58052c702ea05e33d697d7c94c3868cb..a06bc8aedd7c06761d5ae4c2dadbd605a6c091bf 100644 (file)
@@ -726,7 +726,7 @@ public class NameRecord extends Record {
                for(int i=0; i<refs.length; i++) {
                    ptg = new Area3DPtg();
                    ((Area3DPtg) ptg).setExternSheetIndex(externSheetIndex);
-                   ((Area3DPtg) ptg).setArea(refs[i].toString());
+                   ((Area3DPtg) ptg).setArea(refs[i].formatAsString());
                    field_13_name_definition.push(ptg);
                    this.setDefinitionTextLength( (short)(getDefinitionLength() + ptg.getSize()) );
                }
index ac260ffa4eb318d7ebb77e6b97b252eddc5ed934..8dd25c76624d89ad67f4c35a2247a3f66a9b36f4 100644 (file)
@@ -243,21 +243,17 @@ public class Area3DPtg extends Ptg
        public void setArea( String ref )
        {
                AreaReference ar = new AreaReference( ref );
-               CellReference[] crs = ar.getCells();
                
-               CellReference firstCell = crs[0];
-               CellReference lastCell = firstCell;
-               if(crs.length > 1) {
-                       lastCell = crs[1];
-               }
+               CellReference frstCell = ar.getFirstCell();
+               CellReference lastCell = ar.getLastCell();
 
-               setFirstRow(    (short) firstCell.getRow() );
-               setFirstColumn( (short) firstCell.getCol() );
+               setFirstRow(    (short) frstCell.getRow() );
+               setFirstColumn(         frstCell.getCol() );
                setLastRow(     (short) lastCell.getRow() );
-               setLastColumn(  (short) lastCell.getCol() );
-               setFirstColRelative( !firstCell.isColAbsolute() );
+               setLastColumn(          lastCell.getCol() );
+               setFirstColRelative( !frstCell.isColAbsolute() );
                setLastColRelative(  !lastCell.isColAbsolute() );
-               setFirstRowRelative( !firstCell.isRowAbsolute() );
+               setFirstRowRelative( !frstCell.isRowAbsolute() );
                setLastRowRelative(  !lastCell.isRowAbsolute() );
        }
 
@@ -273,9 +269,9 @@ public class Area3DPtg extends Ptg
                        SheetNameFormatter.appendFormat(retval, sheetName);
                        retval.append( '!' );
                }
-               retval.append( ( new CellReference( getFirstRow(), getFirstColumn(), !isFirstRowRelative(), !isFirstColRelative() ) ).toString() );
+               retval.append( ( new CellReference( getFirstRow(), getFirstColumn(), !isFirstRowRelative(), !isFirstColRelative() ) ).formatAsString() );
                retval.append( ':' );
-               retval.append( ( new CellReference( getLastRow(), getLastColumn(), !isLastRowRelative(), !isLastColRelative() ) ).toString() );
+               retval.append( ( new CellReference( getLastRow(), getLastColumn(), !isLastRowRelative(), !isLastColRelative() ) ).formatAsString() );
                return retval.toString();
        }
 
index 908c8d5e3cce9bbcaf1619f98519cd79dee3b0d9..61ce2a0d16c77c920f2c97109c5fefc405186645 100644 (file)
@@ -53,14 +53,16 @@ public class AreaPtg
    
     public AreaPtg(String arearef) {
         AreaReference ar = new AreaReference(arearef);
-        setFirstRow((short)ar.getCells()[0].getRow());
-        setFirstColumn((short)ar.getCells()[0].getCol());
-        setLastRow((short)ar.getCells()[1].getRow());
-        setLastColumn((short)ar.getCells()[1].getCol());
-        setFirstColRelative(!ar.getCells()[0].isColAbsolute());
-        setLastColRelative(!ar.getCells()[1].isColAbsolute());
-        setFirstRowRelative(!ar.getCells()[0].isRowAbsolute());
-        setLastRowRelative(!ar.getCells()[1].isRowAbsolute());        
+        CellReference firstCell = ar.getFirstCell();
+        CellReference lastCell = ar.getLastCell();
+        setFirstRow((short)firstCell.getRow());
+        setFirstColumn(firstCell.getCol());
+        setLastRow((short)lastCell.getRow());
+        setLastColumn(lastCell.getCol());
+        setFirstColRelative(!firstCell.isColAbsolute());
+        setLastColRelative(!lastCell.isColAbsolute());
+        setFirstRowRelative(!firstCell.isRowAbsolute());
+        setLastRowRelative(!lastCell.isRowAbsolute());        
     }
     
     public AreaPtg(short firstRow, short lastRow, short firstColumn, short lastColumn, boolean firstRowRelative, boolean lastRowRelative, boolean firstColRelative, boolean lastColRelative) {
@@ -282,8 +284,8 @@ public class AreaPtg
 
     public String toFormulaString(Workbook book)
     {
-         return (new CellReference(getFirstRow(),getFirstColumn(),!isFirstRowRelative(),!isFirstColRelative())).toString() + ":" +
-                (new CellReference(getLastRow(),getLastColumn(),!isLastRowRelative(),!isLastColRelative())).toString();
+         return (new CellReference(getFirstRow(),getFirstColumn(),!isFirstRowRelative(),!isFirstColRelative())).formatAsString() + ":" +
+                (new CellReference(getLastRow(),getLastColumn(),!isLastRowRelative(),!isLastColRelative())).formatAsString();
     }
 
     public byte getDefaultOperandClass() {
index 510eebb037e9ac2f4dab15a996d848e6284ad98e..ea4c742e2cd146201ce9b1766e751a45782564a9 100644 (file)
@@ -183,7 +183,7 @@ public class Ref3DPtg extends Ptg {
             SheetNameFormatter.appendFormat(retval, sheetName);
             retval.append( '!' );
         }
-        retval.append((new CellReference(getRow(),getColumn(),!isRowRelative(),!isColRelative())).toString()); 
+        retval.append((new CellReference(getRow(),getColumn(),!isRowRelative(),!isColRelative())).formatAsString()); 
         return retval.toString();
     }
 
index df3e5a70bcbe056ad3b39d73eea02cc75bc6a450..3afd6419266cd1a03036193b6bd7f44151fd0137 100644 (file)
@@ -191,7 +191,7 @@ public class ReferencePtg extends Ptg
     public String toFormulaString(Workbook book)
     {
         //TODO -- should we store a cellreference instance in this ptg?? but .. memory is an issue, i believe!
-        return (new CellReference(getRowAsInt(),getColumn(),!isRowRelative(),!isColRelative())).toString();
+        return (new CellReference(getRowAsInt(),getColumn(),!isRowRelative(),!isColRelative())).formatAsString();
     }
     
     public byte getDefaultOperandClass() {
index ba796db3b2475200425cac7ab6caafb3eff8b49c..8e47cbe7a0fc8fd034e56fbdd5c2ead788aa28d2 100755 (executable)
@@ -26,7 +26,7 @@ import java.util.regex.Pattern;
  * 
  * @author Josh Micich
  */
-final class SheetNameFormatter {
+public final class SheetNameFormatter {
        
        private static final String BIFF8_LAST_COLUMN = "IV";
        private static final int BIFF8_LAST_COLUMN_TEXT_LEN = BIFF8_LAST_COLUMN.length();
index e237ed75db23ae926b123ddcd014ebb6b21adb8a..0cbafa32f1dc162f1479f514e7569d032a091c4d 100644 (file)
@@ -1119,12 +1119,12 @@ public class HSSFWorkbook extends POIDocument
        public void setPrintArea(int sheetIndex, int startColumn, int endColumn,
                                                          int startRow, int endRow) {
 
-               //using absolute references because they dont get copied and pasted anyway
+               //using absolute references because they don't get copied and pasted anyway
                CellReference cell = new CellReference(startRow, startColumn, true, true);
-               String reference = cell.toString();
+               String reference = cell.formatAsString();
 
                cell = new CellReference(endRow, endColumn, true, true);
-               reference = reference+":"+cell.toString();
+               reference = reference+":"+cell.formatAsString();
 
                setPrintArea(sheetIndex, reference);
        }
index 8169378e7657900daae42b725b8362e87a944cf8..8a0c9b0bd476217f17787b1cd8b40cdbeda162a2 100644 (file)
@@ -21,26 +21,40 @@ package org.apache.poi.hssf.util;
 import java.util.ArrayList;
 import java.util.StringTokenizer;
 
-public class AreaReference {
-
-
-private CellReference [] cells;
-private int dim;
+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;
 
     /**
-     * Create an area ref from a string representation.
-     * The area reference must be contiguous
+     * 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");
+            throw new IllegalArgumentException(
+                    "References passed to the AreaReference must be contiguous, " +
+                    "use generateContiguous(ref) if you have non-contiguous references");
         }
 
-        String[] refs = seperateAreaRefs(reference);
-        dim = refs.length;
-        cells = new CellReference[dim];
-        for (int i=0;i<dim;i++) {
-            cells[i]=new CellReference(refs[i]);
+        String[] parts = separateAreaRefs(reference);
+        _firstCell = new CellReference(parts[0]);
+        
+        if(parts.length == 2) {
+            _lastCell = new CellReference(parts[1]);
+            _isSingleCell = false;
+        } else {
+            _lastCell = _firstCell;
+            _isSingleCell = true;
         }
     }
 
@@ -73,75 +87,163 @@ private int dim;
         return (AreaReference[])refs.toArray(new AreaReference[refs.size()]);
     }
 
-    //not sure if we need to be flexible here!
-    /** return the dimensions of this area
-     **/
-    public int getDim() {
-        return dim;
+    /**
+     * @return <code>false</code> if this area reference involves more than one cell
+     */
+    public boolean isSingleCell() {
+        return _isSingleCell;
     }
-    /** 
-     * Return the cell references that define this area
-     * (i.e. the two corners) 
+    
+    /**
+     * @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[] getCells() {
-        return cells;
+   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(cells.length == 1) {
-               return cells;
+       if(_isSingleCell) {
+               return  new CellReference[] { _firstCell, };
        }
        // Interpolate between the two
-       int minRow = Math.min(cells[0].getRow(), cells[1].getRow());
-       int maxRow = Math.max(cells[0].getRow(), cells[1].getRow());
-       int minCol = Math.min(cells[0].getCol(), cells[1].getCol());
-       int maxCol = Math.max(cells[0].getCol(), cells[1].getCol());
+        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(row, col, cells[0].isRowAbsolute(), cells[0].isColAbsolute());
-                       ref.setSheetName(cells[0].getSheetName());
+                       CellReference ref = new CellReference(sheetName, row, col, _firstCell.isRowAbsolute(), _firstCell.isColAbsolute());
                        refs.add(ref);
                }
        }
        return (CellReference[])refs.toArray(new CellReference[refs.size()]);
     }
 
-    public String toString() {
-        StringBuffer retval = new StringBuffer();
-        for (int i=0;i<dim;i++){
-            retval.append(':');
-            retval.append(cells[i].toString());
+    /**
+     *  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'&nbsp;</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() {
+        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);
+            }
         }
-        retval.deleteCharAt(0);
-        return retval.toString();
+        return sb.toString();
+    }
+    public String toString() {
+        StringBuffer sb = new StringBuffer(64);
+        sb.append(getClass().getName()).append(" [");
+        sb.append(formatAsString());
+        sb.append("]");
+        return sb.toString();
     }
 
     /**
-     * seperates Area refs in two parts and returns them as seperate elements in a
-     * String array
+     * 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 String[] seperateAreaRefs(String reference) {
-        String[] retval = null;
-
-        int length = reference.length();
-
-        int loc = reference.indexOf(':',0);
-        if(loc == -1){
-           retval = new String[1];
-           retval[0] = reference;
+    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, };
         }
-        else{
-           retval = new String[2];
-           int sheetStart = reference.indexOf("!");
 
-           retval[0] = reference.substring(0, sheetStart+1) + reference.substring(sheetStart + 1,loc);
-           retval[1] = reference.substring(0, sheetStart+1) + reference.substring(loc+1);
+        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, };
         }
-        return retval;
+        
+        String sheetName = partA.substring(0, plingPos + 1); // +1 to include delimiter
+        
+        return new String [] { partA, sheetName + partB, };
     }
 }
\ No newline at end of file
index def58472a8455f8577de38be6ddefe349ec56d05..33e33ba95870ebaa78caa3dc7ab0d8ccbbabded1 100644 (file)
    limitations under the License.
 ==================================================================== */
 
-
 package org.apache.poi.hssf.util;
 
+import org.apache.poi.hssf.record.formula.SheetNameFormatter;
+
 /**
  *
  * @author  Avik Sengupta
  * @author  Dennis Doubleday (patch to seperateRowColumns())
  */
-public class CellReference {
+public final class CellReference {
+    /** The character ($) that signifies a row or column value is absolute instead of relative */ 
+    private static final char ABSOLUTE_REFERENCE_MARKER = '$';
+    /** The character (!) that separates sheet names from cell references */ 
+    private static final char SHEET_NAME_DELIMITER = '!';
+    /** The character (') used to quote sheet names when they contain special characters */
+    private static final char SPECIAL_NAME_DELIMITER = '\'';
+    
 
-    /** Creates new CellReference */
-    private int row;
-    private int col;
-    private String sheetName;
-    private boolean rowAbs;
-    private boolean colAbs;
+    private final int _rowIndex;
+    private final int _colIndex;
+    private final String _sheetName;
+    private final boolean _isRowAbs;
+    private final boolean _isColAbs;
 
+    /**
+     * Create an cell ref from a string representation.  Sheet names containing special characters should be
+     * delimited and escaped as per normal syntax rules for formulas.
+     */
     public CellReference(String cellRef) {
         String[] parts = separateRefParts(cellRef);
-        sheetName = parts[0];
-        String ref = parts[1]; 
-        if ((ref == null)||("".equals(ref)))
-               throw new IllegalArgumentException("Invalid Formula cell reference: '"+cellRef+"'");
-        if (ref.charAt(0) == '$') {
-            colAbs=true;
-            ref=ref.substring(1);
+        _sheetName = parts[0];
+        String colRef = parts[1]; 
+        if (colRef.length() < 1) {
+            throw new IllegalArgumentException("Invalid Formula cell reference: '"+cellRef+"'");
         }
-        col = convertColStringToNum(ref);
-        ref=parts[2];
-        if ((ref == null)||("".equals(ref)))
-               throw new IllegalArgumentException("Invalid Formula cell reference: '"+cellRef+"'");
-        if (ref.charAt(0) == '$') {
-            rowAbs=true;
-            ref=ref.substring(1);
+        _isColAbs = colRef.charAt(0) == '$';
+        if (_isColAbs) {
+            colRef=colRef.substring(1);
         }
-        row = Integer.parseInt(ref)-1;
-    }
-
-    public CellReference(int pRow, int pCol) {
-        this(pRow,pCol,false,false);
+        _colIndex = convertColStringToNum(colRef);
+        
+        String rowRef=parts[2];
+        if (rowRef.length() < 1) {
+            throw new IllegalArgumentException("Invalid Formula cell reference: '"+cellRef+"'");
+        }
+        _isRowAbs = rowRef.charAt(0) == '$';
+        if (_isRowAbs) {
+            rowRef=rowRef.substring(1);
+        }
+        _rowIndex = Integer.parseInt(rowRef)-1; // -1 to convert 1-based to zero-based
     }
 
     public CellReference(int pRow, int pCol, boolean pAbsRow, boolean pAbsCol) {
-        row=pRow;col=pCol;
-        rowAbs = pAbsRow;
-        colAbs=pAbsCol;
-
+        this(null, pRow, pCol, pAbsRow, pAbsCol);
     }
-
-    public int getRow(){return row;}
-    public short getCol(){return (short) col;}
-    public boolean isRowAbsolute(){return rowAbs;}
-    public boolean isColAbsolute(){return colAbs;}
-    public String getSheetName(){return sheetName;}
-    
-    protected void setSheetName(String sheetName) {
-       this.sheetName = sheetName;
+    public CellReference(String pSheetName, int pRow, int pCol, boolean pAbsRow, boolean pAbsCol) {
+        _sheetName = pSheetName;
+        _rowIndex=pRow;
+        _colIndex=pCol;
+        _isRowAbs = pAbsRow;
+        _isColAbs=pAbsCol;
     }
 
+    public int getRow(){return _rowIndex;}
+    public short getCol(){return (short) _colIndex;}
+    public boolean isRowAbsolute(){return _isRowAbs;}
+    public boolean isColAbsolute(){return _isColAbs;}
+    /**
+      * @return possibly <code>null</code> if this is a 2D reference.  Special characters are not
+      * escaped or delimited
+      */
+    public String getSheetName(){
+        return _sheetName;
+    }
+    
     /**
      * takes in a column reference portion of a CellRef and converts it from
      * ALPHA-26 number format to 0-based base 10.
      */
     private int convertColStringToNum(String ref) {
-        int len = ref.length();
+        int lastIx = ref.length()-1;
         int retval=0;
         int pos = 0;
 
-        for (int k = ref.length()-1; k > -1; k--) {
+        for (int k = lastIx; k > -1; k--) {
             char thechar = ref.charAt(k);
             if ( pos == 0) {
                 retval += (Character.getNumericValue(thechar)-9);
@@ -97,36 +113,78 @@ public class CellReference {
 
 
     /**
-     * Seperates the row from the columns and returns an array.  Element in
-     * position one is the substring containing the columns still in ALPHA-26
-     * number format.
+     * Separates the row from the columns and returns an array of three Strings.  The first element
+     * is the sheet name. Only the first element may be null.  The second element in is the column 
+     * name still in ALPHA-26 number format.  The third element is the row.
      */
-    private String[] separateRefParts(String reference) {
-
-        // Look for end of sheet name. This will either set
-        // start to 0 (if no sheet name present) or the
-        // index after the sheet reference ends.
-        String retval[] = new String[3];
-
-        int start = reference.indexOf("!");
-        if (start != -1) retval[0] = reference.substring(0, start);
-        start += 1;
+    private static String[] separateRefParts(String reference) {
+        
+        int plingPos = reference.lastIndexOf(SHEET_NAME_DELIMITER);
+        String sheetName = parseSheetName(reference, plingPos);
+        int start = plingPos+1;
 
         int length = reference.length();
 
 
-        char[] chars = reference.toCharArray();
         int loc = start;
-        if (chars[loc]=='$') loc++;
-        for (; loc < chars.length; loc++) {
-            if (Character.isDigit(chars[loc]) || chars[loc] == '$') {
+        // skip initial dollars 
+        if (reference.charAt(loc)==ABSOLUTE_REFERENCE_MARKER) {
+            loc++;
+        }
+        // step over column name chars until first digit (or dollars) for row number.
+        for (; loc < length; loc++) {
+            char ch = reference.charAt(loc);
+            if (Character.isDigit(ch) || ch == ABSOLUTE_REFERENCE_MARKER) {
                 break;
             }
         }
+        return new String[] {
+           sheetName,
+           reference.substring(start,loc),
+           reference.substring(loc),
+        };
+    }
+
+    private static String parseSheetName(String reference, int indexOfSheetNameDelimiter) {
+        if(indexOfSheetNameDelimiter < 0) {
+            return null;
+        }
+        
+        boolean isQuoted = reference.charAt(0) == SPECIAL_NAME_DELIMITER;
+        if(!isQuoted) {
+            return reference.substring(0, indexOfSheetNameDelimiter);
+        }
+        int lastQuotePos = indexOfSheetNameDelimiter-1;
+        if(reference.charAt(lastQuotePos) != SPECIAL_NAME_DELIMITER) {
+            throw new RuntimeException("Mismatched quotes: (" + reference + ")");
+        }
 
-        retval[1] = reference.substring(start,loc);
-        retval[2] = reference.substring(loc);
-        return retval;
+        // TODO - refactor cell reference parsing logic to one place.
+        // Current known incarnations: 
+        //   FormulaParser.GetName()
+        //   CellReference.parseSheetName() (here)
+        //   AreaReference.separateAreaRefs() 
+        //   SheetNameFormatter.format() (inverse)
+        
+        StringBuffer sb = new StringBuffer(indexOfSheetNameDelimiter);
+        
+        for(int i=1; i<lastQuotePos; i++) { // Note boundaries - skip outer quotes
+            char ch = reference.charAt(i);
+            if(ch != SPECIAL_NAME_DELIMITER) {
+                sb.append(ch);
+                continue;
+            }
+            if(i < lastQuotePos) {
+                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
+                    sb.append(ch);
+                    continue;
+                }
+            }
+            throw new RuntimeException("Bad sheet name quote escaping: (" + reference + ")");
+        }
+        return sb.toString();
     }
 
     /**
@@ -148,14 +206,46 @@ public class CellReference {
         return retval;
     }
 
-
+    /**
+     *  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</td><td>Cell reference without sheet</td></tr>
+     *      <tr><td>Sheet1!A1</td><td>Standard sheet name</td></tr>
+     *      <tr><td>'O''Brien''s Sales'!A1'&nbsp;</td><td>Sheet name with special characters</td></tr>
+     *    </table>
+     * @return the text representation of this cell reference as it would appear in a formula.
+     */
+    public String formatAsString() {
+        StringBuffer sb = new StringBuffer(32);
+        if(_sheetName != null) {
+            SheetNameFormatter.appendFormat(sb, _sheetName);
+            sb.append(SHEET_NAME_DELIMITER);
+        }
+        appendCellReference(sb);
+        return sb.toString();
+    }
+    
     public String toString() {
-        StringBuffer retval = new StringBuffer();
-        retval.append( (colAbs)?"$":"");
-        retval.append( convertNumToColString(col));
-        retval.append((rowAbs)?"$":"");
-        retval.append(row+1);
+        StringBuffer sb = new StringBuffer(64);
+        sb.append(getClass().getName()).append(" [");
+        sb.append(formatAsString());
+        sb.append("]");
+        return sb.toString();
+    }
 
-    return retval.toString();
+    /**
+     * Appends cell reference with '$' markers for absolute values as required.
+     * Sheet name is not included.
+     */
+    /* package */ void appendCellReference(StringBuffer sb) {
+        if(_isColAbs) {
+            sb.append(ABSOLUTE_REFERENCE_MARKER);
+        }
+        sb.append( convertNumToColString(_colIndex));
+        if(_isRowAbs) {
+            sb.append(ABSOLUTE_REFERENCE_MARKER);
+        }
+        sb.append(_rowIndex+1);
     }
 }
index 3b31cc03a3d2460965cfc22661b7501fa19043ac..c849fd4369211fac513871d29646a6ddda4b141b 100644 (file)
@@ -21,14 +21,14 @@ import java.io.FileInputStream;
 import java.util.Iterator;
 import java.util.List;
 
+import junit.framework.TestCase;
+
 import org.apache.poi.hssf.record.FormulaRecord;
 import org.apache.poi.hssf.record.aggregates.FormulaRecordAggregate;
-import org.apache.poi.hssf.record.formula.ExpPtg;
+import org.apache.poi.hssf.usermodel.HSSFFormulaEvaluator.CellValue;
 import org.apache.poi.hssf.util.CellReference;
 
-import junit.framework.TestCase;
-
-public class TestBug42464 extends TestCase {
+public final class TestBug42464 extends TestCase {
        String dirname;
 
        protected void setUp() throws Exception {
@@ -68,26 +68,27 @@ public class TestBug42464 extends TestCase {
                Iterator it = row.cellIterator();
                while(it.hasNext()) {
                        HSSFCell cell = (HSSFCell)it.next();
-                       if(cell.getCellType() == HSSFCell.CELL_TYPE_FORMULA) {
-                               FormulaRecordAggregate record = (FormulaRecordAggregate)
-                                       cell.getCellValueRecord();
-                               FormulaRecord r = record.getFormulaRecord();
-                               List ptgs = r.getParsedExpression();
-                               
-                               String cellRef = (new CellReference(row.getRowNum(), cell.getCellNum())).toString();
-                               if(cellRef.equals("BP24")) {
-                                       System.out.print(cellRef);
-                                       System.out.println(" - has " + r.getNumberOfExpressionTokens() + " ptgs over " + r.getExpressionLength()  + " tokens:");
-                                       for(int i=0; i<ptgs.size(); i++) {
-                                               String c = ptgs.get(i).getClass().toString();
-                                               System.out.println("\t" + c.substring(c.lastIndexOf('.')+1) );
-                                       }
-                                       System.out.println("-> " + cell.getCellFormula());
+                       if(cell.getCellType() != HSSFCell.CELL_TYPE_FORMULA) {
+                           continue;
+                       }
+                       FormulaRecordAggregate record = (FormulaRecordAggregate) cell.getCellValueRecord();
+                       FormulaRecord r = record.getFormulaRecord();
+                       List ptgs = r.getParsedExpression();
+                       
+                       String cellRef = new CellReference(row.getRowNum(), cell.getCellNum(), false, false).formatAsString();
+                       if(false && cellRef.equals("BP24")) { // TODO - replace System.out.println()s with asserts
+                               System.out.print(cellRef);
+                               System.out.println(" - has " + r.getNumberOfExpressionTokens() 
+                                       + " ptgs over " + r.getExpressionLength()  + " tokens:");
+                               for(int i=0; i<ptgs.size(); i++) {
+                                       String c = ptgs.get(i).getClass().toString();
+                                       System.out.println("\t" + c.substring(c.lastIndexOf('.')+1) );
                                }
-                               
-                               eval.evaluate(cell);
-                               
+                               System.out.println("-> " + cell.getCellFormula());
                        }
+                       
+                       CellValue evalResult = eval.evaluate(cell);
+                       assertNotNull(evalResult);
                }
        }
 }
index 1e0edd6825a7300c820f3259f91e3b9885420bef..da37b68adfa4aacbd19694feb1b17948c627d9b7 100644 (file)
@@ -100,11 +100,7 @@ import org.apache.poi.hssf.usermodel.TestReadWriteChart;
 import org.apache.poi.hssf.usermodel.TestSanityChecker;
 import org.apache.poi.hssf.usermodel.TestSheetShiftRows;
 import org.apache.poi.hssf.usermodel.TestWorkbook;
-import org.apache.poi.hssf.util.TestAreaReference;
-import org.apache.poi.hssf.util.TestCellReference;
-import org.apache.poi.hssf.util.TestRKUtil;
-import org.apache.poi.hssf.util.TestRangeAddress;
-import org.apache.poi.hssf.util.TestSheetReferences;
+import org.apache.poi.hssf.util.AllHSSFUtilTests;
 
 /**
  * Test Suite for running just HSSF tests.  Mostly
@@ -202,11 +198,7 @@ public class HSSFTests
         suite.addTest(new TestSuite(TestUnitsRecord.class));
         suite.addTest(new TestSuite(TestValueRangeRecord.class));
         suite.addTest(new TestSuite(TestRowRecordsAggregate.class));
-        suite.addTest(new TestSuite(TestAreaReference.class));
-        suite.addTest(new TestSuite(TestCellReference.class));
-                 suite.addTest(new TestSuite(TestRangeAddress.class));         
-        suite.addTest(new TestSuite(TestRKUtil.class));
-        suite.addTest(new TestSuite(TestSheetReferences.class));
+        suite.addTest(AllHSSFUtilTests.suite());
         
         
         suite.addTest(AllFormulaTests.suite());
index f1e8f497773350e24e788fc74a469072b8f00629..9eb12bd4e1794909dae5eb4f344f232e5c818061 100644 (file)
@@ -302,10 +302,10 @@ extends TestCase {
                 }
                 
                 c = r.getCell((short) y);
-                CellReference cr= new CellReference(refx1,refy1);
-                ref=cr.toString();
-                cr=new CellReference(refx2,refy2);
-                ref2=cr.toString();
+                CellReference cr= new CellReference(refx1,refy1, false, false);
+                ref=cr.formatAsString();
+                cr=new CellReference(refx2,refy2, false, false);
+                ref2=cr.formatAsString();
 
                 c = r.createCell((short) y);
                 c.setCellFormula("" + ref + operator + ref2);
@@ -379,10 +379,10 @@ extends TestCase {
                 }
 
                 c = r.getCell((short) y);
-                CellReference cr= new CellReference(refx1,refy1);
-                ref=cr.toString();
-                cr=new CellReference(refx2,refy2);
-                ref2=cr.toString();
+                CellReference cr= new CellReference(refx1, refy1, false, false);
+                ref=cr.formatAsString();
+                cr=new CellReference(refx2,refy2, false, false);
+                ref2=cr.formatAsString();
                 
                 
                 assertTrue("loop Formula is as expected "+ref+operator+ref2+"!="+c.getCellFormula(),(
index f22de1758cef21b35e731782a87a29eb2a37a253..afbbde026e96eda70d80aa204cf55f221d969e38 100644 (file)
@@ -578,18 +578,16 @@ public class TestNamedRange
         
         // retrieve the cell at the named range and test its contents
         AreaReference aref = new AreaReference(aNamedCell.getReference());
-        CellReference[] crefs = aref.getCells();
-        assertNotNull(crefs);
-        assertEquals("Should be exactly 1 cell in the named cell :'" +cellName+"'", 1, crefs.length);
-        for (int i=0, iSize=crefs.length; i<iSize; i++) {
-            CellReference cref = crefs[i];
-            assertNotNull(cref);
-            HSSFSheet s = wb.getSheet(cref.getSheetName());
-            HSSFRow r = sheet.getRow(cref.getRow());
-            HSSFCell c = r.getCell(cref.getCol());
-            String contents = c.getStringCellValue();
-            assertEquals("Contents of cell retrieved by its named reference", contents, cellValue);
-        }
+        assertTrue("Should be exactly 1 cell in the named cell :'" +cellName+"'", aref.isSingleCell());
+        
+        CellReference cref = aref.getFirstCell();
+        assertNotNull(cref);
+        HSSFSheet s = wb.getSheet(cref.getSheetName());
+        assertNotNull(s);
+        HSSFRow r = sheet.getRow(cref.getRow());
+        HSSFCell c = r.getCell(cref.getCol());
+        String contents = c.getRichStringCellValue().getString();
+        assertEquals("Contents of cell retrieved by its named reference", contents, cellValue);
     }
 
     /**
diff --git a/src/testcases/org/apache/poi/hssf/util/AllHSSFUtilTests.java b/src/testcases/org/apache/poi/hssf/util/AllHSSFUtilTests.java
new file mode 100755 (executable)
index 0000000..1f7aa5f
--- /dev/null
@@ -0,0 +1,39 @@
+/* ====================================================================
+   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.util;
+
+import junit.framework.Test;
+import junit.framework.TestSuite;
+
+/**
+ * Collects all tests for org.apache.poi.hssf.util.
+ * 
+ * @author Josh Micich
+ */
+public class AllHSSFUtilTests {
+       
+       public static Test suite() {
+               TestSuite result = new TestSuite("Tests for org.apache.poi.hssf.util");
+        result.addTestSuite(TestAreaReference.class);
+        result.addTestSuite(TestCellReference.class);
+        result.addTestSuite(TestRangeAddress.class);
+        result.addTestSuite(TestRKUtil.class);
+        result.addTestSuite(TestSheetReferences.class);
+               return result;
+       }
+}
index ccd2a580523df2019724e2f5953924fca76ec944..afdda4435785f28ae88d783fcff8e160496b7fbe 100644 (file)
@@ -1,4 +1,3 @@
-
 /* ====================================================================
    Licensed to the Apache Software Foundation (ASF) under one or more
    contributor license agreements.  See the NOTICE file distributed with
@@ -29,29 +28,28 @@ import org.apache.poi.hssf.record.formula.Area3DPtg;
 import org.apache.poi.hssf.record.formula.UnionPtg;
 
 import java.io.FileInputStream;
+import java.io.IOException;
 import java.io.InputStream;
 import java.util.List;
 
-public class TestAreaReference extends TestCase {
-     public TestAreaReference(String s) {
-        super(s);
-    }
+public final class TestAreaReference extends TestCase {
+
     public void testAreaRef1() {
         AreaReference ar = new AreaReference("$A$1:$B$2");
-        assertTrue("Two cells expected",ar.getCells().length == 2);
-        CellReference cf = ar.getCells()[0];
+        assertFalse("Two cells expected", ar.isSingleCell());
+        CellReference cf = ar.getFirstCell();
         assertTrue("row is 4",cf.getRow()==0);
         assertTrue("col is 1",cf.getCol()==0);
         assertTrue("row is abs",cf.isRowAbsolute());
         assertTrue("col is abs",cf.isColAbsolute());
-        assertTrue("string is $A$1",cf.toString().equals("$A$1"));
+        assertTrue("string is $A$1",cf.formatAsString().equals("$A$1"));
         
-        cf = ar.getCells()[1];
+        cf = ar.getLastCell();
         assertTrue("row is 4",cf.getRow()==1);
         assertTrue("col is 1",cf.getCol()==1);
         assertTrue("row is abs",cf.isRowAbsolute());
         assertTrue("col is abs",cf.isColAbsolute());
-        assertTrue("string is $B$2",cf.toString().equals("$B$2"));
+        assertTrue("string is $B$2",cf.formatAsString().equals("$B$2"));
         
         CellReference[] refs = ar.getAllReferencedCells();
         assertEquals(4, refs.length);
@@ -78,62 +76,31 @@ public class TestAreaReference extends TestCase {
      * Reported by Arne.Clauss@gedas.de
      */
     public void testReferenceWithSheet() {
-       String ref = "Tabelle1!B5";
-               AreaReference myAreaReference = new AreaReference(ref);
-               CellReference[] myCellReference = myAreaReference.getCells();
-
-               assertEquals(1, myCellReference.length);
-               assertNotNull("cell reference not null : "+myCellReference[0]);
-       assertEquals("Not Column B", (short)1,myCellReference[0].getCol());
-               assertEquals("Not Row 5", 4,myCellReference[0].getRow());
-               assertEquals("Shouldn't be absolute", false, myCellReference[0].isRowAbsolute());
-               assertEquals("Shouldn't be absolute", false, myCellReference[0].isColAbsolute());
-               
-               assertEquals(1, myAreaReference.getAllReferencedCells().length);
-               
-               
-               ref = "Tabelle1!$B$5:$B$7";
-               myAreaReference = new AreaReference(ref);
-               myCellReference = myAreaReference.getCells();
-               assertEquals(2, myCellReference.length);
-               
-               assertEquals("Tabelle1", myCellReference[0].getSheetName());
-               assertEquals(4, myCellReference[0].getRow());
-               assertEquals(1, myCellReference[0].getCol());
-               assertTrue(myCellReference[0].isRowAbsolute());
-               assertTrue(myCellReference[0].isColAbsolute());
-               
-               assertEquals("Tabelle1", myCellReference[1].getSheetName());
-               assertEquals(6, myCellReference[1].getRow());
-               assertEquals(1, myCellReference[1].getCol());
-               assertTrue(myCellReference[1].isRowAbsolute());
-               assertTrue(myCellReference[1].isColAbsolute());
-               
-               // And all that make it up
-               myCellReference = myAreaReference.getAllReferencedCells();
-               assertEquals(3, myCellReference.length);
-               
-               assertEquals("Tabelle1", myCellReference[0].getSheetName());
-               assertEquals(4, myCellReference[0].getRow());
-               assertEquals(1, myCellReference[0].getCol());
-               assertTrue(myCellReference[0].isRowAbsolute());
-               assertTrue(myCellReference[0].isColAbsolute());
-               
-               assertEquals("Tabelle1", myCellReference[1].getSheetName());
-               assertEquals(5, myCellReference[1].getRow());
-               assertEquals(1, myCellReference[1].getCol());
-               assertTrue(myCellReference[1].isRowAbsolute());
-               assertTrue(myCellReference[1].isColAbsolute());
-               
-               assertEquals("Tabelle1", myCellReference[2].getSheetName());
-               assertEquals(6, myCellReference[2].getRow());
-               assertEquals(1, myCellReference[2].getCol());
-               assertTrue(myCellReference[2].isRowAbsolute());
-               assertTrue(myCellReference[2].isColAbsolute());
+        AreaReference ar;
+        
+        ar = new AreaReference("Tabelle1!B5");
+        assertTrue(ar.isSingleCell());
+        TestCellReference.confirmCell(ar.getFirstCell(), "Tabelle1", 4, 1, false, false, "Tabelle1!B5");
+        
+        assertEquals(1, ar.getAllReferencedCells().length);
+        
+        
+        ar = new AreaReference("Tabelle1!$B$5:$B$7");
+        assertFalse(ar.isSingleCell());
+        
+        TestCellReference.confirmCell(ar.getFirstCell(), "Tabelle1", 4, 1, true, true, "Tabelle1!$B$5");
+        TestCellReference.confirmCell(ar.getLastCell(), "Tabelle1", 6, 1, true, true, "Tabelle1!$B$7");
+        
+        // And all that make it up
+        CellReference[] allCells = ar.getAllReferencedCells();
+        assertEquals(3, allCells.length);
+        TestCellReference.confirmCell(allCells[0], "Tabelle1", 4, 1, true, true, "Tabelle1!$B$5");
+        TestCellReference.confirmCell(allCells[1], "Tabelle1", 5, 1, true, true, "Tabelle1!$B$6");
+        TestCellReference.confirmCell(allCells[2], "Tabelle1", 6, 1, true, true, "Tabelle1!$B$7");
     }
 
     private static class HSSFWB extends HSSFWorkbook {
-        private HSSFWB(InputStream in) throws Exception {
+        public HSSFWB(InputStream in) throws IOException {
             super(in);
         }
         public Workbook getWorkbook() {
@@ -176,42 +143,42 @@ public class TestAreaReference extends TestCase {
 
         refs = AreaReference.generateContiguous(refSimple);
         assertEquals(1, refs.length);
-        assertEquals(1, refs[0].getDim());
-        assertEquals("$C$10", refs[0].toString());
+        assertTrue(refs[0].isSingleCell());
+        assertEquals("$C$10", refs[0].formatAsString());
 
         refs = AreaReference.generateContiguous(ref2D);
         assertEquals(1, refs.length);
-        assertEquals(2, refs[0].getDim());
-        assertEquals("$C$10:$D$11", refs[0].toString());
+        assertFalse(refs[0].isSingleCell());
+        assertEquals("$C$10:$D$11", refs[0].formatAsString());
 
         refs = AreaReference.generateContiguous(refDCSimple);
         assertEquals(3, refs.length);
-        assertEquals(1, refs[0].getDim());
-        assertEquals(1, refs[1].getDim());
-        assertEquals(1, refs[2].getDim());
-        assertEquals("$C$10", refs[0].toString());
-        assertEquals("$D$12", refs[1].toString());
-        assertEquals("$E$14", refs[2].toString());
+        assertTrue(refs[0].isSingleCell());
+        assertTrue(refs[1].isSingleCell());
+        assertTrue(refs[2].isSingleCell());
+        assertEquals("$C$10", refs[0].formatAsString());
+        assertEquals("$D$12", refs[1].formatAsString());
+        assertEquals("$E$14", refs[2].formatAsString());
 
         refs = AreaReference.generateContiguous(refDC2D);
         assertEquals(3, refs.length);
-        assertEquals(2, refs[0].getDim());
-        assertEquals(1, refs[1].getDim());
-        assertEquals(2, refs[2].getDim());
-        assertEquals("$C$10:$C$11", refs[0].toString());
-        assertEquals("$D$12", refs[1].toString());
-        assertEquals("$E$14:$E$20", refs[2].toString());
+        assertFalse(refs[0].isSingleCell());
+        assertTrue(refs[1].isSingleCell());
+        assertFalse(refs[2].isSingleCell());
+        assertEquals("$C$10:$C$11", refs[0].formatAsString());
+        assertEquals("$D$12", refs[1].formatAsString());
+        assertEquals("$E$14:$E$20", refs[2].formatAsString());
 
         refs = AreaReference.generateContiguous(refDC3D);
         assertEquals(2, refs.length);
-        assertEquals(2, refs[0].getDim());
-        assertEquals(2, refs[1].getDim());
-        assertEquals("$C$10:$C$14", refs[0].toString());
-        assertEquals("$D$10:$D$12", refs[1].toString());
-        assertEquals("Tabelle1", refs[0].getCells()[0].getSheetName());
-        assertEquals("Tabelle1", refs[0].getCells()[1].getSheetName());
-        assertEquals("Tabelle1", refs[1].getCells()[0].getSheetName());
-        assertEquals("Tabelle1", refs[1].getCells()[1].getSheetName());
+        assertFalse(refs[0].isSingleCell());
+        assertFalse(refs[0].isSingleCell());
+        assertEquals("Tabelle1!$C$10:$C$14", refs[0].formatAsString());
+        assertEquals("Tabelle1!$D$10:$D$12", refs[1].formatAsString());
+        assertEquals("Tabelle1", refs[0].getFirstCell().getSheetName());
+        assertEquals("Tabelle1", refs[0].getLastCell().getSheetName());
+        assertEquals("Tabelle1", refs[1].getFirstCell().getSheetName());
+        assertEquals("Tabelle1", refs[1].getLastCell().getSheetName());
     }
 
     public void testDiscontinousReference() throws Exception {
@@ -261,22 +228,46 @@ public class TestAreaReference extends TestCase {
         assertFalse(AreaReference.isContiguous(aNamedCell.getReference()));
         AreaReference[] arefs = AreaReference.generateContiguous(aNamedCell.getReference());
         assertEquals(2, arefs.length);
-        assertEquals(rawRefA, arefs[0].toString());
-        assertEquals(rawRefB, arefs[1].toString());
+        assertEquals(refA, arefs[0].formatAsString());
+        assertEquals(refB, arefs[1].formatAsString());
 
         for(int i=0; i<arefs.length; i++) {
-            CellReference[] crefs = arefs[i].getCells();
-            for (int j=0; j<crefs.length; j++) {
-                // Check it turns into real stuff
-                HSSFSheet s = wb.getSheet(crefs[j].getSheetName());
-                HSSFRow r = s.getRow(crefs[j].getRow());
-                HSSFCell c = r.getCell(crefs[j].getCol());
-            }
+            AreaReference ar = arefs[i];
+            confirmResolveCellRef(wb, ar.getFirstCell());
+            confirmResolveCellRef(wb, ar.getLastCell());
         }
     }
+
+    private static void confirmResolveCellRef(HSSFWorkbook wb, CellReference cref) {
+        HSSFSheet s = wb.getSheet(cref.getSheetName());
+        HSSFRow r = s.getRow(cref.getRow());
+        HSSFCell c = r.getCell(cref.getCol());
+        assertNotNull(c);
+    }
+    
+    public void testSpecialSheetNames() {
+        AreaReference ar;
+        ar = new AreaReference("'Sheet A'!A1");
+        confirmAreaSheetName(ar, "Sheet A", "'Sheet A'!A1");
+        
+        ar = new AreaReference("'Hey! Look Here!'!A1");
+        confirmAreaSheetName(ar, "Hey! Look Here!", "'Hey! Look Here!'!A1");
+        
+        ar = new AreaReference("'O''Toole'!A1:B2");
+        confirmAreaSheetName(ar, "O'Toole", "'O''Toole'!A1:B2");
+        
+        ar = new AreaReference("'one:many'!A1:B2");
+        confirmAreaSheetName(ar, "one:many", "'one:many'!A1:B2");
+    }
+
+    private static void confirmAreaSheetName(AreaReference ar, String sheetName, String expectedFullText) {
+        CellReference[] cells = ar.getAllReferencedCells();
+        assertEquals(sheetName, cells[0].getSheetName());
+        assertEquals(expectedFullText, ar.formatAsString());
+    }
     
-    public static void main(java.lang.String[] args) {
-               junit.textui.TestRunner.run(TestAreaReference.class);
-       }
+    public static void main(String[] args) {
+        junit.textui.TestRunner.run(TestAreaReference.class);
+    }
         
 }
index 88b26fe7ad19c1ce403e54efbfb0450a4340ba66..648fb9a8e32e44ec5c58b36356c54a26ebf041f1 100644 (file)
@@ -1,4 +1,3 @@
-
 /* ====================================================================
    Licensed to the Apache Software Foundation (ASF) under one or more
    contributor license agreements.  See the NOTICE file distributed with
@@ -22,87 +21,74 @@ package org.apache.poi.hssf.util;
 import junit.framework.TestCase;
 
 
-public class TestCellReference extends TestCase {
-    public TestCellReference(String s) {
-        super(s);
-    }
+public final class TestCellReference extends TestCase {
     
     public void testAbsRef1(){
         CellReference cf = new CellReference("$B$5");
-        assertTrue("row is 4",cf.getRow()==4);
-        assertTrue("col is 1",cf.getCol()==1);
-        assertTrue("row is abs",cf.isRowAbsolute());
-        assertTrue("col is abs",cf.isColAbsolute());
-        assertTrue("string is $B$5",cf.toString().equals("$B$5"));
+        confirmCell(cf, null, 4, 1, true, true, "$B$5");
     }
     
     public void  testAbsRef2(){
         CellReference cf = new CellReference(4,1,true,true);
-        assertTrue("row is 4",cf.getRow()==4);
-        assertTrue("col is 1",cf.getCol()==1);
-        assertTrue("row is abs",cf.isRowAbsolute());
-        assertTrue("col is abs",cf.isColAbsolute());
-        assertTrue("string is $B$5",cf.toString().equals("$B$5"));
+        confirmCell(cf, null, 4, 1, true, true, "$B$5");
     }
 
     public void  testAbsRef3(){
         CellReference cf = new CellReference("B$5");
-        assertTrue("row is 4",cf.getRow()==4);
-        assertTrue("col is 1",cf.getCol()==1);
-        assertTrue("row is abs",cf.isRowAbsolute());
-        assertTrue("col is rel",!cf.isColAbsolute());
-        assertTrue("string is B$5",cf.toString().equals("B$5"));
+        confirmCell(cf, null, 4, 1, true, false, "B$5");
     }
     
     public void  testAbsRef4(){
         CellReference cf = new CellReference(4,1,true,false);
-        assertTrue("row is 4",cf.getRow()==4);
-        assertTrue("col is 1",cf.getCol()==1);
-        assertTrue("row is abs",cf.isRowAbsolute());
-        assertTrue("col is rel",!cf.isColAbsolute());
-        assertTrue("string is B$5",cf.toString().equals("B$5"));
+        confirmCell(cf, null, 4, 1, true, false, "B$5");
     }
     
     public void  testAbsRef5(){
         CellReference cf = new CellReference("$B5");
-        assertTrue("row is 4",cf.getRow()==4);
-        assertTrue("col is 1",cf.getCol()==1);
-        assertTrue("row is abs",!cf.isRowAbsolute());
-        assertTrue("col is rel",cf.isColAbsolute());
-        assertTrue("string is B$5",cf.toString().equals("$B5"));
+        confirmCell(cf, null, 4, 1, false, true, "$B5");
     }
     
     public void  testAbsRef6(){
         CellReference cf = new CellReference(4,1,false,true);
-        assertTrue("row is 4",cf.getRow()==4);
-        assertTrue("col is 1",cf.getCol()==1);
-        assertTrue("row is abs",!cf.isRowAbsolute());
-        assertTrue("col is rel",cf.isColAbsolute());
-        assertTrue("string is B$5",cf.toString().equals("$B5"));
+        confirmCell(cf, null, 4, 1, false, true, "$B5");
     }
 
     public void  testAbsRef7(){
         CellReference cf = new CellReference("B5");
-        assertTrue("row is 4",cf.getRow()==4);
-        assertTrue("col is 1",cf.getCol()==1);
-        assertTrue("row is abs",!cf.isRowAbsolute());
-        assertTrue("col is rel",!cf.isColAbsolute());
-        assertTrue("string is B$5",cf.toString().equals("B5"));
+        confirmCell(cf, null, 4, 1, false, false, "B5");
     }
     
     public void  testAbsRef8(){
         CellReference cf = new CellReference(4,1,false,false);
-        assertTrue("row is 4",cf.getRow()==4);
-        assertTrue("col is 1",cf.getCol()==1);
-        assertTrue("row is abs",!cf.isRowAbsolute());
-        assertTrue("col is rel",!cf.isColAbsolute());
-        assertTrue("string is B$5",cf.toString().equals("B5"));
+        confirmCell(cf, null, 4, 1, false, false, "B5");
+    }
+    
+    public void testSpecialSheetNames() {
+        CellReference cf;
+        cf = new CellReference("'profit + loss'!A1");
+        confirmCell(cf, "profit + loss", 0, 0, false, false, "'profit + loss'!A1");
+        
+        cf = new CellReference("'O''Brien''s Sales'!A1");
+        confirmCell(cf, "O'Brien's Sales", 0, 0, false, false, "'O''Brien''s Sales'!A1");
+        
+        cf = new CellReference("'Amazing!'!A1");
+        confirmCell(cf, "Amazing!", 0, 0, false, false, "'Amazing!'!A1");
     }
 
     
+    /* package */ static void confirmCell(CellReference cf, String expSheetName, int expRow, 
+            int expCol, boolean expIsRowAbs, boolean expIsColAbs, String expText) {
+        
+        assertEquals(expSheetName, cf.getSheetName());
+        assertEquals("row index is wrong", expRow, cf.getRow());
+        assertEquals("col index is wrong", expCol, cf.getCol());
+        assertEquals("isRowAbsolute is wrong", expIsRowAbs, cf.isRowAbsolute());
+        assertEquals("isColAbsolute is wrong", expIsColAbs, cf.isColAbsolute());
+        assertEquals("text is wrong", expText, cf.formatAsString());
+    }
+
     public static void main(String [] args) {
         System.out.println("Testing org.apache.poi.hssf.util.TestCellReference");
         junit.textui.TestRunner.run(TestCellReference.class);
     }
-    
 }