]> source.dussan.org Git - poi.git/commitdiff
Merged revisions 642878-642946 via svnmerge from
authorNick Burch <nick@apache.org>
Sat, 5 Apr 2008 13:07:22 +0000 (13:07 +0000)
committerNick Burch <nick@apache.org>
Sat, 5 Apr 2008 13:07:22 +0000 (13:07 +0000)
https://svn.apache.org/repos/asf/poi/trunk

........
  r642878 | josh | 2008-03-31 06:10:35 +0100 (Mon, 31 Mar 2008) | 1 line

  More work on Conditional Formatting (bug 30311) junit and fixes from Dmitriy. Some other clean-up.
........
  r642880 | josh | 2008-03-31 06:19:00 +0100 (Mon, 31 Mar 2008) | 1 line

  removed incorrect test case methods
........
  r642891 | josh | 2008-03-31 06:56:11 +0100 (Mon, 31 Mar 2008) | 1 line

  silenced noisy tests
........
  r642904 | josh | 2008-03-31 07:55:04 +0100 (Mon, 31 Mar 2008) | 1 line

  changes/status for #44675, #44695, #44691
........
  r642946 | yegor | 2008-03-31 10:58:27 +0100 (Mon, 31 Mar 2008) | 1 line

  Implement Sheet.removeShape(Shape shape) in HSLF
........

git-svn-id: https://svn.apache.org/repos/asf/poi/branches/ooxml@645088 13f79535-47bb-0310-9956-ffa450edef68

42 files changed:
src/documentation/content/xdocs/changes.xml
src/documentation/content/xdocs/status.xml
src/java/org/apache/poi/hssf/model/FormulaParser.java
src/java/org/apache/poi/hssf/record/CFHeaderRecord.java
src/java/org/apache/poi/hssf/record/CFRuleRecord.java
src/java/org/apache/poi/hssf/record/ExternalNameRecord.java
src/java/org/apache/poi/hssf/record/aggregates/CFRecordsAggregate.java
src/java/org/apache/poi/hssf/record/cf/CellRange.java
src/java/org/apache/poi/hssf/record/formula/AbstractFunctionPtg.java
src/java/org/apache/poi/hssf/record/formula/FuncPtg.java
src/java/org/apache/poi/hssf/record/formula/FuncVarPtg.java
src/java/org/apache/poi/hssf/record/formula/function/FunctionDataBuilder.java
src/java/org/apache/poi/hssf/record/formula/function/FunctionMetadata.java
src/java/org/apache/poi/hssf/record/formula/function/FunctionMetadataReader.java
src/java/org/apache/poi/hssf/record/formula/function/FunctionMetadataRegistry.java
src/java/org/apache/poi/hssf/record/formula/functions/Pmt.java
src/java/org/apache/poi/hssf/usermodel/HSSFBorderFormatting.java
src/java/org/apache/poi/hssf/usermodel/HSSFConditionalFormatting.java
src/java/org/apache/poi/hssf/usermodel/HSSFConditionalFormattingRule.java
src/java/org/apache/poi/hssf/usermodel/HSSFPatriarch.java
src/java/org/apache/poi/hssf/usermodel/HSSFSheet.java
src/scratchpad/src/org/apache/poi/hslf/model/Sheet.java
src/scratchpad/testcases/org/apache/poi/hslf/model/TestShapes.java
src/testcases/org/apache/poi/hssf/model/TestFormulaParser.java
src/testcases/org/apache/poi/hssf/record/AllRecordTests.java
src/testcases/org/apache/poi/hssf/record/TestCFHeaderRecord.java
src/testcases/org/apache/poi/hssf/record/TestCFRuleRecord.java
src/testcases/org/apache/poi/hssf/record/TestExternalNameRecord.java
src/testcases/org/apache/poi/hssf/record/aggregates/AllRecordAggregateTests.java [new file with mode: 0644]
src/testcases/org/apache/poi/hssf/record/aggregates/TestCFRecordsAggregate.java
src/testcases/org/apache/poi/hssf/record/aggregates/TestColumnInfoRecordsAggregate.java
src/testcases/org/apache/poi/hssf/record/cf/TestCellRange.java
src/testcases/org/apache/poi/hssf/record/formula/AllFormulaTests.java
src/testcases/org/apache/poi/hssf/record/formula/function/AllFormulaFunctionTests.java
src/testcases/org/apache/poi/hssf/record/formula/function/ExcelFileFormatDocFunctionExtractor.java
src/testcases/org/apache/poi/hssf/record/formula/function/TestFunctionMetadataRegistry.java
src/testcases/org/apache/poi/hssf/record/formula/function/TestParseMissingBuiltInFuncs.java
src/testcases/org/apache/poi/hssf/record/formula/function/TestReadMissingBuiltInFuncs.java
src/testcases/org/apache/poi/hssf/record/formula/functions/AllIndividualFunctionEvaluationTests.java
src/testcases/org/apache/poi/hssf/record/formula/functions/TestPmt.java
src/testcases/org/apache/poi/hssf/usermodel/TestBugs.java
src/testcases/org/apache/poi/hssf/usermodel/TestHSSFConfditionalFormatting.java [new file with mode: 0644]

index ab9a4c796ed33a9d9c0a46ec815307d7d39db8b8..5722a7be458761b55cc06067a0d218ca06dbd004 100644 (file)
@@ -26,6 +26,7 @@
         <!-- in strict alphabetical order -->
         <person id="AO" name="Andrew C. Oliver" email="acoliver2@users.sourceforge.net"/>
         <person id="GJS" name="Glen Stampoultzis" email="user@poi.apache.org"/>
+        <person id="JM" name="Josh Micich" email="josh@apache.org"/>
         <person id="MJ" name="Marc Johnson" email="mjohnson@apache.org"/>
         <person id="NKB" name="Nicola Ken Barozzi" email="barozzi@nicolaken.com"/>
         <person id="NB" name="Nick Burch" email="nick@torchbox.com"/>
@@ -36,6 +37,9 @@
 
                <!-- Don't forget to update status.xml too! -->
         <release version="3.0.3-beta1" date="2008-04-??">
+           <action dev="POI-DEVELOPERS" type="add">Implement Sheet.removeShape(Shape shape) in HSLF</action>
+           <action dev="POI-DEVELOPERS" type="add">Various fixes: Recognising var-arg built-in functions #44675, ExternalNameRecord serialisation bug #44695, PMT() bug #44691</action>
+           <action dev="POI-DEVELOPERS" type="add">30311 - More work on Conditional Formatting</action>
            <action dev="POI-DEVELOPERS" type="add">Move the Formula Evaluator code out of scratchpad</action>
            <action dev="POI-DEVELOPERS" type="add">Move the missing record aware eventusermodel code out of scratchpad</action>
            <action dev="POI-DEVELOPERS" type="add">44652 / 44603 - Improved handling of Pictures in Word Documents</action>
index 14c7b817a11462e6d79ba435d1c40d0dd208e061..9d35cb7fd10d8c89485891087d5932ce8469f9b6 100644 (file)
@@ -22,6 +22,7 @@
         <!-- in strict alphabetical order -->
         <person id="AO" name="Andrew C. Oliver" email="acoliver2@users.sourceforge.net"/>
         <person id="GJS" name="Glen Stampoultzis" email="user@poi.apache.org"/>
+        <person id="JM" name="Josh Micich" email="josh@apache.org"/>
         <person id="MJ" name="Marc Johnson" email="mjohnson@apache.org"/>
         <person id="NKB" name="Nicola Ken Barozzi" email="barozzi@nicolaken.com"/>
         <person id="NB" name="Nick Burch" email="nick@torchbox.com"/>
@@ -33,6 +34,9 @@
        <!-- Don't forget to update changes.xml too! -->
     <changes>
         <release version="3.0.3-beta1" date="2008-04-??">
+           <action dev="POI-DEVELOPERS" type="add">Implement Sheet.removeShape(Shape shape) in HSLF</action>
+           <action dev="POI-DEVELOPERS" type="add">Various fixes: Recognising var-arg built-in functions #44675, ExternalNameRecord serialisation bug #44695, PMT() bug #44691</action>
+           <action dev="POI-DEVELOPERS" type="add">30311 - More work on Conditional Formatting</action>
            <action dev="POI-DEVELOPERS" type="add">Move the Formula Evaluator code out of scratchpad</action>
            <action dev="POI-DEVELOPERS" type="add">Move the missing record aware eventusermodel code out of scratchpad</action>
            <action dev="POI-DEVELOPERS" type="add">44652 / 44603 - Improved handling of Pictures in Word Documents</action>
index e6eb296702d245ebb47b4dc88915553660b42a93..721928474339001a7a9d67eebe4e800fc55413f0 100644 (file)
@@ -28,8 +28,6 @@ import org.apache.poi.hssf.record.formula.*;
 import org.apache.poi.hssf.record.formula.function.FunctionMetadata;
 import org.apache.poi.hssf.record.formula.function.FunctionMetadataRegistry;
 
