All Downloads are FREE. Search and download functionalities are using the official Maven repository.

uk.co.spudsoft.birt.emitters.excel.StyleManagerUtils Maven / Gradle / Ivy

There is a newer version: 4.17.0.0
Show newest version
/*************************************************************************************
 * Copyright (c) 2011, 2012, 2013 James Talbut.
 *  [email protected]
 *
 *
 * This program and the accompanying materials are made available under the
 * terms of the Eclipse Public License 2.0 which is available at
 * https://www.eclipse.org/legal/epl-2.0/.
 *
 * SPDX-License-Identifier: EPL-2.0
 *
 * Contributors:
 *     James Talbut - Initial implementation.
 ************************************************************************************/

package uk.co.spudsoft.birt.emitters.excel;

import java.awt.font.FontRenderContext;
import java.awt.font.LineBreakMeasurer;
import java.awt.font.TextAttribute;
import java.awt.font.TextLayout;
import java.awt.font.TextMeasurer;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.URLConnection;
import java.text.AttributedString;
import java.text.DateFormat;
import java.util.Collection;
import java.util.List;
import java.util.Locale;

import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.CellStyle;
import org.apache.poi.ss.usermodel.CellType;
import org.apache.poi.ss.usermodel.DataFormat;
import org.apache.poi.ss.usermodel.FillPatternType;
import org.apache.poi.ss.usermodel.Font;
import org.apache.poi.ss.usermodel.HorizontalAlignment;
import org.apache.poi.ss.usermodel.PrintSetup;
import org.apache.poi.ss.usermodel.RichTextString;
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 org.apache.poi.xssf.usermodel.extensions.XSSFCellBorder.BorderSide;
import org.eclipse.birt.report.engine.content.IPageContent;
import org.eclipse.birt.report.engine.css.engine.StyleConstants;
import org.eclipse.birt.report.engine.css.engine.value.DataFormatValue;
import org.eclipse.birt.report.engine.css.engine.value.StringValue;
import org.eclipse.birt.report.engine.css.engine.value.css.CSSConstants;
import org.eclipse.birt.report.engine.ir.DimensionType;
import org.eclipse.birt.report.model.api.util.ColorUtil;
import org.w3c.dom.css.CSSPrimitiveValue;
import org.w3c.dom.css.CSSValue;

import uk.co.spudsoft.birt.emitters.excel.framework.Logger;

