1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60 package com.puppycrawl.tools.checkstyle.gui;
61
62 import java.awt.Component;
63 import java.awt.Dimension;
64 import java.awt.Graphics;
65 import java.awt.event.ActionEvent;
66 import java.awt.event.MouseEvent;
67 import java.util.EventObject;
68 import java.util.List;
69
70 import javax.swing.Action;
71 import javax.swing.AbstractAction;
72 import javax.swing.JTable;
73 import javax.swing.JTextArea;
74 import javax.swing.JTree;
75 import javax.swing.KeyStroke;
76 import javax.swing.ListSelectionModel;
77 import javax.swing.LookAndFeel;
78 import javax.swing.UIManager;
79 import javax.swing.event.ListSelectionEvent;
80 import javax.swing.event.ListSelectionListener;
81 import javax.swing.table.TableCellEditor;
82 import javax.swing.table.TableCellRenderer;
83 import javax.swing.tree.DefaultTreeCellRenderer;
84 import javax.swing.tree.DefaultTreeSelectionModel;
85 import javax.swing.tree.TreeCellRenderer;
86 import javax.swing.tree.TreeModel;
87 import javax.swing.tree.TreePath;
88
89 import com.puppycrawl.tools.checkstyle.api.DetailAST;
90
91
92
93
94
95
96
97
98
99
100
101
102 public class JTreeTable extends JTable
103 {
104
105 private static final long serialVersionUID = -8493693409423365387L;
106
107 protected TreeTableCellRenderer tree;
108 private JTextArea editor;
109 private List<Integer> lines2position;
110
111 public JTreeTable(TreeTableModel treeTableModel)
112 {
113 super();
114
115
116 tree = new TreeTableCellRenderer(treeTableModel);
117
118
119 super.setModel(new TreeTableModelAdapter(treeTableModel, tree));
120
121
122 final ListToTreeSelectionModelWrapper selectionWrapper = new
123 ListToTreeSelectionModelWrapper();
124 tree.setSelectionModel(selectionWrapper);
125 setSelectionModel(selectionWrapper.getListSelectionModel());
126
127
128 setDefaultRenderer(TreeTableModel.class, tree);
129 setDefaultEditor(TreeTableModel.class, new TreeTableCellEditor());
130
131
132 setShowGrid(false);
133
134
135 setIntercellSpacing(new Dimension(0, 0));
136
137
138
139 if (tree.getRowHeight() < 1) {
140
141 setRowHeight(getRowHeight());
142 }
143
144 final Action expand = new AbstractAction() {
145
146
147
148 private static final long serialVersionUID = -5859674518660156121L;
149
150 @Override
151 public void actionPerformed(ActionEvent e) {
152 final TreePath selected = tree.getSelectionPath();
153
154 DetailAST ast = (DetailAST) selected.getLastPathComponent();
155 new CodeSelector(ast, editor, lines2position).select();
156
157 if (tree.isExpanded(selected)) {
158 tree.collapsePath(selected);
159 }
160 else {
161 tree.expandPath(selected);
162 }
163 tree.setSelectionPath(selected);
164 }
165 };
166 final KeyStroke stroke = KeyStroke.getKeyStroke("ENTER");
167 final String command = "expand/collapse";
168 getInputMap().put(stroke, command);
169 getActionMap().put(command, expand);
170 }
171
172
173
174
175
176
177 @Override
178 public void updateUI()
179 {
180 super.updateUI();
181 if (tree != null) {
182 tree.updateUI();
183 }
184
185
186 LookAndFeel.installColorsAndFont(this, "Tree.background",
187 "Tree.foreground", "Tree.font");
188 }
189
190
191
192
193
194
195
196 @Override
197 public int getEditingRow()
198 {
199 final Class<?> editingClass = getColumnClass(editingColumn);
200 return editingClass == TreeTableModel.class ? -1 : editingRow;
201 }
202
203
204
205
206 @Override
207 public void setRowHeight(int newRowHeight)
208 {
209 super.setRowHeight(newRowHeight);
210 if (tree != null && tree.getRowHeight() != newRowHeight) {
211 tree.setRowHeight(getRowHeight());
212 }
213 }
214
215
216
217
218 public JTree getTree()
219 {
220 return tree;
221 }
222
223
224
225
226 class TreeTableCellRenderer extends JTree implements
227 TableCellRenderer
228 {
229
230
231
232 private static final long serialVersionUID = 4324031590789321581L;
233
234 protected int visibleRow;
235
236
237 public TreeTableCellRenderer(TreeModel model)
238 {
239 super(model);
240 }
241
242
243
244
245
246 @Override
247 public void updateUI()
248 {
249 super.updateUI();
250
251
252 final TreeCellRenderer tcr = getCellRenderer();
253 if (tcr instanceof DefaultTreeCellRenderer) {
254 final DefaultTreeCellRenderer dtcr = (DefaultTreeCellRenderer) tcr;
255
256
257
258
259 dtcr.setTextSelectionColor(UIManager.getColor
260 ("Table.selectionForeground"));
261 dtcr.setBackgroundSelectionColor(UIManager.getColor
262 ("Table.selectionBackground"));
263 }
264 }
265
266
267
268
269
270 @Override
271 public void setRowHeight(int newRowHeight)
272 {
273 if (newRowHeight > 0) {
274 super.setRowHeight(newRowHeight);
275 if (JTreeTable.this != null &&
276 JTreeTable.this.getRowHeight() != newRowHeight)
277 {
278 JTreeTable.this.setRowHeight(getRowHeight());
279 }
280 }
281 }
282
283
284
285
286 @Override
287 public void setBounds(int x, int y, int w, int h)
288 {
289 super.setBounds(x, 0, w, JTreeTable.this.getHeight());
290 }
291
292
293
294
295
296 @Override
297 public void paint(Graphics g)
298 {
299 g.translate(0, -visibleRow * getRowHeight());
300 super.paint(g);
301 }
302
303
304
305
306
307 @Override
308 public Component getTableCellRendererComponent(JTable table,
309 Object value,
310 boolean isSelected,
311 boolean hasFocus,
312 int row, int column)
313 {
314 if (isSelected) {
315 setBackground(table.getSelectionBackground());
316 } else {
317 setBackground(table.getBackground());
318 }
319
320 visibleRow = row;
321 return this;
322 }
323 }
324
325
326
327
328
329
330 public class TreeTableCellEditor extends AbstractCellEditor implements
331 TableCellEditor
332 {
333 @Override
334 public Component getTableCellEditorComponent(JTable table,
335 Object value,
336 boolean isSelected,
337 int r, int c)
338 {
339 return tree;
340 }
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362 @Override
363 public boolean isCellEditable(EventObject e)
364 {
365 if (e instanceof MouseEvent) {
366 for (int counter = getColumnCount() - 1; counter >= 0;
367 counter--) {
368 if (getColumnClass(counter) == TreeTableModel.class) {
369 final MouseEvent me = (MouseEvent) e;
370 final MouseEvent newME = new MouseEvent(tree, me.getID(),
371 me.getWhen(), me.getModifiers(),
372 me.getX() - getCellRect(0, counter, true).x,
373 me.getY(), me.getClickCount(),
374 me.isPopupTrigger());
375 tree.dispatchEvent(newME);
376 break;
377 }
378 }
379 }
380
381 return false;
382 }
383 }
384
385
386
387
388
389
390
391
392 class ListToTreeSelectionModelWrapper extends DefaultTreeSelectionModel
393 {
394
395
396
397 private static final long serialVersionUID = 2267930983939339510L;
398
399 protected boolean updatingListSelectionModel;
400
401 public ListToTreeSelectionModelWrapper()
402 {
403 super();
404 getListSelectionModel().addListSelectionListener
405 (createListSelectionListener());
406 }
407
408
409
410
411
412
413
414
415 ListSelectionModel getListSelectionModel()
416 {
417 return listSelectionModel;
418 }
419
420
421
422
423
424
425 @Override
426 public void resetRowSelection()
427 {
428 if (!updatingListSelectionModel) {
429 updatingListSelectionModel = true;
430 try {
431 super.resetRowSelection();
432 } finally {
433 updatingListSelectionModel = false;
434 }
435 }
436
437
438
439
440
441 }
442
443
444
445
446 private ListSelectionListener createListSelectionListener()
447 {
448 return new ListSelectionHandler();
449 }
450
451
452
453
454
455
456 protected void updateSelectedPathsFromSelectedRows()
457 {
458 if (!updatingListSelectionModel) {
459 updatingListSelectionModel = true;
460 try {
461
462
463 final int min = listSelectionModel.getMinSelectionIndex();
464 final int max = listSelectionModel.getMaxSelectionIndex();
465
466 clearSelection();
467 if (min != -1 && max != -1) {
468 for (int counter = min; counter <= max; counter++) {
469 if (listSelectionModel.isSelectedIndex(counter)) {
470 final TreePath selPath = tree.getPathForRow
471 (counter);
472
473 if (selPath != null) {
474 addSelectionPath(selPath);
475 }
476 }
477 }
478 }
479 } finally {
480 updatingListSelectionModel = false;
481 }
482 }
483 }
484
485
486
487
488
489 class ListSelectionHandler implements ListSelectionListener
490 {
491 @Override
492 public void valueChanged(ListSelectionEvent e)
493 {
494 updateSelectedPathsFromSelectedRows();
495 }
496 }
497 }
498
499 public void setEditor(JTextArea mJTextArea)
500 {
501 this.editor = mJTextArea;
502 }
503
504 public void setLinePositionMap(List<Integer> lines2position)
505 {
506 this.lines2position = lines2position;
507 }
508 }