From c41dee931f95c3d9747c5747316b49504bd15477 Mon Sep 17 00:00:00 2001 From: Andreas Beeker Date: Sun, 19 Apr 2020 20:33:54 +0000 Subject: [PATCH] #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 --- .../apache/poi/hssf/record/OldCellRecord.java | 66 ++--- .../poi/hssf/record/OldFormulaRecord.java | 20 +- .../poi/hssf/record/OldLabelRecord.java | 17 +- .../poi/hssf/record/OldSheetRecord.java | 41 ++- .../poi/hssf/record/OldStringRecord.java | 26 +- .../record/aggregates/CFRecordsAggregate.java | 31 +- .../poi/hssf/record/cf/BorderFormatting.java | 43 +-- .../record/cf/ColorGradientFormatting.java | 34 ++- .../record/cf/ColorGradientThreshold.java | 12 +- .../poi/hssf/record/cf/DataBarFormatting.java | 54 ++-- .../poi/hssf/record/cf/FontFormatting.java | 278 ++++++------------ .../record/cf/IconMultiStateFormatting.java | 63 ++-- .../poi/hssf/record/cf/PatternFormatting.java | 31 +- .../apache/poi/hssf/record/cf/Threshold.java | 25 +- .../poi/hssf/record/common/ExtendedColor.java | 32 +- .../usermodel/IconMultiStateFormatting.java | 32 +- .../BaseTestConditionalFormatting.java | 4 +- 17 files changed, 400 insertions(+), 409 deletions(-) diff --git a/src/java/org/apache/poi/hssf/record/OldCellRecord.java b/src/java/org/apache/poi/hssf/record/OldCellRecord.java index 76f2dd300d..308cf43475 100644 --- a/src/java/org/apache/poi/hssf/record/OldCellRecord.java +++ b/src/java/org/apache/poi/hssf/record/OldCellRecord.java @@ -17,16 +17,21 @@ 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}). * 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 boolean isBiff2; + private final boolean isBiff2; private final int field_1_row; private final short field_2_column; private int field_3_cell_attrs; // Biff 2 @@ -37,7 +42,7 @@ public abstract class OldCellRecord { this.isBiff2 = isBiff2; field_1_row = in.readUShort(); field_2_column = in.readShort(); - + if (isBiff2) { field_3_cell_attrs = in.readUShort() << 8; field_3_cell_attrs += in.readUByte(); @@ -63,7 +68,7 @@ public abstract class OldCellRecord { public final short getXFIndex() { return field_3_xf_index; } - + public int getCellAttrs() { return field_3_cell_attrs; @@ -71,49 +76,30 @@ public abstract class OldCellRecord { /** * Is this a Biff2 record, or newer? - * + * * @return true, if this is a Biff2 record or newer */ public boolean isBiff2() { return isBiff2; } - + public short getSid() { return sid; } - + + @Override + public Map> getGenericProperties() { + return GenericRecordUtil.getGenericProperties( + "row", this::getRow, + "column", this::getColumn, + "biff2", this::isBiff2, + "biff2CellAttrs", this::getCellAttrs, + "xfIndex", this::getXFIndex + ); + } + @Override public final String toString() { - StringBuilder sb = new StringBuilder(); - 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(); + return GenericRecordJsonWriter.marshal(this); } - - /** - * 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(); } diff --git a/src/java/org/apache/poi/hssf/record/OldFormulaRecord.java b/src/java/org/apache/poi/hssf/record/OldFormulaRecord.java index f6b2914606..e1755eb188 100644 --- a/src/java/org/apache/poi/hssf/record/OldFormulaRecord.java +++ b/src/java/org/apache/poi/hssf/record/OldFormulaRecord.java @@ -17,9 +17,13 @@ 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.ptg.Ptg; import org.apache.poi.ss.usermodel.CellType; +import org.apache.poi.util.GenericRecordUtil; /** * Formula Record (0x0006 / 0x0206 / 0x0406) - holds a formula in @@ -103,10 +107,18 @@ public final class OldFormulaRecord extends OldCellRecord { return field_6_parsed_expr; } - protected void appendValueText(StringBuilder sb) { - sb.append(" .value = ").append(getValue()).append("\n"); + @Override + public HSSFRecordTypes getGenericRecordType() { + return HSSFRecordTypes.FORMULA; } - protected String getRecordName() { - return "Old Formula"; + + @Override + public Map> getGenericProperties() { + return GenericRecordUtil.getGenericProperties( + "base", super::getGenericProperties, + "options", this::getOptions, + "formula", this::getFormula, + "value", this::getValue + ); } } diff --git a/src/java/org/apache/poi/hssf/record/OldLabelRecord.java b/src/java/org/apache/poi/hssf/record/OldLabelRecord.java index 6dd80e911e..8a4697ff12 100644 --- a/src/java/org/apache/poi/hssf/record/OldLabelRecord.java +++ b/src/java/org/apache/poi/hssf/record/OldLabelRecord.java @@ -17,6 +17,10 @@ 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.IOUtils; import org.apache.poi.util.POILogFactory; @@ -104,13 +108,16 @@ public final class OldLabelRecord extends OldCellRecord { } @Override - protected void appendValueText(StringBuilder sb) { - sb.append(" .string_len= ").append(HexDump.shortToHex(field_4_string_len)).append("\n"); - sb.append(" .value = ").append(getValue()).append("\n"); + public HSSFRecordTypes getGenericRecordType() { + return HSSFRecordTypes.LABEL; } @Override - protected String getRecordName() { - return "OLD LABEL"; + public Map> getGenericProperties() { + return GenericRecordUtil.getGenericProperties( + "base", super::getGenericProperties, + "stringLength", this::getStringLength, + "value", this::getValue + ); } } diff --git a/src/java/org/apache/poi/hssf/record/OldSheetRecord.java b/src/java/org/apache/poi/hssf/record/OldSheetRecord.java index 2abec6cb8c..9f2120c393 100644 --- a/src/java/org/apache/poi/hssf/record/OldSheetRecord.java +++ b/src/java/org/apache/poi/hssf/record/OldSheetRecord.java @@ -18,8 +18,12 @@ package org.apache.poi.hssf.record; 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.RecordFormatException; @@ -29,17 +33,17 @@ import org.apache.poi.util.RecordFormatException; * and tells where the Beginning of file record is within the HSSF * file. */ -public final class OldSheetRecord { +public final class OldSheetRecord implements GenericRecord { //arbitrarily selected; may need to increase private static final int MAX_RECORD_LENGTH = 100_000; public static final short sid = 0x0085; - private int field_1_position_of_BOF; - private int field_2_visibility; - private int field_3_type; - private byte[] field_5_sheetname; + private final int field_1_position_of_BOF; + private final int field_2_visibility; + private final int field_3_type; + private final byte[] field_5_sheetname; private CodepageRecord codepage; public OldSheetRecord(RecordInputStream in) { @@ -89,15 +93,22 @@ public final class OldSheetRecord { return OldStringRecord.getString(field_5_sheetname, codepage); } - public String toString() { - StringBuilder buffer = new StringBuilder(); + @Override + public HSSFRecordTypes getGenericRecordType() { + return HSSFRecordTypes.BOUND_SHEET; + } - buffer.append("[BOUNDSHEET]\n"); - buffer.append(" .bof = ").append(HexDump.intToHex(getPositionOfBof())).append("\n"); - buffer.append(" .visibility = ").append(HexDump.shortToHex(field_2_visibility)).append("\n"); - buffer.append(" .type = ").append(HexDump.byteToHex(field_3_type)).append("\n"); - buffer.append(" .sheetname = ").append(getSheetname()).append("\n"); - buffer.append("[/BOUNDSHEET]\n"); - return buffer.toString(); + @Override + public Map> getGenericProperties() { + return GenericRecordUtil.getGenericProperties( + "bof", this::getPositionOfBof, + "visibility", () -> field_2_visibility, + "type", () -> field_3_type, + "sheetName", this::getSheetname + ); + } + + public String toString() { + return GenericRecordJsonWriter.marshal(this); } } diff --git a/src/java/org/apache/poi/hssf/record/OldStringRecord.java b/src/java/org/apache/poi/hssf/record/OldStringRecord.java index 87140b7fc9..e81a2aa4b8 100644 --- a/src/java/org/apache/poi/hssf/record/OldStringRecord.java +++ b/src/java/org/apache/poi/hssf/record/OldStringRecord.java @@ -18,9 +18,14 @@ package org.apache.poi.hssf.record; 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.util.CodePageUtil; +import org.apache.poi.util.GenericRecordJsonWriter; +import org.apache.poi.util.GenericRecordUtil; 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 * formula string results. */ -public final class OldStringRecord { +public final class OldStringRecord implements GenericRecord { //arbitrarily selected; may need to increase private static final int MAX_RECORD_LENGTH = 100_000; @@ -90,14 +95,17 @@ public final class OldStringRecord { } } - public String toString() - { - StringBuilder buffer = new StringBuilder(); + @Override + public HSSFRecordTypes getGenericRecordType() { + return HSSFRecordTypes.STRING; + } - buffer.append("[OLD STRING]\n"); - buffer.append(" .string = ") - .append(getString()).append("\n"); - buffer.append("[/OLD STRING]\n"); - return buffer.toString(); + @Override + public Map> getGenericProperties() { + return GenericRecordUtil.getGenericProperties("string", this::getString); + } + + public String toString() { + return GenericRecordJsonWriter.marshal(this); } } diff --git a/src/java/org/apache/poi/hssf/record/aggregates/CFRecordsAggregate.java b/src/java/org/apache/poi/hssf/record/aggregates/CFRecordsAggregate.java index 87c5798df8..42b9ada2e4 100644 --- a/src/java/org/apache/poi/hssf/record/aggregates/CFRecordsAggregate.java +++ b/src/java/org/apache/poi/hssf/record/aggregates/CFRecordsAggregate.java @@ -19,7 +19,10 @@ package org.apache.poi.hssf.record.aggregates; import java.util.ArrayList; 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.record.CFHeader12Record; 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.usermodel.helpers.BaseRowColShifter; 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.POILogger; 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, * not a file format one.

