1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 package fulmine.ui;
17
18 import java.awt.BorderLayout;
19 import java.awt.Color;
20 import java.awt.Component;
21 import java.util.Collection;
22 import java.util.Iterator;
23 import java.util.List;
24 import java.util.TimerTask;
25
26 import javax.swing.JPanel;
27 import javax.swing.JScrollPane;
28 import javax.swing.JTabbedPane;
29 import javax.swing.JTable;
30 import javax.swing.SwingUtilities;
31 import javax.swing.table.DefaultTableCellRenderer;
32 import javax.swing.table.DefaultTableModel;
33 import javax.swing.table.TableColumn;
34
35 import org.apache.commons.logging.Log;
36
37 import fulmine.context.IFulmineContext;
38 import fulmine.event.IEvent;
39 import fulmine.event.IEventSource;
40 import fulmine.event.listener.IEventListener;
41 import fulmine.model.container.IContainer.DataState;
42 import fulmine.model.container.events.ContainerFieldAddedEvent;
43 import fulmine.model.container.events.ContainerFieldRemovedEvent;
44 import fulmine.model.container.events.ContainerStateChangeEvent;
45 import fulmine.model.container.impl.Record;
46 import fulmine.model.field.IField;
47 import fulmine.util.Utils;
48 import fulmine.util.collection.CollectionFactory;
49 import fulmine.util.log.AsyncLog;
50 import fulmine.util.reference.AutoCreatingStore;
51 import fulmine.util.reference.IAutoCreatingStore;
52 import fulmine.util.reference.IObjectBuilder;
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74 public class RecordViewer extends JPanel implements IEventListener
75 {
76 private final static Log LOG = new AsyncLog(RecordViewer.class);
77
78 private static final long serialVersionUID = 1L;
79
80
81
82
83
84
85 class RecordPanel extends JPanel implements IEventListener
86 {
87 private static final long serialVersionUID = 1L;
88
89
90 private static final int VALUE_COLUMN_INDEX = 1;
91
92
93 private final DefaultTableModel model = new DefaultTableModel(1, 2);
94
95
96 private final JTable table = new JTable(model);
97
98
99
100
101
102 private final List<String> fieldNames = CollectionFactory.newList(1);
103
104
105 private final TableUpdateHandler updateHandler =
106 new TableUpdateHandler();
107
108
109 private boolean stale = false;
110
111
112
113
114
115
116 class UpdatingHighlightingRenderer extends DefaultTableCellRenderer
117 {
118
119 private static final long serialVersionUID = 1L;
120
121 @SuppressWarnings("boxing")
122 @Override
123 public Component getTableCellRendererComponent(final JTable table,
124 Object value, boolean isSelected, boolean hasFocus,
125 final int row, int column)
126 {
127 final int convertedColumn =
128 table.convertColumnIndexToModel(column);
129 final Iterator<Integer> iterator =
130 RecordPanel.this.updateHandler.getUpdated().get(row).iterator();
131 final Component renderer =
132 super.getTableCellRendererComponent(table, value,
133 isSelected, hasFocus, row, column);
134 renderer.setBackground(Color.white);
135 renderer.setForeground(Color.black);
136 if (RecordPanel.this.stale)
137 {
138 renderer.setForeground(Color.gray);
139 }
140 while (iterator.hasNext())
141 {
142 final Integer next = iterator.next();
143 if (next.equals(convertedColumn))
144 {
145 iterator.remove();
146
147
148
149 renderer.setBackground(Color.CYAN);
150 TableUpdateHandler.updateTimer.schedule(new TimerTask()
151 {
152 @Override
153 public void run()
154 {
155 SwingUtilities.invokeLater(new Runnable()
156 {
157 public void run()
158 {
159
160 ((DefaultTableModel) table.getModel()).fireTableCellUpdated(
161 row, convertedColumn);
162 }
163 });
164 }
165 }, 500);
166 }
167 }
168 return renderer;
169 }
170
171 }
172
173 public RecordPanel()
174 {
175 super(true);
176 init();
177 }
178
179 public RecordPanel(boolean isDoubleBuffered)
180 {
181 super(isDoubleBuffered);
182 init();
183 }
184
185 private void init()
186 {
187 setLayout(new BorderLayout());
188 this.table.setAutoResizeMode(JTable.AUTO_RESIZE_OFF);
189 add(new JScrollPane(this.table));
190 this.table.setEnabled(false);
191 this.table.getTableHeader().getColumnModel().getColumn(0).setHeaderValue(
192 "field name");
193 final TableColumn valueColumn =
194 this.table.getTableHeader().getColumnModel().getColumn(
195 VALUE_COLUMN_INDEX);
196 valueColumn.setHeaderValue("field value");
197 valueColumn.setCellRenderer(new UpdatingHighlightingRenderer());
198 }
199
200 public void addedAsListenerFor(IEventSource source)
201 {
202
203 }
204
205 public Class<? extends IEvent>[] getEventTypeFilter()
206 {
207 return RecordTable.eventFilter;
208 }
209
210 public void removedAsListenerFrom(IEventSource source)
211 {
212
213 }
214
215 public void update(final IEvent event)
216 {
217
218
219
220
221
222 SwingUtilities.invokeLater(new Runnable()
223 {
224 public void run()
225 {
226 if (event instanceof Record)
227 {
228 handle((Record) event);
229 return;
230 }
231 if (event instanceof ContainerStateChangeEvent)
232 {
233 handle((ContainerStateChangeEvent) event);
234 return;
235 }
236 if (event instanceof ContainerFieldAddedEvent)
237 {
238 handle((ContainerFieldAddedEvent) event);
239 return;
240 }
241 if (event instanceof ContainerFieldRemovedEvent)
242 {
243 handle((ContainerFieldRemovedEvent) event);
244 return;
245 }
246 if (LOG.isDebugEnabled())
247 {
248 LOG.debug("Unhandled event: "
249 + Utils.safeToString(event));
250 }
251 }
252
253 });
254 }
255
256
257
258
259
260
261
262 void handle(ContainerFieldRemovedEvent event)
263 {
264 removeField(event.getField());
265 }
266
267
268
269
270
271
272
273 void handle(ContainerFieldAddedEvent event)
274 {
275 addField(event.getField());
276 }
277
278
279
280
281
282
283
284
285 private void addField(final IField field)
286 {
287 final String fieldName = getFieldId(field);
288 if (!this.fieldNames.contains(fieldName))
289 {
290 this.fieldNames.add(fieldName);
291 this.model.insertRow(fieldNames.size() - 1, new Object[] {
292 fieldName, field.getValueAsString() });
293 }
294 }
295
296
297
298
299
300
301 private void removeField(final IField field)
302 {
303 final String fieldName = getFieldId(field);
304 if (this.fieldNames.contains(fieldName))
305 {
306 final int index = this.fieldNames.indexOf(fieldName);
307 this.fieldNames.remove(index);
308 this.model.removeRow(index);
309 }
310 }
311
312 private String getFieldId(final IField field)
313 {
314
315
316
317
318
319 return field.getIdentity();
320 }
321
322
323
324
325
326
327
328 void handle(ContainerStateChangeEvent event)
329 {
330
331 }
332
333
334
335
336
337
338
339 @SuppressWarnings("boxing")
340 void handle(Record event)
341 {
342 final Collection<IField> changedFields = event.getChangedFields();
343 for (IField field : changedFields)
344 {
345 addField(field);
346 final int row = fieldNames.indexOf(getFieldId(field));
347 this.updateHandler.getUpdated().get(row).add(VALUE_COLUMN_INDEX);
348 this.model.setValueAt(field.getValueAsString(), row,
349 VALUE_COLUMN_INDEX);
350 }
351 if (event.getDataState() == DataState.STALE)
352 {
353 this.stale = true;
354 }
355 else
356 {
357 this.stale = false;
358 }
359 }
360 }
361
362
363 private final IAutoCreatingStore<String, RecordPanel> panels =
364 new AutoCreatingStore<String, RecordPanel>(
365 new IObjectBuilder<String, RecordPanel>()
366 {
367 public RecordPanel create(String key)
368 {
369 final RecordPanel component = new RecordPanel();
370 RecordViewer.this.tabs.addTab(key, component);
371 return component;
372 }
373 });
374
375 private final JTabbedPane tabs;
376
377 public RecordViewer()
378 {
379 super();
380 setLayout(new BorderLayout());
381 this.tabs = new JTabbedPane();
382 add(this.tabs);
383 }
384
385 public void addedAsListenerFor(IEventSource source)
386 {
387
388 }
389
390 public Class<? extends IEvent>[] getEventTypeFilter()
391 {
392 return RecordTable.eventFilter;
393 }
394
395 public void removedAsListenerFrom(IEventSource source)
396 {
397
398 }
399
400 public void update(IEvent event)
401 {
402 final String source = event.getSource().getAddress();
403 this.panels.get(source).update(event);
404 }
405 }