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