]> source.dussan.org Git - poi.git/commitdiff
Further support for whole-column references, including formula strings and the evalua...
authorNick Burch <nick@apache.org>
Fri, 15 Feb 2008 13:50:38 +0000 (13:50 +0000)
committerNick Burch <nick@apache.org>
Fri, 15 Feb 2008 13:50:38 +0000 (13:50 +0000)
git-svn-id: https://svn.apache.org/repos/asf/poi/trunk@628065 13f79535-47bb-0310-9956-ffa450edef68

src/documentation/content/xdocs/changes.xml
src/documentation/content/xdocs/status.xml
src/java/org/apache/poi/hssf/record/formula/Area3DPtg.java
src/java/org/apache/poi/hssf/record/formula/AreaI.java [new file with mode: 0644]
src/java/org/apache/poi/hssf/record/formula/AreaPtg.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/TestBug44410.java
src/testcases/org/apache/poi/hssf/data/SingleLetterRanges.xls

index fc411e2cf730fc2d82798362d6037dfa2b0e4e9b..7ae55cbb0aea56171adce13d014972559efd6917 100644 (file)
@@ -36,7 +36,7 @@
 
                <!-- Don't forget to update status.xml too! -->
         <release version="3.1-beta1" date="2008-??-??">
-           <action dev="POI-DEVELOPERS" type="fix">44410 - Partial support for whole-column ranges, such as C:C, in the formula evaluator</action>
+           <action dev="POI-DEVELOPERS" type="fix">44410 - Support for whole-column ranges, such as C:C, in formula strings and the formula evaluator</action>
            <action dev="POI-DEVELOPERS" type="fix">44421 - Update Match function to properly support Area references</action>
            <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>
index e024f8dc465c7090cdfb40e430c7b91f6f6713a2..2d0943a91fb8e7879505e270985c698a51ca1e39 100644 (file)
@@ -33,7 +33,7 @@
        <!-- Don't forget to update changes.xml too! -->
     <changes>
         <release version="3.1-beta1" date="2008-??-??">
-           <action dev="POI-DEVELOPERS" type="fix">44410 - Partial support for whole-column ranges, such as C:C, in the formula evaluator</action>
+           <action dev="POI-DEVELOPERS" type="fix">44410 - Support for whole-column ranges, such as C:C, in formula strings and the formula evaluator</action>
            <action dev="POI-DEVELOPERS" type="fix">44421 - Update Match function to properly support Area references</action>
            <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>
index 8dd25c76624d89ad67f4c35a2247a3f66a9b36f4..91417994e4d1377cb5af98b66ae6bcffc239c988 100644 (file)
 
 package org.apache.poi.hssf.record.formula;
 
-import org.apache.poi.util.LittleEndian;
-import org.apache.poi.hssf.util.AreaReference;
-import org.apache.poi.hssf.util.CellReference;
-import org.apache.poi.hssf.util.SheetReferences;
-
 import org.apache.poi.hssf.model.Workbook;
 import org.apache.poi.hssf.record.RecordInputStream;
+import org.apache.poi.hssf.util.AreaReference;
+import org.apache.poi.hssf.util.CellReference;
 import org.apache.poi.util.BitField;
 import org.apache.poi.util.BitFieldFactory;
+import org.apache.poi.util.LittleEndian;
 
 
 /**
@@ -38,7 +36,7 @@ import org.apache.poi.util.BitFieldFactory;
  * @version 1.0-pre
  */
 
