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