View Javadoc

1   /*
2    * @(#) LogPanel.java Nov 18, 2003 Copyright (c) 2002-2005 Delft University of
3    * Technology Jaffalaan 5, 2628 BX Delft, the Netherlands. All rights reserved.
4    * This software is proprietary information of Delft University of Technology
5    * The code is published under the Lesser General Public License
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 }