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 java.awt.BorderLayout;
20 import java.text.MessageFormat;
21 import java.util.Date;
22 import javax.swing.BorderFactory;
23 import javax.swing.JEditorPane;
24 import javax.swing.JPanel;
25 import javax.swing.JScrollPane;
26 import javax.swing.JTable;
27 import javax.swing.ListSelectionModel;
28 import javax.swing.event.ListSelectionEvent;
29 import javax.swing.event.ListSelectionListener;
30 import org.apache.log4j.Logger;
31
32 /***
33 * A panel for showing a stack trace.
34 *
35 * @author <a href="mailto:oliver@puppycrawl.com">Oliver Burn</a>
36 */
37 class DetailPanel
38 extends JPanel
39 implements ListSelectionListener
40 {
41 /*** used to log events **/
42 private static final Logger LOG =
43 Logger.getLogger(DetailPanel.class);
44
45 /*** used to format the logging event **/
46 private static final MessageFormat FORMATTER = new MessageFormat(
47 "<b>Time:</b> <code>{0,time,medium}</code>" +
48 " <b>Priority:</b> <code>{1}</code>" +
49 " <b>Thread:</b> <code>{2}</code>" +
50 " <b>NDC:</b> <code>{3}</code>" +
51 "<br><b>Logger:</b> <code>{4}</code>" +
52 "<br><b>Location:</b> <code>{5}</code>" +
53 "<br><b>Message:</b>" +
54 "<pre>{6}</pre>" +
55 "<b>Throwable:</b>" +
56 "<pre>{7}</pre>");
57
58 /*** the model for the data to render **/
59 private final MyTableModel mModel;
60 /*** pane for rendering detail **/
61 private final JEditorPane mDetails;
62
63 /***
64 * Creates a new <code>DetailPanel</code> instance.
65 *
66 * @param aTable the table to listen for selections on
67 * @param aModel the model backing the table
68 */
69 DetailPanel(JTable aTable, final MyTableModel aModel) {
70 mModel = aModel;
71 setLayout(new BorderLayout());
72 setBorder(BorderFactory.createTitledBorder("Details: "));
73
74 mDetails = new JEditorPane();
75 mDetails.setEditable(false);
76 mDetails.setContentType("text/html");
77 add(new JScrollPane(mDetails), BorderLayout.CENTER);
78
79 final ListSelectionModel rowSM = aTable.getSelectionModel();
80 rowSM.addListSelectionListener(this);
81 }
82
83 /*** @see ListSelectionListener **/
84 public void valueChanged(ListSelectionEvent aEvent) {
85
86 if (aEvent.getValueIsAdjusting()) {
87 return;
88 }
89
90 final ListSelectionModel lsm = (ListSelectionModel) aEvent.getSource();
91 if (lsm.isSelectionEmpty()) {
92 mDetails.setText("Nothing selected");
93 } else {
94 final int selectedRow = lsm.getMinSelectionIndex();
95 final EventDetails e = mModel.getEventDetails(selectedRow);
96 final Object[] args =
97 {
98 new Date(e.getTimeStamp()),
99 e.getPriority(),
100 escape(e.getThreadName()),
101 escape(e.getNDC()),
102 escape(e.getCategoryName()),
103 escape(e.getLocationDetails()),
104 escape(e.getMessage()),
105 escape(getThrowableStrRep(e))
106 };
107 mDetails.setText(FORMATTER.format(args));
108 mDetails.setCaretPosition(0);
109 }
110 }
111
112
113
114
115
116 /***
117 * Returns a string representation of a throwable.
118 *
119 * @param aEvent contains the throwable information
120 * @return a <code>String</code> value
121 */
122 private static String getThrowableStrRep(EventDetails aEvent) {
123 final String[] strs = aEvent.getThrowableStrRep();
124 if (strs == null) {
125 return null;
126 }
127
128 final StringBuffer sb = new StringBuffer();
129 for (int i = 0; i < strs.length; i++) {
130 sb.append(strs[i]).append("\n");
131 }
132
133 return sb.toString();
134 }
135
136 /***
137 * Escape <, > & and " as their entities. It is very
138 * dumb about & handling.
139 * @param aStr the String to escape.
140 * @return the escaped String
141 */
142 private String escape(String aStr) {
143 if (aStr == null) {
144 return null;
145 }
146
147 final StringBuffer buf = new StringBuffer();
148 for (int i = 0; i < aStr.length(); i++) {
149 char c = aStr.charAt(i);
150 switch (c) {
151 case '<':
152 buf.append("<");
153 break;
154 case '>':
155 buf.append(">");
156 break;
157 case '\"':
158 buf.append(""");
159 break;
160 case '&':
161 buf.append("&");
162 break;
163 default:
164 buf.append(c);
165 break;
166 }
167 }
168 return buf.toString();
169 }
170 }