By using the last part from Val Blant I've did something that's easier to use, and yet much complex.
Please be aware that there is a single line of code that adds one additional line to the cell height-wise, for personal reasons. If you do not wish that, please remove it. Also feel free to change it to a non-static, I've had to use static methods due to the company I'm working for making the specific class static.
PS: It's my first post on stackoverflow, please be gentle. :)
Solution:
public static Boolean isCellMerged(Cell cell) {
Sheet sheet = cell.getSheet();
for (CellRangeAddress mergedRegionRange : sheet.getMergedRegions()) {
Integer cellColumn = cell.getColumnIndex();
Integer cellRow = cell.getRowIndex();
if (mergedRegionRange.containsColumn(cellColumn) && mergedRegionRange.containsRow(cellRow)) {
return true;
}
}
return false;
}
public static List<List<Cell>> getCellsInRowsInsideRegionRange(Cell cell) {
Sheet sheet = cell.getSheet();
List<List<Cell>> mergedRowList = new ArrayList<>();
List<Cell> mergedCellsList = new ArrayList<>();
//Nejdříve musíme zjistit sloučenou sekci dané buňky
for (CellRangeAddress mergedRegionRange : sheet.getMergedRegions()) {
Integer cellColumn = cell.getColumnIndex();
Integer cellRow = cell.getRowIndex();
if (mergedRegionRange.containsColumn(cellColumn) && mergedRegionRange.containsRow(cellRow)) {
//Protože CellRangeAddress nemá moc metod, musíme si pomoci sami a získat z ní buňky a řádky
for (Row row : sheet) {
for (Cell iteratedCell : row) {
Integer iteratedCellColumn = iteratedCell.getColumnIndex();
Integer iteratedCellRow = iteratedCell.getRowIndex();
if (mergedRegionRange.containsColumn(iteratedCellColumn) && mergedRegionRange.containsRow(iteratedCellRow)) {
//Rozdělování jednotlivých řádků
//Není-li řádek bez buněk...
if (!mergedCellsList.isEmpty()) {
//Tak buňku přidáme do Listu buněk...
mergedCellsList.add(iteratedCell);
} else {
//Pokud se jedná o první buňku prvního řádku, tak přidáme rovnou
mergedCellsList.add(iteratedCell);
}
}
}
//Vložíme List buněk daného řádku do Listu řádků
if (!mergedCellsList.isEmpty()) {
mergedRowList.add(mergedCellsList);
}
//A vyresetujeme list buněk (začneme tak nanovo novým řádkem)
mergedCellsList = null;
mergedCellsList = new ArrayList<>();
}
//Vrátíme výsledný List řádků, obsahující Listy buněk ve sloučené sekci.
if (!mergedRowList.isEmpty()) {
return mergedRowList;
} else {
return null;
}
}
}
return null;
}
public static void adjustRowHeightForRowWithNonMergedCells(Row row) {
row.setHeight((short) -1);
}
public static void adjustRowHeightForRowWithMergedCells(Row row) {
Sheet sheet = row.getSheet();
Cell longestTextCell = null;
//Potřebujeme získat buňku s nejdelším textem
for (Cell iteratedCell : row) {
String iteratedTextString = iteratedCell.getStringCellValue();
if (longestTextCell != null && StringUtils.isNotBlank(longestTextCell.getStringCellValue())) {
if (iteratedTextString.length() > longestTextCell.getStringCellValue().length()) {
longestTextCell = iteratedCell;
}
} else {
longestTextCell = iteratedCell;
}
}
//Z textově nejobsáhlejší buňky potřebujeme dostat údaje
String longestText = "";
if (StringUtils.isNotBlank(longestTextCell.getStringCellValue()) && longestTextCell != null) {
longestText = longestTextCell.getStringCellValue();
//Protože textově nejobsáhlejší buňka nemusí nutně být sloučeného typu, je zapotřebí to všude ošetřit
Boolean isLongestTextCellMerged = isCellMerged(longestTextCell);
Float longestCellWidthInPixels = 0f;
Float longestMergedCellWidthInPixels = 0f;
//Získat šířku nesloučené nejobsáhlejší buňky je jednoduché
if (!isLongestTextCellMerged) {
Integer longestCellColumnIndex = longestTextCell.getColumnIndex();
longestCellWidthInPixels = sheet.getColumnWidthInPixels(longestCellColumnIndex);
} else {
//Musíme přijít na šířku sloučené buňky namísto buňky uvnitř sloučené buňky
List<List<Cell>> cellsInMergedRegion = getCellsInRowsInsideRegionRange(longestTextCell);
longestMergedCellWidthInPixels = 0f;
//Projdeme řádky
for (List<Cell> iteratedCell2List : cellsInMergedRegion) {
Float iteratedMergedCell2WidthInPixels = 0f;
//Projdeme jednotlivé buňky ve sloučené buňce na řádku a sečteme jejich šířky
for (Cell iteratedCell2 : iteratedCell2List) {
Integer iteratedCell2ColumnIndex = iteratedCell2.getColumnIndex();
Float iteratedCell2ColumnWidthInPixels = sheet.getColumnWidthInPixels(iteratedCell2ColumnIndex);
iteratedMergedCell2WidthInPixels = iteratedMergedCell2WidthInPixels + iteratedCell2ColumnWidthInPixels;
}
//Získáme šířku nejširší sloučené buňky na řádku
if (iteratedMergedCell2WidthInPixels > longestMergedCellWidthInPixels) {
longestMergedCellWidthInPixels = iteratedMergedCell2WidthInPixels;
}
//Resetujeme sčítání
iteratedMergedCell2WidthInPixels = 0f;
}
}
//Uložíme si nejširší buňku dle toho, zda je sloučená či nikoliv
Float longestWidthInPixels;
if (isLongestTextCellMerged) {
longestWidthInPixels = longestMergedCellWidthInPixels;
} else {
longestWidthInPixels = longestCellWidthInPixels;
}
//Potřebujeme font
Workbook wb = sheet.getWorkbook();
Short fontIndex = longestTextCell.getCellStyle().getFontIndex();
Font excelFont = wb.getFontAt(fontIndex);
//Potřebujeme i jeho styl
Integer excelFontStyle = java.awt.Font.PLAIN;
if (excelFont.getBold()) excelFontStyle = java.awt.Font.BOLD;
if (excelFont.getItalic()) excelFontStyle = java.awt.Font.ITALIC;
//Potřebujeme získat skutečný font i s velikostí
java.awt.Font currentFont = new java.awt.Font(excelFont.getFontName(), excelFontStyle, excelFont.getFontHeightInPoints());
//Získáme řetězec s vlastností
AttributedString attributedString = new AttributedString(longestText);
attributedString.addAttribute(TextAttribute.FONT, currentFont);
//Použijeme LineBreakMeasurer k zjištění kolik řádků bude text potřebovat
FontRenderContext fontRenderContext = new FontRenderContext(null, true, true);
LineBreakMeasurer measurer = new LineBreakMeasurer(attributedString.getIterator(), fontRenderContext);
Integer nextPosition = 0;
Integer lineCount = 0;
while (measurer.getPosition() < longestText.length()) {
nextPosition = measurer.nextOffset(longestWidthInPixels);
//Také musíme ošetřit případ manuálně zadaných LineBreaků pro všechny možné techtle mechtle :-S
String textLine = StringUtils.substring(longestText, measurer.getPosition(), nextPosition);
Boolean containsNewLine = StringUtils.containsIgnoreCase(textLine, "\r") || StringUtils.containsIgnoreCase(textLine, "\\r") || StringUtils.containsIgnoreCase(textLine, "\n") || StringUtils.containsIgnoreCase(textLine, "\\n");
if (containsNewLine) {
if (StringUtils.containsIgnoreCase(textLine, "\r\n") || StringUtils.containsIgnoreCase(textLine, "\\r\\n")) {
lineCount = lineCount + StringUtils.countMatches(textLine, "\n");
} else {
if (StringUtils.containsIgnoreCase(textLine, "\r") || StringUtils.containsIgnoreCase(textLine, "\\r")) {
lineCount = lineCount + StringUtils.countMatches(textLine, "\r");
}
if (StringUtils.containsIgnoreCase(textLine, "\n") || StringUtils.containsIgnoreCase(textLine, "\\n")) {
lineCount = lineCount + StringUtils.countMatches(textLine, "\n");
}
}
lineCount = lineCount + StringUtils.countMatches(textLine, "\\r?\\n");
}
lineCount++;
measurer.setPosition(nextPosition);
}
//Máme počet řádků, zbývá konečný dopočet výšky řádku a jeho použití
if (lineCount > 1) {
Float fontHeight = currentFont.getLineMetrics(longestText, fontRenderContext).getHeight();
//Pro jistotu přidáme jeden řádek navíc, člověk nikdy neví...
lineCount = lineCount + 1;
//Potřebujeme získat poslední řádek
Row lastRow = null;
if (isCellMerged(longestTextCell)) {
List<List<Cell>> mergedCellsInRows = getCellsInRowsInsideRegionRange(longestTextCell);
Integer lastRowInMergedSectionIndex = mergedCellsInRows.size() - 1;
List<Cell> lastRowInMergedSection = mergedCellsInRows.get(lastRowInMergedSectionIndex);
lastRow = lastRowInMergedSection.get(0).getRow();
} else {
lastRow = longestTextCell.getRow();
}
//Je potřeba ošetřit velikosti, pokud má sloučená buňka vícero řádků
Float cellsMergedAboveHeight = 0f;
if (isCellMerged(longestTextCell)) {
if (getCellsInRowsInsideRegionRange(longestTextCell).size() > 1) {
List<List<Cell>> mergedCellsInRows = getCellsInRowsInsideRegionRange(longestTextCell);
for (List<Cell> rowsWithCells : mergedCellsInRows){
if (!lastRow.equals(rowsWithCells.get(0).getRow())){
cellsMergedAboveHeight = cellsMergedAboveHeight + rowsWithCells.get(0).getRow().getHeight();
}
}
}
}
//Vzorec je ((Velikost fontu krát počet řádků plus (počet řádků krát volný prostor mezi řádky)) krát přepočet Excelu) mínus výška sloučených buněk nad posledním řádkem.
Short finalRowHeight = (short) (((fontHeight * lineCount + (lineCount * 15))* 10) - cellsMergedAboveHeight);
//A výsledek nastavíme na poslední řádek, protože jinak to przní sloupce vlevo a vpravo od vyšších řádků
lastRow.setHeight(finalRowHeight);
}
}
}