]> gerrit.simantics Code Review - simantics/district.git/blob - org.simantics.district.imports.ui/src/org/simantics/district/imports/ui/CSVImportWizardPage.java
Refactor CSV import wizard to only list each property once
[simantics/district.git] / org.simantics.district.imports.ui / src / org / simantics / district / imports / ui / CSVImportWizardPage.java
1 package org.simantics.district.imports.ui;
2
3 import java.io.IOException;
4 import java.util.ArrayList;
5 import java.util.HashMap;
6 import java.util.List;
7 import java.util.Map;
8 import java.util.Map.Entry;
9 import java.util.Set;
10 import java.util.function.Consumer;
11
12 import org.apache.commons.csv.CSVRecord;
13 import org.eclipse.jface.dialogs.IPageChangeProvider;
14 import org.eclipse.jface.dialogs.IPageChangedListener;
15 import org.eclipse.jface.dialogs.PageChangedEvent;
16 import org.eclipse.jface.layout.GridDataFactory;
17 import org.eclipse.jface.layout.TableColumnLayout;
18 import org.eclipse.jface.viewers.ColumnWeightData;
19 import org.eclipse.jface.wizard.IWizardContainer;
20 import org.eclipse.jface.wizard.WizardPage;
21 import org.eclipse.swt.SWT;
22 import org.eclipse.swt.events.ModifyEvent;
23 import org.eclipse.swt.events.ModifyListener;
24 import org.eclipse.swt.events.SelectionAdapter;
25 import org.eclipse.swt.events.SelectionEvent;
26 import org.eclipse.swt.events.SelectionListener;
27 import org.eclipse.swt.layout.GridLayout;
28 import org.eclipse.swt.widgets.Button;
29 import org.eclipse.swt.widgets.Combo;
30 import org.eclipse.swt.widgets.Composite;
31 import org.eclipse.swt.widgets.Group;
32 import org.eclipse.swt.widgets.Label;
33 import org.eclipse.swt.widgets.Table;
34 import org.eclipse.swt.widgets.TableColumn;
35 import org.eclipse.swt.widgets.TableItem;
36 import org.eclipse.swt.widgets.Text;
37 import org.geotools.referencing.CRS;
38 import org.simantics.district.imports.CSVImportModel;
39 import org.simantics.district.network.ui.DynamicComboFieldEditor;
40
41 public class CSVImportWizardPage extends WizardPage {
42
43     private CSVImportModel model;
44
45     private Map<Integer, String> headerIndexAndValues = new HashMap<>();
46
47     private Table headerTable;
48 //    private Button firstAsHeader;
49
50     private Combo delimiterCombo;
51     private TableColumnLayout tableColumnLayout;
52     private Composite tableComposite;
53 //    private FileSelectionWidget wktFileSelection;
54
55     List<DynamicComboFieldEditor> fieldSelectors;
56     
57     private Text edgeConnectionPadding;
58     
59     private Group indexMappingGroup;
60
61     private Composite composite;
62
63     private Button isVertexImport;
64
65     private Combo sourceCRSCombo;
66
67     protected CSVImportWizardPage(CSVImportModel model) {
68         super("Import CSV Data");
69         this.model = model;
70         setMessage("Select column index mappings");
71     }
72
73     @Override
74     public void createControl(Composite parent) {
75         composite = new Composite(parent, SWT.NONE);
76         composite.setLayout(new GridLayout(1, false));
77         GridDataFactory.fillDefaults().grab(true, true).align(SWT.FILL, SWT.FILL).applyTo(composite);
78
79         Label label = new Label(composite, SWT.NONE);
80         label.setText("Select delimiter");
81         
82         delimiterCombo = new Combo(composite, SWT.DROP_DOWN | SWT.READ_ONLY);
83         delimiterCombo.setToolTipText("Select the delimiter that is used to separate elements in the CSV file");
84         String[] formats = model.getDelimiterFormats();
85         delimiterCombo.setItems(formats);
86         if (formats.length > 0)
87             delimiterCombo.select(0);
88         delimiterCombo.addSelectionListener(new SelectionListener() {
89
90             @Override
91             public void widgetSelected(SelectionEvent e) {
92                 model.setDelimiterByLabel(delimiterCombo.getItem(delimiterCombo.getSelectionIndex()));
93                 updateHeaders();
94                 updateCombos();
95             }
96
97             @Override
98             public void widgetDefaultSelected(SelectionEvent e) {
99                 widgetSelected(e);
100             }
101         });
102
103 //        firstAsHeader = new Button(composite, SWT.CHECK);
104 //        firstAsHeader.setText("Read first row as header");
105 //        firstAsHeader.setSelection(model.getReadFirstAsHeader());
106 //        firstAsHeader.addSelectionListener(new SelectionListener() {
107 //
108 //            @Override
109 //            public void widgetSelected(SelectionEvent e) {
110 //                model.setReadFirstAsHeader(firstAsHeader.getSelection());
111 //                updateHeaders();
112 //                updateCombos();
113 //            }
114 //
115 //            @Override
116 //            public void widgetDefaultSelected(SelectionEvent e) {
117 //                widgetSelected(e);
118 //            }
119 //        });
120
121         tableComposite = new Composite(composite, SWT.BORDER);
122         tableColumnLayout = new TableColumnLayout();
123         tableComposite.setLayout(tableColumnLayout);
124
125         label = new Label(composite, SWT.NONE);
126         label.setText("Select source Coordinate Reference System");
127         
128         sourceCRSCombo = new Combo(composite, SWT.NONE);
129         sourceCRSCombo.setToolTipText("Select the coordinate reference system that is used in the source material for possible transformation to target coordinate reference system (EPSG:4326)");
130         Set<String> codes = CRS.getSupportedCodes("EPSG");
131         sourceCRSCombo.setItems(codes.toArray(new String[codes.size()]));
132         sourceCRSCombo.addSelectionListener(new SelectionAdapter() {
133             
134             @Override
135             public void widgetSelected(SelectionEvent e) {
136                 String current = sourceCRSCombo.getItem(sourceCRSCombo.getSelectionIndex());
137                 model.setSourceCRS("EPSG:" + current);
138             }
139         });
140         
141         sourceCRSCombo.addModifyListener(new ModifyListener() {
142             
143             @Override
144             public void modifyText(ModifyEvent e) {
145                 String currentText = sourceCRSCombo.getText();
146                 if (codes.contains(currentText)) {
147                     // Select this
148                     String[] items = sourceCRSCombo.getItems();
149                     int i;
150                     for (i = 0; i < items.length; i++) {
151                         String item = items[i];
152                         if (currentText.equals(item)) {
153                             break;
154                         }
155                     }
156                     if (i != 0) {
157                         sourceCRSCombo.select(i);
158                         model.setSourceCRS("EPSG:" + currentText);
159                     } else {
160                         System.err.println("this should not happen");
161                     }
162                 }
163             }
164         });
165         
166 //        wktFileSelection = new FileSelectionWidget(composite, "WKT file", SWT.OPEN);
167 //        wktFileSelection.addListener(new FileSelectionListener() {
168 //
169 //            @Override
170 //            public void fileSelected(FileOrDirectorySelectionWidget source, String[] filename) {
171 //                String[] selection = wktFileSelection.getFilename();
172 //                if (selection != null && selection.length > 0) {
173 //                    Path wktFile = Paths.get(selection[0]);
174 //                    if (!Files.exists(wktFile)) {
175 //                        setErrorMessage("File " + wktFile.toAbsolutePath() + " does not exist");
176 //                    } else {
177 //                        model.setWKTFile(wktFile);
178 //                        validatePageComplete();
179 //                    }
180 //                }
181 //            }
182 //        });
183
184         isVertexImport = new Button(composite, SWT.CHECK);
185         isVertexImport.setText("File contains vertices");
186         isVertexImport.setToolTipText("Enable this if the file contains vertices, i.e. points");
187         isVertexImport.setSelection(model.isVertexImport());
188         isVertexImport.addSelectionListener(new SelectionListener() {
189
190             @Override
191             public void widgetSelected(SelectionEvent e) {
192                 model.setVertexImport(isVertexImport.getSelection());
193                 updateControls(false);
194             }
195
196             @Override
197             public void widgetDefaultSelected(SelectionEvent e) {
198                 widgetSelected(e);
199             }
200         });
201         
202         updateControls(true);
203         updateHeaders();
204         setControl(composite);
205
206         final IWizardContainer container = getContainer();
207         
208         if (container instanceof IPageChangeProvider) {
209             ((IPageChangeProvider) container).addPageChangedListener(new IPageChangedListener() {
210
211                 @Override
212                 public void pageChanged(PageChangedEvent event) {
213                     if (isCurrentPage())
214                         CSVImportWizardPage.this.updateControls(false);
215                 }
216             });
217         }
218
219         validatePageComplete();
220     }
221     
222     private void updateControls(boolean initial) {
223         createIndexMappingGroup();
224         updateCombos();
225         if (!initial)
226             composite.layout(true, true);
227     }
228     
229     private void createIndexMappingGroup() {
230         if (indexMappingGroup != null)
231             indexMappingGroup.dispose();
232         
233         indexMappingGroup = new Group(composite, SWT.NONE);
234         indexMappingGroup.setText("Column index mapping");
235         GridDataFactory.fillDefaults().grab(true, false).span(2, 1).applyTo(indexMappingGroup);
236         
237         fieldSelectors = new ArrayList<>();
238         
239         createCommonIndexMappingField(indexMappingGroup);
240         
241         if (model.isVertexImport())
242             createVertexIndexMappingField(indexMappingGroup);
243         else
244             createEdgeIndexMappingField(indexMappingGroup);
245         
246         if (!model.isVertexImport()) {
247             Label label = new Label(indexMappingGroup, SWT.NONE);
248             label.setText("Connection point padding");
249             GridDataFactory.fillDefaults().applyTo(label);
250             edgeConnectionPadding = new Text(indexMappingGroup, SWT.BORDER);
251             GridDataFactory.fillDefaults().applyTo(edgeConnectionPadding);
252             edgeConnectionPadding.setText("0.0001"); // default
253             edgeConnectionPadding.addModifyListener(new ModifyListener() {
254                 
255                 @Override
256                 public void modifyText(ModifyEvent e) {
257                     try {
258                         double padding = Double.parseDouble(edgeConnectionPadding.getText());
259                         model.setEdgePadding(padding);
260                     } catch (NumberFormatException ee) {
261                         // ignore
262                     }
263                 }
264             });
265         }
266     }
267
268     private void createCommonIndexMappingField(Group parent) {
269         
270         fieldSelectors.add(createComboField("componentMapping", "Apros component mapping", model::setComponentMappingIndex, parent));
271         
272         fieldSelectors.add(createComboField("id", "ID", model::setIdIndex, parent));
273         fieldSelectors.add(createComboField("regionValue", "Region", model::setRegionIndex, parent));
274     }
275
276     private DynamicComboFieldEditor createComboField(String name, String label, Consumer<Integer> setter, Group parent) {
277         DynamicComboFieldEditor selector = new DynamicComboFieldEditor(name, label, parent);
278         createSelectionListener(selector, setter);
279         return selector;
280     }
281     
282     private void createSelectionListener(DynamicComboFieldEditor editor, Consumer<Integer> setter) {
283         editor.addComboListener(new SelectionListener() {
284     
285             @Override
286             public void widgetSelected(SelectionEvent e) {
287                 widgetDefaultSelected(e);
288             }
289     
290             @Override
291             public void widgetDefaultSelected(SelectionEvent e) {
292                 setter.accept(Integer.parseInt(editor.getValue()));
293                 validatePageComplete();
294             }
295         });
296     }
297
298     private void createVertexIndexMappingField(Group parent) {
299         fieldSelectors.add(createComboField("xCoord", "X Coordinate", model::setXCoordIndex, parent));
300
301         fieldSelectors.add(createComboField("yCoord", "Y Coordinate", model::setYCoordIndex, parent));
302         fieldSelectors.add(createComboField("zValue", "Z Value", model::setZCoordIndex, parent));
303
304         fieldSelectors.add(createComboField("altElevation", "Alternative Elevation", model::setAltElevationIndex, parent));
305         
306         fieldSelectors.add(createComboField("tempValue", "Supply Temperature value", model::setSupplyTempIndex, parent));
307         fieldSelectors.add(createComboField("returnTempValue", "Return Temperature value", model::setReturnTempIndex, parent));
308         fieldSelectors.add(createComboField("pressureValue", "Supply Pressure value", model::setSupplyPressureIndex, parent));
309         fieldSelectors.add(createComboField("returnPressureValue", "Return Pressure value", model::setReturnPressureIndex, parent));
310         fieldSelectors.add(createComboField("dpValue", "Delta pressure ", model::setDeltaPressureIndex, parent));
311         fieldSelectors.add(createComboField("dtValue", "Delta temperature ", model::setDeltaTemperatureIndex, parent));
312         fieldSelectors.add(createComboField("heatPowerValue", "Heat Power", model::setHeatPowerIndex, parent));
313         fieldSelectors.add(createComboField("peakPowerValue", "Peak Power", model::setPeakPowerIndex, parent));
314         
315         fieldSelectors.add(createComboField("nominalHeadMValue", "nominalHeadM", model::setNominalHeadMIndex, parent));
316         fieldSelectors.add(createComboField("nominalHeadBValue", "nominalHeadB", model::setNominalHeadBIndex, parent));
317         fieldSelectors.add(createComboField("nominalFlowValue", "nominalFlow", model::setNominalFlowIndex, parent));
318
319         fieldSelectors.add(createComboField("maximumHeadMValue", "maximumHeadM", model::setMaximumHeadMIndex, parent));
320         fieldSelectors.add(createComboField("heatLoadDsValue", "heatLoadDs", model::setHeatLoadDsIndex, parent));
321         fieldSelectors.add(createComboField("massFlowValue", "massFlow", model::setMassFlowIndex, parent));
322         fieldSelectors.add(createComboField("volFlowValue", "volFlow", model::setVolFlowIndex, parent));
323         fieldSelectors.add(createComboField("velocityValue", "velocity", model::setVelocityIndex, parent));
324         fieldSelectors.add(createComboField("flowAreaValue", "flowArea", model::setFlowAreaIndex, parent));
325         fieldSelectors.add(createComboField("nominalPressureLossValue", "nominalPressureLoss", model::setNominalPressureLossIndex, parent));
326         fieldSelectors.add(createComboField("valvePositionSelectorValue", "valvePositionSelector", model::setValvePositionIndex, parent));
327         fieldSelectors.add(createComboField("addressValue", "addressSelector", model::setAddressIndex, parent));
328     }
329     
330     private void createEdgeIndexMappingField(Group parent) {
331         
332 //        Composite paddingComposite = new Composite(parent, SWT.NONE);
333 //        GridLayoutFactory.fillDefaults().numColumns(2).applyTo(paddingComposite);
334         fieldSelectors.add(createComboField("startxCoord", "Start X Coordinate", model::setStartXCoordIndex, parent));
335         fieldSelectors.add(createComboField("startyCoord", "Start Y Coordinate", model::setStartYCoordIndex, parent));
336         fieldSelectors.add(createComboField("startzValue", "Start Z Value", model::setStartZCoordIndex, parent));
337         
338         fieldSelectors.add(createComboField("endxCoord", "End X Coordinate", model::setEndXCoordIndex, parent));
339         fieldSelectors.add(createComboField("endyCoord", "End Y Coordinate", model::setEndYCoordIndex, parent));
340         fieldSelectors.add(createComboField("endzValue", "End Z Value", model::setEndZCoordIndex, parent));
341         
342         fieldSelectors.add(createComboField("pipeCodeValue", "Pipe Code", model::setPipeCodeIndex, parent));
343         
344         fieldSelectors.add(createComboField("detailedGeometryValue", "Geometry", model::detailedGeometryIndex, parent));
345         fieldSelectors.add(createComboField("diameterValue", "Diameter value", model::setDiameterIndex, parent));
346         fieldSelectors.add(createComboField("outerDiameterValue", "Outer Diameter value", model::setOuterDiameterIndex, parent));
347         fieldSelectors.add(createComboField("nominalMassFlowValue", "Nominal Mass Flow", model::setNominalMassFlowIndex, parent));
348         fieldSelectors.add(createComboField("edgeFlowAreaValue", "Flow Area", model::setEdgeFlowAreaIndex, parent));
349         fieldSelectors.add(createComboField("kReturnValue", "K Return", model::setKReturnIndex, parent));
350         fieldSelectors.add(createComboField("kSupplyValue", "K Supply", model::setKSupplyIndex, parent));
351         fieldSelectors.add(createComboField("tGroundValue", "Temperature Ground", model::setTGroundIndex, parent));
352         fieldSelectors.add(createComboField("lengthValue", "Length", model::setLengthIndex, parent));
353         
354         fieldSelectors.add(createComboField("pipeSizeDNValue", "Pipe Size DN", model::setPipeSizeDNIndex, parent));
355         fieldSelectors.add(createComboField("structureValue", "Structure", model::setStructureIndex, parent));
356         fieldSelectors.add(createComboField("installationYearValue", "Installation Year", model::setInstallationYearIndex, parent));
357         fieldSelectors.add(createComboField("wallThicknessValue", "Wall Thickness", model::setWallThicknessIndex, parent));
358         fieldSelectors.add(createComboField("insulationConductivityValue", "Insulation Conductivity", model::setInsulationConductivityIndex, parent));
359         fieldSelectors.add(createComboField("roughnessValue", "Roughness", model::setRoughnessIndex, parent));
360     }
361
362     private void updateCombos() {
363         String[][] namesAndValues = new String[headerIndexAndValues.size() + 1][];
364
365         namesAndValues[0] = new String[] {"", "-1"};
366         int i = 1;
367         for (Entry<Integer, String> entry : headerIndexAndValues.entrySet()) {
368             int key = entry.getKey();
369             String value = entry.getValue();
370
371             String[] nameAndValue = new String[2];
372             nameAndValue[0] = value;
373             nameAndValue[1] = Integer.toString(key);
374             namesAndValues[i++] = nameAndValue;
375         }
376
377         updateCombos(namesAndValues);
378     }
379
380     private void updateCombos(String[][] namesAndValues) {
381         fieldSelectors.forEach(s -> s.updateCombo(namesAndValues));
382     }
383
384     private void updateHeaders() {
385         if (headerTable != null)
386             headerTable.dispose();
387         headerTable = new Table(tableComposite, SWT.NONE);
388         headerTable.setHeaderVisible(true);
389         headerTable.setLinesVisible(true);
390         GridDataFactory.fillDefaults().grab(true, true).align(SWT.FILL, SWT.FILL).applyTo(tableComposite);
391         for (int i = 0; i < headerTable.getColumns().length; i++) {
392             TableColumn column = headerTable.getColumns()[i];
393             column.dispose();
394         }
395         for (int i = 0; i < headerTable.getItemCount(); i++) {
396             TableItem item = headerTable.getItem(i);
397             item.dispose();
398         }
399
400         headerIndexAndValues.clear();
401
402         try {
403             List<CSVRecord> rows = model.getRows(5, false);
404
405             for (int k = 0; k < rows.size(); k++) {
406                 CSVRecord row = rows.get(k);
407
408                 int columnCount = row.size();
409                 for (int i = 0; i < columnCount; i++) {
410                     String value = row.get(i);
411                     if (k == 0) {
412                         TableColumn headerCol = new TableColumn(headerTable, SWT.NONE);
413                         headerCol.setText(value);
414
415                         tableColumnLayout.setColumnData(headerCol, new ColumnWeightData(10));
416                         headerCol.pack();
417
418                         headerIndexAndValues.put(i, value);
419                     } else {
420                         int actualK = k - 1;
421                         TableItem item;
422                         int itemCount = headerTable.getItemCount();
423                         if (actualK >= itemCount) {
424                             item = new TableItem(headerTable, SWT.NONE);
425                         } else {
426                             item = headerTable.getItem(actualK);
427                         }
428                         item.setText(i, value);
429                     }
430                 }
431             }
432
433         } catch (IOException e) {
434             setErrorMessage(e.getMessage());
435         }
436     }
437
438     protected void validatePageComplete() {
439         if (model.isVertexImport())
440             setPageComplete(model.getXCoordIndex() != -1 && model.getYCoordIndex() != -1 && model.getComponentMappingIndex() != -1);
441         else
442             setPageComplete(model.getStartXCoordIndex() != -1 && model.getStartYCoordIndex() != -1 && model.getEndXCoordIndex() != -1 && model.getEndYCoordIndex() != -1 && model.getComponentMappingIndex() != -1);
443     }
444
445 }