Skip to content

Commit 82f43ab

Browse files
committed
Add note about merging and multiple values. Fix applying border styles for merged cells
1 parent 1262d54 commit 82f43ab

File tree

8 files changed

+215
-28
lines changed

8 files changed

+215
-28
lines changed

docs/merging.adoc

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,11 +9,13 @@ row {
99
merge {
1010
//Anything you can do inside row directly
1111
cell("Foo")
12-
cell("Bar")
12+
skipCells(5)
1313
}
1414
}
1515
----
1616

17+
WARNING: Only one call to `cell()` is allowed inside a merge.
18+
1719
You can also apply default styling to the merged cells
1820

1921
[source,groovy]
@@ -22,7 +24,7 @@ row {
2224
merge(font: Font.BOLD) {
2325
//Anything you can do inside row directly
2426
cell("Foo")
25-
cell("Bar")
27+
skipCells(3)
2628
}
2729
}
2830
----

src/main/groovy/com/jameskleeh/excel/CellStyleBuilder.groovy

Lines changed: 33 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -18,22 +18,30 @@ under the License.
1818
*/
1919
package com.jameskleeh.excel
2020

21+
import com.jameskleeh.excel.style.BorderStyleApplier
22+
import com.jameskleeh.excel.style.CellRangeBorderStyleApplier
23+
import com.jameskleeh.excel.style.CellStyleBorderStyleApplier
2124
import groovy.transform.CompileStatic
2225
import groovy.transform.TypeCheckingMode
2326
import org.apache.poi.ss.usermodel.BorderStyle
27+
import org.apache.poi.ss.usermodel.CellStyle
2428
import org.apache.poi.ss.usermodel.FillPatternType
2529
import org.apache.poi.ss.usermodel.Font as FontType
2630
import org.apache.poi.ss.usermodel.HorizontalAlignment
2731
import org.apache.poi.ss.usermodel.VerticalAlignment
32+
import org.apache.poi.ss.util.CellRangeAddress
33+
import org.apache.poi.ss.util.RegionUtil
2834
import org.apache.poi.xssf.usermodel.XSSFCell
2935
import org.apache.poi.xssf.usermodel.XSSFCellStyle
3036
import org.apache.poi.xssf.usermodel.XSSFColor
3137
import org.apache.poi.xssf.usermodel.XSSFFont
3238
import org.apache.poi.xssf.usermodel.XSSFRow
39+
import org.apache.poi.xssf.usermodel.XSSFSheet
3340
import org.apache.poi.xssf.usermodel.XSSFWorkbook
3441
import org.apache.poi.xssf.usermodel.extensions.XSSFCellBorder.BorderSide
3542

3643
import java.awt.Color
44+
import java.lang.reflect.Method
3745

