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  package org.apache.log4j.lf5.viewer;
    18
    19  import java.awt.BorderLayout;
    20  import java.awt.Color;
    21  import java.awt.Component;
    22  import java.awt.Dimension;
    23  import java.awt.FlowLayout;
    24  import java.awt.Font;
    25  import java.awt.GraphicsEnvironment;
    26  import java.awt.Toolkit;
    27  import java.awt.event.ActionEvent;
    28  import java.awt.event.ActionListener;
    29  import java.awt.event.WindowAdapter;
    30  import java.awt.event.WindowEvent;
    31  import java.io.File;
    32  import java.io.IOException;
    33  import java.io.InputStream;
    34  import java.net.MalformedURLException;
    35  import java.net.URL;
    36  import java.util.ArrayList;
    37  import java.util.HashMap;
    38  import java.util.Iterator;
    39  import java.util.List;
    40  import java.util.Map;
    41  import java.util.StringTokenizer;
    42  import java.util.Vector;
    43
    44  import javax.swing.BorderFactory;
    45  import javax.swing.ImageIcon;
    46  import javax.swing.JButton;
    47  import javax.swing.JCheckBoxMenuItem;
    48  import javax.swing.JColorChooser;
    49  import javax.swing.JComboBox;
    50  import javax.swing.JFileChooser;
    51  import javax.swing.JFrame;
    52  import javax.swing.JLabel;
    53  import javax.swing.JMenu;
    54  import javax.swing.JMenuBar;
    55  import javax.swing.JMenuItem;
    56  import javax.swing.JOptionPane;
    57  import javax.swing.JPanel;
    58  import javax.swing.JScrollPane;
    59  import javax.swing.JSplitPane;
    60  import javax.swing.JTextArea;
    61  import javax.swing.JToolBar;
    62  import javax.swing.KeyStroke;
    63  import javax.swing.SwingUtilities;
    64
    65  import org.apache.log4j.lf5.LogLevel;
    66  import org.apache.log4j.lf5.LogRecord;
    67  import org.apache.log4j.lf5.LogRecordFilter;
    68  import org.apache.log4j.lf5.util.DateFormatManager;
    69  import org.apache.log4j.lf5.util.LogFileParser;
    70  import org.apache.log4j.lf5.viewer.categoryexplorer.CategoryExplorerTree;
    71  import org.apache.log4j.lf5.viewer.categoryexplorer.CategoryPath;
    72  import org.apache.log4j.lf5.viewer.configure.ConfigurationManager;
    73  import org.apache.log4j.lf5.viewer.configure.MRUFileManager;
    74
    75  /**
    76   * LogBrokerMonitor
    77   *.
    78   * @author Michael J. Sikorsky
    79   * @author Robert Shaw
    80   * @author Brad Marlborough
    81   * @author Richard Wan
    82   * @author Brent Sprecher
    83   * @author Richard Hurst
    84   */
    85
    86  // Contributed by ThoughtWorks Inc.
    87
    88  public class LogBrokerMonitor {
    89    //--------------------------------------------------------------------------
    90    //   Constants:
    91    //--------------------------------------------------------------------------
    92
    93    public static final String DETAILED_VIEW = "Detailed";
    94  //    public static final String STANDARD_VIEW = "Standard";
    95  //    public static final String COMPACT_VIEW = "Compact";
    96    //--------------------------------------------------------------------------
    97    //   Protected Variables:
    98    //--------------------------------------------------------------------------
    99    protected JFrame _logMonitorFrame;
    100   protected int _logMonitorFrameWidth = 550;
    101   protected int _logMonitorFrameHeight = 500;
    102   protected LogTable _table;
    103   protected CategoryExplorerTree _categoryExplorerTree;
    104   protected String _searchText;
    105   protected String _NDCTextFilter = "";
    106   protected LogLevel _leastSevereDisplayedLogLevel = LogLevel.DEBUG;
    107
    108   protected JScrollPane _logTableScrollPane;
    109   protected JLabel _statusLabel;
    110   protected Object _lock = new Object();
    111   protected JComboBox _fontSizeCombo;
    112
    113   protected int _fontSize = 10;
    114   protected String _fontName = "Dialog";
    115   protected String _currentView = DETAILED_VIEW;
    116
    117   protected boolean _loadSystemFonts = false;
    118   protected boolean _trackTableScrollPane = true;
    119   protected Dimension _lastTableViewportSize;
    120   protected boolean _callSystemExitOnClose = false;
    121   protected List _displayedLogBrokerProperties = new Vector();
    122
    123   protected Map _logLevelMenuItems = new HashMap();
    124   protected Map _logTableColumnMenuItems = new HashMap();
    125
    126   protected List _levels = null;
    127   protected List _columns = null;
    128   protected boolean _isDisposed = false;
    129
    130   protected ConfigurationManager _configurationManager = null;
    131   protected MRUFileManager _mruFileManager = null;
    132   protected File _fileLocation = null;
    133
    134   //--------------------------------------------------------------------------
    135   //   Private Variables:
    136   //--------------------------------------------------------------------------
    137
    138   //--------------------------------------------------------------------------
    139   //   Constructors:
    140   //--------------------------------------------------------------------------
    141
    142   /**
    143    * Construct a LogBrokerMonitor.
    144    */
    145   public LogBrokerMonitor(List logLevels) {
    146
    147     _levels = logLevels;
    148     _columns = LogTableColumn.getLogTableColumns();
    149     // This allows us to use the LogBroker in command line tools and
    150     // have the option for it to shutdown.
    151
    152     String callSystemExitOnClose =
    153         System.getProperty("monitor.exit");
    154     if (callSystemExitOnClose == null) {
    155       callSystemExitOnClose = "false";
    156     }
    157     callSystemExitOnClose = callSystemExitOnClose.trim().toLowerCase();
    158
    159     if (callSystemExitOnClose.equals("true")) {
    160       _callSystemExitOnClose = true;
    161     }
    162
    163     initComponents();
    164
    165
    166     _logMonitorFrame.addWindowListener(
    167         new LogBrokerMonitorWindowAdaptor(this));
    168
    169   }
    170
    171   //--------------------------------------------------------------------------
    172   //   Public Methods:
    173   //--------------------------------------------------------------------------
    174
    175   /**
    176    * Show the frame for the LogBrokerMonitor. Dispatched to the
    177    * swing thread.
    178    */
    179   public void show(final int delay) {
    180     if (_logMonitorFrame.isVisible()) {
    181       return;
    182     }
    183     // This request is very low priority, let other threads execute first.
    184     SwingUtilities.invokeLater(new Runnable() {
    185       public void run() {
    186         Thread.yield();
    187         pause(delay);
    188         _logMonitorFrame.setVisible(true);
    189       }
    190     });
    191   }
    192
    193   public void show() {
    194     show(0);
    195   }
    196
    197   /**
    198    * Dispose of the frame for the LogBrokerMonitor.
    199    */
    200   public void dispose() {
    201     _logMonitorFrame.dispose();
    202     _isDisposed = true;
    203
    204     if (_callSystemExitOnClose == true) {
    205       System.exit(0);
    206     }
    207   }
    208
    209   /**
    210    * Hide the frame for the LogBrokerMonitor.
    211    */
    212   public void hide() {
    213     _logMonitorFrame.setVisible(false);
    214   }
    215
    216   /**
    217    * Get the DateFormatManager for formatting dates.
    218    */
    219   public DateFormatManager getDateFormatManager() {
    220     return _table.getDateFormatManager();
    221   }
    222
    223   /**
    224    * Set the date format manager for formatting dates.
    225    */
    226   public void setDateFormatManager(DateFormatManager dfm) {
    227     _table.setDateFormatManager(dfm);
    228   }
    229
    230   /**
    231    * Get the value of whether or not System.exit() will be called
    232    * when the LogBrokerMonitor is closed.
    233    */
    234   public boolean getCallSystemExitOnClose() {
    235     return _callSystemExitOnClose;
    236   }
    237
    238   /**
    239    * Set the value of whether or not System.exit() will be called
    240    * when the LogBrokerMonitor is closed.
    241    */
    242   public void setCallSystemExitOnClose(boolean callSystemExitOnClose) {
    243     _callSystemExitOnClose = callSystemExitOnClose;
    244   }
    245
    246   /**
    247    * Add a log record message to be displayed in the LogTable.
    248    * This method is thread-safe as it posts requests to the SwingThread
    249    * rather than processing directly.
    250    */
    251   public void addMessage(final LogRecord lr) {
    252     if (_isDisposed == true) {
    253       // If the frame has been disposed of, do not log any more
    254       // messages.
    255       return;
    256     }
    257
    258     SwingUtilities.invokeLater(new Runnable() {
    259       public void run() {
    260         _categoryExplorerTree.getExplorerModel().addLogRecord(lr);
    261         _table.getFilteredLogTableModel().addLogRecord(lr); // update table
    262         updateStatusLabel(); // show updated counts
    263       }
    264     });
    265   }
    266
    267   public void setMaxNumberOfLogRecords(int maxNumberOfLogRecords) {
    268     _table.getFilteredLogTableModel().setMaxNumberOfLogRecords(maxNumberOfLogRecords);
    269   }
    270
    271   public JFrame getBaseFrame() {
    272     return _logMonitorFrame;
    273   }
    274
    275   public void setTitle(String title) {
    276     _logMonitorFrame.setTitle(title + " - LogFactor5");
    277   }
    278
    279   public void setFrameSize(int width, int height) {
    280     Dimension screen = Toolkit.getDefaultToolkit().getScreenSize();
    281     if (0 < width && width < screen.width) {
    282       _logMonitorFrameWidth = width;
    283     }
    284     if (0 < height && height < screen.height) {
    285       _logMonitorFrameHeight = height;
    286     }
    287     updateFrameSize();
    288   }
    289
    290   public void setFontSize(int fontSize) {
    291     changeFontSizeCombo(_fontSizeCombo, fontSize);
    292     // setFontSizeSilently(actualFontSize); - changeFontSizeCombo fires event
    293     // refreshDetailTextArea();
    294   }
    295
    296   public void addDisplayedProperty(Object messageLine) {
    297     _displayedLogBrokerProperties.add(messageLine);
    298   }
    299
    300   public Map getLogLevelMenuItems() {
    301     return _logLevelMenuItems;
    302   }
    303
    304   public Map getLogTableColumnMenuItems() {
    305     return _logTableColumnMenuItems;
    306   }
    307
    308   public JCheckBoxMenuItem getTableColumnMenuItem(LogTableColumn column) {
    309     return getLogTableColumnMenuItem(column);
    310   }
    311
    312   public CategoryExplorerTree getCategoryExplorerTree() {
    313     return _categoryExplorerTree;
    314   }
    315
    316   // Added in version 1.2 - gets the value of the NDC text filter
    317   // This value is set back to null each time the Monitor is initialized.
    318   public String getNDCTextFilter() {
    319     return _NDCTextFilter;
    320   }
    321
    322   // Added in version 1.2 - sets the NDC Filter based on
    323   // a String passed in by the user.  This value is persisted
    324   // in the XML Configuration file.
    325   public void setNDCLogRecordFilter(String textFilter) {
    326     _table.getFilteredLogTableModel().
    327         setLogRecordFilter(createNDCLogRecordFilter(textFilter));
    328   }
    329   //--------------------------------------------------------------------------
    330   //   Protected Methods:
    331   //--------------------------------------------------------------------------
    332
    333   protected void setSearchText(String text) {
    334     _searchText = text;
    335   }
    336
    337   // Added in version 1.2 - Sets the text filter for the NDC
    338   protected void setNDCTextFilter(String text) {
    339     // if no value is set, set it to a blank string
    340     // otherwise use the value provided
    341     if (text == null) {
    342       _NDCTextFilter = "";
    343     } else {
    344       _NDCTextFilter = text;
    345     }
    346   }
    347
    348   // Added in version 1.2 - Uses a different filter that sorts
    349   // based on an NDC string passed in by the user.  If the string
    350   // is null or is an empty string, we do nothing.
    351   protected void sortByNDC() {
    352     String text = _NDCTextFilter;
    353     if (text == null || text.length() == 0) {
    354       return;
    355     }
    356
    357     // Use new NDC filter
    358     _table.getFilteredLogTableModel().
    359         setLogRecordFilter(createNDCLogRecordFilter(text));
    360   }
    361
    362   protected void findSearchText() {
    363     String text = _searchText;
    364     if (text == null || text.length() == 0) {
    365       return;
    366     }
    367     int startRow = getFirstSelectedRow();
    368     int foundRow = findRecord(
    369         startRow,
    370         text,
    371         _table.getFilteredLogTableModel().getFilteredRecords()
    372     );
    373     selectRow(foundRow);
    374   }
    375
    376   protected int getFirstSelectedRow() {
    377     return _table.getSelectionModel().getMinSelectionIndex();
    378   }
    379
    380   protected void selectRow(int foundRow) {
    381     if (foundRow == -1) {
    382       String message = _searchText + " not found.";
    383       JOptionPane.showMessageDialog(
    384           _logMonitorFrame,
    385           message,
    386           "Text not found",
    387           JOptionPane.INFORMATION_MESSAGE
    388       );
    389       return;
    390     }
    391     LF5SwingUtils.selectRow(foundRow, _table, _logTableScrollPane);
    392   }
    393
    394   protected int findRecord(
    395       int startRow,
    396       String searchText,
    397       List records
    398       ) {
    399     if (startRow < 0) {
    400       startRow = 0; // start at first element if no rows are selected
    401     } else {
    402       startRow++; // start after the first selected row
    403     }
    404     int len = records.size();
    405
    406     for (int i = startRow; i < len; i++) {
    407       if (matches((LogRecord) records.get(i), searchText)) {
    408         return i; // found a record
    409       }
    410     }
    411     // wrap around to beginning if when we reach the end with no match
    412     len = startRow;
    413     for (int i = 0; i < len; i++) {
    414       if (matches((LogRecord) records.get(i), searchText)) {
    415         return i; // found a record
    416       }
    417     }
    418     // nothing found
    419     return -1;
    420   }
    421
    422   /**
    423    * Check to see if the any records contain the search string.
    424    * Searching now supports NDC messages and date.
    425    */
    426   protected boolean matches(LogRecord record, String text) {
    427     String message = record.getMessage();
    428     String NDC = record.getNDC();
    429
    430     if (message == null && NDC == null || text == null) {
    431       return false;
    432     }
    433     if (message.toLowerCase().indexOf(text.toLowerCase()) == -1 &&
    434         NDC.toLowerCase().indexOf(text.toLowerCase()) == -1) {
    435       return false;
    436     }
    437
    438     return true;
    439   }
    440
    441   /**
    442    * When the fontsize of a JTextArea is changed, the word-wrapped lines
    443    * may become garbled.  This method clears and resets the text of the
    444    * text area.
    445    */
    446   protected void refresh(JTextArea textArea) {
    447     String text = textArea.getText();
    448     textArea.setText("");
    449     textArea.setText(text);
    450   }
    451
    452   protected void refreshDetailTextArea() {
    453     refresh(_table._detailTextArea);
    454   }
    455
    456   protected void clearDetailTextArea() {
    457     _table._detailTextArea.setText("");
    458   }
    459
    460   /**
    461    * Changes the font selection in the combo box and returns the
    462    * size actually selected.
    463    * @return -1 if unable to select an appropriate font
    464    */
    465   protected int changeFontSizeCombo(JComboBox box, int requestedSize) {
    466     int len = box.getItemCount();
    467     int currentValue;
    468     Object currentObject;
    469     Object selectedObject = box.getItemAt(0);
    470     int selectedValue = Integer.parseInt(String.valueOf(selectedObject));
    471     for (int i = 0; i < len; i++) {
    472       currentObject = box.getItemAt(i);
    473       currentValue = Integer.parseInt(String.valueOf(currentObject));
    474       if (selectedValue < currentValue && currentValue <= requestedSize) {
    475         selectedValue = currentValue;
    476         selectedObject = currentObject;
    477       }
    478     }
    479     box.setSelectedItem(selectedObject);
    480     return selectedValue;
    481   }
    482
    483   /**
    484    * Does not update gui or cause any events to be fired.
    485    */
    486   protected void setFontSizeSilently(int fontSize) {
    487     _fontSize = fontSize;
    488     setFontSize(_table._detailTextArea, fontSize);
    489     selectRow(0);
    490     setFontSize(_table, fontSize);
    491   }
    492
    493   protected void setFontSize(Component component, int fontSize) {
    494     Font oldFont = component.getFont();
    495     Font newFont =
    496         new Font(oldFont.getFontName(), oldFont.getStyle(), fontSize);
    497     component.setFont(newFont);
    498   }
    499
    500   protected void updateFrameSize() {
    501     _logMonitorFrame.setSize(_logMonitorFrameWidth, _logMonitorFrameHeight);
    502     centerFrame(_logMonitorFrame);
    503   }
    504
    505   protected void pause(int millis) {
    506     try {
    507       Thread.sleep(millis);
    508     } catch (InterruptedException e) {
    509
    510     }
    511   }
    512
    513   protected void initComponents() {
    514     //
    515     // Configure the Frame.
    516     //
    517     _logMonitorFrame = new JFrame("LogFactor5");
    518
    519     _logMonitorFrame.setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE);
    520
    521     String resource =
    522         "/org/apache/log4j/lf5/viewer/images/lf5_small_icon.gif";
    523     URL lf5IconURL = getClass().getResource(resource);
    524
    525     if (lf5IconURL != null) {
    526       _logMonitorFrame.setIconImage(new ImageIcon(lf5IconURL).getImage());
    527     }
    528     updateFrameSize();
    529
    530     //
    531     // Configure the LogTable.
    532     //
    533     JTextArea detailTA = createDetailTextArea();
    534     JScrollPane detailTAScrollPane = new JScrollPane(detailTA);
    535     _table = new LogTable(detailTA);
    536     setView(_currentView, _table);
    537     _table.setFont(new Font(_fontName, Font.PLAIN, _fontSize));
    538     _logTableScrollPane = new JScrollPane(_table);
    539
    540     if (_trackTableScrollPane) {
    541       _logTableScrollPane.getVerticalScrollBar().addAdjustmentListener(
    542           new TrackingAdjustmentListener()
    543       );
    544     }
    545
    546
    547     // Configure the SplitPane between the LogTable & DetailTextArea
    548     //
    549
    550     JSplitPane tableViewerSplitPane = new JSplitPane();
    551     tableViewerSplitPane.setOneTouchExpandable(true);
    552     tableViewerSplitPane.setOrientation(JSplitPane.VERTICAL_SPLIT);
    553     tableViewerSplitPane.setLeftComponent(_logTableScrollPane);
    554     tableViewerSplitPane.setRightComponent(detailTAScrollPane);
    555     // Make sure to do this last..
    556     //tableViewerSplitPane.setDividerLocation(1.0); Doesn't work
    557     //the same under 1.2.x & 1.3
    558     // "350" is a magic number that provides the correct default
    559     // behaviour under 1.2.x & 1.3.  For example, bumping this
    560     // number to 400, causes the pane to be completely open in 1.2.x
    561     // and closed in 1.3
    562     tableViewerSplitPane.setDividerLocation(350);
    563
    564     //
    565     // Configure the CategoryExplorer
    566     //
    567
    568     _categoryExplorerTree = new CategoryExplorerTree();
    569
    570     _table.getFilteredLogTableModel().setLogRecordFilter(createLogRecordFilter());
    571
    572     JScrollPane categoryExplorerTreeScrollPane =
    573         new JScrollPane(_categoryExplorerTree);
    574     categoryExplorerTreeScrollPane.setPreferredSize(new Dimension(130, 400));
    575
    576     // Load most recently used file list
    577     _mruFileManager = new MRUFileManager();
    578
    579     //
    580     // Configure the SplitPane between the CategoryExplorer & (LogTable/Detail)
    581     //
    582
    583     JSplitPane splitPane = new JSplitPane();
    584     splitPane.setOneTouchExpandable(true);
    585     splitPane.setRightComponent(tableViewerSplitPane);
    586     splitPane.setLeftComponent(categoryExplorerTreeScrollPane);
    587     // Do this last.
    588     splitPane.setDividerLocation(130);
    589     //
    590     // Add the MenuBar, StatusArea, CategoryExplorer|LogTable to the
    591     // LogMonitorFrame.
    592     //
    593     _logMonitorFrame.getRootPane().setJMenuBar(createMenuBar());
    594     _logMonitorFrame.getContentPane().add(splitPane, BorderLayout.CENTER);
    595     _logMonitorFrame.getContentPane().add(createToolBar(),
    596         BorderLayout.NORTH);
    597     _logMonitorFrame.getContentPane().add(createStatusArea(),
    598         BorderLayout.SOUTH);
    599
    600     makeLogTableListenToCategoryExplorer();
    601     addTableModelProperties();
    602
    603     //
    604     // Configure ConfigurationManager
    605     //
    606     _configurationManager = new ConfigurationManager(this, _table);
    607
    608   }
    609
    610   protected LogRecordFilter createLogRecordFilter() {
    611     LogRecordFilter result = new LogRecordFilter() {
    612       public boolean passes(LogRecord record) {
    613         CategoryPath path = new CategoryPath(record.getCategory());
    614         return
    615             getMenuItem(record.getLevel()).isSelected() &&
    616             _categoryExplorerTree.getExplorerModel().isCategoryPathActive(path);
    617       }
    618     };
    619     return result;
    620   }
    621
    622   // Added in version 1.2 - Creates a new filter that sorts records based on
    623   // an NDC string passed in by the user.
    624   protected LogRecordFilter createNDCLogRecordFilter(String text) {
    625     _NDCTextFilter = text;
    626     LogRecordFilter result = new LogRecordFilter() {
    627       public boolean passes(LogRecord record) {
    628         String NDC = record.getNDC();
    629         CategoryPath path = new CategoryPath(record.getCategory());
    630         if (NDC == null || _NDCTextFilter == null) {
    631           return false;
    632         } else if (NDC.toLowerCase().indexOf(_NDCTextFilter.toLowerCase()) == -1) {
    633           return false;
    634         } else {
    635           return getMenuItem(record.getLevel()).isSelected() &&
    636               _categoryExplorerTree.getExplorerModel().isCategoryPathActive(path);
    637         }
    638       }
    639     };
    640
    641     return result;
    642   }
    643
    644
    645   protected void updateStatusLabel() {
    646     _statusLabel.setText(getRecordsDisplayedMessage());
    647   }
    648
    649   protected String getRecordsDisplayedMessage() {
    650     FilteredLogTableModel model = _table.getFilteredLogTableModel();
    651     return getStatusText(model.getRowCount(), model.getTotalRowCount());
    652   }
    653
    654   protected void addTableModelProperties() {
    655     final FilteredLogTableModel model = _table.getFilteredLogTableModel();
    656
    657     addDisplayedProperty(new Object() {
    658       public String toString() {
    659         return getRecordsDisplayedMessage();
    660       }
    661     });
    662     addDisplayedProperty(new Object() {
    663       public String toString() {
    664         return "Maximum number of displayed LogRecords: "
    665             + model._maxNumberOfLogRecords;
    666       }
    667     });
    668   }
    669
    670   protected String getStatusText(int displayedRows, int totalRows) {
    671     StringBuffer result = new StringBuffer();
    672     result.append("Displaying: ");
    673     result.append(displayedRows);
    674     result.append(" records out of a total of: ");
    675     result.append(totalRows);
    676     result.append(" records.");
    677     return result.toString();
    678   }
    679
    680   protected void makeLogTableListenToCategoryExplorer() {
    681     ActionListener listener = new ActionListener() {
    682       public void actionPerformed(ActionEvent e) {
    683         _table.getFilteredLogTableModel().refresh();
    684         updateStatusLabel();
    685       }
    686     };
    687     _categoryExplorerTree.getExplorerModel().addActionListener(listener);
    688   }
    689
    690   protected JPanel createStatusArea() {
    691     JPanel statusArea = new JPanel();
    692     JLabel status =
    693         new JLabel("No log records to display.");
    694     _statusLabel = status;
    695     status.setHorizontalAlignment(JLabel.LEFT);
    696
    697     statusArea.setBorder(BorderFactory.createEtchedBorder());
    698     statusArea.setLayout(new FlowLayout(FlowLayout.LEFT, 0, 0));
    699     statusArea.add(status);
    700
    701     return (statusArea);
    702   }
    703
    704   protected JTextArea createDetailTextArea() {
    705     JTextArea detailTA = new JTextArea();
    706     detailTA.setFont(new Font("Monospaced", Font.PLAIN, 14));
    707     detailTA.setTabSize(3);
    708     detailTA.setLineWrap(true);
    709     detailTA.setWrapStyleWord(false);
    710     return (detailTA);
    711   }
    712
    713   protected JMenuBar createMenuBar() {
    714     JMenuBar menuBar = new JMenuBar();
    715     menuBar.add(createFileMenu());
    716     menuBar.add(createEditMenu());
    717     menuBar.add(createLogLevelMenu());
    718     menuBar.add(createViewMenu());
    719     menuBar.add(createConfigureMenu());
    720     menuBar.add(createHelpMenu());
    721
    722     return (menuBar);
    723   }
    724
    725   protected JMenu createLogLevelMenu() {
    726     JMenu result = new JMenu("Log Level");
    727     result.setMnemonic('l');
    728     Iterator levels = getLogLevels();
    729     while (levels.hasNext()) {
    730       result.add(getMenuItem((LogLevel) levels.next()));
    731     }
    732
    733     result.addSeparator();
    734     result.add(createAllLogLevelsMenuItem());
    735     result.add(createNoLogLevelsMenuItem());
    736     result.addSeparator();
    737     result.add(createLogLevelColorMenu());
    738     result.add(createResetLogLevelColorMenuItem());
    739
    740     return result;
    741   }
    742
    743   protected JMenuItem createAllLogLevelsMenuItem() {
    744     JMenuItem result = new JMenuItem("Show all LogLevels");
    745     result.setMnemonic('s');
    746     result.addActionListener(new ActionListener() {
    747       public void actionPerformed(ActionEvent e) {
    748         selectAllLogLevels(true);
    749         _table.getFilteredLogTableModel().refresh();
    750         updateStatusLabel();
    751       }
    752     });
    753     return result;
    754   }
    755
    756   protected JMenuItem createNoLogLevelsMenuItem() {
    757     JMenuItem result = new JMenuItem("Hide all LogLevels");
    758     result.setMnemonic('h');
    759     result.addActionListener(new ActionListener() {
    760       public void actionPerformed(ActionEvent e) {
    761         selectAllLogLevels(false);
    762         _table.getFilteredLogTableModel().refresh();
    763         updateStatusLabel();
    764       }
    765     });
    766     return result;
    767   }
    768
    769   protected JMenu createLogLevelColorMenu() {
    770     JMenu colorMenu = new JMenu("Configure LogLevel Colors");
    771     colorMenu.setMnemonic('c');
    772     Iterator levels = getLogLevels();
    773     while (levels.hasNext()) {
    774       colorMenu.add(createSubMenuItem((LogLevel) levels.next()));
    775     }
    776
    777     return colorMenu;
    778   }
    779
    780   protected JMenuItem createResetLogLevelColorMenuItem() {
    781     JMenuItem result = new JMenuItem("Reset LogLevel Colors");
    782     result.setMnemonic('r');
    783     result.addActionListener(new ActionListener() {
    784       public void actionPerformed(ActionEvent e) {
    785         // reset the level colors in the map
    786         LogLevel.resetLogLevelColorMap();
    787
    788         // refresh the table
    789         _table.getFilteredLogTableModel().refresh();
    790       }
    791     });
    792     return result;
    793   }
    794
    795   protected void selectAllLogLevels(boolean selected) {
    796     Iterator levels = getLogLevels();
    797     while (levels.hasNext()) {
    798       getMenuItem((LogLevel) levels.next()).setSelected(selected);
    799     }
    800   }
    801
    802   protected JCheckBoxMenuItem getMenuItem(LogLevel level) {
    803     JCheckBoxMenuItem result = (JCheckBoxMenuItem) (_logLevelMenuItems.get(level));
    804     if (result == null) {
    805       result = createMenuItem(level);
    806       _logLevelMenuItems.put(level, result);
    807     }
    808     return result;
    809   }
    810
    811   protected JMenuItem createSubMenuItem(LogLevel level) {
    812     final JMenuItem result = new JMenuItem(level.toString());
    813     final LogLevel logLevel = level;
    814     result.setMnemonic(level.toString().charAt(0));
    815     result.addActionListener(new ActionListener() {
    816       public void actionPerformed(ActionEvent e) {
    817         showLogLevelColorChangeDialog(result, logLevel);
    818       }
    819     });
    820
    821     return result;
    822
    823   }
    824
    825   protected void showLogLevelColorChangeDialog(JMenuItem result, LogLevel level) {
    826     JMenuItem menuItem = result;
    827     Color newColor = JColorChooser.showDialog(
    828         _logMonitorFrame,
    829         "Choose LogLevel Color",
    830         result.getForeground());
    831
    832     if (newColor != null) {
    833       // set the color for the record
    834       level.setLogLevelColorMap(level, newColor);
    835       _table.getFilteredLogTableModel().refresh();
    836     }
    837
    838   }
    839
    840   protected JCheckBoxMenuItem createMenuItem(LogLevel level) {
    841     JCheckBoxMenuItem result = new JCheckBoxMenuItem(level.toString());
    842     result.setSelected(true);
    843     result.setMnemonic(level.toString().charAt(0));
    844     result.addActionListener(new ActionListener() {
    845       public void actionPerformed(ActionEvent e) {
    846         _table.getFilteredLogTableModel().refresh();
    847         updateStatusLabel();
    848       }
    849     });
    850     return result;
    851   }
    852
    853   // view menu
    854   protected JMenu createViewMenu() {
    855     JMenu result = new JMenu("View");
    856     result.setMnemonic('v');
    857     Iterator columns = getLogTableColumns();
    858     while (columns.hasNext()) {
    859       result.add(getLogTableColumnMenuItem((LogTableColumn) columns.next()));
    860     }
    861
    862     result.addSeparator();
    863     result.add(createAllLogTableColumnsMenuItem());
    864     result.add(createNoLogTableColumnsMenuItem());
    865     return result;
    866   }
    867
    868   protected JCheckBoxMenuItem getLogTableColumnMenuItem(LogTableColumn column) {
    869     JCheckBoxMenuItem result = (JCheckBoxMenuItem) (_logTableColumnMenuItems.get(column));
    870     if (result == null) {
    871       result = createLogTableColumnMenuItem(column);
    872       _logTableColumnMenuItems.put(column, result);
    873     }
    874     return result;
    875   }
    876
    877   protected JCheckBoxMenuItem createLogTableColumnMenuItem(LogTableColumn column) {
    878     JCheckBoxMenuItem result = new JCheckBoxMenuItem(column.toString());
    879
    880     result.setSelected(true);
    881     result.setMnemonic(column.toString().charAt(0));
    882     result.addActionListener(new ActionListener() {
    883       public void actionPerformed(ActionEvent e) {
    884         // update list of columns and reset the view
    885         List selectedColumns = updateView();
    886         _table.setView(selectedColumns);
    887       }
    888     });
    889     return result;
    890   }
    891
    892   protected List updateView() {
    893     ArrayList updatedList = new ArrayList();
    894     Iterator columnIterator = _columns.iterator();
    895     while (columnIterator.hasNext()) {
    896       LogTableColumn column = (LogTableColumn) columnIterator.next();
    897       JCheckBoxMenuItem result = getLogTableColumnMenuItem(column);
    898       // check and see if the checkbox is checked
    899       if (result.isSelected()) {
    900         updatedList.add(column);
    901       }
    902     }
    903
    904     return updatedList;
    905   }
    906
    907   protected JMenuItem createAllLogTableColumnsMenuItem() {
    908     JMenuItem result = new JMenuItem("Show all Columns");
    909     result.setMnemonic('s');
    910     result.addActionListener(new ActionListener() {
    911       public void actionPerformed(ActionEvent e) {
    912         selectAllLogTableColumns(true);
    913         // update list of columns and reset the view
    914         List selectedColumns = updateView();
    915         _table.setView(selectedColumns);
    916       }
    917     });
    918     return result;
    919   }
    920
    921   protected JMenuItem createNoLogTableColumnsMenuItem() {
    922     JMenuItem result = new JMenuItem("Hide all Columns");
    923     result.setMnemonic('h');
    924     result.addActionListener(new ActionListener() {
    925       public void actionPerformed(ActionEvent e) {
    926         selectAllLogTableColumns(false);
    927         // update list of columns and reset the view
    928         List selectedColumns = updateView();
    929         _table.setView(selectedColumns);
    930       }
    931     });
    932     return result;
    933   }
    934
    935   protected void selectAllLogTableColumns(boolean selected) {
    936     Iterator columns = getLogTableColumns();
    937     while (columns.hasNext()) {
    938       getLogTableColumnMenuItem((LogTableColumn) columns.next()).setSelected(selected);
    939     }
    940   }
    941
    942   protected JMenu createFileMenu() {
    943     JMenu fileMenu = new JMenu("File");
    944     fileMenu.setMnemonic('f');
    945     JMenuItem exitMI;
    946     fileMenu.add(createOpenMI());
    947     fileMenu.add(createOpenURLMI());
    948     fileMenu.addSeparator();
    949     fileMenu.add(createCloseMI());
    950     createMRUFileListMI(fileMenu);
    951     fileMenu.addSeparator();
    952     fileMenu.add(createExitMI());
    953     return fileMenu;
    954   }
    955
    956   /**
    957    * Menu item added to allow log files to be opened with
    958    * the LF5 GUI.
    959    */
    960   protected JMenuItem createOpenMI() {
    961     JMenuItem result = new JMenuItem("Open...");
    962     result.setMnemonic('o');
    963     result.addActionListener(new ActionListener() {
    964       public void actionPerformed(ActionEvent e) {
    965         requestOpen();
    966       }
    967     });
    968     return result;
    969   }
    970
    971   /**
    972    * Menu item added to allow log files loaded from a URL
    973    * to be opened by the LF5 GUI.
    974    */
    975   protected JMenuItem createOpenURLMI() {
    976     JMenuItem result = new JMenuItem("Open URL...");
    977     result.setMnemonic('u');
    978     result.addActionListener(new ActionListener() {
    979       public void actionPerformed(ActionEvent e) {
    980         requestOpenURL();
    981       }
    982     });
    983     return result;
    984   }
    985
    986   protected JMenuItem createCloseMI() {
    987     JMenuItem result = new JMenuItem("Close");
    988     result.setMnemonic('c');
    989     result.setAccelerator(KeyStroke.getKeyStroke("control Q"));
    990     result.addActionListener(new ActionListener() {
    991       public void actionPerformed(ActionEvent e) {
    992         requestClose();
    993       }
    994     });
    995     return result;
    996   }
    997
    998   /**
    999    * Creates a Most Recently Used file list to be
    1000    * displayed in the File menu
    1001    */
    1002   protected void createMRUFileListMI(JMenu menu) {
    1003
    1004     String[] files = _mruFileManager.getMRUFileList();
    1005
    1006     if (files != null) {
    1007       menu.addSeparator();
    1008       for (int i = 0; i < files.length; i++) {
    1009         JMenuItem result = new JMenuItem((i + 1) + " " + files[i]);
    1010         result.setMnemonic(i + 1);
    1011         result.addActionListener(new ActionListener() {
    1012           public void actionPerformed(ActionEvent e) {
    1013             requestOpenMRU(e);
    1014           }
    1015         });
    1016         menu.add(result);
    1017       }
    1018     }
    1019   }
    1020
    1021   protected JMenuItem createExitMI() {
    1022     JMenuItem result = new JMenuItem("Exit");
    1023     result.setMnemonic('x');
    1024     result.addActionListener(new ActionListener() {
    1025       public void actionPerformed(ActionEvent e) {
    1026         requestExit();
    1027       }
    1028     });
    1029     return result;
    1030   }
    1031
    1032   protected JMenu createConfigureMenu() {
    1033     JMenu configureMenu = new JMenu("Configure");
    1034     configureMenu.setMnemonic('c');
    1035     configureMenu.add(createConfigureSave());
    1036     configureMenu.add(createConfigureReset());
    1037     configureMenu.add(createConfigureMaxRecords());
    1038
    1039     return configureMenu;
    1040   }
    1041
    1042   protected JMenuItem createConfigureSave() {
    1043     JMenuItem result = new JMenuItem("Save");
    1044     result.setMnemonic('s');
    1045     result.addActionListener(new ActionListener() {
    1046       public void actionPerformed(ActionEvent e) {
    1047         saveConfiguration();
    1048       }
    1049     });
    1050
    1051     return result;
    1052   }
    1053
    1054   protected JMenuItem createConfigureReset() {
    1055     JMenuItem result = new JMenuItem("Reset");
    1056     result.setMnemonic('r');
    1057     result.addActionListener(new ActionListener() {
    1058       public void actionPerformed(ActionEvent e) {
    1059         resetConfiguration();
    1060       }
    1061     });
    1062
    1063     return result;
    1064   }
    1065
    1066   protected JMenuItem createConfigureMaxRecords() {
    1067     JMenuItem result = new JMenuItem("Set Max Number of Records");
    1068     result.setMnemonic('m');
    1069     result.addActionListener(new ActionListener() {
    1070       public void actionPerformed(ActionEvent e) {
    1071         setMaxRecordConfiguration();
    1072       }
    1073     });
    1074
    1075     return result;
    1076   }
    1077
    1078
    1079   protected void saveConfiguration() {
    1080     _configurationManager.save();
    1081   }
    1082
    1083   protected void resetConfiguration() {
    1084     _configurationManager.reset();
    1085   }
    1086
    1087   protected void setMaxRecordConfiguration() {
    1088     LogFactor5InputDialog inputDialog = new LogFactor5InputDialog(
    1089         getBaseFrame(), "Set Max Number of Records", "", 10);
    1090
    1091     String temp = inputDialog.getText();
    1092
    1093     if (temp != null) {
    1094       try {
    1095         setMaxNumberOfLogRecords(Integer.parseInt(temp));
    1096       } catch (NumberFormatException e) {
    1097         LogFactor5ErrorDialog error = new LogFactor5ErrorDialog(
    1098             getBaseFrame(),
    1099             "'" + temp + "' is an invalid parameter.\nPlease try again.");
    1100         setMaxRecordConfiguration();
    1101       }
    1102     }
    1103   }
    1104
    1105
    1106   protected JMenu createHelpMenu() {
    1107     JMenu helpMenu = new JMenu("Help");
    1108     helpMenu.setMnemonic('h');
    1109     helpMenu.add(createHelpProperties());
    1110     return helpMenu;
    1111   }
    1112
    1113   protected JMenuItem createHelpProperties() {
    1114     final String title = "LogFactor5 Properties";
    1115     final JMenuItem result = new JMenuItem(title);
    1116     result.setMnemonic('l');
    1117     result.addActionListener(new ActionListener() {
    1118       public void actionPerformed(ActionEvent e) {
    1119         showPropertiesDialog(title);
    1120       }
    1121     });
    1122     return result;
    1123   }
    1124
    1125   protected void showPropertiesDialog(String title) {
    1126     JOptionPane.showMessageDialog(
    1127         _logMonitorFrame,
    1128         _displayedLogBrokerProperties.toArray(),
    1129         title,
    1130         JOptionPane.PLAIN_MESSAGE
    1131     );
    1132   }
    1133
    1134   protected JMenu createEditMenu() {
    1135     JMenu editMenu = new JMenu("Edit");
    1136     editMenu.setMnemonic('e');
    1137     editMenu.add(createEditFindMI());
    1138     editMenu.add(createEditFindNextMI());
    1139     editMenu.addSeparator();
    1140     editMenu.add(createEditSortNDCMI());
    1141     editMenu.add(createEditRestoreAllNDCMI());
    1142     return editMenu;
    1143   }
    1144
    1145   protected JMenuItem createEditFindNextMI() {
    1146     JMenuItem editFindNextMI = new JMenuItem("Find Next");
    1147     editFindNextMI.setMnemonic('n');
    1148     editFindNextMI.setAccelerator(KeyStroke.getKeyStroke("F3"));
    1149     editFindNextMI.addActionListener(new ActionListener() {
    1150       public void actionPerformed(ActionEvent e) {
    1151         findSearchText();
    1152       }
    1153     });
    1154     return editFindNextMI;
    1155   }
    1156
    1157   protected JMenuItem createEditFindMI() {
    1158     JMenuItem editFindMI = new JMenuItem("Find");
    1159     editFindMI.setMnemonic('f');
    1160     editFindMI.setAccelerator(KeyStroke.getKeyStroke("control F"));
    1161
    1162     editFindMI.addActionListener(
    1163         new ActionListener() {
    1164           public void actionPerformed(ActionEvent e) {
    1165             String inputValue =
    1166                 JOptionPane.showInputDialog(
    1167                     _logMonitorFrame,
    1168                     "Find text: ",
    1169                     "Search Record Messages",
    1170                     JOptionPane.QUESTION_MESSAGE
    1171                 );
    1172             setSearchText(inputValue);
    1173             findSearchText();
    1174           }
    1175         }
    1176
    1177     );
    1178     return editFindMI;
    1179   }
    1180
    1181   // Added version 1.2 - Allows users to Sort Log Records by an
    1182   // NDC text filter. A new LogRecordFilter was created to
    1183   // sort the records.
    1184   protected JMenuItem createEditSortNDCMI() {
    1185     JMenuItem editSortNDCMI = new JMenuItem("Sort by NDC");
    1186     editSortNDCMI.setMnemonic('s');
    1187     editSortNDCMI.addActionListener(
    1188         new ActionListener() {
    1189           public void actionPerformed(ActionEvent e) {
    1190             String inputValue =
    1191                 JOptionPane.showInputDialog(
    1192                     _logMonitorFrame,
    1193                     "Sort by this NDC: ",
    1194                     "Sort Log Records by NDC",
    1195                     JOptionPane.QUESTION_MESSAGE
    1196                 );
    1197             setNDCTextFilter(inputValue);
    1198             sortByNDC();
    1199             _table.getFilteredLogTableModel().refresh();
    1200             updateStatusLabel();
    1201           }
    1202         }
    1203
    1204     );
    1205     return editSortNDCMI;
    1206   }
    1207
    1208   // Added in version 1.2 - Resets the LogRecordFilter back to default
    1209   // filter.
    1210   protected JMenuItem createEditRestoreAllNDCMI() {
    1211     JMenuItem editRestoreAllNDCMI = new JMenuItem("Restore all NDCs");
    1212     editRestoreAllNDCMI.setMnemonic('r');
    1213     editRestoreAllNDCMI.addActionListener(
    1214         new ActionListener() {
    1215           public void actionPerformed(ActionEvent e) {
    1216             _table.getFilteredLogTableModel().setLogRecordFilter(createLogRecordFilter());
    1217             // reset the text filter
    1218             setNDCTextFilter("");
    1219             _table.getFilteredLogTableModel().refresh();
    1220             updateStatusLabel();
    1221           }
    1222         }
    1223     );
    1224     return editRestoreAllNDCMI;
    1225   }
    1226
    1227   protected JToolBar createToolBar() {
    1228     JToolBar tb = new JToolBar();
    1229     tb.putClientProperty("JToolBar.isRollover", Boolean.TRUE);
    1230     JComboBox fontCombo = new JComboBox();
    1231     JComboBox fontSizeCombo = new JComboBox();
    1232     _fontSizeCombo = fontSizeCombo;
    1233
    1234     ClassLoader cl = this.getClass().getClassLoader();
    1235     if(cl == null) {
    1236         cl = ClassLoader.getSystemClassLoader();
    1237     }
    1238     URL newIconURL = cl.getResource("org/apache/log4j/lf5/viewer/" +
    1239         "images/channelexplorer_new.gif");
    1240
    1241     ImageIcon newIcon = null;
    1242
    1243     if (newIconURL != null) {
    1244       newIcon = new ImageIcon(newIconURL);
    1245     }
    1246
    1247     JButton newButton = new JButton("Clear Log Table");
    1248
    1249     if (newIcon != null) {
    1250       newButton.setIcon(newIcon);
    1251     }
    1252
    1253     newButton.setToolTipText("Clear Log Table.");
    1254     //newButton.setBorder(BorderFactory.createEtchedBorder());
    1255
    1256     newButton.addActionListener(
    1257         new ActionListener() {
    1258           public void actionPerformed(ActionEvent e) {
    1259             _table.clearLogRecords();
    1260             _categoryExplorerTree.getExplorerModel().resetAllNodeCounts();
    1261             updateStatusLabel();
    1262             clearDetailTextArea();
    1263             LogRecord.resetSequenceNumber();
    1264           }
    1265         }
    1266     );
    1267
    1268     Toolkit tk = Toolkit.getDefaultToolkit();
    1269     // This will actually grab all the fonts
    1270
    1271     String[] fonts;
    1272
    1273     if (_loadSystemFonts) {
    1274       fonts = GraphicsEnvironment.
    1275           getLocalGraphicsEnvironment().getAvailableFontFamilyNames();
    1276     } else {
    1277       fonts = tk.getFontList();
    1278     }
    1279
    1280     for (int j = 0; j < fonts.length; j++) {
    1281       fontCombo.addItem(fonts[j]);
    1282     }
    1283
    1284     fontCombo.setSelectedItem(_fontName);
    1285
    1286     fontCombo.addActionListener(
    1287
    1288         new ActionListener() {
    1289           public void actionPerformed(ActionEvent e) {
    1290             JComboBox box = (JComboBox) e.getSource();
    1291             String font = (String) box.getSelectedItem();
    1292             _table.setFont(new Font(font, Font.PLAIN, _fontSize));
    1293             _fontName = font;
    1294           }
    1295         }
    1296     );
    1297
    1298     fontSizeCombo.addItem("8");
    1299     fontSizeCombo.addItem("9");
    1300     fontSizeCombo.addItem("10");
    1301     fontSizeCombo.addItem("12");
    1302     fontSizeCombo.addItem("14");
    1303     fontSizeCombo.addItem("16");
    1304     fontSizeCombo.addItem("18");
    1305     fontSizeCombo.addItem("24");
    1306
    1307     fontSizeCombo.setSelectedItem(String.valueOf(_fontSize));
    1308     fontSizeCombo.addActionListener(
    1309         new ActionListener() {
    1310           public void actionPerformed(ActionEvent e) {
    1311             JComboBox box = (JComboBox) e.getSource();
    1312             String size = (String) box.getSelectedItem();
    1313             int s = Integer.valueOf(size).intValue();
    1314
    1315             setFontSizeSilently(s);
    1316             refreshDetailTextArea();
    1317             _fontSize = s;
    1318           }
    1319         }
    1320     );
    1321
    1322     tb.add(new JLabel(" Font: "));
    1323     tb.add(fontCombo);
    1324     tb.add(fontSizeCombo);
    1325     tb.addSeparator();
    1326     tb.addSeparator();
    1327     tb.add(newButton);
    1328
    1329     newButton.setAlignmentY(0.5f);
    1330     newButton.setAlignmentX(0.5f);
    1331
    1332     fontCombo.setMaximumSize(fontCombo.getPreferredSize());
    1333     fontSizeCombo.setMaximumSize(
    1334         fontSizeCombo.getPreferredSize());
    1335
    1336     return (tb);
    1337   }
    1338
    1339 //    protected void setView(String viewString, LogTable table) {
    1340 //        if (STANDARD_VIEW.equals(viewString)) {
    1341 //            table.setStandardView();
    1342 //        } else if (COMPACT_VIEW.equals(viewString)) {
    1343 //            table.setCompactView();
    1344 //        } else if (DETAILED_VIEW.equals(viewString)) {
    1345 //            table.setDetailedView();
    1346 //        } else {
    1347 //            String message = viewString + "does not match a supported view.";
    1348 //            throw new IllegalArgumentException(message);
    1349 //        }
    1350 //        _currentView = viewString;
    1351 //    }
    1352
    1353   protected void setView(String viewString, LogTable table) {
    1354     if (DETAILED_VIEW.equals(viewString)) {
    1355       table.setDetailedView();
    1356     } else {
    1357       String message = viewString + "does not match a supported view.";
    1358       throw new IllegalArgumentException(message);
    1359     }
    1360     _currentView = viewString;
    1361   }
    1362
    1363   protected JComboBox createLogLevelCombo() {
    1364     JComboBox result = new JComboBox();
    1365     Iterator levels = getLogLevels();
    1366     while (levels.hasNext()) {
    1367       result.addItem(levels.next());
    1368     }
    1369     result.setSelectedItem(_leastSevereDisplayedLogLevel);
    1370
    1371     result.addActionListener(new ActionListener() {
    1372       public void actionPerformed(ActionEvent e) {
    1373         JComboBox box = (JComboBox) e.getSource();
    1374         LogLevel level = (LogLevel) box.getSelectedItem();
    1375         setLeastSevereDisplayedLogLevel(level);
    1376       }
    1377     });
    1378     result.setMaximumSize(result.getPreferredSize());
    1379     return result;
    1380   }
    1381
    1382   protected void setLeastSevereDisplayedLogLevel(LogLevel level) {
    1383     if (level == null || _leastSevereDisplayedLogLevel == level) {
    1384       return; // nothing to do
    1385     }
    1386     _leastSevereDisplayedLogLevel = level;
    1387     _table.getFilteredLogTableModel().refresh();
    1388     updateStatusLabel();
    1389   }
    1390
    1391   /**
    1392    * Ensures that the Table's ScrollPane Viewport will "track" with updates
    1393    * to the Table.  When the vertical scroll bar is at its bottom anchor
    1394    * and tracking is enabled then viewport will stay at the bottom most
    1395    * point of the component.  The purpose of this feature is to allow
    1396    * a developer to watch the table as messages arrive and not have to
    1397    * scroll after each new message arrives.  When the vertical scroll bar
    1398    * is at any other location, then no tracking will happen.
    1399    * @deprecated tracking is now done automatically.
    1400    */
    1401   protected void trackTableScrollPane() {
    1402     // do nothing
    1403   }
    1404
    1405   protected void centerFrame(JFrame frame) {
    1406     Dimension screen = Toolkit.getDefaultToolkit().getScreenSize();
    1407     Dimension comp = frame.getSize();
    1408
    1409     frame.setLocation(((screen.width - comp.width) / 2),
    1410         ((screen.height - comp.height) / 2));
    1411
    1412   }
    1413
    1414   /**
    1415    * Uses a JFileChooser to select a file to opened with the
    1416    * LF5 GUI.
    1417    */
    1418   protected void requestOpen() {
    1419     JFileChooser chooser;
    1420
    1421     if (_fileLocation == null) {
    1422       chooser = new JFileChooser();
    1423     } else {
    1424       chooser = new JFileChooser(_fileLocation);
    1425     }
    1426
    1427     int returnVal = chooser.showOpenDialog(_logMonitorFrame);
    1428     if (returnVal == JFileChooser.APPROVE_OPTION) {
    1429       File f = chooser.getSelectedFile();
    1430       if (loadLogFile(f)) {
    1431         _fileLocation = chooser.getSelectedFile();
    1432         _mruFileManager.set(f);
    1433         updateMRUList();
    1434       }
    1435     }
    1436   }
    1437
    1438   /**
    1439    * Uses a Dialog box to accept a URL to a file to be opened
    1440    * with the LF5 GUI.
    1441    */
    1442   protected void requestOpenURL() {
    1443     LogFactor5InputDialog inputDialog = new LogFactor5InputDialog(
    1444         getBaseFrame(), "Open URL", "URL:");
    1445     String temp = inputDialog.getText();
    1446
    1447     if (temp != null) {
    1448       if (temp.indexOf("://") == -1) {
    1449         temp = "http://" + temp;
    1450       }
    1451
    1452       try {
    1453         URL url = new URL(temp);
    1454         if (loadLogFile(url)) {
    1455           _mruFileManager.set(url);
    1456           updateMRUList();
    1457         }
    1458       } catch (MalformedURLException e) {
    1459         LogFactor5ErrorDialog error = new LogFactor5ErrorDialog(
    1460             getBaseFrame(), "Error reading URL.");
    1461       }
    1462     }
    1463   }
    1464
    1465   /**
    1466    * Removes old file list and creates a new file list
    1467    * with the updated MRU list.
    1468    */
    1469   protected void updateMRUList() {
    1470     JMenu menu = _logMonitorFrame.getJMenuBar().getMenu(0);
    1471     menu.removeAll();
    1472     menu.add(createOpenMI());
    1473     menu.add(createOpenURLMI());
    1474     menu.addSeparator();
    1475     menu.add(createCloseMI());
    1476     createMRUFileListMI(menu);
    1477     menu.addSeparator();
    1478     menu.add(createExitMI());
    1479   }
    1480
    1481   protected void requestClose() {
    1482     setCallSystemExitOnClose(false);
    1483     closeAfterConfirm();
    1484   }
    1485
    1486   /**
    1487    * Opens a file in the MRU list.
    1488    */
    1489   protected void requestOpenMRU(ActionEvent e) {
    1490     String file = e.getActionCommand();
    1491     StringTokenizer st = new StringTokenizer(file);
    1492     String num = st.nextToken().trim();
    1493     file = st.nextToken("\n");
    1494
    1495     try {
    1496       int index = Integer.parseInt(num) - 1;
    1497
    1498       InputStream in = _mruFileManager.getInputStream(index);
    1499       LogFileParser lfp = new LogFileParser(in);
    1500       lfp.parse(this);
    1501
    1502       _mruFileManager.moveToTop(index);
    1503       updateMRUList();
    1504
    1505     } catch (Exception me) {
    1506       LogFactor5ErrorDialog error = new LogFactor5ErrorDialog(
    1507           getBaseFrame(), "Unable to load file " + file);
    1508     }
    1509
    1510   }
    1511
    1512   protected void requestExit() {
    1513     _mruFileManager.save();
    1514     setCallSystemExitOnClose(true);
    1515     closeAfterConfirm();
    1516   }
    1517
    1518   protected void closeAfterConfirm() {
    1519     StringBuffer message = new StringBuffer();
    1520
    1521     if (_callSystemExitOnClose == false) {
    1522       message.append("Are you sure you want to close the logging ");
    1523       message.append("console?\n");
    1524       message.append("(Note: This will not shut down the Virtual Machine,\n");
    1525       message.append("or the Swing event thread.)");
    1526     } else {
    1527       message.append("Are you sure you want to exit?\n");
    1528       message.append("This will shut down the Virtual Machine.\n");
    1529     }
    1530
    1531     String title =
    1532         "Are you sure you want to dispose of the Logging Console?";
    1533
    1534     if (_callSystemExitOnClose == true) {
    1535       title = "Are you sure you want to exit?";
    1536     }
    1537     int value = JOptionPane.showConfirmDialog(
    1538         _logMonitorFrame,
    1539         message.toString(),
    1540         title,
    1541         JOptionPane.OK_CANCEL_OPTION,
    1542         JOptionPane.QUESTION_MESSAGE,
    1543         null
    1544     );
    1545
    1546     if (value == JOptionPane.OK_OPTION) {
    1547       dispose();
    1548     }
    1549   }
    1550
    1551   protected Iterator getLogLevels() {
    1552     return _levels.iterator();
    1553   }
    1554
    1555   protected Iterator getLogTableColumns() {
    1556     return _columns.iterator();
    1557   }
    1558
    1559   /**
    1560    * Loads and parses a log file.
    1561    */
    1562   protected boolean loadLogFile(File file) {
    1563     boolean ok = false;
    1564     try {
    1565       LogFileParser lfp = new LogFileParser(file);
    1566       lfp.parse(this);
    1567       ok = true;
    1568     } catch (IOException e) {
    1569       LogFactor5ErrorDialog error = new LogFactor5ErrorDialog(
    1570           getBaseFrame(), "Error reading " + file.getName());
    1571     }
    1572
    1573     return ok;
    1574   }
    1575
    1576   /**
    1577    * Loads a parses a log file running on a server.
    1578    */
    1579   protected boolean loadLogFile(URL url) {
    1580     boolean ok = false;
    1581     try {
    1582       LogFileParser lfp = new LogFileParser(url.openStream());
    1583       lfp.parse(this);
    1584       ok = true;
    1585     } catch (IOException e) {
    1586       LogFactor5ErrorDialog error = new LogFactor5ErrorDialog(
    1587           getBaseFrame(), "Error reading URL:" + url.getFile());
    1588     }
    1589     return ok;
    1590   }
    1591   //--------------------------------------------------------------------------
    1592   //   Private Methods:
    1593   //--------------------------------------------------------------------------
    1594
    1595   //--------------------------------------------------------------------------
    1596   //   Nested Top-Level Classes or Interfaces:
    1597   //--------------------------------------------------------------------------
    1598
    1599   class LogBrokerMonitorWindowAdaptor extends WindowAdapter {
    1600     protected LogBrokerMonitor _monitor;
    1601
    1602     public LogBrokerMonitorWindowAdaptor(LogBrokerMonitor monitor) {
    1603       _monitor = monitor;
    1604     }
    1605
    1606     public void windowClosing(WindowEvent ev) {
    1607       _monitor.requestClose();
    1608     }
    1609   }
    1610 }
    1611
    1612