X-Git-Url: https://gerrit.simantics.org/r/gitweb?p=simantics%2Fplatform.git;a=blobdiff_plain;f=bundles%2Forg.simantics.charts%2Fsrc%2Forg%2Fsimantics%2Fcharts%2Feditor%2FChartCopyHandler.java;fp=bundles%2Forg.simantics.charts%2Fsrc%2Forg%2Fsimantics%2Fcharts%2Feditor%2FChartCopyHandler.java;h=41b7117e612de048ffa15009e9b562910e3e49bf;hp=0000000000000000000000000000000000000000;hb=969bd23cab98a79ca9101af33334000879fb60c5;hpb=866dba5cd5a3929bbeae85991796acb212338a08 diff --git a/bundles/org.simantics.charts/src/org/simantics/charts/editor/ChartCopyHandler.java b/bundles/org.simantics.charts/src/org/simantics/charts/editor/ChartCopyHandler.java new file mode 100644 index 000000000..41b7117e6 --- /dev/null +++ b/bundles/org.simantics.charts/src/org/simantics/charts/editor/ChartCopyHandler.java @@ -0,0 +1,211 @@ +/******************************************************************************* + * Copyright (c) 2011 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 + *******************************************************************************/ +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.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.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); + + final AtomicBoolean result = new AtomicBoolean(false); + try { + 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); + } + + 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 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; + } + +}