1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package net.sourceforge.jarduino.gui;
18
19 import java.awt.Image;
20 import java.awt.event.MouseAdapter;
21 import java.awt.event.MouseEvent;
22 import java.io.IOException;
23 import java.util.ArrayList;
24 import java.util.List;
25 import javax.imageio.ImageIO;
26 import javax.swing.Icon;
27 import javax.swing.ImageIcon;
28 import javax.swing.JComponent;
29 import javax.swing.JTable;
30 import javax.swing.RowSorter.SortKey;
31 import javax.swing.SortOrder;
32 import javax.swing.SwingConstants;
33 import javax.swing.table.AbstractTableModel;
34 import javax.swing.table.DefaultTableCellRenderer;
35 import javax.swing.table.TableCellRenderer;
36 import javax.swing.table.TableColumn;
37 import javax.swing.table.TableColumnModel;
38 import javax.swing.table.TableRowSorter;
39
40 import net.sourceforge.jarduino.message.ArduinoMessage;
41 import net.sourceforge.jarduino.message.ArduinoMsgFilter;
42 import net.sourceforge.jarduino.message.ArduinoNamedObject;
43 import net.sourceforge.jarduino.message.ArduinoSystem;
44 import net.sourceforge.jarduino.util.ArduinoLogManager;
45 import net.sourceforge.jarduino.util.ArduinoLogger;
46
47
48
49
50 public class ArduinoTableFilter {
51
52
53
54 private static final ArduinoLogger LOGGER = ArduinoLogManager.getLogger(ArduinoTableFilter.class);
55
56
57
58
59 private static final Icon TICKICON = loadIcon("GreenJellyTick.png");
60
61
62
63
64 private static final Icon CROSSICON = loadIcon("OrangeJellyCross.png");
65
66
67
68
69 private static final int ICON_SIZE = 20;
70
71
72
73
74 private static final int WIDTH_SMALL = 60;
75
76
77
78
79 private static final int WIDTH_MEDIUM = 80;
80
81
82
83
84 private static final int WIDTH_LARGE = 150;
85
86
87
88
89 private final ArduinoPanelFilter theParent;
90
91
92
93
94 private final JTable theTable;
95
96
97
98
99 private final ArduinoFilterModel theModel;
100
101
102
103
104 private final ArduinoMsgFilter theMsgFilter;
105
106
107
108
109 private List<ArduinoMessage> theMessages;
110
111
112
113
114 private boolean isBespoke;
115
116
117
118
119
120 ArduinoTableFilter(final ArduinoPanelFilter pParent) {
121
122 theParent = pParent;
123
124
125 theMsgFilter = new ArduinoMsgFilter();
126
127
128 theTable = new JTable();
129 theModel = new ArduinoFilterModel();
130 theTable.setModel(theModel);
131 theTable.addMouseListener(new MouseListener());
132
133
134 theModel.setSorter();
135
136
137 configureColumns();
138 }
139
140
141
142
143
144 JComponent getComponent() {
145 return theTable;
146 }
147
148
149
150
151
152
153 ArduinoMsgFilter getFilter() {
154 return theMsgFilter;
155 }
156
157
158
159
160 private void configureColumns() {
161
162 final TableCellRenderer myRightRenderer = new AlignmentRenderer(SwingConstants.RIGHT);
163 final TableCellRenderer myCenterRenderer = new AlignmentRenderer(SwingConstants.CENTER);
164 final TableCellRenderer myIconRenderer = new IconRenderer();
165
166
167 final TableColumnModel myModel = theTable.getColumnModel();
168
169
170 TableColumn myColumn = myModel.getColumn(ArduinoFilterModel.COL_NAME);
171 myColumn.setPreferredWidth(WIDTH_LARGE);
172 myColumn.setCellRenderer(myRightRenderer);
173
174
175 myColumn = myModel.getColumn(ArduinoFilterModel.COL_ID);
176 myColumn.setPreferredWidth(WIDTH_MEDIUM);
177 myColumn.setCellRenderer(myCenterRenderer);
178
179
180 myColumn = myModel.getColumn(ArduinoFilterModel.COL_RECEIVED);
181 myColumn.setPreferredWidth(WIDTH_SMALL);
182 myColumn.setMaxWidth(WIDTH_SMALL);
183 myColumn.setCellRenderer(myIconRenderer);
184
185
186 myColumn = myModel.getColumn(ArduinoFilterModel.COL_SENT);
187 myColumn.setPreferredWidth(WIDTH_SMALL);
188 myColumn.setMaxWidth(WIDTH_SMALL);
189 myColumn.setCellRenderer(myIconRenderer);
190 }
191
192
193
194
195
196
197 void configureForSystem(final ArduinoSystem pSystem) {
198
199 theMessages = pSystem.getMessages();
200
201
202 configureForNode(pSystem);
203 }
204
205
206
207
208
209
210 void configureForNode(final ArduinoNamedObject pNode) {
211
212 theMsgFilter.resetSelection(pNode);
213
214
215 isBespoke = false;
216
217
218 theModel.fireTableDataChanged();
219 theParent.updateFilter();
220 }
221
222
223
224
225
226 boolean isBespoke() {
227 return isBespoke;
228 }
229
230
231
232
233
234
235 private static Icon loadIcon(final String pName) {
236
237 try {
238 final Image myImage = ImageIO.read(ArduinoTableFilter.class.getResourceAsStream("icons/" + pName));
239 final Image myNewImage = myImage.getScaledInstance(ICON_SIZE, ICON_SIZE, Image.SCALE_SMOOTH);
240 return new ImageIcon(myNewImage);
241 } catch (IOException e) {
242 LOGGER.error("Failed to load icon", e);
243 return null;
244 }
245 }
246
247
248
249
250 private class ArduinoFilterModel
251 extends AbstractTableModel {
252
253
254
255 private static final long serialVersionUID = 240324436537632666L;
256
257
258
259
260 private static final int COL_NAME = 0;
261
262
263
264
265 private static final int COL_ID = COL_NAME + 1;
266
267
268
269
270 private static final int COL_SENT = COL_ID + 1;
271
272
273
274
275 private static final int COL_RECEIVED = COL_SENT + 1;
276
277
278
279
280 ArduinoFilterModel() {
281 }
282
283 @Override
284 public int getRowCount() {
285 return theMessages != null ? theMessages.size() : 0;
286 }
287
288 @Override
289 public String getColumnName(final int pColIndex) {
290 switch (pColIndex) {
291 case COL_NAME:
292 return "Name";
293 case COL_ID:
294 return "Id";
295 case COL_SENT:
296 return "Sent";
297 case COL_RECEIVED:
298 return "Received";
299 default:
300 return null;
301 }
302 }
303
304 @Override
305 public int getColumnCount() {
306 return COL_RECEIVED + 1;
307 }
308
309 @Override
310 public boolean isCellEditable(final int pRowIndex,
311 final int pColIndex) {
312 return false;
313 }
314
315 @Override
316 public Object getValueAt(final int pRowIndex,
317 final int pColIndex) {
318 switch (pColIndex) {
319 case COL_NAME:
320 return theMessages.get(pRowIndex).getName();
321 case COL_ID:
322 return getId(pRowIndex);
323 case COL_SENT:
324 return theMsgFilter.isBuilt(getId(pRowIndex)) ? TICKICON : CROSSICON;
325 case COL_RECEIVED:
326 return theMsgFilter.isParsed(getId(pRowIndex)) ? TICKICON : CROSSICON;
327 default:
328 return null;
329 }
330 }
331
332
333
334
335
336
337 private String getId(final int pRowIndex) {
338 return theMessages.get(pRowIndex).getId();
339 }
340
341
342
343
344 void setSorter() {
345
346 final TableRowSorter<ArduinoFilterModel> mySorter = new TableRowSorter<>(this);
347
348
349 final List<SortKey> mySortKeys = new ArrayList<>();
350 mySortKeys.add(new SortKey(COL_SENT, SortOrder.ASCENDING));
351 mySortKeys.add(new SortKey(COL_RECEIVED, SortOrder.ASCENDING));
352 mySorter.setSortKeys(mySortKeys);
353
354
355 mySorter.setSortsOnUpdates(true);
356 theTable.setRowSorter(mySorter);
357 }
358 }
359
360
361
362
363 private static class AlignmentRenderer extends DefaultTableCellRenderer {
364
365
366
367
368
369 AlignmentRenderer(final int pAlignment) {
370 setHorizontalAlignment(pAlignment);
371 }
372
373 @Override
374 public JComponent getTableCellRendererComponent(final JTable pTable,
375 final Object pValue,
376 final boolean pSelected,
377 final boolean hasFocus,
378 final int pRow,
379 final int pCol) {
380
381 final String myValue = pValue == null
382 ? null
383 : pValue.toString();
384
385
386 setText(myValue);
387
388
389 return this;
390 }
391 }
392
393
394
395
396 private static class IconRenderer extends DefaultTableCellRenderer {
397
398
399
400 IconRenderer() {
401 setHorizontalAlignment(SwingConstants.CENTER);
402 }
403
404 @Override
405 public JComponent getTableCellRendererComponent(final JTable pTable,
406 final Object pValue,
407 final boolean pSelected,
408 final boolean hasFocus,
409 final int pRow,
410 final int pCol) {
411
412 final Icon myIcon = pValue instanceof Icon
413 ? (Icon) pValue
414 : null;
415
416
417 setIcon(myIcon);
418
419
420 return this;
421 }
422 }
423
424
425
426
427
428
429 private class MouseListener
430 extends MouseAdapter {
431 @Override
432 public void mouseClicked(final MouseEvent e) {
433
434 final int myRow = theTable.convertRowIndexToModel(theTable.rowAtPoint(e.getPoint()));
435 final int myCol = theTable.convertColumnIndexToModel(theTable.columnAtPoint(e.getPoint()));
436
437
438 if (myRow != -1
439 && (myCol == ArduinoFilterModel.COL_RECEIVED || myCol == ArduinoFilterModel.COL_SENT)) {
440
441 final ArduinoMessage myMessage = theMessages.get(myRow);
442 processClick(myMessage, myCol);
443 theModel.fireTableCellUpdated(myRow, myCol);
444 theParent.updateFilter();
445 }
446 }
447
448
449
450
451
452
453 void processClick(final ArduinoMessage pMessage,
454 final int pColumn) {
455 final int myFlag = pColumn == ArduinoFilterModel.COL_RECEIVED
456 ? ArduinoMsgFilter.PARSEMSG
457 : ArduinoMsgFilter.BUILDMSG;
458 theMsgFilter.toggleFlag(pMessage.getId(), myFlag);
459 isBespoke = true;
460 }
461 }
462 }