Skip to content

Commit c4a98de

Browse files
author
Olivier Chédru
authored
Merge pull request #203 from apptaro/master
Conditional Formatting Support (expression only)
2 parents 4a483c5 + 8c40eb1 commit c4a98de

File tree

10 files changed

+339
-21
lines changed

10 files changed

+339
-21
lines changed

README.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,10 @@ Apply formatting to a cell containing a timestamp:
7676
ws.value(0, 0, LocalDateTime.now());
7777
ws.style(0, 0).format("yyyy-MM-dd H:mm:ss").set();
7878
```
79+
Apply conditional formatting of expression type to a cell:
80+
```java
81+
ws.style(0, 0).fillColor("FF8800").set(new ConditionalFormattingExpressionRule("LENB(A1)>1", true));
82+
```
7983

8084
### Cell ranges
8185

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
package org.dhatim.fastexcel;
2+
3+
import java.io.IOException;
4+
5+
public class ConditionalFormatting {
6+
private final Range range;
7+
private final ConditionalFormattingRule conditionalFormattingRule;
8+
9+
/**
10+
* Constructor
11+
*
12+
* @param range The Range this validation is applied to
13+
* @param conditionalFormattingRule The Range of the list this validation references
14+
*/
15+
ConditionalFormatting(Range range, ConditionalFormattingRule conditionalFormattingRule) {
16+
this.range = range;
17+
this.conditionalFormattingRule = conditionalFormattingRule;
18+
}
19+
20+
/**
21+
* Get the conditional formatting rule of this conditional formatting.
22+
*
23+
* @return ConditionalFormattingRule conditional formatting rule.
24+
*/
25+
ConditionalFormattingRule getConditionalFormattingRule() {
26+
return this.conditionalFormattingRule;
27+
}
28+
29+
/**
30+
* Write this conditionalFormatting as an XML element.
31+
*
32+
* @param w Output writer.
33+
* @throws IOException If an I/O error occurs.
34+
*/
35+
void write(Writer w) throws IOException {
36+
w.append("<conditionalFormatting sqref=\"").append(range.toString()).append("\">");
37+
conditionalFormattingRule.write(w);
38+
w.append("</conditionalFormatting>");
39+
}
40+
}
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
package org.dhatim.fastexcel;
2+
3+
import java.io.IOException;
4+
5+
/**
6+
* A ConditionalFormattingExpressionRule defines a conditional formatting rule for a worksheet of type = "expression"
7+
*/
8+
public class ConditionalFormattingExpressionRule extends ConditionalFormattingRule {
9+
protected final static String TYPE = "expression";
10+
protected final String expression;
11+
12+
/**
13+
* Constructor
14+
*
15+
* @param expression When the expression evaluates to true, the specified style is applied
16+
* @param stopIfTrue True indicates no rules with lower priority shall be applied over this rule, when this rule evaluates to true
17+
*/
18+
public ConditionalFormattingExpressionRule(String expression, boolean stopIfTrue) {
19+
super(TYPE, stopIfTrue);
20+
this.expression = expression;
21+
}
22+
23+
/**
24+
* Write this conditionalFormatting as an XML element.
25+
*
26+
* @param w Output writer.
27+
* @throws IOException If an I/O error occurs.
28+
*/
29+
@Override
30+
public void write(Writer w) throws IOException {
31+
w
32+
.append("<cfRule type=\"").append(TYPE).append("\" priority=\"").append(priority).append("\" stopIfTrue=\"").append(stopIfTrue ? "1" : "0").append("\" dxfId=\"").append(dxfId).append("\">")
33+
.append("<formula>").append(expression).append("</formula>")
34+
.append("</cfRule>");
35+
}
36+
}
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
package org.dhatim.fastexcel;
2+
3+
import java.io.IOException;
4+
5+
/**
6+
* A ConditionalFormattingRule defines a base class of conditional formatting rule for a worksheet
7+
*/
8+
public abstract class ConditionalFormattingRule {
9+
protected final String type;
10+
protected int priority;
11+
protected final boolean stopIfTrue;
12+
protected int dxfId;
13+
14+
/**
15+
* Constructor
16+
*
17+
* @param type Type of conditional formatting rule
18+
* @param stopIfTrue True indicates no rules with lower priority shall be applied over this rule, when this rule evaluates to true
19+
*/
20+
ConditionalFormattingRule(String type, boolean stopIfTrue) {
21+
this.type = type;
22+
this.stopIfTrue = stopIfTrue;
23+
}
24+
25+
/**
26+
* Set the priority
27+
*
28+
* @param priority The user interface display priority
29+
*/
30+
void setPriority(int priority) {
31+
this.priority = priority;
32+
}
33+
34+
/**
35+
* Set the dxfId
36+
*
37+
* @param dxfId The id of the style to apply when the conditional formatting rule criteria is met
38+
*/
39+
void setDxfId(int dxfId) {
40+
this.dxfId = dxfId;
41+
}
42+
43+
/**
44+
* Write this conditionalFormatting as an XML element.
45+
*
46+
* @param w Output writer.
47+
* @throws IOException If an I/O error occurs.
48+
*/
49+
abstract void write(Writer w) throws IOException;
50+
}
Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,92 @@
1+
package org.dhatim.fastexcel;
2+
3+
import java.io.IOException;
4+
import java.util.Objects;
5+
6+
public class DifferentialFormat {
7+
private final String valueFormatting;
8+
private final Font font;
9+
private final Fill fill;
10+
private final Border border;
11+
private final Alignment alignment;
12+
private final Protection protection;
13+
private int numFmtId;
14+
15+
/**
16+
* Constructor.
17+
*
18+
* @param numFmtId Id of the value formatting to use
19+
* @param font Font to use
20+
* @param fill Fill to use
21+
* @param border Border to use
22+
* @param alignment Alignment to use
23+
* @param protection Proction to use
24+
*/
25+
DifferentialFormat(String valueFormatting, Font font, Fill fill, Border border, Alignment alignment, Protection protection) {
26+
this.valueFormatting = valueFormatting;
27+
this.font = font;
28+
this.fill = fill;
29+
this.border = border;
30+
this.alignment = alignment;
31+
this.protection = protection;
32+
}
33+
34+
public String getValueFormatting() {
35+
return valueFormatting;
36+
}
37+
38+
public void setNumFmtId(int numFmtId) {
39+
this.numFmtId = numFmtId;
40+
}
41+
42+
@Override
43+
public int hashCode() {
44+
return Objects.hash(numFmtId, font, fill, border, alignment, protection);
45+
}
46+
47+
@Override
48+
public boolean equals(Object obj) {
49+
boolean result;
50+
if (obj != null && obj.getClass() == this.getClass()) {
51+
DifferentialFormat other = (DifferentialFormat) obj;
52+
result = Objects.equals(valueFormatting, other.valueFormatting)
53+
&& Objects.equals(font, other.font)
54+
&& Objects.equals(fill, other.fill)
55+
&& Objects.equals(border, other.border)
56+
&& Objects.equals(alignment, other.alignment)
57+
&& Objects.equals(protection, other.protection);
58+
} else {
59+
result = false;
60+
}
61+
return result;
62+
}
63+
64+
/**
65+
* Write this style as an XML element.
66+
*
67+
* @param w Output writer.
68+
* @throws IOException If an I/O error occurs.
69+
*/
70+
void write(Writer w) throws IOException {
71+
w.append("<dxf>");
72+
if (valueFormatting != null) {
73+
w.append("<numFmt numFmtId=\"").append(numFmtId).append("\" formatCode=\"").append(valueFormatting).append("\"/>");
74+
}
75+
if (font != null) {
76+
font.write(w);
77+
}
78+
if (fill != null) {
79+
fill.write(w);
80+
}
81+
if (border != null) {
82+
border.write(w);
83+
}
84+
if (alignment != null) {
85+
alignment.write(w);
86+
}
87+
if (protection != null) {
88+
protection.write(w);
89+
}
90+
w.append("</dxf>");
91+
}
92+
}

fastexcel-writer/src/main/java/org/dhatim/fastexcel/StyleCache.java

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ final class StyleCache {
3636
private final ConcurrentMap<Fill, Integer> fills = new ConcurrentHashMap<>();
3737
private final ConcurrentMap<Border, Integer> borders = new ConcurrentHashMap<>();
3838
private final ConcurrentMap<Style, Integer> styles = new ConcurrentHashMap<>();
39-
private final ConcurrentMap<Fill, Integer> dxfs = new ConcurrentHashMap<>();
39+
private final ConcurrentMap<DifferentialFormat, Integer> dxfs = new ConcurrentHashMap<>();
4040

4141
/**
4242
* Default constructor. Pre-cache Excel-reserved stuff.
@@ -121,7 +121,7 @@ int cacheBorder(Border b) {
121121
* @param f Fill pattern.
122122
* @return Index of the cached fill pattern.
123123
*/
124-
int cacheDxf(Fill f) {
124+
int cacheDxf(DifferentialFormat f) {
125125
return cacheStuff(dxfs, f);
126126
}
127127

@@ -166,9 +166,7 @@ void write(Writer w) throws IOException {
166166
w.append("<cellStyleXfs count=\"1\"><xf numFmtId=\"0\" fontId=\"0\" fillId=\"0\" borderId=\"0\"/></cellStyleXfs>");
167167
writeCache(w, styles, "cellXfs", e -> e.getKey().write(w));
168168
writeCache(w, dxfs, "dxfs", e -> {
169-
w.append("<dxf>");
170169
e.getKey().write(w);
171-
w.append("</dxf>");
172170
});
173171
w.append("</styleSheet>");
174172
}

fastexcel-writer/src/main/java/org/dhatim/fastexcel/StyleSetter.java

Lines changed: 31 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,7 @@ public class StyleSetter {
6666
* Italic flag.
6767
*/
6868
private boolean italic;
69-
/**
69+
/**
7070
* Underlined flag.
7171
*/
7272
private boolean underlined;
@@ -224,8 +224,8 @@ public StyleSetter italic() {
224224
this.italic = true;
225225
return this;
226226
}
227-
228-
/**
227+
228+
/**
229229
* Use underlined text.
230230
*
231231
* @return This style setter.
@@ -443,4 +443,32 @@ public void set() {
443443
range.shadeRows(Fill.fromColor(shadingFillColor, false), eachNRows);
444444
}
445445
}
446+
447+
/**
448+
* Apply style elements conditionally
449+
* @param conditionalFormattingRule Conditional formatting rule to apply
450+
*/
451+
public void set(ConditionalFormattingRule conditionalFormattingRule) {
452+
Alignment alignment = null;
453+
if (horizontalAlignment != null || verticalAlignment != null || wrapText) {
454+
alignment = new Alignment(horizontalAlignment, verticalAlignment, wrapText);
455+
}
456+
Font font = null;
457+
if (bold || italic || underlined || fontColor != null || fontName != null || fontSize != null) {
458+
font = Font.build(bold, italic, underlined, fontName, fontSize, fontColor);
459+
}
460+
Fill fill = null;
461+
if (fillColor != null) {
462+
fill = Fill.fromColor(fillColor, false);
463+
}
464+
Protection protection = null;
465+
if (protectionOptions != null) {
466+
protection = new Protection(protectionOptions);
467+
}
468+
469+
int dxfId = range.getWorksheet().getWorkbook().cacheDifferentialFormat(new DifferentialFormat(valueFormatting, font, fill, border, alignment, protection));
470+
conditionalFormattingRule.setDxfId(dxfId);
471+
ConditionalFormatting conditionalFormatting = new ConditionalFormatting(range, conditionalFormattingRule);
472+
range.getWorksheet().addConditionalFormatting(conditionalFormatting);
473+
}
446474
}

fastexcel-writer/src/main/java/org/dhatim/fastexcel/Workbook.java

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -324,13 +324,15 @@ int mergeAndCacheStyle(int currentStyle, String numberingFormat, Font font, Fill
324324
}
325325

326326
/**
327-
* Cache shading color for alternate rows.
327+
* Cache differential format.
328328
*
329-
* @param fill Fill pattern attributes.
330-
* @return Cached fill pattern index.
329+
* @param differentialFormat DifferentialFormat object.
330+
* @return Cached differential format index.
331331
*/
332-
int cacheShadingFillColor(Fill fill) {
333-
return styleCache.cacheDxf(fill);
332+
int cacheDifferentialFormat(DifferentialFormat differentialFormat) {
333+
int numFmtId = styleCache.cacheValueFormatting(differentialFormat.getValueFormatting());
334+
differentialFormat.setNumFmtId(numFmtId);
335+
return styleCache.cacheDxf(differentialFormat);
334336
}
335337

336338
/**

0 commit comments

Comments
 (0)