1 package org.simantics.district.imports.ui;
3 import java.io.IOException;
4 import java.util.ArrayList;
5 import java.util.HashMap;
8 import java.util.Map.Entry;
10 import java.util.function.Consumer;
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;
41 public class CSVImportWizardPage extends WizardPage {
43 private CSVImportModel model;
45 private Map<Integer, String> headerIndexAndValues = new HashMap<>();
47 private Table headerTable;
48 // private Button firstAsHeader;
50 private Combo delimiterCombo;
51 private TableColumnLayout tableColumnLayout;
52 private Composite tableComposite;
53 // private FileSelectionWidget wktFileSelection;
55 List<DynamicComboFieldEditor> fieldSelectors;
57 private Text edgeConnectionPadding;
59 private Group indexMappingGroup;
61 private Composite composite;
63 private Button isVertexImport;
65 private Combo sourceCRSCombo;
67 protected CSVImportWizardPage(CSVImportModel model) {
68 super("Import CSV Data");
70 setMessage("Select column index mappings");
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);
79 Label label = new Label(composite, SWT.NONE);
80 label.setText("Select delimiter");
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() {
91 public void widgetSelected(SelectionEvent e) {
92 model.setDelimiterByLabel(delimiterCombo.getItem(delimiterCombo.getSelectionIndex()));
98 public void widgetDefaultSelected(SelectionEvent e) {
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() {
109 // public void widgetSelected(SelectionEvent e) {
110 // model.setReadFirstAsHeader(firstAsHeader.getSelection());
116 // public void widgetDefaultSelected(SelectionEvent e) {
117 // widgetSelected(e);
121 tableComposite = new Composite(composite, SWT.BORDER);
122 tableColumnLayout = new TableColumnLayout();
123 tableComposite.setLayout(tableColumnLayout);
125 label = new Label(composite, SWT.NONE);
126 label.setText("Select source Coordinate Reference System");
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() {
135 public void widgetSelected(SelectionEvent e) {
136 String current = sourceCRSCombo.getItem(sourceCRSCombo.getSelectionIndex());
137 model.setSourceCRS("EPSG:" + current);
141 sourceCRSCombo.addModifyListener(new ModifyListener() {
144 public void modifyText(ModifyEvent e) {
145 String currentText = sourceCRSCombo.getText();
146 if (codes.contains(currentText)) {
148 String[] items = sourceCRSCombo.getItems();
150 for (i = 0; i < items.length; i++) {
151 String item = items[i];
152 if (currentText.equals(item)) {
157 sourceCRSCombo.select(i);
158 model.setSourceCRS("EPSG:" + currentText);
160 System.err.println("this should not happen");
166 // wktFileSelection = new FileSelectionWidget(composite, "WKT file", SWT.OPEN);
167 // wktFileSelection.addListener(new FileSelectionListener() {
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");
177 // model.setWKTFile(wktFile);
178 // validatePageComplete();
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() {
191 public void widgetSelected(SelectionEvent e) {
192 model.setVertexImport(isVertexImport.getSelection());
193 updateControls(false);
197 public void widgetDefaultSelected(SelectionEvent e) {
202 updateControls(true);
204 setControl(composite);
206 final IWizardContainer container = getContainer();
208 if (container instanceof IPageChangeProvider) {
209 ((IPageChangeProvider) container).addPageChangedListener(new IPageChangedListener() {
212 public void pageChanged(PageChangedEvent event) {
214 CSVImportWizardPage.this.updateControls(false);
219 validatePageComplete();
222 private void updateControls(boolean initial) {
223 createIndexMappingGroup();
226 composite.layout(true, true);
229 private void createIndexMappingGroup() {
230 if (indexMappingGroup != null)
231 indexMappingGroup.dispose();
233 indexMappingGroup = new Group(composite, SWT.NONE);
234 indexMappingGroup.setText("Column index mapping");
235 GridDataFactory.fillDefaults().grab(true, false).span(2, 1).applyTo(indexMappingGroup);
237 fieldSelectors = new ArrayList<>();
239 createCommonIndexMappingField(indexMappingGroup);
241 if (model.isVertexImport())
242 createVertexIndexMappingField(indexMappingGroup);
244 createEdgeIndexMappingField(indexMappingGroup);
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() {
256 public void modifyText(ModifyEvent e) {
258 double padding = Double.parseDouble(edgeConnectionPadding.getText());
259 model.setEdgePadding(padding);
260 } catch (NumberFormatException ee) {
268 private void createCommonIndexMappingField(Group parent) {
270 fieldSelectors.add(createComboField("componentMapping", "Apros component mapping", model::setComponentMappingIndex, parent));
272 fieldSelectors.add(createComboField("id", "ID", model::setIdIndex, parent));
273 fieldSelectors.add(createComboField("regionValue", "Region", model::setRegionIndex, parent));
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);
282 private void createSelectionListener(DynamicComboFieldEditor editor, Consumer<Integer> setter) {
283 editor.addComboListener(new SelectionListener() {
286 public void widgetSelected(SelectionEvent e) {
287 widgetDefaultSelected(e);
291 public void widgetDefaultSelected(SelectionEvent e) {
292 setter.accept(Integer.parseInt(editor.getValue()));
293 validatePageComplete();
298 private void createVertexIndexMappingField(Group parent) {
299 fieldSelectors.add(createComboField("xCoord", "X Coordinate", model::setXCoordIndex, parent));
301 fieldSelectors.add(createComboField("yCoord", "Y Coordinate", model::setYCoordIndex, parent));
302 fieldSelectors.add(createComboField("zValue", "Z Value", model::setZCoordIndex, parent));
304 fieldSelectors.add(createComboField("altElevation", "Alternative Elevation", model::setAltElevationIndex, parent));
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));
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));
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));
330 private void createEdgeIndexMappingField(Group parent) {
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));
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));
342 fieldSelectors.add(createComboField("pipeCodeValue", "Pipe Code", model::setPipeCodeIndex, parent));
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));
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 fieldSelectors.add(createComboField("conductanceValue", "Conductance", model::setConductanceIndex, parent));
363 private void updateCombos() {
364 String[][] namesAndValues = new String[headerIndexAndValues.size() + 1][];
366 namesAndValues[0] = new String[] {"", "-1"};
368 for (Entry<Integer, String> entry : headerIndexAndValues.entrySet()) {
369 int key = entry.getKey();
370 String value = entry.getValue();
372 String[] nameAndValue = new String[2];
373 nameAndValue[0] = value;
374 nameAndValue[1] = Integer.toString(key);
375 namesAndValues[i++] = nameAndValue;
378 updateCombos(namesAndValues);
381 private void updateCombos(String[][] namesAndValues) {
382 fieldSelectors.forEach(s -> s.updateCombo(namesAndValues));
385 private void updateHeaders() {
386 if (headerTable != null)
387 headerTable.dispose();
388 headerTable = new Table(tableComposite, SWT.NONE);
389 headerTable.setHeaderVisible(true);
390 headerTable.setLinesVisible(true);
391 GridDataFactory.fillDefaults().grab(true, true).align(SWT.FILL, SWT.FILL).applyTo(tableComposite);
392 for (int i = 0; i < headerTable.getColumns().length; i++) {
393 TableColumn column = headerTable.getColumns()[i];
396 for (int i = 0; i < headerTable.getItemCount(); i++) {
397 TableItem item = headerTable.getItem(i);
401 headerIndexAndValues.clear();
404 List<CSVRecord> rows = model.getRows(5, false);
406 for (int k = 0; k < rows.size(); k++) {
407 CSVRecord row = rows.get(k);
409 int columnCount = row.size();
410 for (int i = 0; i < columnCount; i++) {
411 String value = row.get(i);
413 TableColumn headerCol = new TableColumn(headerTable, SWT.NONE);
414 headerCol.setText(value);
416 tableColumnLayout.setColumnData(headerCol, new ColumnWeightData(10));
419 headerIndexAndValues.put(i, value);
423 int itemCount = headerTable.getItemCount();
424 if (actualK >= itemCount) {
425 item = new TableItem(headerTable, SWT.NONE);
427 item = headerTable.getItem(actualK);
429 item.setText(i, value);
434 } catch (IOException e) {
435 setErrorMessage(e.getMessage());
439 protected void validatePageComplete() {
440 if (model.isVertexImport())
441 setPageComplete(model.getXCoordIndex() != -1 && model.getYCoordIndex() != -1 && model.getComponentMappingIndex() != -1);
443 setPageComplete(model.getStartXCoordIndex() != -1 && model.getStartYCoordIndex() != -1 && model.getEndXCoordIndex() != -1 && model.getEndYCoordIndex() != -1 && model.getComponentMappingIndex() != -1);