]> source.dussan.org Git - poi.git/commitdiff
Fix for bug 45519 - keep data validation records together
authorJosh Micich <josh@apache.org>
Thu, 31 Jul 2008 22:44:48 +0000 (22:44 +0000)
committerJosh Micich <josh@apache.org>
Thu, 31 Jul 2008 22:44:48 +0000 (22:44 +0000)
git-svn-id: https://svn.apache.org/repos/asf/poi/trunk@681530 13f79535-47bb-0310-9956-ffa450edef68

13 files changed:
src/documentation/content/xdocs/changes.xml
src/documentation/content/xdocs/status.xml
src/java/org/apache/poi/hssf/model/RecordStream.java
src/java/org/apache/poi/hssf/model/Sheet.java
src/java/org/apache/poi/hssf/record/DVRecord.java
src/java/org/apache/poi/hssf/record/aggregates/DataValidityTable.java [new file with mode: 0644]
src/java/org/apache/poi/hssf/record/aggregates/RecordAggregate.java [new file with mode: 0644]
src/java/org/apache/poi/hssf/usermodel/HSSFSheet.java
src/java/org/apache/poi/hssf/util/HSSFDataValidation.java
src/testcases/org/apache/poi/hssf/data/dvEmpty.xls [new file with mode: 0644]
src/testcases/org/apache/poi/hssf/model/TestSheet.java
src/testcases/org/apache/poi/hssf/model/TestSheetAdditional.java
src/testcases/org/apache/poi/hssf/usermodel/TestDataValidation.java

index 12763c3d3db5af03ac9f0878017bd7a9d3426317..3660da72e47f15b10c5912b33dbedff585a63bbe 100644 (file)
@@ -37,6 +37,7 @@
 
                <!-- Don't forget to update status.xml too! -->
         <release version="3.1.1-alpha1" date="2008-??-??">