3846
/**
3947
* A class to build an {@link org.apache.poi.xssf.usermodel.XSSFCellStyle} from a map
@@ -124,9 +132,9 @@ class CellStyleBuilder {
124132

125133
private void setFormat(XSSFCellStyle cellStyle, Object format) {
126134
if (format instanceof Integer) {
127-
cellStyle.setDataFormat(format)
135+
cellStyle.setDataFormat((Integer)format)
128136
} else if (format instanceof String) {
129-
cellStyle.setDataFormat(workbook.creationHelper.createDataFormat().getFormat(format))
137+
cellStyle.setDataFormat(workbook.creationHelper.createDataFormat().getFormat((String)format))
130138
} else {
131139
throw new IllegalArgumentException('The cell format must be an Integer or String')
132140
}
@@ -206,7 +214,7 @@ class CellStyleBuilder {
206214
} else if (obj instanceof String) {
207215
String hex = (String)obj
208216
if (hex.startsWith('#')) {
209-
color = Color.decode(obj)
217+
color = Color.decode(hex)
210218
} else {
211219
color = Color.decode("#$obj")
212220
}
@@ -225,18 +233,19 @@ class CellStyleBuilder {
225233
throw new IllegalArgumentException("The border style must be an instance of ${BorderStyle.getCanonicalName()}")
226234
}
227235

228-
private void setBorder(Map border, String key, Closure borderCallable, Closure colorCallable) {
236+
private void setBorder(Map border, BorderSide side, BorderStyleApplier styleApplier) {
237+
final String key = side.name()
229238
if (border.containsKey(key)) {
230239
if (border[key] instanceof Map) {
231240
Map edge = (Map) border[key]
232241
if (edge.containsKey(COLOR)) {
233-
colorCallable.call(getColor(edge[COLOR]))
242+
styleApplier.applyColor(side, getColor(edge[COLOR]))
234243
}
235244
if (edge.containsKey(STYLE)) {
236-
borderCallable.call(getBorderStyle(edge[STYLE]))
245+
styleApplier.applyStyle(side, getBorderStyle(edge[STYLE]))
237246
}
238247
} else {
239-
borderCallable.call(getBorderStyle(border[key]))
248+
styleApplier.applyStyle(side, getBorderStyle(border[key]))
240249
}
241250
}
242251
}
@@ -247,7 +256,7 @@ class CellStyleBuilder {
247256
if (horizontalAlignment instanceof HorizontalAlignment) {
248257
hAlign = (HorizontalAlignment)horizontalAlignment
249258
} else if (horizontalAlignment instanceof String) {
250-
hAlign = HorizontalAlignment.valueOf(horizontalAlignment.toUpperCase())
259+
hAlign = HorizontalAlignment.valueOf(((String)horizontalAlignment).toUpperCase())
251260
}
252261

253262
if (hAlign != null) {
@@ -263,7 +272,7 @@ class CellStyleBuilder {
263272
if (verticalAlignment instanceof VerticalAlignment) {
264273
vAlign = (VerticalAlignment) verticalAlignment
265274
} else if (verticalAlignment instanceof String) {
266-
vAlign = VerticalAlignment.valueOf(verticalAlignment.toUpperCase())
275+
vAlign = VerticalAlignment.valueOf(((String)verticalAlignment).toUpperCase())
267276
}
268277

269278
if (vAlign != null) {
@@ -297,33 +306,27 @@ class CellStyleBuilder {
297306
}
298307
}
299308

300-
private void setBorder(XSSFCellStyle cellStyle, Map border) {
309+
private void setBorder(BorderStyleApplier styleApplier, Map border) {
301310
if (border.containsKey(STYLE)) {
302311
BorderStyle style = getBorderStyle(border[STYLE])
303-
cellStyle.setBorderBottom(style)
304-
cellStyle.setBorderTop(style)
305-
cellStyle.setBorderLeft(style)
306-
cellStyle.setBorderRight(style)
312+
styleApplier.applyStyle(style)
307313
}
308314
if (border.containsKey(COLOR)) {
309315
XSSFColor color = getColor(border[COLOR])
310-
cellStyle.setBorderColor(BorderSide.BOTTOM, color)
311-
cellStyle.setBorderColor(BorderSide.TOP, color)
312-
cellStyle.setBorderColor(BorderSide.LEFT, color)
313-
cellStyle.setBorderColor(BorderSide.RIGHT, color)
314-
}
315-
setBorder(border, LEFT, cellStyle.&setBorderLeft, cellStyle.&setLeftBorderColor)
316-
setBorder(border, RIGHT, cellStyle.&setBorderRight, cellStyle.&setRightBorderColor)
317-
setBorder(border, BOTTOM, cellStyle.&setBorderBottom, cellStyle.&setBottomBorderColor)
318-
setBorder(border, TOP, cellStyle.&setBorderTop, cellStyle.&setTopBorderColor)
316+
styleApplier.applyColor(color)
317+
}
318+
setBorder(border, BorderSide.LEFT, styleApplier)
319+
setBorder(border, BorderSide.RIGHT, styleApplier)
320+
setBorder(border, BorderSide.BOTTOM, styleApplier)
321+
setBorder(border, BorderSide.TOP, styleApplier)
319322
}
320323

321324
private void setFill(XSSFCellStyle cellStyle, Object fill) {
322325
FillPatternType fillPattern
323326
if (fill instanceof FillPatternType) {
324327
fillPattern = (FillPatternType) fill
325328
} else if (fill instanceof String) {
326-
fillPattern = FillPatternType.valueOf(fill.toUpperCase())
329+
fillPattern = FillPatternType.valueOf(((String)fill).toUpperCase())
327330
}
328331

329332
if (fillPattern != null) {
@@ -385,7 +388,7 @@ class CellStyleBuilder {
385388
cellStyle.setIndention((short) options[INDENT])
386389
}
387390
if (options.containsKey(BORDER)) {
388-
setBorder(cellStyle, (Map)options[BORDER])
391+
setBorder(new CellStyleBorderStyleApplier(cellStyle), (Map)options[BORDER])
389392
}
390393
if (options.containsKey(FILL)) {
391394
setFill(cellStyle, options[FILL])
@@ -474,5 +477,10 @@ class CellStyleBuilder {
474477
result
475478
}
476479
}
480+
481+
void applyBorderToRegion(CellRangeAddress range, XSSFSheet sheet, Map border) {
482+
BorderStyleApplier borderStyleApplier = new CellRangeBorderStyleApplier(range, sheet)
483+
setBorder(borderStyleApplier, border)
484+
}
477485

478486
}

src/main/groovy/com/jameskleeh/excel/Row.groovy

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,8 @@ class Row extends CreatesCells {
8585
defaultOptions = newDefaultOptions
8686
}
8787

88+
Map borderOptions = defaultOptions.containsKey('border') ? (Map)defaultOptions.remove('border') : Collections.emptyMap()
89+
8890
callable.resolveStrategy = Closure.DELEGATE_FIRST
8991
callable.delegate = this
9092
int startingCellIndex = cellIdx
@@ -93,6 +95,7 @@ class Row extends CreatesCells {
9395
if (endingCellIndex > startingCellIndex) {
9496
CellRangeAddress range = new CellRangeAddress(row.rowNum, row.rowNum, startingCellIndex, endingCellIndex)
9597
sheet.addMergedRegion(range)
98+
styleBuilder.applyBorderToRegion(range, sheet, borderOptions)
9699
}
97100

98101
defaultOptions = existingDefaultOptions
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
package com.jameskleeh.excel.style
2+
3+
import org.apache.poi.ss.usermodel.BorderStyle
4+
import org.apache.poi.xssf.usermodel.XSSFColor
5+
import org.apache.poi.xssf.usermodel.extensions.XSSFCellBorder.BorderSide
6+
7+
/**
8+
* Created by jameskleeh on 7/3/17.
9+
*/
10+
interface BorderStyleApplier {
11+
12+
void applyStyle(BorderSide side, BorderStyle style)
13+
14+
void applyStyle(BorderStyle style)
15+
16+
void applyColor(BorderSide side, XSSFColor color)
17+
18+
void applyColor(XSSFColor color)
19+
}
Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
package com.jameskleeh.excel.style
2+
3+
import groovy.transform.CompileStatic
4+
import groovy.transform.TupleConstructor
5+
import org.apache.poi.ss.usermodel.BorderStyle
6+
import org.apache.poi.ss.usermodel.Sheet
7+
import org.apache.poi.ss.util.CellRangeAddress
8+
import org.apache.poi.ss.util.RegionUtil
9+
import org.apache.poi.xssf.usermodel.XSSFColor
10+
import org.apache.poi.xssf.usermodel.extensions.XSSFCellBorder.BorderSide
11+
import static org.apache.poi.xssf.usermodel.extensions.XSSFCellBorder.BorderSide.*
12+
13+
@CompileStatic
14+
@TupleConstructor
15+
class CellRangeBorderStyleApplier implements BorderStyleApplier {
16+
17+
CellRangeAddress range
18+
Sheet sheet
19+
20+
@Override
21+
void applyStyle(BorderSide side, BorderStyle style) {
22+
switch(side) {
23+
case TOP:
24+
RegionUtil.setBorderTop(style, range, sheet)
25+
break
26+
case BOTTOM:
27+
RegionUtil.setBorderBottom(style, range, sheet)
28+
break
29+
case LEFT:
30+
RegionUtil.setBorderLeft(style, range, sheet)
31+
break
32+
case RIGHT:
33+
RegionUtil.setBorderRight(style, range, sheet)
34+
break
35+
}
36+
}
37+
38+
@Override
39+
void applyStyle(BorderStyle style) {
40+
RegionUtil.setBorderTop(style, range, sheet)
41+
RegionUtil.setBorderBottom(style, range, sheet)
42+
RegionUtil.setBorderLeft(style, range, sheet)
43+
RegionUtil.setBorderRight(style, range, sheet)
44+
}
45+
46+
@Override
47+
void applyColor(BorderSide side, XSSFColor color) {
48+
switch(side) {
49+
case TOP:
50+
RegionUtil.setTopBorderColor(color.index, range, sheet)
51+
break
52+
case BOTTOM:
53+
RegionUtil.setBottomBorderColor(color.index, range, sheet)
54+
break
55+
case LEFT:
56+
RegionUtil.setLeftBorderColor(color.index, range, sheet)
57+
break
58+
case RIGHT:
59+
RegionUtil.setRightBorderColor(color.index, range, sheet)
60+
break
61+
}
62+
}
63+
64+
@Override
65+
void applyColor(XSSFColor color) {
66+
RegionUtil.setTopBorderColor(color.index, range, sheet)
67+
RegionUtil.setBottomBorderColor(color.index, range, sheet)
68+
RegionUtil.setLeftBorderColor(color.index, range, sheet)
69+
RegionUtil.setRightBorderColor(color.index, range, sheet)
70+
}
71+
}
Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
package com.jameskleeh.excel.style
2+
3+
import groovy.transform.CompileStatic
4+
import groovy.transform.TupleConstructor
5+
import org.apache.poi.ss.usermodel.BorderStyle
6+
import org.apache.poi.xssf.usermodel.XSSFCellStyle
7+
import org.apache.poi.xssf.usermodel.XSSFColor
8+
import org.apache.poi.xssf.usermodel.extensions.XSSFCellBorder.BorderSide
9+
import static org.apache.poi.xssf.usermodel.extensions.XSSFCellBorder.BorderSide.*
10+
11+
@CompileStatic
12+
@TupleConstructor
13+
class CellStyleBorderStyleApplier implements BorderStyleApplier {
14+
15+
XSSFCellStyle cellStyle
16+
17+
@Override
18+
void applyStyle(BorderSide side, BorderStyle style) {
19+
switch(side) {
20+
case TOP:
21+
cellStyle.setBorderTop(style)
22+
break
23+
case BOTTOM:
24+
cellStyle.setBorderBottom(style)
25+
break
26+
case LEFT:
27+
cellStyle.setBorderLeft(style)
28+
break
29+
case RIGHT:
30+
cellStyle.setBorderRight(style)
31+
break
32+
}
33+
}
34+
35+
@Override
36+
void applyStyle(BorderStyle style) {
37+
cellStyle.setBorderTop(style)
38+
cellStyle.setBorderBottom(style)
39+
cellStyle.setBorderLeft(style)
40+
cellStyle.setBorderRight(style)
41+
}
42+
43+
@Override
44+
void applyColor(BorderSide side, XSSFColor color) {
45+
switch(side) {
46+
case TOP:
47+
cellStyle.setTopBorderColor(color)
48+
break
49+
case BOTTOM:
50+
cellStyle.setBottomBorderColor(color)
51+
break
52+
case LEFT:
53+
cellStyle.setLeftBorderColor(color)
54+
break
55+
case RIGHT:
56+
cellStyle.setRightBorderColor(color)
57+
break
58+
}
59+
}
60+
61+
@Override
62+
void applyColor(XSSFColor color) {
63+
cellStyle.setTopBorderColor(color)
64+
cellStyle.setBottomBorderColor(color)
65+
cellStyle.setLeftBorderColor(color)
66+
cellStyle.setRightBorderColor(color)
67+
}
68+
69+
}

src/test/groovy/com/jameskleeh/excel/CellStyleBuilderSpec.groovy

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -731,4 +731,19 @@ class CellStyleBuilderSpec extends Specification {
731731
style4.borderBottomEnum == BorderStyle.NONE
732732
}
733733

734+
void "temp test"() {
735+
ExcelBuilder.output(new FileOutputStream(new File('/Users/jameskleeh/Desktop/foo.xlsx'))) {
736+
sheet {
737+
row {
738+
merge([border: BorderStyle.THIN]) {
739+
cell('Test')
740+
skipCells(1)
741+
}
742+
}
743+
}
744+
}
745+
expect:
746+
true
747+
}
748+
734749
}

travis-build.sh

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
#!/bin/bash
22
set -e
33

4-
./gradlew clean test
4+
./gradlew clean check
55

66
EXIT_STATUS=0
77

0 commit comments

Comments
 (0)