From: Josh Micich Date: Thu, 31 Jul 2008 22:44:48 +0000 (+0000) Subject: Fix for bug 45519 - keep data validation records together X-Git-Tag: REL_3_2_FINAL~224 X-Git-Url: https://source.dussan.org/?a=commitdiff_plain;h=b935799609def8a1ccfbd898bf1c910d6827735c;p=poi.git Fix for bug 45519 - keep data validation records together git-svn-id: https://svn.apache.org/repos/asf/poi/trunk@681530 13f79535-47bb-0310-9956-ffa450edef68 --- diff --git a/src/documentation/content/xdocs/changes.xml b/src/documentation/content/xdocs/changes.xml index 12763c3d3d..3660da72e4 100644 --- a/src/documentation/content/xdocs/changes.xml +++ b/src/documentation/content/xdocs/changes.xml @@ -37,6 +37,7 @@ + 45519 - Fixed to keep datavalidation records together Support for creating new HSLF CurrentUserAtoms 45466 - Partial support for removing excel comments (won't work for all excel versions yet) 45437 - Detect encrypted word documents, and throw an EncryptedDocumentException instead of a OOM diff --git a/src/documentation/content/xdocs/status.xml b/src/documentation/content/xdocs/status.xml index 230244190c..4927e7150d 100644 --- a/src/documentation/content/xdocs/status.xml +++ b/src/documentation/content/xdocs/status.xml @@ -34,6 +34,7 @@ + 45519 - Fixed to keep datavalidation records together Support for creating new HSLF CurrentUserAtoms 45466 - Partial support for removing excel comments (won't work for all excel versions yet) 45437 - Detect encrypted word documents, and throw an EncryptedDocumentException instead of a OOM diff --git a/src/java/org/apache/poi/hssf/model/RecordStream.java b/src/java/org/apache/poi/hssf/model/RecordStream.java index 03177c7c22..bec1c40e6a 100755 --- a/src/java/org/apache/poi/hssf/model/RecordStream.java +++ b/src/java/org/apache/poi/hssf/model/RecordStream.java @@ -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; diff --git a/src/java/org/apache/poi/hssf/model/Sheet.java b/src/java/org/apache/poi/hssf/model/Sheet.java index cbbe663b1d..9959dbfb26 100644 --- a/src/java/org/apache/poi/hssf/model/Sheet.java +++ b/src/java/org/apache/poi/hssf/model/Sheet.java @@ -17,13 +17,13 @@ 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

* pagebreakzoom = 0x0

* normalzoom = 0x0

