From: Yegor Kozlov Date: Fri, 4 Jan 2008 14:19:14 +0000 (+0000) Subject: merged TRUNK changes r608809 into REL_3_0_2_BETA2 X-Git-Tag: REL_3_0_2_BETA2^0 X-Git-Url: https://source.dussan.org/?a=commitdiff_plain;h=ce32b7c036323c2b722ee129ac8a428abd4fe5ce;p=poi.git merged TRUNK changes r608809 into REL_3_0_2_BETA2 git-svn-id: https://svn.apache.org/repos/asf/poi/tags/REL_3_0_2_BETA2@608846 13f79535-47bb-0310-9956-ffa450edef68 --- diff --git a/build.xml b/build.xml index 73338a2a7d..8661595b8d 100644 --- a/build.xml +++ b/build.xml @@ -70,6 +70,7 @@ under the License. + @@ -77,6 +78,9 @@ under the License. + + + @@ -116,8 +120,33 @@ under the License. - - + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -130,7 +159,7 @@ under the License. - + @@ -162,6 +191,15 @@ under the License. + + + + + + + + + @@ -225,12 +263,15 @@ under the License. + + + @@ -281,6 +322,57 @@ under the License. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -305,7 +397,7 @@ under the License. - + @@ -363,6 +455,14 @@ under the License. + + + + + + + @@ -590,6 +690,43 @@ under the License. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -976,6 +1113,21 @@ FORREST_HOME environment variable! + + + + + + + + + + + + + + + diff --git a/poi.pom b/poi.pom index 7395157c2f..ed6923b628 100644 --- a/poi.pom +++ b/poi.pom @@ -77,8 +77,8 @@ under the License. - http://svn.apache.org/viewvc/jakarta/poi/trunk - scm:svn:http://svn.apache.org/repos/asf/jakarta/poi/trunk + http://svn.apache.org/viewvc/poi/trunk + scm:svn:http://svn.apache.org/repos/asf/poi/trunk bugzilla diff --git a/src/documentation/content/xdocs/book.xml b/src/documentation/content/xdocs/book.xml index 36c50e6fe9..e8e6eb6741 100644 --- a/src/documentation/content/xdocs/book.xml +++ b/src/documentation/content/xdocs/book.xml @@ -57,6 +57,7 @@ + diff --git a/src/documentation/content/xdocs/changes.xml b/src/documentation/content/xdocs/changes.xml index f429eb361c..23ed0537c5 100644 --- a/src/documentation/content/xdocs/changes.xml +++ b/src/documentation/content/xdocs/changes.xml @@ -35,8 +35,19 @@ - - 43877 and 39512 - Fix for handling mixed OBJ and CONTINUE records. + + Support for tables in HSLF + 43781 - Fix for extracting text from TextBoxes HSLF in + Improve JavaDocs relating to hssf font and fill colourings + 44095, 44097, 44099 - [PATCH] Support for Mid, Replace and Substitute excel functions + 44055 - [PATCH] Support for getting the from field from HSMF messages + 43551 - [PATCH] Support for 1904 date windowing in HSSF (previously only supported 1900 date windowing) + 41064 - [PATCH] Support for String continue records + 27511 - [PATCH] Support for data validation, via DVRecord and DVALRecord + + + + 43877 and 39512 - Fix for handling mixed OBJ and CONTINUE records. 43807 - Throw an IllegalArgumentException if asked to create a merged region with invalid columns or rows, rather than writing out a corrupt file 43837 - [PATCH] Support for unicode NameRecords 43721 - [PATCH] Support for Chart Title Format records diff --git a/src/documentation/content/xdocs/hslf/how-to-shapes.xml b/src/documentation/content/xdocs/hslf/how-to-shapes.xml index df40776a53..36e4a11387 100644 --- a/src/documentation/content/xdocs/hslf/how-to-shapes.xml +++ b/src/documentation/content/xdocs/hslf/how-to-shapes.xml @@ -39,6 +39,7 @@
  • How to work with slide/shape background
  • How to create bulleted lists
  • Hyperlinks
  • +
  • Tables
  • Features @@ -387,6 +388,57 @@ }
    + +
    How to create tables + + //table data + String[][] data = { + {"INPUT FILE", "NUMBER OF RECORDS"}, + {"Item File", "11,559"}, + {"Vendor File", "300"}, + {"Purchase History File", "10,000"}, + {"Total # of requisitions", "10,200,038"} + }; + + SlideShow ppt = new SlideShow(); + + Slide slide = ppt.createSlide(); + //create a table of 5 rows and 2 columns + Table table = new Table(5, 2); + for (int i = 0; i < data.length; i++) { + for (int j = 0; j < data[i].length; j++) { + TableCell cell = table.getCell(i, j); + cell.setText(data[i][j]); + + RichTextRun rt = cell.getTextRun().getRichTextRuns()[0]; + rt.setFontName("Arial"); + rt.setFontSize(10); + + cell.setVerticalAlignment(TextBox.AnchorMiddle); + cell.setHorizontalAlignment(TextBox.AlignCenter); + } + } + + //set table borders + Line border = table.createBorder(); + border.setLineColor(Color.black); + border.setLineWidth(1.0); + table.setAllBorders(border); + + //set width of the 1st column + table.setColumnWidth(0, 300); + //set width of the 2nd column + table.setColumnWidth(1, 150); + + slide.addShape(table); + table.moveTo(100, 100); + + FileOutputStream out = new FileOutputStream("hslf-table.ppt"); + ppt.write(out); + out.close(); + + +
    diff --git a/src/documentation/content/xdocs/hssf/eval.xml b/src/documentation/content/xdocs/hssf/eval.xml index 548df78e76..d697eb082b 100644 --- a/src/documentation/content/xdocs/hssf/eval.xml +++ b/src/documentation/content/xdocs/hssf/eval.xml @@ -63,6 +63,8 @@ HSSFFormulaEvaluator evaluator = new HSSFFormulaEvaluator(sheet, wb); CellReference cellReference = new CellReference("B3"); HSSFRow row = sheet.getRow(cellReference.getRow()); HSSFCell cell = row.getCell(cellReference.getCol()); + +evaluator.setCurrentRow(row); HSSFFormulaEvaluator.CellValue cellValue = evaluator.evaluate(cell); switch (cellValue.getCellType()) { @@ -106,7 +108,7 @@ HSSFFormulaEvaluator evaluator = new HSSFFormulaEvaluator(sheet, wb); CellReference cellReference = new CellReference("B3"); HSSFRow row = sheet.getRow(cellReference.getRow()); HSSFCell cell = row.getCell(cellReference.getCol()); - +evaluator.setCurrentRow(row); if (cell!=null) { switch (evaluator.evaluateInCell(cell).getCellType()) { diff --git a/src/documentation/content/xdocs/hssf/quick-guide.xml b/src/documentation/content/xdocs/hssf/quick-guide.xml index 6dc4dc909b..ddbd447fd1 100644 --- a/src/documentation/content/xdocs/hssf/quick-guide.xml +++ b/src/documentation/content/xdocs/hssf/quick-guide.xml @@ -41,6 +41,7 @@
  • How to create cells
  • How to create date cells
  • Working with different types of cells
  • +
  • Iterate over rows and cells
  • Text Extraction
  • Aligning cells
  • Working with borders
  • @@ -234,6 +235,26 @@ fileOut.close(); + +
    Iterate over rows and cells (including Java 5 foreach loops) +

    Sometimes, you'd like to just iterate over all the rows in + a sheet, or all the cells in a row. If you are using Java + 5 or later, then this is especially handy, as it'll allow the + new foreach loop support to work.

    +

    Luckily, this is very easy. HSSFRow defines a + CellIterator inner class to handle iterating over + the cells (get one with a call to row.cellIterator()), + and HSSFSheet provides a rowIterator() method to + give an iterator over all the rows.

    + + HSSFSheet sheet = wb.getSheetAt(0); + for (HSSFRow row : sheet.rowIterator()) { + for (HSSFCell cell : row.cellIterator()) { + // Do something here + } + } + +
    Text Extraction

    For most text extraction requirements, the standard diff --git a/src/documentation/content/xdocs/index.xml b/src/documentation/content/xdocs/index.xml index 8070093965..45b27b0b09 100644 --- a/src/documentation/content/xdocs/index.xml +++ b/src/documentation/content/xdocs/index.xml @@ -31,7 +31,19 @@ -

    POI 3.0.1 Release +
    POI 3.0.2 BETA1 Release +

    The latest release of Apache POI is 3.0.2 BETA1 which was promoted to "Beta" on 04 December 2007. It contains a mixture of + new features and bug fixes, compared to 3.0.1. A full list of changes + is available in + the changelog, and + download + the source and binaries from your + local mirror. + The release is also available from the central Maven repository under Group ID "org.apache.poi". +

    +
    + +
    POI 3.0.1 Release

    The latest release of Apache POI (formerly Apache Jakarta POI), version 3.0.1, has now been released. It contains a mixture of new features and bug fixes, compared to 3.0. A full list of changes diff --git a/src/documentation/content/xdocs/status.xml b/src/documentation/content/xdocs/status.xml index e4ed1065f0..72761cf9c0 100644 --- a/src/documentation/content/xdocs/status.xml +++ b/src/documentation/content/xdocs/status.xml @@ -32,7 +32,17 @@ - + + Support for tables in HSLF + 43781 - Fix for extracting text from TextBoxes HSLF in + Improve JavaDocs relating to hssf font and fill colourings + 44095, 44097, 44099 - [PATCH] Support for Mid, Replace and Substitute excel functions + 44055 - [PATCH] Support for getting the from field from HSMF messages + 43551 - [PATCH] Support for 1904 date windowing in HSSF (previously only supported 1900 date windowing) + 41064 - [PATCH] Support for String continue records + 27511 - [PATCH] Support for data validation, via DVRecord and DVALRecord + + 43877 - Fix for handling mixed OBJ and CONTINUE records 39512 - Fix for handling mixed OBJ and CONTINUE records 43837 - [PATCH] Support for unicode NameRecords diff --git a/src/java/org/apache/poi/hssf/record/DVALRecord.java b/src/java/org/apache/poi/hssf/record/DVALRecord.java new file mode 100644 index 0000000000..858f525ca0 --- /dev/null +++ b/src/java/org/apache/poi/hssf/record/DVALRecord.java @@ -0,0 +1,157 @@ + +/* ==================================================================== + Copyright 2002-2004 Apache Software Foundation + + Licensed 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; + +import org.apache.poi.util.LittleEndian; + +/** + * Title: DVAL Record

    + * Description: used in data validation ; + * This record is the list header of all data validation records in the current sheet. + * @author Dragos Buleandra (dragos.buleandra@trade2b.ro) + * @version 2.0-pre + */ + +public class DVALRecord extends Record +{ + public final static short sid = 0x01B2; + + //unknown field ; it's size should be 10 + private short field_unknown = 0x0000; + + //Object ID of the drop down arrow object for list boxes ; + //in our case this will be always FFFF , until + //MSODrawingGroup and MSODrawing records are implemented + private int field_cbo_id = 0xFFFFFFFF; + + //Number of following DV records + //Default value is 1 + private int field_3_dv_no = 0x00000000; + + public DVALRecord() + { + } + + /** + * Constructs a DVAL record and sets its fields appropriately. + * + * @param in the RecordInputstream to read the record from + */ + + public DVALRecord(RecordInputStream in) + { + super(in); + } + + protected void validateSid(short id) + { + if (id != sid) + { + throw new RecordFormatException("NOT A valid DVAL RECORD"); + } + } + + protected void fillFields(RecordInputStream in) + { + for ( int i=0; i<5; i++) + { + this.field_unknown = in.readShort(); + } + this.field_cbo_id = in.readInt(); + this.field_3_dv_no = in.readInt(); + } + + /** + * set the object ID of the drop down arrow object for list boxes + * @param cboID - Object ID + */ + public void setObjectID(int cboID) + { + this.field_cbo_id = cboID; + } + + /** + * Set the number of following DV records + * @param dvNo - the DV records number + */ + public void setDVRecNo(int dvNo) + { + this.field_3_dv_no = dvNo; + } + + /** + * get Object ID of the drop down arrow object for list boxes + */ + public int getObjectID( ) + { + return this.field_cbo_id; + } + + /** + * Get number of following DV records + */ + public int getDVRecNo( ) + { + return this.field_3_dv_no; + } + + + public String toString() + { + StringBuffer buffer = new StringBuffer(); + + buffer.append("[DVAL]\n"); + buffer.append(" .comboObjectID = ").append(Integer.toHexString(this.getObjectID())).append("\n"); + buffer.append(" .DVRecordsNumber = ").append(Integer.toHexString(this.getDVRecNo())).append("\n"); + buffer.append("[/DVAL]\n"); + return buffer.toString(); + } + + public int serialize(int offset, byte [] data) + { + LittleEndian.putShort(data, 0 + offset, this.sid); + LittleEndian.putShort(data, 2 + offset, ( short)(this.getRecordSize()-4)); + for ( int i=0; i<5; i++) + { + LittleEndian.putShort(data, 4 + i*2 + offset, (short)this.field_unknown); + } + LittleEndian.putInt(data, 14 + offset, this.getObjectID()); + LittleEndian.putInt(data, 18 + offset, this.getDVRecNo()); + return getRecordSize(); + } + + //with 4 bytes header + public int getRecordSize() + { + return 22; + } + + public short getSid() + { + return this.sid; + } + + public Object clone() + { + DVALRecord rec = new DVALRecord(); + rec.field_unknown = this.field_unknown; + rec.field_cbo_id = this.field_cbo_id; + rec.field_3_dv_no = this.field_3_dv_no; + return rec; + } +} \ No newline at end of file diff --git a/src/java/org/apache/poi/hssf/record/DVRecord.java b/src/java/org/apache/poi/hssf/record/DVRecord.java new file mode 100644 index 0000000000..0bae009bd3 --- /dev/null +++ b/src/java/org/apache/poi/hssf/record/DVRecord.java @@ -0,0 +1,590 @@ +/* ==================================================================== + Copyright 2002-2004 Apache Software Foundation + + Licensed 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; + +import org.apache.poi.util.BitField; +import org.apache.poi.util.LittleEndian; +import org.apache.poi.util.StringUtil; +import org.apache.poi.hssf.util.HSSFCellRangeAddress; +import org.apache.poi.hssf.record.formula.Ptg; + +import java.io.IOException; +import java.util.Stack; +import java.util.Hashtable; +import java.util.Enumeration; + +/** + * Title: DV Record

    + * Description: This record stores data validation settings and a list of cell ranges + * which contain these settings. The data validation settings of a sheet + * are stored in a sequential list of DV records. This list is followed by + * DVAL record(s) + * @author Dragos Buleandra (dragos.buleandra@trade2b.ro) + * @version 2.0-pre + */ +public class DVRecord extends Record +{ + public final static short sid = 0x01BE; + + /** + * Option flags + */ + private int field_option_flags; + + /** + * Title of the prompt box + */ + private String field_title_prompt; + + /** + * Title of the error box + */ + private String field_title_error; + + /** + * Text of the prompt box + */ + private String field_text_prompt; + + /** + * Text of the error box + */ + private String field_text_error; + + /** + * Size of the formula data for first condition + */ + private short field_size_first_formula; + + /** + * Not used + */ + private short field_not_used_1 = 0x3FE0; + + /** + * Formula data for first condition (RPN token array without size field) + */ + private Stack field_rpn_token_1 ; + + /** + * Size of the formula data for second condition + */ + private short field_size_sec_formula; + + /** + * Not used + */ + private short field_not_used_2 = 0x0000; + + /** + * Formula data for second condition (RPN token array without size field) + */ + private Stack field_rpn_token_2 ; + + /** + * Cell range address list with all affected ranges + */ + private HSSFCellRangeAddress field_regions; + + public static final Integer STRING_PROMPT_TITLE = new Integer(0); + public static final Integer STRING_ERROR_TITLE = new Integer(1); + public static final Integer STRING_PROMPT_TEXT = new Integer(2); + public static final Integer STRING_ERROR_TEXT = new Integer(3); + private Hashtable _hash_strings ; + + /** + * Option flags field + * @see org.apache.poi.hssf.util.HSSFDataValidation utility class + */ + private BitField opt_data_type = new BitField(0x0000000F); + 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_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); + + public DVRecord() + { + } + + /** + * Constructs a DV record and sets its fields appropriately. + * + * @param in the RecordInputstream to read the record from + */ + + public DVRecord(RecordInputStream in) + { + super(in); + } + + protected void validateSid(short id) + { + if (id != sid) + { + throw new RecordFormatException("NOT a valid DV RECORD"); + } + } + + protected void fillFields(RecordInputStream in) + { + field_rpn_token_1 = new Stack(); + field_rpn_token_2 = new Stack(); + + this.field_option_flags = in.readInt(); + this._hash_strings = new Hashtable(4); + + StringHandler strHandler_prompt_title = new StringHandler( in ); + this.field_title_prompt = strHandler_prompt_title.getStringData(); + this._hash_strings.put(DVRecord.STRING_PROMPT_TITLE, strHandler_prompt_title); + + StringHandler strHandler_error_title = new StringHandler( in ); + this.field_title_error = strHandler_error_title.getStringData(); + this._hash_strings.put(DVRecord.STRING_ERROR_TITLE, strHandler_error_title); + + StringHandler strHandler_prompt_text = new StringHandler( in ); + this.field_text_prompt = strHandler_prompt_text.getStringData(); + this._hash_strings.put(DVRecord.STRING_PROMPT_TEXT, strHandler_prompt_text); + + StringHandler strHandler_error_text = new StringHandler( in ); + this.field_text_error = strHandler_error_text.getStringData(); + this._hash_strings.put(DVRecord.STRING_ERROR_TEXT, strHandler_error_text); + + this.field_size_first_formula = in.readShort(); + this.field_not_used_1 = in.readShort(); + + //read first formula data condition + // Not sure if this was needed or not... +// try { +// in.skip(this.field_size_first_formula); +// } catch(IOException e) { throw new IllegalStateException(e); } + + int token_pos = 0; + while (token_pos < this.field_size_first_formula) + { + Ptg ptg = Ptg.createPtg(in); + token_pos += ptg.getSize(); + field_rpn_token_1.push(ptg); + } + + this.field_size_sec_formula = in.readShort(); + this.field_not_used_2 = in.readShort(); + + //read sec formula data condition + // Not sure if this was needed or not... + try { + in.skip(this.field_size_sec_formula); + } catch(IOException e) { throw new IllegalStateException(e); } + + token_pos = 0; + while (token_pos < this.field_size_sec_formula) + { + Ptg ptg = Ptg.createPtg(in); + token_pos += ptg.getSize(); + field_rpn_token_2.push(ptg); + } + + //read cell range address list with all affected ranges + this.field_regions = new HSSFCellRangeAddress(in); + } + + + // --> start option flags + /** + * set the condition data type + * @param type - condition data type + * @see org.apache.poi.hssf.util.HSSFDataValidation utility class + */ + public void setDataType(int type) + { + this.field_option_flags = this.opt_data_type.setValue(this.field_option_flags, type); + } + + /** + * get the condition data type + * @return the condition data type + * @see org.apache.poi.hssf.util.HSSFDataValidation utility class + */ + public int getDataType() + { + return this.opt_data_type.getValue(this.field_option_flags); + } + + /** + * set the condition error style + * @param type - condition error style + * @see org.apache.poi.hssf.util.HSSFDataValidation utility class + */ + public void setErrorStyle(int style) + { + this.field_option_flags = this.opt_error_style.setValue(this.field_option_flags, style); + } + + /** + * get the condition error style + * @return the condition error style + * @see org.apache.poi.hssf.util.HSSFDataValidation utility class + */ + public int getErrorStyle() + { + return this.opt_error_style.getValue(this.field_option_flags); + } + + /** + * set if in list validations the string list is explicitly given in the formula + * @param type - true if in list validations the string list is explicitly given in the formula; false otherwise + * @see org.apache.poi.hssf.util.HSSFDataValidation utility class + */ + public void setListExplicitFormula(boolean explicit) + { + this.field_option_flags = this.opt_string_list_formula.setBoolean(this.field_option_flags, explicit); + } + + /** + * return true if in list validations the string list is explicitly given in the formula, false otherwise + * @return true if in list validations the string list is explicitly given in the formula, false otherwise + * @see org.apache.poi.hssf.util.HSSFDataValidation utility class + */ + public boolean getListExplicitFormula() + { + return (this.opt_string_list_formula.isSet(this.field_option_flags)); + } + + /** + * set if empty values are allowed in cells + * @param type - true if empty values are allowed in cells, false otherwise + * @see org.apache.poi.hssf.util.HSSFDataValidation utility class + */ + public void setEmptyCellAllowed(boolean allowed) + { + this.field_option_flags = this.opt_empty_cell_allowed.setBoolean(this.field_option_flags, allowed); + } + + /** + * return true if empty values are allowed in cells, false otherwise + * @return if empty values are allowed in cells, false otherwise + * @see org.apache.poi.hssf.util.HSSFDataValidation utility class + */ + public boolean getEmptyCellAllowed() + { + return (this.opt_empty_cell_allowed.isSet(this.field_option_flags)); + } + + /** + * 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 + * @see org.apache.poi.hssf.util.HSSFDataValidation utility class + */ + public void setSurppresDropdownArrow(boolean surppress) + { + this.field_option_flags = this.opt_surppres_dropdown_arrow.setBoolean(this.field_option_flags, surppress); + } + + /** + * 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 + * @see org.apache.poi.hssf.util.HSSFDataValidation utility class + */ + public boolean getSurppresDropdownArrow() + { + return (this.opt_surppres_dropdown_arrow.isSet(this.field_option_flags)); + } + + /** + * set if a prompt window should appear when cell is selected + * @param type - true if a prompt window should appear when cell is selected, false otherwise + * @see org.apache.poi.hssf.util.HSSFDataValidation utility class + */ + public void setShowPromptOnCellSelected(boolean show) + { + this.field_option_flags = this.opt_show_prompt_on_cell_selected.setBoolean(this.field_option_flags, show); + } + + /** + * return true if a prompt window should appear when cell is selected, false otherwise + * @return if a prompt window should appear when cell is selected, false otherwise + * @see org.apache.poi.hssf.util.HSSFDataValidation utility class + */ + public boolean getShowPromptOnCellSelected() + { + return (this.opt_show_prompt_on_cell_selected.isSet(this.field_option_flags)); + } + + /** + * set if an error window should appear when an invalid value is entered in the cell + * @param type - true if an error window should appear when an invalid value is entered in the cell, false otherwise + * @see org.apache.poi.hssf.util.HSSFDataValidation utility class + */ + public void setShowErrorOnInvalidValue(boolean show) + { + this.field_option_flags = this.opt_show_error_on_invalid_value.setBoolean(this.field_option_flags, show); + } + + /** + * return true if an error window should appear when an invalid value is entered in the cell, false otherwise + * @return if an error window should appear when an invalid value is entered in the cell, false otherwise + * @see org.apache.poi.hssf.util.HSSFDataValidation utility class + */ + public boolean getShowErrorOnInvalidValue() + { + return (this.opt_show_error_on_invalid_value.isSet(this.field_option_flags)); + } + + /** + * set the condition operator + * @param type - condition operator + * @see org.apache.poi.hssf.util.HSSFDataValidation utility class + */ + public void setConditionOperator(int operator) + { + this.field_option_flags = this.opt_condition_operator.setValue(this.field_option_flags, operator); + } + + /** + * get the condition operator + * @return the condition operator + * @see org.apache.poi.hssf.util.HSSFDataValidation utility class + */ + public int getConditionOperator() + { + return this.opt_condition_operator.getValue(this.field_option_flags); + } + // <-- end option flags + + public void setFirstFormulaRPN( Stack rpn ) + { + this.field_rpn_token_1 = rpn; + } + + public void setFirstFormulaSize( short size ) + { + this.field_size_first_formula = size; + } + + public void setSecFormulaRPN( Stack rpn ) + { + this.field_rpn_token_2 = rpn; + } + + public void setSecFormulaSize( short size ) + { + this.field_size_sec_formula = size; + } + + public void setStringField( Integer type, String str_data ) + { + if ( this._hash_strings == null ) + { + this._hash_strings = new Hashtable(); + } + StringHandler strHandler = new StringHandler(); + if ( str_data == null ) + { + str_data = ""; + } + else + { + strHandler.setStringLength(str_data.length()); + } + strHandler.setStringData(str_data); + + strHandler.setUnicodeFlag((byte)0x00); + this._hash_strings.put( type, strHandler); + } + + public String getStringField( Integer type ) + { + return ((StringHandler)this._hash_strings.get(type)).getStringData(); + } + + public void setCellRangeAddress( HSSFCellRangeAddress range ) + { + this.field_regions = range; + } + + public HSSFCellRangeAddress getCellRangeAddress( ) + { + return this.field_regions; + } + + /** + * gets the option flags field. + * @return options - the option flags field + */ + public int getOptionFlags() + { + return this.field_option_flags; + } + + public String toString() + { + /** @todo DVRecord string representation */ + StringBuffer buffer = new StringBuffer(); + + return buffer.toString(); + } + + public int serialize(int offset, byte [] data) + { + int size = this.getRecordSize(); + LittleEndian.putShort(data, 0 + offset, sid); + LittleEndian.putShort(data, 2 + offset, ( short ) (size-4)); + + int pos = 4; + LittleEndian.putInt(data, pos + offset, this.getOptionFlags()); + pos += 4; + pos += ((StringHandler)this._hash_strings.get( DVRecord.STRING_PROMPT_TITLE )).serialize(pos+offset, data); + pos += ((StringHandler)this._hash_strings.get( DVRecord.STRING_ERROR_TITLE )).serialize(pos+offset, data); + pos += ((StringHandler)this._hash_strings.get( DVRecord.STRING_PROMPT_TEXT )).serialize(pos+offset, data); + pos += ((StringHandler)this._hash_strings.get( DVRecord.STRING_ERROR_TEXT )).serialize(pos+offset, data); + LittleEndian.putShort(data, offset+pos, this.field_size_first_formula); + pos += 2; + LittleEndian.putShort(data, offset+pos, this.field_not_used_1); + pos += 2; + + for (int k = 0; k < this.field_rpn_token_1.size(); k++) + { + Ptg ptg = ( Ptg ) this.field_rpn_token_1.get(k); + ptg.writeBytes(data, pos+offset); + pos += ptg.getSize(); + } + + LittleEndian.putShort(data, offset+pos, this.field_size_sec_formula); + pos += 2; + LittleEndian.putShort(data, offset+pos, this.field_not_used_2); + pos += 2; + if ( this.field_size_sec_formula > 0 ) + { + for (int k = 0; k < this.field_rpn_token_2.size(); k++) + { + Ptg ptg = ( Ptg ) this.field_rpn_token_2.get(k); + ptg.writeBytes(data, pos+offset); + pos += ptg.getSize(); + } + } + this.field_regions.serialize(pos+offset, data); + return size; + } + + public int getRecordSize() + { + int size = 4+4+2+2+2+2;//header+options_field+first_formula_size+first_unused+sec_formula_size+sec+unused; + if ( this._hash_strings != null ) + { + Enumeration enum_keys = this._hash_strings.keys(); + while ( enum_keys.hasMoreElements() ) + { + size += ((StringHandler)this._hash_strings.get( (Integer)enum_keys.nextElement() )).getSize(); + } + } + size += this.field_size_first_formula+ this.field_size_sec_formula; + size += this.field_regions.getSize(); + return size; + } + + public short getSid() + { + return this.sid; + } + + /**@todo DVRecord = Serializare */ + + private class StringHandler + { + private int _string_length = 0x0001; + private byte _string_unicode_flag = 0x00; + private String _string_data = "0x00"; + private int _start_offset; + private int _end_offset; + + StringHandler() + { + + } + + StringHandler(RecordInputStream in) + { + this.fillFields(in); + } + + protected void fillFields(RecordInputStream in) + { + this._string_length = in.readUShort(); + this._string_unicode_flag = in.readByte(); + if (this._string_unicode_flag == 1) + { + this._string_data = in.readUnicodeLEString(this._string_length); + } + else + { + this._string_data = in.readCompressedUnicode(this._string_length); + } + } + + private void setStringData( String string_data ) + { + this._string_data = string_data; + } + + private String getStringData() + { + return this._string_data; + } + + private int getEndOffset() + { + return this._end_offset; + } + + public int serialize( int offset, byte[] data ) + { + LittleEndian.putUShort(data, offset, this._string_length ); + data[2 + offset] = this._string_unicode_flag; + if (this._string_unicode_flag == 1) + { + StringUtil.putUnicodeLE(this._string_data, data, 3 + offset); + } + else + { + StringUtil.putCompressedUnicode(this._string_data, data, 3 + offset); + } + return getSize(); + } + + private void setUnicodeFlag( byte flag ) + { + this._string_unicode_flag = flag; + } + + private void setStringLength( int len ) + { + this._string_length = len; + } + + private int getStringByteLength() + { + return (this._string_unicode_flag == 1) ? this._string_length * 2 : this._string_length; + } + + public int getSize() + { + return 2 + 1 + getStringByteLength(); + } + } +} diff --git a/src/java/org/apache/poi/hssf/record/RecordFactory.java b/src/java/org/apache/poi/hssf/record/RecordFactory.java index 927d5f08be..cf705a316d 100644 --- a/src/java/org/apache/poi/hssf/record/RecordFactory.java +++ b/src/java/org/apache/poi/hssf/record/RecordFactory.java @@ -75,7 +75,8 @@ public class RecordFactory HorizontalPageBreakRecord.class, VerticalPageBreakRecord.class, WriteProtectRecord.class, FilePassRecord.class, PaneRecord.class, NoteRecord.class, ObjectProtectRecord.class, ScenarioProtectRecord.class, - FileSharingRecord.class, ChartTitleFormatRecord.class + FileSharingRecord.class, ChartTitleFormatRecord.class, + DVRecord.class, DVALRecord.class }; } private static Map recordsMap = recordsToMap(records); @@ -146,6 +147,9 @@ public class RecordFactory } else if (record.getSid() == ContinueRecord.sid && (lastRecord instanceof DrawingGroupRecord)) { ((DrawingGroupRecord)lastRecord).processContinueRecord(((ContinueRecord)record).getData()); + } else if (record.getSid() == ContinueRecord.sid && + (lastRecord instanceof StringRecord)) { + ((StringRecord)lastRecord).processContinueRecord(((ContinueRecord)record).getData()); } else if (record.getSid() == ContinueRecord.sid) { if (lastRecord instanceof UnknownRecord) { //Gracefully handle records that we dont know about, diff --git a/src/java/org/apache/poi/hssf/record/StringRecord.java b/src/java/org/apache/poi/hssf/record/StringRecord.java index a880d7235b..b3a42aaba4 100644 --- a/src/java/org/apache/poi/hssf/record/StringRecord.java +++ b/src/java/org/apache/poi/hssf/record/StringRecord.java @@ -83,6 +83,14 @@ public class StringRecord field_3_string = StringUtil.getFromCompressedUnicode(data, 0, field_1_string_length); } } + + public void processContinueRecord(byte[] data) { + if(isUnCompressedUnicode()) { + field_3_string += StringUtil.getFromUnicodeLE(data, 0, field_1_string_length - field_3_string.length()); + } else { + field_3_string += StringUtil.getFromCompressedUnicode(data, 0, field_1_string_length - field_3_string.length()); + } + } public boolean isInValueSection() { diff --git a/src/java/org/apache/poi/hssf/usermodel/HSSFCell.java b/src/java/org/apache/poi/hssf/usermodel/HSSFCell.java index ac3943da46..9cc4550719 100644 --- a/src/java/org/apache/poi/hssf/usermodel/HSSFCell.java +++ b/src/java/org/apache/poi/hssf/usermodel/HSSFCell.java @@ -521,7 +521,7 @@ public class HSSFCell */ public void setCellValue(Date value) { - setCellValue(HSSFDateUtil.getExcelDate(value)); + setCellValue(HSSFDateUtil.getExcelDate(value, this.book.isUsing1904DateWindowing())); } /** diff --git a/src/java/org/apache/poi/hssf/usermodel/HSSFCellStyle.java b/src/java/org/apache/poi/hssf/usermodel/HSSFCellStyle.java index e2725937fa..cdea9ee5be 100644 --- a/src/java/org/apache/poi/hssf/usermodel/HSSFCellStyle.java +++ b/src/java/org/apache/poi/hssf/usermodel/HSSFCellStyle.java @@ -294,10 +294,24 @@ public class HSSFCellStyle format.setFontIndex(fontindex); } + /** + * gets the index of the font for this style + * @see org.apache.poi.hssf.usermodel.HSSFWorkbook#getFontAt(short) + */ public short getFontIndex() { return format.getFontIndex(); } + + /** + * gets the font for this style + * @param parentWorkbook The HSSFWorkbook that this style belongs to + * @see org.apache.poi.hssf.usermodel.HSSFCellStyle#getFontIndex() + * @see org.apache.poi.hssf.usermodel.HSSFWorkbook#getFontAt(short) + */ + public HSSFFont getFont(HSSFWorkbook parentWorkbook) { + return parentWorkbook.getFontAt(getFontIndex()); + } /** * set the cell's using this style to be hidden @@ -689,7 +703,6 @@ public class HSSFCellStyle * @see #BORDER_MEDIUM_DASH_DOT_DOT * @see #BORDER_SLANTED_DASH_DOT */ - public short getBorderBottom() { return format.getBorderBottom(); @@ -697,9 +710,8 @@ public class HSSFCellStyle /** * set the color to use for the left border - * @param color + * @param color The index of the color definition */ - public void setLeftBorderColor(short color) { format.setLeftBorderPaletteIdx(color); @@ -707,9 +719,9 @@ public class HSSFCellStyle /** * get the color to use for the left border - * @return color + * @see org.apache.poi.hssf.usermodel.HSSFPalette#getColor(short) + * @param color The index of the color definition */ - public short getLeftBorderColor() { return format.getLeftBorderPaletteIdx(); @@ -717,9 +729,8 @@ public class HSSFCellStyle /** * set the color to use for the right border - * @param color + * @param color The index of the color definition */ - public void setRightBorderColor(short color) { format.setRightBorderPaletteIdx(color); @@ -727,9 +738,9 @@ public class HSSFCellStyle /** * get the color to use for the left border - * @return color + * @see org.apache.poi.hssf.usermodel.HSSFPalette#getColor(short) + * @param color The index of the color definition */ - public short getRightBorderColor() { return format.getRightBorderPaletteIdx(); @@ -737,9 +748,8 @@ public class HSSFCellStyle /** * set the color to use for the top border - * @param color + * @param color The index of the color definition */ - public void setTopBorderColor(short color) { format.setTopBorderPaletteIdx(color); @@ -747,9 +757,9 @@ public class HSSFCellStyle /** * get the color to use for the top border - * @return color + * @see org.apache.poi.hssf.usermodel.HSSFPalette#getColor(short) + * @param color The index of the color definition */ - public short getTopBorderColor() { return format.getTopBorderPaletteIdx(); @@ -757,9 +767,8 @@ public class HSSFCellStyle /** * set the color to use for the bottom border - * @param color + * @param color The index of the color definition */ - public void setBottomBorderColor(short color) { format.setBottomBorderPaletteIdx(color); @@ -767,9 +776,9 @@ public class HSSFCellStyle /** * get the color to use for the left border - * @return color + * @see org.apache.poi.hssf.usermodel.HSSFPalette#getColor(short) + * @param color The index of the color definition */ - public short getBottomBorderColor() { return format.getBottomBorderPaletteIdx(); @@ -871,9 +880,9 @@ public class HSSFCellStyle /** * get the background fill color + * @see org.apache.poi.hssf.usermodel.HSSFPalette#getColor(short) * @return fill color */ - public short getFillBackgroundColor() { short result = format.getFillBackground(); @@ -889,7 +898,6 @@ public class HSSFCellStyle * Note: Ensure Foreground color is set prior to background color. * @param bg color */ - public void setFillForegroundColor(short bg) { format.setFillForeground(bg); @@ -898,12 +906,11 @@ public class HSSFCellStyle /** * get the foreground fill color + * @see org.apache.poi.hssf.usermodel.HSSFPalette#getColor(short) * @return fill color */ - public short getFillForegroundColor() { return format.getFillForeground(); } - } diff --git a/src/java/org/apache/poi/hssf/usermodel/HSSFClientAnchor.java b/src/java/org/apache/poi/hssf/usermodel/HSSFClientAnchor.java index 04a0f57328..4d9098d75a 100644 --- a/src/java/org/apache/poi/hssf/usermodel/HSSFClientAnchor.java +++ b/src/java/org/apache/poi/hssf/usermodel/HSSFClientAnchor.java @@ -82,8 +82,8 @@ public class HSSFClientAnchor */ public float getAnchorHeightInPoints(HSSFSheet sheet ) { - int y1 = Math.min( getDy1(), getDy2() ); - int y2 = Math.max( getDy1(), getDy2() ); + int y1 = getDy1(); + int y2 = getDy2(); int row1 = Math.min( getRow1(), getRow2() ); int row2 = Math.max( getRow1(), getRow2() ); diff --git a/src/java/org/apache/poi/hssf/usermodel/HSSFDateUtil.java b/src/java/org/apache/poi/hssf/usermodel/HSSFDateUtil.java index fc9ac3a3b3..fb3a92df86 100644 --- a/src/java/org/apache/poi/hssf/usermodel/HSSFDateUtil.java +++ b/src/java/org/apache/poi/hssf/usermodel/HSSFDateUtil.java @@ -35,6 +35,8 @@ import java.util.GregorianCalendar; * @author Glen Stampoultzis (glens at apache.org) * @author Dan Sherman (dsherman at isisph.com) * @author Hack Kampbjorn (hak at 2mba.dk) + * @author Alex Jacoby (ajacoby at gmail.com) + * @author Pavel Krupets (pkrupets at palmtreebusiness dot com) */ public class HSSFDateUtil @@ -54,19 +56,26 @@ public class HSSFDateUtil * @return Excel representation of Date (-1 if error - test for error by checking for less than 0.1) * @param date the Date */ - - public static double getExcelDate(Date date) - { + public static double getExcelDate(Date date) { + return getExcelDate(date, false); + } + /** + * Given a Date, converts it into a double representing its internal Excel representation, + * which is the number of days since 1/1/1900. Fractional days represent hours, minutes, and seconds. + * + * @return Excel representation of Date (-1 if error - test for error by checking for less than 0.1) + * @param date the Date + * @param use1904windowing Should 1900 or 1904 date windowing be used? + */ + public static double getExcelDate(Date date, boolean use1904windowing) { Calendar calStart = new GregorianCalendar(); - - calStart.setTime( - date); // If date includes hours, minutes, and seconds, set them to 0 - if (calStart.get(Calendar.YEAR) < 1900) + calStart.setTime(date); // If date includes hours, minutes, and seconds, set them to 0 + + if ((!use1904windowing && calStart.get(Calendar.YEAR) < 1900) || + (use1904windowing && calStart.get(Calendar.YEAR) < 1904)) { return BAD_DATE; - } - else - { + } else { // Because of daylight time saving we cannot use // date.getTime() - calStart.getTimeInMillis() // as the difference in milliseconds between 00:00 and 04:00 @@ -80,32 +89,39 @@ public class HSSFDateUtil ) * 1000 + calStart.get(Calendar.MILLISECOND) ) / ( double ) DAY_MILLISECONDS; calStart = dayStart(calStart); - - double value = fraction + absoluteDay(calStart); - if (value >= 60) { - value += 1; + double value = fraction + absoluteDay(calStart, use1904windowing); + + if (!use1904windowing && value >= 60) { + value++; + } else if (use1904windowing) { + value--; } return value; } } - + /** - * Given a excel date, converts it into a Date. - * Assumes 1900 date windowing. + * Given an Excel date with using 1900 date windowing, and + * converts it to a java.util.Date. * - * @param date the Excel Date - * - * @return Java representation of a date (null if error) - * @see #getJavaDate(double,boolean) + * NOTE: If the default TimeZone in Java uses Daylight + * Saving Time then the conversion back to an Excel date may not give + * the same value, that is the comparison + * excelDate == getExcelDate(getJavaDate(excelDate,false)) + * is not always true. For example if default timezone is + * Europe/Copenhagen, on 2004-03-28 the minute after + * 01:59 CET is 03:00 CEST, if the excel date represents a time between + * 02:00 and 03:00 then it is converted to past 03:00 summer time + * + * @param date The Excel date. + * @return Java representation of the date, or null if date is not a valid Excel date + * @see java.util.TimeZone */ - - public static Date getJavaDate(double date) - { - return getJavaDate(date,false); + public static Date getJavaDate(double date) { + return getJavaDate(date, false); } - /** * Given an Excel date with either 1900 or 1904 date windowing, * converts it to a java.util.Date. @@ -142,7 +158,7 @@ public class HSSFDateUtil GregorianCalendar calendar = new GregorianCalendar(startYear,0, wholeDays + dayAdjust); int millisecondsInDay = (int)((date - Math.floor(date)) * - (double) DAY_MILLISECONDS + 0.5); + DAY_MILLISECONDS + 0.5); calendar.set(GregorianCalendar.MILLISECOND, millisecondsInDay); return calendar.getTime(); } @@ -238,7 +254,7 @@ public class HSSFDateUtil * Check if a cell contains a date * Since dates are stored internally in Excel as double values * we infer it is a date if it is formatted as such. - * @see #isADateFormat(int,string) + * @see #isADateFormat(int, String) * @see #isInternalDateFormat(int) */ public static boolean isCellDateFormatted(HSSFCell cell) { @@ -259,7 +275,7 @@ public class HSSFDateUtil * excel date formats. * As Excel stores a great many of its dates in "non-internal" * date formats, you will not normally want to use this method. - * @see #isADateFormat(int,string) + * @see #isADateFormat(int,String) * @see #isInternalDateFormat(int) */ public static boolean isCellInternalDateFormatted(HSSFCell cell) { @@ -296,10 +312,10 @@ public class HSSFDateUtil * @exception IllegalArgumentException if date is invalid */ - private static int absoluteDay(Calendar cal) + static int absoluteDay(Calendar cal, boolean use1904windowing) { return cal.get(Calendar.DAY_OF_YEAR) - + daysInPriorYears(cal.get(Calendar.YEAR)); + + daysInPriorYears(cal.get(Calendar.YEAR), use1904windowing); } /** @@ -307,14 +323,14 @@ public class HSSFDateUtil * * @return days number of days in years prior to yr. * @param yr a year (1900 < yr < 4000) + * @param use1904windowing * @exception IllegalArgumentException if year is outside of range. */ - private static int daysInPriorYears(int yr) + private static int daysInPriorYears(int yr, boolean use1904windowing) { - if (yr < 1900) { - throw new IllegalArgumentException( - "'year' must be 1900 or greater"); + if ((!use1904windowing && yr < 1900) || (use1904windowing && yr < 1900)) { + throw new IllegalArgumentException("'year' must be 1900 or greater"); } int yr1 = yr - 1; @@ -323,7 +339,7 @@ public class HSSFDateUtil + yr1 / 400 // plus years divisible by 400 - 460; // leap days in previous 1900 years - return 365 * (yr - 1900) + leapDays; + return 365 * (yr - (use1904windowing ? 1904 : 1900)) + leapDays; } // set HH:MM:SS fields of cal to 00:00:00:000 diff --git a/src/java/org/apache/poi/hssf/usermodel/HSSFFont.java b/src/java/org/apache/poi/hssf/usermodel/HSSFFont.java index 852e15ee28..cfaa5e4f48 100644 --- a/src/java/org/apache/poi/hssf/usermodel/HSSFFont.java +++ b/src/java/org/apache/poi/hssf/usermodel/HSSFFont.java @@ -281,8 +281,8 @@ public class HSSFFont * @return color to use * @see #COLOR_NORMAL * @see #COLOR_RED + * @see org.apache.poi.hssf.usermodel.HSSFPalette#getColor(short) */ - public short getColor() { return font.getColorPaletteIndex(); diff --git a/src/java/org/apache/poi/hssf/usermodel/HSSFSheet.java b/src/java/org/apache/poi/hssf/usermodel/HSSFSheet.java index 91098c2dcb..b52fa1e5b2 100644 --- a/src/java/org/apache/poi/hssf/usermodel/HSSFSheet.java +++ b/src/java/org/apache/poi/hssf/usermodel/HSSFSheet.java @@ -23,9 +23,13 @@ package org.apache.poi.hssf.usermodel; import org.apache.poi.ddf.EscherRecord; +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.formula.Ptg; +import org.apache.poi.hssf.util.HSSFCellRangeAddress; +import org.apache.poi.hssf.util.HSSFDataValidation; import org.apache.poi.hssf.util.Region; import org.apache.poi.hssf.util.PaneInformation; import org.apache.poi.util.POILogFactory; @@ -35,6 +39,7 @@ import java.io.PrintWriter; import java.util.ArrayList; import java.util.Iterator; import java.util.List; +import java.util.Stack; import java.util.TreeMap; import java.text.AttributedString; import java.text.NumberFormat; @@ -353,6 +358,94 @@ public class HSSFSheet { return lastrow; } + + /** + * Creates a data validation object + * @param obj_validation 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+";",book); + 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]); + } + 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+";",book); + 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); + + //add dv record + eofLoc = sheet.findFirstRecordLocBySid( EOFRecord.sid ); + sheet.getRecords().add( eofLoc, dvRecord ); + } /** * Get the visibility state for a given column. diff --git a/src/java/org/apache/poi/hssf/util/HSSFCellRangeAddress.java b/src/java/org/apache/poi/hssf/util/HSSFCellRangeAddress.java new file mode 100644 index 0000000000..438f5e5968 --- /dev/null +++ b/src/java/org/apache/poi/hssf/util/HSSFCellRangeAddress.java @@ -0,0 +1,253 @@ +/* ==================================================================== + Copyright 2002-2004 Apache Software Foundation + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +==================================================================== */ + +package org.apache.poi.hssf.util; + +import org.apache.poi.hssf.record.RecordInputStream; +import org.apache.poi.util.LittleEndian; +import java.util.ArrayList; + +/** + *

    Title: HSSFCellRangeAddress

    + *

    Description: + * Implementation of the cell range address lists,like is described in + * OpenOffice.org's Excel Documentation . + * In BIFF8 there is a common way to store absolute cell range address + * lists in several records (not formulas). A cell range address list + * consists of a field with the number of ranges and the list of the range + * addresses. Each cell range address (called an ADDR structure) contains + * 4 16-bit-values.

    + *

    Copyright: Copyright (c) 2004

    + *

    Company:

    + * @author Dragos Buleandra (dragos.buleandra@trade2b.ro) + * @version 2.0-pre + */ + +public class HSSFCellRangeAddress +{ + /** + * Number of following ADDR structures + */ + private short field_addr_number; + + /** + * List of ADDR structures. Each structure represents a cell range + */ + private ArrayList field_regions_list; + + public HSSFCellRangeAddress() + { + + } + + /** + * Construct a new HSSFCellRangeAddress object and sets its fields appropriately . + * Even this isn't an Excel record , I kept the same behavior for reading/writing + * the object's data as for a regular record . + * + * @param in the RecordInputstream to read the record from + */ + public HSSFCellRangeAddress(RecordInputStream in) + { + this.fillFields(in); + } + + public void fillFields(RecordInputStream in) + { + this.field_addr_number = in.readShort(); + this.field_regions_list = new ArrayList(this.field_addr_number); + + for (int k = 0; k < this.field_addr_number; k++) + { + short first_row = in.readShort(); + short first_col = in.readShort(); + short last_row = in.readShort(); + short last_col = in.readShort(); + + AddrStructure region = new AddrStructure(first_row, first_col, last_row, last_col); + this.field_regions_list.add(region); + } + } + + /** + * Get the number of following ADDR structures. + * The number of this structures is automatically set when reading an Excel file + * and/or increased when you manually add a new ADDR structure . + * This is the reason there isn't a set method for this field . + * @return number of ADDR structures + */ + public short getADDRStructureNumber() + { + return this.field_addr_number; + } + + /** + * Add an ADDR structure . + * @param first_row - the upper left hand corner's row + * @param first_col - the upper left hand corner's col + * @param last_row - the lower right hand corner's row + * @param last_col - the lower right hand corner's col + * @return the index of this ADDR structure + */ + public int addADDRStructure(short first_row, short first_col, short last_row, short last_col) + { + if (this.field_regions_list == null) + { + //just to be sure :-) + this.field_addr_number= 0; + this.field_regions_list = new ArrayList(10); + } + AddrStructure region = new AddrStructure(first_row, last_row, first_col, last_col); + + this.field_regions_list.add(region); + this.field_addr_number++; + return this.field_addr_number; + } + + /** + * Remove the ADDR structure stored at the passed in index + * @param index The ADDR structure's index + */ + public void removeADDRStructureAt(int index) + { + this.field_regions_list.remove(index); + this.field_addr_number--; + } + + /** + * return the ADDR structure at the given index. + * @return AddrStructure representing + */ + public AddrStructure getADDRStructureAt(int index) + { + return ( AddrStructure ) this.field_regions_list.get(index); + } + + public int serialize(int offset, byte [] data) + { + int pos = 2; + + LittleEndian.putShort(data, offset, this.getADDRStructureNumber()); + for (int k = 0; k < this.getADDRStructureNumber(); k++) + { + AddrStructure region = this.getADDRStructureAt(k); + LittleEndian.putShort(data, offset + pos, region.getFirstRow()); + pos += 2; + LittleEndian.putShort(data, offset + pos, region.getLastRow()); + pos += 2; + LittleEndian.putShort(data, offset + pos, region.getFirstColumn()); + pos += 2; + LittleEndian.putShort(data, offset + pos, region.getLastColumn()); + pos += 2; + } + return this.getSize(); + } + + public int getSize() + { + return 2 + this.field_addr_number*8; + } + + public class AddrStructure + { + private short _first_row; + private short _first_col; + private short _last_row; + private short _last_col; + + public AddrStructure(short first_row, short last_row, short first_col, short last_col) + { + this._first_row = first_row; + this._last_row = last_row; + this._first_col = first_col; + this._last_col = last_col; + } + + /** + * get the upper left hand corner column number + * @return column number for the upper left hand corner + */ + public short getFirstColumn() + { + return this._first_col; + } + + /** + * get the upper left hand corner row number + * @return row number for the upper left hand corner + */ + public short getFirstRow() + { + return this._first_row; + } + + /** + * get the lower right hand corner column number + * @return column number for the lower right hand corner + */ + public short getLastColumn() + { + return this._last_col; + } + + /** + * get the lower right hand corner row number + * @return row number for the lower right hand corner + */ + public short getLastRow() + { + return this._last_row; + } + + /** + * set the upper left hand corner column number + * @param this._first_col column number for the upper left hand corner + */ + public void setFirstColumn(short first_col) + { + this._first_col = first_col; + } + + /** + * set the upper left hand corner row number + * @param rowFrom row number for the upper left hand corner + */ + public void setFirstRow(short first_row) + { + this._first_row = first_row; + } + + /** + * set the lower right hand corner column number + * @param colTo column number for the lower right hand corner + */ + public void setLastColumn(short last_col) + { + this._last_col = last_col; + } + + /** + * get the lower right hand corner row number + * @param rowTo row number for the lower right hand corner + */ + public void setLastRow(short last_row) + { + this._last_row = last_row; + } + } +} + + diff --git a/src/java/org/apache/poi/hssf/util/HSSFDataValidation.java b/src/java/org/apache/poi/hssf/util/HSSFDataValidation.java new file mode 100644 index 0000000000..af578bee48 --- /dev/null +++ b/src/java/org/apache/poi/hssf/util/HSSFDataValidation.java @@ -0,0 +1,471 @@ +/* ==================================================================== + Copyright 2002-2004 Apache Software Foundation + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +==================================================================== */ + +package org.apache.poi.hssf.util; + +/** + *

    Title: HSSFDataValidation

    + *

    Description: Utilty class for creating data validation cells

    + *

    Copyright: Copyright (c) 2004

    + *

    Company:

    + * @author Dragos Buleandra (dragos.buleandra@trade2b.ro) + * @version 2.0-pre + */ + +public class HSSFDataValidation +{ + /** + * Validation data type constants + */ + /** + * Any type + */ + public static final int DATA_TYPE_ANY = 0x00; + /** + * Integer type + */ + public static final int DATA_TYPE_INTEGER = 0x01; + /** + * Decimal type + */ + public static final int DATA_TYPE_DECIMAL = 0x02; + /** + * List type ( combo box type ) + */ + public static final int DATA_TYPE_LIST = 0x03; + /** + * Date type + */ + public static final int DATA_TYPE_DATE = 0x04; + /** + * Time type + */ + public static final int DATA_TYPE_TIME = 0x05; + /** + * String length type + */ + public static final int DATA_TYPE_TEXT_LENGTH = 0x06; + /** + * Formula ( custom ) type + */ + public static final int DATA_TYPE_FORMULA = 0x07; + + /** + * Error style constants for error box + */ + /** + * STOP style like + */ + public static final int ERROR_STYLE_STOP = 0x00; + /** + * WARNING style like + */ + public static final int ERROR_STYLE_WARNING = 0x01; + /** + * INFO style like + */ + public static final int ERROR_STYLE_INFO = 0x02; + + /** + * Condition operator + */ + public static final int OPERATOR_BETWEEN = 0x00; + public static final int OPERATOR_NOT_BETWEEN = 0x01; + public static final int OPERATOR_EQUAL = 0x02; + public static final int OPERATOR_NOT_EQUAL = 0x03; + public static final int OPERATOR_GREATER_THAN = 0x04; + public static final int OPERATOR_LESS_THAN = 0x05; + public static final int OPERATOR_GREATER_OR_EQUAL = 0x06; + public static final int OPERATOR_LESS_OR_EQUAL = 0x07; + + private short _first_row = 0; + private short _first_col = 0; + private short _last_row = 0; + private short _last_col = 0; + + private String _prompt_title = null; + private String _prompt_text = null; + private String _error_title = null; + private String _error_text = null; + private String _string_first_formula = null; + private String _string_sec_formula = null; + + private int _data_type = HSSFDataValidation.DATA_TYPE_ANY; + private int _error_style = HSSFDataValidation.ERROR_STYLE_STOP; + private boolean _list_explicit_formula = true; + private boolean _empty_cell_allowed = true; + private boolean _surpress_dropdown_arrow = false; + private boolean _show_prompt_box = true; + private boolean _show_error_box = true; + private int _operator = HSSFDataValidation.OPERATOR_BETWEEN; + + + /** + * Empty constructor + */ + public HSSFDataValidation( ) + { + } + + /** + * Constructor wich initializes the cell range on wich this object will be applied + * @param first_row First row + * @param first_col First column + * @param last_row Last row + * @param last_col Last column + */ + public HSSFDataValidation( short first_row, short first_col, short last_row, short last_col ) + { + this._first_row = first_row; + this._first_col = first_col; + this._last_row = last_row; + this._last_col = last_col; + } + + /** + * Set the type of this object + * @param data_type The type + * @see DATA_TYPE_ANY, DATA_TYPE_INTEGER, DATA_TYPE_DECIMNAL, DATA_TYPE_LIST, DATA_TYPE_DATE, + * DATA_TYPE_TIME, DATA_TYPE_TEXT_LENTGH, DATA_TYPE_FORMULA + */ + public void setDataValidationType( int data_type ) + { + this._data_type = data_type; + } + + /** + * The data type of this object + * @return The type + * @see DATA_TYPE_ANY, DATA_TYPE_INTEGER, DATA_TYPE_DECIMNAL, DATA_TYPE_LIST, DATA_TYPE_DATE, + * DATA_TYPE_TIME, DATA_TYPE_TEXT_LENTGH, DATA_TYPE_FORMULA + */ + public int getDataValidationType() + { + return this._data_type; + } + + /** + * Sets the error style for error box + * @param error_style Error style constant + * @see ERROR_STYLE_STOP, ERROR_STYLE_WARNING, ERROR_STYLE_INFO + */ + public void setErrorStyle( int error_style ) + { + this._error_style = error_style; + } + + /** + * returns the error style of errror box + * @return the style constant + * @see ERROR_STYLE_STOP, ERROR_STYLE_WARNING, ERROR_STYLE_INFO + */ + public int getErrorStyle( ) + { + return this._error_style; + } + + /** + * If this object has an explicit formula . This is useful only for list data validation object + * @param explicit True if use an explicit formula + */ + public void setExplicitListFormula( boolean explicit ) + { + this._list_explicit_formula = explicit; + } + + /** + * Returns the settings for explicit formula . This is useful only for list data validation objects. + * This method always returns false if the object isn't a list validation object + * @see setDataValidationType( int data_type ) + * @return + */ + public boolean getExplicitListFormula( ) + { + if ( this._data_type != HSSFDataValidation.DATA_TYPE_LIST ) + { + return false; + } + return this._list_explicit_formula ; + } + + /** + * Sets if this object allows empty as a valid value + * @param allowed True if this object should treats empty as valid value , false otherwise + */ + public void setEmptyCellAllowed( boolean allowed ) + { + this._empty_cell_allowed = allowed; + } + + /** + * Retrieve the settings for empty cells allowed + * @return True if this object should treats empty as valid value , false otherwise + */ + public boolean getEmptyCellAllowed( ) + { + return this._empty_cell_allowed ; + } + + /** + * 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 ) + { + this._surpress_dropdown_arrow = surppres; + } + + /** + * Useful only list validation objects . + * This method always returns false if the object isn't a list validation object + * @return True if a list should display the values into a drop down list , false otherwise . + * @see setDataValidationType( int data_type ) + */ + public boolean getSurppressDropDownArrow( ) + { + if ( this._data_type != HSSFDataValidation.DATA_TYPE_LIST ) + { + return false; + } + return this._surpress_dropdown_arrow ; + } + + /** + * Sets the behaviour when a cell which belongs to this object is selected + * @param show True if an prompt box should be displayed , false otherwise + */ + public void setShowPromptBox( boolean show ) + { + this._show_prompt_box = show; + } + + /** + * @param show True if an prompt box should be displayed , false otherwise + */ + public boolean getShowPromptBox( ) + { + if ( (this.getPromptBoxText() == null) && (this.getPromptBoxTitle() == null) ) + { + return false; + } + return this._show_prompt_box ; + } + + /** + * Sets the behaviour when an invalid value is entered + * @param show True if an error box should be displayed , false otherwise + */ + public void setShowErrorBox( boolean show ) + { + this._show_error_box = show; + } + + /** + * @return True if an error box should be displayed , false otherwise + */ + public boolean getShowErrorBox( ) + { + if ( (this.getErrorBoxText() == null) && (this.getErrorBoxTitle() == null) ) + { + return false; + } + return this._show_error_box ; + } + + /** + * Sets the operator involved in the formula whic governs this object + * Example : if you wants that a cell to accept only values between 1 and 5 , which + * mathematically means 1 <= value <= 5 , then the operator should be OPERATOR_BETWEEN + * @param operator A constant for operator + * @see OPERATOR_BETWEEN, OPERATOR_NOT_BETWEEN, OPERATOR_EQUAL, OPERATOR_NOT_EQUAL + * OPERATOR_GREATER_THAN, OPERATOR_LESS_THAN, OPERATOR_GREATER_OR_EQUAL, + * OPERATOR_LESS_OR_EQUAL + */ + public void setOperator( int operator ) + { + this._operator = operator; + } + + /** + * Retrieves the operator used for this object's formula + * @return + * @see OPERATOR_BETWEEN, OPERATOR_NOT_BETWEEN, OPERATOR_EQUAL, OPERATOR_NOT_EQUAL + * OPERATOR_GREATER_THAN, OPERATOR_LESS_THAN, OPERATOR_GREATER_OR_EQUAL, + * OPERATOR_LESS_OR_EQUAL + */ + public int getOperator() + { + return this._operator; + } + + /** + * Sets the title and text for the prompt box . Prompt box is displayed when the user + * selects a cell which belongs to this validation object . In order for a prompt box + * to be displayed you should also use method setShowPromptBox( boolean show ) + * @param title The prompt box's title + * @param text The prompt box's text + * @see setShowPromptBox( boolean show ) + */ + public void createPromptBox( String title, String text ) + { + this._prompt_title = title; + this._prompt_text = text; + this.setShowPromptBox(true); + } + + /** + * Returns the prompt box's title + * @return Prompt box's title or null + */ + public String getPromptBoxTitle( ) + { + return this._prompt_title; + } + + /** + * Returns the prompt box's text + * @return Prompt box's text or null + */ + public String getPromptBoxText( ) + { + return this._prompt_text; + } + + /** + * Sets the title and text for the error box . Error box is displayed when the user + * enters an invalid value int o a cell which belongs to this validation object . + * In order for an error box to be displayed you should also use method + * setShowErrorBox( boolean show ) + * @param title The error box's title + * @param text The error box's text + * @see setShowErrorBox( boolean show ) + */ + public void createErrorBox( String title, String text ) + { + this._error_title = title; + this._error_text = text; + this.setShowErrorBox(true); + } + + /** + * Returns the error box's title + * @return Error box's title or null + */ + public String getErrorBoxTitle( ) + { + return this._error_title; + } + + /** + * Returns the error box's text + * @return Error box's text or null + */ + public String getErrorBoxText( ) + { + return this._error_text; + } + + /** + * Sets the first formula for this object . + * A formula is divided into three parts : first formula , operator and second formula . + * In other words , a formula contains a left oprand , an operator and a right operand. + * This is the general rule . An example is 1<= value <= 5 . In this case , + * the left operand ( or the first formula ) is the number 1 . The operator is + * OPERATOR_BETWEEN and the right operand ( or the second formula ) is 5 . + * @param formula + */ + public void setFirstFormula( String formula ) + { + this._string_first_formula = formula; + } + + /** + * Returns the first formula + * @return + */ + public String getFirstFormula( ) + { + return this._string_first_formula; + } + + /** + * Sets the first formula for this object . + * A formula is divided into three parts : first formula , operator and second formula . + * In other words , a formula contains a left oprand , an operator and a right operand. + * This is the general rule . An example is 1<= value <=5 . In this case , + * the left operand ( or the first formula ) is the number 1 . The operator is + * OPERATOR_BETWEEN and the right operand ( or the second formula ) is 5 . + * But there are cases when a second formula isn't needed : + * You want somethink like : all values less than 5 . In this case , there's only a first + * formula ( in our case 5 ) and the operator OPERATOR_LESS_THAN + * @param formula + */ + public void setSecondFormula( String formula ) + { + this._string_sec_formula = formula; + } + + /** + * Returns the second formula + * @return + */ + public String getSecondFormula( ) + { + return this._string_sec_formula; + } + + public void setFirstRow( short first_row ) + { + this._first_row = first_row; + } + + public void setFirstColumn( short first_column ) + { + this._first_col = first_column; + } + + public void setLastRow( short last_row ) + { + this._last_row = last_row; + } + + public void setLastColumn( short last_column ) + { + this._last_col = last_column; + } + + public short getFirstRow() + { + return this._first_row; + } + + public short getFirstColumn() + { + return this._first_col; + } + + public short getLastRow() + { + return this._last_row; + } + + public short getLastColumn() + { + return this._last_col; + } + +} \ No newline at end of file diff --git a/src/java/org/apache/poi/poifs/storage/SmallBlockTableWriter.java b/src/java/org/apache/poi/poifs/storage/SmallBlockTableWriter.java index f5bb58a76f..4f89af1545 100644 --- a/src/java/org/apache/poi/poifs/storage/SmallBlockTableWriter.java +++ b/src/java/org/apache/poi/poifs/storage/SmallBlockTableWriter.java @@ -19,6 +19,7 @@ package org.apache.poi.poifs.storage; +import org.apache.poi.poifs.common.POIFSConstants; import org.apache.poi.poifs.filesystem.BATManaged; import org.apache.poi.poifs.filesystem.POIFSDocument; import org.apache.poi.poifs.property.RootProperty; @@ -69,6 +70,8 @@ public class SmallBlockTableWriter { _small_blocks.add(blocks[ j ]); } + } else { + doc.setStartBlock(POIFSConstants.END_OF_CHAIN); } } _sbat.simpleCreateBlocks(); diff --git a/src/java/org/apache/poi/util/IOUtils.java b/src/java/org/apache/poi/util/IOUtils.java index 7126b2b9be..42b69c850b 100644 --- a/src/java/org/apache/poi/util/IOUtils.java +++ b/src/java/org/apache/poi/util/IOUtils.java @@ -19,6 +19,7 @@ package org.apache.poi.util; +import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.InputStream; @@ -28,6 +29,25 @@ public class IOUtils { } + /** + * Reads all the data from the input stream, and returns + * the bytes read. + */ + public static byte[] toByteArray(InputStream stream) throws IOException { + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + + byte[] buffer = new byte[4096]; + int read = 0; + while(read != -1) { + read = stream.read(buffer); + if(read > 0) { + baos.write(buffer, 0, read); + } + } + + return baos.toByteArray(); + } + /** * Helper method, just calls readFully(in, b, 0, b.length) */ diff --git a/src/java/org/apache/poi/util/StringUtil.java b/src/java/org/apache/poi/util/StringUtil.java index 9dd8e4838e..673b5246e1 100644 --- a/src/java/org/apache/poi/util/StringUtil.java +++ b/src/java/org/apache/poi/util/StringUtil.java @@ -161,7 +161,8 @@ public class StringUtil { final int offset, final int len) { try { - return new String(string, offset, len, "ISO-8859-1"); + int len_to_use = Math.min(len, string.length - offset); + return new String(string, offset, len_to_use, "ISO-8859-1"); } catch (UnsupportedEncodingException e) { throw new InternalError(); /* unreachable */ } diff --git a/src/scratchpad/examples/src/org/apache/poi/hslf/examples/TableDemo.java b/src/scratchpad/examples/src/org/apache/poi/hslf/examples/TableDemo.java new file mode 100755 index 0000000000..25ff9ad017 --- /dev/null +++ b/src/scratchpad/examples/src/org/apache/poi/hslf/examples/TableDemo.java @@ -0,0 +1,127 @@ + +/* ==================================================================== + 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.hslf.examples; + +import org.apache.poi.hslf.usermodel.SlideShow; +import org.apache.poi.hslf.usermodel.RichTextRun; +import org.apache.poi.hslf.model.*; + +import java.awt.*; +import java.io.FileOutputStream; + +/** + * Demonstrates how to create tables + * + * @author Yegor Kozlov + */ +public class TableDemo { + + public static void main(String[] args) throws Exception { + + //test data for the first taable + String[][] txt1 = { + {"INPUT FILE", "NUMBER OF RECORDS"}, + {"Item File", "11,559"}, + {"Vendor File", "502"}, + {"Purchase History File - # of PO\u2019s\r(12/01/04 - 05/31/06)", "12,852"}, + {"Purchase History File - # of PO Lines\r(12/01/04 - 05/31/06)", "53,523" }, + {"Total PO History Spend", "$10,172,038"} + }; + + SlideShow ppt = new SlideShow(); + + Slide slide = ppt.createSlide(); + + //six rows, two columns + Table table1 = new Table(6, 2); + for (int i = 0; i < txt1.length; i++) { + for (int j = 0; j < txt1[i].length; j++) { + TableCell cell = table1.getCell(i, j); + cell.setText(txt1[i][j]); + RichTextRun rt = cell.getTextRun().getRichTextRuns()[0]; + rt.setFontName("Arial"); + rt.setFontSize(10); + if(i == 0){ + cell.getFill().setForegroundColor(new Color(227, 227, 227)); + } else { + rt.setBold(true); + } + cell.setVerticalAlignment(TextBox.AnchorMiddle); + cell.setHorizontalAlignment(TextBox.AlignCenter); + } + } + + Line border1 = table1.createBorder(); + border1.setLineColor(Color.black); + border1.setLineWidth(1.0); + table1.setAllBorders(border1); + + table1.setColumnWidth(0, 300); + table1.setColumnWidth(1, 150); + + slide.addShape(table1); + int pgWidth = ppt.getPageSize().width; + table1.moveTo((pgWidth - table1.getAnchor().width)/2, 100); + + //test data for the second taable + String[][] txt2 = { + {"Data Source"}, + {"CAS Internal Metrics - Item Master Summary\r" + + "CAS Internal Metrics - Vendor Summary\r" + + "CAS Internal Metrics - PO History Summary"} + }; + + //two rows, one column + Table table2 = new Table(2, 1); + for (int i = 0; i < txt2.length; i++) { + for (int j = 0; j < txt2[i].length; j++) { + TableCell cell = table2.getCell(i, j); + cell.setText(txt2[i][j]); + RichTextRun rt = cell.getTextRun().getRichTextRuns()[0]; + rt.setFontSize(10); + rt.setFontName("Arial"); + if(i == 0){ + cell.getFill().setForegroundColor(new Color(0, 51, 102)); + rt.setFontColor(Color.white); + rt.setBold(true); + rt.setFontSize(14); + cell.setHorizontalAlignment(TextBox.AlignCenter); + } else { + rt.setBullet(true); + rt.setFontSize(12); + cell.setHorizontalAlignment(TextBox.AlignLeft); + } + cell.setVerticalAlignment(TextBox.AnchorMiddle); + } + } + table2.setColumnWidth(0, 300); + table2.setRowHeight(0, 30); + table2.setRowHeight(1, 70); + + Line border2 = table2.createBorder(); + table2.setOutsideBorders(border2); + + slide.addShape(table2); + table2.moveTo(200, 400); + + FileOutputStream out = new FileOutputStream("hslf-table.ppt"); + ppt.write(out); + out.close(); + + } +} diff --git a/src/scratchpad/examples/src/org/apache/poi/hssf/eventusermodel/examples/XLS2CSVmra.java b/src/scratchpad/examples/src/org/apache/poi/hssf/eventusermodel/examples/XLS2CSVmra.java index 5f7392739f..1c8d994bfe 100644 --- a/src/scratchpad/examples/src/org/apache/poi/hssf/eventusermodel/examples/XLS2CSVmra.java +++ b/src/scratchpad/examples/src/org/apache/poi/hssf/eventusermodel/examples/XLS2CSVmra.java @@ -283,7 +283,7 @@ public class XLS2CSVmra implements HSSFListener { format = format.replaceAll("\\\\-","-"); // Format as a date - Date d = HSSFDateUtil.getJavaDate(value); + Date d = HSSFDateUtil.getJavaDate(value, false); DateFormat df = new SimpleDateFormat(format); return df.format(d); } else { diff --git a/src/scratchpad/src/org/apache/poi/hslf/model/Fill.java b/src/scratchpad/src/org/apache/poi/hslf/model/Fill.java index f0d85400be..7eae4edc4c 100644 --- a/src/scratchpad/src/org/apache/poi/hslf/model/Fill.java +++ b/src/scratchpad/src/org/apache/poi/hslf/model/Fill.java @@ -150,10 +150,12 @@ public class Fill { EscherOptRecord opt = (EscherOptRecord)Shape.getEscherChild(shape.getSpContainer(), EscherOptRecord.RECORD_ID); if (color == null) { Shape.setEscherProperty(opt, EscherProperties.FILL__FILLCOLOR, -1); + Shape.setEscherProperty(opt, EscherProperties.FILL__NOFILLHITTEST, 0x150010); } else { int rgb = new Color(color.getBlue(), color.getGreen(), color.getRed(), 0).getRGB(); Shape.setEscherProperty(opt, EscherProperties.FILL__FILLCOLOR, rgb); + Shape.setEscherProperty(opt, EscherProperties.FILL__NOFILLHITTEST, 0x150011); } } diff --git a/src/scratchpad/src/org/apache/poi/hslf/model/Sheet.java b/src/scratchpad/src/org/apache/poi/hslf/model/Sheet.java index b1761b2d9a..d8ddc7d2f2 100644 --- a/src/scratchpad/src/org/apache/poi/hslf/model/Sheet.java +++ b/src/scratchpad/src/org/apache/poi/hslf/model/Sheet.java @@ -153,7 +153,7 @@ public abstract class Sheet { */ protected static void findTextRuns(Record[] records, Vector found) { // Look for a TextHeaderAtom - for (int i = 0; i < (records.length - 1); i++) { + for (int i = 0, slwtIndex=0; i < (records.length - 1); i++) { if (records[i] instanceof TextHeaderAtom) { TextRun trun = null; TextHeaderAtom tha = (TextHeaderAtom) records[i]; @@ -179,7 +179,6 @@ public abstract class Sheet { // TextSpecInfoAtom - Safe to ignore } else { System.err.println("Found a TextHeaderAtom not followed by a TextBytesAtom or TextCharsAtom: Followed by " + records[i + 1].getRecordType()); - continue; } if (trun != null) { @@ -191,12 +190,14 @@ public abstract class Sheet { Record[] recs = new Record[lst.size()]; lst.toArray(recs); trun._records = recs; + trun.setIndex(slwtIndex); found.add(trun); i++; } else { // Not a valid one, so skip on to next and look again } + slwtIndex++; } } } diff --git a/src/scratchpad/src/org/apache/poi/hslf/model/SimpleShape.java b/src/scratchpad/src/org/apache/poi/hslf/model/SimpleShape.java index 2f634ccd17..1074916004 100644 --- a/src/scratchpad/src/org/apache/poi/hslf/model/SimpleShape.java +++ b/src/scratchpad/src/org/apache/poi/hslf/model/SimpleShape.java @@ -124,8 +124,10 @@ public class SimpleShape extends Shape { int rgb = p1.getPropertyValue(); if (rgb >= 0x8000000) { int idx = rgb % 0x8000000; - ColorSchemeAtom ca = getSheet().getColorScheme(); - if(idx >= 0 && idx <= 7) rgb = ca.getColor(idx); + if(getSheet() != null) { + ColorSchemeAtom ca = getSheet().getColorScheme(); + if(idx >= 0 && idx <= 7) rgb = ca.getColor(idx); + } } Color tmp = new Color(rgb, true); clr = new Color(tmp.getBlue(), tmp.getGreen(), tmp.getRed()); @@ -192,8 +194,10 @@ public class SimpleShape extends Shape { int rgb = p1.getPropertyValue(); if (rgb >= 0x8000000) { int idx = rgb % 0x8000000; - ColorSchemeAtom ca = getSheet().getColorScheme(); - rgb = ca.getColor(idx); + if(getSheet() != null) { + ColorSchemeAtom ca = getSheet().getColorScheme(); + rgb = ca.getColor(idx); + } } Color tmp = new Color(rgb, true); clr = new Color(tmp.getBlue(), tmp.getGreen(), tmp.getRed()); diff --git a/src/scratchpad/src/org/apache/poi/hslf/model/Table.java b/src/scratchpad/src/org/apache/poi/hslf/model/Table.java new file mode 100755 index 0000000000..a9f21b54f3 --- /dev/null +++ b/src/scratchpad/src/org/apache/poi/hslf/model/Table.java @@ -0,0 +1,291 @@ + +/* ==================================================================== + 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.hslf.model; + +import org.apache.poi.ddf.*; +import org.apache.poi.util.LittleEndian; + +import java.util.ArrayList; +import java.util.List; +import java.util.Iterator; +import java.awt.*; + +/** + * Represents a table in a PowerPoint presentation + * + * @author Yegor Kozlov + */ +public class Table extends ShapeGroup { + + protected static final int BORDER_TOP = 1; + protected static final int BORDER_RIGHT = 2; + protected static final int BORDER_BOTTOM = 3; + protected static final int BORDER_LEFT = 4; + + protected static final int BORDERS_ALL = 5; + protected static final int BORDERS_OUTSIDE = 6; + protected static final int BORDERS_INSIDE = 7; + protected static final int BORDERS_NONE = 8; + + + protected TableCell[][] cells; + + /** + * Create a new Table of the given number of rows and columns + * + * @param numrows the number of rows + * @param numcols the number of columns + */ + public Table(int numrows, int numcols) { + super(); + + int x=0, y=0, tblWidth=0, tblHeight=0; + cells = new TableCell[numrows][numcols]; + for (int i = 0; i < cells.length; i++) { + x = 0; + for (int j = 0; j < cells[i].length; j++) { + cells[i][j] = new TableCell(this); + Rectangle anchor = new Rectangle(x, y, TableCell.DEFAULT_WIDTH, TableCell.DEFAULT_HEIGHT); + cells[i][j].setAnchor(anchor); + x += TableCell.DEFAULT_WIDTH; + } + y += TableCell.DEFAULT_HEIGHT; + } + tblWidth = x; + tblHeight = y; + setAnchor(new Rectangle(0, 0, tblWidth, tblHeight)); + + EscherContainerRecord spCont = (EscherContainerRecord) getSpContainer().getChild(0); + List lst = spCont.getChildRecords(); + EscherOptRecord opt = new EscherOptRecord(); + opt.setRecordId((short)0xF122); + opt.addEscherProperty(new EscherSimpleProperty((short)0x39F, 1)); + EscherArrayProperty p = new EscherArrayProperty((short)0x43A0, false, null); + p.setSizeOfElements(0x0004); + p.setNumberOfElementsInArray(numrows); + p.setNumberOfElementsInMemory(numrows); + opt.addEscherProperty(p); + lst.add(lst.size()-1, opt); + + } + + /** + * Create a Table object and initilize it from the supplied Record container. + * + * @param escherRecord EscherSpContainer container which holds information about this shape + * @param parent the parent of the shape + */ + protected Table(EscherContainerRecord escherRecord, Shape parent) { + super(escherRecord, parent); + } + + /** + * Gets a cell + * + * @param row the row index (0-based) + * @param col the column index (0-based) + * @return the cell + */ + public TableCell getCell(int row, int col) { + return cells[row][col]; + } + + public int getNumberOfColumns() { + return cells[0].length; + } + public int getNumberOfRows() { + return cells.length; + } + + protected void afterInsert(Sheet sh){ + EscherContainerRecord spCont = (EscherContainerRecord) getSpContainer().getChild(0); + List lst = spCont.getChildRecords(); + EscherOptRecord opt = (EscherOptRecord)lst.get(lst.size()-2); + EscherArrayProperty p = (EscherArrayProperty)opt.getEscherProperty(1); + for (int i = 0; i < cells.length; i++) { + TableCell cell = cells[i][0]; + int rowHeight = cell.getAnchor().height*MASTER_DPI/POINT_DPI; + byte[] val = new byte[4]; + LittleEndian.putInt(val, rowHeight); + p.setElement(i, val); + for (int j = 0; j < cells[i].length; j++) { + TableCell c = cells[i][j]; + addShape(c); + + Line bt = c.getBorderTop(); + if(bt != null) addShape(bt); + + Line br = c.getBorderRight(); + if(br != null) addShape(br); + + Line bb = c.getBorderBottom(); + if(bb != null) addShape(bb); + + Line bl = c.getBorderLeft(); + if(bl != null) addShape(bl); + + } + } + + } + + /** + * Sets the row height. + * + * @param row the row index (0-based) + * @param height the height to set (in pixels) + */ + public void setRowHeight(int row, int height){ + int currentHeight = cells[row][0].getAnchor().height; + int dy = height - currentHeight; + + for (int i = row; i < cells.length; i++) { + for (int j = 0; j < cells[i].length; j++) { + Rectangle anchor = cells[i][j].getAnchor(); + if(i == row) anchor.height = height; + else anchor.y += dy; + cells[i][j].setAnchor(anchor); + } + } + Rectangle tblanchor = getAnchor(); + tblanchor.height += dy; + setAnchor(tblanchor); + + } + + /** + * Sets the column width. + * + * @param col the column index (0-based) + * @param width the width to set (in pixels) + */ + public void setColumnWidth(int col, int width){ + int currentWidth = cells[0][col].getAnchor().width; + int dx = width - currentWidth; + for (int i = 0; i < cells.length; i++) { + Rectangle anchor = cells[i][col].getAnchor(); + anchor.width = width; + cells[i][col].setAnchor(anchor); + + if(col < cells[i].length - 1) for (int j = col+1; j < cells[i].length; j++) { + anchor = cells[i][j].getAnchor(); + anchor.x += dx; + cells[i][j].setAnchor(anchor); + } + } + Rectangle tblanchor = getAnchor(); + tblanchor.width += dx; + setAnchor(tblanchor); + } + + /** + * Format the table and apply the specified Line to all cell boundaries, + * both outside and inside + * + * @param line the border line + */ + public void setAllBorders(Line line){ + for (int i = 0; i < cells.length; i++) { + for (int j = 0; j < cells[i].length; j++) { + TableCell cell = cells[i][j]; + cell.setBorderTop(cloneBorder(line)); + cell.setBorderLeft(cloneBorder(line)); + if(j == cells[i].length - 1) cell.setBorderRight(cloneBorder(line)); + if(i == cells.length - 1) cell.setBorderBottom(cloneBorder(line)); + } + } + } + + /** + * Format the outside border using the specified Line object + * + * @param line the border line + */ + public void setOutsideBorders(Line line){ + for (int i = 0; i < cells.length; i++) { + for (int j = 0; j < cells[i].length; j++) { + TableCell cell = cells[i][j]; + + if(j == 0) cell.setBorderLeft(cloneBorder(line)); + if(j == cells[i].length - 1) cell.setBorderRight(cloneBorder(line)); + else { + cell.setBorderLeft(null); + cell.setBorderLeft(null); + } + + if(i == 0) cell.setBorderTop(cloneBorder(line)); + else if(i == cells.length - 1) cell.setBorderBottom(cloneBorder(line)); + else { + cell.setBorderTop(null); + cell.setBorderBottom(null); + } + } + } + } + + /** + * Format the inside border using the specified Line object + * + * @param line the border line + */ + public void setInsideBorders(Line line){ + for (int i = 0; i < cells.length; i++) { + for (int j = 0; j < cells[i].length; j++) { + TableCell cell = cells[i][j]; + + if(j != cells[i].length - 1) + cell.setBorderRight(cloneBorder(line)); + else { + cell.setBorderLeft(null); + cell.setBorderLeft(null); + } + if(i != cells.length - 1) cell.setBorderBottom(cloneBorder(line)); + else { + cell.setBorderTop(null); + cell.setBorderBottom(null); + } + } + } + } + + private Line cloneBorder(Line line){ + Line border = createBorder(); + border.setLineWidth(line.getLineWidth()); + border.setLineStyle(line.getLineStyle()); + border.setLineDashing(line.getLineDashing()); + border.setLineColor(line.getLineColor()); + return border; + } + + /** + * Create a border to format this table + * + * @return the created border + */ + public Line createBorder(){ + Line line = new Line(this); + + EscherOptRecord opt = (EscherOptRecord)getEscherChild(line.getSpContainer(), EscherOptRecord.RECORD_ID); + setEscherProperty(opt, EscherProperties.GEOMETRY__SHAPEPATH, -1); + setEscherProperty(opt, EscherProperties.GEOMETRY__FILLOK, -1); + setEscherProperty(opt, EscherProperties.SHADOWSTYLE__SHADOWOBSURED, 0x20000); + setEscherProperty(opt, EscherProperties.THREED__LIGHTFACE, 0x80000); + + return line; + } +} diff --git a/src/scratchpad/src/org/apache/poi/hslf/model/TableCell.java b/src/scratchpad/src/org/apache/poi/hslf/model/TableCell.java new file mode 100755 index 0000000000..bb93e06b71 --- /dev/null +++ b/src/scratchpad/src/org/apache/poi/hslf/model/TableCell.java @@ -0,0 +1,155 @@ + +/* ==================================================================== + 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.hslf.model; + +import org.apache.poi.ddf.*; +import org.apache.poi.hslf.record.EscherTextboxWrapper; +import org.apache.poi.hslf.record.TextHeaderAtom; +import org.apache.poi.hslf.usermodel.RichTextRun; + +import java.awt.*; + +/** + * Represents a cell in a ppt table + * + * @author Yegor Kozlov + */ +public class TableCell extends TextBox { + protected static final int DEFAULT_WIDTH = 100; + protected static final int DEFAULT_HEIGHT = 40; + + private Line borderLeft; + private Line borderRight; + private Line borderTop; + private Line borderBottom; + + /** + * Create a TableCell object and initialize it from the supplied Record container. + * + * @param escherRecord EscherSpContainer container which holds information about this shape + * @param parent the parent of the shape + */ + protected TableCell(EscherContainerRecord escherRecord, Shape parent){ + super(escherRecord, parent); + } + + /** + * Create a new TableCell. This constructor is used when a new shape is created. + * + * @param parent the parent of this Shape. For example, if this text box is a cell + * in a table then the parent is Table. + */ + public TableCell(Shape parent){ + super(parent); + + setShapeType(ShapeTypes.Rectangle); + _txtrun.setRunType(TextHeaderAtom.HALF_BODY_TYPE); + _txtrun.getRichTextRuns()[0].setFlag(false, 0, false); + } + + protected EscherContainerRecord createSpContainer(boolean isChild){ + EscherContainerRecord spContainer = super.createSpContainer(isChild); + EscherOptRecord opt = (EscherOptRecord)getEscherChild(spContainer, EscherOptRecord.RECORD_ID); + setEscherProperty(opt, EscherProperties.TEXT__TEXTID, 0); + setEscherProperty(opt, EscherProperties.TEXT__SIZE_TEXT_TO_FIT_SHAPE, 0x20000); + setEscherProperty(opt, EscherProperties.FILL__NOFILLHITTEST, 0x150001); + setEscherProperty(opt, EscherProperties.SHADOWSTYLE__SHADOWOBSURED, 0x20000); + setEscherProperty(opt, EscherProperties.PROTECTION__LOCKAGAINSTGROUPING, 0x40000); + + return spContainer; + } + + protected void anchorBorder(int type, Line line){ + Rectangle cellAnchor = getAnchor(); + Rectangle lineAnchor = new Rectangle(); + switch(type){ + case Table.BORDER_TOP: + lineAnchor.x = cellAnchor.x; + lineAnchor.y = cellAnchor.y; + lineAnchor.width = cellAnchor.width; + lineAnchor.height = 0; + break; + case Table.BORDER_RIGHT: + lineAnchor.x = cellAnchor.x + cellAnchor.width; + lineAnchor.y = cellAnchor.y; + lineAnchor.width = 0; + lineAnchor.height = cellAnchor.height; + break; + case Table.BORDER_BOTTOM: + lineAnchor.x = cellAnchor.x; + lineAnchor.y = cellAnchor.y + cellAnchor.height; + lineAnchor.width = cellAnchor.width; + lineAnchor.height = 0; + break; + case Table.BORDER_LEFT: + lineAnchor.x = cellAnchor.x; + lineAnchor.y = cellAnchor.y; + lineAnchor.width = 0; + lineAnchor.height = cellAnchor.height; + break; + default: + throw new IllegalArgumentException("Unknown border type: " + type); + } + line.setAnchor(lineAnchor); + } + + public Line getBorderLeft() { + return borderLeft; + } + + public void setBorderLeft(Line line) { + if(line != null) anchorBorder(Table.BORDER_LEFT, line); + this.borderLeft = line; + } + + public Line getBorderRight() { + return borderRight; + } + + public void setBorderRight(Line line) { + if(line != null) anchorBorder(Table.BORDER_RIGHT, line); + this.borderRight = line; + } + + public Line getBorderTop() { + return borderTop; + } + + public void setBorderTop(Line line) { + if(line != null) anchorBorder(Table.BORDER_TOP, line); + this.borderTop = line; + } + + public Line getBorderBottom() { + return borderBottom; + } + + public void setBorderBottom(Line line) { + if(line != null) anchorBorder(Table.BORDER_BOTTOM, line); + this.borderBottom = line; + } + + public void setAnchor(Rectangle anchor){ + super.setAnchor(anchor); + + if(borderTop != null) anchorBorder(Table.BORDER_TOP, borderTop); + if(borderRight != null) anchorBorder(Table.BORDER_RIGHT, borderRight); + if(borderBottom != null) anchorBorder(Table.BORDER_BOTTOM, borderBottom); + if(borderLeft != null) anchorBorder(Table.BORDER_LEFT, borderLeft); + } +} diff --git a/src/scratchpad/src/org/apache/poi/hslf/model/TextBox.java b/src/scratchpad/src/org/apache/poi/hslf/model/TextBox.java index 2d5c866f77..1f9a489a78 100644 --- a/src/scratchpad/src/org/apache/poi/hslf/model/TextBox.java +++ b/src/scratchpad/src/org/apache/poi/hslf/model/TextBox.java @@ -196,7 +196,7 @@ public class TextBox extends SimpleShape { } catch (IOException e){ throw new HSLFException(e); } - if(getAnchor().equals(new java.awt.Rectangle())) resizeToFitText(); + if(getAnchor().equals(new java.awt.Rectangle()) && !"".equals(getText())) resizeToFitText(); } /** @@ -264,6 +264,14 @@ public class TextBox extends SimpleShape { EscherOptRecord opt = (EscherOptRecord)getEscherChild(_escherContainer, EscherOptRecord.RECORD_ID); setEscherProperty(opt, EscherProperties.TEXT__ANCHORTEXT, align); } + + public void setHorizontalAlignment(int align){ + _txtrun.getRichTextRuns()[0].setAlignment(align); + } + public int getHorizontalAlignment(){ + return _txtrun.getRichTextRuns()[0].getAlignment(); + } + /** * Returns the distance (in points) between the bottom of the text frame * and the bottom of the inscribed rectangle of the shape that contains the text. @@ -466,7 +474,11 @@ public class TextBox extends SimpleShape { TextRun[] runs = sheet.getTextRuns(); if (ota != null) { int idx = ota.getTextIndex(); - if(idx < runs.length) _txtrun = runs[idx]; + for (int i = 0; i < runs.length; i++) { + if(runs[i].getIndex() == idx){ + _txtrun = runs[i]; + } + } if(_txtrun == null) { logger.log(POILogger.WARN, "text run not found for OutlineTextRefAtom.TextIndex=" + idx); } @@ -478,9 +490,6 @@ public class TextBox extends SimpleShape { break; } } - if(_txtrun == null) { - logger.log(POILogger.WARN, "text run not found for shapeId=" + shapeId); - } } } diff --git a/src/scratchpad/src/org/apache/poi/hslf/model/TextRun.java b/src/scratchpad/src/org/apache/poi/hslf/model/TextRun.java index 4999df7581..ca6e02d69b 100644 --- a/src/scratchpad/src/org/apache/poi/hslf/model/TextRun.java +++ b/src/scratchpad/src/org/apache/poi/hslf/model/TextRun.java @@ -50,6 +50,7 @@ public class TextRun private SlideShow slideShow; private Sheet sheet; private int shapeId; + private int slwtIndex; //position in the owning SlideListWithText /** * all text run records that follow TextHeaderAtom. * (there can be misc InteractiveInfo, TxInteractiveInfo and other records) @@ -537,6 +538,20 @@ public class TextRun shapeId = id; } + /** + * @return 0-based index of the text run in the SLWT container + */ + protected int getIndex(){ + return slwtIndex; + } + + /** + * @param id 0-based index of the text run in the SLWT container + */ + protected void setIndex(int id){ + slwtIndex = id; + } + /** * Returns the array of all hyperlinks in this text run * diff --git a/src/scratchpad/src/org/apache/poi/hslf/usermodel/RichTextRun.java b/src/scratchpad/src/org/apache/poi/hslf/usermodel/RichTextRun.java index 0ee01b9a96..d16bf7bc02 100644 --- a/src/scratchpad/src/org/apache/poi/hslf/usermodel/RichTextRun.java +++ b/src/scratchpad/src/org/apache/poi/hslf/usermodel/RichTextRun.java @@ -198,7 +198,7 @@ public class RichTextRun setFlag(true, index, value); } - private void setFlag(boolean isCharacter, int index, boolean value) { + public void setFlag(boolean isCharacter, int index, boolean value) { TextPropCollection props; String propname; if (isCharacter){ @@ -282,7 +282,7 @@ public class RichTextRun * @param propName The name of the Character TextProp * @param val The value to set for the TextProp */ - private void setParaTextPropVal(String propName, int val) { + public void setParaTextPropVal(String propName, int val) { // Ensure we have the StyleTextProp atom we're going to need if(paragraphStyle == null) { parentRun.ensureStyleAtomPresent(); @@ -297,7 +297,7 @@ public class RichTextRun * @param propName The name of the Paragraph TextProp * @param val The value to set for the TextProp */ - private void setCharTextPropVal(String propName, int val) { + public void setCharTextPropVal(String propName, int val) { // Ensure we have the StyleTextProp atom we're going to need if(characterStyle == null) { parentRun.ensureStyleAtomPresent(); diff --git a/src/scratchpad/src/org/apache/poi/hsmf/MAPIMessage.java b/src/scratchpad/src/org/apache/poi/hsmf/MAPIMessage.java index ed215f6382..eb915160b3 100644 --- a/src/scratchpad/src/org/apache/poi/hsmf/MAPIMessage.java +++ b/src/scratchpad/src/org/apache/poi/hsmf/MAPIMessage.java @@ -48,15 +48,24 @@ public class MAPIMessage { /** - * Constructor for reading MSG Files. + * Constructor for reading MSG Files from the file system. * @param filename * @throws IOException */ public MAPIMessage(String filename) throws IOException { - InputStream in = new FileInputStream(new File(filename)); + this(new FileInputStream(new File(filename))); + } + + /** + * Constructor for reading MSG Files from an input stream. + * @param in + * @throws IOException + */ + public MAPIMessage(InputStream in) throws IOException { this.fs = new POIFSFileSystem(in); chunkParser = new POIFSChunkParser(this.fs); } + /** * Gets a string value based on the passed chunk. @@ -101,6 +110,16 @@ public class MAPIMessage { return getStringFromChunk(Chunks.getInstance().displayToChunk); } + /** + * Gets the display value of the "FROM" line of the outlook message + * This is not the actual address that was sent from but the formated display of the user name. + * @return + * @throws ChunkNotFoundException + */ + public String getDisplayFrom() throws ChunkNotFoundException { + return getStringFromChunk(Chunks.getInstance().displayFromChunk); + } + /** * Gets the display value of the "TO" line of the outlook message * This is not the actual list of addresses/values that will be sent to if you click Reply in the email. diff --git a/src/scratchpad/src/org/apache/poi/hsmf/datatypes/Chunks.java b/src/scratchpad/src/org/apache/poi/hsmf/datatypes/Chunks.java index 309efeac9d..6a3936d964 100644 --- a/src/scratchpad/src/org/apache/poi/hsmf/datatypes/Chunks.java +++ b/src/scratchpad/src/org/apache/poi/hsmf/datatypes/Chunks.java @@ -29,6 +29,7 @@ public class Chunks { public StringChunk textBodyChunk = new StringChunk(0x1000); //BODY Chunk, for plain/text messages public StringChunk subjectChunk = new StringChunk(0x0037); //Subject link chunk, in plain/text public StringChunk displayToChunk = new StringChunk(0x0E04); //Value that is in the TO field (not actually the addresses as they are stored in recip directory nodes + public StringChunk displayFromChunk = new StringChunk(0x0C1A); //Value that is in the FROM field public StringChunk displayCCChunk = new StringChunk(0x0E03); //value that shows in the CC field public StringChunk displayBCCChunk = new StringChunk(0x0E02); //Value that shows in the BCC field public StringChunk conversationTopic = new StringChunk(0x0070); //Sort of like the subject line, but without the RE: and FWD: parts. diff --git a/src/scratchpad/src/org/apache/poi/hssf/record/formula/functions/Date.java b/src/scratchpad/src/org/apache/poi/hssf/record/formula/functions/Date.java index 34dcc7cdae..6861a02524 100644 --- a/src/scratchpad/src/org/apache/poi/hssf/record/formula/functions/Date.java +++ b/src/scratchpad/src/org/apache/poi/hssf/record/formula/functions/Date.java @@ -70,7 +70,7 @@ public class Date extends NumericFunction { c.set(year, month, day, 0, 0, 0); c.set(Calendar.MILLISECOND, 0); - return new NumberEval(HSSFDateUtil.getExcelDate(c.getTime())); + return new NumberEval(HSSFDateUtil.getExcelDate(c.getTime(), false)); // XXX fix 1900/1904 problem } } diff --git a/src/scratchpad/src/org/apache/poi/hssf/record/formula/functions/Day.java b/src/scratchpad/src/org/apache/poi/hssf/record/formula/functions/Day.java index 283633442e..0ae5694767 100644 --- a/src/scratchpad/src/org/apache/poi/hssf/record/formula/functions/Day.java +++ b/src/scratchpad/src/org/apache/poi/hssf/record/formula/functions/Day.java @@ -46,7 +46,7 @@ srcCellRow, srcCellCol); if (ve instanceof NumericValueEval) { NumericValueEval ne = (NumericValueEval) ve; if (HSSFDateUtil.isValidExcelDate(ne.getNumberValue())) { - java.util.Date d = HSSFDateUtil.getJavaDate(ne.getNumberValue()); + java.util.Date d = HSSFDateUtil.getJavaDate(ne.getNumberValue(), false); // XXX fix 1900/1904 problem java.util.Calendar c = java.util.Calendar.getInstance(); c.setTime(d); retval = new NumberEval(c.get(java.util.Calendar.DAY_OF_MONTH)); diff --git a/src/scratchpad/src/org/apache/poi/hssf/record/formula/functions/Mid.java b/src/scratchpad/src/org/apache/poi/hssf/record/formula/functions/Mid.java index 30593142e8..d6c4399ae3 100644 --- a/src/scratchpad/src/org/apache/poi/hssf/record/formula/functions/Mid.java +++ b/src/scratchpad/src/org/apache/poi/hssf/record/formula/functions/Mid.java @@ -20,6 +20,80 @@ */ package org.apache.poi.hssf.record.formula.functions; -public class Mid extends NotImplementedFunction { +import org.apache.poi.hssf.record.formula.eval.BlankEval; +import org.apache.poi.hssf.record.formula.eval.ErrorEval; +import org.apache.poi.hssf.record.formula.eval.Eval; +import org.apache.poi.hssf.record.formula.eval.NumericValueEval; +import org.apache.poi.hssf.record.formula.eval.StringEval; +import org.apache.poi.hssf.record.formula.eval.StringValueEval; +import org.apache.poi.hssf.record.formula.eval.ValueEval; + +/** + * An implementation of the MID function: + * Returns a specific number of characters from a text string, + * starting at the position you specify, based on the number + * of characters you specify. + * @author Manda Wilson < wilson at c bio dot msk cc dot org > + */ +public class Mid extends TextFunction { + /** + * Returns a specific number of characters from a text string, + * starting at the position you specify, based on the number + * of characters you specify. + * + * @see org.apache.poi.hssf.record.formula.eval.Eval + */ + public Eval evaluate(Eval[] operands, int srcCellRow, short srcCellCol) { + Eval retval = null; + String str = null; + int startNum = 0; + int numChars = 0; + + switch (operands.length) { + default: + retval = ErrorEval.VALUE_INVALID; + case 3: + // first operand is text string containing characters to extract + // second operand is position of first character to extract + // third operand is the number of characters to return + ValueEval firstveval = singleOperandEvaluate(operands[0], srcCellRow, srcCellCol); + ValueEval secondveval = singleOperandEvaluate(operands[1], srcCellRow, srcCellCol); + ValueEval thirdveval = singleOperandEvaluate(operands[2], srcCellRow, srcCellCol); + if (firstveval instanceof StringValueEval + && secondveval instanceof NumericValueEval + && thirdveval instanceof NumericValueEval) { + + StringValueEval strEval = (StringValueEval) firstveval; + str = strEval.getStringValue(); + + NumericValueEval startNumEval = (NumericValueEval) secondveval; + // NOTE: it is safe to cast to int here + // because in Excel =MID("test", 1, 1.7) returns t + // so 1.7 must be truncated to 1 + // and =MID("test", 1.9, 2) returns te + // so 1.9 must be truncated to 1 + startNum = (int) startNumEval.getNumberValue(); + + NumericValueEval numCharsEval = (NumericValueEval) thirdveval; + numChars = (int) numCharsEval.getNumberValue(); + + } else { + retval = ErrorEval.VALUE_INVALID; + } + } + + if (retval == null) { + if (startNum < 1 || numChars < 0) { + retval = ErrorEval.VALUE_INVALID; + } else if (startNum > str.length() || numChars == 0) { + retval = BlankEval.INSTANCE; + } else if (startNum + numChars > str.length()) { + retval = new StringEval(str.substring(startNum - 1)); + } else { + retval = new StringEval(str.substring(startNum - 1, numChars)); + } + } + return retval; + } } diff --git a/src/scratchpad/src/org/apache/poi/hssf/record/formula/functions/Month.java b/src/scratchpad/src/org/apache/poi/hssf/record/formula/functions/Month.java index 065c565d14..d5178b22df 100644 --- a/src/scratchpad/src/org/apache/poi/hssf/record/formula/functions/Month.java +++ b/src/scratchpad/src/org/apache/poi/hssf/record/formula/functions/Month.java @@ -50,7 +50,7 @@ public class Month extends NumericFunction { if (ve instanceof NumericValueEval) { NumericValueEval ne = (NumericValueEval) ve; if (HSSFDateUtil.isValidExcelDate(ne.getNumberValue())) { - java.util.Date d = HSSFDateUtil.getJavaDate(ne.getNumberValue()); + java.util.Date d = HSSFDateUtil.getJavaDate(ne.getNumberValue(), false); // XXX fix 1900/1904 problem retval = new NumberEval(d.getMonth()+1); } else { retval = ErrorEval.NUM_ERROR; diff --git a/src/scratchpad/src/org/apache/poi/hssf/record/formula/functions/Replace.java b/src/scratchpad/src/org/apache/poi/hssf/record/formula/functions/Replace.java index 3ba7a2b2ce..95413f0823 100644 --- a/src/scratchpad/src/org/apache/poi/hssf/record/formula/functions/Replace.java +++ b/src/scratchpad/src/org/apache/poi/hssf/record/formula/functions/Replace.java @@ -20,6 +20,93 @@ */ package org.apache.poi.hssf.record.formula.functions; -public class Replace extends NotImplementedFunction { +import org.apache.poi.hssf.record.formula.eval.ErrorEval; +import org.apache.poi.hssf.record.formula.eval.Eval; +import org.apache.poi.hssf.record.formula.eval.NumericValueEval; +import org.apache.poi.hssf.record.formula.eval.StringEval; +import org.apache.poi.hssf.record.formula.eval.StringValueEval; +import org.apache.poi.hssf.record.formula.eval.ValueEval; + +/** + * An implementation of the REPLACE function: + * Replaces part of a text string based on the number of characters + * you specify, with another text string. + * @author Manda Wilson < wilson at c bio dot msk cc dot org > + */ +public class Replace extends TextFunction { + + /** + * Replaces part of a text string based on the number of characters + * you specify, with another text string. + * + * @see org.apache.poi.hssf.record.formula.eval.Eval + */ + public Eval evaluate(Eval[] operands, int srcCellRow, short srcCellCol) { + Eval retval = null; + String oldStr = null; + String newStr = null; + int startNum = 0; + int numChars = 0; + + switch (operands.length) { + default: + retval = ErrorEval.VALUE_INVALID; + case 4: + // first operand is text string containing characters to replace + // second operand is position of first character to replace + // third operand is the number of characters in the old string + // you want to replace with new string + // fourth operand is the new string + ValueEval firstveval = singleOperandEvaluate(operands[0], srcCellRow, srcCellCol); + ValueEval secondveval = singleOperandEvaluate(operands[1], srcCellRow, srcCellCol); + ValueEval thirdveval = singleOperandEvaluate(operands[2], srcCellRow, srcCellCol); + ValueEval fourthveval = singleOperandEvaluate(operands[3], srcCellRow, srcCellCol); + if (firstveval instanceof StringValueEval + && secondveval instanceof NumericValueEval + && thirdveval instanceof NumericValueEval + && fourthveval instanceof StringValueEval) { + + StringValueEval oldStrEval = (StringValueEval) firstveval; + oldStr = oldStrEval.getStringValue(); + + NumericValueEval startNumEval = (NumericValueEval) secondveval; + // NOTE: it is safe to cast to int here + // because in Excel =REPLACE("task", 2.7, 3, "est") + // returns test + // so 2.7 must be truncated to 2 + // and =REPLACE("task", 1, 1.9, "") returns ask + // so 1.9 must be truncated to 1 + startNum = (int) startNumEval.getNumberValue(); + + NumericValueEval numCharsEval = (NumericValueEval) thirdveval; + numChars = (int) numCharsEval.getNumberValue(); + + StringValueEval newStrEval = (StringValueEval) fourthveval; + newStr = newStrEval.getStringValue(); + } else { + retval = ErrorEval.VALUE_INVALID; + } + } + + if (retval == null) { + if (startNum < 1 || numChars < 0) { + retval = ErrorEval.VALUE_INVALID; + } else { + StringBuffer strBuff = new StringBuffer(oldStr); + // remove any characters that should be replaced + if (startNum <= oldStr.length() && numChars != 0) { + strBuff.delete(startNum - 1, startNum - 1 + numChars); + } + // now insert (or append) newStr + if (startNum > strBuff.length()) { + strBuff.append(newStr); + } else { + strBuff.insert(startNum - 1, newStr); + } + retval = new StringEval(strBuff.toString()); + } + } + return retval; + } } diff --git a/src/scratchpad/src/org/apache/poi/hssf/record/formula/functions/Substitute.java b/src/scratchpad/src/org/apache/poi/hssf/record/formula/functions/Substitute.java index 8a975c569e..9d2e9ce361 100644 --- a/src/scratchpad/src/org/apache/poi/hssf/record/formula/functions/Substitute.java +++ b/src/scratchpad/src/org/apache/poi/hssf/record/formula/functions/Substitute.java @@ -20,6 +20,98 @@ */ package org.apache.poi.hssf.record.formula.functions; -public class Substitute extends NotImplementedFunction { +import org.apache.poi.hssf.record.formula.eval.ErrorEval; +import org.apache.poi.hssf.record.formula.eval.Eval; +import org.apache.poi.hssf.record.formula.eval.NumericValueEval; +import org.apache.poi.hssf.record.formula.eval.StringEval; +import org.apache.poi.hssf.record.formula.eval.StringValueEval; +import org.apache.poi.hssf.record.formula.eval.ValueEval; +/** + * An implementation of the SUBSTITUTE function: + * Substitutes text in a text string with new text, some number of times. + * @author Manda Wilson < wilson at c bio dot msk cc dot org > + */ +public class Substitute extends TextFunction { + private static final int REPLACE_ALL = -1; + + /** + *Substitutes text in a text string with new text, some number of times. + * + * @see org.apache.poi.hssf.record.formula.eval.Eval + */ + public Eval evaluate(Eval[] operands, int srcCellRow, short srcCellCol) { + Eval retval = null; + String oldStr = null; + String searchStr = null; + String newStr = null; + int numToReplace = REPLACE_ALL; + + switch (operands.length) { + default: + retval = ErrorEval.VALUE_INVALID; + case 4: + ValueEval fourthveval = singleOperandEvaluate(operands[3], srcCellRow, srcCellCol); + if (fourthveval instanceof NumericValueEval) { + NumericValueEval numToReplaceEval = (NumericValueEval) fourthveval; + // NOTE: it is safe to cast to int here + // because in Excel =SUBSTITUTE("teststr","t","T",1.9) + // returns Teststr + // so 1.9 must be truncated to 1 + numToReplace = (int) numToReplaceEval.getNumberValue(); + } else { + retval = ErrorEval.VALUE_INVALID; + } + case 3: + // first operand is text string containing characters to replace + // second operand is text to find + // third operand is replacement text + ValueEval firstveval = singleOperandEvaluate(operands[0], srcCellRow, srcCellCol); + ValueEval secondveval = singleOperandEvaluate(operands[1], srcCellRow, srcCellCol); + ValueEval thirdveval = singleOperandEvaluate(operands[2], srcCellRow, srcCellCol); + if (firstveval instanceof StringValueEval + && secondveval instanceof StringValueEval + && thirdveval instanceof StringValueEval) { + + StringValueEval oldStrEval = (StringValueEval) firstveval; + oldStr = oldStrEval.getStringValue(); + + StringValueEval searchStrEval = (StringValueEval) secondveval; + searchStr = searchStrEval.getStringValue(); + + StringValueEval newStrEval = (StringValueEval) thirdveval; + newStr = newStrEval.getStringValue(); + } else { + retval = ErrorEval.VALUE_INVALID; + } + } + + if (retval == null) { + if (numToReplace != REPLACE_ALL && numToReplace < 1) { + retval = ErrorEval.VALUE_INVALID; + } else if (searchStr.length() == 0) { + retval = new StringEval(oldStr); + } else { + StringBuffer strBuff = new StringBuffer(); + int startIndex = 0; + int nextMatch = -1; + for (int leftToReplace = numToReplace; + (leftToReplace > 0 || numToReplace == REPLACE_ALL) + && (nextMatch = oldStr.indexOf(searchStr, startIndex)) != -1; + leftToReplace--) { + // store everything from end of last match to start of this match + strBuff.append(oldStr.substring(startIndex, nextMatch)); + strBuff.append(newStr); + startIndex = nextMatch + searchStr.length(); + } + // store everything from end of last match to end of string + if (startIndex < oldStr.length()) { + strBuff.append(oldStr.substring(startIndex)); + } + retval = new StringEval(strBuff.toString()); + } + } + return retval; + } + } diff --git a/src/scratchpad/src/org/apache/poi/hssf/record/formula/functions/Trim.java b/src/scratchpad/src/org/apache/poi/hssf/record/formula/functions/Trim.java index 69b3ce6f55..5e9d91c7cc 100644 --- a/src/scratchpad/src/org/apache/poi/hssf/record/formula/functions/Trim.java +++ b/src/scratchpad/src/org/apache/poi/hssf/record/formula/functions/Trim.java @@ -14,12 +14,62 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -/* - * Created on May 15, 2005 - * - */ package org.apache.poi.hssf.record.formula.functions; -public class Trim extends NotImplementedFunction { +import org.apache.poi.hssf.record.formula.eval.BlankEval; +import org.apache.poi.hssf.record.formula.eval.ErrorEval; +import org.apache.poi.hssf.record.formula.eval.Eval; +import org.apache.poi.hssf.record.formula.eval.NumberEval; +import org.apache.poi.hssf.record.formula.eval.StringEval; +import org.apache.poi.hssf.record.formula.eval.StringValueEval; +import org.apache.poi.hssf.record.formula.eval.ValueEval; + +/** + * An implementation of the TRIM function: + * Removes leading and trailing spaces from value if evaluated operand + * value is string. + * @author Manda Wilson < wilson at c bio dot msk cc dot org > + */ +public class Trim extends TextFunction { + /** + * Removes leading and trailing spaces from value if evaluated + * operand value is string. + * Returns StringEval only if evaluated operand is of type string + * (and is not blank or null) or number. If evaluated operand is + * of type string and is blank or null, or if evaluated operand is + * of type blank, returns BlankEval. Otherwise returns ErrorEval. + * + * @see org.apache.poi.hssf.record.formula.eval.Eval + */ + public Eval evaluate(Eval[] operands, int srcCellRow, short srcCellCol) { + Eval retval = ErrorEval.VALUE_INVALID; + String str = null; + + switch (operands.length) { + default: + break; + case 1: + ValueEval veval = singleOperandEvaluate(operands[0], srcCellRow, srcCellCol); + if (veval instanceof StringValueEval) { + StringValueEval sve = (StringValueEval) veval; + str = sve.getStringValue(); + if (str == null || str.trim().equals("")) { + return BlankEval.INSTANCE; + } + } + else if (veval instanceof NumberEval) { + NumberEval neval = (NumberEval) veval; + str = neval.getStringValue(); + } + else if (veval instanceof BlankEval) { + return BlankEval.INSTANCE; + } + } + + if (str != null) { + retval = new StringEval(str.trim()); + } + return retval; + } } diff --git a/src/scratchpad/src/org/apache/poi/hssf/record/formula/functions/Year.java b/src/scratchpad/src/org/apache/poi/hssf/record/formula/functions/Year.java index 76ea617cc6..b461a09668 100644 --- a/src/scratchpad/src/org/apache/poi/hssf/record/formula/functions/Year.java +++ b/src/scratchpad/src/org/apache/poi/hssf/record/formula/functions/Year.java @@ -51,7 +51,7 @@ public class Year extends NumericFunction { if (ve instanceof NumericValueEval) { NumericValueEval ne = (NumericValueEval) ve; if (HSSFDateUtil.isValidExcelDate(ne.getNumberValue())) { - java.util.Date d = HSSFDateUtil.getJavaDate(ne.getNumberValue()); + java.util.Date d = HSSFDateUtil.getJavaDate(ne.getNumberValue(), false); // XXX fix 1900/1904 problem retval = new NumberEval(d.getYear()+1900); } else { retval = ErrorEval.NUM_ERROR; diff --git a/src/scratchpad/src/org/apache/poi/hwpf/model/ListTables.java b/src/scratchpad/src/org/apache/poi/hwpf/model/ListTables.java index cec20c91e6..4196566d9a 100644 --- a/src/scratchpad/src/org/apache/poi/hwpf/model/ListTables.java +++ b/src/scratchpad/src/org/apache/poi/hwpf/model/ListTables.java @@ -19,6 +19,8 @@ package org.apache.poi.hwpf.model; import org.apache.poi.util.LittleEndian; +import org.apache.poi.util.POILogFactory; +import org.apache.poi.util.POILogger; import org.apache.poi.hwpf.model.io.*; @@ -37,6 +39,7 @@ public class ListTables { private static final int LIST_DATA_SIZE = 28; private static final int LIST_FORMAT_OVERRIDE_SIZE = 16; + private static POILogger log = POILogFactory.getLogger(ListTables.class); HashMap _listMap = new HashMap(); ArrayList _overrideList = new ArrayList(); @@ -189,8 +192,13 @@ public class ListTables public ListLevel getLevel(int listID, int level) { ListData lst = (ListData)_listMap.get(new Integer(listID)); - ListLevel lvl = lst.getLevels()[level]; - return lvl; + if(level < lst.numLevels()) { + ListLevel lvl = lst.getLevels()[level]; + return lvl; + } else { + log.log(POILogger.WARN, "Requested level " + level + " which was greater than the maximum defined (" + lst.numLevels() + ")"); + return null; + } } public ListData getListData(int listID) diff --git a/src/scratchpad/src/org/apache/poi/hwpf/sprm/TableSprmUncompressor.java b/src/scratchpad/src/org/apache/poi/hwpf/sprm/TableSprmUncompressor.java index 87547565f2..f8fc91f123 100644 --- a/src/scratchpad/src/org/apache/poi/hwpf/sprm/TableSprmUncompressor.java +++ b/src/scratchpad/src/org/apache/poi/hwpf/sprm/TableSprmUncompressor.java @@ -148,8 +148,10 @@ public class TableSprmUncompressor for (int x = 0; x < itcMac; x++) { - if(hasTCs) rgtc[x] = TableCellDescriptor.convertBytesToTC(grpprl, - offset + (1 + ( (itcMac + 1) * 2) + (x * 20))); + // Sometimes, the grpprl does not contain data at every offset. I have no idea why this happens. + if(hasTCs && offset + (1 + ( (itcMac + 1) * 2) + (x * 20)) < grpprl.length) + rgtc[x] = TableCellDescriptor.convertBytesToTC(grpprl, + offset + (1 + ( (itcMac + 1) * 2) + (x * 20))); else rgtc[x] = new TableCellDescriptor(); } diff --git a/src/scratchpad/src/org/apache/poi/hwpf/usermodel/ListEntry.java b/src/scratchpad/src/org/apache/poi/hwpf/usermodel/ListEntry.java index 1b0ba626c2..9bafce7927 100644 --- a/src/scratchpad/src/org/apache/poi/hwpf/usermodel/ListEntry.java +++ b/src/scratchpad/src/org/apache/poi/hwpf/usermodel/ListEntry.java @@ -23,21 +23,28 @@ import org.apache.poi.hwpf.model.ListFormatOverrideLevel; import org.apache.poi.hwpf.model.ListLevel; import org.apache.poi.hwpf.model.ListTables; import org.apache.poi.hwpf.model.PAPX; - -import org.apache.poi.hwpf.sprm.SprmBuffer; +import org.apache.poi.util.POILogFactory; +import org.apache.poi.util.POILogger; public class ListEntry extends Paragraph { - ListLevel _level; - ListFormatOverrideLevel _overrideLevel; + private static POILogger log = POILogFactory.getLogger(ListEntry.class); + + ListLevel _level; + ListFormatOverrideLevel _overrideLevel; ListEntry(PAPX papx, Range parent, ListTables tables) { super(papx, parent); - ListFormatOverride override = tables.getOverride(_props.getIlfo()); - _overrideLevel = override.getOverrideLevel(_props.getIlvl()); - _level = tables.getLevel(override.getLsid(), _props.getIlvl()); + + if(tables != null) { + ListFormatOverride override = tables.getOverride(_props.getIlfo()); + _overrideLevel = override.getOverrideLevel(_props.getIlvl()); + _level = tables.getLevel(override.getLsid(), _props.getIlvl()); + } else { + log.log(POILogger.WARN, "No ListTables found for ListEntry - document probably partly corrupt, and you may experience problems"); + } } public int type() diff --git a/src/scratchpad/testcases/org/apache/poi/hslf/data/43781.ppt b/src/scratchpad/testcases/org/apache/poi/hslf/data/43781.ppt new file mode 100755 index 0000000000..ddea91fe89 Binary files /dev/null and b/src/scratchpad/testcases/org/apache/poi/hslf/data/43781.ppt differ diff --git a/src/scratchpad/testcases/org/apache/poi/hslf/data/sample.pptx b/src/scratchpad/testcases/org/apache/poi/hslf/data/sample.pptx new file mode 100644 index 0000000000..fbd540c1e0 Binary files /dev/null and b/src/scratchpad/testcases/org/apache/poi/hslf/data/sample.pptx differ diff --git a/src/scratchpad/testcases/org/apache/poi/hslf/usermodel/TestBugs.java b/src/scratchpad/testcases/org/apache/poi/hslf/usermodel/TestBugs.java index 933aa176b7..996a733ac9 100644 --- a/src/scratchpad/testcases/org/apache/poi/hslf/usermodel/TestBugs.java +++ b/src/scratchpad/testcases/org/apache/poi/hslf/usermodel/TestBugs.java @@ -25,6 +25,7 @@ import org.apache.poi.hslf.model.Shape; import java.io.*; import java.util.HashSet; import java.util.HashMap; +import java.util.ArrayList; import java.awt.*; /** @@ -298,4 +299,35 @@ public class TestBugs extends TestCase { } + /** + * Bug 38256: RuntimeException: Couldn't instantiate the class for type with id 0. + * ( also fixed followup: getTextRuns() returns no text ) + */ + public void test43781 () throws Exception { + FileInputStream is = new FileInputStream(new File(cwd, "43781.ppt")); + SlideShow ppt = new SlideShow(is); + is.close(); + + assertTrue("No Exceptions while reading file", true); + + Slide slide = ppt.getSlides()[0]; + TextRun[] tr1 = slide.getTextRuns(); + + ArrayList lst = new ArrayList(); + Shape[] shape = slide.getShapes(); + for (int i = 0; i < shape.length; i++) { + if( shape[i] instanceof TextBox){ + TextRun textRun = ((TextBox)shape[i]).getTextRun(); + if(textRun != null) lst.add(textRun); + } + + } + TextRun[] tr2 = new TextRun[lst.size()]; + lst.toArray(tr2); + + assertEquals(tr1.length, tr2.length); + for (int i = 0; i < tr1.length; i++) { + assertEquals(tr1[i].getText(), tr2[i].getText()); + } + } } diff --git a/src/scratchpad/testcases/org/apache/poi/hsmf/model/TestBlankFileRead.java b/src/scratchpad/testcases/org/apache/poi/hsmf/model/TestBlankFileRead.java index 05735870b4..314cc506c4 100644 --- a/src/scratchpad/testcases/org/apache/poi/hsmf/model/TestBlankFileRead.java +++ b/src/scratchpad/testcases/org/apache/poi/hsmf/model/TestBlankFileRead.java @@ -83,6 +83,21 @@ public class TestBlankFileRead extends TestCase { TestCase.assertEquals(obtained, expected); } + /** + * Test to see if we can read the FROM Chunk. + * @throws ChunkNotFoundException + * + */ + public void testReadDisplayFrom() throws ChunkNotFoundException { + try { + mapiMessage.getDisplayFrom(); + } catch(ChunkNotFoundException exp) { + return; + } + + TestCase.fail("Should have thrown a ChunkNotFoundException but didn't"); + } + /** * Test to see if we can read the CC Chunk. * @throws ChunkNotFoundException diff --git a/src/scratchpad/testcases/org/apache/poi/hsmf/model/TestSimpleFileRead.java b/src/scratchpad/testcases/org/apache/poi/hsmf/model/TestSimpleFileRead.java index 0ede68965a..925685218d 100644 --- a/src/scratchpad/testcases/org/apache/poi/hsmf/model/TestSimpleFileRead.java +++ b/src/scratchpad/testcases/org/apache/poi/hsmf/model/TestSimpleFileRead.java @@ -66,6 +66,18 @@ private MAPIMessage mapiMessage; TestCase.assertEquals(obtained, expected); } + /** + * Test to see if we can read the From Chunk. + * @throws ChunkNotFoundException + * + */ + public void testReadDisplayFrom() throws ChunkNotFoundException { + String obtained = mapiMessage.getDisplayFrom(); + String expected = "Travis Ferguson"; + + TestCase.assertEquals(obtained, expected); + } + /** * Test to see if we can read the CC Chunk. * @throws ChunkNotFoundException diff --git a/src/scratchpad/testcases/org/apache/poi/hssf/data/FormulaEvalTestData.xls b/src/scratchpad/testcases/org/apache/poi/hssf/data/FormulaEvalTestData.xls index b2388f1d03..cf4b6fa501 100644 Binary files a/src/scratchpad/testcases/org/apache/poi/hssf/data/FormulaEvalTestData.xls and b/src/scratchpad/testcases/org/apache/poi/hssf/data/FormulaEvalTestData.xls differ diff --git a/src/scratchpad/testcases/org/apache/poi/hssf/record/formula/eval/TestEverything.java b/src/scratchpad/testcases/org/apache/poi/hssf/record/formula/eval/TestEverything.java index d1ab0c7076..ac3ca2eb29 100644 --- a/src/scratchpad/testcases/org/apache/poi/hssf/record/formula/eval/TestEverything.java +++ b/src/scratchpad/testcases/org/apache/poi/hssf/record/formula/eval/TestEverything.java @@ -23,27 +23,37 @@ package org.apache.poi.hssf.record.formula.eval; import junit.framework.TestSuite; /** - * @author Amol S. Deshmukh < amolweb at ya hoo dot com > + * This is a test of all the Eval functions we have implemented. + * Add newly implemented Eval functions in here to have them + * tested. + * For newly implemented functions, + * @see org.apache.poi.hssf.record.formula.functions.TestEverything * + * @author Amol S. Deshmukh < amolweb at ya hoo dot com > */ public class TestEverything extends TestSuite { public static TestSuite suite() throws Exception { TestSuite suite = new TestSuite("Tests for OperationEval concrete implementation classes."); - suite.addTest(new GenericFormulaTestCase("D23")); - suite.addTest(new GenericFormulaTestCase("D27")); - suite.addTest(new GenericFormulaTestCase("D31")); - suite.addTest(new GenericFormulaTestCase("D35")); - suite.addTest(new GenericFormulaTestCase("D39")); - suite.addTest(new GenericFormulaTestCase("D43")); - suite.addTest(new GenericFormulaTestCase("D47")); - suite.addTest(new GenericFormulaTestCase("D51")); - suite.addTest(new GenericFormulaTestCase("D55")); - suite.addTest(new GenericFormulaTestCase("D59")); - suite.addTest(new GenericFormulaTestCase("D63")); - suite.addTest(new GenericFormulaTestCase("D67")); - suite.addTest(new GenericFormulaTestCase("D71")); - suite.addTest(new GenericFormulaTestCase("D75")); + suite.addTest(new GenericFormulaTestCase("D23")); // Add + suite.addTest(new GenericFormulaTestCase("D27")); // ConcatEval + suite.addTest(new GenericFormulaTestCase("D31")); // DivideEval + suite.addTest(new GenericFormulaTestCase("D35")); // EqualEval + suite.addTest(new GenericFormulaTestCase("D39")); // GreaterEqualEval + suite.addTest(new GenericFormulaTestCase("D43")); // GreaterThanEval + suite.addTest(new GenericFormulaTestCase("D47")); // LessEqualEval + suite.addTest(new GenericFormulaTestCase("D51")); // LessThanEval + suite.addTest(new GenericFormulaTestCase("D55")); // MultiplyEval + suite.addTest(new GenericFormulaTestCase("D59")); // NotEqualEval + suite.addTest(new GenericFormulaTestCase("D63")); // PowerEval + suite.addTest(new GenericFormulaTestCase("D67")); // SubtractEval + suite.addTest(new GenericFormulaTestCase("D71")); // UnaryMinusEval + suite.addTest(new GenericFormulaTestCase("D75")); // UnaryPlusEval + + // Add newly implemented Eval functions here + // (Formula functions go in + // @see org.apache.poi.hssf.record.formula.functions.TestEverything ) + return suite; } } diff --git a/src/scratchpad/testcases/org/apache/poi/hssf/record/formula/functions/TestEverything.java b/src/scratchpad/testcases/org/apache/poi/hssf/record/formula/functions/TestEverything.java index ad93996339..8337810216 100644 --- a/src/scratchpad/testcases/org/apache/poi/hssf/record/formula/functions/TestEverything.java +++ b/src/scratchpad/testcases/org/apache/poi/hssf/record/formula/functions/TestEverything.java @@ -25,11 +25,16 @@ import org.apache.poi.hssf.record.formula.eval.GenericFormulaTestCase; import junit.framework.TestSuite; /** - * @author Amol S. Deshmukh < amolweb at ya hoo dot com > + * This is a test of all the normal formula functions we have implemented. + * It should pick up newly implemented functions which are correctly added + * to the test formula excel file, but tweak the rows below if you + * add any past the end of what's currently checked. + * For newly implemented eval functions, + * @see org.apache.poi.hssf.record.formula.eval.TestEverything * + * @author Amol S. Deshmukh < amolweb at ya hoo dot com > */ public class TestEverything extends TestSuite { - public static TestSuite suite() throws Exception { TestSuite suite = new TestSuite("Tests for individual function classes"); String s; diff --git a/src/scratchpad/testcases/org/apache/poi/hwpf/data/AIOOB-Tap.doc b/src/scratchpad/testcases/org/apache/poi/hwpf/data/AIOOB-Tap.doc new file mode 100644 index 0000000000..bfd5906caa Binary files /dev/null and b/src/scratchpad/testcases/org/apache/poi/hwpf/data/AIOOB-Tap.doc differ diff --git a/src/scratchpad/testcases/org/apache/poi/hwpf/data/IllustrativeCases.docx b/src/scratchpad/testcases/org/apache/poi/hwpf/data/IllustrativeCases.docx new file mode 100644 index 0000000000..29dacb652e Binary files /dev/null and b/src/scratchpad/testcases/org/apache/poi/hwpf/data/IllustrativeCases.docx differ diff --git a/src/scratchpad/testcases/org/apache/poi/hwpf/data/ListEntryNoListTable.doc b/src/scratchpad/testcases/org/apache/poi/hwpf/data/ListEntryNoListTable.doc new file mode 100644 index 0000000000..939f5a4a9e Binary files /dev/null and b/src/scratchpad/testcases/org/apache/poi/hwpf/data/ListEntryNoListTable.doc differ diff --git a/src/scratchpad/testcases/org/apache/poi/hwpf/data/sample.docx b/src/scratchpad/testcases/org/apache/poi/hwpf/data/sample.docx new file mode 100644 index 0000000000..8dd04bcdb8 Binary files /dev/null and b/src/scratchpad/testcases/org/apache/poi/hwpf/data/sample.docx differ diff --git a/src/scratchpad/testcases/org/apache/poi/hwpf/usermodel/TestProblems.java b/src/scratchpad/testcases/org/apache/poi/hwpf/usermodel/TestProblems.java new file mode 100644 index 0000000000..8e7f47ed96 --- /dev/null +++ b/src/scratchpad/testcases/org/apache/poi/hwpf/usermodel/TestProblems.java @@ -0,0 +1,77 @@ +/* +* 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.hwpf.usermodel; + +import java.io.ByteArrayOutputStream; +import java.io.FileInputStream; +import java.util.Iterator; +import java.util.List; + +import org.apache.poi.hwpf.HWPFDocument; +import org.apache.poi.hwpf.model.StyleSheet; +import org.apache.poi.hwpf.model.TextPiece; +import org.apache.poi.hwpf.usermodel.Paragraph; +import org.apache.poi.hwpf.usermodel.Range; +import org.apache.poi.util.LittleEndian; + +import junit.framework.TestCase; + +/** + * Test various problem documents + * + * @author Nick Burch (nick at torchbox dot com) + */ +public class TestProblems extends TestCase { + private String dirname = System.getProperty("HWPF.testdata.path"); + + protected void setUp() throws Exception { + } + + /** + * ListEntry passed no ListTable + */ + public void testListEntryNoListTable() throws Exception { + HWPFDocument doc = new HWPFDocument(new FileInputStream(dirname + "/ListEntryNoListTable.doc")); + + Range r = doc.getRange(); + StyleSheet styleSheet = doc.getStyleSheet(); + for (int x = 0; x < r.numSections(); x++) { + Section s = r.getSection(x); + for (int y = 0; y < s.numParagraphs(); y++) { + Paragraph paragraph = s.getParagraph(y); + //System.out.println(paragraph.getCharacterRun(0).text()); + } + } + } + + /** + * AIOOB for TableSprmUncompressor.unCompressTAPOperation + */ + public void testSprmAIOOB() throws Exception { + HWPFDocument doc = new HWPFDocument(new FileInputStream(dirname + "/AIOOB-Tap.doc")); + + Range r = doc.getRange(); + StyleSheet styleSheet = doc.getStyleSheet(); + for (int x = 0; x < r.numSections(); x++) { + Section s = r.getSection(x); + for (int y = 0; y < s.numParagraphs(); y++) { + Paragraph paragraph = s.getParagraph(y); + //System.out.println(paragraph.getCharacterRun(0).text()); + } + } + } +} diff --git a/src/testcases/org/apache/poi/hssf/data/1900DateWindowing.xls b/src/testcases/org/apache/poi/hssf/data/1900DateWindowing.xls index e6d966456e..94fe5c1bec 100644 Binary files a/src/testcases/org/apache/poi/hssf/data/1900DateWindowing.xls and b/src/testcases/org/apache/poi/hssf/data/1900DateWindowing.xls differ diff --git a/src/testcases/org/apache/poi/hssf/data/1904DateWindowing.xls b/src/testcases/org/apache/poi/hssf/data/1904DateWindowing.xls index 142d3148f3..8c0dba1d7a 100644 Binary files a/src/testcases/org/apache/poi/hssf/data/1904DateWindowing.xls and b/src/testcases/org/apache/poi/hssf/data/1904DateWindowing.xls differ diff --git a/src/testcases/org/apache/poi/hssf/data/AverageTaxRates.xlsx b/src/testcases/org/apache/poi/hssf/data/AverageTaxRates.xlsx new file mode 100644 index 0000000000..fee8059e2b Binary files /dev/null and b/src/testcases/org/apache/poi/hssf/data/AverageTaxRates.xlsx differ diff --git a/src/testcases/org/apache/poi/hssf/data/SimpleWithColours.xls b/src/testcases/org/apache/poi/hssf/data/SimpleWithColours.xls new file mode 100755 index 0000000000..ab3cdecf0b Binary files /dev/null and b/src/testcases/org/apache/poi/hssf/data/SimpleWithColours.xls differ diff --git a/src/testcases/org/apache/poi/hssf/data/StringContinueRecords.xls b/src/testcases/org/apache/poi/hssf/data/StringContinueRecords.xls new file mode 100644 index 0000000000..f2ada9eb28 Binary files /dev/null and b/src/testcases/org/apache/poi/hssf/data/StringContinueRecords.xls differ diff --git a/src/testcases/org/apache/poi/hssf/data/Tables.xlsx b/src/testcases/org/apache/poi/hssf/data/Tables.xlsx new file mode 100644 index 0000000000..705e0ae373 Binary files /dev/null and b/src/testcases/org/apache/poi/hssf/data/Tables.xlsx differ diff --git a/src/testcases/org/apache/poi/hssf/data/TestDataValidation.xls b/src/testcases/org/apache/poi/hssf/data/TestDataValidation.xls new file mode 100644 index 0000000000..6b71a77f2d Binary files /dev/null and b/src/testcases/org/apache/poi/hssf/data/TestDataValidation.xls differ diff --git a/src/testcases/org/apache/poi/hssf/data/TwoSheetsNoneHidden.xls b/src/testcases/org/apache/poi/hssf/data/TwoSheetsNoneHidden.xls new file mode 100644 index 0000000000..969f01408e Binary files /dev/null and b/src/testcases/org/apache/poi/hssf/data/TwoSheetsNoneHidden.xls differ diff --git a/src/testcases/org/apache/poi/hssf/data/TwoSheetsOneHidden.xls b/src/testcases/org/apache/poi/hssf/data/TwoSheetsOneHidden.xls new file mode 100644 index 0000000000..940ffc0582 Binary files /dev/null and b/src/testcases/org/apache/poi/hssf/data/TwoSheetsOneHidden.xls differ diff --git a/src/testcases/org/apache/poi/hssf/data/sample-beta.xlsx b/src/testcases/org/apache/poi/hssf/data/sample-beta.xlsx new file mode 100644 index 0000000000..2eb36ee2a0 Binary files /dev/null and b/src/testcases/org/apache/poi/hssf/data/sample-beta.xlsx differ diff --git a/src/testcases/org/apache/poi/hssf/data/sample.xlsx b/src/testcases/org/apache/poi/hssf/data/sample.xlsx index 2eb36ee2a0..a275cf417e 100644 Binary files a/src/testcases/org/apache/poi/hssf/data/sample.xlsx and b/src/testcases/org/apache/poi/hssf/data/sample.xlsx differ diff --git a/src/testcases/org/apache/poi/hssf/data/templateExcelWithAutofilter.xls b/src/testcases/org/apache/poi/hssf/data/templateExcelWithAutofilter.xls new file mode 100644 index 0000000000..5813fde385 Binary files /dev/null and b/src/testcases/org/apache/poi/hssf/data/templateExcelWithAutofilter.xls differ diff --git a/src/testcases/org/apache/poi/hssf/extractor/TestExcelExtractor.java b/src/testcases/org/apache/poi/hssf/extractor/TestExcelExtractor.java index 027495a1b0..0aef5c765a 100644 --- a/src/testcases/org/apache/poi/hssf/extractor/TestExcelExtractor.java +++ b/src/testcases/org/apache/poi/hssf/extractor/TestExcelExtractor.java @@ -68,6 +68,19 @@ public class TestExcelExtractor extends TestCase { ); } + public void testwithContinueRecords() throws Exception { + String path = System.getProperty("HSSF.testdata.path"); + FileInputStream fin = new FileInputStream(path + File.separator + "StringContinueRecords.xls"); + + ExcelExtractor extractor = new ExcelExtractor(new POIFSFileSystem(fin)); + + extractor.getText(); + + // Has masses of text + // Until we fixed bug #41064, this would've + // failed by now + assertTrue(extractor.getText().length() > 40960); + } public void testStringConcat() throws Exception { String path = System.getProperty("HSSF.testdata.path"); diff --git a/src/testcases/org/apache/poi/hssf/usermodel/TestDataValidation.java b/src/testcases/org/apache/poi/hssf/usermodel/TestDataValidation.java new file mode 100644 index 0000000000..f970ff26f1 --- /dev/null +++ b/src/testcases/org/apache/poi/hssf/usermodel/TestDataValidation.java @@ -0,0 +1,910 @@ +/* ==================================================================== + Copyright 2002-2004 Apache Software Foundation + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +==================================================================== */ + +package org.apache.poi.hssf.usermodel; + +import junit.framework.TestCase; + +import org.apache.poi.hssf.util.*; + +import java.io.*; +import java.util.*; +import java.text.SimpleDateFormat; + +/** + *

    Title: TestDataValidation

    + *

    Description: Class for testing Excel's data validation mechanism + * Second test : + * - + *

    + * @author Dragos Buleandra ( dragos.buleandra@trade2b.ro ) + */ +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 + { + System.out.println("\nTest no. 2 - Test Excel's Data validation mechanism"); + String resultFile = System.getProperty("HSSF.testdata.path")+"/TestDataValidation.xls"; + HSSFWorkbook wb = new HSSFWorkbook(); + + HSSFCellStyle style_1 = this.createStyle( wb, HSSFCellStyle.ALIGN_LEFT ); + HSSFCellStyle style_2 = this.createStyle( wb, HSSFCellStyle.ALIGN_CENTER ); + HSSFCellStyle style_3 = this.createStyle( wb, HSSFCellStyle.ALIGN_CENTER, HSSFColor.GREY_25_PERCENT.index, true ); + HSSFCellStyle style_4 = this.createHeaderStyle(wb); + HSSFDataValidation data_validation = null; + + //data validation's number types + System.out.print(" Create sheet for Data Validation's number types ... "); + HSSFSheet fSheet = wb.createSheet("Number types"); + + //"Whole number" validation type + this.createDVTypeRow( wb, 0, style_3, "Whole number"); + this.createHeaderRow( wb, 0, style_4 ); + + short start_row = (short)fSheet.getPhysicalNumberOfRows(); + data_validation = new HSSFDataValidation((short)(start_row),(short)0,(short)(start_row),(short)0); + data_validation.setDataValidationType(HSSFDataValidation.DATA_TYPE_INTEGER); + data_validation.setOperator(HSSFDataValidation.OPERATOR_BETWEEN); + data_validation.setFirstFormula("2"); + data_validation.setSecondFormula("6"); + data_validation.createErrorBox("Invalid input !", "Something is wrong ; check condition !"); + data_validation.createPromptBox("Hi , dear user !", "So , you just selected me ! Thanks !"); + fSheet.addValidationData(data_validation); + this.writeDataValidationSettings( fSheet, style_1, style_2, "Between 2 and 6 ", true, true, true ); + this.writeOtherSettings( fSheet, style_1, "Error box type = STOP" ); + + data_validation.setFirstRow((short)(start_row+1)); + data_validation.setLastRow((short)(start_row+1)); + data_validation.setEmptyCellAllowed(false); + data_validation.setOperator(HSSFDataValidation.OPERATOR_NOT_BETWEEN); + data_validation.setErrorStyle(HSSFDataValidation.ERROR_STYLE_INFO); + fSheet.addValidationData(data_validation); + this.writeDataValidationSettings( fSheet, style_1, style_2, "Not between 2 and 6 ", false, true, true ); + this.writeOtherSettings( fSheet, style_1, "Error box type = INFO" ); + + data_validation.setFirstRow((short)(start_row+2)); + data_validation.setLastRow((short)(start_row+2)); + data_validation.setEmptyCellAllowed(false); + data_validation.setShowPromptBox(false); + data_validation.setFirstFormula("3"); + data_validation.setSecondFormula(null); + data_validation.setOperator(HSSFDataValidation.OPERATOR_EQUAL); + data_validation.setErrorStyle(HSSFDataValidation.ERROR_STYLE_WARNING); + fSheet.addValidationData(data_validation); + this.writeDataValidationSettings( fSheet, style_1, style_2, "Equal to 3", false, false, true ); + this.writeOtherSettings( fSheet, style_1, "Error box type = WARNING" ); + + data_validation.setFirstRow((short)(start_row+3)); + data_validation.setLastRow((short)(start_row+3)); + data_validation.setEmptyCellAllowed(false); + data_validation.setShowPromptBox(false); + data_validation.setShowErrorBox(false); + data_validation.setFirstFormula("3"); + data_validation.setSecondFormula(null); + data_validation.setOperator(HSSFDataValidation.OPERATOR_NOT_EQUAL); + fSheet.addValidationData(data_validation); + this.writeDataValidationSettings( fSheet, style_1, style_2, "Not equal to 3", false, false, false ); + this.writeOtherSettings( fSheet, style_1, "-" ); + + data_validation.setFirstRow((short)(start_row+4)); + data_validation.setLastRow((short)(start_row+4)); + data_validation.setEmptyCellAllowed(true); + data_validation.setShowPromptBox(false); + data_validation.setShowErrorBox(false); + data_validation.setFirstFormula("3"); + data_validation.setSecondFormula(null); + data_validation.setOperator(HSSFDataValidation.OPERATOR_GREATER_THAN); + fSheet.addValidationData(data_validation); + this.writeDataValidationSettings( fSheet, style_1, style_2, "Greater than 3", true, false, false ); + this.writeOtherSettings( fSheet, style_1, "-" ); + + data_validation.setFirstRow((short)(start_row+5)); + data_validation.setLastRow((short)(start_row+5)); + data_validation.setEmptyCellAllowed(true); + data_validation.setShowPromptBox(true); + data_validation.setShowErrorBox(false); + data_validation.setFirstFormula("3"); + data_validation.setSecondFormula(null); + data_validation.setOperator(HSSFDataValidation.OPERATOR_LESS_THAN); + fSheet.addValidationData(data_validation); + this.writeDataValidationSettings( fSheet, style_1, style_2, "Less than 3", true, true, false ); + this.writeOtherSettings( fSheet, style_1, "-" ); + + data_validation.setFirstRow((short)(start_row+6)); + data_validation.setLastRow((short)(start_row+6)); + data_validation.setEmptyCellAllowed(true); + data_validation.setShowPromptBox(false); + data_validation.setErrorStyle(HSSFDataValidation.ERROR_STYLE_STOP); + data_validation.setShowErrorBox(true); + data_validation.setFirstFormula("4"); + data_validation.setSecondFormula(null); + data_validation.setOperator(HSSFDataValidation.OPERATOR_GREATER_OR_EQUAL); + fSheet.addValidationData(data_validation); + this.writeDataValidationSettings( fSheet, style_1, style_2, "Greater than or equal to 4", true, false, true ); + this.writeOtherSettings( fSheet, style_1, "Error box type = STOP" ); + + data_validation.setFirstRow((short)(start_row+7)); + data_validation.setLastRow((short)(start_row+7)); + data_validation.setEmptyCellAllowed(false); + data_validation.setShowPromptBox(true); + data_validation.setShowErrorBox(false); + data_validation.setFirstFormula("4"); + data_validation.setSecondFormula(null); + data_validation.setOperator(HSSFDataValidation.OPERATOR_LESS_OR_EQUAL); + fSheet.addValidationData(data_validation); + this.writeDataValidationSettings( fSheet, style_1, style_2, "Less than or equal to 4", false, true, false ); + this.writeOtherSettings( fSheet, style_1, "-" ); + + //"Decimal" validation type + this.createDVTypeRow( wb, 0, style_3, "Decimal"); + this.createHeaderRow( wb, 0, style_4 ); + + start_row += (short)(8+4); + data_validation = new HSSFDataValidation((short)(start_row),(short)0,(short)(start_row),(short)0); + data_validation.setDataValidationType(HSSFDataValidation.DATA_TYPE_DECIMAL); + data_validation.setOperator(HSSFDataValidation.OPERATOR_BETWEEN); + data_validation.setFirstFormula("2"); + data_validation.setSecondFormula("6"); + data_validation.createErrorBox("Invalid input !", "Something is wrong ; check condition !"); + data_validation.createPromptBox("Hi , dear user !", "So , you just selected me ! Thanks !"); + fSheet.addValidationData(data_validation); + this.writeDataValidationSettings( fSheet, style_1, style_2, "Between 2 and 6 ", true, true, true ); + this.writeOtherSettings( fSheet, style_1, "Error box type = STOP" ); + + data_validation.setFirstRow((short)(start_row+1)); + data_validation.setLastRow((short)(start_row+1)); + data_validation.setEmptyCellAllowed(false); + data_validation.setOperator(HSSFDataValidation.OPERATOR_NOT_BETWEEN); + data_validation.setErrorStyle(HSSFDataValidation.ERROR_STYLE_INFO); + fSheet.addValidationData(data_validation); + this.writeDataValidationSettings( fSheet, style_1, style_2, "Not between 2 and 6 ", false, true, true ); + this.writeOtherSettings( fSheet, style_1, "Error box type = INFO" ); + + data_validation.setFirstRow((short)(start_row+2)); + data_validation.setLastRow((short)(start_row+2)); + data_validation.setEmptyCellAllowed(false); + data_validation.setShowPromptBox(false); + data_validation.setFirstFormula("3"); + data_validation.setSecondFormula(null); + data_validation.setOperator(HSSFDataValidation.OPERATOR_EQUAL); + data_validation.setErrorStyle(HSSFDataValidation.ERROR_STYLE_WARNING); + fSheet.addValidationData(data_validation); + this.writeDataValidationSettings( fSheet, style_1, style_2, "Equal to 3", false, false, true ); + this.writeOtherSettings( fSheet, style_1, "Error box type = WARNING" ); + + data_validation.setFirstRow((short)(start_row+3)); + data_validation.setLastRow((short)(start_row+3)); + data_validation.setEmptyCellAllowed(false); + data_validation.setShowPromptBox(false); + data_validation.setShowErrorBox(false); + data_validation.setFirstFormula("3"); + data_validation.setSecondFormula(null); + data_validation.setOperator(HSSFDataValidation.OPERATOR_NOT_EQUAL); + fSheet.addValidationData(data_validation); + this.writeDataValidationSettings( fSheet, style_1, style_2, "Not equal to 3", false, false, false ); + this.writeOtherSettings( fSheet, style_1, "-" ); + + data_validation.setFirstRow((short)(start_row+4)); + data_validation.setLastRow((short)(start_row+4)); + data_validation.setEmptyCellAllowed(true); + data_validation.setShowPromptBox(false); + data_validation.setShowErrorBox(false); + data_validation.setFirstFormula("3"); + data_validation.setSecondFormula(null); + data_validation.setOperator(HSSFDataValidation.OPERATOR_GREATER_THAN); + fSheet.addValidationData(data_validation); + this.writeDataValidationSettings( fSheet, style_1, style_2, "Greater than 3", true, false, false ); + this.writeOtherSettings( fSheet, style_1, "-" ); + + data_validation.setFirstRow((short)(start_row+5)); + data_validation.setLastRow((short)(start_row+5)); + data_validation.setEmptyCellAllowed(true); + data_validation.setShowPromptBox(true); + data_validation.setShowErrorBox(false); + data_validation.setFirstFormula("3"); + data_validation.setSecondFormula(null); + data_validation.setOperator(HSSFDataValidation.OPERATOR_LESS_THAN); + fSheet.addValidationData(data_validation); + this.writeDataValidationSettings( fSheet, style_1, style_2, "Less than 3", true, true, false ); + this.writeOtherSettings( fSheet, style_1, "-" ); + + data_validation.setFirstRow((short)(start_row+6)); + data_validation.setLastRow((short)(start_row+6)); + data_validation.setEmptyCellAllowed(true); + data_validation.setShowPromptBox(false); + data_validation.setErrorStyle(HSSFDataValidation.ERROR_STYLE_STOP); + data_validation.setShowErrorBox(true); + data_validation.setFirstFormula("4"); + data_validation.setSecondFormula(null); + data_validation.setOperator(HSSFDataValidation.OPERATOR_GREATER_OR_EQUAL); + fSheet.addValidationData(data_validation); + this.writeDataValidationSettings( fSheet, style_1, style_2, "Greater than or equal to 4", true, false, true ); + this.writeOtherSettings( fSheet, style_1, "Error box type = STOP" ); + + data_validation.setFirstRow((short)(start_row+7)); + data_validation.setLastRow((short)(start_row+7)); + data_validation.setEmptyCellAllowed(false); + data_validation.setShowPromptBox(true); + data_validation.setShowErrorBox(false); + data_validation.setFirstFormula("4"); + data_validation.setSecondFormula(null); + data_validation.setOperator(HSSFDataValidation.OPERATOR_LESS_OR_EQUAL); + fSheet.addValidationData(data_validation); + this.writeDataValidationSettings( fSheet, style_1, style_2, "Less than or equal to 4", false, true, false ); + this.writeOtherSettings( fSheet, style_1, "-" ); + + System.out.println("done !"); + + //"List" Data Validation type + /** @todo List*/ + System.out.print(" Create sheet for 'List' Data Validation type ... "); + fSheet = wb.createSheet("Lists"); + + this.createDVTypeRow( wb, 1, style_3, "Explicit lists - list items are explicitly provided"); + this.createDVDeescriptionRow( wb, 1, style_3, "Disadvantage - sum of item's length should be less than 255 characters"); + this.createHeaderRow( wb, 1, style_4 ); + + start_row = (short)fSheet.getPhysicalNumberOfRows(); + data_validation = new HSSFDataValidation((short)(start_row),(short)0,(short)(start_row),(short)0); + data_validation.setDataValidationType(HSSFDataValidation.DATA_TYPE_LIST); + data_validation.setFirstFormula("1+2+3"); + data_validation.setSecondFormula(null); + data_validation.setSurppressDropDownArrow(false); + data_validation.createErrorBox("Invalid input !", "Something is wrong ; check condition !"); + data_validation.createPromptBox("Hi , dear user !", "So , you just selected me ! Thanks !"); + fSheet.addValidationData(data_validation); + this.writeDataValidationSettings( fSheet, style_1, style_2, "POIFS,HSSF,HWPF,HPSF", true, true, true ); + this.writeOtherSettings( fSheet, style_1, "Error box type=STOP ; In-cell dropdown=yes" ); + + data_validation = new HSSFDataValidation((short)(start_row+1),(short)0,(short)(start_row+1),(short)0); + data_validation.setDataValidationType(HSSFDataValidation.DATA_TYPE_LIST); + data_validation.setFirstFormula("4+5+6+7"); + data_validation.setSecondFormula(null); + data_validation.setSurppressDropDownArrow(false); + data_validation.setEmptyCellAllowed(false); + data_validation.setShowPromptBox(false); + data_validation.createErrorBox("Invalid input !", "Something is wrong ; check condition !"); + fSheet.addValidationData(data_validation); + this.writeDataValidationSettings( fSheet, style_1, style_2, "POIFS,HSSF,HWPF,HPSF", false, false, true ); + this.writeOtherSettings( fSheet, style_1, "Error box type=STOP ; In-cell dropdown=yes" ); + + data_validation = new HSSFDataValidation((short)(start_row+2),(short)0,(short)(start_row+2),(short)0); + data_validation.setDataValidationType(HSSFDataValidation.DATA_TYPE_LIST); + data_validation.setFirstFormula("7+21"); + data_validation.setSecondFormula(null); + data_validation.setSurppressDropDownArrow(true); + data_validation.createErrorBox("Invalid input !", "Something is wrong ; check condition !"); + data_validation.createPromptBox("Hi , dear user !", "So , you just selected me ! Thanks !"); + fSheet.addValidationData(data_validation); + this.writeDataValidationSettings( fSheet, style_1, style_2, "POIFS,HSSF,HWPF,HPSF", true, true, true ); + this.writeOtherSettings( fSheet, style_1, "Error box type=STOP ; In-cell dropdown=no" ); + + data_validation = new HSSFDataValidation((short)(start_row+3),(short)0,(short)(start_row+3),(short)0); + data_validation.setDataValidationType(HSSFDataValidation.DATA_TYPE_LIST); + data_validation.setFirstFormula("8/2"); + data_validation.setSecondFormula(null); + data_validation.setSurppressDropDownArrow(true); + data_validation.createErrorBox("Invalid input !", "Something is wrong ; check condition !"); + data_validation.setEmptyCellAllowed(false); + data_validation.setShowPromptBox(false); + fSheet.addValidationData(data_validation); + this.writeDataValidationSettings( fSheet, style_1, style_2, "POIFS,HSSF,HWPF,HPSF", false, false, true ); + this.writeOtherSettings( fSheet, style_1, "Error box type=STOP ; In-cell dropdown=no" ); + + this.createDVTypeRow( wb, 1, style_3, "Reference lists - list items are taken from others cells"); + this.createDVDeescriptionRow( wb, 1, style_3, "Advantage - no restriction regarding the sum of item's length"); + this.createHeaderRow( wb, 1, style_4 ); + + start_row += (short)(4+5); + String cellStrValue = "a b c d e f g h i j k l m n o p r s t u v x y z w 0 1 2 3 4 "+ + "a b c d e f g h i j k l m n o p r s t u v x y z w 0 1 2 3 4 "+ + "a b c d e f g h i j k l m n o p r s t u v x y z w 0 1 2 3 4 "+ + "a b c d e f g h i j k l m n o p r s t u v x y z w 0 1 2 3 4 "; + + String strFormula = "$A$100:$A$120"; + data_validation = new HSSFDataValidation((short)(start_row),(short)0,(short)(start_row),(short)0); + data_validation.setDataValidationType(HSSFDataValidation.DATA_TYPE_LIST); + data_validation.setFirstFormula(strFormula); + data_validation.setSecondFormula(null); + data_validation.setSurppressDropDownArrow(false); + data_validation.createErrorBox("Invalid input !", "Something is wrong ; check condition !"); + data_validation.createPromptBox("Hi , dear user !", "So , you just selected me ! Thanks !"); + fSheet.addValidationData(data_validation); + this.writeDataValidationSettings( fSheet, style_1, style_2, strFormula, true, true, true ); + this.writeOtherSettings( fSheet, style_1, "Error box type=STOP ; In-cell dropdown=yes" ); + + data_validation = new HSSFDataValidation((short)(start_row+1),(short)0,(short)(start_row+1),(short)0); + data_validation.setDataValidationType(HSSFDataValidation.DATA_TYPE_LIST); + data_validation.setFirstFormula(strFormula); + data_validation.setSecondFormula(null); + data_validation.setSurppressDropDownArrow(false); + data_validation.setEmptyCellAllowed(false); + data_validation.setShowPromptBox(false); + data_validation.createErrorBox("Invalid input !", "Something is wrong ; check condition !"); + fSheet.addValidationData(data_validation); + this.writeDataValidationSettings( fSheet, style_1, style_2, strFormula, false, false, true ); + this.writeOtherSettings( fSheet, style_1, "Error box type=STOP ; In-cell dropdown=yes" ); + + data_validation = new HSSFDataValidation((short)(start_row+2),(short)0,(short)(start_row+2),(short)0); + data_validation.setDataValidationType(HSSFDataValidation.DATA_TYPE_LIST); + data_validation.setFirstFormula(strFormula); + data_validation.setSecondFormula(null); + data_validation.setSurppressDropDownArrow(true); + data_validation.createErrorBox("Invalid input !", "Something is wrong ; check condition !"); + data_validation.createPromptBox("Hi , dear user !", "So , you just selected me ! Thanks !"); + fSheet.addValidationData(data_validation); + this.writeDataValidationSettings( fSheet, style_1, style_2, strFormula, true, true, true ); + this.writeOtherSettings( fSheet, style_1, "Error box type=STOP ; In-cell dropdown=no" ); + + data_validation = new HSSFDataValidation((short)(start_row+3),(short)0,(short)(start_row+3),(short)0); + data_validation.setDataValidationType(HSSFDataValidation.DATA_TYPE_LIST); + data_validation.setFirstFormula(strFormula); + data_validation.setSecondFormula(null); + data_validation.setSurppressDropDownArrow(true); + data_validation.createErrorBox("Invalid input !", "Something is wrong ; check condition !"); + data_validation.setEmptyCellAllowed(false); + data_validation.setShowPromptBox(false); + fSheet.addValidationData(data_validation); + this.writeDataValidationSettings( fSheet, style_1, style_2, strFormula, false, false, true ); + this.writeOtherSettings( fSheet, style_1, "Error box type=STOP ; In-cell dropdown=no" ); + + for (int i=100; i<=120; i++) + { + HSSFRow currRow = fSheet.createRow(i); + currRow.createCell((short)0).setCellValue(cellStrValue); +// currRow.hide( true ); + } + + System.out.println("done !"); + + //Date/Time Validation type + System.out.print(" Create sheet for 'Date' and 'Time' Data Validation types ... "); + fSheet = wb.createSheet("Date_Time"); + SimpleDateFormat df = new SimpleDateFormat("m/d/yyyy"); + HSSFDataFormat dataFormat = wb.createDataFormat(); + short fmtDate = dataFormat.getFormat("m/d/yyyy"); + short fmtTime = dataFormat.getFormat("h:mm"); + HSSFCellStyle cellStyle_data = wb.createCellStyle(); + cellStyle_data.setDataFormat(fmtDate); + HSSFCellStyle cellStyle_time = wb.createCellStyle(); + cellStyle_time.setDataFormat(fmtTime); + + this.createDVTypeRow( wb, 2, style_3, "Date ( cells are already formated as date - m/d/yyyy)"); + this.createHeaderRow( wb, 2, style_4 ); + + start_row = (short)fSheet.getPhysicalNumberOfRows(); + data_validation = new HSSFDataValidation((short)(start_row),(short)0,(short)(start_row),(short)0); + data_validation.setDataValidationType(HSSFDataValidation.DATA_TYPE_DATE); + data_validation.setOperator(HSSFDataValidation.OPERATOR_BETWEEN); + + data_validation.setFirstFormula( String.valueOf((int)HSSFDateUtil.getExcelDate(df.parse("1/2/2004"))) ); + data_validation.setSecondFormula( String.valueOf((int)HSSFDateUtil.getExcelDate(df.parse("1/6/2004"))) ); + + data_validation.createErrorBox("Invalid input !", "Something is wrong ; check condition !"); + data_validation.createPromptBox("Hi , dear user !", "So , you just selected me ! Thanks !"); + fSheet.addValidationData(data_validation); + this.writeDataValidationSettings( fSheet, style_1, style_2, "Between 1/2/2004 and 1/6/2004 ", true, true, true ); + this.setCellFormat( fSheet, cellStyle_data ); + this.writeOtherSettings( fSheet, style_1, "Error box type = STOP" ); + + data_validation.setFirstRow((short)(start_row+1)); + data_validation.setLastRow((short)(start_row+1)); + data_validation.setEmptyCellAllowed(false); + data_validation.setOperator(HSSFDataValidation.OPERATOR_NOT_BETWEEN); + data_validation.setErrorStyle(HSSFDataValidation.ERROR_STYLE_INFO); + fSheet.addValidationData(data_validation); + this.writeDataValidationSettings( fSheet, style_1, style_2, "Not between 1/2/2004 and 1/6/2004 ", false, true, true ); + this.setCellFormat( fSheet, cellStyle_data ); + this.writeOtherSettings( fSheet, style_1, "Error box type = INFO" ); + + data_validation.setFirstRow((short)(start_row+2)); + data_validation.setLastRow((short)(start_row+2)); + data_validation.setEmptyCellAllowed(false); + data_validation.setShowPromptBox(false); + data_validation.setFirstFormula(String.valueOf((int)HSSFDateUtil.getExcelDate(df.parse("3/2/2004")))); + data_validation.setSecondFormula(null); + data_validation.setOperator(HSSFDataValidation.OPERATOR_EQUAL); + data_validation.setErrorStyle(HSSFDataValidation.ERROR_STYLE_WARNING); + fSheet.addValidationData(data_validation); + this.writeDataValidationSettings( fSheet, style_1, style_2, "Equal to 3/2/2004", false, false, true ); + this.setCellFormat( fSheet, cellStyle_data ); + this.writeOtherSettings( fSheet, style_1, "Error box type = WARNING" ); + + data_validation.setFirstRow((short)(start_row+3)); + data_validation.setLastRow((short)(start_row+3)); + data_validation.setEmptyCellAllowed(false); + data_validation.setShowPromptBox(false); + data_validation.setShowErrorBox(false); + data_validation.setFirstFormula(String.valueOf((int)HSSFDateUtil.getExcelDate(df.parse("3/2/2004")))); + data_validation.setSecondFormula(null); + data_validation.setOperator(HSSFDataValidation.OPERATOR_NOT_EQUAL); + fSheet.addValidationData(data_validation); + this.writeDataValidationSettings( fSheet, style_1, style_2, "Not equal to 3/2/2004", false, false, false ); + this.setCellFormat( fSheet, cellStyle_data ); + this.writeOtherSettings( fSheet, style_1, "-" ); + + data_validation.setFirstRow((short)(start_row+4)); + data_validation.setLastRow((short)(start_row+4)); + data_validation.setEmptyCellAllowed(true); + data_validation.setShowPromptBox(false); + data_validation.setShowErrorBox(false); + data_validation.setFirstFormula(String.valueOf((int)HSSFDateUtil.getExcelDate(df.parse("3/2/2004")))); + data_validation.setSecondFormula(null); + data_validation.setOperator(HSSFDataValidation.OPERATOR_GREATER_THAN); + fSheet.addValidationData(data_validation); + this.writeDataValidationSettings( fSheet, style_1, style_2, "Greater than 3/2/2004", true, false, false ); + this.setCellFormat( fSheet, cellStyle_data ); + this.writeOtherSettings( fSheet, style_1, "-" ); + + data_validation.setFirstRow((short)(start_row+5)); + data_validation.setLastRow((short)(start_row+5)); + data_validation.setEmptyCellAllowed(true); + data_validation.setShowPromptBox(true); + data_validation.setShowErrorBox(false); + data_validation.setFirstFormula(String.valueOf((int)HSSFDateUtil.getExcelDate(df.parse("3/2/2004")))); + data_validation.setSecondFormula(null); + data_validation.setOperator(HSSFDataValidation.OPERATOR_LESS_THAN); + fSheet.addValidationData(data_validation); + this.writeDataValidationSettings( fSheet, style_1, style_2, "Less than 3/2/2004", true, true, false ); + this.setCellFormat( fSheet, cellStyle_data ); + this.writeOtherSettings( fSheet, style_1, "-" ); + + data_validation.setFirstRow((short)(start_row+6)); + data_validation.setLastRow((short)(start_row+6)); + data_validation.setEmptyCellAllowed(true); + data_validation.setShowPromptBox(false); + data_validation.setErrorStyle(HSSFDataValidation.ERROR_STYLE_STOP); + data_validation.setShowErrorBox(true); + data_validation.setFirstFormula(String.valueOf((int)HSSFDateUtil.getExcelDate(df.parse("3/2/2004")))); + data_validation.setSecondFormula(null); + data_validation.setOperator(HSSFDataValidation.OPERATOR_GREATER_OR_EQUAL); + fSheet.addValidationData(data_validation); + this.writeDataValidationSettings( fSheet, style_1, style_2, "Greater than or equal to 3/2/2004", true, false, true ); + this.setCellFormat( fSheet, cellStyle_data ); + this.writeOtherSettings( fSheet, style_1, "Error box type = STOP" ); + + data_validation.setFirstRow((short)(start_row+7)); + data_validation.setLastRow((short)(start_row+7)); + data_validation.setEmptyCellAllowed(false); + data_validation.setShowPromptBox(true); + data_validation.setShowErrorBox(false); + data_validation.setFirstFormula(String.valueOf((int)HSSFDateUtil.getExcelDate(df.parse("3/4/2004")))); + data_validation.setSecondFormula(null); + data_validation.setOperator(HSSFDataValidation.OPERATOR_LESS_OR_EQUAL); + fSheet.addValidationData(data_validation); + this.writeDataValidationSettings( fSheet, style_1, style_2, "Less than or equal to 3/4/2004", false, true, false ); + this.setCellFormat( fSheet, cellStyle_data ); + this.writeOtherSettings( fSheet, style_1, "-" ); + + //"Time" validation type + this.createDVTypeRow( wb, 2, style_3, "Time ( cells are already formated as time - h:mm)"); + this.createHeaderRow( wb, 2, style_4 ); + + df = new SimpleDateFormat("hh:mm"); + + start_row += (short)(8+4); + data_validation = new HSSFDataValidation((short)(start_row),(short)0,(short)(start_row),(short)0); + data_validation.setDataValidationType(HSSFDataValidation.DATA_TYPE_TIME); + data_validation.setOperator(HSSFDataValidation.OPERATOR_BETWEEN); + data_validation.setFirstFormula(String.valueOf(HSSFDateUtil.getExcelDate(df.parse("12:00")))); + data_validation.setSecondFormula(String.valueOf(HSSFDateUtil.getExcelDate(df.parse("16:00")))); + data_validation.createErrorBox("Invalid input !", "Something is wrong ; check condition !"); + data_validation.createPromptBox("Hi , dear user !", "So , you just selected me ! Thanks !"); + fSheet.addValidationData(data_validation); + this.writeDataValidationSettings( fSheet, style_1, style_2, "Between 12:00 and 16:00 ", true, true, true ); + this.setCellFormat( fSheet, cellStyle_time ); + this.writeOtherSettings( fSheet, style_1, "Error box type = STOP" ); + + data_validation.setFirstRow((short)(start_row+1)); + data_validation.setLastRow((short)(start_row+1)); + data_validation.setEmptyCellAllowed(false); + data_validation.setOperator(HSSFDataValidation.OPERATOR_NOT_BETWEEN); + data_validation.setErrorStyle(HSSFDataValidation.ERROR_STYLE_INFO); + fSheet.addValidationData(data_validation); + this.writeDataValidationSettings( fSheet, style_1, style_2, "Not between 12:00 and 16:00 ", false, true, true ); + this.setCellFormat( fSheet, cellStyle_time ); + this.writeOtherSettings( fSheet, style_1, "Error box type = INFO" ); + + data_validation.setFirstRow((short)(start_row+2)); + data_validation.setLastRow((short)(start_row+2)); + data_validation.setEmptyCellAllowed(false); + data_validation.setShowPromptBox(false); + data_validation.setFirstFormula(String.valueOf((int)HSSFDateUtil.getExcelDate(df.parse("13:35")))); + data_validation.setSecondFormula(null); + data_validation.setOperator(HSSFDataValidation.OPERATOR_EQUAL); + data_validation.setErrorStyle(HSSFDataValidation.ERROR_STYLE_WARNING); + fSheet.addValidationData(data_validation); + this.writeDataValidationSettings( fSheet, style_1, style_2, "Equal to 13:35", false, false, true ); + this.setCellFormat( fSheet, cellStyle_time ); + this.writeOtherSettings( fSheet, style_1, "Error box type = WARNING" ); + + data_validation.setFirstRow((short)(start_row+3)); + data_validation.setLastRow((short)(start_row+3)); + data_validation.setEmptyCellAllowed(false); + data_validation.setShowPromptBox(false); + data_validation.setShowErrorBox(false); + data_validation.setFirstFormula(String.valueOf(HSSFDateUtil.getExcelDate(df.parse("13:35")))); + data_validation.setSecondFormula(null); + data_validation.setOperator(HSSFDataValidation.OPERATOR_NOT_EQUAL); + fSheet.addValidationData(data_validation); + this.writeDataValidationSettings( fSheet, style_1, style_2, "Not equal to 13:35", false, false, false ); + this.setCellFormat( fSheet, cellStyle_time ); + this.writeOtherSettings( fSheet, style_1, "-" ); + + data_validation.setFirstRow((short)(start_row+4)); + data_validation.setLastRow((short)(start_row+4)); + data_validation.setEmptyCellAllowed(true); + data_validation.setShowPromptBox(false); + data_validation.setShowErrorBox(false); + data_validation.setFirstFormula(String.valueOf(HSSFDateUtil.getExcelDate(df.parse("12:00")))); + data_validation.setSecondFormula(null); + data_validation.setOperator(HSSFDataValidation.OPERATOR_GREATER_THAN); + fSheet.addValidationData(data_validation); + this.writeDataValidationSettings( fSheet, style_1, style_2, "Greater than 12:00", true, false, false ); + this.setCellFormat( fSheet, cellStyle_time ); + this.writeOtherSettings( fSheet, style_1, "-" ); + + data_validation.setFirstRow((short)(start_row+5)); + data_validation.setLastRow((short)(start_row+5)); + data_validation.setEmptyCellAllowed(true); + data_validation.setShowPromptBox(true); + data_validation.setShowErrorBox(false); + data_validation.setFirstFormula(String.valueOf(HSSFDateUtil.getExcelDate(df.parse("12:00")))); + data_validation.setSecondFormula(null); + data_validation.setOperator(HSSFDataValidation.OPERATOR_LESS_THAN); + fSheet.addValidationData(data_validation); + this.writeDataValidationSettings( fSheet, style_1, style_2, "Less than 12:00", true, true, false ); + this.setCellFormat( fSheet, cellStyle_time ); + this.writeOtherSettings( fSheet, style_1, "-" ); + + data_validation.setFirstRow((short)(start_row+6)); + data_validation.setLastRow((short)(start_row+6)); + data_validation.setEmptyCellAllowed(true); + data_validation.setShowPromptBox(false); + data_validation.setErrorStyle(HSSFDataValidation.ERROR_STYLE_STOP); + data_validation.setShowErrorBox(true); + data_validation.setFirstFormula(String.valueOf(HSSFDateUtil.getExcelDate(df.parse("14:00")))); + data_validation.setSecondFormula(null); + data_validation.setOperator(HSSFDataValidation.OPERATOR_GREATER_OR_EQUAL); + fSheet.addValidationData(data_validation); + this.writeDataValidationSettings( fSheet, style_1, style_2, "Greater than or equal to 14:00", true, false, true ); + this.setCellFormat( fSheet, cellStyle_time ); + this.writeOtherSettings( fSheet, style_1, "Error box type = STOP" ); + + data_validation.setFirstRow((short)(start_row+7)); + data_validation.setLastRow((short)(start_row+7)); + data_validation.setEmptyCellAllowed(false); + data_validation.setShowPromptBox(true); + data_validation.setShowErrorBox(false); + data_validation.setFirstFormula(String.valueOf(HSSFDateUtil.getExcelDate(df.parse("14:00")))); + data_validation.setSecondFormula(null); + data_validation.setOperator(HSSFDataValidation.OPERATOR_LESS_OR_EQUAL); + fSheet.addValidationData(data_validation); + this.writeDataValidationSettings( fSheet, style_1, style_2, "Less than or equal to 14:00", false, true, false ); + this.setCellFormat( fSheet, cellStyle_time ); + this.writeOtherSettings( fSheet, style_1, "-" ); + + System.out.println("done !"); + + //"Text length" validation type + System.out.print(" Create sheet for 'Text length' Data Validation type... "); + fSheet = wb.createSheet("Text length"); + this.createHeaderRow( wb, 3, style_4 ); + + data_validation = new HSSFDataValidation((short)1,(short)0,(short)1,(short)0); + data_validation.setDataValidationType(HSSFDataValidation.DATA_TYPE_TEXT_LENGTH); + data_validation.setOperator(HSSFDataValidation.OPERATOR_BETWEEN); + data_validation.setFirstFormula("2"); + data_validation.setSecondFormula("6"); + data_validation.createErrorBox("Invalid input !", "Something is wrong ; check condition !"); + data_validation.createPromptBox("Hi , dear user !", "So , you just selected me ! Thanks !"); + fSheet.addValidationData(data_validation); + this.writeDataValidationSettings( fSheet, style_1, style_2, "Between 2 and 6 ", true, true, true ); + this.writeOtherSettings( fSheet, style_1, "Error box type = STOP" ); + + data_validation.setFirstRow((short)2); + data_validation.setLastRow((short)2); + data_validation.setEmptyCellAllowed(false); + data_validation.setOperator(HSSFDataValidation.OPERATOR_NOT_BETWEEN); + data_validation.setErrorStyle(HSSFDataValidation.ERROR_STYLE_INFO); + fSheet.addValidationData(data_validation); + this.writeDataValidationSettings( fSheet, style_1, style_2, "Not between 2 and 6 ", false, true, true ); + this.writeOtherSettings( fSheet, style_1, "Error box type = INFO" ); + + data_validation.setFirstRow((short)3); + data_validation.setLastRow((short)3); + data_validation.setEmptyCellAllowed(false); + data_validation.setShowPromptBox(false); + data_validation.setFirstFormula("3"); + data_validation.setSecondFormula(null); + data_validation.setOperator(HSSFDataValidation.OPERATOR_EQUAL); + data_validation.setErrorStyle(HSSFDataValidation.ERROR_STYLE_WARNING); + fSheet.addValidationData(data_validation); + this.writeDataValidationSettings( fSheet, style_1, style_2, "Equal to 3", false, false, true ); + this.writeOtherSettings( fSheet, style_1, "Error box type = WARNING" ); + + data_validation.setFirstRow((short)4); + data_validation.setLastRow((short)4); + data_validation.setEmptyCellAllowed(false); + data_validation.setShowPromptBox(false); + data_validation.setShowErrorBox(false); + data_validation.setFirstFormula("3"); + data_validation.setSecondFormula(null); + data_validation.setOperator(HSSFDataValidation.OPERATOR_NOT_EQUAL); + fSheet.addValidationData(data_validation); + this.writeDataValidationSettings( fSheet, style_1, style_2, "Not equal to 3", false, false, false ); + this.writeOtherSettings( fSheet, style_1, "-" ); + + data_validation.setFirstRow((short)5); + data_validation.setLastRow((short)5); + data_validation.setEmptyCellAllowed(true); + data_validation.setShowPromptBox(false); + data_validation.setShowErrorBox(false); + data_validation.setFirstFormula("3"); + data_validation.setSecondFormula(null); + data_validation.setOperator(HSSFDataValidation.OPERATOR_GREATER_THAN); + fSheet.addValidationData(data_validation); + this.writeDataValidationSettings( fSheet, style_1, style_2, "Greater than 3", true, false, false ); + this.writeOtherSettings( fSheet, style_1, "-" ); + + data_validation.setFirstRow((short)6); + data_validation.setLastRow((short)6); + data_validation.setEmptyCellAllowed(true); + data_validation.setShowPromptBox(true); + data_validation.setShowErrorBox(false); + data_validation.setFirstFormula("3"); + data_validation.setSecondFormula(null); + data_validation.setOperator(HSSFDataValidation.OPERATOR_LESS_THAN); + fSheet.addValidationData(data_validation); + this.writeDataValidationSettings( fSheet, style_1, style_2, "Less than 3", true, true, false ); + this.writeOtherSettings( fSheet, style_1, "-" ); + + data_validation.setFirstRow((short)7); + data_validation.setLastRow((short)7); + data_validation.setEmptyCellAllowed(true); + data_validation.setShowPromptBox(false); + data_validation.setErrorStyle(HSSFDataValidation.ERROR_STYLE_STOP); + data_validation.setShowErrorBox(true); + data_validation.setFirstFormula("4"); + data_validation.setSecondFormula(null); + data_validation.setOperator(HSSFDataValidation.OPERATOR_GREATER_OR_EQUAL); + fSheet.addValidationData(data_validation); + this.writeDataValidationSettings( fSheet, style_1, style_2, "Greater than or equal to 4", true, false, true ); + this.writeOtherSettings( fSheet, style_1, "Error box type = STOP" ); + + data_validation.setFirstRow((short)8); + data_validation.setLastRow((short)8); + data_validation.setEmptyCellAllowed(false); + data_validation.setShowPromptBox(true); + data_validation.setShowErrorBox(false); + data_validation.setFirstFormula("4"); + data_validation.setSecondFormula(null); + data_validation.setOperator(HSSFDataValidation.OPERATOR_LESS_OR_EQUAL); + fSheet.addValidationData(data_validation); + this.writeDataValidationSettings( fSheet, style_1, style_2, "Less than or equal to 4", false, true, false ); + this.writeOtherSettings( fSheet, style_1, "-" ); + System.out.println("done !"); + + //Custom Validation type + System.out.print(" Create sheet for 'Custom' Data Validation type ... "); + fSheet = wb.createSheet("Custom"); + this.createHeaderRow( wb, 4, style_4 ); + + data_validation = new HSSFDataValidation((short)1,(short)0,(short)1,(short)0); + data_validation.setDataValidationType(HSSFDataValidation.DATA_TYPE_FORMULA); + data_validation.setFirstFormula("ISNUMBER($A2)"); + data_validation.setSecondFormula(null); + data_validation.setShowPromptBox(true); + data_validation.setShowErrorBox(true); + data_validation.createErrorBox("Invalid input !", "Something is wrong ; check condition !"); + data_validation.createPromptBox("Hi , dear user !", "So , you just selected me ! Thanks !"); + fSheet.addValidationData(data_validation); + this.writeDataValidationSettings( fSheet, style_1, style_2, "ISNUMBER(A2)", true, true, true ); + this.writeOtherSettings( fSheet, style_1, "Error box type = STOP" ); + + data_validation = new HSSFDataValidation((short)2,(short)0,(short)2,(short)0); + data_validation.setDataValidationType(HSSFDataValidation.DATA_TYPE_FORMULA); + data_validation.setFirstFormula("IF(SUM(A2:A3)=5,TRUE,FALSE)"); + data_validation.setSecondFormula(null); + data_validation.setShowPromptBox(false); + data_validation.setShowErrorBox(true); + data_validation.setErrorStyle(HSSFDataValidation.ERROR_STYLE_WARNING); + data_validation.createErrorBox("Invalid input !", "Something is wrong ; check condition !"); + data_validation.setEmptyCellAllowed(false); + fSheet.addValidationData(data_validation); + this.writeDataValidationSettings( fSheet, style_1, style_2, "IF(SUM(A2:A3)=5,TRUE,FALSE)", false, false, true ); + this.writeOtherSettings( fSheet, style_1, "Error box type = WARNING" ); + + System.out.println("done !"); + + //so , everything it's ok for now ; it remains for you to open the file + System.out.println("\n Everything it's ok since we've got so far -:) !\n"+ + " In order to complete the test , it remains for you to open the file \n"+ + " and see if there are four sheets , as described !"); + System.out.println(" File was saved in \""+resultFile+"\""); + + FileOutputStream fileOut = new FileOutputStream(resultFile); + wb.write(fileOut); + fileOut.close(); + } + + private void createDVTypeRow( HSSFWorkbook wb, int sheetNo , HSSFCellStyle cellStyle, String strTypeDescription) + { + HSSFSheet sheet = wb.getSheetAt(sheetNo); + HSSFRow row = sheet.createRow(sheet.getPhysicalNumberOfRows()); + row = sheet.createRow(sheet.getPhysicalNumberOfRows()); + sheet.addMergedRegion(new Region((short)(sheet.getPhysicalNumberOfRows()-1),(short)0,(short)(sheet.getPhysicalNumberOfRows()-1),(short)5)); + HSSFCell cell = row.createCell((short)0); + cell.setCellValue(strTypeDescription); + cell.setCellStyle(cellStyle); + row = sheet.createRow(sheet.getPhysicalNumberOfRows()); + } + + private void createDVDeescriptionRow( HSSFWorkbook wb, int sheetNo , HSSFCellStyle cellStyle, String strTypeDescription ) + { + HSSFSheet sheet = wb.getSheetAt(sheetNo); + HSSFRow row = sheet.getRow(sheet.getPhysicalNumberOfRows()-1); + sheet.addMergedRegion(new Region((short)(sheet.getPhysicalNumberOfRows()-1),(short)0,(short)(sheet.getPhysicalNumberOfRows()-1),(short)5)); + HSSFCell cell = row.createCell((short)0); + cell.setCellValue(strTypeDescription); + cell.setCellStyle(cellStyle); + row = sheet.createRow(sheet.getPhysicalNumberOfRows()); + } + + private void createHeaderRow( HSSFWorkbook wb, int sheetNo , HSSFCellStyle cellStyle ) + { + HSSFSheet sheet = wb.getSheetAt(sheetNo); + HSSFRow row = sheet.createRow(sheet.getPhysicalNumberOfRows()); + row.setHeight((short)400); + for ( int i=0; i<6; i++ ) + { + row.createCell((short)i).setCellStyle( cellStyle ); + if ( i==2 || i==3 || i==4 ) + { + sheet.setColumnWidth( (short) i, (short) 3500); + } + else if ( i== 5) + { + sheet.setColumnWidth( (short) i, (short) 10000); + } + else + { + sheet.setColumnWidth( (short) i, (short) 8000); + } + } + HSSFCell cell = row.getCell((short)0); + cell.setCellValue("Data validation cells"); + cell = row.getCell((short)1); + cell.setCellValue("Condition"); + cell = row.getCell((short)2); + cell.setCellValue("Allow blank"); + cell = row.getCell((short)3); + cell.setCellValue("Prompt box"); + cell = row.getCell((short)4); + cell.setCellValue("Error box"); + cell = row.getCell((short)5); + cell.setCellValue("Other settings"); + } + + private HSSFCellStyle createHeaderStyle(HSSFWorkbook wb) + { + HSSFFont font = wb.createFont(); + font.setColor( HSSFColor.WHITE.index ); + font.setBoldweight(HSSFFont.BOLDWEIGHT_BOLD); + + HSSFCellStyle cellStyle = wb.createCellStyle(); + cellStyle.setFillForegroundColor(HSSFColor.BLUE_GREY.index); + cellStyle.setFillPattern(HSSFCellStyle.SOLID_FOREGROUND); + cellStyle.setAlignment(HSSFCellStyle.ALIGN_CENTER); + cellStyle.setVerticalAlignment(HSSFCellStyle.VERTICAL_CENTER); + cellStyle.setBorderLeft(HSSFCellStyle.BORDER_THIN); + cellStyle.setLeftBorderColor(HSSFColor.WHITE.index); + cellStyle.setBorderTop(HSSFCellStyle.BORDER_THIN); + cellStyle.setTopBorderColor(HSSFColor.WHITE.index); + cellStyle.setBorderRight(HSSFCellStyle.BORDER_THIN); + cellStyle.setRightBorderColor(HSSFColor.WHITE.index); + cellStyle.setBorderBottom(HSSFCellStyle.BORDER_THIN); + cellStyle.setBottomBorderColor(HSSFColor.WHITE.index); + cellStyle.setFont(font); + return cellStyle; + } + + private HSSFCellStyle createStyle( HSSFWorkbook wb, short h_align, short color, boolean bold ) + { + HSSFFont font = wb.createFont(); + if ( bold ) + { + font.setBoldweight(HSSFFont.BOLDWEIGHT_BOLD); + } + + HSSFCellStyle cellStyle = wb.createCellStyle(); + cellStyle.setFont(font); + cellStyle.setFillForegroundColor(color); + cellStyle.setFillPattern(HSSFCellStyle.SOLID_FOREGROUND); + cellStyle.setVerticalAlignment(HSSFCellStyle.VERTICAL_CENTER); + cellStyle.setAlignment(h_align); + cellStyle.setBorderLeft(HSSFCellStyle.BORDER_THIN); + cellStyle.setLeftBorderColor(HSSFColor.BLACK.index); + cellStyle.setBorderTop(HSSFCellStyle.BORDER_THIN); + cellStyle.setTopBorderColor(HSSFColor.BLACK.index); + cellStyle.setBorderRight(HSSFCellStyle.BORDER_THIN); + cellStyle.setRightBorderColor(HSSFColor.BLACK.index); + cellStyle.setBorderBottom(HSSFCellStyle.BORDER_THIN); + cellStyle.setBottomBorderColor(HSSFColor.BLACK.index); + + return cellStyle; + } + + private HSSFCellStyle createStyle( HSSFWorkbook wb, short h_align ) + { + return this.createStyle(wb, h_align, HSSFColor.WHITE.index, false); + } + + private void writeDataValidationSettings( HSSFSheet sheet, HSSFCellStyle style_1, HSSFCellStyle style_2, String strCondition, boolean allowEmpty, boolean inputBox, boolean errorBox ) + { + HSSFRow row = sheet.createRow( sheet.getPhysicalNumberOfRows() ); + //condition's string + HSSFCell cell = row.createCell((short)1); + cell.setCellStyle(style_1); + cell.setCellValue(strCondition); + //allow empty cells + cell = row.createCell((short)2); + cell.setCellStyle(style_2); + cell.setCellValue( ((allowEmpty) ? "yes" : "no") ); + //show input box + cell = row.createCell((short)3); + cell.setCellStyle(style_2); + cell.setCellValue( ((inputBox) ? "yes" : "no") ); + //show error box + cell = row.createCell((short)4); + cell.setCellStyle(style_2); + cell.setCellValue( ((errorBox) ? "yes" : "no") ); + } + + private void setCellFormat( HSSFSheet sheet, HSSFCellStyle cell_style ) + { + HSSFRow row = sheet.getRow( sheet.getPhysicalNumberOfRows() -1 ); + HSSFCell cell = row.createCell((short)0); + cell.setCellStyle(cell_style); + } + + private void writeOtherSettings( HSSFSheet sheet, HSSFCellStyle style, String strStettings ) + { + HSSFRow row = sheet.getRow( sheet.getPhysicalNumberOfRows() -1 ); + HSSFCell cell = row.createCell((short)5); + cell.setCellStyle(style); + cell.setCellValue(strStettings); + } + + public static void main(String[] args) + { + junit.textui.TestRunner.run(TestDataValidation.class); + } +} diff --git a/src/testcases/org/apache/poi/hssf/usermodel/TestHSSFCell.java b/src/testcases/org/apache/poi/hssf/usermodel/TestHSSFCell.java index 5742660260..ee3cace263 100644 --- a/src/testcases/org/apache/poi/hssf/usermodel/TestHSSFCell.java +++ b/src/testcases/org/apache/poi/hssf/usermodel/TestHSSFCell.java @@ -44,6 +44,7 @@ import java.util.GregorianCalendar; * paticular datatypes, etc. * @author Andrew C. Oliver (andy at superlinksoftware dot com) * @author Dan Sherman (dsherman at isisph.com) + * @author Alex Jacoby (ajacoby at gmail.com) */ public class TestHSSFCell @@ -107,42 +108,106 @@ extends TestCase { } /** - * Checks that the recognition of files using 1904 date windowing - * is working properly. Conversion of the date is also an issue, - * but there's a separate unit test for that. - */ - public void testDateWindowing() throws Exception { - GregorianCalendar cal = new GregorianCalendar(2000,0,1); // Jan. 1, 2000 - Date date = cal.getTime(); - String path = System.getProperty("HSSF.testdata.path"); - - // first check a file with 1900 Date Windowing - String filename = path + "/1900DateWindowing.xls"; - FileInputStream stream = new FileInputStream(filename); - POIFSFileSystem fs = new POIFSFileSystem(stream); - HSSFWorkbook workbook = new HSSFWorkbook(fs); - HSSFSheet sheet = workbook.getSheetAt(0); - - assertEquals("Date from file using 1900 Date Windowing", - date.getTime(), - sheet.getRow(0).getCell((short)0) - .getDateCellValue().getTime()); - stream.close(); - - // now check a file with 1904 Date Windowing - filename = path + "/1904DateWindowing.xls"; - stream = new FileInputStream(filename); - fs = new POIFSFileSystem(stream); - workbook = new HSSFWorkbook(fs); - sheet = workbook.getSheetAt(0); - - assertEquals("Date from file using 1904 Date Windowing", - date.getTime(), - sheet.getRow(0).getCell((short)0) - .getDateCellValue().getTime()); - stream.close(); - } - + * Checks that the recognition of files using 1904 date windowing + * is working properly. Conversion of the date is also an issue, + * but there's a separate unit test for that. + */ + public void testDateWindowingRead() throws Exception { + GregorianCalendar cal = new GregorianCalendar(2000,0,1); // Jan. 1, 2000 + Date date = cal.getTime(); + String path = System.getProperty("HSSF.testdata.path"); + + // first check a file with 1900 Date Windowing + String filename = path + "/1900DateWindowing.xls"; + FileInputStream stream = new FileInputStream(filename); + POIFSFileSystem fs = new POIFSFileSystem(stream); + HSSFWorkbook workbook = new HSSFWorkbook(fs); + HSSFSheet sheet = workbook.getSheetAt(0); + + assertEquals("Date from file using 1900 Date Windowing", + date.getTime(), + sheet.getRow(0).getCell((short)0) + .getDateCellValue().getTime()); + stream.close(); + + // now check a file with 1904 Date Windowing + filename = path + "/1904DateWindowing.xls"; + stream = new FileInputStream(filename); + fs = new POIFSFileSystem(stream); + workbook = new HSSFWorkbook(fs); + sheet = workbook.getSheetAt(0); + + assertEquals("Date from file using 1904 Date Windowing", + date.getTime(), + sheet.getRow(0).getCell((short)0) + .getDateCellValue().getTime()); + stream.close(); + } + + /** + * Checks that dates are properly written to both types of files: + * those with 1900 and 1904 date windowing. Note that if the + * previous test ({@link #testDateWindowingRead}) fails, the + * results of this test are meaningless. + */ + public void testDateWindowingWrite() throws Exception { + GregorianCalendar cal = new GregorianCalendar(2000,0,1); // Jan. 1, 2000 + Date date = cal.getTime(); + String path = System.getProperty("HSSF.testdata.path"); + + // first check a file with 1900 Date Windowing + String filename = path + "/1900DateWindowing.xls"; + writeCell(filename, 0, (short) 1, date); + assertEquals("Date from file using 1900 Date Windowing", + date.getTime(), + readCell(filename, 0, (short) 1).getTime()); + + // now check a file with 1904 Date Windowing + filename = path + "/1904DateWindowing.xls"; + writeCell(filename, 0, (short) 1, date); + assertEquals("Date from file using 1900 Date Windowing", + date.getTime(), + readCell(filename, 0, (short) 1).getTime()); + } + + /** + * Sets cell value and writes file. + */ + private void writeCell(String filename, + int rowIdx, short colIdx, Date date) throws Exception { + FileInputStream stream = new FileInputStream(filename); + POIFSFileSystem fs = new POIFSFileSystem(stream); + HSSFWorkbook workbook = new HSSFWorkbook(fs); + HSSFSheet sheet = workbook.getSheetAt(0); + HSSFRow row = sheet.getRow(rowIdx); + HSSFCell cell = row.getCell(colIdx); + + if (cell == null) { + cell = row.createCell(colIdx); + } + cell.setCellValue(date); + + // Write the file + stream.close(); + FileOutputStream oStream = new FileOutputStream(filename); + workbook.write(oStream); + oStream.close(); + } + + /** + * Reads cell value from file. + */ + private Date readCell(String filename, + int rowIdx, short colIdx) throws Exception { + FileInputStream stream = new FileInputStream(filename); + POIFSFileSystem fs = new POIFSFileSystem(stream); + HSSFWorkbook workbook = new HSSFWorkbook(fs); + HSSFSheet sheet = workbook.getSheetAt(0); + HSSFRow row = sheet.getRow(rowIdx); + HSSFCell cell = row.getCell(colIdx); + return cell.getDateCellValue(); + } + /** * Tests that the active cell can be correctly read and set */ diff --git a/src/testcases/org/apache/poi/hssf/usermodel/TestHSSFClientAnchor.java b/src/testcases/org/apache/poi/hssf/usermodel/TestHSSFClientAnchor.java index 10c4e390cb..655f78eddb 100644 --- a/src/testcases/org/apache/poi/hssf/usermodel/TestHSSFClientAnchor.java +++ b/src/testcases/org/apache/poi/hssf/usermodel/TestHSSFClientAnchor.java @@ -85,4 +85,23 @@ public class TestHSSFClientAnchor extends TestCase assertEquals(anchor[i].getRow2(), record.getRow2()); } } + + public void testAnchorHeightInPoints(){ + HSSFWorkbook wb = new HSSFWorkbook(); + HSSFSheet sheet = wb.createSheet(); + + HSSFClientAnchor[] anchor = { + new HSSFClientAnchor( 0 , 0, 0 , 0 ,(short)0, 1,(short)1, 3), + new HSSFClientAnchor( 0 , 254 , 0 , 126 ,(short)0, 1,(short)1, 3), + new HSSFClientAnchor( 0 , 128 , 0 , 128 ,(short)0, 1,(short)1, 3), + new HSSFClientAnchor( 0 , 0 , 0 , 128 ,(short)0, 1,(short)1, 3), + }; + float[] ref = {24.0f, 18.0f, 24.0f, 30.0f}; + for (int i = 0; i < anchor.length; i++) { + float height = anchor[i].getAnchorHeightInPoints(sheet); + assertEquals(ref[i], height, 0); + } + + } + } diff --git a/src/testcases/org/apache/poi/hssf/usermodel/TestHSSFDateUtil.java b/src/testcases/org/apache/poi/hssf/usermodel/TestHSSFDateUtil.java index f8aeb8517e..6b37f749ee 100644 --- a/src/testcases/org/apache/poi/hssf/usermodel/TestHSSFDateUtil.java +++ b/src/testcases/org/apache/poi/hssf/usermodel/TestHSSFDateUtil.java @@ -36,6 +36,8 @@ import org.apache.poi.poifs.filesystem.POIFSFileSystem; * * @author Dan Sherman (dsherman at isisph.com) * @author Hack Kampbjorn (hak at 2mba.dk) + * @author Pavel Krupets (pkrupets at palmtreebusiness dot com) + * @author Alex Jacoby (ajacoby at gmail.com) * @version %I%, %G% */ @@ -47,7 +49,9 @@ public class TestHSSFDateUtil public static final int CALENDAR_FEBRUARY = 1; public static final int CALENDAR_MARCH = 2; public static final int CALENDAR_APRIL = 3; - + public static final int CALENDAR_JULY = 6; + public static final int CALENDAR_OCTOBER = 9; + public TestHSSFDateUtil(String s) { super(s); @@ -67,10 +71,10 @@ public class TestHSSFDateUtil GregorianCalendar date = new GregorianCalendar(2002, 0, 1, hour, 1, 1); double excelDate = - HSSFDateUtil.getExcelDate(date.getTime()); + HSSFDateUtil.getExcelDate(date.getTime(), false); assertEquals("Checking hour = " + hour, date.getTime().getTime(), - HSSFDateUtil.getJavaDate(excelDate).getTime()); + HSSFDateUtil.getJavaDate(excelDate, false).getTime()); } // check 1900 and 1904 date windowing conversions @@ -99,7 +103,7 @@ public class TestHSSFDateUtil public void testExcelConversionOnDSTStart() { TimeZone cet = TimeZone.getTimeZone("Europe/Copenhagen"); TimeZone.setDefault(cet); - Calendar cal = new GregorianCalendar(2004, Calendar.MARCH, 28); + Calendar cal = new GregorianCalendar(2004, CALENDAR_MARCH, 28); for (int hour = 0; hour < 24; hour++) { // Skip 02:00 CET as that is the Daylight change time @@ -110,7 +114,7 @@ public class TestHSSFDateUtil cal.set(Calendar.HOUR_OF_DAY, hour); Date javaDate = cal.getTime(); - double excelDate = HSSFDateUtil.getExcelDate(javaDate); + double excelDate = HSSFDateUtil.getExcelDate(javaDate, false); double difference = excelDate - Math.floor(excelDate); int differenceInHours = (int) (difference * 24 * 60 + 0.5) / 60; assertEquals("Checking " + hour + " hour on Daylight Saving Time start date", @@ -118,7 +122,7 @@ public class TestHSSFDateUtil differenceInHours); assertEquals("Checking " + hour + " hour on Daylight Saving Time start date", javaDate.getTime(), - HSSFDateUtil.getJavaDate(excelDate).getTime()); + HSSFDateUtil.getJavaDate(excelDate, false).getTime()); } } @@ -129,8 +133,8 @@ public class TestHSSFDateUtil public void testJavaConversionOnDSTStart() { TimeZone cet = TimeZone.getTimeZone("Europe/Copenhagen"); TimeZone.setDefault(cet); - Calendar cal = new GregorianCalendar(2004, Calendar.MARCH, 28); - double excelDate = HSSFDateUtil.getExcelDate(cal.getTime()); + Calendar cal = new GregorianCalendar(2004, CALENDAR_MARCH, 28); + double excelDate = HSSFDateUtil.getExcelDate(cal.getTime(), false); double oneHour = 1.0 / 24; double oneMinute = oneHour / 60; for (int hour = 0; hour < 24; hour++, excelDate += oneHour) { @@ -142,10 +146,10 @@ public class TestHSSFDateUtil } cal.set(Calendar.HOUR_OF_DAY, hour); - Date javaDate = HSSFDateUtil.getJavaDate(excelDate); + Date javaDate = HSSFDateUtil.getJavaDate(excelDate, false); assertEquals("Checking " + hour + " hours on Daylight Saving Time start date", excelDate, - HSSFDateUtil.getExcelDate(javaDate), oneMinute); + HSSFDateUtil.getExcelDate(javaDate, false), oneMinute); } } @@ -156,11 +160,11 @@ public class TestHSSFDateUtil public void testExcelConversionOnDSTEnd() { TimeZone cet = TimeZone.getTimeZone("Europe/Copenhagen"); TimeZone.setDefault(cet); - Calendar cal = new GregorianCalendar(2004, Calendar.OCTOBER, 31); + Calendar cal = new GregorianCalendar(2004, CALENDAR_OCTOBER, 31); for (int hour = 0; hour < 24; hour++) { cal.set(Calendar.HOUR_OF_DAY, hour); Date javaDate = cal.getTime(); - double excelDate = HSSFDateUtil.getExcelDate(javaDate); + double excelDate = HSSFDateUtil.getExcelDate(javaDate, false); double difference = excelDate - Math.floor(excelDate); int differenceInHours = (int) (difference * 24 * 60 + 0.5) / 60; assertEquals("Checking " + hour + " hour on Daylight Saving Time end date", @@ -168,7 +172,7 @@ public class TestHSSFDateUtil differenceInHours); assertEquals("Checking " + hour + " hour on Daylight Saving Time start date", javaDate.getTime(), - HSSFDateUtil.getJavaDate(excelDate).getTime()); + HSSFDateUtil.getJavaDate(excelDate, false).getTime()); } } @@ -179,16 +183,16 @@ public class TestHSSFDateUtil public void testJavaConversionOnDSTEnd() { TimeZone cet = TimeZone.getTimeZone("Europe/Copenhagen"); TimeZone.setDefault(cet); - Calendar cal = new GregorianCalendar(2004, Calendar.OCTOBER, 31); - double excelDate = HSSFDateUtil.getExcelDate(cal.getTime()); + Calendar cal = new GregorianCalendar(2004, CALENDAR_OCTOBER, 31); + double excelDate = HSSFDateUtil.getExcelDate(cal.getTime(), false); double oneHour = 1.0 / 24; double oneMinute = oneHour / 60; for (int hour = 0; hour < 24; hour++, excelDate += oneHour) { cal.set(Calendar.HOUR_OF_DAY, hour); - Date javaDate = HSSFDateUtil.getJavaDate(excelDate); + Date javaDate = HSSFDateUtil.getJavaDate(excelDate, false); assertEquals("Checking " + hour + " hours on Daylight Saving Time start date", excelDate, - HSSFDateUtil.getExcelDate(javaDate), oneMinute); + HSSFDateUtil.getExcelDate(javaDate, false), oneMinute); } } @@ -315,25 +319,38 @@ public class TestHSSFDateUtil } public void testDateBug_2Excel() { - assertEquals(59.0, HSSFDateUtil.getExcelDate(createDate(1900, CALENDAR_FEBRUARY, 28)), 0.00001); - assertEquals(61.0, HSSFDateUtil.getExcelDate(createDate(1900, CALENDAR_MARCH, 1)), 0.00001); + assertEquals(59.0, HSSFDateUtil.getExcelDate(createDate(1900, CALENDAR_FEBRUARY, 28), false), 0.00001); + assertEquals(61.0, HSSFDateUtil.getExcelDate(createDate(1900, CALENDAR_MARCH, 1), false), 0.00001); - assertEquals(37315.00, HSSFDateUtil.getExcelDate(createDate(2002, CALENDAR_FEBRUARY, 28)), 0.00001); - assertEquals(37316.00, HSSFDateUtil.getExcelDate(createDate(2002, CALENDAR_MARCH, 1)), 0.00001); - assertEquals(37257.00, HSSFDateUtil.getExcelDate(createDate(2002, CALENDAR_JANUARY, 1)), 0.00001); - assertEquals(38074.00, HSSFDateUtil.getExcelDate(createDate(2004, CALENDAR_MARCH, 28)), 0.00001); + assertEquals(37315.00, HSSFDateUtil.getExcelDate(createDate(2002, CALENDAR_FEBRUARY, 28), false), 0.00001); + assertEquals(37316.00, HSSFDateUtil.getExcelDate(createDate(2002, CALENDAR_MARCH, 1), false), 0.00001); + assertEquals(37257.00, HSSFDateUtil.getExcelDate(createDate(2002, CALENDAR_JANUARY, 1), false), 0.00001); + assertEquals(38074.00, HSSFDateUtil.getExcelDate(createDate(2004, CALENDAR_MARCH, 28), false), 0.00001); } public void testDateBug_2Java() { - assertEquals(createDate(1900, Calendar.FEBRUARY, 28), HSSFDateUtil.getJavaDate(59.0)); - assertEquals(createDate(1900, Calendar.MARCH, 1), HSSFDateUtil.getJavaDate(61.0)); + assertEquals(createDate(1900, CALENDAR_FEBRUARY, 28), HSSFDateUtil.getJavaDate(59.0, false)); + assertEquals(createDate(1900, CALENDAR_MARCH, 1), HSSFDateUtil.getJavaDate(61.0, false)); - assertEquals(createDate(2002, Calendar.FEBRUARY, 28), HSSFDateUtil.getJavaDate(37315.00)); - assertEquals(createDate(2002, Calendar.MARCH, 1), HSSFDateUtil.getJavaDate(37316.00)); - assertEquals(createDate(2002, Calendar.JANUARY, 1), HSSFDateUtil.getJavaDate(37257.00)); - assertEquals(createDate(2004, Calendar.MARCH, 28), HSSFDateUtil.getJavaDate(38074.00)); + assertEquals(createDate(2002, CALENDAR_FEBRUARY, 28), HSSFDateUtil.getJavaDate(37315.00, false)); + assertEquals(createDate(2002, CALENDAR_MARCH, 1), HSSFDateUtil.getJavaDate(37316.00, false)); + assertEquals(createDate(2002, CALENDAR_JANUARY, 1), HSSFDateUtil.getJavaDate(37257.00, false)); + assertEquals(createDate(2004, CALENDAR_MARCH, 28), HSSFDateUtil.getJavaDate(38074.00, false)); } - + + public void testDate1904() { + assertEquals(createDate(1904, CALENDAR_JANUARY, 2), HSSFDateUtil.getJavaDate(1.0, true)); + assertEquals(createDate(1904, CALENDAR_JANUARY, 1), HSSFDateUtil.getJavaDate(0.0, true)); + assertEquals(0.0, HSSFDateUtil.getExcelDate(createDate(1904, CALENDAR_JANUARY, 1), true), 0.00001); + assertEquals(1.0, HSSFDateUtil.getExcelDate(createDate(1904, CALENDAR_JANUARY, 2), true), 0.00001); + + assertEquals(createDate(1998, CALENDAR_JULY, 5), HSSFDateUtil.getJavaDate(35981, false)); + assertEquals(createDate(1998, CALENDAR_JULY, 5), HSSFDateUtil.getJavaDate(34519, true)); + + assertEquals(35981.0, HSSFDateUtil.getExcelDate(createDate(1998, CALENDAR_JULY, 5), false), 0.00001); + assertEquals(34519.0, HSSFDateUtil.getExcelDate(createDate(1998, CALENDAR_JULY, 5), true), 0.00001); + } + private Date createDate(int year, int month, int day) { Calendar c = new GregorianCalendar(); c.set(year, month, day, 0, 0, 0); @@ -341,10 +358,21 @@ public class TestHSSFDateUtil return c.getTime(); } + /** + * Check if HSSFDateUtil.getAbsoluteDay works as advertised. + */ + public void testAbsoluteDay() { + // 1 Jan 1900 is 1 day after 31 Dec 1899 + GregorianCalendar calendar = new GregorianCalendar(1900, 0, 1); + assertEquals("Checking absolute day (1 Jan 1900)", 1, HSSFDateUtil.absoluteDay(calendar, false)); + // 1 Jan 1901 is 366 days after 31 Dec 1899 + calendar = new GregorianCalendar(1901, 0, 1); + assertEquals("Checking absolute day (1 Jan 1901)", 366, HSSFDateUtil.absoluteDay(calendar, false)); + } + public static void main(String [] args) { System.out .println("Testing org.apache.poi.hssf.usermodel.TestHSSFDateUtil"); junit.textui.TestRunner.run(TestHSSFDateUtil.class); } } - diff --git a/src/testcases/org/apache/poi/hssf/usermodel/TestHSSFPalette.java b/src/testcases/org/apache/poi/hssf/usermodel/TestHSSFPalette.java index 8504b8dd7e..c5674b9e76 100644 --- a/src/testcases/org/apache/poi/hssf/usermodel/TestHSSFPalette.java +++ b/src/testcases/org/apache/poi/hssf/usermodel/TestHSSFPalette.java @@ -95,6 +95,71 @@ public class TestHSSFPalette extends TestCase assertEquals(msg, (short) 100, actualRGB[2]); } + /** + * Uses the palette from cell stylings + */ + public void testPaletteFromCellColours() throws Exception { + String dir = System.getProperty("HSSF.testdata.path"); + File sample = new File(dir + "/SimpleWithColours.xls"); + assertTrue("SimpleWithColours.xls exists and is readable", sample.canRead()); + FileInputStream fis = new FileInputStream(sample); + HSSFWorkbook book = new HSSFWorkbook(fis); + fis.close(); + + HSSFPalette p = book.getCustomPalette(); + + HSSFCell cellA = book.getSheetAt(0).getRow(0).getCell((short)0); + HSSFCell cellB = book.getSheetAt(0).getRow(1).getCell((short)0); + HSSFCell cellC = book.getSheetAt(0).getRow(2).getCell((short)0); + HSSFCell cellD = book.getSheetAt(0).getRow(3).getCell((short)0); + HSSFCell cellE = book.getSheetAt(0).getRow(4).getCell((short)0); + + // Plain + assertEquals("I'm plain", cellA.getStringCellValue()); + assertEquals(64, cellA.getCellStyle().getFillForegroundColor()); + assertEquals(64, cellA.getCellStyle().getFillBackgroundColor()); + assertEquals(HSSFFont.COLOR_NORMAL, cellA.getCellStyle().getFont(book).getColor()); + assertEquals(0, cellA.getCellStyle().getFillPattern()); + assertEquals("0:0:0", p.getColor((short)64).getHexString()); + assertEquals(null, p.getColor((short)32767)); + + // Red + assertEquals("I'm red", cellB.getStringCellValue()); + assertEquals(64, cellB.getCellStyle().getFillForegroundColor()); + assertEquals(64, cellB.getCellStyle().getFillBackgroundColor()); + assertEquals(10, cellB.getCellStyle().getFont(book).getColor()); + assertEquals(0, cellB.getCellStyle().getFillPattern()); + assertEquals("0:0:0", p.getColor((short)64).getHexString()); + assertEquals("FFFF:0:0", p.getColor((short)10).getHexString()); + + // Red + green bg + assertEquals("I'm red with a green bg", cellC.getStringCellValue()); + assertEquals(11, cellC.getCellStyle().getFillForegroundColor()); + assertEquals(64, cellC.getCellStyle().getFillBackgroundColor()); + assertEquals(10, cellC.getCellStyle().getFont(book).getColor()); + assertEquals(1, cellC.getCellStyle().getFillPattern()); + assertEquals("0:FFFF:0", p.getColor((short)11).getHexString()); + assertEquals("FFFF:0:0", p.getColor((short)10).getHexString()); + + // Pink with yellow + assertEquals("I'm pink with a yellow pattern (none)", cellD.getStringCellValue()); + assertEquals(13, cellD.getCellStyle().getFillForegroundColor()); + assertEquals(64, cellD.getCellStyle().getFillBackgroundColor()); + assertEquals(14, cellD.getCellStyle().getFont(book).getColor()); + assertEquals(0, cellD.getCellStyle().getFillPattern()); + assertEquals("FFFF:FFFF:0", p.getColor((short)13).getHexString()); + assertEquals("FFFF:0:FFFF", p.getColor((short)14).getHexString()); + + // Pink with yellow - full + assertEquals("I'm pink with a yellow pattern (full)", cellE.getStringCellValue()); + assertEquals(13, cellE.getCellStyle().getFillForegroundColor()); + assertEquals(64, cellE.getCellStyle().getFillBackgroundColor()); + assertEquals(14, cellE.getCellStyle().getFont(book).getColor()); + assertEquals(0, cellE.getCellStyle().getFillPattern()); + assertEquals("FFFF:FFFF:0", p.getColor((short)13).getHexString()); + assertEquals("FFFF:0:FFFF", p.getColor((short)14).getHexString()); + } + /** * Verifies that the generated gnumeric-format string values match the * hardcoded values in the HSSFColor default color palette diff --git a/src/testcases/org/apache/poi/hssf/usermodel/TestReadWriteChart.java b/src/testcases/org/apache/poi/hssf/usermodel/TestReadWriteChart.java index f53b2f88da..7f2819433b 100644 --- a/src/testcases/org/apache/poi/hssf/usermodel/TestReadWriteChart.java +++ b/src/testcases/org/apache/poi/hssf/usermodel/TestReadWriteChart.java @@ -63,7 +63,7 @@ public class TestReadWriteChart //System.out.println("first assertion for date"); assertEquals(new GregorianCalendar(2000, 0, 1, 10, 51, 2).getTime(), HSSFDateUtil - .getJavaDate(firstCell.getNumericCellValue())); + .getJavaDate(firstCell.getNumericCellValue(), false)); HSSFRow row = sheet.createRow(( short ) 15); HSSFCell cell = row.createCell(( short ) 1); diff --git a/src/testcases/org/apache/poi/hssf/usermodel/TestSheetHiding.java b/src/testcases/org/apache/poi/hssf/usermodel/TestSheetHiding.java new file mode 100644 index 0000000000..9628ab23e4 --- /dev/null +++ b/src/testcases/org/apache/poi/hssf/usermodel/TestSheetHiding.java @@ -0,0 +1,105 @@ +/* +* Licensed to the Apache Software Foundation (ASF) under one or more +* contributor license agreements. See the NOTICE file distributed with +* this work for additional information regarding copyright ownership. +* The ASF licenses this file to You under the Apache License, Version 2.0 +* (the "License"); you may not use this file except in compliance with +* the License. You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ +package org.apache.poi.hssf.usermodel; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.FileInputStream; +import java.io.FileNotFoundException; + +import org.apache.poi.poifs.filesystem.POIFSFileSystem; + +import junit.framework.TestCase; + +/** + * Tests for how HSSFWorkbook behaves with XLS files + * with a WORKBOOK directory entry (instead of the more + * usual, Workbook) + */ +public class TestSheetHiding extends TestCase { + private String dirPath; + private String xlsHidden = "TwoSheetsOneHidden.xls"; + private String xlsShown = "TwoSheetsNoneHidden.xls"; + + protected void setUp() throws Exception { + super.setUp(); + + dirPath = System.getProperty("HSSF.testdata.path"); + } + + /** + * Test that we get the right number of sheets, + * with the right text on them, no matter what + * the hidden flags are + */ + public void testTextSheets() throws Exception { + FileInputStream isH = new FileInputStream(dirPath + "/" + xlsHidden); + POIFSFileSystem fsH = new POIFSFileSystem(isH); + + FileInputStream isU = new FileInputStream(dirPath + "/" + xlsShown); + POIFSFileSystem fsU = new POIFSFileSystem(isU); + + HSSFWorkbook wbH = new HSSFWorkbook(fsH); + HSSFWorkbook wbU = new HSSFWorkbook(fsU); + + // Both should have two sheets + assertEquals(2, wbH.sheets.size()); + assertEquals(2, wbU.sheets.size()); + + // All sheets should have one row + assertEquals(0, wbH.getSheetAt(0).getLastRowNum()); + assertEquals(0, wbH.getSheetAt(1).getLastRowNum()); + assertEquals(0, wbU.getSheetAt(0).getLastRowNum()); + assertEquals(0, wbU.getSheetAt(1).getLastRowNum()); + + // All rows should have one column + assertEquals(1, wbH.getSheetAt(0).getRow(0).getLastCellNum()); + assertEquals(1, wbH.getSheetAt(1).getRow(0).getLastCellNum()); + assertEquals(1, wbU.getSheetAt(0).getRow(0).getLastCellNum()); + assertEquals(1, wbU.getSheetAt(1).getRow(0).getLastCellNum()); + + // Text should be sheet based + assertEquals("Sheet1A1", wbH.getSheetAt(0).getRow(0).getCell((short)0).getStringCellValue()); + assertEquals("Sheet2A1", wbH.getSheetAt(1).getRow(0).getCell((short)0).getStringCellValue()); + assertEquals("Sheet1A1", wbU.getSheetAt(0).getRow(0).getCell((short)0).getStringCellValue()); + assertEquals("Sheet2A1", wbU.getSheetAt(1).getRow(0).getCell((short)0).getStringCellValue()); + } + + /** + * Check that we can get and set the hidden flags + * as expected + */ + public void testHideUnHideFlags() throws Exception { + // TODO + } + + /** + * Turn the sheet with none hidden into the one with + * one hidden + */ + public void testHide() throws Exception { + // TODO + } + + /** + * Turn the sheet with one hidden into the one with + * none hidden + */ + public void testUnHide() throws Exception { + // TODO + } +} diff --git a/src/testcases/org/apache/poi/poifs/filesystem/TestEmptyDocument.java b/src/testcases/org/apache/poi/poifs/filesystem/TestEmptyDocument.java index a56a1d2a3a..4f67f98767 100644 --- a/src/testcases/org/apache/poi/poifs/filesystem/TestEmptyDocument.java +++ b/src/testcases/org/apache/poi/poifs/filesystem/TestEmptyDocument.java @@ -23,6 +23,7 @@ import java.io.ByteArrayOutputStream; import junit.framework.TestCase; +import org.apache.poi.util.IOUtils; import org.apache.poi.poifs.filesystem.POIFSFileSystem; import org.apache.poi.poifs.filesystem.POIFSWriterEvent; import org.apache.poi.poifs.filesystem.POIFSWriterListener; @@ -140,4 +141,28 @@ public class TestEmptyDocument extends TestCase { fs.writeFilesystem(out); new POIFSFileSystem(new ByteArrayInputStream(out.toByteArray())); } + + public void testEmptyDocumentBug11744() throws Exception { + byte[] testData = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }; + + POIFSFileSystem fs = new POIFSFileSystem(); + fs.createDocument(new ByteArrayInputStream(new byte[0]), "Empty"); + fs.createDocument(new ByteArrayInputStream(testData), "NotEmpty"); + ByteArrayOutputStream out = new ByteArrayOutputStream(); + fs.writeFilesystem(out); + out.toByteArray(); + + // This line caused the error. + fs = new POIFSFileSystem(new ByteArrayInputStream(out.toByteArray())); + + DocumentEntry entry = (DocumentEntry) fs.getRoot().getEntry("Empty"); + assertEquals("Expected zero size", 0, entry.getSize()); + assertEquals("Expected zero read from stream", 0, + IOUtils.toByteArray(new DocumentInputStream(entry)).length); + + entry = (DocumentEntry) fs.getRoot().getEntry("NotEmpty"); + assertEquals("Expected size was wrong", testData.length, entry.getSize()); + assertEquals("Expected different data read from stream", testData, + IOUtils.toByteArray(new DocumentInputStream(entry))); + } }