/* * Copyright (C) 2009-2010 Open Wide * Contact: contact@openwide.fr * * Licensed 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 fr.openwide.core.export.excel; import java.util.ArrayList; import java.util.Collection; import java.util.Date; import java.util.List; import java.util.Map; import java.util.Map.Entry; import org.apache.poi.hssf.util.HSSFColor; import org.apache.poi.ss.usermodel.Cell; import org.apache.poi.ss.usermodel.CellStyle; import org.apache.poi.ss.usermodel.Font; import org.apache.poi.ss.usermodel.Hyperlink; import org.apache.poi.ss.usermodel.Row; import org.apache.poi.ss.usermodel.Sheet; import org.apache.poi.ss.usermodel.Workbook; import org.apache.poi.ss.util.CellRangeAddress; import com.google.common.collect.ContiguousSet; import com.google.common.collect.DiscreteDomain; import com.google.common.collect.Lists; import com.google.common.collect.Range; import com.google.common.collect.RangeMap; import com.google.common.collect.TreeRangeMap; import fr.openwide.core.commons.util.functional.Joiners; /** * <p>Classe abstraite permettant de construire des tableaux Excel.</p> * * @author Open Wide */ public abstract class AbstractExcelTableExport extends AbstractExcelExport { /** * Index de la couleur des bordures */ protected static final short BORDER_COLOR_INDEX = (short) 35; /** * Index de la couleur de fond du header */ protected static final short HEADER_BACKGROUND_COLOR_INDEX = (short) 36; /** * Index de la couleur du texte du header */ protected static final short HEADER_FONT_COLOR_INDEX = (short) 37; /** * Index de la couleur des lignes paires */ protected static final short EVEN_ROW_BACKGROUND_COLOR_INDEX = (short) 38; /** * Index de la couleur de la police des liens */ protected static final short LINK_FONT_COLOR_INDEX = (short) 39; /** * Ratio pour redimensionner les colonnes correctement */ protected static final float COLUMN_RESIZE_RATIO = 1.25f; /** * Taille maximale autorisée pour une colonne */ protected static final int ABSOLUTE_MAX_COLUMN_WIDTH = 65000; protected static final String FONT_NORMAL_NAME = "fontNormal"; protected static final String FONT_LINK_NAME = "fontLink"; protected static final String FONT_HEADER_NAME = "fontHeader"; protected static final String ROW_ODD_NAME = "Odd"; protected static final String ROW_EVEN_NAME = "Even"; protected static final String STYLE_DEFAULT_NAME = "default"; protected static final String STYLE_HEADER_NAME = "header"; protected static final String STYLE_STANDARD_NAME = "standard"; protected static final String STYLE_INTEGER_NAME = "integer"; protected static final String STYLE_DECIMAL_NAME = "decimal"; protected static final String STYLE_DATE_NAME = "date"; protected static final String STYLE_DATE_TIME_NAME = "datetime"; protected static final String STYLE_PERCENT_NAME = "percent"; protected static final String STYLE_PERCENT_RELATIVE_NAME = "percentRelative"; protected static final String STYLE_LINK_NAME = "link"; protected static final String STYLE_FILE_SIZE_NAME = "fileSize"; /** * Police utilisée dans le document */ private String fontName = "Verdana"; /** * Taille de police utilisée dans le corps d'une table */ private short normalFontHeight = 9; /** * Taille de police utilisée dans le header d'une table */ private short headerFontHeight = 9; /** * Couleur des bordures */ private String borderColor = "#D1D1D1"; /** * Couleur de fond du header */ private String headerBackgroundColor = "#007CAF"; /** * Couleur du texte du header */ private String headerFontColor = "#000000"; /** * Couleur des liens */ private String linkFontColor = "#0077CC"; /** * Couleur des lignes paires */ private String evenRowBackgroundColor = "#EEEEEE"; /** * Format des pour les nombres entiers */ private String integerDataFormat = "# ### ### ### ##0"; /** * Format des pour les nombres décimaux */ private String decimalDataFormat = "# ### ### ### ##0.##"; /** * Format des dates */ private String dateDataFormat = "DD/MM/YYYY"; /** * Format des dates avec heure */ private String dateTimeDataFormat = "DD/MM/YYYY HH:mm"; /** * Format des pourcentages */ private String percentDataFormat = "0.00%"; /** * Format des pourcentages avec signe +/- */ private String percentRelativeDataFormat = "+0.00%;-0.00%"; /** * Format de taille de fichier * * J'aurai bien mis en octets aussi, malheureusement Excel n'accepte visiblement que deux conditions... pas trois. */ private String fileSizeDataFormat = "[<1000000]0.0,\" Ko\";[<1000000000]0.0,,\" Mo\";0.0,,,\" Go\""; /** * Constructeur */ public AbstractExcelTableExport(Workbook workbook) { super(workbook); } /** * Initilisation générale */ public void init() { initColors(); initFonts(); initStyles(); } /** * Initialisation des couleurs */ protected void initColors() { registerColor(BORDER_COLOR_INDEX, borderColor); registerColor(HEADER_BACKGROUND_COLOR_INDEX, headerBackgroundColor); registerColor(HEADER_FONT_COLOR_INDEX, headerFontColor); registerColor(EVEN_ROW_BACKGROUND_COLOR_INDEX, evenRowBackgroundColor); registerColor(LINK_FONT_COLOR_INDEX, linkFontColor); } /** * Initialisation des polices */ protected void initFonts() { Font fontHeader = workbook.createFont(); fontHeader.setFontHeightInPoints(getHeaderFontHeight()); fontHeader.setFontName(getFontName()); fontHeader.setBoldweight(Font.BOLDWEIGHT_BOLD); setFontColor(fontHeader, colorRegistry, HEADER_FONT_COLOR_INDEX); registerFont(FONT_HEADER_NAME, fontHeader); Font fontNormal = workbook.createFont(); fontNormal.setFontHeightInPoints(getNormalFontHeight()); fontNormal.setFontName(getFontName()); registerFont(FONT_NORMAL_NAME, fontNormal); Font fontLink = workbook.createFont(); fontLink.setFontHeightInPoints(getNormalFontHeight()); fontLink.setFontName(getFontName()); fontLink.setUnderline(Font.U_SINGLE); setFontColor(fontLink, colorRegistry, LINK_FONT_COLOR_INDEX); registerFont(FONT_LINK_NAME, fontLink); } /** * Initialisation des styles de cellule */ protected void initStyles() { CellStyle defaultStyle = workbook.createCellStyle(); defaultStyle.setFont(getFont(FONT_NORMAL_NAME)); setStyleFillForegroundColor(defaultStyle, colorRegistry, HSSFColor.WHITE.index); defaultStyle.setFillPattern(CellStyle.SOLID_FOREGROUND); defaultStyle.setBorderBottom(CellStyle.BORDER_THIN); setStyleBottomBorderColor(defaultStyle, colorRegistry, BORDER_COLOR_INDEX); defaultStyle.setBorderLeft(CellStyle.BORDER_THIN); setStyleLeftBorderColor(defaultStyle, colorRegistry, BORDER_COLOR_INDEX); defaultStyle.setBorderRight(CellStyle.BORDER_THIN); setStyleRightBorderColor(defaultStyle, colorRegistry, BORDER_COLOR_INDEX); defaultStyle.setBorderTop(CellStyle.BORDER_THIN); setStyleTopBorderColor(defaultStyle, colorRegistry, BORDER_COLOR_INDEX); defaultStyle.setVerticalAlignment(CellStyle.VERTICAL_CENTER); defaultStyle.setWrapText(true); registerStyle(STYLE_DEFAULT_NAME, defaultStyle); CellStyle styleHeader = workbook.createCellStyle(); styleHeader.setAlignment(CellStyle.ALIGN_CENTER); styleHeader.setFont(getFont(FONT_HEADER_NAME)); setStyleFillForegroundColor(styleHeader, colorRegistry, HEADER_BACKGROUND_COLOR_INDEX); styleHeader.setFillPattern(CellStyle.SOLID_FOREGROUND); styleHeader.setBorderBottom(CellStyle.BORDER_THIN); setStyleBottomBorderColor(styleHeader, colorRegistry, BORDER_COLOR_INDEX); styleHeader.setBorderLeft(CellStyle.BORDER_THIN); setStyleLeftBorderColor(styleHeader, colorRegistry, BORDER_COLOR_INDEX); styleHeader.setBorderRight(CellStyle.BORDER_THIN); setStyleRightBorderColor(styleHeader, colorRegistry, BORDER_COLOR_INDEX); styleHeader.setBorderTop(CellStyle.BORDER_THIN); setStyleTopBorderColor(styleHeader, colorRegistry, BORDER_COLOR_INDEX); styleHeader.setDataFormat((short) 0); styleHeader.setWrapText(true); registerStyle(STYLE_HEADER_NAME, styleHeader); CellStyle styleOdd = cloneStyle(defaultStyle); registerStyle(STYLE_STANDARD_NAME + ROW_ODD_NAME, styleOdd); CellStyle styleEven = cloneStyle(styleOdd); setStyleFillForegroundColor(styleEven, colorRegistry, EVEN_ROW_BACKGROUND_COLOR_INDEX); registerStyle(STYLE_STANDARD_NAME + ROW_EVEN_NAME, styleEven); // styles pour les nombres entiers short integerFormatIndex = dataFormat.getFormat(integerDataFormat); CellStyle styleOddInteger = cloneStyle(styleOdd); styleOddInteger.setAlignment(CellStyle.ALIGN_RIGHT); styleOddInteger.setDataFormat(integerFormatIndex); registerStyle(STYLE_INTEGER_NAME + ROW_ODD_NAME, styleOddInteger); CellStyle styleEvenInteger = cloneStyle(styleEven); styleEvenInteger.setAlignment(CellStyle.ALIGN_RIGHT); styleEvenInteger.setDataFormat(integerFormatIndex); registerStyle(STYLE_INTEGER_NAME + ROW_EVEN_NAME, styleEvenInteger); // styles pour les nombres décimaux short decimalFormatIndex = dataFormat.getFormat(decimalDataFormat); CellStyle styleOddDecimal = cloneStyle(styleOdd); styleOddDecimal.setAlignment(CellStyle.ALIGN_RIGHT); styleOddDecimal.setDataFormat(decimalFormatIndex); registerStyle(STYLE_DECIMAL_NAME + ROW_ODD_NAME, styleOddDecimal); CellStyle styleEvenDecimal = cloneStyle(styleEven); styleEvenDecimal.setAlignment(CellStyle.ALIGN_RIGHT); styleEvenDecimal.setDataFormat(decimalFormatIndex); registerStyle(STYLE_DECIMAL_NAME + ROW_EVEN_NAME, styleEvenDecimal); // styles pour les dates short dateFormatIndex = dataFormat.getFormat(dateDataFormat); CellStyle styleOddDate = cloneStyle(styleOdd); styleOddDate.setDataFormat(dateFormatIndex); registerStyle(STYLE_DATE_NAME + ROW_ODD_NAME, styleOddDate); CellStyle styleEvenDate = cloneStyle(styleEven); styleEvenDate.setDataFormat(dateFormatIndex); registerStyle(STYLE_DATE_NAME + ROW_EVEN_NAME, styleEvenDate); // styles pour les dates avec heure short dateTimeFormatIndex = dataFormat.getFormat(dateTimeDataFormat); CellStyle styleOddDateTime = cloneStyle(styleOdd); styleOddDateTime.setDataFormat(dateTimeFormatIndex); registerStyle(STYLE_DATE_TIME_NAME + ROW_ODD_NAME, styleOddDateTime); CellStyle styleEvenDateTime = cloneStyle(styleEven); styleEvenDateTime.setDataFormat(dateTimeFormatIndex); registerStyle(STYLE_DATE_TIME_NAME + ROW_EVEN_NAME, styleEvenDateTime); // styles pour les pourcentages short percentFormatIndex = dataFormat.getFormat(percentDataFormat); CellStyle styleOddPercent = cloneStyle(styleOdd); styleOddPercent.setDataFormat(percentFormatIndex); registerStyle(STYLE_PERCENT_NAME + ROW_ODD_NAME, styleOddPercent); CellStyle styleEvenPercent = cloneStyle(styleEven); styleEvenPercent.setDataFormat(percentFormatIndex); registerStyle(STYLE_PERCENT_NAME + ROW_EVEN_NAME, styleEvenPercent); short percentRelativeFormatIndex = dataFormat.getFormat(percentRelativeDataFormat); CellStyle styleOddPercentRelative = cloneStyle(styleOdd); styleOddPercentRelative.setDataFormat(percentRelativeFormatIndex); registerStyle(STYLE_PERCENT_RELATIVE_NAME + ROW_ODD_NAME, styleOddPercentRelative); CellStyle styleEvenPercentRelative = cloneStyle(styleEven); styleEvenPercentRelative.setDataFormat(percentRelativeFormatIndex); registerStyle(STYLE_PERCENT_RELATIVE_NAME + ROW_EVEN_NAME, styleEvenPercentRelative); // styles pour les liens CellStyle styleOddLink = cloneStyle(styleOdd); styleOddLink.setFont(getFont(FONT_LINK_NAME)); registerStyle(STYLE_LINK_NAME + ROW_ODD_NAME, styleOddLink); CellStyle styleEvenLink = cloneStyle(styleEven); styleEvenLink.setFont(getFont(FONT_LINK_NAME)); registerStyle(STYLE_LINK_NAME + ROW_EVEN_NAME, styleEvenLink); // styles pour les tailles de fichiers short fileSizeFormatIndex = dataFormat.getFormat(fileSizeDataFormat); CellStyle styleOddFileSize = cloneStyle(styleOdd); styleOddFileSize.setDataFormat(fileSizeFormatIndex); registerStyle(STYLE_FILE_SIZE_NAME + ROW_ODD_NAME, styleOddFileSize); CellStyle styleEvenFileSize = cloneStyle(styleEven); styleEvenFileSize.setDataFormat(fileSizeFormatIndex); registerStyle(STYLE_FILE_SIZE_NAME + ROW_EVEN_NAME, styleEvenFileSize); } /** * Ajoute une cellule texte. * * @param row ligne * @param columnIndex numéro de la colonne * @param text texte à insérer dans la cellule * @return cellule */ protected Cell addTextCell(Row row, int columnIndex, String text) { Cell cell = row.createCell(columnIndex); cell.setCellStyle(getRowStyle(STYLE_STANDARD_NAME, row.getRowNum())); cell.setCellType(Cell.CELL_TYPE_STRING); cell.setCellValue(creationHelper.createRichTextString(normalizeLineBreaks(text == null ? "" : text))); return cell; } /** * Ajoute une cellule formule. * * @param row ligne * @param columnIndex numéro de la colonne * @param formula formule à insérer dans la cellule * @return cellule */ protected Cell addFormulaCell(Row row, int columnIndex, String formula) { Cell cell = row.createCell(columnIndex); cell.setCellStyle(getRowStyle(STYLE_STANDARD_NAME, row.getRowNum())); cell.setCellType(Cell.CELL_TYPE_FORMULA); cell.setCellFormula(formula); return cell; } /** * Ajoute une cellule d'en-tête. * * @param row ligne * @param columnIndex numéro de la colonne * @param text texte à insérer dans la cellule * @return cellule */ protected Cell addHeaderCell(Row row, int columnIndex, String text) { Cell cell = row.createCell(columnIndex); cell.setCellStyle(getStyle(STYLE_HEADER_NAME)); cell.setCellType(Cell.CELL_TYPE_STRING); cell.setCellValue(creationHelper.createRichTextString(normalizeLineBreaks(text == null ? "" : text))); return cell; } /** * Unifie les retours à la ligne avant ajout du texte. */ protected String normalizeLineBreaks(String input) { if (input == null) { return null; } return input.replace("\r\n", "\n").replace("\r", "\n"); } /** * Ajoute une cellule au format date. * * @param row ligne * @param columnIndex numéro de la colonne * @param date date à insérer dans la cellule * @return cellule */ protected Cell addDateCell(Row row, int columnIndex, Date date) { Cell cell = row.createCell(columnIndex); cell.setCellStyle(getRowStyle(STYLE_DATE_NAME, row.getRowNum())); if (date != null) { cell.setCellValue(date); } return cell; } /** * Ajoute une cellule au format date + heure. * * @param row ligne * @param columnIndex numéro de la colonne * @param date date à insérer dans la cellule * @return cellule */ protected Cell addDateTimeCell(Row row, int columnIndex, Date date) { Cell cell = row.createCell(columnIndex); cell.setCellStyle(getRowStyle(STYLE_DATE_TIME_NAME, row.getRowNum())); if (date != null) { cell.setCellValue(date); } return cell; } /** * Ajoute une cellule contenant un nombre entier. * * @param row ligne * @param columnIndex numéro de la colonne * @param number nombre à insérer dans la cellule * @return cellule */ protected Cell addIntegerCell(Row row, int columnIndex, Number number) { Cell cell = row.createCell(columnIndex); cell.setCellType(Cell.CELL_TYPE_NUMERIC); cell.setCellStyle(getRowStyle(STYLE_INTEGER_NAME, row.getRowNum())); if (number != null) { cell.setCellValue(number.doubleValue()); } return cell; } /** * Ajoute une cellule contenant un nombre décimal. * * @param row ligne * @param columnIndex numéro de la colonne * @param number nombre à insérer dans la cellule * @return cellule */ protected Cell addDecimalCell(Row row, int columnIndex, Number number) { Cell cell = row.createCell(columnIndex); cell.setCellType(Cell.CELL_TYPE_NUMERIC); cell.setCellStyle(getRowStyle(STYLE_DECIMAL_NAME, row.getRowNum())); if (number != null) { cell.setCellValue(number.doubleValue()); } return cell; } /** * Ajoute une cellule contenant un pourcentage. * * @param row ligne * @param columnIndex numéro de la colonne * @param number nombre à insérer dans la cellule * @return cellule */ protected Cell addPercentCell(Row row, int columnIndex, Number number) { Cell cell = row.createCell(columnIndex); cell.setCellType(Cell.CELL_TYPE_NUMERIC); cell.setCellStyle(getRowStyle(STYLE_PERCENT_NAME, row.getRowNum())); if (number != null) { cell.setCellValue(number.doubleValue()); } return cell; } /** * Ajoute une cellule contenant un pourcentage avec signe +/-. * * @param row ligne * @param columnIndex numéro de la colonne * @param number nombre à insérer dans la cellule * @return cellule */ protected Cell addPercentRelativeCell(Row row, int columnIndex, Number number) { Cell cell = row.createCell(columnIndex); cell.setCellType(Cell.CELL_TYPE_NUMERIC); cell.setCellStyle(getRowStyle(STYLE_PERCENT_RELATIVE_NAME, row.getRowNum())); if (number != null) { cell.setCellValue(number.doubleValue()); } return cell; } /** * Ajoute un lien hypertexte sur la cellule. * * @param cell cellule * @param hyperlink lien à ajouter * @return cellule */ protected Cell addLinkToCell(Cell cell, Hyperlink hyperlink) { cell.setHyperlink(hyperlink); cell.setCellStyle(getRowStyle(STYLE_LINK_NAME, cell.getRowIndex())); return cell; } /** * Ajoute une cellule contenant une taille de fichier * * @param row ligne * @param columnIndex numéro de la colonne * @param fileSizeInBytes taille de fichier en octets * @return cellule */ protected Cell addFileSizeCell(Row row, int columnIndex, Long fileSizeInBytes) { Cell cell = row.createCell(columnIndex); cell.setCellType(Cell.CELL_TYPE_NUMERIC); cell.setCellStyle(getRowStyle(STYLE_FILE_SIZE_NAME, row.getRowNum())); if (fileSizeInBytes != null) { cell.setCellValue(fileSizeInBytes); } return cell; } /** * Ajoute plusieurs cellules vides stylées pour garder la cohérence des lignes odd/even * * @param row ligne * @param columnIndex numéro de la colonne */ protected List<Cell> addEmptyCells(Row row, int startColumnIndex, int nbCells) { List<Cell> cells = Lists.newArrayListWithExpectedSize(nbCells); for (int i = 0 ; i < nbCells ; ++i) { cells.add(addEmptyCell(row, startColumnIndex + i)); } return cells; } /** * Ajoute une cellule vide stylée pour garder la cohérence des lignes odd/even * * @param row ligne * @param columnIndex numéro de la colonne */ protected Cell addEmptyCell(Row row, int startColumnIndex) { return addTextCell(row, startColumnIndex, null); } protected void addIterableTextCell(Row row, int columnIndex, Iterable<String> iterable) { addTextCell(row, columnIndex, Joiners.onNewLine().join(iterable)); } /** * Retourne le style de la ligne en tenant compte des alternances de * couleurs pour les lignes paires/impaires. * * @param prefix prefixe du nom du style auquel est ajouté Even ou Odd * @param rowIndex numéro de la ligne * @return style à utiliser pour la ligne */ protected CellStyle getRowStyle(String prefix, int rowIndex) { StringBuilder styleName = new StringBuilder(prefix); if (rowIndex % 2 == 0) { styleName.append(ROW_EVEN_NAME); } else { styleName.append(ROW_ODD_NAME); } return getStyle(styleName.toString()); } /** * Ajoute les en-têtes dans la feuille de calcul. * * @param sheet feuille de calcul * @param rowIndex numéro de la ligne * @param headers en-têtes */ protected void addHeadersToSheet(Sheet sheet, int rowIndex, List<String> headers) { int columnIndex = 0; Row rowHeader = sheet.createRow(rowIndex); for (String header : headers) { addHeaderCell(rowHeader, columnIndex, getColumnLabel(header)); columnIndex++; } } /** * Ajoute les en-têtes dans la feuille de calcul et cache les colonnes qui doivent l'être, <strong>en utilisant la clé * de la map comme clé de ressource pour le header si {@code columnInformation.getHeaderKey()} est null</strong>. * * @param sheet feuille de calcul * @param rowIndex numéro de la ligne * @param columnInfos map contenant l'en-tête et les informations d'une colonne * * @deprecated Utiliser de préférence {@link #addHeadersToSheet(Sheet, int, Collection)}. */ @Deprecated protected void addHeadersToSheet(Sheet sheet, int rowIndex, Map<String, ColumnInformation> columnInfos) { int columnIndex = 0; Row rowHeader = sheet.createRow(rowIndex); for (Entry<String, ColumnInformation> entry : columnInfos.entrySet()) { ColumnInformation columnInformation = entry.getValue(); sheet.setColumnHidden(columnIndex, columnInformation.isHidden()); addHeaderCell(rowHeader, columnIndex, getColumnLabel(columnInformation.getHeaderKey() != null ? columnInformation.getHeaderKey() : entry.getKey())); columnIndex++; } } /** * Ajoute les en-têtes dans la feuille de calcul et cache les colonnes qui doivent l'être. * * @param sheet feuille de calcul * @param rowIndex numéro de la ligne * @param columnInfos collection contenant les informations de colonnes */ protected void addHeadersToSheet(Sheet sheet, int rowIndex, Collection<ColumnInformation> columnInfos) { int columnIndex = 0; Row rowHeader = sheet.createRow(rowIndex); for (ColumnInformation columnInformation : columnInfos) { sheet.setColumnHidden(columnIndex, columnInformation.isHidden()); addHeaderCell(rowHeader, columnIndex, getColumnLabel(columnInformation.getHeaderKey())); columnIndex++; } } /** * Ajoute les en-têtes dans la feuille de calcul et cache les colonnes qui doivent l'être. * * @param sheet feuille de calcul * @param rowIndex numéro de la ligne * @param columnInfos RangeMap contenant les informations de colonnes (valeurs) et les index sur auxquelles s'appliquent ces colonnes (clés). * Les "colonnes" s'étendant sur plus d'un index seront automatiquement fusionnées. */ protected void addHeadersToSheet(Sheet sheet, int rowIndex, RangeMap<Integer, ColumnInformation> columnInfos) { Row rowHeader = sheet.createRow(rowIndex); for (Map.Entry<Range<Integer>, ColumnInformation> entry : columnInfos.asMapOfRanges().entrySet()) { Range<Integer> range = entry.getKey(); ColumnInformation columnInformation = entry.getValue(); addHeaderCell(rowHeader, range.lowerEndpoint(), getColumnLabel(columnInformation.getHeaderKey())); for (Integer columnIndex : ContiguousSet.create(range, DiscreteDomain.integers())) { sheet.setColumnHidden(columnIndex, columnInformation.isHidden()); } int beginIndex = range.lowerEndpoint(); int endIndex = range.upperEndpoint(); if (beginIndex != endIndex) { sheet.addMergedRegion(new CellRangeAddress(rowIndex, rowIndex, beginIndex, endIndex)); } } } protected void finalizeSheet(Sheet sheet, List<String> headers) { // Par défaut, le format d'impression est en paysage pour les tableaux Excel finalizeSheet(sheet, headers, true); } /** * Finalise la création de la feuille de calcul, notamment en demandant le * redimensionnement automatique des colonnes. * * @param sheet feuilles de calcul * @param headers en-têtes * @param landscapePrintSetup définit si la feuille est imprimée en paysage ou non */ protected void finalizeSheet(Sheet sheet, List<String> headers, boolean landscapePrintSetup) { int nbColumns = headers.size(); for (int i = 0; i < nbColumns; i++) { sheet.autoSizeColumn(i); int columnWidth = (int) (sheet.getColumnWidth(i) * COLUMN_RESIZE_RATIO); sheet.setColumnWidth(i, columnWidth < ABSOLUTE_MAX_COLUMN_WIDTH ? columnWidth : ABSOLUTE_MAX_COLUMN_WIDTH); } finalizeSheet(sheet, landscapePrintSetup); } /** * @deprecated Utiliser de préférence {@link #finalizeSheet(Sheet, Collection)}. */ @Deprecated protected void finalizeSheet(Sheet sheet, Map<String, ColumnInformation> columnInfos) { finalizeSheet(sheet, columnInfos.values()); } /** * @deprecated Utiliser de préférence {@link #finalizeSheet(Sheet, Collection, boolean)}. */ @Deprecated protected void finalizeSheet(Sheet sheet, Map<String, ColumnInformation> columnInfos, boolean landscapePrintSetup) { finalizeSheet(sheet, columnInfos.values(), landscapePrintSetup); } /** * @see #finalizeSheet(Sheet, Collection, boolean) */ protected void finalizeSheet(Sheet sheet, Collection<ColumnInformation> columnInfos) { // Par défaut, le format d'impression est en paysage pour les tableaux Excel finalizeSheet(sheet, columnInfos, true); } /** * Finalise la création de la feuille de calcul, notamment en demandant le * redimensionnement automatique des colonnes. * * @param sheet feuilles de calcul * @param columnInfos collection contenant les informations de colonnes * @param landscapePrintSetup définit si la feuille est imprimée en paysage ou non */ protected void finalizeSheet(Sheet sheet, Collection<ColumnInformation> columnInfos, boolean landscapePrintSetup) { RangeMap<Integer, ColumnInformation> map = TreeRangeMap.create(); int index = 0; for (ColumnInformation column : columnInfos) { map.put(Range.singleton(index), column); ++index; } finalizeSheet(sheet, map, landscapePrintSetup); } /** * @see #finalizeSheet(Sheet, RangeMap, boolean) */ protected void finalizeSheet(Sheet sheet, RangeMap<Integer, ColumnInformation> columnInfos) { // Par défaut, le format d'impression est en paysage pour les tableaux Excel finalizeSheet(sheet, columnInfos, true); } /** * Finalise la création de la feuille de calcul, notamment en demandant le * redimensionnement automatique des colonnes. * * @param sheet feuilles de calcul * @param columnInfos map contenant l'en-tête et les informations d'une colonne * @param landscapePrintSetup définit si la feuille est imprimée en paysage ou non */ protected void finalizeSheet(Sheet sheet, RangeMap<Integer, ColumnInformation> columnInfos, boolean landscapePrintSetup) { for (Map.Entry<Range<Integer>, ColumnInformation> entry : columnInfos.asMapOfRanges().entrySet()) { ColumnInformation columnInformation = entry.getValue(); Range<Integer> range = entry.getKey(); int beginIndex = range.lowerEndpoint(); int endIndex = range.upperEndpoint(); // Détermination de la taille maximum de cette colonne int maxColumnWidth; if (columnInformation.getColumnMaxWidth() != -1) { maxColumnWidth = columnInformation.getColumnMaxWidth(); } else { maxColumnWidth = ABSOLUTE_MAX_COLUMN_WIDTH; } // Détermination de la taille souhaitée pour la colonne if (columnInformation.getColumnWidth() != -1) { // On force la taille des colonnes en fonction de la columnInformation int columnWidth = columnInformation.getColumnWidth(); columnWidth = Math.min(columnWidth, maxColumnWidth); // On prend en compte le fait que la "colonne" peut s'étendre en fait sur plusieurs colonnes (fusion de cellules au niveau du header) int columnSpan = endIndex - beginIndex + 1; columnWidth = columnWidth / columnSpan; // On redimmensionne les colonnes for (int columnIndex = beginIndex ; columnIndex <= endIndex ; ++columnIndex) { sheet.setColumnWidth(columnIndex, columnWidth); } } else { // On redimmensionne les colonnes une à une en prennant leur taille actuelle et en les augmentant un petit peu for (int columnIndex = beginIndex ; columnIndex <= endIndex ; ++columnIndex) { sheet.autoSizeColumn(columnIndex); int columnWidth = (int) (sheet.getColumnWidth(beginIndex) * COLUMN_RESIZE_RATIO); columnWidth = Math.min(columnWidth, maxColumnWidth); sheet.setColumnWidth(columnIndex, columnWidth); } } } finalizeSheet(sheet, landscapePrintSetup); } protected void finalizeSheet(Sheet sheet, boolean landscapePrintSetup) { sheet.getPrintSetup().setLandscape(landscapePrintSetup); sheet.setAutobreaks(true); sheet.getPrintSetup().setFitWidth((short) 1); sheet.getPrintSetup().setFitHeight((short) 10000); } /** * @deprecated Utiliser de préférence {@link #resizeMergedColumns(Sheet, Collection)}. */ @Deprecated protected void resizeMergedColumns(Sheet sheet, Map<String, ColumnInformation> columns) { resizeMergedColumns(sheet, columns.values()); } /** * Redimensionne les colonnes qui contiennent des régions fusionnées. * * Dans POI, les régions fusionnées ne sont pas prises en compte dans le autoSizeColumn. * Quand on fusionne des cellules sur une même colonne, on corrige la taille de cette colonne si nécessaire. * * @param sheet feuille de calcul * @param columns map contenant l'en-tête et les informations d'une colonne */ protected void resizeMergedColumns(Sheet sheet, Collection<ColumnInformation> columns) { if (sheet.getNumMergedRegions() > 0) { List<ColumnInformation> columnsInfo = new ArrayList<ColumnInformation>(columns); for (int i = 0; i < sheet.getNumMergedRegions(); i++) { CellRangeAddress mergedRegion = sheet.getMergedRegion(i); if (mergedRegion.getFirstColumn() == mergedRegion.getLastColumn()) { int columnIndex = mergedRegion.getFirstColumn(); String headerText = getColumnLabel(columnsInfo.get(columnIndex).getHeaderKey()); int headerSize = (int) (headerText.length() * 300 * COLUMN_RESIZE_RATIO); if (sheet.getColumnWidth(columnIndex) < headerSize) { sheet.setColumnWidth(columnIndex, headerSize); } } } } } /** * Retourne le message correspondant à la clé en fonction du Locale * * @param key clé * @return message */ protected abstract String getLocalizedLabel(String key); /** * Peut être surchargé pour permettre, par exemple, de considérer la "headerKey" comme le libellé déjà localisé. */ protected String getColumnLabel(String headerKey) { return getLocalizedLabel(headerKey); } public String getFontName() { return fontName; } public void setFontName(String fontName) { this.fontName = fontName; } public short getNormalFontHeight() { return normalFontHeight; } public void setNormalFontHeight(short normalFontHeight) { this.normalFontHeight = normalFontHeight; } public short getHeaderFontHeight() { return headerFontHeight; } public void setHeaderFontHeight(short headerFontHeight) { this.headerFontHeight = headerFontHeight; } public String getBorderColor() { return borderColor; } public void setBorderColor(String borderColor) { this.borderColor = borderColor; } public String getHeaderBackgroundColor() { return headerBackgroundColor; } public void setHeaderBackgroundColor(String headerBackgroundColor) { this.headerBackgroundColor = headerBackgroundColor; } public String getHeaderFontColor() { return headerFontColor; } public void setHeaderFontColor(String headerFontColor) { this.headerFontColor = headerFontColor; } public String getLinkFontColor() { return linkFontColor; } public void setLinkFontColor(String linkFontColor) { this.linkFontColor = linkFontColor; } public String getEvenRowBackgroundColor() { return evenRowBackgroundColor; } public void setEvenRowBackgroundColor(String evenRoxBackgroundColor) { this.evenRowBackgroundColor = evenRoxBackgroundColor; } public String getIntegerDataFormat() { return integerDataFormat; } public void setIntegerDataFormat(String numericDataFormat) { this.integerDataFormat = numericDataFormat; } public String getDecimalDataFormat() { return decimalDataFormat; } public void setDecimalDataFormat(String decimalDataFormat) { this.decimalDataFormat = decimalDataFormat; } public String getDateDataFormat() { return dateDataFormat; } public void setDateDataFormat(String dateDataFormat) { this.dateDataFormat = dateDataFormat; } public String getDateTimeDataFormat() { return dateTimeDataFormat; } public void setDateTimeDataFormat(String dateTimeDataFormat) { this.dateTimeDataFormat = dateTimeDataFormat; } public String getPercentDataFormat() { return percentDataFormat; } public void setPercentDataFormat(String percentDataFormat) { this.percentDataFormat = percentDataFormat; } }