View Javadoc

    1   /*
    2    * Licensed to the Apache Software Foundation (ASF) under one or more
    3    * contributor license agreements.  See the NOTICE file distributed with
    4    * this work for additional information regarding copyright ownership.
    5    * The ASF licenses this file to You under the Apache License, Version 2.0
    6    * (the "License"); you may not use this file except in compliance with
    7    * the License.  You may obtain a copy of the License at
    8    *
    9    *      http://www.apache.org/licenses/LICENSE-2.0
    10   *
    11   * Unless required by applicable law or agreed to in writing, software
    12   * distributed under the License is distributed on an "AS IS" BASIS,
    13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    14   * See the License for the specific language governing permissions and
    15   * limitations under the License.
    16   */
    17
    18  package org.apache.log4j.chainsaw.messages;
    19
    20  import java.awt.BorderLayout;
    21  import java.awt.Component;
    22  import java.awt.event.ActionEvent;
    23  import java.beans.PropertyChangeEvent;
    24  import java.beans.PropertyChangeListener;
    25  import java.beans.PropertyChangeSupport;
    26
    27  import javax.swing.AbstractAction;
    28  import javax.swing.Action;
    29  import javax.swing.DefaultListCellRenderer;
    30  import javax.swing.ImageIcon;
    31  import javax.swing.JButton;
    32  import javax.swing.JComponent;
    33  import javax.swing.JList;
    34  import javax.swing.JPanel;
    35  import javax.swing.JPopupMenu;
    36  import javax.swing.JScrollPane;
    37  import javax.swing.JToolBar;
    38  import javax.swing.ListCellRenderer;
    39  import javax.swing.ListModel;
    40  import javax.swing.event.ListDataEvent;
    41  import javax.swing.event.ListDataListener;
    42
    43  import org.apache.log4j.Layout;
    44  import org.apache.log4j.Level;
    45  import org.apache.log4j.Logger;
    46  import org.apache.log4j.TTCCLayout;
    47  import org.apache.log4j.chainsaw.ChainsawConstants;
    48  import org.apache.log4j.chainsaw.LoggingEventWrapper;
    49  import org.apache.log4j.chainsaw.PopupListener;
    50  import org.apache.log4j.chainsaw.SmallButton;
    51  import org.apache.log4j.chainsaw.icons.ChainsawIcons;
    52  import org.apache.log4j.varia.ListModelAppender;
    53
    54
    55  /**
    56   * The MessageCenter is central place for all elements within Chainsaw to
    57   * notify the user of important information.
    58   *
    59   * This class uses log4j itself quite significantly.  All user message
    60   * are sent to this classes log4j Logger (org.apache.log4j.chainsaw.message.MessageCenter).
    61   *
    62   * To register a message with the user, you can use the addMessage(String) style methods on
    63   * this class, or just as easily, get a handle to this class' logger, and log
    64   * it as you would normally do.
    65   *
    66   * All events to this logger are trapped within a Custom appender (additivity
    67   * will be switched OFF), which stores the events in a ListModel.
    68   *
    69   * You can invoke the setVisible() method to display all the messages
    70   *
    71   * @author Paul Smith &lt;psmith@apache.org&gt;
    72   *
    73   */
    74  public class MessageCenter {
    75    private static final MessageCenter instance = new MessageCenter();
    76    private final Logger logger = Logger.getLogger(MessageCenter.class);
    77    private Layout layout = new TTCCLayout();
    78    private final JList messageList = new JList();
    79    private final ListModelAppender appender = new ListModelAppender();
    80    private ListCellRenderer listCellRenderer =
    81      new LayoutListCellRenderer(layout);
    82    private PropertyChangeSupport propertySupport =
    83      new PropertyChangeSupport(this);
    84    private JScrollPane pane = new JScrollPane(messageList);
    85    private final JToolBar toolbar = new JToolBar();
    86    private JPopupMenu popupMenu = new JPopupMenu();
    87    private PopupListener popupListener = new PopupListener(popupMenu);
    88    private Action clearAction;
    89    private final JPanel componentPanel = new JPanel(new BorderLayout());
    90
    91    private MessageCenter() {
    92      setupActions();
    93      setupComponentPanel();
    94      setupLogger();
    95      setupListeners();
    96      setupPopMenu();
    97      setupToolbar();
    98    }
    99
    100   /**
    101    *
    102    */
    103   private void setupPopMenu() {
    104     popupMenu.add(clearAction);
    105   }
    106
    107   /**
    108    *
    109    */
    110   private void setupToolbar() {
    111     JButton clearButton = new SmallButton(clearAction);
    112     clearButton.setText(null);
    113     toolbar.add(clearButton);
    114
    115     toolbar.setFloatable(false);
    116   }
    117
    118   private void setupActions() {
    119     clearAction =
    120       new AbstractAction("Clear") {
    121           public void actionPerformed(ActionEvent e) {
    122             appender.clearModel();
    123           }
    124         };
    125     clearAction.putValue(
    126       Action.SMALL_ICON, new ImageIcon(ChainsawIcons.DELETE));
    127   }
    128
    129   private void setupListeners() {
    130     propertySupport.addPropertyChangeListener(
    131       "layout",
    132       new PropertyChangeListener() {
    133         public void propertyChange(PropertyChangeEvent evt) {
    134           Layout newLayout = (Layout) evt.getNewValue();
    135           messageList.setCellRenderer(new LayoutListCellRenderer(newLayout));
    136         }
    137       });
    138     messageList.addMouseListener(popupListener);
    139
    140     appender.getModel().addListDataListener(
    141       new ListDataListener() {
    142         public void contentsChanged(ListDataEvent e) {
    143           updateActions();
    144         }
    145
    146         public void intervalAdded(ListDataEvent e) {
    147           updateActions();
    148         }
    149
    150         public void intervalRemoved(ListDataEvent e) {
    151           updateActions();
    152         }
    153       });
    154   }
    155
    156   /**
    157    *
    158    */
    159   private void updateActions() {
    160     clearAction.putValue(
    161       "enabled",
    162       (appender.getModel().getSize() > 0) ? Boolean.TRUE : Boolean.FALSE);
    163   }
    164
    165   private void setupLogger() {
    166     logger.addAppender(appender);
    167     logger.setAdditivity(true);
    168     logger.setLevel(Boolean.getBoolean("log4j.debug")?Level.DEBUG:Level.INFO);
    169   }
    170
    171   private void setupComponentPanel() {
    172     messageList.setModel(appender.getModel());
    173     messageList.setCellRenderer(listCellRenderer);
    174
    175     componentPanel.add(this.toolbar, BorderLayout.NORTH);
    176     componentPanel.add(this.pane, BorderLayout.CENTER);
    177   }
    178
    179   public final JComponent getGUIComponent() {
    180     return componentPanel;
    181   }
    182
    183   public ListModel getModel() {
    184     return messageList.getModel();
    185   }
    186
    187   public static MessageCenter getInstance() {
    188     return instance;
    189   }
    190
    191   public void addMessage(String message) {
    192     logger.info(message);
    193   }
    194
    195
    196   /**
    197    * @return Returns the layout used by the MessageCenter.
    198    */
    199   public final Layout getLayout() {
    200     return layout;
    201   }
    202
    203   /**
    204    * @param layout Sets the layout to be used by the MessageCenter .
    205    */
    206   public final void setLayout(Layout layout) {
    207     Layout oldValue = this.layout;
    208     this.layout = layout;
    209     propertySupport.firePropertyChange("layout", oldValue, this.layout);
    210   }
    211
    212   /**
    213    * Returns the logger that can be used to log
    214    * messages to display within the Message Center.
    215    * @return logger
    216    */
    217   public final Logger getLogger() {
    218     return this.logger;
    219   }
    220
    221   /**
    222    * This class simply renders an event by delegating the effort to a
    223    * Log4j layout instance.
    224    *
    225    * @author Paul Smith &lt;psmith@apache.org&gt;
    226    */
    227   private static class LayoutListCellRenderer extends DefaultListCellRenderer {
    228     private Layout layout;
    229
    230     /**
    231      * @param layout
    232      */
    233     public LayoutListCellRenderer(Layout layout) {
    234       super();
    235       this.layout = layout;
    236     }
    237
    238     /* (non-Javadoc)
    239      * @see javax.swing.ListCellRenderer#getListCellRendererComponent(javax.swing.JList, java.lang.Object, int, boolean, boolean)
    240      */
    241     public Component getListCellRendererComponent(
    242       JList list, Object value, int index, boolean isSelected,
    243       boolean cellHasFocus) {
    244       value = layout.format(((LoggingEventWrapper) value).getLoggingEvent());
    245
    246       Component c =
    247         super.getListCellRendererComponent(
    248           list, value, index, isSelected, cellHasFocus);
    249       c.setBackground(
    250         ((index % 2) == 0) ? ChainsawConstants.COLOR_EVEN_ROW_BACKGROUND
    251                            : ChainsawConstants.COLOR_ODD_ROW_BACKGROUND);
    252
    253       return c;
    254     }
    255   }
    256 }