]> gerrit.simantics Code Review - simantics/district.git/blob - org.simantics.district.network.ui/src/org/simantics/district/network/ui/techtype/table/TechTypeTableDataProvider.java
Hide "enabled" column for non-component type tech type tables
[simantics/district.git] / org.simantics.district.network.ui / src / org / simantics / district / network / ui / techtype / table / TechTypeTableDataProvider.java
1 package org.simantics.district.network.ui.techtype.table;
2
3 import java.io.IOException;
4 import java.io.StringReader;
5 import java.nio.file.Path;
6 import java.nio.file.Paths;
7 import java.util.ArrayList;
8 import java.util.Comparator;
9 import java.util.Iterator;
10 import java.util.List;
11 import java.util.stream.IntStream;
12
13 import org.apache.commons.csv.CSVRecord;
14 import org.eclipse.core.runtime.ListenerList;
15 import org.eclipse.nebula.widgets.nattable.data.IDataProvider;
16 import org.eclipse.nebula.widgets.nattable.sort.SortDirectionEnum;
17 import org.simantics.district.imports.DistrictImportUtils;
18 import org.simantics.district.network.techtype.TechTypeUtils;
19 import org.slf4j.Logger;
20 import org.slf4j.LoggerFactory;
21
22 public class TechTypeTableDataProvider implements IDataProvider {
23
24     private final static Logger LOGGER = LoggerFactory.getLogger(TechTypeTableDataProvider.class);
25
26     private List<CSVRecord> records = new ArrayList<>();
27     private boolean[] enabled;
28     private String filter = null;
29     private List<String> variables = null;
30     private List<String> headers = null;
31     private int[] filteredRows;
32
33     private ListenerList<EnableListener> enableListeners = new ListenerList<EnableListener>();
34
35     private int[] sortedRows;
36     
37         private boolean showEnabled = true;
38
39         private static final Comparator<? super String> VALUE_COMPARATOR = (a, b) -> {
40                 try {
41                         double da = Double.valueOf(a.replace(",", "."));
42                         double db = Double.valueOf(b.replace(",", "."));
43                         return Double.compare(da, db);
44                 } catch (NumberFormatException e) {
45                         return TechTypeUtils.compareNatural(a, b);
46                 }
47         };
48
49     public TechTypeTableDataProvider(String data, int[] enabledList) {
50         setData(data);
51         setEnabledFlags(enabledList);
52         showEnabled = enabledList != null;
53     }
54     
55     public TechTypeTableDataProvider(String data) {
56         setData(data);
57         showEnabled = false;
58     }
59     
60     public void setEnabledFlags(int[] enabledList) {
61         this.enabled = new boolean[records.size()];
62         if (enabledList != null) {
63             for (int i : enabledList) {
64                 if (i >= 0 && i < enabled.length)
65                     enabled[i] = true;
66             }
67         }
68         
69         showEnabled = enabledList != null;
70     }
71     
72     public boolean isCheckBoxColumn(int columnIndex) {
73         return isEnabledColumn(columnIndex);
74     }
75
76     public String getVariableName(int columnIndex) {
77         return variables != null && columnIndex > 0 && columnIndex <= variables.size()
78                         ? variables.get(columnIndex - columnOffset())
79                                 : null;
80     }
81
82         private int columnOffset() {
83                 return showEnabled ? 1 : 0;
84         }
85
86     public int getVariableIndex(String variableName) {
87         return variables != null ? variables.indexOf(variableName) + columnOffset() : -1;
88     }
89     
90     public CSVRecord getRecord(int rowIndex) {
91         return records.get(recordIndex(rowIndex));
92     }
93
94     public boolean isEnabled(int rowIndex) {
95         return enabled[recordIndex(rowIndex)];
96     }
97
98     private int recordIndex(int rowIndex) {
99         return sortedRows[filteredRows[rowIndex]];
100     }
101     
102     public String getHeaderValue(int columnIndex) {
103         if (headers == null) {
104             return "<empty>";
105         } else if (isEnabledColumn(columnIndex)) {
106             return "Enabled";
107         } else {
108             return headers.get(columnIndex - columnOffset());
109         }
110     }
111
112     @Override
113     public Object getDataValue(int columnIndex, int rowIndex) {
114         if (isEnabledColumn(columnIndex)) {
115             return isEnabled(rowIndex);
116         }
117         return getRecord(rowIndex).get(columnIndex - columnOffset());
118     }
119
120     @Override
121     public void setDataValue(int columnIndex, int rowIndex, Object newValue) {
122         if (isEnabledColumn(columnIndex)) {
123             boolean value = Boolean.parseBoolean((String) newValue);
124             enabled[recordIndex(rowIndex)] = value;
125             fireEnableEvent(rowIndex, value);
126         }
127     }
128     
129     public void addEnableListener(EnableListener listener) {
130         enableListeners.add(listener);
131     }
132
133     private void fireEnableEvent(int rowIndex, boolean newValue) {
134         enableListeners.forEach(l -> l.rowEnabled(rowIndex, newValue));
135     }
136
137     @Override
138     public int getColumnCount() {
139         if (records.isEmpty()) {
140             return 0;
141         }
142         return records.get(0).size() + columnOffset();
143     }
144
145     @Override
146     public int getRowCount() {
147         return filteredRows.length;
148     }
149
150     public boolean isEditable(int columnIndex, int rowIndex) {
151         return isEnabledColumn(columnIndex);
152     }
153
154         private boolean isEnabledColumn(int columnIndex) {
155                 return showEnabled && columnIndex == 0;
156         }
157
158     public void setFilter(String text) {
159         this.filter = text != null ? text.toLowerCase() : null;
160
161         filteredRows = IntStream.range(0, records.size())
162                 .filter(k -> isMatch(records.get(sortedRows[k]), filter))
163                 .toArray();
164     }
165
166     private static boolean isMatch(CSVRecord record, String filterString) {
167         if (filterString == null || filterString.isEmpty())
168             return true;
169         
170         for (int i = 0; i < record.size(); i++) {
171             String columnContent = record.get(i);
172             if (columnContent.toLowerCase().contains(filterString)) {
173                 return true;
174             }
175         }
176         
177         return false;
178     }
179
180     /**
181      * Read a CSV file into table contents.
182      * 
183      * Set path to null to create an empty table.
184      * 
185      * @param path  The path of the CSV file to be read.
186      */
187     public void setPath(String path) {
188         records.clear();
189
190         if (path != null) {
191             Path techTypeCsv = Paths.get(path);
192             try {
193                 DistrictImportUtils.consumeCSV(techTypeCsv, ';', false, record -> {
194                     records.add(record);
195                     return true;
196                 });
197             } catch (IOException e) {
198                 e.printStackTrace();
199             }
200         }
201
202         enabled = new boolean[records.size()];
203         sortedRows = IntStream.range(0, records.size()).toArray();
204         
205         setFilter(null);
206     }
207
208     /**
209      * Set table data contents to a given string of CSV data.
210      * 
211      * Set 'data' to null to create an empty table.
212      * 
213      * @param data  The CSV data to be shown in the table.
214      */
215     public void setData(String data) {
216         records.clear();
217
218         if (data != null) {
219             long ncommas = data.chars().filter(c -> c == ',').count();
220             long nsemis = data.chars().filter(c -> c == ';').count();
221             char delim = nsemis > ncommas ? ';' : ',';
222             StringReader reader = new StringReader(data);
223             try {
224                 DistrictImportUtils.consumeCSV(reader, delim, false, record -> {
225                     records.add(record);
226                     return true;
227                 });
228             } catch (IOException e) {
229                 LOGGER.error("Error reading CSV file", e);
230                 return;
231             }
232
233             CSVRecord header = records.remove(0);
234             CSVRecord units = records.remove(0);
235
236             variables = new ArrayList<>();
237             headers = new ArrayList<>();
238
239             Iterator<String> it = header.iterator();
240             Iterator<String> uit = units.iterator();
241
242             while (it.hasNext()) {
243                 String variable = it.next().trim();
244                 String unit = uit.hasNext() ? uit.next().trim() : null;
245
246                 variables.add(variable);
247                 headers.add(variable + (unit != null && !unit.isEmpty() && !(unit.startsWith("(") && unit.endsWith(")")) ? " [" + unit + "]" : ""));
248             }
249         }
250         
251         enabled = new boolean[records.size()];
252         sortedRows = IntStream.range(0, records.size()).toArray();
253
254         setFilter(null);
255     }
256
257     public void sortBy(int columnIndex, SortDirectionEnum sortDirection) {
258         
259         if (columnIndex >= 0 && !sortDirection.equals(SortDirectionEnum.NONE)) {
260                 int offset = columnOffset();
261             Comparator<Integer> comparator = isEnabledColumn(columnIndex) ?
262                     Comparator.comparing(k -> enabled[sortedRows[(int) k]]) :
263                     Comparator.comparing(k -> records.get(sortedRows[(int) k]).get(columnIndex-offset), VALUE_COMPARATOR);
264             
265             if (sortDirection.equals(SortDirectionEnum.DESC))
266                 comparator = comparator.reversed();
267             
268             sortedRows = IntStream.range(0, records.size())
269                     .mapToObj(i -> i)
270                     .sorted(comparator)
271                     .mapToInt(i -> sortedRows[i])
272                     .toArray();
273         } else {
274             sortedRows = IntStream.range(0, records.size()).toArray();
275         }
276     }
277
278 }