mirror of https://github.com/apache/poi.git
Bug #57517: Fix various things in HSSFOptimiser to make many more cases work fine: Column styles, row styles, user defined styles, ...
Also call optimise in integration-tests and handle some cases of invalid content in files. git-svn-id: https://svn.apache.org/repos/asf/poi/trunk@1814373 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
parent
d4ad2ffd53
commit
ce77cd6270
|
@ -17,6 +17,7 @@
|
||||||
package org.apache.poi.stress;
|
package org.apache.poi.stress;
|
||||||
|
|
||||||
import static org.junit.Assert.assertFalse;
|
import static org.junit.Assert.assertFalse;
|
||||||
|
import static org.junit.Assert.assertNotNull;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.FileInputStream;
|
import java.io.FileInputStream;
|
||||||
|
@ -27,11 +28,13 @@ import java.io.PrintStream;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
||||||
import org.apache.poi.EncryptedDocumentException;
|
|
||||||
import org.apache.poi.hssf.OldExcelFormatException;
|
import org.apache.poi.hssf.OldExcelFormatException;
|
||||||
import org.apache.poi.hssf.dev.BiffViewer;
|
import org.apache.poi.hssf.dev.BiffViewer;
|
||||||
|
import org.apache.poi.hssf.usermodel.HSSFOptimiser;
|
||||||
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
|
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
|
||||||
import org.apache.poi.util.RecordFormatException;
|
import org.apache.poi.ss.usermodel.Cell;
|
||||||
|
import org.apache.poi.ss.usermodel.Row;
|
||||||
|
import org.apache.poi.ss.usermodel.Sheet;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
|
|
||||||
public class HSSFFileHandler extends SpreadsheetHandler {
|
public class HSSFFileHandler extends SpreadsheetHandler {
|
||||||
|
@ -40,7 +43,7 @@ public class HSSFFileHandler extends SpreadsheetHandler {
|
||||||
public void handleFile(InputStream stream, String path) throws Exception {
|
public void handleFile(InputStream stream, String path) throws Exception {
|
||||||
HSSFWorkbook wb = new HSSFWorkbook(stream);
|
HSSFWorkbook wb = new HSSFWorkbook(stream);
|
||||||
handleWorkbook(wb);
|
handleWorkbook(wb);
|
||||||
|
|
||||||
// TODO: some documents fail currently...
|
// TODO: some documents fail currently...
|
||||||
// Note - as of Bugzilla 48036 (svn r828244, r828247) POI is capable of evaluating
|
// Note - as of Bugzilla 48036 (svn r828244, r828247) POI is capable of evaluating
|
||||||
// IntersectionPtg. However it is still not capable of parsing it.
|
// IntersectionPtg. However it is still not capable of parsing it.
|
||||||
|
@ -52,6 +55,15 @@ public class HSSFFileHandler extends SpreadsheetHandler {
|
||||||
|
|
||||||
// also try to see if some of the Records behave incorrectly
|
// also try to see if some of the Records behave incorrectly
|
||||||
// TODO: still fails on some records... RecordsStresser.handleWorkbook(wb);
|
// TODO: still fails on some records... RecordsStresser.handleWorkbook(wb);
|
||||||
|
|
||||||
|
HSSFOptimiser.optimiseCellStyles(wb);
|
||||||
|
for(Sheet sheet : wb) {
|
||||||
|
for (Row row : sheet) {
|
||||||
|
for (Cell cell : row) {
|
||||||
|
assertNotNull(cell.getCellStyle());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static final Set<String> EXPECTED_ADDITIONAL_FAILURES = new HashSet<>();
|
private static final Set<String> EXPECTED_ADDITIONAL_FAILURES = new HashSet<>();
|
||||||
|
@ -86,14 +98,6 @@ public class HSSFFileHandler extends SpreadsheetHandler {
|
||||||
EXPECTED_ADDITIONAL_FAILURES.contains(file.getParentFile().getName() + "/" + file.getName()));
|
EXPECTED_ADDITIONAL_FAILURES.contains(file.getParentFile().getName() + "/" + file.getName()));
|
||||||
} catch (OldExcelFormatException e) {
|
} catch (OldExcelFormatException e) {
|
||||||
// old excel formats are not supported here
|
// old excel formats are not supported here
|
||||||
} catch (EncryptedDocumentException e) {
|
|
||||||
if(!EXPECTED_ADDITIONAL_FAILURES.contains(file.getParentFile().getName() + "/" + file.getName())) {
|
|
||||||
throw e;
|
|
||||||
}
|
|
||||||
} catch (RecordFormatException e) {
|
|
||||||
if(!EXPECTED_ADDITIONAL_FAILURES.contains(file.getParentFile().getName() + "/" + file.getName())) {
|
|
||||||
throw e;
|
|
||||||
}
|
|
||||||
} catch (RuntimeException e) {
|
} catch (RuntimeException e) {
|
||||||
if(!EXPECTED_ADDITIONAL_FAILURES.contains(file.getParentFile().getName() + "/" + file.getName())) {
|
if(!EXPECTED_ADDITIONAL_FAILURES.contains(file.getParentFile().getName() + "/" + file.getName())) {
|
||||||
throw e;
|
throw e;
|
||||||
|
@ -107,12 +111,9 @@ public class HSSFFileHandler extends SpreadsheetHandler {
|
||||||
@Test
|
@Test
|
||||||
public void test() throws Exception {
|
public void test() throws Exception {
|
||||||
File file = new File("test-data/spreadsheet/49219.xls");
|
File file = new File("test-data/spreadsheet/49219.xls");
|
||||||
|
|
||||||
InputStream stream = new FileInputStream(file);
|
try (InputStream stream = new FileInputStream(file)) {
|
||||||
try {
|
|
||||||
handleFile(stream, file.getPath());
|
handleFile(stream, file.getPath());
|
||||||
} finally {
|
|
||||||
stream.close();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1680,4 +1680,12 @@ public final class InternalSheet {
|
||||||
public int getColumnOutlineLevel(int columnIndex) {
|
public int getColumnOutlineLevel(int columnIndex) {
|
||||||
return _columnInfos.getOutlineLevel(columnIndex);
|
return _columnInfos.getOutlineLevel(columnIndex);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public int getMinColumnIndex() {
|
||||||
|
return _columnInfos.getMinColumnIndex();
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getMaxColumnIndex() {
|
||||||
|
return _columnInfos.getMaxColumnIndex();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -936,6 +936,27 @@ public final class InternalWorkbook {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Update the StyleRecord to point to the new
|
||||||
|
* given index.
|
||||||
|
*
|
||||||
|
* @param oldXf the extended format index that was previously associated with this StyleRecord
|
||||||
|
* @param newXf the extended format index that is now associated with this StyleRecord
|
||||||
|
*/
|
||||||
|
public void updateStyleRecord(int oldXf, int newXf) {
|
||||||
|
// Style records always follow after
|
||||||
|
// the ExtendedFormat records
|
||||||
|
for(int i=records.getXfpos(); i<records.size(); i++) {
|
||||||
|
Record r = records.get(i);
|
||||||
|
if (r instanceof StyleRecord) {
|
||||||
|
StyleRecord sr = (StyleRecord)r;
|
||||||
|
if (sr.getXFIndex() == oldXf) {
|
||||||
|
sr.setXFIndex(newXf);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a new StyleRecord, for the given Extended
|
* Creates a new StyleRecord, for the given Extended
|
||||||
* Format index, and adds it onto the end of the
|
* Format index, and adds it onto the end of the
|
||||||
|
|
|
@ -489,6 +489,7 @@ public final class ColumnInfoRecordsAggregate extends RecordAggregate implements
|
||||||
setColumn(i, null, null, Integer.valueOf(level), null, null);
|
setColumn(i, null, null, Integer.valueOf(level), null, null);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Finds the <tt>ColumnInfoRecord</tt> which contains the specified columnIndex
|
* Finds the <tt>ColumnInfoRecord</tt> which contains the specified columnIndex
|
||||||
* @param columnIndex index of the column (not the index of the ColumnInfoRecord)
|
* @param columnIndex index of the column (not the index of the ColumnInfoRecord)
|
||||||
|
@ -504,6 +505,7 @@ public final class ColumnInfoRecordsAggregate extends RecordAggregate implements
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
public int getMaxOutlineLevel() {
|
public int getMaxOutlineLevel() {
|
||||||
int result = 0;
|
int result = 0;
|
||||||
int count=records.size();
|
int count=records.size();
|
||||||
|
@ -513,6 +515,7 @@ public final class ColumnInfoRecordsAggregate extends RecordAggregate implements
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
public int getOutlineLevel(int columnIndex) {
|
public int getOutlineLevel(int columnIndex) {
|
||||||
ColumnInfoRecord ci = findColumnInfo(columnIndex);
|
ColumnInfoRecord ci = findColumnInfo(columnIndex);
|
||||||
if (ci != null) {
|
if (ci != null) {
|
||||||
|
@ -521,4 +524,34 @@ public final class ColumnInfoRecordsAggregate extends RecordAggregate implements
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public int getMinColumnIndex() {
|
||||||
|
if(records.isEmpty()) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int minIndex = Integer.MAX_VALUE;
|
||||||
|
int nInfos = records.size();
|
||||||
|
for(int i=0; i< nInfos; i++) {
|
||||||
|
ColumnInfoRecord ci = getColInfo(i);
|
||||||
|
minIndex = Math.min(minIndex, ci.getFirstColumn());
|
||||||
|
}
|
||||||
|
|
||||||
|
return minIndex;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getMaxColumnIndex() {
|
||||||
|
if(records.isEmpty()) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int maxIndex = 0;
|
||||||
|
int nInfos = records.size();
|
||||||
|
for(int i=0; i< nInfos; i++) {
|
||||||
|
ColumnInfoRecord ci = getColInfo(i);
|
||||||
|
maxIndex = Math.max(maxIndex, ci.getLastColumn());
|
||||||
|
}
|
||||||
|
|
||||||
|
return maxIndex;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -20,6 +20,7 @@ import java.util.HashSet;
|
||||||
|
|
||||||
import org.apache.poi.hssf.record.ExtendedFormatRecord;
|
import org.apache.poi.hssf.record.ExtendedFormatRecord;
|
||||||
import org.apache.poi.hssf.record.FontRecord;
|
import org.apache.poi.hssf.record.FontRecord;
|
||||||
|
import org.apache.poi.hssf.record.StyleRecord;
|
||||||
import org.apache.poi.hssf.record.common.UnicodeString;
|
import org.apache.poi.hssf.record.common.UnicodeString;
|
||||||
import org.apache.poi.ss.usermodel.Cell;
|
import org.apache.poi.ss.usermodel.Cell;
|
||||||
import org.apache.poi.ss.usermodel.CellType;
|
import org.apache.poi.ss.usermodel.CellType;
|
||||||
|
@ -185,50 +186,81 @@ public class HSSFOptimiser {
|
||||||
|
|
||||||
// Get each style record, so we can do deletes
|
// Get each style record, so we can do deletes
|
||||||
// without getting confused
|
// without getting confused
|
||||||
ExtendedFormatRecord[] xfrs = new ExtendedFormatRecord[newPos.length];
|
ExtendedFormatRecord[] xfrs = new ExtendedFormatRecord[newPos.length];
|
||||||
for(int i=0; i<newPos.length; i++) {
|
for(int i=0; i<newPos.length; i++) {
|
||||||
xfrs[i] = workbook.getWorkbook().getExFormatAt(i);
|
xfrs[i] = workbook.getWorkbook().getExFormatAt(i);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Loop over each style, seeing if it is the same
|
// Loop over each style, seeing if it is the same
|
||||||
// as an earlier one. If it is, point users of the
|
// as an earlier one. If it is, point users of the
|
||||||
// later duplicate copy to the earlier one, and
|
// later duplicate copy to the earlier one, and
|
||||||
// mark the later one as needing deleting
|
// mark the later one as needing deleting
|
||||||
// Only work on user added ones, which come after 20
|
// Only work on user added ones, which come after 20
|
||||||
for(int i=21; i<newPos.length; i++) {
|
for (int i = 21; i < newPos.length; i++) {
|
||||||
// Check this one for being a duplicate
|
// Check this one for being a duplicate
|
||||||
// of an earlier one
|
// of an earlier one
|
||||||
int earlierDuplicate = -1;
|
int earlierDuplicate = -1;
|
||||||
for(int j=0; j<i && earlierDuplicate == -1; j++) {
|
for (int j = 0; j < i && earlierDuplicate == -1; j++) {
|
||||||
ExtendedFormatRecord xfCheck = workbook.getWorkbook().getExFormatAt(j);
|
ExtendedFormatRecord xfCheck = workbook.getWorkbook().getExFormatAt(j);
|
||||||
if(xfCheck.equals(xfrs[i])) {
|
if (xfCheck.equals(xfrs[i]) &&
|
||||||
earlierDuplicate = j;
|
// newer duplicate user defined styles
|
||||||
}
|
!isUserDefined(workbook, j)) {
|
||||||
}
|
earlierDuplicate = j;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// If we got a duplicate, mark it as such
|
// If we got a duplicate, mark it as such
|
||||||
if(earlierDuplicate != -1) {
|
if(earlierDuplicate != -1) {
|
||||||
newPos[i] = (short)earlierDuplicate;
|
newPos[i] = (short)earlierDuplicate;
|
||||||
zapRecords[i] = true;
|
zapRecords[i] = true;
|
||||||
}
|
}
|
||||||
// If we got a duplicate, mark the one we're keeping as used
|
|
||||||
if(earlierDuplicate != -1) {
|
|
||||||
isUsed[earlierDuplicate] = true;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Loop over all the cells in the file, and identify any user defined
|
// Loop over all the cells in the file, and identify any user defined
|
||||||
// styles aren't actually being used (don't touch built-in ones)
|
// styles aren't actually being used (don't touch built-in ones)
|
||||||
for(int sheetNum=0; sheetNum<workbook.getNumberOfSheets(); sheetNum++) {
|
for (int sheetNum = 0; sheetNum < workbook.getNumberOfSheets(); sheetNum++) {
|
||||||
HSSFSheet s = workbook.getSheetAt(sheetNum);
|
HSSFSheet s = workbook.getSheetAt(sheetNum);
|
||||||
for (Row row : s) {
|
for (Row row : s) {
|
||||||
for (Cell cellI : row) {
|
for (Cell cellI : row) {
|
||||||
HSSFCell cell = (HSSFCell)cellI;
|
HSSFCell cell = (HSSFCell) cellI;
|
||||||
short oldXf = cell.getCellValueRecord().getXFIndex();
|
short oldXf = cell.getCellValueRecord().getXFIndex();
|
||||||
isUsed[oldXf] = true;
|
// some documents contain invalid values here
|
||||||
}
|
if(oldXf < newPos.length) {
|
||||||
}
|
isUsed[oldXf] = true;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// also mark row style as being used
|
||||||
|
short oldXf = ((HSSFRow) row).getRowRecord().getXFIndex();
|
||||||
|
// some documents contain invalid values here
|
||||||
|
if(oldXf < newPos.length) {
|
||||||
|
isUsed[oldXf] = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// also mark column styles as being used
|
||||||
|
for (int col = s.getSheet().getMinColumnIndex(); col <= s.getSheet().getMaxColumnIndex(); col++) {
|
||||||
|
short oldXf = s.getSheet().getXFIndexForColAt((short) col);
|
||||||
|
// some documents contain invalid values here
|
||||||
|
if(oldXf < newPos.length) {
|
||||||
|
isUsed[oldXf] = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Propagate isUsed for duplicates and always set user styles to being used to never optimize them away
|
||||||
|
for (int i = 21; i < isUsed.length; i++) {
|
||||||
|
// user defined styles are always "used"
|
||||||
|
if (isUserDefined(workbook, i)) {
|
||||||
|
isUsed[i] = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// If we got a duplicate which is used, mark the one we're keeping as used
|
||||||
|
if(newPos[i] != i && isUsed[i]) {
|
||||||
|
isUsed[newPos[i]] = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Mark any that aren't used as needing zapping
|
// Mark any that aren't used as needing zapping
|
||||||
for (int i=21; i<isUsed.length; i++) {
|
for (int i=21; i<isUsed.length; i++) {
|
||||||
if (! isUsed[i]) {
|
if (! isUsed[i]) {
|
||||||
|
@ -251,9 +283,21 @@ public class HSSFOptimiser {
|
||||||
if(zapRecords[j]) newPosition--;
|
if(zapRecords[j]) newPosition--;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Update the new position
|
// Update the new position
|
||||||
newPos[i] = newPosition;
|
newPos[i] = newPosition;
|
||||||
}
|
// also update StyleRecord and Parent-link
|
||||||
|
if (i != newPosition && newPosition != 0) {
|
||||||
|
workbook.getWorkbook().updateStyleRecord(i, newPosition);
|
||||||
|
|
||||||
|
ExtendedFormatRecord exFormat = workbook.getWorkbook().getExFormatAt(i);
|
||||||
|
short oldParent = exFormat.getParentIndex();
|
||||||
|
// some documents contain invalid values here
|
||||||
|
if(oldParent < newPos.length) {
|
||||||
|
short newParent = newPos[oldParent];
|
||||||
|
exFormat.setParentIndex(newParent);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Zap the un-needed user style records
|
// Zap the un-needed user style records
|
||||||
// removing by index, because removing by object may delete
|
// removing by index, because removing by object may delete
|
||||||
|
@ -269,20 +313,47 @@ public class HSSFOptimiser {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Finally, update the cells to point at their new extended format records
|
// Finally, update the cells to point at their new extended format records
|
||||||
for(int sheetNum=0; sheetNum<workbook.getNumberOfSheets(); sheetNum++) {
|
for (int sheetNum = 0; sheetNum < workbook.getNumberOfSheets(); sheetNum++) {
|
||||||
HSSFSheet s = workbook.getSheetAt(sheetNum);
|
HSSFSheet s = workbook.getSheetAt(sheetNum);
|
||||||
for (Row row : s) {
|
for (Row row : s) {
|
||||||
for (Cell cellI : row) {
|
for (Cell cell : row) {
|
||||||
HSSFCell cell = (HSSFCell)cellI;
|
short oldXf = ((HSSFCell) cell).getCellValueRecord().getXFIndex();
|
||||||
short oldXf = cell.getCellValueRecord().getXFIndex();
|
// some documents contain invalid values here
|
||||||
|
if(oldXf >= newPos.length) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
HSSFCellStyle newStyle = workbook.getCellStyleAt(newPos[oldXf]);
|
||||||
|
cell.setCellStyle(newStyle);
|
||||||
|
}
|
||||||
|
|
||||||
HSSFCellStyle newStyle = workbook.getCellStyleAt(
|
// adjust row column style
|
||||||
newPos[oldXf]
|
short oldXf = ((HSSFRow) row).getRowRecord().getXFIndex();
|
||||||
);
|
// some documents contain invalid values here
|
||||||
cell.setCellStyle(newStyle);
|
if(oldXf >= newPos.length) {
|
||||||
}
|
continue;
|
||||||
}
|
}
|
||||||
}
|
HSSFCellStyle newStyle = workbook.getCellStyleAt(newPos[oldXf]);
|
||||||
|
row.setRowStyle(newStyle);
|
||||||
|
}
|
||||||
|
|
||||||
|
// adjust cell column style
|
||||||
|
for (int col = s.getSheet().getMinColumnIndex(); col <= s.getSheet().getMaxColumnIndex(); col++) {
|
||||||
|
short oldXf = s.getSheet().getXFIndexForColAt((short) col);
|
||||||
|
// some documents contain invalid values here
|
||||||
|
if(oldXf >= newPos.length) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
HSSFCellStyle newStyle = workbook.getCellStyleAt(newPos[oldXf]);
|
||||||
|
s.setDefaultColumnStyle(col, newStyle);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static boolean isUserDefined(HSSFWorkbook workbook, int index) {
|
||||||
|
StyleRecord styleRecord = workbook.getWorkbook().getStyleRecord(index);
|
||||||
|
return styleRecord != null &&
|
||||||
|
!styleRecord.isBuiltin() &&
|
||||||
|
styleRecord.getName() != null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,12 +16,16 @@
|
||||||
==================================================================== */
|
==================================================================== */
|
||||||
package org.apache.poi.hssf.usermodel;
|
package org.apache.poi.hssf.usermodel;
|
||||||
|
|
||||||
import org.apache.poi.ss.usermodel.BorderStyle;
|
import java.io.IOException;
|
||||||
import org.apache.poi.ss.usermodel.HorizontalAlignment;
|
|
||||||
|
|
||||||
import junit.framework.TestCase;
|
import org.apache.poi.ss.usermodel.*;
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
public final class TestHSSFOptimiser extends TestCase {
|
import static org.junit.Assert.assertEquals;
|
||||||
|
import static org.junit.Assert.assertNotNull;
|
||||||
|
|
||||||
|
public final class TestHSSFOptimiser {
|
||||||
|
@Test
|
||||||
public void testDoesNoHarmIfNothingToDo() {
|
public void testDoesNoHarmIfNothingToDo() {
|
||||||
HSSFWorkbook wb = new HSSFWorkbook();
|
HSSFWorkbook wb = new HSSFWorkbook();
|
||||||
|
|
||||||
|
@ -60,6 +64,7 @@ public final class TestHSSFOptimiser extends TestCase {
|
||||||
assertEquals(f, s.getFont(wb));
|
assertEquals(f, s.getFont(wb));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
public void testOptimiseFonts() {
|
public void testOptimiseFonts() {
|
||||||
HSSFWorkbook wb = new HSSFWorkbook();
|
HSSFWorkbook wb = new HSSFWorkbook();
|
||||||
|
|
||||||
|
@ -158,6 +163,7 @@ public final class TestHSSFOptimiser extends TestCase {
|
||||||
assertEquals(8, r.getCell(1).getRichStringCellValue().getFontAtIndex(7));
|
assertEquals(8, r.getCell(1).getRichStringCellValue().getFontAtIndex(7));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
public void testOptimiseStyles() {
|
public void testOptimiseStyles() {
|
||||||
HSSFWorkbook wb = new HSSFWorkbook();
|
HSSFWorkbook wb = new HSSFWorkbook();
|
||||||
|
|
||||||
|
@ -274,6 +280,7 @@ public final class TestHSSFOptimiser extends TestCase {
|
||||||
assertEquals(21, r.getCell(8).getCellValueRecord().getXFIndex());
|
assertEquals(21, r.getCell(8).getCellValueRecord().getXFIndex());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
public void testOptimiseStylesCheckActualStyles() {
|
public void testOptimiseStylesCheckActualStyles() {
|
||||||
HSSFWorkbook wb = new HSSFWorkbook();
|
HSSFWorkbook wb = new HSSFWorkbook();
|
||||||
|
|
||||||
|
@ -313,4 +320,383 @@ public final class TestHSSFOptimiser extends TestCase {
|
||||||
assertEquals(BorderStyle.DASH_DOT, r.getCell(1).getCellStyle().getBorderBottom());
|
assertEquals(BorderStyle.DASH_DOT, r.getCell(1).getCellStyle().getBorderBottom());
|
||||||
assertEquals(BorderStyle.THICK, r.getCell(2).getCellStyle().getBorderBottom());
|
assertEquals(BorderStyle.THICK, r.getCell(2).getCellStyle().getBorderBottom());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testColumnAndRowStyles() {
|
||||||
|
HSSFWorkbook wb = new HSSFWorkbook();
|
||||||
|
assertEquals("Usually we have 21 pre-defined styles in a newly created Workbook, see InternalWorkbook.createWorkbook()",
|
||||||
|
21, wb.getNumCellStyles());
|
||||||
|
|
||||||
|
HSSFSheet sheet = wb.createSheet();
|
||||||
|
|
||||||
|
Row row = sheet.createRow(0);
|
||||||
|
row.createCell(0);
|
||||||
|
row.createCell(1);
|
||||||
|
row.setRowStyle(createColorStyle(wb, IndexedColors.RED));
|
||||||
|
|
||||||
|
row = sheet.createRow(1);
|
||||||
|
row.createCell(0);
|
||||||
|
row.createCell(1);
|
||||||
|
row.setRowStyle(createColorStyle(wb, IndexedColors.RED));
|
||||||
|
|
||||||
|
sheet.setDefaultColumnStyle(0, createColorStyle(wb, IndexedColors.RED));
|
||||||
|
sheet.setDefaultColumnStyle(1, createColorStyle(wb, IndexedColors.RED));
|
||||||
|
|
||||||
|
// now the color should be equal for those two columns and rows
|
||||||
|
checkColumnStyles(sheet, 0, 1, false);
|
||||||
|
checkRowStyles(sheet, 0, 1, false);
|
||||||
|
|
||||||
|
// Optimise styles
|
||||||
|
HSSFOptimiser.optimiseCellStyles(wb);
|
||||||
|
|
||||||
|
// We should have the same style-objects for these two columns and rows
|
||||||
|
checkColumnStyles(sheet, 0, 1, true);
|
||||||
|
checkRowStyles(sheet, 0, 1, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testUnusedStyle() {
|
||||||
|
HSSFWorkbook wb = new HSSFWorkbook();
|
||||||
|
assertEquals("Usually we have 21 pre-defined styles in a newly created Workbook, see InternalWorkbook.createWorkbook()",
|
||||||
|
21, wb.getNumCellStyles());
|
||||||
|
|
||||||
|
HSSFSheet sheet = wb.createSheet();
|
||||||
|
|
||||||
|
Row row = sheet.createRow(0);
|
||||||
|
row.createCell(0);
|
||||||
|
row.createCell(1).setCellStyle(
|
||||||
|
createColorStyle(wb, IndexedColors.GREEN));
|
||||||
|
|
||||||
|
|
||||||
|
row = sheet.createRow(1);
|
||||||
|
row.createCell(0);
|
||||||
|
row.createCell(1).setCellStyle(
|
||||||
|
createColorStyle(wb, IndexedColors.RED));
|
||||||
|
|
||||||
|
|
||||||
|
// Create style. But don't use it.
|
||||||
|
for (int i = 0; i < 3; i++) {
|
||||||
|
// Set Cell Color : AQUA
|
||||||
|
createColorStyle(wb, IndexedColors.AQUA);
|
||||||
|
}
|
||||||
|
|
||||||
|
assertEquals(21 + 2 + 3, wb.getNumCellStyles());
|
||||||
|
assertEquals(IndexedColors.GREEN.getIndex(), sheet.getRow(0).getCell(1).getCellStyle().getFillForegroundColor());
|
||||||
|
assertEquals(IndexedColors.RED.getIndex(), sheet.getRow(1).getCell(1).getCellStyle().getFillForegroundColor());
|
||||||
|
|
||||||
|
// Optimise styles
|
||||||
|
HSSFOptimiser.optimiseCellStyles(wb);
|
||||||
|
|
||||||
|
assertEquals(21 + 2, wb.getNumCellStyles());
|
||||||
|
assertEquals(IndexedColors.GREEN.getIndex(), sheet.getRow(0).getCell(1).getCellStyle().getFillForegroundColor());
|
||||||
|
assertEquals(IndexedColors.RED.getIndex(), sheet.getRow(1).getCell(1).getCellStyle().getFillForegroundColor());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testUnusedStyleOneUsed() {
|
||||||
|
HSSFWorkbook wb = new HSSFWorkbook();
|
||||||
|
assertEquals("Usually we have 21 pre-defined styles in a newly created Workbook, see InternalWorkbook.createWorkbook()",
|
||||||
|
21, wb.getNumCellStyles());
|
||||||
|
|
||||||
|
HSSFSheet sheet = wb.createSheet();
|
||||||
|
|
||||||
|
Row row = sheet.createRow(0);
|
||||||
|
row.createCell(0);
|
||||||
|
row.createCell(1).setCellStyle(
|
||||||
|
createColorStyle(wb, IndexedColors.GREEN));
|
||||||
|
|
||||||
|
// Create style. But don't use it.
|
||||||
|
for (int i = 0; i < 3; i++) {
|
||||||
|
// Set Cell Color : AQUA
|
||||||
|
createColorStyle(wb, IndexedColors.AQUA);
|
||||||
|
}
|
||||||
|
|
||||||
|
row = sheet.createRow(1);
|
||||||
|
row.createCell(0).setCellStyle(createColorStyle(wb, IndexedColors.AQUA));
|
||||||
|
row.createCell(1).setCellStyle(
|
||||||
|
createColorStyle(wb, IndexedColors.RED));
|
||||||
|
|
||||||
|
assertEquals(21 + 3 + 3, wb.getNumCellStyles());
|
||||||
|
assertEquals(IndexedColors.GREEN.getIndex(), sheet.getRow(0).getCell(1).getCellStyle().getFillForegroundColor());
|
||||||
|
assertEquals(IndexedColors.AQUA.getIndex(), sheet.getRow(1).getCell(0).getCellStyle().getFillForegroundColor());
|
||||||
|
assertEquals(IndexedColors.RED.getIndex(), sheet.getRow(1).getCell(1).getCellStyle().getFillForegroundColor());
|
||||||
|
|
||||||
|
// Optimise styles
|
||||||
|
HSSFOptimiser.optimiseCellStyles(wb);
|
||||||
|
|
||||||
|
assertEquals(21 + 3, wb.getNumCellStyles());
|
||||||
|
assertEquals(IndexedColors.GREEN.getIndex(), sheet.getRow(0).getCell(1).getCellStyle().getFillForegroundColor());
|
||||||
|
assertEquals(IndexedColors.AQUA.getIndex(), sheet.getRow(1).getCell(0).getCellStyle().getFillForegroundColor());
|
||||||
|
assertEquals(IndexedColors.RED.getIndex(), sheet.getRow(1).getCell(1).getCellStyle().getFillForegroundColor());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testDefaultColumnStyleWitoutCell() throws IOException {
|
||||||
|
HSSFWorkbook wb = new HSSFWorkbook();
|
||||||
|
assertEquals("Usually we have 21 pre-defined styles in a newly created Workbook, see InternalWorkbook.createWorkbook()",
|
||||||
|
21, wb.getNumCellStyles());
|
||||||
|
|
||||||
|
HSSFSheet sheet = wb.createSheet();
|
||||||
|
|
||||||
|
//Set CellStyle and RowStyle and ColumnStyle
|
||||||
|
for (int i = 0; i < 2; i++) {
|
||||||
|
sheet.createRow(i);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create a test font and style, and use them
|
||||||
|
int obj_cnt = wb.getNumCellStyles();
|
||||||
|
int cnt = wb.getNumCellStyles();
|
||||||
|
|
||||||
|
// Set Column Color : Red
|
||||||
|
sheet.setDefaultColumnStyle(3,
|
||||||
|
createColorStyle(wb, IndexedColors.RED));
|
||||||
|
obj_cnt++;
|
||||||
|
|
||||||
|
// Set Column Color : Red
|
||||||
|
sheet.setDefaultColumnStyle(4,
|
||||||
|
createColorStyle(wb, IndexedColors.RED));
|
||||||
|
obj_cnt++;
|
||||||
|
|
||||||
|
assertEquals(obj_cnt, wb.getNumCellStyles());
|
||||||
|
|
||||||
|
// now the color should be equal for those two columns and rows
|
||||||
|
checkColumnStyles(sheet, 3, 4, false);
|
||||||
|
|
||||||
|
// Optimise styles
|
||||||
|
HSSFOptimiser.optimiseCellStyles(wb);
|
||||||
|
|
||||||
|
// We should have the same style-objects for these two columns and rows
|
||||||
|
checkColumnStyles(sheet, 3, 4, true);
|
||||||
|
|
||||||
|
// (GREEN + RED + BLUE + CORAL) + YELLOW(2*2)
|
||||||
|
assertEquals(cnt + 1, wb.getNumCellStyles());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testUserDefinedStylesAreNeverOptimizedAway() throws IOException {
|
||||||
|
HSSFWorkbook wb = new HSSFWorkbook();
|
||||||
|
assertEquals("Usually we have 21 pre-defined styles in a newly created Workbook, see InternalWorkbook.createWorkbook()",
|
||||||
|
21, wb.getNumCellStyles());
|
||||||
|
|
||||||
|
HSSFSheet sheet = wb.createSheet();
|
||||||
|
|
||||||
|
//Set CellStyle and RowStyle and ColumnStyle
|
||||||
|
for (int i = 0; i < 2; i++) {
|
||||||
|
sheet.createRow(i);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create a test font and style, and use them
|
||||||
|
int obj_cnt = wb.getNumCellStyles();
|
||||||
|
int cnt = wb.getNumCellStyles();
|
||||||
|
for (int i = 0; i < 3; i++) {
|
||||||
|
HSSFCellStyle s = null;
|
||||||
|
if (i == 0) {
|
||||||
|
// Set cell color : +2(user style + proxy of it)
|
||||||
|
s = (HSSFCellStyle) createColorStyle(wb,
|
||||||
|
IndexedColors.YELLOW);
|
||||||
|
s.setUserStyleName("user define");
|
||||||
|
obj_cnt += 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
HSSFRow row = sheet.getRow(1);
|
||||||
|
row.createCell(i).setCellStyle(s);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create style. But don't use it.
|
||||||
|
for (int i = 3; i < 6; i++) {
|
||||||
|
// Set Cell Color : AQUA
|
||||||
|
createColorStyle(wb, IndexedColors.AQUA);
|
||||||
|
obj_cnt++;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set cell color : +2(user style + proxy of it)
|
||||||
|
HSSFCellStyle s = (HSSFCellStyle) createColorStyle(wb,IndexedColors.YELLOW);
|
||||||
|
s.setUserStyleName("user define2");
|
||||||
|
obj_cnt += 2;
|
||||||
|
|
||||||
|
sheet.createRow(10).createCell(0).setCellStyle(s);
|
||||||
|
|
||||||
|
assertEquals(obj_cnt, wb.getNumCellStyles());
|
||||||
|
|
||||||
|
// Confirm user style name
|
||||||
|
checkUserStyles(sheet);
|
||||||
|
|
||||||
|
// Optimise styles
|
||||||
|
HSSFOptimiser.optimiseCellStyles(wb);
|
||||||
|
|
||||||
|
// Confirm user style name
|
||||||
|
checkUserStyles(sheet);
|
||||||
|
|
||||||
|
// (GREEN + RED + BLUE + CORAL) + YELLOW(2*2)
|
||||||
|
assertEquals(cnt + 2 * 2, wb.getNumCellStyles());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testBug57517() throws IOException {
|
||||||
|
HSSFWorkbook wb = new HSSFWorkbook();
|
||||||
|
assertEquals("Usually we have 21 pre-defined styles in a newly created Workbook, see InternalWorkbook.createWorkbook()",
|
||||||
|
21, wb.getNumCellStyles());
|
||||||
|
|
||||||
|
HSSFSheet sheet = wb.createSheet();
|
||||||
|
|
||||||
|
//Set CellStyle and RowStyle and ColumnStyle
|
||||||
|
for (int i = 0; i < 2; i++) {
|
||||||
|
sheet.createRow(i);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create a test font and style, and use them
|
||||||
|
int obj_cnt = wb.getNumCellStyles();
|
||||||
|
int cnt = wb.getNumCellStyles();
|
||||||
|
for (int i = 0; i < 3; i++) {
|
||||||
|
// Set Cell Color : GREEN
|
||||||
|
HSSFRow row = sheet.getRow(0);
|
||||||
|
row.createCell(i).setCellStyle(
|
||||||
|
createColorStyle(wb, IndexedColors.GREEN));
|
||||||
|
obj_cnt++;
|
||||||
|
|
||||||
|
// Set Column Color : Red
|
||||||
|
sheet.setDefaultColumnStyle(i + 3,
|
||||||
|
createColorStyle(wb, IndexedColors.RED));
|
||||||
|
obj_cnt++;
|
||||||
|
|
||||||
|
// Set Row Color : Blue
|
||||||
|
row = sheet.createRow(i + 3);
|
||||||
|
row.setRowStyle(createColorStyle(wb, IndexedColors.BLUE));
|
||||||
|
obj_cnt++;
|
||||||
|
|
||||||
|
HSSFCellStyle s = null;
|
||||||
|
if (i == 0) {
|
||||||
|
// Set cell color : +2(user style + proxy of it)
|
||||||
|
s = (HSSFCellStyle) createColorStyle(wb,
|
||||||
|
IndexedColors.YELLOW);
|
||||||
|
s.setUserStyleName("user define");
|
||||||
|
obj_cnt += 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
row = sheet.getRow(1);
|
||||||
|
row.createCell(i).setCellStyle(s);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create style. But don't use it.
|
||||||
|
for (int i = 3; i < 6; i++) {
|
||||||
|
// Set Cell Color : AQUA
|
||||||
|
createColorStyle(wb, IndexedColors.AQUA);
|
||||||
|
obj_cnt++;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set CellStyle and RowStyle and ColumnStyle
|
||||||
|
for (int i = 9; i < 11; i++) {
|
||||||
|
sheet.createRow(i);
|
||||||
|
}
|
||||||
|
|
||||||
|
//Set 0 or 255 index of ColumnStyle.
|
||||||
|
HSSFCellStyle s = (HSSFCellStyle) createColorStyle(wb, IndexedColors.CORAL);
|
||||||
|
obj_cnt++;
|
||||||
|
sheet.setDefaultColumnStyle(0, s);
|
||||||
|
sheet.setDefaultColumnStyle(255, s);
|
||||||
|
|
||||||
|
// Create a test font and style, and use them
|
||||||
|
for (int i = 3; i < 6; i++) {
|
||||||
|
// Set Cell Color : GREEN
|
||||||
|
HSSFRow row = sheet.getRow(0 + 9);
|
||||||
|
row.createCell(i - 3).setCellStyle(
|
||||||
|
createColorStyle(wb, IndexedColors.GREEN));
|
||||||
|
obj_cnt++;
|
||||||
|
|
||||||
|
// Set Column Color : Red
|
||||||
|
sheet.setDefaultColumnStyle(i + 3,
|
||||||
|
createColorStyle(wb, IndexedColors.RED));
|
||||||
|
obj_cnt++;
|
||||||
|
|
||||||
|
// Set Row Color : Blue
|
||||||
|
row = sheet.createRow(i + 3);
|
||||||
|
row.setRowStyle(createColorStyle(wb, IndexedColors.BLUE));
|
||||||
|
obj_cnt++;
|
||||||
|
|
||||||
|
if (i == 3) {
|
||||||
|
// Set cell color : +2(user style + proxy of it)
|
||||||
|
s = (HSSFCellStyle) createColorStyle(wb,
|
||||||
|
IndexedColors.YELLOW);
|
||||||
|
s.setUserStyleName("user define2");
|
||||||
|
obj_cnt += 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
row = sheet.getRow(1 + 9);
|
||||||
|
row.createCell(i - 3).setCellStyle(s);
|
||||||
|
}
|
||||||
|
|
||||||
|
assertEquals(obj_cnt, wb.getNumCellStyles());
|
||||||
|
|
||||||
|
// now the color should be equal for those two columns and rows
|
||||||
|
checkColumnStyles(sheet, 3, 4, false);
|
||||||
|
checkRowStyles(sheet, 3, 4, false);
|
||||||
|
|
||||||
|
// Confirm user style name
|
||||||
|
checkUserStyles(sheet);
|
||||||
|
|
||||||
|
// out = new FileOutputStream(new File(tmpDirName, "out.xls"));
|
||||||
|
// wb.write(out);
|
||||||
|
// out.close();
|
||||||
|
|
||||||
|
// Optimise styles
|
||||||
|
HSSFOptimiser.optimiseCellStyles(wb);
|
||||||
|
|
||||||
|
// out = new FileOutputStream(new File(tmpDirName, "out_optimised.xls"));
|
||||||
|
// wb.write(out);
|
||||||
|
// out.close();
|
||||||
|
|
||||||
|
// We should have the same style-objects for these two columns and rows
|
||||||
|
checkColumnStyles(sheet, 3, 4, true);
|
||||||
|
checkRowStyles(sheet, 3, 4, true);
|
||||||
|
|
||||||
|
// Confirm user style name
|
||||||
|
checkUserStyles(sheet);
|
||||||
|
|
||||||
|
// (GREEN + RED + BLUE + CORAL) + YELLOW(2*2)
|
||||||
|
assertEquals(cnt + 4 + 2 * 2, wb.getNumCellStyles());
|
||||||
|
}
|
||||||
|
|
||||||
|
private void checkUserStyles(HSSFSheet sheet) {
|
||||||
|
HSSFCellStyle parentStyle1 = sheet.getRow(1).getCell(0).getCellStyle().getParentStyle();
|
||||||
|
assertNotNull(parentStyle1);
|
||||||
|
assertEquals(parentStyle1.getUserStyleName(), "user define");
|
||||||
|
|
||||||
|
HSSFCellStyle parentStyle10 = sheet.getRow(10).getCell(0).getCellStyle().getParentStyle();
|
||||||
|
assertNotNull(parentStyle10);
|
||||||
|
assertEquals(parentStyle10.getUserStyleName(), "user define2");
|
||||||
|
}
|
||||||
|
|
||||||
|
private void checkColumnStyles(HSSFSheet sheet, int col1, int col2, boolean checkEquals) {
|
||||||
|
// we should have the same color for the column styles
|
||||||
|
HSSFCellStyle columnStyle1 = sheet.getColumnStyle(col1);
|
||||||
|
assertNotNull(columnStyle1);
|
||||||
|
HSSFCellStyle columnStyle2 = sheet.getColumnStyle(col2);
|
||||||
|
assertNotNull(columnStyle2);
|
||||||
|
assertEquals(columnStyle1.getFillForegroundColor(), columnStyle2.getFillForegroundColor());
|
||||||
|
if(checkEquals) {
|
||||||
|
assertEquals(columnStyle1.getIndex(), columnStyle2.getIndex());
|
||||||
|
assertEquals(columnStyle1, columnStyle2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void checkRowStyles(HSSFSheet sheet, int row1, int row2, boolean checkEquals) {
|
||||||
|
// we should have the same color for the row styles
|
||||||
|
HSSFCellStyle rowStyle1 = sheet.getRow(row1).getRowStyle();
|
||||||
|
assertNotNull(rowStyle1);
|
||||||
|
HSSFCellStyle rowStyle2 = sheet.getRow(row2).getRowStyle();
|
||||||
|
assertNotNull(rowStyle2);
|
||||||
|
assertEquals(rowStyle1.getFillForegroundColor(), rowStyle2.getFillForegroundColor());
|
||||||
|
if(checkEquals) {
|
||||||
|
assertEquals(rowStyle1.getIndex(), rowStyle2.getIndex());
|
||||||
|
assertEquals(rowStyle1, rowStyle2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private CellStyle createColorStyle(Workbook wb, IndexedColors c) {
|
||||||
|
CellStyle cs = wb.createCellStyle();
|
||||||
|
cs.setFillPattern(FillPatternType.SOLID_FOREGROUND);
|
||||||
|
cs.setFillForegroundColor(c.getIndex());
|
||||||
|
return cs;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue