package org.simantics.simulation.export; import java.io.File; import java.io.IOException; import java.text.DecimalFormatSymbols; import java.util.Collections; import java.util.List; import java.util.Locale; import org.eclipse.core.runtime.preferences.InstanceScope; import org.eclipse.jface.preference.IPreferenceStore; import org.eclipse.ui.preferences.ScopedPreferenceStore; import org.osgi.service.prefs.Preferences; import org.simantics.databoard.Accessors; import org.simantics.databoard.Bindings; import org.simantics.databoard.Datatypes; import org.simantics.databoard.accessor.RecordAccessor; import org.simantics.databoard.accessor.error.AccessorConstructionException; import org.simantics.databoard.accessor.error.AccessorException; import org.simantics.databoard.accessor.reference.ChildReference; import org.simantics.databoard.binding.mutable.Variant; import org.simantics.databoard.type.Datatype; import org.simantics.databoard.type.DoubleType; import org.simantics.databoard.type.RecordType; import org.simantics.export.core.ExportContext; import org.simantics.export.core.error.ExportException; import org.simantics.export.core.intf.FormatClass; import org.simantics.export.core.manager.Content; import org.simantics.history.HistoryException; import org.simantics.history.csv.ColumnSeparator; import org.simantics.history.csv.DecimalSeparator; /** * This class represents the CSV (Comma Separated Value) file format. * * @author toni.kalajainen@semantum.fi */ public class CSVFormat implements FormatClass { // Accessor paths public static ChildReference P_CSV_COLUMN_SEPARATOR = ChildReference.parsePath("Comma Separated Value (CSV)/Column Separator"); public static ChildReference P_CSV_DECIMAL_SEPARATOR = ChildReference.parsePath("Comma Separated Value (CSV)/Decimal Separator"); public static ChildReference P_CSV_TIME_STEP = ChildReference.parsePath("Comma Separated Value (CSV)/Time Step"); static RecordType options; static RecordType csvOptions; static { Datatype second = new DoubleType("s"); csvOptions = new RecordType(); csvOptions.addComponent("Time Step", second); csvOptions.addComponent("Column Separator", Datatypes.STRING); csvOptions.addComponent("Decimal Separator", Datatypes.STRING); options = new RecordType(); options.addComponent("Comma Separated Value (CSV)", csvOptions); } @Override public RecordType options(ExportContext context) throws ExportException { return options; } @Override public List validate(ExportContext context, Variant options) throws ExportException { return Collections.emptyList(); } @Override public void fillDefaultPrefs( ExportContext ctx, Variant options ) throws ExportException { // 1. Figure out suitable default values IPreferenceStore csvnode = new ScopedPreferenceStore( InstanceScope.INSTANCE, CSVPreferences.P_NODE ); Double timeStep = CSVPreferences.DEFAULT_CSV_TIME_STEP; String decimalSeparator = "."; String columnSeparator = "\t"; Locale locale = Locale.getDefault(); DecimalFormatSymbols symbols = DecimalFormatSymbols.getInstance( locale ); decimalSeparator = symbols.getDecimalSeparator()+""; columnSeparator = decimalSeparator.equals(",")?"\\t":","; if (csvnode != null) { if ( csvnode.contains(CSVPreferences.P_CSV_TIME_STEP) ) timeStep = csvnode.getDouble(CSVPreferences.P_CSV_TIME_STEP); if ( csvnode.contains(CSVPreferences.P_CSV_DECIMAL_SEPARATOR) ) decimalSeparator = csvnode.getString(CSVPreferences.P_CSV_DECIMAL_SEPARATOR); if ( csvnode.contains(CSVPreferences.P_CSV_COLUMN_SEPARATOR) ) columnSeparator = csvnode.getString(CSVPreferences.P_CSV_COLUMN_SEPARATOR); } // 2. Write default values try { RecordAccessor ra = Accessors.getAccessor(options); ra.setValue(P_CSV_COLUMN_SEPARATOR, Bindings.STRING, columnSeparator); ra.setValue(P_CSV_DECIMAL_SEPARATOR, Bindings.STRING, decimalSeparator); ra.setValue(P_CSV_TIME_STEP, Bindings.DOUBLE, timeStep); } catch (AccessorConstructionException e) { throw new ExportException(e); } catch (AccessorException e) { throw new ExportException(e); } } @Override public void savePref(Variant options, Preferences contentScopeNode, Preferences workbenchScopeNode) throws ExportException { try { RecordAccessor ra = Accessors.getAccessor(options); String columnSeparator = (String) ra.getValue( P_CSV_COLUMN_SEPARATOR, Bindings.STRING ); if ( columnSeparator != null ) workbenchScopeNode.put(CSVPreferences.P_CSV_COLUMN_SEPARATOR, columnSeparator); String decimalSeparator = (String) ra.getValue(P_CSV_DECIMAL_SEPARATOR, Bindings.STRING ); if ( decimalSeparator != null ) workbenchScopeNode.put(CSVPreferences.P_CSV_DECIMAL_SEPARATOR, decimalSeparator); Double timeStep = (Double) ra.getValue(P_CSV_TIME_STEP, Bindings.DOUBLE ); if ( timeStep != null ) contentScopeNode.putDouble(CSVPreferences.P_CSV_TIME_STEP, timeStep); } catch (AccessorConstructionException e) { throw new ExportException(e); } catch (AccessorException e) { throw new ExportException(e); } } @Override public void loadPref(Variant options, Preferences contentScopeNode, Preferences workbenchScopeNode) throws ExportException { try { RecordAccessor ra = Accessors.getAccessor(options); String columnSeparator = workbenchScopeNode.get(CSVPreferences.P_CSV_COLUMN_SEPARATOR, null); if ( columnSeparator != null ) ra.setValue(P_CSV_COLUMN_SEPARATOR, Bindings.STRING, columnSeparator ); String decimalSeparator = workbenchScopeNode.get(CSVPreferences.P_CSV_DECIMAL_SEPARATOR, null); if ( decimalSeparator != null ) ra.setValue(P_CSV_DECIMAL_SEPARATOR, Bindings.STRING, decimalSeparator ); Double timeStep = contentScopeNode.getDouble(CSVPreferences.P_CSV_TIME_STEP, 0); if ( timeStep != null ) ra.setValue(P_CSV_TIME_STEP, Bindings.DOUBLE, timeStep ); } catch (AccessorConstructionException e) { throw new ExportException(e); } catch (AccessorException e) { throw new ExportException(e); } } @Override public Object createFile(ExportContext context, File outputFile, Variant options) throws ExportException { CSVWriter writer = new CSVWriter(); writer.file = outputFile; try { /// Read configurations RecordAccessor ra = Accessors.getAccessor(options); // Start, End time Double startTime = (Double) ra.getValue( ExperimentExportClass.P_EXPERIMENT_START, Bindings.DOUBLE ); Double endTime = (Double) ra.getValue( ExperimentExportClass.P_EXPERIMENT_END, Bindings.DOUBLE ); writer.setTimeRange(startTime, endTime); // Separators String columnSeparator = (String) ra.getValue( CSVFormat.P_CSV_COLUMN_SEPARATOR, Bindings.STRING ); writer.setColumnSeparator(ColumnSeparator.fromPreference(columnSeparator)); String decimalSeparator = (String) ra.getValue( CSVFormat.P_CSV_DECIMAL_SEPARATOR, Bindings.STRING ); writer.setDecimalSeparator(DecimalSeparator.fromPreference(decimalSeparator)); Double timeStep = (Double) ra.getValue( CSVFormat.P_CSV_TIME_STEP, Bindings.DOUBLE ); writer.setTimeStep(timeStep); } catch (AccessorConstructionException e) { throw new ExportException(e); } catch (AccessorException e) { throw new ExportException(e); } return writer; } @Override public Object openFile(ExportContext context, File inputFile, Variant options) throws ExportException { throw new ExportException("Not implemented"); } @Override public void closeFile(ExportContext context, Object handle_) throws ExportException { CSVWriter handle = (CSVWriter) handle_; try { handle.write(); } catch (IOException e) { throw new ExportException(e); } catch (HistoryException e) { throw new ExportException(e); } } @Override public void addAttachment(ExportContext context, Object handle, List attachments) throws ExportException { throw new ExportException( "Cannot add attachments to a CSV file." ); } }