<section><title>Adjust column width to fit the contents</title>
<source>
Sheet sheet = workbook.getSheetAt(0);
- sheet.autoSizeColumn((short)0); //adjust width of the first column
- sheet.autoSizeColumn((short)1); //adjust width of the second column
+ sheet.autoSizeColumn(0); //adjust width of the first column
+ sheet.autoSizeColumn(1); //adjust width of the second column
</source>
+ <p>
+ Note, that Sheet#autoSizeColumn() does not evaluate formula cells,
+ the width of formula cells is calculated based on the cached formula result.
+ If your workbook has many formulas then it is a good idea to evaluate them before auto-sizing.
+ </p>
<warning>
To calculate column width HSSFSheet.autoSizeColumn uses Java2D classes
that throw exception if graphical environment is not available. In case if graphical environment
<changes>
<release version="3.8-beta1" date="2010-??-??">
+ <action dev="poi-developers" type="fix">49761 - Tolerate Double.NaN when reading .xls files</action>
+ <action dev="poi-developers" type="fix">50211 - Use cached formula result when auto-sizing formula cells</action>
<action dev="poi-developers" type="fix">50118 - OLE2 does allow a directory with an empty name, so support this in POIFS</action>
<action dev="poi-developers" type="fix">50119 - avoid NPE when XSSFReader comes across chart sheets</action>
</release>
import org.apache.poi.ss.util.CellRangeAddress;
import org.apache.poi.ss.util.CellReference;
import org.apache.poi.ss.util.SSCellRange;
+import org.apache.poi.ss.util.SheetUtil;
import org.apache.poi.util.POILogFactory;
import org.apache.poi.util.POILogger;
}
//only shift if the region outside the shifted rows is not merged too
- if (!containsCell(merged, startRow-1, 0) && !containsCell(merged, endRow+1, 0)){
+ if (!SheetUtil.containsCell(merged, startRow-1, 0) &&
+ !SheetUtil.containsCell(merged, endRow+1, 0)){
merged.setFirstRow(merged.getFirstRow()+n);
merged.setLastRow(merged.getLastRow()+n);
//have to remove/add it back
this.addMergedRegion(region);
}
}
- private static boolean containsCell(CellRangeAddress cr, int rowIx, int colIx) {
- if (cr.getFirstRow() <= rowIx && cr.getLastRow() >= rowIx
- && cr.getFirstColumn() <= colIx && cr.getLastColumn() >= colIx)
- {
- return true;
- }
- return false;
- }
/**
* Shifts rows between startRow and endRow n number of rows.
* @param useMergedCells whether to use the contents of merged cells when calculating the width of the column
*/
public void autoSizeColumn(int column, boolean useMergedCells) {
- AttributedString str;
- TextLayout layout;
- /**
- * Excel measures columns in units of 1/256th of a character width
- * but the docs say nothing about what particular character is used.
- * '0' looks to be a good choice.
- */
- char defaultChar = '0';
-
- /**
- * This is the multiple that the font height is scaled by when determining the
- * boundary of rotated text.
- */
- double fontHeightMultiple = 2.0;
-
- FontRenderContext frc = new FontRenderContext(null, true, true);
-
- HSSFWorkbook wb = HSSFWorkbook.create(_book); // TODO - is it important to not use _workbook?
- HSSFDataFormatter formatter = new HSSFDataFormatter();
- HSSFFont defaultFont = wb.getFontAt((short) 0);
-
- str = new AttributedString("" + defaultChar);
- copyAttributes(defaultFont, str, 0, 1);
- layout = new TextLayout(str.getIterator(), frc);
- int defaultCharWidth = (int)layout.getAdvance();
-
- double width = -1;
- rows:
- for (Iterator<Row> it = rowIterator(); it.hasNext();) {
- HSSFRow row = (HSSFRow) it.next();
- HSSFCell cell = row.getCell(column);
-
- if (cell == null) {
- continue;
- }
-
- int colspan = 1;
- for (int i = 0 ; i < getNumMergedRegions(); i++) {
- CellRangeAddress region = 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();
- }
- }
-
- HSSFCellStyle style = cell.getCellStyle();
- int cellType = cell.getCellType();
- if(cellType == HSSFCell.CELL_TYPE_FORMULA) cellType = cell.getCachedFormulaResultType();
-
- HSSFFont font = wb.getFontAt(style.getFontIndex());
-
- if (cellType == HSSFCell.CELL_TYPE_STRING) {
- HSSFRichTextString 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) {
- for (int j = 0; j < lines[i].length(); j++) {
- int idx = rt.getFontAtIndex(j);
- if (idx != 0) {
- HSSFFont fnt = wb.getFontAt((short) idx);
- copyAttributes(fnt, str, j, j + 1);
- }
- }
- }
-
- layout = new TextLayout(str.getIterator(), frc);
- 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 == HSSFCell.CELL_TYPE_NUMERIC) {
- // Try to get it formatted to look the same as excel
- try {
- sval = formatter.formatCellValue(cell);
- } catch (Exception e) {
- sval = "" + cell.getNumericCellValue();
- }
- } else if (cellType == HSSFCell.CELL_TYPE_BOOLEAN) {
- sval = String.valueOf(cell.getBooleanCellValue());
- }
- if(sval != null) {
- String txt = sval + defaultChar;
- str = new AttributedString(txt);
- copyAttributes(font, str, 0, txt.length());
-
- layout = new TextLayout(str.getIterator(), frc);
- 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());
- }
- }
- }
-
- }
- if (width != -1) {
- width *= 256;
- if (width > Short.MAX_VALUE) { //width can be bigger that Short.MAX_VALUE!
- width = Short.MAX_VALUE;
- }
- _sheet.setColumnWidth(column, (short) (width));
- }
- }
-
- /**
- * Copy text attributes from the supplied HSSFFont to Java2D AttributedString
- */
- private void copyAttributes(HSSFFont font, AttributedString str, int startIdx, int endIdx) {
- str.addAttribute(TextAttribute.FAMILY, font.getFontName(), startIdx, endIdx);
- str.addAttribute(TextAttribute.SIZE, new Float(font.getFontHeightInPoints()));
- if (font.getBoldweight() == HSSFFont.BOLDWEIGHT_BOLD) str.addAttribute(TextAttribute.WEIGHT, TextAttribute.WEIGHT_BOLD, startIdx, endIdx);
- if (font.getItalic() ) str.addAttribute(TextAttribute.POSTURE, TextAttribute.POSTURE_OBLIQUE, startIdx, endIdx);
- if (font.getUnderline() == HSSFFont.U_SINGLE ) str.addAttribute(TextAttribute.UNDERLINE, TextAttribute.UNDERLINE_ON, startIdx, endIdx);
+ double width = SheetUtil.getColumnWidth(this, column, useMergedCells);
+ if(width != -1) setColumnWidth(column, (int) (256*width));
}
/**
--- /dev/null
+/* ====================================================================
+ Licensed to the Apache Software Foundation (ASF) under one or more
+ contributor license agreements. See the NOTICE file distributed with
+ this work for additional information regarding copyright ownership.
+ The ASF licenses this file to You under the Apache License, Version 2.0
+ (the "License"); you may not use this file except in compliance with
+ the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+==================================================================== */
+
+package org.apache.poi.ss.util;
+
+import org.apache.poi.ss.usermodel.*;
+
+import java.text.AttributedString;
+import java.awt.font.TextLayout;
+import java.awt.font.FontRenderContext;
+import java.awt.font.TextAttribute;
+import java.awt.geom.AffineTransform;
+
+
+/**
+ * Helper methods for when working with Usermodel sheets
+ *
+ * @author Yegor Kozlov
+ */
+public class SheetUtil {
+
+ /**
+ * Excel measures columns in units of 1/256th of a character width
+ * but the docs say nothing about what particular character is used.
+ * '0' looks to be a good choice.
+ */
+ private static final char defaultChar = '0';
+
+ /**
+ * This is the multiple that the font height is scaled by when determining the
+ * boundary of rotated text.
+ */
+ private static final double fontHeightMultiple = 2.0;
+
+ /**
+ * Dummy formula evaluator that does nothing.
+ * YK: The only reason of having this class is that
+ * {@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
+ */
+ private static final FormulaEvaluator dummyEvaluator = new FormulaEvaluator(){
+ public void clearAllCachedResultValues(){}
+ public void notifySetFormula(Cell cell) {}
+ public void notifyDeleteCell(Cell cell) {}
+ public void notifyUpdateCell(Cell cell) {}
+ public CellValue evaluate(Cell cell) {return null; }
+ public Cell evaluateInCell(Cell cell) { return null; }
+
+ public int evaluateFormulaCell(Cell cell) {
+ return cell.getCachedFormulaResultType();
+ }
+
+ };
+
+ /**
+ * drawing context to measure text
+ */
+ private static final FontRenderContext fontRenderContext = new FontRenderContext(null, true, true);
+
+ /**
+ * Compute width of a column 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
+ * @return the width in pixels
+ */
+ public static double getColumnWidth(Sheet sheet, int column, boolean useMergedCells){
+ 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;
+ rows:
+ for (Row row : sheet) {
+ Cell cell = row.getCell(column);
+
+ if (cell == null) {
+ 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();
+ }
+ }
+
+ 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;
+ }
+
+ /**
+ * Copy text attributes from the supplied Font to Java2D AttributedString
+ */
+ private static void copyAttributes(Font font, AttributedString str, int startIdx, int endIdx) {
+ str.addAttribute(TextAttribute.FAMILY, font.getFontName(), startIdx, endIdx);
+ str.addAttribute(TextAttribute.SIZE, (float)font.getFontHeightInPoints());
+ if (font.getBoldweight() == Font.BOLDWEIGHT_BOLD) str.addAttribute(TextAttribute.WEIGHT, TextAttribute.WEIGHT_BOLD, startIdx, endIdx);
+ if (font.getItalic() ) str.addAttribute(TextAttribute.POSTURE, TextAttribute.POSTURE_OBLIQUE, startIdx, endIdx);
+ if (font.getUnderline() == Font.U_SINGLE ) str.addAttribute(TextAttribute.UNDERLINE, TextAttribute.UNDERLINE_ON, startIdx, endIdx);
+ }
+
+ public static boolean containsCell(CellRangeAddress cr, int rowIx, int colIx) {
+ if (cr.getFirstRow() <= rowIx && cr.getLastRow() >= rowIx
+ && cr.getFirstColumn() <= colIx && cr.getLastColumn() >= colIx)
+ {
+ return true;
+ }
+ return false;
+ }
+
+}
\ No newline at end of file
import org.apache.poi.ss.usermodel.Header;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.Sheet;
-import org.apache.poi.ss.util.CellRangeAddress;
-import org.apache.poi.ss.util.CellRangeAddressList;
-import org.apache.poi.ss.util.CellReference;
-import org.apache.poi.ss.util.SSCellRange;
+import org.apache.poi.ss.util.*;
import org.apache.poi.util.HexDump;
import org.apache.poi.util.Internal;
import org.apache.poi.util.POILogFactory;
* @param useMergedCells whether to use the contents of merged cells when calculating the width of the column
*/
public void autoSizeColumn(int column, boolean useMergedCells) {
- double width = ColumnHelper.getColumnWidth(this, column, useMergedCells);
+ double width = SheetUtil.getColumnWidth(this, column, useMergedCells);
if(width != -1){
columnHelper.setColBestFit(column, true);
columnHelper.setCustomWidth(column, true);
}
return -1;
}
-
- public static double getColumnWidth(XSSFSheet sheet, int column, boolean useMergedCells){
- AttributedString str;
- TextLayout layout;
- /**
- * Excel measures columns in units of 1/256th of a character width
- * but the docs say nothing about what particular character is used.
- * '0' looks to be a good choice.
- */
- char defaultChar = '0';
-
- /**
- * This is the multiple that the font height is scaled by when determining the
- * boundary of rotated text.
- */
- double fontHeightMultiple = 2.0;
-
- FontRenderContext frc = new FontRenderContext(null, true, true);
-
- XSSFWorkbook wb = sheet.getWorkbook();
- XSSFFont defaultFont = wb.getFontAt((short) 0);
-
- str = new AttributedString("" + defaultChar);
- copyAttributes(defaultFont, str, 0, 1);
- layout = new TextLayout(str.getIterator(), frc);
- int defaultCharWidth = (int)layout.getAdvance();
-
- double width = -1;
- rows:
- for (Iterator it = sheet.rowIterator(); it.hasNext();) {
- XSSFRow row = (XSSFRow) it.next();
- XSSFCell cell = row.getCell(column);
-
- if (cell == null) {
- 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();
- }
- }
-
- XSSFCellStyle style = cell.getCellStyle();
- int cellType = cell.getCellType();
- if(cellType == XSSFCell.CELL_TYPE_FORMULA) cellType = cell.getCachedFormulaResultType();
- XSSFFont font = wb.getFontAt(style.getFontIndex());
-
- if (cellType == XSSFCell.CELL_TYPE_STRING) {
- XSSFRichTextString 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) {
- int pos = 0;
- for (int j = 0; j < rt.numFormattingRuns(); j++) {
- XSSFFont fnt = rt.getFontOfFormattingRun(j);
- if (fnt != null) {
- int len = rt.getLengthOfFormattingRun(j);
- if(len > 0) { //ignore degenerate zero-length runs
- copyAttributes(fnt, str, pos, pos + len);
- pos += len;
- }
- }
- }
- }
-
- layout = new TextLayout(str.getIterator(), frc);
- 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 == XSSFCell.CELL_TYPE_NUMERIC) {
- String dfmt = style.getDataFormatString();
- String format = dfmt == null ? null : dfmt.replaceAll("\"", "");
- double value = cell.getNumericCellValue();
- try {
- NumberFormat fmt;
- if ("General".equals(format))
- sval = "" + value;
- else
- {
- fmt = new DecimalFormat(format);
- sval = fmt.format(value);
- }
- } catch (Exception e) {
- sval = "" + value;
- }
- } else if (cellType == XSSFCell.CELL_TYPE_BOOLEAN) {
- sval = String.valueOf(cell.getBooleanCellValue());
- }
- if(sval != null) {
- String txt = sval + defaultChar;
- str = new AttributedString(txt);
- copyAttributes(font, str, 0, txt.length());
-
- layout = new TextLayout(str.getIterator(), frc);
- 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;
- }
-
- /**
- * Copy text attributes from the supplied HSSFFont to Java2D AttributedString
- */
- private static void copyAttributes(XSSFFont font, AttributedString str, int startIdx, int endIdx) {
- str.addAttribute(TextAttribute.FAMILY, font.getFontName(), startIdx, endIdx);
- str.addAttribute(TextAttribute.SIZE, new Float(font.getFontHeightInPoints()));
- if (font.getBoldweight() == XSSFFont.BOLDWEIGHT_BOLD) str.addAttribute(TextAttribute.WEIGHT, TextAttribute.WEIGHT_BOLD, startIdx, endIdx);
- if (font.getItalic() ) str.addAttribute(TextAttribute.POSTURE, TextAttribute.POSTURE_OBLIQUE, startIdx, endIdx);
- if (font.getUnderline() == XSSFFont.U_SINGLE ) str.addAttribute(TextAttribute.UNDERLINE, TextAttribute.UNDERLINE_ON, startIdx, endIdx);
- }
-
- private static boolean containsCell(CellRangeAddress cr, int rowIx, int colIx) {
- if (cr.getFirstRow() <= rowIx && cr.getLastRow() >= rowIx
- && cr.getFirstColumn() <= colIx && cr.getLastColumn() >= colIx)
- {
- return true;
- }
- return false;
- }
-
}
--- /dev/null
+/* ====================================================================
+ Licensed to the Apache Software Foundation (ASF) under one or more
+ contributor license agreements. See the NOTICE file distributed with
+ this work for additional information regarding copyright ownership.
+ The ASF licenses this file to You under the Apache License, Version 2.0
+ (the "License"); you may not use this file except in compliance with
+ the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+==================================================================== */
+
+package org.apache.poi.xssf.usermodel;
+
+import org.apache.poi.ss.usermodel.BaseTestSheetAutosizeColumn;
+import org.apache.poi.xssf.XSSFITestDataProvider;
+
+/**
+ * @author Yegor Kozlov
+ */
+public final class TestXSSFSheetAutosizeColumn extends BaseTestSheetAutosizeColumn {
+
+ public TestXSSFSheetAutosizeColumn(){
+ super(XSSFITestDataProvider.instance);
+ }
+}
\ No newline at end of file
--- /dev/null
+/* ====================================================================
+ Licensed to the Apache Software Foundation (ASF) under one or more
+ contributor license agreements. See the NOTICE file distributed with
+ this work for additional information regarding copyright ownership.
+ The ASF licenses this file to You under the Apache License, Version 2.0
+ (the "License"); you may not use this file except in compliance with
+ the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+==================================================================== */
+
+package org.apache.poi.hssf.usermodel;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+
+import junit.framework.AssertionFailedError;
+
+import org.apache.poi.ddf.EscherDgRecord;
+import org.apache.poi.hssf.HSSFITestDataProvider;
+import org.apache.poi.hssf.HSSFTestDataSamples;
+import org.apache.poi.hssf.model.DrawingManager2;
+import org.apache.poi.hssf.model.InternalWorkbook;
+import org.apache.poi.hssf.model.InternalSheet;
+import org.apache.poi.hssf.record.*;
+import org.apache.poi.hssf.record.formula.Ptg;
+import org.apache.poi.hssf.record.formula.Area3DPtg;
+import org.apache.poi.hssf.record.aggregates.WorksheetProtectionBlock;
+import org.apache.poi.hssf.usermodel.RecordInspector.RecordCollector;
+import org.apache.poi.ss.usermodel.*;
+import org.apache.poi.ss.util.CellRangeAddress;
+import org.apache.poi.ss.util.CellRangeAddressList;
+import org.apache.poi.util.TempFile;
+
+/**
+ * Test auto-sizing columns in HSSF
+ *
+ * @author Yegor Kozlov
+ */
+public final class TestHSSFSheetAutosizeColumn extends BaseTestSheetAutosizeColumn {
+
+ public TestHSSFSheetAutosizeColumn() {
+ super(HSSFITestDataProvider.instance);
+ }
+
+}
\ No newline at end of file
--- /dev/null
+/* ====================================================================
+ Licensed to the Apache Software Foundation (ASF) under one or more
+ contributor license agreements. See the NOTICE file distributed with
+ this work for additional information regarding copyright ownership.
+ The ASF licenses this file to You under the Apache License, Version 2.0
+ (the "License"); you may not use this file except in compliance with
+ the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+==================================================================== */
+
+package org.apache.poi.ss.usermodel;
+
+import junit.framework.TestCase;
+import org.apache.poi.ss.ITestDataProvider;
+import org.apache.poi.ss.util.CellRangeAddress;
+
+import java.util.Calendar;
+
+/**
+ * Common superclass for testing automatic sizing of sheet columns
+ *
+ * @author Yegor Kozlov
+ */
+public abstract class BaseTestSheetAutosizeColumn extends TestCase {
+
+ private final ITestDataProvider _testDataProvider;
+
+ protected BaseTestSheetAutosizeColumn(ITestDataProvider testDataProvider) {
+ _testDataProvider = testDataProvider;
+ }
+
+ // TODO should we have this stuff in the FormulaEvaluator?
+ private void evaluateWorkbook(Workbook workbook){
+ FormulaEvaluator eval = workbook.getCreationHelper().createFormulaEvaluator();
+ for(int i=0; i < workbook.getNumberOfSheets(); i++) {
+ Sheet sheet = workbook.getSheetAt(i);
+ for (Row r : sheet) {
+ for (Cell c : r) {
+ if (c.getCellType() == Cell.CELL_TYPE_FORMULA){
+ eval.evaluateFormulaCell(c);
+ }
+ }
+ }
+ }
+ }
+
+ public void testNumericCells(){
+ Workbook workbook = _testDataProvider.createWorkbook();
+ DataFormat df = workbook.getCreationHelper().createDataFormat();
+ Sheet sheet = workbook.createSheet();
+
+ Row row = sheet.createRow(0);
+ row.createCell(0).setCellValue(0); // getCachedFormulaResult() returns 0 for not evaluated formula cells
+ row.createCell(1).setCellValue(10);
+ row.createCell(2).setCellValue("10");
+ row.createCell(3).setCellFormula("(A1+B1)*1.0"); // a formula that returns '10'
+
+ Cell cell4 = row.createCell(4); // numeric cell with a custom style
+ CellStyle style4 = workbook.createCellStyle();
+ style4.setDataFormat(df.getFormat("0.0000"));
+ cell4.setCellStyle(style4);
+ cell4.setCellValue(10); // formatted as '10.0000'
+
+ row.createCell(5).setCellValue("10.0000");
+
+ // autosize not-evaluated cells, formula cells are sized as if the result is 0
+ for (int i = 0; i < 6; i++) sheet.autoSizeColumn(i);
+
+ assertTrue(sheet.getColumnWidth(0) < sheet.getColumnWidth(1)); // width of '0' is less then width of '10'
+ assertEquals(sheet.getColumnWidth(1), sheet.getColumnWidth(2)); // 10 and '10' should be sized equally
+ assertEquals(sheet.getColumnWidth(3), sheet.getColumnWidth(0)); // formula result is unknown, the width is calculated for '0'
+ assertEquals(sheet.getColumnWidth(4), sheet.getColumnWidth(5)); // 10.0000 and '10.0000'
+
+ // evaluate formulas and re-autosize
+ evaluateWorkbook(workbook);
+
+ for (int i = 0; i < 6; i++) sheet.autoSizeColumn(i);
+
+ assertTrue(sheet.getColumnWidth(0) < sheet.getColumnWidth(1)); // width of '0' is less then width of '10'
+ assertEquals(sheet.getColumnWidth(1), sheet.getColumnWidth(2)); // columns 1, 2 and 3 should have the same width
+ assertEquals(sheet.getColumnWidth(2), sheet.getColumnWidth(3)); // columns 1, 2 and 3 should have the same width
+ assertEquals(sheet.getColumnWidth(4), sheet.getColumnWidth(5)); // 10.0000 and '10.0000'
+ }
+
+ public void testBooleanCells(){
+ Workbook workbook = _testDataProvider.createWorkbook();
+ Sheet sheet = workbook.createSheet();
+
+ Row row = sheet.createRow(0);
+ row.createCell(0).setCellValue(0); // getCachedFormulaResult() returns 0 for not evaluated formula cells
+ row.createCell(1).setCellValue(true);
+ row.createCell(2).setCellValue("TRUE");
+ row.createCell(3).setCellFormula("1 > 0"); // a formula that returns true
+
+ // autosize not-evaluated cells, formula cells are sized as if the result is 0
+ for (int i = 0; i < 4; i++) sheet.autoSizeColumn(i);
+
+ assertTrue(sheet.getColumnWidth(1) > sheet.getColumnWidth(0)); // 'true' is wider than '0'
+ assertEquals(sheet.getColumnWidth(1), sheet.getColumnWidth(2)); // 10 and '10' should be sized equally
+ assertEquals(sheet.getColumnWidth(3), sheet.getColumnWidth(0)); // formula result is unknown, the width is calculated for '0'
+
+ // evaluate formulas and re-autosize
+ evaluateWorkbook(workbook);
+
+ for (int i = 0; i < 4; i++) sheet.autoSizeColumn(i);
+
+ assertTrue(sheet.getColumnWidth(1) > sheet.getColumnWidth(0)); // 'true' is wider than '0'
+ assertEquals(sheet.getColumnWidth(1), sheet.getColumnWidth(2)); // columns 1, 2 and 3 should have the same width
+ assertEquals(sheet.getColumnWidth(2), sheet.getColumnWidth(3)); // columns 1, 2 and 3 should have the same width
+ }
+
+ public void testDateCells(){
+ Workbook workbook = _testDataProvider.createWorkbook();
+ Sheet sheet = workbook.createSheet();
+ DataFormat df = workbook.getCreationHelper().createDataFormat();
+
+ CellStyle style1 = workbook.createCellStyle();
+ style1.setDataFormat(df.getFormat("m"));
+
+ CellStyle style3 = workbook.createCellStyle();
+ style3.setDataFormat(df.getFormat("mmm"));
+
+ CellStyle style5 = workbook.createCellStyle(); //rotated text
+ style5.setDataFormat(df.getFormat("mmm/dd/yyyy"));
+
+ Calendar calendar = Calendar.getInstance();
+ calendar.set(2010, 0, 1); // Jan 1 2010
+
+ Row row = sheet.createRow(0);
+ row.createCell(0).setCellValue(DateUtil.getJavaDate(0)); //default date
+
+ Cell cell1 = row.createCell(1);
+ cell1.setCellValue(calendar);
+ cell1.setCellStyle(style1);
+ row.createCell(2).setCellValue("1"); // column 1 should be sized as '1'
+
+ Cell cell3 = row.createCell(3);
+ cell3.setCellValue(calendar);
+ cell3.setCellStyle(style3);
+ row.createCell(4).setCellValue("Jan");
+
+ Cell cell5 = row.createCell(5);
+ cell5.setCellValue(calendar);
+ cell5.setCellStyle(style5);
+ row.createCell(6).setCellValue("Jan/01/2010");
+
+ Cell cell7 = row.createCell(7);
+ cell7.setCellFormula("DATE(2010,1,1)");
+ cell7.setCellStyle(style3); // should be sized as 'Jan'
+
+ // autosize not-evaluated cells, formula cells are sized as if the result is 0
+ for (int i = 0; i < 8; i++) sheet.autoSizeColumn(i);
+
+ assertEquals(sheet.getColumnWidth(2), sheet.getColumnWidth(1)); // date formatted as 'm'
+ assertTrue(sheet.getColumnWidth(3) > sheet.getColumnWidth(1)); // 'mmm' is wider than 'm'
+ assertEquals(sheet.getColumnWidth(4), sheet.getColumnWidth(3)); // date formatted as 'mmm'
+ assertTrue(sheet.getColumnWidth(5) > sheet.getColumnWidth(3)); // 'mmm/dd/yyyy' is wider than 'mmm'
+ assertEquals(sheet.getColumnWidth(6), sheet.getColumnWidth(5)); // date formatted as 'mmm/dd/yyyy'
+
+ // YK: width of not-evaluated formulas that return data is not determined
+ // POI seems to conevert '0' to Excel date which is the beginng of the Excel's date system
+
+ // evaluate formulas and re-autosize
+ evaluateWorkbook(workbook);
+
+ for (int i = 0; i < 8; i++) sheet.autoSizeColumn(i);
+
+ assertEquals(sheet.getColumnWidth(2), sheet.getColumnWidth(1)); // date formatted as 'm'
+ assertTrue(sheet.getColumnWidth(3) > sheet.getColumnWidth(1)); // 'mmm' is wider than 'm'
+ assertEquals(sheet.getColumnWidth(4), sheet.getColumnWidth(3)); // date formatted as 'mmm'
+ assertTrue(sheet.getColumnWidth(5) > sheet.getColumnWidth(3)); // 'mmm/dd/yyyy' is wider than 'mmm'
+ assertEquals(sheet.getColumnWidth(6), sheet.getColumnWidth(5)); // date formatted as 'mmm/dd/yyyy'
+ assertEquals(sheet.getColumnWidth(4), sheet.getColumnWidth(7)); // date formula formatted as 'mmm'
+ }
+
+ public void testStringCells(){
+ Workbook workbook = _testDataProvider.createWorkbook();
+ Sheet sheet = workbook.createSheet();
+ Row row = sheet.createRow(0);
+
+ Font defaultFont = workbook.getFontAt((short)0);
+
+ CellStyle style1 = workbook.createCellStyle();
+ Font font1 = workbook.createFont();
+ font1.setFontHeight((short)(2*defaultFont.getFontHeight()));
+ style1.setFont(font1);
+
+ row.createCell(0).setCellValue("x");
+ row.createCell(1).setCellValue("xxxx");
+ row.createCell(2).setCellValue("xxxxxxxxxxxx");
+ row.createCell(3).setCellValue("Apache\nSoftware Foundation"); // the text is splitted into two lines
+ row.createCell(4).setCellValue("Software Foundation");
+
+ Cell cell5 = row.createCell(5);
+ cell5.setCellValue("Software Foundation");
+ cell5.setCellStyle(style1); // same as in column 4 but the font is twice larger than the default font
+
+ for (int i = 0; i < 10; i++) sheet.autoSizeColumn(i);
+
+ assertTrue(2*sheet.getColumnWidth(0) < sheet.getColumnWidth(1)); // width is roughly proportional to the number of characters
+ assertTrue(2*sheet.getColumnWidth(1) < sheet.getColumnWidth(2));
+ assertEquals(sheet.getColumnWidth(4), sheet.getColumnWidth(3));
+ assertTrue(sheet.getColumnWidth(5) > sheet.getColumnWidth(4)); //larger font results in a wider column width
+ }
+
+ public void testRotatedText(){
+ Workbook workbook = _testDataProvider.createWorkbook();
+ Sheet sheet = workbook.createSheet();
+ Row row = sheet.createRow(0);
+
+ CellStyle style1 = workbook.createCellStyle();
+ style1.setRotation((short)90);
+
+ Cell cell0 = row.createCell(0);
+ cell0.setCellValue("Apache Software Foundation");
+ cell0.setCellStyle(style1);
+
+ Cell cell1 = row.createCell(1);
+ cell1.setCellValue("Apache Software Foundation");
+
+ for (int i = 0; i < 2; i++) sheet.autoSizeColumn(i);
+
+ int w0 = sheet.getColumnWidth(0);
+ int w1 = sheet.getColumnWidth(1);
+
+ assertTrue(w0*5 < w1); // rotated text occupies at least five times less horizontal space than normal text
+ }
+
+ public void testMergedCells(){
+ Workbook workbook = _testDataProvider.createWorkbook();
+ Sheet sheet = workbook.createSheet();
+
+ Row row = sheet.createRow(0);
+ sheet.addMergedRegion(CellRangeAddress.valueOf("A1:B1"));
+
+ Cell cell0 = row.createCell(0);
+ cell0.setCellValue("Apache Software Foundation");
+
+ int defaulWidth = sheet.getColumnWidth(0);
+ sheet.autoSizeColumn(0);
+ // column is unchanged if merged regions are ignored (Excel like behavior)
+ assertEquals(defaulWidth, sheet.getColumnWidth(0));
+
+ sheet.autoSizeColumn(0, true);
+ assertTrue(sheet.getColumnWidth(0) > defaulWidth);
+ }
+
+}
\ No newline at end of file