]> gerrit.simantics Code Review - simantics/platform.git/blob - bundles/org.simantics.charts/src/org/simantics/charts/editor/e4/ChartCopyHandler.java
Migrated source code from Simantics SVN
[simantics/platform.git] / bundles / org.simantics.charts / src / org / simantics / charts / editor / e4 / ChartCopyHandler.java
1 /*******************************************************************************\r
2  * Copyright (c) 2011 Association for Decentralized Information Management in\r
3  * Industry THTH ry.\r
4  * All rights reserved. This program and the accompanying materials\r
5  * are made available under the terms of the Eclipse Public License v1.0\r
6  * which accompanies this distribution, and is available at\r
7  * http://www.eclipse.org/legal/epl-v10.html\r
8  *\r
9  * Contributors:\r
10  *     VTT Technical Research Centre of Finland - initial API and implementation\r
11  *******************************************************************************/\r
12 package org.simantics.charts.editor.e4;\r
13 \r
14 import java.awt.Toolkit;\r
15 import java.awt.datatransfer.Clipboard;\r
16 import java.awt.datatransfer.StringSelection;\r
17 import java.io.BufferedWriter;\r
18 import java.io.File;\r
19 import java.io.FileOutputStream;\r
20 import java.io.IOException;\r
21 import java.io.OutputStreamWriter;\r
22 import java.lang.reflect.InvocationTargetException;\r
23 import java.nio.charset.Charset;\r
24 import java.util.Collections;\r
25 import java.util.List;\r
26 import java.util.concurrent.atomic.AtomicBoolean;\r
27 \r
28 import javax.inject.Named;\r
29 \r
30 import org.eclipse.core.commands.ExecutionException;\r
31 import org.eclipse.core.runtime.IProgressMonitor;\r
32 import org.eclipse.core.runtime.preferences.InstanceScope;\r
33 import org.eclipse.e4.core.di.annotations.CanExecute;\r
34 import org.eclipse.e4.core.di.annotations.Execute;\r
35 import org.eclipse.e4.ui.model.application.ui.basic.MPart;\r
36 import org.eclipse.e4.ui.services.IServiceConstants;\r
37 import org.eclipse.jface.action.IStatusLineManager;\r
38 import org.eclipse.jface.operation.IRunnableWithProgress;\r
39 import org.eclipse.jface.preference.IPreferenceStore;\r
40 import org.eclipse.swt.SWT;\r
41 import org.eclipse.swt.widgets.FileDialog;\r
42 import org.eclipse.swt.widgets.Shell;\r
43 import org.eclipse.ui.IWorkbenchPart;\r
44 import org.eclipse.ui.PlatformUI;\r
45 import org.eclipse.ui.preferences.ScopedPreferenceStore;\r
46 import org.simantics.charts.ui.CSVProgressMonitor;\r
47 import org.simantics.databoard.binding.error.BindingException;\r
48 import org.simantics.databoard.parser.StringEscapeUtils;\r
49 import org.simantics.databoard.util.Bean;\r
50 import org.simantics.databoard.util.StreamUtil;\r
51 import org.simantics.history.HistoryException;\r
52 import org.simantics.history.ItemManager;\r
53 import org.simantics.history.csv.CSVFormatter;\r
54 import org.simantics.history.csv.ColumnSeparator;\r
55 import org.simantics.history.csv.DecimalSeparator;\r
56 import org.simantics.history.csv.ExportInterpolation;\r
57 import org.simantics.history.util.subscription.SamplingFormat;\r
58 import org.simantics.modeling.preferences.CSVPreferences;\r
59 import org.simantics.trend.configuration.TrendItem;\r
60 import org.simantics.trend.impl.TrendNode;\r
61 import org.simantics.utils.format.FormattingUtils;\r
62 import org.simantics.utils.ui.ErrorLogger;\r
63 import org.simantics.utils.ui.workbench.WorkbenchUtils;\r
64 \r
65 /**\r
66  * @author Tuukka Lehtonen\r
67  */\r
68 public class ChartCopyHandler {\r
69 \r
70         String lastFile;\r
71         \r
72     @CanExecute\r
73     public boolean canExecute(@Named(IServiceConstants.ACTIVE_PART) MPart part) {\r
74         if (part == null)\r
75             return false;\r
76         if (part.getObject() instanceof TimeSeriesEditor == false)\r
77             return false;\r
78         return true;\r
79     }\r
80         \r
81     @Execute\r
82     public void execute(@Named(IServiceConstants.ACTIVE_PART) MPart part, @Named(IServiceConstants.ACTIVE_SHELL) Shell shell) throws ExecutionException {\r
83         if (part.getObject() instanceof TimeSeriesEditor == false)\r
84             return;\r
85         TimeSeriesEditor editor = (TimeSeriesEditor) part.getObject();\r
86         final TrendNode trendNode = editor.trendNode;\r
87         IWorkbenchPart wbpart = WorkbenchUtils.getActiveWorkbenchPart();\r
88         IStatusLineManager status = WorkbenchUtils.getStatusLine(wbpart);\r
89 \r
90         final AtomicBoolean result = new AtomicBoolean(false);\r
91         try {\r
92             PlatformUI.getWorkbench().getProgressService().busyCursorWhile(new IRunnableWithProgress() {\r
93                 @Override\r
94                 public void run(IProgressMonitor monitor) throws InvocationTargetException, InterruptedException {\r
95                     result.set( copyDataToClipboard(monitor, trendNode, Format.JOINED_TIME, shell) );\r
96                 }\r
97             });\r
98             if (!result.get()) {\r
99                 status.setMessage("No data to copy");\r
100             } else {\r
101                 status.setMessage("Copied chart data to clipboard");\r
102             }\r
103             status.setErrorMessage(null);\r
104         } catch (InvocationTargetException e) {\r
105             ErrorLogger.defaultLogError(e.getCause());\r
106         } catch (InterruptedException e) {\r
107             ErrorLogger.defaultLogError(e);\r
108         }\r
109     }\r
110 \r
111     static enum Format {\r
112         TIME_VALUE_PAIRS,\r
113         JOINED_TIME\r
114     }\r
115 \r
116     public boolean copyDataToClipboard(IProgressMonitor monitor, TrendNode t, Format format, final Shell shell) {\r
117         Charset UTF8        = Charset.forName("UTF-8");\r
118         try {\r
119                 // String builder can be really slow when it is extended many times over. \r
120                 // Instead stream to file with buffering\r
121 //            StringBuilder sb = new StringBuilder();\r
122                 IPreferenceStore csvnode = new ScopedPreferenceStore( InstanceScope.INSTANCE, CSVPreferences.P_NODE );\r
123                 String ext = csvnode.getString(CSVPreferences.P_CSV_FILE_EXTENSION);\r
124                 File tmpFile = File.createTempFile("clipboard", ext);\r
125                 tmpFile.deleteOnExit();\r
126                 FileOutputStream fos = new FileOutputStream(tmpFile); \r
127                 BufferedWriter w = new BufferedWriter(new OutputStreamWriter(fos, UTF8));\r
128                 try {\r
129                         ItemManager im = new ItemManager( t.historian.getItems() );\r
130                     CSVFormatter formatter = new CSVFormatter();            \r
131                     formatter.setTimeRange(t.horizRuler.from, t.horizRuler.end);\r
132                     \r
133                     // Write preferences\r
134                     formatter.setStartTime( csvnode.getDouble(CSVPreferences.P_CSV_START_TIME) );\r
135                     formatter.setTimeStep( csvnode.getDouble(CSVPreferences.P_CSV_TIME_STEP) );\r
136                     formatter.setDecimalSeparator( DecimalSeparator.fromPreference(csvnode.getString(CSVPreferences.P_CSV_DECIMAL_SEPARATOR) ) );\r
137                     formatter.setColumnSeparator( ColumnSeparator.fromPreference(StringEscapeUtils.unescape( csvnode.getString(CSVPreferences.P_CSV_COLUMN_SEPARATOR) ) ) );\r
138                     formatter.setResample( csvnode.getBoolean(CSVPreferences.P_CSV_RESAMPLE) );\r
139                     formatter.setNumberInterpolation( ExportInterpolation.fromPreference (csvnode.getString(CSVPreferences.P_CSV_SAMPLING_MODE) ) );\r
140                     formatter.setTimeFormat( FormattingUtils.significantDigitFormat( csvnode.getInt(CSVPreferences.P_CSV_TIME_DIGITS) ) );\r
141                     formatter.setFloatFormat( FormattingUtils.significantDigitFormat( csvnode.getInt(CSVPreferences.P_CSV_FLOAT_DIGITS) ) );\r
142                     formatter.setNumberFormat( FormattingUtils.significantDigitFormat( csvnode.getInt(CSVPreferences.P_CSV_DOUBLE_DIGITS) ) );\r
143                     \r
144                     for (TrendItem i : t.spec.items) {\r
145                         if (i.hidden) continue;\r
146                         List<Bean> items = im.search("variableId", i.variableId);\r
147                         Collections.sort(items, SamplingFormat.INTERVAL_COMPARATOR);\r
148                         if (items.isEmpty()) continue;\r
149                         Bean config = items.get(0);\r
150                         String historyId = (String) config.getFieldUnchecked("id");\r
151                         formatter.addItem( t.historian, historyId, i.simpleLabel, i.variableReference, i.unit);\r
152                     }\r
153                     formatter.sort();\r
154                     switch (format) {\r
155                         case TIME_VALUE_PAIRS: \r
156 //                                              formatter.formulate1(new CSVProgressMonitor(monitor), w);\r
157                             break;\r
158                         case JOINED_TIME:\r
159                             formatter.formulate2(new CSVProgressMonitor(monitor), w);\r
160                             break;\r
161                         default:\r
162                             throw new UnsupportedOperationException("unsupported format " + format);\r
163                     }\r
164                     w.flush();\r
165         \r
166                     if (tmpFile.length()==0) return false;\r
167         \r
168                     Toolkit toolkit = Toolkit.getDefaultToolkit();\r
169                     Clipboard clipboard = toolkit.getSystemClipboard();\r
170                     w.flush();\r
171                     fos.close();\r
172                     fos = null;\r
173                         \r
174                     System.out.println("Exported to "+tmpFile+" size: "+tmpFile.length());\r
175                     if ( tmpFile.length() > 10*1024*1024 ) {\r
176 //                      String msg = "The data has been written to temporary file:\n"+tmpFile.getCanonicalPath();\r
177 //                      ShowMessage.showInformation( shell.getDisplay(), "Too much data for clipboard.", msg);\r
178                         final File csvFile = tmpFile;\r
179                         tmpFile = null;\r
180                         shell.getDisplay().asyncExec( new Runnable() {\r
181                                                 @Override\r
182                                                 public void run() {\r
183                                         FileDialog fd = new FileDialog(shell, SWT.SAVE);\r
184                                         fd.setText("Write CSV to File");\r
185                                         fd.setFileName( lastFile!=null ? lastFile : csvFile.getAbsolutePath() );\r
186                                         String newFile = fd.open();\r
187                                         if ( newFile != null ) {\r
188                                                 lastFile = newFile;\r
189                                                 File ff = new File( newFile );\r
190                                                 ff.delete();\r
191                                                 csvFile.renameTo( ff );\r
192                                         } else {\r
193                                                 csvFile.delete();\r
194                                         }\r
195                                                 }} ); \r
196                     } else {\r
197                             String str = StreamUtil.readString(tmpFile, UTF8);\r
198                             \r
199                             StringSelection strSel = new StringSelection(str);\r
200                             clipboard.setContents(strSel, null);\r
201                     }\r
202                     \r
203                         } catch (BindingException e1) {\r
204                                 ErrorLogger.defaultLogError(e1);\r
205                                 return false;\r
206                         } catch (IOException e) {\r
207                                 ErrorLogger.defaultLogError(e);\r
208                         } finally {\r
209                         if ( fos != null ) try { fos.close(); } catch (IOException e) { ErrorLogger.defaultLogError(e); }\r
210                         if ( tmpFile != null ) tmpFile.delete();\r
211                         }                       \r
212 \r
213             return true;\r
214         } catch (HistoryException e) {\r
215             ErrorLogger.defaultLogError(e);\r
216         } catch (IOException e) {\r
217             ErrorLogger.defaultLogError(e);\r
218                 }\r
219         return false;\r
220     }\r
221 \r
222 }\r