-public class Area3DPtg extends Ptg
+public class Area3DPtg extends Ptg implements AreaI
 {
        public final static byte sid = 0x3b;
        private final static int SIZE = 11; // 10 + 1 for Ptg
@@ -263,15 +261,18 @@ public class Area3DPtg extends Ptg
      */
        public String toFormulaString(Workbook book)
        {
+               // First do the sheet name
                StringBuffer retval = new StringBuffer();
                String sheetName = Ref3DPtg.getSheetName(book, field_1_index_extern_sheet);
                if(sheetName != null) {
                        SheetNameFormatter.appendFormat(retval, sheetName);
                        retval.append( '!' );
                }
-               retval.append( ( new CellReference( getFirstRow(), getFirstColumn(), !isFirstRowRelative(), !isFirstColRelative() ) ).formatAsString() );
-               retval.append( ':' );
-               retval.append( ( new CellReference( getLastRow(), getLastColumn(), !isLastRowRelative(), !isLastColRelative() ) ).formatAsString() );
+               
+               // Now the normal area bit
+               retval.append( AreaPtg.toFormulaString(this, book) );
+               
+               // All done
                return retval.toString();
        }
 
diff --git a/src/java/org/apache/poi/hssf/record/formula/AreaI.java b/src/java/org/apache/poi/hssf/record/formula/AreaI.java
new file mode 100644 (file)
index 0000000..974ff95
--- /dev/null
@@ -0,0 +1,60 @@
+/* ====================================================================
+   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;
+
+/**
+ * Common interface for AreaPtg and Area3DPtg, and their
+ *  child classes.
+ */
+public interface AreaI {
+    /**
+     * @return the first row in the area
+     */
+    public short getFirstRow();
+
+    /**
+     * @return last row in the range (x2 in x1,y1-x2,y2)
+     */
+    public short getLastRow();
+    
+    /**
+     * @return the first column number in the area.
+     */
+    public short getFirstColumn();
+    
+    /**
+     * @return lastcolumn in the area
+     */
+    public short getLastColumn();
+    
+    /**
+     * @return isrelative first column to relative or not
+     */
+    public boolean isFirstColRelative();
+    /**
+     * @return lastcol relative or not
+     */
+    public boolean isLastColRelative();
+    /**
+     * @return whether or not the first row is a relative reference or not.
+     */
+    public boolean isFirstRowRelative();
+    /**
+     * @return last row relative or not
+     */
+    public boolean isLastRowRelative();
+}
\ No newline at end of file
index 127a9891836f032d96f357fcaad301e005c24adf..ae408c34c7cffe1f3c9e7e3b0a67d919b9556f77 100644 (file)
@@ -34,7 +34,7 @@ import org.apache.poi.hssf.record.RecordInputStream;
  */
 
 public class AreaPtg
-    extends Ptg
+    extends Ptg implements AreaI
 {
     public final static short sid  = 0x25;
     private final static int  SIZE = 9;
@@ -281,14 +281,20 @@ public class AreaPtg
     {
         field_4_last_column = column;
     }
-
+    
     public String toFormulaString(Workbook book)
     {
-         // TODO:
-         //  For a reference like C:C, which is stored as
-         //   C1:C0 (last row is -1), return as C:C 
-         return (new CellReference(getFirstRow(),getFirstColumn(),!isFirstRowRelative(),!isFirstColRelative())).formatAsString() + ":" +
-                (new CellReference(getLastRow(),getLastColumn(),!isLastRowRelative(),!isLastColRelative())).formatAsString();
+       return toFormulaString(this, book);
+    }
+    protected static String toFormulaString(AreaI area, Workbook book) {
+       CellReference topLeft = new CellReference(area.getFirstRow(),area.getFirstColumn(),!area.isFirstRowRelative(),!area.isFirstColRelative());
+       CellReference botRight = new CellReference(area.getLastRow(),area.getLastColumn(),!area.isLastRowRelative(),!area.isLastColRelative());
+       
+       if(AreaReference.isWholeColumnReference(topLeft, botRight)) {
+               return (new AreaReference(topLeft, botRight)).formatAsString();
+       } else {
+               return topLeft.formatAsString() + ":" + botRight.formatAsString(); 
+       }
     }
 
     public byte getDefaultOperandClass() {
index 8a0c9b0bd476217f17787b1cd8b40cdbeda162a2..fbd128842de45883558f789627b521316405e83b 100644 (file)
@@ -47,6 +47,17 @@ public final class AreaReference {
         }
 
         String[] parts = separateAreaRefs(reference);
+        
+        // Special handling for whole-column references
+        if(parts.length == 2 && parts[0].length() == 1 &&
+                       parts[1].length() == 1 && 
+                       parts[0].charAt(0) >= 'A' && parts[0].charAt(0) <= 'Z' &&
+                       parts[1].charAt(0) >= 'A' && parts[1].charAt(0) <= 'Z') {
+               // Represented internally as x$1 to x$0
+               parts[0] = parts[0] + "$1";
+               parts[1] = parts[1] + "$0";
+        }
+        
         _firstCell = new CellReference(parts[0]);
         
         if(parts.length == 2) {
@@ -57,6 +68,15 @@ public final class AreaReference {
             _isSingleCell = true;
         }
     }
+    
+    /**
+     * Creates an area ref from a pair of Cell References.
+     */
+    public AreaReference(CellReference topLeft, CellReference botRight) {
+       _firstCell = topLeft;
+       _lastCell = botRight;
+       _isSingleCell = false;
+    }
 
     /**
      * Is the reference for a contiguous (i.e.
@@ -71,6 +91,24 @@ public final class AreaReference {
         }
         return false;
     }
+    
+    /**
+     * Is the reference for a whole-column reference,
+     *  such as C:C or D:G ?
+     */
+    public static boolean isWholeColumnReference(CellReference topLeft, CellReference botRight) {
+       // These are represented as something like
+       //   C$1:C$0 or D$1:F$0
+       // i.e. absolute from 1st row to 0th one
+       if(topLeft.getRow() == 0 && topLeft.isRowAbsolute() &&
+               botRight.getRow() == -1 && botRight.isRowAbsolute()) {
+               return true;
+       }
+       return false;
+    }
+    public boolean isWholeColumnReference() {
+       return isWholeColumnReference(_firstCell, _lastCell);
+    }
 
     /**
      * Takes a non-contiguous area reference, and
@@ -150,6 +188,14 @@ public final class AreaReference {
      * @return the text representation of this area reference as it would appear in a formula.
      */
     public String formatAsString() {
+       // Special handling for whole-column references
+       if(isWholeColumnReference()) {
+               return
+                       CellReference.convertNumToColString(_firstCell.getCol())
+                       + ":" +
+                       CellReference.convertNumToColString(_lastCell.getCol());
+       }
+       
         StringBuffer sb = new StringBuffer(32);
         sb.append(_firstCell.formatAsString());
         if(!_isSingleCell) {
index 33e33ba95870ebaa78caa3dc7ab0d8ccbbabded1..cb8368772857842a6b538f79e21e45263cf949d0 100644 (file)
@@ -188,9 +188,11 @@ public final class CellReference {
     }
 
     /**
-     * takes in a 0-based base-10 column and returns a ALPHA-26 representation
+     * Takes in a 0-based base-10 column and returns a ALPHA-26
+     *  representation.
+     * eg column #3 -> D
      */
-    private static String convertNumToColString(int col) {
+    protected static String convertNumToColString(int col) {
         String retval = null;
         int mod = col % 26;
         int div = col / 26;
index 4fcda6bcd1034433a03963e82ad91dd9eea0cf5f..03e35e6af29826e6a883025b7b8a62619456b702 100644 (file)
@@ -23,11 +23,9 @@ import java.io.FileInputStream;
 import java.io.File;
 import java.util.List;
 
-import org.apache.poi.hssf.record.FormulaRecord;
 import org.apache.poi.hssf.record.aggregates.FormulaRecordAggregate;
 import org.apache.poi.hssf.record.formula.AreaPtg;
-import org.apache.poi.hssf.record.formula.AttrPtg;
-import org.apache.poi.hssf.record.formula.functions.Sumproduct;
+import org.apache.poi.hssf.record.formula.FuncVarPtg;
 
 /**
  * Bug 44410: SUM(C:C) is valid in excel, and means a sum
@@ -52,6 +50,8 @@ public class TestBug44410 extends TestCase {
         HSSFRow rowIDX = (HSSFRow)sheet.getRow(3);
         // =sum(C:C)         -> 6
         HSSFRow rowSUM = (HSSFRow)sheet.getRow(4);
+        // =sum(C:D)         -> 66
+        HSSFRow rowSUM2D = (HSSFRow)sheet.getRow(5);
         
         // Test the sum
         HSSFCell cellSUM = rowSUM.getCell((short)0);
@@ -59,8 +59,9 @@ public class TestBug44410 extends TestCase {
         FormulaRecordAggregate frec = 
                (FormulaRecordAggregate)cellSUM.getCellValueRecord();
         List ops = frec.getFormulaRecord().getParsedExpression();
+        assertEquals(2, ops.size());
         assertEquals(AreaPtg.class, ops.get(0).getClass());
-        assertEquals(AttrPtg.class, ops.get(1).getClass());
+        assertEquals(FuncVarPtg.class, ops.get(1).getClass());
 
         // Actually stored as C1 to C0 (last row is -1)
         AreaPtg ptg = (AreaPtg)ops.get(0);
@@ -68,12 +69,12 @@ public class TestBug44410 extends TestCase {
         assertEquals(2, ptg.getLastColumn());
         assertEquals(0, ptg.getFirstRow());
         assertEquals(-1, ptg.getLastRow());
-        assertEquals("C$1:C$0", ptg.toFormulaString(wb.getWorkbook()));
+        assertEquals("C:C", ptg.toFormulaString(wb.getWorkbook()));
         
-        // So will show up wrong here, as we don't
-        //  have the sheet to hand when turning the Ptgs
-        //  into a string
-        assertEquals("SUM(C$1:C$0)", cellSUM.getCellFormula());
+        // Will show as C:C, but won't know how many
+        //  rows it covers as we don't have the sheet
+        //  to hand when turning the Ptgs into a string
+        assertEquals("SUM(C:C)", cellSUM.getCellFormula());
         eva.setCurrentRow(rowSUM);
         
         // But the evaluator knows the sheet, so it
@@ -82,12 +83,17 @@ public class TestBug44410 extends TestCase {
         
         
         // Test the index
-        // Again, the formula string will be wrong, as we
-        //  don't have the sheet to hand, but the
-        //  evaluator will be correct
+        // Again, the formula string will be right but
+        //  lacking row count, evaluated will be right
         HSSFCell cellIDX = rowIDX.getCell((short)0);
-        assertEquals("INDEX(C$1:C$0,2,1)", cellIDX.getCellFormula());
+        assertEquals("INDEX(C:C,2,1)", cellIDX.getCellFormula());
         eva.setCurrentRow(rowIDX);
         assertEquals(2, eva.evaluate(cellIDX).getNumberValue(), 0);
+        
+        // Across two colums
+        HSSFCell cellSUM2D = rowSUM2D.getCell((short)0);
+        assertEquals("SUM(C:D)", cellSUM2D.getCellFormula());
+        eva.setCurrentRow(rowSUM2D);
+        assertEquals(66, eva.evaluate(cellSUM2D).getNumberValue(), 0);
     }
 }
index 386f1c8aecab23dc3ee44b02041490d34a9fd3e1..e35058d410f6c8708ed12a3c3dfe574ae30190d2 100644 (file)
Binary files a/src/testcases/org/apache/poi/hssf/data/SingleLetterRanges.xls and b/src/testcases/org/apache/poi/hssf/data/SingleLetterRanges.xls differ