1 /*******************************************************************************
2 * Copyright (c) 2011 Association for Decentralized Information Management in
4 * All rights reserved. This program and the accompanying materials
5 * are made available under the terms of the Eclipse Public License v1.0
6 * which accompanies this distribution, and is available at
7 * http://www.eclipse.org/legal/epl-v10.html
10 * VTT Technical Research Centre of Finland - initial API and implementation
11 *******************************************************************************/
12 package org.simantics.charts.editor;
14 import java.awt.Toolkit;
15 import java.awt.datatransfer.Clipboard;
16 import java.awt.datatransfer.StringSelection;
17 import java.io.BufferedWriter;
19 import java.io.FileOutputStream;
20 import java.io.IOException;
21 import java.io.OutputStreamWriter;
22 import java.lang.reflect.InvocationTargetException;
23 import java.nio.charset.Charset;
24 import java.util.Collections;
25 import java.util.List;
26 import java.util.concurrent.atomic.AtomicBoolean;
28 import org.eclipse.core.commands.AbstractHandler;
29 import org.eclipse.core.commands.ExecutionEvent;
30 import org.eclipse.core.commands.ExecutionException;
31 import org.eclipse.core.runtime.IProgressMonitor;
32 import org.eclipse.core.runtime.preferences.InstanceScope;
33 import org.eclipse.jface.action.IStatusLineManager;
34 import org.eclipse.jface.operation.IRunnableWithProgress;
35 import org.eclipse.jface.preference.IPreferenceStore;
36 import org.eclipse.swt.SWT;
37 import org.eclipse.swt.widgets.FileDialog;
38 import org.eclipse.swt.widgets.Shell;
39 import org.eclipse.ui.IEditorPart;
40 import org.eclipse.ui.PlatformUI;
41 import org.eclipse.ui.handlers.HandlerUtil;
42 import org.eclipse.ui.preferences.ScopedPreferenceStore;
43 import org.simantics.charts.ui.CSVProgressMonitor;
44 import org.simantics.databoard.binding.error.BindingException;
45 import org.simantics.databoard.parser.StringEscapeUtils;
46 import org.simantics.databoard.util.Bean;
47 import org.simantics.databoard.util.StreamUtil;
48 import org.simantics.history.HistoryException;
49 import org.simantics.history.ItemManager;
50 import org.simantics.history.csv.CSVFormatter;
51 import org.simantics.history.csv.ColumnSeparator;
52 import org.simantics.history.csv.DecimalSeparator;
53 import org.simantics.history.csv.ExportInterpolation;
54 import org.simantics.history.util.subscription.SamplingFormat;
55 import org.simantics.modeling.preferences.CSVPreferences;
56 import org.simantics.trend.configuration.TrendItem;
57 import org.simantics.trend.impl.TrendNode;
58 import org.simantics.utils.format.FormattingUtils;
59 import org.simantics.utils.ui.ErrorLogger;
62 * @author Tuukka Lehtonen
64 public class ChartCopyHandler extends AbstractHandler {
69 public Object execute(ExecutionEvent event) throws ExecutionException {
70 IEditorPart ep = HandlerUtil.getActiveEditor(event);
71 if (ep instanceof TimeSeriesEditor == false) return null;
72 TimeSeriesEditor editor = (TimeSeriesEditor) ep;
73 final TrendNode trendNode = editor.trendNode;
74 IStatusLineManager status = editor.getEditorSite().getActionBars().getStatusLineManager();
75 final Shell shell = HandlerUtil.getActiveShell(event);
77 final AtomicBoolean result = new AtomicBoolean(false);
79 PlatformUI.getWorkbench().getProgressService().busyCursorWhile(new IRunnableWithProgress() {
81 public void run(IProgressMonitor monitor) throws InvocationTargetException, InterruptedException {
82 result.set( copyDataToClipboard(monitor, trendNode, Format.JOINED_TIME, shell) );
86 status.setMessage("No data to copy");
88 status.setMessage("Copied chart data to clipboard");
90 status.setErrorMessage(null);
91 } catch (InvocationTargetException e) {
92 ErrorLogger.defaultLogError(e.getCause());
93 } catch (InterruptedException e) {
94 ErrorLogger.defaultLogError(e);
105 public boolean copyDataToClipboard(IProgressMonitor monitor, TrendNode t, Format format, final Shell shell) {
106 Charset UTF8 = Charset.forName("UTF-8");
108 // String builder can be really slow when it is extended many times over.
109 // Instead stream to file with buffering
110 // StringBuilder sb = new StringBuilder();
111 IPreferenceStore csvnode = new ScopedPreferenceStore( InstanceScope.INSTANCE, CSVPreferences.P_NODE );
112 String ext = csvnode.getString(CSVPreferences.P_CSV_FILE_EXTENSION);
113 File tmpFile = File.createTempFile("clipboard", ext);
114 tmpFile.deleteOnExit();
115 FileOutputStream fos = new FileOutputStream(tmpFile);
116 BufferedWriter w = new BufferedWriter(new OutputStreamWriter(fos, UTF8));
118 ItemManager im = new ItemManager( t.historian.getItems() );
119 CSVFormatter formatter = new CSVFormatter();
120 formatter.setTimeRange(t.horizRuler.from, t.horizRuler.end);
123 formatter.setStartTime( csvnode.getDouble(CSVPreferences.P_CSV_START_TIME) );
124 formatter.setTimeStep( csvnode.getDouble(CSVPreferences.P_CSV_TIME_STEP) );
125 formatter.setDecimalSeparator( DecimalSeparator.fromPreference(csvnode.getString(CSVPreferences.P_CSV_DECIMAL_SEPARATOR) ) );
126 formatter.setColumnSeparator( ColumnSeparator.fromPreference(StringEscapeUtils.unescape( csvnode.getString(CSVPreferences.P_CSV_COLUMN_SEPARATOR) ) ) );
127 formatter.setResample( csvnode.getBoolean(CSVPreferences.P_CSV_RESAMPLE) );
128 formatter.setNumberInterpolation( ExportInterpolation.fromPreference (csvnode.getString(CSVPreferences.P_CSV_SAMPLING_MODE) ) );
129 formatter.setTimeFormat( FormattingUtils.significantDigitFormat( csvnode.getInt(CSVPreferences.P_CSV_TIME_DIGITS) ) );
130 formatter.setFloatFormat( FormattingUtils.significantDigitFormat( csvnode.getInt(CSVPreferences.P_CSV_FLOAT_DIGITS) ) );
131 formatter.setNumberFormat( FormattingUtils.significantDigitFormat( csvnode.getInt(CSVPreferences.P_CSV_DOUBLE_DIGITS) ) );
133 for (TrendItem i : t.spec.items) {
134 if (i.hidden) continue;
135 List<Bean> items = im.search("variableId", i.variableId);
136 Collections.sort(items, SamplingFormat.INTERVAL_COMPARATOR);
137 if (items.isEmpty()) continue;
138 Bean config = items.get(0);
139 String historyId = (String) config.getFieldUnchecked("id");
140 formatter.addItem( t.historian, historyId, i.simpleLabel, i.variableReference, i.unit);
144 case TIME_VALUE_PAIRS:
145 // formatter.formulate1(new CSVProgressMonitor(monitor), w);
148 formatter.formulate2(new CSVProgressMonitor(monitor), w);
151 throw new UnsupportedOperationException("unsupported format " + format);
155 if (tmpFile.length()==0) return false;
157 Toolkit toolkit = Toolkit.getDefaultToolkit();
158 Clipboard clipboard = toolkit.getSystemClipboard();
163 System.out.println("Exported to "+tmpFile+" size: "+tmpFile.length());
164 if ( tmpFile.length() > 10*1024*1024 ) {
165 // String msg = "The data has been written to temporary file:\n"+tmpFile.getCanonicalPath();
166 // ShowMessage.showInformation( shell.getDisplay(), "Too much data for clipboard.", msg);
167 final File csvFile = tmpFile;
169 shell.getDisplay().asyncExec( new Runnable() {
172 FileDialog fd = new FileDialog(shell, SWT.SAVE);
173 fd.setText("Write CSV to File");
174 fd.setFileName( lastFile!=null ? lastFile : csvFile.getAbsolutePath() );
175 String newFile = fd.open();
176 if ( newFile != null ) {
178 File ff = new File( newFile );
180 csvFile.renameTo( ff );
186 String str = StreamUtil.readString(tmpFile, UTF8);
188 StringSelection strSel = new StringSelection(str);
189 clipboard.setContents(strSel, null);
192 } catch (BindingException e1) {
193 ErrorLogger.defaultLogError(e1);
195 } catch (IOException e) {
196 ErrorLogger.defaultLogError(e);
198 if ( fos != null ) try { fos.close(); } catch (IOException e) { ErrorLogger.defaultLogError(e); }
199 if ( tmpFile != null ) tmpFile.delete();
203 } catch (HistoryException e) {
204 ErrorLogger.defaultLogError(e);
205 } catch (IOException e) {
206 ErrorLogger.defaultLogError(e);