* Conditional Formatting Header v12 record CFHEADER12 (0x0879),
* for conditional formattings introduced in Excel 2007 and newer.
*/
-public final class CFHeader12Record extends CFHeaderRecord {
+public final class CFHeader12Record extends CFHeaderBase {
public static final short sid = 0x0879;
private FtrHeader futureHeader;
/** Creates new CFHeaderRecord */
public CFHeader12Record() {
- super();
+ createEmpty();
futureHeader = new FtrHeader();
futureHeader.setRecordType(sid);
}
futureHeader = new FtrHeader();
futureHeader.setRecordType(sid);
}
-
- public CFHeader12Record(RecordInputStream in)
- {
+ public CFHeader12Record(RecordInputStream in) {
futureHeader = new FtrHeader(in);
read(in);
}
public Object clone() {
CFHeader12Record result = new CFHeader12Record();
result.futureHeader = (FtrHeader)futureHeader.clone();
- // TODO Clone the rest via the base
+ super.copyTo(result);
return result;
}
}
--- /dev/null
+/* ====================================================================
+ 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 org.apache.poi.hssf.record.cf.CellRangeUtil;
+import org.apache.poi.ss.util.CellRangeAddress;
+import org.apache.poi.ss.util.CellRangeAddressList;
+import org.apache.poi.util.LittleEndianOutput;
+
+/**
+ * Parent of Conditional Formatting Header records,
+ * {@link CFHeaderRecord} and {@link CFHeader12Record}.
+ */
+public abstract class CFHeaderBase extends StandardRecord {
+ private int field_1_numcf;
+ private int field_2_need_recalculation_and_id;
+ private CellRangeAddress field_3_enclosing_cell_range;
+ private CellRangeAddressList field_4_cell_ranges;
+
+ /** Creates new CFHeaderBase */
+ protected CFHeaderBase() {
+ }
+ protected CFHeaderBase(CellRangeAddress[] regions, int nRules) {
+ CellRangeAddress[] unmergedRanges = regions;
+ CellRangeAddress[] mergeCellRanges = CellRangeUtil.mergeCellRanges(unmergedRanges);
+ setCellRanges(mergeCellRanges);
+ field_1_numcf = nRules;
+ }
+
+ protected void createEmpty() {
+ field_3_enclosing_cell_range = new CellRangeAddress(0, 0, 0, 0);
+ field_4_cell_ranges = new CellRangeAddressList();
+ }
+ protected void read(RecordInputStream in) {
+ field_1_numcf = in.readShort();
+ field_2_need_recalculation_and_id = in.readShort();
+ field_3_enclosing_cell_range = new CellRangeAddress(in);
+ field_4_cell_ranges = new CellRangeAddressList(in);
+ }
+
+ public int getNumberOfConditionalFormats() {
+ return field_1_numcf;
+ }
+ public void setNumberOfConditionalFormats(int n) {
+ field_1_numcf=n;
+ }
+
+ public boolean getNeedRecalculation() {
+ // Held on the 1st bit
+ return field_2_need_recalculation_and_id % 2 == 1;
+ }
+ public void setNeedRecalculation(boolean b) {
+ // held on the first bit
+ if (b == getNeedRecalculation()) return;
+ if (b) field_2_need_recalculation_and_id++;
+ else field_2_need_recalculation_and_id--;
+ }
+
+ public int getID() {
+ // Remaining 15 bits of field 2
+ return field_2_need_recalculation_and_id>>1;
+ }
+ public void setID(int id) {
+ // Remaining 15 bits of field 2
+ boolean needsRecalc = getNeedRecalculation();
+ field_2_need_recalculation_and_id = (id<<1);
+ if (needsRecalc) field_2_need_recalculation_and_id++;
+ }
+
+ public CellRangeAddress getEnclosingCellRange() {
+ return field_3_enclosing_cell_range;
+ }
+ public void setEnclosingCellRange(CellRangeAddress cr) {
+ field_3_enclosing_cell_range = cr;
+ }
+
+ /**
+ * Set cell ranges list to a single cell range and
+ * modify the enclosing cell range accordingly.
+ * @param cellRanges - list of CellRange objects
+ */
+ public void setCellRanges(CellRangeAddress[] cellRanges) {
+ if(cellRanges == null) {
+ throw new IllegalArgumentException("cellRanges must not be null");
+ }
+ CellRangeAddressList cral = new CellRangeAddressList();
+ CellRangeAddress enclosingRange = null;
+ for (int i = 0; i < cellRanges.length; i++) {
+ CellRangeAddress cr = cellRanges[i];
+ enclosingRange = CellRangeUtil.createEnclosingCellRange(cr, enclosingRange);
+ cral.addCellRangeAddress(cr);
+ }
+ field_3_enclosing_cell_range = enclosingRange;
+ field_4_cell_ranges = cral;
+ }
+
+ public CellRangeAddress[] getCellRanges() {
+ return field_4_cell_ranges.getCellRangeAddresses();
+ }
+
+ protected abstract String getRecordName();
+ public String toString() {
+ StringBuffer buffer = new StringBuffer();
+
+ buffer.append("[").append(getRecordName()).append("]\n");
+ buffer.append("\t.numCF = ").append(getNumberOfConditionalFormats()).append("\n");
+ buffer.append("\t.needRecalc = ").append(getNeedRecalculation()).append("\n");
+ buffer.append("\t.id = ").append(getID()).append("\n");
+ buffer.append("\t.enclosingCellRange= ").append(getEnclosingCellRange()).append("\n");
+ buffer.append("\t.cfranges=[");
+ for( int i=0; i<field_4_cell_ranges.countRanges(); i++) {
+ buffer.append(i==0?"":",").append(field_4_cell_ranges.getCellRangeAddress(i).toString());
+ }
+ buffer.append("]\n");
+ buffer.append("[/").append(getRecordName()).append("]\n");
+ return buffer.toString();
+ }
+
+ protected int getDataSize() {
+ return 4 // 2 short fields
+ + CellRangeAddress.ENCODED_SIZE
+ + field_4_cell_ranges.getSize();
+ }
+
+ public void serialize(LittleEndianOutput out) {
+ out.writeShort(field_1_numcf);
+ out.writeShort(field_2_need_recalculation_and_id);
+ field_3_enclosing_cell_range.serialize(out);
+ field_4_cell_ranges.serialize(out);
+ }
+
+ protected void copyTo(CFHeaderBase result) {
+ result.field_1_numcf = field_1_numcf;
+ result.field_2_need_recalculation_and_id = field_2_need_recalculation_and_id;
+ result.field_3_enclosing_cell_range = field_3_enclosing_cell_range.copy();
+ result.field_4_cell_ranges = field_4_cell_ranges.copy();
+ }
+}
package org.apache.poi.hssf.record;
-import org.apache.poi.hssf.record.cf.CellRangeUtil;
import org.apache.poi.ss.util.CellRangeAddress;
-import org.apache.poi.ss.util.CellRangeAddressList;
-import org.apache.poi.util.LittleEndianOutput;
/**
* Conditional Formatting Header record CFHEADER (0x01B0).
* Used to describe a {@link CFRuleRecord}.
* @see CFHeader12Record
- * TODO Move most of the logic into a base class
*/
-public class CFHeaderRecord extends StandardRecord {
+public final class CFHeaderRecord extends CFHeaderBase {
public static final short sid = 0x01B0;
- private int field_1_numcf;
- private int field_2_need_recalculation_and_id;
- private CellRangeAddress field_3_enclosing_cell_range;
- private CellRangeAddressList field_4_cell_ranges;
-
/** Creates new CFHeaderRecord */
public CFHeaderRecord() {
- field_3_enclosing_cell_range = new CellRangeAddress(0, 0, 0, 0);
- field_4_cell_ranges = new CellRangeAddressList();
+ createEmpty();
}
public CFHeaderRecord(CellRangeAddress[] regions, int nRules) {
- CellRangeAddress[] unmergedRanges = regions;
- CellRangeAddress[] mergeCellRanges = CellRangeUtil.mergeCellRanges(unmergedRanges);
- setCellRanges(mergeCellRanges);
- field_1_numcf = nRules;
+ super(regions, nRules);
}
public CFHeaderRecord(RecordInputStream in) {
read(in);
}
- protected void read(RecordInputStream in) {
- field_1_numcf = in.readShort();
- field_2_need_recalculation_and_id = in.readShort();
- field_3_enclosing_cell_range = new CellRangeAddress(in);
- field_4_cell_ranges = new CellRangeAddressList(in);
- }
-
- public int getNumberOfConditionalFormats() {
- return field_1_numcf;
- }
- public void setNumberOfConditionalFormats(int n) {
- field_1_numcf=n;
- }
-
- public boolean getNeedRecalculation() {
- // Held on the 1st bit
- return field_2_need_recalculation_and_id % 2 == 1;
- }
- public void setNeedRecalculation(boolean b) {
- // held on the first bit
- if (b == getNeedRecalculation()) return;
- if (b) field_2_need_recalculation_and_id++;
- else field_2_need_recalculation_and_id--;
- }
-
- public int getID() {
- // Remaining 15 bits of field 2
- return field_2_need_recalculation_and_id>>1;
- }
- public void setID(int id) {
- // Remaining 15 bits of field 2
- boolean needsRecalc = getNeedRecalculation();
- field_2_need_recalculation_and_id = (id<<1);
- if (needsRecalc) field_2_need_recalculation_and_id++;
- }
-
- public CellRangeAddress getEnclosingCellRange() {
- return field_3_enclosing_cell_range;
- }
- public void setEnclosingCellRange(CellRangeAddress cr) {
- field_3_enclosing_cell_range = cr;
- }
-
- /**
- * Set cell ranges list to a single cell range and
- * modify the enclosing cell range accordingly.
- * @param cellRanges - list of CellRange objects
- */
- public void setCellRanges(CellRangeAddress[] cellRanges) {
- if(cellRanges == null) {
- throw new IllegalArgumentException("cellRanges must not be null");
- }
- CellRangeAddressList cral = new CellRangeAddressList();
- CellRangeAddress enclosingRange = null;
- for (int i = 0; i < cellRanges.length; i++) {
- CellRangeAddress cr = cellRanges[i];
- enclosingRange = CellRangeUtil.createEnclosingCellRange(cr, enclosingRange);
- cral.addCellRangeAddress(cr);
- }
- field_3_enclosing_cell_range = enclosingRange;
- field_4_cell_ranges = cral;
- }
-
- public CellRangeAddress[] getCellRanges() {
- return field_4_cell_ranges.getCellRangeAddresses();
- }
protected String getRecordName() {
return "CFHEADER";
}
- public String toString() {
- StringBuffer buffer = new StringBuffer();
-
- buffer.append("[").append(getRecordName()).append("]\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");
- buffer.append(" .cfranges=[");
- for( int i=0; i<field_4_cell_ranges.countRanges(); i++) {
- buffer.append(i==0?"":",").append(field_4_cell_ranges.getCellRangeAddress(i).toString());
- }
- buffer.append("]\n");
- buffer.append("[/").append(getRecordName()).append("]\n");
- return buffer.toString();
- }
-
- protected int getDataSize() {
- return 4 // 2 short fields
- + CellRangeAddress.ENCODED_SIZE
- + field_4_cell_ranges.getSize();
- }
-
- public void serialize(LittleEndianOutput out) {
- out.writeShort(field_1_numcf);
- out.writeShort(field_2_need_recalculation_and_id);
- field_3_enclosing_cell_range.serialize(out);
- field_4_cell_ranges.serialize(out);
- }
public short getSid() {
return sid;
public Object clone() {
CFHeaderRecord result = new CFHeaderRecord();
- result.field_1_numcf = field_1_numcf;
- result.field_2_need_recalculation_and_id = field_2_need_recalculation_and_id;
- result.field_3_enclosing_cell_range = field_3_enclosing_cell_range.copy();
- result.field_4_cell_ranges = field_4_cell_ranges.copy();
+ super.copyTo(result);
return result;
}
}
import org.apache.poi.ss.util.CellRangeAddress;
/**
- * Tests the serialization and deserialization of the TestCFHeaderRecord
- * class works correctly.
- *
- * @author Dmitriy Kumshayev
+ * Tests the serialization and deserialization of the {@link CFHeaderRecord}
+ * and {@link CFHeader12Record} classes works correctly.
*/
-public final class TestCFHeaderRecord extends TestCase
-{
-
- public void testCreateCFHeaderRecord ()
- {
+public final class TestCFHeaderRecord extends TestCase {
+ public void testCreateCFHeaderRecord () {
CFHeaderRecord record = new CFHeaderRecord();
CellRangeAddress[] ranges = {
new CellRangeAddress(0,0xFFFF,5,5),
assertEquals(65535, enclosingCellRange.getLastRow());
assertEquals(0, enclosingCellRange.getFirstColumn());
assertEquals(6, enclosingCellRange.getLastColumn());
+
+ assertEquals(false, record.getNeedRecalculation());
+ assertEquals(0, record.getID());
+
record.setNeedRecalculation(true);
- assertTrue(record.getNeedRecalculation());
+ assertEquals(true, record.getNeedRecalculation());
+ assertEquals(0, record.getID());
+
+ record.setID(7);
record.setNeedRecalculation(false);
- assertFalse(record.getNeedRecalculation());
+ assertEquals(false, record.getNeedRecalculation());
+ assertEquals(7, record.getID());
}
+ public void testCreateCFHeader12Record () {
+ CFHeader12Record record = new CFHeader12Record();
+ CellRangeAddress[] ranges = {
+ new CellRangeAddress(0,0xFFFF,5,5),
+ new CellRangeAddress(0,0xFFFF,6,6),
+ new CellRangeAddress(0,1,0,1),
+ new CellRangeAddress(0,1,2,3),
+ new CellRangeAddress(2,3,0,1),
+ new CellRangeAddress(2,3,2,3),
+ };
+ record.setCellRanges(ranges);
+ ranges = record.getCellRanges();
+ assertEquals(6,ranges.length);
+ CellRangeAddress enclosingCellRange = record.getEnclosingCellRange();
+ assertEquals(0, enclosingCellRange.getFirstRow());
+ assertEquals(65535, enclosingCellRange.getLastRow());
+ assertEquals(0, enclosingCellRange.getFirstColumn());
+ assertEquals(6, enclosingCellRange.getLastColumn());
+
+ assertEquals(false, record.getNeedRecalculation());
+ assertEquals(0, record.getID());
+
+ record.setNeedRecalculation(true);
+ assertEquals(true, record.getNeedRecalculation());
+ assertEquals(0, record.getID());
+
+ record.setID(7);
+ record.setNeedRecalculation(false);
+ assertEquals(false, record.getNeedRecalculation());
+ assertEquals(7, record.getID());
+ }
+
public void testSerialization() {
byte[] recordData =
{