1 /*******************************************************************************
2 * Copyright (c) 2012 Association for Decentralized Information Management in
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
10 * VTT Technical Research Centre of Finland - initial API and implementation
11 *******************************************************************************/
12 package org.simantics.charts.ui;
15 import java.lang.reflect.InvocationTargetException;
16 import java.util.ArrayList;
17 import java.util.Collection;
18 import java.util.Collections;
19 import java.util.Comparator;
20 import java.util.HashMap;
21 import java.util.HashSet;
22 import java.util.List;
25 import java.util.stream.Collectors;
27 import org.eclipse.core.runtime.IProgressMonitor;
28 import org.eclipse.core.runtime.SubMonitor;
29 import org.eclipse.core.runtime.preferences.InstanceScope;
30 import org.eclipse.jface.layout.GridDataFactory;
31 import org.eclipse.jface.layout.GridLayoutFactory;
32 import org.eclipse.jface.preference.IPreferenceStore;
33 import org.eclipse.jface.wizard.WizardPage;
34 import org.eclipse.swt.SWT;
35 import org.eclipse.swt.custom.CCombo;
36 import org.eclipse.swt.custom.ScrolledComposite;
37 import org.eclipse.swt.events.ModifyListener;
38 import org.eclipse.swt.events.SelectionAdapter;
39 import org.eclipse.swt.events.SelectionEvent;
40 import org.eclipse.swt.events.SelectionListener;
41 import org.eclipse.swt.layout.GridData;
42 import org.eclipse.swt.widgets.Button;
43 import org.eclipse.swt.widgets.Composite;
44 import org.eclipse.swt.widgets.FileDialog;
45 import org.eclipse.swt.widgets.Group;
46 import org.eclipse.swt.widgets.Label;
47 import org.eclipse.swt.widgets.Table;
48 import org.eclipse.swt.widgets.TableItem;
49 import org.eclipse.swt.widgets.Text;
50 import org.eclipse.ui.preferences.ScopedPreferenceStore;
51 import org.simantics.NameLabelUtil;
52 import org.simantics.Simantics;
53 import org.simantics.browsing.ui.common.ColumnKeys;
54 import org.simantics.charts.ontology.ChartResource;
55 import org.simantics.databoard.Bindings;
56 import org.simantics.databoard.parser.StringEscapeUtils;
57 import org.simantics.db.ReadGraph;
58 import org.simantics.db.Resource;
59 import org.simantics.db.common.NamedResource;
60 import org.simantics.db.common.request.IsParent;
61 import org.simantics.db.exception.DatabaseException;
62 import org.simantics.db.layer0.SelectionHints;
63 import org.simantics.db.layer0.request.ProjectModels;
64 import org.simantics.db.request.Read;
65 import org.simantics.history.csv.ColumnSeparator;
66 import org.simantics.history.csv.DecimalSeparator;
67 import org.simantics.history.csv.ExportInterpolation;
68 import org.simantics.layer0.Layer0;
69 import org.simantics.modeling.ModelingResources;
70 import org.simantics.modeling.ModelingUtils;
71 import org.simantics.modeling.preferences.CSVPreferences;
72 import org.simantics.modeling.ui.modelBrowser2.label.SubscriptionItemLabelRule;
73 import org.simantics.utils.datastructures.Arrays;
74 import org.simantics.utils.strings.AlphanumComparator;
75 import org.simantics.utils.ui.ISelectionUtils;
76 import org.simantics.utils.ui.SWTUtils;
77 import org.slf4j.Logger;
78 import org.slf4j.LoggerFactory;
82 * @author Antti Villberg
84 public class CSVExportPage extends WizardPage {
86 private static final Logger LOGGER = LoggerFactory.getLogger(CSVExportPage.class);
88 private static class Model {
89 private static final Comparator<NamedResource> COMP =
90 (o1,o2) -> AlphanumComparator.CASE_INSENSITIVE_COMPARATOR.compare(
91 o1.getName(), o2.getName());
93 public final NamedResource model;
94 public List<NamedResource> sortedSubs = new ArrayList<>();
95 public Map<Resource, NamedResource> subs = new HashMap<>();
96 public Map<Resource, Resource> chartItemsToSubs = new HashMap<>();
97 public Set<NamedResource> initiallySelectedSubscriptions = Collections.emptySet();
99 public Model(NamedResource model) {
103 public void initialize(ReadGraph graph, Collection<Resource> inputSelection) throws DatabaseException {
104 Layer0 L0 = Layer0.getInstance(graph);
105 ModelingResources MOD = ModelingResources.getInstance(graph);
106 ChartResource CHART = ChartResource.getInstance(graph);
107 SubscriptionItemLabelRule rule = new SubscriptionItemLabelRule();
109 Resource m = model.getResource();
110 String name = graph.getPossibleRelatedValue(m, L0.HasName, Bindings.STRING);
114 name = NameLabelUtil.modalName(graph, m);
115 for (Resource item : ModelingUtils.searchByTypeShallow(graph, m, MOD.Subscription_Item)) {
116 String subscriptionLabel = null;
117 Resource subscription = graph.getPossibleObject(item, L0.PartOf);
118 if (subscription != null)
119 subscriptionLabel = graph.getPossibleRelatedValue(subscription, L0.HasLabel, Bindings.STRING);
120 String label = rule.getLabel(graph, item).get(ColumnKeys.SINGLE);
123 if (subscriptionLabel != null)
124 label = subscriptionLabel + "/" + label;
125 subs.put(item, new NamedResource(label, item));
127 for (Resource cItem : ModelingUtils.searchByTypeShallow(graph, m, CHART.Chart_Item)) {
128 Resource sItem = graph.getPossibleObject(cItem, CHART.Chart_Item_HasSubscriptionItem);
129 if (sItem != null && subs.containsKey(sItem))
130 chartItemsToSubs.put(cItem, sItem);
133 sortedSubs = subs.values().stream().sorted(COMP).collect(Collectors.toList());
134 initiallySelectedSubscriptions = initiallySelectedSubscriptions(graph, inputSelection);
137 private Set<NamedResource> initiallySelectedSubscriptions(ReadGraph graph, Collection<Resource> inputSelection) throws DatabaseException {
138 if (inputSelection == null)
139 return Collections.emptySet();
141 HashSet<NamedResource> result = new HashSet<>();
143 for (Resource i : inputSelection) {
144 for (NamedResource nr : sortedSubs)
145 if (graph.syncRequest(new IsParent(i, nr.getResource())))
147 for (Map.Entry<Resource, Resource> cs : chartItemsToSubs.entrySet())
148 if (graph.syncRequest(new IsParent(i, cs.getKey())))
149 result.add( subs.get( cs.getValue() ) );
156 CSVExportPlan exportModel;
159 Button selectAllItems;
160 SelectionAdapter selectAllItemsListener;
161 CCombo exportLocation;
163 CCombo decimalSeparator;
164 CCombo columnSeparator;
171 Text singlePrecision;
172 Text doublePrecision;
175 Collection<Resource> initialSelection;
176 List<Model> models = Collections.emptyList();
178 ModifyListener m = (e) -> validatePage();
180 SelectionListener s = new SelectionAdapter() {
182 public void widgetSelected(SelectionEvent e) {
187 protected CSVExportPage(CSVExportPlan model) {
188 super("Export CSV Data", "Define Export Properties", null);
189 this.exportModel = model;
193 public void createControl(Composite parent) {
194 ScrolledComposite scroller = new ScrolledComposite(parent, SWT.V_SCROLL);
195 scroller.setExpandHorizontal(true);
196 scroller.setExpandVertical(true);
198 Composite container = new Composite(scroller, SWT.NONE);
199 scroller.setContent(container);
200 GridLayoutFactory.swtDefaults().spacing(20, 10).numColumns(3).applyTo(container);
201 new Label(container, SWT.NONE).setText("Select a model:");
202 model = new CCombo(container, SWT.BORDER);
204 model.setEditable(false);
206 model.setToolTipText("Selects the Model To Export From");
207 GridDataFactory.fillDefaults().grab(true, false).span(2, 1).applyTo(model);
210 new Label(container, SWT.NONE).setText("Exported items:");
211 item = new Table(container, SWT.BORDER | SWT.MULTI | SWT.FULL_SELECTION | SWT.CHECK);
213 item.setToolTipText("Selects the Subscription Items");
214 GridDataFactory.fillDefaults().grab(true, true).span(2, 1).hint(SWT.DEFAULT, 105).applyTo(item);
216 item.addSelectionListener(new SelectionAdapter() {
218 public void widgetSelected(SelectionEvent e) {
219 if (e.detail == SWT.CHECK) {
220 TableItem[] selected = item.getSelection();
221 TableItem it = (TableItem) e.item;
222 boolean checkedWasSelected = Arrays.contains(selected, it);
223 if (checkedWasSelected) {
224 boolean check = it.getChecked();
225 for (TableItem i : selected)
228 int checked = countCheckedItems(item);
229 int totalItems = item.getItemCount();
230 updateSelectAll(checked > 0, checked < totalItems, false);
235 new Label(container, 0);
236 selectAllItems = new Button(container, SWT.CHECK);
238 selectAllItems.setText("&Select All");
239 selectAllItems.setToolTipText("Select/Deselect All Listed Subscription Items");
240 GridDataFactory.fillDefaults().grab(true, false).span(2, 1).applyTo(selectAllItems);
242 selectAllItemsListener = new SelectionAdapter() {
244 public void widgetSelected(SelectionEvent e) {
245 boolean select = selectAllItems.getSelection();
246 updateSelectAll(select, false, false);
247 item.setRedraw(false);
248 for (TableItem it : item.getItems())
249 it.setChecked(select);
250 item.setRedraw(true);
255 selectAllItems.addSelectionListener(selectAllItemsListener);
257 new Label(container, SWT.NONE).setText("&Output file:");
258 exportLocation = new CCombo(container, SWT.BORDER);
260 exportLocation.setText("");
261 GridDataFactory.fillDefaults().grab(true, false).span(1, 1).applyTo(exportLocation);
262 exportLocation.addModifyListener(m);
264 Button browseFileButton = new Button(container, SWT.PUSH);
266 browseFileButton.setText("Browse...");
267 browseFileButton.setLayoutData(new GridData(SWT.RIGHT, SWT.CENTER, false, false));
268 browseFileButton.addSelectionListener(new SelectionAdapter() {
270 public void widgetSelected(SelectionEvent e) {
271 FileDialog dialog = new FileDialog(getShell(), SWT.SAVE);
272 dialog.setText("Choose Output File");
273 dialog.setFilterPath(new File(exportLocation.getText()).getParent());
274 dialog.setFilterExtensions(new String[] { "*.csv" });
275 dialog.setFilterNames(new String[] { "Comma separated values (*.csv)" });
276 dialog.setOverwrite(false);
277 String file = dialog.open();
280 exportLocation.setText(file);
287 Label horizRule = new Label(container, SWT.BORDER);
288 GridDataFactory.fillDefaults().hint(SWT.DEFAULT, 0).grab(true, false).span(3, 1).applyTo(horizRule);
290 new Label(container, SWT.NONE).setText("&Decimal separator:");
291 decimalSeparator = new CCombo(container, SWT.READ_ONLY | SWT.BORDER);
292 for(DecimalSeparator s : DecimalSeparator.values())
293 decimalSeparator.add(s.label);
294 decimalSeparator.select(0);
295 decimalSeparator.addSelectionListener(s);
296 GridDataFactory.fillDefaults().grab(true, false).span(2, 1).applyTo(decimalSeparator);
298 new Label(container, SWT.NONE).setText("&Column separator:");
299 columnSeparator = new CCombo(container, SWT.READ_ONLY | SWT.BORDER);
300 for(ColumnSeparator s : ColumnSeparator.values())
301 columnSeparator.add(s.label);
302 columnSeparator.select(0);
303 columnSeparator.addSelectionListener(s);
304 GridDataFactory.fillDefaults().grab(true, false).span(2, 1).applyTo(columnSeparator);
306 new Label(container, SWT.NONE).setText("Sampling:");
307 sampling = new CCombo(container, SWT.READ_ONLY | SWT.BORDER);
308 sampling.add("Recorded samples");
309 sampling.add("Resampled");
311 sampling.addSelectionListener(s);
312 GridDataFactory.fillDefaults().grab(true, false).span(2, 1).applyTo(sampling);
314 resampling = new Group(container, SWT.NONE);
315 resampling.setText("Resampling settings (not used with recorded samples)");
316 GridDataFactory.fillDefaults().grab(true, false).span(3, 1).applyTo(resampling);
317 GridLayoutFactory.swtDefaults().numColumns(3).applyTo(resampling);
319 new Label(resampling, SWT.NONE).setText("&Start time:");
320 startTime = new Text(resampling, SWT.BORDER);
321 startTime.addModifyListener(m);
322 GridDataFactory.fillDefaults().grab(true, false).applyTo(startTime);
323 new Label(resampling, SWT.NONE).setText(" seconds");
325 new Label(resampling, SWT.NONE).setText("&Time step:");
326 timeStep = new Text(resampling, SWT.BORDER);
327 timeStep.addModifyListener(m);
328 GridDataFactory.fillDefaults().grab(true, false).applyTo(timeStep);
329 new Label(resampling, SWT.NONE).setText(" seconds");
331 new Label(resampling, SWT.NONE).setText("Sampling mode:");
332 samplingMode = new CCombo(resampling, SWT.READ_ONLY | SWT.BORDER);
333 samplingMode.add("Linear interpolation");
334 samplingMode.add("Previous sample");
335 samplingMode.select(0);
336 samplingMode.addSelectionListener(s);
337 GridDataFactory.fillDefaults().grab(true, false).span(2,1).applyTo(samplingMode);
339 Group digits = new Group(container, SWT.NONE);
340 digits.setText("Significant digits");
341 GridDataFactory.fillDefaults().grab(true, false).span(3, 1).applyTo(digits);
342 GridLayoutFactory.swtDefaults().numColumns(2).applyTo(digits);
344 new Label(digits, SWT.NONE).setText("&Time stamps:");
345 timeStamps = new Text(digits, SWT.BORDER);
346 timeStamps.addModifyListener(m);
347 GridDataFactory.fillDefaults().grab(true, false).applyTo(timeStamps);
349 new Label(digits, SWT.NONE).setText("&Single precision floating point:");
350 singlePrecision = new Text(digits, SWT.BORDER);
351 singlePrecision.addModifyListener(m);
352 GridDataFactory.fillDefaults().grab(true, false).applyTo(singlePrecision);
354 new Label(digits, SWT.NONE).setText("&Double precision floating point:");
355 doublePrecision = new Text(digits, SWT.BORDER);
356 doublePrecision.addModifyListener(m);
357 GridDataFactory.fillDefaults().grab(true, false).applyTo(doublePrecision);
359 overwrite = new Button(container, SWT.CHECK);
360 overwrite.setText("&Overwrite existing files without warning");
361 overwrite.setSelection(exportModel.overwrite);
362 GridDataFactory.fillDefaults().grab(true, false).span(3, 1).applyTo(overwrite);
363 overwrite.addSelectionListener(new SelectionAdapter() {
365 public void widgetSelected(SelectionEvent e) {
370 model.addSelectionListener(s);
372 initialSelection = ISelectionUtils.getPossibleKeys(exportModel.selection, SelectionHints.KEY_MAIN, Resource.class);
373 initializeWidgetsFromPreferences();
376 scroller.setMinSize(container.computeSize(SWT.DEFAULT, SWT.DEFAULT));
377 setControl(scroller);
381 private void initializeWidgetsFromPreferences() {
382 // Write preferences to formatter
383 IPreferenceStore csvnode = new ScopedPreferenceStore( InstanceScope.INSTANCE, CSVPreferences.P_NODE );
385 Double startTime = csvnode.getDouble(CSVPreferences.P_CSV_START_TIME);
386 Double timeStep = csvnode.getDouble(CSVPreferences.P_CSV_TIME_STEP);
387 String decimalSeparator = csvnode.getString(CSVPreferences.P_CSV_DECIMAL_SEPARATOR);
388 String columnSeparator = StringEscapeUtils.unescape( csvnode.getString(CSVPreferences.P_CSV_COLUMN_SEPARATOR) );
389 Boolean resample = csvnode.getBoolean(CSVPreferences.P_CSV_RESAMPLE);
390 String samplingModePreference = csvnode.getString(CSVPreferences.P_CSV_SAMPLING_MODE);
391 int timeDigits = csvnode.getInt(CSVPreferences.P_CSV_TIME_DIGITS);
392 int floatDigits = csvnode.getInt(CSVPreferences.P_CSV_FLOAT_DIGITS);
393 int doubleDigits = csvnode.getInt(CSVPreferences.P_CSV_DOUBLE_DIGITS);
395 this.decimalSeparator.select(DecimalSeparator.fromPreference(decimalSeparator).ordinal());
396 this.columnSeparator.select(ColumnSeparator.fromPreference(columnSeparator).ordinal());
398 this.sampling.select(resample ? 1 : 0);
399 this.samplingMode.select(ExportInterpolation.fromPreference(samplingModePreference).index());
401 this.startTime.setText("" + startTime);
402 this.timeStep.setText("" + timeStep);
403 this.timeStamps.setText("" + timeDigits);
404 this.singlePrecision.setText("" + floatDigits);
405 this.doublePrecision.setText("" + doubleDigits);
407 for (String path : exportModel.recentLocations)
408 exportLocation.add(path);
409 if (exportLocation.getItemCount() > 0)
410 exportLocation.select(0);
413 private void initializeData() {
415 getContainer().run(true, true, monitor -> {
417 initializeModelData(monitor);
418 SWTUtils.asyncExec(model, () -> {
419 if (!model.isDisposed())
420 initializeModelAndItemSelection();
422 } catch (DatabaseException e) {
423 throw new InvocationTargetException(e);
428 } catch (InvocationTargetException e) {
429 setErrorMessage(e.getMessage());
430 LOGGER.error("Failed to initialized model data for wizard.", e.getCause());
431 } catch (InterruptedException e) {
432 setErrorMessage(e.getMessage());
433 LOGGER.error("Interrupted wizard model data initialization.", e);
437 private void initializeModelData(IProgressMonitor monitor) throws DatabaseException {
438 models = exportModel.sessionContext.getSession().syncRequest(
439 (Read<List<Model>>) graph -> readModelData(monitor, graph));
442 private List<Model> readModelData(IProgressMonitor monitor, ReadGraph graph) throws DatabaseException {
443 List<Model> result = new ArrayList<>();
444 Layer0 L0 = Layer0.getInstance(graph);
445 Collection<Resource> models = graph.syncRequest(new ProjectModels(Simantics.getProjectResource()));
446 SubMonitor mon = SubMonitor.convert(monitor, "Reading model subscriptions", models.size());
447 for (Resource model : models) {
448 String name = graph.getPossibleRelatedValue(model, L0.HasName, Bindings.STRING);
450 name = NameLabelUtil.modalName(graph, model);
452 Model m = new Model(new NamedResource(name, model));
453 m.initialize(graph, initialSelection);
461 private void initializeModelAndItemSelection() {
462 boolean initialSelectionDone = false;
463 for (int i = 0; i < models.size(); i++) {
464 Model m = models.get(i);
465 model.add(m.model.getName());
466 if (!initialSelectionDone) {
467 boolean hasInitialSelection = m.sortedSubs.stream().anyMatch(m.initiallySelectedSubscriptions::contains);
468 if (hasInitialSelection) {
469 initializeItemSelectionForModel(m);
470 initialSelectionDone = true;
476 private void initializeItemSelectionForModel(Model m) {
477 int i = models.indexOf(m);
480 exportModel.items.clear();
483 item.setRedraw(false);
484 for (NamedResource nr : m.sortedSubs) {
485 TableItem ti = new TableItem(item, SWT.NONE);
486 ti.setText(nr.getName());
488 if (m.initiallySelectedSubscriptions.contains(nr)) {
489 exportModel.items.add(nr.getResource());
491 if (firstIndex == -1)
496 item.setTopIndex(Math.max(0, firstIndex));
498 item.setRedraw(true);
500 int checked = countCheckedItems(item);
501 updateSelectAll(checked > 0, checked < item.getItemCount(), false);
504 private void updateSelectAll(boolean checked, boolean gray, boolean notify) {
506 selectAllItems.setText("Select None");
508 selectAllItems.setText("Select All");
511 selectAllItems.removeSelectionListener(selectAllItemsListener);
512 selectAllItems.setGrayed(checked && gray);
513 selectAllItems.setSelection(checked);
515 selectAllItems.addSelectionListener(selectAllItemsListener);
518 protected int countCheckedItems(Table table) {
520 for (TableItem item : table.getItems())
521 ret += item.getChecked() ? 1 : 0;
525 Integer validInteger(String s) {
527 return Integer.parseInt(s);
528 } catch (NumberFormatException e) {
533 Double validDouble(String s) {
535 return Double.parseDouble(s);
536 } catch (NumberFormatException e) {
541 Model getModel(String name) {
542 for (Model m : models)
543 if (m.model.getName().equals(name))
548 private void setText(Group g, String text) {
549 if (!g.getText().equals(text))
553 void validatePage() {
554 boolean resample = sampling.getText().equals("Resampled");
556 setText(resampling, "Resampling settings");
557 timeStep.setEnabled(true);
558 startTime.setEnabled(true);
559 samplingMode.setEnabled(true);
561 setText(resampling, "Resampling settings (not used with recorded samples)");
562 timeStep.setEnabled(false);
563 startTime.setEnabled(false);
564 samplingMode.setEnabled(false);
567 String selectedModel = model.getText();
568 Model m = getModel(selectedModel);
570 Model existing = (Model) item.getData();
571 if (!m.equals(existing)) {
572 item.setRedraw(false);
574 for (NamedResource sub : m.sortedSubs) {
575 TableItem ti = new TableItem(item, SWT.NONE);
576 ti.setText(sub.getName());
578 ti.setChecked(m.initiallySelectedSubscriptions.contains(sub));
581 item.setRedraw(true);
584 exportModel.items = java.util.Arrays.stream(item.getItems())
585 .filter(TableItem::getChecked)
586 .map(ti -> ((NamedResource) ti.getData()).getResource())
587 .collect(Collectors.toSet());
590 Double validStartTime = validDouble(startTime.getText());
591 Double validStepSize = validDouble(timeStep.getText());
595 if (validStartTime == null) {
596 setErrorMessage("Start time must be a number.");
597 setPageComplete(false);
601 if (validStepSize == null) {
602 setErrorMessage("Step size must be a number.");
603 setPageComplete(false);
606 if (validStepSize <= 0) {
607 setErrorMessage("Step size must be greater than 0.");
608 setPageComplete(false);
614 if (exportModel.items.size() > 1) {
615 setErrorMessage("Recorded samples can only be exported for a single subscription item.");
616 setPageComplete(false);
622 if (item.getItemCount() == 0) {
623 setErrorMessage("No subscription items in selected model.");
624 setPageComplete(false);
628 if (exportModel.items.isEmpty()) {
629 setErrorMessage("No items selected for export.");
630 setPageComplete(false);
634 String exportLoc = exportLocation.getText();
635 if (exportLoc.isEmpty()) {
636 setErrorMessage("Select output file.");
637 setPageComplete(false);
640 File file = new File(exportLoc);
641 if (file.isDirectory()) {
642 setErrorMessage("The output file is a directory.");
643 setPageComplete(false);
646 File parent = file.getParentFile();
647 if (parent == null || !parent.isDirectory()) {
648 setErrorMessage("The output directory does not exist.");
649 setPageComplete(false);
653 exportModel.columnSeparator = ColumnSeparator.fromIndex(columnSeparator.getSelectionIndex());
654 exportModel.decimalSeparator = DecimalSeparator.fromIndex(decimalSeparator.getSelectionIndex());
655 if (exportModel.columnSeparator.preference.equals(exportModel.decimalSeparator.preference)) {
656 setErrorMessage("Decimal and column separator cannot be the same character.");
657 setPageComplete(false);
661 Integer validTimeDigits = validInteger(timeStamps.getText());
663 if (validTimeDigits == null) {
664 setErrorMessage("Time stamps needs to be an integer number.");
665 setPageComplete(false);
669 Integer validSinglePrecision = validInteger(singlePrecision.getText());
670 if (validSinglePrecision == null) {
671 setErrorMessage("Single precision needs to be an integer number.");
672 setPageComplete(false);
676 Integer validDoublePrecision = validInteger(doublePrecision.getText());
677 if (validDoublePrecision == null) {
678 setErrorMessage("Double precision needs to be an integer number.");
679 setPageComplete(false);
683 exportModel.exportLocation = file;
684 exportModel.overwrite = overwrite.getSelection();
686 exportModel.startTime = validStartTime;
687 exportModel.timeStep = validStepSize;
689 exportModel.resample = sampling.getSelectionIndex() == 1;
690 exportModel.samplingMode = ExportInterpolation.fromIndex(samplingMode.getSelectionIndex());
692 exportModel.timeDigits = validTimeDigits;
693 exportModel.floatDigits = validSinglePrecision;
694 exportModel.doubleDigits = validDoublePrecision;
696 setErrorMessage(null);
697 setMessage("Press Finish to export subscription data for " + exportModel.items.size() + " items.");
698 setPageComplete(true);