-/*******************************************************************************\r
- * Copyright (c) 2011 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.editor;\r
-\r
-import java.awt.Toolkit;\r
-import java.awt.datatransfer.Clipboard;\r
-import java.awt.datatransfer.StringSelection;\r
-import java.io.BufferedWriter;\r
-import java.io.File;\r
-import java.io.FileOutputStream;\r
-import java.io.IOException;\r
-import java.io.OutputStreamWriter;\r
-import java.lang.reflect.InvocationTargetException;\r
-import java.nio.charset.Charset;\r
-import java.util.Collections;\r
-import java.util.List;\r
-import java.util.concurrent.atomic.AtomicBoolean;\r
-\r
-import org.eclipse.core.commands.AbstractHandler;\r
-import org.eclipse.core.commands.ExecutionEvent;\r
-import org.eclipse.core.commands.ExecutionException;\r
-import org.eclipse.core.runtime.IProgressMonitor;\r
-import org.eclipse.core.runtime.preferences.InstanceScope;\r
-import org.eclipse.jface.action.IStatusLineManager;\r
-import org.eclipse.jface.operation.IRunnableWithProgress;\r
-import org.eclipse.jface.preference.IPreferenceStore;\r
-import org.eclipse.swt.SWT;\r
-import org.eclipse.swt.widgets.FileDialog;\r
-import org.eclipse.swt.widgets.Shell;\r
-import org.eclipse.ui.IEditorPart;\r
-import org.eclipse.ui.PlatformUI;\r
-import org.eclipse.ui.handlers.HandlerUtil;\r
-import org.eclipse.ui.preferences.ScopedPreferenceStore;\r
-import org.simantics.charts.ui.CSVProgressMonitor;\r
-import org.simantics.databoard.binding.error.BindingException;\r
-import org.simantics.databoard.parser.StringEscapeUtils;\r
-import org.simantics.databoard.util.Bean;\r
-import org.simantics.databoard.util.StreamUtil;\r
-import org.simantics.history.HistoryException;\r
-import org.simantics.history.ItemManager;\r
-import org.simantics.history.csv.CSVFormatter;\r
-import org.simantics.history.csv.ColumnSeparator;\r
-import org.simantics.history.csv.DecimalSeparator;\r
-import org.simantics.history.csv.ExportInterpolation;\r
-import org.simantics.history.util.subscription.SamplingFormat;\r
-import org.simantics.modeling.preferences.CSVPreferences;\r
-import org.simantics.trend.configuration.TrendItem;\r
-import org.simantics.trend.impl.TrendNode;\r
-import org.simantics.utils.format.FormattingUtils;\r
-import org.simantics.utils.ui.ErrorLogger;\r
-\r
-/**\r
- * @author Tuukka Lehtonen\r
- */\r
-public class ChartCopyHandler extends AbstractHandler {\r
-\r
- String lastFile;\r
- \r
- @Override\r
- public Object execute(ExecutionEvent event) throws ExecutionException {\r
- IEditorPart ep = HandlerUtil.getActiveEditor(event);\r
- if (ep instanceof TimeSeriesEditor == false) return null;\r
- TimeSeriesEditor editor = (TimeSeriesEditor) ep;\r
- final TrendNode trendNode = editor.trendNode;\r
- IStatusLineManager status = editor.getEditorSite().getActionBars().getStatusLineManager();\r
- final Shell shell = HandlerUtil.getActiveShell(event);\r
-\r
- final AtomicBoolean result = new AtomicBoolean(false);\r
- try {\r
- PlatformUI.getWorkbench().getProgressService().busyCursorWhile(new IRunnableWithProgress() {\r
- @Override\r
- public void run(IProgressMonitor monitor) throws InvocationTargetException, InterruptedException {\r
- result.set( copyDataToClipboard(monitor, trendNode, Format.JOINED_TIME, shell) );\r
- }\r
- });\r
- if (!result.get()) {\r
- status.setMessage("No data to copy");\r
- } else {\r
- status.setMessage("Copied chart data to clipboard");\r
- }\r
- status.setErrorMessage(null);\r
- } catch (InvocationTargetException e) {\r
- ErrorLogger.defaultLogError(e.getCause());\r
- } catch (InterruptedException e) {\r
- ErrorLogger.defaultLogError(e);\r
- }\r
-\r
- return null;\r
- }\r
-\r
- static enum Format {\r
- TIME_VALUE_PAIRS,\r
- JOINED_TIME\r
- }\r
-\r
- public boolean copyDataToClipboard(IProgressMonitor monitor, TrendNode t, Format format, final Shell shell) {\r
- Charset UTF8 = Charset.forName("UTF-8");\r
- try {\r
- // String builder can be really slow when it is extended many times over. \r
- // Instead stream to file with buffering\r
-// StringBuilder sb = new StringBuilder();\r
- IPreferenceStore csvnode = new ScopedPreferenceStore( InstanceScope.INSTANCE, CSVPreferences.P_NODE );\r
- String ext = csvnode.getString(CSVPreferences.P_CSV_FILE_EXTENSION);\r
- File tmpFile = File.createTempFile("clipboard", ext);\r
- tmpFile.deleteOnExit();\r
- FileOutputStream fos = new FileOutputStream(tmpFile); \r
- BufferedWriter w = new BufferedWriter(new OutputStreamWriter(fos, UTF8));\r
- try {\r
- ItemManager im = new ItemManager( t.historian.getItems() );\r
- CSVFormatter formatter = new CSVFormatter(); \r
- formatter.setTimeRange(t.horizRuler.from, t.horizRuler.end);\r
- \r
- // Write preferences\r
- formatter.setStartTime( csvnode.getDouble(CSVPreferences.P_CSV_START_TIME) );\r
- formatter.setTimeStep( csvnode.getDouble(CSVPreferences.P_CSV_TIME_STEP) );\r
- formatter.setDecimalSeparator( DecimalSeparator.fromPreference(csvnode.getString(CSVPreferences.P_CSV_DECIMAL_SEPARATOR) ) );\r
- formatter.setColumnSeparator( ColumnSeparator.fromPreference(StringEscapeUtils.unescape( csvnode.getString(CSVPreferences.P_CSV_COLUMN_SEPARATOR) ) ) );\r
- formatter.setResample( csvnode.getBoolean(CSVPreferences.P_CSV_RESAMPLE) );\r
- formatter.setNumberInterpolation( ExportInterpolation.fromPreference (csvnode.getString(CSVPreferences.P_CSV_SAMPLING_MODE) ) );\r
- formatter.setTimeFormat( FormattingUtils.significantDigitFormat( csvnode.getInt(CSVPreferences.P_CSV_TIME_DIGITS) ) );\r
- formatter.setFloatFormat( FormattingUtils.significantDigitFormat( csvnode.getInt(CSVPreferences.P_CSV_FLOAT_DIGITS) ) );\r
- formatter.setNumberFormat( FormattingUtils.significantDigitFormat( csvnode.getInt(CSVPreferences.P_CSV_DOUBLE_DIGITS) ) );\r
- \r
- for (TrendItem i : t.spec.items) {\r
- if (i.hidden) continue;\r
- List<Bean> items = im.search("variableId", i.variableId);\r
- Collections.sort(items, SamplingFormat.INTERVAL_COMPARATOR);\r
- if (items.isEmpty()) continue;\r
- Bean config = items.get(0);\r
- String historyId = (String) config.getFieldUnchecked("id");\r
- formatter.addItem( t.historian, historyId, i.simpleLabel, i.variableReference, i.unit);\r
- }\r
- formatter.sort();\r
- switch (format) {\r
- case TIME_VALUE_PAIRS: \r
-// formatter.formulate1(new CSVProgressMonitor(monitor), w);\r
- break;\r
- case JOINED_TIME:\r
- formatter.formulate2(new CSVProgressMonitor(monitor), w);\r
- break;\r
- default:\r
- throw new UnsupportedOperationException("unsupported format " + format);\r
- }\r
- w.flush();\r
- \r
- if (tmpFile.length()==0) return false;\r
- \r
- Toolkit toolkit = Toolkit.getDefaultToolkit();\r
- Clipboard clipboard = toolkit.getSystemClipboard();\r
- w.flush();\r
- fos.close();\r
- fos = null;\r
- \r
- System.out.println("Exported to "+tmpFile+" size: "+tmpFile.length());\r
- if ( tmpFile.length() > 10*1024*1024 ) {\r
-// String msg = "The data has been written to temporary file:\n"+tmpFile.getCanonicalPath();\r
-// ShowMessage.showInformation( shell.getDisplay(), "Too much data for clipboard.", msg);\r
- final File csvFile = tmpFile;\r
- tmpFile = null;\r
- shell.getDisplay().asyncExec( new Runnable() {\r
- @Override\r
- public void run() {\r
- FileDialog fd = new FileDialog(shell, SWT.SAVE);\r
- fd.setText("Write CSV to File");\r
- fd.setFileName( lastFile!=null ? lastFile : csvFile.getAbsolutePath() );\r
- String newFile = fd.open();\r
- if ( newFile != null ) {\r
- lastFile = newFile;\r
- File ff = new File( newFile );\r
- ff.delete();\r
- csvFile.renameTo( ff );\r
- } else {\r
- csvFile.delete();\r
- }\r
- }} ); \r
- } else {\r
- String str = StreamUtil.readString(tmpFile, UTF8);\r
- \r
- StringSelection strSel = new StringSelection(str);\r
- clipboard.setContents(strSel, null);\r
- }\r
- \r
- } catch (BindingException e1) {\r
- ErrorLogger.defaultLogError(e1);\r
- return false;\r
- } catch (IOException e) {\r
- ErrorLogger.defaultLogError(e);\r
- } finally {\r
- if ( fos != null ) try { fos.close(); } catch (IOException e) { ErrorLogger.defaultLogError(e); }\r
- if ( tmpFile != null ) tmpFile.delete();\r
- } \r
-\r
- return true;\r
- } catch (HistoryException e) {\r
- ErrorLogger.defaultLogError(e);\r
- } catch (IOException e) {\r
- ErrorLogger.defaultLogError(e);\r
- }\r
- return false;\r
- }\r
-\r
-}\r
+/*******************************************************************************
+ * Copyright (c) 2011,2020 Association for Decentralized Information Management
+ * in Industry THTH ry.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * VTT Technical Research Centre of Finland - initial API and implementation
+ * Semantum Oy - #501
+ *******************************************************************************/
+package org.simantics.charts.editor;
+
+import java.awt.Toolkit;
+import java.awt.datatransfer.Clipboard;
+import java.awt.datatransfer.StringSelection;
+import java.io.BufferedWriter;
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.OutputStreamWriter;
+import java.lang.reflect.InvocationTargetException;
+import java.nio.charset.Charset;
+import java.util.Collections;
+import java.util.List;
+import java.util.concurrent.atomic.AtomicBoolean;
+
+import org.eclipse.core.commands.AbstractHandler;
+import org.eclipse.core.commands.ExecutionEvent;
+import org.eclipse.core.commands.ExecutionException;
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.core.runtime.preferences.InstanceScope;
+import org.eclipse.jface.action.IStatusLineManager;
+import org.eclipse.jface.operation.IRunnableWithProgress;
+import org.eclipse.jface.preference.IPreferenceStore;
+import org.eclipse.jface.preference.PreferenceDialog;
+import org.eclipse.jface.window.Window;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.widgets.FileDialog;
+import org.eclipse.swt.widgets.Shell;
+import org.eclipse.ui.IEditorPart;
+import org.eclipse.ui.PlatformUI;
+import org.eclipse.ui.dialogs.PreferencesUtil;
+import org.eclipse.ui.handlers.HandlerUtil;
+import org.eclipse.ui.preferences.ScopedPreferenceStore;
+import org.simantics.charts.ui.CSVProgressMonitor;
+import org.simantics.databoard.binding.error.BindingException;
+import org.simantics.databoard.parser.StringEscapeUtils;
+import org.simantics.databoard.util.Bean;
+import org.simantics.databoard.util.StreamUtil;
+import org.simantics.history.HistoryException;
+import org.simantics.history.ItemManager;
+import org.simantics.history.csv.CSVFormatter;
+import org.simantics.history.csv.ColumnSeparator;
+import org.simantics.history.csv.DecimalSeparator;
+import org.simantics.history.csv.ExportInterpolation;
+import org.simantics.history.util.subscription.SamplingFormat;
+import org.simantics.modeling.preferences.CSVPreferences;
+import org.simantics.trend.configuration.TrendItem;
+import org.simantics.trend.impl.TrendNode;
+import org.simantics.utils.format.FormattingUtils;
+import org.simantics.utils.ui.ErrorLogger;
+
+/**
+ * @author Tuukka Lehtonen
+ */
+public class ChartCopyHandler extends AbstractHandler {
+
+ String lastFile;
+
+ @Override
+ public Object execute(ExecutionEvent event) throws ExecutionException {
+ IEditorPart ep = HandlerUtil.getActiveEditor(event);
+ if (ep instanceof TimeSeriesEditor == false) return null;
+ TimeSeriesEditor editor = (TimeSeriesEditor) ep;
+ final TrendNode trendNode = editor.trendNode;
+ IStatusLineManager status = editor.getEditorSite().getActionBars().getStatusLineManager();
+ final Shell shell = HandlerUtil.getActiveShell(event);
+
+ // Find a good value to use for START_TIME based on the current horizontal ruler
+ // time range and the data start time.
+ IPreferenceStore csvnode = new ScopedPreferenceStore( InstanceScope.INSTANCE, CSVPreferences.P_NODE );
+ double oldStartTime = csvnode.getDouble(CSVPreferences.P_CSV_START_TIME);
+ double timeStep = csvnode.getDouble(CSVPreferences.P_CSV_TIME_STEP);
+ double visibleChartMinTime = trendNode.horizRuler.from;
+ double dataStartTime = trendNode.horizRuler.getItemFromTime();
+ // Find the first sample time that contains data if startTime < _from
+ double n = Math.max(0, Math.ceil((visibleChartMinTime-dataStartTime) / timeStep));
+ double temporaryStartTime = dataStartTime + n*timeStep;
+ csvnode.setValue(CSVPreferences.P_CSV_START_TIME, temporaryStartTime);
+
+ try {
+ PreferenceDialog dialog = PreferencesUtil.createPreferenceDialogOn(
+ shell, "org.simantics.modeling.csv.preferences",
+ new String[] { "org.simantics.modeling.csv.preferences" },
+ null);
+ dialog.setMessage("Select Used CSV Export Settings");
+ if (dialog.open() != Window.OK)
+ return null;
+
+ AtomicBoolean result = new AtomicBoolean(false);
+ PlatformUI.getWorkbench().getProgressService().busyCursorWhile(new IRunnableWithProgress() {
+ @Override
+ public void run(IProgressMonitor monitor) throws InvocationTargetException, InterruptedException {
+ result.set( copyDataToClipboard(monitor, trendNode, Format.JOINED_TIME, shell) );
+ }
+ });
+ if (!result.get()) {
+ status.setMessage("No data to copy");
+ } else {
+ status.setMessage("Copied chart data to clipboard");
+ }
+ status.setErrorMessage(null);
+ } catch (InvocationTargetException e) {
+ ErrorLogger.defaultLogError(e.getCause());
+ } catch (InterruptedException e) {
+ ErrorLogger.defaultLogError(e);
+ } finally {
+ csvnode.setValue(CSVPreferences.P_CSV_START_TIME, oldStartTime);
+ }
+
+ return null;
+ }
+
+ static enum Format {
+ TIME_VALUE_PAIRS,
+ JOINED_TIME
+ }
+
+ public boolean copyDataToClipboard(IProgressMonitor monitor, TrendNode t, Format format, final Shell shell) {
+ Charset UTF8 = Charset.forName("UTF-8");
+ try {
+ // String builder can be really slow when it is extended many times over.
+ // Instead stream to file with buffering
+// StringBuilder sb = new StringBuilder();
+ IPreferenceStore csvnode = new ScopedPreferenceStore( InstanceScope.INSTANCE, CSVPreferences.P_NODE );
+ String ext = csvnode.getString(CSVPreferences.P_CSV_FILE_EXTENSION);
+ File tmpFile = File.createTempFile("clipboard", ext);
+ tmpFile.deleteOnExit();
+ FileOutputStream fos = new FileOutputStream(tmpFile);
+ BufferedWriter w = new BufferedWriter(new OutputStreamWriter(fos, UTF8));
+ try {
+ ItemManager im = new ItemManager( t.historian.getItems() );
+ CSVFormatter formatter = new CSVFormatter();
+ formatter.setTimeRange(t.horizRuler.from, t.horizRuler.end);
+
+ // Write preferences
+ formatter.setStartTime( csvnode.getDouble(CSVPreferences.P_CSV_START_TIME) );
+ formatter.setTimeStep( csvnode.getDouble(CSVPreferences.P_CSV_TIME_STEP) );
+ formatter.setDecimalSeparator( DecimalSeparator.fromPreference(csvnode.getString(CSVPreferences.P_CSV_DECIMAL_SEPARATOR) ) );
+ formatter.setColumnSeparator( ColumnSeparator.fromPreference(StringEscapeUtils.unescape( csvnode.getString(CSVPreferences.P_CSV_COLUMN_SEPARATOR) ) ) );
+ formatter.setResample( csvnode.getBoolean(CSVPreferences.P_CSV_RESAMPLE) );
+ formatter.setNumberInterpolation( ExportInterpolation.fromPreference (csvnode.getString(CSVPreferences.P_CSV_SAMPLING_MODE) ) );
+ formatter.setTimeFormat( FormattingUtils.significantDigitFormat( csvnode.getInt(CSVPreferences.P_CSV_TIME_DIGITS) ) );
+ formatter.setFloatFormat( FormattingUtils.significantDigitFormat( csvnode.getInt(CSVPreferences.P_CSV_FLOAT_DIGITS) ) );
+ formatter.setNumberFormat( FormattingUtils.significantDigitFormat( csvnode.getInt(CSVPreferences.P_CSV_DOUBLE_DIGITS) ) );
+
+ for (TrendItem i : t.spec.items) {
+ if (i.hidden) continue;
+ List<Bean> items = im.search("variableId", i.variableId);
+ Collections.sort(items, SamplingFormat.INTERVAL_COMPARATOR);
+ if (items.isEmpty()) continue;
+ Bean config = items.get(0);
+ String historyId = (String) config.getFieldUnchecked("id");
+ formatter.addItem( t.historian, historyId, i.simpleLabel, i.variableReference, i.unit);
+ }
+ formatter.sort();
+ switch (format) {
+ case TIME_VALUE_PAIRS:
+// formatter.formulate1(new CSVProgressMonitor(monitor), w);
+ break;
+ case JOINED_TIME:
+ formatter.formulate2(new CSVProgressMonitor(monitor), w);
+ break;
+ default:
+ throw new UnsupportedOperationException("unsupported format " + format);
+ }
+ w.flush();
+
+ if (tmpFile.length()==0) return false;
+
+ Toolkit toolkit = Toolkit.getDefaultToolkit();
+ Clipboard clipboard = toolkit.getSystemClipboard();
+ w.flush();
+ fos.close();
+ fos = null;
+
+ System.out.println("Exported to "+tmpFile+" size: "+tmpFile.length());
+ if ( tmpFile.length() > 10*1024*1024 ) {
+// String msg = "The data has been written to temporary file:\n"+tmpFile.getCanonicalPath();
+// ShowMessage.showInformation( shell.getDisplay(), "Too much data for clipboard.", msg);
+ final File csvFile = tmpFile;
+ tmpFile = null;
+ shell.getDisplay().asyncExec( new Runnable() {
+ @Override
+ public void run() {
+ FileDialog fd = new FileDialog(shell, SWT.SAVE);
+ fd.setText("Write CSV to File");
+ fd.setFileName( lastFile!=null ? lastFile : csvFile.getAbsolutePath() );
+ String newFile = fd.open();
+ if ( newFile != null ) {
+ lastFile = newFile;
+ File ff = new File( newFile );
+ ff.delete();
+ csvFile.renameTo( ff );
+ } else {
+ csvFile.delete();
+ }
+ }} );
+ } else {
+ String str = StreamUtil.readString(tmpFile, UTF8);
+
+ StringSelection strSel = new StringSelection(str);
+ clipboard.setContents(strSel, null);
+ }
+
+ } catch (BindingException e1) {
+ ErrorLogger.defaultLogError(e1);
+ return false;
+ } catch (IOException e) {
+ ErrorLogger.defaultLogError(e);
+ } finally {
+ if ( fos != null ) try { fos.close(); } catch (IOException e) { ErrorLogger.defaultLogError(e); }
+ if ( tmpFile != null ) tmpFile.delete();
+ }
+
+ return true;
+ } catch (HistoryException e) {
+ ErrorLogger.defaultLogError(e);
+ } catch (IOException e) {
+ ErrorLogger.defaultLogError(e);
+ }
+ return false;
+ }
+
+}