/**
 * 

* StyleManagerUtils contains methods implementing the details of converting * BIRT styles to POI styles. *

*

* StyleManagerUtils is abstract to support a small number of methods that * require HSSF/XSSF specific implementations. * * @author Jim Talbut * */ public abstract class StyleManagerUtils { protected Logger log; protected static final FontRenderContext frc = new FontRenderContext(null, true, true); /** * Constructor of factory interface * * @since 3.3 * */ public interface Factory { /** * @param log * @return Return a style manager util object */ StyleManagerUtils create(Logger log); } /** * @param log The Logger to use for any information reports to be made. */ public StyleManagerUtils(Logger log) { this.log = log; } /** * Create a RichTextString representing a given string. * * @param value The string to represent in the RichTextString. * @return A RichTextString representing value. */ public abstract RichTextString createRichTextString(String value); /** * Compare two objects in a null-safe manner. * * @param lhs The first object to compare. * @param rhs The second object to compare. * @return true is both objects are null or lhs.equals(rhs), otherwise false. */ public static boolean objectsEqual(Object lhs, Object rhs) { return (lhs == null) ? (rhs == null) : lhs.equals(rhs); } /** * Compare date formats * * @param dataFormat1 date format 1 * @param dataFormat2 date format 2 * @return Retun the result of the date format compare */ public static boolean dataFormatsEquivalent(DataFormatValue dataFormat1, DataFormatValue dataFormat2) { if (dataFormat1 == null) { return (dataFormat2 == null); } if (dataFormat2 == null) { return false; } if (!objectsEqual(dataFormat1.getNumberPattern(), dataFormat2.getNumberPattern()) || !objectsEqual(dataFormat1.getDatePattern(), dataFormat2.getDatePattern()) || !objectsEqual(dataFormat1.getDateTimePattern(), dataFormat2.getDateTimePattern()) || !objectsEqual(dataFormat1.getTimePattern(), dataFormat2.getTimePattern())) { return false; } return true; } /** * Convert a BIRT text alignment string into a POI CellStyle constant. * * @param alignment The BIRT alignment string. * @return One of the CellStyle.ALIGN* constants. */ public HorizontalAlignment poiAlignmentFromBirtAlignment(String alignment) { if (CSSConstants.CSS_LEFT_VALUE.equals(alignment)) { return HorizontalAlignment.LEFT; // CellStyle.ALIGN_LEFT; } if (CSSConstants.CSS_RIGHT_VALUE.equals(alignment)) { return HorizontalAlignment.RIGHT; // CellStyle.ALIGN_RIGHT; } if (CSSConstants.CSS_CENTER_VALUE.equals(alignment)) { return HorizontalAlignment.CENTER; // CellStyle.ALIGN_CENTER; } return HorizontalAlignment.GENERAL; // CellStyle.ALIGN_GENERAL; } /** * Convert a BIRT font size string (either a dimensioned string or "xx-small" - * "xx-large") to a point size. * * @param fontSize The BIRT font size. * @return An appropriate size in points. */ public short fontSizeInPoints(String fontSize) { if (fontSize == null) { return 11; } if ("xx-small".equals(fontSize)) { return 6; } else if ("x-small".equals(fontSize)) { return 8; } else if ("small".equals(fontSize)) { return 10; } else if ("medium".equals(fontSize)) { return 11; } else if ("large".equals(fontSize)) { return 14; } else if ("x-large".equals(fontSize)) { return 18; } else if ("xx-large".equals(fontSize)) { return 24; } else if ("smaller".equals(fontSize)) { return 10; } else if ("larger".equals(fontSize)) { return 14; } DimensionType dim = DimensionType.parserUnit(fontSize, "pt"); // log.debug( "fontSize: \"", fontSize, "\", parses as: \"", dim.toString(), "\" // (", dim.getMeasure(), " ", dim.getUnits(), ")"); if (DimensionType.UNITS_PX.equals(dim.getUnits())) { double px = dim.getMeasure(); double inches = px / 96; double points = 72 * inches; return (short) points; } else if (DimensionType.UNITS_EM.equals(dim.getUnits())) { return (short) (12 * dim.getMeasure()); } else if (DimensionType.UNITS_PERCENTAGE.equals(dim.getUnits())) { return (short) (12 * dim.getMeasure() / 100.0); } else { double points = dim.convertTo(DimensionType.UNITS_PT); return (short) points; } } /** * Obtain a POI column width from a BIRT DimensionType. * * @param dim The BIRT dimension, which must be in absolute units. * @return The column with in width units, or zero if a suitable conversion * could not be performed. */ public int poiColumnWidthFromDimension(DimensionType dim) { if (dim != null) { double mmWidth = dim.getMeasure(); if ((DimensionType.UNITS_CM.equals(dim.getUnits())) || (DimensionType.UNITS_IN.equals(dim.getUnits())) || (DimensionType.UNITS_PT.equals(dim.getUnits())) || (DimensionType.UNITS_PC.equals(dim.getUnits())) ) { mmWidth = dim.convertTo("mm"); } else if ((DimensionType.UNITS_PX.equals(dim.getUnits()))) { mmWidth = ClientAnchorConversions.pixels2Millimetres(mmWidth); } int result = ClientAnchorConversions.millimetres2WidthUnits(mmWidth); // log.debug( "Column width in mm: ", mmWidth, "; converted result: ", result ); return result; } return 0; } /** * Calculation of millimetres based on dimension * * @param dim The BIRT dimension, which must be in absolute units. * @return The calculated millimetres unit */ public double convertDimensionToMillimetres(DimensionType dim) { if (dim != null) { double mmWidth = dim.getMeasure(); if ((DimensionType.UNITS_CM.equals(dim.getUnits())) || (DimensionType.UNITS_IN.equals(dim.getUnits())) || (DimensionType.UNITS_PT.equals(dim.getUnits())) || (DimensionType.UNITS_PC.equals(dim.getUnits()))) { mmWidth = dim.convertTo("mm"); } else if ((DimensionType.UNITS_PX.equals(dim.getUnits()))) { mmWidth = ClientAnchorConversions.pixels2Millimetres(mmWidth); } return mmWidth; } return 0; } /** * Converting from millimetres to indent width * * @param mmWidth The BIRT millimetres * @return The calculated indent with unit */ public int poiIndentUnit(double mmWidth) { return ClientAnchorConversions.millimetres2IndentUnits(mmWidth); } /** * Converting from millimetres to indent width * * @param dim The BIRT dimension millimetres * @return The calculated indent with unit */ public int poiIndentUnit(DimensionType dim) { if (dim != null) { double mmWidth = dim.getMeasure(); if (DimensionType.UNITS_MM.equals(dim.getUnits())) { return ClientAnchorConversions.millimetres2IndentUnits(mmWidth); } } return 0; } /** * Object a POI font weight from a BIRT string. * * @param fontWeight The font weight as understood by BIRT. * @return One of the Font.BOLDWEIGHT_* constants. */ public boolean poiFontWeightFromBirt(String fontWeight) { if (fontWeight == null) { return false; // 0; } if ("bold".equals(fontWeight)) { return true; // Font.BOLDWEIGHT_BOLD; } return false; // Font.BOLDWEIGHT_NORMAL; } /** * Convert a BIRT font name into a system font name.
* Just returns the passed in name unless that is a known family name ("serif" * or "sans-serif"). * * @param fontName The font name from BIRT. * @return A real font name. */ public String poiFontNameFromBirt(String fontName) { if ("serif".equals(fontName)) { return "Times New Roman"; } else if ("sans-serif".equals(fontName)) { return "Arial"; } else if ("monospace".equals(fontName)) { return "Courier New"; } return fontName; } /** *

* Add a colour (specified as "rgb(r, g, b)") to a Font. *

*

* In the current implementations the XSSF implementation will always produce * exactly the right colour, whilst the HSSF implementation takes the best * approximation from the current palette. * * @param workbook The workbook in which the Font is to be used, needed to * obtain the colour palette. * @param font The font to which the colour is to be added. * @param colour The colour to add. */ public abstract void addColourToFont(Workbook workbook, Font font, String colour); /** *

* Add a colour (specified as "rgb(r, g, b)") as the * background colour of a CellStyle. *

*

* In the current implementations the XSSF implementation will always produce * exactly the right colour, whilst the HSSF implementation takes the best * approximation from the current palette. * * @param workbook The workbook in which the Font is to be used, needed to * obtain the colour palette. * @param style The style to which the colour is to be added. * @param colour The colour to add. */ public abstract void addBackgroundColourToStyle(Workbook workbook, CellStyle style, String colour); /** * Check whether a cell is empty and unformatted. * * @param cell The cell to consider. * @return true is the cell is empty and has no style or has no background fill. */ public static boolean cellIsEmpty(Cell cell) { // if (cell.getCellType() != Cell.CELL_TYPE_BLANK) { if (!CellType.BLANK.equals(cell.getCellType())) { return false; } CellStyle cellStyle = cell.getCellStyle(); // if (cellStyle.getFillPattern() == CellStyle.NO_FILL) { if ((cellStyle == null) || FillPatternType.NO_FILL.equals(cellStyle.getFillPattern())) { return true; } return false; } /** * Apply a BIRT border style to one side of a POI CellStyle usage: xls-format / * StyleManagerHUtils * * @param workbook The workbook that contains the cell being styled. * @param style The POI CellStyle that is to have the border applied to * it. * @param side The side of the border that is to be applied.
* Note that although this value is from XSSFCellBorder it is * equally valid for HSSFCellStyles. * @param colour The colour for the new border. * @param borderStyle The BIRT style for the new border. * @param width The width of the new border. */ public abstract void applyBorderStyle(Workbook workbook, CellStyle style, BorderSide side, CSSValue colour, CSSValue borderStyle, CSSValue width); /** * Apply a BIRT border style to one side of a POI CellStyle. usage: xlsx-format * / StyleManagerXUtils * * @param workbook The workbook that contains the cell being styled. * @param style The POI CellStyle that is to have the border applied to it. * @param birtStyle birt cell style with all border information * @since 4.13 */ public abstract void applyBorderStyle(Workbook workbook, CellStyle style, BirtStyle birtStyle); /** *

* Convert a MIME string into a Workbook.PICTURE* constant. *

*

* In some cases BIRT fails to submit a MIME string, in which case this method * falls back to basic data signatures for JPEG and PNG images. *

* * @param mimeType The MIME type. * @param data The image data to consider if no recognisable MIME type is * provided. * @return A Workbook.PICTURE* constant. */ public int poiImageTypeFromMimeType(String mimeType, byte[] data) { if ("image/jpeg".equals(mimeType)) { return Workbook.PICTURE_TYPE_JPEG; } else if ("image/png".equals(mimeType)) { return Workbook.PICTURE_TYPE_PNG; } else if ("image/bmp".equals(mimeType)) { return Workbook.PICTURE_TYPE_DIB; } else { if (null != data) { log.debug("Data bytes: " + " " + Integer.toHexString(data[0]).toUpperCase() + " " + Integer.toHexString(data[1]).toUpperCase() + " " + Integer.toHexString(data[2]).toUpperCase() + " " + Integer.toHexString(data[3]).toUpperCase()); if ((data.length > 2) && (data[0] == (byte) 0xFF) && (data[1] == (byte) 0xD8) && (data[2] == (byte) 0xFF)) { return Workbook.PICTURE_TYPE_JPEG; } if ((data.length > 4) && (data[0] == (byte) 0x89) && (data[1] == (byte) 'P') && (data[2] == (byte) 'N') && (data[3] == (byte) 'G')) { return Workbook.PICTURE_TYPE_PNG; } } return 0; } } /** * Read an InputStream in full and put the results into a byte[].
* This is needed by the emitter to handle images accessed by URL. * * @param stream The InputStream to read. * @param length The length of the InputStream * @return A byte array containing the contents of the InputStream. * @throws IOException */ public byte[] streamToByteArray(InputStream stream, int length) throws IOException { ByteArrayOutputStream buffer; if (length > 0) { buffer = new ByteArrayOutputStream(length); } else { buffer = new ByteArrayOutputStream(); } int nRead; byte[] data = new byte[16384]; while ((nRead = stream.read(data, 0, data.length)) != -1) { buffer.write(data, 0, nRead); } buffer.flush(); return buffer.toByteArray(); } /** * Read an image from a URLConnection into a byte array. * * @param conn The URLConnection to provide the data. * @return A byte array containing the data downloaded from the URL. */ public byte[] downloadImage(URLConnection conn) { try { int contentLength = conn.getContentLength(); InputStream imageStream = conn.getInputStream(); try (imageStream) { return streamToByteArray(imageStream, contentLength); } } catch (IOException ex) { log.debug(ex.getClass(), ": ", ex.getMessage()); return null; } } /** * Convert a BIRT paper size string into a POI PrintSetup.*PAPERSIZE constant. * * @param name The paper size as a BIRT string. * @return A POI PrintSetup.*PAPERSIZE constant. */ public short getPaperSizeFromString(String name) { if ("a4".equals(name)) { return PrintSetup.A4_PAPERSIZE; } else if ("a3".equals(name)) { return PrintSetup.A3_PAPERSIZE; } else if ("us-letter".equals(name)) { return PrintSetup.LETTER_PAPERSIZE; } return PrintSetup.A4_PAPERSIZE; } /** * Check whether a DimensionType represents an absolute (physical) dimension. * * @param dim The DimensionType to consider. * @return true if dim represents an absolute measurement. */ public boolean isAbsolute(DimensionType dim) { if (dim == null) { return false; } String units = dim.getUnits(); return DimensionType.UNITS_CM.equals(units) || DimensionType.UNITS_IN.equals(units) || DimensionType.UNITS_MM.equals(units) || DimensionType.UNITS_PT.equals(units) || DimensionType.UNITS_PC.equals(units); } /** * Check whether a DimensionType represents pixels. * * @param dim The DimensionType to consider. * @return true if dim represents pixels. */ public boolean isPixels(DimensionType dim) { return (dim != null) && DimensionType.UNITS_PX.equals(dim.getUnits()); } /** *

* Convert a BIRT number format to a POI data format. *

*

* There is no way this function is complete! More special cases will be added * as they are found. *

* * @param birtFormat A string representing a number format in BIRT. * @return A string representing a data format in Excel. */ private String poiNumberFormatFromBirt(String birtFormat) { if ("General Number".equalsIgnoreCase(birtFormat)) { return null; } if (birtFormat.startsWith(ExcelEmitter.CUSTOM_NUMBER_FORMAT)) { return birtFormat.substring(ExcelEmitter.CUSTOM_NUMBER_FORMAT.length()); } birtFormat = birtFormat.replace("E00", "E+00"); birtFormat = birtFormat.replaceAll("^([^0#.\\-,E;%\u2030\u00A4']*)", "\"$1\""); int brace = birtFormat.indexOf('{'); if (brace >= 0) { birtFormat = birtFormat.substring(0, brace); } return birtFormat; } /** *

* Convert a BIRT date/time format to a POI data format. *

*

* This function is likely to be more complete than poiNumberFormatFromBirt, but * it is still likely to have issues. More special cases will be added as they * are found. *

* * @param birtFormat A string representing a date/time format in BIRT. * @return A string representing a data format in Excel. */ private String poiDateTimeFormatFromBirt(String birtFormat, Locale locale) { if ("General Date".equalsIgnoreCase(birtFormat)) { birtFormat = DateFormatConverter.getJavaDateTimePattern(DateFormat.LONG, locale); } if ("Long Date".equalsIgnoreCase(birtFormat)) { birtFormat = DateFormatConverter.getJavaDatePattern(DateFormat.LONG, locale); } if ("Medium Date".equalsIgnoreCase(birtFormat)) { birtFormat = DateFormatConverter.getJavaDatePattern(DateFormat.MEDIUM, locale); } if ("Short Date".equalsIgnoreCase(birtFormat)) { birtFormat = DateFormatConverter.getJavaDatePattern(DateFormat.SHORT, locale); } if ("Long Time".equalsIgnoreCase(birtFormat)) { birtFormat = DateFormatConverter.getJavaTimePattern(DateFormat.LONG, locale); } if ("Medium Time".equalsIgnoreCase(birtFormat)) { birtFormat = DateFormatConverter.getJavaTimePattern(DateFormat.MEDIUM, locale); } if ("Short Time".equalsIgnoreCase(birtFormat)) { birtFormat = "kk:mm"; // DateFormatConverter.getJavaTimePattern(DateFormat.SHORT, locale); } return DateFormatConverter.convert(locale, birtFormat); } /** * Get number format * * @param style birt style * @return Return the number format */ public static String getNumberFormat(BirtStyle style) { CSSValue dataFormat = style.getProperty(StyleConstants.STYLE_DATA_FORMAT); if (dataFormat instanceof DataFormatValue) { DataFormatValue dataFormatValue = (DataFormatValue) dataFormat; return dataFormatValue.getNumberPattern(); } return null; } /** * Get date format * * @param style birt style * @return Return the date format */ public static String getDateFormat(BirtStyle style) { CSSValue dataFormat = style.getProperty(StyleConstants.STYLE_DATA_FORMAT); if (dataFormat instanceof DataFormatValue) { DataFormatValue dataFormatValue = (DataFormatValue) dataFormat; return dataFormatValue.getDatePattern(); } return null; } /** * Get date time format * * @param style birt style * @return Return the date time format */ public static String getDateTimeFormat(BirtStyle style) { CSSValue dataFormat = style.getProperty(StyleConstants.STYLE_DATA_FORMAT); if (dataFormat instanceof DataFormatValue) { DataFormatValue dataFormatValue = (DataFormatValue) dataFormat; return dataFormatValue.getDateTimePattern(); } return null; } /** * Get time format * * @param style birt style * @return Return the time format */ public static String getTimeFormat(BirtStyle style) { CSSValue dataFormat = style.getProperty(StyleConstants.STYLE_DATA_FORMAT); if (dataFormat instanceof DataFormatValue) { DataFormatValue dataFormatValue = (DataFormatValue) dataFormat; return dataFormatValue.getTimePattern(); } return null; } /** * Clone the date format * * @param dataValue date format value * @return Return the cloned date format value */ public static DataFormatValue cloneDataFormatValue(DataFormatValue dataValue) { DataFormatValue newValue = new DataFormatValue(); newValue.setDateFormat(dataValue.getDatePattern(), dataValue.getDateLocale()); newValue.setDateTimeFormat(dataValue.getDateTimePattern(), dataValue.getDateTimeLocale()); newValue.setTimeFormat(dataValue.getTimePattern(), dataValue.getTimeLocale()); newValue.setNumberFormat(dataValue.getNumberPattern(), dataValue.getNumberLocale()); newValue.setStringFormat(dataValue.getStringPattern(), dataValue.getStringLocale()); return newValue; } /** * Set the number format * * @param style birt style * @param pattern pattern of format * @param locale locale */ public static void setNumberFormat(BirtStyle style, String pattern, String locale) { DataFormatValue dfv = (DataFormatValue) style.getProperty(StyleConstants.STYLE_DATA_FORMAT); if (dfv == null) { dfv = new DataFormatValue(); } else { dfv = cloneDataFormatValue(dfv); } dfv.setNumberFormat(pattern, locale); style.setProperty(StyleConstants.STYLE_DATA_FORMAT, dfv); } /** * Set the date format * * @param style birt style * @param pattern pattern of format * @param locale locale */ public static void setDateFormat(BirtStyle style, String pattern, String locale) { DataFormatValue dfv = (DataFormatValue) style.getProperty(StyleConstants.STYLE_DATA_FORMAT); if (dfv == null) { dfv = new DataFormatValue(); } else { dfv = cloneDataFormatValue(dfv); } dfv.setDateFormat(pattern, locale); style.setProperty(StyleConstants.STYLE_DATA_FORMAT, dfv); } /** * Set the date time format * * @param style birt style * @param pattern pattern of format * @param locale locale */ public static void setDateTimeFormat(BirtStyle style, String pattern, String locale) { DataFormatValue dfv = (DataFormatValue) style.getProperty(StyleConstants.STYLE_DATA_FORMAT); if (dfv == null) { dfv = new DataFormatValue(); } else { dfv = cloneDataFormatValue(dfv); } dfv.setDateTimeFormat(pattern, locale); style.setProperty(StyleConstants.STYLE_DATA_FORMAT, dfv); } /** * Set the time format * * @param style birt style * @param pattern pattern of format * @param locale locale */ public static void setTimeFormat(BirtStyle style, String pattern, String locale) { DataFormatValue dfv = (DataFormatValue) style.getProperty(StyleConstants.STYLE_DATA_FORMAT); if (dfv == null) { dfv = new DataFormatValue(); } else { dfv = cloneDataFormatValue(dfv); } dfv.setTimeFormat(pattern, locale); style.setProperty(StyleConstants.STYLE_DATA_FORMAT, dfv); } /** * Apply a BIRT number/date/time format to a POI CellStyle. * * @param workbook The workbook containing the CellStyle (needed to create a * new DataFormat). * @param birtStyle The BIRT style which may contain a number format. * @param poiStyle The CellStyle that is to receive the number format. * @param locale Locale */ public void applyNumberFormat(Workbook workbook, BirtStyle birtStyle, CellStyle poiStyle, Locale locale) { String dataFormat = null; String format = getNumberFormat(birtStyle); if (format != null) { log.debug("BIRT number format == ", format); dataFormat = poiNumberFormatFromBirt(format); } else { format = getDateTimeFormat(birtStyle); if (format != null) { log.debug("BIRT date/time format == ", format); dataFormat = poiDateTimeFormatFromBirt(format, locale); } else { format = getTimeFormat(birtStyle); if (format != null) { log.debug("BIRT time format == ", format); dataFormat = poiDateTimeFormatFromBirt(format, locale); } else { format = getDateFormat(birtStyle); if (format != null) { log.debug("BIRT date format == ", format); dataFormat = poiDateTimeFormatFromBirt(format, locale); } } } } if (dataFormat != null) { DataFormat poiFormat = workbook.createDataFormat(); log.debug("Setting POI data format to ", dataFormat); poiStyle.setDataFormat(poiFormat.getFormat(dataFormat)); } } /** * Add font details to an AttributedString. * * @param attrString The AttributedString to modify. * @param font The font to take attributes from. * @param startIdx The index of the first character to be attributed * (inclusive). * @param endIdx The index of the last character to be attributed * (inclusive). */ protected void addFontAttributes(AttributedString attrString, Font font, int startIdx, int endIdx) { attrString.addAttribute(TextAttribute.FAMILY, font.getFontName(), startIdx, endIdx); attrString.addAttribute(TextAttribute.SIZE, (float) font.getFontHeightInPoints(), startIdx, endIdx); // if (font.getBoldweight() == Font.BOLDWEIGHT_BOLD) if (font.getBold()) { attrString.addAttribute(TextAttribute.WEIGHT, TextAttribute.WEIGHT_BOLD, startIdx, endIdx); } if (font.getItalic()) { attrString.addAttribute(TextAttribute.POSTURE, TextAttribute.POSTURE_OBLIQUE, startIdx, endIdx); } if (font.getUnderline() == Font.U_SINGLE) { attrString.addAttribute(TextAttribute.UNDERLINE, TextAttribute.UNDERLINE_ON, startIdx, endIdx); } } /** * Find a RichTextRun that includes a specific index. * * @param richTextRuns The list of RichTextRuns to search. * @param startIndex The character index being sought. * @return The index into richTextRuns such that * richTextRuns.get(index).startIndex has the largest value less that * startIndex. */ protected int getRichTextRunIndexForStart(List richTextRuns, int startIndex) { if (richTextRuns.isEmpty()) { return -1; } for (int i = 0; i < richTextRuns.size(); ++i) { if (richTextRuns.get(i).startIndex >= startIndex) { return i - 1; } } return richTextRuns.size() - 1; } /** * Calculate the height of a string formatted according to a set of RichTextRuns * and fitted within a give width. * * @param sourceText The string to be measured. * @param defaultFont The font to be used prior to the first RichTextRun. * @param widthMM The width of the output. * @param richTextRuns The list of RichTextRuns to be applied to the string * @param wrap If the excel cell marked as wrapped text then use the * wrapped line break LineBreakMeasurer else use raw * TextMeasurer * @return The height, in points, of a box big enough to contain the formatted * sourceText. */ public float calculateTextHeightPoints(String sourceText, Font defaultFont, double widthMM, List richTextRuns, boolean wrap) { log.debug("Calculating height for ", sourceText); final float widthPt = (float) (72 * Math.max(0, widthMM - 6) / 25.4); float totalHeight = 0; String[] textLines = sourceText.split("\n"); int lineStartIndex = 0; String lastLine = null; Font font = defaultFont; for (String textLine : textLines) { if (lastLine != null) { lineStartIndex += lastLine.length() + 1; } lastLine = textLine; AttributedString attrString = new AttributedString(textLine.isEmpty() ? " " : textLine); int runEnd = textLine.length(); int richTextRunIndex = getRichTextRunIndexForStart(richTextRuns, lineStartIndex); if (richTextRunIndex >= 0) { font = richTextRuns.get(richTextRunIndex).font; if ((richTextRunIndex < richTextRuns.size() - 1) && (richTextRuns.get(richTextRunIndex + 1).startIndex < runEnd)) { runEnd = richTextRuns.get(richTextRunIndex + 1).startIndex; } } log.debug("Adding attribute - [", 0, " - ", runEnd, "] = ", defaultFont.getFontName(), " ", defaultFont.getFontHeightInPoints(), "pt"); addFontAttributes(attrString, font, 0, textLine.isEmpty() ? 1 : runEnd); for (++richTextRunIndex; (richTextRunIndex < richTextRuns.size()) && (richTextRuns.get(richTextRunIndex).startIndex < lineStartIndex + textLine.length()); ++richTextRunIndex) { RichTextRun run = richTextRuns.get(richTextRunIndex); RichTextRun nextRun = richTextRunIndex < richTextRuns.size() - 1 ? richTextRuns.get(richTextRunIndex + 1) : null; if ((run.startIndex >= lineStartIndex) && (run.startIndex < lineStartIndex + textLine.length() + 1)) { int startIdx = run.startIndex - lineStartIndex; int endIdx = (nextRun == null ? sourceText.length() : nextRun.startIndex) - lineStartIndex; if (endIdx > textLine.length()) { endIdx = textLine.length(); } if (startIdx < endIdx) { log.debug("Adding attribute: [", startIdx, " - ", endIdx, "] = ", run.font.getFontName(), " ", run.font.getFontHeightInPoints(), "pt"); addFontAttributes(attrString, run.font, startIdx, endIdx); } } } try { if (wrap) { LineBreakMeasurer measurer = new LineBreakMeasurer(attrString.getIterator(), frc); float heightAdjustment = 0.0F; int lineLength = textLine.isEmpty() ? 1 : textLine.length(); while (measurer.getPosition() < lineLength) { TextLayout layout = measurer.nextLayout(widthPt); float lineHeight = layout.getAscent() + layout.getDescent() + layout.getLeading(); if (layout.getDescent() + layout.getLeading() > heightAdjustment) { heightAdjustment = layout.getDescent() + layout.getLeading(); } log.debug("Line: ", textLine, " gives height ", lineHeight, "(", layout.getAscent(), "/", layout.getDescent(), "/", layout.getLeading(), ")"); totalHeight += lineHeight; } totalHeight += heightAdjustment; } else { if (textLine.length() > 0) { TextMeasurer measurer = new TextMeasurer(attrString.getIterator(), frc); TextLayout layout = measurer.getLayout(0, textLine.length()); float lineHeight = layout.getAscent() + 2 * (layout.getDescent() + layout.getLeading()); log.debug("Line: ", textLine, " gives height ", lineHeight, "(", layout.getAscent(), "/", layout.getDescent(), "/", layout.getLeading(), ")"); totalHeight += lineHeight; } } } catch (Throwable ex) { log.error(0, "Calculating height of line \"" + textLine + "\" threw: ", ex); } } log.debug("Height calculated as ", totalHeight); return totalHeight; } protected String contrastColour(int colour[]) { if ((colour[0] == 0) && (colour[1] == 0) && (colour[2] == 0)) { return "white"; } return "black"; } protected int[] rgbOnly(int rgb[]) { if (rgb == null) { return new int[] { 0, 0, 0 }; } else if (rgb.length == 3) { return rgb; } else if (rgb.length > 3) { return new int[] { rgb[rgb.length - 3], rgb[rgb.length - 2], rgb[rgb.length - 1] }; } else if (rgb.length == 2) { return new int[] { rgb[0], rgb[1], 0 }; } else if (rgb.length == 2) { return new int[] { rgb[0], 0, 0 }; } else { return new int[] { 0, 0, 0 }; } } protected int[] rgbOnly(byte rgb[]) { if (rgb == null) { return new int[] { 0, 0, 0 }; } else if (rgb.length >= 3) { return new int[] { rgb[rgb.length - 3] & 0xFF, rgb[rgb.length - 2] & 0xFF, rgb[rgb.length - 1] & 0xFF }; } else if (rgb.length == 2) { return new int[] { rgb[0] & 0xFF, rgb[1] & 0xFF, 0 }; } else if (rgb.length == 2) { return new int[] { rgb[0] & 0xFF, 0, 0 }; } else { return new int[] { 0, 0, 0 }; } } int[] parseColour(String colour, String defaultColour) { if ((colour == null) || (CSSConstants.CSS_TRANSPARENT_VALUE.equals(colour)) || (CSSConstants.CSS_AUTO_VALUE.equals(colour))) { return rgbOnly(ColorUtil.getRGBs(defaultColour)); } return rgbOnly(ColorUtil.getRGBs(colour)); } /** * Correction of font color if background * * @param fm font manager * @param wb workbook * @param birtStyle birt style * @param font font * @return Return the corrected font color */ public abstract Font correctFontColorIfBackground(FontManager fm, Workbook wb, BirtStyle birtStyle, Font font); /** * Correction of font color if background * * @param birtStyle birt style */ public void correctFontColorIfBackground(BirtStyle birtStyle) { CSSValue bgColour = birtStyle.getProperty(StyleConstants.STYLE_BACKGROUND_COLOR); CSSValue fgColour = birtStyle.getProperty(StyleConstants.STYLE_COLOR); int bgRgb[] = parseColour(bgColour == null ? null : bgColour.getCssText(), "white"); int fgRgb[] = parseColour(fgColour == null ? null : fgColour.getCssText(), "black"); if ((bgRgb[0] == fgRgb[0]) && (bgRgb[1] == fgRgb[1]) && (bgRgb[2] == fgRgb[2])) { CSSValue newColour = new StringValue(CSSPrimitiveValue.CSS_STRING, contrastColour(bgRgb)); birtStyle.setProperty(StyleConstants.STYLE_COLOR, newColour); } } /** * Convert a horizontal position in a column (in mm) to a ClientAnchor DX * position. * * @param width The position within the column. * @param colWidth The width of the column. * @return A value suitable for use as an argument to setDx2() on ClientAnchor. */ public abstract int anchorDxFromMM(double width, double colWidth); /** * Convert a vertical position in a row (in points) to a ClientAnchor DY * position. * * @param height The position within the row. * @param rowHeight The height of the row. * @return A value suitable for use as an argument to setDy2() on ClientAnchor. * * */ public abstract int anchorDyFromPoints(float height, float rowHeight); /** * Prepare the margin dimensions on the sheet as per the BIRT page. * * @param sheet Sheet * @param page The BIRT page. */ public abstract void prepareMarginDimensions(Sheet sheet, IPageContent page); /** * Place a border around a region on the current sheet. This is used to apply * borders to entire rows or entire tables. * * @param sm * @param sheet * * @param colStart The column marking the left-side boundary of the region. * @param colEnd The column marking the right-side boundary of the region. * @param rowStart The row marking the top boundary of the region. * @param rowEnd The row marking the bottom boundary of the region. * @param borderStyle The BIRT border style to apply to the region. */ public void applyBordersToArea(StyleManager sm, Sheet sheet, int colStart, int colEnd, int rowStart, int rowEnd, BirtStyle borderStyle) { StringBuilder borderMsg = new StringBuilder(); borderMsg.append("applyBordersToArea [").append(colStart).append(",").append(rowStart).append("]-[") .append(colEnd).append(",").append(rowEnd).append("]"); CSSValue borderStyleBottom = borderStyle.getProperty(StyleConstants.STYLE_BORDER_BOTTOM_STYLE); CSSValue borderWidthBottom = borderStyle.getProperty(StyleConstants.STYLE_BORDER_BOTTOM_WIDTH); CSSValue borderColourBottom = borderStyle.getProperty(StyleConstants.STYLE_BORDER_BOTTOM_COLOR); CSSValue borderStyleLeft = borderStyle.getProperty(StyleConstants.STYLE_BORDER_LEFT_STYLE); CSSValue borderWidthLeft = borderStyle.getProperty(StyleConstants.STYLE_BORDER_LEFT_WIDTH); CSSValue borderColourLeft = borderStyle.getProperty(StyleConstants.STYLE_BORDER_LEFT_COLOR); CSSValue borderStyleRight = borderStyle.getProperty(StyleConstants.STYLE_BORDER_RIGHT_STYLE); CSSValue borderWidthRight = borderStyle.getProperty(StyleConstants.STYLE_BORDER_RIGHT_WIDTH); CSSValue borderColourRight = borderStyle.getProperty(StyleConstants.STYLE_BORDER_RIGHT_COLOR); CSSValue borderStyleTop = borderStyle.getProperty(StyleConstants.STYLE_BORDER_TOP_STYLE); CSSValue borderWidthTop = borderStyle.getProperty(StyleConstants.STYLE_BORDER_TOP_WIDTH); CSSValue borderColourTop = borderStyle.getProperty(StyleConstants.STYLE_BORDER_TOP_COLOR); CSSValue borderStyleDiagonal = borderStyle.getProperty(StyleConstants.STYLE_BORDER_DIAGONAL_STYLE); CSSValue borderWidthDiagonal = borderStyle.getProperty(StyleConstants.STYLE_BORDER_DIAGONAL_WIDTH); CSSValue borderColourDiagonal = borderStyle.getProperty(StyleConstants.STYLE_BORDER_DIAGONAL_COLOR); CSSValue borderStyleAntidiagonal = borderStyle.getProperty(StyleConstants.STYLE_BORDER_ANTIDIAGONAL_STYLE); CSSValue borderWidthAntidiagonal = borderStyle.getProperty(StyleConstants.STYLE_BORDER_ANTIDIAGONAL_WIDTH); CSSValue borderColourAntidiagonal = borderStyle.getProperty(StyleConstants.STYLE_BORDER_ANTIDIAGONAL_COLOR); /* * borderMsg.append( ", Bottom:" ).append( borderStyleBottom ).append( "/" * ).append( borderWidthBottom ).append( "/" + borderColourBottom ); * borderMsg.append( ", Left:" ).append( borderStyleLeft ).append( "/" ).append( * borderWidthLeft ).append( "/" + borderColourLeft ); borderMsg.append( * ", Right:" ).append( borderStyleRight ).append( "/" ).append( * borderWidthRight ).append( "/" ).append( borderColourRight ); * borderMsg.append( ", Top:" ).append( borderStyleTop ).append( "/" ).append( * borderWidthTop ).append( "/" ).append( borderColourTop ); log.debug( * borderMsg.toString() ); */ if ((borderStyleBottom == null) || (CSSConstants.CSS_NONE_VALUE.equals(borderStyleBottom)) || (borderWidthBottom == null) || ("0".equals(borderWidthBottom)) || (borderColourBottom == null) || (CSSConstants.CSS_TRANSPARENT_VALUE.equals(borderColourBottom.getCssText()))) { borderStyleBottom = null; borderWidthBottom = null; borderColourBottom = null; } if ((borderStyleLeft == null) || (CSSConstants.CSS_NONE_VALUE.equals(borderStyleLeft)) || (borderWidthLeft == null) || ("0".equals(borderWidthLeft)) || (borderColourLeft == null) || (CSSConstants.CSS_TRANSPARENT_VALUE.equals(borderColourLeft.getCssText()))) { borderStyleLeft = null; borderWidthLeft = null; borderColourLeft = null; } if ((borderStyleRight == null) || (CSSConstants.CSS_NONE_VALUE.equals(borderStyleRight)) || (borderWidthRight == null) || ("0".equals(borderWidthRight)) || (borderColourRight == null) || (CSSConstants.CSS_TRANSPARENT_VALUE.equals(borderColourRight.getCssText()))) { borderStyleRight = null; borderWidthRight = null; borderColourRight = null; } if ((borderStyleTop == null) || (CSSConstants.CSS_NONE_VALUE.equals(borderStyleTop)) || (borderWidthTop == null) || ("0".equals(borderWidthTop)) || (borderColourTop == null) || (CSSConstants.CSS_TRANSPARENT_VALUE.equals(borderColourTop.getCssText()))) { borderStyleTop = null; borderWidthTop = null; borderColourTop = null; } if ((borderStyleDiagonal == null) || (CSSConstants.CSS_NONE_VALUE.equals(borderStyleDiagonal)) || (borderWidthDiagonal == null) || ("0".equals(borderWidthDiagonal)) || (borderColourDiagonal == null) || (CSSConstants.CSS_TRANSPARENT_VALUE.equals(borderColourDiagonal.getCssText()))) { borderStyleDiagonal = null; borderWidthDiagonal = null; borderColourDiagonal = null; } if ((borderStyleAntidiagonal == null) || (CSSConstants.CSS_NONE_VALUE.equals(borderStyleAntidiagonal)) || (borderWidthAntidiagonal == null) || ("0".equals(borderWidthDiagonal)) || (borderColourDiagonal == null) || (CSSConstants.CSS_TRANSPARENT_VALUE.equals(borderColourAntidiagonal.getCssText()))) { borderStyleAntidiagonal = null; borderWidthAntidiagonal = null; borderColourAntidiagonal = null; } if ((borderStyleBottom != null) || (borderWidthBottom != null) || (borderColourBottom != null) || (borderStyleLeft != null) || (borderWidthLeft != null) || (borderColourLeft != null) || (borderStyleRight != null) || (borderWidthRight != null) || (borderColourRight != null) || (borderStyleTop != null) || (borderWidthTop != null) || (borderColourTop != null) || (borderStyleDiagonal != null) || (borderWidthDiagonal != null) || (borderColourDiagonal != null) || (borderStyleAntidiagonal != null) || (borderWidthAntidiagonal != null) || (borderColourAntidiagonal != null) ) { for (int row = rowStart; row <= rowEnd; ++row) { Row styleRow = sheet.getRow(row); if (styleRow != null) { for (int col = colStart; col <= colEnd; ++col) { if ((col == colStart) || (col == colEnd) || (row == rowStart) || (row == rowEnd)) { Cell styleCell = styleRow.getCell(col); if (styleCell == null) { log.debug("Creating cell[", row, ",", col, "]"); styleCell = styleRow.createCell(col); } if (styleCell != null) { // log.debug( "Applying border to cell [R" + styleCell.getRowIndex() + "C" + // styleCell.getColumnIndex() + "]"); CellStyle newStyle = sm.getStyleWithBorders(styleCell.getCellStyle(), ((row == rowEnd) ? borderStyleBottom : null), ((row == rowEnd) ? borderWidthBottom : null), ((row == rowEnd) ? borderColourBottom : null), ((col == colStart) ? borderStyleLeft : null), ((col == colStart) ? borderWidthLeft : null), ((col == colStart) ? borderColourLeft : null), ((col == colEnd) ? borderStyleRight : null), ((col == colEnd) ? borderWidthRight : null), ((col == colEnd) ? borderColourRight : null), ((row == rowStart) ? borderStyleTop : null), ((row == rowStart) ? borderWidthTop : null), ((row == rowStart) ? borderColourTop : null), ((row == rowStart) ? borderStyleDiagonal : null), ((row == rowStart) ? borderWidthDiagonal : null), ((row == rowStart) ? borderColourDiagonal : null), ((row == rowStart) ? borderStyleAntidiagonal : null), ((row == rowStart) ? borderWidthAntidiagonal : null), ((row == rowStart) ? borderColourAntidiagonal : null) ); styleCell.setCellStyle(newStyle); } } } } } } } /** * Place a border around a region on the current sheet. This is used to apply * borders to entire rows or entire tables. * * @param sm Style manager * @param sheet Sheet * @param colStart The column marking the left-side boundary of the region. * @param colEnd The column marking the right-side boundary of the region. * @param row The row to get a bottom border. * @param borderStyle The BIRT border style to apply to the region. */ public void applyBottomBorderToRow(StyleManager sm, Sheet sheet, int colStart, int colEnd, int row, BirtStyle borderStyle) { CSSValue borderStyleBottom = borderStyle.getProperty(StyleConstants.STYLE_BORDER_BOTTOM_STYLE); CSSValue borderWidthBottom = borderStyle.getProperty(StyleConstants.STYLE_BORDER_BOTTOM_WIDTH); CSSValue borderColourBottom = borderStyle.getProperty(StyleConstants.STYLE_BORDER_BOTTOM_COLOR); if ((borderStyleBottom == null) || (CSSConstants.CSS_NONE_VALUE.equals(borderStyleBottom.getCssText())) || (borderWidthBottom == null) || ("0".equals(borderWidthBottom)) || (borderColourBottom == null) || (CSSConstants.CSS_TRANSPARENT_VALUE.equals(borderColourBottom.getCssText()))) { borderStyleBottom = null; borderWidthBottom = null; borderColourBottom = null; } if ((borderStyleBottom != null) || (borderWidthBottom != null) || (borderColourBottom != null)) { Row styleRow = sheet.getRow(row); if (styleRow != null) { for (int col = colStart; col <= colEnd; ++col) { Cell styleCell = styleRow.getCell(col); if (styleCell == null) { styleCell = styleRow.createCell(col); } if (styleCell != null) { // log.debug( "Applying border to cell [R" + styleCell.getRowIndex() + "C" + // styleCell.getColumnIndex() + "]"); CellStyle newStyle = sm.getStyleWithBorders(styleCell.getCellStyle(), borderStyleBottom, borderWidthBottom, borderColourBottom, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null); styleCell.setCellStyle(newStyle); } } } } } /** * Apply the area border to cell * * @param knownAreaBorders Area borders collection * @param cell cell instance * @param birtCellStyle birt cell style * @param rowIndex row index * @param colIndex column index * @return Return the column index */ public int applyAreaBordersToCell(Collection knownAreaBorders, Cell cell, BirtStyle birtCellStyle, int rowIndex, int colIndex) { for (AreaBorders areaBorders : knownAreaBorders) { if ((areaBorders.bottom == rowIndex) && ((areaBorders.left <= colIndex) && (areaBorders.right >= colIndex))) { if ((areaBorders.cssStyle[0] != null) && (areaBorders.cssWidth[0] != null) && (areaBorders.cssColour[0] != null)) { birtCellStyle.setProperty(StyleConstants.STYLE_BORDER_BOTTOM_STYLE, areaBorders.cssStyle[0]); birtCellStyle.setProperty(StyleConstants.STYLE_BORDER_BOTTOM_WIDTH, areaBorders.cssWidth[0]); birtCellStyle.setProperty(StyleConstants.STYLE_BORDER_BOTTOM_COLOR, areaBorders.cssColour[0]); } } if ((areaBorders.left == colIndex) && ((areaBorders.top <= rowIndex) && ((areaBorders.bottom < 0) || (areaBorders.bottom >= rowIndex)))) { if ((areaBorders.cssStyle[1] != null) && (areaBorders.cssWidth[1] != null) && (areaBorders.cssColour[1] != null)) { birtCellStyle.setProperty(StyleConstants.STYLE_BORDER_LEFT_STYLE, areaBorders.cssStyle[1]); birtCellStyle.setProperty(StyleConstants.STYLE_BORDER_LEFT_WIDTH, areaBorders.cssWidth[1]); birtCellStyle.setProperty(StyleConstants.STYLE_BORDER_LEFT_COLOR, areaBorders.cssColour[1]); } } if ((areaBorders.right == colIndex) && ((areaBorders.top <= rowIndex) && ((areaBorders.bottom < 0) || (areaBorders.bottom >= rowIndex)))) { if ((areaBorders.cssStyle[2] != null) && (areaBorders.cssWidth[2] != null) && (areaBorders.cssColour[2] != null)) { birtCellStyle.setProperty(StyleConstants.STYLE_BORDER_RIGHT_STYLE, areaBorders.cssStyle[2]); birtCellStyle.setProperty(StyleConstants.STYLE_BORDER_RIGHT_WIDTH, areaBorders.cssWidth[2]); birtCellStyle.setProperty(StyleConstants.STYLE_BORDER_RIGHT_COLOR, areaBorders.cssColour[2]); } } if ((areaBorders.top == rowIndex) && ((areaBorders.left <= colIndex) && (areaBorders.right >= colIndex))) { if ((areaBorders.cssStyle[3] != null) && (areaBorders.cssWidth[3] != null) && (areaBorders.cssColour[3] != null)) { birtCellStyle.setProperty(StyleConstants.STYLE_BORDER_TOP_STYLE, areaBorders.cssStyle[3]); birtCellStyle.setProperty(StyleConstants.STYLE_BORDER_TOP_WIDTH, areaBorders.cssWidth[3]); birtCellStyle.setProperty(StyleConstants.STYLE_BORDER_TOP_COLOR, areaBorders.cssColour[3]); } } if ((areaBorders.left == colIndex) && ((areaBorders.top <= rowIndex) && ((areaBorders.bottom < 0) || (areaBorders.bottom >= rowIndex)))) { if ((areaBorders.cssStyle[4] != null) && (areaBorders.cssWidth[4] != null) && (areaBorders.cssColour[4] != null)) { birtCellStyle.setProperty(StyleConstants.STYLE_BORDER_DIAGONAL_STYLE, areaBorders.cssStyle[4]); birtCellStyle.setProperty(StyleConstants.STYLE_BORDER_DIAGONAL_WIDTH, areaBorders.cssWidth[4]); birtCellStyle.setProperty(StyleConstants.STYLE_BORDER_DIAGONAL_COLOR, areaBorders.cssColour[4]); } } if ((areaBorders.left == colIndex) && ((areaBorders.top <= rowIndex) && ((areaBorders.bottom < 0) || (areaBorders.bottom >= rowIndex)))) { if ((areaBorders.cssStyle[5] != null) && (areaBorders.cssWidth[5] != null) && (areaBorders.cssColour[5] != null)) { birtCellStyle.setProperty(StyleConstants.STYLE_BORDER_ANTIDIAGONAL_STYLE, areaBorders.cssStyle[5]); birtCellStyle.setProperty(StyleConstants.STYLE_BORDER_ANTIDIAGONAL_WIDTH, areaBorders.cssWidth[5]); birtCellStyle.setProperty(StyleConstants.STYLE_BORDER_ANTIDIAGONAL_COLOR, areaBorders.cssColour[5]); } } } return colIndex; } /** * Extend rows * * @param state handler state * @param startRow start row * @param startCol start column * @param endRow end row * @param endCol end column */ public void extendRows(HandlerState state, int startRow, int startCol, int endRow, int endCol) { for (int colNum = startCol; colNum < endCol; ++colNum) { Cell lastCell = null; for (int rowNum = startRow; rowNum < endRow; ++rowNum) { Row row = state.currentSheet.getRow(rowNum); if (row != null) { Cell cell = row.getCell(colNum); if (cell != null) { lastCell = cell; } } } if ((lastCell != null) && (lastCell.getRowIndex() < endRow - 1)) { CellRangeAddress range = new CellRangeAddress(lastCell.getRowIndex(), endRow - 1, lastCell.getColumnIndex(), lastCell.getColumnIndex()); log.debug("Extend: merging from [", range.getFirstRow(), ",", range.getFirstColumn(), "] to [", range.getLastRow(), ",", range.getLastColumn(), "]"); state.currentSheet.addMergedRegion(range); for (int rowNum = lastCell.getRowIndex() + 1; rowNum < endRow; ++rowNum) { Row row = state.currentSheet.getRow(rowNum); if (row == null) { log.error(0, "Creating a row (for column " + colNum + "), this really shouldn't be necessary", null); row = state.currentSheet.createRow(rowNum); } Cell cell = row.createCell(colNum); cell.setCellStyle(lastCell.getCellStyle()); } } } } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy