]> gerrit.simantics Code Review - simantics/platform.git/blob - bundles/org.simantics.charts/src/org/simantics/charts/ui/CSVExportPage.java
Merge commit 'ffdf837'
[simantics/platform.git] / bundles / org.simantics.charts / src / org / simantics / charts / ui / CSVExportPage.java
1 /*******************************************************************************\r
2  * Copyright (c) 2012 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.ui;\r
13 \r
14 import java.io.File;\r
15 import java.util.ArrayList;\r
16 import java.util.Collection;\r
17 import java.util.Collections;\r
18 import java.util.HashSet;\r
19 import java.util.List;\r
20 import java.util.Map;\r
21 import java.util.Set;\r
22 \r
23 import org.eclipse.core.runtime.preferences.InstanceScope;\r
24 import org.eclipse.jface.layout.GridDataFactory;\r
25 import org.eclipse.jface.layout.GridLayoutFactory;\r
26 import org.eclipse.jface.preference.IPreferenceStore;\r
27 import org.eclipse.jface.wizard.WizardPage;\r
28 import org.eclipse.swt.SWT;\r
29 import org.eclipse.swt.custom.CCombo;\r
30 import org.eclipse.swt.custom.ScrolledComposite;\r
31 import org.eclipse.swt.events.ModifyListener;\r
32 import org.eclipse.swt.events.SelectionAdapter;\r
33 import org.eclipse.swt.events.SelectionEvent;\r
34 import org.eclipse.swt.events.SelectionListener;\r
35 import org.eclipse.swt.layout.GridData;\r
36 import org.eclipse.swt.widgets.Button;\r
37 import org.eclipse.swt.widgets.Composite;\r
38 import org.eclipse.swt.widgets.FileDialog;\r
39 import org.eclipse.swt.widgets.Group;\r
40 import org.eclipse.swt.widgets.Label;\r
41 import org.eclipse.swt.widgets.Table;\r
42 import org.eclipse.swt.widgets.TableItem;\r
43 import org.eclipse.swt.widgets.Text;\r
44 import org.eclipse.ui.preferences.ScopedPreferenceStore;\r
45 import org.simantics.NameLabelUtil;\r
46 import org.simantics.Simantics;\r
47 import org.simantics.browsing.ui.common.ColumnKeys;\r
48 import org.simantics.databoard.Bindings;\r
49 import org.simantics.databoard.parser.StringEscapeUtils;\r
50 import org.simantics.db.ReadGraph;\r
51 import org.simantics.db.Resource;\r
52 import org.simantics.db.common.NamedResource;\r
53 import org.simantics.db.common.request.IsParent;\r
54 import org.simantics.db.common.request.UniqueRead;\r
55 import org.simantics.db.exception.DatabaseException;\r
56 import org.simantics.db.layer0.SelectionHints;\r
57 import org.simantics.history.csv.ColumnSeparator;\r
58 import org.simantics.history.csv.DecimalSeparator;\r
59 import org.simantics.history.csv.ExportInterpolation;\r
60 import org.simantics.layer0.Layer0;\r
61 import org.simantics.modeling.ModelingResources;\r
62 import org.simantics.modeling.ModelingUtils;\r
63 import org.simantics.modeling.preferences.CSVPreferences;\r
64 import org.simantics.modeling.ui.modelBrowser2.label.SubscriptionItemLabelRule;\r
65 import org.simantics.utils.datastructures.Arrays;\r
66 import org.simantics.utils.datastructures.Pair;\r
67 import org.simantics.utils.strings.AlphanumComparator;\r
68 import org.simantics.utils.ui.ISelectionUtils;\r
69 \r
70 \r
71 /**\r
72  * @author Antti Villberg\r
73  */\r
74 public class CSVExportPage extends WizardPage {\r
75 \r
76     CSVExportPlan       exportModel;\r
77     CCombo              model;\r
78     Table               item;\r
79     Button              selectAllItems;\r
80     SelectionAdapter    selectAllItemsListener;\r
81     CCombo              exportLocation;\r
82 \r
83     CCombo decimalSeparator;\r
84     CCombo columnSeparator;\r
85     CCombo sampling;\r
86     Text timeStep;\r
87     Text startTime;\r
88     Text timeStamps;\r
89     CCombo samplingMode;\r
90     Text singlePrecision;\r
91     Text doublePrecision;\r
92 \r
93     Group resampling;\r
94 \r
95     Collection<Resource> initialSelection;\r
96 \r
97     List<Pair<NamedResource,List<NamedResource>>> models = new ArrayList<>();\r
98 \r
99     private Button      overwrite;\r
100 \r
101     ModifyListener m = (e) -> validatePage();\r
102 \r
103     SelectionListener s = new SelectionAdapter() {\r
104         @Override\r
105         public void widgetSelected(SelectionEvent e) {\r
106             validatePage();\r
107         }\r
108     };\r
109 \r
110     protected CSVExportPage(CSVExportPlan model) {\r
111         super("Export CSV Data", "Define Export Properties", null);\r
112         this.exportModel = model;\r
113     }\r
114 \r
115     @Override\r
116     public void createControl(Composite parent) {\r
117         ScrolledComposite scroller = new ScrolledComposite(parent, SWT.V_SCROLL);\r
118         scroller.setExpandHorizontal(true);\r
119         scroller.setExpandVertical(true);\r
120 \r
121         Composite container = new Composite(scroller, SWT.NONE);\r
122         scroller.setContent(container);\r
123         GridLayoutFactory.swtDefaults().spacing(20, 10).numColumns(3).applyTo(container);\r
124         new Label(container, SWT.NONE).setText("Select a model:");\r
125         model = new CCombo(container, SWT.BORDER);\r
126         {\r
127             model.setEditable(false);\r
128             model.setText("");\r
129             model.setToolTipText("Selects the Model To Export From");\r
130             GridDataFactory.fillDefaults().grab(true, false).span(2, 1).applyTo(model);\r
131         }\r
132 \r
133         new Label(container, SWT.NONE).setText("Exported items:");\r
134         item = new Table(container, SWT.BORDER | SWT.MULTI | SWT.FULL_SELECTION | SWT.CHECK);\r
135         {\r
136             item.setToolTipText("Selects the Subscription Items");\r
137             GridDataFactory.fillDefaults().grab(true, true).span(2, 1).hint(SWT.DEFAULT, 105).applyTo(item);\r
138         }\r
139         item.addSelectionListener(new SelectionAdapter() {\r
140             @Override\r
141             public void widgetSelected(SelectionEvent e) {\r
142                 if (e.detail == SWT.CHECK) {\r
143                     TableItem[] selected = item.getSelection();\r
144                     TableItem it = (TableItem) e.item;\r
145                     boolean checkedWasSelected = Arrays.contains(selected, it);\r
146                     if (checkedWasSelected) {\r
147                         boolean check = it.getChecked();\r
148                         for (TableItem i : selected)\r
149                             i.setChecked(check);\r
150                     }\r
151                     int checked = countCheckedItems(item);\r
152                     int totalItems = item.getItemCount();\r
153                     updateSelectAll(checked > 0, checked < totalItems, false);\r
154                     validatePage();\r
155                 }\r
156             }\r
157         });\r
158         new Label(container, 0);\r
159         selectAllItems = new Button(container, SWT.CHECK);\r
160         {\r
161             selectAllItems.setText("&Select All");\r
162             selectAllItems.setToolTipText("Select/Deselect All Listed Subscription Items");\r
163             GridDataFactory.fillDefaults().grab(true, false).span(2, 1).applyTo(selectAllItems);\r
164         }\r
165         selectAllItemsListener = new SelectionAdapter() {\r
166             @Override\r
167             public void widgetSelected(SelectionEvent e) {\r
168                 boolean select = selectAllItems.getSelection();\r
169                 updateSelectAll(select, false, false);\r
170                 item.setRedraw(false);\r
171                 for (TableItem it : item.getItems())\r
172                     it.setChecked(select);\r
173                 item.setRedraw(true);\r
174 \r
175                 validatePage();\r
176             }\r
177         };\r
178         selectAllItems.addSelectionListener(selectAllItemsListener);\r
179 \r
180         new Label(container, SWT.NONE).setText("&Output file:");\r
181         exportLocation = new CCombo(container, SWT.BORDER);\r
182         {\r
183             exportLocation.setText("");\r
184             GridDataFactory.fillDefaults().grab(true, false).span(1, 1).applyTo(exportLocation);\r
185             exportLocation.addModifyListener(m);\r
186         }\r
187         Button browseFileButton = new Button(container, SWT.PUSH);\r
188         {\r
189             browseFileButton.setText("Browse...");\r
190             browseFileButton.setLayoutData(new GridData(SWT.RIGHT, SWT.CENTER, false, false));\r
191             browseFileButton.addSelectionListener(new SelectionAdapter() {\r
192                 @Override\r
193                 public void widgetSelected(SelectionEvent e) {\r
194                     FileDialog dialog = new FileDialog(getShell(), SWT.SAVE);\r
195                     dialog.setText("Choose Output File");\r
196                     dialog.setFilterPath(new File(exportLocation.getText()).getParent());\r
197                     dialog.setFilterExtensions(new String[] { "*.csv" });\r
198                     dialog.setFilterNames(new String[] { "Comma separated values (*.csv)" });\r
199                     dialog.setOverwrite(false);\r
200                     String file = dialog.open();\r
201                     if (file == null)\r
202                         return;\r
203                     exportLocation.setText(file);\r
204                     validatePage();\r
205                 }\r
206             });\r
207         }\r
208 \r
209         \r
210         Label horizRule = new Label(container, SWT.BORDER);\r
211         GridDataFactory.fillDefaults().hint(SWT.DEFAULT, 0).grab(true, false).span(3, 1).applyTo(horizRule);\r
212 \r
213         new Label(container, SWT.NONE).setText("&Decimal separator:");\r
214         decimalSeparator = new CCombo(container, SWT.READ_ONLY | SWT.BORDER);\r
215         for(DecimalSeparator s : DecimalSeparator.values())\r
216             decimalSeparator.add(s.label);\r
217         decimalSeparator.select(0);\r
218         decimalSeparator.addSelectionListener(s);\r
219         GridDataFactory.fillDefaults().grab(true, false).span(2, 1).applyTo(decimalSeparator);\r
220 \r
221         new Label(container, SWT.NONE).setText("&Column separator:");\r
222         columnSeparator = new CCombo(container, SWT.READ_ONLY | SWT.BORDER);\r
223         for(ColumnSeparator s : ColumnSeparator.values())\r
224             columnSeparator.add(s.label);\r
225         columnSeparator.select(0);\r
226         columnSeparator.addSelectionListener(s);\r
227         GridDataFactory.fillDefaults().grab(true, false).span(2, 1).applyTo(columnSeparator);\r
228 \r
229         new Label(container, SWT.NONE).setText("Sampling:");\r
230         sampling = new CCombo(container, SWT.READ_ONLY | SWT.BORDER);\r
231         sampling.add("Recorded samples");\r
232         sampling.add("Resampled");\r
233         sampling.select(0);\r
234         sampling.addSelectionListener(s);\r
235         GridDataFactory.fillDefaults().grab(true, false).span(2, 1).applyTo(sampling);\r
236 \r
237         resampling = new Group(container, SWT.NONE);\r
238                 resampling.setText("Resampling settings (not used with recorded samples)");\r
239         GridDataFactory.fillDefaults().grab(true, false).span(3, 1).applyTo(resampling);\r
240         GridLayoutFactory.swtDefaults().numColumns(3).applyTo(resampling);\r
241 \r
242         new Label(resampling, SWT.NONE).setText("&Start time:");\r
243         startTime = new Text(resampling, SWT.BORDER);\r
244         startTime.addModifyListener(m);\r
245         GridDataFactory.fillDefaults().grab(true, false).applyTo(startTime);\r
246         new Label(resampling, SWT.NONE).setText(" seconds");\r
247 \r
248         new Label(resampling, SWT.NONE).setText("&Time step:");\r
249         timeStep = new Text(resampling, SWT.BORDER);\r
250         timeStep.addModifyListener(m);\r
251         GridDataFactory.fillDefaults().grab(true, false).applyTo(timeStep);\r
252         new Label(resampling, SWT.NONE).setText(" seconds");\r
253         \r
254         new Label(resampling, SWT.NONE).setText("Sampling mode:");\r
255         samplingMode = new CCombo(resampling, SWT.READ_ONLY | SWT.BORDER);\r
256         samplingMode.add("Linear interpolation");\r
257         samplingMode.add("Previous sample");\r
258         samplingMode.select(0);\r
259         samplingMode.addSelectionListener(s);\r
260         GridDataFactory.fillDefaults().grab(true, false).span(2,1).applyTo(samplingMode);\r
261 \r
262         Group digits = new Group(container, SWT.NONE);\r
263         digits.setText("Significant digits");\r
264         GridDataFactory.fillDefaults().grab(true, false).span(3, 1).applyTo(digits);\r
265         GridLayoutFactory.swtDefaults().numColumns(2).applyTo(digits);\r
266 \r
267         new Label(digits, SWT.NONE).setText("&Time stamps:");\r
268         timeStamps = new Text(digits, SWT.BORDER);\r
269         timeStamps.addModifyListener(m);\r
270         GridDataFactory.fillDefaults().grab(true, false).applyTo(timeStamps);\r
271         \r
272         new Label(digits, SWT.NONE).setText("&Single precision floating point:");\r
273         singlePrecision = new Text(digits, SWT.BORDER);\r
274         singlePrecision.addModifyListener(m);\r
275         GridDataFactory.fillDefaults().grab(true, false).applyTo(singlePrecision);\r
276 \r
277         new Label(digits, SWT.NONE).setText("&Double precision floating point:");\r
278         doublePrecision = new Text(digits, SWT.BORDER);\r
279         doublePrecision.addModifyListener(m);\r
280         GridDataFactory.fillDefaults().grab(true, false).applyTo(doublePrecision);\r
281 \r
282         overwrite = new Button(container, SWT.CHECK);\r
283         overwrite.setText("&Overwrite existing files without warning");\r
284         overwrite.setSelection(exportModel.overwrite);\r
285         GridDataFactory.fillDefaults().grab(true, false).span(3, 1).applyTo(overwrite);\r
286         overwrite.addSelectionListener(new SelectionAdapter() {\r
287             @Override\r
288             public void widgetSelected(SelectionEvent e) {\r
289                 validatePage();\r
290             }\r
291         });\r
292 \r
293         try {\r
294             initializeData();\r
295         } catch (DatabaseException e) {\r
296             e.printStackTrace();\r
297         }\r
298 \r
299         model.addSelectionListener(s);\r
300 \r
301         scroller.setMinSize(container.computeSize(SWT.DEFAULT, SWT.DEFAULT));\r
302 \r
303         setControl(scroller);\r
304         validatePage();\r
305         \r
306     }\r
307 \r
308     void updateSelectAll(boolean checked, boolean gray, boolean notify) {\r
309         if (checked) {\r
310             selectAllItems.setText("Select None");\r
311         } else {\r
312             selectAllItems.setText("Select All");\r
313         }\r
314         if (!notify)\r
315             selectAllItems.removeSelectionListener(selectAllItemsListener);\r
316         selectAllItems.setGrayed(checked && gray);\r
317         selectAllItems.setSelection(checked);\r
318         if (!notify)\r
319             selectAllItems.addSelectionListener(selectAllItemsListener);\r
320     }\r
321 \r
322     protected int countCheckedItems(Table table) {\r
323         int ret = 0;\r
324         for (TableItem item : table.getItems())\r
325             ret += item.getChecked() ? 1 : 0;\r
326         return ret;\r
327     }\r
328 \r
329     private void initializeData() throws DatabaseException {\r
330 \r
331         // Write preferences to formatter\r
332         IPreferenceStore csvnode = new ScopedPreferenceStore( InstanceScope.INSTANCE, CSVPreferences.P_NODE );\r
333         \r
334         Double startTime =  csvnode.getDouble(CSVPreferences.P_CSV_START_TIME);\r
335         Double timeStep =  csvnode.getDouble(CSVPreferences.P_CSV_TIME_STEP);\r
336         String decimalSeparator = csvnode.getString(CSVPreferences.P_CSV_DECIMAL_SEPARATOR);\r
337         String columnSeparator = StringEscapeUtils.unescape( csvnode.getString(CSVPreferences.P_CSV_COLUMN_SEPARATOR) );\r
338         Boolean resample = csvnode.getBoolean(CSVPreferences.P_CSV_RESAMPLE);\r
339         String samplingModePreference = csvnode.getString(CSVPreferences.P_CSV_SAMPLING_MODE);\r
340         int timeDigits = csvnode.getInt(CSVPreferences.P_CSV_TIME_DIGITS);\r
341         int floatDigits = csvnode.getInt(CSVPreferences.P_CSV_FLOAT_DIGITS);\r
342         int doubleDigits = csvnode.getInt(CSVPreferences.P_CSV_DOUBLE_DIGITS);\r
343         \r
344         initialSelection =  ISelectionUtils.getPossibleKeys(exportModel.selection, SelectionHints.KEY_MAIN, Resource.class);\r
345 \r
346         models = exportModel.sessionContext.getSession().syncRequest(new UniqueRead<List<Pair<NamedResource,List<NamedResource>>>>() {\r
347 \r
348                         @Override\r
349                         public List<Pair<NamedResource,List<NamedResource>>> perform(ReadGraph graph) throws DatabaseException {\r
350                                 Layer0 L0 = Layer0.getInstance(graph);\r
351                                 ModelingResources MOD = ModelingResources.getInstance(graph);\r
352                                 List<Pair<NamedResource,List<NamedResource>>> result = new ArrayList<>();\r
353                                 for(Resource model : graph.syncRequest(new org.simantics.db.layer0.request.ProjectModels(Simantics.getProjectResource()))) {\r
354                                         String name = graph.getPossibleRelatedValue(model, L0.HasName, Bindings.STRING);\r
355                                         if(name == null) continue;\r
356                                         name = NameLabelUtil.modalName(graph, model);\r
357                                         List<NamedResource> subs = new ArrayList<>();\r
358                                         for(Resource item : ModelingUtils.searchByType(graph, model, MOD.Subscription_Item)) {\r
359                                                 String subscriptionLabel = null;\r
360                                                 Resource subscription = graph.getPossibleObject(item, L0.PartOf);\r
361                                                 if(subscription != null) {\r
362                                                         subscriptionLabel = graph.getPossibleRelatedValue(subscription, L0.HasLabel, Bindings.STRING);\r
363                                                 }\r
364                                                 SubscriptionItemLabelRule rule = new SubscriptionItemLabelRule();\r
365                                                 Map<String,String> map = rule.getLabel(graph, item); \r
366                                                 String label = map.get(ColumnKeys.SINGLE);\r
367                                                 if(label == null) continue;\r
368                                                 if(subscriptionLabel != null) label = subscriptionLabel + "/" + label;\r
369                                                 subs.add(new NamedResource(label, item));\r
370                                         }\r
371                                         subs.sort((o1,o2) -> AlphanumComparator.CASE_INSENSITIVE_COMPARATOR.compare(o1.getName(), o2.getName()));\r
372                                         result.add(new Pair<>(new NamedResource(name, model), subs));\r
373                                 }\r
374                                 return result;\r
375                         }\r
376                 \r
377         });\r
378         \r
379         Set<NamedResource> selected = exportModel.sessionContext.getSession().syncRequest(new UniqueRead<Set<NamedResource>>() {\r
380 \r
381                         @Override\r
382                         public Set<NamedResource> perform(ReadGraph graph) throws DatabaseException {\r
383 \r
384                                 if(initialSelection == null) return Collections.emptySet();\r
385 \r
386                                 HashSet<NamedResource> result = new HashSet<>();\r
387                                 \r
388                                 for(Pair<NamedResource,List<NamedResource>> p : models) {\r
389                         for(NamedResource nr : p.second) {\r
390                                 for(Resource i : initialSelection) {\r
391                                         if(graph.syncRequest(new IsParent(i, nr.getResource()))) result.add(nr);\r
392                                 }\r
393                         }\r
394                                 }\r
395                                 return result;\r
396                         }\r
397                 \r
398         });\r
399  \r
400 \r
401         for(int i=0;i<models.size();i++) {\r
402                 \r
403                 Pair<NamedResource,List<NamedResource>> p = models.get(i);\r
404             model.add(p.first.getName());\r
405 \r
406             boolean hasInitial = false;\r
407             for(NamedResource nr : p.second) {\r
408                 if(selected.contains(nr)) hasInitial = true;\r
409             }\r
410             if(hasInitial) {\r
411                 model.select(i);\r
412                 item.removeAll();\r
413                 exportModel.models.clear();\r
414                 int index = 0;\r
415                 int firstIndex = 0;\r
416                 for(NamedResource nr : p.second) {\r
417                         TableItem ti = new TableItem(item, SWT.NONE);\r
418                         ti.setText(nr.getName());\r
419                         ti.setData(nr);\r
420                         if(selected.contains(nr)) {\r
421                                 exportModel.models.add(nr);\r
422                                 ti.setChecked(true);\r
423                                 if(firstIndex == 0) firstIndex = index;\r
424                         }\r
425                         index++;\r
426                 }\r
427                 item.setTopIndex(firstIndex);\r
428                 item.setData(p.first);\r
429             }\r
430             \r
431         }\r
432         \r
433         this.decimalSeparator.select(DecimalSeparator.fromPreference(decimalSeparator).ordinal());\r
434         this.columnSeparator.select(ColumnSeparator.fromPreference(columnSeparator).ordinal());\r
435         \r
436         if(resample) {\r
437                 this.sampling.select(1);\r
438         } else {\r
439                 this.sampling.select(0);\r
440         }\r
441         \r
442         this.samplingMode.select(ExportInterpolation.fromPreference(samplingModePreference).index());\r
443         \r
444         this.startTime.setText("" + startTime);\r
445         this.timeStep.setText("" + timeStep);\r
446         this.timeStamps.setText("" + timeDigits);\r
447         this.singlePrecision.setText("" + floatDigits);\r
448         this.doublePrecision.setText("" + doubleDigits);\r
449         \r
450         for (String path : exportModel.recentLocations) {\r
451             exportLocation.add(path);\r
452         }\r
453         if (exportLocation.getItemCount() > 0)\r
454             exportLocation.select(0);\r
455         \r
456     }\r
457 \r
458     Integer validInteger(String s) {\r
459         try {\r
460                 return Integer.parseInt(s);\r
461         } catch (NumberFormatException e) {\r
462                 return null;\r
463         }\r
464     }\r
465 \r
466     Double validDouble(String s) {\r
467         try {\r
468                 return Double.parseDouble(s);\r
469         } catch (NumberFormatException e) {\r
470                 return null;\r
471         }\r
472     }\r
473     \r
474     Pair<NamedResource,List<NamedResource>> getModel(String name) {\r
475         for(Pair<NamedResource,List<NamedResource>> data : models) {\r
476                 if(data.first.getName().equals(name)) return data;\r
477         }\r
478         return null;\r
479     }\r
480     \r
481     void validatePage() {\r
482 \r
483         boolean resample = sampling.getText().equals("Resampled"); \r
484         \r
485         if(resample) {\r
486                 resampling.setText("Resampling settings");\r
487                 timeStep.setEnabled(true);\r
488                 startTime.setEnabled(true);\r
489                 samplingMode.setEnabled(true);\r
490         } else {\r
491                 resampling.setText("Resampling settings (not used with recorded samples)");\r
492                 timeStep.setEnabled(false);\r
493                 startTime.setEnabled(false);\r
494                 samplingMode.setEnabled(false);\r
495         }\r
496         \r
497         String selectedModel = model.getText();\r
498         Pair<NamedResource,List<NamedResource>> p = getModel(selectedModel);\r
499         if(p != null) {\r
500                 \r
501                 HashSet<NamedResource> checked = new HashSet<>();\r
502                 \r
503                 NamedResource existing = (NamedResource)item.getData();\r
504                 if(!p.first.equals(existing)) {\r
505                 \r
506                         item.removeAll();\r
507                         for(NamedResource nr : p.second) {\r
508                                 TableItem ti = new TableItem(item, SWT.NONE);\r
509                                 ti.setText(nr.getName());\r
510                                 ti.setData(nr);\r
511                         }\r
512                         item.setData(p.first);\r
513                         \r
514                 }\r
515                 \r
516                 for(TableItem ti : item.getItems()) {\r
517                         if(ti.getChecked()) checked.add((NamedResource)ti.getData());\r
518                 }\r
519                 \r
520                 exportModel.models = checked;\r
521                 \r
522         }\r
523 \r
524         Double validStartTime = validDouble(startTime.getText());\r
525         Double validStepSize = validDouble(timeStep.getText());\r
526 \r
527         if(resample) {\r
528                 \r
529             if(validStartTime == null) {\r
530                 setErrorMessage("Start time must be a number.");\r
531                 setPageComplete(false);\r
532                 return;\r
533             }\r
534             \r
535             if(validStepSize == null) {\r
536                 setErrorMessage("Step size must be a number.");\r
537                 setPageComplete(false);\r
538                 return;\r
539             }\r
540             if(validStepSize <= 0) {\r
541                 setErrorMessage("Step size must be greater than 0.");\r
542                 setPageComplete(false);\r
543                 return;\r
544             }\r
545 \r
546         } else {\r
547                 \r
548                 if(exportModel.models.size() > 1) {\r
549                 setErrorMessage("Recorded samples can only be exported for a single subscription item.");\r
550                 setPageComplete(false);\r
551                 return;\r
552                 }\r
553 \r
554         }\r
555         \r
556         if(item.getItemCount() == 0) {\r
557             setErrorMessage("No subscription items in selected model.");\r
558             setPageComplete(false);\r
559             return;\r
560         }\r
561         \r
562         if (exportModel.models.isEmpty()) {\r
563             setErrorMessage("No items selected for export.");\r
564             setPageComplete(false);\r
565             return;\r
566         }\r
567         \r
568         String exportLoc = exportLocation.getText();\r
569         if (exportLoc.isEmpty()) {\r
570             setErrorMessage("Select output file.");\r
571             setPageComplete(false);\r
572             return;\r
573         }\r
574         File file = new File(exportLoc);\r
575         if (file.isDirectory()) {\r
576             setErrorMessage("The output file is a directory.");\r
577             setPageComplete(false);\r
578             return;\r
579         }\r
580         File parent = file.getParentFile();\r
581         if (parent == null || !parent.isDirectory()) {\r
582             setErrorMessage("The output directory does not exist.");\r
583             setPageComplete(false);\r
584             return;\r
585         }\r
586 \r
587         exportModel.columnSeparator = ColumnSeparator.fromIndex(columnSeparator.getSelectionIndex());\r
588         exportModel.decimalSeparator = DecimalSeparator.fromIndex(decimalSeparator.getSelectionIndex());\r
589         if (exportModel.columnSeparator.preference.equals(exportModel.decimalSeparator.preference)) {\r
590             setErrorMessage("Decimal and column separator cannot be the same character.");\r
591             setPageComplete(false);\r
592             return;\r
593         }\r
594 \r
595         Integer validTimeDigits = validInteger(timeStamps.getText());\r
596 \r
597         if(validTimeDigits == null) {\r
598             setErrorMessage("Time stamps needs to be an integer number.");\r
599             setPageComplete(false);\r
600             return;\r
601         }\r
602 \r
603         Integer validSinglePrecision = validInteger(singlePrecision.getText());\r
604         if(validSinglePrecision == null) {\r
605             setErrorMessage("Single precision needs to be an integer number.");\r
606             setPageComplete(false);\r
607             return;\r
608         }\r
609 \r
610         Integer validDoublePrecision = validInteger(doublePrecision.getText());\r
611         if(validDoublePrecision == null) {\r
612             setErrorMessage("Double precision needs to be an integer number.");\r
613             setPageComplete(false);\r
614             return;\r
615         }\r
616 \r
617         exportModel.exportLocation = file;\r
618         exportModel.overwrite = overwrite.getSelection();\r
619 \r
620         exportModel.startTime = validStartTime;\r
621         exportModel.timeStep = validStepSize;\r
622 \r
623         exportModel.resample = sampling.getSelectionIndex() == 1;\r
624         exportModel.samplingMode = ExportInterpolation.fromIndex(samplingMode.getSelectionIndex());\r
625         \r
626         exportModel.timeDigits = validTimeDigits;\r
627         exportModel.floatDigits = validSinglePrecision;\r
628         exportModel.doubleDigits = validDoublePrecision;\r
629         \r
630         setErrorMessage(null);\r
631         setMessage("Press Finish to export subscription data.");\r
632         setPageComplete(true);\r
633         \r
634     }\r
635 \r
636 }\r