]> gerrit.simantics Code Review - simantics/district.git/blobdiff - org.simantics.district.network.ui/src/org/simantics/district/network/ui/techtype/table/TechTypeTableDataProvider.java
Sorting support for tech type table columns
[simantics/district.git] / org.simantics.district.network.ui / src / org / simantics / district / network / ui / techtype / table / TechTypeTableDataProvider.java
index 534be1dafe5a57d2dfef57884de4b6e676203017..af0e28d07bc84be4b9b01ab221105b2f3c5269a9 100644 (file)
 package org.simantics.district.network.ui.techtype.table;
 
 import java.io.IOException;
+import java.io.StringReader;
 import java.nio.file.Path;
 import java.nio.file.Paths;
 import java.util.ArrayList;
+import java.util.Comparator;
+import java.util.Iterator;
 import java.util.List;
-import java.util.stream.Collectors;
+import java.util.stream.IntStream;
 
 import org.apache.commons.csv.CSVRecord;
+import org.eclipse.core.runtime.ListenerList;
 import org.eclipse.nebula.widgets.nattable.data.IDataProvider;
+import org.eclipse.nebula.widgets.nattable.sort.SortDirectionEnum;
 import org.simantics.district.imports.DistrictImportUtils;
+import org.simantics.district.network.techtype.TechTypeUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
 
 public class TechTypeTableDataProvider implements IDataProvider {
 
+    private final static Logger LOGGER = LoggerFactory.getLogger(TechTypeTableDataProvider.class);
+
     private List<CSVRecord> records = new ArrayList<>();
-    private List<CSVRecord> filteredRecords = new ArrayList<>();
-    private String filter = "";
+    private boolean[] enabled;
+    private String filter = null;
+    private List<String> variables = null;
+    private List<String> headers = null;
+    private int[] filteredRows;
+
+    private ListenerList<EnableListener> enableListeners = new ListenerList<EnableListener>();
+
+    private int[] sortedRows;
 
-    public TechTypeTableDataProvider() {
+       private static final Comparator<? super String> VALUE_COMPARATOR = (a, b) -> {
+               try {
+                       double da = Double.valueOf(a.replace(",", "."));
+                       double db = Double.valueOf(b.replace(",", "."));
+                       return Double.compare(da, db);
+               } catch (NumberFormatException e) {
+                       return TechTypeUtils.compareNatural(a, b);
+               }
+       };
+
+    public TechTypeTableDataProvider(String data, int[] enabledList) {
+        setData(data);
+        setEnabledFlags(enabledList);
+    }
+    
+    public TechTypeTableDataProvider(String data) {
         // load csv
+        setData(data);
+    }
+    
+    public void setEnabledFlags(int[] enabledList) {
+        this.enabled = new boolean[records.size()];
+        if (enabledList != null) {
+            for (int i : enabledList) {
+                if (i >= 0 && i < enabled.length)
+                    enabled[i] = true;
+            }
+        }
+    }
 
-        setPath("C:\\projektit\\apros\\Semantum_VTT_Fortum portaali 2018-17-12\\järvenpää\\qgis\\TechTypeData.csv");
+    public String getVariableName(int columnIndex) {
+        return variables != null && columnIndex > 0 && columnIndex <= variables.size() ? variables.get(columnIndex - 1) : null;
     }
 
-    public Object getHeaderValue(int columnIndex) {
-        if (records.isEmpty()) {
+    public int getVariableIndex(String variableName) {
+        return variables != null ? variables.indexOf(variableName) + 1 : -1;
+    }
+    
+    public CSVRecord getRecord(int rowIndex) {
+        return records.get(recordIndex(rowIndex));
+    }
+
+    public boolean isEnabled(int rowIndex) {
+        return enabled[recordIndex(rowIndex)];
+    }
+
+    private int recordIndex(int rowIndex) {
+        return sortedRows[filteredRows[rowIndex]];
+    }
+    
+    public String getHeaderValue(int columnIndex) {
+        if (headers == null) {
             return "<empty>";
+        } else if (columnIndex == 0) {
+            return "Enabled";
+        } else {
+            return headers.get(columnIndex - 1);
         }
-        return records.get(0).get(columnIndex);
     }
 
     @Override
     public Object getDataValue(int columnIndex, int rowIndex) {
-        return filteredRecords.get(rowIndex + 1).get(columnIndex);
+        if (columnIndex == 0) {
+            return isEnabled(rowIndex);
+        }
+        return getRecord(rowIndex).get(columnIndex - 1);
     }
 
     @Override
     public void setDataValue(int columnIndex, int rowIndex, Object newValue) {
+        if (columnIndex == 0) {
+            boolean value = Boolean.parseBoolean((String) newValue);
+            enabled[recordIndex(rowIndex)] = value;
+            fireEnableEvent(rowIndex, value);
+        }
+    }
+    
+    public void addEnableListener(EnableListener listener) {
+        enableListeners.add(listener);
+    }
 
+    private void fireEnableEvent(int rowIndex, boolean newValue) {
+        enableListeners.forEach(l -> l.rowEnabled(rowIndex, newValue));
     }
 
     @Override
@@ -45,46 +124,135 @@ public class TechTypeTableDataProvider implements IDataProvider {
         if (records.isEmpty()) {
             return 0;
         }
-        return records.get(0).size();
+        return records.get(0).size() + 1;
     }
 
     @Override
     public int getRowCount() {
-        return filteredRecords.size() - 1;
+        return filteredRows.length;
     }
 
     public boolean isEditable(int columnIndex, int rowIndex) {
-        return false;
+        return columnIndex == 0;
     }
 
     public void setFilter(String text) {
-        this.filter = text.toLowerCase();
+        this.filter = text != null ? text.toLowerCase() : null;
 
-        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;
-                }
+        filteredRows = IntStream.range(0, records.size())
+                .filter(k -> isMatch(records.get(sortedRows[k]), filter))
+                .toArray();
+    }
+
+    private static boolean isMatch(CSVRecord record, String filterString) {
+        if (filterString == null || filterString.isEmpty())
+            return true;
+        
+        for (int i = 0; i < record.size(); i++) {
+            String columnContent = record.get(i);
+            if (columnContent.toLowerCase().contains(filterString)) {
+                return true;
             }
-            return false;
-        }).collect(Collectors.toList());
+        }
+        
+        return false;
     }
 
+    /**
+     * Read a CSV file into table contents.
+     * 
+     * Set path to null to create an empty table.
+     * 
+     * @param path  The path of the CSV file to be read.
+     */
     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();
+
+        if (path != null) {
+            Path techTypeCsv = Paths.get(path);
+            try {
+                DistrictImportUtils.consumeCSV(techTypeCsv, ';', false, record -> {
+                    records.add(record);
+                    return true;
+                });
+            } catch (IOException e) {
+                e.printStackTrace();
+            }
+        }
+
+        enabled = new boolean[records.size()];
+        sortedRows = IntStream.range(0, records.size()).toArray();
+        
+        setFilter(null);
+    }
+
+    /**
+     * Set table data contents to a given string of CSV data.
+     * 
+     * Set 'data' to null to create an empty table.
+     * 
+     * @param data  The CSV data to be shown in the table.
+     */
+    public void setData(String data) {
+        records.clear();
+
+        if (data != null) {
+            long ncommas = data.chars().filter(c -> c == ',').count();
+            long nsemis = data.chars().filter(c -> c == ';').count();
+            char delim = nsemis > ncommas ? ';' : ',';
+            StringReader reader = new StringReader(data);
+            try {
+                DistrictImportUtils.consumeCSV(reader, delim, false, record -> {
+                    records.add(record);
+                    return true;
+                });
+            } catch (IOException e) {
+                LOGGER.error("Error reading CSV file", e);
+                return;
+            }
+
+            CSVRecord header = records.remove(0);
+            CSVRecord units = records.remove(0);
+
+            variables = new ArrayList<>();
+            headers = new ArrayList<>();
+
+            Iterator<String> it = header.iterator();
+            Iterator<String> uit = units.iterator();
+
+            while (it.hasNext()) {
+                String variable = it.next().trim();
+                String unit = uit.hasNext() ? uit.next().trim() : null;
+
+                variables.add(variable);
+                headers.add(variable + (unit != null && !unit.isEmpty() && !(unit.startsWith("(") && unit.endsWith(")")) ? " [" + unit + "]" : ""));
+            }
         }
+        
+        enabled = new boolean[records.size()];
+        sortedRows = IntStream.range(0, records.size()).toArray();
 
-        setFilter("");
+        setFilter(null);
+    }
+
+    public void sortBy(int columnIndex, SortDirectionEnum sortDirection) {
+        
+        if (columnIndex >= 0 && !sortDirection.equals(SortDirectionEnum.NONE)) {
+            Comparator<Integer> comparator = columnIndex == 0 ?
+                    Comparator.comparing(k -> enabled[sortedRows[(int) k]]) :
+                    Comparator.comparing(k -> records.get(sortedRows[(int) k]).get(columnIndex-1), VALUE_COMPARATOR);
+            
+            if (sortDirection.equals(SortDirectionEnum.DESC))
+                comparator = comparator.reversed();
+            
+            sortedRows = IntStream.range(0, records.size())
+                    .mapToObj(i -> i)
+                    .sorted(comparator)
+                    .mapToInt(i -> sortedRows[i])
+                    .toArray();
+        } else {
+            sortedRows = IntStream.range(0, records.size()).toArray();
+        }
     }
 
-}
+}
\ No newline at end of file