1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.apache.log4j.chainsaw;
18
19 import org.apache.log4j.LogManager;
20 import org.apache.log4j.Logger;
21
22 import javax.swing.*;
23 import javax.swing.table.TableColumn;
24 import javax.swing.tree.DefaultMutableTreeNode;
25 import javax.swing.tree.DefaultTreeModel;
26 import javax.swing.tree.TreeModel;
27 import java.awt.*;
28 import java.awt.event.ActionListener;
29 import java.awt.event.MouseAdapter;
30 import java.awt.event.MouseEvent;
31 import java.util.ArrayList;
32 import java.util.Enumeration;
33 import java.util.List;
34
35
36
37
38
39
40
41 public class LogPanelPreferencePanel extends AbstractPreferencePanel {
42
43
44 private final LogPanelPreferenceModel preferenceModel;
45 private final ModifiableListModel columnListModel = new ModifiableListModel();
46 private static final Logger logger = LogManager.getLogger(LogPanelPreferencePanel.class);
47 private ApplicationPreferenceModel appPreferenceModel;
48
49
50
51 public LogPanelPreferencePanel(LogPanelPreferenceModel model, ApplicationPreferenceModel appModel) {
52 preferenceModel = model;
53 appPreferenceModel = appModel;
54 initComponents();
55
56 getOkButton().addActionListener(e -> hidePanel());
57
58 getCancelButton().addActionListener(e -> hidePanel());
59 }
60
61
62
63
64
65
66
67
68 public static void main(String[] args) {
69 JFrame f = new JFrame("Preferences Panel Test Bed");
70 LogPanelPreferenceModel model = new LogPanelPreferenceModel();
71 ApplicationPreferenceModel appModel = new ApplicationPreferenceModel();
72 LogPanelPreferencePanel panel = new LogPanelPreferencePanel(model, appModel);
73 f.getContentPane().add(panel);
74
75 model.addPropertyChangeListener(evt -> logger.warn(evt.toString()));
76 panel.setOkCancelActionListener(e -> System.exit(1));
77
78 f.setSize(640, 480);
79 f.setVisible(true);
80 }
81
82 protected TreeModel createTreeModel() {
83 final DefaultMutableTreeNode rootNode =
84 new DefaultMutableTreeNode("Preferences");
85 DefaultTreeModel model = new DefaultTreeModel(rootNode);
86
87 DefaultMutableTreeNode visuals =
88 new DefaultMutableTreeNode(new VisualsPrefPanel());
89 DefaultMutableTreeNode formatting =
90 new DefaultMutableTreeNode(new FormattingPanel());
91 DefaultMutableTreeNode columns =
92 new DefaultMutableTreeNode(new ColumnSelectorPanel());
93
94 rootNode.add(visuals);
95 rootNode.add(formatting);
96 rootNode.add(columns);
97
98 return model;
99 }
100
101
102
103
104
105
106
107
108 public class ColumnSelectorPanel extends BasicPrefPanel {
109
110
111 ColumnSelectorPanel() {
112 super("Columns");
113 initComponents();
114 }
115
116
117
118 private void initComponents() {
119 setLayout(new BoxLayout(this, BoxLayout.Y_AXIS));
120
121 Box columnBox = new Box(BoxLayout.Y_AXIS);
122
123
124 final JList columnList = new JList();
125 columnList.setVisibleRowCount(17);
126
127 for (Object o : preferenceModel.getColumns()) {
128 TableColumn col = (TableColumn) o;
129 Enumeration enumeration = columnListModel.elements();
130 boolean found = false;
131 while (enumeration.hasMoreElements()) {
132 TableColumn thisCol = (TableColumn) enumeration.nextElement();
133 if (thisCol.getHeaderValue().equals(col.getHeaderValue())) {
134 found = true;
135 }
136 }
137 if (!found) {
138 columnListModel.addElement(col);
139 }
140 }
141
142 columnList.setModel(columnListModel);
143
144 CheckListCellRenderer cellRenderer = new CheckListCellRenderer() {
145 protected boolean isSelected(Object value) {
146 return LogPanelPreferencePanel.this.preferenceModel.isColumnVisible((TableColumn)
147 value);
148 }
149 };
150
151 columnList.addMouseListener(new MouseAdapter() {
152 public void mouseClicked(MouseEvent e) {
153 int i = columnList.locationToIndex(e.getPoint());
154
155 if (i >= 0) {
156 Object column = columnListModel.get(i);
157 preferenceModel.toggleColumn(((TableColumn) column));
158 }
159 }
160 });
161 JButton setAsDefaultsButton = new JButton("Use selected columns as default visible columns");
162 setAsDefaultsButton.addActionListener(actionEvent -> {
163 List selectedColumns = new ArrayList();
164 for (int i = 0; i < columnListModel.getSize(); i++) {
165 if (preferenceModel.isColumnVisible((TableColumn) columnListModel.get(i))) {
166 selectedColumns.add(((TableColumn) columnListModel.get(i)).getHeaderValue());
167 }
168 }
169 appPreferenceModel.setDefaultColumnNames(selectedColumns);
170 });
171 columnList.setCellRenderer(cellRenderer);
172 columnBox.add(new JScrollPane(columnList));
173 columnBox.add(Box.createVerticalStrut(5));
174 columnBox.add(setAsDefaultsButton);
175 add(columnBox);
176 add(Box.createVerticalGlue());
177 }
178 }
179
180
181
182
183
184 private class FormattingPanel extends BasicPrefPanel {
185
186
187 private JTextField customFormatText = new JTextField("", 10);
188 private JTextField loggerPrecision = new JTextField(10);
189 private JRadioButton rdCustom = new JRadioButton("Custom Format ");
190 private final JRadioButton rdISO =
191 new JRadioButton(
192 "<html><b>Fast</b> ISO 8601 format (yyyy-MM-dd HH:mm:ss) </html>");
193 private final JTextField timeZone = new JTextField(10);
194 private final JRadioButton rdLevelIcons = new JRadioButton("Icons ");
195 private final JRadioButton rdLevelText = new JRadioButton("Text ");
196 private JRadioButton rdLast;
197
198
199
200 private FormattingPanel() {
201 super("Formatting");
202 this.initComponents();
203 setupListeners();
204 }
205
206
207
208 private void initComponents() {
209 setLayout(new BoxLayout(this, BoxLayout.Y_AXIS));
210
211 JPanel dateFormatPanel = new JPanel();
212 dateFormatPanel.setLayout(new BoxLayout(dateFormatPanel, BoxLayout.Y_AXIS));
213 dateFormatPanel.setBorder(
214 BorderFactory.createTitledBorder(
215 BorderFactory.createEtchedBorder(), "Timestamp"));
216
217 ButtonGroup bgDateFormat = new ButtonGroup();
218
219 rdISO.setSelected(preferenceModel.isUseISO8601Format());
220
221 rdISO.setHorizontalTextPosition(SwingConstants.RIGHT);
222 rdISO.setAlignmentX(Component.LEFT_ALIGNMENT);
223
224 bgDateFormat.add(rdISO);
225 dateFormatPanel.add(rdISO);
226
227 for (Object DATE_FORMAT : LogPanelPreferenceModel.DATE_FORMATS) {
228 final String format = (String) DATE_FORMAT;
229 final JRadioButton rdFormat = new JRadioButton(format);
230 rdFormat.setHorizontalTextPosition(SwingConstants.RIGHT);
231 rdFormat.setAlignmentX(Component.LEFT_ALIGNMENT);
232
233 rdFormat.addActionListener(e -> {
234 preferenceModel.setDateFormatPattern(format);
235 customFormatText.setEnabled(rdCustom.isSelected());
236 rdLast = rdFormat;
237 });
238
239
240 preferenceModel.addPropertyChangeListener(
241 "dateFormatPattern", evt -> {
242 rdFormat.setSelected(
243 preferenceModel.getDateFormatPattern().equals(format));
244 rdLast = rdFormat;
245 });
246
247 dateFormatPanel.add(rdFormat);
248 bgDateFormat.add(rdFormat);
249 }
250
251 customFormatText.setPreferredSize(new Dimension(100, 20));
252 customFormatText.setMaximumSize(customFormatText.getPreferredSize());
253 customFormatText.setMinimumSize(customFormatText.getPreferredSize());
254 customFormatText.setEnabled(false);
255
256 bgDateFormat.add(rdCustom);
257 rdCustom.setSelected(preferenceModel.isCustomDateFormat());
258
259
260 if (preferenceModel.isCustomDateFormat()) {
261 customFormatText.setText(preferenceModel.getDateFormatPattern());
262 customFormatText.setEnabled(true);
263 }
264
265 JPanel customPanel = new JPanel();
266 customPanel.setLayout(new BoxLayout(customPanel, BoxLayout.X_AXIS));
267 customPanel.add(rdCustom);
268 customPanel.add(customFormatText);
269 customPanel.setAlignmentX(Component.LEFT_ALIGNMENT);
270
271 dateFormatPanel.add(customPanel);
272 dateFormatPanel.add(Box.createVerticalStrut(5));
273
274 JLabel dateFormatLabel = new JLabel("Time zone of events (or blank for local time zone");
275 dateFormatPanel.add(dateFormatLabel);
276
277 timeZone.setMaximumSize(timeZone.getPreferredSize());
278 dateFormatPanel.add(Box.createVerticalStrut(5));
279 dateFormatPanel.add(timeZone);
280
281 add(dateFormatPanel);
282
283 JPanel levelFormatPanel = new JPanel();
284 levelFormatPanel.setLayout(
285 new BoxLayout(levelFormatPanel, BoxLayout.Y_AXIS));
286 levelFormatPanel.setBorder(
287 BorderFactory.createTitledBorder(
288 BorderFactory.createEtchedBorder(), "Level"));
289 levelFormatPanel.setAlignmentX(Component.LEFT_ALIGNMENT);
290
291 ButtonGroup bgLevel = new ButtonGroup();
292 bgLevel.add(rdLevelIcons);
293 bgLevel.add(rdLevelText);
294
295 rdLevelIcons.setSelected(preferenceModel.isLevelIcons());
296
297 levelFormatPanel.add(rdLevelIcons);
298 levelFormatPanel.add(rdLevelText);
299
300 add(levelFormatPanel);
301
302 JPanel loggerFormatPanel = new JPanel();
303 loggerFormatPanel.setLayout(
304 new BoxLayout(loggerFormatPanel, BoxLayout.Y_AXIS));
305 loggerFormatPanel.setBorder(
306 BorderFactory.createTitledBorder(
307 BorderFactory.createEtchedBorder(), "Logger"));
308 loggerFormatPanel.setAlignmentX(Component.LEFT_ALIGNMENT);
309
310 loggerFormatPanel.add(Box.createVerticalStrut(3));
311
312 final JLabel precisionLabel =
313 new JLabel("Number of package levels to hide (or blank to display full logger)");
314
315 loggerFormatPanel.add(precisionLabel);
316 loggerFormatPanel.add(Box.createVerticalStrut(5));
317
318 loggerPrecision.setMaximumSize(loggerPrecision.getPreferredSize());
319 loggerFormatPanel.add(loggerPrecision);
320
321 add(loggerFormatPanel);
322 }
323
324
325
326
327 private void reset() {
328
329 if (preferenceModel.isCustomDateFormat()) {
330 customFormatText.setText(preferenceModel.getDateFormatPattern());
331 } else {
332 if (rdLast != null) {
333 rdLast.setSelected(true);
334 }
335 customFormatText.setEnabled(false);
336 }
337
338 loggerPrecision.setText(preferenceModel.getLoggerPrecision());
339 timeZone.setText(preferenceModel.getTimeZone());
340 }
341
342
343
344
345 private void commit() {
346 if (rdCustom.isSelected()) {
347 preferenceModel.setDateFormatPattern(customFormatText.getText());
348 }
349 preferenceModel.setLoggerPrecision(loggerPrecision.getText());
350 preferenceModel.setTimeZone(timeZone.getText());
351 }
352
353
354
355
356 private void setupListeners() {
357 getOkButton().addActionListener(evt -> commit());
358
359 getCancelButton().addActionListener(evt -> reset());
360
361 rdCustom.addActionListener(e -> {
362 customFormatText.setEnabled(rdCustom.isSelected());
363 customFormatText.grabFocus();
364 });
365
366
367 preferenceModel.addPropertyChangeListener(
368 "dateFormatPattern", evt -> {
369
370
371
372
373 if (
374 preferenceModel.isCustomDateFormat()
375 && !customFormatText.getText().equals(
376 evt.getNewValue().toString())) {
377 customFormatText.setText(preferenceModel.getDateFormatPattern());
378 rdCustom.setSelected(true);
379 customFormatText.setEnabled(true);
380 } else {
381 rdCustom.setSelected(false);
382 }
383 });
384
385 rdISO.addActionListener(e -> {
386 preferenceModel.setDateFormatPattern("ISO8601");
387 customFormatText.setEnabled(rdCustom.isSelected());
388 rdLast = rdISO;
389 });
390 preferenceModel.addPropertyChangeListener(
391 "dateFormatPattern", evt -> {
392 rdISO.setSelected(preferenceModel.isUseISO8601Format());
393 rdLast = rdISO;
394 });
395 preferenceModel.addPropertyChangeListener(
396 "dateFormatTimeZone", evt -> timeZone.setText(preferenceModel.getTimeZone())
397 );
398
399 ActionListener levelIconListener = e -> preferenceModel.setLevelIcons(rdLevelIcons.isSelected());
400
401 rdLevelIcons.addActionListener(levelIconListener);
402 rdLevelText.addActionListener(levelIconListener);
403
404 preferenceModel.addPropertyChangeListener(
405 "levelIcons", evt -> {
406 boolean value = (Boolean) evt.getNewValue();
407 rdLevelIcons.setSelected(value);
408 rdLevelText.setSelected(!value);
409 });
410 }
411 }
412
413
414
415
416
417
418
419
420 private class VisualsPrefPanel extends BasicPrefPanel {
421
422
423 private final JCheckBox detailPanelVisible =
424 new JCheckBox("Show Event Detail panel");
425
426 private final JCheckBox loggerTreePanel =
427 new JCheckBox("Show Logger Tree");
428 private final JCheckBox wrapMessage = new JCheckBox("Wrap message field (display multi-line rows) ");
429 private final JCheckBox searchResultsVisible = new JCheckBox("Display find results in details panel ");
430 private final JCheckBox highlightSearchMatchText = new JCheckBox("Highlight find match text ");
431 private final JCheckBox scrollToBottom =
432 new JCheckBox("Scroll to bottom (view tracks with new events)");
433 private final JCheckBox showMillisDeltaAsGap =
434 new JCheckBox("Display timestamp delta between events as row gap");
435 private final JCheckBox toolTips =
436 new JCheckBox("Show Event Detail Tooltips");
437 private final JCheckBox thumbnailBarToolTips =
438 new JCheckBox("Show Thumbnail Bar Tooltips");
439 private final JEditorPane clearTableExpression = new JEditorPane();
440
441
442
443
444
445
446 private VisualsPrefPanel() {
447 super("Visuals");
448 initPanelComponents();
449 setupListeners();
450 }
451
452
453
454
455
456
457 private void initPanelComponents() {
458 JTextComponentFormatter.applySystemFontAndSize(clearTableExpression);
459 setLayout(new BoxLayout(this, BoxLayout.Y_AXIS));
460 toolTips.setAlignmentX(Component.LEFT_ALIGNMENT);
461 thumbnailBarToolTips.setAlignmentX(Component.LEFT_ALIGNMENT);
462 detailPanelVisible.setAlignmentX(Component.LEFT_ALIGNMENT);
463 loggerTreePanel.setAlignmentX(Component.LEFT_ALIGNMENT);
464 scrollToBottom.setAlignmentX(Component.LEFT_ALIGNMENT);
465 showMillisDeltaAsGap.setAlignmentX(Component.LEFT_ALIGNMENT);
466 add(toolTips);
467 add(thumbnailBarToolTips);
468 add(detailPanelVisible);
469 add(loggerTreePanel);
470 add(scrollToBottom);
471 add(wrapMessage);
472 add(highlightSearchMatchText);
473 add(searchResultsVisible);
474 add(showMillisDeltaAsGap);
475 JPanel clearPanel = new JPanel(new BorderLayout());
476 clearPanel.setAlignmentX(Component.LEFT_ALIGNMENT);
477 clearPanel.add(new JLabel("Clear all events if expression matches"), BorderLayout.NORTH);
478 clearTableExpression.setText(preferenceModel.getClearTableExpression());
479 clearTableExpression.setPreferredSize(new Dimension(300, 50));
480 JPanel clearTableScrollPanel = new JPanel(new BorderLayout());
481 clearTableScrollPanel.add(new JScrollPane(clearTableExpression), BorderLayout.NORTH);
482 clearPanel.add(clearTableScrollPanel, BorderLayout.CENTER);
483 add(clearPanel);
484
485 toolTips.setSelected(preferenceModel.isToolTips());
486 thumbnailBarToolTips.setSelected(preferenceModel.isThumbnailBarToolTips());
487 detailPanelVisible.setSelected(preferenceModel.isDetailPaneVisible());
488 searchResultsVisible.setSelected(preferenceModel.isSearchResultsVisible());
489 loggerTreePanel.setSelected(preferenceModel.isLogTreePanelVisible());
490 }
491
492
493
494
495 private void setupListeners() {
496 ActionListener wrapMessageListener = e -> preferenceModel.setWrapMessage(wrapMessage.isSelected());
497
498 wrapMessage.addActionListener(wrapMessageListener);
499
500 ActionListener searchResultsVisibleListener = e -> preferenceModel.setSearchResultsVisible(searchResultsVisible.isSelected());
501
502 searchResultsVisible.addActionListener(searchResultsVisibleListener);
503
504 ActionListener highlightSearchMatchTextListener = e -> preferenceModel.setHighlightSearchMatchText(highlightSearchMatchText.isSelected());
505
506 highlightSearchMatchText.addActionListener(highlightSearchMatchTextListener);
507
508 preferenceModel.addPropertyChangeListener(
509 "wrapMessage", evt -> {
510 boolean value = (Boolean) evt.getNewValue();
511 wrapMessage.setSelected(value);
512 });
513
514 preferenceModel.addPropertyChangeListener(
515 "searchResultsVisible", evt -> {
516 boolean value = (Boolean) evt.getNewValue();
517 searchResultsVisible.setSelected(value);
518 });
519
520 preferenceModel.addPropertyChangeListener(
521 "highlightSearchMatchText", evt -> {
522 boolean value = (Boolean) evt.getNewValue();
523 highlightSearchMatchText.setSelected(value);
524 });
525
526 toolTips.addActionListener(e -> preferenceModel.setToolTips(toolTips.isSelected()));
527
528 thumbnailBarToolTips.addActionListener(e -> preferenceModel.setThumbnailBarToolTips(thumbnailBarToolTips.isSelected()));
529
530 getOkButton().addActionListener(e -> preferenceModel.setClearTableExpression(clearTableExpression.getText().trim()));
531
532 preferenceModel.addPropertyChangeListener(
533 "toolTips", evt -> {
534 boolean value = (Boolean) evt.getNewValue();
535 toolTips.setSelected(value);
536 });
537
538 preferenceModel.addPropertyChangeListener(
539 "thumbnailBarToolTips", evt -> {
540 boolean value = (Boolean) evt.getNewValue();
541 thumbnailBarToolTips.setSelected(value);
542 });
543
544 detailPanelVisible.addActionListener(e -> preferenceModel.setDetailPaneVisible(detailPanelVisible.isSelected()));
545
546 preferenceModel.addPropertyChangeListener(
547 "detailPaneVisible", evt -> {
548 boolean value = (Boolean) evt.getNewValue();
549 detailPanelVisible.setSelected(value);
550 });
551
552 scrollToBottom.addActionListener(e -> preferenceModel.setScrollToBottom(scrollToBottom.isSelected()));
553
554 showMillisDeltaAsGap.addActionListener(e -> preferenceModel.setShowMillisDeltaAsGap(showMillisDeltaAsGap.isSelected()));
555
556 preferenceModel.addPropertyChangeListener("showMillisDeltaAsGap", evt -> {
557 boolean value = (Boolean) evt.getNewValue();
558 showMillisDeltaAsGap.setSelected(value);
559 });
560 preferenceModel.addPropertyChangeListener(
561 "scrollToBottom", evt -> {
562 boolean value = (Boolean) evt.getNewValue();
563 scrollToBottom.setSelected(value);
564 });
565
566 loggerTreePanel.addActionListener(e -> preferenceModel.setLogTreePanelVisible(loggerTreePanel.isSelected()));
567
568 preferenceModel.addPropertyChangeListener(
569 "logTreePanelVisible", evt -> {
570 boolean value = (Boolean) evt.getNewValue();
571 loggerTreePanel.setSelected(value);
572 });
573
574 preferenceModel.addPropertyChangeListener("columns", evt -> {
575 List cols = (List) evt.getNewValue();
576 for (Object col1 : cols) {
577 TableColumn col = (TableColumn) col1;
578 Enumeration enumeration = columnListModel.elements();
579 boolean found = false;
580 while (enumeration.hasMoreElements()) {
581 TableColumn thisCol = (TableColumn) enumeration.nextElement();
582 if (thisCol.getHeaderValue().equals(col.getHeaderValue())) {
583 found = true;
584 }
585 }
586 if (!found) {
587 columnListModel.addElement(col);
588 columnListModel.fireContentsChanged();
589 }
590 }
591 });
592
593 preferenceModel.addPropertyChangeListener(
594 "visibleColumns", evt -> columnListModel.fireContentsChanged());
595
596 preferenceModel.addPropertyChangeListener("clearTableExpression", evt -> clearTableExpression.setText(((LogPanelPreferenceModel) evt.getSource()).getClearTableExpression()));
597 }
598 }
599 }