From 21a8a53496be22f0b987ac8bc28265e681b76ceb Mon Sep 17 00:00:00 2001 From: Nick Burch Date: Mon, 20 Jul 2015 03:21:57 +0000 Subject: [PATCH] #58130 Begin CF DataBar support git-svn-id: https://svn.apache.org/repos/asf/poi/trunk@1691867 13f79535-47bb-0310-9956-ffa450edef68 --- .../poi/hssf/record/CFRule12Record.java | 69 +++++++- .../poi/hssf/record/cf/DataBarFormatting.java | 160 ++++++++++++++++++ .../poi/hssf/record/cf/DataBarThreshold.java | 41 +++++ .../HSSFSheetConditionalFormatting.java | 35 ++-- .../usermodel/SheetConditionalFormatting.java | 26 ++- .../XSSFSheetConditionalFormatting.java | 34 ++-- 6 files changed, 310 insertions(+), 55 deletions(-) create mode 100644 src/java/org/apache/poi/hssf/record/cf/DataBarFormatting.java create mode 100644 src/java/org/apache/poi/hssf/record/cf/DataBarThreshold.java diff --git a/src/java/org/apache/poi/hssf/record/CFRule12Record.java b/src/java/org/apache/poi/hssf/record/CFRule12Record.java index 359f6c3a8f..6cb977433a 100644 --- a/src/java/org/apache/poi/hssf/record/CFRule12Record.java +++ b/src/java/org/apache/poi/hssf/record/CFRule12Record.java @@ -21,6 +21,8 @@ import java.util.Arrays; import org.apache.poi.hssf.record.cf.ColorGradientFormatting; import org.apache.poi.hssf.record.cf.ColorGradientThreshold; +import org.apache.poi.hssf.record.cf.DataBarFormatting; +import org.apache.poi.hssf.record.cf.DataBarThreshold; import org.apache.poi.hssf.record.cf.IconMultiStateFormatting; import org.apache.poi.hssf.record.cf.IconMultiStateThreshold; import org.apache.poi.hssf.record.cf.Threshold; @@ -30,6 +32,7 @@ import org.apache.poi.hssf.record.common.FutureRecord; import org.apache.poi.hssf.usermodel.HSSFSheet; 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.ss.usermodel.IconMultiStateFormatting.IconSet; import org.apache.poi.ss.util.CellRangeAddress; import org.apache.poi.util.HexDump; @@ -59,11 +62,10 @@ public final class CFRule12Record extends CFRuleBase implements FutureRecord { private byte template_param_length; private byte[] template_params; + private DataBarFormatting data_bar; private IconMultiStateFormatting multistate; private ColorGradientFormatting color_gradient; - - // TODO Parse these - private byte[] databar_data; + // TODO Parse this, see #58150 private byte[] filter_data; /** Creates new CFRuleRecord */ @@ -122,6 +124,27 @@ public final class CFRule12Record extends CFRuleBase implements FutureRecord { return new CFRule12Record(CONDITION_TYPE_CELL_VALUE_IS, comparisonOperation, formula1, formula2, formula3); } + /** + * Creates a new Data Bar formatting + */ + public static CFRule12Record create(HSSFSheet sheet, ExtendedColor color) { + CFRule12Record r = new CFRule12Record(CONDITION_TYPE_DATA_BAR, + ComparisonOperator.NO_COMPARISON); + DataBarFormatting dbf = r.createDataBarFormatting(); + dbf.setColor(color); + dbf.setPercentMin((byte)50); + dbf.setPercentMax((byte)50); + + DataBarThreshold min = new DataBarThreshold(); + min.setType(RangeType.MIN.id); + dbf.setThresholdMin(min); + + DataBarThreshold max = new DataBarThreshold(); + max.setType(RangeType.MAX.id); + dbf.setThresholdMax(max); + + return r; + } /** * Creates a new Icon Set / Multi-State formatting */ @@ -158,7 +181,6 @@ public final class CFRule12Record extends CFRuleBase implements FutureRecord { cgf.setColors(colors); return r; } - // TODO Static creators for Data Bars public CFRule12Record(RecordInputStream in) { futureHeader = new FtrHeader(in); @@ -202,7 +224,7 @@ public final class CFRule12Record extends CFRuleBase implements FutureRecord { if (type == CONDITION_TYPE_COLOR_SCALE) { color_gradient = new ColorGradientFormatting(in); } else if (type == CONDITION_TYPE_DATA_BAR) { - databar_data = in.readRemainder(); + data_bar = new DataBarFormatting(in); } else if (type == CONDITION_TYPE_FILTER) { filter_data = in.readRemainder(); } else if (type == CONDITION_TYPE_ICON_SET) { @@ -210,6 +232,21 @@ public final class CFRule12Record extends CFRuleBase implements FutureRecord { } } + public boolean containsDataBarBlock() { + return (data_bar != null); + } + public DataBarFormatting getDataBarFormatting() { + return data_bar; + } + public DataBarFormatting createDataBarFormatting() { + if (data_bar != null) return data_bar; + + // Convert, setup and return + setConditionType(CONDITION_TYPE_DATA_BAR); + data_bar = new DataBarFormatting(); + return data_bar; + } + public boolean containsMultiStateBlock() { return (multistate != null); } @@ -302,7 +339,7 @@ public final class CFRule12Record extends CFRuleBase implements FutureRecord { if (type == CONDITION_TYPE_COLOR_SCALE) { color_gradient.serialize(out); } else if (type == CONDITION_TYPE_DATA_BAR) { - out.write(databar_data); + data_bar.serialize(out); } else if (type == CONDITION_TYPE_FILTER) { out.write(filter_data); } else if (type == CONDITION_TYPE_ICON_SET) { @@ -326,7 +363,7 @@ public final class CFRule12Record extends CFRuleBase implements FutureRecord { if (type == CONDITION_TYPE_COLOR_SCALE) { len += color_gradient.getDataLength(); } else if (type == CONDITION_TYPE_DATA_BAR) { - len += databar_data.length; + len += data_bar.getDataLength(); } else if (type == CONDITION_TYPE_FILTER) { len += filter_data.length; } else if (type == CONDITION_TYPE_ICON_SET) { @@ -358,7 +395,6 @@ public final class CFRule12Record extends CFRuleBase implements FutureRecord { buffer.append(" .priority =").append(priority).append("\n"); buffer.append(" .template_type =").append(template_type).append("\n"); buffer.append(" .template_params=").append(HexDump.toHex(template_params)).append("\n"); - buffer.append(" .databar_data =").append(HexDump.toHex(databar_data)).append("\n"); buffer.append(" .filter_data =").append(HexDump.toHex(filter_data)).append("\n"); if (color_gradient != null) { buffer.append(color_gradient); @@ -366,6 +402,9 @@ public final class CFRule12Record extends CFRuleBase implements FutureRecord { if (multistate != null) { buffer.append(multistate); } + if (data_bar != null) { + buffer.append(data_bar); + } buffer.append("[/CFRULE12]\n"); return buffer.toString(); } @@ -389,7 +428,19 @@ public final class CFRule12Record extends CFRuleBase implements FutureRecord { rec.template_params = new byte[template_param_length]; System.arraycopy(template_params, 0, rec.template_params, 0, template_param_length); - // TODO Clone the rgbCT data like Gradients, Databars etc + if (color_gradient != null) { + rec.color_gradient = (ColorGradientFormatting)color_gradient.clone(); + } + if (multistate != null) { + rec.multistate = (IconMultiStateFormatting)multistate.clone(); + } + if (data_bar != null) { + rec.data_bar = (DataBarFormatting)data_bar.clone(); + } + if (filter_data != null) { + rec.filter_data = new byte[filter_data.length]; + System.arraycopy(filter_data, 0, rec.filter_data, 0, filter_data.length); + } return rec; } diff --git a/src/java/org/apache/poi/hssf/record/cf/DataBarFormatting.java b/src/java/org/apache/poi/hssf/record/cf/DataBarFormatting.java new file mode 100644 index 0000000000..3ca419553e --- /dev/null +++ b/src/java/org/apache/poi/hssf/record/cf/DataBarFormatting.java @@ -0,0 +1,160 @@ +/* ==================================================================== + Licensed to the Apache Software Foundation (ASF) under one or more + contributor license agreements. See the NOTICE file distributed with + this work for additional information regarding copyright ownership. + The ASF licenses this file to You under the Apache License, Version 2.0 + (the "License"); you may not use this file except in compliance with + the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +==================================================================== */ + +package org.apache.poi.hssf.record.cf; + +import org.apache.poi.hssf.record.common.ExtendedColor; +import org.apache.poi.util.BitField; +import org.apache.poi.util.BitFieldFactory; +import org.apache.poi.util.LittleEndianInput; +import org.apache.poi.util.LittleEndianOutput; +import org.apache.poi.util.POILogFactory; +import org.apache.poi.util.POILogger; + +/** + * Data Bar Conditional Formatting Rule Record. + */ +public final class DataBarFormatting implements Cloneable { + private static POILogger log = POILogFactory.getLogger(DataBarFormatting.class); + + private byte options = 0; + private byte percentMin = 0; + private byte percentMax = 0; + private ExtendedColor color; + private DataBarThreshold thresholdMin; + private DataBarThreshold thresholdMax; + + private static BitField iconOnly = BitFieldFactory.getInstance(0x01); + private static BitField reversed = BitFieldFactory.getInstance(0x04); + + public DataBarFormatting() { + options = 2; + } + public DataBarFormatting(LittleEndianInput in) { + in.readShort(); // Ignored + in.readByte(); // Reserved + options = in.readByte(); + + percentMin = in.readByte(); + percentMax = in.readByte(); + if (percentMin < 0 || percentMin > 100) + log.log(POILogger.WARN, "Inconsistent Minimum Percentage found " + percentMin); + if (percentMax < 0 || percentMax > 100) + log.log(POILogger.WARN, "Inconsistent Minimum Percentage found " + percentMin); + + color = new ExtendedColor(in); + thresholdMin = new DataBarThreshold(in); + thresholdMax = new DataBarThreshold(in); + } + + public boolean isIconOnly() { + return getOptionFlag(iconOnly); + } + public void setIconOnly(boolean only) { + setOptionFlag(only, iconOnly); + } + + public boolean isReversed() { + return getOptionFlag(reversed); + } + 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 byte getPercentMin() { + return percentMin; + } + public void setPercentMin(byte percentMin) { + this.percentMin = percentMin; + } + + public byte getPercentMax() { + return percentMax; + } + public void setPercentMax(byte percentMax) { + this.percentMax = percentMax; + } + + public ExtendedColor getColor() { + return color; + } + public void setColor(ExtendedColor color) { + this.color = color; + } + + public DataBarThreshold getThresholdMin() { + return thresholdMin; + } + public void setThresholdMin(DataBarThreshold thresholdMin) { + this.thresholdMin = thresholdMin; + } + + public DataBarThreshold getThresholdMax() { + return thresholdMax; + } + public void setThresholdMax(DataBarThreshold thresholdMax) { + this.thresholdMax = thresholdMax; + } + + public String toString() { + StringBuffer buffer = new StringBuffer(); + 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(); + } + + public Object clone() { + DataBarFormatting rec = new DataBarFormatting(); + rec.options = options; + rec.percentMin = percentMin; + rec.percentMax = percentMax; + rec.color = (ExtendedColor)color.clone(); + rec.thresholdMin = (DataBarThreshold)thresholdMin.clone(); + rec.thresholdMax = (DataBarThreshold)thresholdMax.clone(); + return rec; + } + + public int getDataLength() { + return 6 + color.getDataLength() + + thresholdMin.getDataLength() + + thresholdMax.getDataLength(); + } + + public void serialize(LittleEndianOutput out) { + out.writeShort(0); + out.writeByte(0); + out.writeByte(options); + out.writeByte(percentMin); + out.writeByte(percentMax); + color.serialize(out); + thresholdMin.serialize(out); + thresholdMax.serialize(out); + } +} diff --git a/src/java/org/apache/poi/hssf/record/cf/DataBarThreshold.java b/src/java/org/apache/poi/hssf/record/cf/DataBarThreshold.java new file mode 100644 index 0000000000..9164aaddef --- /dev/null +++ b/src/java/org/apache/poi/hssf/record/cf/DataBarThreshold.java @@ -0,0 +1,41 @@ +/* ==================================================================== + Licensed to the Apache Software Foundation (ASF) under one or more + contributor license agreements. See the NOTICE file distributed with + this work for additional information regarding copyright ownership. + The ASF licenses this file to You under the Apache License, Version 2.0 + (the "License"); you may not use this file except in compliance with + the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +==================================================================== */ + +package org.apache.poi.hssf.record.cf; + +import org.apache.poi.util.LittleEndianInput; + +/** + * Data Bar specific Threshold / value (CFVO), + * for changes in Conditional Formatting + */ +public final class DataBarThreshold extends Threshold { + public DataBarThreshold() { + super(); + } + + /** Creates new Data Bar Threshold */ + public DataBarThreshold(LittleEndianInput in) { + super(in); + } + + public Object clone() { + DataBarThreshold rec = new DataBarThreshold(); + super.copyTo(rec); + return rec; + } +} diff --git a/src/java/org/apache/poi/hssf/usermodel/HSSFSheetConditionalFormatting.java b/src/java/org/apache/poi/hssf/usermodel/HSSFSheetConditionalFormatting.java index 13032c2fbc..537587eb65 100644 --- a/src/java/org/apache/poi/hssf/usermodel/HSSFSheetConditionalFormatting.java +++ b/src/java/org/apache/poi/hssf/usermodel/HSSFSheetConditionalFormatting.java @@ -25,6 +25,7 @@ import org.apache.poi.hssf.record.aggregates.ConditionalFormattingTable; import org.apache.poi.ss.SpreadsheetVersion; import org.apache.poi.ss.usermodel.ConditionalFormatting; import org.apache.poi.ss.usermodel.ConditionalFormattingRule; +import org.apache.poi.ss.usermodel.ExtendedColor; import org.apache.poi.ss.usermodel.IconMultiStateFormatting.IconSet; import org.apache.poi.ss.usermodel.SheetConditionalFormatting; import org.apache.poi.ss.util.CellRangeAddress; @@ -106,6 +107,24 @@ public final class HSSFSheetConditionalFormatting implements SheetConditionalFor return new HSSFConditionalFormattingRule(_sheet, rr); } + /** + * Create a Databar conditional formatting rule. + *

