--- /dev/null
+package org.simantics.district.network.ui.table;
+
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.Map;
+
+import javax.inject.Inject;
+import javax.inject.Named;
+
+import org.eclipse.e4.core.di.annotations.Execute;
+import org.eclipse.e4.ui.services.IServiceConstants;
+import org.eclipse.e4.ui.workbench.modeling.EPartService;
+import org.eclipse.swt.widgets.FileDialog;
+import org.eclipse.swt.widgets.Shell;
+import org.simantics.district.imports.DistrictImportUtils;
+import org.simantics.district.network.ui.techtype.table.TechTypeTableView;
+import org.simantics.utils.ui.ExceptionUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class ImportTechTypeCSVHandler {
+
+ private static final Logger LOGGER = LoggerFactory.getLogger(ImportTechTypeCSVHandler.class);
+
+ @Inject
+ EPartService partService;
+
+ @Execute
+ public void execute(@Named(IServiceConstants.ACTIVE_SHELL) Shell s) {
+ // here we can import based on the current CSV table data
+
+ FileDialog dialog = new FileDialog(s);
+ String path = dialog.open();
+ try {
+ if (path != null) {
+
+ Path p = Paths.get(path);
+ if (Files.exists(p)) {
+ Map<String, Integer> readCSVHeader = DistrictImportUtils.readCSVHeader(p, ';', true);
+ TechTypeTableView.table.setTechTypePath(path);
+ } else {
+ LOGGER.warn("Path does not exist even though path != null: {}", p);
+ }
+ } else {
+ LOGGER.error("Invalid file path given {}", path);
+ }
+ } catch (Exception e) {
+ LOGGER.error("Could not read file {}", path, e);
+ ExceptionUtils.logAndShowError("Could not read file " + path + " : " + e.getMessage(), e);
+ }
+ }
+}
--- /dev/null
+package org.simantics.district.network.ui.techtype.table;
+
+import org.eclipse.nebula.widgets.nattable.data.IDataProvider;
+
+public class TechTypeColumnHeaderTableDataProvider implements IDataProvider {
+
+ private TechTypeTableDataProvider bodyDataProvider;
+
+ public TechTypeColumnHeaderTableDataProvider(TechTypeTableDataProvider bodyDataProvider) {
+ this.bodyDataProvider = bodyDataProvider;
+ }
+
+ @Override
+ public Object getDataValue(int columnIndex, int rowIndex) {
+ return bodyDataProvider.getHeaderValue(columnIndex);
+ }
+
+ @Override
+ public void setDataValue(int columnIndex, int rowIndex, Object newValue) {
+
+ }
+
+ @Override
+ public int getColumnCount() {
+ return bodyDataProvider.getColumnCount();
+ }
+
+ @Override
+ public int getRowCount() {
+ return 1;
+ }
+
+}
--- /dev/null
+package org.simantics.district.network.ui.techtype.table;
+
+import org.eclipse.nebula.widgets.nattable.data.IDataProvider;
+
+public class TechTypeRowHeaderTableDataProvider implements IDataProvider {
+
+ protected final IDataProvider bodyDataProvider;
+
+ public TechTypeRowHeaderTableDataProvider(IDataProvider bodyDataProvider) {
+ this.bodyDataProvider = bodyDataProvider;
+ }
+
+ @Override
+ public int getColumnCount() {
+ return 1;
+ }
+
+ @Override
+ public int getRowCount() {
+ return this.bodyDataProvider.getRowCount();
+ }
+
+ @Override
+ public Object getDataValue(int columnIndex, int rowIndex) {
+ return Integer.valueOf(rowIndex + 1);
+ }
+
+ @Override
+ public void setDataValue(int columnIndex, int rowIndex, Object newValue) {
+ throw new UnsupportedOperationException();
+ }
+
+}
--- /dev/null
+package org.simantics.district.network.ui.techtype.table;
+
+import java.io.Serializable;
+
+import org.eclipse.jface.layout.GridDataFactory;
+import org.eclipse.jface.layout.GridLayoutFactory;
+import org.eclipse.nebula.widgets.nattable.NatTable;
+import org.eclipse.nebula.widgets.nattable.config.DefaultNatTableStyleConfiguration;
+import org.eclipse.nebula.widgets.nattable.config.IConfigRegistry;
+import org.eclipse.nebula.widgets.nattable.copy.command.CopyDataCommandHandler;
+import org.eclipse.nebula.widgets.nattable.data.IDataProvider;
+import org.eclipse.nebula.widgets.nattable.data.IRowIdAccessor;
+import org.eclipse.nebula.widgets.nattable.freeze.CompositeFreezeLayer;
+import org.eclipse.nebula.widgets.nattable.freeze.FreezeLayer;
+import org.eclipse.nebula.widgets.nattable.grid.GridRegion;
+import org.eclipse.nebula.widgets.nattable.grid.data.DefaultCornerDataProvider;
+import org.eclipse.nebula.widgets.nattable.grid.layer.ColumnHeaderLayer;
+import org.eclipse.nebula.widgets.nattable.grid.layer.CornerLayer;
+import org.eclipse.nebula.widgets.nattable.grid.layer.DefaultColumnHeaderDataLayer;
+import org.eclipse.nebula.widgets.nattable.grid.layer.DefaultRowHeaderDataLayer;
+import org.eclipse.nebula.widgets.nattable.grid.layer.GridLayer;
+import org.eclipse.nebula.widgets.nattable.grid.layer.RowHeaderLayer;
+import org.eclipse.nebula.widgets.nattable.group.ColumnGroupHeaderLayer;
+import org.eclipse.nebula.widgets.nattable.group.ColumnGroupModel;
+import org.eclipse.nebula.widgets.nattable.hideshow.ColumnHideShowLayer;
+import org.eclipse.nebula.widgets.nattable.hover.HoverLayer;
+import org.eclipse.nebula.widgets.nattable.hover.config.BodyHoverStylingBindings;
+import org.eclipse.nebula.widgets.nattable.layer.DataLayer;
+import org.eclipse.nebula.widgets.nattable.layer.ILayer;
+import org.eclipse.nebula.widgets.nattable.layer.IUniqueIndexLayer;
+import org.eclipse.nebula.widgets.nattable.reorder.RowReorderLayer;
+import org.eclipse.nebula.widgets.nattable.selection.RowSelectionModel;
+import org.eclipse.nebula.widgets.nattable.selection.SelectionLayer;
+import org.eclipse.nebula.widgets.nattable.sort.SortHeaderLayer;
+import org.eclipse.nebula.widgets.nattable.viewport.ViewportLayer;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.dnd.Clipboard;
+import org.eclipse.swt.events.ModifyEvent;
+import org.eclipse.swt.events.ModifyListener;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Text;
+
+public class TechTypeTable extends Composite {
+
+ NatTable table;
+ private TechTypeTableDataProvider bodyDataProvider;
+ DataLayer bodyDataLayer;
+ private IConfigRegistry summaryConfigRegistry;
+ private IUniqueIndexLayer summaryRowLayer;
+ private ViewportLayer viewportLayer;
+ private CompositeFreezeLayer compositeFreezeLayer;
+ private FreezeLayer freezeLayer;
+ //private TableDataSortModel sortModel;
+ private ColumnHideShowLayer columnHideShowLayer;
+ private ColumnGroupModel columnGroupModel = new ColumnGroupModel();
+ private TechTypeColumnHeaderTableDataProvider columnHeaderDataProvider;
+ Clipboard cpb;
+ public SelectionLayer selectionLayer;
+ private TechTypeTableSortModel sortModel;
+
+ public TechTypeTable(Composite parent, int style) {
+ super(parent, style);
+ defaultInitializeUI();
+ }
+
+ private void defaultInitializeUI() {
+ GridDataFactory.fillDefaults().grab(true, true).applyTo(this);
+ GridLayoutFactory.fillDefaults().numColumns(1).applyTo(this);
+
+ Composite filterComposite = new Composite(this, SWT.NONE);
+ GridDataFactory.fillDefaults().grab(true, false).applyTo(filterComposite);
+ GridLayoutFactory.fillDefaults().numColumns(1).applyTo(filterComposite);
+
+
+ createFilterBar(filterComposite);
+
+ Composite tableComposite = new Composite(this, SWT.NONE);
+ GridDataFactory.fillDefaults().grab(true, true).applyTo(tableComposite);
+ GridLayoutFactory.fillDefaults().numColumns(1).applyTo(tableComposite);
+ createTable(tableComposite);
+ }
+
+ private void createFilterBar(Composite filterComposite) {
+
+ Text filterText = new Text(filterComposite, SWT.BORDER);
+ GridDataFactory.fillDefaults().grab(true, true).applyTo(filterText);
+ filterText.addModifyListener(new ModifyListener() {
+
+ @Override
+ public void modifyText(ModifyEvent e) {
+ System.out.println("text modified");
+ bodyDataProvider.setFilter(filterText.getText());
+ table.refresh(true);
+ }
+ });
+
+ }
+
+ private void createTable(Composite parent) {
+
+ // build the body layer stack
+ // Usually you would create a new layer stack by extending AbstractIndexLayerTransform and
+ // setting the ViewportLayer as underlying layer. But in this case using the ViewportLayer
+ // directly as body layer is also working.
+ bodyDataProvider = new TechTypeTableDataProvider();
+ bodyDataLayer = new DataLayer(bodyDataProvider);
+
+ RowReorderLayer rowReorderLayer =
+ new RowReorderLayer(columnHideShowLayer = new ColumnHideShowLayer(bodyDataLayer));
+
+ HoverLayer hoverLayer = new HoverLayer(rowReorderLayer, false);
+ // we need to ensure that the hover styling is removed when the mouse
+ // cursor moves out of the cell area
+ hoverLayer.addConfiguration(new BodyHoverStylingBindings(hoverLayer));
+
+ selectionLayer = new SelectionLayer(hoverLayer);
+
+ viewportLayer = new ViewportLayer(selectionLayer);
+ viewportLayer.setRegionName(GridRegion.BODY);
+ freezeLayer = new FreezeLayer(selectionLayer);
+ compositeFreezeLayer = new CompositeFreezeLayer(freezeLayer, viewportLayer, selectionLayer);
+
+ // build the column header layer
+ columnHeaderDataProvider = new TechTypeColumnHeaderTableDataProvider(bodyDataProvider);
+ DataLayer columnHeaderDataLayer = new DefaultColumnHeaderDataLayer(columnHeaderDataProvider);
+ columnHeaderDataLayer.setRowsResizableByDefault(false);
+ columnHeaderDataLayer.setColumnsResizableByDefault(true);
+ ColumnHeaderLayer columnHeaderLayer = new ColumnHeaderLayer(columnHeaderDataLayer, compositeFreezeLayer, selectionLayer);
+ ColumnGroupHeaderLayer columnGroupHeaderLayer = new ColumnGroupHeaderLayer(columnHeaderLayer, selectionLayer, columnGroupModel);
+ columnGroupHeaderLayer.setCalculateHeight(true);
+ SortHeaderLayer<String> columnSortHeaderLayer = new SortHeaderLayer<>(columnGroupHeaderLayer, sortModel = new TechTypeTableSortModel(bodyDataProvider));
+
+ // build the row header layer
+ IDataProvider rowHeaderDataProvider = new TechTypeRowHeaderTableDataProvider(bodyDataProvider);
+ DataLayer rowHeaderDataLayer = new DefaultRowHeaderDataLayer(rowHeaderDataProvider);
+ rowHeaderDataLayer.setRowsResizableByDefault(false);
+ rowHeaderDataLayer.setColumnsResizableByDefault(false);
+ RowHeaderLayer rowHeaderLayer = new RowHeaderLayer(rowHeaderDataLayer, compositeFreezeLayer, selectionLayer);
+
+ // build the corner layer
+ IDataProvider cornerDataProvider = new DefaultCornerDataProvider(columnHeaderDataProvider, rowHeaderDataProvider);
+ DataLayer cornerDataLayer = new DataLayer(cornerDataProvider);
+ ILayer cornerLayer = new CornerLayer(cornerDataLayer, rowHeaderLayer, columnSortHeaderLayer);
+
+ // build the grid layer
+ GridLayer gridLayer = new GridLayer(compositeFreezeLayer, columnSortHeaderLayer, rowHeaderLayer, cornerLayer);
+
+ table = new NatTable(parent, NatTable.DEFAULT_STYLE_OPTIONS | SWT.BORDER, gridLayer, false);
+ GridDataFactory.fillDefaults().grab(true, true).applyTo(table);
+
+ // Register a CopyDataCommandHandler that also copies the headers and
+ // uses the configured IDisplayConverters
+ CopyDataCommandHandler copyHandler = new CopyDataCommandHandler(
+ selectionLayer,
+ columnHeaderDataLayer,
+ rowHeaderDataLayer);
+ copyHandler.setCopyFormattedText(true);
+ gridLayer.registerCommandHandler(copyHandler);
+
+ // initialize paste handler with SWT clipboard
+ cpb = new Clipboard(getDisplay());
+ //PasteDataCommandHandler pasteHandler = new PasteDataCommandHandler(bodyDataProvider, bodyDataLayer, selectionLayer, cpb);
+ //bodyDataLayer.registerCommandHandler(pasteHandler);
+
+ table.addConfiguration(new DefaultNatTableStyleConfiguration());
+ //table.addConfiguration(new EditingSupportConfiguration(bodyDataProvider));
+ table.configure();
+ }
+
+ @Override
+ public void dispose() {
+ cpb.dispose();
+ super.dispose();
+ }
+
+ public void setTechTypePath(String path) {
+ bodyDataProvider.setPath(path);
+ table.refresh(true);
+ }
+
+}
--- /dev/null
+package org.simantics.district.network.ui.techtype.table;
+
+import java.io.IOException;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.stream.Collectors;
+
+import org.apache.commons.csv.CSVRecord;
+import org.eclipse.nebula.widgets.nattable.data.IDataProvider;
+import org.simantics.district.imports.DistrictImportUtils;
+
+public class TechTypeTableDataProvider implements IDataProvider {
+
+ private List<CSVRecord> records = new ArrayList<>();
+ private List<CSVRecord> filteredRecords = new ArrayList<>();
+ private String filter = "";
+
+ public TechTypeTableDataProvider() {
+ // load csv
+
+ setPath("C:\\projektit\\apros\\Semantum_VTT_Fortum portaali 2018-17-12\\järvenpää\\qgis\\TechTypeData.csv");
+ }
+
+ public Object getHeaderValue(int columnIndex) {
+ if (records.isEmpty()) {
+ return "<empty>";
+ }
+ return records.get(0).get(columnIndex);
+ }
+
+ @Override
+ public Object getDataValue(int columnIndex, int rowIndex) {
+ return filteredRecords.get(rowIndex + 1).get(columnIndex);
+ }
+
+ @Override
+ public void setDataValue(int columnIndex, int rowIndex, Object newValue) {
+
+ }
+
+ @Override
+ public int getColumnCount() {
+ if (records.isEmpty()) {
+ return 0;
+ }
+ return records.get(0).size();
+ }
+
+ @Override
+ public int getRowCount() {
+ return filteredRecords.size() - 1;
+ }
+
+ public boolean isEditable(int columnIndex, int rowIndex) {
+ return false;
+ }
+
+ public void setFilter(String text) {
+ this.filter = text.toLowerCase();
+
+ filteredRecords = records.stream().filter(record -> {
+ for (int i = 0; i < record.size(); i++) {
+ String columnContent = record.get(i);
+ if (columnContent.toLowerCase().contains(filter)) {
+ return true;
+ }
+ }
+ return false;
+ }).collect(Collectors.toList());
+ }
+
+ public void setPath(String path) {
+ records.clear();
+ filteredRecords.clear();
+ Path techTypeCsv = Paths.get(path);
+ try {
+ DistrictImportUtils.consumeCSV(techTypeCsv, ';', false, record -> {
+ records.add(record);
+ return true;
+ });
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+
+ setFilter("");
+ }
+
+}
--- /dev/null
+package org.simantics.district.network.ui.techtype.table;
+
+import java.lang.reflect.Array;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.List;
+
+import org.eclipse.nebula.widgets.nattable.sort.ISortModel;
+import org.eclipse.nebula.widgets.nattable.sort.SortDirectionEnum;
+import org.simantics.utils.strings.AlphanumComparator;
+
+public class TechTypeTableSortModel implements ISortModel {
+
+ private static final SortDirectionEnum[] NO_DIRECTIONS = {};
+ private static final boolean[] NO_BOOLEANS = {};
+
+ /**
+ * Array that contains the sort direction for every column.
+ * Needed to access the current sort state of a column.
+ */
+ protected SortDirectionEnum[] sortDirections = NO_DIRECTIONS;
+
+ /**
+ * Array that contains the sorted flags for every column.
+ * Needed to access the current sort state of a column.
+ */
+ protected boolean[] sorted = NO_BOOLEANS;
+
+ /**
+ * As this implementation only supports single column sorting,
+ * this property contains the the column index of the column that
+ * is currently used for sorting.
+ * Initial value = -1 for no sort column
+ */
+ protected int currentSortColumn = -1;
+
+ /**
+ * As this implementation only supports single column sorting,
+ * this property contains the current sort direction of the column that
+ * is currently used for sorting.
+ */
+ protected SortDirectionEnum currentSortDirection = SortDirectionEnum.ASC;
+
+ private TechTypeTableDataProvider bodyDataProvider;
+
+ public TechTypeTableSortModel(TechTypeTableDataProvider bodyDataProvider) {
+ this.bodyDataProvider = bodyDataProvider;
+ }
+
+
+ @Override
+ public List<Integer> getSortedColumnIndexes() {
+ List<Integer> indexes = new ArrayList<Integer>();
+ if (currentSortColumn > -1) {
+ indexes.add(Integer.valueOf(currentSortColumn));
+ }
+ return indexes;
+ }
+
+ @Override
+ public boolean isColumnIndexSorted(int columnIndex) {
+ if (sorted.length <= columnIndex)
+ return false;
+ return sorted[columnIndex];
+ }
+
+ @Override
+ public SortDirectionEnum getSortDirection(int columnIndex) {
+ if (sortDirections.length <= columnIndex)
+ return SortDirectionEnum.NONE;
+ return sortDirections[columnIndex];
+ }
+
+ @Override
+ public int getSortOrder(int columnIndex) {
+ return 0;
+ }
+
+ @Override
+ public List<Comparator> getComparatorsForColumnIndex(int columnIndex) {
+ return Collections.singletonList(AlphanumComparator.COMPARATOR);
+ }
+
+ @Override
+ public Comparator<?> getColumnComparator(int columnIndex) {
+ return AlphanumComparator.COMPARATOR;
+ }
+
+ @Override
+ public void sort(int columnIndex, SortDirectionEnum sortDirection, boolean accumulate) {
+
+ if (!isColumnIndexSorted(columnIndex)) {
+ clear();
+ }
+ int columnCount = bodyDataProvider.getColumnCount();
+ sortDirections = ensureArraySize(sortDirections, columnCount, SortDirectionEnum.class, SortDirectionEnum.NONE);
+
+
+ sortDirections[columnIndex] = sortDirection;
+ sorted[columnIndex] = !sortDirection.equals(SortDirectionEnum.NONE);
+ currentSortColumn = columnIndex;
+ currentSortDirection = sortDirection;
+ }
+
+ @Override
+ public void clear() {
+ Arrays.fill(this.sortDirections, SortDirectionEnum.NONE);
+ Arrays.fill(this.sorted, false);
+ this.currentSortColumn = -1;
+ this.currentSortDirection = SortDirectionEnum.NONE;
+ }
+
+ @SuppressWarnings("unchecked")
+ public static <T> T[] ensureArraySize(T[] array, int l, Class<T> clazz, T defaultValue) {
+ boolean fill = true;
+ if (array == null || array.length != l) {
+ array = (T[]) Array.newInstance(clazz, l);
+ fill = defaultValue != null;
+ }
+ if (fill)
+ Arrays.fill(array, defaultValue);
+ return array;
+ }
+
+}
--- /dev/null
+package org.simantics.district.network.ui.techtype.table;
+
+import org.eclipse.swt.widgets.Composite;
+
+public class TechTypeTableUI extends Composite {
+
+ public TechTypeTableUI(Composite parent, int style) {
+ super(parent, style);
+ }
+
+}
--- /dev/null
+package org.simantics.district.network.ui.techtype.table;
+
+
+import javax.annotation.PostConstruct;
+import javax.annotation.PreDestroy;
+import javax.inject.Inject;
+
+import org.eclipse.e4.ui.model.application.MApplication;
+import org.eclipse.e4.ui.model.application.commands.MCommand;
+import org.eclipse.e4.ui.model.application.ui.basic.MPart;
+import org.eclipse.e4.ui.model.application.ui.menu.MHandledToolItem;
+import org.eclipse.e4.ui.model.application.ui.menu.MMenuFactory;
+import org.eclipse.e4.ui.model.application.ui.menu.MToolBar;
+import org.eclipse.e4.ui.workbench.modeling.ESelectionService;
+import org.eclipse.swt.widgets.Composite;
+
+public class TechTypeTableView {
+
+ @Inject ESelectionService selectionService;
+
+ public static TechTypeTable table;
+
+ @Inject
+ public void init(MPart part, MApplication app) {
+ MToolBar toolBar = MMenuFactory.INSTANCE.createToolBar();
+ toolBar.setToBeRendered(true);
+ toolBar.getChildren().add(createImportCSVDataToolItem(app));
+ part.setToolbar(toolBar);
+ }
+
+ private MHandledToolItem createImportCSVDataToolItem(MApplication app) {
+ MHandledToolItem createHandledToolItem = MMenuFactory.INSTANCE.createHandledToolItem();
+ // Command is contributed via fragment
+ MCommand command = app.getCommand("org.simantics.district.network.ui.command.importtechtypecsv");
+ createHandledToolItem.setCommand(command); //$NON-NLS-1$
+ createHandledToolItem.setLabel("Import Tech Type");
+ createHandledToolItem.setIconURI("platform:/plugin/com.famfamfam.silk/icons/table_edit.png"); //$NON-NLS-1$
+ return createHandledToolItem;
+ }
+
+ @PostConstruct
+ public void postConstruct(Composite parent) {
+ table = new TechTypeTable(parent, 0);
+
+ }
+
+ @PreDestroy
+ public void dispose() {
+ table.dispose();
+ table = null;
+ }
+
+}