--- /dev/null
+/*******************************************************************************\r
+ * Copyright (c) 2012 Association for Decentralized Information Management in\r
+ * Industry THTH ry.\r
+ * All rights reserved. This program and the accompanying materials\r
+ * are made available under the terms of the Eclipse Public License v1.0\r
+ * which accompanies this distribution, and is available at\r
+ * http://www.eclipse.org/legal/epl-v10.html\r
+ *\r
+ * Contributors:\r
+ * VTT Technical Research Centre of Finland - initial API and implementation\r
+ *******************************************************************************/\r
+package org.simantics.charts.ui;\r
+\r
+import java.io.BufferedOutputStream;\r
+import java.io.File;\r
+import java.io.FileOutputStream;\r
+import java.io.IOException;\r
+import java.io.PrintStream;\r
+import java.io.RandomAccessFile;\r
+import java.lang.reflect.InvocationTargetException;\r
+import java.util.ArrayList;\r
+import java.util.Collection;\r
+import java.util.HashSet;\r
+import java.util.List;\r
+import java.util.Set;\r
+\r
+import org.eclipse.core.commands.ExecutionException;\r
+import org.eclipse.core.runtime.IProgressMonitor;\r
+import org.eclipse.core.runtime.IStatus;\r
+import org.eclipse.core.runtime.Status;\r
+import org.eclipse.core.runtime.SubMonitor;\r
+import org.eclipse.core.runtime.preferences.IScopeContext;\r
+import org.eclipse.core.runtime.preferences.InstanceScope;\r
+import org.eclipse.jface.operation.IRunnableWithProgress;\r
+import org.osgi.service.prefs.BackingStoreException;\r
+import org.osgi.service.prefs.Preferences;\r
+import org.simantics.Simantics;\r
+import org.simantics.charts.Activator;\r
+import org.simantics.charts.editor.ChartData;\r
+import org.simantics.charts.editor.ChartKeys;\r
+import org.simantics.databoard.binding.error.BindingException;\r
+import org.simantics.databoard.serialization.SerializationException;\r
+import org.simantics.db.ReadGraph;\r
+import org.simantics.db.Resource;\r
+import org.simantics.db.Session;\r
+import org.simantics.db.common.NamedResource;\r
+import org.simantics.db.common.request.UniqueRead;\r
+import org.simantics.db.common.utils.Logger;\r
+import org.simantics.db.exception.DatabaseException;\r
+import org.simantics.db.layer0.request.PossibleModel;\r
+import org.simantics.history.HistoryException;\r
+import org.simantics.history.csv.CSVFormatter;\r
+import org.simantics.modeling.preferences.CSVPreferences;\r
+import org.simantics.utils.datastructures.hints.IHintContext.Key;\r
+import org.simantics.utils.format.FormattingUtils;\r
+import org.simantics.utils.ui.dialogs.ShowMessage;\r
+\r
+/**\r
+ * @author Antti Villberg\r
+ */\r
+public class CSVExporter implements IRunnableWithProgress {\r
+\r
+ CSVExportPlan exportModel;\r
+\r
+ public CSVExporter(CSVExportPlan exportModel) {\r
+ this.exportModel = exportModel;\r
+ }\r
+\r
+ @Override\r
+ public void run(IProgressMonitor monitor) throws InvocationTargetException, InterruptedException {\r
+ SubMonitor progress = SubMonitor.convert(monitor, 50);\r
+ try {\r
+ exportModel(progress.newChild(50, SubMonitor.SUPPRESS_NONE));\r
+ } catch (IOException e) {\r
+ throw new InvocationTargetException(e);\r
+ } catch (DatabaseException e) {\r
+ throw new InvocationTargetException(e);\r
+ } catch (BindingException e) {\r
+ throw new InvocationTargetException(e);\r
+ } finally {\r
+ monitor.done();\r
+ }\r
+ }\r
+\r
+ void exportModel(SubMonitor mon) throws IOException, DatabaseException, SerializationException, BindingException{\r
+ \r
+ try {\r
+ doExport(mon, exportModel.exportLocation, exportModel);\r
+ } catch (ExecutionException e) {\r
+ e.printStackTrace();\r
+ Logger.defaultLogError(e);\r
+ mon.setCanceled(true);\r
+ ShowMessage.showError("Export failed.", "Internal application error in export. See log for details.");\r
+ } finally {\r
+ mon.setWorkRemaining(0);\r
+ }\r
+ \r
+ }\r
+ \r
+ private static Set<Resource> resolveContainingModels(final Collection<NamedResource> res) throws DatabaseException {\r
+ return Simantics.getSession().syncRequest(new UniqueRead<Set<Resource>>() {\r
+ @Override\r
+ public Set<Resource> perform(ReadGraph graph) throws DatabaseException {\r
+ Set<Resource> models = new HashSet<Resource>();\r
+ for (NamedResource r : res) {\r
+ Resource m = graph.syncRequest(new PossibleModel(r.getResource()));\r
+ if (m != null)\r
+ models.add(m);\r
+ }\r
+ return models;\r
+ }\r
+ });\r
+ }\r
+ \r
+ public static void doExport(IProgressMonitor monitor, final File f, final CSVExportPlan plan) throws ExecutionException, IOException {\r
+ \r
+ IScopeContext context = InstanceScope.INSTANCE;\r
+ Preferences node = context.getNode(CSVPreferences.P_NODE);\r
+\r
+ node.putDouble(CSVPreferences.P_CSV_START_TIME, plan.startTime);\r
+ node.putDouble(CSVPreferences.P_CSV_TIME_STEP, plan.timeStep);\r
+ node.put(CSVPreferences.P_CSV_DECIMAL_SEPARATOR, plan.decimalSeparator.toPreference());\r
+ node.put(CSVPreferences.P_CSV_COLUMN_SEPARATOR, plan.columnSeparator.toPreference());\r
+ \r
+ node.putBoolean(CSVPreferences.P_CSV_RESAMPLE, plan.resample);\r
+ node.put(CSVPreferences.P_CSV_SAMPLING_MODE, plan.samplingMode.toPreference());\r
+ \r
+ node.putInt(CSVPreferences.P_CSV_TIME_DIGITS, plan.timeDigits);\r
+ node.putInt(CSVPreferences.P_CSV_FLOAT_DIGITS, plan.floatDigits);\r
+ node.putInt(CSVPreferences.P_CSV_DOUBLE_DIGITS, plan.doubleDigits);\r
+\r
+ try {\r
+ node.flush();\r
+ } catch (BackingStoreException ex) {\r
+ Activator.getDefault().getLog().log(\r
+ new Status(IStatus.WARNING, Activator.PLUGIN_ID, "Could not store preferences for node " + node.absolutePath()));\r
+ }\r
+\r
+ Set<Resource> models;\r
+ try {\r
+ models = resolveContainingModels(plan.models);\r
+ } catch (DatabaseException e3) {\r
+ throw new ExecutionException("Containing model resolution failed.", e3);\r
+ }\r
+ if (models.isEmpty())\r
+ throw new ExecutionException("Selected resources are not part of any model");\r
+ if (models.size() > 1)\r
+ throw new ExecutionException("Selected resources are part of several models, only subscriptions from a single model can be selected");\r
+ Resource model = models.iterator().next();\r
+ Key chartDataKey = ChartKeys.chartSourceKey(model);\r
+ \r
+ final ChartData data = Simantics.getProject().getHint(chartDataKey);\r
+ if ( data == null ) {\r
+ throw new ExecutionException("There is no "+chartDataKey);\r
+ }\r
+ if ( data.history == null ) {\r
+ throw new ExecutionException("There is no history in "+chartDataKey);\r
+ }\r
+\r
+ final CSVFormatter csv = new CSVFormatter();\r
+\r
+ csv.setStartTime( plan.startTime );\r
+ csv.setTimeStep( plan.timeStep );\r
+ csv.setDecimalSeparator( plan.decimalSeparator );\r
+ csv.setColumnSeparator( plan.columnSeparator );\r
+ csv.setResample( plan.resample );\r
+ csv.setNumberInterpolation( plan.samplingMode );\r
+ csv.setTimeFormat( FormattingUtils.significantDigitFormat( plan.timeDigits ) );\r
+ csv.setFloatFormat( FormattingUtils.significantDigitFormat( plan.floatDigits ) );\r
+ csv.setNumberFormat( FormattingUtils.significantDigitFormat( plan.doubleDigits ) );\r
+\r
+ try {\r
+ Session session = Simantics.getSession();\r
+ List<Resource> list = new ArrayList<Resource>();\r
+ for(NamedResource nr : plan.models) list.add(nr.getResource());\r
+ session.sync( new CSVParamsQuery(data.history, csv, list) );\r
+ csv.sort();\r
+ } catch (DatabaseException e2) {\r
+ throw new ExecutionException(e2.getMessage(), e2);\r
+ } catch (HistoryException e) {\r
+ throw new ExecutionException(e.getMessage(), e);\r
+ }\r
+ \r
+ try {\r
+ // Ensure all views are built.\r
+ monitor.beginTask("Exporting Time Series as CSV...", IProgressMonitor.UNKNOWN);\r
+ try {\r
+ data.collector.flush();\r
+ if ( !f.exists() ) {\r
+ f.createNewFile();\r
+ } else {\r
+ RandomAccessFile raf = new RandomAccessFile(f, "rw");\r
+ raf.setLength(0);\r
+ raf.close();\r
+ }\r
+ \r
+ FileOutputStream fos = new FileOutputStream(f, true);\r
+ BufferedOutputStream bos = new BufferedOutputStream( fos );\r
+ try {\r
+ PrintStream ps = new PrintStream( bos );\r
+ csv.formulate2( new CSVProgressMonitor( monitor ), ps );\r
+ bos.flush();\r
+ } finally {\r
+ fos.close();\r
+ }\r
+ } catch (HistoryException e) {\r
+ throw new ExecutionException(e.getMessage(), e);\r
+ } catch (IOException e1) {\r
+ throw new ExecutionException(e1.getMessage(), e1);\r
+ }\r
+ monitor.setTaskName("Done");\r
+ } finally {\r
+ monitor.done();\r
+ }\r
+ \r
+ }\r
+ \r
+}\r