1
2
3
4
5
6
7 package nl.tudelft.simulation.logger.gui;
8
9 import java.awt.BorderLayout;
10 import java.awt.Color;
11 import java.awt.Dimension;
12 import java.awt.event.ActionEvent;
13 import java.awt.event.ActionListener;
14 import java.util.logging.Handler;
15 import java.util.logging.Level;
16 import java.util.logging.Logger;
17
18 import javax.swing.BorderFactory;
19 import javax.swing.BoxLayout;
20 import javax.swing.JButton;
21 import javax.swing.JCheckBox;
22 import javax.swing.JComboBox;
23 import javax.swing.JOptionPane;
24 import javax.swing.JPanel;
25 import javax.swing.JScrollPane;
26 import javax.swing.JTextField;
27 import javax.swing.JTextPane;
28 import javax.swing.ScrollPaneConstants;
29 import javax.swing.text.BadLocationException;
30 import javax.swing.text.Document;
31 import javax.swing.text.Style;
32 import javax.swing.text.StyleConstants;
33
34 import nl.tudelft.simulation.event.EventInterface;
35 import nl.tudelft.simulation.event.EventListenerInterface;
36 import nl.tudelft.simulation.logger.formatters.StyledTextFormatter;
37 import nl.tudelft.simulation.logger.handlers.EventLogHandler;
38 import nl.tudelft.simulation.logger.handlers.MemoryHandler;
39
40 /***
41 * A LogPanel <br>
42 * (c) copyright 2002-2005 <a href="http://www.simulation.tudelft.nl">Delft
43 * University of Technology </a>, the Netherlands. <br>
44 * See for project information <a
45 * href="http://www.simulation.tudelft.nl">www.simulation.tudelft.nl </a> <br>
46 * License of use: <a href="http://www.gnu.org/copyleft/lesser.html">Lesser
47 * General Public License (LGPL) </a>, no warranty.
48 *
49 * @version $Revision: 1.7 $ $Date: 2005/08/04 12:09:00 $
50 * @author <a href="http://www.peter-jacobs.com">Peter Jacobs </a>,, <a
51 * href="mailto:nlang@fbk.eur.nl">Niels Lang </a>
52 */
53 public class LogPanel extends JPanel implements EventListenerInterface
54 {
55
56 /*** the maximum number of records to show */
57 private int bufferSize = 10000;
58
59 /*** the logger to display */
60 private Logger logger = null;
61
62 /*** the handler for this panel */
63 private EventLogHandler handler = null;
64
65 /*** defines whether we clean automatically */
66 private JCheckBox autoCheck = null;
67
68 /*** the textPane */
69 private JTextPane textPane = new JTextPane();
70
71 /*** counts the row number */
72 private int row = 0;
73
74 /***
75 * constructs a new LogPanel
76 *
77 * @param logger the logger to show
78 */
79 public LogPanel(final Logger logger)
80 {
81 super();
82 this.logger = logger;
83 this.initializePanel();
84 this.initializeLogger();
85 }
86
87 /***
88 * @see java.lang.Object#finalize()
89 */
90 @Override
91 public synchronized void finalize()
92 {
93 if (this.handler != null)
94 {
95 Handler[] handlers = this.logger.getHandlers();
96 if (handlers.length == 1)
97 {
98 this.logger.addHandler(new MemoryHandler());
99 }
100 this.logger.removeHandler(this.handler);
101 }
102 }
103
104 /***
105 * gets bufferSize
106 *
107 * @return Returns the bufferSize.
108 */
109 public int getBufferSize()
110 {
111 return this.bufferSize;
112 }
113
114 /***
115 * @see nl.tudelft.simulation.event.EventListenerInterface
116 * #notify(nl.tudelft.simulation.event.EventInterface)
117 */
118 public void notify(final EventInterface event)
119 {
120 if (!event.getType().equals(EventLogHandler.LOG_RECORD_PRODUCED_EVENT))
121 {
122 return;
123 }
124 try
125 {
126 synchronized (this.textPane.getDocument())
127 {
128 this.row++;
129 Record[] records = this.constructMessage((String) event
130 .getContent());
131 for (int i = records.length - 1; i > -1; i--)
132 {
133 this.textPane.getDocument().insertString(0,
134 records[i].getMessage(), records[i].getStyle());
135 }
136 this.textPane.getDocument().insertString(0,
137 "(" + this.row + ") ", records[0].getStyle());
138 if (this.autoCheck.isSelected()
139 && this.textPane.getDocument().getLength() > this.bufferSize)
140 {
141 this.textPane.getDocument().remove(
142 this.bufferSize,
143 this.textPane.getDocument().getLength()
144 - this.bufferSize);
145 }
146 }
147 } catch (Exception exception)
148 {
149 exception.printStackTrace();
150 }
151 }
152
153 /***
154 * sets the bufferSize
155 *
156 * @param bufferSize The bufferSize to set.
157 */
158 public void setBufferSize(final int bufferSize)
159 {
160 this.bufferSize = bufferSize;
161 }
162
163 /*** *************** PRIVATE METHODS ************************* */
164
165 /***
166 * creates a clearPanel
167 *
168 * @return the clearPanel
169 */
170 private JPanel createClearPanel()
171 {
172 JPanel result = new JPanel();
173
174 JPanel bufferSizePanel = new JPanel();
175 bufferSizePanel.setLayout(new BoxLayout(bufferSizePanel,
176 BoxLayout.X_AXIS));
177 bufferSizePanel.setBorder(BorderFactory
178 .createTitledBorder("LogPanel settings"));
179 JButton clearButton = new JButton("Clear");
180 clearButton.addActionListener(new DocumentCleaner(this.textPane
181 .getDocument()));
182 this.autoCheck = new JCheckBox("auto", true);
183 this.autoCheck.setPreferredSize(new Dimension(75, 1));
184 JTextField clearText = new JTextField("" + this.bufferSize);
185 clearText.setEditable(false);
186 clearText.setPreferredSize(new Dimension(80, 20));
187 JButton updateSize = new JButton("Change max buffer-size");
188 updateSize.addActionListener(new ChangeBufferSizeListener(this,
189 clearText));
190 bufferSizePanel.add(clearButton);
191 bufferSizePanel.add(this.autoCheck);
192 bufferSizePanel.add(clearText);
193 bufferSizePanel.add(updateSize);
194 result.add(bufferSizePanel, BorderLayout.CENTER);
195 return result;
196 }
197
198 /***
199 * returns the message as an array of
200 *
201 * @param styledMessage the message
202 * @return Record[] the record
203 */
204 private Record[] constructMessage(final String styledMessage)
205 {
206 String[] records = styledMessage.split(StyledTextFormatter.SEPARATOR);
207 Record[] result = new Record[records.length];
208 for (int i = 0; i < records.length; i++)
209 {
210 result[i] = this.constructRecord(records[i]);
211 }
212 return result;
213 }
214
215 /***
216 * constructs a styledRecord
217 *
218 * @param styledRecord the styled message
219 * @return Record the record
220 */
221 private Record constructRecord(final String styledRecord)
222 {
223 if (styledRecord.startsWith("<" + StyledTextFormatter.STYLE_DEFAULT
224 + ">")
225 && styledRecord.endsWith("</"
226 + StyledTextFormatter.STYLE_DEFAULT + ">"))
227 {
228 return new Record(this.constructMessage(
229 StyledTextFormatter.STYLE_DEFAULT, styledRecord),
230 this.textPane.getStyle(StyledTextFormatter.STYLE_DEFAULT));
231 }
232 if (styledRecord.startsWith("<" + StyledTextFormatter.STYLE_FINE + ">")
233 && styledRecord.endsWith("</" + StyledTextFormatter.STYLE_FINE
234 + ">"))
235 {
236 return new Record(this.constructMessage(
237 StyledTextFormatter.STYLE_FINE, styledRecord),
238 this.textPane.getStyle(StyledTextFormatter.STYLE_FINE));
239 }
240 if (styledRecord.startsWith("<" + StyledTextFormatter.STYLE_ORIGIN
241 + ">")
242 && styledRecord.endsWith("</"
243 + StyledTextFormatter.STYLE_ORIGIN + ">"))
244 {
245 return new Record(this.constructMessage(
246 StyledTextFormatter.STYLE_ORIGIN, styledRecord),
247 this.textPane.getStyle(StyledTextFormatter.STYLE_ORIGIN));
248 }
249 if (styledRecord.startsWith("<" + StyledTextFormatter.STYLE_SOURCE
250 + ">")
251 && styledRecord.endsWith("</"
252 + StyledTextFormatter.STYLE_SOURCE + ">"))
253 {
254 return new Record(this.constructMessage(
255 StyledTextFormatter.STYLE_SOURCE, styledRecord),
256 this.textPane.getStyle(StyledTextFormatter.STYLE_SOURCE));
257 }
258 if (styledRecord.startsWith("<" + StyledTextFormatter.STYLE_WARNING
259 + ">")
260 && styledRecord.endsWith("</"
261 + StyledTextFormatter.STYLE_WARNING + ">"))
262 {
263 return new Record(this.constructMessage(
264 StyledTextFormatter.STYLE_WARNING, styledRecord),
265 this.textPane.getStyle(StyledTextFormatter.STYLE_WARNING));
266 }
267 return null;
268 }
269
270 /***
271 * regenerates the message from the record
272 *
273 * @param tag the used tag
274 * @param message the message
275 * @return String the message
276 */
277 private String constructMessage(final String tag, final String message)
278 {
279 return message.substring(new String("<" + tag + ">").length(), message
280 .length()
281 - new String("</" + tag + ">").length());
282 }
283
284 /***
285 * initializes the logger
286 */
287 private void initializeLogger()
288 {
289 this.handler = new EventLogHandler();
290 this.handler.setFormatter(new StyledTextFormatter(true));
291 this.handler.addListener(this,
292 EventLogHandler.LOG_RECORD_PRODUCED_EVENT);
293 this.logger.addHandler(this.handler);
294 Handler[] handlers = this.logger.getHandlers();
295 for (int i = 0; i < handlers.length; i++)
296 {
297 if (handlers[i] instanceof MemoryHandler)
298 {
299 ((MemoryHandler) handlers[i]).push(this.handler);
300 this.logger.removeHandler(handlers[i]);
301 }
302 }
303 }
304
305 /***
306 * initializes the panel
307 */
308 private void initializePanel()
309 {
310 this.textPane.setEditable(false);
311 this.setOpaque(true);
312 this.setPreferredSize(new Dimension(500, 500));
313 this.setLayout(new BorderLayout());
314
315 this.add(new JScrollPane(this.textPane,
316 ScrollPaneConstants.VERTICAL_SCROLLBAR_ALWAYS,
317 ScrollPaneConstants.HORIZONTAL_SCROLLBAR_AS_NEEDED),
318 BorderLayout.CENTER);
319
320 JComboBox levelChooser = new JComboBox(new Level[] { Level.ALL,
321 Level.SEVERE, Level.WARNING, Level.INFO, Level.CONFIG,
322 Level.FINE, Level.FINER, Level.FINEST, Level.OFF });
323 levelChooser.setSelectedItem(this.logger.getLevel());
324 levelChooser.addActionListener(new MyLevelChooser(this.logger,
325 levelChooser));
326 this.add(levelChooser, BorderLayout.NORTH);
327 this.add(this.createClearPanel(), BorderLayout.SOUTH);
328 this.initStyles();
329 }
330
331 /***
332 * initializes the styles
333 */
334 private void initStyles()
335 {
336 Style defaultStyle = this.textPane.addStyle(
337 StyledTextFormatter.STYLE_DEFAULT, null);
338
339 Style sourceStyle = this.textPane.addStyle(
340 StyledTextFormatter.STYLE_SOURCE, defaultStyle);
341 StyleConstants.setForeground(sourceStyle, Color.BLUE);
342
343 Style warningStyle = this.textPane.addStyle(
344 StyledTextFormatter.STYLE_WARNING, defaultStyle);
345 StyleConstants.setForeground(warningStyle, Color.RED);
346
347 Style fineStyle = this.textPane.addStyle(
348 StyledTextFormatter.STYLE_FINE, defaultStyle);
349 StyleConstants.setForeground(fineStyle, Color.GREEN);
350
351 Style originStyle = this.textPane.addStyle(
352 StyledTextFormatter.STYLE_ORIGIN, defaultStyle);
353 StyleConstants.setForeground(originStyle, Color.GRAY);
354 }
355
356 /***
357 * The ChangeMaxRecordListener
358 */
359 private class MyLevelChooser implements ActionListener
360 {
361 /*** the owner */
362 private Logger logger = null;
363
364 /*** the owner */
365 private JComboBox owner = null;
366
367 /***
368 * constructs a new logPanel
369 *
370 * @param logger the logger
371 * @param owner the owner
372 */
373 public MyLevelChooser(final Logger logger, final JComboBox owner)
374 {
375 this.logger = logger;
376 this.owner = owner;
377 }
378
379 /***
380 * @see java.awt.event.ActionListener#actionPerformed(java.awt.event.ActionEvent)
381 */
382 public void actionPerformed(final ActionEvent actionEvent)
383 {
384 if (actionEvent.getSource() != null)
385 {
386 this.logger.setLevel((Level) this.owner.getSelectedItem());
387 }
388 }
389 }
390
391 /***
392 * The ChangeBufferSizeListener
393 */
394 private class ChangeBufferSizeListener implements ActionListener
395 {
396 /*** the owner */
397 private LogPanel owner = null;
398
399 /*** the textField */
400 private JTextField textField = null;
401
402 /***
403 * constructs a new logPanel
404 *
405 * @param logPanel the logPanel
406 * @param textField the textField
407 */
408 public ChangeBufferSizeListener(final LogPanel logPanel,
409 final JTextField textField)
410 {
411 this.owner = logPanel;
412 this.textField = textField;
413 }
414
415 /***
416 * @see java.awt.event.ActionListener
417 * #actionPerformed(java.awt.event.ActionEvent)
418 */
419 public void actionPerformed(final ActionEvent actionEvent)
420 {
421 if (actionEvent == null)
422 {
423 nl.tudelft.simulation.logger.Logger.warning(this,
424 "actionPerformed", "actionEvent=null");
425 }
426 String result = JOptionPane
427 .showInputDialog("Enter desired buffersize (integer)");
428 if (result != null)
429 {
430 try
431 {
432 int value = (int) Math.round(Double.parseDouble(result));
433 if (value <= 0.0)
434 {
435 throw new IllegalArgumentException();
436 }
437 this.owner.setBufferSize(value);
438 this.textField.setText(value + "");
439 } catch (Exception exception)
440 {
441 try
442 {
443 JOptionPane.showMessageDialog(null, "Invalid input: "
444 + result
445 + ". value should be long and larger than 0");
446 } catch (Exception remoteException)
447 {
448 nl.tudelft.simulation.logger.Logger.warning(this,
449 "actionPerformed", remoteException);
450 }
451 }
452 }
453 }
454 }
455
456 /***
457 * A DocumentCleaner
458 */
459 private class DocumentCleaner implements ActionListener
460 {
461 /*** the document to clean */
462 private Document document = null;
463
464 /***
465 * creates a new DocumentCleanner
466 *
467 * @param document the document
468 */
469 public DocumentCleaner(final Document document)
470 {
471 this.document = document;
472 }
473
474 /***
475 * @see java.awt.event.ActionListener
476 * #actionPerformed(java.awt.event.ActionEvent)
477 */
478 public void actionPerformed(final ActionEvent actionEvent)
479 {
480 if (actionEvent == null)
481 {
482 nl.tudelft.simulation.logger.Logger.warning(this,
483 "actionPerformed", "actionEvent=null");
484 }
485 synchronized (this.document)
486 {
487 try
488 {
489 this.document.remove(0, this.document.getLength());
490 } catch (BadLocationException exception)
491 {
492 nl.tudelft.simulation.logger.Logger.warning(this,
493 "actionPerformed", exception);
494 }
495 }
496 }
497 }
498
499 /***
500 * defines a record
501 */
502 private class Record
503 {
504 /*** the message */
505 private String message;
506
507 /*** the style */
508 private Style style;
509
510 /***
511 * constructs a new Record
512 *
513 * @param message the message
514 * @param style the style
515 */
516 public Record(final String message, final Style style)
517 {
518 this.message = message;
519 this.style = style;
520 }
521
522 /***
523 * gets the message
524 *
525 * @return String message
526 */
527 public String getMessage()
528 {
529 return this.message;
530 }
531
532 /***
533 * gets the style
534 *
535 * @return style
536 */
537 public Style getStyle()
538 {
539 return this.style;
540 }
541 }
542 }