blob: f988f0b3b1211a8fe2a6f716ab3504f810a08ec5 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2016, 2020 Uwe Peuker 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:
* Uwe Peuker <dev@upeuker.net> - Bug 500789 - initial API and implementation
******************************************************************************/
package org.eclipse.nebula.widgets.nattable.export.csv;
import java.io.IOException;
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.FilePathOutputStreamProvider;
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.swt.widgets.Shell;
/**
* Simple CSV-Exporter ignoring cell spans.
*
* @since 1.5
*/
public class CsvExporter implements ILayerExporter {
private static final String CSV_FILE_EXTENSION = "*.csv"; //$NON-NLS-1$
private static final String CSV_FILE_FILTER = "CSV (*.csv)"; //$NON-NLS-1$
private static final String DEFAULT_EXPORT_FILE_NAME = "csv_export.csv"; //$NON-NLS-1$
private static final String NEW_LINE_REGEX = "\\n\\r|\\r\\n|\\n|\\r"; //$NON-NLS-1$
private static final String LINE_SEPARATOR = System.getProperty("line.separator"); //$NON-NLS-1$
private final IOutputStreamProvider outputStreamProvider;
private String charset = "windows-1252"; //$NON-NLS-1$
private String delimiter = ";"; //$NON-NLS-1$
/* used during export runtime. */
private final StringBuilder currentRow = new StringBuilder(2048);
private boolean rowCellInserted;
private Charset usedCharset;
/**
* Creates a CsvExporter using the given stream provider which defines the
* destination for the export.
*
* If the stream provider ist set to null a default
* {@link FileOutputStreamProvider} will be used.
*
* @param outputStreamProvider
* the used stream provider
*/
public CsvExporter(final IOutputStreamProvider outputStreamProvider) {
if (outputStreamProvider == null) {
this.outputStreamProvider = new FileOutputStreamProvider(
DEFAULT_EXPORT_FILE_NAME,
new String[] { CSV_FILE_FILTER },
new String[] { CSV_FILE_EXTENSION });
} else {
this.outputStreamProvider = outputStreamProvider;
}
}
/**
* Creates a CsvExporter using a default {@link FileOutputStreamProvider} to
* define the destination for the export.
*/
public CsvExporter() {
this((IOutputStreamProvider) null);
}
/**
* Creates a CsvExporter using a {@link FilePathOutputStreamProvider}.
*
* The destination fpr the export will be a file with the given path.
*
* @param filePath
* the path of the export file
*/
public CsvExporter(final String filePath) {
this.outputStreamProvider = new FilePathOutputStreamProvider(filePath);
}
@Override
public OutputStream getOutputStream(final Shell shell) {
return this.outputStreamProvider.getOutputStream(shell);
}
@Override
public Object getResult() {
return this.outputStreamProvider.getResult();
}
@Override
public void exportBegin(final OutputStream outputStream) throws IOException {
this.usedCharset = Charset.forName(this.charset);
}
@Override
public void exportEnd(final OutputStream outputStream) throws IOException {
// do noting
}
@Override
public void exportLayerBegin(final OutputStream outputStream, final String layerName) throws IOException {
// do nothing
}
@Override
public void exportLayerEnd(final OutputStream outputStream, final String layerName) throws IOException {
// do nothing
}
@Override
public void exportRowBegin(final OutputStream outputStream, final int rowPosition) throws IOException {
this.currentRow.setLength(0);
this.rowCellInserted = false;
}
@Override
public void exportRowEnd(final OutputStream outputStream, final int rowPosition) throws IOException {
this.currentRow.append(LINE_SEPARATOR);
outputStream.write(this.currentRow.toString().getBytes(this.usedCharset));
}
@Override
public void exportCell(
final OutputStream outputStream,
final Object exportDisplayValue,
final ILayerCell cell,
final 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;
}
if (this.rowCellInserted) {
this.currentRow.append(this.delimiter);
} else {
this.rowCellInserted = true;
}
if (exportDisplayValue != null) {
// handle values according to RFC4180
String value = exportDisplayValue.toString();
// If double-quotes are used to enclose fields, then a double-quote
// appearing inside a field must be escaped by preceding it with
// another double quote.
value = value.replaceAll("\"", "\"\""); //$NON-NLS-1$ //$NON-NLS-2$
// Fields containing line breaks (CRLF), double quotes, and commas
// should be enclosed in double-quotes.
if (value.contains("\"") || value.contains(",") || value.split(NEW_LINE_REGEX).length > 1) { //$NON-NLS-1$ //$NON-NLS-2$
value = "\"" + value + "\""; //$NON-NLS-1$ //$NON-NLS-2$
}
this.currentRow.append(value);
}
}
/**
* Defines the name of the charset which should be used as encoding for the
* export file.
*
* The default ist set to windows-1252.
*
* @param charset
* the name of the charset
*/
public void setCharset(final String charset) {
this.charset = charset;
}
/**
* Defines the delimiter which should be used between columns.
*
* The default is the character ';'.
*
* @param delimiter
* the column delimiter
*/
public void setDelimiter(final String delimiter) {
this.delimiter = delimiter;
}
}