The thresholds and colour for it will be created, but will be + * empty and require configuring with + * {@link HSSFConditionalFormattingRule#getDataBarFormatting()} + * then + * {@link HSSFDataBarFormatting#getMinThreshold()} + * and + * {@link HSSFDataBarFormatting#getMaxThreshold()} + */ + public HSSFConditionalFormattingRule createConditionalFormattingRule(HSSFExtendedColor color) { + CFRule12Record rr = CFRule12Record.create(_sheet, color.getExtendedColor()); + return new HSSFConditionalFormattingRule(_sheet, rr); + } + public HSSFConditionalFormattingRule createConditionalFormattingRule(ExtendedColor color) { + return createConditionalFormattingRule((HSSFExtendedColor)color); + } + /** * Create a Color Scale / Color Gradient conditional formatting rule. *

The thresholds and colours for it will be created, but will be @@ -121,22 +140,6 @@ public final class HSSFSheetConditionalFormatting implements SheetConditionalFor return new HSSFConditionalFormattingRule(_sheet, rr); } - /** - * Create a Databar conditional formatting rule. - *

The thresholds and colour for it will be created, but will be - * empty and require configuring with - * {@link HSSFConditionalFormattingRule#getDataBarFormatting()} - * then - * {@link HSSFDataBarFormatting#getMinThreshold()} - * and - * {@link HSSFDataBarFormatting#getMaxThreshold()} - * and - * {@link HSSFDataBarFormatting#getColor()} - */ - public HSSFConditionalFormattingRule createConditionalFormattingDataBarRule() { - throw new IllegalStateException("Not Implemented Yet!"); // TODO Implement - } - /** * Adds a copy of HSSFConditionalFormatting object to the sheet *

This method could be used to copy HSSFConditionalFormatting object diff --git a/src/java/org/apache/poi/ss/usermodel/SheetConditionalFormatting.java b/src/java/org/apache/poi/ss/usermodel/SheetConditionalFormatting.java index e8f7ea4d73..853eec6ff0 100644 --- a/src/java/org/apache/poi/ss/usermodel/SheetConditionalFormatting.java +++ b/src/java/org/apache/poi/ss/usermodel/SheetConditionalFormatting.java @@ -136,6 +136,18 @@ public interface SheetConditionalFormatting { */ ConditionalFormattingRule createConditionalFormattingRule(String formula); + /** + * Create a Databar conditional formatting rule. + *

The thresholds and colour for it will be created, but will be + * empty and require configuring with + * {@link ConditionalFormattingRule#getDataBarFormatting()} + * then + * {@link DataBarFormatting#getMinThreshold()} + * and + * {@link DataBarFormatting#getMaxThreshold()} + */ + ConditionalFormattingRule createConditionalFormattingRule(ExtendedColor color); + /** * Create an Icon Set / Multi-State conditional formatting rule. *

The thresholds for it will be created, but will be empty @@ -158,20 +170,6 @@ public interface SheetConditionalFormatting { */ ConditionalFormattingRule createConditionalFormattingColorScaleRule(); - /** - * Create a Databar conditional formatting rule. - *

The thresholds and colour for it will be created, but will be - * empty and require configuring with - * {@link ConditionalFormattingRule#getDataBarFormatting()} - * then - * {@link DataBarFormatting#getMinThreshold()} - * and - * {@link DataBarFormatting#getMaxThreshold()} - * and - * {@link DataBarFormatting#getColor()} - */ - ConditionalFormattingRule createConditionalFormattingDataBarRule(); - /** * Gets Conditional Formatting object at a particular index * diff --git a/src/ooxml/java/org/apache/poi/xssf/usermodel/XSSFSheetConditionalFormatting.java b/src/ooxml/java/org/apache/poi/xssf/usermodel/XSSFSheetConditionalFormatting.java index ae77b02d04..3c155c77e2 100644 --- a/src/ooxml/java/org/apache/poi/xssf/usermodel/XSSFSheetConditionalFormatting.java +++ b/src/ooxml/java/org/apache/poi/xssf/usermodel/XSSFSheetConditionalFormatting.java @@ -27,6 +27,7 @@ import org.apache.poi.ss.SpreadsheetVersion; import org.apache.poi.ss.usermodel.ComparisonOperator; import org.apache.poi.ss.usermodel.ConditionalFormatting; import org.apache.poi.ss.usermodel.ConditionalFormattingRule; +import org.apache.poi.ss.usermodel.ExtendedColor; import org.apache.poi.ss.usermodel.IconMultiStateFormatting.IconSet; import org.apache.poi.ss.usermodel.SheetConditionalFormatting; import org.apache.poi.ss.util.CellRangeAddress; @@ -119,6 +120,23 @@ public class XSSFSheetConditionalFormatting implements SheetConditionalFormattin return rule; } + /** + * Create a Databar conditional formatting rule. + *

The thresholds and colour for it will be created, but will be + * empty and require configuring with + * {@link XSSFConditionalFormattingRule#getDataBarFormatting()} + * then + * {@link XSSFDataBarFormatting#getMinThreshold()} + * and + * {@link XSSFDataBarFormatting#getMaxThreshold()} + */ + public XSSFConditionalFormattingRule createConditionalFormattingRule(XSSFColor color) { + throw new IllegalStateException("Not Implemented Yet!"); // TODO Implement + } + public XSSFConditionalFormattingRule createConditionalFormattingRule(ExtendedColor color) { + return createConditionalFormattingRule((XSSFColor)color); + } + /** * A factory method allowing the creation of conditional formatting * rules using an Icon Set / Multi-State formatting. @@ -158,22 +176,6 @@ public class XSSFSheetConditionalFormatting implements SheetConditionalFormattin return rule; } - /** - * Create a Databar conditional formatting rule. - *

The thresholds and colour for it will be created, but will be - * empty and require configuring with - * {@link XSSFConditionalFormattingRule#getDataBarFormatting()} - * then - * {@link XSSFDataBarFormatting#getMinThreshold()} - * and - * {@link XSSFDataBarFormatting#getMaxThreshold()} - * and - * {@link XSSFDataBarFormatting#getColor()} - */ - public XSSFConditionalFormattingRule createConditionalFormattingDataBarRule() { - throw new IllegalStateException("Not Implemented Yet!"); // TODO Implement - } - @SuppressWarnings("deprecation") public int addConditionalFormatting(CellRangeAddress[] regions, ConditionalFormattingRule[] cfRules) { if (regions == null) {