*/ -public final class CFRecordsAggregate extends RecordAggregate { +public final class CFRecordsAggregate extends RecordAggregate implements GenericRecord { /** Excel 97-2003 allows up to 3 conditional formating rules */ private static final int MAX_97_2003_CONDTIONAL_FORMAT_RULES = 3; private static final POILogger logger = POILogFactory.getLogger(CFRecordsAggregate.class); @@ -188,25 +193,19 @@ public final class CFRecordsAggregate extends RecordAggregate { return rules.size(); } + @Override + public Map> getGenericProperties() { + return GenericRecordUtil.getGenericProperties( + "header", this::getHeader, + "rules", () -> rules + ); + } + /** * String representation of CFRecordsAggregate */ public String toString() { - StringBuilder buffer = new StringBuilder(); - 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(); + return GenericRecordJsonWriter.marshal(this); } public void visitContainedRecords(RecordVisitor rv) { diff --git a/src/java/org/apache/poi/hssf/record/cf/BorderFormatting.java b/src/java/org/apache/poi/hssf/record/cf/BorderFormatting.java index a87a24a81b..f1dd9ec413 100644 --- a/src/java/org/apache/poi/hssf/record/cf/BorderFormatting.java +++ b/src/java/org/apache/poi/hssf/record/cf/BorderFormatting.java @@ -17,9 +17,16 @@ 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.usermodel.GenericRecord; import org.apache.poi.util.BitField; import org.apache.poi.util.BitFieldFactory; +import org.apache.poi.util.GenericRecordJsonWriter; import org.apache.poi.util.LittleEndian; import org.apache.poi.util.LittleEndianInput; 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. */ -public final class BorderFormatting implements Duplicatable { +public final class BorderFormatting implements Duplicatable, GenericRecord { /** No border */ public static final short BORDER_NONE = 0x0; /** Thin border */ @@ -436,26 +443,28 @@ public final class BorderFormatting implements Duplicatable { return bordTlBrLineOnOff.isSet(field_13_border_styles1); } + @Override + public Map> getGenericProperties() { + final Map> 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() { - StringBuilder buffer = new StringBuilder(); - 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(); + return GenericRecordJsonWriter.marshal(this); } @Override - @SuppressWarnings("squid:S2975") + @SuppressWarnings({"squid:S2975", "MethodDoesntCallSuperMethod"}) @Deprecated @Removal(version = "5.0.0") public BorderFormatting clone() { @@ -467,7 +476,7 @@ public final class BorderFormatting implements Duplicatable { } 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); return 8; } diff --git a/src/java/org/apache/poi/hssf/record/cf/ColorGradientFormatting.java b/src/java/org/apache/poi/hssf/record/cf/ColorGradientFormatting.java index 830d24fd73..26c18b50de 100644 --- a/src/java/org/apache/poi/hssf/record/cf/ColorGradientFormatting.java +++ b/src/java/org/apache/poi/hssf/record/cf/ColorGradientFormatting.java @@ -17,12 +17,17 @@ package org.apache.poi.hssf.record.cf; +import java.util.Map; +import java.util.function.Supplier; import java.util.stream.Stream; 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.util.BitField; 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.LittleEndianOutput; 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 * 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 BitField clamp = BitFieldFactory.getInstance(0x01); private static final BitField background = BitFieldFactory.getInstance(0x02); - private byte options; + private final byte options; private ColorGradientThreshold[] thresholds; private ExtendedColor[] colors; @@ -132,23 +137,22 @@ public final class ColorGradientFormatting implements Duplicatable { } } + @Override + public Map> getGenericProperties() { + return GenericRecordUtil.getGenericProperties( + "clampToCurve", this::isClampToCurve, + "background", this::isAppliesToBackground, + "thresholds", this::getThresholds, + "colors", this::getColors + ); + } + public String toString() { - StringBuilder buffer = new StringBuilder(); - 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(); + return GenericRecordJsonWriter.marshal(this); } @Override - @SuppressWarnings("squid:S2975") + @SuppressWarnings({"squid:S2975", "MethodDoesntCallSuperMethod"}) @Deprecated @Removal(version = "5.0.0") public ColorGradientFormatting clone() { diff --git a/src/java/org/apache/poi/hssf/record/cf/ColorGradientThreshold.java b/src/java/org/apache/poi/hssf/record/cf/ColorGradientThreshold.java index 9c41995dbd..6335237813 100644 --- a/src/java/org/apache/poi/hssf/record/cf/ColorGradientThreshold.java +++ b/src/java/org/apache/poi/hssf/record/cf/ColorGradientThreshold.java @@ -17,7 +17,12 @@ 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.usermodel.GenericRecord; +import org.apache.poi.util.GenericRecordUtil; import org.apache.poi.util.LittleEndianInput; import org.apache.poi.util.LittleEndianOutput; import org.apache.poi.util.Removal; @@ -26,7 +31,7 @@ import org.apache.poi.util.Removal; * Color Gradient / Color Scale specific Threshold / value (CFVO), * 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; public ColorGradientThreshold() { @@ -72,4 +77,9 @@ public final class ColorGradientThreshold extends Threshold implements Duplicata super.serialize(out); out.writeDouble(position); } + + @Override + public Map> getGenericProperties() { + return GenericRecordUtil.getGenericProperties("position", this::getPosition); + } } diff --git a/src/java/org/apache/poi/hssf/record/cf/DataBarFormatting.java b/src/java/org/apache/poi/hssf/record/cf/DataBarFormatting.java index 466fad4990..a0f29b1d05 100644 --- a/src/java/org/apache/poi/hssf/record/cf/DataBarFormatting.java +++ b/src/java/org/apache/poi/hssf/record/cf/DataBarFormatting.java @@ -17,10 +17,18 @@ 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.usermodel.GenericRecord; import org.apache.poi.hssf.record.common.ExtendedColor; import org.apache.poi.util.BitField; 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.LittleEndianOutput; import org.apache.poi.util.POILogFactory; @@ -30,11 +38,11 @@ import org.apache.poi.util.Removal; /** * Data Bar Conditional Formatting Rule Record. */ -public final class DataBarFormatting implements Duplicatable { - private static POILogger log = POILogFactory.getLogger(DataBarFormatting.class); +public final class DataBarFormatting implements Duplicatable, GenericRecord { + private static final POILogger LOG = POILogFactory.getLogger(DataBarFormatting.class); - private static final BitField iconOnly = BitFieldFactory.getInstance(0x01); - private static final BitField reversed = BitFieldFactory.getInstance(0x04); + private static final BitField ICON_ONLY = BitFieldFactory.getInstance(0x01); + private static final BitField REVERSED = BitFieldFactory.getInstance(0x04); private byte options; private byte percentMin; @@ -64,9 +72,9 @@ public final class DataBarFormatting implements Duplicatable { percentMin = in.readByte(); percentMax = in.readByte(); 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) - log.log(POILogger.WARN, "Inconsistent Minimum Percentage found " + percentMin); + LOG.log(POILogger.WARN, "Inconsistent Minimum Percentage found " + percentMin); color = new ExtendedColor(in); thresholdMin = new DataBarThreshold(in); @@ -74,22 +82,22 @@ public final class DataBarFormatting implements Duplicatable { } public boolean isIconOnly() { - return getOptionFlag(iconOnly); + return getOptionFlag(ICON_ONLY); } public void setIconOnly(boolean only) { - setOptionFlag(only, iconOnly); + setOptionFlag(only, ICON_ONLY); } public boolean isReversed() { - return getOptionFlag(reversed); + return getOptionFlag(REVERSED); } public void setReversed(boolean rev) { - setOptionFlag(rev, reversed); + setOptionFlag(rev, REVERSED); } private boolean getOptionFlag(BitField field) { int value = field.getValue(options); - return value==0 ? false : true; + return value != 0; } private void setOptionFlag(boolean option, BitField field) { options = field.setByteBoolean(options, option); @@ -130,20 +138,24 @@ public final class DataBarFormatting implements Duplicatable { this.thresholdMax = thresholdMax; } + @Override + public Map> 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() { - StringBuilder buffer = new StringBuilder(); - 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(); + return GenericRecordJsonWriter.marshal(this); } @Override - @SuppressWarnings("squid:S2975") + @SuppressWarnings({"squid:S2975", "MethodDoesntCallSuperMethod"}) @Deprecated @Removal(version = "5.0.0") public DataBarFormatting clone() { diff --git a/src/java/org/apache/poi/hssf/record/cf/FontFormatting.java b/src/java/org/apache/poi/hssf/record/cf/FontFormatting.java index d8b2d11275..afed4f1e02 100644 --- a/src/java/org/apache/poi/hssf/record/cf/FontFormatting.java +++ b/src/java/org/apache/poi/hssf/record/cf/FontFormatting.java @@ -18,19 +18,27 @@ 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.usermodel.GenericRecord; import org.apache.poi.hssf.record.RecordInputStream; import org.apache.poi.util.BitField; import org.apache.poi.util.BitFieldFactory; +import org.apache.poi.util.GenericRecordJsonWriter; import org.apache.poi.util.LittleEndian; import org.apache.poi.util.Removal; /** * 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_HEIGHT = 64; 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; - // 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 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); + // option flags and font options masks + // in the options flags, a true bit activates the overriding and in the font option the bit sets the state + 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 CANCELLATION = BitFieldFactory.getInstance(0x00000080); /** * Escapement type - None @@ -166,7 +168,7 @@ public final class FontFormatting implements Duplicatable { } 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) { @@ -202,8 +204,7 @@ public final class FontFormatting implements Duplicatable { * @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); } @@ -212,20 +213,17 @@ public final class FontFormatting implements Duplicatable { * * @return fontheight (in points/20); or -1 if not modified */ - public int getFontHeight() - { + public int getFontHeight() { 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); options = field.setBoolean(options, option); setInt(OFFSET_FONT_OPTIONS, options); } - private boolean getFontOption(BitField field) - { + private boolean getFontOption(BitField field) { int options = getInt(OFFSET_FONT_OPTIONS); return field.isSet(options); } @@ -237,9 +235,8 @@ public final class FontFormatting implements Duplicatable { * @see #setFontOption(boolean, org.apache.poi.util.BitField) */ - public void setItalic(boolean italic) - { - setFontOption(italic, posture); + public void setItalic(boolean italic) { + setFontOption(italic, POSTURE); } /** @@ -249,29 +246,24 @@ public final class FontFormatting implements Duplicatable { * @see #getFontOption(org.apache.poi.util.BitField) */ - public boolean isItalic() - { - return getFontOption(posture); + public boolean isItalic() { + return getFontOption(POSTURE); } - public void setOutline(boolean on) - { - setFontOption(on, outline); + public void setOutline(boolean on) { + setFontOption(on, OUTLINE); } - public boolean isOutlineOn() - { - return getFontOption(outline); + public boolean isOutlineOn() { + return getFontOption(OUTLINE); } - public void setShadow(boolean on) - { - setFontOption(on, shadow); + public void setShadow(boolean on) { + setFontOption(on, SHADOW); } - public boolean isShadowOn() - { - return getFontOption(shadow); + public boolean isShadowOn() { + return getFontOption(SHADOW); } /** @@ -279,9 +271,8 @@ public final class FontFormatting implements Duplicatable { * * @param strike - whether the font is stricken out or not */ - public void setStrikeout(boolean strike) - { - setFontOption(strike, cancellation); + public void setStrikeout(boolean strike) { + setFontOption(strike, CANCELLATION); } /** @@ -290,9 +281,8 @@ public final class FontFormatting implements Duplicatable { * @return strike - whether the font is stricken out or not * @see #getFontOption(org.apache.poi.util.BitField) */ - public boolean isStruckout() - { - return getFontOption(cancellation); + public boolean isStruckout() { + return getFontOption(CANCELLATION); } /** @@ -301,7 +291,6 @@ public final class FontFormatting implements Duplicatable { * * @param bw - a number between 100-1000 for the fonts "boldness" */ - private void setFontWeight(short 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 */ - public void setBold(boolean bold) - { + public void setBold(boolean bold) { 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" */ - - public short getFontWeight() - { + public short getFontWeight() { return getShort(OFFSET_FONT_WEIGHT); } @@ -333,9 +319,7 @@ public final class FontFormatting implements Duplicatable { * * @return bold - whether the font is bold or not */ - - public boolean isBold() - { + public boolean isBold() { 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_SUB */ - public short getEscapementType() - { + public short getEscapementType() { 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_SUB */ - public void setEscapementType( short escapementType) - { + public void setEscapementType( short 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_DOUBLE_ACCOUNTING */ - public short getUnderlineType() - { + public short getUnderlineType() { 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_DOUBLE_ACCOUNTING */ - public void setUnderlineType( short underlineType) - { + public void setUnderlineType( short underlineType) { setShort(OFFSET_UNDERLINE_TYPE, underlineType); } - public short getFontColorIndex() - { + public short getFontColorIndex() { return (short)getInt(OFFSET_FONT_COLOR_INDEX); } - public void setFontColorIndex(short fci ) - { + public void setFontColorIndex(short fci ) { setInt(OFFSET_FONT_COLOR_INDEX,fci); } @@ -414,8 +392,7 @@ public final class FontFormatting implements Duplicatable { return value == 0; } - private void setOptionFlag(boolean modified, BitField field) - { + private void setOptionFlag(boolean modified, BitField field) { int value = modified? 0 : 1; int optionFlags = getInt(OFFSET_OPTION_FLAGS); optionFlags = field.setValue(optionFlags, value); @@ -423,161 +400,92 @@ public final class FontFormatting implements Duplicatable { } - public boolean isFontStyleModified() - { - return getOptionFlag(styleModified); + public boolean isFontStyleModified() { + return getOptionFlag(POSTURE); } - public void setFontStyleModified(boolean modified) - { - setOptionFlag(modified, styleModified); + public void setFontStyleModified(boolean modified) { + setOptionFlag(modified, POSTURE); } - public boolean isFontOutlineModified() - { - return getOptionFlag(outlineModified); + public boolean isFontOutlineModified() { + return getOptionFlag(OUTLINE); } - public void setFontOutlineModified(boolean modified) - { - setOptionFlag(modified, outlineModified); + public void setFontOutlineModified(boolean modified) { + setOptionFlag(modified, OUTLINE); } - public boolean isFontShadowModified() - { - return getOptionFlag(shadowModified); + public boolean isFontShadowModified() { + return getOptionFlag(SHADOW); } - public void setFontShadowModified(boolean modified) - { - setOptionFlag(modified, shadowModified); + public void setFontShadowModified(boolean modified) { + setOptionFlag(modified, SHADOW); } - public void setFontCancellationModified(boolean modified) - { - setOptionFlag(modified, cancellationModified); + public void setFontCancellationModified(boolean modified) { + setOptionFlag(modified, CANCELLATION); } - public boolean isFontCancellationModified() - { - return getOptionFlag(cancellationModified); + public boolean isFontCancellationModified() { + return getOptionFlag(CANCELLATION); } - public void setEscapementTypeModified(boolean modified) - { + public void setEscapementTypeModified(boolean modified) { int value = modified? 0 : 1; setInt(OFFSET_ESCAPEMENT_TYPE_MODIFIED, value); } - public boolean isEscapementTypeModified() - { + + public boolean isEscapementTypeModified() { int escapementModified = getInt(OFFSET_ESCAPEMENT_TYPE_MODIFIED); return escapementModified == 0; } - public void setUnderlineTypeModified(boolean modified) - { + public void setUnderlineTypeModified(boolean modified) { int value = modified? 0 : 1; setInt(OFFSET_UNDERLINE_TYPE_MODIFIED, value); } - public boolean isUnderlineTypeModified() - { + public boolean isUnderlineTypeModified() { int underlineModified = getInt(OFFSET_UNDERLINE_TYPE_MODIFIED); return underlineModified == 0; } - public void setFontWieghtModified(boolean modified) - { + public void setFontWieghtModified(boolean modified) { int value = modified? 0 : 1; setInt(OFFSET_FONT_WEIGHT_MODIFIED, value); } - public boolean isFontWeightModified() - { + public boolean isFontWeightModified() { int fontStyleModified = getInt(OFFSET_FONT_WEIGHT_MODIFIED); return fontStyleModified == 0; } - public String toString() - { - StringBuilder buffer = new StringBuilder(); - buffer.append(" [Font Formatting]\n"); + @Override + public Map> getGenericProperties() { + final Map> m = new LinkedHashMap<>(); + 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"); - - 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(); + public String toString() { + return GenericRecordJsonWriter.marshal(this); } @Override diff --git a/src/java/org/apache/poi/hssf/record/cf/IconMultiStateFormatting.java b/src/java/org/apache/poi/hssf/record/cf/IconMultiStateFormatting.java index 08d3ea04f6..85ffc30056 100644 --- a/src/java/org/apache/poi/hssf/record/cf/IconMultiStateFormatting.java +++ b/src/java/org/apache/poi/hssf/record/cf/IconMultiStateFormatting.java @@ -17,12 +17,17 @@ package org.apache.poi.hssf.record.cf; +import java.util.Map; +import java.util.function.Supplier; import java.util.stream.Stream; 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.util.BitField; 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.LittleEndianOutput; import org.apache.poi.util.POILogFactory; @@ -32,16 +37,16 @@ import org.apache.poi.util.Removal; /** * Icon / Multi-State Conditional Formatting Rule Record. */ -public final class IconMultiStateFormatting implements Duplicatable { - private static final POILogger log = POILogFactory.getLogger(IconMultiStateFormatting.class); +public final class IconMultiStateFormatting implements Duplicatable, GenericRecord { + 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 byte options; private Threshold[] thresholds; - private static BitField iconOnly = BitFieldFactory.getInstance(0x01); - private static BitField reversed = BitFieldFactory.getInstance(0x04); - public IconMultiStateFormatting() { iconSet = IconSet.GYR_3_TRAFFIC_LIGHTS; options = 0; @@ -63,7 +68,7 @@ public final class IconMultiStateFormatting implements Duplicatable { int set = in.readByte(); iconSet = IconSet.byId(set); 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(); @@ -88,42 +93,36 @@ public final class IconMultiStateFormatting implements Duplicatable { } public boolean isIconOnly() { - return getOptionFlag(iconOnly); + return ICON_ONLY.isSet(options); } public void setIconOnly(boolean only) { - setOptionFlag(only, iconOnly); + options = ICON_ONLY.setByteBoolean(options, only); } public boolean isReversed() { - return getOptionFlag(reversed); + return REVERSED.isSet(options); } + public void setReversed(boolean rev) { - setOptionFlag(rev, reversed); - } - - 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(); + options = REVERSED.setByteBoolean(options, rev); } @Override - @SuppressWarnings("squid:S2975") + public Map> 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 @Removal(version = "5.0.0") public IconMultiStateFormatting clone() { diff --git a/src/java/org/apache/poi/hssf/record/cf/PatternFormatting.java b/src/java/org/apache/poi/hssf/record/cf/PatternFormatting.java index e03e652698..b495d6183d 100644 --- a/src/java/org/apache/poi/hssf/record/cf/PatternFormatting.java +++ b/src/java/org/apache/poi/hssf/record/cf/PatternFormatting.java @@ -17,9 +17,17 @@ 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.usermodel.GenericRecord; import org.apache.poi.util.BitField; 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.LittleEndianOutput; 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. */ -public final class PatternFormatting implements Duplicatable { +public final class PatternFormatting implements Duplicatable, GenericRecord { /** No background */ public static final short NO_FILL = 0 ; /** Solidly filled */ @@ -162,18 +170,23 @@ public final class PatternFormatting implements Duplicatable { return patternColorIndex.getValue(field_16_pattern_color_indexes); } + @Override + public Map> 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() { - StringBuilder buffer = new StringBuilder(); - 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(); + return GenericRecordJsonWriter.marshal(this); } @Override - @SuppressWarnings("squid:S2975") + @SuppressWarnings({"squid:S2975", "MethodDoesntCallSuperMethod"}) @Deprecated @Removal(version = "5.0.0") public PatternFormatting clone() { diff --git a/src/java/org/apache/poi/hssf/record/cf/Threshold.java b/src/java/org/apache/poi/hssf/record/cf/Threshold.java index 4ce6a1e107..6c161d7927 100644 --- a/src/java/org/apache/poi/hssf/record/cf/Threshold.java +++ b/src/java/org/apache/poi/hssf/record/cf/Threshold.java @@ -17,18 +17,22 @@ 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.ptg.Ptg; 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.LittleEndianOutput; /** * Threshold / value (CFVO) for changes in Conditional Formatting */ -public abstract class Threshold { +public abstract class Threshold implements GenericRecord { private byte type; private Formula formula; private Double value; @@ -107,14 +111,17 @@ public abstract class Threshold { return len; } + @Override + public Map> getGenericProperties() { + return GenericRecordUtil.getGenericProperties( + "type", this::getType, + "formula", this::getFormula, + "value", this::getValue + ); + } + public String toString() { - StringBuilder buffer = new StringBuilder(); - 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(); + return GenericRecordJsonWriter.marshal(this); } public void serialize(LittleEndianOutput out) { diff --git a/src/java/org/apache/poi/hssf/record/common/ExtendedColor.java b/src/java/org/apache/poi/hssf/record/common/ExtendedColor.java index 145b2e2085..af6e889a7a 100644 --- a/src/java/org/apache/poi/hssf/record/common/ExtendedColor.java +++ b/src/java/org/apache/poi/hssf/record/common/ExtendedColor.java @@ -17,8 +17,13 @@ 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.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.LittleEndianOutput; import org.apache.poi.util.Removal; @@ -32,7 +37,7 @@ import org.apache.poi.util.Removal; * Formatting, Sheet Extensions), this XSSF-style color record * 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_INDEXED = 1; public static final int TYPE_RGB = 2; @@ -147,20 +152,23 @@ public final class ExtendedColor implements Duplicatable { this.tint = tint; } + @Override + public Map> getGenericProperties() { + return GenericRecordUtil.getGenericProperties( + "type", this::getType, + "tint", this::getTint, + "colorIndex", this::getColorIndex, + "rgba", this::getRGBA, + "themeIndex", this::getThemeIndex + ); + } + public String toString() { - StringBuilder buffer = new StringBuilder(); - 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(); + return GenericRecordJsonWriter.marshal(this); } @Override - @SuppressWarnings("squid:S2975") + @SuppressWarnings({"squid:S2975", "MethodDoesntCallSuperMethod"}) @Deprecated @Removal(version = "5.0.0") public ExtendedColor clone() { diff --git a/src/java/org/apache/poi/ss/usermodel/IconMultiStateFormatting.java b/src/java/org/apache/poi/ss/usermodel/IconMultiStateFormatting.java index 24eebdf201..d99630996f 100644 --- a/src/java/org/apache/poi/ss/usermodel/IconMultiStateFormatting.java +++ b/src/java/org/apache/poi/ss/usermodel/IconMultiStateFormatting.java @@ -20,11 +20,11 @@ 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 */ public interface IconMultiStateFormatting { - public enum IconSet { + enum IconSet { /** Green Up / Yellow Side / Red Down arrows */ GYR_3_ARROW(0, 3, "3Arrows"), /** Grey Up / Side / Down arrows */ @@ -33,11 +33,11 @@ public interface IconMultiStateFormatting { GYR_3_FLAGS(2, 3, "3Flags"), /** Green / Yellow / Red traffic lights (no background). Default */ 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 */ GYR_3_TRAFFIC_LIGHTS_BOX(4, 3, "3TrafficLights2"), /** 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"), /** Green Tick / Yellow ! / Red Cross on a circle background */ GYR_3_SYMBOLS_CIRCLE(6, 3, "3Symbols"), @@ -56,20 +56,18 @@ public interface IconMultiStateFormatting { GREY_5_ARROWS(0xE, 5, "5ArrowsGray"), RATINGS_5(0xF, 5, "5Rating"), QUARTERS_5(0x10, 5, "5Quarters"); - - protected static final IconSet DEFAULT_ICONSET = IconSet.GYR_3_TRAFFIC_LIGHTS; - + /** Numeric ID of the icon set */ public final int id; /** How many icons in the set */ public final int num; /** Name (system) of the set */ public final String name; - + public String toString() { return id + " - " + name; } - + public static IconSet byId(int id) { return values()[id]; } @@ -79,26 +77,26 @@ public interface IconMultiStateFormatting { } 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; } } - + /** * Get the Icon Set used */ IconSet getIconSet(); - + /** * Changes the Icon Set used - * + * *

If the new Icon Set has a different number of * icons to the old one, you must update the * thresholds before saving!

*/ void setIconSet(IconSet set); - + /** * 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 */ void setIconOnly(boolean only); - + boolean isReversed(); void setReversed(boolean reversed); - + /** * Gets the list of thresholds */ diff --git a/src/testcases/org/apache/poi/ss/usermodel/BaseTestConditionalFormatting.java b/src/testcases/org/apache/poi/ss/usermodel/BaseTestConditionalFormatting.java index fd33cf0319..5b17cc964d 100644 --- a/src/testcases/org/apache/poi/ss/usermodel/BaseTestConditionalFormatting.java +++ b/src/testcases/org/apache/poi/ss/usermodel/BaseTestConditionalFormatting.java @@ -563,8 +563,8 @@ public abstract class BaseTestConditionalFormatting { ConditionalFormatting cf = sheetCF.getConditionalFormattingAt(i); if (cf instanceof HSSFConditionalFormatting) { String str = cf.toString(); - if (str.contains("[CF]")) fCF++; - if (str.contains("[CF12]")) fCF12++; + if (str.contains("/* CF_RULE */")) fCF++; + if (str.contains("/* CF_RULE_12 */")) fCF12++; if (str.contains("[CFEX]")) fCFEX++; } else { ConditionType type = cf.getRule(cf.getNumberOfRules() - 1).getConditionType();