Commit d99e6afb authored by jsimomaa's avatar jsimomaa

First testing version of TechTypeTable

gitlab #93

Change-Id: I341d7a7735ee8dbc954a53492563f46a18cb3bb7
parent 4301fe59
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);
}
}
}
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;
}
}
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();
}
}
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);
}
}
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\\jrvenp\\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("");
}
}
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;
}
}
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);
}
}
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;
}