diff options
author | Nick Burch <nick@apache.org> | 2008-03-29 17:00:47 +0000 |
---|---|---|
committer | Nick Burch <nick@apache.org> | 2008-03-29 17:00:47 +0000 |
commit | fb33f585f596d2d149409e5c88e8f4a7ea47921a (patch) | |
tree | f2c19ddae637adbb346872a08a362f3f97cef572 | |
parent | cfe2e40f4b62ec7bd8ad8b183322e852c91ca4d0 (diff) | |
download | poi-fb33f585f596d2d149409e5c88e8f4a7ea47921a.tar.gz poi-fb33f585f596d2d149409e5c88e8f4a7ea47921a.zip |
Merged revisions 638001-638784,638786-639486,639488-639601,639603-639836 via svnmerge from
https://svn.apache.org/repos/asf/poi/trunk
........
r638803 | nick | 2008-03-19 11:57:38 +0000 (Wed, 19 Mar 2008) | 1 line
Added test to show that bug #41546 is already fixed. Also rename a test file to be more consistent
........
r638804 | nick | 2008-03-19 12:01:32 +0000 (Wed, 19 Mar 2008) | 1 line
Add test to show that bug #43251 is already fixed
........
r638812 | nick | 2008-03-19 12:28:56 +0000 (Wed, 19 Mar 2008) | 1 line
Patch from Dmitriy from bug #30311 - Support for conditional formatting records
........
r638815 | nick | 2008-03-19 12:49:35 +0000 (Wed, 19 Mar 2008) | 1 line
Fix bug #44627 - improve the thread safety of POILogFactory
........
r639231 | nick | 2008-03-20 10:06:59 +0000 (Thu, 20 Mar 2008) | 1 line
Test relating to bug #44636
........
r639232 | nick | 2008-03-20 10:16:15 +0000 (Thu, 20 Mar 2008) | 1 line
Simple patch from Josh from bug #44636 - fix for RefVPtg and edit-in-excel oddness
........
r639242 | nick | 2008-03-20 11:02:39 +0000 (Thu, 20 Mar 2008) | 1 line
Fix for readCompressedUnicode not moaning about length=0, from bug #44643
........
r639254 | nick | 2008-03-20 11:43:14 +0000 (Thu, 20 Mar 2008) | 1 line
Make junit happy
........
r639836 | nick | 2008-03-21 21:04:47 +0000 (Fri, 21 Mar 2008) | 1 line
Tweak how you get dataformat strings out of cell styles, to be more logical, and in keeping with how we'll want to do things for xssf too
........
git-svn-id: https://svn.apache.org/repos/asf/poi/branches/ooxml@642557 13f79535-47bb-0310-9956-ffa450edef68
36 files changed, 5097 insertions, 54 deletions
diff --git a/src/documentation/content/xdocs/changes.xml b/src/documentation/content/xdocs/changes.xml index 4bfd32b0e6..b1504a7023 100644 --- a/src/documentation/content/xdocs/changes.xml +++ b/src/documentation/content/xdocs/changes.xml @@ -36,6 +36,9 @@ <!-- Don't forget to update status.xml too! --> <release version="3.1-beta1" date="2008-??-??"> + <action dev="POI-DEVELOPERS" type="fix">44636 - Fix formula parsing of RefVPtg, which was causing #VALUE to be shown on subsequent edits</action> + <action dev="POI-DEVELOPERS" type="fix">44627 - Improve the thread safety of POILogFactory</action> + <action dev="POI-DEVELOPERS" type="add">30311 - Initial support for Conditional Formatting</action> <action dev="POI-DEVELOPERS" type="fix">44609 - Handle leading spaces in formulas, such as '= 4'</action> <action dev="POI-DEVELOPERS" type="add">44608 - Support for PercentPtg in the formula evaluator</action> <action dev="POI-DEVELOPERS" type="fix">44606 - Support calculated string values for evaluated formulas</action> diff --git a/src/documentation/content/xdocs/status.xml b/src/documentation/content/xdocs/status.xml index a6467d5164..d29d57ff8d 100644 --- a/src/documentation/content/xdocs/status.xml +++ b/src/documentation/content/xdocs/status.xml @@ -33,6 +33,9 @@ <!-- Don't forget to update changes.xml too! --> <changes> <release version="3.1-beta1" date="2008-??-??"> + <action dev="POI-DEVELOPERS" type="fix">44636 - Fix formula parsing of RefVPtg, which was causing #VALUE to be shown on subsequent edits</action> + <action dev="POI-DEVELOPERS" type="fix">44627 - Improve the thread safety of POILogFactory</action> + <action dev="POI-DEVELOPERS" type="add">30311 - Initial support for Conditional Formatting</action> <action dev="POI-DEVELOPERS" type="fix">44609 - Handle leading spaces in formulas, such as '= 4'</action> <action dev="POI-DEVELOPERS" type="add">44608 - Support for PercentPtg in the formula evaluator</action> <action dev="POI-DEVELOPERS" type="fix">44606 - Support calculated string values for evaluated formulas</action> diff --git a/src/java/org/apache/poi/hssf/model/Sheet.java b/src/java/org/apache/poi/hssf/model/Sheet.java index f3f7deba07..451cde7579 100644 --- a/src/java/org/apache/poi/hssf/model/Sheet.java +++ b/src/java/org/apache/poi/hssf/model/Sheet.java @@ -24,6 +24,7 @@ import org.apache.poi.hssf.record.aggregates.ColumnInfoRecordsAggregate; import org.apache.poi.hssf.record.aggregates.FormulaRecordAggregate; import org.apache.poi.hssf.record.aggregates.RowRecordsAggregate; import org.apache.poi.hssf.record.aggregates.ValueRecordsAggregate; +import org.apache.poi.hssf.record.aggregates.CFRecordsAggregate; import org.apache.poi.hssf.record.formula.Ptg; import org.apache.poi.hssf.util.PaneInformation; @@ -96,6 +97,7 @@ public class Sheet implements Model protected ObjectProtectRecord objprotect = null; protected ScenarioProtectRecord scenprotect = null; protected PasswordRecord password = null; + protected List condFormatting = new ArrayList();; /** Add an UncalcedRecord if not true indicating formulas have not been calculated */ protected boolean uncalced = false; @@ -184,6 +186,17 @@ public class Sheet implements Model retval.merged = ( MergeCellsRecord ) rec; retval.numMergedRegions += retval.merged.getNumAreas(); } + else if ( rec.getSid() == CFHeaderRecord.sid ) + { + CFRecordsAggregate cfAgg = CFRecordsAggregate.createCFAggregate(recs, k); + retval.condFormatting.add(cfAgg); + rec = cfAgg; + } + else if ( rec.getSid() == CFRuleRecord.sid ) + { + // Skip it since it is processed by CFRecordsAggregate + rec = null; + } else if (rec.getSid() == ColumnInfoRecord.sid) { ColumnInfoRecord col = (ColumnInfoRecord)rec; @@ -604,6 +617,66 @@ public class Sheet implements Model { return numMergedRegions; } + // Find correct position to add new CF record + private int findConditionalFormattingPosition() + { + // This is default. + // If the algorithm does not find the right position, + // this one will be used (this is a position before EOF record) + int index = records.size()-2; + + for( int i=index; i>=0; i-- ) + { + Record rec = (Record)records.get(i); + short sid = rec.getSid(); + + // CFRecordsAggregate records already exist, just add to the end + if (rec instanceof CFRecordsAggregate) { return i+1; } + + if( sid == (short)0x00ef ) { return i+1; }// PHONETICPR + if( sid == (short)0x015f ) { return i+1; }// LABELRANGES + if( sid == MergeCellsRecord.sid ) { return i+1; } + if( sid == (short)0x0099 ) { return i+1; }// STANDARDWIDTH + if( sid == SelectionRecord.sid ) { return i+1; } + if( sid == PaneRecord.sid ) { return i+1; } + if( sid == SCLRecord.sid ) { return i+1; } + if( sid == WindowTwoRecord.sid ) { return i+1; } + } + + return index; + } + + public int addConditionalFormatting(CFRecordsAggregate cfAggregate) + { + int index = findConditionalFormattingPosition(); + records.add(index, cfAggregate); + condFormatting.add(cfAggregate); + return condFormatting.size()-1; + } + + public void removeConditionalFormatting(int index) + { + if (index >= 0 && index <= condFormatting.size()-1 ) + { + CFRecordsAggregate cfAggregate = getCFRecordsAggregateAt(index); + records.remove(cfAggregate); + condFormatting.remove(index); + } + } + + public CFRecordsAggregate getCFRecordsAggregateAt(int index) + { + if (index >= 0 && index <= condFormatting.size()-1 ) + { + return (CFRecordsAggregate) condFormatting.get(index); + } + return null; + } + + public int getNumConditionalFormattings() + { + return condFormatting.size(); + } /** * Returns the number of low level binary records in this sheet. This adjusts things for the so called diff --git a/src/java/org/apache/poi/hssf/record/CFHeaderRecord.java b/src/java/org/apache/poi/hssf/record/CFHeaderRecord.java new file mode 100644 index 0000000000..00a8646b4f --- /dev/null +++ b/src/java/org/apache/poi/hssf/record/CFHeaderRecord.java @@ -0,0 +1,223 @@ +/* ==================================================================== + 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. +==================================================================== */ + +/* + * ConditionalFormattingHeaderRecord.java + * + * Created on January 17, 2008, 3:05 AM + */ +package org.apache.poi.hssf.record; + +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; + +import org.apache.poi.hssf.record.cf.CellRange; +import org.apache.poi.util.LittleEndian; + +/** + * Conditional Formatting Header record (CFHEADER) + * + * @author Dmitriy Kumshayev + */ +public class CFHeaderRecord extends Record +{ + public static final short sid = 0x1B0; + + private int field_1_numcf; + private int field_2_need_recalculation; + private CellRange field_3_enclosing_cell_range; + private List field_4_cell_ranges; + + /** Creates new CFHeaderRecord */ + public CFHeaderRecord() + { + field_4_cell_ranges = new ArrayList(5); + } + + public CFHeaderRecord(RecordInputStream in) + { + super(in); + } + + protected void fillFields(RecordInputStream in) + { + field_1_numcf = in.readShort(); + field_2_need_recalculation = in.readShort(); + field_3_enclosing_cell_range = new CellRange(in.readShort(),in.readShort(),in.readShort(),in.readShort()); + int numCellRanges = in.readShort(); + field_4_cell_ranges = new ArrayList(5); + for( int i=0; i<numCellRanges; i++) + { + field_4_cell_ranges.add(new CellRange(in.readShort(),in.readShort(),in.readShort(),in.readShort())); + } + } + + public int getNumberOfConditionalFormats() + { + return field_1_numcf; + } + public void setNumberOfConditionalFormats(int n) + { + field_1_numcf=n; + } + + public boolean getNeedRecalculation() + { + return field_2_need_recalculation==1?true:false; + } + + public void setNeedRecalculation(boolean b) + { + field_2_need_recalculation=b?1:0; + } + + public CellRange getEnclosingCellRange() + { + return field_3_enclosing_cell_range; + } + + public void setEnclosingCellRange( CellRange cr) + { + field_3_enclosing_cell_range = cr.cloneCellRange(); + } + + /** + * Set cell ranges list to a single cell range and + * modify the enclosing cell range accordingly. + * @param List cellRanges - list of CellRange objects + */ + public void setCellRanges( List cellRanges ) + { + field_4_cell_ranges.clear(); + if(cellRanges!=null) + { + field_3_enclosing_cell_range=null; + for( int i=0; i<cellRanges.size(); i++) + { + field_4_cell_ranges.add(cellRanges.get(i)); + recalculateEnclosingRange((CellRange)cellRanges.get(i)); + } + } + } + + private void recalculateEnclosingRange(CellRange cellRange) + { + field_3_enclosing_cell_range = cellRange.createEnclosingCellRange(field_3_enclosing_cell_range); + } + + public List getCellRanges() + { + return field_4_cell_ranges; + } + + public String toString() + { + StringBuffer buffer = new StringBuffer(); + + buffer.append("[CFHEADER]\n"); + buffer.append(" .id = ").append(Integer.toHexString(sid)).append("\n"); + buffer.append(" .numCF = ").append(getNumberOfConditionalFormats()).append("\n"); + buffer.append(" .needRecalc = ").append(getNeedRecalculation()).append("\n"); + buffer.append(" .enclosingCellRange= ").append(getEnclosingCellRange()).append("\n"); + if( field_4_cell_ranges.size()>0) + { + buffer.append(" .cfranges=["); + for( int i=0; i<field_4_cell_ranges.size(); i++) + { + buffer.append(i==0?"":",").append(field_4_cell_ranges.get(i)); + } + buffer.append("]\n"); + } + buffer.append("[/CFHEADER]\n"); + return buffer.toString(); + } + + /** + * @return byte array containing instance data + */ + + public int serialize(int offset, byte[] data) + { + int recordsize = getRecordSize(); + + LittleEndian.putShort(data, 0 + offset, sid); + LittleEndian.putShort(data, 2 + offset, (short) (recordsize-4)); + LittleEndian.putShort(data, 4 + offset, (short) field_1_numcf); + LittleEndian.putShort(data, 6 + offset, (short) field_2_need_recalculation); + LittleEndian.putShort(data, 8 + offset, (short) field_3_enclosing_cell_range.getFirstRow()); + LittleEndian.putShort(data, 10 + offset, (short) field_3_enclosing_cell_range.getLastRow()); + LittleEndian.putShort(data, 12 + offset, (short) field_3_enclosing_cell_range.getFirstColumn()); + LittleEndian.putShort(data, 14 + offset, (short) field_3_enclosing_cell_range.getLastColumn()); + LittleEndian.putShort(data, 16 + offset, (short) field_4_cell_ranges.size()); + for( int i=0 ; i!=field_4_cell_ranges.size(); i++) + { + LittleEndian.putShort(data, 18 + 0 + 8 * i + offset, + (short) ((CellRange) field_4_cell_ranges.get(i)).getFirstRow()); + LittleEndian.putShort(data, 18 + 2 + 8 * i + offset, + (short) ((CellRange) field_4_cell_ranges.get(i)).getLastRow()); + LittleEndian.putShort(data, 18 + 4 + 8 * i + offset, + (short) ((CellRange) field_4_cell_ranges.get(i)).getFirstColumn()); + LittleEndian.putShort(data, 18 + 6 + 8 * i + offset, + (short) ((CellRange) field_4_cell_ranges.get(i)).getLastColumn()); + } + return getRecordSize(); + } + + public int getRecordSize() + { + return 18+8*field_4_cell_ranges.size(); + } + + /** + * called by constructor, should throw runtime exception in the event of a + * record passed with a differing ID. + * + * @param id alleged id for this record + */ + + protected void validateSid(short id) + { + if (id != sid) + { + throw new RecordFormatException( + "NOT A ConditionalFormattingHeaderRecord RECORD"); + } + } + + public short getSid() + { + return sid; + } + + public Object clone() + { + CFHeaderRecord rec = new CFHeaderRecord(); + rec.field_1_numcf = field_1_numcf; + rec.field_2_need_recalculation = field_2_need_recalculation; + rec.field_3_enclosing_cell_range = field_3_enclosing_cell_range; + rec.field_4_cell_ranges = new ArrayList(field_4_cell_ranges.size()); + Iterator iterator = field_4_cell_ranges.iterator(); + while (iterator.hasNext()) + { + CellRange oldRange = (CellRange)iterator.next(); + rec.field_4_cell_ranges.add(oldRange.cloneCellRange()); + } + return rec; + } + +} diff --git a/src/java/org/apache/poi/hssf/record/CFRuleRecord.java b/src/java/org/apache/poi/hssf/record/CFRuleRecord.java new file mode 100644 index 0000000000..0108443460 --- /dev/null +++ b/src/java/org/apache/poi/hssf/record/CFRuleRecord.java @@ -0,0 +1,657 @@ + +/* ==================================================================== + 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. +==================================================================== */ + + +/* + * ConditionalFormattingRuleRecord.java + * + * Created on January 23, 2008, 9:56 AM + */ +package org.apache.poi.hssf.record; + +import java.util.List; +import java.util.Stack; + +import org.apache.poi.hssf.record.cf.BorderFormatting; +import org.apache.poi.hssf.record.cf.FontFormatting; +import org.apache.poi.hssf.record.cf.PatternFormatting; +import org.apache.poi.hssf.record.formula.Ptg; +import org.apache.poi.util.BitField; +import org.apache.poi.util.BitFieldFactory; +import org.apache.poi.util.LittleEndian; + +/** + * Conditional Formatting Rule Record. + * @author Dmitriy Kumshayev + */ + +public class CFRuleRecord extends Record +{ + + public static final short sid = 0x01B1; + + private byte field_1_condition_type; + public static final byte CONDITION_TYPE_NO_CONDITION_TYPE = 0; + public static final byte CONDITION_TYPE_CELL_VALUE_IS = 1; + public static final byte CONDITION_TYPE_FORMULA = 2; + + private byte field_2_comparison_operator; + public static final byte COMPARISON_OPERATOR_NO_COMPARISON = 0; + public static final byte COMPARISON_OPERATOR_BETWEEN = 1; + public static final byte COMPARISON_OPERATOR_NOT_BETWEEN = 2; + public static final byte COMPARISON_OPERATOR_EQUAL = 3; + public static final byte COMPARISON_OPERATOR_NOT_EQUAL = 4; + public static final byte COMPARISON_OPERATOR_GT = 5; + public static final byte COMPARISON_OPERATOR_LT = 6; + public static final byte COMPARISON_OPERATOR_GE = 7; + public static final byte COMPARISON_OPERATOR_LE = 8; + + private short field_3_formula1_len; + private short field_4_formula2_len; + + private int field_5_options; + + private static final BitField modificationBits = BitFieldFactory.getInstance(0x83FFFFFF); // Bits: font,align,bord,patt,prot + private static final BitField alignHor = BitFieldFactory.getInstance(0x00000001); // 0 = Horizontal alignment modified + private static final BitField alignVer = BitFieldFactory.getInstance(0x00000002); // 0 = Vertical alignment modified + private static final BitField alignWrap = BitFieldFactory.getInstance(0x00000004); // 0 = Text wrapped flag modified + private static final BitField alignRot = BitFieldFactory.getInstance(0x00000008); // 0 = Text rotation modified + private static final BitField alignJustLast = BitFieldFactory.getInstance(0x00000010); // 0 = Justify last line flag modified + private static final BitField alignIndent = BitFieldFactory.getInstance(0x00000020); // 0 = Indentation modified + private static final BitField alignShrink = BitFieldFactory.getInstance(0x00000040); // 0 = Shrink to fit flag modified + private static final BitField notUsed1 = BitFieldFactory.getInstance(0x00000080); // Always 1 + private static final BitField protLocked = BitFieldFactory.getInstance(0x00000100); // 0 = Cell locked flag modified + private static final BitField protHidden = BitFieldFactory.getInstance(0x00000200); // 0 = Cell hidden flag modified + private static final BitField bordLeft = BitFieldFactory.getInstance(0x00000400); // 0 = Left border style and colour modified + private static final BitField bordRight = BitFieldFactory.getInstance(0x00000800); // 0 = Right border style and colour modified + private static final BitField bordTop = BitFieldFactory.getInstance(0x00001000); // 0 = Top border style and colour modified + private static final BitField bordBot = BitFieldFactory.getInstance(0x00002000); // 0 = Bottom border style and colour modified + private static final BitField bordTlBr = BitFieldFactory.getInstance(0x00004000); // 0 = Top-left to bottom-right border flag modified + private static final BitField bordBlTr = BitFieldFactory.getInstance(0x00008000); // 0 = Bottom-left to top-right border flag modified + private static final BitField pattStyle = BitFieldFactory.getInstance(0x00010000); // 0 = Pattern style modified + private static final BitField pattCol = BitFieldFactory.getInstance(0x00020000); // 0 = Pattern colour modified + private static final BitField pattBgCol = BitFieldFactory.getInstance(0x00040000); // 0 = Pattern background colour modified + private static final BitField notUsed2 = BitFieldFactory.getInstance(0x00380000); // Always 111 + private static final BitField undocumented = BitFieldFactory.getInstance(0x03C00000); // Undocumented bits + private static final BitField fmtBlockBits = BitFieldFactory.getInstance(0x7C000000); // Bits: font,align,bord,patt,prot + private static final BitField font = BitFieldFactory.getInstance(0x04000000); // 1 = Record contains font formatting block + private static final BitField align = BitFieldFactory.getInstance(0x08000000); // 1 = Record contains alignment formatting block + private static final BitField bord = BitFieldFactory.getInstance(0x10000000); // 1 = Record contains border formatting block + private static final BitField patt = BitFieldFactory.getInstance(0x20000000); // 1 = Record contains pattern formatting block + private static final BitField prot = BitFieldFactory.getInstance(0x40000000); // 1 = Record contains protection formatting block + private static final BitField alignTextDir = BitFieldFactory.getInstance(0x80000000); // 0 = Text direction modified + + + private short field_6_not_used; + + private FontFormatting fontFormatting; + + private byte field_8_align_text_break; + private byte field_9_align_text_rotation_angle; + private short field_10_align_indentation; + private short field_11_relative_indentation; + private short field_12_not_used; + + private BorderFormatting borderFormatting; + + private PatternFormatting patternFormatting; + + private Stack field_17_formula1; + private Stack field_18_formula2; + + /** Creates new CFRuleRecord */ + public CFRuleRecord() + { + field_1_condition_type=CONDITION_TYPE_NO_CONDITION_TYPE; + field_2_comparison_operator=COMPARISON_OPERATOR_NO_COMPARISON; + setExpression1Length((short)0); + setExpression2Length((short)0); + + // Set modification flags to 1: by default options are not modified + setOptions(modificationBits.setValue(field_5_options, -1)); + // Set formatting block flags to 0 (no formatting blocks) + setOptions(fmtBlockBits.setValue(field_5_options, 0)); + + field_6_not_used = 0; + fontFormatting=null; + field_8_align_text_break = 0; + field_9_align_text_rotation_angle = 0; + field_10_align_indentation = 0; + field_11_relative_indentation = 0; + field_12_not_used = 0; + borderFormatting=null; + patternFormatting=null; + field_17_formula1=null; + field_18_formula2=null; + } + + /** + * Constructs a Formula record and sets its fields appropriately. + * Note - id must be 0x06 (NOT 0x406 see MSKB #Q184647 for an + * "explanation of this bug in the documentation) or an exception + * will be throw upon validation + * + * @param in the RecordInputstream to read the record from + */ + + public CFRuleRecord(RecordInputStream in) + { + super(in); + } + + protected void fillFields(RecordInputStream in) + { + try { + field_1_condition_type = in.readByte(); + field_2_comparison_operator = in.readByte(); + field_3_formula1_len = in.readShort(); + field_4_formula2_len = in.readShort(); + field_5_options = in.readInt(); + field_6_not_used = in.readShort(); + + if(containsFontFormattingBlock()) + { + fontFormatting = new FontFormatting(in); + } + + if(containsBorderFormattingBlock()) + { + borderFormatting = new BorderFormatting(in); + } + + if( containsPatternFormattingBlock()) + { + patternFormatting = new PatternFormatting(in); + } + + if(field_3_formula1_len>0) + { + field_17_formula1 = Ptg.createParsedExpressionTokens(field_3_formula1_len, in); + + // Now convert any fields as required + field_17_formula1 = SharedFormulaRecord.convertSharedFormulas( + field_17_formula1, 0, 0 + ); + } + if(field_4_formula2_len>0) + { + field_18_formula2 = Ptg.createParsedExpressionTokens(field_4_formula2_len, in); + + // Now convert any fields as required + field_18_formula2 = SharedFormulaRecord.convertSharedFormulas( + field_18_formula2, 0, 0 + ); + } + } catch (java.lang.UnsupportedOperationException uoe) { + throw new RecordFormatException(uoe); + } + + } + + public void setConditionType(byte conditionType) + { + field_1_condition_type = + conditionType == CONDITION_TYPE_CELL_VALUE_IS ? + CONDITION_TYPE_CELL_VALUE_IS : + CONDITION_TYPE_FORMULA; + } + + public byte getConditionType() + { + return field_1_condition_type; + } + + /** + * set the option flags + * + * @param options bitmask + */ + + public void setOptions(int options) + { + field_5_options = options; + } + + public boolean containsFontFormattingBlock() + { + return getOptionFlag(font); + } + public void setFontFormatting(FontFormatting fontFormatting) + { + this.fontFormatting = fontFormatting; + setOptionFlag(true,font); + } + public void setFontFormattingUnchanged() + { + setOptionFlag(false,font); + } + + public boolean containsAlignFormattingBlock() + { + return getOptionFlag(align); + } + public void setAlignFormattingUnchanged() + { + setOptionFlag(false,align); + } + + public boolean containsBorderFormattingBlock() + { + return getOptionFlag(bord); + } + public void setBorderFormatting(BorderFormatting borderFormatting) + { + this.borderFormatting = borderFormatting; + setOptionFlag(true,bord); + } + public void setBorderFormattingUnchanged() + { + setOptionFlag(false,bord); + } + + public boolean containsPatternFormattingBlock() + { + return getOptionFlag(patt); + } + public void setPatternFormatting(PatternFormatting patternFormatting) + { + this.patternFormatting = patternFormatting; + setOptionFlag(true,patt); + } + public void setPatternFormattingUnchanged() + { + setOptionFlag(false,patt); + } + + public boolean containsProtectionFormattingBlock() + { + return getOptionFlag(prot); + } + public void setProtectionFormattingUnchanged() + { + setOptionFlag(false,prot); + } + + public void setComparisonOperation(byte operation) + { + field_2_comparison_operator = operation; + } + + public byte getComparisonOperation() + { + return field_2_comparison_operator; + } + + /** + * set the length (in number of tokens) of the expression 1 + * @param len length + */ + + private void setExpression1Length(short len) + { + field_3_formula1_len = len; + } + + /** + * get the length (in number of tokens) of the expression 1 + * @return expression length + */ + + public short getExpression1Length() + { + return field_3_formula1_len; + } + + /** + * set the length (in number of tokens) of the expression 2 + * @param len length + */ + + private void setExpression2Length(short len) + { + field_4_formula2_len = len; + } + + /** + * get the length (in number of tokens) of the expression 2 + * @return expression length + */ + + public short getExpression2Length() + { + return field_4_formula2_len; + } + /** + * get the option flags + * + * @return bit mask + */ + public int getOptions() + { + return field_5_options; + } + + private boolean isModified(BitField field) + { + return !field.isSet(field_5_options); + } + + private void setModified(boolean modified, BitField field) + { + field_5_options = field.setBoolean(field_5_options, !modified); + } + + public boolean isLeftBorderModified() + { + return isModified(bordLeft); + } + + public void setLeftBorderModified(boolean modified) + { + setModified(modified,bordLeft); + } + + public boolean isRightBorderModified() + { + return isModified(bordRight); + } + + public void setRightBorderModified(boolean modified) + { + setModified(modified,bordRight); + } + + public boolean isTopBorderModified() + { + return isModified(bordTop); + } + + public void setTopBorderModified(boolean modified) + { + setModified(modified,bordTop); + } + + public boolean isBottomBorderModified() + { + return isModified(bordBot); + } + + public void setBottomBorderModified(boolean modified) + { + setModified(modified,bordBot); + } + + public boolean isTopLeftBottomRightBorderModified() + { + return isModified(bordTlBr); + } + + public void setTopLeftBottomRightBorderModified(boolean modified) + { + setModified(modified,bordTlBr); + } + + public boolean isBottomLeftTopRightBorderModified() + { + return isModified(bordBlTr); + } + + public void setBottomLeftTopRightBorderModified(boolean modified) + { + setModified(modified,bordBlTr); + } + + public boolean isPatternStyleModified() + { + return isModified(pattStyle); + } + + public void setPatternStyleModified(boolean modified) + { + setModified(modified,pattStyle); + } + + public boolean isPatternColorModified() + { + return isModified(pattCol); + } + + public void setPatternColorModified(boolean modified) + { + setModified(modified,pattCol); + } + + public boolean isPatternBackgroundColorModified() + { + return isModified(pattBgCol); + } + + public void setPatternBackgroundColorModified(boolean modified) + { + setModified(modified,pattBgCol); + } + + private boolean getOptionFlag(BitField field) + { + return field.isSet(field_5_options); + } + + private void setOptionFlag(boolean flag, BitField field) + { + field_5_options = field.setBoolean(field_5_options, flag); + } + + /** + * get the stack of the 1st expression as a list + * + * @return list of tokens (casts stack to a list and returns it!) + * this method can return null is we are unable to create Ptgs from + * existing excel file + * callers should check for null! + */ + + public List getParsedExpression1() + { + return field_17_formula1; + } + + /** + * get the stack of the 2nd expression as a list + * + * @return list of tokens (casts stack to a list and returns it!) + * this method can return null is we are unable to create Ptgs from + * existing excel file + * callers should check for null! + */ + + public List getParsedExpression2() + { + return field_18_formula2; + } + + public void setParsedExpression1(Stack ptgs) { + setExpression1Length(getTotalPtgSize(field_17_formula1 = ptgs)); + } + + public void setParsedExpression2(Stack ptgs) { + setExpression1Length(getTotalPtgSize(field_18_formula2 = ptgs)); + } + + /** + * called by constructor, should throw runtime exception in the event of a + * record passed with a differing ID. + * + * @param id alleged id for this record + */ + + protected void validateSid(short id) + { + if (id != sid) + { + throw new RecordFormatException("NOT A CFRULE RECORD"); + } + } + + public short getSid() + { + return sid; + } + + /** + * called by the class that is responsible for writing this sucker. + * Subclasses should implement this so that their data is passed back in a + * byte array. + * + * @param offset to begin writing at + * @param data byte array containing instance data + * @return number of bytes written + */ + + public int serialize(int offset, byte [] data) + { + int recordsize = getRecordSize(); + LittleEndian.putShort(data, 0 + offset, sid); + LittleEndian.putShort(data, 2 + offset, (short)(recordsize-4)); + data[4 + offset] = field_1_condition_type; + data[5 + offset] = field_2_comparison_operator; + LittleEndian.putShort(data, 6 + offset, field_3_formula1_len); + LittleEndian.putShort(data, 8 + offset, field_4_formula2_len); + LittleEndian.putInt(data, 10 + offset, field_5_options); + LittleEndian.putShort(data,14 + offset, field_6_not_used); + + offset += 16; + + if( containsFontFormattingBlock() ) + { + byte[] fontFormattingRawRecord = fontFormatting.getRawRecord(); + System.arraycopy(fontFormattingRawRecord, 0, data, offset, fontFormattingRawRecord.length); + offset += fontFormattingRawRecord.length; + } + + if( containsBorderFormattingBlock()) + { + offset += borderFormatting.serialize(offset, data); + } + + if( containsPatternFormattingBlock() ) + { + offset += patternFormatting.serialize(offset, data); + } + + if (getExpression1Length()>0) + { + Ptg.serializePtgStack(this.field_17_formula1, data, offset); + offset += getExpression1Length(); + } + + if (getExpression2Length()>0) + { + Ptg.serializePtgStack(this.field_18_formula2, data, offset); + offset += getExpression2Length(); + } + return recordsize; + } + + + + + public int getRecordSize() + { + int retval =16+ + (containsFontFormattingBlock()?fontFormatting.getRawRecord().length:0)+ + (containsBorderFormattingBlock()?8:0)+ + (containsPatternFormattingBlock()?4:0)+ + getExpression1Length()+ + getExpression2Length() + ; + return retval; + } + + private short getTotalPtgSize(List list) + { + short retval = 0; + if( list!=null) + { + for (int k = 0; k < list.size(); k++) + { + Ptg ptg = ( Ptg ) list.get(k); + + retval += ptg.getSize(); + } + } + return retval; + } + + public String toString() + { + StringBuffer buffer = new StringBuffer(); + buffer.append("[CFRULE]\n"); + if( containsFontFormattingBlock()) + { + buffer.append(fontFormatting.toString()); + } + if( containsBorderFormattingBlock()) + { + buffer.append(borderFormatting.toString()); + } + if( containsPatternFormattingBlock()) + { + buffer.append(patternFormatting.toString()); + } + buffer.append("[/CFRULE]\n"); + return buffer.toString(); + } + + public Object clone() { + CFRuleRecord rec = new CFRuleRecord(); + rec.field_1_condition_type= field_1_condition_type; + rec.field_2_comparison_operator = field_2_comparison_operator; + rec.field_3_formula1_len = field_3_formula1_len; + rec.field_4_formula2_len = field_4_formula2_len; + rec.field_5_options = field_5_options; + rec.field_6_not_used = field_6_not_used; + if( containsFontFormattingBlock()) + { + rec.fontFormatting = (FontFormatting)fontFormatting.clone(); + } + if( containsBorderFormattingBlock()) + { + rec.borderFormatting = (BorderFormatting)borderFormatting.clone(); + } + if( containsPatternFormattingBlock()) + { + rec.patternFormatting = (PatternFormatting)patternFormatting.clone(); + } + if( field_3_formula1_len>0) + { + rec.field_17_formula1 = (Stack)field_17_formula1.clone(); + } + if( field_4_formula2_len>0) + { + rec.field_18_formula2 = (Stack)field_18_formula2.clone(); + } + + return rec; + } + + public FontFormatting getFontFormatting() + { + return fontFormatting; + } + +} diff --git a/src/java/org/apache/poi/hssf/record/RecordFactory.java b/src/java/org/apache/poi/hssf/record/RecordFactory.java index f247a8d4b9..1dada4450f 100644 --- a/src/java/org/apache/poi/hssf/record/RecordFactory.java +++ b/src/java/org/apache/poi/hssf/record/RecordFactory.java @@ -82,6 +82,8 @@ public class RecordFactory SupBookRecord.class, CRNCountRecord.class, CRNRecord.class, + CFHeaderRecord.class, + CFRuleRecord.class, }; } private static Map recordsMap = recordsToMap(records); diff --git a/src/java/org/apache/poi/hssf/record/RecordInputStream.java b/src/java/org/apache/poi/hssf/record/RecordInputStream.java index 431558ccc8..ba900b2a28 100755 --- a/src/java/org/apache/poi/hssf/record/RecordInputStream.java +++ b/src/java/org/apache/poi/hssf/record/RecordInputStream.java @@ -266,6 +266,9 @@ public class RecordInputStream extends InputStream } public String readCompressedUnicode(int length) { + if(length == 0) { + return ""; + } if ((length < 0) || ((remaining() < length) && !isContinueNext())) { throw new IllegalArgumentException("Illegal length " + length); } @@ -273,7 +276,7 @@ public class RecordInputStream extends InputStream StringBuffer buf = new StringBuffer(length); for (int i=0;i<length;i++) { if ((remaining() == 0) && (isContinueNext())) { - nextRecord(); + nextRecord(); int compressByte = readByte(); if(compressByte != 0) throw new IllegalArgumentException("compressByte in continue records must be 0 while reading compressed unicode"); } diff --git a/src/java/org/apache/poi/hssf/record/SharedFormulaRecord.java b/src/java/org/apache/poi/hssf/record/SharedFormulaRecord.java index b2fd9ae4f5..a7715474ac 100755 --- a/src/java/org/apache/poi/hssf/record/SharedFormulaRecord.java +++ b/src/java/org/apache/poi/hssf/record/SharedFormulaRecord.java @@ -180,19 +180,17 @@ public final class SharedFormulaRecord extends Record { return ((getFirstRow() <= formulaRow) && (getLastRow() >= formulaRow) && (getFirstColumn() <= formulaColumn) && (getLastColumn() >= formulaColumn)); } - - /** Creates a non shared formula from the shared formula counter part*/ - public void convertSharedFormulaRecord(FormulaRecord formula) { - //Sanity checks - final int formulaRow = formula.getRow(); - final int formulaColumn = formula.getColumn(); - if (isFormulaInShared(formula)) { - formula.setExpressionLength(getExpressionLength()); + + /** + * Creates a non shared formula from the shared formula + * counter part + */ + protected static Stack convertSharedFormulas(Stack ptgs, int formulaRow, int formulaColumn) { Stack newPtgStack = new Stack(); - if (field_7_parsed_expr != null) - for (int k = 0; k < field_7_parsed_expr.size(); k++) { - Ptg ptg = (Ptg) field_7_parsed_expr.get(k); + if (ptgs != null) + for (int k = 0; k < ptgs.size(); k++) { + Ptg ptg = (Ptg) ptgs.get(k); if (ptg instanceof RefNPtg) { RefNPtg refNPtg = (RefNPtg)ptg; ptg = new ReferencePtg(fixupRelativeRow(formulaRow,refNPtg.getRow(),refNPtg.isRowRelative()), @@ -243,7 +241,23 @@ public final class SharedFormulaRecord extends Record { areaNAPtg.isLastColRelative()); } newPtgStack.add(ptg); - } + } + return newPtgStack; + } + + /** + * Creates a non shared formula from the shared formula + * counter part + */ + public void convertSharedFormulaRecord(FormulaRecord formula) { + //Sanity checks + final int formulaRow = formula.getRow(); + final int formulaColumn = formula.getColumn(); + if (isFormulaInShared(formula)) { + formula.setExpressionLength(getExpressionLength()); + + Stack newPtgStack = + convertSharedFormulas(field_7_parsed_expr, formulaRow, formulaColumn); formula.setParsedExpression(newPtgStack); //Now its not shared! formula.setSharedFormula(false); @@ -252,7 +266,7 @@ public final class SharedFormulaRecord extends Record { } } - private int fixupRelativeColumn(int currentcolumn, int column, boolean relative) { + private static int fixupRelativeColumn(int currentcolumn, int column, boolean relative) { if(relative) { // mask out upper bits to produce 'wrapping' at column 256 ("IV") return (column + currentcolumn) & 0x00FF; @@ -260,7 +274,7 @@ public final class SharedFormulaRecord extends Record { return column; } - private int fixupRelativeRow(int currentrow, int row, boolean relative) { + private static int fixupRelativeRow(int currentrow, int row, boolean relative) { if(relative) { // mask out upper bits to produce 'wrapping' at row 65536 return (row+currentrow) & 0x00FFFF; diff --git a/src/java/org/apache/poi/hssf/record/aggregates/CFRecordsAggregate.java b/src/java/org/apache/poi/hssf/record/aggregates/CFRecordsAggregate.java new file mode 100644 index 0000000000..78d1ecbd33 --- /dev/null +++ b/src/java/org/apache/poi/hssf/record/aggregates/CFRecordsAggregate.java @@ -0,0 +1,224 @@ +/* ==================================================================== + Licensed to the Apache Software Foundation (ASF) under one or more + contributor license agreements. See the NOTICE file distributed with + this work for additional information regarding copyright ownership. + The ASF licenses this file to You under the Apache License, Version 2.0 + (the "License"); you may not use this file except in compliance with + the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +==================================================================== */ +package org.apache.poi.hssf.record.aggregates; + +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; + +import org.apache.poi.hssf.record.CFHeaderRecord; +import org.apache.poi.hssf.record.CFRuleRecord; +import org.apache.poi.hssf.record.Record; +import org.apache.poi.hssf.record.RecordInputStream; +import org.apache.poi.util.POILogFactory; +import org.apache.poi.util.POILogger; + +/** + * CFRecordsAggregate - aggregates Conditional Formatting records CFHeaderRecord + * and number of up to three CFRuleRecord records together to simplify + * access to them. + * + * @author Dmitriy Kumshayev + * + */ +public class CFRecordsAggregate extends Record +{ + public final static short sid = -2008; + + private static POILogger log = POILogFactory.getLogger(CFRecordsAggregate.class); + + private CFHeaderRecord header; + + // List of CFRuleRecord objects + private List rules; + + public CFRecordsAggregate() + { + header = null; + rules = new ArrayList(3); + } + + /** + * Create CFRecordsAggregate from a list of CF Records + * @param recs - list of {@link Record} objects + * @param offset - position of {@link CFHeaderRecord} object in the list of Record objects + * @return CFRecordsAggregate object + */ + public static CFRecordsAggregate createCFAggregate(List recs, int offset) + { + CFRecordsAggregate cfRecords = new CFRecordsAggregate(); + ArrayList records = new ArrayList(4); + + int count = 0; + Record rec = ( Record ) recs.get(offset++); + + if (rec.getSid() == CFHeaderRecord.sid) + { + records.add(rec); + cfRecords.header = (CFHeaderRecord)rec; + + int nRules = cfRecords.header.getNumberOfConditionalFormats(); + int rulesCount = 0; + while( offset<recs.size() && + (rec = (Record)recs.get(offset++)).getSid() == CFRuleRecord.sid && + rec instanceof CFRuleRecord && + rulesCount++ < nRules + ) + { + records.add(rec); + cfRecords.rules.add(rec); + } + + if (nRules != cfRecords.rules.size()) + { + if (log.check(POILogger.DEBUG)) + { + log.log(POILogger.DEBUG, "Expected " + nRules + " Conditional Formats, " + + "but found " + cfRecords.rules.size() + " rules"); + } + cfRecords.header.setNumberOfConditionalFormats(nRules); + } + + } + return cfRecords; + } + + /** + * Create a deep clone of the record + * @return + */ + public CFRecordsAggregate cloneCFAggregate() + { + + ArrayList records = new ArrayList(this.rules.size()+1); + + records.add(this.header.clone()); + + for (int i=0; i<this.rules.size();i++) + { + Record rec = (Record)((Record)this.rules.get(i)).clone(); + records.add(rec); + } + return createCFAggregate(records, 0); + } + + /** You never fill an aggregate */ + protected void fillFields(RecordInputStream in) + { + } + + public short getSid() + { + return sid; + } + + /** + * called by the class that is responsible for writing this sucker. + * Subclasses should implement this so that their data is passed back in a + * byte array. + * + * @param offset to begin writing at + * @param data byte array containing instance data + * @return number of bytes written + */ + + public int serialize(int offset, byte[] data) + { + int pos = offset; + if( header != null && rules.size()>0 ) + { + header.setNumberOfConditionalFormats(rules.size()); + + pos += (( Record ) header).serialize(pos, data); + + for(Iterator itr = rules.iterator(); itr.hasNext();) + { + pos += (( Record ) itr.next()).serialize(pos, data); + } + } + return pos - offset; + } + + protected void validateSid(short id) + { + // do nothing here + } + + /** + * @return the header + */ + public CFHeaderRecord getHeader() + { + return header; + } + + /** + * @return the rules + */ + public List getRules() + { + return rules; + } + + /** + * @return sum of sizes of all aggregated records + */ + public int getRecordSize() + { + int size = 0; + if( header != null) + { + size += header.getRecordSize(); + } + if( rules != null) + { + for(Iterator irecs = rules.iterator(); irecs.hasNext(); ) + { + size += (( Record ) irecs.next()).getRecordSize(); + } + } + return size; + } + + /** + * String representation of CFRecordsAggregate + */ + public String toString() + { + StringBuffer buffer = new StringBuffer(); + + buffer.append("[CF]\n"); + if( header != null ) + { + buffer.append(header.toString()); + } + if( rules != null ) + { + for(int i=0; i<rules.size(); i++) + { + CFRuleRecord cfRule = (CFRuleRecord)rules.get(i); + if(cfRule!=null) + { + buffer.append(cfRule.toString()); + } + } + } + buffer.append("[/CF]\n"); + return buffer.toString(); + } + +} diff --git a/src/java/org/apache/poi/hssf/record/cf/BorderFormatting.java b/src/java/org/apache/poi/hssf/record/cf/BorderFormatting.java new file mode 100644 index 0000000000..4343760ddd --- /dev/null +++ b/src/java/org/apache/poi/hssf/record/cf/BorderFormatting.java @@ -0,0 +1,560 @@ + +/* ==================================================================== + 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. +==================================================================== */ + + +/* + * FontFormatting.java + * + * Created on January 22, 2008, 10:05 PM + */ +package org.apache.poi.hssf.record.cf; + +import org.apache.poi.hssf.record.RecordInputStream; +import org.apache.poi.util.BitField; +import org.apache.poi.util.BitFieldFactory; +import org.apache.poi.util.LittleEndian; + +/** + * Border Formatting Block of the Conditional Formatting Rule Record. + * + * @author Dmitriy Kumshayev + */ + +public class BorderFormatting +{ + + /** + * No border + */ + + public final static short BORDER_NONE = 0x0; + + /** + * Thin border + */ + + public final static short BORDER_THIN = 0x1; + + /** + * Medium border + */ + + public final static short BORDER_MEDIUM = 0x2; + + /** + * dash border + */ + + public final static short BORDER_DASHED = 0x3; + + /** + * dot border + */ + + public final static short BORDER_HAIR = 0x4; + + /** + * Thick border + */ + + public final static short BORDER_THICK = 0x5; + + /** + * double-line border + */ + + public final static short BORDER_DOUBLE = 0x6; + + /** + * hair-line border + */ + + public final static short BORDER_DOTTED = 0x7; + + /** + * Medium dashed border + */ + + public final static short BORDER_MEDIUM_DASHED = 0x8; + + /** + * dash-dot border + */ + + public final static short BORDER_DASH_DOT = 0x9; + + /** + * medium dash-dot border + */ + + public final static short BORDER_MEDIUM_DASH_DOT = 0xA; + + /** + * dash-dot-dot border + */ + + public final static short BORDER_DASH_DOT_DOT = 0xB; + + /** + * medium dash-dot-dot border + */ + + public final static short BORDER_MEDIUM_DASH_DOT_DOT = 0xC; + + /** + * slanted dash-dot border + */ + + public final static short BORDER_SLANTED_DASH_DOT = 0xD; + + public BorderFormatting() + { + field_13_border_styles1 = (short)0; + field_14_border_styles2 = (short)0; + } + + /** Creates new FontFormatting */ + public BorderFormatting(RecordInputStream in) + { + field_13_border_styles1 = in.readInt(); + field_14_border_styles2 = in.readInt(); + } + + // BORDER FORMATTING BLOCK + // For Border Line Style codes see HSSFCellStyle.BORDER_XXXXXX + private int field_13_border_styles1; + private static final BitField bordLeftLineStyle = BitFieldFactory.getInstance(0x0000000F); + private static final BitField bordRightLineStyle = BitFieldFactory.getInstance(0x000000F0); + private static final BitField bordTopLineStyle = BitFieldFactory.getInstance(0x00000F00); + private static final BitField bordBottomLineStyle= BitFieldFactory.getInstance(0x0000F000); + private static final BitField bordLeftLineColor = BitFieldFactory.getInstance(0x007F0000); + private static final BitField bordRightLineColor = BitFieldFactory.getInstance(0x3F800000); + private static final BitField bordTlBrLineOnOff = BitFieldFactory.getInstance(0x40000000); + private static final BitField bordBlTrtLineOnOff = BitFieldFactory.getInstance(0x80000000); + + private int field_14_border_styles2; + private static final BitField bordTopLineColor = BitFieldFactory.getInstance(0x0000007F); + private static final BitField bordBottomLineColor= BitFieldFactory.getInstance(0x00003f80); + private static final BitField bordDiagLineColor = BitFieldFactory.getInstance(0x001FC000); + private static final BitField bordDiagLineStyle = BitFieldFactory.getInstance(0x01E00000); + + /** + * set the type of border to use for the left border of the cell + * @param border type + * @see #BORDER_NONE + * @see #BORDER_THIN + * @see #BORDER_MEDIUM + * @see #BORDER_DASHED + * @see #BORDER_DOTTED + * @see #BORDER_THICK + * @see #BORDER_DOUBLE + * @see #BORDER_HAIR + * @see #BORDER_MEDIUM_DASHED + * @see #BORDER_DASH_DOT + * @see #BORDER_MEDIUM_DASH_DOT + * @see #BORDER_DASH_DOT_DOT + * @see #BORDER_MEDIUM_DASH_DOT_DOT + * @see #BORDER_SLANTED_DASH_DOT + */ + + public void setBorderLeft(short border) + { + field_13_border_styles1 = bordLeftLineStyle.setValue(field_13_border_styles1, border); + } + + /** + * get the type of border to use for the left border of the cell + * @return border type + * @see #BORDER_NONE + * @see #BORDER_THIN + * @see #BORDER_MEDIUM + * @see #BORDER_DASHED + * @see #BORDER_DOTTED + * @see #BORDER_THICK + * @see #BORDER_DOUBLE + * @see #BORDER_HAIR + * @see #BORDER_MEDIUM_DASHED + * @see #BORDER_DASH_DOT + * @see #BORDER_MEDIUM_DASH_DOT + * @see #BORDER_DASH_DOT_DOT + * @see #BORDER_MEDIUM_DASH_DOT_DOT + * @see #BORDER_SLANTED_DASH_DOT + */ + + public short getBorderLeft() + { + return (short)bordLeftLineStyle.getValue(field_13_border_styles1); + } + + /** + * set the type of border to use for the right border of the cell + * @param border type + * @see #BORDER_NONE + * @see #BORDER_THIN + * @see #BORDER_MEDIUM + * @see #BORDER_DASHED + * @see #BORDER_DOTTED + * @see #BORDER_THICK + * @see #BORDER_DOUBLE + * @see #BORDER_HAIR + * @see #BORDER_MEDIUM_DASHED + * @see #BORDER_DASH_DOT + * @see #BORDER_MEDIUM_DASH_DOT + * @see #BORDER_DASH_DOT_DOT + * @see #BORDER_MEDIUM_DASH_DOT_DOT + * @see #BORDER_SLANTED_DASH_DOT + */ + + public void setBorderRight(short border) + { + field_13_border_styles1 = bordRightLineStyle.setValue(field_13_border_styles1, border); + } + + /** + * get the type of border to use for the right border of the cell + * @return border type + * @see #BORDER_NONE + * @see #BORDER_THIN + * @see #BORDER_MEDIUM + * @see #BORDER_DASHED + * @see #BORDER_DOTTED + * @see #BORDER_THICK + * @see #BORDER_DOUBLE + * @see #BORDER_HAIR + * @see #BORDER_MEDIUM_DASHED + * @see #BORDER_DASH_DOT + * @see #BORDER_MEDIUM_DASH_DOT + * @see #BORDER_DASH_DOT_DOT + * @see #BORDER_MEDIUM_DASH_DOT_DOT + * @see #BORDER_SLANTED_DASH_DOT + */ + + public short getBorderRight() + { + return (short)bordRightLineStyle.getValue(field_13_border_styles1); + } + + /** + * set the type of border to use for the top border of the cell + * @param border type + * @see #BORDER_NONE + * @see #BORDER_THIN + * @see #BORDER_MEDIUM + * @see #BORDER_DASHED + * @see #BORDER_DOTTED + * @see #BORDER_THICK + * @see #BORDER_DOUBLE + * @see #BORDER_HAIR + * @see #BORDER_MEDIUM_DASHED + * @see #BORDER_DASH_DOT + * @see #BORDER_MEDIUM_DASH_DOT + * @see #BORDER_DASH_DOT_DOT + * @see #BORDER_MEDIUM_DASH_DOT_DOT + * @see #BORDER_SLANTED_DASH_DOT + */ + + public void setBorderTop(short border) + { + field_13_border_styles1 = bordTopLineStyle.setValue(field_13_border_styles1, border); + } + + /** + * get the type of border to use for the top border of the cell + * @return border type + * @see #BORDER_NONE + * @see #BORDER_THIN + * @see #BORDER_MEDIUM + * @see #BORDER_DASHED + * @see #BORDER_DOTTED + * @see #BORDER_THICK + * @see #BORDER_DOUBLE + * @see #BORDER_HAIR + * @see #BORDER_MEDIUM_DASHED + * @see #BORDER_DASH_DOT + * @see #BORDER_MEDIUM_DASH_DOT + * @see #BORDER_DASH_DOT_DOT + * @see #BORDER_MEDIUM_DASH_DOT_DOT + * @see #BORDER_SLANTED_DASH_DOT + */ + + public short getBorderTop() + { + return (short)bordTopLineStyle.getValue(field_13_border_styles1); + } + + /** + * set the type of border to use for the bottom border of the cell + * @param border type + * @see #BORDER_NONE + * @see #BORDER_THIN + * @see #BORDER_MEDIUM + * @see #BORDER_DASHED + * @see #BORDER_DOTTED + * @see #BORDER_THICK + * @see #BORDER_DOUBLE + * @see #BORDER_HAIR + * @see #BORDER_MEDIUM_DASHED + * @see #BORDER_DASH_DOT + * @see #BORDER_MEDIUM_DASH_DOT + * @see #BORDER_DASH_DOT_DOT + * @see #BORDER_MEDIUM_DASH_DOT_DOT + * @see #BORDER_SLANTED_DASH_DOT + */ + + public void setBorderBottom(short border) + { + field_13_border_styles1 = bordBottomLineStyle.setValue(field_13_border_styles1, border); + } + + /** + * get the type of border to use for the bottom border of the cell + * @return border type + * @see #BORDER_NONE + * @see #BORDER_THIN + * @see #BORDER_MEDIUM + * @see #BORDER_DASHED + * @see #BORDER_DOTTED + * @see #BORDER_THICK + * @see #BORDER_DOUBLE + * @see #BORDER_HAIR + * @see #BORDER_MEDIUM_DASHED + * @see #BORDER_DASH_DOT + * @see #BORDER_MEDIUM_DASH_DOT + * @see #BORDER_DASH_DOT_DOT + * @see #BORDER_MEDIUM_DASH_DOT_DOT + * @see #BORDER_SLANTED_DASH_DOT + */ + public short getBorderBottom() + { + return (short)bordBottomLineStyle.getValue(field_13_border_styles1); + } + + /** + * set the type of border to use for the diagonal border of the cell + * @param border type + * @see #BORDER_NONE + * @see #BORDER_THIN + * @see #BORDER_MEDIUM + * @see #BORDER_DASHED + * @see #BORDER_DOTTED + * @see #BORDER_THICK + * @see #BORDER_DOUBLE + * @see #BORDER_HAIR + * @see #BORDER_MEDIUM_DASHED + * @see #BORDER_DASH_DOT + * @see #BORDER_MEDIUM_DASH_DOT + * @see #BORDER_DASH_DOT_DOT + * @see #BORDER_MEDIUM_DASH_DOT_DOT + * @see #BORDER_SLANTED_DASH_DOT + */ + + public void setBorderDiagonal(short border) + { + field_14_border_styles2 = bordDiagLineStyle.setValue(field_14_border_styles2, border); + } + + /** + * get the type of border to use for the diagonal border of the cell + * @return border type + * @see #BORDER_NONE + * @see #BORDER_THIN + * @see #BORDER_MEDIUM + * @see #BORDER_DASHED + * @see #BORDER_DOTTED + * @see #BORDER_THICK + * @see #BORDER_DOUBLE + * @see #BORDER_HAIR + * @see #BORDER_MEDIUM_DASHED + * @see #BORDER_DASH_DOT + * @see #BORDER_MEDIUM_DASH_DOT + * @see #BORDER_DASH_DOT_DOT + * @see #BORDER_MEDIUM_DASH_DOT_DOT + * @see #BORDER_SLANTED_DASH_DOT + */ + public short getBorderDiagonal() + { + return (short)bordDiagLineStyle.getValue(field_14_border_styles2); + } + + /** + * set the color to use for the left border + * @param color The index of the color definition + */ + public void setLeftBorderColor(short color) + { + field_13_border_styles1 = bordLeftLineColor.setValue(field_13_border_styles1, color); + } + + /** + * get the color to use for the left border + * @see org.apache.poi.hssf.usermodel.HSSFPalette#getColor(short) + * @param color The index of the color definition + */ + public short getLeftBorderColor() + { + return (short)bordLeftLineColor.getValue(field_13_border_styles1); + } + + /** + * set the color to use for the right border + * @param color The index of the color definition + */ + public void setRightBorderColor(short color) + { + field_13_border_styles1 = bordRightLineColor.setValue(field_13_border_styles1, color); + } + + /** + * get the color to use for the right border + * @see org.apache.poi.hssf.usermodel.HSSFPalette#getColor(short) + * @param color The index of the color definition + */ + public short getRightBorderColor() + { + return (short)bordRightLineColor.getValue(field_13_border_styles1); + } + + /** + * set the color to use for the top border + * @param color The index of the color definition + */ + public void setTopBorderColor(short color) + { + field_14_border_styles2 = bordTopLineColor.setValue(field_14_border_styles2, color); + } + + /** + * get the color to use for the top border + * @see org.apache.poi.hssf.usermodel.HSSFPalette#getColor(short) + * @param color The index of the color definition + */ + public short getTopBorderColor() + { + return (short)bordTopLineColor.getValue(field_14_border_styles2); + } + + /** + * set the color to use for the bottom border + * @param color The index of the color definition + */ + public void setBottomBorderColor(short color) + { + field_14_border_styles2 = bordBottomLineColor.setValue(field_14_border_styles2, color); + } + + /** + * get the color to use for the bottom border + * @see org.apache.poi.hssf.usermodel.HSSFPalette#getColor(short) + * @param color The index of the color definition + */ + public short getBottomBorderColor() + { + return (short)bordBottomLineColor.getValue(field_14_border_styles2); + } + + /** + * set the color to use for the diagonal borders + * @param color The index of the color definition + */ + public void setDiagonalBorderColor(short color) + { + field_14_border_styles2 = bordDiagLineColor.setValue(field_14_border_styles2, color); + } + + /** + * get the color to use for the diagonal border + * @see org.apache.poi.hssf.usermodel.HSSFPalette#getColor(short) + * @param color The index of the color definition + */ + public short getDiagonalBorderColor() + { + return (short)bordDiagLineColor.getValue(field_14_border_styles2); + } + + /** + * Of/off bottom left to top right line + * + * @param on - if true - on, otherwise off + */ + public void setForwardDiagonalOn(boolean on) + { + field_13_border_styles1 = bordBlTrtLineOnOff.setBoolean(field_13_border_styles1, on); + } + + /** + * Of/off top left to bottom right line + * + * @param on - if true - on, otherwise off + */ + public void setBackwardDiagonalOn(boolean on) + { + field_13_border_styles1 = bordTlBrLineOnOff.setBoolean(field_13_border_styles1, on); + } + + /** + * @return true if forward diagonal is on + */ + public boolean isForwardDiagonalOn() + { + return bordBlTrtLineOnOff.isSet(field_13_border_styles1); + } + + /** + * @return true if backward diagonal is on + */ + public boolean isBackwardDiagonalOn() + { + return bordTlBrLineOnOff.isSet(field_13_border_styles1); + } + + + public String toString() + { + StringBuffer buffer = new StringBuffer(); + buffer.append(" [Border Formatting]\n"); + buffer.append(" .lftln = ").append(Integer.toHexString(getBorderLeft())).append("\n"); + buffer.append(" .rgtln = ").append(Integer.toHexString(getBorderRight())).append("\n"); + buffer.append(" .topln = ").append(Integer.toHexString(getBorderTop())).append("\n"); + buffer.append(" .btmln = ").append(Integer.toHexString(getBorderBottom())).append("\n"); + buffer.append(" .leftborder= ").append(Integer.toHexString(getLeftBorderColor())).append("\n"); + buffer.append(" .rghtborder= ").append(Integer.toHexString(getRightBorderColor())).append("\n"); + buffer.append(" .topborder= ").append(Integer.toHexString(getTopBorderColor())).append("\n"); + buffer.append(" .bottomborder= ").append(Integer.toHexString(getBottomBorderColor())).append("\n"); + buffer.append(" .fwdiag= ").append(isForwardDiagonalOn()).append("\n"); + buffer.append(" .bwdiag= ").append(isBackwardDiagonalOn()).append("\n"); + buffer.append(" [/Border Formatting]\n"); + return buffer.toString(); + } + + public Object clone() + { + BorderFormatting rec = new BorderFormatting(); + rec.field_13_border_styles1 = field_13_border_styles1; + rec.field_14_border_styles2 = field_14_border_styles2; + return rec; + } + + public int serialize(int offset, byte [] data) + { + LittleEndian.putInt(data, offset, field_13_border_styles1); + offset += 4; + LittleEndian.putInt(data, offset, field_14_border_styles2); + offset += 4; + return 8; + } +} diff --git a/src/java/org/apache/poi/hssf/record/cf/CellRange.java b/src/java/org/apache/poi/hssf/record/cf/CellRange.java new file mode 100644 index 0000000000..88ec15b4a7 --- /dev/null +++ b/src/java/org/apache/poi/hssf/record/cf/CellRange.java @@ -0,0 +1,259 @@ +/* ==================================================================== + Licensed to the Apache Software Foundation (ASF) under one or more + contributor license agreements. See the NOTICE file distributed with + this work for additional information regarding copyright ownership. + The ASF licenses this file to You under the Apache License, Version 2.0 + (the "License"); you may not use this file except in compliance with + the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +==================================================================== */ + +package org.apache.poi.hssf.record.cf; + +/** + * CellRange.java + * Created on January 22, 2008, 10:05 PM + * + * @author Dmitriy Kumshayev + */ + +public class CellRange +{ + private int field_1_first_row; + private int field_2_last_row; + private short field_3_first_column; + private short field_4_last_column; + + public CellRange(int firstRow, int lastRow, short firstColumn, short lastColumn) + { + this.field_1_first_row = firstRow; + this.field_2_last_row = lastRow; + this.field_3_first_column = firstColumn; + this.field_4_last_column = lastColumn; + validateRegion(); + } + + private void validateRegion() + { + if( field_1_first_row < 0 || + field_2_last_row < -1 || + field_3_first_column < 0 || + field_4_last_column < -1 || + field_2_last_row>=0 && field_2_last_row<field_1_first_row || + field_4_last_column>=0 && field_4_last_column<field_3_first_column + ) + { + throw new IllegalArgumentException("Invalid cell region "+toString()); + } + } + + public int getFirstRow() + { + return field_1_first_row; + } + private void setFirstRow(int firstRow) + { + this.field_1_first_row = firstRow; + } + public int getLastRow() + { + return field_2_last_row; + } + private void setLastRow(int lastRow) + { + this.field_2_last_row = lastRow; + } + public short getFirstColumn() + { + return field_3_first_column; + } + private void setFirstColumn(short firstColumn) + { + this.field_3_first_column = firstColumn; + } + public short getLastColumn() + { + return field_4_last_column; + } + private void setLastColumn(short lastColumn) + { + this.field_4_last_column = lastColumn; + } + + public static final int NO_INTERSECTION = 1; + public static final int OVERLAP = 2; + public static final int INSIDE = 3; + public static final int ENCLOSES = 4; + + /** + * Intersect this range with the specified range. + * + * @param another - the specified range + * @return code which reflects how the specified range is related to this range.<br/> + * Possible return codes are: + * NO_INTERSECTION - the specified range is outside of this range;<br/> + * OVERLAP - both ranges partially overlap;<br/> + * INSIDE - the specified range is inside of this one<br/> + * ENCLOSES - the specified range encloses this range<br/> + */ + public int intersect(CellRange another ) + { + int firstRow = another.getFirstRow(); + int lastRow = another.getLastRow(); + short firstCol = another.getFirstColumn(); + short lastCol = another.getLastColumn(); + + if + ( + gt(this.getFirstRow(),lastRow) || + lt(this.getLastRow(),firstRow) || + gt(this.getFirstColumn(),lastCol) || + lt(this.getLastColumn(),firstCol) + ) + { + return NO_INTERSECTION; + } + else if( this.contains(another) ) + { + return INSIDE; + } + else if( another.contains(this) ) + { + return ENCLOSES; + } + else + { + return OVERLAP; + } + + } + + /** + * Check if the specified range is located inside of this cell range. + * + * @param range + * @return true if this cell range contains the argument range inside if it's area + */ + public boolean contains(CellRange range) + { + int firstRow = range.getFirstRow(); + int lastRow = range.getLastRow(); + short firstCol = range.getFirstColumn(); + short lastCol = range.getLastColumn(); + return le(this.getFirstRow(), firstRow) && ge(this.getLastRow(), lastRow) + && le(this.getFirstColumn(), firstCol) && ge(this.getLastColumn(), lastCol); + } + + public boolean contains(int row, short column) + { + return le(this.getFirstRow(), row) && ge(this.getLastRow(), row) + && le(this.getFirstColumn(), column) && ge(this.getLastColumn(), column); + } + + /** + * Check if the specified cell range has a shared border with the current range. + * + * @return true if the ranges have a shared border. + */ + public boolean hasSharedBorder(CellRange range) + { + int firstRow = range.getFirstRow(); + int lastRow = range.getLastRow(); + short firstCol = range.getFirstColumn(); + short lastCol = range.getLastColumn(); + return + (this.getFirstRow()>0 && this.getFirstRow() - 1 == lastRow || firstRow>0 &&this.getLastRow() == firstRow -1)&& + (this.getFirstColumn() == firstCol) && + (this.getLastColumn() == lastCol) || + (this.getFirstColumn()>0 && this.getFirstColumn() - 1 == lastCol || firstCol>0 && this.getLastColumn() == firstCol -1) && + (this.getFirstRow() == firstRow) && + (this.getLastRow() == lastRow) + ; + } + + /** + * Create an enclosing CellRange for the two cell ranges. + * + * @return enclosing CellRange + */ + public CellRange createEnclosingCellRange(CellRange range) + { + if( range == null) + { + return cloneCellRange(); + } + else + { + CellRange cellRange = + new CellRange( + lt(range.getFirstRow(),getFirstRow())?range.getFirstRow():getFirstRow(), + gt(range.getLastRow(),getLastRow())?range.getLastRow():getLastRow(), + lt(range.getFirstColumn(),getFirstColumn())?range.getFirstColumn():getFirstColumn(), + gt(range.getLastColumn(),getLastColumn())?range.getLastColumn():getLastColumn() + ); + return cellRange; + } + } + + public CellRange cloneCellRange() + { + return new CellRange(getFirstRow(),getLastRow(),getFirstColumn(),getLastColumn()); + } + + /** + * Copy data from antother cell range to this cell range + * @param cr - another cell range + */ + public void setCellRange(CellRange cr) + { + setFirstRow(cr.getFirstRow()); + setLastRow(cr.getLastRow()); + setFirstColumn(cr.getFirstColumn()); + setLastColumn(cr.getLastColumn()); + } + + /** + * @return true if a < b + */ + private static boolean lt(int a, int b) + { + return a == -1 ? false : (b == -1 ? true : a < b); + } + + /** + * @return true if a <= b + */ + private static boolean le(int a, int b) + { + return a == b || lt(a,b); + } + + /** + * @return true if a > b + */ + private static boolean gt(int a, int b) + { + return lt(b,a); + } + + /** + * @return true if a >= b + */ + private static boolean ge(int a, int b) + { + return !lt(a,b); + } + + public String toString() + { + return "("+this.getFirstRow()+","+this.getLastRow()+","+this.getFirstColumn()+","+this.getLastColumn()+")"; + } + +} diff --git a/src/java/org/apache/poi/hssf/record/cf/FontFormatting.java b/src/java/org/apache/poi/hssf/record/cf/FontFormatting.java new file mode 100644 index 0000000000..1e6abee7c9 --- /dev/null +++ b/src/java/org/apache/poi/hssf/record/cf/FontFormatting.java @@ -0,0 +1,591 @@ + +/* ==================================================================== + Licensed to the Apache Software Foundation (ASF) under one or more + contributor license agreements. See the NOTICE file distributed with + this work for additional information regarding copyright ownership. + The ASF licenses this file to You under the Apache License, Version 2.0 + (the "License"); you may not use this file except in compliance with + the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +==================================================================== */ + +package org.apache.poi.hssf.record.cf; + +import org.apache.poi.hssf.record.RecordInputStream; +import org.apache.poi.util.BitField; +import org.apache.poi.util.BitFieldFactory; +import org.apache.poi.util.LittleEndian; + +/** + * Font Formatting Block of the Conditional Formatting Rule Record. + * + * Created on January 22, 2008, 10:05 PM + * + * @author Dmitriy Kumshayev + */ + +public class FontFormatting +{ + private byte [] record; + + private static final int OFFSET_FONT_NAME = 0; + private static final int OFFSET_FONT_HEIGHT = 64; + private static final int OFFSET_FONT_OPTIONS = 68; + private static final int OFFSET_FONT_WEIGHT = 72; + private static final int OFFSET_ESCAPEMENT_TYPE = 74; + private static final int OFFSET_UNDERLINE_TYPE = 76; + private static final int OFFSET_FONT_COLOR_INDEX = 80; + private static final int OFFSET_OPTION_FLAGS = 88; + private static final int OFFSET_ESCAPEMENT_TYPE_MODIFIED = 92; + private static final int OFFSET_UNDERLINE_TYPE_MODIFIED = 96; + private static final int OFFSET_NOT_USED1 = 100; + private static final int OFFSET_NOT_USED2 = 104; + private static final int OFFSET_FONT_FORMATING_END = 116; + + + public final static int FONT_CELL_HEIGHT_PRESERVED = 0xFFFFFFFF; + + // FONT OPTIONS MASKS + private static final BitField posture = BitFieldFactory.getInstance(0x00000002); + private static final BitField outline = BitFieldFactory.getInstance(0x00000008); + private static final BitField shadow = BitFieldFactory.getInstance(0x00000010); + private static final BitField condense = BitFieldFactory.getInstance(0x00000020); + private static final BitField cancellation = BitFieldFactory.getInstance(0x00000080); + + // OPTION FLAGS MASKS + + private static final BitField styleModified = BitFieldFactory.getInstance(0x00000002); + private static final BitField outlineModified = BitFieldFactory.getInstance(0x00000008); + private static final BitField shadowModified = BitFieldFactory.getInstance(0x00000010); + private static final BitField condenseModified = BitFieldFactory.getInstance(0x00000020); + private static final BitField cancellationModified = BitFieldFactory.getInstance(0x00000080); + + /** + * Escapement type - None + */ + public final static short SS_NONE = 0; + + /** + * Escapement type - Superscript + */ + public final static short SS_SUPER = 1; + + /** + * Escapement type - Subscript + */ + public final static short SS_SUB = 2; + + /** + * Underline type - None + */ + public final static byte U_NONE = 0; + + /** + * Underline type - Single + */ + public final static byte U_SINGLE = 1; + + /** + * Underline type - Double + */ + public final static byte U_DOUBLE = 2; + + /** + * Underline type - Single Accounting + */ + public final static byte U_SINGLE_ACCOUNTING = 0x21; + + /** + * Underline type - Double Accounting + */ + public final static byte U_DOUBLE_ACCOUNTING = 0x22; + + /** + * Normal boldness (not bold) + */ + + protected final static short FONT_WEIGHT_NORMAL = 0x190; + + /** + * Bold boldness (bold) + */ + + protected final static short FONT_WEIGHT_BOLD = 0x2bc; + + public FontFormatting() + { + this(new byte[118]); + + this.setFontHeight((short)-1); + this.setItalic(false); + this.setBold(false); + this.setOutline(false); + this.setShadow(false); + this.setCondense(false); + this.setStrikeout(false); + this.setEscapementType((short)0); + this.setUnderlineType((byte)0); + this.setFontColorIndex((short)-1); + + this.setFontStyleModified(false); + this.setFontOutlineModified(false); + this.setFontShadowModified(false); + this.setFontCondenseModified(false); + this.setFontCancellationModified(false); + + this.setEscapementTypeModified(false); + this.setUnderlineTypeModified(false); + + LittleEndian.putShort(record, OFFSET_FONT_NAME, (short)0); + LittleEndian.putInt(record, OFFSET_NOT_USED1, 0x00000001); + LittleEndian.putInt(record, OFFSET_NOT_USED2, 0x00000001); + LittleEndian.putShort(record, OFFSET_FONT_FORMATING_END, (short)0x0001); + } + + /** Creates new FontFormatting */ + private FontFormatting(byte[] record) + { + this.record = record; + } + + /** Creates new FontFormatting */ + public FontFormatting(RecordInputStream in) + { + record = new byte[118]; + for (int i = 0; i != record.length; i++) + { + record[i] = in.readByte(); + } + } + + public byte[] getRawRecord() + { + return record; + } + + /** + * sets the height of the font in 1/20th point units + * + * + * @param height fontheight (in points/20); or -1 to preserve the cell font height + */ + + public void setFontHeight(short height) + { + LittleEndian.putInt(record, OFFSET_FONT_HEIGHT, height); + } + + /** + * gets the height of the font in 1/20th point units + * + * @return fontheight (in points/20); or -1 if not modified + */ + public short getFontHeight() + { + return (short) LittleEndian.getInt(record, OFFSET_FONT_HEIGHT); + } + + private void setFontOption(boolean option, BitField field) + { + int options = LittleEndian.getInt(record,OFFSET_FONT_OPTIONS); + options = field.setBoolean(options, option); + LittleEndian.putInt(record,OFFSET_FONT_OPTIONS, options); + } + + private boolean getFontOption(BitField field) + { + int options = LittleEndian.getInt(record,OFFSET_FONT_OPTIONS); + return field.isSet(options); + } + + /** + * set the font to be italics or not + * + * @param italics - whether the font is italics or not + * @see #setAttributes(short) + */ + + public void setItalic(boolean italic) + { + setFontOption(italic, posture); + } + + /** + * get whether the font is to be italics or not + * + * @return italics - whether the font is italics or not + * @see #getAttributes() + */ + + public boolean isItalic() + { + return getFontOption(posture); + } + + public void setOutline(boolean on) + { + setFontOption(on, outline); + } + + public boolean isOutlineOn() + { + return getFontOption(outline); + } + + public void setShadow(boolean on) + { + setFontOption(on, shadow); + } + + public boolean isShadowOn() + { + return getFontOption(shadow); + } + + public void setCondense(boolean on) + { + setFontOption(on, condense); + } + + public boolean isCondenseOn() + { + return getFontOption(condense); + } + + /** + * set the font to be stricken out or not + * + * @param strike - whether the font is stricken out or not + */ + + public void setStrikeout(boolean strike) + { + setFontOption(strike, cancellation); + } + + /** + * get whether the font is to be stricken out or not + * + * @return strike - whether the font is stricken out or not + * @see #getAttributes() + */ + + public boolean isStruckout() + { + return getFontOption(cancellation); + } + + /** + * set the font weight (100-1000dec or 0x64-0x3e8). Default is + * 0x190 for normal and 0x2bc for bold + * + * @param bw - a number between 100-1000 for the fonts "boldness" + */ + + private void setFontWeight(short bw) + { + if( bw<100) { bw=100; } + if( bw>1000){ bw=1000; } + LittleEndian.putShort(record,OFFSET_FONT_WEIGHT, bw); + } + + /** + * set the font weight to bold (weight=700) or to normal(weight=400) boldness. + * + * @param bold - set font weight to bold if true; to normal otherwise + */ + public void setBold(boolean bold) + { + setFontWeight(bold?FONT_WEIGHT_BOLD:FONT_WEIGHT_NORMAL); + } + + /** + * get the font weight for this font (100-1000dec or 0x64-0x3e8). Default is + * 0x190 for normal and 0x2bc for bold + * + * @return bw - a number between 100-1000 for the fonts "boldness" + */ + + public short getFontWeight() + { + return LittleEndian.getShort(record,OFFSET_FONT_WEIGHT); + } + + /** + * get whether the font weight is set to bold or not + * + * @return bold - whether the font is bold or not + */ + + public boolean isBold() + { + return getFontWeight()==FONT_WEIGHT_BOLD; + } + + /** + * get the type of super or subscript for the font + * + * @return super or subscript option + * @see org.apache.poi.hssf.usermodel.HSSFFontFormatting#SS_NONE + * @see org.apache.poi.hssf.usermodel.HSSFFontFormatting#SS_SUPER + * @see org.apache.poi.hssf.usermodel.HSSFFontFormatting#SS_SUB + */ + public short getEscapementType() + { + return LittleEndian.getShort(record,OFFSET_ESCAPEMENT_TYPE); + } + + /** + * set the escapement type for the font + * + * @param escapementType super or subscript option + * @see org.apache.poi.hssf.usermodel.HSSFFontFormatting#SS_NONE + * @see org.apache.poi.hssf.usermodel.HSSFFontFormatting#SS_SUPER + * @see org.apache.poi.hssf.usermodel.HSSFFontFormatting#SS_SUB + */ + public void setEscapementType( short escapementType) + { + LittleEndian.putShort(record,OFFSET_ESCAPEMENT_TYPE, escapementType); + } + + /** + * get the type of underlining for the font + * + * @return font underlining type + * + * @see org.apache.poi.hssf.usermodel.HSSFFontFormatting#U_NONE + * @see org.apache.poi.hssf.usermodel.HSSFFontFormatting#U_SINGLE + * @see org.apache.poi.hssf.usermodel.HSSFFontFormatting#U_DOUBLE + * @see org.apache.poi.hssf.usermodel.HSSFFontFormatting#U_SINGLE_ACCOUNTING + * @see org.apache.poi.hssf.usermodel.HSSFFontFormatting#U_DOUBLE_ACCOUNTING + */ + + public short getUnderlineType() + { + return LittleEndian.getShort(record,OFFSET_UNDERLINE_TYPE); + } + + /** + * set the type of underlining type for the font + * + * @param u super or subscript option + * + * @see org.apache.poi.hssf.usermodel.HSSFFontFormatting#U_NONE + * @see org.apache.poi.hssf.usermodel.HSSFFontFormatting#U_SINGLE + * @see org.apache.poi.hssf.usermodel.HSSFFontFormatting#U_DOUBLE + * @see org.apache.poi.hssf.usermodel.HSSFFontFormatting#U_SINGLE_ACCOUNTING + * @see org.apache.poi.hssf.usermodel.HSSFFontFormatting#U_DOUBLE_ACCOUNTING + */ + public void setUnderlineType( short underlineType) + { + LittleEndian.putShort(record,OFFSET_UNDERLINE_TYPE, underlineType); + } + + + public short getFontColorIndex() + { + return (short)LittleEndian.getInt(record,OFFSET_FONT_COLOR_INDEX); + } + + public void setFontColorIndex(short fci ) + { + LittleEndian.putInt(record,OFFSET_FONT_COLOR_INDEX,fci); + } + + private boolean getOptionFlag(BitField field) + { + int optionFlags = LittleEndian.getInt(record,OFFSET_OPTION_FLAGS); + int value = field.getValue(optionFlags); + return value==0? true : false ; + } + + private void setOptionFlag(boolean modified, BitField field) + { + int value = modified? 0 : 1; + int optionFlags = LittleEndian.getInt(record,OFFSET_OPTION_FLAGS); + optionFlags = field.setValue(optionFlags, value); + LittleEndian.putInt(record,OFFSET_OPTION_FLAGS, optionFlags); + } + + + public boolean isFontStyleModified() + { + return getOptionFlag(styleModified); + } + + public void setFontStyleModified(boolean modified) + { + setOptionFlag(modified, styleModified); + } + + public boolean isFontOutlineModified() + { + return getOptionFlag(outlineModified); + } + + public void setFontOutlineModified(boolean modified) + { + setOptionFlag(modified, outlineModified); + } + + public boolean isFontShadowModified() + { + return getOptionFlag(shadowModified); + } + + public void setFontShadowModified(boolean modified) + { + setOptionFlag(modified, shadowModified); + } + public boolean isFontCondenseModified() + { + return getOptionFlag(condenseModified); + } + + public void setFontCondenseModified(boolean modified) + { + setOptionFlag(modified, condenseModified); + } + + public void setFontCancellationModified(boolean modified) + { + setOptionFlag(modified, cancellationModified); + } + + public boolean isFontCancellationModified() + { + return getOptionFlag(cancellationModified); + } + + public void setEscapementTypeModified(boolean modified) + { + int value = modified? 0 : 1; + LittleEndian.putInt(record,OFFSET_ESCAPEMENT_TYPE_MODIFIED, value); + } + + public boolean isEscapementTypeModified() + { + int escapementModified = LittleEndian.getInt(record,OFFSET_ESCAPEMENT_TYPE_MODIFIED); + return escapementModified == 0; + } + + public void setUnderlineTypeModified(boolean modified) + { + int value = modified? 0 : 1; + LittleEndian.putInt(record,OFFSET_UNDERLINE_TYPE_MODIFIED, value); + } + + public boolean isUnderlineTypeModified() + { + int underlineModified = LittleEndian.getInt(record,OFFSET_UNDERLINE_TYPE_MODIFIED); + return underlineModified == 0; + } + + public String toString() + { + StringBuffer buffer = new StringBuffer(); + buffer.append(" [Font Formatting]\n"); + + buffer.append(" .font height = ").append(getFontHeight()).append(" twips\n"); + + if( isFontStyleModified() ) + { + buffer.append(" .font posture = ").append(isItalic()?"Italic":"Normal").append("\n"); + } + else + { + buffer.append(" .font posture = ]not modified]").append("\n"); + } + + if( isFontOutlineModified() ) + { + buffer.append(" .font outline = ").append(isOutlineOn()).append("\n"); + } + else + { + buffer.append(" .font outline is not modified\n"); + } + + if( isFontShadowModified() ) + { + buffer.append(" .font shadow = ").append(isShadowOn()).append("\n"); + } + else + { + buffer.append(" .font shadow is not modified\n"); + } + if( isFontCondenseModified() ) + { + buffer.append(" .font condense = ").append(isCondenseOn()).append("\n"); + } + else + { + buffer.append(" .font condense is not modified\n"); + } + + if( isFontCancellationModified() ) + { + buffer.append(" .font strikeout = ").append(isStruckout()).append("\n"); + } + else + { + buffer.append(" .font strikeout is not modified\n"); + } + + if( isFontStyleModified() ) + { + buffer.append(" .font weight = "). + append(getFontWeight()). + append( + getFontWeight() == FONT_WEIGHT_NORMAL ? "(Normal)" + : getFontWeight() == FONT_WEIGHT_BOLD ? "(Bold)" : "0x"+Integer.toHexString(getFontWeight())). + append("\n"); + } + else + { + buffer.append(" .font weight = ]not modified]").append("\n"); + } + + if( isEscapementTypeModified() ) + { + buffer.append(" .escapement type = ").append(getEscapementType()).append("\n"); + } + else + { + buffer.append(" .escapement type is not modified\n"); + } + + if( isUnderlineTypeModified() ) + { + buffer.append(" .underline type = ").append(getUnderlineType()).append("\n"); + } + else + { + buffer.append(" .underline type is not modified\n"); + } + buffer.append(" .color index = ").append("0x"+Integer.toHexString(getFontColorIndex()).toUpperCase()).append("\n"); + + + buffer.append(" [/Font Formatting]\n"); + return buffer.toString(); + } + + public Object clone() + { + FontFormatting rec = new FontFormatting(); + if( record != null) + { + byte[] clone = new byte[record.length]; + System.arraycopy(record, 0, clone, 0, record.length); + rec.record = clone; + } + return rec; + } +} diff --git a/src/java/org/apache/poi/hssf/record/cf/PatternFormatting.java b/src/java/org/apache/poi/hssf/record/cf/PatternFormatting.java new file mode 100644 index 0000000000..3157bf46c8 --- /dev/null +++ b/src/java/org/apache/poi/hssf/record/cf/PatternFormatting.java @@ -0,0 +1,206 @@ + +/* ==================================================================== + 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. +==================================================================== */ + + +/* + * FontFormatting.java + * + * Created on January 22, 2008, 10:05 PM + */ +package org.apache.poi.hssf.record.cf; + +import org.apache.poi.hssf.record.RecordInputStream; +import org.apache.poi.util.BitField; +import org.apache.poi.util.BitFieldFactory; +import org.apache.poi.util.LittleEndian; + +/** + * Pattern Formatting Block of the Conditional Formatting Rule Record. + * + * @author Dmitriy Kumshayev + */ + +public class PatternFormatting implements Cloneable +{ + /** No background */ + public final static short NO_FILL = 0 ; + /** Solidly filled */ + public final static short SOLID_FOREGROUND = 1 ; + /** Small fine dots */ + public final static short FINE_DOTS = 2 ; + /** Wide dots */ + public final static short ALT_BARS = 3 ; + /** Sparse dots */ + public final static short SPARSE_DOTS = 4 ; + /** Thick horizontal bands */ + public final static short THICK_HORZ_BANDS = 5 ; + /** Thick vertical bands */ + public final static short THICK_VERT_BANDS = 6 ; + /** Thick backward facing diagonals */ + public final static short THICK_BACKWARD_DIAG = 7 ; + /** Thick forward facing diagonals */ + public final static short THICK_FORWARD_DIAG = 8 ; + /** Large spots */ + public final static short BIG_SPOTS = 9 ; + /** Brick-like layout */ + public final static short BRICKS = 10 ; + /** Thin horizontal bands */ + public final static short THIN_HORZ_BANDS = 11 ; + /** Thin vertical bands */ + public final static short THIN_VERT_BANDS = 12 ; + /** Thin backward diagonal */ + public final static short THIN_BACKWARD_DIAG = 13 ; + /** Thin forward diagonal */ + public final static short THIN_FORWARD_DIAG = 14 ; + /** Squares */ + public final static short SQUARES = 15 ; + /** Diamonds */ + public final static short DIAMONDS = 16 ; + /** Less Dots */ + public final static short LESS_DOTS = 17 ; + /** Least Dots */ + public final static short LEAST_DOTS = 18 ; + + public PatternFormatting() + { + field_15_pattern_style = (short)0; + field_16_pattern_color_indexes = (short)0; + } + + /** Creates new FontFormatting */ + public PatternFormatting(RecordInputStream in) + { + field_15_pattern_style = in.readShort(); + field_16_pattern_color_indexes = in.readShort(); + } + + // PATTERN FORMATING BLOCK + // For Pattern Styles see constants at HSSFCellStyle (from NO_FILL to LEAST_DOTS) + private short field_15_pattern_style; + private static final BitField fillPatternStyle = BitFieldFactory.getInstance(0xFC00); + + private short field_16_pattern_color_indexes; + private static final BitField patternColorIndex = BitFieldFactory.getInstance(0x007F); + private static final BitField patternBackgroundColorIndex = BitFieldFactory.getInstance(0x3F80); + + /** + * setting fill pattern + * + * @see #NO_FILL + * @see #SOLID_FOREGROUND + * @see #FINE_DOTS + * @see #ALT_BARS + * @see #SPARSE_DOTS + * @see #THICK_HORZ_BANDS + * @see #THICK_VERT_BANDS + * @see #THICK_BACKWARD_DIAG + * @see #THICK_FORWARD_DIAG + * @see #BIG_SPOTS + * @see #BRICKS + * @see #THIN_HORZ_BANDS + * @see #THIN_VERT_BANDS + * @see #THIN_BACKWARD_DIAG + * @see #THIN_FORWARD_DIAG + * @see #SQUARES + * @see #DIAMONDS + * + * @param fp fill pattern + */ + public void setFillPattern(short fp) + { + field_15_pattern_style = fillPatternStyle.setShortValue(field_15_pattern_style, fp); + } + + /** + * get the fill pattern + * @return fill pattern + */ + + public short getFillPattern() + { + return fillPatternStyle.getShortValue(field_15_pattern_style); + } + + /** + * set the background fill color. + * + * @param bg color + */ + + public void setFillBackgroundColor(short bg) + { + field_16_pattern_color_indexes = patternBackgroundColorIndex.setShortValue(field_16_pattern_color_indexes,bg); + } + + /** + * get the background fill color + * @see org.apache.poi.hssf.usermodel.HSSFPalette#getColor(short) + * @return fill color + */ + public short getFillBackgroundColor() + { + return patternBackgroundColorIndex.getShortValue(field_16_pattern_color_indexes); + } + + /** + * set the foreground fill color + * @param bg color + */ + public void setFillForegroundColor(short fg) + { + field_16_pattern_color_indexes = patternColorIndex.setShortValue(field_16_pattern_color_indexes,fg); + } + + /** + * get the foreground fill color + * @see org.apache.poi.hssf.usermodel.HSSFPalette#getColor(short) + * @return fill color + */ + public short getFillForegroundColor() + { + return patternColorIndex.getShortValue(field_16_pattern_color_indexes); + } + + public String toString() + { + StringBuffer buffer = new StringBuffer(); + buffer.append(" [Pattern Formatting]\n"); + buffer.append(" .fillpattern= ").append(Integer.toHexString(getFillPattern())).append("\n"); + buffer.append(" .fgcoloridx= ").append(Integer.toHexString(getFillForegroundColor())).append("\n"); + buffer.append(" .bgcoloridx= ").append(Integer.toHexString(getFillBackgroundColor())).append("\n"); + buffer.append(" [/Pattern Formatting]\n"); + return buffer.toString(); + } + + public Object clone() + { + PatternFormatting rec = new PatternFormatting(); + rec.field_15_pattern_style = field_15_pattern_style; + rec.field_16_pattern_color_indexes = field_16_pattern_color_indexes; + return rec; + } + + public int serialize(int offset, byte [] data) + { + LittleEndian.putShort(data, offset, field_15_pattern_style); + offset += 2; + LittleEndian.putShort(data, offset, field_16_pattern_color_indexes); + offset += 2; + return 4; + } +} diff --git a/src/java/org/apache/poi/hssf/record/formula/RefVPtg.java b/src/java/org/apache/poi/hssf/record/formula/RefVPtg.java index 8a6b2c03b4..75c6348907 100644 --- a/src/java/org/apache/poi/hssf/record/formula/RefVPtg.java +++ b/src/java/org/apache/poi/hssf/record/formula/RefVPtg.java @@ -32,6 +32,7 @@ public final class RefVPtg extends ReferencePtg { public RefVPtg(int row, int column, boolean isRowRelative, boolean isColumnRelative) { super(row, column, isRowRelative, isColumnRelative); + setClass(CLASS_VALUE); } diff --git a/src/java/org/apache/poi/hssf/usermodel/HSSFBorderFormatting.java b/src/java/org/apache/poi/hssf/usermodel/HSSFBorderFormatting.java new file mode 100644 index 0000000000..622f3a6742 --- /dev/null +++ b/src/java/org/apache/poi/hssf/usermodel/HSSFBorderFormatting.java @@ -0,0 +1,128 @@ +/* ==================================================================== + 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 org.apache.poi.hssf.record.cf.BorderFormatting; + +/** + * High level representation for Border Formatting component + * of Conditional Formatting settings + * + * @author Dmitriy Kumshayev + * + */ +public class HSSFBorderFormatting +{ + /** + * No border + */ + + public final static short BORDER_NONE = BorderFormatting.BORDER_NONE; + + /** + * Thin border + */ + + public final static short BORDER_THIN = BorderFormatting.BORDER_THIN; + + /** + * Medium border + */ + + public final static short BORDER_MEDIUM = BorderFormatting.BORDER_MEDIUM; + + /** + * dash border + */ + + public final static short BORDER_DASHED = BorderFormatting.BORDER_DASHED; + + /** + * dot border + */ + + public final static short BORDER_HAIR = BorderFormatting.BORDER_HAIR; + + /** + * Thick border + */ + + public final static short BORDER_THICK = BorderFormatting.BORDER_THICK; + + /** + * double-line border + */ + + public final static short BORDER_DOUBLE = BorderFormatting.BORDER_DOUBLE; + + /** + * hair-line border + */ + + public final static short BORDER_DOTTED = BorderFormatting.BORDER_DOTTED; + + /** + * Medium dashed border + */ + + public final static short BORDER_MEDIUM_DASHED = BorderFormatting.BORDER_MEDIUM_DASHED; + + /** + * dash-dot border + */ + + public final static short BORDER_DASH_DOT = BorderFormatting.BORDER_DASH_DOT; + + /** + * medium dash-dot border + */ + + public final static short BORDER_MEDIUM_DASH_DOT = BorderFormatting.BORDER_MEDIUM_DASH_DOT; + + /** + * dash-dot-dot border + */ + + public final static short BORDER_DASH_DOT_DOT = BorderFormatting.BORDER_DASH_DOT_DOT; + + /** + * medium dash-dot-dot border + */ + + public final static short BORDER_MEDIUM_DASH_DOT_DOT = BorderFormatting.BORDER_MEDIUM_DASH_DOT_DOT; + + /** + * slanted dash-dot border + */ + + public final static short BORDER_SLANTED_DASH_DOT = BorderFormatting.BORDER_SLANTED_DASH_DOT; + + + private BorderFormatting borderFormatting; + + public HSSFBorderFormatting() + { + borderFormatting = new BorderFormatting(); + } + + protected BorderFormatting getBorderFormattingBlock() + { + return borderFormatting; + } + +} diff --git a/src/java/org/apache/poi/hssf/usermodel/HSSFCellStyle.java b/src/java/org/apache/poi/hssf/usermodel/HSSFCellStyle.java index d0d29b5b79..11d14782be 100644 --- a/src/java/org/apache/poi/hssf/usermodel/HSSFCellStyle.java +++ b/src/java/org/apache/poi/hssf/usermodel/HSSFCellStyle.java @@ -277,7 +277,7 @@ public class HSSFCellStyle implements CellStyle /** * Get the contents of the format string, by looking up - * the DataFormat against the supplied workbook + * the DataFormat against the bound workbook * @see org.apache.poi.hssf.usermodel.HSSFDataFormat */ public String getDataFormatString() { @@ -285,6 +285,16 @@ public class HSSFCellStyle implements CellStyle return format.getFormat(getDataFormat()); } + /** + * Get the contents of the format string, by looking up + * the DataFormat against the supplied workbook + * @see org.apache.poi.hssf.usermodel.HSSFDataFormat + */ + public String getDataFormatString(org.apache.poi.ss.usermodel.Workbook workbook) { + HSSFDataFormat format = new HSSFDataFormat( ((HSSFWorkbook)workbook).getWorkbook() ); + + return format.getFormat(getDataFormat()); + } /** * set the font for this style diff --git a/src/java/org/apache/poi/hssf/usermodel/HSSFConditionalFormatting.java b/src/java/org/apache/poi/hssf/usermodel/HSSFConditionalFormatting.java new file mode 100644 index 0000000000..e5fbb1d300 --- /dev/null +++ b/src/java/org/apache/poi/hssf/usermodel/HSSFConditionalFormatting.java @@ -0,0 +1,201 @@ +/* ==================================================================== + 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.util.ArrayList; +import java.util.List; + +import org.apache.poi.hssf.record.CFHeaderRecord; +import org.apache.poi.hssf.record.CFRuleRecord; +import org.apache.poi.hssf.record.aggregates.CFRecordsAggregate; +import org.apache.poi.hssf.record.cf.CellRange; +import org.apache.poi.hssf.util.Region; + +public class HSSFConditionalFormatting +{ + HSSFSheet sheet; + CFRecordsAggregate cfAggregate; + + protected HSSFConditionalFormatting(HSSFSheet sheet) + { + this.sheet = sheet; + this.cfAggregate = new CFRecordsAggregate(); + } + + protected HSSFConditionalFormatting(HSSFSheet sheet, CFRecordsAggregate cfAggregate) + { + this.sheet = sheet; + this.cfAggregate = cfAggregate; + } + + + public void setFormattingRegions(Region[] regions) + { + if( regions != null) + { + CFHeaderRecord header = cfAggregate.getHeader(); + header.setCellRanges(mergeCellRanges(toCellRangeList(regions))); + } + } + + public Region[] getFormattingRegions() + { + CFHeaderRecord cfh = cfAggregate.getHeader(); + + List cellRanges = cfh.getCellRanges(); + + if (cellRanges != null) + { + return toRegionArray(cellRanges); + } + return null; + } + + public void setConditionalFormat(int idx, HSSFConditionalFormattingRule cfRule) + { + cfAggregate.getRules().set(idx, cfRule); + } + + public void addConditionalFormat(HSSFConditionalFormattingRule cfRule) + { + cfAggregate.getRules().add(cfRule); + } + + public HSSFConditionalFormattingRule getConditionalFormat(int idx) + { + CFRuleRecord ruleRecord = (CFRuleRecord)cfAggregate.getRules().get(idx); + return new HSSFConditionalFormattingRule(sheet.workbook, ruleRecord); + } + + /** + * Do all possible cell merges between cells of the list so that:<br> + * <li>if a cell range is completely inside of another cell range, it gets removed from the list + * <li>if two cells have a shared border, merge them into one bigger cell range + * @param cellRangeList + * @return updated List of cell ranges + */ + private static List mergeCellRanges(List cellRangeList) + { + boolean merged = false; + + do + { + merged = false; + + if( cellRangeList.size()>1 ) + { + for( int i=0; i<cellRangeList.size(); i++) + { + CellRange range1 = (CellRange)cellRangeList.get(i); + for( int j=i+1; j<cellRangeList.size(); j++) + { + CellRange range2 = (CellRange)cellRangeList.get(j); + + switch(range1.intersect(range2)) + { + case CellRange.NO_INTERSECTION: + { + if( range1.hasSharedBorder(range2)) + { + cellRangeList.set(i, range1.createEnclosingCellRange(range2)); + cellRangeList.remove(j--); + merged = true; + } + else + { + // No intersection and no shared border: do nothing + } + break; + } + case CellRange.OVERLAP: + { + // TODO split and re-merge the intersected area + break; + } + case CellRange.INSIDE: + { + // Remove range2, since it is completely inside of range1 + cellRangeList.remove(j--); + merged = true; + break; + } + case CellRange.ENCLOSES: + { + // range2 encloses range1, so replace it with the enclosing one + cellRangeList.set(i, range2); + cellRangeList.remove(j--); + merged = true; + break; + } + } + } + } + } + } + while( merged ); + + return cellRangeList; + } + + /** + * Convert a List of CellRange objects to an array of regions + * + * @param List of CellRange objects + * @return regions + */ + private static Region[] toRegionArray(List cellRanges) + { + int size = cellRanges.size(); + Region[] regions = new Region[size]; + + for (int i = 0; i != size; i++) + { + CellRange cr = (CellRange) cellRanges.get(i); + regions[i] = new Region(cr.getFirstRow(), cr.getFirstColumn(), + cr.getLastRow(), cr.getLastColumn()); + } + return regions; + } + + /** + * Convert array of regions to a List of CellRange objects + * + * @param regions + * @return List of CellRange objects + */ + private static List toCellRangeList(Region[] regions) + { + List cellRangeList = new ArrayList(); + for( int i=0; i<regions.length; i++) + { + Region r = regions[i]; + CellRange cr = new CellRange(r.getRowFrom(), r.getRowTo(), r.getColumnFrom(), r + .getColumnTo()); + cellRangeList.add(cr); + } + return cellRangeList; + } + + public String toString() + { + if(cfAggregate!=null) + { + return cfAggregate.toString(); + } + return null; + } +} diff --git a/src/java/org/apache/poi/hssf/usermodel/HSSFConditionalFormattingRule.java b/src/java/org/apache/poi/hssf/usermodel/HSSFConditionalFormattingRule.java new file mode 100644 index 0000000000..3d003dc491 --- /dev/null +++ b/src/java/org/apache/poi/hssf/usermodel/HSSFConditionalFormattingRule.java @@ -0,0 +1,248 @@ +/* ==================================================================== + 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.util.List; +import java.util.Stack; + +import org.apache.poi.hssf.model.FormulaParser; +import org.apache.poi.hssf.record.CFRuleRecord; +import org.apache.poi.hssf.record.formula.Ptg; + +/** + * + * High level representation of Conditional Format + * + * @author Dmitriy Kumshayev + */ + +public class HSSFConditionalFormattingRule +{ + public static final byte CELL_COMPARISON = CFRuleRecord.CONDITION_TYPE_CELL_VALUE_IS; + public static final byte FORMULA = CFRuleRecord.CONDITION_TYPE_FORMULA; + + public static final byte COMPARISON_OPERATOR_NO_COMPARISON = CFRuleRecord.COMPARISON_OPERATOR_NO_COMPARISON; + public static final byte COMPARISON_OPERATOR_BETWEEN = CFRuleRecord.COMPARISON_OPERATOR_BETWEEN; + public static final byte COMPARISON_OPERATOR_NOT_BETWEEN = CFRuleRecord.COMPARISON_OPERATOR_NOT_BETWEEN; + public static final byte COMPARISON_OPERATOR_EQUAL = CFRuleRecord.COMPARISON_OPERATOR_EQUAL; + public static final byte COMPARISON_OPERATOR_NOT_EQUAL = CFRuleRecord.COMPARISON_OPERATOR_NOT_EQUAL; + public static final byte COMPARISON_OPERATOR_GT = CFRuleRecord.COMPARISON_OPERATOR_GT; + public static final byte COMPARISON_OPERATOR_LT = CFRuleRecord.COMPARISON_OPERATOR_LT; + public static final byte COMPARISON_OPERATOR_GE = CFRuleRecord.COMPARISON_OPERATOR_GE; + public static final byte COMPARISON_OPERATOR_LE = CFRuleRecord.COMPARISON_OPERATOR_LE; + + + + private CFRuleRecord cfRuleRecord; + private HSSFWorkbook workbook; + + protected HSSFConditionalFormattingRule(HSSFWorkbook workbook) + { + this.workbook = workbook; + this.cfRuleRecord = new CFRuleRecord(); + } + + protected HSSFConditionalFormattingRule(HSSFWorkbook workbook, CFRuleRecord cfRuleRecord) + { + this.workbook = workbook; + this.cfRuleRecord = cfRuleRecord; + } + + /** + * Keep Font Formatting unchanged for this Conditional Formatting Rule + */ + public void setFontFormattingUnchanged() + { + cfRuleRecord.setFontFormattingUnchanged(); + } + /** + * Keep Border Formatting unchanged for this Conditional Formatting Rule + */ + public void setBorderFormattingUnchanged() + { + cfRuleRecord.setBorderFormattingUnchanged(); + } + /** + * Keep Pattern Formatting unchanged for this Conditional Formatting Rule + */ + public void setPatternFormattingUnchanged() + { + cfRuleRecord.setPatternFormattingUnchanged(); + } + + public void setFontFormatting(HSSFFontFormatting fontFormatting) + { + if( fontFormatting!=null ) + { + cfRuleRecord.setFontFormatting(fontFormatting.getFontFormattingBlock()); + } + else + { + setFontFormattingUnchanged(); + } + } + public void setBorderFormatting(HSSFBorderFormatting borderFormatting) + { + if( borderFormatting != null ) + { + cfRuleRecord.setBorderFormatting(borderFormatting.getBorderFormattingBlock()); + } + else + { + setBorderFormattingUnchanged(); + } + } + public void setPatternFormatting(HSSFPatternFormatting patternFormatting) + { + if( patternFormatting != null) + { + cfRuleRecord.setPatternFormatting(patternFormatting.getPatternFormattingBlock()); + } + else + { + setPatternFormattingUnchanged(); + } + } + + public void setCellComparisonCondition(byte comparisonOperation, String formula1, String formula2) + { + cfRuleRecord.setConditionType(CELL_COMPARISON); + cfRuleRecord.setComparisonOperation(comparisonOperation); + + // Formula 1 + setFormula1(formula1); + + // Formula 2 + setFormula1(formula2); + } + + public void setFormulaCondition(String formula) + { + cfRuleRecord.setConditionType(FORMULA); + // Formula 1 + setFormula1(formula); + } + + public void setFormula1(String formula) + { + // Formula 1 + if( formula != null) + { + Stack parsedExpression = parseFormula(formula); + if( parsedExpression != null ) + { + cfRuleRecord.setParsedExpression1(parsedExpression); + } + else + { + cfRuleRecord.setParsedExpression1(null); + } + } + else + { + cfRuleRecord.setParsedExpression1(null); + } + } + + public void setFormula2(String formula) + { + // Formula 2 + if( formula != null) + { + Stack parsedExpression = parseFormula(formula); + if( parsedExpression != null ) + { + cfRuleRecord.setParsedExpression2(parsedExpression); + } + else + { + cfRuleRecord.setParsedExpression2(null); + } + } + else + { + cfRuleRecord.setParsedExpression2(null); + } + } + + public String getFormula1() + { + return toFormulaString(cfRuleRecord.getParsedExpression1()); + } + + public String getFormula2() + { + byte conditionType = cfRuleRecord.getConditionType(); + switch(conditionType) + { + case CELL_COMPARISON: + { + byte comparisonOperation = cfRuleRecord.getComparisonOperation(); + switch(comparisonOperation) + { + case COMPARISON_OPERATOR_BETWEEN: + case COMPARISON_OPERATOR_NOT_BETWEEN: + return toFormulaString(cfRuleRecord.getParsedExpression2()); + } + } + } + return null; + } + + private String toFormulaString(List parsedExpression) + { + String formula = null; + if(parsedExpression!=null) + { + formula = FormulaParser.toFormulaString(workbook.getWorkbook(),parsedExpression); + } + return formula; + } + + + private Stack parseFormula(String formula2) + { + FormulaParser parser = + new FormulaParser(formula2, workbook.getWorkbook()); + parser.parse(); + + Stack parsedExpression = convertToTokenStack(parser.getRPNPtg()); + parsedExpression = convertToTokenStack(parser.getRPNPtg()); + return parsedExpression; + } + + private static Stack convertToTokenStack(Ptg[] ptgs) + { + if( ptgs != null) + { + Stack parsedExpression = new Stack(); + // fill the Ptg Stack with Ptgs of new formula + for (int k = 0; k < ptgs.length; k++) + { + parsedExpression.push(ptgs[ k ]); + } + return parsedExpression; + } + else + { + return null; + } + } + + +} diff --git a/src/java/org/apache/poi/hssf/usermodel/HSSFFontFormatting.java b/src/java/org/apache/poi/hssf/usermodel/HSSFFontFormatting.java new file mode 100644 index 0000000000..ee1352fc8c --- /dev/null +++ b/src/java/org/apache/poi/hssf/usermodel/HSSFFontFormatting.java @@ -0,0 +1,456 @@ +/* ==================================================================== + 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 org.apache.poi.hssf.record.cf.FontFormatting; +/** + * High level representation for Font Formatting component + * of Conditional Formatting settings + * + * @author Dmitriy Kumshayev + * + */ +public class HSSFFontFormatting +{ + /** + * Escapement type - None + */ + public final static short SS_NONE = FontFormatting.SS_NONE; + + /** + * Escapement type - Superscript + */ + public final static short SS_SUPER = FontFormatting.SS_SUPER; + + /** + * Escapement type - Subscript + */ + public final static short SS_SUB = FontFormatting.SS_SUB; + + /** + * Underline type - None + */ + public final static byte U_NONE = FontFormatting.U_NONE; + /** + * Underline type - Single + */ + public final static byte U_SINGLE = FontFormatting.U_SINGLE; + /** + * Underline type - Double + */ + public final static byte U_DOUBLE = FontFormatting.U_DOUBLE; + /** + * Underline type - Single Accounting + */ + public final static byte U_SINGLE_ACCOUNTING = FontFormatting.U_SINGLE_ACCOUNTING; + /** + * Underline type - Double Accounting + */ + public final static byte U_DOUBLE_ACCOUNTING = FontFormatting.U_DOUBLE_ACCOUNTING; + + private FontFormatting fontFormatting; + + public HSSFFontFormatting() + { + fontFormatting = new FontFormatting(); + } + + protected FontFormatting getFontFormattingBlock() + { + return fontFormatting; + } + + /** + * get the type of super or subscript for the font + * + * @return super or subscript option + * @see #SS_NONE + * @see #SS_SUPER + * @see #SS_SUB + */ + public short getEscapementType() + { + return fontFormatting.getEscapementType(); + } + + /** + * @return font color index + */ + public short getFontColorIndex() + { + return fontFormatting.getFontColorIndex(); + } + + /** + * gets the height of the font in 1/20th point units + * + * @return fontheight (in points/20); or -1 if not modified + */ + public short getFontHeight() + { + return fontFormatting.getFontHeight(); + } + + /** + * get the font weight for this font (100-1000dec or 0x64-0x3e8). Default is + * 0x190 for normal and 0x2bc for bold + * + * @return bw - a number between 100-1000 for the fonts "boldness" + */ + + public short getFontWeight() + { + return fontFormatting.getFontWeight(); + } + + /** + * @return + * @see org.apache.poi.hssf.record.cf.FontFormatting#getRawRecord() + */ + protected byte[] getRawRecord() + { + return fontFormatting.getRawRecord(); + } + + /** + * get the type of underlining for the font + * + * @return font underlining type + * + * @see #U_NONE + * @see #U_SINGLE + * @see #U_DOUBLE + * @see #U_SINGLE_ACCOUNTING + * @see #U_DOUBLE_ACCOUNTING + */ + public short getUnderlineType() + { + return fontFormatting.getUnderlineType(); + } + + /** + * get whether the font weight is set to bold or not + * + * @return bold - whether the font is bold or not + */ + public boolean isBold() + { + return fontFormatting.isBold(); + } + + /** + * @return whether the font is condense or not + */ + public boolean isCondenseOn() + { + return fontFormatting.isFontOutlineModified() && fontFormatting.isCondenseOn(); + } + + /** + * @return true if escapement type was modified from default + */ + public boolean isEscapementTypeModified() + { + return fontFormatting.isEscapementTypeModified(); + } + + /** + * @return true if font cancellation was modified from default + */ + public boolean isFontCancellationModified() + { + return fontFormatting.isFontCancellationModified(); + } + + /** + * @return true if font condense type was modified from default + */ + public boolean isFontCondenseModified() + { + return fontFormatting.isFontCondenseModified(); + } + + /** + * @return true if font outline type was modified from default + */ + public boolean isFontOutlineModified() + { + return fontFormatting.isFontOutlineModified(); + } + + /** + * @return true if font shadow type was modified from default + */ + public boolean isFontShadowModified() + { + return fontFormatting.isFontShadowModified(); + } + + /** + * @return true if font style was modified from default + */ + public boolean isFontStyleModified() + { + return fontFormatting.isFontStyleModified(); + } + + /** + * @return true if font style was set to <i>italic</i> + */ + public boolean isItalic() + { + return fontFormatting.isFontStyleModified() && fontFormatting.isItalic(); + } + + /** + * @return true if font outline is on + */ + public boolean isOutlineOn() + { + return fontFormatting.isFontOutlineModified() && fontFormatting.isOutlineOn(); + } + + /** + * @return true if font shadow is on + */ + public boolean isShadowOn() + { + return fontFormatting.isFontOutlineModified() && fontFormatting.isShadowOn(); + } + + /** + * @return true if font strikeout is on + */ + public boolean isStruckout() + { + return fontFormatting.isFontCancellationModified() && fontFormatting.isStruckout(); + } + + /** + * @return true if font underline type was modified from default + */ + public boolean isUnderlineTypeModified() + { + return fontFormatting.isUnderlineTypeModified(); + } + + /** + * set font style options. + * + * @param italic - if true, set posture style to italic, otherwise to normal + * @param bold- if true, set font weight to bold, otherwise to normal + */ + + public void setFontStyle(boolean italic, boolean bold) + { + boolean modified = italic || bold; + fontFormatting.setItalic(italic); + fontFormatting.setBold(bold); + fontFormatting.setFontStyleModified(modified); + } + + /** + * set font style options to default values (non-italic, non-bold) + */ + public void resetFontStyle() + { + setFontStyle(false,false); + } + + /** + * set the escapement type for the font + * + * @param escapementType super or subscript option + * @see #SS_NONE + * @see #SS_SUPER + * @see #SS_SUB + */ + public void setCondense(boolean on) + { + fontFormatting.setCondense(on); + fontFormatting.setFontCondenseModified(on); + } + + /** + * set the escapement type for the font + * + * @param escapementType super or subscript option + * @see #SS_NONE + * @see #SS_SUPER + * @see #SS_SUB + */ + public void setEscapementType(short escapementType) + { + switch(escapementType) + { + case HSSFFontFormatting.SS_SUB: + case HSSFFontFormatting.SS_SUPER: + fontFormatting.setEscapementType(escapementType); + fontFormatting.setEscapementTypeModified(true); + break; + case HSSFFontFormatting.SS_NONE: + fontFormatting.setEscapementType(escapementType); + fontFormatting.setEscapementTypeModified(false); + break; + default: + } + } + + /** + * @param modified + * @see org.apache.poi.hssf.record.cf.FontFormatting#setEscapementTypeModified(boolean) + */ + public void setEscapementTypeModified(boolean modified) + { + fontFormatting.setEscapementTypeModified(modified); + } + + /** + * @param modified + * @see org.apache.poi.hssf.record.cf.FontFormatting#setFontCancellationModified(boolean) + */ + public void setFontCancellationModified(boolean modified) + { + fontFormatting.setFontCancellationModified(modified); + } + + /** + * @param fci + * @see org.apache.poi.hssf.record.cf.FontFormatting#setFontColorIndex(short) + */ + public void setFontColorIndex(short fci) + { + fontFormatting.setFontColorIndex(fci); + } + + /** + * @param modified + * @see org.apache.poi.hssf.record.cf.FontFormatting#setFontCondenseModified(boolean) + */ + public void setFontCondenseModified(boolean modified) + { + fontFormatting.setFontCondenseModified(modified); + } + + /** + * @param height + * @see org.apache.poi.hssf.record.cf.FontFormatting#setFontHeight(short) + */ + public void setFontHeight(short height) + { + fontFormatting.setFontHeight(height); + } + + /** + * @param modified + * @see org.apache.poi.hssf.record.cf.FontFormatting#setFontOutlineModified(boolean) + */ + public void setFontOutlineModified(boolean modified) + { + fontFormatting.setFontOutlineModified(modified); + } + + /** + * @param modified + * @see org.apache.poi.hssf.record.cf.FontFormatting#setFontShadowModified(boolean) + */ + public void setFontShadowModified(boolean modified) + { + fontFormatting.setFontShadowModified(modified); + } + + /** + * @param modified + * @see org.apache.poi.hssf.record.cf.FontFormatting#setFontStyleModified(boolean) + */ + public void setFontStyleModified(boolean modified) + { + fontFormatting.setFontStyleModified(modified); + } + + /** + * @param on + * @see org.apache.poi.hssf.record.cf.FontFormatting#setOutline(boolean) + */ + public void setOutline(boolean on) + { + fontFormatting.setOutline(on); + fontFormatting.setFontOutlineModified(on); + } + + /** + * @param on + * @see org.apache.poi.hssf.record.cf.FontFormatting#setShadow(boolean) + */ + public void setShadow(boolean on) + { + fontFormatting.setShadow(on); + fontFormatting.setFontShadowModified(on); + } + + /** + * @param strike + * @see org.apache.poi.hssf.record.cf.FontFormatting#setStrikeout(boolean) + */ + public void setStrikeout(boolean strike) + { + fontFormatting.setStrikeout(strike); + fontFormatting.setFontCancellationModified(strike); + } + + /** + * set the type of underlining type for the font + * + * @param u super or subscript option + * + * @see #U_NONE + * @see #U_SINGLE + * @see #U_DOUBLE + * @see #U_SINGLE_ACCOUNTING + * @see #U_DOUBLE_ACCOUNTING + */ + public void setUnderlineType(short underlineType) + { + switch(underlineType) + { + case HSSFFontFormatting.U_SINGLE: + case HSSFFontFormatting.U_DOUBLE: + case HSSFFontFormatting.U_SINGLE_ACCOUNTING: + case HSSFFontFormatting.U_DOUBLE_ACCOUNTING: + fontFormatting.setUnderlineType(underlineType); + setUnderlineTypeModified(true); + break; + + case HSSFFontFormatting.U_NONE: + fontFormatting.setUnderlineType(underlineType); + setUnderlineTypeModified(false); + break; + default: + } + } + + /** + * @param modified + * @see org.apache.poi.hssf.record.cf.FontFormatting#setUnderlineTypeModified(boolean) + */ + public void setUnderlineTypeModified(boolean modified) + { + fontFormatting.setUnderlineTypeModified(modified); + } + +} diff --git a/src/java/org/apache/poi/hssf/usermodel/HSSFPatternFormatting.java b/src/java/org/apache/poi/hssf/usermodel/HSSFPatternFormatting.java new file mode 100644 index 0000000000..352a5b4872 --- /dev/null +++ b/src/java/org/apache/poi/hssf/usermodel/HSSFPatternFormatting.java @@ -0,0 +1,134 @@ +/* ==================================================================== + 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 org.apache.poi.hssf.record.cf.PatternFormatting; + +/** + * High level representation for Conditional Formatting settings + * + * @author Dmitriy Kumshayev + * + */ +public class HSSFPatternFormatting +{ + /** No background */ + public final static short NO_FILL = PatternFormatting.NO_FILL; + /** Solidly filled */ + public final static short SOLID_FOREGROUND = PatternFormatting.SOLID_FOREGROUND; + /** Small fine dots */ + public final static short FINE_DOTS = PatternFormatting.FINE_DOTS; + /** Wide dots */ + public final static short ALT_BARS = PatternFormatting.ALT_BARS; + /** Sparse dots */ + public final static short SPARSE_DOTS = PatternFormatting.SPARSE_DOTS; + /** Thick horizontal bands */ + public final static short THICK_HORZ_BANDS = PatternFormatting.THICK_HORZ_BANDS; + /** Thick vertical bands */ + public final static short THICK_VERT_BANDS = PatternFormatting.THICK_VERT_BANDS; + /** Thick backward facing diagonals */ + public final static short THICK_BACKWARD_DIAG = PatternFormatting.THICK_BACKWARD_DIAG; + /** Thick forward facing diagonals */ + public final static short THICK_FORWARD_DIAG = PatternFormatting.THICK_FORWARD_DIAG; + /** Large spots */ + public final static short BIG_SPOTS = PatternFormatting.BIG_SPOTS; + /** Brick-like layout */ + public final static short BRICKS = PatternFormatting.BRICKS; + /** Thin horizontal bands */ + public final static short THIN_HORZ_BANDS = PatternFormatting.THIN_HORZ_BANDS; + /** Thin vertical bands */ + public final static short THIN_VERT_BANDS = PatternFormatting.THIN_VERT_BANDS; + /** Thin backward diagonal */ + public final static short THIN_BACKWARD_DIAG = PatternFormatting.THIN_BACKWARD_DIAG; + /** Thin forward diagonal */ + public final static short THIN_FORWARD_DIAG = PatternFormatting.THIN_FORWARD_DIAG; + /** Squares */ + public final static short SQUARES = PatternFormatting.SQUARES; + /** Diamonds */ + public final static short DIAMONDS = PatternFormatting.DIAMONDS; + /** Less Dots */ + public final static short LESS_DOTS = PatternFormatting.LESS_DOTS; + /** Least Dots */ + public final static short LEAST_DOTS = PatternFormatting.LEAST_DOTS; + + private PatternFormatting patternFormatting; + + public HSSFPatternFormatting() + { + patternFormatting = new PatternFormatting(); + } + + protected PatternFormatting getPatternFormattingBlock() + { + return patternFormatting; + } + + /** + * @return + * @see org.apache.poi.hssf.record.cf.PatternFormatting#getFillBackgroundColor() + */ + public short getFillBackgroundColor() + { + return patternFormatting.getFillBackgroundColor(); + } + + /** + * @return + * @see org.apache.poi.hssf.record.cf.PatternFormatting#getFillForegroundColor() + */ + public short getFillForegroundColor() + { + return patternFormatting.getFillForegroundColor(); + } + + /** + * @return + * @see org.apache.poi.hssf.record.cf.PatternFormatting#getFillPattern() + */ + public short getFillPattern() + { + return patternFormatting.getFillPattern(); + } + + /** + * @param bg + * @see org.apache.poi.hssf.record.cf.PatternFormatting#setFillBackgroundColor(short) + */ + public void setFillBackgroundColor(short bg) + { + patternFormatting.setFillBackgroundColor(bg); + } + + /** + * @param fg + * @see org.apache.poi.hssf.record.cf.PatternFormatting#setFillForegroundColor(short) + */ + public void setFillForegroundColor(short fg) + { + patternFormatting.setFillForegroundColor(fg); + } + + /** + * @param fp + * @see org.apache.poi.hssf.record.cf.PatternFormatting#setFillPattern(short) + */ + public void setFillPattern(short fp) + { + patternFormatting.setFillPattern(fp); + } +} diff --git a/src/java/org/apache/poi/hssf/usermodel/HSSFSheet.java b/src/java/org/apache/poi/hssf/usermodel/HSSFSheet.java index 047d7fcb3b..d553f7b0a6 100644 --- a/src/java/org/apache/poi/hssf/usermodel/HSSFSheet.java +++ b/src/java/org/apache/poi/hssf/usermodel/HSSFSheet.java @@ -53,6 +53,7 @@ import org.apache.poi.hssf.record.SCLRecord; import org.apache.poi.hssf.record.VCenterRecord; import org.apache.poi.hssf.record.WSBoolRecord; import org.apache.poi.hssf.record.WindowTwoRecord; +import org.apache.poi.hssf.record.aggregates.CFRecordsAggregate; import org.apache.poi.hssf.record.formula.Ptg; import org.apache.poi.hssf.record.formula.ReferencePtg; import org.apache.poi.hssf.util.HSSFCellRangeAddress; @@ -1844,4 +1845,161 @@ public class HSSFSheet implements org.apache.poi.ss.usermodel.Sheet return null; } + + /** + * A factory method allowing to create a conditional formatting rule + * with a cell comparison operator and + * formatting rules such as font format, border format and pattern format + * + * @param comparisonOperation - one of the following values: <p> + * <li>{@link HSSFConditionalFormattingRule#COMPARISON_OPERATOR_BETWEEN}</li> + * <li>{@link HSSFConditionalFormattingRule#COMPARISON_OPERATOR_NOT_BETWEEN}</li> + * <li>{@link HSSFConditionalFormattingRule#COMPARISON_OPERATOR_EQUAL}</li> + * <li>{@link HSSFConditionalFormattingRule#COMPARISON_OPERATOR_NOT_EQUAL}</li> + * <li>{@link HSSFConditionalFormattingRule#COMPARISON_OPERATOR_GT}</li> + * <li>{@link HSSFConditionalFormattingRule#COMPARISON_OPERATOR_LT}</li> + * <li>{@link HSSFConditionalFormattingRule#COMPARISON_OPERATOR_GE}</li> + * <li>{@link HSSFConditionalFormattingRule#COMPARISON_OPERATOR_LE}</li> + * </p> + * @param formula1 - formula for the valued, compared with the cell + * @param formula2 - second formula (only used with + * {@link HSSFConditionalFormattingRule#COMPARISON_OPERATOR_BETWEEN}) and + * {@link HSSFConditionalFormattingRule#COMPARISON_OPERATOR_NOT_BETWEEN} operations) + * @param fontFmt - font formatting rules + * @param bordFmt - border formatting rules + * @param patternFmt - pattern formatting rules + * @return + * + */ + public HSSFConditionalFormattingRule createConditionalFormattingRule( + byte comparisonOperation, + String formula1, + String formula2, + HSSFFontFormatting fontFmt, + HSSFBorderFormatting bordFmt, + HSSFPatternFormatting patternFmt) + { + HSSFConditionalFormattingRule cf = new HSSFConditionalFormattingRule(workbook); + cf.setFontFormatting(fontFmt); + cf.setBorderFormatting(bordFmt); + cf.setPatternFormatting(patternFmt); + cf.setCellComparisonCondition(comparisonOperation, formula1, formula2); + return cf; + } + + /** + * A factory method allowing to create a conditional formatting rule with a formula + * and formatting rules such as font format, border format and pattern format. <br> + * + * The formatting rules are applied by Excel when the value of the formula not equal to 0. + * + * @param comparisonOperation - one of the following values: <p> + * <li>{@link HSSFConditionalFormattingRule#COMPARISON_OPERATOR_BETWEEN}</li> + * <li>{@link HSSFConditionalFormattingRule#COMPARISON_OPERATOR_NOT_BETWEEN}</li> + * <li>{@link HSSFConditionalFormattingRule#COMPARISON_OPERATOR_EQUAL}</li> + * <li>{@link HSSFConditionalFormattingRule#COMPARISON_OPERATOR_NOT_EQUAL}</li> + * <li>{@link HSSFConditionalFormattingRule#COMPARISON_OPERATOR_GT}</li> + * <li>{@link HSSFConditionalFormattingRule#COMPARISON_OPERATOR_LT}</li> + * <li>{@link HSSFConditionalFormattingRule#COMPARISON_OPERATOR_GE}</li> + * <li>{@link HSSFConditionalFormattingRule#COMPARISON_OPERATOR_LE}</li> + * </p> + * @param formula1 - formula for the valued, compared with the cell + * @param formula2 - second formula (only used with + * {@link HSSFConditionalFormattingRule#COMPARISON_OPERATOR_BETWEEN}) and + * {@link HSSFConditionalFormattingRule#COMPARISON_OPERATOR_NOT_BETWEEN} operations) + * @param fontFmt - font formatting rules + * @param bordFmt - border formatting rules + * @param patternFmt - pattern formatting rules + * @return + * + */ + public HSSFConditionalFormattingRule createConditionalFormattingRule( + String formula, + HSSFFontFormatting fontFmt, + HSSFBorderFormatting bordFmt, + HSSFPatternFormatting patternFmt) + { + HSSFConditionalFormattingRule cf = new HSSFConditionalFormattingRule(workbook); + cf.setFontFormatting(fontFmt); + cf.setBorderFormatting(bordFmt); + cf.setPatternFormatting(patternFmt); + cf.setFormulaCondition(formula); + return cf; + } + + /** + * Adds a copy of HSSFConditionalFormatting object to the sheet + * <p>This method could be used to copy HSSFConditionalFormatting object + * from one sheet to another. For example: + * <pre> + * HSSFConditionalFormatting cf = sheet.getConditionalFormattingAt(index); + * newSheet.addConditionalFormatting(cf); + * </pre> + * + * @param cf HSSFConditionalFormatting object + * @return index of the new Conditional Formatting object + */ + public int addConditionalFormatting( HSSFConditionalFormatting cf ) + { + HSSFConditionalFormatting cfClone = new HSSFConditionalFormatting(this,cf.cfAggregate.cloneCFAggregate()); + cfClone.sheet=this; + return sheet.addConditionalFormatting(cfClone.cfAggregate); + } + + /** + * Allows to add a new Conditional Formatting set to the sheet. + * + * @param regions - list of rectangular regions to apply conditional formatting rules + * @param cfRules - set of up to three conditional formatting rules + * + * @return index of the newly created Conditional Formatting object + */ + + public int addConditionalFormatting( Region [] regions, HSSFConditionalFormattingRule [] cfRules ) + { + HSSFConditionalFormatting cf = new HSSFConditionalFormatting(this); + cf.setFormattingRegions(regions); + if( cfRules != null ) + { + for( int i=0; i!= cfRules.length; i++ ) + { + cf.addConditionalFormat(cfRules[i]); + } + } + return sheet.addConditionalFormatting(cf.cfAggregate); + } + + /** + * gets Conditional Formatting object at a particular index + * @param index of the Conditional Formatting object to fetch + * @return Conditional Formatting object + */ + + public HSSFConditionalFormatting getConditionalFormattingAt(int index) + { + CFRecordsAggregate cf = sheet.getCFRecordsAggregateAt(index); + if( cf != null ) + { + return new HSSFConditionalFormatting(this,cf); + } + return null; + } + + /** + * @return number of Conditional Formatting objects of the sheet + */ + public int getNumConditionalFormattings() + { + return sheet.getNumConditionalFormattings(); + } + + /** + * removes a Conditional Formatting object by index + * @param index of a Conditional Formatting object to remove + */ + public void removeConditionalFormatting(int index) + { + sheet.removeConditionalFormatting(index); + } + } diff --git a/src/java/org/apache/poi/util/POILogFactory.java b/src/java/org/apache/poi/util/POILogFactory.java index 74ea822a5f..a9ce66f36b 100644 --- a/src/java/org/apache/poi/util/POILogFactory.java +++ b/src/java/org/apache/poi/util/POILogFactory.java @@ -33,14 +33,25 @@ import java.util.*; public class POILogFactory { - // map of POILogger instances, with classes as keys - private static Map _loggers = new HashMap();; - + /** + * Map of POILogger instances, with classes as keys + */ + private static Map _loggers = new HashMap();; /** - * construct a POILogFactory. + * A common instance of NullLogger, as it does nothing + * we only need the one + */ + private static POILogger _nullLogger = new NullLogger(); + /** + * The name of the class to use. Initialised the + * first time we need it */ + private static String _loggerClassName = null; + /** + * Construct a POILogFactory. + */ private POILogFactory() { } @@ -69,28 +80,48 @@ public class POILogFactory public static POILogger getLogger(final String cat) { POILogger logger = null; + + // If we haven't found out what logger to use yet, + // then do so now + // Don't look it up until we're first asked, so + // that our users can set the system property + // between class loading and first use + if(_loggerClassName == null) { + try { + _loggerClassName = System.getProperty("org.apache.poi.util.POILogger"); + } catch(Exception e) {} + + // Use the default logger if none specified, + // or none could be fetched + if(_loggerClassName == null) { + _loggerClassName = _nullLogger.getClass().getName(); + } + } + + // Short circuit for the null logger, which + // ignores all categories + if(_loggerClassName.equals(_nullLogger.getClass().getName())) { + return _nullLogger; + } - if (_loggers.containsKey(cat)) - { + + // Fetch the right logger for them, creating + // it if that's required + if (_loggers.containsKey(cat)) { logger = ( POILogger ) _loggers.get(cat); - } - else - { - try{ - String loggerClassName = System.getProperty("org.apache.poi.util.POILogger"); - Class loggerClass = Class.forName(loggerClassName); + } else { + try { + Class loggerClass = Class.forName(_loggerClassName); logger = ( POILogger ) loggerClass.newInstance(); + logger.initialize(cat); + } catch(Exception e) { + // Give up and use the null logger + logger = _nullLogger; } - catch(Exception e){ - - logger = new NullLogger(); - } - - logger.initialize(cat); + // Save for next time _loggers.put(cat, logger); } return logger; } - -} // end public class POILogFactory +} // end public class POILogFactory
\ No newline at end of file diff --git a/src/scratchpad/src/org/apache/poi/hssf/usermodel/HSSFFormulaEvaluator.java b/src/scratchpad/src/org/apache/poi/hssf/usermodel/HSSFFormulaEvaluator.java index 58ab5b47ae..bb16fdfadd 100644 --- a/src/scratchpad/src/org/apache/poi/hssf/usermodel/HSSFFormulaEvaluator.java +++ b/src/scratchpad/src/org/apache/poi/hssf/usermodel/HSSFFormulaEvaluator.java @@ -19,6 +19,7 @@ package org.apache.poi.hssf.usermodel; import java.lang.reflect.Constructor; import java.util.HashMap; +import java.util.Iterator; import java.util.Map; import java.util.Stack; @@ -251,6 +252,35 @@ public class HSSFFormulaEvaluator { } return cell; } + + /** + * Loops over all cells in all sheets of the supplied + * workbook. + * For cells that contain formulas, their formulas are + * evaluated, and the results are saved. These cells + * remain as formula cells. + * For cells that do not contain formulas, no changes + * are made. + * This is a helpful wrapper around looping over all + * cells, and calling evaluateFormulaCell on each one. + */ + public static void evaluateAllFormulaCells(HSSFWorkbook wb) { + for(int i=0; i<wb.getNumberOfSheets(); i++) { + HSSFSheet sheet = wb.getSheetAt(i); + HSSFFormulaEvaluator evaluator = new HSSFFormulaEvaluator(sheet, wb); + + for (Iterator rit = sheet.rowIterator(); rit.hasNext();) { + HSSFRow r = (HSSFRow)rit.next(); + evaluator.setCurrentRow(r); + + for (Iterator cit = r.cellIterator(); cit.hasNext();) { + HSSFCell c = (HSSFCell)cit.next(); + if (c.getCellType() == HSSFCell.CELL_TYPE_FORMULA) + evaluator.evaluateFormulaCell(c); + } + } + } + } /** diff --git a/src/scratchpad/testcases/org/apache/poi/hssf/usermodel/TestFormulaEvaluatorBugs.java b/src/scratchpad/testcases/org/apache/poi/hssf/usermodel/TestFormulaEvaluatorBugs.java new file mode 100644 index 0000000000..db4be7f410 --- /dev/null +++ b/src/scratchpad/testcases/org/apache/poi/hssf/usermodel/TestFormulaEvaluatorBugs.java @@ -0,0 +1,88 @@ +/* ==================================================================== + 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.File; +import java.io.FileInputStream; +import java.io.FileOutputStream; +import java.util.Iterator; + +import junit.framework.TestCase; + +public final class TestFormulaEvaluatorBugs extends TestCase { + private String dirName; + private String tmpDirName; + + protected void setUp() throws Exception { + super.setUp(); + dirName = System.getProperty("HSSF.testdata.path"); + tmpDirName = System.getProperty("java.io.tmpdir"); + } + + /** + * An odd problem with evaluateFormulaCell giving the + * right values when file is opened, but changes + * to the source data in some versions of excel + * doesn't cause them to be updated. However, other + * versions of excel, and gnumeric, work just fine + * WARNING - tedious bug where you actually have to + * open up excel + */ + public void test44636() throws Exception { + // Open the existing file, tweak one value and + // re-calculate + FileInputStream in = new FileInputStream(new File(dirName,"44636.xls")); + HSSFWorkbook wb = new HSSFWorkbook(in); + HSSFSheet sheet = wb.getSheetAt (0); + HSSFRow row = sheet.getRow (0); + + row.getCell((short)0).setCellValue(4.2); + row.getCell((short)2).setCellValue(25); + + HSSFFormulaEvaluator.evaluateAllFormulaCells(wb); + assertEquals(4.2*25, row.getCell((short)3).getNumericCellValue(), 0.0001); + + // Save + File existing = new File(tmpDirName,"44636-existing.xls"); + FileOutputStream out = new FileOutputStream(existing); + wb.write(out); + out.close(); + System.err.println("Existing file for bug #44636 written to " + existing.toString()); + + + // Now, do a new file from scratch + wb = new HSSFWorkbook(); + sheet = wb.createSheet(); + + row = sheet.createRow(0); + row.createCell((short)0).setCellValue(1.2); + row.createCell((short)1).setCellValue(4.2); + + row = sheet.createRow(1); + row.createCell((short)0).setCellFormula("SUM(A1:B1)"); + + HSSFFormulaEvaluator.evaluateAllFormulaCells(wb); + assertEquals(5.4, row.getCell((short)0).getNumericCellValue(), 0.0001); + + // Save + File scratch = new File(tmpDirName,"44636-scratch.xls"); + out = new FileOutputStream(scratch); + wb.write(out); + out.close(); + System.err.println("New file for bug #44636 written to " + scratch.toString()); + } +} diff --git a/src/testcases/org/apache/poi/hssf/data/41546.xls b/src/testcases/org/apache/poi/hssf/data/41546.xls Binary files differnew file mode 100644 index 0000000000..1332f3eef5 --- /dev/null +++ b/src/testcases/org/apache/poi/hssf/data/41546.xls diff --git a/src/testcases/org/apache/poi/hssf/data/43251.xls b/src/testcases/org/apache/poi/hssf/data/43251.xls Binary files differnew file mode 100644 index 0000000000..abc476ab0f --- /dev/null +++ b/src/testcases/org/apache/poi/hssf/data/43251.xls diff --git a/src/testcases/org/apache/poi/hssf/data/Bug44593.xls b/src/testcases/org/apache/poi/hssf/data/44593.xls Binary files differindex 84d1311441..84d1311441 100644 --- a/src/testcases/org/apache/poi/hssf/data/Bug44593.xls +++ b/src/testcases/org/apache/poi/hssf/data/44593.xls diff --git a/src/testcases/org/apache/poi/hssf/data/44636.xls b/src/testcases/org/apache/poi/hssf/data/44636.xls Binary files differnew file mode 100644 index 0000000000..3108a620b2 --- /dev/null +++ b/src/testcases/org/apache/poi/hssf/data/44636.xls diff --git a/src/testcases/org/apache/poi/hssf/data/44643.xls b/src/testcases/org/apache/poi/hssf/data/44643.xls Binary files differnew file mode 100644 index 0000000000..7ae5071864 --- /dev/null +++ b/src/testcases/org/apache/poi/hssf/data/44643.xls diff --git a/src/testcases/org/apache/poi/hssf/record/TestCFHeaderRecord.java b/src/testcases/org/apache/poi/hssf/record/TestCFHeaderRecord.java new file mode 100644 index 0000000000..c3e5684798 --- /dev/null +++ b/src/testcases/org/apache/poi/hssf/record/TestCFHeaderRecord.java @@ -0,0 +1,145 @@ +/* ==================================================================== + Licensed to the Apache Software Foundation (ASF) under one or more + contributor license agreements. See the NOTICE file distributed with + this work for additional information regarding copyright ownership. + The ASF licenses this file to You under the Apache License, Version 2.0 + (the "License"); you may not use this file except in compliance with + the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +==================================================================== */ + +package org.apache.poi.hssf.record; + +import java.util.ArrayList; +import java.util.List; + +import junit.framework.TestCase; + +import org.apache.poi.hssf.record.cf.CellRange; + +/** + * Tests the serialization and deserialization of the TestCFHeaderRecord + * class works correctly. + * + * @author Dmitriy Kumshayev + */ +public class TestCFHeaderRecord + extends TestCase +{ + + public TestCFHeaderRecord(String name) + { + super(name); + } + + public void testCreateCFHeaderRecord () + { + CFHeaderRecord record = new CFHeaderRecord(); + List ranges = new ArrayList(); + ranges.add(new CellRange(0,-1,(short)5,(short)5)); + ranges.add(new CellRange(0,-1,(short)6,(short)6)); + ranges.add(new CellRange(0,1,(short)0,(short)1)); + ranges.add(new CellRange(0,1,(short)2,(short)3)); + ranges.add(new CellRange(2,3,(short)0,(short)1)); + ranges.add(new CellRange(2,3,(short)2,(short)3)); + record.setCellRanges(ranges); + ranges = record.getCellRanges(); + assertEquals(6,ranges.size()); + CellRange enclosingCellRange = record.getEnclosingCellRange(); + assertEquals(0, enclosingCellRange.getFirstRow()); + assertEquals(-1, enclosingCellRange.getLastRow()); + assertEquals(0, enclosingCellRange.getFirstColumn()); + assertEquals(6, enclosingCellRange.getLastColumn()); + record.setNeedRecalculation(true); + assertTrue(record.getNeedRecalculation()); + record.setNeedRecalculation(false); + assertFalse(record.getNeedRecalculation()); + } + + public void testSerialization() { + byte[] recordData = new byte[] + { + (byte)0x03, (byte)0x00, + (byte)0x01, (byte)0x00, + + (byte)0x00, (byte)0x00, + (byte)0x03, (byte)0x00, + (byte)0x00, (byte)0x00, + (byte)0x03, (byte)0x00, + + (byte)0x04, (byte)0x00, + + (byte)0x00, (byte)0x00, + (byte)0x01, (byte)0x00, + (byte)0x00, (byte)0x00, + (byte)0x01, (byte)0x00, + + (byte)0x00, (byte)0x00, + (byte)0x01, (byte)0x00, + (byte)0x02, (byte)0x00, + (byte)0x03, (byte)0x00, + + (byte)0x02, (byte)0x00, + (byte)0x03, (byte)0x00, + (byte)0x00, (byte)0x00, + (byte)0x01, (byte)0x00, + + (byte)0x02, (byte)0x00, + (byte)0x03, (byte)0x00, + (byte)0x02, (byte)0x00, + (byte)0x03, (byte)0x00, + }; + + CFHeaderRecord record = new CFHeaderRecord(new TestcaseRecordInputStream(CFHeaderRecord.sid, (short)recordData.length, recordData)); + + assertEquals("#CFRULES", 3, record.getNumberOfConditionalFormats()); + assertTrue(record.getNeedRecalculation()); + CellRange enclosingCellRange = record.getEnclosingCellRange(); + assertEquals(0, enclosingCellRange.getFirstRow()); + assertEquals(3, enclosingCellRange.getLastRow()); + assertEquals(0, enclosingCellRange.getFirstColumn()); + assertEquals(3, enclosingCellRange.getLastColumn()); + List ranges = record.getCellRanges(); + assertEquals(0, ((CellRange)ranges.get(0)).getFirstRow()); + assertEquals(1, ((CellRange)ranges.get(0)).getLastRow()); + assertEquals(0, ((CellRange)ranges.get(0)).getFirstColumn()); + assertEquals(1, ((CellRange)ranges.get(0)).getLastColumn()); + assertEquals(0, ((CellRange)ranges.get(1)).getFirstRow()); + assertEquals(1, ((CellRange)ranges.get(1)).getLastRow()); + assertEquals(2, ((CellRange)ranges.get(1)).getFirstColumn()); + assertEquals(3, ((CellRange)ranges.get(1)).getLastColumn()); + assertEquals(2, ((CellRange)ranges.get(2)).getFirstRow()); + assertEquals(3, ((CellRange)ranges.get(2)).getLastRow()); + assertEquals(0, ((CellRange)ranges.get(2)).getFirstColumn()); + assertEquals(1, ((CellRange)ranges.get(2)).getLastColumn()); + assertEquals(2, ((CellRange)ranges.get(3)).getFirstRow()); + assertEquals(3, ((CellRange)ranges.get(3)).getLastRow()); + assertEquals(2, ((CellRange)ranges.get(3)).getFirstColumn()); + assertEquals(3, ((CellRange)ranges.get(3)).getLastColumn()); + assertEquals(recordData.length+4, record.getRecordSize()); + + byte[] output = record.serialize(); + + assertEquals("Output size", recordData.length+4, output.length); //includes sid+recordlength + + for (int i = 0; i < recordData.length;i++) + { + assertEquals("CFHeaderRecord doesn't match", recordData[i], output[i+4]); + } + } + + + public static void main(String[] ignored_args) + { + System.out.println("Testing org.apache.poi.hssf.record.CFHeaderRecord"); + junit.textui.TestRunner.run(TestCFHeaderRecord.class); + } + +} diff --git a/src/testcases/org/apache/poi/hssf/record/TestCFRuleRecord.java b/src/testcases/org/apache/poi/hssf/record/TestCFRuleRecord.java new file mode 100644 index 0000000000..77731d7812 --- /dev/null +++ b/src/testcases/org/apache/poi/hssf/record/TestCFRuleRecord.java @@ -0,0 +1,296 @@ +/* ==================================================================== + Licensed to the Apache Software Foundation (ASF) under one or more + contributor license agreements. See the NOTICE file distributed with + this work for additional information regarding copyright ownership. + The ASF licenses this file to You under the Apache License, Version 2.0 + (the "License"); you may not use this file except in compliance with + the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +==================================================================== */ + +package org.apache.poi.hssf.record; + +import junit.framework.TestCase; + +import org.apache.poi.hssf.record.cf.BorderFormatting; +import org.apache.poi.hssf.record.cf.FontFormatting; +import org.apache.poi.hssf.record.cf.PatternFormatting; +import org.apache.poi.hssf.util.HSSFColor; + +/** + * Tests the serialization and deserialization of the TestCFRuleRecord + * class works correctly. + * + * @author Dmitriy Kumshayev + */ +public class TestCFRuleRecord + extends TestCase +{ + + public TestCFRuleRecord(String name) + { + super(name); + } + + public void testCreateCFRuleRecord () + { + CFRuleRecord record = new CFRuleRecord(); + testCFRuleRecord(record); + + // Serialize + byte [] serializedRecord = record.serialize(); + + // Strip header + byte [] recordData = new byte[serializedRecord.length-4]; + System.arraycopy(serializedRecord, 4, recordData, 0, recordData.length); + + // Deserialize + record = new CFRuleRecord(new TestcaseRecordInputStream(CFRuleRecord.sid, (short)recordData.length, recordData)); + + // Serialize again + byte[] output = record.serialize(); + + // Compare + assertEquals("Output size", recordData.length+4, output.length); //includes sid+recordlength + + for (int i = 0; i < recordData.length;i++) + { + assertEquals("CFRuleRecord doesn't match", recordData[i], output[i+4]); + } + } + + private void testCFRuleRecord(CFRuleRecord record) + { + FontFormatting fontFormatting = new FontFormatting(); + testFontFormattingAccessors(fontFormatting); + assertFalse(record.containsFontFormattingBlock()); + record.setFontFormatting(fontFormatting); + assertTrue(record.containsFontFormattingBlock()); + + BorderFormatting borderFormatting = new BorderFormatting(); + testBorderFormattingAccessors(borderFormatting); + assertFalse(record.containsBorderFormattingBlock()); + record.setBorderFormatting(borderFormatting); + assertTrue(record.containsBorderFormattingBlock()); + + assertFalse(record.isLeftBorderModified()); + record.setLeftBorderModified(true); + assertTrue(record.isLeftBorderModified()); + + assertFalse(record.isRightBorderModified()); + record.setRightBorderModified(true); + assertTrue(record.isRightBorderModified()); + + assertFalse(record.isTopBorderModified()); + record.setTopBorderModified(true); + assertTrue(record.isTopBorderModified()); + + assertFalse(record.isBottomBorderModified()); + record.setBottomBorderModified(true); + assertTrue(record.isBottomBorderModified()); + + assertFalse(record.isTopLeftBottomRightBorderModified()); + record.setTopLeftBottomRightBorderModified(true); + assertTrue(record.isTopLeftBottomRightBorderModified()); + + assertFalse(record.isBottomLeftTopRightBorderModified()); + record.setBottomLeftTopRightBorderModified(true); + assertTrue(record.isBottomLeftTopRightBorderModified()); + + + PatternFormatting patternFormatting = new PatternFormatting(); + testPatternFormattingAccessors(patternFormatting); + assertFalse(record.containsPatternFormattingBlock()); + record.setPatternFormatting(patternFormatting); + assertTrue(record.containsPatternFormattingBlock()); + + assertFalse(record.isPatternBackgroundColorModified()); + record.setPatternBackgroundColorModified(true); + assertTrue(record.isPatternBackgroundColorModified()); + + assertFalse(record.isPatternColorModified()); + record.setPatternColorModified(true); + assertTrue(record.isPatternColorModified()); + + assertFalse(record.isPatternStyleModified()); + record.setPatternStyleModified(true); + assertTrue(record.isPatternStyleModified()); + } + + private void testPatternFormattingAccessors(PatternFormatting patternFormatting) + { + patternFormatting.setFillBackgroundColor(HSSFColor.GREEN.index); + assertEquals(HSSFColor.GREEN.index,patternFormatting.getFillBackgroundColor()); + + patternFormatting.setFillForegroundColor(HSSFColor.INDIGO.index); + assertEquals(HSSFColor.INDIGO.index,patternFormatting.getFillForegroundColor()); + + patternFormatting.setFillPattern(PatternFormatting.DIAMONDS); + assertEquals(PatternFormatting.DIAMONDS,patternFormatting.getFillPattern()); + + } + + private void testBorderFormattingAccessors(BorderFormatting borderFormatting) + { + borderFormatting.setBackwardDiagonalOn(false); + assertFalse(borderFormatting.isBackwardDiagonalOn()); + borderFormatting.setBackwardDiagonalOn(true); + assertTrue(borderFormatting.isBackwardDiagonalOn()); + + borderFormatting.setBorderBottom(BorderFormatting.BORDER_DOTTED); + assertEquals(BorderFormatting.BORDER_DOTTED, borderFormatting.getBorderBottom()); + + borderFormatting.setBorderDiagonal(BorderFormatting.BORDER_MEDIUM); + assertEquals(BorderFormatting.BORDER_MEDIUM, borderFormatting.getBorderDiagonal()); + + borderFormatting.setBorderLeft(BorderFormatting.BORDER_MEDIUM_DASH_DOT_DOT); + assertEquals(BorderFormatting.BORDER_MEDIUM_DASH_DOT_DOT, borderFormatting.getBorderLeft()); + + borderFormatting.setBorderRight(BorderFormatting.BORDER_MEDIUM_DASHED); + assertEquals(BorderFormatting.BORDER_MEDIUM_DASHED, borderFormatting.getBorderRight()); + + borderFormatting.setBorderTop(BorderFormatting.BORDER_HAIR); + assertEquals(BorderFormatting.BORDER_HAIR, borderFormatting.getBorderTop()); + + borderFormatting.setBottomBorderColor(HSSFColor.AQUA.index); + assertEquals(HSSFColor.AQUA.index, borderFormatting.getBottomBorderColor()); + + borderFormatting.setDiagonalBorderColor(HSSFColor.RED.index); + assertEquals(HSSFColor.RED.index, borderFormatting.getDiagonalBorderColor()); + + assertFalse(borderFormatting.isForwardDiagonalOn()); + borderFormatting.setForwardDiagonalOn(true); + assertTrue(borderFormatting.isForwardDiagonalOn()); + + borderFormatting.setLeftBorderColor(HSSFColor.BLACK.index); + assertEquals(HSSFColor.BLACK.index, borderFormatting.getLeftBorderColor()); + + borderFormatting.setRightBorderColor(HSSFColor.BLUE.index); + assertEquals(HSSFColor.BLUE.index, borderFormatting.getRightBorderColor()); + + borderFormatting.setTopBorderColor(HSSFColor.GOLD.index); + assertEquals(HSSFColor.GOLD.index, borderFormatting.getTopBorderColor()); + } + + + private void testFontFormattingAccessors(FontFormatting fontFormatting) + { + // Check for defaults + assertFalse(fontFormatting.isEscapementTypeModified()); + assertFalse(fontFormatting.isFontCancellationModified()); + assertFalse(fontFormatting.isFontCondenseModified()); + assertFalse(fontFormatting.isFontOutlineModified()); + assertFalse(fontFormatting.isFontShadowModified()); + assertFalse(fontFormatting.isFontStyleModified()); + assertFalse(fontFormatting.isUnderlineTypeModified()); + + assertFalse(fontFormatting.isBold()); + assertFalse(fontFormatting.isCondenseOn()); + assertFalse(fontFormatting.isItalic()); + assertFalse(fontFormatting.isOutlineOn()); + assertFalse(fontFormatting.isShadowOn()); + assertFalse(fontFormatting.isStruckout()); + + assertEquals(0, fontFormatting.getEscapementType()); + assertEquals(-1, fontFormatting.getFontColorIndex()); + assertEquals(-1, fontFormatting.getFontHeight()); + assertEquals(400, fontFormatting.getFontWeight()); + assertEquals(0, fontFormatting.getUnderlineType()); + + fontFormatting.setBold(true); + assertTrue(fontFormatting.isBold()); + fontFormatting.setBold(false); + assertFalse(fontFormatting.isBold()); + + fontFormatting.setCondense(true); + assertTrue(fontFormatting.isCondenseOn()); + fontFormatting.setCondense(false); + assertFalse(fontFormatting.isCondenseOn()); + + fontFormatting.setEscapementType(FontFormatting.SS_SUB); + assertEquals(FontFormatting.SS_SUB, fontFormatting.getEscapementType()); + fontFormatting.setEscapementType(FontFormatting.SS_SUPER); + assertEquals(FontFormatting.SS_SUPER, fontFormatting.getEscapementType()); + fontFormatting.setEscapementType(FontFormatting.SS_NONE); + assertEquals(FontFormatting.SS_NONE, fontFormatting.getEscapementType()); + + fontFormatting.setEscapementTypeModified(false); + assertFalse(fontFormatting.isEscapementTypeModified()); + fontFormatting.setEscapementTypeModified(true); + assertTrue(fontFormatting.isEscapementTypeModified()); + + fontFormatting.setFontCancellationModified(false); + assertFalse(fontFormatting.isFontCancellationModified()); + fontFormatting.setFontCancellationModified(true); + assertTrue(fontFormatting.isFontCancellationModified()); + + fontFormatting.setFontColorIndex((short)10); + assertEquals(10,fontFormatting.getFontColorIndex()); + + fontFormatting.setFontCondenseModified(false); + assertFalse(fontFormatting.isFontCondenseModified()); + fontFormatting.setFontCondenseModified(true); + assertTrue(fontFormatting.isFontCondenseModified()); + + fontFormatting.setFontHeight((short)100); + assertEquals(100,fontFormatting.getFontHeight()); + + fontFormatting.setFontOutlineModified(false); + assertFalse(fontFormatting.isFontOutlineModified()); + fontFormatting.setFontOutlineModified(true); + assertTrue(fontFormatting.isFontOutlineModified()); + + fontFormatting.setFontShadowModified(false); + assertFalse(fontFormatting.isFontShadowModified()); + fontFormatting.setFontShadowModified(true); + assertTrue(fontFormatting.isFontShadowModified()); + + fontFormatting.setFontStyleModified(false); + assertFalse(fontFormatting.isFontStyleModified()); + fontFormatting.setFontStyleModified(true); + assertTrue(fontFormatting.isFontStyleModified()); + + fontFormatting.setItalic(false); + assertFalse(fontFormatting.isItalic()); + fontFormatting.setItalic(true); + assertTrue(fontFormatting.isItalic()); + + fontFormatting.setOutline(false); + assertFalse(fontFormatting.isOutlineOn()); + fontFormatting.setOutline(true); + assertTrue(fontFormatting.isOutlineOn()); + + fontFormatting.setShadow(false); + assertFalse(fontFormatting.isShadowOn()); + fontFormatting.setShadow(true); + assertTrue(fontFormatting.isShadowOn()); + + fontFormatting.setStrikeout(false); + assertFalse(fontFormatting.isStruckout()); + fontFormatting.setStrikeout(true); + assertTrue(fontFormatting.isStruckout()); + + fontFormatting.setUnderlineType(FontFormatting.U_DOUBLE_ACCOUNTING); + assertEquals(FontFormatting.U_DOUBLE_ACCOUNTING, fontFormatting.getUnderlineType()); + + fontFormatting.setUnderlineTypeModified(false); + assertFalse(fontFormatting.isUnderlineTypeModified()); + fontFormatting.setUnderlineTypeModified(true); + assertTrue(fontFormatting.isUnderlineTypeModified()); + } + + + public static void main(String[] ignored_args) + { + System.out.println("Testing org.apache.poi.hssf.record.CFRuleRecord"); + junit.textui.TestRunner.run(TestCFRuleRecord.class); + } + +} diff --git a/src/testcases/org/apache/poi/hssf/record/aggregates/TestCFRecordsAggregate.java b/src/testcases/org/apache/poi/hssf/record/aggregates/TestCFRecordsAggregate.java new file mode 100644 index 0000000000..332c99209f --- /dev/null +++ b/src/testcases/org/apache/poi/hssf/record/aggregates/TestCFRecordsAggregate.java @@ -0,0 +1,111 @@ +/* ==================================================================== + Licensed to the Apache Software Foundation (ASF) under one or more + contributor license agreements. See the NOTICE file distributed with + this work for additional information regarding copyright ownership. + The ASF licenses this file to You under the Apache License, Version 2.0 + (the "License"); you may not use this file except in compliance with + the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +==================================================================== */ + +package org.apache.poi.hssf.record.aggregates; + +import java.io.ByteArrayInputStream; +import java.io.InputStream; +import java.util.ArrayList; +import java.util.List; + +import junit.framework.TestCase; + +import org.apache.poi.hssf.record.CFHeaderRecord; +import org.apache.poi.hssf.record.CFRuleRecord; +import org.apache.poi.hssf.record.RecordFactory; +import org.apache.poi.hssf.record.cf.CellRange; + +/** + * Tests the serialization and deserialization of the CFRecordsAggregate + * class works correctly. + * + * @author Dmitriy Kumshayev + */ +public class TestCFRecordsAggregate + extends TestCase +{ + + public TestCFRecordsAggregate(String name) + { + super(name); + } + + public void testCFRecordsAggregate() + { + CFRecordsAggregate record = new CFRecordsAggregate(); + List recs = new ArrayList(); + CFHeaderRecord header = new CFHeaderRecord(); + CFRuleRecord rule1 = new CFRuleRecord(); + CFRuleRecord rule2 = new CFRuleRecord(); + CFRuleRecord rule3 = new CFRuleRecord(); + header.setNumberOfConditionalFormats(3); + CellRange range1 = new CellRange(0,1,(short)0,(short)0); + CellRange range2 = new CellRange(0,1,(short)2,(short)2); + List cellRanges = new ArrayList(); + cellRanges.add(range1); + cellRanges.add(range2); + header.setCellRanges(cellRanges); + recs.add(header); + recs.add(rule1); + recs.add(rule2); + recs.add(rule3); + record = CFRecordsAggregate.createCFAggregate(recs, 0); + + // Serialize + byte [] serializedRecord = record.serialize(); + InputStream in = new ByteArrayInputStream(serializedRecord); + + //Parse + recs = RecordFactory.createRecords(in); + + // Verify + assertNotNull(recs); + assertEquals(4, recs.size()); + + header = (CFHeaderRecord)recs.get(0); + rule1 = (CFRuleRecord)recs.get(1); + rule2 = (CFRuleRecord)recs.get(2); + rule3 = (CFRuleRecord)recs.get(3); + cellRanges = header.getCellRanges(); + + assertEquals(2, cellRanges.size()); + assertEquals(3, header.getNumberOfConditionalFormats()); + + record = CFRecordsAggregate.createCFAggregate(recs, 0); + + record = record.cloneCFAggregate(); + + assertNotNull(record.getHeader()); + assertEquals(3,record.getRules().size()); + + header = record.getHeader(); + rule1 = (CFRuleRecord)record.getRules().get(0); + rule2 = (CFRuleRecord)record.getRules().get(1); + rule3 = (CFRuleRecord)record.getRules().get(2); + cellRanges = header.getCellRanges(); + + assertEquals(2, cellRanges.size()); + assertEquals(3, header.getNumberOfConditionalFormats()); + } + + public static void main(String[] ignored_args) + { + System.out.println("Testing org.apache.poi.hssf.record.aggregates.CFRecordsAggregate"); + junit.textui.TestRunner.run(TestCFRecordsAggregate.class); + } + +} diff --git a/src/testcases/org/apache/poi/hssf/record/cf/TestCellRange.java b/src/testcases/org/apache/poi/hssf/record/cf/TestCellRange.java new file mode 100644 index 0000000000..f9857fb248 --- /dev/null +++ b/src/testcases/org/apache/poi/hssf/record/cf/TestCellRange.java @@ -0,0 +1,139 @@ +/* ==================================================================== +Licensed to the Apache Software Foundation (ASF) under one or more +contributor license agreements. See the NOTICE file distributed with +this work for additional information regarding copyright ownership. +The ASF licenses this file to You under the Apache License, Version 2.0 +(the "License"); you may not use this file except in compliance with +the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +==================================================================== */ + +package org.apache.poi.hssf.record.cf; + +import junit.framework.TestCase; + +/** + * Tests CellRange operations. + */ +public class TestCellRange extends TestCase +{ + private static final CellRange biggest = new CellRange(0, -1,(short) 0,(short)-1); + private static final CellRange tenthColumn = new CellRange(0, -1,(short)10,(short)10); + private static final CellRange tenthRow = new CellRange(10,10,(short) 0,(short)-1); + private static final CellRange box10x10 = new CellRange(0, 10,(short) 0,(short)10); + private static final CellRange box9x9 = new CellRange(0, 9,(short) 0,(short) 9); + private static final CellRange box10to20c = new CellRange(0, 10,(short)10,(short)20); + private static final CellRange oneCell = new CellRange(10,10,(short)10,(short)10); + + boolean [][] contanis = new boolean[][] + { + // biggest, tenthColumn, tenthRow, box10x10, box9x9, box10to20c, oneCell + /*biggest */ new boolean[]{true, true , true , true , true , true , true}, + /*tenthColumn*/ new boolean[]{false, true , false, false, false, false, true}, + /*tenthRow */ new boolean[]{false, false, true , false, false, false, true}, + /*box10x10 */ new boolean[]{false, false, false, true , true , false, true}, + /*box9x9 */ new boolean[]{false, false, false, false, true , false, false}, + /*box10to20c */ new boolean[]{false, false, false, false, false, true , true}, + /*oneCell */ new boolean[]{false, false, false, false, false, false, true}, + } ; + + + public void testContainsMethod() + { + CellRange [] ranges = new CellRange[]{biggest,tenthColumn,tenthRow,box10x10,box9x9,box10to20c,oneCell}; + testContainsMethod(contanis,ranges); + } + + private void testContainsMethod(boolean[][]contains,CellRange[] ranges) + { + for(int i=0; i!=ranges.length;i++) + { + for(int j=0; j!=ranges.length;j++) + { + assertEquals("("+i+","+j+"): ",contains[i][j],ranges[i].contains(ranges[j])); + } + } + } + + private static final CellRange col1 = new CellRange(0, -1,(short) 1,(short)1); + private static final CellRange col2 = new CellRange(0, -1,(short) 2,(short)2); + private static final CellRange row1 = new CellRange(1, 1,(short) 0,(short)-1); + private static final CellRange row2 = new CellRange(2, 2,(short) 0,(short)-1); + + private static final CellRange box0 = new CellRange( 0, 2,(short) 0,(short)2); + private static final CellRange box1 = new CellRange( 0, 1,(short) 0,(short)1); + private static final CellRange box2 = new CellRange( 0, 1,(short) 2,(short)3); + private static final CellRange box3 = new CellRange( 2, 3,(short) 0,(short)1); + private static final CellRange box4 = new CellRange( 2, 3,(short) 2,(short)3); + private static final CellRange box5 = new CellRange( 1, 3,(short) 1,(short)3); + + public void testHasSharedBorderMethod() + { + assertFalse(col1.hasSharedBorder(col1)); + assertFalse(col2.hasSharedBorder(col2)); + assertTrue(col1.hasSharedBorder(col2)); + assertTrue(col2.hasSharedBorder(col1)); + + assertFalse(row1.hasSharedBorder(row1)); + assertFalse(row2.hasSharedBorder(row2)); + assertTrue(row1.hasSharedBorder(row2)); + assertTrue(row2.hasSharedBorder(row1)); + + assertFalse(row1.hasSharedBorder(col1)); + assertFalse(row1.hasSharedBorder(col2)); + assertFalse(col1.hasSharedBorder(row1)); + assertFalse(col2.hasSharedBorder(row1)); + assertFalse(row2.hasSharedBorder(col1)); + assertFalse(row2.hasSharedBorder(col2)); + assertFalse(col1.hasSharedBorder(row2)); + assertFalse(col2.hasSharedBorder(row2)); + assertTrue(col2.hasSharedBorder(col1)); + + assertFalse(box1.hasSharedBorder(box1)); + assertTrue(box1.hasSharedBorder(box2)); + assertTrue(box1.hasSharedBorder(box3)); + assertFalse(box1.hasSharedBorder(box4)); + + assertTrue(box2.hasSharedBorder(box1)); + assertFalse(box2.hasSharedBorder(box2)); + assertFalse(box2.hasSharedBorder(box3)); + assertTrue(box2.hasSharedBorder(box4)); + + assertTrue(box3.hasSharedBorder(box1)); + assertFalse(box3.hasSharedBorder(box2)); + assertFalse(box3.hasSharedBorder(box3)); + assertTrue(box3.hasSharedBorder(box4)); + + assertFalse(box4.hasSharedBorder(box1)); + assertTrue(box4.hasSharedBorder(box2)); + assertTrue(box4.hasSharedBorder(box3)); + assertFalse(box4.hasSharedBorder(box4)); + } + + public void testIntersectMethod() + { + assertEquals( CellRange.OVERLAP,box0.intersect(box5)); + assertEquals( CellRange.OVERLAP,box5.intersect(box0)); + assertEquals(CellRange.NO_INTERSECTION,box1.intersect(box4)); + assertEquals(CellRange.NO_INTERSECTION,box4.intersect(box1)); + assertEquals(CellRange.NO_INTERSECTION,box2.intersect(box3)); + assertEquals(CellRange.NO_INTERSECTION,box3.intersect(box2)); + assertEquals(CellRange.INSIDE,box0.intersect(box1)); + assertEquals(CellRange.INSIDE,box0.intersect(box0)); + assertEquals(CellRange.ENCLOSES,box1.intersect(box0)); + assertEquals(CellRange.INSIDE,tenthColumn.intersect(oneCell)); + assertEquals(CellRange.ENCLOSES,oneCell.intersect(tenthColumn)); + assertEquals(CellRange.OVERLAP,tenthColumn.intersect(tenthRow)); + assertEquals(CellRange.OVERLAP,tenthRow.intersect(tenthColumn)); + assertEquals(CellRange.INSIDE,tenthColumn.intersect(tenthColumn)); + assertEquals(CellRange.INSIDE,tenthRow.intersect(tenthRow)); + } + +} diff --git a/src/testcases/org/apache/poi/hssf/usermodel/TestBugs.java b/src/testcases/org/apache/poi/hssf/usermodel/TestBugs.java index f06f591c42..05ba29d09e 100644 --- a/src/testcases/org/apache/poi/hssf/usermodel/TestBugs.java +++ b/src/testcases/org/apache/poi/hssf/usermodel/TestBugs.java @@ -1035,6 +1035,28 @@ extends TestCase { } /** + * Bug 41546: Constructing HSSFWorkbook is failed, + * Unknown Ptg in Formula: 0x1a (26) + */ + public void test41546() throws Exception { + FileInputStream in = new FileInputStream(new File(cwd, "41546.xls")); + HSSFWorkbook wb = new HSSFWorkbook(in); + in.close(); + + assertTrue("No Exceptions while reading file", true); + assertEquals(1, wb.getNumberOfSheets()); + + //serialize and read again + ByteArrayOutputStream out = new ByteArrayOutputStream(); + wb.write(out); + out.close(); + + wb = new HSSFWorkbook(new ByteArrayInputStream(out.toByteArray())); + assertTrue("No Exceptions while reading file", true); + assertEquals(1, wb.getNumberOfSheets()); + } + + /** * Bug 42564: Some files from Access were giving a RecordFormatException * when reading the BOFRecord */ @@ -1115,6 +1137,20 @@ extends TestCase { } /** + * Something up with the FileSharingRecord + */ + public void test43251() throws Exception { + FileInputStream in = new FileInputStream(new File(cwd, "43251.xls")); + + // Used to blow up with an IllegalArgumentException + // when creating a FileSharingRecord + HSSFWorkbook wb = new HSSFWorkbook(in); + in.close(); + + assertEquals(1, wb.getNumberOfSheets()); + } + + /** * Crystal reports generates files with short * StyleRecords, which is against the spec */ @@ -1157,7 +1193,7 @@ extends TestCase { * probably due to dropdowns */ public void test44593() throws Exception { - FileInputStream in = new FileInputStream(new File(cwd, "Bug44593.xls")); + FileInputStream in = new FileInputStream(new File(cwd, "44593.xls")); // Used to blow up with an IllegalArgumentException // when creating a DVRecord @@ -1168,6 +1204,20 @@ extends TestCase { assertEquals(2, wb.getNumberOfSheets()); } + + /** + * Used to give problems due to trying to read a zero + * length string, but that's now properly handled + */ + public void test44643() throws Exception { + FileInputStream in = new FileInputStream(new File(cwd, "44643.xls")); + + // Used to blow up with an IllegalArgumentException + HSSFWorkbook wb = new HSSFWorkbook(in); + in.close(); + + assertEquals(1, wb.getNumberOfSheets()); + } } diff --git a/src/testcases/org/apache/poi/poifs/storage/TestRawDataBlock.java b/src/testcases/org/apache/poi/poifs/storage/TestRawDataBlock.java index 4c84f04b71..73ddcad543 100644 --- a/src/testcases/org/apache/poi/poifs/storage/TestRawDataBlock.java +++ b/src/testcases/org/apache/poi/poifs/storage/TestRawDataBlock.java @@ -36,23 +36,23 @@ import junit.framework.*; public class TestRawDataBlock extends TestCase { + static { + // We always want to use our own + // logger + System.setProperty( + "org.apache.poi.util.POILogger", + "org.apache.poi.util.DummyPOILogger" + ); + } /** * Constructor TestRawDataBlock * * @param name */ - public TestRawDataBlock(String name) { super(name); - - // We always want to use our own - // logger - System.setProperty( - "org.apache.poi.util.POILogger", - "org.apache.poi.util.DummyPOILogger" - ); } /** diff --git a/src/testcases/org/apache/poi/poifs/storage/TestRawDataBlockList.java b/src/testcases/org/apache/poi/poifs/storage/TestRawDataBlockList.java index d151029762..0f65c0e8a4 100644 --- a/src/testcases/org/apache/poi/poifs/storage/TestRawDataBlockList.java +++ b/src/testcases/org/apache/poi/poifs/storage/TestRawDataBlockList.java @@ -36,23 +36,23 @@ import junit.framework.*; public class TestRawDataBlockList extends TestCase { + static { + // We always want to use our own + // logger + System.setProperty( + "org.apache.poi.util.POILogger", + "org.apache.poi.util.DummyPOILogger" + ); + } /** * Constructor TestRawDataBlockList * * @param name */ - public TestRawDataBlockList(String name) { super(name); - - // We always want to use our own - // logger - System.setProperty( - "org.apache.poi.util.POILogger", - "org.apache.poi.util.DummyPOILogger" - ); } /** @@ -60,7 +60,6 @@ public class TestRawDataBlockList * * @exception IOException */ - public void testNormalConstructor() throws IOException { |