- * @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; + } } diff --git a/src/java/org/apache/poi/hssf/record/DVRecord.java b/src/java/org/apache/poi/hssf/record/DVRecord.java index c4e37114d9..cbc732234f 100644 --- a/src/java/org/apache/poi/hssf/record/DVRecord.java +++ b/src/java/org/apache/poi/hssf/record/DVRecord.java @@ -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\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 index 0000000000..b3d2069ca9 --- /dev/null +++ b/src/java/org/apache/poi/hssf/record/aggregates/DataValidityTable.java @@ -0,0 +1,240 @@ +/* ==================================================================== + Licensed to the Apache Software Foundation (ASF) under one or more + contributor license agreements. See the NOTICE file distributed with + this work for additional information regarding copyright ownership. + The ASF licenses this file to You under the Apache License, Version 2.0 + (the "License"); you may not use this file except in compliance with + the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +==================================================================== */ + +package org.apache.poi.hssf.record.aggregates; + +import java.util.ArrayList; +import java.util.List; +import java.util.Stack; + +import org.apache.poi.hssf.model.FormulaParser; +import org.apache.poi.hssf.model.RecordStream; +import org.apache.poi.hssf.record.CFHeaderRecord; +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; +import org.apache.poi.hssf.record.HyperlinkRecord; +import org.apache.poi.hssf.record.MergeCellsRecord; +import org.apache.poi.hssf.record.PaneRecord; +import org.apache.poi.hssf.record.Record; +import org.apache.poi.hssf.record.SelectionRecord; +import org.apache.poi.hssf.record.WindowTwoRecord; +import org.apache.poi.hssf.record.formula.Ptg; +import org.apache.poi.hssf.usermodel.HSSFWorkbook; +import org.apache.poi.hssf.util.HSSFCellRangeAddress; +import org.apache.poi.hssf.util.HSSFDataValidation; + +/** + * Manages the DVALRecord and DVRecords for a single sheet
+ * See OOO excelfileformat.pdf section 4.14 + * @author Josh Micich + */ +public final class DataValidityTable extends RecordAggregate { + + private static final short sid = -0x01B2; // not a real record + private final DVALRecord _headerRec; + /** + * The list of data validations for the current sheet. + * Note - this may be empty (contrary to OOO documentation) + */ + private final List _validationList; + + public DataValidityTable(RecordStream rs) { + _headerRec = (DVALRecord) rs.getNext(); + List temp = new ArrayList(); + while (rs.peekNextClass() == DVRecord.class) { + temp.add(rs.getNext()); + } + _validationList = temp; + } + + private DataValidityTable() { + _headerRec = new DVALRecord(); + _validationList = new ArrayList(); + } + + public short getSid() { + return sid; + } + + public int serialize(int offset, byte[] data) { + int result = _headerRec.serialize(offset, data); + for (int i = 0; i < _validationList.size(); i++) { + result += ((Record) _validationList.get(i)).serialize(offset + result, data); + } + return result; + } + + public int getRecordSize() { + int result = _headerRec.getRecordSize(); + for (int i = _validationList.size() - 1; i >= 0; i--) { + result += ((Record) _validationList.get(i)).getRecordSize(); + } + return result; + } + + /** + * Creates a new DataValidityTable and inserts it in the right + * place in the sheetRecords list. + */ + public static DataValidityTable createForSheet(List sheetRecords) { + int index = findDVTableInsertPos(sheetRecords); + + DataValidityTable result = new DataValidityTable(); + sheetRecords.add(index, result); + return result; + } + + /** + * Finds the index where the sheet validations header record should be inserted + * @param records the records for this sheet + * + * + WINDOW2 + * o SCL + * o PANE + * oo SELECTION + * o STANDARDWIDTH + * oo MERGEDCELLS + * o LABELRANGES + * o PHONETICPR + * o Conditional Formatting Table + * o Hyperlink Table + * o Data Validity Table + * o SHEETLAYOUT + * o SHEETPROTECTION + * o RANGEPROTECTION + * + EOF + */ + private static int findDVTableInsertPos(List records) { + int i = records.size() - 1; + if (!(records.get(i) instanceof EOFRecord)) { + throw new IllegalStateException("Last sheet record should be EOFRecord"); + } + while (i > 0) { + i--; + Record rec = (Record) records.get(i); + if (isPriorRecord(rec.getSid())) { + Record nextRec = (Record) records.get(i + 1); + if (!isSubsequentRecord(nextRec.getSid())) { + throw new IllegalStateException("Unexpected (" + nextRec.getClass().getName() + + ") found after (" + rec.getClass().getName() + ")"); + } + return i; + } + if (!isSubsequentRecord(rec.getSid())) { + throw new IllegalStateException("Unexpected (" + rec.getClass().getName() + + ") while looking for DV Table insert pos"); + } + } + return 0; + } + + // TODO - add UninterpretedRecord as base class for many of these + // unimplemented sids + + private static boolean isPriorRecord(short sid) { + switch(sid) { + case WindowTwoRecord.sid: + case 0x00A0: // SCL + case PaneRecord.sid: + case SelectionRecord.sid: + case 0x0099: // STANDARDWIDTH + case MergeCellsRecord.sid: + case 0x015F: // LABELRANGES + case 0x00EF: // PHONETICPR + case CFHeaderRecord.sid: + case CFRuleRecord.sid: + case HyperlinkRecord.sid: + case 0x0800: // QUICKTIP + return true; + } + return false; + } + + private static boolean isSubsequentRecord(short sid) { + switch(sid) { + case 0x0862: // SHEETLAYOUT + case 0x0867: // SHEETPROTECTION + case 0x0868: // RANGEPROTECTION + case EOFRecord.sid: + return true; + } + return false; + } + + public void addDataValidation(HSSFDataValidation dataValidation, HSSFWorkbook workbook) { + + DVRecord dvRecord = new DVRecord(); + + // dv record's option flags + dvRecord.setDataType(dataValidation.getDataValidationType()); + dvRecord.setErrorStyle(dataValidation.getErrorStyle()); + dvRecord.setEmptyCellAllowed(dataValidation.getEmptyCellAllowed()); + dvRecord.setSuppressDropdownArrow(dataValidation.getSuppressDropDownArrow()); + dvRecord.setShowPromptOnCellSelected(dataValidation.getShowPromptBox()); + dvRecord.setShowErrorOnInvalidValue(dataValidation.getShowErrorBox()); + dvRecord.setConditionOperator(dataValidation.getOperator()); + + // string fields + dvRecord.setStringField(DVRecord.STRING_PROMPT_TITLE, dataValidation.getPromptBoxTitle()); + dvRecord.setStringField(DVRecord.STRING_PROMPT_TEXT, dataValidation.getPromptBoxText()); + dvRecord.setStringField(DVRecord.STRING_ERROR_TITLE, dataValidation.getErrorBoxTitle()); + dvRecord.setStringField(DVRecord.STRING_ERROR_TEXT, dataValidation.getErrorBoxText()); + + // formula fields ( size and data ) + Stack ptg_arr = new Stack(); + Ptg[] ptg = FormulaParser.parse(dataValidation.getFirstFormula(), workbook); + 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]); + } + dvRecord.setFirstFormulaRPN(ptg_arr); + dvRecord.setFirstFormulaSize((short) size); + + dvRecord.setListExplicitFormula(dataValidation.getExplicitListFormula()); + + if (dataValidation.getSecondFormula() != null) { + + ptg_arr = new Stack(); + ptg = FormulaParser.parse(dataValidation.getSecondFormula(), workbook); + 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(dataValidation.getFirstRow(), dataValidation.getFirstColumn(), + dataValidation.getLastRow(), dataValidation.getLastColumn()); + dvRecord.setCellRangeAddress(cell_range); + + _validationList.add(dvRecord); + _headerRec.setDVRecNo(_validationList.size()); + } +} 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 index 0000000000..3a86871e8b --- /dev/null +++ b/src/java/org/apache/poi/hssf/record/aggregates/RecordAggregate.java @@ -0,0 +1,41 @@ +/* ==================================================================== + Licensed to the Apache Software Foundation (ASF) under one or more + contributor license agreements. See the NOTICE file distributed with + this work for additional information regarding copyright ownership. + The ASF licenses this file to You under the Apache License, Version 2.0 + (the "License"); you may not use this file except in compliance with + the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +==================================================================== */ + +package org.apache.poi.hssf.record.aggregates; + +import org.apache.poi.hssf.record.Record; +import org.apache.poi.hssf.record.RecordInputStream; + +/** + * RecordAggregates are groups of of BIFF Records that are typically stored + * together and/or updated together. Workbook / Sheet records are typically stored in a sequential + * list, which does not provide much structure to coordinate updates. + * + * @author Josh Micich + */ +public abstract class RecordAggregate extends Record { + // TODO - convert existing aggregate classes to proper subclasses of this one + protected final void validateSid(short id) { + // TODO - break class hierarchy and make separate from Record + throw new RuntimeException("Should not be called"); + } + protected final void fillFields(RecordInputStream in) { + throw new RuntimeException("Should not be called"); + } + // force subclassses to provide better implementation than default + public abstract int getRecordSize(); +} diff --git a/src/java/org/apache/poi/hssf/usermodel/HSSFSheet.java b/src/java/org/apache/poi/hssf/usermodel/HSSFSheet.java index e2973df232..9b6c206190 100644 --- a/src/java/org/apache/poi/hssf/usermodel/HSSFSheet.java +++ b/src/java/org/apache/poi/hssf/usermodel/HSSFSheet.java @@ -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) diff --git a/src/java/org/apache/poi/hssf/util/HSSFDataValidation.java b/src/java/org/apache/poi/hssf/util/HSSFDataValidation.java index af578bee48..4d8f48b929 100644 --- a/src/java/org/apache/poi/hssf/util/HSSFDataValidation.java +++ b/src/java/org/apache/poi/hssf/util/HSSFDataValidation.java @@ -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 index 0000000000..72c78cfa49 Binary files /dev/null and b/src/testcases/org/apache/poi/hssf/data/dvEmpty.xls differ diff --git a/src/testcases/org/apache/poi/hssf/model/TestSheet.java b/src/testcases/org/apache/poi/hssf/model/TestSheet.java index ef21cc9b36..71881accec 100644 --- a/src/testcases/org/apache/poi/hssf/model/TestSheet.java +++ b/src/testcases/org/apache/poi/hssf/model/TestSheet.java @@ -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 diff --git a/src/testcases/org/apache/poi/hssf/model/TestSheetAdditional.java b/src/testcases/org/apache/poi/hssf/model/TestSheetAdditional.java index f1c3b7c9ca..f86c2941a9 100644 --- a/src/testcases/org/apache/poi/hssf/model/TestSheetAdditional.java +++ b/src/testcases/org/apache/poi/hssf/model/TestSheetAdditional.java @@ -17,13 +17,10 @@ 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); diff --git a/src/testcases/org/apache/poi/hssf/usermodel/TestDataValidation.java b/src/testcases/org/apache/poi/hssf/usermodel/TestDataValidation.java index 34885e7a21..32f3e77a70 100644 --- a/src/testcases/org/apache/poi/hssf/usermodel/TestDataValidation.java +++ b/src/testcases/org/apache/poi/hssf/usermodel/TestDataValidation.java @@ -16,13 +16,25 @@ 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; /** *

Title: TestDataValidation

@@ -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; + } }