-
-
 /**
  * This class parses a formula string into a List of tokens in RPN order.
  * Inspired by
@@ -48,11 +46,11 @@ import org.apache.poi.hssf.record.formula.function.FunctionMetadataRegistry;
  *  @author Pavel Krupets (pkrupets at palmtreebusiness dot com)
  */
 public final class FormulaParser {
-    
+
     /**
      * Specific exception thrown when a supplied formula does not parse properly.<br/>
      * Primarily used by test cases when testing for specific parsing exceptions.</p>
-     *    
+     *
      */
     static final class FormulaParseException extends RuntimeException {
         // This class was given package scope until it would become clear that it is useful to
index 00a8646b4f50ee54723c41354d241cb5024884b8..7f2d5c319782da76973e618016cc30bd8289449e 100644 (file)
    limitations under the License.
 ==================================================================== */
 
-/*
- * ConditionalFormattingHeaderRecord.java
- *
- * Created on January 17, 2008, 3:05 AM
- */
 package org.apache.poi.hssf.record;
 
-import java.util.ArrayList;
-import java.util.Iterator;
-import java.util.List;
-
 import org.apache.poi.hssf.record.cf.CellRange;
+import org.apache.poi.hssf.util.Region;
 import org.apache.poi.util.LittleEndian;
 
 /**
@@ -34,19 +26,27 @@ import org.apache.poi.util.LittleEndian;
  * 
  * @author Dmitriy Kumshayev
  */
-public class CFHeaderRecord extends Record
+public final class CFHeaderRecord extends Record
 {
        public static final short sid = 0x1B0;
 
+       private static final CellRange[] EMPTY_CELL_RANGE_ARRAY = { };
+
        private int field_1_numcf;
        private int field_2_need_recalculation;
        private CellRange field_3_enclosing_cell_range;
-       private List field_4_cell_ranges;
+       private CellRange[] field_4_cell_ranges;
 
        /** Creates new CFHeaderRecord */
        public CFHeaderRecord()
        {
-               field_4_cell_ranges = new ArrayList(5);
+               field_4_cell_ranges = EMPTY_CELL_RANGE_ARRAY;
+       }
+       public CFHeaderRecord(Region[] regions)
+       {
+               CellRange[] unmergedRanges = CellRange.convertRegionsToCellRanges(regions);
+               CellRange[] mergeCellRanges = CellRange.mergeCellRanges(unmergedRanges);
+               setCellRanges(mergeCellRanges);
        }
 
        public CFHeaderRecord(RecordInputStream in)
@@ -60,11 +60,12 @@ public class CFHeaderRecord extends Record
                field_2_need_recalculation = in.readShort();
                field_3_enclosing_cell_range = new CellRange(in.readShort(),in.readShort(),in.readShort(),in.readShort());
                int numCellRanges = in.readShort();
-               field_4_cell_ranges = new ArrayList(5);
+               CellRange[] crs = new CellRange[numCellRanges];
                for( int i=0; i<numCellRanges; i++)
                {
-                       field_4_cell_ranges.add(new CellRange(in.readShort(),in.readShort(),in.readShort(),in.readShort()));
+                       crs[i] = new CellRange(in.readShort(),in.readShort(),in.readShort(),in.readShort());
                }
+               field_4_cell_ranges = crs;
        }
        
        public int getNumberOfConditionalFormats()
@@ -101,28 +102,24 @@ public class CFHeaderRecord extends Record
         * modify the enclosing cell range accordingly.
         * @param List cellRanges - list of CellRange objects
         */
-       public void setCellRanges( List cellRanges )
+       public void setCellRanges(CellRange[] cellRanges)
        {
-               field_4_cell_ranges.clear();
-               if(cellRanges!=null)
+               if(cellRanges == null)
                {
-                       field_3_enclosing_cell_range=null;
-                       for( int i=0; i<cellRanges.size(); i++)
-                       {
-                               field_4_cell_ranges.add(cellRanges.get(i));
-                               recalculateEnclosingRange((CellRange)cellRanges.get(i));
-                       }
+                       throw new IllegalArgumentException("cellRanges must not be null");
                }
-       }
-
-       private void recalculateEnclosingRange(CellRange cellRange)
-       {
-               field_3_enclosing_cell_range = cellRange.createEnclosingCellRange(field_3_enclosing_cell_range);
+               field_4_cell_ranges = (CellRange[]) cellRanges.clone();
+               CellRange enclosingRange = null;
+               for (int i = 0; i < cellRanges.length; i++)
+               {
+                       enclosingRange = cellRanges[i].createEnclosingCellRange(enclosingRange);
+               }
+               field_3_enclosing_cell_range=enclosingRange;
        }
        
-       public List getCellRanges()
+       public CellRange[] getCellRanges()
        {
-               return field_4_cell_ranges;
+               return (CellRange[]) field_4_cell_ranges.clone();
        }
 
        public String toString()
@@ -130,16 +127,16 @@ public class CFHeaderRecord extends Record
                StringBuffer buffer = new StringBuffer();
 
                buffer.append("[CFHEADER]\n");
-        buffer.append("    .id        = ").append(Integer.toHexString(sid)).append("\n");
-               buffer.append("    .numCF            = ").append(getNumberOfConditionalFormats()).append("\n");
-               buffer.append("    .needRecalc       = ").append(getNeedRecalculation()).append("\n");
-               buffer.append("    .enclosingCellRange= ").append(getEnclosingCellRange()).append("\n");
-               if( field_4_cell_ranges.size()>0)
+               buffer.append(" .id             = ").append(Integer.toHexString(sid)).append("\n");
+               buffer.append(" .numCF                  = ").append(getNumberOfConditionalFormats()).append("\n");
+               buffer.append(" .needRecalc        = ").append(getNeedRecalculation()).append("\n");
+               buffer.append(" .enclosingCellRange= ").append(getEnclosingCellRange()).append("\n");
+               if( field_4_cell_ranges.length>0)
                {
-                       buffer.append("    .cfranges=[");
-                       for( int i=0; i<field_4_cell_ranges.size(); i++)
+                       buffer.append(" .cfranges=[");
+                       for( int i=0; i<field_4_cell_ranges.length; i++)
                        {
-                               buffer.append(i==0?"":",").append(field_4_cell_ranges.get(i));
+                               buffer.append(i==0?"":",").append(field_4_cell_ranges[i].toString());
                        }
                        buffer.append("]\n");
                }
@@ -163,24 +160,21 @@ public class CFHeaderRecord extends Record
                LittleEndian.putShort(data, 10 + offset, (short) field_3_enclosing_cell_range.getLastRow());
                LittleEndian.putShort(data, 12 + offset, (short) field_3_enclosing_cell_range.getFirstColumn());
                LittleEndian.putShort(data, 14 + offset, (short) field_3_enclosing_cell_range.getLastColumn());
-               LittleEndian.putShort(data, 16 + offset, (short) field_4_cell_ranges.size());
-               for( int i=0 ; i!=field_4_cell_ranges.size(); i++)
+               LittleEndian.putShort(data, 16 + offset, (short) field_4_cell_ranges.length);
+               for( int i=0 ; i!=field_4_cell_ranges.length; i++)
                {
-                       LittleEndian.putShort(data, 18 + 0 + 8 * i + offset,
-                                       (short) ((CellRange) field_4_cell_ranges.get(i)).getFirstRow());
-                       LittleEndian.putShort(data, 18 + 2 + 8 * i + offset,
-                                       (short) ((CellRange) field_4_cell_ranges.get(i)).getLastRow());
-                       LittleEndian.putShort(data, 18 + 4 + 8 * i + offset,
-                                       (short) ((CellRange) field_4_cell_ranges.get(i)).getFirstColumn());
-                       LittleEndian.putShort(data, 18 + 6 + 8 * i + offset,
-                                       (short) ((CellRange) field_4_cell_ranges.get(i)).getLastColumn());
+                       CellRange cr = field_4_cell_ranges[i];
+                       LittleEndian.putShort(data, 18 + 0 + 8 * i + offset, (short) cr.getFirstRow());
+                       LittleEndian.putShort(data, 18 + 2 + 8 * i + offset, (short) cr.getLastRow());
+                       LittleEndian.putShort(data, 18 + 4 + 8 * i + offset, (short) cr.getFirstColumn());
+                       LittleEndian.putShort(data, 18 + 6 + 8 * i + offset, (short) cr.getLastColumn());
                }
                return getRecordSize();
        }
 
        public int getRecordSize()
        {
-               return 18+8*field_4_cell_ranges.size();
+               return 18+8*field_4_cell_ranges.length;
        }
 
        /**
@@ -204,20 +198,17 @@ public class CFHeaderRecord extends Record
                return sid;
        }
 
-    public Object clone() 
-    {
-       CFHeaderRecord rec = new CFHeaderRecord();
-       rec.field_1_numcf = field_1_numcf;
-       rec.field_2_need_recalculation = field_2_need_recalculation;
-       rec.field_3_enclosing_cell_range = field_3_enclosing_cell_range;
-        rec.field_4_cell_ranges = new ArrayList(field_4_cell_ranges.size());
-        Iterator iterator = field_4_cell_ranges.iterator();
-        while (iterator.hasNext()) 
-        {
-           CellRange oldRange = (CellRange)iterator.next();
-           rec.field_4_cell_ranges.add(oldRange.cloneCellRange());
-        }
-        return rec;
-    }
-
+       public Object clone() 
+       {
+               CFHeaderRecord result = new CFHeaderRecord();
+               result.field_1_numcf = field_1_numcf;
+               result.field_2_need_recalculation = field_2_need_recalculation;
+               result.field_3_enclosing_cell_range = field_3_enclosing_cell_range;
+               CellRange[] crs = new CellRange[field_4_cell_ranges.length];
+               for (int i = 0; i < crs.length; i++) {
+                       crs[i] = field_4_cell_ranges[i].cloneCellRange();
+               }
+               result.field_4_cell_ranges = crs;
+               return result;
+       }
 }
index 01084434608644b05bdda2aaf7d28c473c1449ce..43da6260acd355fb044f000be31e97cd5fc5f2d1 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
 ==================================================================== */
         
 
-/*
- * ConditionalFormattingRuleRecord.java
- *
- * Created on January 23, 2008, 9:56 AM
- */
 package org.apache.poi.hssf.record;
 
-import java.util.List;
 import java.util.Stack;
 
+import org.apache.poi.hssf.model.FormulaParser;
+import org.apache.poi.hssf.model.Workbook;
 import org.apache.poi.hssf.record.cf.BorderFormatting;
 import org.apache.poi.hssf.record.cf.FontFormatting;
 import org.apache.poi.hssf.record.cf.PatternFormatting;
@@ -39,316 +34,292 @@ import org.apache.poi.util.LittleEndian;
  * Conditional Formatting Rule Record.
  * @author Dmitriy Kumshayev
  */
-
-public class CFRuleRecord extends Record
+public final class CFRuleRecord extends Record
 {
-    
-    public static final short sid = 0x01B1;
-    
-    private byte             field_1_condition_type;
-    public static final byte CONDITION_TYPE_NO_CONDITION_TYPE = 0;
-    public static final byte CONDITION_TYPE_CELL_VALUE_IS = 1;
-    public static final byte CONDITION_TYPE_FORMULA = 2;
-    
-    private byte             field_2_comparison_operator;
-    public static final byte COMPARISON_OPERATOR_NO_COMPARISON = 0;
-    public static final byte COMPARISON_OPERATOR_BETWEEN          = 1;
-    public static final byte COMPARISON_OPERATOR_NOT_BETWEEN   = 2;
-    public static final byte COMPARISON_OPERATOR_EQUAL         = 3;
-    public static final byte COMPARISON_OPERATOR_NOT_EQUAL     = 4;
-    public static final byte COMPARISON_OPERATOR_GT            = 5;
-    public static final byte COMPARISON_OPERATOR_LT            = 6;
-    public static final byte COMPARISON_OPERATOR_GE            = 7;
-    public static final byte COMPARISON_OPERATOR_LE            = 8;
-    
-    private short            field_3_formula1_len;
-    private short            field_4_formula2_len;
-    
-    private int              field_5_options;
-
-    private static final BitField modificationBits = BitFieldFactory.getInstance(0x83FFFFFF); // Bits: font,align,bord,patt,prot
-    private static final BitField alignHor             = BitFieldFactory.getInstance(0x00000001); // 0 = Horizontal alignment modified
-       private static final BitField alignVer          = BitFieldFactory.getInstance(0x00000002); // 0 = Vertical alignment modified
-       private static final BitField alignWrap         = BitFieldFactory.getInstance(0x00000004); // 0 = Text wrapped flag modified
-       private static final BitField alignRot          = BitFieldFactory.getInstance(0x00000008); // 0 = Text rotation modified
-       private static final BitField alignJustLast = BitFieldFactory.getInstance(0x00000010); // 0 = Justify last line flag modified
-       private static final BitField alignIndent       = BitFieldFactory.getInstance(0x00000020); // 0 = Indentation modified
-       private static final BitField alignShrink       = BitFieldFactory.getInstance(0x00000040); // 0 = Shrink to fit flag modified
-       private static final BitField notUsed1          = BitFieldFactory.getInstance(0x00000080); // Always 1
-       private static final BitField protLocked    = BitFieldFactory.getInstance(0x00000100); // 0 = Cell locked flag modified
-       private static final BitField protHidden        = BitFieldFactory.getInstance(0x00000200); // 0 = Cell hidden flag modified
-       private static final BitField bordLeft          = BitFieldFactory.getInstance(0x00000400); // 0 = Left border style and colour modified
-       private static final BitField bordRight         = BitFieldFactory.getInstance(0x00000800); // 0 = Right border style and colour modified
-       private static final BitField bordTop           = BitFieldFactory.getInstance(0x00001000); // 0 = Top border style and colour modified
-       private static final BitField bordBot           = BitFieldFactory.getInstance(0x00002000); // 0 = Bottom border style and colour modified
-       private static final BitField bordTlBr          = BitFieldFactory.getInstance(0x00004000); // 0 = Top-left to bottom-right border flag modified
-       private static final BitField bordBlTr          = BitFieldFactory.getInstance(0x00008000); // 0 = Bottom-left to top-right border flag modified
-       private static final BitField pattStyle         = BitFieldFactory.getInstance(0x00010000); // 0 = Pattern style modified
-       private static final BitField pattCol           = BitFieldFactory.getInstance(0x00020000); // 0 = Pattern colour modified
-       private static final BitField pattBgCol         = BitFieldFactory.getInstance(0x00040000); // 0 = Pattern background colour modified
-       private static final BitField notUsed2          = BitFieldFactory.getInstance(0x00380000); // Always 111
-       private static final BitField undocumented      = BitFieldFactory.getInstance(0x03C00000); // Undocumented bits
-    private static final BitField fmtBlockBits  = BitFieldFactory.getInstance(0x7C000000); // Bits: font,align,bord,patt,prot
-       private static final BitField font                      = BitFieldFactory.getInstance(0x04000000); // 1 = Record contains font formatting block
-       private static final BitField align             = BitFieldFactory.getInstance(0x08000000); // 1 = Record contains alignment formatting block
-       private static final BitField bord              = BitFieldFactory.getInstance(0x10000000); // 1 = Record contains border formatting block
-       private static final BitField patt              = BitFieldFactory.getInstance(0x20000000); // 1 = Record contains pattern formatting block
-       private static final BitField prot              = BitFieldFactory.getInstance(0x40000000); // 1 = Record contains protection formatting block
-       private static final BitField alignTextDir      = BitFieldFactory.getInstance(0x80000000); // 0 = Text direction modified
-    
-    
-    private short            field_6_not_used;
-    
-    private FontFormatting fontFormatting;
-
-    private byte                        field_8_align_text_break;
-    private byte                        field_9_align_text_rotation_angle;
-    private short                       field_10_align_indentation;
-    private short                       field_11_relative_indentation;
-    private short                       field_12_not_used;
-    
-    private BorderFormatting borderFormatting;
-
-    private PatternFormatting patternFormatting;
-    
-    private Stack            field_17_formula1;
-    private Stack            field_18_formula2;
-    
-    /** Creates new CFRuleRecord */
-    public CFRuleRecord()
-    {
-       field_1_condition_type=CONDITION_TYPE_NO_CONDITION_TYPE;
-       field_2_comparison_operator=COMPARISON_OPERATOR_NO_COMPARISON;
-       setExpression1Length((short)0);
-       setExpression2Length((short)0);
-       
-       // Set modification flags to 1: by default options are not modified
-       setOptions(modificationBits.setValue(field_5_options, -1));
-       // Set formatting block flags to 0 (no formatting blocks)
-       setOptions(fmtBlockBits.setValue(field_5_options, 0));
-       
-       field_6_not_used = 0;
-       fontFormatting=null;
-        field_8_align_text_break = 0;
-        field_9_align_text_rotation_angle = 0;
-        field_10_align_indentation = 0;
-        field_11_relative_indentation = 0;
-        field_12_not_used = 0;
-       borderFormatting=null;
-       patternFormatting=null;
-       field_17_formula1=null;
-       field_18_formula2=null;
-    }
-
-    /**
-     * Constructs a Formula record and sets its fields appropriately.
-     * Note - id must be 0x06 (NOT 0x406 see MSKB #Q184647 for an 
-     * "explanation of this bug in the documentation) or an exception
-     *  will be throw upon validation
-     *
-     * @param in the RecordInputstream to read the record from
-     */
-
-    public CFRuleRecord(RecordInputStream in)
-    {
-        super(in);
-    }
-
-    protected void fillFields(RecordInputStream in)
-    {
-        try {
-          field_1_condition_type               = in.readByte();
-          field_2_comparison_operator   = in.readByte();
-          field_3_formula1_len                 = in.readShort();
-          field_4_formula2_len                 = in.readShort();
-          field_5_options                              = in.readInt();
-          field_6_not_used              = in.readShort();
-
-          if(containsFontFormattingBlock())
-          {
-               fontFormatting = new FontFormatting(in);
-          }
-
-          if(containsBorderFormattingBlock())
-          {
-                 borderFormatting = new BorderFormatting(in);
-          }
-                  
-          if( containsPatternFormattingBlock())
-          {
-                 patternFormatting =  new PatternFormatting(in);
-          }
-          
-          if(field_3_formula1_len>0)
-          {
-              field_17_formula1 = Ptg.createParsedExpressionTokens(field_3_formula1_len, in);
-              
-              // Now convert any fields as required
-              field_17_formula1 = SharedFormulaRecord.convertSharedFormulas(
-                  field_17_formula1, 0, 0
-              );
-          }
-          if(field_4_formula2_len>0)
-          {
-              field_18_formula2 = Ptg.createParsedExpressionTokens(field_4_formula2_len, in);
-              
-              // Now convert any fields as required
-              field_18_formula2 = SharedFormulaRecord.convertSharedFormulas(
-                  field_18_formula2, 0, 0
-              );
-          }
-        } catch (java.lang.UnsupportedOperationException uoe)  {
-          throw new RecordFormatException(uoe);
-        }
-        
-    }
-    
-    public void setConditionType(byte conditionType)
-    {
-       field_1_condition_type = 
-               conditionType == CONDITION_TYPE_CELL_VALUE_IS ? 
-                       CONDITION_TYPE_CELL_VALUE_IS :
-                               CONDITION_TYPE_FORMULA;
-    }
-
-    public byte getConditionType()
-    {
-       return field_1_condition_type;
-    }
-
-    /**
-     * set the option flags
-     *
-     * @param options  bitmask
-     */
-
-    public void setOptions(int options)
-    {
-        field_5_options = options;
-    }
-
-    public boolean containsFontFormattingBlock()
-    {
-       return getOptionFlag(font);
-    }
-    public void setFontFormatting(FontFormatting fontFormatting)
-    {
-       this.fontFormatting = fontFormatting;
-       setOptionFlag(true,font);
-    }
-    public void setFontFormattingUnchanged()
-    {
-       setOptionFlag(false,font);
-    }
-    
-    public boolean containsAlignFormattingBlock()
-    {
-       return getOptionFlag(align);
-    }
-    public void setAlignFormattingUnchanged()
-    {
-       setOptionFlag(false,align);
-    }
-    
-    public boolean containsBorderFormattingBlock()
-    {
-       return getOptionFlag(bord);
-    }
-    public void setBorderFormatting(BorderFormatting borderFormatting)
-    {
-       this.borderFormatting = borderFormatting;
-       setOptionFlag(true,bord);
-    }
-    public void setBorderFormattingUnchanged()
-    {
-       setOptionFlag(false,bord);
-    }
-    
-    public boolean containsPatternFormattingBlock()
-    {
-       return getOptionFlag(patt);
-    }
-    public void setPatternFormatting(PatternFormatting patternFormatting)
-    {
-       this.patternFormatting = patternFormatting;
-       setOptionFlag(true,patt);
-    }
-    public void setPatternFormattingUnchanged()
-    {
-       setOptionFlag(false,patt);
-    }
-    
-    public boolean containsProtectionFormattingBlock()
-    {
-       return getOptionFlag(prot);
-    }
-    public void setProtectionFormattingUnchanged()
-    {
-       setOptionFlag(false,prot);
-    }
-    
-    public void setComparisonOperation(byte operation)
-    {
-       field_2_comparison_operator = operation;
-    }
-
-    public byte getComparisonOperation()
-    {
-       return field_2_comparison_operator;
-    }
-    
-    /**
-     * set the length (in number of tokens) of the expression 1
-     * @param len  length
-     */
-
-    private void setExpression1Length(short len)
-    {
-        field_3_formula1_len = len;
-    }
-
-    /**
-     * get the length (in number of tokens) of the expression 1
-     * @return  expression length
-     */
-
-    public short getExpression1Length()
-    {
-        return field_3_formula1_len;
-    }
-    
-    /**
-     * set the length (in number of tokens) of the expression 2
-     * @param len  length
-     */
-
-    private void setExpression2Length(short len)
-    {
-       field_4_formula2_len = len;
-    }
-
-    /**
-     * get the length (in number of tokens) of the expression 2
-     * @return  expression length
-     */
-
-    public short getExpression2Length()
-    {
-        return field_4_formula2_len;
-    }
-    /**
-     * get the option flags
-     *
-     * @return bit mask
-     */
-    public int getOptions()
-    {
-        return field_5_options;
-    }    
-
-    private boolean isModified(BitField field)
-       {
-       return !field.isSet(field_5_options);
+
+       public static final short sid = 0x01B1;
+
+       public static final class ComparisonOperator {
+               public static final byte NO_COMPARISON = 0;
+               public static final byte BETWEEN       = 1;
+               public static final byte NOT_BETWEEN   = 2;
+               public static final byte EQUAL         = 3;
+               public static final byte NOT_EQUAL     = 4;
+               public static final byte GT            = 5;
+               public static final byte LT            = 6;
+               public static final byte GE            = 7;
+               public static final byte LE            = 8;
+       }
+
+       private byte  field_1_condition_type;
+       public static final byte CONDITION_TYPE_CELL_VALUE_IS = 1;
+       public static final byte CONDITION_TYPE_FORMULA = 2;
+
+       private byte  field_2_comparison_operator;
+
+       private short field_3_formula1_len;
+       private short field_4_formula2_len;
+
+       private int   field_5_options;
+
+       private static final BitField modificationBits = bf(0x83FFFFFF); // Bits: font,align,bord,patt,prot
+       private static final BitField alignHor      = bf(0x00000001); // 0 = Horizontal alignment modified
+       private static final BitField alignVer      = bf(0x00000002); // 0 = Vertical alignment modified
+       private static final BitField alignWrap     = bf(0x00000004); // 0 = Text wrapped flag modified
+       private static final BitField alignRot      = bf(0x00000008); // 0 = Text rotation modified
+       private static final BitField alignJustLast = bf(0x00000010); // 0 = Justify last line flag modified
+       private static final BitField alignIndent   = bf(0x00000020); // 0 = Indentation modified
+       private static final BitField alignShrin    = bf(0x00000040); // 0 = Shrink to fit flag modified
+       private static final BitField notUsed1      = bf(0x00000080); // Always 1
+       private static final BitField protLocked    = bf(0x00000100); // 0 = Cell locked flag modified
+       private static final BitField protHidden    = bf(0x00000200); // 0 = Cell hidden flag modified
+       private static final BitField bordLeft      = bf(0x00000400); // 0 = Left border style and colour modified
+       private static final BitField bordRight     = bf(0x00000800); // 0 = Right border style and colour modified
+       private static final BitField bordTop       = bf(0x00001000); // 0 = Top border style and colour modified
+       private static final BitField bordBot       = bf(0x00002000); // 0 = Bottom border style and colour modified
+       private static final BitField bordTlBr      = bf(0x00004000); // 0 = Top-left to bottom-right border flag modified
+       private static final BitField bordBlTr      = bf(0x00008000); // 0 = Bottom-left to top-right border flag modified
+       private static final BitField pattStyle     = bf(0x00010000); // 0 = Pattern style modified
+       private static final BitField pattCol       = bf(0x00020000); // 0 = Pattern colour modified
+       private static final BitField pattBgCol     = bf(0x00040000); // 0 = Pattern background colour modified
+       private static final BitField notUsed2      = bf(0x00380000); // Always 111
+       private static final BitField undocumented  = bf(0x03C00000); // Undocumented bits
+       private static final BitField fmtBlockBits  = bf(0x7C000000); // Bits: font,align,bord,patt,prot
+       private static final BitField font          = bf(0x04000000); // 1 = Record contains font formatting block
+       private static final BitField align         = bf(0x08000000); // 1 = Record contains alignment formatting block
+       private static final BitField bord          = bf(0x10000000); // 1 = Record contains border formatting block
+       private static final BitField patt          = bf(0x20000000); // 1 = Record contains pattern formatting block
+       private static final BitField prot          = bf(0x40000000); // 1 = Record contains protection formatting block
+       private static final BitField alignTextDir  = bf(0x80000000); // 0 = Text direction modified
+
+
+       private static BitField bf(int i) {
+               return BitFieldFactory.getInstance(i);
+       }
+
+       private short field_6_not_used;
+
+       private FontFormatting fontFormatting;
+
+       private byte  field_8_align_text_break;
+       private byte  field_9_align_text_rotation_angle;
+       private short field_10_align_indentation;
+       private short field_11_relative_indentation;
+       private short field_12_not_used;
+       
+       private BorderFormatting borderFormatting;
+
+       private PatternFormatting patternFormatting;
+       
+       private Ptg[] field_17_formula1;
+       private Ptg[] field_18_formula2;
+       
+       /** Creates new CFRuleRecord */
+       private CFRuleRecord(byte conditionType, byte comparisonOperation)
+       {
+               field_1_condition_type=conditionType;
+               field_2_comparison_operator=comparisonOperation;
+               field_3_formula1_len = (short)0;
+               field_4_formula2_len = (short)0;
+
+               // Set modification flags to 1: by default options are not modified
+               field_5_options = modificationBits.setValue(field_5_options, -1);
+               // Set formatting block flags to 0 (no formatting blocks)
+               field_5_options = fmtBlockBits.setValue(field_5_options, 0);
+               field_5_options = undocumented.clear(field_5_options);
+
+               field_6_not_used = (short)0x8002; // Excel seems to write this value, but it doesn't seem to care what it reads
+               fontFormatting=null;
+               field_8_align_text_break = 0;
+               field_9_align_text_rotation_angle = 0;
+               field_10_align_indentation = 0;
+               field_11_relative_indentation = 0;
+               field_12_not_used = 0;
+               borderFormatting=null;
+               patternFormatting=null;
+               field_17_formula1=null;
+               field_18_formula2=null;
+       }
+       
+       private CFRuleRecord(byte conditionType, byte comparisonOperation, Ptg[] formula1, Ptg[] formula2) {
+               this(conditionType, comparisonOperation); 
+               field_1_condition_type = CONDITION_TYPE_CELL_VALUE_IS;
+               field_2_comparison_operator = comparisonOperation;
+               setParsedExpression1(formula1);
+               setParsedExpression2(formula2);
+       }
+
+       /**
+        * Creates a new comparison operation rule
+        */
+       public static CFRuleRecord create(Workbook workbook, String formulaText) {
+               Ptg[] formula1 = parseFormula(formulaText, workbook);
+               return new CFRuleRecord(CONDITION_TYPE_FORMULA, ComparisonOperator.NO_COMPARISON,
+                               formula1, null);
+       }
+       /**
+        * Creates a new comparison operation rule
+        */
+       public static CFRuleRecord create(Workbook workbook, byte comparisonOperation,
+                       String formulaText1, String formulaText2) {
+               Ptg[] formula1 = parseFormula(formulaText1, workbook);
+               Ptg[] formula2 = parseFormula(formulaText2, workbook);
+               return new CFRuleRecord(CONDITION_TYPE_CELL_VALUE_IS, comparisonOperation, formula1, formula2);
+               
+       }
+
+       /**
+        * Constructs a Formula record and sets its fields appropriately.
+        * Note - id must be 0x06 (NOT 0x406 see MSKB #Q184647 for an 
+        * "explanation of this bug in the documentation) or an exception
+        *  will be throw upon validation
+        *
+        * @param in the RecordInputstream to read the record from
+        */
+
+       public CFRuleRecord(RecordInputStream in)
+       {
+               super(in);
+       }
+
+
+
+       protected void fillFields(RecordInputStream in) {
+               try {
+                       field_1_condition_type = in.readByte();
+                       field_2_comparison_operator = in.readByte();
+                       field_3_formula1_len = in.readShort();
+                       field_4_formula2_len = in.readShort();
+                       field_5_options = in.readInt();
+                       field_6_not_used = in.readShort();
+
+                       if (containsFontFormattingBlock()) {
+                               fontFormatting = new FontFormatting(in);
+                       }
+
+                       if (containsBorderFormattingBlock()) {
+                               borderFormatting = new BorderFormatting(in);
+                       }
+
+                       if (containsPatternFormattingBlock()) {
+                               patternFormatting = new PatternFormatting(in);
+                       }
+
+                       if (field_3_formula1_len > 0) {
+                               Stack ptgs = Ptg.createParsedExpressionTokens(field_3_formula1_len, in);
+                               // Now convert any fields as required
+                               ptgs = SharedFormulaRecord.convertSharedFormulas(ptgs, 0, 0);
+                               field_17_formula1 = toArray(ptgs);
+                       }
+                       if (field_4_formula2_len > 0) {
+                               Stack ptgs = Ptg.createParsedExpressionTokens(field_4_formula2_len, in);
+
+                               // Now convert any fields as required
+                               ptgs = SharedFormulaRecord.convertSharedFormulas(ptgs, 0, 0);
+                               field_18_formula2 = toArray(ptgs);
+                       }
+               } catch (java.lang.UnsupportedOperationException uoe) {
+                       throw new RecordFormatException(uoe);
+               }
+
+       }
+
+       public byte getConditionType()
+       {
+               return field_1_condition_type;
+       }
+
+       public boolean containsFontFormattingBlock()
+       {
+               return getOptionFlag(font);
+       }
+       public void setFontFormatting(FontFormatting fontFormatting)
+       {
+               this.fontFormatting = fontFormatting;
+               setOptionFlag(fontFormatting != null, font);
+       }
+       
+       public boolean containsAlignFormattingBlock()
+       {
+               return getOptionFlag(align);
+       }
+       public void setAlignFormattingUnchanged()
+       {
+               setOptionFlag(false,align);
+       }
+       
+       public boolean containsBorderFormattingBlock()
+       {
+               return getOptionFlag(bord);
+       }
+       public void setBorderFormatting(BorderFormatting borderFormatting)
+       {
+               this.borderFormatting = borderFormatting;
+               setOptionFlag(borderFormatting != null, bord);
+       }
+       
+       public boolean containsPatternFormattingBlock()
+       {
+               return getOptionFlag(patt);
+       }
+       public void setPatternFormatting(PatternFormatting patternFormatting)
+       {
+               this.patternFormatting = patternFormatting;
+               setOptionFlag(patternFormatting!=null, patt);
+       }
+
+       
+       public boolean containsProtectionFormattingBlock()
+       {
+               return getOptionFlag(prot);
+       }
+       public void setProtectionFormattingUnchanged()
+       {
+               setOptionFlag(false,prot);
+       }
+       
+       public void setComparisonOperation(byte operation)
+       {
+               field_2_comparison_operator = operation;
+       }
+
+       public byte getComparisonOperation()
+       {
+               return field_2_comparison_operator;
+       }
+       
+
+       /**
+        * get the length (in number of tokens) of the expression 1
+        * @return  expression length
+        */
+       private short getExpression1Length()
+       {
+               return field_3_formula1_len;
+       }
+       
+
+       /**
+        * get the length (in number of tokens) of the expression 2
+        * @return  expression length
+        */
+       private short getExpression2Length()
+       {
+               return field_4_formula2_len;
+       }
+       /**
+        * get the option flags
+        *
+        * @return bit mask
+        */
+       public int getOptions()
+       {
+               return field_5_options;
+       }       
+
+       private boolean isModified(BitField field)
+       {
+               return !field.isSet(field_5_options);
        }
 
        private void setModified(boolean modified, BitField field)
@@ -365,7 +336,7 @@ public class CFRuleRecord extends Record
        {
                setModified(modified,bordLeft);
        }
-    
+       
        public boolean isRightBorderModified()
        {
                return isModified(bordRight);
@@ -375,7 +346,7 @@ public class CFRuleRecord extends Record
        {
                setModified(modified,bordRight);
        }
-    
+       
        public boolean isTopBorderModified()
        {
                return isModified(bordTop);
@@ -385,7 +356,7 @@ public class CFRuleRecord extends Record
        {
                setModified(modified,bordTop);
        }
-    
+       
        public boolean isBottomBorderModified()
        {
                return isModified(bordBot);
@@ -395,7 +366,7 @@ public class CFRuleRecord extends Record
        {
                setModified(modified,bordBot);
        }
-    
+       
        public boolean isTopLeftBottomRightBorderModified()
        {
                return isModified(bordTlBr);
@@ -405,7 +376,7 @@ public class CFRuleRecord extends Record
        {
                setModified(modified,bordTlBr);
        }
-    
+       
        public boolean isBottomLeftTopRightBorderModified()
        {
                return isModified(bordBlTr);
@@ -415,7 +386,7 @@ public class CFRuleRecord extends Record
        {
                setModified(modified,bordBlTr);
        }
-    
+       
        public boolean isPatternStyleModified()
        {
                return isModified(pattStyle);
@@ -446,9 +417,9 @@ public class CFRuleRecord extends Record
                setModified(modified,pattBgCol);
        }
        
-    private boolean getOptionFlag(BitField field)
+       private boolean getOptionFlag(BitField field)
        {
-       return field.isSet(field_5_options);
+               return field.isSet(field_5_options);
        }
 
        private void setOptionFlag(boolean flag, BitField field)
@@ -456,202 +427,226 @@ public class CFRuleRecord extends Record
                field_5_options = field.setBoolean(field_5_options, flag);
        }
        
-    /**
-     * get the stack of the 1st expression as a list
-     *
-     * @return list of tokens (casts stack to a list and returns it!)
-     * this method can return null is we are unable to create Ptgs from 
-     *     existing excel file
-     * callers should check for null!
-     */
-
-    public List getParsedExpression1()
-    {
-        return field_17_formula1;
-    }
-
-    /**
-     * get the stack of the 2nd expression as a list
-     *
-     * @return list of tokens (casts stack to a list and returns it!)
-     * this method can return null is we are unable to create Ptgs from 
-     *     existing excel file
-     * callers should check for null!
-     */
-
-    public List getParsedExpression2()
-    {
-        return field_18_formula2;
-    }
-    
-    public void setParsedExpression1(Stack ptgs) {
-      setExpression1Length(getTotalPtgSize(field_17_formula1 = ptgs));
-    }
-
-    public void setParsedExpression2(Stack ptgs) {
-        setExpression1Length(getTotalPtgSize(field_18_formula2 = ptgs));
-    }
-    
-    /**
-     * called by constructor, should throw runtime exception in the event of a
-     * record passed with a differing ID.
-     *
-     * @param id alleged id for this record
-     */
-
-    protected void validateSid(short id)
-    {
-        if (id != sid)
-        {
-            throw new RecordFormatException("NOT A CFRULE RECORD");
-        }
-    }
-
-    public short getSid()
-    {
-        return sid;
-    }
-
-    /**
-     * called by the class that is responsible for writing this sucker.
-     * Subclasses should implement this so that their data is passed back in a
-     * byte array.
-     *
-     * @param offset to begin writing at
-     * @param data byte array containing instance data
-     * @return number of bytes written
-     */
-
-    public int serialize(int offset, byte [] data)
-    {
-       int recordsize = getRecordSize();
-        LittleEndian.putShort(data, 0 + offset, sid);
-        LittleEndian.putShort(data, 2 + offset, (short)(recordsize-4));
-        data[4 + offset] = field_1_condition_type;
-        data[5 + offset] = field_2_comparison_operator;
-        LittleEndian.putShort(data, 6 + offset, field_3_formula1_len);
-        LittleEndian.putShort(data, 8 + offset, field_4_formula2_len);
-        LittleEndian.putInt(data,  10 + offset, field_5_options);
-        LittleEndian.putShort(data,14 + offset, field_6_not_used);
-        
-        offset += 16;
-        
-        if( containsFontFormattingBlock() )
-        {
-               byte[] fontFormattingRawRecord  = fontFormatting.getRawRecord();
-               System.arraycopy(fontFormattingRawRecord, 0, data, offset, fontFormattingRawRecord.length);
-               offset += fontFormattingRawRecord.length;
-        }
-        
-        if( containsBorderFormattingBlock())
-        {
-               offset += borderFormatting.serialize(offset, data);
-        }
-        
-        if( containsPatternFormattingBlock() )
-        {
-               offset += patternFormatting.serialize(offset, data);
-        }
-        
-        if (getExpression1Length()>0)
-        {
-            Ptg.serializePtgStack(this.field_17_formula1, data, offset);
-            offset += getExpression1Length();
-        }
-
-        if (getExpression2Length()>0)
-        {
-            Ptg.serializePtgStack(this.field_18_formula2, data, offset);
-            offset += getExpression2Length();
-        }
-        return recordsize;
-    }
-    
-    
-    
-
-    public int getRecordSize()
-    {
-        int retval =16+
-                               (containsFontFormattingBlock()?fontFormatting.getRawRecord().length:0)+
-                               (containsBorderFormattingBlock()?8:0)+
-                               (containsPatternFormattingBlock()?4:0)+
-                               getExpression1Length()+
-                               getExpression2Length()
-                               ;
-        return retval;
-    }
-
-    private short getTotalPtgSize(List list)
-    {
-       short  retval = 0;
-       if( list!=null)
-       {
-            for (int k = 0; k < list.size(); k++)
-            {
-                Ptg ptg = ( Ptg ) list.get(k);
-
-                retval += ptg.getSize();
-            }
-       }
-        return retval;
-    }
-
-    public String toString()
-    {
-        StringBuffer buffer = new StringBuffer();
-        buffer.append("[CFRULE]\n");
-        if( containsFontFormattingBlock())
-        {
-            buffer.append(fontFormatting.toString());
-        }
-        if( containsBorderFormattingBlock())
-        {
-            buffer.append(borderFormatting.toString());
-        }
-        if( containsPatternFormattingBlock())
-        {
-            buffer.append(patternFormatting.toString());
-        }
-        buffer.append("[/CFRULE]\n");
-        return buffer.toString();
-    }
-    
-    public Object clone() {
-      CFRuleRecord rec = new CFRuleRecord();
-      rec.field_1_condition_type= field_1_condition_type;
-      rec.field_2_comparison_operator = field_2_comparison_operator;
-      rec.field_3_formula1_len = field_3_formula1_len;
-      rec.field_4_formula2_len = field_4_formula2_len;
-      rec.field_5_options = field_5_options;
-      rec.field_6_not_used = field_6_not_used;
-      if( containsFontFormattingBlock())
-      {
-         rec.fontFormatting = (FontFormatting)fontFormatting.clone();
-      }
-      if( containsBorderFormattingBlock())
-      {
-         rec.borderFormatting = (BorderFormatting)borderFormatting.clone();
-      }
-      if( containsPatternFormattingBlock())
-      {
-         rec.patternFormatting = (PatternFormatting)patternFormatting.clone();
-      }
-      if( field_3_formula1_len>0)
-      {
-          rec.field_17_formula1 = (Stack)field_17_formula1.clone();
-      }
-      if( field_4_formula2_len>0)
-      {
-          rec.field_18_formula2 = (Stack)field_18_formula2.clone();
-      }
-      
-      return rec;
-    }
+       /**
+        * get the stack of the 1st expression as a list
+        *
+        * @return list of tokens (casts stack to a list and returns it!)
+        * this method can return null is we are unable to create Ptgs from 
+        *       existing excel file
+        * callers should check for null!
+        */
+
+       public Ptg[] getParsedExpression1()
+       {
+               return field_17_formula1;
+       }
+
+       /**
+        * get the stack of the 2nd expression as a list
+        *
+        * @return list of tokens (casts stack to a list and returns it!)
+        * this method can return null is we are unable to create Ptgs from 
+        *       existing excel file
+        * callers should check for null!
+        */
+
+       public Ptg[] getParsedExpression2()
+       {
+               return field_18_formula2;
+       }
+       
+       private void setParsedExpression1(Ptg[] ptgs) {
+               short len = getTotalPtgSize(field_17_formula1 = ptgs);
+               field_3_formula1_len = len;
+       }
+
+       private void setParsedExpression2(Ptg[] ptgs) {
+               short len = getTotalPtgSize(field_18_formula2 = ptgs);
+               field_4_formula2_len = len;
+       }
+       
+       /**
+        * called by constructor, should throw runtime exception in the event of a
+        * record passed with a differing ID.
+        *
+        * @param id alleged id for this record
+        */
+
+       protected void validateSid(short id)
+       {
+               if (id != sid)
+               {
+                       throw new RecordFormatException("NOT A CFRULE RECORD");
+               }
+       }
+
+       public short getSid()
+       {
+               return sid;
+       }
+
+       /**
+        * called by the class that is responsible for writing this sucker.
+        * Subclasses should implement this so that their data is passed back in a
+        * byte array.
+        *
+        * @param offset to begin writing at
+        * @param data byte array containing instance data
+        * @return number of bytes written
+        */
+
+       public int serialize(int pOffset, byte [] data)
+       {
+               
+               int offset = pOffset;
+               int recordsize = getRecordSize();
+               LittleEndian.putShort(data, 0 + offset, sid);
+               LittleEndian.putShort(data, 2 + offset, (short)(recordsize-4));
+               data[4 + offset] = field_1_condition_type;
+               data[5 + offset] = field_2_comparison_operator;
+               LittleEndian.putShort(data, 6 + offset, field_3_formula1_len);
+               LittleEndian.putShort(data, 8 + offset, field_4_formula2_len);
+               LittleEndian.putInt(data,  10 + offset, field_5_options);
+               LittleEndian.putShort(data,14 + offset, field_6_not_used);
+               
+               offset += 16;
+               
+               if( containsFontFormattingBlock() )
+               {
+                       byte[] fontFormattingRawRecord  = fontFormatting.getRawRecord();
+                       System.arraycopy(fontFormattingRawRecord, 0, data, offset, fontFormattingRawRecord.length);
+                       offset += fontFormattingRawRecord.length;
+               }
+               
+               if( containsBorderFormattingBlock())
+               {
+                       offset += borderFormatting.serialize(offset, data);
+               }
+               
+               if( containsPatternFormattingBlock() )
+               {
+                       offset += patternFormatting.serialize(offset, data);
+               }
+               
+               if (getExpression1Length()>0)
+               {
+                       Ptg.serializePtgStack(convertToTokenStack(field_17_formula1), data, offset);
+                       offset += getExpression1Length();
+               }
+
+               if (getExpression2Length()>0)
+               {
+                       Ptg.serializePtgStack(convertToTokenStack(field_18_formula2), data, offset);
+                       offset += getExpression2Length();
+               }
+               if(offset - pOffset != recordsize) {
+                       throw new IllegalStateException("write mismatch (" + (offset - pOffset) + "!=" + recordsize + ")");
+               }
+               return recordsize;
+       }
+
+
+       public int getRecordSize()
+       {
+               int retval =16+
+                                       (containsFontFormattingBlock()?fontFormatting.getRawRecord().length:0)+
+                                       (containsBorderFormattingBlock()?8:0)+
+                                       (containsPatternFormattingBlock()?4:0)+
+                                       getExpression1Length()+
+                                       getExpression2Length()
+                                       ;
+               return retval;
+       }
+
+       private short getTotalPtgSize(Ptg[] ptgs)
+       {
+               if( ptgs == null) {
+                       return 0;
+               }
+               short  retval = 0;
+               for (int i = 0; i < ptgs.length; i++)
+               {
+                       retval += ptgs[i].getSize();
+               }
+               return retval;
+       }
+
+       public String toString()
+       {
+               StringBuffer buffer = new StringBuffer();
+               buffer.append("[CFRULE]\n");
+               if( containsFontFormattingBlock())
+               {
+                       buffer.append(fontFormatting.toString());
+               }
+               if( containsBorderFormattingBlock())
+               {
+                       buffer.append(borderFormatting.toString());
+               }
+               if( containsPatternFormattingBlock())
+               {
+                       buffer.append(patternFormatting.toString());
+               }
+               buffer.append("[/CFRULE]\n");
+               return buffer.toString();
+       }
+       
+       public Object clone() {
+               CFRuleRecord rec = new CFRuleRecord(field_1_condition_type, field_2_comparison_operator);
+               rec.field_3_formula1_len = field_3_formula1_len;
+               rec.field_4_formula2_len = field_4_formula2_len;
+               rec.field_5_options = field_5_options;
+               rec.field_6_not_used = field_6_not_used;
+               if (containsFontFormattingBlock()) {
+                       rec.fontFormatting = (FontFormatting) fontFormatting.clone();
+               }
+               if (containsBorderFormattingBlock()) {
+                       rec.borderFormatting = (BorderFormatting) borderFormatting.clone();
+               }
+               if (containsPatternFormattingBlock()) {
+                       rec.patternFormatting = (PatternFormatting) patternFormatting.clone();
+               }
+               if (field_3_formula1_len > 0) {
+                       rec.field_17_formula1 = (Ptg[]) field_17_formula1.clone();
+               }
+               if (field_4_formula2_len > 0) {
+                       rec.field_18_formula2 = (Ptg[]) field_18_formula2.clone();
+               }
+
+               return rec;
+       }
 
        public FontFormatting getFontFormatting()
        {
                return fontFormatting;
        }
 
+       
+       /**
+        * @return <code>null</code> if <tt>formula</tt> was null.
+        */
+       private static Ptg[] parseFormula(String formula, Workbook workbook)
+       {
+               if(formula == null) {
+                       return null;
+               }
+               return FormulaParser.parse(formula, workbook);
+       }
+
+       // TODO - treat formulas as token arrays instead of Stacks throughout the rest of POI
+       private static Stack convertToTokenStack(Ptg[] ptgs)
+       {
+               Stack parsedExpression = new Stack();
+               // fill the Ptg Stack with Ptgs of new formula
+               for (int k = 0; k < ptgs.length; k++) 
+               {
+                       parsedExpression.push(ptgs[ k ]);
+               }
+               return parsedExpression;
+       }
+       private static Ptg[] toArray(Stack ptgs) {
+               Ptg[] result = new Ptg[ptgs.size()];
+               ptgs.toArray(result);
+               return result;
+       }
 }
index 99890f805bdc2d7a7958a53e3e742b7d2d24bf84..47be0497daa6d91f72a01c3aef2d7bace214484e 100755 (executable)
@@ -37,7 +37,7 @@ public final class ExternalNameRecord extends Record {
        private static final int OPT_PICTURE_LINK          = 0x0004;
        private static final int OPT_STD_DOCUMENT_NAME     = 0x0008;
        private static final int OPT_OLE_LINK              = 0x0010;
-//     private static final int OPT_CLIP_FORMAT_MASK      = 0x7FE0;
+//     private static final int OPT_CLIP_FORMAT_MASK      = 0x7FE0;
        private static final int OPT_ICONIFIED_PICTURE_LINK= 0x8000;
 
 
index d6e81c7ea2b24c5b28ad45d38880aa11d4956c20..81154ebb22c5a43893bb85c1c5d9b2ba956259af 100644 (file)
@@ -24,6 +24,7 @@ import org.apache.poi.hssf.record.CFHeaderRecord;
 import org.apache.poi.hssf.record.CFRuleRecord;
 import org.apache.poi.hssf.record.Record;
 import org.apache.poi.hssf.record.RecordInputStream;
+import org.apache.poi.hssf.util.Region;
 import org.apache.poi.util.POILogFactory;
 import org.apache.poi.util.POILogger;
 
@@ -37,19 +38,38 @@ import org.apache.poi.util.POILogger;
  */
 public final class CFRecordsAggregate extends Record
 {
+       /** Excel allows up to 3 conditional formating rules */
+       private static final int MAX_CONDTIONAL_FORMAT_RULES = 3;
+
        public final static short sid = -2008; // not a real BIFF record
 
-       private static POILogger  log = POILogFactory.getLogger(CFRecordsAggregate.class);
+       private static POILogger log = POILogFactory.getLogger(CFRecordsAggregate.class);
 
-       private CFHeaderRecord header;
+       private final CFHeaderRecord header;
 
-       // List of CFRuleRecord objects
+       /** List of CFRuleRecord objects */
        private final List rules;
 
-       public CFRecordsAggregate()
-       {
-               header = null;
-               rules  = new ArrayList(3);
+       private CFRecordsAggregate(CFHeaderRecord pHeader, CFRuleRecord[] pRules) {
+               if(pHeader == null) {
+                       throw new IllegalArgumentException("header must not be null");
+               }
+               if(pRules == null) {
+                       throw new IllegalArgumentException("rules must not be null");
+               }
+               if(pRules.length > MAX_CONDTIONAL_FORMAT_RULES) {
+                       throw new IllegalArgumentException("No more than " 
+                                       + MAX_CONDTIONAL_FORMAT_RULES + " rules may be specified");
+               }
+               header = pHeader;
+               rules = new ArrayList(3);
+               for (int i = 0; i < pRules.length; i++) {
+                       rules.add(pRules[i]);
+               }
+       }
+
+       public CFRecordsAggregate(Region[] regions, CFRuleRecord[] rules) {
+               this(new CFHeaderRecord(regions), rules);
        }
 
        /**
@@ -60,42 +80,46 @@ public final class CFRecordsAggregate extends Record
         */
        public static CFRecordsAggregate createCFAggregate(List recs, int pOffset)
        {
+               Record rec = ( Record ) recs.get(pOffset);
+               if (rec.getSid() != CFHeaderRecord.sid) {
+                       throw new IllegalStateException("next record sid was " + rec.getSid() 
+                                       + " instead of " + CFHeaderRecord.sid + " as expected");
+               }
 
-               int offset = pOffset;
-               CFRecordsAggregate      cfRecords  = new CFRecordsAggregate();
-               ArrayList               records = new ArrayList(4);
-
-               Record rec = ( Record ) recs.get(offset++);
+               CFHeaderRecord header = (CFHeaderRecord)rec;
+               int nRules = header.getNumberOfConditionalFormats();
 
-               if (rec.getSid() == CFHeaderRecord.sid)
-               {
-                       records.add(rec);
-                       cfRecords.header = (CFHeaderRecord)rec;
-
-                       int nRules = cfRecords.header.getNumberOfConditionalFormats();
-                       int rulesCount = 0;
-                       while(  offset<recs.size() &&
-                                       (rec = (Record)recs.get(offset++)).getSid() == CFRuleRecord.sid && 
-                                       rec instanceof CFRuleRecord &&
-                                       rulesCount++ < nRules
-                                )
-                       {
-                               records.add(rec);
-                               cfRecords.rules.add(rec);
+               CFRuleRecord[] rules = new CFRuleRecord[nRules];
+               int offset = pOffset;
+               int countFound = 0;
+               while (countFound < rules.length) {
+                       offset++;
+                       if(offset>=recs.size()) {
+                               break;
                        }
+                       rec = (Record)recs.get(offset);
+                       if(rec instanceof CFRuleRecord) {
+                               rules[countFound] = (CFRuleRecord) rec;
+                               countFound++;
+                       } else {
+                               break;
+                       }
+               }
 
-                       if (nRules != cfRecords.rules.size())
+               if (countFound < nRules)
+               { // TODO -(MAR-2008) can this ever happen? write junit 
+                       
+                       if (log.check(POILogger.DEBUG))
                        {
-                               if (log.check(POILogger.DEBUG))
-                               {
-                                       log.log(POILogger.DEBUG, "Expected  " + nRules + " Conditional Formats, "
-                                                       + "but found " + cfRecords.rules.size() + " rules");
-                               }
-                               cfRecords.header.setNumberOfConditionalFormats(nRules);
+                               log.log(POILogger.DEBUG, "Expected  " + nRules + " Conditional Formats, "
+                                               + "but found " + countFound + " rules");
                        }
-
+                       header.setNumberOfConditionalFormats(nRules);
+                       CFRuleRecord[] lessRules = new CFRuleRecord[countFound];
+                       System.arraycopy(rules, 0, lessRules, 0, countFound);
+                       rules = lessRules;
                }
-               return cfRecords;
+               return new CFRecordsAggregate(header, rules);
        }
 
        /**
@@ -104,22 +128,17 @@ public final class CFRecordsAggregate extends Record
         */
        public CFRecordsAggregate cloneCFAggregate()
        {
-
-         ArrayList records = new ArrayList(this.rules.size()+1);
          
-         records.add(this.header.clone());
-         
-         for (int i=0; i<this.rules.size();i++) 
-         {
-               Record rec = (Record)((Record)this.rules.get(i)).clone();
-               records.add(rec);
-         }
-         return createCFAggregate(records, 0);
+               CFRuleRecord[] newRecs = new CFRuleRecord[rules.size()];
+               for (int i = 0; i < newRecs.length; i++) {
+                       newRecs[i] = (CFRuleRecord) getRule(i).clone();
+               }
+               return new CFRecordsAggregate((CFHeaderRecord) header.clone(), newRecs);
        }
 
-       /** You never fill an aggregate */
        protected void fillFields(RecordInputStream in)
        {
+            // You never fill an aggregate record
        }
 
        public short getSid()
@@ -139,17 +158,14 @@ public final class CFRecordsAggregate extends Record
 
        public int serialize(int offset, byte[] data)
        {
-               int pos = offset;
-               if( header != null && rules.size()>0 )
-               {
-                       header.setNumberOfConditionalFormats(rules.size());
+               int nRules = rules.size();
+               header.setNumberOfConditionalFormats(nRules);
 
-                       pos += (( Record ) header).serialize(pos, data);
+               int pos = offset;
 
-                       for(Iterator itr = rules.iterator(); itr.hasNext();)
-                       {
-                               pos += (( Record ) itr.next()).serialize(pos, data);
-                       }
+               pos += header.serialize(pos, data);
+               for(int i=0; i< nRules; i++) {
+                       pos += getRule(i).serialize(pos, data);
                }
                return pos - offset;
        }
@@ -160,19 +176,37 @@ public final class CFRecordsAggregate extends Record
        }
 
        /**
-        * @return the header
+        * @return the header. Never <code>null</code>.
         */
        public CFHeaderRecord getHeader()
        {
                return header;
        }
-
-       /**
-        * @return the rules
-        */
-       public List getRules()
-       {
-               return rules;
+       
+       private void checkRuleIndex(int idx) {
+               if(idx < 0 || idx >= rules.size()) {
+                       throw new IllegalArgumentException("Bad rule record index (" + idx 
+                                       + ") nRules=" + rules.size());
+               }
+       }
+       public CFRuleRecord getRule(int idx) {
+               checkRuleIndex(idx);
+               return (CFRuleRecord) rules.get(idx);
+       }
+       public void setRule(int idx, CFRuleRecord r) {
+               checkRuleIndex(idx);
+               rules.set(idx, r);
+       }
+       public void addRule(CFRuleRecord r) {
+               if(rules.size() >= MAX_CONDTIONAL_FORMAT_RULES) {
+                       throw new IllegalStateException("Cannot have more than " 
+                                       + MAX_CONDTIONAL_FORMAT_RULES + " conditional format rules");
+               }
+               rules.add(r);
+               header.setNumberOfConditionalFormats(rules.size());
+       }
+       public int getNumberOfRules() {
+               return rules.size();
        }
 
        /**
index 88ec15b4a749d1cd94b8859738f0c155a0b9f64a..16093ee582dfd9a4fb25e032bc29f5ce9830e95c 100644 (file)
 
 package org.apache.poi.hssf.record.cf;
 
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+import org.apache.poi.hssf.util.Region;
+
 /**
- * CellRange.java
- * Created on January 22, 2008, 10:05 PM
  * 
  * @author Dmitriy Kumshayev
  */
-
-public class CellRange
+public final class CellRange
 {
-    private int               field_1_first_row;
-    private int               field_2_last_row;
-    private short             field_3_first_column;
-    private short             field_4_last_column;
-    
-    public CellRange(int firstRow, int lastRow, short firstColumn, short lastColumn)
-    {
-               this.field_1_first_row = firstRow;
-               this.field_2_last_row = lastRow;
-               this.field_3_first_column = firstColumn;
-               this.field_4_last_column = lastColumn;
-               validateRegion();
-       }
-    
-    private void validateRegion()
-    {
-       if( field_1_first_row < 0 || 
-               field_2_last_row < -1 ||
-               field_3_first_column < 0 ||
-               field_4_last_column < -1 ||
-               field_2_last_row>=0 && field_2_last_row<field_1_first_row  || 
-               field_4_last_column>=0 && field_4_last_column<field_3_first_column 
-       )
-       {
-               throw new IllegalArgumentException("Invalid cell region "+toString());
-       }
-    }
-    
-       public int getFirstRow()
+       /** 
+        * max index for both row and column<p/>
+        * 
+        * Note - this value converts to <tt>-1</tt> when cast to a <tt>short</tt> 
+        */
+       private static final int MAX_INDEX = Integer.MAX_VALUE;
+
+       private static final Region[] EMPTY_REGION_ARRAY = { };
+       
+       private int _firstRow;
+       private int _lastRow;
+       private int _firstColumn;
+       private int _lastColumn;
+       
+       /**
+        * 
+        * @param firstRow
+        * @param lastRow pass <tt>-1</tt> for full column ranges
+        * @param firstColumn
+        * @param lastColumn  pass <tt>-1</tt> for full row ranges
+        */
+       public CellRange(int firstRow, int lastRow, int firstColumn, int lastColumn)
        {
-               return field_1_first_row;
+               if(!isValid(firstRow, lastRow, firstColumn, lastColumn)) {
+                       throw new IllegalArgumentException("invalid cell range (" + firstRow + ", " + lastRow 
+                                       + ", " + firstColumn + ", " + lastColumn + ")");
+               }
+               _firstRow = firstRow;
+               _lastRow = convertM1ToMax(lastRow);
+               _firstColumn = firstColumn;
+               _lastColumn = convertM1ToMax(lastColumn);
        }
-       private void setFirstRow(int firstRow)
-       {
-               this.field_1_first_row = firstRow;
+       
+       private static int convertM1ToMax(int lastIx) {
+               if(lastIx < 0) {
+                       return MAX_INDEX;
+               }
+               return lastIx;
        }
-       public int getLastRow()
-       {
-               return field_2_last_row;
+       private static int convertMaxToM1(int lastIx) {
+               if(lastIx == MAX_INDEX) {
+                       return -1;
+               }
+               return lastIx;
+       }
+
+       public boolean isFullColumnRange() {
+               return _firstColumn == 0 && _lastColumn == MAX_INDEX;
+       }
+       public boolean isFullRowRange() {
+               return _firstRow == 0 && _lastRow == MAX_INDEX;
+       }
+       
+       public CellRange(Region r) {
+               this(r.getRowFrom(), r.getRowTo(), r.getColumnFrom(), r.getColumnTo());
        }
-       private void setLastRow(int lastRow)
+
+       
+       
+       private static boolean isValid(int firstRow, int lastRow, int firstColumn, int lastColumn)
        {
-               this.field_2_last_row = lastRow;
+               if(lastRow == -1) {
+                       if(firstRow !=0) {
+                               return false;
+                       }
+               }
+               if(firstRow < 0 || lastRow < -1) {
+                       return false;
+               }
+               
+               if(lastColumn == -1) {
+                       if(firstColumn !=0) {
+                               return false;
+                       }
+               }
+               if(firstColumn < 0 || lastColumn < -1) {
+                       return false;
+               }
+               return true;
        }
-       public short getFirstColumn()
+       
+       public int getFirstRow()
        {
-               return field_3_first_column;
+               return _firstRow;
        }
-       private void setFirstColumn(short firstColumn)
+       /**
+        * @return <tt>-1</tt> for whole column ranges
+        */
+       public int getLastRow()
        {
-               this.field_3_first_column = firstColumn;
+               return convertMaxToM1(_lastRow);
        }
-       public short getLastColumn()
+       public int getFirstColumn()
        {
-               return field_4_last_column;
+               return _firstColumn;
        }
-       private void setLastColumn(short lastColumn)
+       /**
+        * @return <tt>-1</tt> for whole row ranges
+        */
+       public int getLastColumn()
        {
-               this.field_4_last_column = lastColumn;
+               return convertMaxToM1(_lastColumn);
        }
        
        public static final int NO_INTERSECTION = 1;
        public static final int OVERLAP = 2;
+       /** first range is within the second range */
        public static final int INSIDE = 3;
+       /** first range encloses or is equal to the second */
        public static final int ENCLOSES = 4;
        
        /**
@@ -101,30 +149,31 @@ public class CellRange
         *              NO_INTERSECTION - the specified range is outside of this range;<br/> 
         *              OVERLAP - both ranges partially overlap;<br/>
         *              INSIDE - the specified range is inside of this one<br/>
-        *              ENCLOSES - the specified range encloses this range<br/>
+        *              ENCLOSES - the specified range encloses (possibly exactly the same as) this range<br/>
         */
        public int intersect(CellRange another )
        {
-               int   firstRow = another.getFirstRow();
-               int   lastRow  = another.getLastRow();
-               short firstCol = another.getFirstColumn();
-               short lastCol  = another.getLastColumn();
+               
+               int firstRow = another.getFirstRow();
+               int lastRow  = another.getLastRow();
+               int firstCol = another.getFirstColumn();
+               int lastCol  = another.getLastColumn();
                
                if
                ( 
-                               gt(this.getFirstRow(),lastRow) || 
-                               lt(this.getLastRow(),firstRow) ||
-                               gt(this.getFirstColumn(),lastCol) || 
-                               lt(this.getLastColumn(),firstCol) 
+                               gt(getFirstRow(),lastRow) || 
+                               lt(getLastRow(),firstRow) ||
+                               gt(getFirstColumn(),lastCol) || 
+                               lt(getLastColumn(),firstCol) 
                )
                {
                        return NO_INTERSECTION;
                }
-               else if( this.contains(another) )
+               else if( contains(another) )
                {
                        return INSIDE;
                }
-               else if( another.contains(this) )
+               else if( another.contains(this))
                {
                        return ENCLOSES;
                }
@@ -134,7 +183,234 @@ public class CellRange
                }
                        
        }
+       
+       /**
+        * Do all possible cell merges between cells of the list so that:<br>
+        *      <li>if a cell range is completely inside of another cell range, it gets removed from the list 
+        *      <li>if two cells have a shared border, merge them into one bigger cell range
+        * @param cellRangeList
+        * @return updated List of cell ranges
+        */
+       public static CellRange[] mergeCellRanges(CellRange[] cellRanges) {
+               if(cellRanges.length < 1) {
+                       return cellRanges;
+               }
+               List temp = mergeCellRanges(Arrays.asList(cellRanges));
+               return toArray(temp);
+       }
+       private static List mergeCellRanges(List cellRangeList)
+       {
+
+               while(cellRangeList.size() > 1)
+               {
+                       boolean somethingGotMerged = false;
+                       
+                       for( int i=0; i<cellRangeList.size(); i++)
+                       {
+                               CellRange range1 = (CellRange)cellRangeList.get(i);
+                               for( int j=i+1; j<cellRangeList.size(); j++)
+                               {
+                                       CellRange range2 = (CellRange)cellRangeList.get(j);
+                                       
+                                       CellRange[] mergeResult = mergeRanges(range1, range2);
+                                       if(mergeResult == null) {
+                                               continue;
+                                       }
+                                       somethingGotMerged = true;
+                                       // overwrite range1 with first result 
+                                       cellRangeList.set(i, mergeResult[0]);
+                                       // remove range2
+                                       cellRangeList.remove(j--);
+                                       // add any extra results beyond the first
+                                       for(int k=1; k<mergeResult.length; k++) {
+                                               j++;
+                                               cellRangeList.add(j, mergeResult[k]);
+                                       }
+                               }
+                       }
+                       if(!somethingGotMerged) {
+                               break;
+                       }
+               }
                
+
+               return cellRangeList;
+       }
+       
+       /**
+        * @return the new range(s) to replace the supplied ones.  <code>null</code> if no merge is possible
+        */
+       private static CellRange[] mergeRanges(CellRange range1, CellRange range2) {
+               
+               int x = range1.intersect(range2);
+               switch(x)
+               {
+                       case CellRange.NO_INTERSECTION: 
+                               if( range1.hasExactSharedBorder(range2))
+                               {
+                                       return new CellRange[] { range1.createEnclosingCellRange(range2), };
+                               }
+                               // else - No intersection and no shared border: do nothing 
+                               return null;
+                       case CellRange.OVERLAP:
+                               return resolveRangeOverlap(range1, range2);
+                       case CellRange.INSIDE:
+                               // Remove range2, since it is completely inside of range1
+                               return new CellRange[] { range1, };
+                       case CellRange.ENCLOSES:
+                               // range2 encloses range1, so replace it with the enclosing one
+                               return new CellRange[] { range2, };
+               }
+               throw new RuntimeException("unexpected intersection result (" + x + ")");
+       }
+       
+       // TODO - write junit test for this
+       static CellRange[] resolveRangeOverlap(CellRange rangeA, CellRange rangeB) {
+               
+               if(rangeA.isFullColumnRange()) {
+                       if(rangeB.isFullRowRange()) {
+                               // Excel seems to leave these unresolved
+                               return null;
+                       }
+                       return rangeA.sliceUp(rangeB);
+               }
+               if(rangeA.isFullRowRange()) {
+                       if(rangeB.isFullColumnRange()) {
+                               // Excel seems to leave these unresolved
+                               return null;
+                       }
+                       return rangeA.sliceUp(rangeB);
+               }
+               if(rangeB.isFullColumnRange()) {
+                       return rangeB.sliceUp(rangeA);
+               }
+               if(rangeB.isFullRowRange()) {
+                       return rangeB.sliceUp(rangeA);
+               }
+               return rangeA.sliceUp(rangeB);
+       }
+
+       /**
+        * @param range never a full row or full column range
+        * @return an array including <b>this</b> <tt>CellRange</tt> and all parts of <tt>range</tt> 
+        * outside of this range  
+        */
+       private CellRange[] sliceUp(CellRange range) {
+               
+               List temp = new ArrayList();
+               
+               // Chop up range horizontally and vertically
+               temp.add(range);
+               if(!isFullColumnRange()) {
+                       temp = cutHorizontally(_firstRow, temp);
+                       temp = cutHorizontally(_lastRow+1, temp);
+               }
+               if(!isFullRowRange()) {
+                       temp = cutVertically(_firstColumn, temp);
+                       temp = cutVertically(_lastColumn+1, temp);
+               }
+               CellRange[] crParts = toArray(temp);
+
+               // form result array
+               temp.clear();
+               temp.add(this);
+               
+               for (int i = 0; i < crParts.length; i++) {
+                       CellRange crPart = crParts[i];
+                       // only include parts that are not enclosed by this
+                       if(intersect(crPart) != ENCLOSES) {
+                               temp.add(crPart);
+                       }
+               }
+               return toArray(temp);
+       }
+
+       private static List cutHorizontally(int cutRow, List input) {
+               
+               List result = new ArrayList();
+               CellRange[] crs = toArray(input);
+               for (int i = 0; i < crs.length; i++) {
+                       CellRange cr = crs[i];
+                       if(cr._firstRow < cutRow && cutRow < cr._lastRow) {
+                               result.add(new CellRange(cr._firstRow, cutRow, cr._firstColumn, cr._lastColumn));
+                               result.add(new CellRange(cutRow+1, cr._lastRow, cr._firstColumn, cr._lastColumn));
+                       } else {
+                               result.add(cr);
+                       }
+               }
+               return result;
+       }
+       private static List cutVertically(int cutColumn, List input) {
+               
+               List result = new ArrayList();
+               CellRange[] crs = toArray(input);
+               for (int i = 0; i < crs.length; i++) {
+                       CellRange cr = crs[i];
+                       if(cr._firstColumn < cutColumn && cutColumn < cr._lastColumn) {
+                               result.add(new CellRange(cr._firstRow, cr._lastRow, cr._firstColumn, cutColumn));
+                               result.add(new CellRange(cr._firstRow, cr._lastRow, cutColumn+1, cr._lastColumn));
+                       } else {
+                               result.add(cr);
+                       }
+               }
+               return result;
+       }
+
+
+       private static CellRange[] toArray(List temp) {
+               CellRange[] result = new CellRange[temp.size()];
+               temp.toArray(result);
+               return result;
+       }
+
+       /**
+        * Convert array of regions to a List of CellRange objects
+        *  
+        * @param regions
+        * @return List of CellRange objects
+        */
+       public static CellRange[] convertRegionsToCellRanges(Region[] regions)
+       {
+               CellRange[] result = new CellRange[regions.length];
+               for( int i=0; i<regions.length; i++)
+               {
+                       result[i] = new CellRange(regions[i]);
+               }
+               return result;
+       }
+       
+       /**
+        * Convert a List of CellRange objects to an array of regions 
+        *  
+        * @param List of CellRange objects
+        * @return regions
+        */
+       public static Region[] convertCellRangesToRegions(CellRange[] cellRanges)
+       {
+               int size = cellRanges.length;
+               if(size < 1) {
+                       return EMPTY_REGION_ARRAY;
+               }
+               
+               Region[] result = new Region[size];
+
+               for (int i = 0; i != size; i++)
+               {
+                       result[i] = cellRanges[i].convertToRegion();
+               }
+               return result;
+       }
+
+
+               
+       private Region convertToRegion() {
+               int lastRow = convertMaxToM1(_lastRow);
+               int lastColumn = convertMaxToM1(_lastColumn);
+               
+               return new Region(_firstRow, (short)_firstColumn, lastRow, (short)lastColumn);
+       }
+
+
        /**
         *  Check if the specified range is located inside of this cell range.
         *  
@@ -145,44 +421,52 @@ public class CellRange
    {
                int firstRow = range.getFirstRow();
                int lastRow = range.getLastRow();
-               short firstCol = range.getFirstColumn();
-               short lastCol = range.getLastColumn();
-               return le(this.getFirstRow(), firstRow) && ge(this.getLastRow(), lastRow)
-                               && le(this.getFirstColumn(), firstCol) && ge(this.getLastColumn(), lastCol);
+               int firstCol = range.getFirstColumn();
+               int lastCol = range.getLastColumn();
+               return le(getFirstRow(), firstRow) && ge(getLastRow(), lastRow)
+                               && le(getFirstColumn(), firstCol) && ge(getLastColumn(), lastCol);
        }
    
        public boolean contains(int row, short column)
        {
-               return le(this.getFirstRow(), row) && ge(this.getLastRow(), row)
-                               && le(this.getFirstColumn(), column) && ge(this.getLastColumn(), column);
+               return le(getFirstRow(), row) && ge(getLastRow(), row)
+                               && le(getFirstColumn(), column) && ge(getLastColumn(), column);
        }
        
    /**
-    * Check if the specified cell range has a shared border with the current range.
-    * 
-    * @return true if the ranges have a shared border.
-    */
-       public boolean hasSharedBorder(CellRange range)
+       * Check if the specified cell range has a shared border with the current range.
+       * 
+       * @return <code>true</code> if the ranges have a complete shared border (i.e.
+       * the two ranges together make a simple rectangular region.
+       */
+       public boolean hasExactSharedBorder(CellRange range)
        {
-               int   firstRow = range.getFirstRow();
-               int   lastRow  = range.getLastRow();
-               short firstCol = range.getFirstColumn();
-               short lastCol  = range.getLastColumn();
-               return 
-                       (this.getFirstRow()>0 && this.getFirstRow() - 1 == lastRow || firstRow>0 &&this.getLastRow() == firstRow -1)&& 
-                       (this.getFirstColumn() == firstCol) && 
-                       (this.getLastColumn() == lastCol)                       ||
-                       (this.getFirstColumn()>0 && this.getFirstColumn() - 1 == lastCol || firstCol>0 && this.getLastColumn() == firstCol -1) && 
-                       (this.getFirstRow() == firstRow) && 
-                       (this.getLastRow() == lastRow)
-               ;
+               int oFirstRow = range._firstRow;
+               int oLastRow  = range._lastRow;
+               int oFirstCol = range._firstColumn;
+               int oLastCol  = range._lastColumn;
+               
+               if (_firstRow > 0 && _firstRow-1 == oLastRow || 
+                       oFirstRow > 0 && oFirstRow-1 == _lastRow) {
+                       // ranges have a horizontal border in common
+                       // make sure columns are identical:
+                       return _firstColumn == oFirstCol && _lastColumn == oLastCol;
+               }
+
+               if (_firstColumn>0 && _firstColumn - 1 == oLastCol ||
+                       oFirstCol>0 && _lastColumn == oFirstCol -1) {
+                       // ranges have a vertical border in common
+                       // make sure rows are identical:
+                       return _firstRow == oFirstRow && _lastRow == oLastRow;
+               }
+               return false;
        }
        
-    /**
-     * Create an enclosing CellRange for the two cell ranges.
-     * 
-     * @return enclosing CellRange
-     */
+       /**
+        * Create an enclosing CellRange for the two cell ranges.
+        
+        * @return enclosing CellRange
+        */
        public CellRange createEnclosingCellRange(CellRange range)
        {
                if( range == null)
@@ -206,18 +490,6 @@ public class CellRange
        {
                return new CellRange(getFirstRow(),getLastRow(),getFirstColumn(),getLastColumn());
        }
-       
-       /**
-        * Copy data from antother cell range to this cell range
-        * @param cr - another cell range
-        */
-       public void setCellRange(CellRange cr)
-       {
-               setFirstRow(cr.getFirstRow());
-               setLastRow(cr.getLastRow());
-               setFirstColumn(cr.getFirstColumn());
-               setLastColumn(cr.getLastColumn());
-       }
 
        /**
         * @return true if a < b
@@ -253,7 +525,7 @@ public class CellRange
        
        public String toString()
        {
-               return "("+this.getFirstRow()+","+this.getLastRow()+","+this.getFirstColumn()+","+this.getLastColumn()+")";
+               return "("+getFirstRow()+","+getLastRow()+","+getFirstColumn()+","+getLastColumn()+")";
        }
-    
+       
 }
index 149ff2359f05bdd5bfe46df461bee405de600304..f0fc1fccf4c69b083ad7bd937b033df65341f489 100644 (file)
@@ -23,27 +23,27 @@ import org.apache.poi.hssf.record.formula.function.FunctionMetadataRegistry;
 
 
 /**
- * This class provides the base functionality for Excel sheet functions 
+ * This class provides the base functionality for Excel sheet functions
  * There are two kinds of function Ptgs - tFunc and tFuncVar
  * Therefore, this class will have ONLY two subclasses
  * @author  Avik Sengupta
  * @author Andrew C. Oliver (acoliver at apache dot org)
  */
 public abstract class AbstractFunctionPtg extends OperationPtg {
-    
+
     /**
      * The name of the IF function (i.e. "IF").  Extracted as a constant for clarity.
-     */ 
+     */
     public static final String FUNCTION_NAME_IF = "IF";
     /** All external functions have function index 255 */
     private static final short FUNCTION_INDEX_EXTERNAL = 255;
-    
+
     protected byte returnClass;
     protected byte[] paramClass;
-    
+
     protected byte field_1_num_args;
     protected short field_2_fnc_index;
+
     public String toString() {
         StringBuffer sb = new StringBuffer(64);
         sb.append(getClass().getName()).append(" [");
@@ -51,17 +51,17 @@ public abstract class AbstractFunctionPtg extends OperationPtg {
         sb.append("]");
         return sb.toString();
     }
-   
+
     public int getType() {
         return -1;
-    }   
-    
-   
-    
+    }
+
+
+
     public short getFunctionIndex() {
         return field_2_fnc_index;
     }
-    
+
     public String getName() {
         return lookupName(field_2_fnc_index);
     }
@@ -72,14 +72,14 @@ public abstract class AbstractFunctionPtg extends OperationPtg {
     public boolean isExternalFunction() {
         return field_2_fnc_index == FUNCTION_INDEX_EXTERNAL;
     }
-    
+
     public String toFormulaString(Workbook book) {
         return getName();
     }
-    
+
     public String toFormulaString(String[] operands) {
-        StringBuffer buf = new StringBuffer();        
-        
+        StringBuffer buf = new StringBuffer();
+
         if(isExternalFunction()) {
             buf.append(operands[0]); // first operand is actually the function name
             appendArgs(buf, 1, operands);
@@ -100,23 +100,23 @@ public abstract class AbstractFunctionPtg extends OperationPtg {
         }
         buf.append(")");
     }
-    
+
     public abstract void writeBytes(byte[] array, int offset);
     public abstract int getSize();
-    
-   
+
+
     /**
      * Used to detect whether a function name found in a formula is one of the standard excel functions
      * <p>
      * The name matching is case insensitive.
-     * @return <code>true</code> if the name specifies a standard worksheet function, 
+     * @return <code>true</code> if the name specifies a standard worksheet function,
      *  <code>false</code> if the name should be assumed to be an external function.
      */
     public static final boolean isInternalFunctionName(String name) {
         short ix = FunctionMetadataRegistry.lookupIndexByName(name.toUpperCase());
         return ix >= 0;
     }
-    
+
     protected String lookupName(short index) {
         if(index == FunctionMetadataRegistry.FUNCTION_INDEX_EXTERNAL) {
             return "#external#";
@@ -127,7 +127,7 @@ public abstract class AbstractFunctionPtg extends OperationPtg {
         }
         return fm.getName();
     }
-    
+
     /**
      * Resolves internal function names into function indexes.
      * <p>
@@ -145,7 +145,7 @@ public abstract class AbstractFunctionPtg extends OperationPtg {
     public byte getDefaultOperandClass() {
         return returnClass;
     }
-    
+
     public byte getParameterClass(int index) {
         try {
             return paramClass[index];
index a94355a0f002e46de393b3d54f6b1306ccbd65b8..69edf88aae0ca05c2e9d0e7ccea3c7172467ef40 100644 (file)
@@ -27,11 +27,11 @@ import org.apache.poi.hssf.record.formula.function.FunctionMetadataRegistry;
  * @author Danny Mui (dmui at apache dot org) (Leftover handling)
  */
 public final class FuncPtg extends AbstractFunctionPtg {
-    
+
     public final static byte sid  = 0x21;
     public final static int  SIZE = 3;
     private int numParams=0;
-    
+
     /**
      * FuncPtgs are defined to be 4 bytes but the actual FuncPtg uses only 2 bytes.
      * If we have leftOvers that are read from the file we should serialize them back out.
@@ -39,18 +39,18 @@ public final class FuncPtg extends AbstractFunctionPtg {
      * If the leftovers are removed, a prompt "Warning: Data may have been lost occurs in Excel"
      */
        //protected byte[] leftOvers = null;
-    
+
     private FuncPtg() {
-      //Required for clone methods      
+      //Required for clone methods
     }
 
-    /**Creates new function pointer from a byte array 
-     * usually called while reading an excel file. 
+    /**Creates new function pointer from a byte array
+     * usually called while reading an excel file.
      */
     public FuncPtg(RecordInputStream in) {
         //field_1_num_args = data[ offset + 0 ];
         field_2_fnc_index  = in.readShort();
-        
+
         FunctionMetadata fm = FunctionMetadataRegistry.getFunctionByIndex(field_2_fnc_index);
         if(fm == null) {
             throw new RuntimeException("Invalid built-in function index (" + field_2_fnc_index + ")");
@@ -62,12 +62,12 @@ public final class FuncPtg extends AbstractFunctionPtg {
         numParams = numberOfParameters;
         paramClass = new byte[] { Ptg.CLASS_VALUE, }; // TODO
     }
-    
+
     public void writeBytes(byte[] array, int offset) {
         array[offset+0]= (byte) (sid + ptgClass);
         LittleEndian.putShort(array,offset+1,field_2_fnc_index);
     }
-    
+
     public int getNumberOfOperands() {
         return numParams;
     }
@@ -79,11 +79,11 @@ public final class FuncPtg extends AbstractFunctionPtg {
       ptg.setClass(ptgClass);
      return ptg;
     }
-    
+
     public int getSize() {
         return SIZE;
     }
-    
+
     public String toString() {
         StringBuffer sb = new StringBuffer(64);
         sb.append(getClass().getName()).append(" [");
index b4732c72873359cee6d9652bf864e8e3014b10fa..fb652713933d09b40fe64b0be60859cdf385c288 100644 (file)
@@ -15,7 +15,6 @@
    limitations under the License.
 ==================================================================== */
 
-
 package org.apache.poi.hssf.record.formula;
 import org.apache.poi.util.LittleEndian;
 import org.apache.poi.hssf.record.RecordInputStream;
@@ -27,22 +26,22 @@ import org.apache.poi.hssf.record.formula.function.FunctionMetadataRegistry;
  * @author Jason Height (jheight at chariot dot net dot au)
  */
 public final class FuncVarPtg extends AbstractFunctionPtg{
-    
+
     public final static byte sid  = 0x22;
-    private final static int  SIZE = 4;  
-    
+    private final static int  SIZE = 4;
+
     private FuncVarPtg() {
       //Required for clone methods
     }
 
- /**Creates new function pointer from a byte array 
-     * usually called while reading an excel file. 
+ /**Creates new function pointer from a byte array
+     * usually called while reading an excel file.
      */
     public FuncVarPtg(RecordInputStream in) {
         field_1_num_args = in.readByte();
         field_2_fnc_index  = in.readShort();
     }
-    
+
     /**
      * Create a function ptg from a string tokenised by the parser
      */
@@ -59,17 +58,17 @@ public final class FuncVarPtg extends AbstractFunctionPtg{
             paramClass = new byte[] {Ptg.CLASS_VALUE};
         }
     }
-    
+
      public void writeBytes(byte[] array, int offset) {
         array[offset+0]=(byte) (sid + ptgClass);
         array[offset+1]=field_1_num_args;
         LittleEndian.putShort(array,offset+2,field_2_fnc_index);
     }
-    
+
      public int getNumberOfOperands() {
         return field_1_num_args;
     }
-    
+
     public Object clone() {
       FuncVarPtg ptg = new FuncVarPtg();
       ptg.field_1_num_args = field_1_num_args;
@@ -77,11 +76,11 @@ public final class FuncVarPtg extends AbstractFunctionPtg{
       ptg.setClass(ptgClass);
       return ptg;
     }
-    
+
     public int getSize() {
         return SIZE;
     }
-    
+
     public String toString() {
         StringBuffer sb = new StringBuffer(64);
         sb.append(getClass().getName()).append(" [");
index b304ec3d42371fbd74a7ae53396bc1da627cf3dc..2009ebae1ff4793feaa7139d53ece759cb07511c 100644 (file)
@@ -23,7 +23,7 @@ import java.util.Map;
 import java.util.Set;
 
 /**
- * Temporarily collects <tt>FunctionMetadata</tt> instances for creation of a 
+ * Temporarily collects <tt>FunctionMetadata</tt> instances for creation of a
  * <tt>FunctionMetadataRegistry</tt>.
  * 
  * @author Josh Micich
index 9df2db93ca227168ade0a96ea9f537b43314dbfd..94f1659b5128bf11d7a561e5527fbc41d6b3de3b 100644 (file)
@@ -17,6 +17,7 @@
 
 package org.apache.poi.hssf.record.formula.function;
 /**
+ * Holds information about Excel built-in functions.
  * 
  * @author Josh Micich
  */
@@ -46,7 +47,7 @@ public final class FunctionMetadata {
                return _maxParams;
        }
        public boolean hasFixedArgsLength() {
-           return _minParams == _maxParams;
+               return _minParams == _maxParams;
        }
        public String toString() {
                StringBuffer sb = new StringBuffer(64);
index bd50bf04d5fef7b2d170fd0855393ba8a19cd56e..bd72a9223374ff4b71e80f6310bcc74b96864f24 100644 (file)
@@ -46,7 +46,7 @@ final class FunctionMetadataReader {
 
        public static FunctionMetadataRegistry createRegistry() {
                InputStream is = FunctionMetadataReader.class.getResourceAsStream(METADATA_FILE_NAME);
-               if(is == null) {
+               if (is == null) {
                        throw new RuntimeException("resource '" + METADATA_FILE_NAME + "' not found");
                }
 
index 0cc8de37d6d7dd8c207e6ac19be17342ab3e4ec2..fe243bf0117bcd01dff3faa6d1769a7f0b042712 100644 (file)
@@ -19,7 +19,11 @@ package org.apache.poi.hssf.record.formula.function;
 
 import java.util.Map;
 import java.util.Set;
-
+/**
+ * Allows clients to get <tt>FunctionMetadata</tt> instances for any built-in function of Excel.
+ * 
+ * @author Josh Micich
+ */
 public final class FunctionMetadataRegistry {
        /**
         * The name of the IF function (i.e. "IF").  Extracted as a constant for clarity.
@@ -35,7 +39,6 @@ public final class FunctionMetadataRegistry {
        private static FunctionMetadataRegistry getInstance() {
                if (_instance == null) {
                        _instance = FunctionMetadataReader.createRegistry();
-//                     _instance = POIFunctionMetadataCreator.createInstance();
                }
                return _instance;
        }
index 58628053c0ba19645d907d0c3cddd5bbda20263a..68a8d43dce1bf9e2d0c1fe65cfc12d4a352e464d 100644 (file)
@@ -46,15 +46,15 @@ public final class Pmt extends FinanceFunction {
                if(args.length < 3 || args.length > 5) {
                        return ErrorEval.VALUE_INVALID;
                }
-               
-               try {
-                       // evaluate first three (always present) args
+
+               try {
+                       // evaluate first three (always present) args
                        double rate = evalArg(args[0], srcRow, srcCol);
                        double nper = evalArg(args[1], srcRow, srcCol);
-                       double pv  = evalArg(args[2], srcRow, srcCol); 
+                       double pv  = evalArg(args[2], srcRow, srcCol);
                        double fv = 0;
                        boolean arePaymentsAtPeriodBeginning = false;
-                       
+
                        switch (args.length) {
                                case 5:
                                        ValueEval ve = singleOperandNumericAsBoolean(args[4], srcRow, srcCol);
@@ -67,10 +67,10 @@ public final class Pmt extends FinanceFunction {
                        }
                        double d = FinanceLib.pmt(rate, nper, pv, fv, arePaymentsAtPeriodBeginning);
                        if (Double.isNaN(d)) {
-                               return (ValueEval) ErrorEval.VALUE_INVALID;
+                               return ErrorEval.VALUE_INVALID;
                        }
                        if (Double.isInfinite(d)) {
-                               return (ValueEval) ErrorEval.NUM_ERROR;
+                               return ErrorEval.NUM_ERROR;
                        }
                        return new NumberEval(d);
                } catch (EvaluationException e) {
index 622f3a6742414aafe87527da426314b34d3eefbf..408c774b6208c1273bc33da85da135ba1605e8b0 100644 (file)
@@ -26,103 +26,167 @@ import org.apache.poi.hssf.record.cf.BorderFormatting;
  * @author Dmitriy Kumshayev
  *
  */
-public class HSSFBorderFormatting
+public final class HSSFBorderFormatting
 {
-    /**
-     * No border
-     */
+       /** No border */
+       public final static short BORDER_NONE =  BorderFormatting.BORDER_NONE;
+       /** Thin border */
+       public final static short BORDER_THIN =  BorderFormatting.BORDER_THIN;
+       /** Medium border */
+       public final static short BORDER_MEDIUM =  BorderFormatting.BORDER_MEDIUM;
+       /** dash border */
+       public final static short BORDER_DASHED =  BorderFormatting.BORDER_DASHED;
+       /** dot border */
+       public final static short BORDER_HAIR =  BorderFormatting.BORDER_HAIR;
+       /** Thick border */
+       public final static short BORDER_THICK =  BorderFormatting.BORDER_THICK;
+       /** double-line border */
+       public final static short BORDER_DOUBLE =  BorderFormatting.BORDER_DOUBLE;
+       /** hair-line border */
+       public final static short BORDER_DOTTED =  BorderFormatting.BORDER_DOTTED;
+       /** Medium dashed border */
+       public final static short BORDER_MEDIUM_DASHED =  BorderFormatting.BORDER_MEDIUM_DASHED;
+       /** dash-dot border */
+       public final static short BORDER_DASH_DOT =  BorderFormatting.BORDER_DASH_DOT;
+       /** medium dash-dot border */
+       public final static short BORDER_MEDIUM_DASH_DOT =  BorderFormatting.BORDER_MEDIUM_DASH_DOT;
+       /** dash-dot-dot border */
+       public final static short BORDER_DASH_DOT_DOT =  BorderFormatting.BORDER_DASH_DOT_DOT;
+       /** medium dash-dot-dot border */
+       public final static short BORDER_MEDIUM_DASH_DOT_DOT =  BorderFormatting.BORDER_MEDIUM_DASH_DOT_DOT;
+       /** slanted dash-dot border */
+       public final static short BORDER_SLANTED_DASH_DOT =  BorderFormatting.BORDER_SLANTED_DASH_DOT;
 
-    public final static short BORDER_NONE =  BorderFormatting.BORDER_NONE;
-
-    /**
-     * Thin border
-     */
-
-    public final static short BORDER_THIN =  BorderFormatting.BORDER_THIN;
-
-    /**
-     * Medium border
-     */
+       
+       private final BorderFormatting borderFormatting;
+       
+       public HSSFBorderFormatting()
+       {
+               borderFormatting = new BorderFormatting();
+       }
 
-    public final static short BORDER_MEDIUM =  BorderFormatting.BORDER_MEDIUM;
+       protected BorderFormatting getBorderFormattingBlock()
+       {
+               return borderFormatting;
+       }
 
-    /**
-     * dash border
-     */
+       public short getBorderBottom()
+       {
+               return borderFormatting.getBorderBottom();
+       }
 
-    public final static short BORDER_DASHED =  BorderFormatting.BORDER_DASHED;
+       public short getBorderDiagonal()
+       {
+               return borderFormatting.getBorderDiagonal();
+       }
 
-    /**
-     * dot border
-     */
+       public short getBorderLeft()
+       {
+               return borderFormatting.getBorderLeft();
+       }
 
-    public final static short BORDER_HAIR =  BorderFormatting.BORDER_HAIR;
+       public short getBorderRight()
+       {
+               return borderFormatting.getBorderRight();
+       }
 
-    /**
-     * Thick border
-     */
+       public short getBorderTop()
+       {
+               return borderFormatting.getBorderTop();
+       }
 
-    public final static short BORDER_THICK =  BorderFormatting.BORDER_THICK;
+       public short getBottomBorderColor()
+       {
+               return borderFormatting.getBottomBorderColor();
+       }
 
-    /**
-     * double-line border
-     */
+       public short getDiagonalBorderColor()
+       {
+               return borderFormatting.getDiagonalBorderColor();
+       }
 
-    public final static short BORDER_DOUBLE =  BorderFormatting.BORDER_DOUBLE;
+       public short getLeftBorderColor()
+       {
+               return borderFormatting.getLeftBorderColor();
+       }
 
-    /**
-     * hair-line border
-     */
+       public short getRightBorderColor()
+       {
+               return borderFormatting.getRightBorderColor();
+       }
 
-    public final static short BORDER_DOTTED =  BorderFormatting.BORDER_DOTTED;
+       public short getTopBorderColor()
+       {
+               return borderFormatting.getTopBorderColor();
+       }
 
-    /**
-     * Medium dashed border
-     */
+       public boolean isBackwardDiagonalOn()
+       {
+               return borderFormatting.isBackwardDiagonalOn();
+       }
 
-    public final static short BORDER_MEDIUM_DASHED =  BorderFormatting.BORDER_MEDIUM_DASHED;
+       public boolean isForwardDiagonalOn()
+       {
+               return borderFormatting.isForwardDiagonalOn();
+       }
 
-    /**
-     * dash-dot border
-     */
+       public void setBackwardDiagonalOn(boolean on)
+       {
+               borderFormatting.setBackwardDiagonalOn(on);
+       }
 
-    public final static short BORDER_DASH_DOT =  BorderFormatting.BORDER_DASH_DOT;
+       public void setBorderBottom(short border)
+       {
+               borderFormatting.setBorderBottom(border);
+       }
 
-    /**
-     * medium dash-dot border
-     */
+       public void setBorderDiagonal(short border)
+       {
+               borderFormatting.setBorderDiagonal(border);
+       }
 
-    public final static short BORDER_MEDIUM_DASH_DOT =  BorderFormatting.BORDER_MEDIUM_DASH_DOT;
+       public void setBorderLeft(short border)
+       {
+               borderFormatting.setBorderLeft(border);
+       }
 
-    /**
-     * dash-dot-dot border
-     */
+       public void setBorderRight(short border)
+       {
+               borderFormatting.setBorderRight(border);
+       }
 
-    public final static short BORDER_DASH_DOT_DOT =  BorderFormatting.BORDER_DASH_DOT_DOT;
+       public void setBorderTop(short border)
+       {
+               borderFormatting.setBorderTop(border);
+       }
 
-    /**
-     * medium dash-dot-dot border
-     */
+       public void setBottomBorderColor(short color)
+       {
+               borderFormatting.setBottomBorderColor(color);
+       }
 
-    public final static short BORDER_MEDIUM_DASH_DOT_DOT =  BorderFormatting.BORDER_MEDIUM_DASH_DOT_DOT;
+       public void setDiagonalBorderColor(short color)
+       {
+               borderFormatting.setDiagonalBorderColor(color);
+       }
 
-    /**
-     * slanted dash-dot border
-     */
+       public void setForwardDiagonalOn(boolean on)
+       {
+               borderFormatting.setForwardDiagonalOn(on);
+       }
 
-    public final static short BORDER_SLANTED_DASH_DOT =  BorderFormatting.BORDER_SLANTED_DASH_DOT;
+       public void setLeftBorderColor(short color)
+       {
+               borderFormatting.setLeftBorderColor(color);
+       }
 
-    
-       private BorderFormatting borderFormatting;
-       
-       public HSSFBorderFormatting()
+       public void setRightBorderColor(short color)
        {
-               borderFormatting = new BorderFormatting();
+               borderFormatting.setRightBorderColor(color);
        }
 
-       protected BorderFormatting getBorderFormattingBlock()
+       public void setTopBorderColor(short color)
        {
-               return borderFormatting;
+               borderFormatting.setTopBorderColor(color);
        }
-    
 }
index c7018a0e1a56e76b6252ab0f3dbb6a6a858b8ffd..d9e470a68cdd9dbc682d3ad8486d65732d27dce1 100644 (file)
@@ -16,9 +16,7 @@
 ==================================================================== */
 package org.apache.poi.hssf.usermodel;
 
-import java.util.ArrayList;
-import java.util.List;
-
+import org.apache.poi.hssf.model.Workbook;
 import org.apache.poi.hssf.record.CFHeaderRecord;
 import org.apache.poi.hssf.record.CFRuleRecord;
 import org.apache.poi.hssf.record.aggregates.CFRecordsAggregate;
@@ -86,13 +84,9 @@ import org.apache.poi.hssf.util.Region;
  */
 public final class HSSFConditionalFormatting
 {
-       private final HSSFSheet sheet;
+       private final Workbook workbook;
        private final CFRecordsAggregate cfAggregate;
 
-       HSSFConditionalFormatting(HSSFSheet sheet) {
-               this(sheet, new CFRecordsAggregate());
-       }
-
        HSSFConditionalFormatting(HSSFSheet sheet, CFRecordsAggregate cfAggregate)
        {
                if(sheet == null) {
@@ -101,36 +95,25 @@ public final class HSSFConditionalFormatting
                if(cfAggregate == null) {
                        throw new IllegalArgumentException("cfAggregate must not be null");
                }
-               this.sheet = sheet;
+               workbook = sheet.workbook.getWorkbook();
                this.cfAggregate = cfAggregate;
        }
        CFRecordsAggregate getCFRecordsAggregate() {
                return cfAggregate;
        }
 
-       public void setFormattingRegions(Region[] regions)
-       {
-               if( regions != null)
-               {
-                       CFHeaderRecord header = cfAggregate.getHeader();
-                       header.setCellRanges(mergeCellRanges(toCellRangeList(regions)));
-               }
-       }
-
        /**
-        * @return array of <tt>Region</tt>s. never <code>null</code>
+        * @return array of <tt>Region</tt>s. never <code>null</code> 
         */
        public Region[] getFormattingRegions()
        {
                CFHeaderRecord cfh = cfAggregate.getHeader();
-
-               List cellRanges = cfh.getCellRanges();
-
-               return toRegionArray(cellRanges);
+               CellRange[] cellRanges = cfh.getCellRanges();
+               return CellRange.convertCellRangesToRegions(cellRanges);
        }
 
        /**
-        * set a Conditional Formatting rule at position idx. 
+        * Replaces an existing Conditional Formatting rule at position idx. 
         * Excel allows to create up to 3 Conditional Formatting rules.
         * This method can be useful to modify existing  Conditional Formatting rules.
         * 
@@ -139,11 +122,7 @@ public final class HSSFConditionalFormatting
         */
        public void setRule(int idx, HSSFConditionalFormattingRule cfRule)
        {
-           if (idx < 0 || idx > 2) {
-               throw new IllegalArgumentException("idx must be between 0 and 2 but was (" 
-                       + idx + ")");
-           }
-               cfAggregate.getRules().set(idx, cfRule);
+               cfAggregate.setRule(idx, cfRule.getCfRuleRecord());
        }
 
        /**
@@ -153,136 +132,24 @@ public final class HSSFConditionalFormatting
         */
        public void addRule(HSSFConditionalFormattingRule cfRule)
        {
-               cfAggregate.getRules().add(cfRule);
+               cfAggregate.addRule(cfRule.getCfRuleRecord());
        }
 
        /**
-        * get a Conditional Formatting rule at position idx. 
-        * @param idx
-        * @return a Conditional Formatting rule at position idx.
+        * @return the Conditional Formatting rule at position idx.
         */
        public HSSFConditionalFormattingRule getRule(int idx)
        {
-               CFRuleRecord ruleRecord = (CFRuleRecord)cfAggregate.getRules().get(idx);
-               return new HSSFConditionalFormattingRule(sheet.workbook, ruleRecord);
+               CFRuleRecord ruleRecord = cfAggregate.getRule(idx);
+               return new HSSFConditionalFormattingRule(workbook, ruleRecord);
        }
 
        /**
         * @return number of Conditional Formatting rules.
         */
-       public int getNumbOfRules()
+       public int getNumberOfRules()
        {
-               return cfAggregate.getRules().size();
-       }
-
-
-       /**
-        * Do all possible cell merges between cells of the list so that:<br>
-        *      <li>if a cell range is completely inside of another cell range, it gets removed from the list 
-        *      <li>if two cells have a shared border, merge them into one bigger cell range
-        * @param cellRangeList
-        * @return updated List of cell ranges
-        */
-       private static List mergeCellRanges(List cellRangeList)
-       {
-               boolean merged = false;
-
-               do
-               {
-                       merged = false;
-
-                       if( cellRangeList.size()>1 )
-                       {
-                               for( int i=0; i<cellRangeList.size(); i++)
-                               {
-                                       CellRange range1 = (CellRange)cellRangeList.get(i);
-                                       for( int j=i+1; j<cellRangeList.size(); j++)
-                                       {
-                                               CellRange range2 = (CellRange)cellRangeList.get(j);
-
-                                               switch(range1.intersect(range2))
-                                               {
-                                                       case CellRange.NO_INTERSECTION: 
-                                                       {
-                                                               if( range1.hasSharedBorder(range2))
-                                                               {
-                                                                       cellRangeList.set(i, range1.createEnclosingCellRange(range2));
-                                                                       cellRangeList.remove(j--);
-                                                                       merged = true;
-                                                               }
-                                                               else
-                                                               {
-                                                                       // No intersection and no shared border: do nothing 
-                                                               }
-                                                               break;
-                                                       }
-                                                       case CellRange.OVERLAP:
-                                                       {
-                                                               // TODO split and re-merge the intersected area
-                                                               break;
-                                                       }
-                                                       case CellRange.INSIDE:
-                                                       {
-                                                               // Remove range2, since it is completely inside of range1
-                                                               cellRangeList.remove(j--);
-                                                               merged = true;
-                                                               break;
-                                                       }
-                                                       case CellRange.ENCLOSES:
-                                                       {
-                                                               // range2 encloses range1, so replace it with the enclosing one
-                                                               cellRangeList.set(i, range2);
-                                                               cellRangeList.remove(j--);
-                                                               merged = true;
-                                                               break;
-                                                       }
-                                               }
-                                       }
-                               }
-                       }
-               }
-               while( merged );
-
-               return cellRangeList;
-       }
-
-       /**
-        * Convert a List of CellRange objects to an array of regions 
-        *  
-        * @param List of CellRange objects
-        * @return regions
-        */
-       private static Region[] toRegionArray(List cellRanges)
-       {
-               int size = cellRanges.size();
-               Region[] regions = new Region[size];
-
-               for (int i = 0; i != size; i++)
-               {
-                       CellRange cr = (CellRange) cellRanges.get(i);
-                       regions[i] = new Region(cr.getFirstRow(), cr.getFirstColumn(), 
-                                       cr.getLastRow(), cr.getLastColumn());
-               }
-               return regions;
-       }
-
-       /**
-        * Convert array of regions to a List of CellRange objects
-        *  
-        * @param regions
-        * @return List of CellRange objects
-        */
-       private static List toCellRangeList(Region[] regions)
-       {
-               List cellRangeList = new ArrayList();
-               for( int i=0; i<regions.length; i++)
-               {
-                       Region r = regions[i];
-                       CellRange cr = new CellRange(r.getRowFrom(), r.getRowTo(), r.getColumnFrom(), r
-                                       .getColumnTo());
-                       cellRangeList.add(cr);
-               }
-               return cellRangeList;
+               return cfAggregate.getNumberOfRules();
        }
 
        public String toString()
index 3d003dc491b2f3d72e86c1de3176f4928f942be5..8f220fdf6e8e3794df67e8fe2e76241c66ff87c5 100644 (file)
 package org.apache.poi.hssf.usermodel;
 
 import java.util.List;
-import java.util.Stack;
 
 import org.apache.poi.hssf.model.FormulaParser;
+import org.apache.poi.hssf.model.Workbook;
 import org.apache.poi.hssf.record.CFRuleRecord;
+import org.apache.poi.hssf.record.CFRuleRecord.ComparisonOperator;
+import org.apache.poi.hssf.record.cf.BorderFormatting;
+import org.apache.poi.hssf.record.cf.FontFormatting;
+import org.apache.poi.hssf.record.cf.PatternFormatting;
 import org.apache.poi.hssf.record.formula.Ptg;
 
 /**
  * 
- * High level representation of Conditional Format  
+ * High level representation of Conditional Formatting Rule.
+ * It allows to specify formula based conditions for the Conditional Formatting
+ * and the formatting settings such as font, border and pattern.
  * 
  * @author Dmitriy Kumshayev
  */
 
-public class HSSFConditionalFormattingRule
+public final class HSSFConditionalFormattingRule
 {
-    public static final byte CELL_COMPARISON = CFRuleRecord.CONDITION_TYPE_CELL_VALUE_IS;
-    public static final byte FORMULA = CFRuleRecord.CONDITION_TYPE_FORMULA;
+    private static final byte CELL_COMPARISON = CFRuleRecord.CONDITION_TYPE_CELL_VALUE_IS;
 
-    public static final byte COMPARISON_OPERATOR_NO_COMPARISON = CFRuleRecord.COMPARISON_OPERATOR_NO_COMPARISON;
-    public static final byte COMPARISON_OPERATOR_BETWEEN          = CFRuleRecord.COMPARISON_OPERATOR_BETWEEN;
-    public static final byte COMPARISON_OPERATOR_NOT_BETWEEN   = CFRuleRecord.COMPARISON_OPERATOR_NOT_BETWEEN;
-    public static final byte COMPARISON_OPERATOR_EQUAL         = CFRuleRecord.COMPARISON_OPERATOR_EQUAL;
-    public static final byte COMPARISON_OPERATOR_NOT_EQUAL     = CFRuleRecord.COMPARISON_OPERATOR_NOT_EQUAL;
-    public static final byte COMPARISON_OPERATOR_GT            = CFRuleRecord.COMPARISON_OPERATOR_GT;
-    public static final byte COMPARISON_OPERATOR_LT            = CFRuleRecord.COMPARISON_OPERATOR_LT;
-    public static final byte COMPARISON_OPERATOR_GE            = CFRuleRecord.COMPARISON_OPERATOR_GE;
-    public static final byte COMPARISON_OPERATOR_LE            = CFRuleRecord.COMPARISON_OPERATOR_LE;
-    
-    
 
-       private CFRuleRecord cfRuleRecord;
-       private HSSFWorkbook workbook;
-       
-       protected HSSFConditionalFormattingRule(HSSFWorkbook workbook)
-       {
-               this.workbook = workbook;
-               this.cfRuleRecord = new CFRuleRecord();
-       }
 
-       protected HSSFConditionalFormattingRule(HSSFWorkbook workbook, CFRuleRecord cfRuleRecord)
-       {
-               this.workbook = workbook;
-               this.cfRuleRecord = cfRuleRecord;
-       }
+       private final CFRuleRecord cfRuleRecord;
+       private final Workbook workbook;
 
-       /** 
-        *  Keep Font Formatting unchanged for this Conditional Formatting Rule 
-        */
-       public void setFontFormattingUnchanged()
-       {
-               cfRuleRecord.setFontFormattingUnchanged();
-       }
-       /** 
-        *  Keep Border Formatting unchanged for this Conditional Formatting Rule 
-        */
-       public void setBorderFormattingUnchanged()
-       {
-               cfRuleRecord.setBorderFormattingUnchanged();
+       HSSFConditionalFormattingRule(Workbook pWorkbook, CFRuleRecord pRuleRecord) {
+               workbook = pWorkbook;
+               cfRuleRecord = pRuleRecord;
        }
-       /** 
-        *  Keep Pattern Formatting unchanged for this Conditional Formatting Rule 
-        */
-       public void setPatternFormattingUnchanged()
-       {
-               cfRuleRecord.setPatternFormattingUnchanged();
+       HSSFConditionalFormattingRule(Workbook pWorkbook, CFRuleRecord pRuleRecord, 
+                       HSSFFontFormatting fontFmt, HSSFBorderFormatting bordFmt, HSSFPatternFormatting patternFmt) {
+               this(pWorkbook, pRuleRecord);
+               setFontFormatting(fontFmt);
+               setBorderFormatting(bordFmt);
+               setPatternFormatting(patternFmt);
        }
-       
-       public void setFontFormatting(HSSFFontFormatting fontFormatting)
-       {
-               if( fontFormatting!=null )
-               {
-                       cfRuleRecord.setFontFormatting(fontFormatting.getFontFormattingBlock());
-               }
-               else
-               {
-                       setFontFormattingUnchanged();
-               }
-       }
-       public void setBorderFormatting(HSSFBorderFormatting borderFormatting)
+
+       CFRuleRecord getCfRuleRecord()
        {
-               if( borderFormatting != null )
-               {
-                       cfRuleRecord.setBorderFormatting(borderFormatting.getBorderFormattingBlock());
-               }
-               else
-               {
-                       setBorderFormattingUnchanged();
-               }
-       }
-       public void setPatternFormatting(HSSFPatternFormatting patternFormatting)
-       {
-               if( patternFormatting != null)
-               {
-                       cfRuleRecord.setPatternFormatting(patternFormatting.getPatternFormattingBlock());
-               }
-               else
-               {
-                       setPatternFormattingUnchanged();
-               }
+               return cfRuleRecord;
        }
        
-       public void setCellComparisonCondition(byte comparisonOperation, String formula1, String formula2)
-       {
-               cfRuleRecord.setConditionType(CELL_COMPARISON);
-               cfRuleRecord.setComparisonOperation(comparisonOperation);
-               
-               // Formula 1
-               setFormula1(formula1);
-               
-               // Formula 2
-               setFormula1(formula2);
-       }
        
-       public void setFormulaCondition(String formula)
+       /**
+        * @param fontFmt pass <code>null</code> to signify 'font unchanged'
+        */
+       public void setFontFormatting(HSSFFontFormatting fontFmt)
        {
-               cfRuleRecord.setConditionType(FORMULA);
-               // Formula 1
-               setFormula1(formula);
+               FontFormatting block = fontFmt==null ? null : fontFmt.getFontFormattingBlock();
+               cfRuleRecord.setFontFormatting(block);
        }
-       
-       public void setFormula1(String formula)
+       /**
+        * @param borderFmt pass <code>null</code> to signify 'border unchanged'
+        */
+       public void setBorderFormatting(HSSFBorderFormatting borderFmt)
        {
-               // Formula 1
-               if( formula != null)
-               {
-                   Stack parsedExpression = parseFormula(formula);
-                       if( parsedExpression != null )
-                       {
-                               cfRuleRecord.setParsedExpression1(parsedExpression);
-                       }
-                       else
-                       {
-                               cfRuleRecord.setParsedExpression1(null);
-                       }
-               }
-               else
-               {
-                       cfRuleRecord.setParsedExpression1(null);
-               }
+               BorderFormatting block = borderFmt==null ? null : borderFmt.getBorderFormattingBlock();
+               cfRuleRecord.setBorderFormatting(block);
        }
-       
-       public void setFormula2(String formula)
+       /**
+        * @param patternFmt pass <code>null</code> to signify 'pattern unchanged'
+        */
+       public void setPatternFormatting(HSSFPatternFormatting patternFmt)
        {
-               // Formula 2
-               if( formula != null)
-               {
-                   Stack parsedExpression = parseFormula(formula);
-                       if( parsedExpression != null )
-                       {
-                               cfRuleRecord.setParsedExpression2(parsedExpression);
-                       }
-                       else
-                       {
-                               cfRuleRecord.setParsedExpression2(null);
-                       }
-               }
-               else
-               {
-                       cfRuleRecord.setParsedExpression2(null);
-               }
+               PatternFormatting block = patternFmt==null ? null : patternFmt.getPatternFormattingBlock();
+               cfRuleRecord.setPatternFormatting(block);
        }
        
        public String getFormula1()
        {
-        return toFormulaString(cfRuleRecord.getParsedExpression1());
+               return toFormulaString(cfRuleRecord.getParsedExpression1());
        }
 
        public String getFormula2()
        {
                byte conditionType = cfRuleRecord.getConditionType();
-               switch(conditionType)
-               {
-                       case CELL_COMPARISON:
+               if (conditionType == CELL_COMPARISON) {
+                       byte comparisonOperation = cfRuleRecord.getComparisonOperation();
+                       switch(comparisonOperation)
                        {
-                               byte comparisonOperation = cfRuleRecord.getComparisonOperation();
-                               switch(comparisonOperation)
-                               {
-                                       case COMPARISON_OPERATOR_BETWEEN:
-                                       case COMPARISON_OPERATOR_NOT_BETWEEN:
-                                               return toFormulaString(cfRuleRecord.getParsedExpression2());
-                               }
+                               case ComparisonOperator.BETWEEN:
+                               case ComparisonOperator.NOT_BETWEEN:
+                                       return toFormulaString(cfRuleRecord.getParsedExpression2());
                        }
                }
                return null;
        }
 
-       private String toFormulaString(List parsedExpression)
+       private String toFormulaString(Ptg[] parsedExpression)
        {
                String formula = null;
                if(parsedExpression!=null)
                {
-               formula = FormulaParser.toFormulaString(workbook.getWorkbook(),parsedExpression);
+               formula = FormulaParser.toFormulaString(workbookparsedExpression);
                }
                return formula;
        }
-       
-
-       private Stack parseFormula(String formula2)
-       {
-               FormulaParser parser = 
-                       new FormulaParser(formula2, workbook.getWorkbook());
-               parser.parse();
-
-               Stack parsedExpression = convertToTokenStack(parser.getRPNPtg());
-           parsedExpression = convertToTokenStack(parser.getRPNPtg());
-               return parsedExpression;
-       }
-
-       private static Stack convertToTokenStack(Ptg[] ptgs)
-       {
-               if( ptgs != null)
-               {
-                       Stack parsedExpression = new Stack();
-                       // fill the Ptg Stack with Ptgs of new formula
-                       for (int k = 0; k < ptgs.length; k++) 
-                       {
-                           parsedExpression.push(ptgs[ k ]);
-                       }
-                       return parsedExpression;
-               }
-               else
-               {
-                       return null;
-               }
-       }
-       
-       
 }
index 9e69fa255d89ffbd04a3c00892ef506e4befae5c..2d3d6781caab924d77bf58cdfe59ce39ca73299d 100644 (file)
@@ -58,7 +58,7 @@ public class HSSFPatriarch
      */
     HSSFPatriarch(HSSFSheet sheet, EscherAggregate boundAggregate)
     {
-       this.boundAggregate = boundAggregate;
+        this.boundAggregate = boundAggregate;
         this.sheet = sheet;
     }
 
@@ -197,29 +197,29 @@ public class HSSFPatriarch
      *  to work on some charts so far)
      */
     public boolean containsChart() {
-       // TODO - support charts properly in usermodel
-       
-       // We're looking for a EscherOptRecord
-       EscherOptRecord optRecord = (EscherOptRecord)
-               boundAggregate.findFirstWithId(EscherOptRecord.RECORD_ID);
-       if(optRecord == null) {
-               // No opt record, can't have chart
-               return false;
-       }
-       
-       for(Iterator it = optRecord.getEscherProperties().iterator(); it.hasNext();) {
-               EscherProperty prop = (EscherProperty)it.next();
-               if(prop.getPropertyNumber() == 896 && prop.isComplex()) {
-                       EscherComplexProperty cp = (EscherComplexProperty)prop;
-                       String str = StringUtil.getFromUnicodeLE(cp.getComplexData());
-                       System.err.println(str);
-                       if(str.equals("Chart 1\0")) {
-                               return true;
-                       }
-               }
-       }
+        // TODO - support charts properly in usermodel
+        
+        // We're looking for a EscherOptRecord
+        EscherOptRecord optRecord = (EscherOptRecord)
+            boundAggregate.findFirstWithId(EscherOptRecord.RECORD_ID);
+        if(optRecord == null) {
+            // No opt record, can't have chart
+            return false;
+        }
+        
+        for(Iterator it = optRecord.getEscherProperties().iterator(); it.hasNext();) {
+            EscherProperty prop = (EscherProperty)it.next();
+            if(prop.getPropertyNumber() == 896 && prop.isComplex()) {
+                EscherComplexProperty cp = (EscherComplexProperty)prop;
+                String str = StringUtil.getFromUnicodeLE(cp.getComplexData());
+                //System.err.println(str);
+                if(str.equals("Chart 1\0")) {
+                    return true;
+                }
+            }
+        }
 
-       return false;
+        return false;
     }
 
     /**
@@ -258,6 +258,6 @@ public class HSSFPatriarch
      * Returns the aggregate escher record we're bound to 
      */
     protected EscherAggregate _getBoundAggregate() {
-       return boundAggregate;
+        return boundAggregate;
     }
 }
index 0e8759f4fd03383da021cc6397b9e2035a4a5daa..4aad1e1b18f7c1e28f4a9b4ca1c2cb5203696491 100644 (file)
@@ -36,6 +36,7 @@ import org.apache.poi.hssf.model.FormulaParser;
 import org.apache.poi.hssf.model.Sheet;
 import org.apache.poi.hssf.model.Workbook;
 import org.apache.poi.hssf.record.CellValueRecordInterface;
+import org.apache.poi.hssf.record.CFRuleRecord;
 import org.apache.poi.hssf.record.DVALRecord;
 import org.apache.poi.hssf.record.DVRecord;
 import org.apache.poi.hssf.record.EOFRecord;
@@ -1106,8 +1107,8 @@ public class HSSFSheet implements org.apache.poi.ss.usermodel.Sheet
      * @param leftcol the left column to show in desktop window pane
      */
     public void showInPane(short toprow, short leftcol){
-        this.sheet.setTopRow((short)toprow);
-        this.sheet.setLeftCol((short)leftcol);
+        this.sheet.setTopRow(toprow);
+        this.sheet.setLeftCol(leftcol);
         }
 
     /**
@@ -1454,7 +1455,7 @@ public class HSSFSheet implements org.apache.poi.ss.usermodel.Sheet
           int i = 0;
           while (iterator.hasNext()) {
             PageBreakRecord.Break breakItem = (PageBreakRecord.Break)iterator.next();
-            returnValue[i++] = (int)breakItem.main;
+            returnValue[i++] = breakItem.main;
           }
           return returnValue;
         }
@@ -1822,7 +1823,7 @@ public class HSSFSheet implements org.apache.poi.ss.usermodel.Sheet
      *
      * @return cell comment or <code>null</code> if not found
      */
-     public HSSFComment getCellComment(int row, int column){
+     public HSSFComment getCellComment(int row, int column) {
         // Don't call findCellComment directly, otherwise
         //  two calls to this method will result in two
         //  new HSSFComment instances, which is bad
@@ -1846,25 +1847,26 @@ public class HSSFSheet implements org.apache.poi.ss.usermodel.Sheet
       * with a cell comparison operator and
       * formatting rules such as font format, border format and pattern format
       *
-      * @param comparisonOperation - one of the following values: <p>
-      *         <li>{@link HSSFConditionalFormattingRule#COMPARISON_OPERATOR_BETWEEN}</li>
-      *         <li>{@link HSSFConditionalFormattingRule#COMPARISON_OPERATOR_NOT_BETWEEN}</li>
-      *         <li>{@link HSSFConditionalFormattingRule#COMPARISON_OPERATOR_EQUAL}</li>
-      *         <li>{@link HSSFConditionalFormattingRule#COMPARISON_OPERATOR_NOT_EQUAL}</li>
-      *         <li>{@link HSSFConditionalFormattingRule#COMPARISON_OPERATOR_GT}</li>
-      *         <li>{@link HSSFConditionalFormattingRule#COMPARISON_OPERATOR_LT}</li>
-      *         <li>{@link HSSFConditionalFormattingRule#COMPARISON_OPERATOR_GE}</li>
-      *         <li>{@link HSSFConditionalFormattingRule#COMPARISON_OPERATOR_LE}</li>
+      * @param comparisonOperation - a constant value from
+      *         <tt>{@link HSSFConditionalFormattingRule.ComparisonOperator}</tt>: <p>
+      * <ul>
+      *         <li>BETWEEN</li>
+      *         <li>NOT_BETWEEN</li>
+      *         <li>EQUAL</li>
+      *         <li>NOT_EQUAL</li>
+      *         <li>GT</li>
+      *         <li>LT</li>
+      *         <li>GE</li>
+      *         <li>LE</li>
+      * </ul>
       * </p>
       * @param formula1 - formula for the valued, compared with the cell
       * @param formula2 - second formula (only used with
       * {@link HSSFConditionalFormattingRule#COMPARISON_OPERATOR_BETWEEN}) and
       * {@link HSSFConditionalFormattingRule#COMPARISON_OPERATOR_NOT_BETWEEN} operations)
-      * @param fontFmt - font formatting rules
-      * @param bordFmt - border formatting rules
-      * @param patternFmt - pattern formatting rules
-      * @return
-      *
+      * @param fontFmt - font formatting rules (may be <code>null</code>)
+      * @param bordFmt - border formatting rules (may be <code>null</code>)
+      * @param patternFmt - pattern formatting rules (may be <code>null</code>)
       */
      public HSSFConditionalFormattingRule createConditionalFormattingRule(
              byte comparisonOperation,
@@ -1872,14 +1874,11 @@ public class HSSFSheet implements org.apache.poi.ss.usermodel.Sheet
              String formula2,
              HSSFFontFormatting fontFmt,
              HSSFBorderFormatting bordFmt,
-             HSSFPatternFormatting patternFmt)
-     {
-         HSSFConditionalFormattingRule cf = new HSSFConditionalFormattingRule(workbook);
-         cf.setFontFormatting(fontFmt);
-         cf.setBorderFormatting(bordFmt);
-         cf.setPatternFormatting(patternFmt);
-         cf.setCellComparisonCondition(comparisonOperation, formula1, formula2);
-         return cf;
+             HSSFPatternFormatting patternFmt) {
+        
+        Workbook wb = workbook.getWorkbook();
+        CFRuleRecord rr = CFRuleRecord.create(wb, comparisonOperation, formula1, formula2);
+        return new HSSFConditionalFormattingRule(wb, rr, fontFmt, bordFmt, patternFmt);
      }
 
      /**
@@ -1888,38 +1887,19 @@ public class HSSFSheet implements org.apache.poi.ss.usermodel.Sheet
       *
       * The formatting rules are applied by Excel when the value of the formula not equal to 0.
       *
-      * @param comparisonOperation - one of the following values: <p>
-      *         <li>{@link HSSFConditionalFormattingRule#COMPARISON_OPERATOR_BETWEEN}</li>
-      *         <li>{@link HSSFConditionalFormattingRule#COMPARISON_OPERATOR_NOT_BETWEEN}</li>
-      *         <li>{@link HSSFConditionalFormattingRule#COMPARISON_OPERATOR_EQUAL}</li>
-      *         <li>{@link HSSFConditionalFormattingRule#COMPARISON_OPERATOR_NOT_EQUAL}</li>
-      *         <li>{@link HSSFConditionalFormattingRule#COMPARISON_OPERATOR_GT}</li>
-      *         <li>{@link HSSFConditionalFormattingRule#COMPARISON_OPERATOR_LT}</li>
-      *         <li>{@link HSSFConditionalFormattingRule#COMPARISON_OPERATOR_GE}</li>
-      *         <li>{@link HSSFConditionalFormattingRule#COMPARISON_OPERATOR_LE}</li>
-      * </p>
-      * @param formula1 - formula for the valued, compared with the cell
-      * @param formula2 - second formula (only used with
-      * {@link HSSFConditionalFormattingRule#COMPARISON_OPERATOR_BETWEEN}) and
-      * {@link HSSFConditionalFormattingRule#COMPARISON_OPERATOR_NOT_BETWEEN} operations)
-      * @param fontFmt - font formatting rules
-      * @param bordFmt - border formatting rules
-      * @param patternFmt - pattern formatting rules
-      * @return
-      *
+      * @param formula - formula for the valued, compared with the cell
+      * @param fontFmt - font formatting rules (may be <code>null</code>)
+      * @param bordFmt - border formatting rules (may be <code>null</code>)
+      * @param patternFmt - pattern formatting rules (may be <code>null</code>)
       */
      public HSSFConditionalFormattingRule createConditionalFormattingRule(
              String formula,
              HSSFFontFormatting fontFmt,
              HSSFBorderFormatting bordFmt,
-             HSSFPatternFormatting patternFmt)
-     {
-         HSSFConditionalFormattingRule cf = new HSSFConditionalFormattingRule(workbook);
-         cf.setFontFormatting(fontFmt);
-         cf.setBorderFormatting(bordFmt);
-         cf.setPatternFormatting(patternFmt);
-         cf.setFormulaCondition(formula);
-         return cf;
+             HSSFPatternFormatting patternFmt) {
+         Workbook wb = workbook.getWorkbook();
+         CFRuleRecord rr = CFRuleRecord.create(wb, formula);
+         return new HSSFConditionalFormattingRule(wb, rr, fontFmt, bordFmt, patternFmt);
      }
 
      /**
@@ -1934,8 +1914,7 @@ public class HSSFSheet implements org.apache.poi.ss.usermodel.Sheet
       * @param cf HSSFConditionalFormatting object
       * @return index of the new Conditional Formatting object
       */
-     public int addConditionalFormatting( HSSFConditionalFormatting cf )
-     {
+     public int addConditionalFormatting( HSSFConditionalFormatting cf ) {
          CFRecordsAggregate cfraClone = cf.getCFRecordsAggregate().cloneCFAggregate();
 
          return sheet.addConditionalFormatting(cfraClone);
@@ -1945,46 +1924,46 @@ public class HSSFSheet implements org.apache.poi.ss.usermodel.Sheet
       * Allows to add a new Conditional Formatting set to the sheet.
       *
       * @param regions - list of rectangular regions to apply conditional formatting rules
-      * @param cfRules - set of up to three conditional formatting rules
+      * @param hcfRules - set of up to three conditional formatting rules
       *
       * @return index of the newly created Conditional Formatting object
       */
 
-     public int addConditionalFormatting( Region [] regions, HSSFConditionalFormattingRule [] cfRules )
-     {
-         HSSFConditionalFormatting cf = new HSSFConditionalFormatting(this);
-         cf.setFormattingRegions(regions);
-         if( cfRules != null )
-         {
-             for( int i=0; i!= cfRules.length; i++ )
-             {
-                 cf.addRule(cfRules[i]);
-             }
-         }
-         return sheet.addConditionalFormatting(cf.getCFRecordsAggregate());
+    public int addConditionalFormatting(Region [] regions, HSSFConditionalFormattingRule [] hcfRules) {
+        if (regions == null) {
+            throw new IllegalArgumentException("regions must not be null");
+        }
+        if (hcfRules == null) {
+            throw new IllegalArgumentException("hcfRules must not be null");
+        }
+
+        CFRuleRecord[] rules = new CFRuleRecord[hcfRules.length];
+        for (int i = 0; i != hcfRules.length; i++) {
+            rules[i] = hcfRules[i].getCfRuleRecord();
+        }
+        CFRecordsAggregate cfra = new CFRecordsAggregate(regions, rules);
+        return sheet.addConditionalFormatting(cfra);
      }
 
     /**
      * gets Conditional Formatting object at a particular index
-     * @param index of the Conditional Formatting object to fetch
+     * 
+     * @param index
+     *            of the Conditional Formatting object to fetch
      * @return Conditional Formatting object
      */
-
-    public HSSFConditionalFormatting getConditionalFormattingAt(int index)
-    {
+    public HSSFConditionalFormatting getConditionalFormattingAt(int index) {
         CFRecordsAggregate cf = sheet.getCFRecordsAggregateAt(index);
-        if( cf != null )
-        {
-            return new HSSFConditionalFormatting(this,cf);
+        if (cf == null) {
+            return null;
         }
-        return null;
+        return new HSSFConditionalFormatting(this,cf);
     }
 
     /**
      * @return number of Conditional Formatting objects of the sheet
      */
-    public int getNumConditionalFormattings()
-    {
+    public int getNumConditionalFormattings() {
         return sheet.getNumConditionalFormattings();
     }
 
@@ -1992,8 +1971,7 @@ public class HSSFSheet implements org.apache.poi.ss.usermodel.Sheet
      * removes a Conditional Formatting object by index
      * @param index of a Conditional Formatting object to remove
      */
-    public void removeConditionalFormatting(int index)
-    {
+    public void removeConditionalFormatting(int index) {
         sheet.removeConditionalFormatting(index);
     }
 }
index d8ddc7d2f2e9013b6c7cde4cf9d04cd1edba782e..135b625f1d7ba7640ebfb7805cec41fe0bfcdb5c 100644 (file)
@@ -265,6 +265,31 @@ public abstract class Sheet {
         }
     }
 
+    /**
+     * Removes the specified shape from this sheet.
+     *
+     * @param shape shape to be removed from this sheet, if present.
+     * @return <tt>true</tt> if the shape was deleted.
+     */
+    public boolean removeShape(Shape shape) {
+        PPDrawing ppdrawing = getPPDrawing();
+
+        EscherContainerRecord dg = (EscherContainerRecord) ppdrawing.getEscherRecords()[0];
+        EscherContainerRecord spgr = null;
+
+        for (Iterator it = dg.getChildRecords().iterator(); it.hasNext();) {
+            EscherRecord rec = (EscherRecord) it.next();
+            if (rec.getRecordId() == EscherContainerRecord.SPGR_CONTAINER) {
+                spgr = (EscherContainerRecord) rec;
+                break;
+            }
+        }
+        if(spgr == null) return false;
+
+        List lst = spgr.getChildRecords();
+        return lst.remove(shape.getSpContainer());
+    }
+
     /**
      * Return the master sheet .
      */
index 6dd5d9be1700827f7178d769efa97087bc0a5ff4..1fe8f7e5e6d88d135c6edecabd2cabc31c20e19b 100644 (file)
@@ -26,6 +26,7 @@ import java.awt.Rectangle;
 import java.io.ByteArrayOutputStream;
 import java.io.ByteArrayInputStream;
 import java.io.File;
+import java.io.IOException;
 import java.util.ArrayList;
 
 /**
@@ -279,4 +280,31 @@ public class TestShapes extends TestCase {
         line = (Line)grshape[1];
         assertEquals(new Rectangle(300, 300, 500, 0), line.getAnchor());
     }
+
+    /**
+     * Test functionality of Sheet.removeShape(Shape shape)
+     */
+    public void testRemoveShapes() throws IOException {
+        String file = System.getProperty("HSLF.testdata.path")+ "/with_textbox.ppt";
+        SlideShow ppt = new SlideShow(new HSLFSlideShow(file));
+        Slide sl = ppt.getSlides()[0];
+        Shape[] sh = sl.getShapes();
+        assertEquals("expected four shaped in " + file, 4, sh.length);
+        //remove all
+        for (int i = 0; i < sh.length; i++) {
+            boolean ok = sl.removeShape(sh[i]);
+            assertTrue("Failed to delete shape #" + i, ok);
+        }
+        //now Slide.getShapes() should return an empty array
+        assertEquals("expected 0 shaped in " + file, 0, sl.getShapes().length);
+
+        //serialize and read again. The file should be readable and contain no shapes
+        ByteArrayOutputStream out = new ByteArrayOutputStream();
+        ppt.write(out);
+        out.close();
+
+        ppt = new SlideShow(new ByteArrayInputStream(out.toByteArray()));
+        sl = ppt.getSlides()[0];
+        assertEquals("expected 0 shaped in " + file, 0, sl.getShapes().length);
+    }
 }
index 3b98aed0aed318710db0d9b477dde202973457d7..2589aa90dd0b2830fdd14d3c67aa6df445526752 100644 (file)
@@ -14,7 +14,7 @@
    See the License for the specific language governing permissions and
    limitations under the License.
 ==================================================================== */
-        
+
 package org.apache.poi.hssf.model;
 
 import junit.framework.AssertionFailedError;
@@ -54,7 +54,7 @@ import org.apache.poi.hssf.usermodel.HSSFSheet;
 import org.apache.poi.hssf.usermodel.HSSFWorkbook;
 
 /**
- * Test the low level formula parser functionality. High level tests are to 
+ * Test the low level formula parser functionality. High level tests are to
  *  be done via usermodel/HSSFCell.setFormulaValue() .
  * Some tests are also done in scratchpad, if they need
  *  HSSFFormulaEvaluator, which is there
@@ -71,7 +71,7 @@ public final class TestFormulaParser extends TestCase {
         assertNotNull("Ptg array should not be null", result);
         return result;
     }
-    
+
     public void testSimpleFormula() {
         FormulaParser fp = new FormulaParser("2+2",null);
         fp.parse();
@@ -86,9 +86,9 @@ public final class TestFormulaParser extends TestCase {
         assertTrue("",(ptgs[0] instanceof IntPtg));
         assertTrue("",(ptgs[1] instanceof IntPtg));
         assertTrue("",(ptgs[2] instanceof AddPtg));
-        
+
     }
-    
+
     public void testFormulaWithSpace2() {
         Ptg[] ptgs;
         FormulaParser fp;
@@ -97,7 +97,7 @@ public final class TestFormulaParser extends TestCase {
         ptgs = fp.getRPNPtg();
         assertTrue("five tokens expected, got "+ptgs.length,ptgs.length == 5);
     }
-    
+
      public void testFormulaWithSpaceNRef() {
         Ptg[] ptgs;
         FormulaParser fp;
@@ -106,7 +106,7 @@ public final class TestFormulaParser extends TestCase {
         ptgs = fp.getRPNPtg();
         assertTrue("two tokens expected, got "+ptgs.length,ptgs.length == 2);
     }
-    
+
     public void testFormulaWithString() {
         Ptg[] ptgs;
         FormulaParser fp;
@@ -172,7 +172,7 @@ public final class TestFormulaParser extends TestCase {
                
                
        }
-    
+
        /**
         * Make sure the ptgs are generated properly with two functions embedded
         *
@@ -225,7 +225,7 @@ public final class TestFormulaParser extends TestCase {
                assertEquals("4 Ptgs expected", 4, asts.length);
                
        }
-        
+       
        /**
         * Bug Reported by xt-jens.riis@nokia.com (Jens Riis)
         * Refers to Bug <a href="http://issues.apache.org/bugzilla/show_bug.cgi?id=17582">#17582</a>
@@ -247,7 +247,7 @@ public final class TestFormulaParser extends TestCase {
                
                                        
        }
-        
+
        public void testSimpleLogical() {
                FormulaParser fp=new FormulaParser("IF(A1<A2,B1,B2)",null);
                fp.parse();
@@ -255,10 +255,10 @@ public final class TestFormulaParser extends TestCase {
       assertTrue("Ptg array should not be null", ptgs !=null);
       assertEquals("Ptg array length", 9, ptgs.length);
       assertEquals("3rd Ptg is less than",LessThanPtg.class,ptgs[2].getClass());
-            
-           
+
+
        }
-        
+       
        public void testParenIf() {
                FormulaParser fp=new FormulaParser("IF((A1+A2)<=3,\"yes\",\"no\")",null);
                fp.parse();
@@ -281,7 +281,7 @@ public final class TestFormulaParser extends TestCase {
                assertEquals("15th Ptg is not the inner IF variable function ptg",FuncVarPtg.class,ptgs[14].getClass());
                
        }
-           
+       
     public void testMacroFunction() {
         Workbook w = Workbook.createWorkbook();
         FormulaParser fp = new FormulaParser("FOO()", w);
@@ -291,7 +291,7 @@ public final class TestFormulaParser extends TestCase {
         // the name gets encoded as the first arg
         NamePtg tname = (NamePtg) ptg[0];
         assertEquals("FOO", tname.toFormulaString(w));
-        
+
         AbstractFunctionPtg tfunc = (AbstractFunctionPtg) ptg[1];
         assertTrue(tfunc.isExternalFunction());
     }
@@ -302,9 +302,9 @@ public final class TestFormulaParser extends TestCase {
         Ptg[] ptg = fp.getRPNPtg();
         assertTrue("first ptg is string",ptg[0] instanceof StringPtg);
         assertTrue("second ptg is string",ptg[1] instanceof StringPtg);
-        
+
     }
-    
+
     public void testConcatenate(){
          FormulaParser fp = new FormulaParser("CONCATENATE(\"first\",\"second\")",null);
          fp.parse();
@@ -312,7 +312,7 @@ public final class TestFormulaParser extends TestCase {
         assertTrue("first ptg is string",ptg[0] instanceof StringPtg);
         assertTrue("second ptg is string",ptg[1] instanceof StringPtg);
     }
-    
+
     public void testWorksheetReferences()
     {
        HSSFWorkbook wb = new HSSFWorkbook();
@@ -330,7 +330,7 @@ public final class TestFormulaParser extends TestCase {
        cell = row.createCell((short)1);
        cell.setCellFormula("'Quotes Needed Here &#$@'!A1");
     }
-    
+
     public void testUnaryMinus()
     {
                FormulaParser fp = new FormulaParser("-A1", null);
@@ -340,7 +340,7 @@ public final class TestFormulaParser extends TestCase {
                assertTrue("first ptg is reference",ptg[0] instanceof ReferencePtg);
                assertTrue("second ptg is Minus",ptg[1] instanceof UnaryMinusPtg);
      }
-    
+
     public void testUnaryPlus()
     {
                FormulaParser fp = new FormulaParser("+A1", null);
@@ -350,14 +350,14 @@ public final class TestFormulaParser extends TestCase {
                assertTrue("first ptg is reference",ptg[0] instanceof ReferencePtg);
                assertTrue("second ptg is Plus",ptg[1] instanceof UnaryPlusPtg);
      }
-    
+
        public void testLeadingSpaceInString()
        {
                String value = "  hi  ";
                FormulaParser fp = new FormulaParser("\"" + value + "\"", null);
                fp.parse();
                Ptg[] ptg = fp.getRPNPtg();
-    
+
                assertTrue("got 1 ptg", ptg.length == 1);
                assertTrue("ptg0 is a StringPtg", ptg[0] instanceof StringPtg);
                assertTrue("ptg0 contains exact value", ((StringPtg)ptg[0]).getValue().equals(value));
@@ -368,14 +368,14 @@ public final class TestFormulaParser extends TestCase {
                FormulaParser fp = new FormulaParser("lookup(A1, A3:A52, B3:B52)", null);
                fp.parse();
                Ptg[] ptg = fp.getRPNPtg();
-    
+
                assertTrue("got 4 ptg", ptg.length == 4);
                assertTrue("ptg0 has Value class", ptg[0].getPtgClass() == Ptg.CLASS_VALUE);
                
                fp = new FormulaParser("match(A1, A3:A52)", null);
                fp.parse();
                ptg = fp.getRPNPtg();
-    
+
                assertTrue("got 3 ptg", ptg.length == 3);
                assertTrue("ptg0 has Value class", ptg[0].getPtgClass() == Ptg.CLASS_VALUE);
        }
@@ -521,77 +521,77 @@ public final class TestFormulaParser extends TestCase {
         System.out.println("Testing org.apache.poi.hssf.record.formula.FormulaParser");
         junit.textui.TestRunner.run(TestFormulaParser.class);
     }
-    
+
     public void testNumbers() {
         HSSFWorkbook wb = new HSSFWorkbook();
-        
+
         wb.createSheet("Cash_Flow");
-        
+
         HSSFSheet sheet = wb.createSheet("Test");
         HSSFRow row = sheet.createRow(0);
         HSSFCell cell = row.createCell((short)0);
         String formula = null;
-        
+
         // starts from decimal point
-        
+
         cell.setCellFormula(".1");
         formula = cell.getCellFormula();
         assertEquals("0.1", formula);
-        
+
         cell.setCellFormula("+.1");
         formula = cell.getCellFormula();
         assertEquals("+0.1", formula);
-        
+
         cell.setCellFormula("-.1");
         formula = cell.getCellFormula();
         assertEquals("-0.1", formula);
-        
+
         // has exponent
-        
+
         cell.setCellFormula("10E1");
         formula = cell.getCellFormula();
         assertEquals("100.0", formula);
-        
+
         cell.setCellFormula("10E+1");
         formula = cell.getCellFormula();
         assertEquals("100.0", formula);
-        
+
         cell.setCellFormula("10E-1");
         formula = cell.getCellFormula();
         assertEquals("1.0", formula);
     }
-    
+
     public void testRanges() {
         HSSFWorkbook wb = new HSSFWorkbook();
-        
+
         wb.createSheet("Cash_Flow");
-        
+
         HSSFSheet sheet = wb.createSheet("Test");
         HSSFRow row = sheet.createRow(0);
         HSSFCell cell = row.createCell((short)0);
         String formula = null;
-        
+
         cell.setCellFormula("A1.A2");
         formula = cell.getCellFormula();
         assertEquals("A1:A2", formula);
-        
+
         cell.setCellFormula("A1..A2");
         formula = cell.getCellFormula();
         assertEquals("A1:A2", formula);
-        
+
         cell.setCellFormula("A1...A2");
         formula = cell.getCellFormula();
         assertEquals("A1:A2", formula);
     }
-    
+
     /**
      * Test for bug observable at svn revision 618865 (5-Feb-2008)<br/>
      * a formula consisting of a single no-arg function got rendered without the function braces
      */
     public void testToFormulaStringZeroArgFunction() {
-        
+
         Workbook book = Workbook.createWorkbook(); // not really used in this test
-        
+
         Ptg[] ptgs = {
                 new FuncPtg(10, 0),
         };
@@ -610,21 +610,21 @@ public final class TestFormulaParser extends TestCase {
         assertEquals(2, ptgs.length);
         assertEquals(ptgs[0].getClass(), IntPtg.class);
         assertEquals(ptgs[1].getClass(), PercentPtg.class);
-        
-        
-        // double percent OK 
+
+
+        // double percent OK
         ptgs = parseFormula("12345.678%%");
         assertEquals(3, ptgs.length);
         assertEquals(ptgs[0].getClass(), NumberPtg.class);
         assertEquals(ptgs[1].getClass(), PercentPtg.class);
         assertEquals(ptgs[2].getClass(), PercentPtg.class);
-        
+
         // percent of a bracketed expression
         ptgs = parseFormula("(A1+35)%*B1%");
         assertEquals(8, ptgs.length);
         assertEquals(ptgs[4].getClass(), PercentPtg.class);
         assertEquals(ptgs[6].getClass(), PercentPtg.class);
-        
+
         // percent of a text quantity
         ptgs = parseFormula("\"8.75\"%");
         assertEquals(2, ptgs.length);
@@ -641,64 +641,64 @@ public final class TestFormulaParser extends TestCase {
 
         //
         // things that parse OK but would *evaluate* to an error
-        
+
         ptgs = parseFormula("\"abc\"%");
         assertEquals(2, ptgs.length);
         assertEquals(ptgs[0].getClass(), StringPtg.class);
         assertEquals(ptgs[1].getClass(), PercentPtg.class);
-        
+
         ptgs = parseFormula("#N/A%");
         assertEquals(2, ptgs.length);
         assertEquals(ptgs[0].getClass(), ErrPtg.class);
         assertEquals(ptgs[1].getClass(), PercentPtg.class);
     }
-    
+
     /**
      * Tests combinations of various operators in the absence of brackets
      */
     public void testPrecedenceAndAssociativity() {
 
         Class[] expClss;
-        
+
         // TRUE=TRUE=2=2  evaluates to FALSE
-        expClss = new Class[] { BoolPtg.class, BoolPtg.class, EqualPtg.class, 
+        expClss = new Class[] { BoolPtg.class, BoolPtg.class, EqualPtg.class,
                 IntPtg.class, EqualPtg.class, IntPtg.class, EqualPtg.class,  };
         confirmTokenClasses("TRUE=TRUE=2=2", expClss);
-       
+
 
         //  2^3^2    evaluates to 64 not 512
-        expClss = new Class[] { IntPtg.class, IntPtg.class, PowerPtg.class, 
+        expClss = new Class[] { IntPtg.class, IntPtg.class, PowerPtg.class,
                 IntPtg.class, PowerPtg.class, };
         confirmTokenClasses("2^3^2", expClss);
-        
+
         // "abc" & 2 + 3 & "def"   evaluates to "abc5def"
-        expClss = new Class[] { StringPtg.class, IntPtg.class, IntPtg.class, 
+        expClss = new Class[] { StringPtg.class, IntPtg.class, IntPtg.class,
                 AddPtg.class, ConcatPtg.class, StringPtg.class, ConcatPtg.class, };
         confirmTokenClasses("\"abc\"&2+3&\"def\"", expClss);
-        
-        
+
+
         //  (1 / 2) - (3 * 4)
-        expClss = new Class[] { IntPtg.class, IntPtg.class, DividePtg.class, 
+        expClss = new Class[] { IntPtg.class, IntPtg.class, DividePtg.class,
                 IntPtg.class, IntPtg.class, MultiplyPtg.class, SubtractPtg.class, };
         confirmTokenClasses("1/2-3*4", expClss);
-        
+
         // 2 * (2^2)
         expClss = new Class[] { IntPtg.class, IntPtg.class, IntPtg.class, PowerPtg.class, MultiplyPtg.class, };
         // NOT: (2 *2) ^ 2 -> int int multiply int power
         confirmTokenClasses("2*2^2", expClss);
-        
+
         //  2^200% -> 2 not 1.6E58
         expClss = new Class[] { IntPtg.class, IntPtg.class, PercentPtg.class, PowerPtg.class, };
         confirmTokenClasses("2^200%", expClss);
     }
-    
+
     private static void confirmTokenClasses(String formula, Class[] expectedClasses) {
         Ptg[] ptgs = parseFormula(formula);
         assertEquals(expectedClasses.length, ptgs.length);
         for (int i = 0; i < expectedClasses.length; i++) {
             if(expectedClasses[i] != ptgs[i].getClass()) {
                 fail("difference at token[" + i + "]: expected ("
-                    + expectedClasses[i].getName() + ") but got (" 
+                    + expectedClasses[i].getName() + ") but got ("
                     + ptgs[i].getClass().getName() + ")");
             }
         }
@@ -718,38 +718,38 @@ public final class TestFormulaParser extends TestCase {
 
     public void testParseNumber() {
         IntPtg ip;
-        
+
         // bug 33160
         ip = (IntPtg) parseSingleToken("40", IntPtg.class);
         assertEquals(40, ip.getValue());
         ip = (IntPtg) parseSingleToken("40000", IntPtg.class);
         assertEquals(40000, ip.getValue());
-        
+
         // check the upper edge of the IntPtg range:
         ip = (IntPtg) parseSingleToken("65535", IntPtg.class);
         assertEquals(65535, ip.getValue());
         NumberPtg np = (NumberPtg) parseSingleToken("65536", NumberPtg.class);
         assertEquals(65536, np.getValue(), 0);
-        
+
         np = (NumberPtg) parseSingleToken("65534.6", NumberPtg.class);
         assertEquals(65534.6, np.getValue(), 0);
     }
-    
+
     public void testMissingArgs() {
-        
+
         Class[] expClss;
-        
-        expClss = new Class[] { ReferencePtg.class, MissingArgPtg.class, ReferencePtg.class, 
+
+        expClss = new Class[] { ReferencePtg.class, MissingArgPtg.class, ReferencePtg.class,
                 FuncVarPtg.class, };
         confirmTokenClasses("if(A1, ,C1)", expClss);
-        
+
         expClss = new Class[] { MissingArgPtg.class, AreaPtg.class, MissingArgPtg.class,
                 FuncVarPtg.class, };
         confirmTokenClasses("counta( , A1:B2, )", expClss);
     }
 
     public void testParseErrorLiterals() {
-        
+
         confirmParseErrorLiteral(ErrPtg.NULL_INTERSECTION, "#NULL!");
         confirmParseErrorLiteral(ErrPtg.DIV_ZERO, "#DIV/0!");
         confirmParseErrorLiteral(ErrPtg.VALUE_INVALID, "#VALUE!");
@@ -762,7 +762,7 @@ public final class TestFormulaParser extends TestCase {
     private static void confirmParseErrorLiteral(ErrPtg expectedToken, String formula) {
         assertEquals(expectedToken, parseSingleToken(formula, ErrPtg.class));
     }
-    
+
     /**
      * To aid readability the parameters have been encoded with single quotes instead of double
      * quotes.  This method converts single quotes to double quotes before performing the parse
@@ -772,23 +772,23 @@ public final class TestFormulaParser extends TestCase {
         // formula: internal quotes become double double, surround with double quotes
         String formula = '"' + singleQuotedValue.replaceAll("'", "\"\"") + '"';
         String expectedValue = singleQuotedValue.replace('\'', '"');
-        
+
         StringPtg sp = (StringPtg) parseSingleToken(formula, StringPtg.class);
         assertEquals(expectedValue, sp.getValue());
     }
-    
+
     public void testPaseStringLiterals() {
         confirmStringParse("goto considered harmful");
-        
+
         confirmStringParse("goto 'considered' harmful");
-        
+
         confirmStringParse("");
         confirmStringParse("'");
         confirmStringParse("''");
         confirmStringParse("' '");
         confirmStringParse(" ' ");
     }
-    
+
     public void testParseSumIfSum() {
         String formulaString;
         Ptg[] ptgs;
@@ -809,14 +809,14 @@ public final class TestFormulaParser extends TestCase {
         parseExpectedException("1 + #N / A * 2");
         parseExpectedException("#value?");
         parseExpectedException("#DIV/ 0+2");
-        
-        
+
+
         if (false) { // TODO - add functionality to detect func arg count mismatch
             parseExpectedException("IF(TRUE)");
             parseExpectedException("countif(A1:B5, C1, D1)");
         }
     }
-    
+
     private static void parseExpectedException(String formula) {
         try {
             parseFormula(formula);
@@ -831,11 +831,11 @@ public final class TestFormulaParser extends TestCase {
     }
 
     public void testSetFormulaWithRowBeyond32768_Bug44539() {
-        
+
         HSSFWorkbook wb = new HSSFWorkbook();
         HSSFSheet sheet = wb.createSheet();
         wb.setSheetName(0, "Sheet1");
-        
+
         HSSFRow row = sheet.createRow(0);
         HSSFCell cell = row.createCell((short)0);
         cell.setCellFormula("SUM(A32769:A32770)");
@@ -862,11 +862,11 @@ public final class TestFormulaParser extends TestCase {
             throw e;
         }
         // FormulaParser strips spaces anyway
-        assertEquals("4", formulaString); 
+        assertEquals("4", formulaString);
 
         ptgs = new Ptg[] { new IntPtg(3), spacePtg, new IntPtg(4), spacePtg, new AddPtg()};
         formulaString = FormulaParser.toFormulaString(null, ptgs);
-        assertEquals("3+4", formulaString); 
+        assertEquals("3+4", formulaString);
     }
 
     /**
@@ -875,7 +875,7 @@ public final class TestFormulaParser extends TestCase {
     public void testTooFewOperandArgs() {
         // Simulating badly encoded cell formula of "=/1"
         // Not sure if Excel could ever produce this
-        Ptg[] ptgs = { 
+        Ptg[] ptgs = {
                 // Excel would probably have put tMissArg here
                 new IntPtg(1),
                 new DividePtg(),
index 9da8f45ebc26689543410303b518513ed5ab30d9..32b16cf6561b99a478460b72bc71f565d10af936 100755 (executable)
@@ -17,7 +17,9 @@
 
 package org.apache.poi.hssf.record;
 
+import org.apache.poi.hssf.record.aggregates.AllRecordAggregateTests;
 import org.apache.poi.hssf.record.formula.AllFormulaTests;
+import org.apache.poi.hssf.record.formula.functions.AllIndividualFunctionEvaluationTests;
 
 import junit.framework.Test;
 import junit.framework.TestSuite;
@@ -33,7 +35,8 @@ public final class AllRecordTests {
                TestSuite result = new TestSuite(AllRecordTests.class.getName());
 
                result.addTest(AllFormulaTests.suite());
-               
+               result.addTest(AllRecordAggregateTests.suite());
+
                result.addTestSuite(TestAreaFormatRecord.class);
                result.addTestSuite(TestAreaRecord.class);
                result.addTestSuite(TestAxisLineFormatRecord.class);
@@ -45,6 +48,8 @@ public final class AllRecordTests {
                result.addTestSuite(TestBarRecord.class);
                result.addTestSuite(TestBoundSheetRecord.class);
                result.addTestSuite(TestCategorySeriesAxisRecord.class);
+               result.addTestSuite(TestCFHeaderRecord.class);
+               result.addTestSuite(TestCFRuleRecord.class);
                result.addTestSuite(TestChartRecord.class);
                result.addTestSuite(TestChartTitleFormatRecord.class);
                result.addTestSuite(TestCommonObjectDataSubRecord.class);
index c3e5684798e2fad7e8d7c11c892a8ddca40db422..2a6faaccdd9c83d10161fdaf77ccfb8f381f6f35 100644 (file)
@@ -17,9 +17,6 @@
 
 package org.apache.poi.hssf.record;
 
-import java.util.ArrayList;
-import java.util.List;
-
 import junit.framework.TestCase;
 
 import org.apache.poi.hssf.record.cf.CellRange;
@@ -30,116 +27,114 @@ import org.apache.poi.hssf.record.cf.CellRange;
  *
  * @author Dmitriy Kumshayev 
  */
-public class TestCFHeaderRecord
-        extends TestCase
+public final class TestCFHeaderRecord extends TestCase
 {
 
-    public TestCFHeaderRecord(String name)
-    {
-        super(name);
-    }
+       public void testCreateCFHeaderRecord () 
+       {
+               CFHeaderRecord record = new CFHeaderRecord();
+               CellRange[] ranges = {
+                       new CellRange(0,-1,5,5),
+                       new CellRange(0,-1,6,6),
+                       new CellRange(0,1,0,1),
+                       new CellRange(0,1,2,3),
+                       new CellRange(2,3,0,1),
+                       new CellRange(2,3,2,3),
+               };
+               record.setCellRanges(ranges);
+               ranges = record.getCellRanges();
+               assertEquals(6,ranges.length);
+               CellRange enclosingCellRange = record.getEnclosingCellRange();
+               assertEquals(0, enclosingCellRange.getFirstRow());
+               assertEquals(-1, enclosingCellRange.getLastRow());
+               assertEquals(0, enclosingCellRange.getFirstColumn());
+               assertEquals(6, enclosingCellRange.getLastColumn());
+               record.setNeedRecalculation(true);
+               assertTrue(record.getNeedRecalculation());
+               record.setNeedRecalculation(false);
+               assertFalse(record.getNeedRecalculation());
+       }
+       
+       public void testSerialization() {
+               byte[] recordData = new byte[]
+               {
+                       (byte)0x03, (byte)0x00,
+                       (byte)0x01,     (byte)0x00,
+                       
+                       (byte)0x00,     (byte)0x00,
+                       (byte)0x03,     (byte)0x00,
+                       (byte)0x00,     (byte)0x00,
+                       (byte)0x03,     (byte)0x00,
+                       
+                       (byte)0x04,     (byte)0x00,
+                       
+                       (byte)0x00,     (byte)0x00,
+                       (byte)0x01,     (byte)0x00,
+                       (byte)0x00,     (byte)0x00,
+                       (byte)0x01,     (byte)0x00,
+                       
+                       (byte)0x00,     (byte)0x00,
+                       (byte)0x01,     (byte)0x00,
+                       (byte)0x02,     (byte)0x00,
+                       (byte)0x03,     (byte)0x00,
+                       
+                       (byte)0x02,     (byte)0x00,
+                       (byte)0x03,     (byte)0x00,
+                       (byte)0x00,     (byte)0x00,
+                       (byte)0x01,     (byte)0x00,
+                       
+                       (byte)0x02,     (byte)0x00,
+                       (byte)0x03,     (byte)0x00,
+                       (byte)0x02,     (byte)0x00,
+                       (byte)0x03,     (byte)0x00,
+               };
+
+               CFHeaderRecord record = new CFHeaderRecord(new TestcaseRecordInputStream(CFHeaderRecord.sid, (short)recordData.length, recordData));
+
+               assertEquals("#CFRULES", 3, record.getNumberOfConditionalFormats());
+               assertTrue(record.getNeedRecalculation());
+               CellRange enclosingCellRange = record.getEnclosingCellRange();
+               assertEquals(0, enclosingCellRange.getFirstRow());
+               assertEquals(3, enclosingCellRange.getLastRow());
+               assertEquals(0, enclosingCellRange.getFirstColumn());
+               assertEquals(3, enclosingCellRange.getLastColumn());
+               CellRange[] ranges = record.getCellRanges();
+               CellRange range0 = ranges[0];
+               assertEquals(0, range0.getFirstRow());
+               assertEquals(1, range0.getLastRow());
+               assertEquals(0, range0.getFirstColumn());
+               assertEquals(1, range0.getLastColumn());
+               CellRange range1 = ranges[1];
+               assertEquals(0, range1.getFirstRow());
+               assertEquals(1, range1.getLastRow());
+               assertEquals(2, range1.getFirstColumn());
+               assertEquals(3, range1.getLastColumn());
+               CellRange range2 = ranges[2];
+               assertEquals(2, range2.getFirstRow());
+               assertEquals(3, range2.getLastRow());
+               assertEquals(0, range2.getFirstColumn());
+               assertEquals(1, range2.getLastColumn());
+               CellRange range3 = ranges[3];
+               assertEquals(2, range3.getFirstRow());
+               assertEquals(3, range3.getLastRow());
+               assertEquals(2, range3.getFirstColumn());
+               assertEquals(3, range3.getLastColumn());
+               assertEquals(recordData.length+4, record.getRecordSize());
 
-    public void testCreateCFHeaderRecord () 
-    {
-        CFHeaderRecord record = new CFHeaderRecord();
-        List ranges = new ArrayList();
-        ranges.add(new CellRange(0,-1,(short)5,(short)5));
-        ranges.add(new CellRange(0,-1,(short)6,(short)6));
-        ranges.add(new CellRange(0,1,(short)0,(short)1));
-        ranges.add(new CellRange(0,1,(short)2,(short)3));
-        ranges.add(new CellRange(2,3,(short)0,(short)1));
-        ranges.add(new CellRange(2,3,(short)2,(short)3));
-        record.setCellRanges(ranges);
-        ranges = record.getCellRanges();
-        assertEquals(6,ranges.size());
-        CellRange enclosingCellRange = record.getEnclosingCellRange();
-        assertEquals(0, enclosingCellRange.getFirstRow());
-        assertEquals(-1, enclosingCellRange.getLastRow());
-        assertEquals(0, enclosingCellRange.getFirstColumn());
-        assertEquals(6, enclosingCellRange.getLastColumn());
-        record.setNeedRecalculation(true);
-        assertTrue(record.getNeedRecalculation());
-        record.setNeedRecalculation(false);
-        assertFalse(record.getNeedRecalculation());
-    }
-    
-    public void testSerialization() {
-       byte[] recordData = new byte[]
-       {
-                       (byte)0x03, (byte)0x00,
-                       (byte)0x01,     (byte)0x00,
-                       
-                       (byte)0x00,     (byte)0x00,
-                       (byte)0x03,     (byte)0x00,
-                       (byte)0x00,     (byte)0x00,
-                       (byte)0x03,     (byte)0x00,
-                       
-                       (byte)0x04,     (byte)0x00,
-                       
-                       (byte)0x00,     (byte)0x00,
-                       (byte)0x01,     (byte)0x00,
-                       (byte)0x00,     (byte)0x00,
-                       (byte)0x01,     (byte)0x00,
-                       
-                       (byte)0x00,     (byte)0x00,
-                       (byte)0x01,     (byte)0x00,
-                       (byte)0x02,     (byte)0x00,
-                       (byte)0x03,     (byte)0x00,
-                       
-                       (byte)0x02,     (byte)0x00,
-                       (byte)0x03,     (byte)0x00,
-                       (byte)0x00,     (byte)0x00,
-                       (byte)0x01,     (byte)0x00,
-                       
-                       (byte)0x02,     (byte)0x00,
-                       (byte)0x03,     (byte)0x00,
-                       (byte)0x02,     (byte)0x00,
-                       (byte)0x03,     (byte)0x00,
-       };
-       
-       CFHeaderRecord record = new CFHeaderRecord(new TestcaseRecordInputStream(CFHeaderRecord.sid, (short)recordData.length, recordData));
-               
-       assertEquals("#CFRULES", 3, record.getNumberOfConditionalFormats());
-       assertTrue(record.getNeedRecalculation());
-        CellRange enclosingCellRange = record.getEnclosingCellRange();
-        assertEquals(0, enclosingCellRange.getFirstRow());
-        assertEquals(3, enclosingCellRange.getLastRow());
-        assertEquals(0, enclosingCellRange.getFirstColumn());
-        assertEquals(3, enclosingCellRange.getLastColumn());
-        List ranges = record.getCellRanges();
-        assertEquals(0, ((CellRange)ranges.get(0)).getFirstRow());
-        assertEquals(1, ((CellRange)ranges.get(0)).getLastRow());
-        assertEquals(0, ((CellRange)ranges.get(0)).getFirstColumn());
-        assertEquals(1, ((CellRange)ranges.get(0)).getLastColumn());
-        assertEquals(0, ((CellRange)ranges.get(1)).getFirstRow());
-        assertEquals(1, ((CellRange)ranges.get(1)).getLastRow());
-        assertEquals(2, ((CellRange)ranges.get(1)).getFirstColumn());
-        assertEquals(3, ((CellRange)ranges.get(1)).getLastColumn());
-        assertEquals(2, ((CellRange)ranges.get(2)).getFirstRow());
-        assertEquals(3, ((CellRange)ranges.get(2)).getLastRow());
-        assertEquals(0, ((CellRange)ranges.get(2)).getFirstColumn());
-        assertEquals(1, ((CellRange)ranges.get(2)).getLastColumn());
-        assertEquals(2, ((CellRange)ranges.get(3)).getFirstRow());
-        assertEquals(3, ((CellRange)ranges.get(3)).getLastRow());
-        assertEquals(2, ((CellRange)ranges.get(3)).getFirstColumn());
-        assertEquals(3, ((CellRange)ranges.get(3)).getLastColumn());
-        assertEquals(recordData.length+4, record.getRecordSize());
-       
                byte[] output = record.serialize();
-               
+
                assertEquals("Output size", recordData.length+4, output.length); //includes sid+recordlength
-               
+
                for (int i = 0; i < recordData.length;i++) 
                {
                        assertEquals("CFHeaderRecord doesn't match", recordData[i], output[i+4]);
                }
-    }
-    
-    
-    public static void main(String[] ignored_args)
+       }
+       
+
+       public static void main(String[] ignored_args)
        {
                System.out.println("Testing org.apache.poi.hssf.record.CFHeaderRecord");
                junit.textui.TestRunner.run(TestCFHeaderRecord.class);
        }
-    
 }
index 77731d78125eb923f6cabe2d0b2a4450d74b0baf..e65025a31d7454694e76fcb71504caa335d9b52c 100644 (file)
@@ -19,109 +19,107 @@ package org.apache.poi.hssf.record;
 
 import junit.framework.TestCase;
 
+import org.apache.poi.hssf.model.Workbook;
+import org.apache.poi.hssf.record.CFRuleRecord.ComparisonOperator;
 import org.apache.poi.hssf.record.cf.BorderFormatting;
 import org.apache.poi.hssf.record.cf.FontFormatting;
 import org.apache.poi.hssf.record.cf.PatternFormatting;
 import org.apache.poi.hssf.util.HSSFColor;
+import org.apache.poi.util.LittleEndian;
 
 /**
  * Tests the serialization and deserialization of the TestCFRuleRecord
- * class works correctly.  
+ * class works correctly.
  *
  * @author Dmitriy Kumshayev 
  */
-public class TestCFRuleRecord
-        extends TestCase
+public final class TestCFRuleRecord extends TestCase
 {
 
-    public TestCFRuleRecord(String name)
-    {
-        super(name);
-    }
-
-    public void testCreateCFRuleRecord () 
-    {
-       CFRuleRecord record = new CFRuleRecord();
-       testCFRuleRecord(record);
-       
-       // Serialize
-       byte [] serializedRecord = record.serialize();
-
-       // Strip header
-       byte [] recordData = new byte[serializedRecord.length-4];
-               System.arraycopy(serializedRecord, 4, recordData, 0, recordData.length);
-               
-               // Deserialize
-       record = new CFRuleRecord(new TestcaseRecordInputStream(CFRuleRecord.sid, (short)recordData.length, recordData));
-       
-       // Serialize again
+       public void testCreateCFRuleRecord () 
+       {
+               Workbook workbook = Workbook.createWorkbook();
+               CFRuleRecord record = CFRuleRecord.create(workbook, "7");
+               testCFRuleRecord(record);
+
+               // Serialize
+               byte [] serializedRecord = record.serialize();
+
+               // Strip header
+               byte [] recordData = new byte[serializedRecord.length-4];
+               System.arraycopy(serializedRecord, 4, recordData, 0, recordData.length);
+
+               // Deserialize
+               record = new CFRuleRecord(new TestcaseRecordInputStream(CFRuleRecord.sid, (short)recordData.length, recordData));
+
+               // Serialize again
                byte[] output = record.serialize();
-       
+
                // Compare
                assertEquals("Output size", recordData.length+4, output.length); //includes sid+recordlength
-               
+
                for (int i = 0; i < recordData.length;i++) 
                {
                        assertEquals("CFRuleRecord doesn't match", recordData[i], output[i+4]);
                }
-    }
+       }
 
        private void testCFRuleRecord(CFRuleRecord record)
        {
                FontFormatting fontFormatting = new FontFormatting();
-       testFontFormattingAccessors(fontFormatting);
-       assertFalse(record.containsFontFormattingBlock());
-       record.setFontFormatting(fontFormatting);
-       assertTrue(record.containsFontFormattingBlock());
-       
-       BorderFormatting borderFormatting = new BorderFormatting();
-       testBorderFormattingAccessors(borderFormatting);
-       assertFalse(record.containsBorderFormattingBlock());
-       record.setBorderFormatting(borderFormatting);
-       assertTrue(record.containsBorderFormattingBlock());
-       
-       assertFalse(record.isLeftBorderModified());
-       record.setLeftBorderModified(true);
-       assertTrue(record.isLeftBorderModified());
-       
-       assertFalse(record.isRightBorderModified());
-       record.setRightBorderModified(true);
-       assertTrue(record.isRightBorderModified());
-       
-       assertFalse(record.isTopBorderModified());
-       record.setTopBorderModified(true);
-       assertTrue(record.isTopBorderModified());
-       
-       assertFalse(record.isBottomBorderModified());
-       record.setBottomBorderModified(true);
-       assertTrue(record.isBottomBorderModified());
-       
-       assertFalse(record.isTopLeftBottomRightBorderModified());
-       record.setTopLeftBottomRightBorderModified(true);
-       assertTrue(record.isTopLeftBottomRightBorderModified());
-       
-       assertFalse(record.isBottomLeftTopRightBorderModified());
-       record.setBottomLeftTopRightBorderModified(true);
-       assertTrue(record.isBottomLeftTopRightBorderModified());
-       
-       
-       PatternFormatting patternFormatting = new PatternFormatting();
-       testPatternFormattingAccessors(patternFormatting);
-       assertFalse(record.containsPatternFormattingBlock());
-       record.setPatternFormatting(patternFormatting);
-       assertTrue(record.containsPatternFormattingBlock());
-       
-       assertFalse(record.isPatternBackgroundColorModified());
-       record.setPatternBackgroundColorModified(true);
-       assertTrue(record.isPatternBackgroundColorModified());
-       
-       assertFalse(record.isPatternColorModified());
-       record.setPatternColorModified(true);
-       assertTrue(record.isPatternColorModified());
-
-       assertFalse(record.isPatternStyleModified());
-       record.setPatternStyleModified(true);
-       assertTrue(record.isPatternStyleModified());
+               testFontFormattingAccessors(fontFormatting);
+               assertFalse(record.containsFontFormattingBlock());
+               record.setFontFormatting(fontFormatting);
+               assertTrue(record.containsFontFormattingBlock());
+
+               BorderFormatting borderFormatting = new BorderFormatting();
+               testBorderFormattingAccessors(borderFormatting);
+               assertFalse(record.containsBorderFormattingBlock());
+               record.setBorderFormatting(borderFormatting);
+               assertTrue(record.containsBorderFormattingBlock());
+
+               assertFalse(record.isLeftBorderModified());
+               record.setLeftBorderModified(true);
+               assertTrue(record.isLeftBorderModified());
+
+               assertFalse(record.isRightBorderModified());
+               record.setRightBorderModified(true);
+               assertTrue(record.isRightBorderModified());
+
+               assertFalse(record.isTopBorderModified());
+               record.setTopBorderModified(true);
+               assertTrue(record.isTopBorderModified());
+
+               assertFalse(record.isBottomBorderModified());
+               record.setBottomBorderModified(true);
+               assertTrue(record.isBottomBorderModified());
+
+               assertFalse(record.isTopLeftBottomRightBorderModified());
+               record.setTopLeftBottomRightBorderModified(true);
+               assertTrue(record.isTopLeftBottomRightBorderModified());
+
+               assertFalse(record.isBottomLeftTopRightBorderModified());
+               record.setBottomLeftTopRightBorderModified(true);
+               assertTrue(record.isBottomLeftTopRightBorderModified());
+
+
+               PatternFormatting patternFormatting = new PatternFormatting();
+               testPatternFormattingAccessors(patternFormatting);
+               assertFalse(record.containsPatternFormattingBlock());
+               record.setPatternFormatting(patternFormatting);
+               assertTrue(record.containsPatternFormattingBlock());
+
+               assertFalse(record.isPatternBackgroundColorModified());
+               record.setPatternBackgroundColorModified(true);
+               assertTrue(record.isPatternBackgroundColorModified());
+
+               assertFalse(record.isPatternColorModified());
+               record.setPatternColorModified(true);
+               assertTrue(record.isPatternColorModified());
+
+               assertFalse(record.isPatternStyleModified());
+               record.setPatternStyleModified(true);
+               assertTrue(record.isPatternStyleModified());
        }
 
        private void testPatternFormattingAccessors(PatternFormatting patternFormatting)
@@ -131,10 +129,9 @@ public class TestCFRuleRecord
 
                patternFormatting.setFillForegroundColor(HSSFColor.INDIGO.index);
                assertEquals(HSSFColor.INDIGO.index,patternFormatting.getFillForegroundColor());
-               
+
                patternFormatting.setFillPattern(PatternFormatting.DIAMONDS);
                assertEquals(PatternFormatting.DIAMONDS,patternFormatting.getFillPattern());
-               
        }
        
        private void testBorderFormattingAccessors(BorderFormatting borderFormatting)
@@ -143,13 +140,13 @@ public class TestCFRuleRecord
                assertFalse(borderFormatting.isBackwardDiagonalOn());
                borderFormatting.setBackwardDiagonalOn(true);
                assertTrue(borderFormatting.isBackwardDiagonalOn());
-               
+
                borderFormatting.setBorderBottom(BorderFormatting.BORDER_DOTTED);
                assertEquals(BorderFormatting.BORDER_DOTTED, borderFormatting.getBorderBottom());
-               
+
                borderFormatting.setBorderDiagonal(BorderFormatting.BORDER_MEDIUM);
                assertEquals(BorderFormatting.BORDER_MEDIUM, borderFormatting.getBorderDiagonal());
-               
+
                borderFormatting.setBorderLeft(BorderFormatting.BORDER_MEDIUM_DASH_DOT_DOT);
                assertEquals(BorderFormatting.BORDER_MEDIUM_DASH_DOT_DOT, borderFormatting.getBorderLeft());
 
@@ -178,119 +175,137 @@ public class TestCFRuleRecord
                borderFormatting.setTopBorderColor(HSSFColor.GOLD.index);
                assertEquals(HSSFColor.GOLD.index, borderFormatting.getTopBorderColor());
        }
-    
-    
+
+
        private void testFontFormattingAccessors(FontFormatting fontFormatting)
        {
                // Check for defaults
-       assertFalse(fontFormatting.isEscapementTypeModified());
-       assertFalse(fontFormatting.isFontCancellationModified());
-       assertFalse(fontFormatting.isFontCondenseModified());
-       assertFalse(fontFormatting.isFontOutlineModified());
-       assertFalse(fontFormatting.isFontShadowModified());
-       assertFalse(fontFormatting.isFontStyleModified());
-       assertFalse(fontFormatting.isUnderlineTypeModified());
-       
-       assertFalse(fontFormatting.isBold());
-       assertFalse(fontFormatting.isCondenseOn());
-       assertFalse(fontFormatting.isItalic());
-       assertFalse(fontFormatting.isOutlineOn());
-       assertFalse(fontFormatting.isShadowOn());
-       assertFalse(fontFormatting.isStruckout());
-
-       assertEquals(0, fontFormatting.getEscapementType());
-       assertEquals(-1, fontFormatting.getFontColorIndex());
-       assertEquals(-1, fontFormatting.getFontHeight());
-       assertEquals(400, fontFormatting.getFontWeight());
-       assertEquals(0, fontFormatting.getUnderlineType());
-       
-       fontFormatting.setBold(true);
-       assertTrue(fontFormatting.isBold());
-       fontFormatting.setBold(false);
-       assertFalse(fontFormatting.isBold());
-       
-       fontFormatting.setCondense(true);
-       assertTrue(fontFormatting.isCondenseOn());
-       fontFormatting.setCondense(false);
-       assertFalse(fontFormatting.isCondenseOn());
-       
-       fontFormatting.setEscapementType(FontFormatting.SS_SUB);
-       assertEquals(FontFormatting.SS_SUB, fontFormatting.getEscapementType());
-       fontFormatting.setEscapementType(FontFormatting.SS_SUPER);
-       assertEquals(FontFormatting.SS_SUPER, fontFormatting.getEscapementType());
-       fontFormatting.setEscapementType(FontFormatting.SS_NONE);
-       assertEquals(FontFormatting.SS_NONE, fontFormatting.getEscapementType());
-       
-       fontFormatting.setEscapementTypeModified(false);
-       assertFalse(fontFormatting.isEscapementTypeModified());
-       fontFormatting.setEscapementTypeModified(true);
-       assertTrue(fontFormatting.isEscapementTypeModified());
-
-       fontFormatting.setFontCancellationModified(false);
-       assertFalse(fontFormatting.isFontCancellationModified());
-       fontFormatting.setFontCancellationModified(true);
-       assertTrue(fontFormatting.isFontCancellationModified());
-       
-       fontFormatting.setFontColorIndex((short)10);
-       assertEquals(10,fontFormatting.getFontColorIndex());
-
-       fontFormatting.setFontCondenseModified(false);
-       assertFalse(fontFormatting.isFontCondenseModified());
-       fontFormatting.setFontCondenseModified(true);
-       assertTrue(fontFormatting.isFontCondenseModified());
-       
-       fontFormatting.setFontHeight((short)100);
-       assertEquals(100,fontFormatting.getFontHeight());
-       
-       fontFormatting.setFontOutlineModified(false);
-       assertFalse(fontFormatting.isFontOutlineModified());
-       fontFormatting.setFontOutlineModified(true);
-       assertTrue(fontFormatting.isFontOutlineModified());
-
-       fontFormatting.setFontShadowModified(false);
-       assertFalse(fontFormatting.isFontShadowModified());
-       fontFormatting.setFontShadowModified(true);
-       assertTrue(fontFormatting.isFontShadowModified());
-
-       fontFormatting.setFontStyleModified(false);
-       assertFalse(fontFormatting.isFontStyleModified());
-       fontFormatting.setFontStyleModified(true);
-       assertTrue(fontFormatting.isFontStyleModified());
-
-       fontFormatting.setItalic(false);
-       assertFalse(fontFormatting.isItalic());
-       fontFormatting.setItalic(true);
-       assertTrue(fontFormatting.isItalic());
-
-       fontFormatting.setOutline(false);
-       assertFalse(fontFormatting.isOutlineOn());
-       fontFormatting.setOutline(true);
-       assertTrue(fontFormatting.isOutlineOn());
-
-       fontFormatting.setShadow(false);
-       assertFalse(fontFormatting.isShadowOn());
-       fontFormatting.setShadow(true);
-       assertTrue(fontFormatting.isShadowOn());
-       
-       fontFormatting.setStrikeout(false);
-       assertFalse(fontFormatting.isStruckout());
-       fontFormatting.setStrikeout(true);
-       assertTrue(fontFormatting.isStruckout());
-       
-       fontFormatting.setUnderlineType(FontFormatting.U_DOUBLE_ACCOUNTING);
-       assertEquals(FontFormatting.U_DOUBLE_ACCOUNTING, fontFormatting.getUnderlineType());
-
-       fontFormatting.setUnderlineTypeModified(false);
-       assertFalse(fontFormatting.isUnderlineTypeModified());
-       fontFormatting.setUnderlineTypeModified(true);
-       assertTrue(fontFormatting.isUnderlineTypeModified());
+               assertFalse(fontFormatting.isEscapementTypeModified());
+               assertFalse(fontFormatting.isFontCancellationModified());
+               assertFalse(fontFormatting.isFontCondenseModified());
+               assertFalse(fontFormatting.isFontOutlineModified());
+               assertFalse(fontFormatting.isFontShadowModified());
+               assertFalse(fontFormatting.isFontStyleModified());
+               assertFalse(fontFormatting.isUnderlineTypeModified());
+
+               assertFalse(fontFormatting.isBold());
+               assertFalse(fontFormatting.isCondenseOn());
+               assertFalse(fontFormatting.isItalic());
+               assertFalse(fontFormatting.isOutlineOn());
+               assertFalse(fontFormatting.isShadowOn());
+               assertFalse(fontFormatting.isStruckout());
+
+               assertEquals(0, fontFormatting.getEscapementType());
+               assertEquals(-1, fontFormatting.getFontColorIndex());
+               assertEquals(-1, fontFormatting.getFontHeight());
+               assertEquals(400, fontFormatting.getFontWeight());
+               assertEquals(0, fontFormatting.getUnderlineType());
+
+               fontFormatting.setBold(true);
+               assertTrue(fontFormatting.isBold());
+               fontFormatting.setBold(false);
+               assertFalse(fontFormatting.isBold());
+
+               fontFormatting.setCondense(true);
+               assertTrue(fontFormatting.isCondenseOn());
+               fontFormatting.setCondense(false);
+               assertFalse(fontFormatting.isCondenseOn());
+
+               fontFormatting.setEscapementType(FontFormatting.SS_SUB);
+               assertEquals(FontFormatting.SS_SUB, fontFormatting.getEscapementType());
+               fontFormatting.setEscapementType(FontFormatting.SS_SUPER);
+               assertEquals(FontFormatting.SS_SUPER, fontFormatting.getEscapementType());
+               fontFormatting.setEscapementType(FontFormatting.SS_NONE);
+               assertEquals(FontFormatting.SS_NONE, fontFormatting.getEscapementType());
+
+               fontFormatting.setEscapementTypeModified(false);
+               assertFalse(fontFormatting.isEscapementTypeModified());
+               fontFormatting.setEscapementTypeModified(true);
+               assertTrue(fontFormatting.isEscapementTypeModified());
+
+               fontFormatting.setFontCancellationModified(false);
+               assertFalse(fontFormatting.isFontCancellationModified());
+               fontFormatting.setFontCancellationModified(true);
+               assertTrue(fontFormatting.isFontCancellationModified());
+
+               fontFormatting.setFontColorIndex((short)10);
+               assertEquals(10,fontFormatting.getFontColorIndex());
+
+               fontFormatting.setFontCondenseModified(false);
+               assertFalse(fontFormatting.isFontCondenseModified());
+               fontFormatting.setFontCondenseModified(true);
+               assertTrue(fontFormatting.isFontCondenseModified());
+
+               fontFormatting.setFontHeight((short)100);
+               assertEquals(100,fontFormatting.getFontHeight());
+
+               fontFormatting.setFontOutlineModified(false);
+               assertFalse(fontFormatting.isFontOutlineModified());
+               fontFormatting.setFontOutlineModified(true);
+               assertTrue(fontFormatting.isFontOutlineModified());
+
+               fontFormatting.setFontShadowModified(false);
+               assertFalse(fontFormatting.isFontShadowModified());
+               fontFormatting.setFontShadowModified(true);
+               assertTrue(fontFormatting.isFontShadowModified());
+
+               fontFormatting.setFontStyleModified(false);
+               assertFalse(fontFormatting.isFontStyleModified());
+               fontFormatting.setFontStyleModified(true);
+               assertTrue(fontFormatting.isFontStyleModified());
+
+               fontFormatting.setItalic(false);
+               assertFalse(fontFormatting.isItalic());
+               fontFormatting.setItalic(true);
+               assertTrue(fontFormatting.isItalic());
+
+               fontFormatting.setOutline(false);
+               assertFalse(fontFormatting.isOutlineOn());
+               fontFormatting.setOutline(true);
+               assertTrue(fontFormatting.isOutlineOn());
+
+               fontFormatting.setShadow(false);
+               assertFalse(fontFormatting.isShadowOn());
+               fontFormatting.setShadow(true);
+               assertTrue(fontFormatting.isShadowOn());
+
+               fontFormatting.setStrikeout(false);
+               assertFalse(fontFormatting.isStruckout());
+               fontFormatting.setStrikeout(true);
+               assertTrue(fontFormatting.isStruckout());
+
+               fontFormatting.setUnderlineType(FontFormatting.U_DOUBLE_ACCOUNTING);
+               assertEquals(FontFormatting.U_DOUBLE_ACCOUNTING, fontFormatting.getUnderlineType());
+
+               fontFormatting.setUnderlineTypeModified(false);
+               assertFalse(fontFormatting.isUnderlineTypeModified());
+               fontFormatting.setUnderlineTypeModified(true);
+               assertTrue(fontFormatting.isUnderlineTypeModified());
        }
-    
-    
-    public static void main(String[] ignored_args)
+
+       public void testWrite() {
+               Workbook workbook = Workbook.createWorkbook();
+               CFRuleRecord rr = CFRuleRecord.create(workbook, ComparisonOperator.BETWEEN, "5", "10");
+
+               PatternFormatting patternFormatting = new PatternFormatting();
+               patternFormatting.setFillPattern(PatternFormatting.BRICKS);
+               rr.setPatternFormatting(patternFormatting);
+
+               byte[] data = rr.serialize();
+               assertEquals(26, data.length);
+               assertEquals(3, LittleEndian.getShort(data, 6));
+               assertEquals(3, LittleEndian.getShort(data, 8));
+
+               int flags = LittleEndian.getInt(data, 10);
+               assertEquals("unused flags should be 111", 0x00380000, flags & 0x00380000);
+               assertEquals("undocumented flags should be 0000", 0, flags & 0x03C00000); // Otherwise Excel gets unhappy
+               assertEquals(0xA03FFFFF, flags);
+       }
+
+
+       public static void main(String[] ignored_args)
        {
                System.out.println("Testing org.apache.poi.hssf.record.CFRuleRecord");
                junit.textui.TestRunner.run(TestCFRuleRecord.class);
        }
-    
 }
index 960627a39b250a57f5cc679c265622021e481d31..3c35b29a26bcc2f6cd5d187110bb8246eed467d7 100644 (file)
@@ -44,7 +44,7 @@ public final class TestExternalNameRecord extends TestCase {
                        }\r
                }\r
        }\r
-       \r
+\r
        public void testBasicSize() {\r
                ExternalNameRecord enr = createSimpleENR();\r
                if(enr.getRecordSize() == 13) {\r
diff --git a/src/testcases/org/apache/poi/hssf/record/aggregates/AllRecordAggregateTests.java b/src/testcases/org/apache/poi/hssf/record/aggregates/AllRecordAggregateTests.java
new file mode 100644 (file)
index 0000000..862fe67
--- /dev/null
@@ -0,0 +1,40 @@
+/* ====================================================================\r
+   Licensed to the Apache Software Foundation (ASF) under one or more\r
+   contributor license agreements.  See the NOTICE file distributed with\r
+   this work for additional information regarding copyright ownership.\r
+   The ASF licenses this file to You under the Apache License, Version 2.0\r
+   (the "License"); you may not use this file except in compliance with\r
+   the License.  You may obtain a copy of the License at\r
+\r
+       http://www.apache.org/licenses/LICENSE-2.0\r
+\r
+   Unless required by applicable law or agreed to in writing, software\r
+   distributed under the License is distributed on an "AS IS" BASIS,\r
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+   See the License for the specific language governing permissions and\r
+   limitations under the License.\r
+==================================================================== */\r
+\r
+package org.apache.poi.hssf.record.aggregates;\r
+\r
+import junit.framework.Test;\r
+import junit.framework.TestSuite;\r
+\r
+/**\r
+ * Collects all tests for package <tt>org.apache.poi.hssf.record.aggregates</tt>.\r
+ * \r
+ * @author Josh Micich\r
+ */\r
+public final class AllRecordAggregateTests {\r
+       \r
+       public static Test suite() {\r
+               TestSuite result = new TestSuite(AllRecordAggregateTests.class.getName());\r
+\r
+               result.addTestSuite(TestCFRecordsAggregate.class);\r
+               result.addTestSuite(TestColumnInfoRecordsAggregate.class);\r
+               result.addTestSuite(TestFormulaRecordAggregate.class);\r
+               result.addTestSuite(TestRowRecordsAggregate.class);\r
+               result.addTestSuite(TestValueRecordsAggregate.class);\r
+               return result;\r
+       }\r
+}\r
index 332c99209f8f6b8f750de21f7321606d4b1697ca..f605097768d5523e013c254d6045fd8785b40aa0 100644 (file)
@@ -24,9 +24,11 @@ import java.util.List;
 
 import junit.framework.TestCase;
 
+import org.apache.poi.hssf.model.Workbook;
 import org.apache.poi.hssf.record.CFHeaderRecord;
 import org.apache.poi.hssf.record.CFRuleRecord;
 import org.apache.poi.hssf.record.RecordFactory;
+import org.apache.poi.hssf.record.CFRuleRecord.ComparisonOperator;
 import org.apache.poi.hssf.record.cf.CellRange;
 
 /**
@@ -35,77 +37,71 @@ import org.apache.poi.hssf.record.cf.CellRange;
  *
  * @author Dmitriy Kumshayev 
  */
-public class TestCFRecordsAggregate
-        extends TestCase
+public final class TestCFRecordsAggregate extends TestCase
 {
 
-    public TestCFRecordsAggregate(String name)
-    {
-        super(name);
-    }
-
-    public void testCFRecordsAggregate() 
-    {
-       CFRecordsAggregate record = new CFRecordsAggregate();
-       List recs = new ArrayList();
-       CFHeaderRecord header = new CFHeaderRecord();
-       CFRuleRecord rule1 = new CFRuleRecord();
-       CFRuleRecord rule2 = new CFRuleRecord();
-       CFRuleRecord rule3 = new CFRuleRecord();
-       header.setNumberOfConditionalFormats(3);
-       CellRange range1 = new CellRange(0,1,(short)0,(short)0);
-       CellRange range2 = new CellRange(0,1,(short)2,(short)2);
-       List cellRanges = new ArrayList();
-       cellRanges.add(range1);
-       cellRanges.add(range2);
-       header.setCellRanges(cellRanges);
-       recs.add(header);
-       recs.add(rule1);
-       recs.add(rule2);
-       recs.add(rule3);
-       record = CFRecordsAggregate.createCFAggregate(recs, 0);
-       
-       // Serialize
-       byte [] serializedRecord = record.serialize();
-       InputStream in = new ByteArrayInputStream(serializedRecord);
-       
-       //Parse
-       recs = RecordFactory.createRecords(in);
-       
-       // Verify
-       assertNotNull(recs);
-       assertEquals(4, recs.size());
-       
-       header = (CFHeaderRecord)recs.get(0);
-       rule1 = (CFRuleRecord)recs.get(1);
-       rule2 = (CFRuleRecord)recs.get(2);
-       rule3 = (CFRuleRecord)recs.get(3);
-       cellRanges = header.getCellRanges();
-       
-       assertEquals(2, cellRanges.size());
-       assertEquals(3, header.getNumberOfConditionalFormats());
-       
-       record = CFRecordsAggregate.createCFAggregate(recs, 0);
-       
-       record = record.cloneCFAggregate();
-       
-       assertNotNull(record.getHeader());
-       assertEquals(3,record.getRules().size());
-       
-       header = record.getHeader();
-       rule1 = (CFRuleRecord)record.getRules().get(0);
-       rule2 = (CFRuleRecord)record.getRules().get(1);
-       rule3 = (CFRuleRecord)record.getRules().get(2);
-       cellRanges = header.getCellRanges();
-       
-       assertEquals(2, cellRanges.size());
-       assertEquals(3, header.getNumberOfConditionalFormats());
-    }
-
-    public static void main(String[] ignored_args)
+       public void testCFRecordsAggregate() 
+       {
+               Workbook workbook = Workbook.createWorkbook();
+               List recs = new ArrayList();
+               CFHeaderRecord header = new CFHeaderRecord();
+               CFRuleRecord rule1 = CFRuleRecord.create(workbook, "7");
+               CFRuleRecord rule2 = CFRuleRecord.create(workbook, ComparisonOperator.BETWEEN, "2", "5");
+               CFRuleRecord rule3 = CFRuleRecord.create(workbook, ComparisonOperator.GE, "100", null);
+               header.setNumberOfConditionalFormats(3);
+               CellRange[] cellRanges = {
+                               new CellRange(0,1,0,0),
+                               new CellRange(0,1,2,2),
+               };
+               header.setCellRanges(cellRanges);
+               recs.add(header);
+               recs.add(rule1);
+               recs.add(rule2);
+               recs.add(rule3);
+               CFRecordsAggregate record;
+               record = CFRecordsAggregate.createCFAggregate(recs, 0);
+
+               // Serialize
+               byte [] serializedRecord = record.serialize();
+               InputStream in = new ByteArrayInputStream(serializedRecord);
+
+               //Parse
+               recs = RecordFactory.createRecords(in);
+
+               // Verify
+               assertNotNull(recs);
+               assertEquals(4, recs.size());
+
+               header = (CFHeaderRecord)recs.get(0);
+               rule1 = (CFRuleRecord)recs.get(1);
+               rule2 = (CFRuleRecord)recs.get(2);
+               rule3 = (CFRuleRecord)recs.get(3);
+               cellRanges = header.getCellRanges();
+
+               assertEquals(2, cellRanges.length);
+               assertEquals(3, header.getNumberOfConditionalFormats());
+
+               record = CFRecordsAggregate.createCFAggregate(recs, 0);
+
+               record = record.cloneCFAggregate();
+
+               assertNotNull(record.getHeader());
+               assertEquals(3,record.getNumberOfRules());
+
+               header = record.getHeader();
+               rule1 = record.getRule(0);
+               rule2 = record.getRule(1);
+               rule3 = record.getRule(2);
+               cellRanges = header.getCellRanges();
+
+               assertEquals(2, cellRanges.length);
+               assertEquals(3, header.getNumberOfConditionalFormats());
+       }
+
+       public static void main(String[] ignored_args)
        {
                System.out.println("Testing org.apache.poi.hssf.record.aggregates.CFRecordsAggregate");
                junit.textui.TestRunner.run(TestCFRecordsAggregate.class);
        }
-    
+       
 }
index d0095c18cb5477236c2abdadf96138d27ed6e8a3..20fded35e99125764cd07a76028a15cd05e5b801 100644 (file)
@@ -23,7 +23,7 @@ import org.apache.poi.hssf.record.ColumnInfoRecord;
 /**
  * @author Glen Stampoultzis
  */
-public class TestColumnInfoRecordsAggregate extends TestCase
+public final class TestColumnInfoRecordsAggregate extends TestCase
 {
     ColumnInfoRecordsAggregate columnInfoRecordsAggregate;
 
@@ -35,7 +35,7 @@ public class TestColumnInfoRecordsAggregate extends TestCase
         columnInfoRecordsAggregate.insertColumn( createColumn( (short)8, (short)8 ));
 //        columnInfoRecordsAggregate.setColumn( (short)2, new Short( (short)200 ), new Integer( 1 ), new Boolean( true ), null);
         columnInfoRecordsAggregate.groupColumnRange( (short)2, (short)5, true );
-        System.out.println( "columnInfoRecordsAggregate = " + columnInfoRecordsAggregate.getNumColumns() );
+        assertEquals(6, columnInfoRecordsAggregate.getNumColumns());
 
         assertEquals(columnInfoRecordsAggregate.getRecordSize(), columnInfoRecordsAggregate.serialize().length);
 
index f9857fb2485737260214087a4f657c355481a2d6..ade097e6979e786252f1a930a89c7f6bc2032dea 100644 (file)
@@ -24,13 +24,13 @@ import junit.framework.TestCase;
  */
 public class TestCellRange extends TestCase
 {
-       private static final CellRange biggest     = new CellRange(0, -1,(short) 0,(short)-1);
-       private static final CellRange tenthColumn = new CellRange(0, -1,(short)10,(short)10);
-       private static final CellRange tenthRow    = new CellRange(10,10,(short) 0,(short)-1);
-       private static final CellRange box10x10    = new CellRange(0, 10,(short) 0,(short)10);
-       private static final CellRange box9x9      = new CellRange(0,  9,(short) 0,(short) 9);
-       private static final CellRange box10to20c  = new CellRange(0, 10,(short)10,(short)20);
-       private static final CellRange oneCell     = new CellRange(10,10,(short)10,(short)10);
+       private static final CellRange biggest     = new CellRange( 0, -1, 0,-1);
+       private static final CellRange tenthColumn = new CellRange( 0, -1,10,10);
+       private static final CellRange tenthRow    = new CellRange(10, 10, 0,-1);
+       private static final CellRange box10x10    = new CellRange( 0, 10, 0,10);
+       private static final CellRange box9x9      = new CellRange( 0,  9, 0, 9);
+       private static final CellRange box10to20c  = new CellRange( 0, 10,10,20);
+       private static final CellRange oneCell     = new CellRange(10, 10,10,10);
 
        boolean [][] contanis = new boolean[][]
     {
@@ -61,62 +61,62 @@ public class TestCellRange extends TestCase
                        }
                }
        }
-       
-       private static final CellRange col1     = new CellRange(0, -1,(short) 1,(short)1);
-       private static final CellRange col2     = new CellRange(0, -1,(short) 2,(short)2);
-       private static final CellRange row1     = new CellRange(1,  1,(short) 0,(short)-1);
-       private static final CellRange row2     = new CellRange(2,  2,(short) 0,(short)-1);
 
-       private static final CellRange box0     = new CellRange( 0, 2,(short) 0,(short)2);
-       private static final CellRange box1     = new CellRange( 0, 1,(short) 0,(short)1);
-       private static final CellRange box2     = new CellRange( 0, 1,(short) 2,(short)3);
-       private static final CellRange box3     = new CellRange( 2, 3,(short) 0,(short)1);
-       private static final CellRange box4     = new CellRange( 2, 3,(short) 2,(short)3);
-       private static final CellRange box5     = new CellRange( 1, 3,(short) 1,(short)3);
+       private static final CellRange col1     = new CellRange( 0, -1, 1,1);
+       private static final CellRange col2     = new CellRange( 0, -1, 2,2);
+       private static final CellRange row1     = new CellRange( 1,  1, 0,-1);
+       private static final CellRange row2     = new CellRange( 2,  2, 0,-1);
+
+       private static final CellRange box0     = new CellRange( 0, 2, 0,2);
+       private static final CellRange box1     = new CellRange( 0, 1, 0,1);
+       private static final CellRange box2     = new CellRange( 0, 1, 2,3);
+       private static final CellRange box3     = new CellRange( 2, 3, 0,1);
+       private static final CellRange box4     = new CellRange( 2, 3, 2,3);
+       private static final CellRange box5     = new CellRange( 1, 3, 1,3);
 
        public void testHasSharedBorderMethod()
        {
-               assertFalse(col1.hasSharedBorder(col1));
-               assertFalse(col2.hasSharedBorder(col2));
-               assertTrue(col1.hasSharedBorder(col2));
-               assertTrue(col2.hasSharedBorder(col1));
+               assertFalse(col1.hasExactSharedBorder(col1));
+               assertFalse(col2.hasExactSharedBorder(col2));
+               assertTrue(col1.hasExactSharedBorder(col2));
+               assertTrue(col2.hasExactSharedBorder(col1));
 
-               assertFalse(row1.hasSharedBorder(row1));
-               assertFalse(row2.hasSharedBorder(row2));
-               assertTrue(row1.hasSharedBorder(row2));
-               assertTrue(row2.hasSharedBorder(row1));
+               assertFalse(row1.hasExactSharedBorder(row1));
+               assertFalse(row2.hasExactSharedBorder(row2));
+               assertTrue(row1.hasExactSharedBorder(row2));
+               assertTrue(row2.hasExactSharedBorder(row1));
                
-               assertFalse(row1.hasSharedBorder(col1));
-               assertFalse(row1.hasSharedBorder(col2));
-               assertFalse(col1.hasSharedBorder(row1));
-               assertFalse(col2.hasSharedBorder(row1));
-               assertFalse(row2.hasSharedBorder(col1));
-               assertFalse(row2.hasSharedBorder(col2));
-               assertFalse(col1.hasSharedBorder(row2));
-               assertFalse(col2.hasSharedBorder(row2));
-               assertTrue(col2.hasSharedBorder(col1));
+               assertFalse(row1.hasExactSharedBorder(col1));
+               assertFalse(row1.hasExactSharedBorder(col2));
+               assertFalse(col1.hasExactSharedBorder(row1));
+               assertFalse(col2.hasExactSharedBorder(row1));
+               assertFalse(row2.hasExactSharedBorder(col1));
+               assertFalse(row2.hasExactSharedBorder(col2));
+               assertFalse(col1.hasExactSharedBorder(row2));
+               assertFalse(col2.hasExactSharedBorder(row2));
+               assertTrue(col2.hasExactSharedBorder(col1));
                
-               assertFalse(box1.hasSharedBorder(box1));
-               assertTrue(box1.hasSharedBorder(box2));
-               assertTrue(box1.hasSharedBorder(box3));
-               assertFalse(box1.hasSharedBorder(box4));
+               assertFalse(box1.hasExactSharedBorder(box1));
+               assertTrue(box1.hasExactSharedBorder(box2));
+               assertTrue(box1.hasExactSharedBorder(box3));
+               assertFalse(box1.hasExactSharedBorder(box4));
                
-               assertTrue(box2.hasSharedBorder(box1));
-               assertFalse(box2.hasSharedBorder(box2));
-               assertFalse(box2.hasSharedBorder(box3));
-               assertTrue(box2.hasSharedBorder(box4));
+               assertTrue(box2.hasExactSharedBorder(box1));
+               assertFalse(box2.hasExactSharedBorder(box2));
+               assertFalse(box2.hasExactSharedBorder(box3));
+               assertTrue(box2.hasExactSharedBorder(box4));
                
-               assertTrue(box3.hasSharedBorder(box1));
-               assertFalse(box3.hasSharedBorder(box2));
-               assertFalse(box3.hasSharedBorder(box3));
-               assertTrue(box3.hasSharedBorder(box4));
+               assertTrue(box3.hasExactSharedBorder(box1));
+               assertFalse(box3.hasExactSharedBorder(box2));
+               assertFalse(box3.hasExactSharedBorder(box3));
+               assertTrue(box3.hasExactSharedBorder(box4));
                
-               assertFalse(box4.hasSharedBorder(box1));
-               assertTrue(box4.hasSharedBorder(box2));
-               assertTrue(box4.hasSharedBorder(box3));
-               assertFalse(box4.hasSharedBorder(box4));
+               assertFalse(box4.hasExactSharedBorder(box1));
+               assertTrue(box4.hasExactSharedBorder(box2));
+               assertTrue(box4.hasExactSharedBorder(box3));
+               assertFalse(box4.hasExactSharedBorder(box4));
        }
-       
+
        public void testIntersectMethod()
        {
                assertEquals( CellRange.OVERLAP,box0.intersect(box5));
@@ -135,5 +135,4 @@ public class TestCellRange extends TestCase
                assertEquals(CellRange.INSIDE,tenthColumn.intersect(tenthColumn));
                assertEquals(CellRange.INSIDE,tenthRow.intersect(tenthRow));
        }
-       
 }
index b50e95fa86b282fd1f4e6648ca2c449f6cde0757..645709bb6e355e79fff7023b7f8dea005ffa8116 100644 (file)
 
 package org.apache.poi.hssf.record.formula;
 
+import org.apache.poi.hssf.record.formula.eval.AllFormulaEvalTests;
 import org.apache.poi.hssf.record.formula.function.AllFormulaFunctionTests;
+import org.apache.poi.hssf.record.formula.functions.AllIndividualFunctionEvaluationTests;
 
 import junit.framework.Test;
 import junit.framework.TestSuite;
 
 /**
- * Collects all tests for this package.
+ * Collects all tests for <tt>org.apache.poi.hssf.record.formula</tt>.
  * 
  * @author Josh Micich
  */
@@ -31,6 +33,10 @@ public class AllFormulaTests {
        
        public static Test suite() {
                TestSuite result = new TestSuite(AllFormulaTests.class.getName());
+               result.addTest(AllFormulaEvalTests.suite());
+               result.addTest(AllFormulaFunctionTests.suite());
+               result.addTest(AllIndividualFunctionEvaluationTests.suite());
+
                result.addTestSuite(TestArea3DPtg.class);
                result.addTestSuite(TestAreaErrPtg.class);
                result.addTestSuite(TestAreaPtg.class);
index 8a59095e460eafb6652e42aa79cfc981b35a8798..01f88bd069937f389d707d7fb2413f86d0858d7a 100644 (file)
@@ -21,7 +21,7 @@ import junit.framework.Test;
 import junit.framework.TestSuite;
 
 /**
- * Collects all tests for this package.
+ * Collects all tests for this <tt>org.apache.poi.hssf.record.formula.function</tt>.
  * 
  * @author Josh Micich
  */
index c7d74b6f75076a6bf4922706666b004624ff1f1e..48a76e31d83d011f138dfde149461e7c19b28d1c 100644 (file)
@@ -49,14 +49,14 @@ import org.xml.sax.XMLReader;
 import org.xml.sax.helpers.XMLReaderFactory;
 
 /**
- * This class is not used during normal POI run-time but is used at development time to generate 
+ * This class is not used during normal POI run-time but is used at development time to generate
  * the file 'functionMetadata.txt'.   There are more than 300 built-in functions in Excel and the
  * intention of this class is to make it easier to maintain the metadata, by extracting it from
  * a reliable source.
  * 
  * @author Josh Micich
  */
-public class ExcelFileFormatDocFunctionExtractor {
+public final class ExcelFileFormatDocFunctionExtractor {
 
        private static final String SOURCE_DOC_FILE_NAME = "excelfileformat.odt";
 
@@ -195,19 +195,19 @@ public class ExcelFileFormatDocFunctionExtractor {
                        "table:table-row", "table:table-cell", "text:p", "text:span", "text:note-ref",
                };
 
-               
+
                private final Stack _elemNameStack;
                /** <code>true</code> only when parsing the target tables */
                private boolean _isInsideTable;
-               
+
                private final List _rowData; 
                private final StringBuffer _textNodeBuffer;
                private final List _rowNoteFlags;
                private boolean _cellHasNote;
-               
+
                private final FunctionDataCollector _fdc;
                private String _lastHeadingText;
-               
+
                public EFFDocHandler(FunctionDataCollector fdc) {
                        _fdc = fdc;
                        _elemNameStack = new Stack();
@@ -216,7 +216,7 @@ public class ExcelFileFormatDocFunctionExtractor {
                        _textNodeBuffer = new StringBuffer();
                        _rowNoteFlags = new ArrayList();
                }
-               
+
                private boolean matchesTargetPath() {
                        return matchesPath(0, TABLE_BASE_PATH_NAMES);
                }
@@ -365,7 +365,7 @@ public class ExcelFileFormatDocFunctionExtractor {
                xr.setContentHandler(new EFFDocHandler(fdc));
 
                InputSource inSrc = new InputSource(is);
-               
+
                try {
                        xr.parse(inSrc);
                        is.close();
@@ -407,30 +407,30 @@ public class ExcelFileFormatDocFunctionExtractor {
        }
 
        private static void outputLicenseHeader(PrintStream ps) {
-           String[] lines= {
-            "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.",
-           };
-           for (int i = 0; i < lines.length; i++) {
-               ps.print("# ");
-            ps.println(lines[i]);
-        }
-        ps.println();
-    }
-
-    /**
+               String[] lines= {
+                       "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.",
+               };
+               for (int i = 0; i < lines.length; i++) {
+                       ps.print("# ");
+                       ps.println(lines[i]);
+               }
+               ps.println();
+       }
+
+       /**
         * Helps identify the source file
         */
        private static String getFileCRC(File f) {
@@ -451,10 +451,10 @@ public class ExcelFileFormatDocFunctionExtractor {
                }
                return "0x" + Long.toHexString(crc.getValue()).toUpperCase();
        }
-       
+
        private static File getSourceFile() {
-               if (true) {
-                       File dir = new File("c:/josh/ref-docs");
+               if (false) {
+                       File dir = new File("c:/temp");
                        File effDocFile = new File(dir, SOURCE_DOC_FILE_NAME);
                        return effDocFile;
                }
@@ -464,7 +464,7 @@ public class ExcelFileFormatDocFunctionExtractor {
                } catch (MalformedURLException e) {
                        throw new RuntimeException(e);
                }
-               
+
                File result;
                byte[]buf = new byte[2048];
                try {
@@ -488,16 +488,15 @@ public class ExcelFileFormatDocFunctionExtractor {
                System.out.println("file downloaded ok");
                return result;
        }
-       
+
        public static void main(String[] args) {
-               
+
                File effDocFile = getSourceFile();
                if(!effDocFile.exists()) {
                        throw new RuntimeException("file '" + effDocFile.getAbsolutePath() + "' does not exist");
                }
-               
+
                File outFile = new File("functionMetadata-asGenerated.txt");
                processFile(effDocFile, outFile);
        }
-       
 }
index edb215ec50c22e536012e18e98146bdf4356ab1f..c175c473bf3d3a7fa91e4ad5725f6ef98d9cd999 100644 (file)
 package org.apache.poi.hssf.record.formula.function;
 
 import junit.framework.TestCase;
+
 /**
  * 
  * @author Josh Micich
  */
 public final class TestFunctionMetadataRegistry extends TestCase {
 
-    public void testWellKnownFunctions() {
-        confirmFunction(0, "COUNT");
-        confirmFunction(1, "IF");
-        
-    }
-
-    private static void confirmFunction(int index, String funcName) {
-        FunctionMetadata fm;
-        fm = FunctionMetadataRegistry.getFunctionByIndex(index);
-        assertNotNull(fm);
-        assertEquals(funcName, fm.getName());
-        
-        fm = FunctionMetadataRegistry.getFunctionByName(funcName);
-        assertNotNull(fm);
-        assertEquals(index, fm.getIndex());
-    }
+       public void testWellKnownFunctions() {
+               confirmFunction(0, "COUNT");
+               confirmFunction(1, "IF");
+
+       }
+
+       private static void confirmFunction(int index, String funcName) {
+               FunctionMetadata fm;
+               fm = FunctionMetadataRegistry.getFunctionByIndex(index);
+               assertNotNull(fm);
+               assertEquals(funcName, fm.getName());
+
+               fm = FunctionMetadataRegistry.getFunctionByName(funcName);
+               assertNotNull(fm);
+               assertEquals(index, fm.getIndex());
+       }
 }
index fe1b8fccc839fe325ca2b74c38d971e387fb9acb..3671d37c1a8382f1b835696d345eaf366711c0ae 100644 (file)
@@ -44,8 +44,8 @@ public final class TestParseMissingBuiltInFuncs extends TestCase {
                }
                AbstractFunctionPtg func = (AbstractFunctionPtg) ptgF;
                if(func.getFunctionIndex() == 255) {
-                   throw new AssertionFailedError("Failed to recognise built-in function in formula '" 
-                           + formula + "'");
+                       throw new AssertionFailedError("Failed to recognise built-in function in formula '" 
+                                       + formula + "'");
                }
                
                assertEquals(expPtgArraySize, ptgs.length);
index 7e1d0317eca3b756cb8084c65c1eaa9b4d0cb886..f1e6bcfacf22d35eae424d8ee48c4ebccfc01764 100644 (file)
@@ -48,7 +48,7 @@ public final class TestReadMissingBuiltInFuncs extends TestCase {
                }
                sht = wb.getSheetAt(0);
        }
-       
+
        public void testDatedif() {
                
                String formula;
@@ -56,9 +56,9 @@ public final class TestReadMissingBuiltInFuncs extends TestCase {
                        formula = getCellFormula(0);
                } catch (IllegalStateException e) {
                        if(e.getMessage().startsWith("Too few arguments")) {
-                           if(e.getMessage().indexOf("AttrPtg") > 0) {
-                       throw afe("tAttrVolatile not supported in FormulaParser.toFormulaString");
-                           }
+                               if(e.getMessage().indexOf("AttrPtg") > 0) {
+                                       throw afe("tAttrVolatile not supported in FormulaParser.toFormulaString");
+                               }
                                throw afe("NOW() registered with 1 arg instead of 0");
                        }
                        if(e.getMessage().startsWith("too much stuff")) {
@@ -70,7 +70,7 @@ public final class TestReadMissingBuiltInFuncs extends TestCase {
                assertEquals("DATEDIF(NOW(),NOW(),\"d\")", formula);
        }
        public void testDdb() {
-               
+
                String formula = getCellFormula(1);
                if("externalflag(1,1,1,1,1)".equals(formula)) {
                        throw afe("DDB() not registered");
@@ -78,14 +78,14 @@ public final class TestReadMissingBuiltInFuncs extends TestCase {
                assertEquals("DDB(1,1,1,1,1)", formula);
        }
        public void testAtan() {
-       
+
                String formula = getCellFormula(2);
                if(formula.equals("ARCTAN(1)")) {
                        throw afe("func ix 18 registered as ARCTAN() instead of ATAN()");
                }
                assertEquals("ATAN(1)", formula);
        }
-       
+
        public void testUsdollar() {
        
                String formula = getCellFormula(3);
@@ -128,7 +128,7 @@ public final class TestReadMissingBuiltInFuncs extends TestCase {
                }
                assertEquals("ISNONTEXT(\"abc\")", formula);
        }
-       
+
        private String getCellFormula(int rowIx) {
                String result = sht.getRow(rowIx).getCell((short)0).getCellFormula();
                if (false) {
index 66d2a1d27050567ed87b50b461eee29ecee96b44..5973d7cb2d25bc2933d170f1a982a18902aad835 100755 (executable)
@@ -27,9 +27,8 @@ import junit.framework.TestSuite;
  */
 public final class AllIndividualFunctionEvaluationTests {
 
-       // TODO - have this suite incorporated into a higher level one
        public static Test suite() {
-               TestSuite result = new TestSuite("Tests for org.apache.poi.hssf.record.formula.functions");
+               TestSuite result = new TestSuite(AllIndividualFunctionEvaluationTests.class.getName());
                result.addTestSuite(TestAverage.class);
                result.addTestSuite(TestCountFuncs.class);
                result.addTestSuite(TestDate.class);
index 935615acaed239f55feafe1cb91b3b0e8220b79f..2fecef7046d3a38b5ff48afb1da33a883df96eb7 100644 (file)
@@ -30,7 +30,7 @@ import org.apache.poi.hssf.usermodel.HSSFErrorConstants;
  * @author Josh Micich
  */
 public final class TestPmt extends TestCase {
-       
+
        private static void confirm(double expected, NumberEval ne) {
                // only asserting accuracy to 4 fractional digits
                assertEquals(expected, ne.getNumberValue(), 0.00005);
@@ -61,12 +61,12 @@ public final class TestPmt extends TestCase {
                confirm(expected, invokeNormal(args));
        }
 
-       
+
        public void testBasic() {
                confirm(-1037.0321, (0.08/12), 10, 10000, 0, false);
                confirm(-1030.1643, (0.08/12), 10, 10000, 0, true);
        }
-       
+
        public void test3args() {
                
                Eval[] args = { 
index 94c19cbc04cd5a7982d4565d61ee0a4a275c91f3..f05c1d1157d23e98b12204798e760e954f54d94a 100644 (file)
@@ -357,14 +357,14 @@ extends TestCase {
         book.createSheet("TEST");
         HSSFSheet sheet = book.cloneSheet(0);
         book.setSheetName(1,"CLONE");
-        sheet.createRow(0).createCell((short)0).setCellValue("Test");
+        sheet.createRow(0).createCell((short)0).setCellValue(new HSSFRichTextString("Test"));
         book.write(out);
         
         book = new HSSFWorkbook(new ByteArrayInputStream(out.toByteArray()));
         sheet = book.getSheet("CLONE");
         HSSFRow row = sheet.getRow(0);
         HSSFCell cell = row.getCell((short)0);
-        System.out.println(cell.getStringCellValue());
+        assertEquals("Test", cell.getRichStringCellValue().getString());
     }
     
     /**
diff --git a/src/testcases/org/apache/poi/hssf/usermodel/TestHSSFConfditionalFormatting.java b/src/testcases/org/apache/poi/hssf/usermodel/TestHSSFConfditionalFormatting.java
new file mode 100644 (file)
index 0000000..6186d22
--- /dev/null
@@ -0,0 +1,90 @@
+/* ====================================================================
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+==================================================================== */
+
+package org.apache.poi.hssf.usermodel;
+
+import junit.framework.TestCase;
+
+import org.apache.poi.hssf.record.CFRuleRecord.ComparisonOperator;
+import org.apache.poi.hssf.util.HSSFColor;
+import org.apache.poi.hssf.util.Region;
+/**
+ * 
+ * @author Dmitriy Kumshayev
+ */
+public final class TestHSSFConfditionalFormatting extends TestCase
+{
+       public void testLastAndFirstColumns() 
+       {
+               HSSFWorkbook workbook = new HSSFWorkbook();
+               HSSFSheet sheet = workbook.createSheet();
+               String formula = "7";
+
+               HSSFFontFormatting fontFmt = new HSSFFontFormatting();
+               fontFmt.setFontStyle(true, false);
+
+               HSSFBorderFormatting bordFmt = new HSSFBorderFormatting();
+               bordFmt.setBorderBottom(HSSFBorderFormatting.BORDER_THIN);
+               bordFmt.setBorderTop(HSSFBorderFormatting.BORDER_THICK);
+               bordFmt.setBorderLeft(HSSFBorderFormatting.BORDER_DASHED);
+               bordFmt.setBorderRight(HSSFBorderFormatting.BORDER_DOTTED);
+
+               HSSFPatternFormatting patternFmt = new HSSFPatternFormatting();
+               patternFmt.setFillBackgroundColor(HSSFColor.RED.index);
+
+               HSSFConditionalFormattingRule [] cfRules =
+               {
+                       sheet.createConditionalFormattingRule(formula, fontFmt, bordFmt, patternFmt),
+                       sheet.createConditionalFormattingRule(ComparisonOperator.BETWEEN, "1", "2", fontFmt, bordFmt, patternFmt)
+               };
+
+               short col = 1;
+               Region [] regions =
+               {
+                       new Region(0,col,-1,col)
+               };
+
+               sheet.addConditionalFormatting(regions, cfRules);
+               sheet.addConditionalFormatting(regions, cfRules);
+
+               // Verification
+               assertEquals(2, sheet.getNumConditionalFormattings());
+               sheet.removeConditionalFormatting(1);
+               assertEquals(1, sheet.getNumConditionalFormattings());
+               HSSFConditionalFormatting cf = sheet.getConditionalFormattingAt(0);
+               assertNotNull(cf);
+
+               regions = cf.getFormattingRegions();
+               assertNotNull(regions);
+               assertEquals(1, regions.length);
+               Region r = regions[0];
+               assertEquals(1, r.getColumnFrom());
+               assertEquals(1, r.getColumnTo());
+               assertEquals(0, r.getRowFrom());
+               assertEquals(-1, r.getRowTo());
+
+               assertEquals(2, cf.getNumberOfRules());
+
+               HSSFConditionalFormattingRule rule1 = cf.getRule(0);
+               assertEquals("7",rule1.getFormula1()); 
+               assertNull(rule1.getFormula2());
+
+               HSSFConditionalFormattingRule rule2 = cf.getRule(1);
+               assertEquals("2",rule2.getFormula2()); 
+               assertEquals("1",rule2.getFormula1()); 
+       }
+}