+           <action dev="POI-DEVELOPERS" type="fix">45519 - Fixed to keep datavalidation records together</action>
            <action dev="POI-DEVELOPERS" type="add">Support for creating new HSLF CurrentUserAtoms</action>
            <action dev="POI-DEVELOPERS" type="add">45466 - Partial support for removing excel comments (won't work for all excel versions yet)</action>
            <action dev="POI-DEVELOPERS" type="fix">45437 - Detect encrypted word documents, and throw an EncryptedDocumentException instead of a OOM</action>
index 230244190c19133914b5decf4031c4e6cbeca02c..4927e7150d2738a5b6cc4d95ab301ecf782e2e6a 100644 (file)
@@ -34,6 +34,7 @@
        <!-- Don't forget to update changes.xml too! -->
     <changes>
         <release version="3.1.1-alpha1" date="2008-??-??">
+           <action dev="POI-DEVELOPERS" type="fix">45519 - Fixed to keep datavalidation records together</action>
            <action dev="POI-DEVELOPERS" type="add">Support for creating new HSLF CurrentUserAtoms</action>
            <action dev="POI-DEVELOPERS" type="add">45466 - Partial support for removing excel comments (won't work for all excel versions yet)</action>
            <action dev="POI-DEVELOPERS" type="fix">45437 - Detect encrypted word documents, and throw an EncryptedDocumentException instead of a OOM</action>
index 03177c7c22c15b942ec208109bcc9307e545a768..bec1c40e6a5daaccbd482de6d969109abcef706f 100755 (executable)
@@ -25,7 +25,7 @@ import org.apache.poi.hssf.record.Record;
  *
  * @author Josh Micich
  */
-final class RecordStream {
+public final class RecordStream {
 
        private final List _list;
        private int _nextIndex;
index cbbe663b1dfa386c3917392a7f581367df485a68..9959dbfb26a5d0eb5a61c7806903ac2c3da68aaa 100644 (file)
 
 package org.apache.poi.hssf.model;
 
-import org.apache.poi.hssf.record.*;
+import org.apache.poi.hssf.record.*; // normally I don't do this, buy we literally mean ALL
 import org.apache.poi.hssf.record.aggregates.ColumnInfoRecordsAggregate;
+import org.apache.poi.hssf.record.aggregates.DataValidityTable;
 import org.apache.poi.hssf.record.aggregates.FormulaRecordAggregate;
 import org.apache.poi.hssf.record.aggregates.RowRecordsAggregate;
 import org.apache.poi.hssf.record.aggregates.ValueRecordsAggregate;
 import org.apache.poi.hssf.record.aggregates.CFRecordsAggregate;
-import org.apache.poi.hssf.record.formula.Ptg;
 import org.apache.poi.hssf.util.PaneInformation;
 
 import org.apache.poi.util.POILogFactory;
@@ -31,7 +31,7 @@ import org.apache.poi.util.POILogger;
 
 import java.util.ArrayList;
 import java.util.Iterator;
-import java.util.List;   // normally I don't do this, buy we literally mean ALL
+import java.util.List;   
 
 /**
  * Low level model implementation of a Sheet (one workbook contains many sheets)
@@ -90,6 +90,7 @@ public final class Sheet implements Model {
     protected ProtectRecord              protect           =     null;
     protected PageBreakRecord            rowBreaks         =     null;
     protected PageBreakRecord            colBreaks         =     null;
+    private   DataValidityTable          _dataValidityTable=     null;
     protected ObjectProtectRecord        objprotect        =     null;
     protected ScenarioProtectRecord      scenprotect       =     null;
     protected PasswordRecord             password          =     null;
@@ -299,7 +300,12 @@ public final class Sheet implements Model {
                 // and POI always re-calculates its contents 
                 rec = null;
             }
-
+            else if ( rec.getSid() == DVALRecord.sid) {
+                RecordStream rs = new RecordStream(recs, k);
+                retval._dataValidityTable = new DataValidityTable(rs);
+                k += rs.getCountRead() - 1; // TODO - convert this method result to be zero based
+                rec = retval._dataValidityTable;
+            }
             else if ( rec.getSid() == ProtectRecord.sid )
             {
                 retval.protect = (ProtectRecord) rec;
@@ -425,56 +431,56 @@ public final class Sheet implements Model {
         Sheet     retval  = new Sheet();
         ArrayList records = new ArrayList(30);
 
-        records.add(retval.createBOF());
+        records.add(createBOF());
 
         // records.add(retval.createIndex());
-        records.add(retval.createCalcMode());
-        records.add(retval.createCalcCount() );
-        records.add( retval.createRefMode() );
-        records.add( retval.createIteration() );
-        records.add( retval.createDelta() );
-        records.add( retval.createSaveRecalc() );
-        records.add( retval.createPrintHeaders() );
-        retval.printGridlines = (PrintGridlinesRecord) retval.createPrintGridlines();
+        records.add(createCalcMode());
+        records.add(createCalcCount() );
+        records.add(createRefMode() );
+        records.add(createIteration() );
+        records.add(createDelta() );
+        records.add(createSaveRecalc() );
+        records.add(createPrintHeaders() );
+        retval.printGridlines = createPrintGridlines();
         records.add( retval.printGridlines );
-        retval.gridset = (GridsetRecord) retval.createGridset();
+        retval.gridset = createGridset();
         records.add( retval.gridset );
         records.add( retval.createGuts() );
-        retval.defaultrowheight =
-                (DefaultRowHeightRecord) retval.createDefaultRowHeight();
+        retval.defaultrowheight = createDefaultRowHeight();
         records.add( retval.defaultrowheight );
         records.add( retval.createWSBool() );
-
+        
+        // 'Page Settings Block'
         retval.rowBreaks = new PageBreakRecord(PageBreakRecord.HORIZONTAL_SID);
         records.add(retval.rowBreaks);
         retval.colBreaks = new PageBreakRecord(PageBreakRecord.VERTICAL_SID);
         records.add(retval.colBreaks);
 
-        retval.header = (HeaderRecord) retval.createHeader();
+        retval.header = createHeader();
         records.add( retval.header );
-        retval.footer = (FooterRecord) retval.createFooter();
+        retval.footer = createFooter();
         records.add( retval.footer );
-        records.add( retval.createHCenter() );
-        records.add( retval.createVCenter() );
-        retval.printSetup = (PrintSetupRecord) retval.createPrintSetup();
+        records.add(createHCenter() );
+        records.add(createVCenter() );
+        retval.printSetup = createPrintSetup();
         records.add( retval.printSetup );
-        retval.defaultcolwidth =
-                (DefaultColWidthRecord) retval.createDefaultColWidth();
+
+        // 'Worksheet Protection Block' (after 'Page Settings Block' and before DEFCOLWIDTH)
+        // PROTECT record normally goes here, don't add yet since the flag is initially false
+        
+        retval.defaultcolwidth = createDefaultColWidth();
         records.add( retval.defaultcolwidth);
         ColumnInfoRecordsAggregate columns = new ColumnInfoRecordsAggregate();
         records.add( columns );
         retval.columns = columns;
-        retval.dims    = ( DimensionsRecord ) retval.createDimensions();
+        retval.dims    =  createDimensions();
         records.add(retval.dims);
         retval.dimsloc = records.size()-1;
         records.add(retval.windowTwo = retval.createWindowTwo());
         retval.setLoc(records.size() - 1);
-        retval.selection =
-                (SelectionRecord) retval.createSelection();
+        retval.selection = createSelection();
         records.add(retval.selection);
-        retval.protect = (ProtectRecord) retval.createProtect();
-        records.add(retval.protect);
-        records.add(retval.createEOF());
+        records.add(new EOFRecord());
 
 
         retval.records = records;
@@ -522,7 +528,7 @@ public final class Sheet implements Model {
 
         if (merged == null || merged.getNumAreas() == 1027)
         {
-            merged = ( MergeCellsRecord ) createMergedCells();
+            merged = createMergedCells();
             mergedRecords.add(merged);
             records.add(records.size() - 1, merged);
         }
@@ -911,124 +917,11 @@ public final class Sheet implements Model {
 
     /**
      * Create a row record.  (does not add it to the records contained in this sheet)
-     *
-     * @param row number
-     * @return RowRecord created for the passed in row number
-     * @see org.apache.poi.hssf.record.RowRecord
      */
-
-    public RowRecord createRow(int row)
-    {
+    private static RowRecord createRow(int row) {
         return RowRecordsAggregate.createRow( row );
     }
 
-    /**
-     * Create a LABELSST Record (does not add it to the records contained in this sheet)
-     *
-     * @param row the row the LabelSST is a member of
-     * @param col the column the LabelSST defines
-     * @param index the index of the string within the SST (use workbook addSSTString method)
-     * @return LabelSSTRecord newly created containing your SST Index, row,col.
-     * @see org.apache.poi.hssf.record.SSTRecord
-     */
-    public LabelSSTRecord createLabelSST(int row, short col, int index)
-    {
-        log.logFormatted(POILogger.DEBUG, "create labelsst row,col,index %,%,%",
-                         new int[]
-        {
-            row, col, index
-        });
-        LabelSSTRecord rec = new LabelSSTRecord();
-
-        rec.setRow(row);
-        rec.setColumn(col);
-        rec.setSSTIndex(index);
-        rec.setXFIndex(( short ) 0x0f);
-        return rec;
-    }
-
-    /**
-     * Create a NUMBER Record (does not add it to the records contained in this sheet)
-     *
-     * @param row the row the NumberRecord is a member of
-     * @param col the column the NumberRecord defines
-     * @param value for the number record
-     *
-     * @return NumberRecord for that row, col containing that value as added to the sheet
-     */
-    public NumberRecord createNumber(int row, short col, double value)
-    {
-        log.logFormatted(POILogger.DEBUG, "create number row,col,value %,%,%",
-                         new double[]
-        {
-            row, col, value
-        });
-        NumberRecord rec = new NumberRecord();
-
-        rec.setRow(row);
-        rec.setColumn(col);
-        rec.setValue(value);
-        rec.setXFIndex(( short ) 0x0f);
-        return rec;
-    }
-
-    /**
-     * create a BLANK record (does not add it to the records contained in this sheet)
-     *
-     * @param row - the row the BlankRecord is a member of
-     * @param col - the column the BlankRecord is a member of
-     */
-    public BlankRecord createBlank(int row, short col)
-    {
-        log.logFormatted(POILogger.DEBUG, "create blank row,col %,%", new int[]
-        {
-            row, col
-        });
-        BlankRecord rec = new BlankRecord();
-
-        rec.setRow(row);
-        rec.setColumn(col);
-        rec.setXFIndex(( short ) 0x0f);
-        return rec;
-    }
-
-    /**
-     * Attempts to parse the formula into PTGs and create a formula record
-     * DOES NOT WORK YET
-     *
-     * @param row - the row for the formula record
-     * @param col - the column of the formula record
-     * @param formula - a String representing the formula.  To be parsed to PTGs
-     * @return bogus/useless formula record
-     */
-    public FormulaRecord createFormula(int row, short col, String formula)
-    {
-        log.logFormatted(POILogger.DEBUG, "create formula row,col,formula %,%,%",
-                         new int[]
-        {
-            row, col
-        }, formula);
-        FormulaRecord rec = new FormulaRecord();
-
-        rec.setRow(row);
-        rec.setColumn(col);
-        rec.setOptions(( short ) 2);
-        rec.setValue(0);
-        rec.setXFIndex(( short ) 0x0f);
-        FormulaParser fp = new FormulaParser(formula,null); //fix - do we need this method?
-        fp.parse();
-        Ptg[] ptg  = fp.getRPNPtg();
-        int   size = 0;
-
-        for (int k = 0; k < ptg.length; k++)
-        {
-            size += ptg[ k ].getSize();
-            rec.pushExpressionToken(ptg[ k ]);
-        }
-        rec.setExpressionLength(( short ) size);
-        return rec;
-    }
-
     /**
      * Adds a value record to the sheet's contained binary records
      * (i.e. LabelSSTRecord or NumberRecord).
@@ -1247,13 +1140,8 @@ public final class Sheet implements Model {
 
     /**
      * creates the BOF record
-     * @see org.apache.poi.hssf.record.BOFRecord
-     * @see org.apache.poi.hssf.record.Record
-     * @return record containing a BOFRecord
      */
-
-    protected Record createBOF()
-    {
+    private static BOFRecord createBOF() {
         BOFRecord retval = new BOFRecord();
 
         retval.setVersion(( short ) 0x600);
@@ -1266,31 +1154,10 @@ public final class Sheet implements Model {
         return retval;
     }
 
-    /**
-     * creates the Index record  - not currently used
-     * @see org.apache.poi.hssf.record.IndexRecord
-     * @see org.apache.poi.hssf.record.Record
-     * @return record containing a IndexRecord
-     */
-
-    protected Record createIndex()
-    {
-        IndexRecord retval = new IndexRecord();
-
-        retval.setFirstRow(0);   // must be set explicitly
-        retval.setLastRowAdd1(0);
-        return retval;
-    }
-
     /**
      * creates the CalcMode record and sets it to 1 (automatic formula caculation)
-     * @see org.apache.poi.hssf.record.CalcModeRecord
-     * @see org.apache.poi.hssf.record.Record
-     * @return record containing a CalcModeRecord
      */
-
-    protected Record createCalcMode()
-    {
+    private static CalcModeRecord createCalcMode() {
         CalcModeRecord retval = new CalcModeRecord();
 
         retval.setCalcMode(( short ) 1);
@@ -1298,29 +1165,19 @@ public final class Sheet implements Model {
     }
 
     /**
-     * creates the CalcCount record and sets it to 0x64 (default number of iterations)
-     * @see org.apache.poi.hssf.record.CalcCountRecord
-     * @see org.apache.poi.hssf.record.Record
-     * @return record containing a CalcCountRecord
+     * creates the CalcCount record and sets it to 100 (default number of iterations)
      */
-
-    protected Record createCalcCount()
-    {
+    private static CalcCountRecord createCalcCount() {
         CalcCountRecord retval = new CalcCountRecord();
 
-        retval.setIterations(( short ) 0x64);   // default 64 iterations
+        retval.setIterations(( short ) 100);   // default 100 iterations
         return retval;
     }
 
     /**
      * creates the RefMode record and sets it to A1 Mode (default reference mode)
-     * @see org.apache.poi.hssf.record.RefModeRecord
-     * @see org.apache.poi.hssf.record.Record
-     * @return record containing a RefModeRecord
      */
-
-    protected Record createRefMode()
-    {
+    private static RefModeRecord createRefMode() {
         RefModeRecord retval = new RefModeRecord();
 
         retval.setMode(RefModeRecord.USE_A1_MODE);
@@ -1329,13 +1186,8 @@ public final class Sheet implements Model {
 
     /**
      * creates the Iteration record and sets it to false (don't iteratively calculate formulas)
-     * @see org.apache.poi.hssf.record.IterationRecord
-     * @see org.apache.poi.hssf.record.Record
-     * @return record containing a IterationRecord
      */
-
-    protected Record createIteration()
-    {
+    private static IterationRecord createIteration() {
         IterationRecord retval = new IterationRecord();
 
         retval.setIteration(false);
@@ -1344,13 +1196,8 @@ public final class Sheet implements Model {
 
     /**
      * creates the Delta record and sets it to 0.0010 (default accuracy)
-     * @see org.apache.poi.hssf.record.DeltaRecord
-     * @see org.apache.poi.hssf.record.Record
-     * @return record containing a DeltaRecord
      */
-
-    protected Record createDelta()
-    {
+    private static DeltaRecord createDelta() {
         DeltaRecord retval = new DeltaRecord();
 
         retval.setMaxChange(0.0010);
@@ -1359,13 +1206,8 @@ public final class Sheet implements Model {
 
     /**
      * creates the SaveRecalc record and sets it to true (recalculate before saving)
-     * @see org.apache.poi.hssf.record.SaveRecalcRecord
-     * @see org.apache.poi.hssf.record.Record
-     * @return record containing a SaveRecalcRecord
      */
-
-    protected Record createSaveRecalc()
-    {
+    private static SaveRecalcRecord createSaveRecalc() {
         SaveRecalcRecord retval = new SaveRecalcRecord();
 
         retval.setRecalc(true);
@@ -1374,13 +1216,8 @@ public final class Sheet implements Model {
 
     /**
      * creates the PrintHeaders record and sets it to false (we don't create headers yet so why print them)
-     * @see org.apache.poi.hssf.record.PrintHeadersRecord
-     * @see org.apache.poi.hssf.record.Record
-     * @return record containing a PrintHeadersRecord
      */
-
-    protected Record createPrintHeaders()
-    {
+    private static PrintHeadersRecord createPrintHeaders() {
         PrintHeadersRecord retval = new PrintHeadersRecord();
 
         retval.setPrintHeaders(false);
@@ -1390,14 +1227,8 @@ public final class Sheet implements Model {
     /**
      * creates the PrintGridlines record and sets it to false (that makes for ugly sheets).  As far as I can
      * tell this does the same thing as the GridsetRecord
-     *
-     * @see org.apache.poi.hssf.record.PrintGridlinesRecord
-     * @see org.apache.poi.hssf.record.Record
-     * @return record containing a PrintGridlinesRecord
      */
-
-    protected Record createPrintGridlines()
-    {
+    private static PrintGridlinesRecord createPrintGridlines() {
         PrintGridlinesRecord retval = new PrintGridlinesRecord();
 
         retval.setPrintGridlines(false);
@@ -1406,13 +1237,8 @@ public final class Sheet implements Model {
 
     /**
      * creates the Gridset record and sets it to true (user has mucked with the gridlines)
-     * @see org.apache.poi.hssf.record.GridsetRecord
-     * @see org.apache.poi.hssf.record.Record
-     * @return record containing a GridsetRecord
      */
-
-    protected Record createGridset()
-    {
+    private static GridsetRecord createGridset() {
         GridsetRecord retval = new GridsetRecord();
 
         retval.setGridset(true);
@@ -1421,13 +1247,8 @@ public final class Sheet implements Model {
 
     /**
      * creates the Guts record and sets leftrow/topcol guttter and rowlevelmax/collevelmax to 0
-     * @see org.apache.poi.hssf.record.GutsRecord
-     * @see org.apache.poi.hssf.record.Record
-     * @return record containing a GutsRecordRecord
-     */
-
-    protected Record createGuts()
-    {
+      */
+    private static GutsRecord createGuts() {
         GutsRecord retval = new GutsRecord();
 
         retval.setLeftRowGutter(( short ) 0);
@@ -1439,13 +1260,8 @@ public final class Sheet implements Model {
 
     /**
      * creates the DefaultRowHeight Record and sets its options to 0 and rowheight to 0xff
-     * @see org.apache.poi.hssf.record.DefaultRowHeightRecord
-     * @see org.apache.poi.hssf.record.Record
-     * @return record containing a DefaultRowHeightRecord
      */
-
-    protected Record createDefaultRowHeight()
-    {
+    private static DefaultRowHeightRecord createDefaultRowHeight() {
         DefaultRowHeightRecord retval = new DefaultRowHeightRecord();
 
         retval.setOptionFlags(( short ) 0);
@@ -1455,13 +1271,8 @@ public final class Sheet implements Model {
 
     /**
      * creates the WSBoolRecord and sets its values to defaults
-     * @see org.apache.poi.hssf.record.WSBoolRecord
-     * @see org.apache.poi.hssf.record.Record
-     * @return record containing a WSBoolRecord
      */
-
-    protected Record createWSBool()
-    {
+    private static WSBoolRecord createWSBool() {
         WSBoolRecord retval = new WSBoolRecord();
 
         retval.setWSBool1(( byte ) 0x4);
@@ -1471,13 +1282,8 @@ public final class Sheet implements Model {
 
     /**
      * creates the Header Record and sets it to nothing/0 length
-     * @see org.apache.poi.hssf.record.HeaderRecord
-     * @see org.apache.poi.hssf.record.Record
-     * @return record containing a HeaderRecord
      */
-
-    protected Record createHeader()
-    {
+    private static HeaderRecord createHeader() {
         HeaderRecord retval = new HeaderRecord();
 
         retval.setHeaderLength(( byte ) 0);
@@ -1487,13 +1293,8 @@ public final class Sheet implements Model {
 
     /**
      * creates the Footer Record and sets it to nothing/0 length
-     * @see org.apache.poi.hssf.record.FooterRecord
-     * @see org.apache.poi.hssf.record.Record
-     * @return record containing a FooterRecord
      */
-
-    protected Record createFooter()
-    {
+    private static FooterRecord createFooter() {
         FooterRecord retval = new FooterRecord();
 
         retval.setFooterLength(( byte ) 0);
@@ -1503,13 +1304,8 @@ public final class Sheet implements Model {
 
     /**
      * creates the HCenter Record and sets it to false (don't horizontally center)
-     * @see org.apache.poi.hssf.record.HCenterRecord
-     * @see org.apache.poi.hssf.record.Record
-     * @return record containing a HCenterRecord
      */
-
-    protected Record createHCenter()
-    {
+    private static HCenterRecord createHCenter() {
         HCenterRecord retval = new HCenterRecord();
 
         retval.setHCenter(false);
@@ -1518,13 +1314,8 @@ public final class Sheet implements Model {
 
     /**
      * creates the VCenter Record and sets it to false (don't horizontally center)
-     * @see org.apache.poi.hssf.record.VCenterRecord
-     * @see org.apache.poi.hssf.record.Record
-     * @return record containing a VCenterRecord
-     */
-
-    protected Record createVCenter()
-    {
+    */
+    private static VCenterRecord createVCenter() {
         VCenterRecord retval = new VCenterRecord();
 
         retval.setVCenter(false);
@@ -1537,9 +1328,7 @@ public final class Sheet implements Model {
      * @see org.apache.poi.hssf.record.Record
      * @return record containing a PrintSetupRecord
      */
-
-    protected Record createPrintSetup()
-    {
+    private static PrintSetupRecord createPrintSetup() {
         PrintSetupRecord retval = new PrintSetupRecord();
 
         retval.setPaperSize(( short ) 1);
@@ -1558,30 +1347,13 @@ public final class Sheet implements Model {
 
     /**
      * creates the DefaultColWidth Record and sets it to 8
-     * @see org.apache.poi.hssf.record.DefaultColWidthRecord
-     * @see org.apache.poi.hssf.record.Record
-     * @return record containing a DefaultColWidthRecord
-     */
-
-    protected Record createDefaultColWidth()
-    {
+      */
+    private static DefaultColWidthRecord createDefaultColWidth() {
         DefaultColWidthRecord retval = new DefaultColWidthRecord();
-
         retval.setColWidth(( short ) 8);
         return retval;
     }
 
-    /**
-     * creates the ColumnInfo Record and sets it to a default column/width
-     * @see org.apache.poi.hssf.record.ColumnInfoRecord
-     * @return record containing a ColumnInfoRecord
-     */
-    // TODO change return type to ColumnInfoRecord 
-    protected Record createColInfo()
-    {
-        return ColumnInfoRecordsAggregate.createColInfo();
-    }
-
     /**
      * get the default column width for the sheet (if the columns do not define their own width)
      * @return default column width
@@ -1600,7 +1372,7 @@ public final class Sheet implements Model {
     public boolean isGridsPrinted()
     {
         if (gridset == null) {
-            gridset = (GridsetRecord)createGridset();
+            gridset = createGridset();
             //Insert the newlycreated Gridset record at the end of the record (just before the EOF)
             int loc = findFirstRecordLocBySid(EOFRecord.sid);
             records.add(loc, gridset);
@@ -1816,22 +1588,18 @@ public final class Sheet implements Model {
 
         GutsRecord guts = (GutsRecord) findFirstRecordBySid( GutsRecord.sid );
         guts.setColLevelMax( (short) ( maxLevel+1 ) );
-        if (maxLevel == 0)
+        if (maxLevel == 0) {
             guts.setTopColGutter( (short)0 );
-        else
+        } else {
             guts.setTopColGutter( (short) ( 29 + (12 * (maxLevel-1)) ) );
+        }
     }
 
     /**
      * creates the Dimensions Record and sets it to bogus values (you should set this yourself
      * or let the high level API do it for you)
-     * @see org.apache.poi.hssf.record.DimensionsRecord
-     * @see org.apache.poi.hssf.record.Record
-     * @return record containing a DimensionsRecord
      */
-
-    protected Record createDimensions()
-    {
+    private static DimensionsRecord createDimensions() {
         DimensionsRecord retval = new DimensionsRecord();
 
         retval.setFirstCol(( short ) 0);
@@ -1849,13 +1617,8 @@ public final class Sheet implements Model {
      * headercolor    = 0x40 <P>
      * pagebreakzoom  = 0x0 <P>
      * normalzoom     = 0x0 <p>
-     * @see org.apache.poi.hssf.record.WindowTwoRecord
-     * @see org.apache.poi.hssf.record.Record
-     * @return record containing a WindowTwoRecord
      */
-
-    protected WindowTwoRecord createWindowTwo()
-    {
+    private static WindowTwoRecord createWindowTwo() {
         WindowTwoRecord retval = new WindowTwoRecord();
 
         retval.setOptions(( short ) 0x6b6);
@@ -1869,14 +1632,8 @@ public final class Sheet implements Model {
 
     /**
      * Creates the Selection record and sets it to nothing selected
-     *
-     * @see org.apache.poi.hssf.record.SelectionRecord
-     * @see org.apache.poi.hssf.record.Record
-     * @return record containing a SelectionRecord
-     */
-
-    protected Record createSelection()
-    {
+    */
+    private static SelectionRecord createSelection() {
         SelectionRecord retval = new SelectionRecord();
 
         retval.setPane(( byte ) 0x3);
@@ -1903,19 +1660,15 @@ public final class Sheet implements Model {
      * Sets the left column to show in desktop window pane.
      * @param leftCol the left column to show in desktop window pane
      */
-        public void setLeftCol(short leftCol){
-            if (windowTwo!=null)
-            {
+    public void setLeftCol(short leftCol){
+        if (windowTwo!=null) {
             windowTwo.setLeftCol(leftCol);
-            }
         }
+    }
 
-        public short getLeftCol()
-        {
-            return (windowTwo==null) ? (short) 0 : windowTwo.getLeftCol();
-        }
-
-
+    public short getLeftCol() {
+        return (windowTwo==null) ? (short) 0 : windowTwo.getLeftCol();
+    }
 
     /**
      * Returns the active row
@@ -1977,25 +1730,12 @@ public final class Sheet implements Model {
         }
     }
 
-    protected Record createMergedCells()
-    {
+    private static  MergeCellsRecord createMergedCells() {
         MergeCellsRecord retval = new MergeCellsRecord();
         retval.setNumAreas(( short ) 0);
         return retval;
     }
 
-    /**
-     * creates the EOF record
-     * @see org.apache.poi.hssf.record.EOFRecord
-     * @see org.apache.poi.hssf.record.Record
-     * @return record containing a EOFRecord
-     */
-
-    protected Record createEOF()
-    {
-        return new EOFRecord();
-    }
-
     /**
      * get the location of the DimensionsRecord (which is the last record before the value section)
      * @return location in the array of records of the DimensionsRecord
@@ -2383,28 +2123,20 @@ public final class Sheet implements Model {
 
     /**
      * creates a Protect record with protect set to false.
-     * @see org.apache.poi.hssf.record.ProtectRecord
-     * @see org.apache.poi.hssf.record.Record
-     * @return a ProtectRecord
      */
-    protected Record createProtect()
-    {
-        if (log.check( POILogger.DEBUG ))
+    private static ProtectRecord createProtect() {
+        if (log.check( POILogger.DEBUG )) {
             log.log(POILogger.DEBUG, "create protect record with protection disabled");
-        ProtectRecord retval = new ProtectRecord();
-
-        retval.setProtect(false);
+        }
+        ProtectRecord retval = new ProtectRecord(); 
+        retval.setProtect(false); // TODO - supply param to constructor
         return retval;
     }
 
     /**
      * creates an ObjectProtect record with protect set to false.
-     * @see org.apache.poi.hssf.record.ObjectProtectRecord
-     * @see org.apache.poi.hssf.record.Record
-     * @return an ObjectProtectRecord
      */
-    protected ObjectProtectRecord createObjectProtect()
-    {
+    private static ObjectProtectRecord createObjectProtect() {
         if (log.check( POILogger.DEBUG ))
             log.log(POILogger.DEBUG, "create protect record with protection disabled");
         ObjectProtectRecord retval = new ObjectProtectRecord();
@@ -2415,12 +2147,8 @@ public final class Sheet implements Model {
 
     /**
      * creates a ScenarioProtect record with protect set to false.
-     * @see org.apache.poi.hssf.record.ScenarioProtectRecord
-     * @see org.apache.poi.hssf.record.Record
-     * @return a ScenarioProtectRecord
      */
-    protected ScenarioProtectRecord createScenarioProtect()
-    {
+    private static ScenarioProtectRecord createScenarioProtect() {
         if (log.check( POILogger.DEBUG ))
             log.log(POILogger.DEBUG, "create protect record with protection disabled");
         ScenarioProtectRecord retval = new ScenarioProtectRecord();
@@ -2435,9 +2163,9 @@ public final class Sheet implements Model {
     public ProtectRecord getProtect()
     {
         if (protect == null) {
-            protect = (ProtectRecord)createProtect();
-            //Insert the newlycreated protect record at the end of the record (just before the EOF)
-            int loc = findFirstRecordLocBySid(EOFRecord.sid);
+            protect = createProtect();
+            // Insert the newly created protect record just before DefaultColWidthRecord
+            int loc = findFirstRecordLocBySid(DefaultColWidthRecord.sid);
             records.add(loc, protect);
         }
         return protect;
@@ -2459,14 +2187,11 @@ public final class Sheet implements Model {
 
     /**
      * creates a Password record with password set to 00.
-     * @see org.apache.poi.hssf.record.PasswordRecord
-     * @see org.apache.poi.hssf.record.Record
-     * @return a PasswordRecord
      */
-    protected PasswordRecord createPassword()
-    {
-        if (log.check( POILogger.DEBUG ))
-            log.log(POILogger.DEBUG, "create password record with 00 password");
+    private static PasswordRecord createPassword() {
+        if (log.check( POILogger.DEBUG )) {
+                       log.log(POILogger.DEBUG, "create password record with 00 password");
+               }
         PasswordRecord retval = new PasswordRecord();
 
         retval.setPassword((short)00);
@@ -2892,4 +2617,10 @@ public final class Sheet implements Model {
             rows.expandRow( row );
         }
     }
+    public DataValidityTable getOrCreateDataValidityTable() {
+        if (_dataValidityTable == null) {
+            _dataValidityTable = DataValidityTable.createForSheet(records);
+        }
+        return _dataValidityTable;
+    }
 }
index c4e37114d958c209741624cb376cc7bbb2911e5a..cbc732234fd401cfd663d04bf8f4235271ffd043 100644 (file)
@@ -23,6 +23,7 @@ import java.util.Stack;
 
 import org.apache.poi.hssf.record.formula.Ptg;
 import org.apache.poi.hssf.util.HSSFCellRangeAddress;
+import org.apache.poi.hssf.util.HSSFCellRangeAddress.AddrStructure;
 import org.apache.poi.util.BitField;
 import org.apache.poi.util.LittleEndian;
 import org.apache.poi.util.StringUtil;
@@ -114,7 +115,7 @@ public final class DVRecord extends Record
     private BitField          opt_error_style                  = new BitField(0x00000070);
     private BitField          opt_string_list_formula          = new BitField(0x00000080);
     private BitField          opt_empty_cell_allowed           = new BitField(0x00000100);
-    private BitField          opt_surppres_dropdown_arrow      = new BitField(0x00000200);
+    private BitField          opt_suppress_dropdown_arrow      = new BitField(0x00000200);
     private BitField          opt_show_prompt_on_cell_selected = new BitField(0x00040000);
     private BitField          opt_show_error_on_invalid_value  = new BitField(0x00080000);
     private BitField          opt_condition_operator           = new BitField(0x00F00000);
@@ -283,25 +284,37 @@ public final class DVRecord extends Record
     {
        return (this.opt_empty_cell_allowed.isSet(this.field_option_flags));
     }
+    /**
+     * @deprecated - (Jul-2008) use setSuppressDropDownArrow
+      */
+    public void setSurppresDropdownArrow(boolean suppress) {
+        setSuppressDropdownArrow(suppress);
+    }
+    /**
+     * @deprecated - (Jul-2008) use getSuppressDropDownArrow
+      */
+    public boolean getSurppresDropdownArrow() {
+        return getSuppressDropdownArrow();
+    }
 
     /**
-     * set if drop down arrow should be surppressed when list validation is used
-     * @param type - true if drop down arrow should be surppressed when list validation is used, false otherwise
+     * set if drop down arrow should be suppressed when list validation is used
+     * @param type - true if drop down arrow should be suppressed when list validation is used, false otherwise
      * @see org.apache.poi.hssf.util.HSSFDataValidation utility class
      */
-    public void setSurppresDropdownArrow(boolean surppress)
+    public void setSuppressDropdownArrow(boolean suppress)
     {
-        this.field_option_flags =  this.opt_surppres_dropdown_arrow.setBoolean(this.field_option_flags, surppress);
+        this.field_option_flags =  this.opt_suppress_dropdown_arrow.setBoolean(this.field_option_flags, suppress);
     }
 
     /**
-     * return true if drop down arrow should be surppressed when list validation is used, false otherwise
-     * @return if drop down arrow should be surppressed when list validation is used, false otherwise
+     * return true if drop down arrow should be suppressed when list validation is used, false otherwise
+     * @return if drop down arrow should be suppressed when list validation is used, false otherwise
      * @see org.apache.poi.hssf.util.HSSFDataValidation utility class
      */
-    public boolean getSurppresDropdownArrow()
+    public boolean getSuppressDropdownArrow()
     {
-       return (this.opt_surppres_dropdown_arrow.isSet(this.field_option_flags));
+       return (this.opt_suppress_dropdown_arrow.isSet(this.field_option_flags));
     }
 
     /**
@@ -433,9 +446,40 @@ public final class DVRecord extends Record
     public String toString()
     {
       /** @todo DVRecord string representation */
-        StringBuffer buffer = new StringBuffer();
+        StringBuffer sb = new StringBuffer();
+        sb.append("[DV]\n");
+        sb.append(" options=").append(Integer.toHexString(field_option_flags));
+        sb.append(" title-prompt=").append(field_title_prompt);
+        sb.append(" title-error=").append(field_title_error);
+        sb.append(" text-prompt=").append(field_text_prompt);
+        sb.append(" text-error=").append(field_text_error);
+        sb.append("\n");
+        appendFormula(sb, "Formula 1:",  field_rpn_token_1);
+        appendFormula(sb, "Formula 2:",  field_rpn_token_2);
+        int nRegions = field_regions.getADDRStructureNumber();
+        for(int i=0; i<nRegions; i++) {
+            AddrStructure addr = field_regions.getADDRStructureAt(i);
+            sb.append('(').append(addr.getFirstRow()).append(',').append(addr.getLastRow());
+            sb.append(',').append(addr.getFirstColumn()).append(',').append(addr.getLastColumn()).append(')');
+        }
+        sb.append("\n");
+        sb.append("[/DV]");
 
-        return buffer.toString();
+        return sb.toString();
+    }
+
+    private void appendFormula(StringBuffer sb, String label, Stack stack) {
+        sb.append(label);
+        if (stack.isEmpty()) {
+            sb.append("<empty>\n");
+            return;
+        }
+        sb.append("\n");
+        Ptg[] ptgs = new Ptg[stack.size()];
+        stack.toArray(ptgs);
+        for (int i = 0; i < ptgs.length; i++) {
+            sb.append('\t').append(ptgs[i].toString()).append('\n');
+        }
     }
 
     public int serialize(int offset, byte [] data)
@@ -506,7 +550,7 @@ public final class DVRecord extends Record
      *  contents are somewhat complex
      */
     public Object clone() {
-       return cloneViaReserialise();
+        return cloneViaReserialise();
     }
 
     /**@todo DVRecord = Serializare */
@@ -535,7 +579,7 @@ public final class DVRecord extends Record
             this._string_unicode_flag = in.readByte(); 
             if (this._string_unicode_flag == 1)
             {
-               this._string_data = in.readUnicodeLEString(this._string_length);
+                this._string_data = in.readUnicodeLEString(this._string_length);
             }
             else
             {
diff --git a/src/java/org/apache/poi/hssf/record/aggregates/DataValidityTable.java b/src/java/org/apache/poi/hssf/record/aggregates/DataValidityTable.java
new file mode 100644 (file)
index 0000000..b3d2069
--- /dev/null
@@ -0,0 +1,240 @@
+/* ====================================================================\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 java.util.ArrayList;\r
+import java.util.List;\r
+import java.util.Stack;\r
+\r
+import org.apache.poi.hssf.model.FormulaParser;\r
+import org.apache.poi.hssf.model.RecordStream;\r
+import org.apache.poi.hssf.record.CFHeaderRecord;\r
+import org.apache.poi.hssf.record.CFRuleRecord;\r
+import org.apache.poi.hssf.record.DVALRecord;\r
+import org.apache.poi.hssf.record.DVRecord;\r
+import org.apache.poi.hssf.record.EOFRecord;\r
+import org.apache.poi.hssf.record.HyperlinkRecord;\r
+import org.apache.poi.hssf.record.MergeCellsRecord;\r
+import org.apache.poi.hssf.record.PaneRecord;\r
+import org.apache.poi.hssf.record.Record;\r
+import org.apache.poi.hssf.record.SelectionRecord;\r
+import org.apache.poi.hssf.record.WindowTwoRecord;\r
+import org.apache.poi.hssf.record.formula.Ptg;\r
+import org.apache.poi.hssf.usermodel.HSSFWorkbook;\r
+import org.apache.poi.hssf.util.HSSFCellRangeAddress;\r
+import org.apache.poi.hssf.util.HSSFDataValidation;\r
+\r
+/**\r
+ * Manages the DVALRecord and DVRecords for a single sheet<br/>\r
+ * See OOO excelfileformat.pdf section 4.14\r
+ * @author Josh Micich\r
+ */\r
+public final class DataValidityTable extends RecordAggregate {\r
+\r
+       private static final short sid = -0x01B2; // not a real record\r
+       private final DVALRecord _headerRec;\r
+       /**\r
+        * The list of data validations for the current sheet.\r
+        * Note - this may be empty (contrary to OOO documentation)\r
+        */\r
+       private final List _validationList;\r
+\r
+       public DataValidityTable(RecordStream rs) {\r
+               _headerRec = (DVALRecord) rs.getNext();\r
+               List temp = new ArrayList();\r
+               while (rs.peekNextClass() == DVRecord.class) {\r
+                       temp.add(rs.getNext());\r
+               }\r
+               _validationList = temp;\r
+       }\r
+\r
+       private DataValidityTable() {\r
+               _headerRec = new DVALRecord();\r
+               _validationList = new ArrayList();\r
+       }\r
+\r
+       public short getSid() {\r
+               return sid;\r
+       }\r
+\r
+       public int serialize(int offset, byte[] data) {\r
+               int result = _headerRec.serialize(offset, data);\r
+               for (int i = 0; i < _validationList.size(); i++) {\r
+                       result += ((Record) _validationList.get(i)).serialize(offset + result, data);\r
+               }\r
+               return result;\r
+       }\r
+\r
+       public int getRecordSize() {\r
+               int result = _headerRec.getRecordSize();\r
+               for (int i = _validationList.size() - 1; i >= 0; i--) {\r
+                       result += ((Record) _validationList.get(i)).getRecordSize();\r
+               }\r
+               return result;\r
+       }\r
+\r
+       /**\r
+        * Creates a new <tt>DataValidityTable</tt> and inserts it in the right\r
+        * place in the sheetRecords list.\r
+        */\r
+       public static DataValidityTable createForSheet(List sheetRecords) {\r
+               int index = findDVTableInsertPos(sheetRecords);\r
+\r
+               DataValidityTable result = new DataValidityTable();\r
+               sheetRecords.add(index, result);\r
+               return result;\r
+       }\r
+       \r
+    /**\r
+     * Finds the index where the sheet validations header record should be inserted\r
+     * @param records the records for this sheet\r
+     * \r
+     * + WINDOW2\r
+     * o SCL\r
+     * o PANE\r
+     * oo SELECTION\r
+     * o STANDARDWIDTH\r
+     * oo MERGEDCELLS\r
+     * o LABELRANGES\r
+     * o PHONETICPR\r
+     * o Conditional Formatting Table\r
+     * o Hyperlink Table\r
+     * o Data Validity Table\r
+     * o SHEETLAYOUT\r
+     * o SHEETPROTECTION\r
+     * o RANGEPROTECTION\r
+     * + EOF\r
+     */\r
+    private static int findDVTableInsertPos(List records) {\r
+               int i = records.size() - 1;\r
+               if (!(records.get(i) instanceof EOFRecord)) {\r
+                       throw new IllegalStateException("Last sheet record should be EOFRecord");\r
+               }\r
+               while (i > 0) {\r
+                       i--;\r
+                       Record rec = (Record) records.get(i);\r
+                       if (isPriorRecord(rec.getSid())) {\r
+                               Record nextRec = (Record) records.get(i + 1);\r
+                               if (!isSubsequentRecord(nextRec.getSid())) {\r
+                                       throw new IllegalStateException("Unexpected (" + nextRec.getClass().getName()\r
+                                                       + ") found after (" + rec.getClass().getName() + ")");\r
+                               }\r
+                               return i;\r
+                       }\r
+                       if (!isSubsequentRecord(rec.getSid())) {\r
+                               throw new IllegalStateException("Unexpected (" + rec.getClass().getName()\r
+                                               + ") while looking for DV Table insert pos");\r
+                       }\r
+               }\r
+               return 0;\r
+       }\r
+\r
+       // TODO - add UninterpretedRecord as base class for many of these\r
+       // unimplemented sids\r
+\r
+       private static boolean isPriorRecord(short sid) {\r
+               switch(sid) {\r
+                       case WindowTwoRecord.sid:\r
+                       case 0x00A0: // SCL\r
+                       case PaneRecord.sid:\r
+                       case SelectionRecord.sid:\r
+                       case 0x0099: // STANDARDWIDTH\r
+                       case MergeCellsRecord.sid:\r
+                       case 0x015F: // LABELRANGES\r
+                       case 0x00EF: // PHONETICPR\r
+                       case CFHeaderRecord.sid:\r
+                       case CFRuleRecord.sid:\r
+                       case HyperlinkRecord.sid:\r
+                       case 0x0800: // QUICKTIP\r
+                               return true;\r
+               }\r
+               return false;\r
+       }\r
+\r
+       private static boolean isSubsequentRecord(short sid) {\r
+               switch(sid) {\r
+                       case 0x0862: // SHEETLAYOUT\r
+                       case 0x0867: // SHEETPROTECTION\r
+                       case 0x0868: // RANGEPROTECTION\r
+                       case EOFRecord.sid:\r
+                               return true;\r
+               }\r
+               return false;\r
+       }\r
+\r
+       public void addDataValidation(HSSFDataValidation dataValidation, HSSFWorkbook workbook) {\r
+\r
+               DVRecord dvRecord = new DVRecord();\r
+\r
+               // dv record's option flags\r
+               dvRecord.setDataType(dataValidation.getDataValidationType());\r
+               dvRecord.setErrorStyle(dataValidation.getErrorStyle());\r
+               dvRecord.setEmptyCellAllowed(dataValidation.getEmptyCellAllowed());\r
+               dvRecord.setSuppressDropdownArrow(dataValidation.getSuppressDropDownArrow());\r
+               dvRecord.setShowPromptOnCellSelected(dataValidation.getShowPromptBox());\r
+               dvRecord.setShowErrorOnInvalidValue(dataValidation.getShowErrorBox());\r
+               dvRecord.setConditionOperator(dataValidation.getOperator());\r
+\r
+               // string fields\r
+               dvRecord.setStringField(DVRecord.STRING_PROMPT_TITLE, dataValidation.getPromptBoxTitle());\r
+               dvRecord.setStringField(DVRecord.STRING_PROMPT_TEXT, dataValidation.getPromptBoxText());\r
+               dvRecord.setStringField(DVRecord.STRING_ERROR_TITLE, dataValidation.getErrorBoxTitle());\r
+               dvRecord.setStringField(DVRecord.STRING_ERROR_TEXT, dataValidation.getErrorBoxText());\r
+\r
+               // formula fields ( size and data )\r
+               Stack ptg_arr = new Stack();\r
+               Ptg[] ptg = FormulaParser.parse(dataValidation.getFirstFormula(), workbook);\r
+               int size = 0;\r
+               for (int k = 0; k < ptg.length; k++) {\r
+                       if (ptg[k] instanceof org.apache.poi.hssf.record.formula.AreaPtg) {\r
+                               // we should set ptgClass to Ptg.CLASS_REF and explicit formula\r
+                               // string to false\r
+                               // ptg[k].setClass(Ptg.CLASS_REF);\r
+                               // obj_validation.setExplicitListFormula(false);\r
+                       }\r
+                       size += ptg[k].getSize();\r
+                       ptg_arr.push(ptg[k]);\r
+               }\r
+               dvRecord.setFirstFormulaRPN(ptg_arr);\r
+               dvRecord.setFirstFormulaSize((short) size);\r
+\r
+               dvRecord.setListExplicitFormula(dataValidation.getExplicitListFormula());\r
+\r
+               if (dataValidation.getSecondFormula() != null) {\r
+\r
+                       ptg_arr = new Stack();\r
+                       ptg = FormulaParser.parse(dataValidation.getSecondFormula(), workbook);\r
+                       size = 0;\r
+                       for (int k = 0; k < ptg.length; k++) {\r
+                               size += ptg[k].getSize();\r
+                               ptg_arr.push(ptg[k]);\r
+                       }\r
+                       dvRecord.setSecFormulaRPN(ptg_arr);\r
+                       dvRecord.setSecFormulaSize((short) size);\r
+               }\r
+\r
+               // dv records cell range field\r
+               HSSFCellRangeAddress cell_range = new HSSFCellRangeAddress();\r
+               cell_range.addADDRStructure(dataValidation.getFirstRow(), dataValidation.getFirstColumn(),\r
+                               dataValidation.getLastRow(), dataValidation.getLastColumn());\r
+               dvRecord.setCellRangeAddress(cell_range);\r
+\r
+               _validationList.add(dvRecord);\r
+               _headerRec.setDVRecNo(_validationList.size());\r
+       }\r
+}\r
diff --git a/src/java/org/apache/poi/hssf/record/aggregates/RecordAggregate.java b/src/java/org/apache/poi/hssf/record/aggregates/RecordAggregate.java
new file mode 100644 (file)
index 0000000..3a86871
--- /dev/null
@@ -0,0 +1,41 @@
+/* ====================================================================\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 org.apache.poi.hssf.record.Record;\r
+import org.apache.poi.hssf.record.RecordInputStream;\r
+\r
+/**\r
+ * <tt>RecordAggregate</tt>s are groups of of BIFF <tt>Record</tt>s that are typically stored \r
+ * together and/or updated together.  Workbook / Sheet records are typically stored in a sequential\r
+ * list, which does not provide much structure to coordinate updates.\r
+ * \r
+ * @author Josh Micich\r
+ */\r
+public abstract class RecordAggregate extends Record {\r
+       // TODO - convert existing aggregate classes to proper subclasses of this one\r
+       protected final void validateSid(short id) {\r
+               // TODO - break class hierarchy and make separate from Record\r
+               throw new RuntimeException("Should not be called");\r
+       }\r
+       protected final void fillFields(RecordInputStream in) {\r
+               throw new RuntimeException("Should not be called");\r
+       }\r
+       // force subclassses to provide better implementation than default\r
+       public abstract int getRecordSize();\r
+}\r
index e2973df232f2f77e9ad9fe30dbde1db2d22c1d3f..9b6c206190aaa628f15edb033feb5d5c79aaad1d 100644 (file)
@@ -28,7 +28,6 @@ import java.text.NumberFormat;
 import java.util.ArrayList;
 import java.util.Iterator;
 import java.util.List;
-import java.util.Stack;
 import java.util.TreeMap;
 
 import org.apache.poi.ddf.EscherRecord;
@@ -36,9 +35,9 @@ 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.*;
+import org.apache.poi.hssf.record.aggregates.DataValidityTable;
 import org.apache.poi.hssf.record.formula.Ptg;
 import org.apache.poi.hssf.record.formula.RefPtg;
-import org.apache.poi.hssf.util.HSSFCellRangeAddress;
 import org.apache.poi.hssf.util.HSSFDataValidation;
 import org.apache.poi.hssf.util.PaneInformation;
 import org.apache.poi.hssf.util.Region;
@@ -375,92 +374,18 @@ public final class HSSFSheet {
 
     /**
      * Creates a data validation object
-     * @param obj_validation The Data validation object settings
+     * @param dataValidation The Data validation object settings
      */
-    public void addValidationData(HSSFDataValidation obj_validation)
-    {
-       if ( obj_validation == null )
-       {
-         return;
-       }
-       DVALRecord dvalRec = (DVALRecord)sheet.findFirstRecordBySid( DVALRecord.sid );
-       int eofLoc = sheet.findFirstRecordLocBySid( EOFRecord.sid );
-       if ( dvalRec == null )
-       {
-          dvalRec = new DVALRecord();
-          sheet.getRecords().add( eofLoc, dvalRec );
-       }
-       int curr_dvRecNo = dvalRec.getDVRecNo();
-       dvalRec.setDVRecNo(curr_dvRecNo+1);
-
-       //create dv record
-       DVRecord dvRecord = new DVRecord();
-
-       //dv record's option flags
-       dvRecord.setDataType( obj_validation.getDataValidationType() );
-       dvRecord.setErrorStyle(obj_validation.getErrorStyle());
-       dvRecord.setEmptyCellAllowed(obj_validation.getEmptyCellAllowed());
-       dvRecord.setSurppresDropdownArrow(obj_validation.getSurppressDropDownArrow());
-       dvRecord.setShowPromptOnCellSelected(obj_validation.getShowPromptBox());
-       dvRecord.setShowErrorOnInvalidValue(obj_validation.getShowErrorBox());
-       dvRecord.setConditionOperator(obj_validation.getOperator());
-
-       //string fields
-       dvRecord.setStringField( DVRecord.STRING_PROMPT_TITLE,obj_validation.getPromptBoxTitle());
-       dvRecord.setStringField( DVRecord.STRING_PROMPT_TEXT, obj_validation.getPromptBoxText());
-       dvRecord.setStringField( DVRecord.STRING_ERROR_TITLE, obj_validation.getErrorBoxTitle());
-       dvRecord.setStringField( DVRecord.STRING_ERROR_TEXT, obj_validation.getErrorBoxText());
-
-       //formula fields ( size and data )
-       String str_formula = obj_validation.getFirstFormula();
-       FormulaParser fp = new FormulaParser(str_formula, workbook);
-       fp.parse();
-       Stack ptg_arr = new Stack();
-       Ptg[] ptg  = fp.getRPNPtg();
-       int size = 0;
-       for (int k = 0; k < ptg.length; k++)
-       {
-           if ( ptg[k] instanceof org.apache.poi.hssf.record.formula.AreaPtg )
-           {
-              //we should set ptgClass to Ptg.CLASS_REF and explicit formula string to false
-              ptg[k].setClass(Ptg.CLASS_REF);
-              obj_validation.setExplicitListFormula(false);
-           }
-           size += ptg[k].getSize();
-           ptg_arr.push(ptg[k]);
+    public void addValidationData(HSSFDataValidation dataValidation) {
+       if (dataValidation == null) {
+           throw new IllegalArgumentException("objValidation must not be null");
        }
-       dvRecord.setFirstFormulaRPN(ptg_arr);
-       dvRecord.setFirstFormulaSize((short)size);
-
-       dvRecord.setListExplicitFormula(obj_validation.getExplicitListFormula());
-
-       if ( obj_validation.getSecondFormula() != null )
-       {
-         str_formula = obj_validation.getSecondFormula();
-         fp = new FormulaParser(str_formula, workbook);
-         fp.parse();
-         ptg_arr = new Stack();
-         ptg  = fp.getRPNPtg();
-         size = 0;
-         for (int k = 0; k < ptg.length; k++)
-         {
-             size += ptg[k].getSize();
-             ptg_arr.push(ptg[k]);
-         }
-         dvRecord.setSecFormulaRPN(ptg_arr);
-         dvRecord.setSecFormulaSize((short)size);
-       }
-
-       //dv records cell range field
-       HSSFCellRangeAddress cell_range = new HSSFCellRangeAddress();
-       cell_range.addADDRStructure(obj_validation.getFirstRow(), obj_validation.getFirstColumn(), obj_validation.getLastRow(), obj_validation.getLastColumn());
-       dvRecord.setCellRangeAddress(cell_range);
+       DataValidityTable dvt = sheet.getOrCreateDataValidityTable();
 
-       //add dv record
-       eofLoc = sheet.findFirstRecordLocBySid( EOFRecord.sid );
-       sheet.getRecords().add( eofLoc, dvRecord );
+       dvt.addDataValidation(dataValidation, workbook);
     }
 
+
     /**
      * Get the visibility state for a given column.
      * @param column - the column to get (0-based)
index af578bee48b10d9f1e15b3a108ae3b2bad5c8474..4d8f48b929a882eea6bfc28e71e5bca7638aed16 100644 (file)
@@ -218,13 +218,25 @@ public class HSSFDataValidation
   {
      return this._empty_cell_allowed ;
   }
+  /**
+   * @deprecated - (Jul-2008) use setSuppressDropDownArrow
+    */
+  public void setSurppressDropDownArrow( boolean suppress ) {
+    setSuppressDropDownArrow(suppress);
+  }
+  /**
+   * @deprecated - (Jul-2008) use getSuppressDropDownArrow
+    */
+  public boolean getSurppressDropDownArrow( ) {
+    return getSuppressDropDownArrow();
+  }
 
   /**
    * Useful for list validation objects .
    * @param surppres True if a list should display the values into a drop down list , false otherwise .
    *                 In other words , if a list should display the arrow sign on its right side
    */
-  public void setSurppressDropDownArrow( boolean surppres )
+  public void setSuppressDropDownArrow( boolean surppres )
   {
      this._surpress_dropdown_arrow = surppres;
   }
@@ -235,7 +247,7 @@ public class HSSFDataValidation
    * @return True if a list should display the values into a drop down list , false otherwise .
    * @see setDataValidationType( int data_type )
    */
-  public boolean getSurppressDropDownArrow( )
+  public boolean getSuppressDropDownArrow( )
   {
      if ( this._data_type != HSSFDataValidation.DATA_TYPE_LIST )
      {
diff --git a/src/testcases/org/apache/poi/hssf/data/dvEmpty.xls b/src/testcases/org/apache/poi/hssf/data/dvEmpty.xls
new file mode 100644 (file)
index 0000000..72c78cf
Binary files /dev/null and b/src/testcases/org/apache/poi/hssf/data/dvEmpty.xls differ
index ef21cc9b362f3a524966e161b0c6930be905555a..71881accec32469db02f99e6fff5c0f781d5021c 100644 (file)
@@ -297,7 +297,8 @@ public final class TestSheet extends TestCase {
         xfindex = sheet.getXFIndexForColAt((short) 1);
         assertEquals(DEFAULT_IDX, xfindex);
 
-        ColumnInfoRecord nci = ( ColumnInfoRecord ) sheet.createColInfo();
+        // TODO change return type to ColumnInfoRecord 
+        ColumnInfoRecord nci = (ColumnInfoRecord)ColumnInfoRecordsAggregate.createColInfo();
         sheet.columns.insertColumn(nci);
 
         // single column ColumnInfoRecord
index f1c3b7c9cace67319cc2214d56c8f920a44d8906..f86c2941a970cdb3681acb3ccffb9381decc31bf 100644 (file)
 
 package org.apache.poi.hssf.model;
 
-import java.lang.reflect.Field;
-import java.util.ArrayList;
-import java.util.List;
-
 import junit.framework.TestCase;
 
 import org.apache.poi.hssf.record.ColumnInfoRecord;
+import org.apache.poi.hssf.record.aggregates.ColumnInfoRecordsAggregate;
 
 /**
  * @author Tony Poppleton
@@ -32,7 +29,8 @@ public final class TestSheetAdditional extends TestCase {
        
        public void testGetCellWidth() {
                Sheet sheet = Sheet.createSheet();
-               ColumnInfoRecord nci = ( ColumnInfoRecord ) sheet.createColInfo();
+               // TODO change return type to ColumnInfoRecord 
+               ColumnInfoRecord nci = (ColumnInfoRecord)ColumnInfoRecordsAggregate.createColInfo();
 
                // Prepare test model
                nci.setFirstColumn((short)5);
index 34885e7a21d88ec843ba926776cdf4006099fe74..32f3e77a70d5c05bbb699c13b3d42ba9ceb79da1 100644 (file)
 
 package org.apache.poi.hssf.usermodel;
 
-import junit.framework.TestCase;
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.text.SimpleDateFormat;
 
-import org.apache.poi.hssf.util.*;
+import junit.framework.AssertionFailedError;
+import junit.framework.TestCase;
 
-import java.io.*;
-import java.util.*;
-import java.text.SimpleDateFormat;
+import org.apache.poi.hssf.HSSFTestDataSamples;
+import org.apache.poi.hssf.eventmodel.ERFListener;
+import org.apache.poi.hssf.eventmodel.EventRecordFactory;
+import org.apache.poi.hssf.record.DVRecord;
+import org.apache.poi.hssf.record.RecordFormatException;
+import org.apache.poi.hssf.util.HSSFColor;
+import org.apache.poi.hssf.util.HSSFDataValidation;
+import org.apache.poi.hssf.util.Region;
+import org.apache.poi.poifs.filesystem.POIFSFileSystem;
 
 /**
  * <p>Title: TestDataValidation</p>
@@ -34,19 +46,6 @@ import java.text.SimpleDateFormat;
  */
 public class TestDataValidation extends TestCase
 {
-  public TestDataValidation(String name)
-  {
-    super(name);
-  }
-
-  protected void setUp()
-  {
-    String filename = System.getProperty("HSSF.testdata.path");
-    if (filename == null)
-    {
-       System.setProperty("HSSF.testdata.path", "src/testcases/org/apache/poi/hssf/data");
-    }
-  }
 
   public void testDataValidation() throws Exception
   {
@@ -903,8 +902,88 @@ public class TestDataValidation extends TestCase
      cell.setCellValue(strStettings);
   }
 
-  public static void main(String[] args)
-  {
-    junit.textui.TestRunner.run(TestDataValidation.class);
-  }
+  
+       public void testAddToExistingSheet() {
+
+               // dvEmpty.xls is a simple one sheet workbook.  With a DataValidations header record but no 
+               // DataValidations.  It's important that the example has one SHEETPROTECTION record.
+               // Such a workbook can be created in Excel (2007) by adding datavalidation for one cell
+               // and then deleting the row that contains the cell.
+               HSSFWorkbook wb = HSSFTestDataSamples.openSampleWorkbook("dvEmpty.xls");  
+               int dvRow = 0;
+               HSSFSheet sheet = wb.getSheetAt(0);
+               sheet.createRow(dvRow).createCell((short)0);
+               HSSFDataValidation dv = new HSSFDataValidation((short)dvRow, (short)0, (short)dvRow, (short)0);
+               
+               dv.setDataValidationType(HSSFDataValidation.DATA_TYPE_INTEGER);
+               dv.setEmptyCellAllowed(false);
+               dv.setOperator(HSSFDataValidation.OPERATOR_EQUAL);
+               dv.setFirstFormula("42");
+               dv.setErrorStyle(HSSFDataValidation.ERROR_STYLE_STOP);
+               dv.setShowPromptBox(true);
+               dv.createErrorBox("Error", "The value is wrong");
+               dv.setSurppressDropDownArrow(true);
+
+               sheet.addValidationData(dv);
+               wb.toString();
+               
+               ByteArrayOutputStream baos = new ByteArrayOutputStream();
+               try {
+                       wb.write(baos);
+               } catch (IOException e) {
+                       throw new RuntimeException(e);
+               }
+               
+               byte[] wbData = baos.toByteArray();
+               
+               if (false) { // TODO (Jul 2008) fix EventRecordFactory to process unknown records, (and DV records for that matter)
+                       EventRecordFactory erf = new EventRecordFactory();
+                       ERFListener erfListener = null; // new MyERFListener();
+                       erf.registerListener(erfListener, null);
+                       try {
+                               POIFSFileSystem fs = new POIFSFileSystem(new ByteArrayInputStream(baos.toByteArray()));
+                               erf.processRecords(fs.createDocumentInputStream("Workbook"));
+                       } catch (RecordFormatException e) {
+                               throw new RuntimeException(e);
+                       } catch (IOException e) {
+                               throw new RuntimeException(e);
+                       }
+               }
+               // else verify record ordering by navigating the raw bytes
+               
+               byte[] dvHeaderRecStart= { (byte)0xB2, 0x01, 0x12, 0x00, };
+               int dvHeaderOffset = findIndex(wbData, dvHeaderRecStart);
+               assertTrue(dvHeaderOffset > 0);
+               int nextRecIndex = dvHeaderOffset + 22;
+               int nextSid 
+                       = ((wbData[nextRecIndex + 0] << 0) & 0x00FF) 
+                       + ((wbData[nextRecIndex + 1] << 8) & 0xFF00)
+                       ;
+               // nextSid should be for a DVRecord.  If anything comes between the DV header record 
+               // and the DV records, Excel will not be able to open the workbook without error.
+               
+               if (nextSid == 0x0867) {
+                       throw new AssertionFailedError("Identified bug XXXX");
+               }
+               assertEquals(DVRecord.sid, nextSid);
+       }
+       private int findIndex(byte[] largeData, byte[] searchPattern) {
+               byte firstByte = searchPattern[0];
+               for (int i = 0; i < largeData.length; i++) {
+                       if(largeData[i] != firstByte) {
+                               continue;
+                       }
+                       boolean match = true;
+                       for (int j = 1; j < searchPattern.length; j++) {
+                               if(searchPattern[j] != largeData[i+j]) {
+                                       match = false;
+                                       break;
+                               }
+                       }
+                       if (match) {
+                               return i;
+                       }
+               }
+               return -1;
+       }
 }