|
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481 |
- /* ====================================================================
- Licensed to the Apache Software Foundation (ASF) under one or more
- contributor license agreements. See the NOTICE file distributed with
- this work for additional information regarding copyright ownership.
- The ASF licenses this file to You under the Apache License, Version 2.0
- (the "License"); you may not use this file except in compliance with
- the License. You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
- ==================================================================== */
-
- package org.apache.poi.hssf.record;
-
- import java.util.Map;
- import java.util.function.Supplier;
-
- import org.apache.logging.log4j.LogManager;
- import org.apache.logging.log4j.Logger;
- import org.apache.poi.hssf.model.HSSFFormulaParser;
- import org.apache.poi.hssf.record.cf.BorderFormatting;
- import org.apache.poi.hssf.record.cf.FontFormatting;
- import org.apache.poi.hssf.record.cf.PatternFormatting;
- import org.apache.poi.hssf.usermodel.HSSFSheet;
- import org.apache.poi.ss.formula.Formula;
- import org.apache.poi.ss.formula.FormulaType;
- import org.apache.poi.ss.formula.ptg.Ptg;
- import org.apache.poi.util.BitField;
- import org.apache.poi.util.BitFieldFactory;
- import org.apache.poi.util.GenericRecordUtil;
- import org.apache.poi.util.LittleEndianOutput;
-
- /**
- * Conditional Formatting Rules. This can hold old-style rules
- *
- *
- * <p>This is for the older-style Excel conditional formattings,
- * new-style (Excel 2007+) also make use of {@link CFRule12Record}
- * for their rules.</p>
- */
- public abstract class CFRuleBase extends StandardRecord {
- // FIXME: Merge with org.apache.poi.ss.usermodel.ComparisonOperator and rewrite as an enum
- public interface ComparisonOperator {
- byte NO_COMPARISON = 0;
- byte BETWEEN = 1;
- byte NOT_BETWEEN = 2;
- byte EQUAL = 3;
- byte NOT_EQUAL = 4;
- byte GT = 5;
- byte LT = 6;
- byte GE = 7;
- byte LE = 8;
- byte max_operator = 8;
- }
-
- // The only kinds that CFRuleRecord handles
- public static final byte CONDITION_TYPE_CELL_VALUE_IS = 1;
- public static final byte CONDITION_TYPE_FORMULA = 2;
- // These are CFRule12Rule only
- public static final byte CONDITION_TYPE_COLOR_SCALE = 3;
- public static final byte CONDITION_TYPE_DATA_BAR = 4;
- public static final byte CONDITION_TYPE_FILTER = 5;
- public static final byte CONDITION_TYPE_ICON_SET = 6;
-
- public static final int TEMPLATE_CELL_VALUE = 0x0000;
- public static final int TEMPLATE_FORMULA = 0x0001;
- public static final int TEMPLATE_COLOR_SCALE_FORMATTING = 0x0002;
- public static final int TEMPLATE_DATA_BAR_FORMATTING = 0x0003;
- public static final int TEMPLATE_ICON_SET_FORMATTING = 0x0004;
- public static final int TEMPLATE_FILTER = 0x0005;
- public static final int TEMPLATE_UNIQUE_VALUES = 0x0007;
- public static final int TEMPLATE_CONTAINS_TEXT = 0x0008;
- public static final int TEMPLATE_CONTAINS_BLANKS = 0x0009;
- public static final int TEMPLATE_CONTAINS_NO_BLANKS = 0x000A;
- public static final int TEMPLATE_CONTAINS_ERRORS = 0x000B;
- public static final int TEMPLATE_CONTAINS_NO_ERRORS = 0x000C;
- public static final int TEMPLATE_TODAY = 0x000F;
- public static final int TEMPLATE_TOMORROW = 0x0010;
- public static final int TEMPLATE_YESTERDAY = 0x0011;
- public static final int TEMPLATE_LAST_7_DAYS = 0x0012;
- public static final int TEMPLATE_LAST_MONTH = 0x0013;
- public static final int TEMPLATE_NEXT_MONTH = 0x0014;
- public static final int TEMPLATE_THIS_WEEK = 0x0015;
- public static final int TEMPLATE_NEXT_WEEK = 0x0016;
- public static final int TEMPLATE_LAST_WEEK = 0x0017;
- public static final int TEMPLATE_THIS_MONTH = 0x0018;
- public static final int TEMPLATE_ABOVE_AVERAGE = 0x0019;
- public static final int TEMPLATE_BELOW_AVERAGE = 0x001A;
- public static final int TEMPLATE_DUPLICATE_VALUES = 0x001B;
- public static final int TEMPLATE_ABOVE_OR_EQUAL_TO_AVERAGE = 0x001D;
- public static final int TEMPLATE_BELOW_OR_EQUAL_TO_AVERAGE = 0x001E;
-
- protected static final Logger LOG = LogManager.getLogger(CFRuleBase.class);
-
- static final BitField modificationBits = bf(0x003FFFFF); // Bits: font,align,bord,patt,prot
- static final BitField alignHor = bf(0x00000001); // 0 = Horizontal alignment modified
- static final BitField alignVer = bf(0x00000002); // 0 = Vertical alignment modified
- static final BitField alignWrap = bf(0x00000004); // 0 = Text wrapped flag modified
- static final BitField alignRot = bf(0x00000008); // 0 = Text rotation modified
- static final BitField alignJustLast = bf(0x00000010); // 0 = Justify last line flag modified
- static final BitField alignIndent = bf(0x00000020); // 0 = Indentation modified
- static final BitField alignShrin = bf(0x00000040); // 0 = Shrink to fit flag modified
- static final BitField mergeCell = bf(0x00000080); // Normally 1, 0 = Merge Cell flag modified
- static final BitField protLocked = bf(0x00000100); // 0 = Cell locked flag modified
- static final BitField protHidden = bf(0x00000200); // 0 = Cell hidden flag modified
- static final BitField bordLeft = bf(0x00000400); // 0 = Left border style and colour modified
- static final BitField bordRight = bf(0x00000800); // 0 = Right border style and colour modified
- static final BitField bordTop = bf(0x00001000); // 0 = Top border style and colour modified
- static final BitField bordBot = bf(0x00002000); // 0 = Bottom border style and colour modified
- static final BitField bordTlBr = bf(0x00004000); // 0 = Top-left to bottom-right border flag modified
- static final BitField bordBlTr = bf(0x00008000); // 0 = Bottom-left to top-right border flag modified
- static final BitField pattStyle = bf(0x00010000); // 0 = Pattern style modified
- static final BitField pattCol = bf(0x00020000); // 0 = Pattern colour modified
- static final BitField pattBgCol = bf(0x00040000); // 0 = Pattern background colour modified
- static final BitField notUsed2 = bf(0x00380000); // Always 111 (ifmt / ifnt / 1)
- static final BitField undocumented = bf(0x03C00000); // Undocumented bits
- static final BitField fmtBlockBits = bf(0x7C000000); // Bits: font,align,bord,patt,prot
- static final BitField font = bf(0x04000000); // 1 = Record contains font formatting block
- static final BitField align = bf(0x08000000); // 1 = Record contains alignment formatting block
- static final BitField bord = bf(0x10000000); // 1 = Record contains border formatting block
- static final BitField patt = bf(0x20000000); // 1 = Record contains pattern formatting block
- static final BitField prot = bf(0x40000000); // 1 = Record contains protection formatting block
- static final BitField alignTextDir = bf(0x80000000); // 0 = Text direction modified
-
- private static BitField bf(int i) {
- return BitFieldFactory.getInstance(i);
- }
-
-
- private byte condition_type;
- private byte comparison_operator;
-
- protected int formatting_options;
- // TODO Decode this properly
- protected short formatting_not_used;
-
- protected FontFormatting _fontFormatting;
- protected BorderFormatting _borderFormatting;
- protected PatternFormatting _patternFormatting;
-
- private Formula formula1;
- private Formula formula2;
-
- /**
- * Creates new CFRuleRecord
- *
- * @param conditionType the condition type
- * @param comparisonOperation the comparison operation
- */
- protected CFRuleBase(byte conditionType, byte comparisonOperation) {
- setConditionType(conditionType);
- setComparisonOperation(comparisonOperation);
- formula1 = Formula.create(Ptg.EMPTY_PTG_ARRAY);
- formula2 = Formula.create(Ptg.EMPTY_PTG_ARRAY);
- }
-
- protected CFRuleBase(byte conditionType, byte comparisonOperation, Ptg[] formula1, Ptg[] formula2) {
- this(conditionType, comparisonOperation);
- this.formula1 = Formula.create(formula1);
- this.formula2 = Formula.create(formula2);
- }
-
- protected CFRuleBase() {}
-
- protected CFRuleBase(CFRuleBase other) {
- super(other);
- setConditionType(other.getConditionType());
- setComparisonOperation(other.getComparisonOperation());
- formatting_options = other.formatting_options;
- formatting_not_used = other.formatting_not_used;
- _fontFormatting = (!other.containsFontFormattingBlock()) ? null : other.getFontFormatting().copy();
- _borderFormatting = (!other.containsBorderFormattingBlock()) ? null : other.getBorderFormatting().copy();
- _patternFormatting = (!other.containsPatternFormattingBlock()) ? null : other.getPatternFormatting().copy();
- formula1 = other.getFormula1().copy();
- formula2 = other.getFormula2().copy();
- }
-
- protected int readFormatOptions(RecordInputStream in) {
- formatting_options = in.readInt();
- formatting_not_used = in.readShort();
-
- int len = 6;
-
- if (containsFontFormattingBlock()) {
- _fontFormatting = new FontFormatting(in);
- len += _fontFormatting.getDataLength();
- }
-
- if (containsBorderFormattingBlock()) {
- _borderFormatting = new BorderFormatting(in);
- len += _borderFormatting.getDataLength();
- }
-
- if (containsPatternFormattingBlock()) {
- _patternFormatting = new PatternFormatting(in);
- len += _patternFormatting.getDataLength();
- }
-
- return len;
- }
-
- public byte getConditionType() {
- return condition_type;
- }
- protected void setConditionType(byte condition_type) {
- if ((this instanceof CFRuleRecord)) {
- if (!(condition_type == CONDITION_TYPE_CELL_VALUE_IS ||
- condition_type == CONDITION_TYPE_FORMULA)) {
- throw new IllegalArgumentException("CFRuleRecord only accepts Value-Is and Formula types");
- }
- }
- this.condition_type = condition_type;
- }
-
- public void setComparisonOperation(byte operation) {
- if (operation < 0 || operation > ComparisonOperator.max_operator)
- throw new IllegalArgumentException(
- "Valid operators are only in the range 0 to " +ComparisonOperator.max_operator);
-
- this.comparison_operator = operation;
- }
- public byte getComparisonOperation() {
- return comparison_operator;
- }
-
- public boolean containsFontFormattingBlock() {
- return getOptionFlag(font);
- }
- public void setFontFormatting(FontFormatting fontFormatting) {
- _fontFormatting = fontFormatting;
- setOptionFlag(fontFormatting != null, font);
- }
- public FontFormatting getFontFormatting() {
- if( containsFontFormattingBlock()) {
- return _fontFormatting;
- }
- return null;
- }
-
- public boolean containsAlignFormattingBlock() {
- return getOptionFlag(align);
- }
- public void setAlignFormattingUnchanged() {
- setOptionFlag(false,align);
- }
-
- public boolean containsBorderFormattingBlock() {
- return getOptionFlag(bord);
- }
- public void setBorderFormatting(BorderFormatting borderFormatting) {
- _borderFormatting = borderFormatting;
- setOptionFlag(borderFormatting != null, bord);
- }
- public BorderFormatting getBorderFormatting() {
- if( containsBorderFormattingBlock()) {
- return _borderFormatting;
- }
- return null;
- }
-
- public boolean containsPatternFormattingBlock() {
- return getOptionFlag(patt);
- }
- public void setPatternFormatting(PatternFormatting patternFormatting) {
- _patternFormatting = patternFormatting;
- setOptionFlag(patternFormatting!=null, patt);
- }
- public PatternFormatting getPatternFormatting() {
- if( containsPatternFormattingBlock())
- {
- return _patternFormatting;
- }
- return null;
- }
-
- public boolean containsProtectionFormattingBlock() {
- return getOptionFlag(prot);
- }
- public void setProtectionFormattingUnchanged() {
- setOptionFlag(false,prot);
- }
-
- /**
- * get the option flags
- *
- * @return bit mask
- */
- public int getOptions() {
- return formatting_options;
- }
-
- private boolean isModified(BitField field) {
- return !field.isSet(formatting_options);
- }
- private void setModified(boolean modified, BitField field) {
- formatting_options = field.setBoolean(formatting_options, !modified);
- }
-
- public boolean isLeftBorderModified() {
- return isModified(bordLeft);
- }
- public void setLeftBorderModified(boolean modified) {
- setModified(modified,bordLeft);
- }
-
- public boolean isRightBorderModified() {
- return isModified(bordRight);
- }
- public void setRightBorderModified(boolean modified)
- {
- setModified(modified,bordRight);
- }
-
- public boolean isTopBorderModified() {
- return isModified(bordTop);
- }
- public void setTopBorderModified(boolean modified) {
- setModified(modified,bordTop);
- }
-
- public boolean isBottomBorderModified() {
- return isModified(bordBot);
- }
- public void setBottomBorderModified(boolean modified) {
- setModified(modified,bordBot);
- }
-
- public boolean isTopLeftBottomRightBorderModified() {
- return isModified(bordTlBr);
- }
- public void setTopLeftBottomRightBorderModified(boolean modified) {
- setModified(modified,bordTlBr);
- }
-
- public boolean isBottomLeftTopRightBorderModified() {
- return isModified(bordBlTr);
- }
- public void setBottomLeftTopRightBorderModified(boolean modified) {
- setModified(modified,bordBlTr);
- }
-
- public boolean isPatternStyleModified() {
- return isModified(pattStyle);
- }
- public void setPatternStyleModified(boolean modified) {
- setModified(modified,pattStyle);
- }
-
- public boolean isPatternColorModified() {
- return isModified(pattCol);
- }
- public void setPatternColorModified(boolean modified) {
- setModified(modified,pattCol);
- }
-
- public boolean isPatternBackgroundColorModified() {
- return isModified(pattBgCol);
- }
- public void setPatternBackgroundColorModified(boolean modified) {
- setModified(modified,pattBgCol);
- }
-
- private boolean getOptionFlag(BitField field) {
- return field.isSet(formatting_options);
- }
- private void setOptionFlag(boolean flag, BitField field) {
- formatting_options = field.setBoolean(formatting_options, flag);
- }
-
- protected int getFormattingBlockSize() {
- return 6 +
- (containsFontFormattingBlock()?_fontFormatting.getRawRecord().length:0)+
- (containsBorderFormattingBlock()?8:0)+
- (containsPatternFormattingBlock()?4:0);
- }
- protected void serializeFormattingBlock(LittleEndianOutput out) {
- out.writeInt(formatting_options);
- out.writeShort(formatting_not_used);
-
- if (containsFontFormattingBlock()) {
- byte[] fontFormattingRawRecord = _fontFormatting.getRawRecord();
- out.write(fontFormattingRawRecord);
- }
-
- if (containsBorderFormattingBlock()) {
- _borderFormatting.serialize(out);
- }
-
- if (containsPatternFormattingBlock()) {
- _patternFormatting.serialize(out);
- }
- }
-
- /**
- * get the stack of the 1st expression as a list
- *
- * @return list of tokens (casts stack to a list and returns it!)
- * this method can return null is we are unable to create Ptgs from
- * existing excel file
- * callers should check for null!
- */
- public Ptg[] getParsedExpression1() {
- return formula1.getTokens();
- }
- public void setParsedExpression1(Ptg[] ptgs) {
- formula1 = Formula.create(ptgs);
- }
- protected Formula getFormula1() {
- return formula1;
- }
- protected void setFormula1(Formula formula1) {
- this.formula1 = formula1;
- }
-
- /**
- * get the stack of the 2nd expression as a list
- *
- * @return array of {@link Ptg}s, possibly <code>null</code>
- */
- public Ptg[] getParsedExpression2() {
- return Formula.getTokens(formula2);
- }
- public void setParsedExpression2(Ptg[] ptgs) {
- formula2 = Formula.create(ptgs);
- }
- protected Formula getFormula2() {
- return formula2;
- }
- protected void setFormula2(Formula formula2) {
- this.formula2 = formula2;
- }
-
- /**
- * @param formula must not be <code>null</code>
- * @return encoded size of the formula tokens (does not include 2 bytes for ushort length)
- */
- protected static int getFormulaSize(Formula formula) {
- return formula.getEncodedTokenSize();
- }
-
- /**
- * TODO - parse conditional format formulas properly i.e. produce tRefN and tAreaN instead of tRef and tArea
- * this call will produce the wrong results if the formula contains any cell references
- * One approach might be to apply the inverse of SharedFormulaRecord.convertSharedFormulas(Stack, int, int)
- * Note - two extra parameters (rowIx & colIx) will be required. They probably come from one of the Region objects.
- *
- * @param formula The formula to parse, excluding the leading equals sign.
- * @param sheet The sheet that the formula is on.
- * @return <code>null</code> if <tt>formula</tt> was null.
- */
- public static Ptg[] parseFormula(String formula, HSSFSheet sheet) {
- if(formula == null) {
- return null;
- }
- int sheetIndex = sheet.getWorkbook().getSheetIndex(sheet);
- return HSSFFormulaParser.parse(formula, sheet.getWorkbook(), FormulaType.CELL, sheetIndex);
- }
-
- @Override
- public abstract CFRuleBase copy();
-
- @Override
- public Map<String, Supplier<?>> getGenericProperties() {
- return GenericRecordUtil.getGenericProperties(
- "conditionType", this::getConditionType,
- "comparisonOperation", this::getComparisonOperation,
- "formattingOptions", this::getOptions,
- "formattingNotUsed", () -> formatting_not_used,
- "fontFormatting", this::getFontFormatting,
- "borderFormatting", this::getBorderFormatting,
- "patternFormatting", this::getPatternFormatting,
- "formula1", this::getFormula1,
- "formula2", this::getFormula2
- );
- }
- }
|