| /******************************************************************************* |
| * Copyright (c) 2012, 2020 Original authors and others. |
| * |
| * 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: |
| * Original authors and others - initial API and implementation |
| * Dirk Fauth <dirk.fauth@googlemail.com> - Bug 450443 |
| * Jan Haensli <jan.haensli@inventage.com> - Bug 452453 |
| * Uwe Peuker <dev@upeuker.net> - Bug 500787 |
| ******************************************************************************/ |
| package org.eclipse.nebula.widgets.nattable.export.excel; |
| |
| import java.io.BufferedReader; |
| import java.io.IOException; |
| import java.io.InputStreamReader; |
| import java.io.OutputStream; |
| import java.nio.charset.Charset; |
| |
| import org.eclipse.nebula.widgets.nattable.config.IConfigRegistry; |
| import org.eclipse.nebula.widgets.nattable.export.FileOutputStreamProvider; |
| import org.eclipse.nebula.widgets.nattable.export.ILayerExporter; |
| import org.eclipse.nebula.widgets.nattable.export.IOutputStreamProvider; |
| import org.eclipse.nebula.widgets.nattable.layer.cell.ILayerCell; |
| import org.eclipse.nebula.widgets.nattable.style.CellStyleAttributes; |
| import org.eclipse.nebula.widgets.nattable.style.CellStyleProxy; |
| import org.eclipse.nebula.widgets.nattable.style.DisplayMode; |
| import org.eclipse.nebula.widgets.nattable.util.GUIHelper; |
| import org.eclipse.swt.graphics.Color; |
| import org.eclipse.swt.graphics.Font; |
| import org.eclipse.swt.graphics.FontData; |
| import org.eclipse.swt.widgets.Shell; |
| import org.slf4j.Logger; |
| import org.slf4j.LoggerFactory; |
| |
| /** |
| * This class is used to export a NatTable to an Excel spreadsheet by using a |
| * XML format. |
| */ |
| public class ExcelExporter implements ILayerExporter { |
| |
| private static final Logger LOG = LoggerFactory.getLogger(ExcelExporter.class); |
| |
| private static final String EXCEL_HEADER_FILE = "excelExportHeader.txt"; //$NON-NLS-1$ |
| |
| private static final String CHARSET_PLACEHOLDER = "${charset}"; //$NON-NLS-1$ |
| private static final String SHEETNAME_PLACEHOLDER = "${sheetname}"; //$NON-NLS-1$ |
| |
| private String charset = "windows-1252"; //$NON-NLS-1$ |
| private Charset exportCharSet; |
| private String sheetname = "Sheet1"; //$NON-NLS-1$ |
| |
| /** |
| * The IOutputStreamProvider that is used to create new OutputStreams on |
| * beginning new export operations. |
| */ |
| private final IOutputStreamProvider outputStreamProvider; |
| |
| /** |
| * Creates a new ExcelExporter using a FileOutputStreamProvider with default |
| * values. |
| */ |
| public ExcelExporter() { |
| this(new FileOutputStreamProvider("table_export.xls", //$NON-NLS-1$ |
| new String[] { "Excel Workbook (*.xls)" }, new String[] { "*.xls" })); //$NON-NLS-1$ //$NON-NLS-2$ |
| } |
| |
| /** |
| * Creates a new ExcelExporter that uses the given IOutputStreamProvider for |
| * retrieving the OutputStream to write the export to. |
| * |
| * @param outputStreamProvider |
| * The IOutputStreamProvider that is used to retrieve the |
| * OutputStream to write the export to. |
| */ |
| public ExcelExporter(IOutputStreamProvider outputStreamProvider) { |
| this.outputStreamProvider = outputStreamProvider; |
| } |
| |
| @Override |
| public OutputStream getOutputStream(Shell shell) { |
| return this.outputStreamProvider.getOutputStream(shell); |
| } |
| |
| @Override |
| public void exportBegin(OutputStream outputStream) throws IOException { |
| this.exportCharSet = Charset.forName(this.charset); |
| } |
| |
| @Override |
| public void exportEnd(OutputStream outputStream) throws IOException { |
| // no specific action needed on export end in this exporter |
| } |
| |
| @Override |
| public void exportLayerBegin(OutputStream outputStream, String layerName) throws IOException { |
| writeHeader(outputStream); |
| outputStream.write(asBytes("<body><table border='1'>")); //$NON-NLS-1$ |
| } |
| |
| /** |
| * Writes the Excel header informations that are stored locally in the |
| * package structure. |
| * |
| * @throws IOException |
| * if an I/O error occurs on closing the stream to the header |
| * content file |
| */ |
| private void writeHeader(OutputStream outputStream) throws IOException { |
| try (BufferedReader reader = new BufferedReader( |
| new InputStreamReader(this.getClass().getResourceAsStream(EXCEL_HEADER_FILE)));) { |
| |
| String line = null; |
| while ((line = reader.readLine()) != null) { |
| // don not export comments in export header template |
| if (!line.startsWith("#")) { //$NON-NLS-1$ |
| line = line.replace(CHARSET_PLACEHOLDER, this.charset); |
| line = line.replace(SHEETNAME_PLACEHOLDER, this.sheetname); |
| outputStream.write(line.getBytes()); |
| outputStream.write(System.getProperty("line.separator").getBytes()); //$NON-NLS-1$ |
| } |
| } |
| } catch (Exception e) { |
| LOG.error("Excel Exporter failed: {}", e.getMessage(), e); //$NON-NLS-1$ |
| } |
| } |
| |
| @Override |
| public void exportLayerEnd(OutputStream outputStream, String layerName) throws IOException { |
| outputStream.write(asBytes("</table></body></html>")); //$NON-NLS-1$ |
| } |
| |
| @Override |
| public void exportRowBegin(OutputStream outputStream, int rowPosition) throws IOException { |
| outputStream.write(asBytes("<tr>\n")); //$NON-NLS-1$ |
| } |
| |
| @Override |
| public void exportRowEnd(OutputStream outputStream, int rowPosition) throws IOException { |
| outputStream.write(asBytes("</tr>\n")); //$NON-NLS-1$ |
| } |
| |
| @Override |
| public void exportCell(OutputStream outputStream, |
| Object exportDisplayValue, ILayerCell cell, |
| IConfigRegistry configRegistry) throws IOException { |
| |
| if (cell.getBounds().width == 0 || cell.getBounds().height == 0) { |
| // if the cell is not visible to the user, it should not be exported |
| return; |
| } |
| |
| CellStyleProxy cellStyle = new CellStyleProxy( |
| configRegistry, |
| DisplayMode.NORMAL, |
| cell.getConfigLabels()); |
| Color fg = cellStyle.getAttributeValue(CellStyleAttributes.FOREGROUND_COLOR); |
| Color bg = cellStyle.getAttributeValue(CellStyleAttributes.BACKGROUND_COLOR); |
| Font font = cellStyle.getAttributeValue(CellStyleAttributes.FONT); |
| |
| if (fg == null) { |
| fg = GUIHelper.COLOR_BLACK; |
| } |
| if (bg == null) { |
| bg = GUIHelper.COLOR_WHITE; |
| } |
| if (font == null) { |
| font = GUIHelper.DEFAULT_FONT; |
| } |
| |
| String htmlAttributes = String.format("style='color: %s; background-color: %s; %s;'", //$NON-NLS-1$ |
| getColorInCSSFormat(fg), getColorInCSSFormat(bg), |
| getFontInCSSFormat(font)); |
| |
| String htmlText = exportDisplayValue != null ? exportDisplayValue.toString() : ""; //$NON-NLS-1$ |
| |
| if (htmlText.startsWith(" ")) { //$NON-NLS-1$ |
| htmlAttributes += " x:str=\"'" + htmlText + "\";"; //$NON-NLS-1$ //$NON-NLS-2$ |
| htmlText = htmlText.replaceFirst("^(\\ *)", "<span style='mso-spacerun:yes'>$1</span>"); //$NON-NLS-1$ //$NON-NLS-2$ |
| } |
| |
| outputStream.write(asBytes(String.format("\t<td %s>%s</td>\n", htmlAttributes, htmlText))); //$NON-NLS-1$ |
| } |
| |
| private byte[] asBytes(String string) { |
| return string.getBytes(this.exportCharSet); |
| } |
| |
| private String getFontInCSSFormat(Font font) { |
| FontData fontData = font.getFontData()[0]; |
| String fontName = fontData.getName(); |
| int fontStyle = fontData.getStyle(); |
| String HTML_STYLES[] = new String[] { "NORMAL", "BOLD", "ITALIC" }; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ |
| |
| return String.format("font: %s; font-family: %s", //$NON-NLS-1$ |
| fontStyle <= 2 ? HTML_STYLES[fontStyle] : HTML_STYLES[0], |
| fontName); |
| } |
| |
| private String getColorInCSSFormat(Color color) { |
| return String.format("rgb(%d,%d,%d)", //$NON-NLS-1$ |
| Integer.valueOf(color.getRed()), |
| Integer.valueOf(color.getGreen()), |
| Integer.valueOf(color.getBlue())); |
| } |
| |
| @Override |
| public Object getResult() { |
| return this.outputStreamProvider.getResult(); |
| } |
| |
| /** |
| * @param charset |
| * The charset that should be used as replacement for the charset |
| * value in the export header. Default is <i>windows-1252</i> |
| */ |
| public void setCharset(String charset) { |
| this.charset = charset; |
| } |
| |
| /** |
| * |
| * @param sheetname |
| * The name that should be set as sheet name in the resulting |
| * Excel file. Default is <i>Sheet1</i> |
| */ |
| public void setSheetname(String sheetname) { |
| this.sheetname = sheetname; |
| } |
| } |