diff --git a/src/documentation/content/xdocs/changes.xml b/src/documentation/content/xdocs/changes.xml
index 4bfd32b0e..b1504a702 100644
--- a/src/documentation/content/xdocs/changes.xml
+++ b/src/documentation/content/xdocs/changes.xml
@@ -36,6 +36,9 @@
+ *
+ * OVERLAP - both ranges partially overlap;
+ * INSIDE - the specified range is inside of this one
+ * ENCLOSES - the specified range encloses this range
+ */
+ 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 000000000..1e6abee7c
--- /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 000000000..3157bf46c
--- /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 8a6b2c03b..75c634890 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 000000000..622f3a674
--- /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 d0d29b5b7..11d14782b 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 000000000..e5fbb1d30
--- /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:
+ *
+ *
This method could be used to copy HSSFConditionalFormatting object + * from one sheet to another. For example: + *
+ * HSSFConditionalFormatting cf = sheet.getConditionalFormattingAt(index); + * newSheet.addConditionalFormatting(cf); + *+ * + * @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 74ea822a5..a9ce66f36 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 (_loggers.containsKey(cat)) - { - logger = ( POILogger ) _loggers.get(cat); + + // 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(); + } } - else - { - try{ - String loggerClassName = System.getProperty("org.apache.poi.util.POILogger"); - Class loggerClass = Class.forName(loggerClassName); + + // Short circuit for the null logger, which + // ignores all categories + if(_loggerClassName.equals(_nullLogger.getClass().getName())) { + return _nullLogger; + } + + + // Fetch the right logger for them, creating + // it if that's required + if (_loggers.containsKey(cat)) { + logger = ( POILogger ) _loggers.get(cat); + } else { + try { + Class loggerClass = Class.forName(_loggerClassName); logger = ( POILogger ) loggerClass.newInstance(); - } - catch(Exception e){ - - logger = new NullLogger(); + logger.initialize(cat); + } catch(Exception e) { + // Give up and use the null logger + logger = _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 58ab5b47a..bb16fdfad 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