#63745 - Add traversing and debugging interface to HSSF

a few more HSSF / Old Excel classes

git-svn-id: https://svn.apache.org/repos/asf/poi/trunk@1876732 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
Andreas Beeker 2020-04-19 20:33:54 +00:00
parent fbcf0c81ba
commit c41dee931f
17 changed files with 400 additions and 409 deletions

View File

@ -17,16 +17,21 @@
package org.apache.poi.hssf.record; package org.apache.poi.hssf.record;
import org.apache.poi.util.HexDump; import java.util.Map;
import java.util.function.Supplier;
import org.apache.poi.common.usermodel.GenericRecord;
import org.apache.poi.util.GenericRecordJsonWriter;
import org.apache.poi.util.GenericRecordUtil;
/** /**
* Base class for all old (Biff 2 - Biff 4) cell value records * Base class for all old (Biff 2 - Biff 4) cell value records
* (implementors of {@link CellValueRecordInterface}). * (implementors of {@link CellValueRecordInterface}).
* Subclasses are expected to manage the cell data values (of various types). * Subclasses are expected to manage the cell data values (of various types).
*/ */
public abstract class OldCellRecord { public abstract class OldCellRecord implements GenericRecord {
private final short sid; private final short sid;
private final boolean isBiff2; private final boolean isBiff2;
private final int field_1_row; private final int field_1_row;
private final short field_2_column; private final short field_2_column;
private int field_3_cell_attrs; // Biff 2 private int field_3_cell_attrs; // Biff 2
@ -37,7 +42,7 @@ public abstract class OldCellRecord {
this.isBiff2 = isBiff2; this.isBiff2 = isBiff2;
field_1_row = in.readUShort(); field_1_row = in.readUShort();
field_2_column = in.readShort(); field_2_column = in.readShort();
if (isBiff2) { if (isBiff2) {
field_3_cell_attrs = in.readUShort() << 8; field_3_cell_attrs = in.readUShort() << 8;
field_3_cell_attrs += in.readUByte(); field_3_cell_attrs += in.readUByte();
@ -63,7 +68,7 @@ public abstract class OldCellRecord {
public final short getXFIndex() { public final short getXFIndex() {
return field_3_xf_index; return field_3_xf_index;
} }
public int getCellAttrs() public int getCellAttrs()
{ {
return field_3_cell_attrs; return field_3_cell_attrs;
@ -71,49 +76,30 @@ public abstract class OldCellRecord {
/** /**
* Is this a Biff2 record, or newer? * Is this a Biff2 record, or newer?
* *
* @return true, if this is a Biff2 record or newer * @return true, if this is a Biff2 record or newer
*/ */
public boolean isBiff2() { public boolean isBiff2() {
return isBiff2; return isBiff2;
} }
public short getSid() { public short getSid() {
return sid; return sid;
} }
@Override
public Map<String, Supplier<?>> getGenericProperties() {
return GenericRecordUtil.getGenericProperties(
"row", this::getRow,
"column", this::getColumn,
"biff2", this::isBiff2,
"biff2CellAttrs", this::getCellAttrs,
"xfIndex", this::getXFIndex
);
}
@Override @Override
public final String toString() { public final String toString() {
StringBuilder sb = new StringBuilder(); return GenericRecordJsonWriter.marshal(this);
String recordName = getRecordName();
sb.append("[").append(recordName).append("]\n");
sb.append(" .row = ").append(HexDump.shortToHex(getRow())).append("\n");
sb.append(" .col = ").append(HexDump.shortToHex(getColumn())).append("\n");
if (isBiff2()) {
sb.append(" .cellattrs = ").append(HexDump.shortToHex(getCellAttrs())).append("\n");
} else {
sb.append(" .xfindex = ").append(HexDump.shortToHex(getXFIndex())).append("\n");
}
appendValueText(sb);
sb.append("\n");
sb.append("[/").append(recordName).append("]\n");
return sb.toString();
} }
/**
* Append specific debug info (used by {@link #toString()} for the value
* contained in this record. Trailing new-line should not be appended
* (superclass does that).
*
* @param sb the StringBuilder to append to
*/
protected abstract void appendValueText(StringBuilder sb);
/**
* Gets the debug info BIFF record type name (used by {@link #toString()}.
*
* @return the debug info BIFF record type name
*/
protected abstract String getRecordName();
} }

View File

@ -17,9 +17,13 @@
package org.apache.poi.hssf.record; package org.apache.poi.hssf.record;
import java.util.Map;
import java.util.function.Supplier;
import org.apache.poi.ss.formula.Formula; import org.apache.poi.ss.formula.Formula;
import org.apache.poi.ss.formula.ptg.Ptg; import org.apache.poi.ss.formula.ptg.Ptg;
import org.apache.poi.ss.usermodel.CellType; import org.apache.poi.ss.usermodel.CellType;
import org.apache.poi.util.GenericRecordUtil;
/** /**
* Formula Record (0x0006 / 0x0206 / 0x0406) - holds a formula in * Formula Record (0x0006 / 0x0206 / 0x0406) - holds a formula in
@ -103,10 +107,18 @@ public final class OldFormulaRecord extends OldCellRecord {
return field_6_parsed_expr; return field_6_parsed_expr;
} }
protected void appendValueText(StringBuilder sb) { @Override
sb.append(" .value = ").append(getValue()).append("\n"); public HSSFRecordTypes getGenericRecordType() {
return HSSFRecordTypes.FORMULA;
} }
protected String getRecordName() {
return "Old Formula"; @Override
public Map<String, Supplier<?>> getGenericProperties() {
return GenericRecordUtil.getGenericProperties(
"base", super::getGenericProperties,
"options", this::getOptions,
"formula", this::getFormula,
"value", this::getValue
);
} }
} }

View File

@ -17,6 +17,10 @@
package org.apache.poi.hssf.record; package org.apache.poi.hssf.record;
import java.util.Map;
import java.util.function.Supplier;
import org.apache.poi.util.GenericRecordUtil;
import org.apache.poi.util.HexDump; import org.apache.poi.util.HexDump;
import org.apache.poi.util.IOUtils; import org.apache.poi.util.IOUtils;
import org.apache.poi.util.POILogFactory; import org.apache.poi.util.POILogFactory;
@ -104,13 +108,16 @@ public final class OldLabelRecord extends OldCellRecord {
} }
@Override @Override
protected void appendValueText(StringBuilder sb) { public HSSFRecordTypes getGenericRecordType() {
sb.append(" .string_len= ").append(HexDump.shortToHex(field_4_string_len)).append("\n"); return HSSFRecordTypes.LABEL;
sb.append(" .value = ").append(getValue()).append("\n");
} }
@Override @Override
protected String getRecordName() { public Map<String, Supplier<?>> getGenericProperties() {
return "OLD LABEL"; return GenericRecordUtil.getGenericProperties(
"base", super::getGenericProperties,
"stringLength", this::getStringLength,
"value", this::getValue
);
} }
} }

View File

@ -18,8 +18,12 @@
package org.apache.poi.hssf.record; package org.apache.poi.hssf.record;
import java.io.IOException; import java.io.IOException;
import java.util.Map;
import java.util.function.Supplier;
import org.apache.poi.util.HexDump; import org.apache.poi.common.usermodel.GenericRecord;
import org.apache.poi.util.GenericRecordJsonWriter;
import org.apache.poi.util.GenericRecordUtil;
import org.apache.poi.util.IOUtils; import org.apache.poi.util.IOUtils;
import org.apache.poi.util.RecordFormatException; import org.apache.poi.util.RecordFormatException;
@ -29,17 +33,17 @@ import org.apache.poi.util.RecordFormatException;
* and tells where the Beginning of file record is within the HSSF * and tells where the Beginning of file record is within the HSSF
* file. * file.
*/ */
public final class OldSheetRecord { public final class OldSheetRecord implements GenericRecord {
//arbitrarily selected; may need to increase //arbitrarily selected; may need to increase
private static final int MAX_RECORD_LENGTH = 100_000; private static final int MAX_RECORD_LENGTH = 100_000;
public static final short sid = 0x0085; public static final short sid = 0x0085;
private int field_1_position_of_BOF; private final int field_1_position_of_BOF;
private int field_2_visibility; private final int field_2_visibility;
private int field_3_type; private final int field_3_type;
private byte[] field_5_sheetname; private final byte[] field_5_sheetname;
private CodepageRecord codepage; private CodepageRecord codepage;
public OldSheetRecord(RecordInputStream in) { public OldSheetRecord(RecordInputStream in) {
@ -89,15 +93,22 @@ public final class OldSheetRecord {
return OldStringRecord.getString(field_5_sheetname, codepage); return OldStringRecord.getString(field_5_sheetname, codepage);
} }
public String toString() { @Override
StringBuilder buffer = new StringBuilder(); public HSSFRecordTypes getGenericRecordType() {
return HSSFRecordTypes.BOUND_SHEET;
}
buffer.append("[BOUNDSHEET]\n"); @Override
buffer.append(" .bof = ").append(HexDump.intToHex(getPositionOfBof())).append("\n"); public Map<String, Supplier<?>> getGenericProperties() {
buffer.append(" .visibility = ").append(HexDump.shortToHex(field_2_visibility)).append("\n"); return GenericRecordUtil.getGenericProperties(
buffer.append(" .type = ").append(HexDump.byteToHex(field_3_type)).append("\n"); "bof", this::getPositionOfBof,
buffer.append(" .sheetname = ").append(getSheetname()).append("\n"); "visibility", () -> field_2_visibility,
buffer.append("[/BOUNDSHEET]\n"); "type", () -> field_3_type,
return buffer.toString(); "sheetName", this::getSheetname
);
}
public String toString() {
return GenericRecordJsonWriter.marshal(this);
} }
} }

View File

@ -18,9 +18,14 @@
package org.apache.poi.hssf.record; package org.apache.poi.hssf.record;
import java.io.UnsupportedEncodingException; import java.io.UnsupportedEncodingException;
import java.util.Map;
import java.util.function.Supplier;
import org.apache.poi.common.usermodel.GenericRecord;
import org.apache.poi.hpsf.Property; import org.apache.poi.hpsf.Property;
import org.apache.poi.util.CodePageUtil; import org.apache.poi.util.CodePageUtil;
import org.apache.poi.util.GenericRecordJsonWriter;
import org.apache.poi.util.GenericRecordUtil;
import org.apache.poi.util.IOUtils; import org.apache.poi.util.IOUtils;
@ -28,7 +33,7 @@ import org.apache.poi.util.IOUtils;
* Biff2 - Biff 4 Label Record (0x0007 / 0x0207) - read only support for * Biff2 - Biff 4 Label Record (0x0007 / 0x0207) - read only support for
* formula string results. * formula string results.
*/ */
public final class OldStringRecord { public final class OldStringRecord implements GenericRecord {
//arbitrarily selected; may need to increase //arbitrarily selected; may need to increase
private static final int MAX_RECORD_LENGTH = 100_000; private static final int MAX_RECORD_LENGTH = 100_000;
@ -90,14 +95,17 @@ public final class OldStringRecord {
} }
} }
public String toString() @Override
{ public HSSFRecordTypes getGenericRecordType() {
StringBuilder buffer = new StringBuilder(); return HSSFRecordTypes.STRING;
}
buffer.append("[OLD STRING]\n"); @Override
buffer.append(" .string = ") public Map<String, Supplier<?>> getGenericProperties() {
.append(getString()).append("\n"); return GenericRecordUtil.getGenericProperties("string", this::getString);
buffer.append("[/OLD STRING]\n"); }
return buffer.toString();
public String toString() {
return GenericRecordJsonWriter.marshal(this);
} }
} }

View File

@ -19,7 +19,10 @@ package org.apache.poi.hssf.record.aggregates;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.Map;
import java.util.function.Supplier;
import org.apache.poi.common.usermodel.GenericRecord;
import org.apache.poi.hssf.model.RecordStream; import org.apache.poi.hssf.model.RecordStream;
import org.apache.poi.hssf.record.CFHeader12Record; import org.apache.poi.hssf.record.CFHeader12Record;
import org.apache.poi.hssf.record.CFHeaderBase; import org.apache.poi.hssf.record.CFHeaderBase;
@ -32,6 +35,8 @@ import org.apache.poi.ss.formula.FormulaShifter;
import org.apache.poi.ss.formula.ptg.Ptg; import org.apache.poi.ss.formula.ptg.Ptg;
import org.apache.poi.ss.usermodel.helpers.BaseRowColShifter; import org.apache.poi.ss.usermodel.helpers.BaseRowColShifter;
import org.apache.poi.ss.util.CellRangeAddress; import org.apache.poi.ss.util.CellRangeAddress;
import org.apache.poi.util.GenericRecordJsonWriter;
import org.apache.poi.util.GenericRecordUtil;
import org.apache.poi.util.POILogFactory; import org.apache.poi.util.POILogFactory;
import org.apache.poi.util.POILogger; import org.apache.poi.util.POILogger;
import org.apache.poi.util.RecordFormatException; import org.apache.poi.util.RecordFormatException;
@ -44,7 +49,7 @@ import org.apache.poi.util.RecordFormatException;
* unlimited numbers, as can Apache OpenOffice. This is an Excel limitation, * unlimited numbers, as can Apache OpenOffice. This is an Excel limitation,
* not a file format one.</p> * not a file format one.</p>
*/ */
public final class CFRecordsAggregate extends RecordAggregate { public final class CFRecordsAggregate extends RecordAggregate implements GenericRecord {
/** Excel 97-2003 allows up to 3 conditional formating rules */ /** Excel 97-2003 allows up to 3 conditional formating rules */
private static final int MAX_97_2003_CONDTIONAL_FORMAT_RULES = 3; private static final int MAX_97_2003_CONDTIONAL_FORMAT_RULES = 3;
private static final POILogger logger = POILogFactory.getLogger(CFRecordsAggregate.class); private static final POILogger logger = POILogFactory.getLogger(CFRecordsAggregate.class);
@ -188,25 +193,19 @@ public final class CFRecordsAggregate extends RecordAggregate {
return rules.size(); return rules.size();
} }
@Override
public Map<String, Supplier<?>> getGenericProperties() {
return GenericRecordUtil.getGenericProperties(
"header", this::getHeader,
"rules", () -> rules
);
}
/** /**
* String representation of CFRecordsAggregate * String representation of CFRecordsAggregate
*/ */
public String toString() { public String toString() {
StringBuilder buffer = new StringBuilder(); return GenericRecordJsonWriter.marshal(this);
String type = "CF";
if (header instanceof CFHeader12Record) {
type = "CF12";
}
buffer.append("[").append(type).append("]\n");
if( header != null ) {
buffer.append(header);
}
for (CFRuleBase cfRule : rules) {
buffer.append(cfRule);
}
buffer.append("[/").append(type).append("]\n");
return buffer.toString();
} }
public void visitContainedRecords(RecordVisitor rv) { public void visitContainedRecords(RecordVisitor rv) {

View File

@ -17,9 +17,16 @@
package org.apache.poi.hssf.record.cf; package org.apache.poi.hssf.record.cf;
import java.util.Collections;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.function.Supplier;
import org.apache.poi.common.Duplicatable; import org.apache.poi.common.Duplicatable;
import org.apache.poi.common.usermodel.GenericRecord;
import org.apache.poi.util.BitField; import org.apache.poi.util.BitField;
import org.apache.poi.util.BitFieldFactory; import org.apache.poi.util.BitFieldFactory;
import org.apache.poi.util.GenericRecordJsonWriter;
import org.apache.poi.util.LittleEndian; import org.apache.poi.util.LittleEndian;
import org.apache.poi.util.LittleEndianInput; import org.apache.poi.util.LittleEndianInput;
import org.apache.poi.util.LittleEndianOutput; import org.apache.poi.util.LittleEndianOutput;
@ -28,7 +35,7 @@ import org.apache.poi.util.Removal;
/** /**
* Border Formatting Block of the Conditional Formatting Rule Record. * Border Formatting Block of the Conditional Formatting Rule Record.
*/ */
public final class BorderFormatting implements Duplicatable { public final class BorderFormatting implements Duplicatable, GenericRecord {
/** No border */ /** No border */
public static final short BORDER_NONE = 0x0; public static final short BORDER_NONE = 0x0;
/** Thin border */ /** Thin border */
@ -436,26 +443,28 @@ public final class BorderFormatting implements Duplicatable {
return bordTlBrLineOnOff.isSet(field_13_border_styles1); return bordTlBrLineOnOff.isSet(field_13_border_styles1);
} }
@Override
public Map<String, Supplier<?>> getGenericProperties() {
final Map<String,Supplier<?>> m = new LinkedHashMap<>();
m.put("borderLeft", this::getBorderLeft);
m.put("borderRight", this::getBorderRight);
m.put("borderTop", this::getBorderTop);
m.put("borderBottom", this::getBorderBottom);
m.put("leftBorderColor", this::getLeftBorderColor);
m.put("rightBorderColor", this::getRightBorderColor);
m.put("topBorderColor", this::getTopBorderColor);
m.put("bottomBorderColor", this::getBottomBorderColor);
m.put("forwardDiagonalOn", this::isForwardDiagonalOn);
m.put("backwardDiagonalOn", this::isBackwardDiagonalOn);
return Collections.unmodifiableMap(m);
}
public String toString() { public String toString() {
StringBuilder buffer = new StringBuilder(); return GenericRecordJsonWriter.marshal(this);
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();
} }
@Override @Override
@SuppressWarnings("squid:S2975") @SuppressWarnings({"squid:S2975", "MethodDoesntCallSuperMethod"})
@Deprecated @Deprecated
@Removal(version = "5.0.0") @Removal(version = "5.0.0")
public BorderFormatting clone() { public BorderFormatting clone() {
@ -467,7 +476,7 @@ public final class BorderFormatting implements Duplicatable {
} }
public int serialize(int offset, byte [] data) { public int serialize(int offset, byte [] data) {
LittleEndian.putInt(data, offset+0, field_13_border_styles1); LittleEndian.putInt(data, offset, field_13_border_styles1);
LittleEndian.putInt(data, offset+4, field_14_border_styles2); LittleEndian.putInt(data, offset+4, field_14_border_styles2);
return 8; return 8;
} }

View File

@ -17,12 +17,17 @@
package org.apache.poi.hssf.record.cf; package org.apache.poi.hssf.record.cf;
import java.util.Map;
import java.util.function.Supplier;
import java.util.stream.Stream; import java.util.stream.Stream;
import org.apache.poi.common.Duplicatable; import org.apache.poi.common.Duplicatable;
import org.apache.poi.common.usermodel.GenericRecord;
import org.apache.poi.hssf.record.common.ExtendedColor; import org.apache.poi.hssf.record.common.ExtendedColor;
import org.apache.poi.util.BitField; import org.apache.poi.util.BitField;
import org.apache.poi.util.BitFieldFactory; import org.apache.poi.util.BitFieldFactory;
import org.apache.poi.util.GenericRecordJsonWriter;
import org.apache.poi.util.GenericRecordUtil;
import org.apache.poi.util.LittleEndianInput; import org.apache.poi.util.LittleEndianInput;
import org.apache.poi.util.LittleEndianOutput; import org.apache.poi.util.LittleEndianOutput;
import org.apache.poi.util.POILogFactory; import org.apache.poi.util.POILogFactory;
@ -34,13 +39,13 @@ import org.apache.poi.util.Removal;
* (Called Color Gradient in the file format docs, but more commonly * (Called Color Gradient in the file format docs, but more commonly
* Color Scale in the UI) * Color Scale in the UI)
*/ */
public final class ColorGradientFormatting implements Duplicatable { public final class ColorGradientFormatting implements Duplicatable, GenericRecord {
private static final POILogger log = POILogFactory.getLogger(ColorGradientFormatting.class); private static final POILogger log = POILogFactory.getLogger(ColorGradientFormatting.class);
private static final BitField clamp = BitFieldFactory.getInstance(0x01); private static final BitField clamp = BitFieldFactory.getInstance(0x01);
private static final BitField background = BitFieldFactory.getInstance(0x02); private static final BitField background = BitFieldFactory.getInstance(0x02);
private byte options; private final byte options;
private ColorGradientThreshold[] thresholds; private ColorGradientThreshold[] thresholds;
private ExtendedColor[] colors; private ExtendedColor[] colors;
@ -132,23 +137,22 @@ public final class ColorGradientFormatting implements Duplicatable {
} }
} }
@Override
public Map<String, Supplier<?>> getGenericProperties() {
return GenericRecordUtil.getGenericProperties(
"clampToCurve", this::isClampToCurve,
"background", this::isAppliesToBackground,
"thresholds", this::getThresholds,
"colors", this::getColors
);
}
public String toString() { public String toString() {
StringBuilder buffer = new StringBuilder(); return GenericRecordJsonWriter.marshal(this);
buffer.append(" [Color Gradient Formatting]\n");
buffer.append(" .clamp = ").append(isClampToCurve()).append("\n");
buffer.append(" .background= ").append(isAppliesToBackground()).append("\n");
for (Threshold t : thresholds) {
buffer.append(t);
}
for (ExtendedColor c : colors) {
buffer.append(c);
}
buffer.append(" [/Color Gradient Formatting]\n");
return buffer.toString();
} }
@Override @Override
@SuppressWarnings("squid:S2975") @SuppressWarnings({"squid:S2975", "MethodDoesntCallSuperMethod"})
@Deprecated @Deprecated
@Removal(version = "5.0.0") @Removal(version = "5.0.0")
public ColorGradientFormatting clone() { public ColorGradientFormatting clone() {

View File

@ -17,7 +17,12 @@
package org.apache.poi.hssf.record.cf; package org.apache.poi.hssf.record.cf;
import java.util.Map;
import java.util.function.Supplier;
import org.apache.poi.common.Duplicatable; import org.apache.poi.common.Duplicatable;
import org.apache.poi.common.usermodel.GenericRecord;
import org.apache.poi.util.GenericRecordUtil;
import org.apache.poi.util.LittleEndianInput; import org.apache.poi.util.LittleEndianInput;
import org.apache.poi.util.LittleEndianOutput; import org.apache.poi.util.LittleEndianOutput;
import org.apache.poi.util.Removal; import org.apache.poi.util.Removal;
@ -26,7 +31,7 @@ import org.apache.poi.util.Removal;
* Color Gradient / Color Scale specific Threshold / value (CFVO), * Color Gradient / Color Scale specific Threshold / value (CFVO),
* for changes in Conditional Formatting * for changes in Conditional Formatting
*/ */
public final class ColorGradientThreshold extends Threshold implements Duplicatable { public final class ColorGradientThreshold extends Threshold implements Duplicatable, GenericRecord {
private double position; private double position;
public ColorGradientThreshold() { public ColorGradientThreshold() {
@ -72,4 +77,9 @@ public final class ColorGradientThreshold extends Threshold implements Duplicata
super.serialize(out); super.serialize(out);
out.writeDouble(position); out.writeDouble(position);
} }
@Override
public Map<String, Supplier<?>> getGenericProperties() {
return GenericRecordUtil.getGenericProperties("position", this::getPosition);
}
} }

View File

@ -17,10 +17,18 @@
package org.apache.poi.hssf.record.cf; package org.apache.poi.hssf.record.cf;
import static org.apache.poi.util.GenericRecordUtil.getBitsAsString;
import java.util.Map;
import java.util.function.Supplier;
import org.apache.poi.common.Duplicatable; import org.apache.poi.common.Duplicatable;
import org.apache.poi.common.usermodel.GenericRecord;
import org.apache.poi.hssf.record.common.ExtendedColor; import org.apache.poi.hssf.record.common.ExtendedColor;
import org.apache.poi.util.BitField; import org.apache.poi.util.BitField;
import org.apache.poi.util.BitFieldFactory; import org.apache.poi.util.BitFieldFactory;
import org.apache.poi.util.GenericRecordJsonWriter;
import org.apache.poi.util.GenericRecordUtil;
import org.apache.poi.util.LittleEndianInput; import org.apache.poi.util.LittleEndianInput;
import org.apache.poi.util.LittleEndianOutput; import org.apache.poi.util.LittleEndianOutput;
import org.apache.poi.util.POILogFactory; import org.apache.poi.util.POILogFactory;
@ -30,11 +38,11 @@ import org.apache.poi.util.Removal;
/** /**
* Data Bar Conditional Formatting Rule Record. * Data Bar Conditional Formatting Rule Record.
*/ */
public final class DataBarFormatting implements Duplicatable { public final class DataBarFormatting implements Duplicatable, GenericRecord {
private static POILogger log = POILogFactory.getLogger(DataBarFormatting.class); private static final POILogger LOG = POILogFactory.getLogger(DataBarFormatting.class);
private static final BitField iconOnly = BitFieldFactory.getInstance(0x01); private static final BitField ICON_ONLY = BitFieldFactory.getInstance(0x01);
private static final BitField reversed = BitFieldFactory.getInstance(0x04); private static final BitField REVERSED = BitFieldFactory.getInstance(0x04);
private byte options; private byte options;
private byte percentMin; private byte percentMin;
@ -64,9 +72,9 @@ public final class DataBarFormatting implements Duplicatable {
percentMin = in.readByte(); percentMin = in.readByte();
percentMax = in.readByte(); percentMax = in.readByte();
if (percentMin < 0 || percentMin > 100) if (percentMin < 0 || percentMin > 100)
log.log(POILogger.WARN, "Inconsistent Minimum Percentage found " + percentMin); LOG.log(POILogger.WARN, "Inconsistent Minimum Percentage found " + percentMin);
if (percentMax < 0 || percentMax > 100) if (percentMax < 0 || percentMax > 100)
log.log(POILogger.WARN, "Inconsistent Minimum Percentage found " + percentMin); LOG.log(POILogger.WARN, "Inconsistent Minimum Percentage found " + percentMin);
color = new ExtendedColor(in); color = new ExtendedColor(in);
thresholdMin = new DataBarThreshold(in); thresholdMin = new DataBarThreshold(in);
@ -74,22 +82,22 @@ public final class DataBarFormatting implements Duplicatable {
} }
public boolean isIconOnly() { public boolean isIconOnly() {
return getOptionFlag(iconOnly); return getOptionFlag(ICON_ONLY);
} }
public void setIconOnly(boolean only) { public void setIconOnly(boolean only) {
setOptionFlag(only, iconOnly); setOptionFlag(only, ICON_ONLY);
} }
public boolean isReversed() { public boolean isReversed() {
return getOptionFlag(reversed); return getOptionFlag(REVERSED);
} }
public void setReversed(boolean rev) { public void setReversed(boolean rev) {
setOptionFlag(rev, reversed); setOptionFlag(rev, REVERSED);
} }
private boolean getOptionFlag(BitField field) { private boolean getOptionFlag(BitField field) {
int value = field.getValue(options); int value = field.getValue(options);
return value==0 ? false : true; return value != 0;
} }
private void setOptionFlag(boolean option, BitField field) { private void setOptionFlag(boolean option, BitField field) {
options = field.setByteBoolean(options, option); options = field.setByteBoolean(options, option);
@ -130,20 +138,24 @@ public final class DataBarFormatting implements Duplicatable {
this.thresholdMax = thresholdMax; this.thresholdMax = thresholdMax;
} }
@Override
public Map<String, Supplier<?>> getGenericProperties() {
return GenericRecordUtil.getGenericProperties(
"options", getBitsAsString(() -> options, new BitField[]{ICON_ONLY, REVERSED}, new String[]{"ICON_ONLY", "REVERSED"}),
"color", this::getColor,
"percentMin", this::getPercentMin,
"percentMax", this::getPercentMax,
"thresholdMin", this::getThresholdMin,
"thresholdMax", this::getThresholdMax
);
}
public String toString() { public String toString() {
StringBuilder buffer = new StringBuilder(); return GenericRecordJsonWriter.marshal(this);
buffer.append(" [Data Bar Formatting]\n");
buffer.append(" .icon_only= ").append(isIconOnly()).append("\n");
buffer.append(" .reversed = ").append(isReversed()).append("\n");
buffer.append(color);
buffer.append(thresholdMin);
buffer.append(thresholdMax);
buffer.append(" [/Data Bar Formatting]\n");
return buffer.toString();
} }
@Override @Override
@SuppressWarnings("squid:S2975") @SuppressWarnings({"squid:S2975", "MethodDoesntCallSuperMethod"})
@Deprecated @Deprecated
@Removal(version = "5.0.0") @Removal(version = "5.0.0")
public DataBarFormatting clone() { public DataBarFormatting clone() {

View File

@ -18,19 +18,27 @@
package org.apache.poi.hssf.record.cf; package org.apache.poi.hssf.record.cf;
import java.util.Locale; import static org.apache.poi.util.GenericRecordUtil.getBitsAsString;
import static org.apache.poi.util.GenericRecordUtil.getEnumBitsAsString;
import java.util.Collections;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.function.Supplier;
import org.apache.poi.common.Duplicatable; import org.apache.poi.common.Duplicatable;
import org.apache.poi.common.usermodel.GenericRecord;
import org.apache.poi.hssf.record.RecordInputStream; import org.apache.poi.hssf.record.RecordInputStream;
import org.apache.poi.util.BitField; import org.apache.poi.util.BitField;
import org.apache.poi.util.BitFieldFactory; import org.apache.poi.util.BitFieldFactory;
import org.apache.poi.util.GenericRecordJsonWriter;
import org.apache.poi.util.LittleEndian; import org.apache.poi.util.LittleEndian;
import org.apache.poi.util.Removal; import org.apache.poi.util.Removal;
/** /**
* Font Formatting Block of the Conditional Formatting Rule Record. * Font Formatting Block of the Conditional Formatting Rule Record.
*/ */
public final class FontFormatting implements Duplicatable { public final class FontFormatting implements Duplicatable, GenericRecord {
private static final int OFFSET_FONT_NAME = 0; private static final int OFFSET_FONT_NAME = 0;
private static final int OFFSET_FONT_HEIGHT = 64; private static final int OFFSET_FONT_HEIGHT = 64;
private static final int OFFSET_FONT_OPTIONS = 68; private static final int OFFSET_FONT_OPTIONS = 68;
@ -51,18 +59,12 @@ public final class FontFormatting implements Duplicatable {
public static final int FONT_CELL_HEIGHT_PRESERVED = 0xFFFFFFFF; public static final int FONT_CELL_HEIGHT_PRESERVED = 0xFFFFFFFF;
// FONT OPTIONS MASKS // option flags and font options masks
private static final BitField posture = BitFieldFactory.getInstance(0x00000002); // in the options flags, a true bit activates the overriding and in the font option the bit sets the state
private static final BitField outline = BitFieldFactory.getInstance(0x00000008); private static final BitField POSTURE = BitFieldFactory.getInstance(0x00000002);
private static final BitField shadow = BitFieldFactory.getInstance(0x00000010); private static final BitField OUTLINE = BitFieldFactory.getInstance(0x00000008);
private static final BitField cancellation = BitFieldFactory.getInstance(0x00000080); private static final BitField SHADOW = BitFieldFactory.getInstance(0x00000010);
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 cancellationModified = BitFieldFactory.getInstance(0x00000080);
/** /**
* Escapement type - None * Escapement type - None
@ -166,7 +168,7 @@ public final class FontFormatting implements Duplicatable {
} }
public FontFormatting(FontFormatting other) { public FontFormatting(FontFormatting other) {
System.arraycopy(other._rawData, 0, _rawData, 0, _rawData.length); System.arraycopy(other._rawData, 0, _rawData, 0, RAW_DATA_SIZE);
} }
public FontFormatting(RecordInputStream in) { public FontFormatting(RecordInputStream in) {
@ -202,8 +204,7 @@ public final class FontFormatting implements Duplicatable {
* @param height fontheight (in points/20); or -1 to preserve the cell font height * @param height fontheight (in points/20); or -1 to preserve the cell font height
*/ */
public void setFontHeight(int height) public void setFontHeight(int height) {
{
setInt(OFFSET_FONT_HEIGHT, height); setInt(OFFSET_FONT_HEIGHT, height);
} }
@ -212,20 +213,17 @@ public final class FontFormatting implements Duplicatable {
* *
* @return fontheight (in points/20); or -1 if not modified * @return fontheight (in points/20); or -1 if not modified
*/ */
public int getFontHeight() public int getFontHeight() {
{
return getInt(OFFSET_FONT_HEIGHT); return getInt(OFFSET_FONT_HEIGHT);
} }
private void setFontOption(boolean option, BitField field) private void setFontOption(boolean option, BitField field) {
{
int options = getInt(OFFSET_FONT_OPTIONS); int options = getInt(OFFSET_FONT_OPTIONS);
options = field.setBoolean(options, option); options = field.setBoolean(options, option);
setInt(OFFSET_FONT_OPTIONS, options); setInt(OFFSET_FONT_OPTIONS, options);
} }
private boolean getFontOption(BitField field) private boolean getFontOption(BitField field) {
{
int options = getInt(OFFSET_FONT_OPTIONS); int options = getInt(OFFSET_FONT_OPTIONS);
return field.isSet(options); return field.isSet(options);
} }
@ -237,9 +235,8 @@ public final class FontFormatting implements Duplicatable {
* @see #setFontOption(boolean, org.apache.poi.util.BitField) * @see #setFontOption(boolean, org.apache.poi.util.BitField)
*/ */
public void setItalic(boolean italic) public void setItalic(boolean italic) {
{ setFontOption(italic, POSTURE);
setFontOption(italic, posture);
} }
/** /**
@ -249,29 +246,24 @@ public final class FontFormatting implements Duplicatable {
* @see #getFontOption(org.apache.poi.util.BitField) * @see #getFontOption(org.apache.poi.util.BitField)
*/ */
public boolean isItalic() public boolean isItalic() {
{ return getFontOption(POSTURE);
return getFontOption(posture);
} }
public void setOutline(boolean on) public void setOutline(boolean on) {
{ setFontOption(on, OUTLINE);
setFontOption(on, outline);
} }
public boolean isOutlineOn() public boolean isOutlineOn() {
{ return getFontOption(OUTLINE);
return getFontOption(outline);
} }
public void setShadow(boolean on) public void setShadow(boolean on) {
{ setFontOption(on, SHADOW);
setFontOption(on, shadow);
} }
public boolean isShadowOn() public boolean isShadowOn() {
{ return getFontOption(SHADOW);
return getFontOption(shadow);
} }
/** /**
@ -279,9 +271,8 @@ public final class FontFormatting implements Duplicatable {
* *
* @param strike - whether the font is stricken out or not * @param strike - whether the font is stricken out or not
*/ */
public void setStrikeout(boolean strike) public void setStrikeout(boolean strike) {
{ setFontOption(strike, CANCELLATION);
setFontOption(strike, cancellation);
} }
/** /**
@ -290,9 +281,8 @@ public final class FontFormatting implements Duplicatable {
* @return strike - whether the font is stricken out or not * @return strike - whether the font is stricken out or not
* @see #getFontOption(org.apache.poi.util.BitField) * @see #getFontOption(org.apache.poi.util.BitField)
*/ */
public boolean isStruckout() public boolean isStruckout() {
{ return getFontOption(CANCELLATION);
return getFontOption(cancellation);
} }
/** /**
@ -301,7 +291,6 @@ public final class FontFormatting implements Duplicatable {
* *
* @param bw - a number between 100-1000 for the fonts "boldness" * @param bw - a number between 100-1000 for the fonts "boldness"
*/ */
private void setFontWeight(short bw) { private void setFontWeight(short bw) {
setShort(OFFSET_FONT_WEIGHT, Math.max(100, Math.min(1000, bw))); setShort(OFFSET_FONT_WEIGHT, Math.max(100, Math.min(1000, bw)));
} }
@ -311,8 +300,7 @@ public final class FontFormatting implements Duplicatable {
* *
* @param bold - set font weight to bold if true; to normal otherwise * @param bold - set font weight to bold if true; to normal otherwise
*/ */
public void setBold(boolean bold) public void setBold(boolean bold) {
{
setFontWeight(bold?FONT_WEIGHT_BOLD:FONT_WEIGHT_NORMAL); setFontWeight(bold?FONT_WEIGHT_BOLD:FONT_WEIGHT_NORMAL);
} }
@ -322,9 +310,7 @@ public final class FontFormatting implements Duplicatable {
* *
* @return bw - a number between 100-1000 for the fonts "boldness" * @return bw - a number between 100-1000 for the fonts "boldness"
*/ */
public short getFontWeight() {
public short getFontWeight()
{
return getShort(OFFSET_FONT_WEIGHT); return getShort(OFFSET_FONT_WEIGHT);
} }
@ -333,9 +319,7 @@ public final class FontFormatting implements Duplicatable {
* *
* @return bold - whether the font is bold or not * @return bold - whether the font is bold or not
*/ */
public boolean isBold() {
public boolean isBold()
{
return getFontWeight()==FONT_WEIGHT_BOLD; return getFontWeight()==FONT_WEIGHT_BOLD;
} }
@ -347,8 +331,7 @@ public final class FontFormatting implements Duplicatable {
* @see org.apache.poi.ss.usermodel.Font#SS_SUPER * @see org.apache.poi.ss.usermodel.Font#SS_SUPER
* @see org.apache.poi.ss.usermodel.Font#SS_SUB * @see org.apache.poi.ss.usermodel.Font#SS_SUB
*/ */
public short getEscapementType() public short getEscapementType() {
{
return getShort(OFFSET_ESCAPEMENT_TYPE); return getShort(OFFSET_ESCAPEMENT_TYPE);
} }
@ -360,8 +343,7 @@ public final class FontFormatting implements Duplicatable {
* @see org.apache.poi.ss.usermodel.Font#SS_SUPER * @see org.apache.poi.ss.usermodel.Font#SS_SUPER
* @see org.apache.poi.ss.usermodel.Font#SS_SUB * @see org.apache.poi.ss.usermodel.Font#SS_SUB
*/ */
public void setEscapementType( short escapementType) public void setEscapementType( short escapementType) {
{
setShort(OFFSET_ESCAPEMENT_TYPE, escapementType); setShort(OFFSET_ESCAPEMENT_TYPE, escapementType);
} }
@ -376,8 +358,7 @@ public final class FontFormatting implements Duplicatable {
* @see org.apache.poi.ss.usermodel.Font#U_SINGLE_ACCOUNTING * @see org.apache.poi.ss.usermodel.Font#U_SINGLE_ACCOUNTING
* @see org.apache.poi.ss.usermodel.Font#U_DOUBLE_ACCOUNTING * @see org.apache.poi.ss.usermodel.Font#U_DOUBLE_ACCOUNTING
*/ */
public short getUnderlineType() public short getUnderlineType() {
{
return getShort(OFFSET_UNDERLINE_TYPE); return getShort(OFFSET_UNDERLINE_TYPE);
} }
@ -392,19 +373,16 @@ public final class FontFormatting implements Duplicatable {
* @see org.apache.poi.ss.usermodel.Font#U_SINGLE_ACCOUNTING * @see org.apache.poi.ss.usermodel.Font#U_SINGLE_ACCOUNTING
* @see org.apache.poi.ss.usermodel.Font#U_DOUBLE_ACCOUNTING * @see org.apache.poi.ss.usermodel.Font#U_DOUBLE_ACCOUNTING
*/ */
public void setUnderlineType( short underlineType) public void setUnderlineType( short underlineType) {
{
setShort(OFFSET_UNDERLINE_TYPE, underlineType); setShort(OFFSET_UNDERLINE_TYPE, underlineType);
} }
public short getFontColorIndex() public short getFontColorIndex() {
{
return (short)getInt(OFFSET_FONT_COLOR_INDEX); return (short)getInt(OFFSET_FONT_COLOR_INDEX);
} }
public void setFontColorIndex(short fci ) public void setFontColorIndex(short fci ) {
{
setInt(OFFSET_FONT_COLOR_INDEX,fci); setInt(OFFSET_FONT_COLOR_INDEX,fci);
} }
@ -414,8 +392,7 @@ public final class FontFormatting implements Duplicatable {
return value == 0; return value == 0;
} }
private void setOptionFlag(boolean modified, BitField field) private void setOptionFlag(boolean modified, BitField field) {
{
int value = modified? 0 : 1; int value = modified? 0 : 1;
int optionFlags = getInt(OFFSET_OPTION_FLAGS); int optionFlags = getInt(OFFSET_OPTION_FLAGS);
optionFlags = field.setValue(optionFlags, value); optionFlags = field.setValue(optionFlags, value);
@ -423,161 +400,92 @@ public final class FontFormatting implements Duplicatable {
} }
public boolean isFontStyleModified() public boolean isFontStyleModified() {
{ return getOptionFlag(POSTURE);
return getOptionFlag(styleModified);
} }
public void setFontStyleModified(boolean modified) public void setFontStyleModified(boolean modified) {
{ setOptionFlag(modified, POSTURE);
setOptionFlag(modified, styleModified);
} }
public boolean isFontOutlineModified() public boolean isFontOutlineModified() {
{ return getOptionFlag(OUTLINE);
return getOptionFlag(outlineModified);
} }
public void setFontOutlineModified(boolean modified) public void setFontOutlineModified(boolean modified) {
{ setOptionFlag(modified, OUTLINE);
setOptionFlag(modified, outlineModified);
} }
public boolean isFontShadowModified() public boolean isFontShadowModified() {
{ return getOptionFlag(SHADOW);
return getOptionFlag(shadowModified);
} }
public void setFontShadowModified(boolean modified) public void setFontShadowModified(boolean modified) {
{ setOptionFlag(modified, SHADOW);
setOptionFlag(modified, shadowModified);
} }
public void setFontCancellationModified(boolean modified) public void setFontCancellationModified(boolean modified) {
{ setOptionFlag(modified, CANCELLATION);
setOptionFlag(modified, cancellationModified);
} }
public boolean isFontCancellationModified() public boolean isFontCancellationModified() {
{ return getOptionFlag(CANCELLATION);
return getOptionFlag(cancellationModified);
} }
public void setEscapementTypeModified(boolean modified) public void setEscapementTypeModified(boolean modified) {
{
int value = modified? 0 : 1; int value = modified? 0 : 1;
setInt(OFFSET_ESCAPEMENT_TYPE_MODIFIED, value); setInt(OFFSET_ESCAPEMENT_TYPE_MODIFIED, value);
} }
public boolean isEscapementTypeModified()
{ public boolean isEscapementTypeModified() {
int escapementModified = getInt(OFFSET_ESCAPEMENT_TYPE_MODIFIED); int escapementModified = getInt(OFFSET_ESCAPEMENT_TYPE_MODIFIED);
return escapementModified == 0; return escapementModified == 0;
} }
public void setUnderlineTypeModified(boolean modified) public void setUnderlineTypeModified(boolean modified) {
{
int value = modified? 0 : 1; int value = modified? 0 : 1;
setInt(OFFSET_UNDERLINE_TYPE_MODIFIED, value); setInt(OFFSET_UNDERLINE_TYPE_MODIFIED, value);
} }
public boolean isUnderlineTypeModified() public boolean isUnderlineTypeModified() {
{
int underlineModified = getInt(OFFSET_UNDERLINE_TYPE_MODIFIED); int underlineModified = getInt(OFFSET_UNDERLINE_TYPE_MODIFIED);
return underlineModified == 0; return underlineModified == 0;
} }
public void setFontWieghtModified(boolean modified) public void setFontWieghtModified(boolean modified) {
{
int value = modified? 0 : 1; int value = modified? 0 : 1;
setInt(OFFSET_FONT_WEIGHT_MODIFIED, value); setInt(OFFSET_FONT_WEIGHT_MODIFIED, value);
} }
public boolean isFontWeightModified() public boolean isFontWeightModified() {
{
int fontStyleModified = getInt(OFFSET_FONT_WEIGHT_MODIFIED); int fontStyleModified = getInt(OFFSET_FONT_WEIGHT_MODIFIED);
return fontStyleModified == 0; return fontStyleModified == 0;
} }
public String toString() @Override
{ public Map<String, Supplier<?>> getGenericProperties() {
StringBuilder buffer = new StringBuilder(); final Map<String,Supplier<?>> m = new LinkedHashMap<>();
buffer.append(" [Font Formatting]\n"); m.put("fontHeight", this::getFontHeight);
m.put("options", getBitsAsString(() -> getInt(OFFSET_OPTION_FLAGS),
new BitField[]{POSTURE,OUTLINE,SHADOW,CANCELLATION},
new String[]{"POSTURE_MODIFIED","OUTLINE_MODIFIED","SHADOW_MODIFIED","STRUCKOUT_MODIFIED"}));
m.put("fontOptions", getBitsAsString(() -> getInt(OFFSET_FONT_OPTIONS),
new BitField[]{POSTURE,OUTLINE,SHADOW,CANCELLATION},
new String[]{"ITALIC","OUTLINE","SHADOW","STRUCKOUT"}));
m.put("fontWEightModified", this::isFontWeightModified);
m.put("fontWeight", getEnumBitsAsString(this::getFontWeight,
new int[]{FONT_WEIGHT_NORMAL,FONT_WEIGHT_BOLD},
new String[]{"NORMAL","BOLD"}));
m.put("escapementTypeModified", this::isEscapementTypeModified);
m.put("escapementType", this::getEscapementType);
m.put("underlineTypeModified", this::isUnderlineTypeModified);
m.put("underlineType", this::getUnderlineType);
m.put("colorIndex", this::getFontColorIndex);
return Collections.unmodifiableMap(m);
}
buffer.append(" .font height = ").append(getFontHeight()).append(" twips\n"); public String toString() {
return GenericRecordJsonWriter.marshal(this);
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( 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")
.append(Integer.toHexString(getFontColorIndex()).toUpperCase(Locale.ROOT)).append('\n');
buffer.append(" [/Font Formatting]\n");
return buffer.toString();
} }
@Override @Override

View File

@ -17,12 +17,17 @@
package org.apache.poi.hssf.record.cf; package org.apache.poi.hssf.record.cf;
import java.util.Map;
import java.util.function.Supplier;
import java.util.stream.Stream; import java.util.stream.Stream;
import org.apache.poi.common.Duplicatable; import org.apache.poi.common.Duplicatable;
import org.apache.poi.common.usermodel.GenericRecord;
import org.apache.poi.ss.usermodel.IconMultiStateFormatting.IconSet; import org.apache.poi.ss.usermodel.IconMultiStateFormatting.IconSet;
import org.apache.poi.util.BitField; import org.apache.poi.util.BitField;
import org.apache.poi.util.BitFieldFactory; import org.apache.poi.util.BitFieldFactory;
import org.apache.poi.util.GenericRecordJsonWriter;
import org.apache.poi.util.GenericRecordUtil;
import org.apache.poi.util.LittleEndianInput; import org.apache.poi.util.LittleEndianInput;
import org.apache.poi.util.LittleEndianOutput; import org.apache.poi.util.LittleEndianOutput;
import org.apache.poi.util.POILogFactory; import org.apache.poi.util.POILogFactory;
@ -32,16 +37,16 @@ import org.apache.poi.util.Removal;
/** /**
* Icon / Multi-State Conditional Formatting Rule Record. * Icon / Multi-State Conditional Formatting Rule Record.
*/ */
public final class IconMultiStateFormatting implements Duplicatable { public final class IconMultiStateFormatting implements Duplicatable, GenericRecord {
private static final POILogger log = POILogFactory.getLogger(IconMultiStateFormatting.class); private static final POILogger LOG = POILogFactory.getLogger(IconMultiStateFormatting.class);
private static BitField ICON_ONLY = BitFieldFactory.getInstance(0x01);
private static BitField REVERSED = BitFieldFactory.getInstance(0x04);
private IconSet iconSet; private IconSet iconSet;
private byte options; private byte options;
private Threshold[] thresholds; private Threshold[] thresholds;
private static BitField iconOnly = BitFieldFactory.getInstance(0x01);
private static BitField reversed = BitFieldFactory.getInstance(0x04);
public IconMultiStateFormatting() { public IconMultiStateFormatting() {
iconSet = IconSet.GYR_3_TRAFFIC_LIGHTS; iconSet = IconSet.GYR_3_TRAFFIC_LIGHTS;
options = 0; options = 0;
@ -63,7 +68,7 @@ public final class IconMultiStateFormatting implements Duplicatable {
int set = in.readByte(); int set = in.readByte();
iconSet = IconSet.byId(set); iconSet = IconSet.byId(set);
if (iconSet.num != num) { if (iconSet.num != num) {
log.log(POILogger.WARN, "Inconsistent Icon Set defintion, found " + iconSet + " but defined as " + num + " entries"); LOG.log(POILogger.WARN, "Inconsistent Icon Set defintion, found " + iconSet + " but defined as " + num + " entries");
} }
options = in.readByte(); options = in.readByte();
@ -88,42 +93,36 @@ public final class IconMultiStateFormatting implements Duplicatable {
} }
public boolean isIconOnly() { public boolean isIconOnly() {
return getOptionFlag(iconOnly); return ICON_ONLY.isSet(options);
} }
public void setIconOnly(boolean only) { public void setIconOnly(boolean only) {
setOptionFlag(only, iconOnly); options = ICON_ONLY.setByteBoolean(options, only);
} }
public boolean isReversed() { public boolean isReversed() {
return getOptionFlag(reversed); return REVERSED.isSet(options);
} }
public void setReversed(boolean rev) { public void setReversed(boolean rev) {
setOptionFlag(rev, reversed); options = REVERSED.setByteBoolean(options, rev);
}
private boolean getOptionFlag(BitField field) {
int value = field.getValue(options);
return value==0 ? false : true;
}
private void setOptionFlag(boolean option, BitField field) {
options = field.setByteBoolean(options, option);
}
public String toString() {
StringBuilder buffer = new StringBuilder();
buffer.append(" [Icon Formatting]\n");
buffer.append(" .icon_set = ").append(iconSet).append("\n");
buffer.append(" .icon_only= ").append(isIconOnly()).append("\n");
buffer.append(" .reversed = ").append(isReversed()).append("\n");
for (Threshold t : thresholds) {
buffer.append(t);
}
buffer.append(" [/Icon Formatting]\n");
return buffer.toString();
} }
@Override @Override
@SuppressWarnings("squid:S2975") public Map<String, Supplier<?>> getGenericProperties() {
return GenericRecordUtil.getGenericProperties(
"iconSet", this::getIconSet,
"iconOnly", this::isIconOnly,
"reversed", this::isReversed,
"thresholds", this::getThresholds
);
}
public String toString() {
return GenericRecordJsonWriter.marshal(this);
}
@Override
@SuppressWarnings({"squid:S2975", "MethodDoesntCallSuperMethod"})
@Deprecated @Deprecated
@Removal(version = "5.0.0") @Removal(version = "5.0.0")
public IconMultiStateFormatting clone() { public IconMultiStateFormatting clone() {

View File

@ -17,9 +17,17 @@
package org.apache.poi.hssf.record.cf; package org.apache.poi.hssf.record.cf;
import static org.apache.poi.util.GenericRecordUtil.getEnumBitsAsString;
import java.util.Map;
import java.util.function.Supplier;
import org.apache.poi.common.Duplicatable; import org.apache.poi.common.Duplicatable;
import org.apache.poi.common.usermodel.GenericRecord;
import org.apache.poi.util.BitField; import org.apache.poi.util.BitField;
import org.apache.poi.util.BitFieldFactory; import org.apache.poi.util.BitFieldFactory;
import org.apache.poi.util.GenericRecordJsonWriter;
import org.apache.poi.util.GenericRecordUtil;
import org.apache.poi.util.LittleEndianInput; import org.apache.poi.util.LittleEndianInput;
import org.apache.poi.util.LittleEndianOutput; import org.apache.poi.util.LittleEndianOutput;
import org.apache.poi.util.Removal; import org.apache.poi.util.Removal;
@ -27,7 +35,7 @@ import org.apache.poi.util.Removal;
/** /**
* Pattern Formatting Block of the Conditional Formatting Rule Record. * Pattern Formatting Block of the Conditional Formatting Rule Record.
*/ */
public final class PatternFormatting implements Duplicatable { public final class PatternFormatting implements Duplicatable, GenericRecord {
/** No background */ /** No background */
public static final short NO_FILL = 0 ; public static final short NO_FILL = 0 ;
/** Solidly filled */ /** Solidly filled */
@ -162,18 +170,23 @@ public final class PatternFormatting implements Duplicatable {
return patternColorIndex.getValue(field_16_pattern_color_indexes); return patternColorIndex.getValue(field_16_pattern_color_indexes);
} }
@Override
public Map<String, Supplier<?>> getGenericProperties() {
return GenericRecordUtil.getGenericProperties(
"fillPattern", getEnumBitsAsString(this::getFillPattern,
new int[]{NO_FILL, SOLID_FOREGROUND, FINE_DOTS, ALT_BARS, SPARSE_DOTS, THICK_HORZ_BANDS, THICK_VERT_BANDS, THICK_BACKWARD_DIAG, THICK_FORWARD_DIAG, BIG_SPOTS, BRICKS, THIN_HORZ_BANDS, THIN_VERT_BANDS, THIN_BACKWARD_DIAG, THIN_FORWARD_DIAG, SQUARES, DIAMONDS, LESS_DOTS, LEAST_DOTS},
new String[]{"NO_FILL", "SOLID_FOREGROUND", "FINE_DOTS", "ALT_BARS", "SPARSE_DOTS", "THICK_HORZ_BANDS", "THICK_VERT_BANDS", "THICK_BACKWARD_DIAG", "THICK_FORWARD_DIAG", "BIG_SPOTS", "BRICKS", "THIN_HORZ_BANDS", "THIN_VERT_BANDS", "THIN_BACKWARD_DIAG", "THIN_FORWARD_DIAG", "SQUARES", "DIAMONDS", "LESS_DOTS", "LEAST_DOTS"}),
"fillForegroundColor", this::getFillForegroundColor,
"fillBackgroundColor", this::getFillForegroundColor
);
}
public String toString() { public String toString() {
StringBuilder buffer = new StringBuilder(); return GenericRecordJsonWriter.marshal(this);
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();
} }
@Override @Override
@SuppressWarnings("squid:S2975") @SuppressWarnings({"squid:S2975", "MethodDoesntCallSuperMethod"})
@Deprecated @Deprecated
@Removal(version = "5.0.0") @Removal(version = "5.0.0")
public PatternFormatting clone() { public PatternFormatting clone() {

View File

@ -17,18 +17,22 @@
package org.apache.poi.hssf.record.cf; package org.apache.poi.hssf.record.cf;
import java.util.Arrays; import java.util.Map;
import java.util.function.Supplier;
import org.apache.poi.common.usermodel.GenericRecord;
import org.apache.poi.ss.formula.Formula; import org.apache.poi.ss.formula.Formula;
import org.apache.poi.ss.formula.ptg.Ptg; import org.apache.poi.ss.formula.ptg.Ptg;
import org.apache.poi.ss.usermodel.ConditionalFormattingThreshold.RangeType; import org.apache.poi.ss.usermodel.ConditionalFormattingThreshold.RangeType;
import org.apache.poi.util.GenericRecordJsonWriter;
import org.apache.poi.util.GenericRecordUtil;
import org.apache.poi.util.LittleEndianInput; import org.apache.poi.util.LittleEndianInput;
import org.apache.poi.util.LittleEndianOutput; import org.apache.poi.util.LittleEndianOutput;
/** /**
* Threshold / value (CFVO) for changes in Conditional Formatting * Threshold / value (CFVO) for changes in Conditional Formatting
*/ */
public abstract class Threshold { public abstract class Threshold implements GenericRecord {
private byte type; private byte type;
private Formula formula; private Formula formula;
private Double value; private Double value;
@ -107,14 +111,17 @@ public abstract class Threshold {
return len; return len;
} }
@Override
public Map<String, Supplier<?>> getGenericProperties() {
return GenericRecordUtil.getGenericProperties(
"type", this::getType,
"formula", this::getFormula,
"value", this::getValue
);
}
public String toString() { public String toString() {
StringBuilder buffer = new StringBuilder(); return GenericRecordJsonWriter.marshal(this);
buffer.append(" [CF Threshold]\n");
buffer.append(" .type = ").append(Integer.toHexString(type)).append("\n");
buffer.append(" .formula = ").append(Arrays.toString(formula.getTokens())).append("\n");
buffer.append(" .value = ").append(value).append("\n");
buffer.append(" [/CF Threshold]\n");
return buffer.toString();
} }
public void serialize(LittleEndianOutput out) { public void serialize(LittleEndianOutput out) {

View File

@ -17,8 +17,13 @@
package org.apache.poi.hssf.record.common; package org.apache.poi.hssf.record.common;
import java.util.Map;
import java.util.function.Supplier;
import org.apache.poi.common.Duplicatable; import org.apache.poi.common.Duplicatable;
import org.apache.poi.util.HexDump; import org.apache.poi.common.usermodel.GenericRecord;
import org.apache.poi.util.GenericRecordJsonWriter;
import org.apache.poi.util.GenericRecordUtil;
import org.apache.poi.util.LittleEndianInput; import org.apache.poi.util.LittleEndianInput;
import org.apache.poi.util.LittleEndianOutput; import org.apache.poi.util.LittleEndianOutput;
import org.apache.poi.util.Removal; import org.apache.poi.util.Removal;
@ -32,7 +37,7 @@ import org.apache.poi.util.Removal;
* Formatting, Sheet Extensions), this XSSF-style color record * Formatting, Sheet Extensions), this XSSF-style color record
* can be used. * can be used.
*/ */
public final class ExtendedColor implements Duplicatable { public final class ExtendedColor implements Duplicatable, GenericRecord {
public static final int TYPE_AUTO = 0; public static final int TYPE_AUTO = 0;
public static final int TYPE_INDEXED = 1; public static final int TYPE_INDEXED = 1;
public static final int TYPE_RGB = 2; public static final int TYPE_RGB = 2;
@ -147,20 +152,23 @@ public final class ExtendedColor implements Duplicatable {
this.tint = tint; this.tint = tint;
} }
@Override
public Map<String, Supplier<?>> getGenericProperties() {
return GenericRecordUtil.getGenericProperties(
"type", this::getType,
"tint", this::getTint,
"colorIndex", this::getColorIndex,
"rgba", this::getRGBA,
"themeIndex", this::getThemeIndex
);
}
public String toString() { public String toString() {
StringBuilder buffer = new StringBuilder(); return GenericRecordJsonWriter.marshal(this);
buffer.append(" [Extended Color]\n");
buffer.append(" .type = ").append(type).append("\n");
buffer.append(" .tint = ").append(tint).append("\n");
buffer.append(" .c_idx = ").append(colorIndex).append("\n");
buffer.append(" .rgba = ").append(HexDump.toHex(rgba)).append("\n");
buffer.append(" .t_idx = ").append(themeIndex).append("\n");
buffer.append(" [/Extended Color]\n");
return buffer.toString();
} }
@Override @Override
@SuppressWarnings("squid:S2975") @SuppressWarnings({"squid:S2975", "MethodDoesntCallSuperMethod"})
@Deprecated @Deprecated
@Removal(version = "5.0.0") @Removal(version = "5.0.0")
public ExtendedColor clone() { public ExtendedColor clone() {

View File

@ -20,11 +20,11 @@
package org.apache.poi.ss.usermodel; package org.apache.poi.ss.usermodel;
/** /**
* High level representation for the Icon / Multi-State Formatting * High level representation for the Icon / Multi-State Formatting
* component of Conditional Formatting settings * component of Conditional Formatting settings
*/ */
public interface IconMultiStateFormatting { public interface IconMultiStateFormatting {
public enum IconSet { enum IconSet {
/** Green Up / Yellow Side / Red Down arrows */ /** Green Up / Yellow Side / Red Down arrows */
GYR_3_ARROW(0, 3, "3Arrows"), GYR_3_ARROW(0, 3, "3Arrows"),
/** Grey Up / Side / Down arrows */ /** Grey Up / Side / Down arrows */
@ -33,11 +33,11 @@ public interface IconMultiStateFormatting {
GYR_3_FLAGS(2, 3, "3Flags"), GYR_3_FLAGS(2, 3, "3Flags"),
/** Green / Yellow / Red traffic lights (no background). Default */ /** Green / Yellow / Red traffic lights (no background). Default */
GYR_3_TRAFFIC_LIGHTS(3, 3, "3TrafficLights1"), GYR_3_TRAFFIC_LIGHTS(3, 3, "3TrafficLights1"),
/** Green / Yellow / Red traffic lights on a black square background. /** Green / Yellow / Red traffic lights on a black square background.
* Note, MS-XLS docs v20141018 say this is id=5 but seems to be id=4 */ * Note, MS-XLS docs v20141018 say this is id=5 but seems to be id=4 */
GYR_3_TRAFFIC_LIGHTS_BOX(4, 3, "3TrafficLights2"), GYR_3_TRAFFIC_LIGHTS_BOX(4, 3, "3TrafficLights2"),
/** Green Circle / Yellow Triangle / Red Diamond. /** Green Circle / Yellow Triangle / Red Diamond.
* Note, MS-XLS docs v20141018 say this is id=4 but seems to be id=5 */ * Note, MS-XLS docs v20141018 say this is id=4 but seems to be id=5 */
GYR_3_SHAPES(5, 3, "3Signs"), GYR_3_SHAPES(5, 3, "3Signs"),
/** Green Tick / Yellow ! / Red Cross on a circle background */ /** Green Tick / Yellow ! / Red Cross on a circle background */
GYR_3_SYMBOLS_CIRCLE(6, 3, "3Symbols"), GYR_3_SYMBOLS_CIRCLE(6, 3, "3Symbols"),
@ -56,20 +56,18 @@ public interface IconMultiStateFormatting {
GREY_5_ARROWS(0xE, 5, "5ArrowsGray"), GREY_5_ARROWS(0xE, 5, "5ArrowsGray"),
RATINGS_5(0xF, 5, "5Rating"), RATINGS_5(0xF, 5, "5Rating"),
QUARTERS_5(0x10, 5, "5Quarters"); QUARTERS_5(0x10, 5, "5Quarters");
protected static final IconSet DEFAULT_ICONSET = IconSet.GYR_3_TRAFFIC_LIGHTS;
/** Numeric ID of the icon set */ /** Numeric ID of the icon set */
public final int id; public final int id;
/** How many icons in the set */ /** How many icons in the set */
public final int num; public final int num;
/** Name (system) of the set */ /** Name (system) of the set */
public final String name; public final String name;
public String toString() { public String toString() {
return id + " - " + name; return id + " - " + name;
} }
public static IconSet byId(int id) { public static IconSet byId(int id) {
return values()[id]; return values()[id];
} }
@ -79,26 +77,26 @@ public interface IconMultiStateFormatting {
} }
return null; return null;
} }
private IconSet(int id, int num, String name) { IconSet(int id, int num, String name) {
this.id = id; this.num = num; this.name = name; this.id = id; this.num = num; this.name = name;
} }
} }
/** /**
* Get the Icon Set used * Get the Icon Set used
*/ */
IconSet getIconSet(); IconSet getIconSet();
/** /**
* Changes the Icon Set used * Changes the Icon Set used
* *
* <p>If the new Icon Set has a different number of * <p>If the new Icon Set has a different number of
* icons to the old one, you <em>must</em> update the * icons to the old one, you <em>must</em> update the
* thresholds before saving!</p> * thresholds before saving!</p>
*/ */
void setIconSet(IconSet set); void setIconSet(IconSet set);
/** /**
* Should Icon + Value be displayed, or only the Icon? * Should Icon + Value be displayed, or only the Icon?
*/ */
@ -107,10 +105,10 @@ public interface IconMultiStateFormatting {
* Control if only the Icon is shown, or Icon + Value * Control if only the Icon is shown, or Icon + Value
*/ */
void setIconOnly(boolean only); void setIconOnly(boolean only);
boolean isReversed(); boolean isReversed();
void setReversed(boolean reversed); void setReversed(boolean reversed);
/** /**
* Gets the list of thresholds * Gets the list of thresholds
*/ */

View File

@ -563,8 +563,8 @@ public abstract class BaseTestConditionalFormatting {
ConditionalFormatting cf = sheetCF.getConditionalFormattingAt(i); ConditionalFormatting cf = sheetCF.getConditionalFormattingAt(i);
if (cf instanceof HSSFConditionalFormatting) { if (cf instanceof HSSFConditionalFormatting) {
String str = cf.toString(); String str = cf.toString();
if (str.contains("[CF]")) fCF++; if (str.contains("/* CF_RULE */")) fCF++;
if (str.contains("[CF12]")) fCF12++; if (str.contains("/* CF_RULE_12 */")) fCF12++;
if (str.contains("[CFEX]")) fCFEX++; if (str.contains("[CFEX]")) fCFEX++;
} else { } else {
ConditionType type = cf.getRule(cf.getNumberOfRules() - 1).getConditionType(); ConditionType type = cf.getRule(cf.getNumberOfRules() - 1).getConditionType();