applied patch from Bugzilla 52314: SheetUtil.getColumnWidth could be more flexible
git-svn-id: https://svn.apache.org/repos/asf/poi/trunk@1215079 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
parent
79a10931dc
commit
2e67e48e71
@ -34,6 +34,7 @@
|
||||
|
||||
<changes>
|
||||
<release version="3.8-beta6" date="2012-??-??">
|
||||
<action dev="poi-developers" type="fix">52314 - enhanced SheetUtil.getColumnWidth</action>
|
||||
</release>
|
||||
<release version="3.8-beta5" date="2011-12-17">
|
||||
<action dev="poi-developers" type="fix">52204 - Deprecated XSSFWorkbook(String path) constructor because it does not close underlying .zip file</action>
|
||||
|
@ -74,6 +74,117 @@ public class SheetUtil {
|
||||
*/
|
||||
private static final FontRenderContext fontRenderContext = new FontRenderContext(null, true, true);
|
||||
|
||||
/**
|
||||
* Compute width of a single cell
|
||||
*
|
||||
* @param cell the cell whose width is to be calculated
|
||||
* @param defaultCharWidth the width of a single character
|
||||
* @param formatter formatter used to prepare the text to be measured
|
||||
* @param useMergedCells whether to use merged cells
|
||||
* @return the width in pixels
|
||||
*/
|
||||
public static double getCellWidth(Cell cell, int defaultCharWidth, DataFormatter formatter, boolean useMergedCells) {
|
||||
|
||||
Sheet sheet = cell.getSheet();
|
||||
Workbook wb = sheet.getWorkbook();
|
||||
Row row = cell.getRow();
|
||||
int column = cell.getColumnIndex();
|
||||
|
||||
int colspan = 1;
|
||||
for (int i = 0 ; i < sheet.getNumMergedRegions(); i++) {
|
||||
CellRangeAddress region = sheet.getMergedRegion(i);
|
||||
if (containsCell(region, row.getRowNum(), column)) {
|
||||
if (!useMergedCells) {
|
||||
// If we're not using merged cells, skip this one and move on to the next.
|
||||
return -1;
|
||||
}
|
||||
cell = row.getCell(region.getFirstColumn());
|
||||
colspan = 1 + region.getLastColumn() - region.getFirstColumn();
|
||||
}
|
||||
}
|
||||
|
||||
CellStyle style = cell.getCellStyle();
|
||||
int cellType = cell.getCellType();
|
||||
|
||||
// for formula cells we compute the cell width for the cached formula result
|
||||
if(cellType == Cell.CELL_TYPE_FORMULA) cellType = cell.getCachedFormulaResultType();
|
||||
|
||||
Font font = wb.getFontAt(style.getFontIndex());
|
||||
|
||||
AttributedString str;
|
||||
TextLayout layout;
|
||||
|
||||
double width = -1;
|
||||
if (cellType == Cell.CELL_TYPE_STRING) {
|
||||
RichTextString rt = cell.getRichStringCellValue();
|
||||
String[] lines = rt.getString().split("\\n");
|
||||
for (int i = 0; i < lines.length; i++) {
|
||||
String txt = lines[i] + defaultChar;
|
||||
|
||||
str = new AttributedString(txt);
|
||||
copyAttributes(font, str, 0, txt.length());
|
||||
|
||||
if (rt.numFormattingRuns() > 0) {
|
||||
// TODO: support rich text fragments
|
||||
}
|
||||
|
||||
layout = new TextLayout(str.getIterator(), fontRenderContext);
|
||||
if(style.getRotation() != 0){
|
||||
/*
|
||||
* Transform the text using a scale so that it's height is increased by a multiple of the leading,
|
||||
* and then rotate the text before computing the bounds. The scale results in some whitespace around
|
||||
* the unrotated top and bottom of the text that normally wouldn't be present if unscaled, but
|
||||
* is added by the standard Excel autosize.
|
||||
*/
|
||||
AffineTransform trans = new AffineTransform();
|
||||
trans.concatenate(AffineTransform.getRotateInstance(style.getRotation()*2.0*Math.PI/360.0));
|
||||
trans.concatenate(
|
||||
AffineTransform.getScaleInstance(1, fontHeightMultiple)
|
||||
);
|
||||
width = Math.max(width, ((layout.getOutline(trans).getBounds().getWidth() / colspan) / defaultCharWidth) + cell.getCellStyle().getIndention());
|
||||
} else {
|
||||
width = Math.max(width, ((layout.getBounds().getWidth() / colspan) / defaultCharWidth) + cell.getCellStyle().getIndention());
|
||||
}
|
||||
}
|
||||
} else {
|
||||
String sval = null;
|
||||
if (cellType == Cell.CELL_TYPE_NUMERIC) {
|
||||
// Try to get it formatted to look the same as excel
|
||||
try {
|
||||
sval = formatter.formatCellValue(cell, dummyEvaluator);
|
||||
} catch (Exception e) {
|
||||
sval = String.valueOf(cell.getNumericCellValue());
|
||||
}
|
||||
} else if (cellType == Cell.CELL_TYPE_BOOLEAN) {
|
||||
sval = String.valueOf(cell.getBooleanCellValue()).toUpperCase();
|
||||
}
|
||||
if(sval != null) {
|
||||
String txt = sval + defaultChar;
|
||||
str = new AttributedString(txt);
|
||||
copyAttributes(font, str, 0, txt.length());
|
||||
|
||||
layout = new TextLayout(str.getIterator(), fontRenderContext);
|
||||
if(style.getRotation() != 0){
|
||||
/*
|
||||
* Transform the text using a scale so that it's height is increased by a multiple of the leading,
|
||||
* and then rotate the text before computing the bounds. The scale results in some whitespace around
|
||||
* the unrotated top and bottom of the text that normally wouldn't be present if unscaled, but
|
||||
* is added by the standard Excel autosize.
|
||||
*/
|
||||
AffineTransform trans = new AffineTransform();
|
||||
trans.concatenate(AffineTransform.getRotateInstance(style.getRotation()*2.0*Math.PI/360.0));
|
||||
trans.concatenate(
|
||||
AffineTransform.getScaleInstance(1, fontHeightMultiple)
|
||||
);
|
||||
width = Math.max(width, ((layout.getOutline(trans).getBounds().getWidth() / colspan) / defaultCharWidth) + cell.getCellStyle().getIndention());
|
||||
} else {
|
||||
width = Math.max(width, ((layout.getBounds().getWidth() / colspan) / defaultCharWidth) + cell.getCellStyle().getIndention());
|
||||
}
|
||||
}
|
||||
}
|
||||
return width;
|
||||
}
|
||||
|
||||
/**
|
||||
* Compute width of a column and return the result
|
||||
*
|
||||
@ -96,7 +207,6 @@ public class SheetUtil {
|
||||
int defaultCharWidth = (int)layout.getAdvance();
|
||||
|
||||
double width = -1;
|
||||
rows:
|
||||
for (Row row : sheet) {
|
||||
Cell cell = row.getCell(column);
|
||||
|
||||
@ -104,95 +214,49 @@ public class SheetUtil {
|
||||
continue;
|
||||
}
|
||||
|
||||
int colspan = 1;
|
||||
for (int i = 0 ; i < sheet.getNumMergedRegions(); i++) {
|
||||
CellRangeAddress region = sheet.getMergedRegion(i);
|
||||
if (containsCell(region, row.getRowNum(), column)) {
|
||||
if (!useMergedCells) {
|
||||
// If we're not using merged cells, skip this one and move on to the next.
|
||||
continue rows;
|
||||
}
|
||||
cell = row.getCell(region.getFirstColumn());
|
||||
colspan = 1 + region.getLastColumn() - region.getFirstColumn();
|
||||
double cellWidth = getCellWidth(cell, defaultCharWidth, formatter, useMergedCells);
|
||||
width = Math.max(width, cellWidth);
|
||||
}
|
||||
return width;
|
||||
}
|
||||
|
||||
/**
|
||||
* Compute width of a column based on a subset of the rows and return the result
|
||||
*
|
||||
* @param sheet the sheet to calculate
|
||||
* @param column 0-based index of the column
|
||||
* @param useMergedCells whether to use merged cells
|
||||
* @param firstRow 0-based index of the first row to consider (inclusive)
|
||||
* @param lastRow 0-based index of the last row to consider (inclusive)
|
||||
* @return the width in pixels
|
||||
*/
|
||||
public static double getColumnWidth(Sheet sheet, int column, boolean useMergedCells, int firstRow, int lastRow){
|
||||
AttributedString str;
|
||||
TextLayout layout;
|
||||
|
||||
Workbook wb = sheet.getWorkbook();
|
||||
DataFormatter formatter = new DataFormatter();
|
||||
Font defaultFont = wb.getFontAt((short) 0);
|
||||
|
||||
str = new AttributedString(String.valueOf(defaultChar));
|
||||
copyAttributes(defaultFont, str, 0, 1);
|
||||
layout = new TextLayout(str.getIterator(), fontRenderContext);
|
||||
int defaultCharWidth = (int)layout.getAdvance();
|
||||
|
||||
double width = -1;
|
||||
for (int rowIdx = firstRow; rowIdx <= lastRow; ++rowIdx) {
|
||||
Row row = sheet.getRow(rowIdx);
|
||||
if( row != null ) {
|
||||
|
||||
Cell cell = row.getCell(column);
|
||||
|
||||
if (cell == null) {
|
||||
continue;
|
||||
}
|
||||
|
||||
double cellWidth = getCellWidth(cell, defaultCharWidth, formatter, useMergedCells);
|
||||
width = Math.max(width, cellWidth);
|
||||
}
|
||||
|
||||
CellStyle style = cell.getCellStyle();
|
||||
int cellType = cell.getCellType();
|
||||
|
||||
// for formula cells we compute the cell width for the cached formula result
|
||||
if(cellType == Cell.CELL_TYPE_FORMULA) cellType = cell.getCachedFormulaResultType();
|
||||
|
||||
Font font = wb.getFontAt(style.getFontIndex());
|
||||
|
||||
if (cellType == Cell.CELL_TYPE_STRING) {
|
||||
RichTextString rt = cell.getRichStringCellValue();
|
||||
String[] lines = rt.getString().split("\\n");
|
||||
for (int i = 0; i < lines.length; i++) {
|
||||
String txt = lines[i] + defaultChar;
|
||||
|
||||
str = new AttributedString(txt);
|
||||
copyAttributes(font, str, 0, txt.length());
|
||||
|
||||
if (rt.numFormattingRuns() > 0) {
|
||||
// TODO: support rich text fragments
|
||||
}
|
||||
|
||||
layout = new TextLayout(str.getIterator(), fontRenderContext);
|
||||
if(style.getRotation() != 0){
|
||||
/*
|
||||
* Transform the text using a scale so that it's height is increased by a multiple of the leading,
|
||||
* and then rotate the text before computing the bounds. The scale results in some whitespace around
|
||||
* the unrotated top and bottom of the text that normally wouldn't be present if unscaled, but
|
||||
* is added by the standard Excel autosize.
|
||||
*/
|
||||
AffineTransform trans = new AffineTransform();
|
||||
trans.concatenate(AffineTransform.getRotateInstance(style.getRotation()*2.0*Math.PI/360.0));
|
||||
trans.concatenate(
|
||||
AffineTransform.getScaleInstance(1, fontHeightMultiple)
|
||||
);
|
||||
width = Math.max(width, ((layout.getOutline(trans).getBounds().getWidth() / colspan) / defaultCharWidth) + cell.getCellStyle().getIndention());
|
||||
} else {
|
||||
width = Math.max(width, ((layout.getBounds().getWidth() / colspan) / defaultCharWidth) + cell.getCellStyle().getIndention());
|
||||
}
|
||||
}
|
||||
} else {
|
||||
String sval = null;
|
||||
if (cellType == Cell.CELL_TYPE_NUMERIC) {
|
||||
// Try to get it formatted to look the same as excel
|
||||
try {
|
||||
sval = formatter.formatCellValue(cell, dummyEvaluator);
|
||||
} catch (Exception e) {
|
||||
sval = String.valueOf(cell.getNumericCellValue());
|
||||
}
|
||||
} else if (cellType == Cell.CELL_TYPE_BOOLEAN) {
|
||||
sval = String.valueOf(cell.getBooleanCellValue()).toUpperCase();
|
||||
}
|
||||
if(sval != null) {
|
||||
String txt = sval + defaultChar;
|
||||
str = new AttributedString(txt);
|
||||
copyAttributes(font, str, 0, txt.length());
|
||||
|
||||
layout = new TextLayout(str.getIterator(), fontRenderContext);
|
||||
if(style.getRotation() != 0){
|
||||
/*
|
||||
* Transform the text using a scale so that it's height is increased by a multiple of the leading,
|
||||
* and then rotate the text before computing the bounds. The scale results in some whitespace around
|
||||
* the unrotated top and bottom of the text that normally wouldn't be present if unscaled, but
|
||||
* is added by the standard Excel autosize.
|
||||
*/
|
||||
AffineTransform trans = new AffineTransform();
|
||||
trans.concatenate(AffineTransform.getRotateInstance(style.getRotation()*2.0*Math.PI/360.0));
|
||||
trans.concatenate(
|
||||
AffineTransform.getScaleInstance(1, fontHeightMultiple)
|
||||
);
|
||||
width = Math.max(width, ((layout.getOutline(trans).getBounds().getWidth() / colspan) / defaultCharWidth) + cell.getCellStyle().getIndention());
|
||||
} else {
|
||||
width = Math.max(width, ((layout.getBounds().getWidth() / colspan) / defaultCharWidth) + cell.getCellStyle().getIndention());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
return width;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user