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