![JAR search and dependency download from the Maven repository](/logo.png)
eu.agrosense.client.io.csv.CsvDataObject Maven / Gradle / Ivy
/**
* Copyright (C) 2008-2013 LimeTri. All rights reserved.
*
* AgroSense is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* There are special exceptions to the terms and conditions of the GPLv3 as it is applied to
* this software, see the FLOSS License Exception
* .
*
* AgroSense is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with AgroSense. If not, see .
*/
package eu.agrosense.client.io.csv;
import au.com.bytecode.opencsv.CSVReader;
import eu.agrosense.api.mapping.MappableSource;
import eu.agrosense.api.mapping.SourceAttributeDescriptor;
import eu.agrosense.api.mapping.SourceRecord;
import eu.agrosense.api.mapping.SourceRecordGenerator;
import eu.agrosense.api.mapping.SourceRecordIterator;
import eu.agrosense.client.imp.ImportDataObject;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.Reader;
import java.io.StringReader;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.swing.JEditorPane;
import javax.swing.SwingUtilities;
import org.netbeans.core.spi.multiview.MultiViewElement;
import org.netbeans.core.spi.multiview.text.MultiViewEditorElement;
import org.openide.awt.ActionID;
import org.openide.awt.ActionReference;
import org.openide.awt.ActionReferences;
import org.openide.filesystems.FileObject;
import org.openide.filesystems.MIMEResolver;
import org.openide.loaders.DataObject;
import org.openide.loaders.DataObjectExistsException;
import org.openide.loaders.MultiFileLoader;
import org.openide.util.Exceptions;
import org.openide.util.Lookup;
import org.openide.util.NbBundle.Messages;
import org.openide.windows.TopComponent;
@Messages({
"LBL_Csv_LOADER=Files of Csv"
})
@MIMEResolver.ExtensionRegistration(
displayName = "#LBL_Csv_LOADER",
mimeType = CsvDataObject.MIME_TYPE,
extension = {"csv", "CSV"},
position=1)
@DataObject.Registration(
mimeType = CsvDataObject.MIME_TYPE,
iconBase = CsvDataObject.ICON_BASE,
displayName = "#LBL_Csv_LOADER",
position = 300)
@ActionReferences({
@ActionReference(
path = "Loaders/text/csv/Actions",
id =
@ActionID(category = "System", id = "org.openide.actions.OpenAction"),
position = 100,
separatorAfter = 200),
@ActionReference(
path = "Loaders/text/csv/Actions",
id =
@ActionID(category = "Edit", id = "org.openide.actions.DeleteAction"),
position = 600),
@ActionReference(
path = "Loaders/text/csv/Actions",
id =
@ActionID(category = "System", id = "org.openide.actions.RenameAction"),
position = 700,
separatorAfter = 800),
@ActionReference(
path = "Loaders/text/csv/Actions",
id =
@ActionID(category = "System", id = "org.openide.actions.ToolsAction"),
position = 1300),
})
public class CsvDataObject extends ImportDataObject {
public static final String PRIMARY_EXT = "csv";
public static final String MIME_TYPE = "text/csv";
public static final String ICON_BASE = "eu/agrosense/client/io/csv/file_extension_txt.png";
private static final Logger LOGGER = Logger.getLogger("eu.agrosense.client.data.csv.CsvDataObject");
public static final String PROP_SEPARATOR_CHAR = "separatorChar";
public static final String PROP_QUOTE_CHAR = "quoteChar";
public static final String PROP_ESCAPE_CHAR = "escapeChar";
public static final String PROP_SKIP_LINES = "skipLines";
private static final String ATT_SEPARATOR_CHAR = "att_separator_char";
private static final String ATT_QUOTE_CHAR = "att_quote_char";
private static final String ATT_ESCAPE_CHAR = "att_escape_char";
private static final String ATT_SKIP_LINES = "att_skip_lines";
public static final char DEFAULT_SEPARATOR_CHAR = ',';
public static final char DEFAULT_QUOTE_CHAR = '"';
public static final char DEFAULT_ESCAPE_CHAR = '\\';
public static final int DEFAULT_SKIP_LINES = 1; // require header line, differs from CsvReader.DEFAULT_SKIP_LINES
private final CsvMappableSource mappableSource;
private final Charset charset = StandardCharsets.UTF_8; // maybe later: make configurable via the attributesPanel
public CsvDataObject(FileObject pf, MultiFileLoader loader) throws DataObjectExistsException, IOException {
super(pf, loader);
registerEditor(MIME_TYPE, true);
mappableSource = new CsvMappableSource();
ic.add(mappableSource);
init();
}
private void init() {
if (getSeparatorChar() == null) {
CsvFileAttributes cfa = CsvFileAttributeRegistry.getInstance().find(getHeaderLine());
if (cfa != null) {
setSepararatorChar(cfa.getSeparatorChar());
setQuoteChar(cfa.getQuoteChar());
setEscapeChar(cfa.getEscapeChar());
setSkipLines(cfa.getSkipLines());
} else {
setSepararatorChar(DEFAULT_SEPARATOR_CHAR);
setQuoteChar(DEFAULT_QUOTE_CHAR);
setEscapeChar(DEFAULT_ESCAPE_CHAR);
setSkipLines(DEFAULT_SKIP_LINES);
}
}
}
@Override
protected int associateLookup() {
return 1;
}
public Character getSeparatorChar() {
String str = (String) getPrimaryFile().getAttribute(ATT_SEPARATOR_CHAR);
return str == null || str.isEmpty() ? null : str.charAt(0);
}
void setSepararatorChar(Character ch) {
try {
Character old = getSeparatorChar();
// org.openide.filesystemsXmlMapAttr.java, line 956:
// if (value.trim().length() != 1) {
// so can't store tab or space separator as characters...
String str = ch == null ? null : ch.toString();
getPrimaryFile().setAttribute(ATT_SEPARATOR_CHAR, str);
firePropertyChange(PROP_SEPARATOR_CHAR, old, ch);
} catch (IOException ex) {
LOGGER.log(Level.WARNING, "could not save separator char property for csv data object {0}", getName());
}
}
public Character getQuoteChar() {
return (Character) getPrimaryFile().getAttribute(ATT_QUOTE_CHAR);
}
void setQuoteChar(Character ch) {
try {
Character old = getQuoteChar();
getPrimaryFile().setAttribute(ATT_QUOTE_CHAR, ch);
firePropertyChange(PROP_QUOTE_CHAR, old, ch);
} catch (IOException ex) {
LOGGER.log(Level.WARNING, "could not save quote char property for csv data object {0}", getName());
}
}
public Character getEscapeChar() {
return (Character) getPrimaryFile().getAttribute(ATT_ESCAPE_CHAR);
}
void setEscapeChar(Character ch) {
try {
Character old = getEscapeChar();
getPrimaryFile().setAttribute(ATT_ESCAPE_CHAR, ch);
firePropertyChange(PROP_ESCAPE_CHAR, old, ch);
} catch (IOException ex) {
LOGGER.log(Level.WARNING, "could not save escape char property for csv data object {0}", getName());
}
}
public Integer getSkipLines() {
return (Integer) getPrimaryFile().getAttribute(ATT_SKIP_LINES);
}
void setSkipLines(Integer i) {
try {
Integer old = getSkipLines();
getPrimaryFile().setAttribute(ATT_SKIP_LINES, i);
firePropertyChange(PROP_SKIP_LINES, old, i);
} catch (IOException ex) {
LOGGER.log(Level.WARNING, "could not save skip lines property for csv data object {0}", getName());
}
}
@MultiViewElement.Registration(
displayName = "#LBL_Csv_EDITOR",
iconBase = ICON_BASE,
mimeType = MIME_TYPE,
persistenceType = TopComponent.PERSISTENCE_ONLY_OPENED,
preferredID = "Csv",
position = 2000)
@Messages("LBL_Csv_EDITOR=Source")
public static MultiViewEditorElement createEditor(Lookup lkp) {
final MultiViewEditorElement mvee = new MultiViewEditorElement(lkp);
// make source view read only:
SwingUtilities.invokeLater(new Runnable() {
@Override public void run() {
JEditorPane pane = mvee.getEditorPane();
pane.setEditable(false);
// FIXME: skipping BOM workaround for now, as it has some side effects:
// It opens the source tab at the bottom of the document, and marks it as savable.
// The extra character in a read only view is less harmful.
// pane.setText(stripBOM(pane.getText()));
}
});
return mvee;
}
private String getHeaderLine() {
// can't use first value from getPrimaryFile().asLines().iterator():
// FileObjectLineIterator keeps a Reader open unless iterated all the way...
String s = null;
try (InputStream is = getPrimaryFile().getInputStream();
Reader r = new InputStreamReader(is, charset);
BufferedReader br = new BufferedReader(r)) {
s = stripBOM(br.readLine());
} catch (IOException ex) {
LOGGER.warning(ex.toString());
// Exceptions.printStackTrace(ex);
}
return s;
}
private String getContents() {
try {
return stripBOM(getPrimaryFile().asText(charset.name()));
} catch (IOException ex) {
Exceptions.printStackTrace(ex);
return null;
}
}
// Remove byte order mark when present
// https://netbeans.org/bugzilla/show_bug.cgi?id=161015
private static String stripBOM(String s) {
if (s == null) return null;
return s.startsWith("\uFEFF") ? s.substring(1) : s;
}
private class CsvMappableSource implements MappableSource {
@Override
public String[] getColumnNames() {
String header = getHeaderLine();
if (header != null) {
CSVReader csvReader = new CSVReader(new StringReader(header), getSeparatorChar());
try {
return csvReader.readNext();
} catch (IOException ex) {
LOGGER.log(Level.WARNING, "could not read CSV column names: {0}", ex.toString());
}
}
return new String[0];
}
@Override
public String getName() {
return getPrimaryFile().getNameExt();
}
@Override
public List getAttributeDescriptors() {
List descriptors = new ArrayList<>();
for (String name : getColumnNames()) {
descriptors.add(new SourceAttributeDescriptor(name, String.class));
}
return descriptors;
}
@Override
public String[][] getContents() {
try {
String contents = CsvDataObject.this.getContents();
int skipLines = getSkipLines();
CSVReader csvReader = new CSVReader(new StringReader(contents), getSeparatorChar(), DEFAULT_QUOTE_CHAR, skipLines);
List rows = csvReader.readAll();
return rows.toArray(new String[0][0]);
} catch (IOException ex) {
LOGGER.warning(ex.toString());
}
return new String[0][0];
}
@Override
public SourceRecordIterator getRecordIterator() {
return new CsvRecordGenerator();
}
@Override
public SourceRecord getGlobals() {
return SourceRecord.empty();
}
}
private class CsvRecordGenerator extends SourceRecordGenerator {
private final List descriptors = mappableSource.getAttributeDescriptors();
private final CSVReader csvReader;
public CsvRecordGenerator() {
String contents = CsvDataObject.this.getContents();
int skipLines = getSkipLines();
csvReader = new CSVReader(new StringReader(contents), getSeparatorChar(), DEFAULT_QUOTE_CHAR, skipLines);
}
@Override
protected SourceRecord getNextRecord() {
if (csvReader == null) { return null; }
try {
String[] next = csvReader.readNext();
return next == null ? null : SourceRecord.createFromColumnValues(descriptors, next);
} catch (IOException ex) {
LOGGER.warning(ex.toString());
return null;
}
}
@Override
public void close() throws IOException {
if (csvReader != null) {
csvReader.close();
}
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy