Line 0
Link Here
|
|
|
1 |
package org.apache.batik.util.gui; |
2 |
|
3 |
import java.awt.BorderLayout; |
4 |
import java.awt.Color; |
5 |
import java.awt.Component; |
6 |
import java.awt.Container; |
7 |
import java.awt.Dimension; |
8 |
import java.awt.FlowLayout; |
9 |
import java.awt.GradientPaint; |
10 |
import java.awt.Graphics; |
11 |
import java.awt.Graphics2D; |
12 |
import java.awt.SystemColor; |
13 |
import java.awt.event.ActionEvent; |
14 |
import java.awt.event.ActionListener; |
15 |
import java.awt.event.ItemEvent; |
16 |
import java.awt.event.ItemListener; |
17 |
import java.awt.event.MouseAdapter; |
18 |
import java.awt.event.MouseEvent; |
19 |
import java.awt.event.MouseListener; |
20 |
import java.io.PrintWriter; |
21 |
import java.io.StringWriter; |
22 |
import java.util.ArrayList; |
23 |
import java.util.Enumeration; |
24 |
import java.util.HashMap; |
25 |
import java.util.Iterator; |
26 |
import java.util.List; |
27 |
import java.util.Locale; |
28 |
import java.util.Map; |
29 |
import java.util.ResourceBundle; |
30 |
|
31 |
import javax.swing.AbstractAction; |
32 |
import javax.swing.AbstractButton; |
33 |
import javax.swing.Action; |
34 |
import javax.swing.BorderFactory; |
35 |
import javax.swing.Box; |
36 |
import javax.swing.BoxLayout; |
37 |
import javax.swing.ButtonGroup; |
38 |
import javax.swing.ButtonModel; |
39 |
import javax.swing.ImageIcon; |
40 |
import javax.swing.JButton; |
41 |
import javax.swing.JDialog; |
42 |
import javax.swing.JLabel; |
43 |
import javax.swing.JOptionPane; |
44 |
import javax.swing.JPanel; |
45 |
import javax.swing.JPopupMenu; |
46 |
import javax.swing.JScrollPane; |
47 |
import javax.swing.JTextArea; |
48 |
import javax.swing.JTextPane; |
49 |
import javax.swing.JToggleButton; |
50 |
import javax.swing.JToolBar; |
51 |
|
52 |
import org.apache.batik.util.gui.resource.ActionMap; |
53 |
import org.apache.batik.util.gui.resource.ButtonFactory; |
54 |
import org.apache.batik.util.gui.resource.Hyperlink; |
55 |
import org.apache.batik.util.gui.resource.JToolbarSeparator; |
56 |
import org.apache.batik.util.gui.resource.MenuFactory; |
57 |
import org.apache.batik.util.gui.resource.MissingListenerException; |
58 |
import org.apache.batik.util.gui.resource.ResourceManager; |
59 |
import org.apache.batik.util.gui.resource.Hyperlink.HyperlinkEvent; |
60 |
import org.w3c.dom.Document; |
61 |
|
62 |
public class ErrorConsole extends JPanel implements ActionMap { |
63 |
|
64 |
/** |
65 |
* The resource file name |
66 |
*/ |
67 |
protected static final String RESOURCES = "org.apache.batik.util.gui.resources.ErrorConsole"; |
68 |
|
69 |
/** |
70 |
* The resource bundle |
71 |
*/ |
72 |
protected static ResourceBundle bundle; |
73 |
|
74 |
/** |
75 |
* The resource manager |
76 |
*/ |
77 |
protected static ResourceManager resources; |
78 |
|
79 |
static { |
80 |
bundle = ResourceBundle.getBundle(RESOURCES, Locale.getDefault()); |
81 |
resources = new ResourceManager(bundle); |
82 |
} |
83 |
|
84 |
/** |
85 |
* The button factory. |
86 |
*/ |
87 |
protected ButtonFactory bf = new ButtonFactory(bundle, this); |
88 |
|
89 |
/** |
90 |
* The menu factory. |
91 |
*/ |
92 |
protected MenuFactory mf = new MenuFactory(bundle, this); |
93 |
|
94 |
private Box consoleList; |
95 |
|
96 |
private ButtonGroup errorGroup; |
97 |
|
98 |
private int displayType; |
99 |
|
100 |
private boolean sortOrderAscending = true; |
101 |
|
102 |
private JPopupMenu popupMenu; |
103 |
|
104 |
public ErrorConsole(Throwable th, int type) { |
105 |
this(th, null, type); |
106 |
} |
107 |
|
108 |
public ErrorConsole(Throwable th, String uri, int type) { |
109 |
super(new BorderLayout()); |
110 |
|
111 |
actions.put("DisplayAllButtonAction", new DisplayAllButtonAction()); |
112 |
actions.put("DisplayErrorsButtonAction", |
113 |
new DisplayErrorsButtonAction()); |
114 |
actions.put("DisplayWarningsButtonAction", |
115 |
new DisplayWarningsButtonAction()); |
116 |
actions.put("DisplayMessagesButtonAction", |
117 |
new DisplayMessagesButtonAction()); |
118 |
actions.put("ClearButtonAction", new ClearButtonAction()); |
119 |
|
120 |
actions.put("FirstLastSortMenuAction", new FirstLastSortMenuAction()); |
121 |
actions.put("LastFirstSortMenuAction", new LastFirstSortMenuAction()); |
122 |
actions.put("CopyMenuAction", new CopyMenuAction()); |
123 |
|
124 |
JPanel errorPanel = new JPanel(new BorderLayout()); |
125 |
errorPanel.setBackground(Color.white); |
126 |
|
127 |
JScrollPane errorScrollPane = new JScrollPane(errorPanel); |
128 |
add(errorScrollPane); |
129 |
|
130 |
errorGroup = new ButtonGroup(); |
131 |
|
132 |
consoleList = new Box(BoxLayout.Y_AXIS); |
133 |
errorPanel.add(consoleList, BorderLayout.NORTH); |
134 |
|
135 |
popupMenu = createPopupMenu(); |
136 |
|
137 |
add(createToolBar(), BorderLayout.NORTH); |
138 |
add(th, uri, type); |
139 |
setPreferredSize(new Dimension(550, 400)); |
140 |
} |
141 |
|
142 |
private JToolBar createToolBar() { |
143 |
JToolBar toolbar = new JToolBar(); |
144 |
toolbar.setFloatable(false); |
145 |
|
146 |
BooleanButtonGroup displayGroup = new BooleanButtonGroup(); |
147 |
|
148 |
JToggleButton displayAll = bf |
149 |
.createJToolbarToggleButton("DisplayAllButton"); |
150 |
displayGroup.add(displayAll); |
151 |
displayAll.setSelected(true); |
152 |
displayType(-1, true); |
153 |
toolbar.add(displayAll); |
154 |
|
155 |
JToggleButton displayErrors = bf |
156 |
.createJToolbarToggleButton("DisplayErrorsButton"); |
157 |
displayGroup.addOr(displayErrors); |
158 |
toolbar.add(displayErrors); |
159 |
|
160 |
JToggleButton displayWarnings = bf |
161 |
.createJToolbarToggleButton("DisplayWarningsButton"); |
162 |
displayGroup.addOr(displayWarnings); |
163 |
toolbar.add(displayWarnings); |
164 |
|
165 |
JToggleButton displayMessages = bf |
166 |
.createJToolbarToggleButton("DisplayMessagesButton"); |
167 |
displayGroup.addOr(displayMessages); |
168 |
toolbar.add(displayMessages); |
169 |
|
170 |
toolbar.add(new JToolbarSeparator()); |
171 |
|
172 |
JButton clear = bf.createJToolbarButton("ClearButton"); |
173 |
displayGroup.add(clear); |
174 |
toolbar.add(clear); |
175 |
|
176 |
return toolbar; |
177 |
} |
178 |
|
179 |
private class BooleanButtonGroup extends ButtonGroup implements ItemListener { |
180 |
|
181 |
private List orElements = new ArrayList(); |
182 |
|
183 |
private AbstractButton orButton = new JToggleButton(); |
184 |
|
185 |
public BooleanButtonGroup() { |
186 |
orButton.addItemListener(this); |
187 |
add(orButton); |
188 |
} |
189 |
|
190 |
public void itemStateChanged(ItemEvent e) { |
191 |
if (e.getSource() == orButton && e.getStateChange() == ItemEvent.DESELECTED) { |
192 |
for (Iterator i = orElements.iterator(); i.hasNext();) { |
193 |
AbstractButton button = (AbstractButton)i.next(); |
194 |
button.setSelected(false); |
195 |
} |
196 |
} else if (e.getStateChange() == ItemEvent.SELECTED) { |
197 |
setSelected(((AbstractButton)e.getSource()).getModel(), true); |
198 |
} |
199 |
} |
200 |
|
201 |
public void addOr(AbstractButton button) { |
202 |
orElements.add(button); |
203 |
button.addItemListener(this); |
204 |
} |
205 |
|
206 |
public void setSelected(ButtonModel model, boolean selected) { |
207 |
for (Iterator i = orElements.iterator(); i.hasNext();) { |
208 |
AbstractButton button = (AbstractButton)i.next(); |
209 |
if (button.getModel() == model) { |
210 |
orButton.setSelected(selected); |
211 |
return; |
212 |
} |
213 |
} |
214 |
super.setSelected(model, selected); |
215 |
} |
216 |
} |
217 |
|
218 |
private JPopupMenu createPopupMenu() { |
219 |
JPopupMenu popupMenu = mf.createJMenu("PopupMenu").getPopupMenu(); |
220 |
return popupMenu; |
221 |
} |
222 |
|
223 |
public JDialog createDialog(Component owner, String title) { |
224 |
JDialog dialog = new JDialog(JOptionPane.getFrameForComponent(owner), |
225 |
title); |
226 |
dialog.getContentPane().add(this, BorderLayout.CENTER); |
227 |
dialog.pack(); |
228 |
return dialog; |
229 |
} |
230 |
|
231 |
public void add(Throwable th, String uri, int type) { |
232 |
ErrorButton errorButton = new ErrorButton(th, uri, type); |
233 |
errorButton.setPopupMenu(popupMenu); |
234 |
consoleList.add(errorButton); |
235 |
errorGroup.add(errorButton); |
236 |
} |
237 |
|
238 |
/** |
239 |
* The map that contains the actions |
240 |
*/ |
241 |
protected Map actions = new HashMap(); |
242 |
|
243 |
/** |
244 |
* Returns the action associated with the given string or null on error |
245 |
* |
246 |
* @param key |
247 |
* the key mapped with the action to get |
248 |
* @throws MissingListenerException |
249 |
* if the action is not found |
250 |
*/ |
251 |
public Action getAction(String key) throws MissingListenerException { |
252 |
return (Action) actions.get(key); |
253 |
} |
254 |
|
255 |
/** |
256 |
* The action associated with the 'All' button. |
257 |
*/ |
258 |
protected class DisplayAllButtonAction extends AbstractAction { |
259 |
|
260 |
public void actionPerformed(ActionEvent evt) { |
261 |
displayType(-1, true); |
262 |
} |
263 |
} |
264 |
|
265 |
/** |
266 |
* The action associated with the 'Errors' button. |
267 |
*/ |
268 |
protected class DisplayErrorsButtonAction extends AbstractAction { |
269 |
|
270 |
public void actionPerformed(ActionEvent evt) { |
271 |
boolean selected = ((AbstractButton)evt.getSource()).isSelected(); |
272 |
displayType(JOptionPane.ERROR_MESSAGE, selected); |
273 |
} |
274 |
} |
275 |
|
276 |
/** |
277 |
* The action associated with the 'Warnings' button. |
278 |
*/ |
279 |
protected class DisplayWarningsButtonAction extends AbstractAction { |
280 |
|
281 |
public void actionPerformed(ActionEvent evt) { |
282 |
boolean selected = ((AbstractButton)evt.getSource()).isSelected(); |
283 |
displayType(JOptionPane.WARNING_MESSAGE, selected); |
284 |
} |
285 |
} |
286 |
|
287 |
/** |
288 |
* The action associated with the 'Messages' button. |
289 |
*/ |
290 |
protected class DisplayMessagesButtonAction extends AbstractAction { |
291 |
|
292 |
public void actionPerformed(ActionEvent evt) { |
293 |
boolean selected = ((AbstractButton)evt.getSource()).isSelected(); |
294 |
displayType(JOptionPane.INFORMATION_MESSAGE, selected); |
295 |
} |
296 |
} |
297 |
|
298 |
/** |
299 |
* The action associated with the 'Clear' button. |
300 |
*/ |
301 |
protected class ClearButtonAction extends AbstractAction { |
302 |
|
303 |
public void actionPerformed(ActionEvent evt) { |
304 |
clearType(displayType); |
305 |
Enumeration<AbstractButton> buttons = errorGroup.getElements(); |
306 |
while (buttons.hasMoreElements()) { |
307 |
errorGroup.remove(buttons.nextElement()); |
308 |
} |
309 |
} |
310 |
} |
311 |
|
312 |
/** |
313 |
* The action associated with the 'First to Last Sort' menu item. |
314 |
*/ |
315 |
protected class FirstLastSortMenuAction extends AbstractAction { |
316 |
|
317 |
public void actionPerformed(ActionEvent evt) { |
318 |
if (sortOrderAscending) { |
319 |
return; |
320 |
} |
321 |
reverseComponentOrder(consoleList); |
322 |
sortOrderAscending = true; |
323 |
} |
324 |
} |
325 |
|
326 |
/** |
327 |
* The action associated with the 'Last to First Sort' menu item. |
328 |
*/ |
329 |
protected class LastFirstSortMenuAction extends AbstractAction { |
330 |
|
331 |
public void actionPerformed(ActionEvent evt) { |
332 |
if (!sortOrderAscending) { |
333 |
return; |
334 |
} |
335 |
reverseComponentOrder(consoleList); |
336 |
sortOrderAscending = false; |
337 |
} |
338 |
} |
339 |
|
340 |
private void reverseComponentOrder(Container container) { |
341 |
Component[] components = container.getComponents(); |
342 |
consoleList.removeAll(); |
343 |
for (int i = components.length - 1; i >= 0; i--) { |
344 |
consoleList.add(components[i]); |
345 |
} |
346 |
} |
347 |
|
348 |
/** |
349 |
* The action associated with the 'Copy' menu item. |
350 |
*/ |
351 |
protected class CopyMenuAction extends AbstractAction { |
352 |
|
353 |
public void actionPerformed(ActionEvent evt) { |
354 |
|
355 |
} |
356 |
} |
357 |
|
358 |
private void clearType(int type) { |
359 |
Component[] components = consoleList.getComponents(); |
360 |
for (int i = 0; i < components.length; i++) { |
361 |
ErrorButton eb = (ErrorButton) components[i]; |
362 |
if (type < 0 || eb.getType() == type) { |
363 |
consoleList.remove(eb); |
364 |
} |
365 |
} |
366 |
} |
367 |
|
368 |
private void displayType(int type, boolean visible) { |
369 |
displayType = type; |
370 |
Component[] components = consoleList.getComponents(); |
371 |
for (Component c : components) { |
372 |
ErrorButton eb = (ErrorButton) c; |
373 |
if (type < 0 || (eb.getType() == type)) { |
374 |
eb.setVisible(visible); |
375 |
} |
376 |
} |
377 |
} |
378 |
|
379 |
private class ErrorButton extends JToggleButton { |
380 |
|
381 |
private int type; |
382 |
|
383 |
private JTextPane textPane; |
384 |
|
385 |
private Hyperlink link; |
386 |
|
387 |
private ImageIcon icon; |
388 |
|
389 |
private GradientPaint gradient; |
390 |
|
391 |
private JPanel details; |
392 |
|
393 |
private JPopupMenu popupMenu; |
394 |
|
395 |
private ItemListener il = new ItemListener() { |
396 |
public void itemStateChanged(ItemEvent e) { |
397 |
if (e.getStateChange() == ItemEvent.SELECTED) { |
398 |
details.setVisible(true); |
399 |
} else if (e.getStateChange() == ItemEvent.DESELECTED) { |
400 |
details.setVisible(false); |
401 |
} else { |
402 |
return; |
403 |
} |
404 |
repaint(); |
405 |
} |
406 |
}; |
407 |
|
408 |
private MouseListener ml = new MouseAdapter() { |
409 |
public void mouseClicked(MouseEvent e) { |
410 |
if (e.getButton() == MouseEvent.BUTTON3) { |
411 |
popupMenu.show(ErrorButton.this, e.getX(), e.getY()); |
412 |
} |
413 |
} |
414 |
}; |
415 |
|
416 |
public ErrorButton(Throwable th, String uri, int type) { |
417 |
this.type = type; |
418 |
|
419 |
setLayout(new BorderLayout(10, 10)); |
420 |
setContentAreaFilled(false); |
421 |
setBorderPainted(false); |
422 |
setOpaque(false); |
423 |
setFocusPainted(false); |
424 |
setBorder(BorderFactory.createEmptyBorder(10, 10, 10, 10)); |
425 |
addItemListener(il); |
426 |
addMouseListener(ml); |
427 |
|
428 |
String s; |
429 |
switch (type) { |
430 |
case JOptionPane.WARNING_MESSAGE: |
431 |
s = resources.getString("ErrorButton.warning_icon"); |
432 |
break; |
433 |
case JOptionPane.INFORMATION_MESSAGE: |
434 |
s = resources.getString("ErrorButton.message_icon"); |
435 |
break; |
436 |
case JOptionPane.ERROR_MESSAGE: |
437 |
default: |
438 |
s = resources.getString("ErrorButton.error_icon"); |
439 |
break; |
440 |
} |
441 |
icon = new ImageIcon(getClass().getResource(s)); |
442 |
add(new JLabel(icon), BorderLayout.WEST); |
443 |
|
444 |
Box centerPane = new Box(BoxLayout.Y_AXIS); |
445 |
add(centerPane); |
446 |
|
447 |
textPane = new JTextPane(); |
448 |
textPane.setText(th.getMessage()); |
449 |
textPane.setEditable(false); |
450 |
textPane.setOpaque(false); |
451 |
textPane.addMouseListener(new MouseAdapter() { |
452 |
public void mouseClicked(MouseEvent e) { |
453 |
ErrorButton.this.setSelected(true); |
454 |
} |
455 |
}); |
456 |
centerPane.add(textPane, BorderLayout.NORTH); |
457 |
|
458 |
if (uri != null) { |
459 |
link = new Hyperlink(uri, |
460 |
new Hyperlink.HyperlinkCallback() { |
461 |
public void linkClicked(HyperlinkEvent e) { |
462 |
// new DocumentViewer(doc).setVisible(true); |
463 |
} |
464 |
}); |
465 |
centerPane.add(link, BorderLayout.SOUTH); |
466 |
} |
467 |
|
468 |
details = new JPanel(new BorderLayout()); |
469 |
details.setOpaque(false); |
470 |
details.setVisible(false); |
471 |
add(details, BorderLayout.SOUTH); |
472 |
|
473 |
StringWriter sw = new StringWriter(); |
474 |
th.printStackTrace(new PrintWriter(sw)); |
475 |
sw.flush(); |
476 |
|
477 |
JTextArea stackTraceText = new JTextArea(sw.toString()); |
478 |
final JScrollPane stackTraceScrollPane = new JScrollPane( |
479 |
stackTraceText); |
480 |
stackTraceScrollPane.setVisible(false); |
481 |
final JButton btnShowDetails = new JButton("Show Details >>"); |
482 |
btnShowDetails.addActionListener(new ActionListener() { |
483 |
public void actionPerformed(ActionEvent e) { |
484 |
boolean visible = stackTraceScrollPane.isVisible(); |
485 |
stackTraceScrollPane.setVisible(!visible); |
486 |
btnShowDetails.setText(visible ? "Show Details >>" |
487 |
: "<< Hide Details"); |
488 |
} |
489 |
}); |
490 |
JPanel button = new JPanel(new FlowLayout(FlowLayout.LEADING)); |
491 |
button.setOpaque(false); |
492 |
button.add(btnShowDetails); |
493 |
details.add(button, BorderLayout.NORTH); |
494 |
details.add(stackTraceScrollPane); |
495 |
|
496 |
Dimension dim = getPreferredSize(); |
497 |
gradient = new GradientPaint(0, 0, new Color(217, 226, 234), 0, |
498 |
2 * dim.height, new Color(193, 207, 221)); |
499 |
|
500 |
} |
501 |
|
502 |
public void paintComponent(Graphics g) { |
503 |
Graphics2D g2 = (Graphics2D) g; |
504 |
int width = getWidth(), height = getHeight(); |
505 |
g2.setPaint(isSelected() ? gradient : Color.white); |
506 |
g2.fillRect(0, 0, width, height); |
507 |
g2.setColor(SystemColor.controlShadow); |
508 |
g2.drawLine(0, height - 1, width, height - 1); |
509 |
super.paintComponent(g); |
510 |
} |
511 |
|
512 |
public int getType() { |
513 |
return type; |
514 |
} |
515 |
|
516 |
public void setType(int type) { |
517 |
this.type = type; |
518 |
repaint(); |
519 |
} |
520 |
|
521 |
public JPopupMenu getPopupMenu() { |
522 |
return popupMenu; |
523 |
} |
524 |
|
525 |
public void setPopupMenu(JPopupMenu popupMenu) { |
526 |
this.popupMenu = popupMenu; |
527 |
} |
528 |
} |
529 |
|
530 |
public static void main(String[] args) { |
531 |
ErrorConsole ec = new ErrorConsole(new Exception("Test Exception"), |
532 |
JOptionPane.ERROR_MESSAGE); |
533 |
ec.add(new Exception("Test Exception"), null, JOptionPane.WARNING_MESSAGE); |
534 |
ec.add(new Exception("Test Exception"), null, JOptionPane.INFORMATION_MESSAGE); |
535 |
JDialog d = ec.createDialog(null, |
536 |
"Error Console 0.1"); |
537 |
d.setDefaultCloseOperation(JDialog.DISPOSE_ON_CLOSE); |
538 |
d.setVisible(true); |
539 |
} |
540 |
} |