Skip to content

Commit b5d2426

Browse files
authored
Fix Row.setRowStyle() not propagating styles to cells in XSSFCell and SXSSFCell (#1031)
* Fix row style propagation bug in XSSFCell and SXSSFCell * Fix HSSF style inheritance and update XSSF tests - Add fallback to column and row styles for unstyled HSSF cells - Convert XSSF workbook text fixtures to use try-with-resources - Clean up test formatting and static JUnit assertions
1 parent e657fc9 commit b5d2426

7 files changed

Lines changed: 300 additions & 27 deletions

File tree

poi-ooxml/src/main/java/org/apache/poi/xssf/streaming/SXSSFCell.java

Lines changed: 28 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -584,7 +584,10 @@ public void setCellStyle(CellStyle style)
584584
}
585585

586586
/**
587-
* Return the cell's style.
587+
* Return the cell's style. Since POI v5.2.3, this returns the column style if the
588+
* cell has no style of its own. If no column default style is set, the row default style is checked.
589+
* This method has always fallen back to return the default style
590+
* if there is no other style to return.
588591
*
589592
* @return the cell's style. Never null. Default cell style has zero index and can be obtained as
590593
* <code>workbook.getCellStyleAt(0)</code>
@@ -593,24 +596,37 @@ public void setCellStyle(CellStyle style)
593596
@Override
594597
public CellStyle getCellStyle()
595598
{
596-
if (_style == null) {
597-
CellStyle style = getDefaultCellStyleFromColumn();
598-
if (style == null) {
599-
SXSSFWorkbook wb = getSheet().getWorkbook();
600-
style = wb.getCellStyleAt(0);
601-
}
602-
_style = style;
599+
if (_style != null) {
600+
return _style;
601+
}
602+
CellStyle style = getDefaultCellStyleFromColumn();
603+
if (style == null) {
604+
style = getDefaultCellStyleFromRow();
605+
}
606+
if (style == null) {
607+
SXSSFWorkbook wb = getSheet().getWorkbook();
608+
style = wb.getCellStyleAt(0);
603609
}
604-
return _style;
610+
return style;
605611
}
606612

607613
private CellStyle getDefaultCellStyleFromColumn() {
608-
CellStyle style = null;
609614
SXSSFSheet sheet = getSheet();
610615
if (sheet != null) {
611-
style = sheet.getColumnStyle(getColumnIndex());
616+
int idx = sheet._sh.getColumnHelper().getColDefaultStyle(getColumnIndex());
617+
if (idx >= 0) {
618+
return getSheet().getWorkbook().getCellStyleAt(idx);
619+
}
612620
}
613-
return style;
621+
return null;
622+
}
623+
624+
private CellStyle getDefaultCellStyleFromRow() {
625+
SXSSFRow row = (SXSSFRow) getRow();
626+
if (row != null && row.isFormatted()) {
627+
return row.getRowStyle();
628+
}
629+
return null;
614630
}
615631

616632
/**

poi-ooxml/src/main/java/org/apache/poi/xssf/usermodel/XSSFCell.java

Lines changed: 21 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -572,6 +572,12 @@ public XSSFCellStyle getCellStyle() {
572572
if (style == null) {
573573
style = getDefaultCellStyleFromColumn();
574574
}
575+
if (style == null) {
576+
style = getDefaultCellStyleFromRow();
577+
}
578+
if (style == null && _stylesSource.getNumCellStyles() > 0) {
579+
style = _stylesSource.getStyleAt(0);
580+
}
575581
return style;
576582
}
577583

@@ -587,24 +593,27 @@ private XSSFCellStyle getExplicitCellStyle() {
587593
}
588594

589595
private XSSFCellStyle getDefaultCellStyleFromColumn() {
590-
XSSFCellStyle style = null;
591596
XSSFSheet sheet = getSheet();
592597
if (sheet != null) {
593-
style = (XSSFCellStyle) sheet.getColumnStyle(getColumnIndex());
598+
int idx = sheet.getColumnHelper().getColDefaultStyle(getColumnIndex());
599+
if (idx >= 0) {
600+
return _stylesSource.getStyleAt(idx);
601+
}
594602
}
595-
return style;
603+
return null;
604+
}
605+
606+
private XSSFCellStyle getDefaultCellStyleFromRow() {
607+
XSSFRow row = getRow();
608+
if (row != null && row.isFormatted()) {
609+
return row.getRowStyle();
610+
}
611+
return null;
596612
}
597613

598614
protected void applyDefaultCellStyleIfNecessary() {
599-
XSSFCellStyle style = getExplicitCellStyle();
600-
if (style == null) {
601-
XSSFSheet sheet = getSheet();
602-
if (sheet != null) {
603-
XSSFCellStyle defaultStyle = getDefaultCellStyleFromColumn();
604-
if (defaultStyle != null) {
605-
setCellStyle(defaultStyle);
606-
}
607-
}
615+
if (getExplicitCellStyle() == null) {
616+
setCellStyle(getCellStyle());
608617
}
609618
}
610619

poi-ooxml/src/test/java/org/apache/poi/xssf/streaming/TestSXSSFRow.java

Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,14 +20,24 @@
2020
package org.apache.poi.xssf.streaming;
2121

2222
import org.apache.poi.ss.tests.usermodel.BaseTestXRow;
23+
import org.apache.poi.ss.usermodel.CellStyle;
2324
import org.apache.poi.xssf.SXSSFITestDataProvider;
25+
import org.apache.poi.xssf.usermodel.XSSFCell;
26+
import org.apache.poi.xssf.usermodel.XSSFCellStyle;
27+
import org.apache.poi.xssf.usermodel.XSSFFont;
28+
import org.apache.poi.xssf.usermodel.XSSFRow;
29+
import org.apache.poi.xssf.usermodel.XSSFSheet;
30+
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
2431
import org.junit.jupiter.api.AfterEach;
2532
import org.junit.jupiter.api.Disabled;
2633
import org.junit.jupiter.api.Test;
2734

2835
import java.io.IOException;
2936

3037
import static org.junit.jupiter.api.Assertions.assertEquals;
38+
import static org.junit.jupiter.api.Assertions.assertNotNull;
39+
import static org.junit.jupiter.api.Assertions.assertTrue;
40+
import static org.junit.jupiter.api.Assertions.assertFalse;
3141

3242
/**
3343
* Tests for XSSFRow
@@ -66,4 +76,85 @@ void testCellColumn() throws IOException {
6676
}
6777
}
6878

79+
@Test
80+
void testSetRowStylePropagatedToCells() throws IOException {
81+
try (SXSSFWorkbook wb = new SXSSFWorkbook()) {
82+
SXSSFSheet sheet = wb.createSheet("test");
83+
84+
// create a bold style
85+
XSSFCellStyle boldStyle = (XSSFCellStyle) wb.createCellStyle();
86+
XSSFFont boldFont = (XSSFFont) wb.createFont();
87+
boldFont.setBold(true);
88+
boldStyle.setFont(boldFont);
89+
90+
// apply style to row, then create cells
91+
SXSSFRow row = sheet.createRow(0);
92+
row.setRowStyle(boldStyle);
93+
94+
SXSSFCell cell0 = row.createCell(0);
95+
cell0.setCellValue("Header A");
96+
SXSSFCell cell1 = row.createCell(1);
97+
cell1.setCellValue("Header B");
98+
99+
// cells without explicit style should inherit the row style via getCellStyle()
100+
CellStyle cellStyle0 = cell0.getCellStyle();
101+
assertNotNull(cellStyle0);
102+
assertTrue(wb.getFontAt(cellStyle0.getFontIndex()).getBold(),
103+
"cell should inherit bold font from row style");
104+
105+
CellStyle cellStyle1 = cell1.getCellStyle();
106+
assertNotNull(cellStyle1);
107+
assertTrue(wb.getFontAt(cellStyle1.getFontIndex()).getBold(),
108+
"cell should inherit bold font from row style");
109+
110+
// a cell with an explicit style should NOT be overridden by row style
111+
CellStyle plainStyle = wb.createCellStyle();
112+
SXSSFCell cell2 = row.createCell(2);
113+
cell2.setCellStyle(plainStyle);
114+
cell2.setCellValue("Plain");
115+
116+
CellStyle cellStyle2 = cell2.getCellStyle();
117+
assertFalse(wb.getFontAt(cellStyle2.getFontIndex()).getBold(),
118+
"cell with explicit non-bold style should remain non-bold");
119+
}
120+
}
121+
122+
@Test
123+
void testSetRowStylePropagatedAfterWrite() throws IOException {
124+
try (SXSSFWorkbook wb = new SXSSFWorkbook()) {
125+
SXSSFSheet sheet = wb.createSheet("test");
126+
127+
// create a bold style
128+
XSSFCellStyle boldStyle = (XSSFCellStyle) wb.createCellStyle();
129+
XSSFFont boldFont = (XSSFFont) wb.createFont();
130+
boldFont.setBold(true);
131+
boldStyle.setFont(boldFont);
132+
133+
// apply style to row, then create cells
134+
SXSSFRow row = sheet.createRow(0);
135+
row.setRowStyle(boldStyle);
136+
row.createCell(0).setCellValue("Column A");
137+
row.createCell(1).setCellValue("Column B");
138+
row.createCell(2).setCellValue("Column C");
139+
140+
// write and read back — SXSSFITestDataProvider returns XSSFWorkbook
141+
XSSFWorkbook wb2 = SXSSFITestDataProvider.instance.writeOutAndReadBack(wb);
142+
143+
XSSFSheet sheet2 = wb2.getSheet("test");
144+
XSSFRow row2 = sheet2.getRow(0);
145+
assertNotNull(row2);
146+
147+
for (int i = 0; i < 3; i++) {
148+
XSSFCell cell = row2.getCell(i);
149+
assertNotNull(cell, "cell " + i + " should exist after read-back");
150+
XSSFCellStyle style = cell.getCellStyle();
151+
assertNotNull(style, "cell " + i + " should have a style after read-back");
152+
assertTrue(wb2.getFontAt(style.getFontIndex()).getBold(),
153+
"cell " + i + " should be bold after write/read-back");
154+
}
155+
156+
wb2.close();
157+
}
158+
}
159+
69160
}

poi-ooxml/src/test/java/org/apache/poi/xssf/usermodel/TestXSSFRow.java

Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -485,6 +485,86 @@ void duplicateRows() throws IOException {
485485
}
486486
}
487487

488+
@Test
489+
void testSetRowStylePropagatedToCells() throws IOException {
490+
try (XSSFWorkbook workbook = new XSSFWorkbook()) {
491+
final XSSFSheet sheet = workbook.createSheet("test");
492+
493+
// create a bold style
494+
XSSFCellStyle boldStyle = workbook.createCellStyle();
495+
XSSFFont boldFont = workbook.createFont();
496+
boldFont.setBold(true);
497+
boldStyle.setFont(boldFont);
498+
499+
// apply style to row, then create cells
500+
final XSSFRow row = sheet.createRow(0);
501+
row.setRowStyle(boldStyle);
502+
503+
XSSFCell cell0 = row.createCell(0);
504+
cell0.setCellValue("Header A");
505+
XSSFCell cell1 = row.createCell(1);
506+
cell1.setCellValue("Header B");
507+
508+
// cells without explicit style should inherit the row style via getCellStyle()
509+
XSSFCellStyle cellStyle0 = cell0.getCellStyle();
510+
assertNotNull(cellStyle0);
511+
assertTrue(workbook.getFontAt(cellStyle0.getFontIndex()).getBold(),
512+
"cell should inherit bold font from row style");
513+
514+
XSSFCellStyle cellStyle1 = cell1.getCellStyle();
515+
assertNotNull(cellStyle1);
516+
assertTrue(workbook.getFontAt(cellStyle1.getFontIndex()).getBold(),
517+
"cell should inherit bold font from row style");
518+
519+
// a cell with an explicit style should NOT be overridden by row style
520+
XSSFCellStyle plainStyle = workbook.createCellStyle();
521+
XSSFCell cell2 = row.createCell(2);
522+
cell2.setCellStyle(plainStyle);
523+
cell2.setCellValue("Plain");
524+
525+
XSSFCellStyle cellStyle2 = cell2.getCellStyle();
526+
assertFalse(workbook.getFontAt(cellStyle2.getFontIndex()).getBold(),
527+
"cell with explicit non-bold style should remain non-bold");
528+
}
529+
}
530+
531+
@Test
532+
void testSetRowStylePropagatedAfterWrite() throws IOException {
533+
try (XSSFWorkbook workbook = new XSSFWorkbook()) {
534+
final XSSFSheet sheet = workbook.createSheet("test");
535+
536+
// create a bold style
537+
XSSFCellStyle boldStyle = workbook.createCellStyle();
538+
XSSFFont boldFont = workbook.createFont();
539+
boldFont.setBold(true);
540+
boldStyle.setFont(boldFont);
541+
542+
// apply style to row, then create cells
543+
final XSSFRow row = sheet.createRow(0);
544+
row.setRowStyle(boldStyle);
545+
row.createCell(0, CellType.STRING).setCellValue("Column A");
546+
row.createCell(1, CellType.STRING).setCellValue("Column B");
547+
row.createCell(2, CellType.STRING).setCellValue("Column C");
548+
549+
// write and read back — exercises onDocumentWrite() ->
550+
// applyDefaultCellStyleIfNecessary()
551+
try (XSSFWorkbook wb2 = XSSFTestDataSamples.writeOutAndReadBack(workbook)) {
552+
XSSFSheet sheet2 = wb2.getSheet("test");
553+
XSSFRow row2 = sheet2.getRow(0);
554+
assertNotNull(row2);
555+
556+
for (int i = 0; i < 3; i++) {
557+
XSSFCell cell = row2.getCell(i);
558+
assertNotNull(cell, "cell " + i + " should exist after read-back");
559+
XSSFCellStyle style = cell.getCellStyle();
560+
assertNotNull(style, "cell " + i + " should have a style after read-back");
561+
assertTrue(wb2.getFontAt(style.getFontIndex()).getBold(),
562+
"cell " + i + " should be bold after write/read-back");
563+
}
564+
}
565+
}
566+
}
567+
488568
private void fillData(int startAtRow, Sheet sheet) {
489569
Row header = sheet.createRow(0);
490570
for (int rownum = startAtRow; rownum < 2; rownum++) {

poi/src/main/java/org/apache/poi/hssf/usermodel/HSSFCell.java

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -978,14 +978,30 @@ public void setCellStyle(HSSFCellStyle style) {
978978

979979
/**
980980
* get the style for the cell. This is a reference to a cell style contained in the workbook
981-
* object.
981+
* object. If the cell does not have an explicit style assigned, this method will fall back
982+
* to returning the column or row style (if any).
982983
* @see org.apache.poi.hssf.usermodel.HSSFWorkbook#getCellStyleAt(int)
983984
*/
984985
@Override
985986
public HSSFCellStyle getCellStyle()
986987
{
987988
short styleIndex=_record.getXFIndex();
988989
ExtendedFormatRecord xf = _book.getWorkbook().getExFormatAt(styleIndex);
990+
991+
if (styleIndex == 0x0f) {
992+
// Fallback to column style
993+
HSSFCellStyle colStyle = _sheet.getColumnStyle(getColumnIndex());
994+
if (colStyle != null) {
995+
return colStyle;
996+
}
997+
998+
// Fallback to row style
999+
HSSFCellStyle rowStyle = getRow().getRowStyle();
1000+
if (rowStyle != null) {
1001+
return rowStyle;
1002+
}
1003+
}
1004+
9891005
return new HSSFCellStyle(styleIndex, xf, _book);
9901006
}
9911007

0 commit comments

Comments
 (0)