aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorNick Burch <nick@apache.org>2008-03-29 17:00:47 +0000
committerNick Burch <nick@apache.org>2008-03-29 17:00:47 +0000
commitfb33f585f596d2d149409e5c88e8f4a7ea47921a (patch)
treef2c19ddae637adbb346872a08a362f3f97cef572
parentcfe2e40f4b62ec7bd8ad8b183322e852c91ca4d0 (diff)
downloadpoi-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
-rw-r--r--src/documentation/content/xdocs/changes.xml3
-rw-r--r--src/documentation/content/xdocs/status.xml3
-rw-r--r--src/java/org/apache/poi/hssf/model/Sheet.java73
-rw-r--r--src/java/org/apache/poi/hssf/record/CFHeaderRecord.java223
-rw-r--r--src/java/org/apache/poi/hssf/record/CFRuleRecord.java657
-rw-r--r--src/java/org/apache/poi/hssf/record/RecordFactory.java2
-rwxr-xr-xsrc/java/org/apache/poi/hssf/record/RecordInputStream.java5
-rwxr-xr-xsrc/java/org/apache/poi/hssf/record/SharedFormulaRecord.java42
-rw-r--r--src/java/org/apache/poi/hssf/record/aggregates/CFRecordsAggregate.java224
-rw-r--r--src/java/org/apache/poi/hssf/record/cf/BorderFormatting.java560
-rw-r--r--src/java/org/apache/poi/hssf/record/cf/CellRange.java259
-rw-r--r--src/java/org/apache/poi/hssf/record/cf/FontFormatting.java591
-rw-r--r--src/java/org/apache/poi/hssf/record/cf/PatternFormatting.java206
-rw-r--r--src/java/org/apache/poi/hssf/record/formula/RefVPtg.java1
-rw-r--r--src/java/org/apache/poi/hssf/usermodel/HSSFBorderFormatting.java128
-rw-r--r--src/java/org/apache/poi/hssf/usermodel/HSSFCellStyle.java12
-rw-r--r--src/java/org/apache/poi/hssf/usermodel/HSSFConditionalFormatting.java201
-rw-r--r--src/java/org/apache/poi/hssf/usermodel/HSSFConditionalFormattingRule.java248
-rw-r--r--src/java/org/apache/poi/hssf/usermodel/HSSFFontFormatting.java456
-rw-r--r--src/java/org/apache/poi/hssf/usermodel/HSSFPatternFormatting.java134
-rw-r--r--src/java/org/apache/poi/hssf/usermodel/HSSFSheet.java158
-rw-r--r--src/java/org/apache/poi/util/POILogFactory.java71
-rw-r--r--src/scratchpad/src/org/apache/poi/hssf/usermodel/HSSFFormulaEvaluator.java30
-rw-r--r--src/scratchpad/testcases/org/apache/poi/hssf/usermodel/TestFormulaEvaluatorBugs.java88
-rw-r--r--src/testcases/org/apache/poi/hssf/data/41546.xlsbin0 -> 18432 bytes
-rw-r--r--src/testcases/org/apache/poi/hssf/data/43251.xlsbin0 -> 166400 bytes
-rw-r--r--src/testcases/org/apache/poi/hssf/data/44593.xls (renamed from src/testcases/org/apache/poi/hssf/data/Bug44593.xls)bin2586112 -> 2586112 bytes
-rw-r--r--src/testcases/org/apache/poi/hssf/data/44636.xlsbin0 -> 13824 bytes
-rw-r--r--src/testcases/org/apache/poi/hssf/data/44643.xlsbin0 -> 15872 bytes
-rw-r--r--src/testcases/org/apache/poi/hssf/record/TestCFHeaderRecord.java145
-rw-r--r--src/testcases/org/apache/poi/hssf/record/TestCFRuleRecord.java296
-rw-r--r--src/testcases/org/apache/poi/hssf/record/aggregates/TestCFRecordsAggregate.java111
-rw-r--r--src/testcases/org/apache/poi/hssf/record/cf/TestCellRange.java139
-rw-r--r--src/testcases/org/apache/poi/hssf/usermodel/TestBugs.java52
-rw-r--r--src/testcases/org/apache/poi/poifs/storage/TestRawDataBlock.java16
-rw-r--r--src/testcases/org/apache/poi/poifs/storage/TestRawDataBlockList.java17
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
new file mode 100644
index 0000000000..1332f3eef5
--- /dev/null
+++ b/src/testcases/org/apache/poi/hssf/data/41546.xls
Binary files differ
diff --git a/src/testcases/org/apache/poi/hssf/data/43251.xls b/src/testcases/org/apache/poi/hssf/data/43251.xls
new file mode 100644
index 0000000000..abc476ab0f
--- /dev/null
+++ b/src/testcases/org/apache/poi/hssf/data/43251.xls
Binary files differ
diff --git a/src/testcases/org/apache/poi/hssf/data/Bug44593.xls b/src/testcases/org/apache/poi/hssf/data/44593.xls
index 84d1311441..84d1311441 100644
--- a/src/testcases/org/apache/poi/hssf/data/Bug44593.xls
+++ b/src/testcases/org/apache/poi/hssf/data/44593.xls
Binary files differ
diff --git a/src/testcases/org/apache/poi/hssf/data/44636.xls b/src/testcases/org/apache/poi/hssf/data/44636.xls
new file mode 100644
index 0000000000..3108a620b2
--- /dev/null
+++ b/src/testcases/org/apache/poi/hssf/data/44636.xls
Binary files differ
diff --git a/src/testcases/org/apache/poi/hssf/data/44643.xls b/src/testcases/org/apache/poi/hssf/data/44643.xls
new file mode 100644
index 0000000000..7ae5071864
--- /dev/null
+++ b/src/testcases/org/apache/poi/hssf/data/44643.xls
Binary files differ
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
{