* {@link org.apache.poi.ss.usermodel.DataFormatter#formatCellValue(org.apache.poi.ss.usermodel.Cell)}
* returns formula string for formula cells. Dummy evaluator makes it to format the cached formula result.
*
- * See Bugzilla #50021
+ * See Bugzilla #50021
*/
private static final FormulaEvaluator dummyEvaluator = new FormulaEvaluator(){
public void clearAllCachedResultValues(){}
*/
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
*
int defaultCharWidth = (int)layout.getAdvance();
double width = -1;
- rows:
for (Row row : sheet) {
Cell cell = row.getCell(column);
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;
+ }
- 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());
- }
+ /**
+ * 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);
+ }
}
- return width;
+ return width;
}
/**