mirror of https://github.com/apache/poi.git
use cached formula result when autosizing sheet columns, see Bugzilla 50211
git-svn-id: https://svn.apache.org/repos/asf/poi/trunk@1033005 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
parent
81a9293f1c
commit
3aef93a73b
|
@ -1371,9 +1371,14 @@ Examples:
|
||||||
<section><title>Adjust column width to fit the contents</title>
|
<section><title>Adjust column width to fit the contents</title>
|
||||||
<source>
|
<source>
|
||||||
Sheet sheet = workbook.getSheetAt(0);
|
Sheet sheet = workbook.getSheetAt(0);
|
||||||
sheet.autoSizeColumn((short)0); //adjust width of the first column
|
sheet.autoSizeColumn(0); //adjust width of the first column
|
||||||
sheet.autoSizeColumn((short)1); //adjust width of the second column
|
sheet.autoSizeColumn(1); //adjust width of the second column
|
||||||
</source>
|
</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>
|
<warning>
|
||||||
To calculate column width HSSFSheet.autoSizeColumn uses Java2D classes
|
To calculate column width HSSFSheet.autoSizeColumn uses Java2D classes
|
||||||
that throw exception if graphical environment is not available. In case if graphical environment
|
that throw exception if graphical environment is not available. In case if graphical environment
|
||||||
|
|
|
@ -34,6 +34,8 @@
|
||||||
|
|
||||||
<changes>
|
<changes>
|
||||||
<release version="3.8-beta1" date="2010-??-??">
|
<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">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>
|
<action dev="poi-developers" type="fix">50119 - avoid NPE when XSSFReader comes across chart sheets</action>
|
||||||
</release>
|
</release>
|
||||||
|
|
|
@ -54,6 +54,7 @@ import org.apache.poi.ss.usermodel.Row;
|
||||||
import org.apache.poi.ss.util.CellRangeAddress;
|
import org.apache.poi.ss.util.CellRangeAddress;
|
||||||
import org.apache.poi.ss.util.CellReference;
|
import org.apache.poi.ss.util.CellReference;
|
||||||
import org.apache.poi.ss.util.SSCellRange;
|
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.POILogFactory;
|
||||||
import org.apache.poi.util.POILogger;
|
import org.apache.poi.util.POILogger;
|
||||||
|
|
||||||
|
@ -1146,7 +1147,8 @@ public final class HSSFSheet implements org.apache.poi.ss.usermodel.Sheet {
|
||||||
}
|
}
|
||||||
|
|
||||||
//only shift if the region outside the shifted rows is not merged too
|
//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.setFirstRow(merged.getFirstRow()+n);
|
||||||
merged.setLastRow(merged.getLastRow()+n);
|
merged.setLastRow(merged.getLastRow()+n);
|
||||||
//have to remove/add it back
|
//have to remove/add it back
|
||||||
|
@ -1164,14 +1166,6 @@ public final class HSSFSheet implements org.apache.poi.ss.usermodel.Sheet {
|
||||||
this.addMergedRegion(region);
|
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.
|
* Shifts rows between startRow and endRow n number of rows.
|
||||||
|
@ -1741,153 +1735,8 @@ public final class HSSFSheet implements org.apache.poi.ss.usermodel.Sheet {
|
||||||
* @param useMergedCells whether to use the contents of merged cells when calculating the width of the column
|
* @param useMergedCells whether to use the contents of merged cells when calculating the width of the column
|
||||||
*/
|
*/
|
||||||
public void autoSizeColumn(int column, boolean useMergedCells) {
|
public void autoSizeColumn(int column, boolean useMergedCells) {
|
||||||
AttributedString str;
|
double width = SheetUtil.getColumnWidth(this, column, useMergedCells);
|
||||||
TextLayout layout;
|
if(width != -1) setColumnWidth(column, (int) (256*width));
|
||||||
/**
|
|
||||||
* 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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -0,0 +1,219 @@
|
||||||
|
/* ====================================================================
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -49,10 +49,7 @@ import org.apache.poi.ss.usermodel.Footer;
|
||||||
import org.apache.poi.ss.usermodel.Header;
|
import org.apache.poi.ss.usermodel.Header;
|
||||||
import org.apache.poi.ss.usermodel.Row;
|
import org.apache.poi.ss.usermodel.Row;
|
||||||
import org.apache.poi.ss.usermodel.Sheet;
|
import org.apache.poi.ss.usermodel.Sheet;
|
||||||
import org.apache.poi.ss.util.CellRangeAddress;
|
import org.apache.poi.ss.util.*;
|
||||||
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.util.HexDump;
|
import org.apache.poi.util.HexDump;
|
||||||
import org.apache.poi.util.Internal;
|
import org.apache.poi.util.Internal;
|
||||||
import org.apache.poi.util.POILogFactory;
|
import org.apache.poi.util.POILogFactory;
|
||||||
|
@ -334,7 +331,7 @@ public class XSSFSheet extends POIXMLDocumentPart implements Sheet {
|
||||||
* @param useMergedCells whether to use the contents of merged cells when calculating the width of the column
|
* @param useMergedCells whether to use the contents of merged cells when calculating the width of the column
|
||||||
*/
|
*/
|
||||||
public void autoSizeColumn(int column, boolean useMergedCells) {
|
public void autoSizeColumn(int column, boolean useMergedCells) {
|
||||||
double width = ColumnHelper.getColumnWidth(this, column, useMergedCells);
|
double width = SheetUtil.getColumnWidth(this, column, useMergedCells);
|
||||||
if(width != -1){
|
if(width != -1){
|
||||||
columnHelper.setColBestFit(column, true);
|
columnHelper.setColBestFit(column, true);
|
||||||
columnHelper.setCustomWidth(column, true);
|
columnHelper.setCustomWidth(column, true);
|
||||||
|
|
|
@ -299,169 +299,4 @@ public class ColumnHelper {
|
||||||
}
|
}
|
||||||
return -1;
|
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,31 @@
|
||||||
|
/* ====================================================================
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,53 @@
|
||||||
|
/* ====================================================================
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,255 @@
|
||||||
|
/* ====================================================================
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
Loading…
Reference in New Issue