1 package org.simantics.district.imports.ui;
3 import java.io.IOException;
4 import java.util.HashMap;
7 import java.util.Map.Entry;
9 import java.util.function.Consumer;
11 import org.apache.commons.csv.CSVRecord;
12 import org.eclipse.jface.dialogs.IPageChangeProvider;
13 import org.eclipse.jface.dialogs.IPageChangedListener;
14 import org.eclipse.jface.dialogs.PageChangedEvent;
15 import org.eclipse.jface.layout.GridDataFactory;
16 import org.eclipse.jface.layout.TableColumnLayout;
17 import org.eclipse.jface.viewers.ColumnWeightData;
18 import org.eclipse.jface.wizard.IWizardContainer;
19 import org.eclipse.jface.wizard.WizardPage;
20 import org.eclipse.swt.SWT;
21 import org.eclipse.swt.events.ModifyEvent;
22 import org.eclipse.swt.events.ModifyListener;
23 import org.eclipse.swt.events.SelectionAdapter;
24 import org.eclipse.swt.events.SelectionEvent;
25 import org.eclipse.swt.events.SelectionListener;
26 import org.eclipse.swt.layout.GridLayout;
27 import org.eclipse.swt.widgets.Button;
28 import org.eclipse.swt.widgets.Combo;
29 import org.eclipse.swt.widgets.Composite;
30 import org.eclipse.swt.widgets.Group;
31 import org.eclipse.swt.widgets.Label;
32 import org.eclipse.swt.widgets.Table;
33 import org.eclipse.swt.widgets.TableColumn;
34 import org.eclipse.swt.widgets.TableItem;
35 import org.eclipse.swt.widgets.Text;
36 import org.geotools.referencing.CRS;
37 import org.simantics.district.imports.CSVImportModel;
38 import org.simantics.district.network.ui.DynamicComboFieldEditor;
40 public class CSVImportWizardPage extends WizardPage {
42 private CSVImportModel model;
44 private Map<Integer, String> headerIndexAndValues = new HashMap<>();
46 private Table headerTable;
47 // private Button firstAsHeader;
49 private Combo delimiterCombo;
50 private TableColumnLayout tableColumnLayout;
51 private Composite tableComposite;
52 // private FileSelectionWidget wktFileSelection;
54 // Common for vertex and edge
55 private DynamicComboFieldEditor componentMappingSelector;
56 private DynamicComboFieldEditor idSelector;
59 private DynamicComboFieldEditor xCoordSelector;
60 private DynamicComboFieldEditor yCoordSelector;
61 private DynamicComboFieldEditor zValueSelector;
62 private DynamicComboFieldEditor altElevationValueSelector;
64 private DynamicComboFieldEditor supplyTempValueSelector;
65 private DynamicComboFieldEditor returnTempValueSelector;
66 private DynamicComboFieldEditor supplyPressureValueSelector;
67 private DynamicComboFieldEditor returnPressureValueSelector;
68 private DynamicComboFieldEditor dpSelector;
69 private DynamicComboFieldEditor dtSelector;
70 private DynamicComboFieldEditor heatPowerSelector;
71 private DynamicComboFieldEditor peakPowerSelector;
72 private DynamicComboFieldEditor regionSelector;
73 private DynamicComboFieldEditor nominalHeadMSelector;
74 private DynamicComboFieldEditor nominalHeadBSelector;
75 private DynamicComboFieldEditor nominalFlowSelector;
76 private DynamicComboFieldEditor maximumHeadMSelector;
77 private DynamicComboFieldEditor heatLoadDsSelector;
78 private DynamicComboFieldEditor massFlowSelector;
79 private DynamicComboFieldEditor volFlowSelector;
80 private DynamicComboFieldEditor velocitySelector;
81 private DynamicComboFieldEditor flowAreaSelector;
82 private DynamicComboFieldEditor nominalPressureLossSelector;
83 private DynamicComboFieldEditor valvePositionSelector;
84 private DynamicComboFieldEditor addressSelector;
85 private DynamicComboFieldEditor lengthSelector;
88 private DynamicComboFieldEditor startXCoordSelector;
89 private DynamicComboFieldEditor startYCoordSelector;
90 private DynamicComboFieldEditor startZValueSelector;
91 private DynamicComboFieldEditor endXCoordSelector;
92 private DynamicComboFieldEditor endYCoordSelector;
93 private DynamicComboFieldEditor endZValueSelector;
94 private DynamicComboFieldEditor detailedGeometrySelector;
95 private DynamicComboFieldEditor pipeCodeSelector;
96 private DynamicComboFieldEditor installationYearSelector;
97 private DynamicComboFieldEditor wallThicknessSelector;
98 private DynamicComboFieldEditor insulationConductivitySelector;
99 private DynamicComboFieldEditor pipeSizeDNSelector;
100 private DynamicComboFieldEditor roughnessSelector;
101 private DynamicComboFieldEditor structureSelector;
103 private Text edgeConnectionPadding;
105 private DynamicComboFieldEditor outerDiameterSelector;
106 private DynamicComboFieldEditor diameterSelector;
107 private DynamicComboFieldEditor nominalMassFlowSelector;
109 private Group indexMappingGroup;
111 private Composite composite;
113 private Button isVertexImport;
115 private Combo sourceCRSCombo;
117 private DynamicComboFieldEditor edgeFlowAreaSelector;
119 private DynamicComboFieldEditor kReturnSelector;
121 private DynamicComboFieldEditor kSupplySelector;
123 private DynamicComboFieldEditor tGroundSelector;
125 protected CSVImportWizardPage(CSVImportModel model) {
126 super("Import CSV Data");
128 setMessage("Select column index mappings");
132 public void createControl(Composite parent) {
133 composite = new Composite(parent, SWT.NONE);
134 composite.setLayout(new GridLayout(1, false));
135 GridDataFactory.fillDefaults().grab(true, true).align(SWT.FILL, SWT.FILL).applyTo(composite);
137 Label label = new Label(composite, SWT.NONE);
138 label.setText("Select delimiter");
140 delimiterCombo = new Combo(composite, SWT.DROP_DOWN | SWT.READ_ONLY);
141 delimiterCombo.setToolTipText("Select the delimiter that is used to separate elements in the CSV file");
142 String[] formats = model.getDelimiterFormats();
143 delimiterCombo.setItems(formats);
144 if (formats.length > 0)
145 delimiterCombo.select(0);
146 delimiterCombo.addSelectionListener(new SelectionListener() {
149 public void widgetSelected(SelectionEvent e) {
150 model.setDelimiterByLabel(delimiterCombo.getItem(delimiterCombo.getSelectionIndex()));
156 public void widgetDefaultSelected(SelectionEvent e) {
161 // firstAsHeader = new Button(composite, SWT.CHECK);
162 // firstAsHeader.setText("Read first row as header");
163 // firstAsHeader.setSelection(model.getReadFirstAsHeader());
164 // firstAsHeader.addSelectionListener(new SelectionListener() {
167 // public void widgetSelected(SelectionEvent e) {
168 // model.setReadFirstAsHeader(firstAsHeader.getSelection());
174 // public void widgetDefaultSelected(SelectionEvent e) {
175 // widgetSelected(e);
179 tableComposite = new Composite(composite, SWT.BORDER);
180 tableColumnLayout = new TableColumnLayout();
181 tableComposite.setLayout(tableColumnLayout);
183 label = new Label(composite, SWT.NONE);
184 label.setText("Select source Coordinate Reference System");
186 sourceCRSCombo = new Combo(composite, SWT.NONE);
187 sourceCRSCombo.setToolTipText("Select the coordinate reference system that is used in the source material for possible transformation to target coordinate reference system (EPSG:4326)");
188 Set<String> codes = CRS.getSupportedCodes("EPSG");
189 sourceCRSCombo.setItems(codes.toArray(new String[codes.size()]));
190 sourceCRSCombo.addSelectionListener(new SelectionAdapter() {
193 public void widgetSelected(SelectionEvent e) {
194 String current = sourceCRSCombo.getItem(sourceCRSCombo.getSelectionIndex());
195 model.setSourceCRS("EPSG:" + current);
199 sourceCRSCombo.addModifyListener(new ModifyListener() {
202 public void modifyText(ModifyEvent e) {
203 String currentText = sourceCRSCombo.getText();
204 if (codes.contains(currentText)) {
206 String[] items = sourceCRSCombo.getItems();
208 for (i = 0; i < items.length; i++) {
209 String item = items[i];
210 if (currentText.equals(item)) {
215 sourceCRSCombo.select(i);
216 model.setSourceCRS("EPSG:" + currentText);
218 System.err.println("this should not happen");
224 // wktFileSelection = new FileSelectionWidget(composite, "WKT file", SWT.OPEN);
225 // wktFileSelection.addListener(new FileSelectionListener() {
228 // public void fileSelected(FileOrDirectorySelectionWidget source, String[] filename) {
229 // String[] selection = wktFileSelection.getFilename();
230 // if (selection != null && selection.length > 0) {
231 // Path wktFile = Paths.get(selection[0]);
232 // if (!Files.exists(wktFile)) {
233 // setErrorMessage("File " + wktFile.toAbsolutePath() + " does not exist");
235 // model.setWKTFile(wktFile);
236 // validatePageComplete();
242 isVertexImport = new Button(composite, SWT.CHECK);
243 isVertexImport.setText("File contains vertices");
244 isVertexImport.setToolTipText("Enable this if the file contains vertices, i.e. points");
245 isVertexImport.setSelection(model.isVertexImport());
246 isVertexImport.addSelectionListener(new SelectionListener() {
249 public void widgetSelected(SelectionEvent e) {
250 model.setVertexImport(isVertexImport.getSelection());
251 updateControls(false);
255 public void widgetDefaultSelected(SelectionEvent e) {
260 updateControls(true);
262 setControl(composite);
264 final IWizardContainer container = getContainer();
266 if (container instanceof IPageChangeProvider) {
267 ((IPageChangeProvider) container).addPageChangedListener(new IPageChangedListener() {
270 public void pageChanged(PageChangedEvent event) {
272 CSVImportWizardPage.this.updateControls(false);
277 validatePageComplete();
280 private void updateControls(boolean initial) {
281 createIndexMappingGroup();
284 composite.layout(true, true);
287 private void createIndexMappingGroup() {
288 if (indexMappingGroup != null)
289 indexMappingGroup.dispose();
291 indexMappingGroup = new Group(composite, SWT.NONE);
292 indexMappingGroup.setText("Column index mapping");
293 GridDataFactory.fillDefaults().grab(true, false).span(2, 1).applyTo(indexMappingGroup);
295 if (model.isVertexImport())
296 createVertexIndexMappingField(indexMappingGroup);
298 createEdgeIndexMappingField(indexMappingGroup);
300 createCommonIndexMappingField(indexMappingGroup);
302 if (!model.isVertexImport()) {
303 Label label = new Label(indexMappingGroup, SWT.NONE);
304 label.setText("Connection point padding");
305 GridDataFactory.fillDefaults().applyTo(label);
306 edgeConnectionPadding = new Text(indexMappingGroup, SWT.BORDER);
307 GridDataFactory.fillDefaults().applyTo(edgeConnectionPadding);
308 edgeConnectionPadding.setText("0.0001"); // default
309 edgeConnectionPadding.addModifyListener(new ModifyListener() {
312 public void modifyText(ModifyEvent e) {
314 double padding = Double.parseDouble(edgeConnectionPadding.getText());
315 model.setEdgePadding(padding);
316 } catch (NumberFormatException ee) {
324 private void createCommonIndexMappingField(Group parent) {
326 componentMappingSelector = createComboField("componentMapping", "Apros component mapping", model::setComponentMappingIndex, parent);
328 idSelector = createComboField("id", "ID", model::setIdIndex, parent);
329 regionSelector = createComboField("regionValue", "Region", model::setRegionIndex, parent);
332 private DynamicComboFieldEditor createComboField(String name, String label, Consumer<Integer> setter, Group parent) {
333 DynamicComboFieldEditor selector = new DynamicComboFieldEditor(name, label, parent);
334 createSelectionListener(selector, setter);
338 private void createSelectionListener(DynamicComboFieldEditor editor, Consumer<Integer> setter) {
339 editor.addComboListener(new SelectionListener() {
342 public void widgetSelected(SelectionEvent e) {
343 widgetDefaultSelected(e);
347 public void widgetDefaultSelected(SelectionEvent e) {
348 setter.accept(Integer.parseInt(editor.getValue()));
349 validatePageComplete();
354 private void createVertexIndexMappingField(Group parent) {
355 xCoordSelector = createComboField("xCoord", "X Coordinate", model::setXCoordIndex, parent);
357 yCoordSelector = createComboField("yCoord", "Y Coordinate", model::setYCoordIndex, parent);
358 zValueSelector = createComboField("zValue", "Z Value", model::setZCoordIndex, parent);
360 altElevationValueSelector = createComboField("altElevation", "Alternative Elevation", model::setAltElevationIndex, parent);
362 supplyTempValueSelector = createComboField("tempValue", "Supply Temperature value", model::setSupplyTempIndex, parent);
363 returnTempValueSelector = createComboField("returnTempValue", "Return Temperature value", model::setReturnTempIndex, parent);
364 supplyPressureValueSelector = createComboField("pressureValue", "Supply Pressure value", model::setSupplyPressureIndex, parent);
365 returnPressureValueSelector = createComboField("returnPressureValue", "Return Pressure value", model::setReturnPressureIndex, parent);
366 dpSelector = createComboField("dpValue", "Delta pressure ", model::setDeltaPressureIndex, parent);
367 dtSelector = createComboField("dtValue", "Delta temperature ", model::setDeltaTemperatureIndex, parent);
368 heatPowerSelector = createComboField("heatPowerValue", "Heat Power", model::setHeatPowerIndex, parent);
369 peakPowerSelector = createComboField("peakPowerValue", "Peak Power", model::setPeakPowerIndex, parent);
371 nominalHeadMSelector = createComboField("nominalHeadMValue", "nominalHeadM", model::setNominalHeadMIndex, parent);
372 nominalHeadBSelector = createComboField("nominalHeadBValue", "nominalHeadB", model::setNominalHeadBIndex, parent);
373 nominalFlowSelector = createComboField("nominalFlowValue", "nominalFlow", model::setNominalFlowIndex, parent);
375 maximumHeadMSelector = createComboField("maximumHeadMValue", "maximumHeadM", model::setMaximumHeadMIndex, parent);
376 heatLoadDsSelector = createComboField("heatLoadDsValue", "heatLoadDs", model::setHeatLoadDsIndex, parent);
377 massFlowSelector = createComboField("massFlowValue", "massFlow", model::setMassFlowIndex, parent);
378 volFlowSelector = createComboField("volFlowValue", "volFlow", model::setVolFlowIndex, parent);
379 velocitySelector = createComboField("velocityValue", "velocity", model::setVelocityIndex, parent);
380 flowAreaSelector = createComboField("flowAreaValue", "flowArea", model::setFlowAreaIndex, parent);
381 nominalPressureLossSelector = createComboField("nominalPressureLossValue", "nominalPressureLoss", model::setNominalPressureLossIndex, parent);
382 valvePositionSelector = createComboField("valvePositionSelectorValue", "valvePositionSelector", model::setValvePositionIndex, parent);
383 addressSelector = createComboField("addressValue", "addressSelector", model::setAddressIndex, parent);
388 private void createEdgeIndexMappingField(Group parent) {
390 // Composite paddingComposite = new Composite(parent, SWT.NONE);
391 // GridLayoutFactory.fillDefaults().numColumns(2).applyTo(paddingComposite);
392 startXCoordSelector = createComboField("startxCoord", "Start X Coordinate", model::setStartXCoordIndex, parent);
393 startYCoordSelector = createComboField("startyCoord", "Start Y Coordinate", model::setStartYCoordIndex, parent);
394 startZValueSelector = createComboField("startzValue", "Start Z Value", model::setStartZCoordIndex, parent);
396 endXCoordSelector = createComboField("endxCoord", "End X Coordinate", model::setEndXCoordIndex, parent);
397 endYCoordSelector = createComboField("endyCoord", "End Y Coordinate", model::setEndYCoordIndex, parent);
398 endZValueSelector = createComboField("endzValue", "End Z Value", model::setEndZCoordIndex, parent);
400 pipeCodeSelector = createComboField("pipeCodeValue", "Pipe Code", model::setPipeCodeIndex, parent);
402 detailedGeometrySelector = createComboField("detailedGeometryValue", "Geometry", model::detailedGeometryIndex, parent);
403 diameterSelector = createComboField("diameterValue", "Diameter value", model::setDiameterIndex, parent);
404 outerDiameterSelector = createComboField("outerDiameterValue", "Outer Diameter value", model::setOuterDiameterIndex, parent);
405 nominalMassFlowSelector = createComboField("nominalMassFlowValue", "Nominal Mass Flow", model::setNominalMassFlowIndex, parent);
406 edgeFlowAreaSelector = createComboField("edgeFlowAreaValue", "Flow Area", model::setEdgeFlowAreaIndex, parent);
407 kReturnSelector = createComboField("kReturnValue", "K Return", model::setKReturnIndex, parent);
408 kSupplySelector = createComboField("kSupplyValue", "K Supply", model::setKSupplyIndex, parent);
409 tGroundSelector = createComboField("tGroundValue", "Temperature Ground", model::setTGroundIndex, parent);
410 lengthSelector = createComboField("lengthValue", "lengthSelector", model::setLengthIndex, parent);
412 pipeSizeDNSelector = createComboField("pipeSizeDNValue", "Pipe Size DN", model::setPipeSizeDNIndex, parent);
413 structureSelector = createComboField("structureValue", "Structure", model::setStructureIndex, parent);
414 installationYearSelector = createComboField("installationYearValue", "Installation Year", model::setInstallationYearIndex, parent);
415 wallThicknessSelector = createComboField("wallThicknessValue", "Wall Thickness", model::setWallThicknessIndex, parent);
416 insulationConductivitySelector = createComboField("insulationConductivityValue", "Insulation Conductivity", model::setInsulationConductivityIndex, parent);
417 roughnessSelector = createComboField("roughnessValue", "Roughness", model::setRoughnessIndex, parent);
420 private void updateCombos() {
421 String[][] namesAndValues = new String[headerIndexAndValues.size() + 1][];
423 namesAndValues[0] = new String[] {"", "-1"};
425 for (Entry<Integer, String> entry : headerIndexAndValues.entrySet()) {
426 int key = entry.getKey();
427 String value = entry.getValue();
429 String[] nameAndValue = new String[2];
430 nameAndValue[0] = value;
431 nameAndValue[1] = Integer.toString(key);
432 namesAndValues[i++] = nameAndValue;
435 if (model.isVertexImport())
436 updateVertexCombos(namesAndValues);
438 updateEdgeCombos(namesAndValues);
440 componentMappingSelector.updateCombo(namesAndValues);
441 idSelector.updateCombo(namesAndValues);
444 private void updateEdgeCombos(String[][] namesAndValues) {
445 startXCoordSelector.updateCombo(namesAndValues);
446 endXCoordSelector.updateCombo(namesAndValues);
447 startYCoordSelector.updateCombo(namesAndValues);
448 endYCoordSelector.updateCombo(namesAndValues);
449 startZValueSelector.updateCombo(namesAndValues);
450 endZValueSelector.updateCombo(namesAndValues);
451 pipeCodeSelector.updateCombo(namesAndValues);
452 detailedGeometrySelector.updateCombo(namesAndValues);
453 diameterSelector.updateCombo(namesAndValues);
454 outerDiameterSelector.updateCombo(namesAndValues);
455 nominalMassFlowSelector.updateCombo(namesAndValues);
456 edgeFlowAreaSelector.updateCombo(namesAndValues);
457 kReturnSelector.updateCombo(namesAndValues);
458 kSupplySelector.updateCombo(namesAndValues);
459 tGroundSelector.updateCombo(namesAndValues);
460 lengthSelector.updateCombo(namesAndValues);
461 pipeSizeDNSelector.updateCombo(namesAndValues);
462 structureSelector.updateCombo(namesAndValues);
463 installationYearSelector.updateCombo(namesAndValues);
464 wallThicknessSelector.updateCombo(namesAndValues);
465 insulationConductivitySelector.updateCombo(namesAndValues);
466 roughnessSelector.updateCombo(namesAndValues);
469 private void updateVertexCombos(String[][] namesAndValues) {
470 xCoordSelector.updateCombo(namesAndValues);
471 yCoordSelector.updateCombo(namesAndValues);
472 zValueSelector.updateCombo(namesAndValues);
473 altElevationValueSelector.updateCombo(namesAndValues);
474 supplyTempValueSelector.updateCombo(namesAndValues);
475 returnTempValueSelector.updateCombo(namesAndValues);
476 supplyPressureValueSelector.updateCombo(namesAndValues);
477 returnPressureValueSelector.updateCombo(namesAndValues);
478 dpSelector.updateCombo(namesAndValues);
479 dtSelector.updateCombo(namesAndValues);
480 heatPowerSelector.updateCombo(namesAndValues);
481 valvePositionSelector.updateCombo(namesAndValues);
482 nominalHeadMSelector.updateCombo(namesAndValues);
483 nominalHeadBSelector.updateCombo(namesAndValues);
484 nominalFlowSelector.updateCombo(namesAndValues);
485 maximumHeadMSelector.updateCombo(namesAndValues);
486 heatLoadDsSelector.updateCombo(namesAndValues);
487 massFlowSelector.updateCombo(namesAndValues);
488 volFlowSelector.updateCombo(namesAndValues);
489 velocitySelector.updateCombo(namesAndValues);
490 flowAreaSelector.updateCombo(namesAndValues);
491 nominalPressureLossSelector.updateCombo(namesAndValues);
492 addressSelector.updateCombo(namesAndValues);
497 private void updateHeaders() {
498 if (headerTable != null)
499 headerTable.dispose();
500 headerTable = new Table(tableComposite, SWT.NONE);
501 headerTable.setHeaderVisible(true);
502 headerTable.setLinesVisible(true);
503 GridDataFactory.fillDefaults().grab(true, true).align(SWT.FILL, SWT.FILL).applyTo(tableComposite);
504 for (int i = 0; i < headerTable.getColumns().length; i++) {
505 TableColumn column = headerTable.getColumns()[i];
508 for (int i = 0; i < headerTable.getItemCount(); i++) {
509 TableItem item = headerTable.getItem(i);
513 headerIndexAndValues.clear();
516 List<CSVRecord> rows = model.getRows(5, false);
518 for (int k = 0; k < rows.size(); k++) {
519 CSVRecord row = rows.get(k);
521 int columnCount = row.size();
522 for (int i = 0; i < columnCount; i++) {
523 String value = row.get(i);
525 TableColumn headerCol = new TableColumn(headerTable, SWT.NONE);
526 headerCol.setText(value);
528 tableColumnLayout.setColumnData(headerCol, new ColumnWeightData(10));
531 headerIndexAndValues.put(i, value);
535 int itemCount = headerTable.getItemCount();
536 if (actualK >= itemCount) {
537 item = new TableItem(headerTable, SWT.NONE);
539 item = headerTable.getItem(actualK);
541 item.setText(i, value);
546 } catch (IOException e) {
547 setErrorMessage(e.getMessage());
551 protected void validatePageComplete() {
552 if (model.isVertexImport())
553 setPageComplete(model.getXCoordIndex() != -1 && model.getYCoordIndex() != -1 && model.getComponentMappingIndex() != -1);
555 setPageComplete(model.getStartXCoordIndex() != -1 && model.getStartYCoordIndex() != -1 && model.getEndXCoordIndex() != -1 && model.getEndYCoordIndex() != -1 && model.getComponentMappingIndex() != -1);