You are viewing a plain text version of this content. The canonical link for it is here.
Posted to log4j-cvs@jakarta.apache.org by ce...@apache.org on 2002/04/26 17:48:44 UTC

cvs commit: jakarta-log4j/src/java/org/apache/log4j/lf5/viewer/images channelexplorer_new.gif channelexplorer_satellite.gif lf5_about.gif lf5_small_icon.gif lf5_small_icon.png

ceki        02/04/26 08:48:44

  Added:       src/java/org/apache/log4j/lf5 AppenderFinalizer.java
                        DefaultLF5Configurator.java LF5Appender.java
                        Log4JLogRecord.java LogLevel.java
                        LogLevelFormatException.java LogRecord.java
                        LogRecordFilter.java PassingLogRecordFilter.java
                        StartLogFactor5.java
               src/java/org/apache/log4j/lf5/util AdapterLogRecord.java
                        DateFormatManager.java LogFileParser.java
                        LogMonitorAdapter.java ProductProperties.java
                        Resource.java ResourceUtils.java StreamUtils.java
               src/java/org/apache/log4j/lf5/viewer
                        FilteredLogTableModel.java LF5SwingUtils.java
                        LogBrokerMonitor.java LogFactor5AboutDialog.java
                        LogFactor5Dialog.java LogFactor5ErrorDialog.java
                        LogFactor5InputDialog.java
                        LogFactor5LoadingDialog.java LogTable.java
                        LogTableColumn.java
                        LogTableColumnFormatException.java
                        LogTableModel.java LogTableRowRenderer.java
                        TrackingAdjustmentListener.java
               src/java/org/apache/log4j/lf5/viewer/categoryexplorer
                        CategoryAbstractCellEditor.java
                        CategoryElement.java
                        CategoryExplorerLogRecordFilter.java
                        CategoryExplorerModel.java
                        CategoryExplorerTree.java
                        CategoryImmediateEditor.java CategoryNode.java
                        CategoryNodeEditor.java
                        CategoryNodeEditorRenderer.java
                        CategoryNodeRenderer.java CategoryPath.java
                        TreeModelAdapter.java
               src/java/org/apache/log4j/lf5/viewer/configure
                        ConfigurationManager.java MRUFileManager.java
               src/java/org/apache/log4j/lf5/viewer/images
                        channelexplorer_new.gif
                        channelexplorer_satellite.gif lf5_about.gif
                        lf5_small_icon.gif lf5_small_icon.png
  Log:
  The paperwork for the donation of LogFactor5 is now complete and we
  are ready to add LogFactor5 source code to our CVS repository.
  
  Many thanks to Thoughtworks Inc. for their contribution and to Brad
  Marlborough for following through with the paperwork.
  
  Revision  Changes    Path
  1.1                  jakarta-log4j/src/java/org/apache/log4j/lf5/AppenderFinalizer.java
  
  Index: AppenderFinalizer.java
  ===================================================================
  /*
   * Copyright (C) The Apache Software Foundation. All rights reserved.
   *
   * This software is published under the terms of the Apache Software
   * License version 1.1, a copy of which has been included with this
   * distribution in the LICENSE.txt file.
   */
  package org.apache.log4j.lf5;
  
  import org.apache.log4j.lf5.viewer.LogBrokerMonitor;
  
  /**
   * <code>AppenderFinalizer</code> has a single method that will finalize
   * resources associated with a <code>LogBrokerMonitor</code> in the event
   * that the <code>LF5Appender</code> class is destroyed, and the class loader
   * is garbage collected.
   *
   * @author Brent Sprecher
   */
  
  // Contributed by ThoughtWorks Inc.
  
  public class AppenderFinalizer {
    //--------------------------------------------------------------------------
    // Constants:
    //--------------------------------------------------------------------------
  
    //--------------------------------------------------------------------------
    // Protected Variables:
    //--------------------------------------------------------------------------
  
    protected LogBrokerMonitor _defaultMonitor = null;
  
    //--------------------------------------------------------------------------
    // Private Variables:
    //--------------------------------------------------------------------------
  
    //--------------------------------------------------------------------------
    // Constructors:
    //--------------------------------------------------------------------------
  
    public AppenderFinalizer(LogBrokerMonitor defaultMonitor) {
      _defaultMonitor = defaultMonitor;
    }
    //--------------------------------------------------------------------------
    // Public Methods:
    //--------------------------------------------------------------------------
  
    //--------------------------------------------------------------------------
    // Protected Methods:
    //--------------------------------------------------------------------------
  
    /**
     * @throws java.lang.Throwable
     */
    protected void finalize() throws Throwable {
      System.out.println("Disposing of the default LogBrokerMonitor instance");
      _defaultMonitor.dispose();
    }
  
    //--------------------------------------------------------------------------
    // Private Methods:
    //--------------------------------------------------------------------------
  
    //--------------------------------------------------------------------------
    // Nested Top-Level Classes or Interfaces:
    //--------------------------------------------------------------------------
  
  }
  
  
  1.1                  jakarta-log4j/src/java/org/apache/log4j/lf5/DefaultLF5Configurator.java
  
  Index: DefaultLF5Configurator.java
  ===================================================================
  /*
   * Copyright (C) The Apache Software Foundation. All rights reserved.
   *
   * This software is published under the terms of the Apache Software
   * License version 1.1, a copy of which has been included with this
   * distribution in the LICENSE.txt file.
   */
  
  package org.apache.log4j.lf5;
  
  import org.apache.log4j.PropertyConfigurator;
  import org.apache.log4j.spi.Configurator;
  import org.apache.log4j.spi.LoggerRepository;
  
  import java.io.IOException;
  import java.net.URL;
  
  /**
   * The <code>DefaultLF5Configurator</code> provides a default
   * configuration for the <code>LF5Appender</code>.
   *
   * Note: The preferred method for configuring a <code>LF5Appender</code>
   * is to use the <code>LF5Manager</code> class. This class ensures
   * that configuration does not occur multiple times, and improves system
   * performance. Reconfiguring the monitor multiple times can result in
   * unexpected behavior.
   *
   * @author Brent Sprecher
   */
  
  // Contributed by ThoughtWorks Inc.
  
  public class DefaultLF5Configurator implements Configurator {
    //--------------------------------------------------------------------------
    // Constants:
    //--------------------------------------------------------------------------
  
    //--------------------------------------------------------------------------
    // Protected Variables:
    //--------------------------------------------------------------------------
  
    //--------------------------------------------------------------------------
    // Private Variables:
    //--------------------------------------------------------------------------
  
    //--------------------------------------------------------------------------
    // Constructors:
    //--------------------------------------------------------------------------
    /**
     * This class should never be instantiated! It implements the <code>
     * Configurator</code>
     * interface, but does not provide the same functionality as full
     * configurator class.
     */
    private DefaultLF5Configurator() {
  
    }
  
    //--------------------------------------------------------------------------
    // Public Methods:
    //--------------------------------------------------------------------------
    /**
     * This method configures the <code>LF5Appender</code> using a
     * default configuration file. The default configuration file is
     * <bold>defaultconfig.properties</bold>.
     * @throws java.io.IOException
     */
    public static void configure() throws IOException {
      String resource =
          "/org/apache/log4j/lf5/config/defaultconfig.properties";
      URL configFileResource =
          DefaultLF5Configurator.class.getResource(resource);
  
      if (configFileResource != null) {
        PropertyConfigurator.configure(configFileResource);
      } else {
        throw new IOException("Error: Unable to open the resource" +
            resource);
      }
  
    }
  
    /**
     * This is a dummy method that will throw an
     * <code>IllegalStateException</code> if used.
     */
    public void doConfigure(URL configURL, LoggerRepository repository) {
      throw new IllegalStateException("This class should NOT be" +
          " instantiated!");
    }
  
    //--------------------------------------------------------------------------
    // Protected Methods:
    //--------------------------------------------------------------------------
  
    //--------------------------------------------------------------------------
    // Private Methods:
    //--------------------------------------------------------------------------
  
    //--------------------------------------------------------------------------
    // Nested Top-Level Classes or Interfaces:
    //--------------------------------------------------------------------------
  
  }
  
  
  1.1                  jakarta-log4j/src/java/org/apache/log4j/lf5/LF5Appender.java
  
  Index: LF5Appender.java
  ===================================================================
  /*
   * Copyright (C) The Apache Software Foundation. All rights reserved.
   *
   * This software is published under the terms of the Apache Software
   * License version 1.1, a copy of which has been included with this
   * distribution in the LICENSE.txt file.
   */
  
  package org.apache.log4j.lf5;
  
  import org.apache.log4j.lf5.util.Resource;
  import org.apache.log4j.lf5.viewer.LogBrokerMonitor;
  import org.apache.log4j.AppenderSkeleton;
  import org.apache.log4j.spi.LocationInfo;
  import org.apache.log4j.spi.LoggingEvent;
  
  import java.awt.*;
  
  /**
   * <code>LF5Appender</code> logs events to a swing based logging
   * console. The swing console supports turning categories on and off,
   * multiple detail level views, as well as full text searching and many
   * other capabilties.
   *
   * @author Brent Sprecher
   */
  
  // Contributed by ThoughtWorks Inc.
  
  public class LF5Appender extends AppenderSkeleton {
    //--------------------------------------------------------------------------
    // Constants:
    //--------------------------------------------------------------------------
  
    //--------------------------------------------------------------------------
    // Protected Variables:
    //--------------------------------------------------------------------------
  
    protected LogBrokerMonitor _logMonitor;
    protected static LogBrokerMonitor _defaultLogMonitor;
    protected static AppenderFinalizer _finalizer;
  
    //--------------------------------------------------------------------------
    // Private Variables:
    //--------------------------------------------------------------------------
  
    //--------------------------------------------------------------------------
    // Constructors:
    //--------------------------------------------------------------------------
  
    /**
     * Constructs a <code>LF5Appender</code> using the default instance of
     * the <code>LogBrokerMonitor</code>. This constructor should <bold>always
     * </bold> be  preferred over the
     * <code>LF5Appender(LogBrokerMonitor monitor)</code>
     * constructor, unless you need to spawn additional log monitoring
     * windows.
     */
    public LF5Appender() {
      this(getDefaultInstance());
    }
  
    /**
     * Constructs a <code>LF5Appender<code> using an instance of
     * a <code>LogBrokerMonitor<code> supplied by the user. This
     * constructor should only be used when you need to spawn
     * additional log monitoring windows.
     *
     * @param monitor An instance of a <code>LogBrokerMonitor<code>
     * created by the user.
     */
    public LF5Appender(LogBrokerMonitor monitor) {
  
      if (monitor != null) {
        _logMonitor = monitor;
      }
    }
  
    //--------------------------------------------------------------------------
    // Public Methods:
    //--------------------------------------------------------------------------
  
    /**
     * Appends a <code>LoggingEvent</code> record to the
     * <code>LF5Appender</code>.
     * @param event The <code>LoggingEvent</code>
     * to be appended.
     */
    public void append(LoggingEvent event) {
      // Retrieve the information from the log4j LoggingEvent.
      String category = event.categoryName;
      String logMessage = event.getRenderedMessage();
      String nestedDiagnosticContext = event.getNDC();
      String threadDescription = event.getThreadName();
      String level = event.level.toString();
      long time = event.timeStamp;
      LocationInfo locationInfo = event.getLocationInformation();
  
      // Add the logging event information to a LogRecord
      Log4JLogRecord record = new Log4JLogRecord();
  
      record.setCategory(category);
      record.setMessage(logMessage);
      record.setLocation(locationInfo.fullInfo);
      record.setMillis(time);
      record.setThreadDescription(threadDescription);
  
      if (nestedDiagnosticContext != null) {
        record.setNDC(nestedDiagnosticContext);
      } else {
        record.setNDC("");
      }
  
      if (event.getThrowableInformation() != null) {
        record.setThrownStackTrace(event.getThrowableInformation());
      }
  
      try {
        record.setLevel(LogLevel.valueOf(level));
      } catch (LogLevelFormatException e) {
        // If the priority level doesn't match one of the predefined
        // log levels, then set the level to warning.
        record.setLevel(LogLevel.WARN);
      }
  
      if (_logMonitor != null) {
        _logMonitor.addMessage(record);
      }
    }
  
    /**
     * This method is an empty implementation of the close() method inherited
     * from the <code>org.apache.log4j.Appender</code> interface.
     */
    public void close() {
    }
  
    /**
     * Returns a value that indicates whether this appender requires a
     * <code>Layout</code>. This method always returns false.
     * No layout is required for the <code>LF5Appender</code>.
     */
    public boolean requiresLayout() {
      return false;
    }
  
    /**
     * This method is used to set the property that controls whether
     * the <code>LogBrokerMonitor</code> is hidden or closed when a user
     * exits
     * the monitor. By default, the <code>LogBrokerMonitor</code> will hide
     * itself when the log window is exited, and the swing thread will
     * continue to run in the background. If this property is
     * set to true, the <code>LogBrokerMonitor</code> will call System.exit(0)
     * and will shut down swing thread and the virtual machine.
     *
     * @param callSystemExitOnClose A boolean value indicating whether
     * to call System.exit(0) when closing the log window.
     */
    public void setCallSystemExitOnClose(boolean callSystemExitOnClose) {
      _logMonitor.setCallSystemExitOnClose(callSystemExitOnClose);
    }
  
    /**
     * The equals method compares two LF5Appenders and determines whether
     * they are equal. Two <code>Appenders</code> will be considered equal
     * if, and only if, they both contain references to the same <code>
     * LogBrokerMonitor</code>.
     *
     * @param compareTo A boolean value indicating whether
     * the two LF5Appenders are equal.
     */
    public boolean equals(LF5Appender compareTo) {
      // If both reference the same LogBrokerMonitor, they are equal.
      return _logMonitor == compareTo.getLogBrokerMonitor();
    }
  
    public LogBrokerMonitor getLogBrokerMonitor() {
      return _logMonitor;
    }
  
    public static void main(String[] args) {
      new LF5Appender();
    }
  
    public void setMaxNumberOfRecords(int maxNumberOfRecords) {
      _defaultLogMonitor.setMaxNumberOfLogRecords(maxNumberOfRecords);
    }
    //--------------------------------------------------------------------------
    // Protected Methods:
    //--------------------------------------------------------------------------
  
    /**
     * @return The default instance of the <code>LogBrokerMonitor</code>.
     */
    protected static synchronized LogBrokerMonitor getDefaultInstance() {
      if (_defaultLogMonitor == null) {
        try {
          _defaultLogMonitor =
              new LogBrokerMonitor(LogLevel.getLog4JLevels());
          _finalizer = new AppenderFinalizer(_defaultLogMonitor);
  
          _defaultLogMonitor.setFrameSize(getDefaultMonitorWidth(),
              getDefaultMonitorHeight());
          _defaultLogMonitor.setFontSize(12);
          _defaultLogMonitor.show();
  
        } catch (SecurityException e) {
          _defaultLogMonitor = null;
        }
      }
  
      return _defaultLogMonitor;
    }
  
    /**
     * @return the screen width from Toolkit.getScreenSize()
     * if possible, otherwise returns 800
     * @see java.awt.Toolkit
     */
    protected static int getScreenWidth() {
      try {
        return Toolkit.getDefaultToolkit().getScreenSize().width;
      } catch (Throwable t) {
        return 800;
      }
    }
  
    /**
     * @return the screen height from Toolkit.getScreenSize()
     * if possible, otherwise returns 600
     * @see java.awt.Toolkit
     */
    protected static int getScreenHeight() {
      try {
        return Toolkit.getDefaultToolkit().getScreenSize().height;
      } catch (Throwable t) {
        return 600;
      }
    }
  
    protected static int getDefaultMonitorWidth() {
      return (3 * getScreenWidth()) / 4;
    }
  
    protected static int getDefaultMonitorHeight() {
      return (3 * getScreenHeight()) / 4;
    }
    //--------------------------------------------------------------------------
    // Private Methods:
    //--------------------------------------------------------------------------
  
  
    //--------------------------------------------------------------------------
    // Nested Top-Level Classes or Interfaces:
    //--------------------------------------------------------------------------
  
  }
  
  
  1.1                  jakarta-log4j/src/java/org/apache/log4j/lf5/Log4JLogRecord.java
  
  Index: Log4JLogRecord.java
  ===================================================================
  /*
   * Copyright (C) The Apache Software Foundation. All rights reserved.
   *
   * This software is published under the terms of the Apache Software
   * License version 1.1, a copy of which has been included with this
   * distribution in the LICENSE.txt file.
   */
  
  package org.apache.log4j.lf5;
  
  import org.apache.log4j.spi.ThrowableInformation;
  
  /**
   * A <code>Log4JLogRecord</code> encapsulates
   * the details of your log4j <code>LoggingEvent</code> in a format usable
   * by the <code>LogBrokerMonitor</code>.
   *
   * @author Brent Sprecher
   */
  
  // Contributed by ThoughtWorks Inc.
  
  public class Log4JLogRecord extends LogRecord {
    //--------------------------------------------------------------------------
    //   Constants:
    //--------------------------------------------------------------------------
  
    //--------------------------------------------------------------------------
    //   Protected Variables:
    //--------------------------------------------------------------------------
  
    //--------------------------------------------------------------------------
    //   Private Variables:
    //--------------------------------------------------------------------------
  
    //--------------------------------------------------------------------------
    //   Constructors:
    //--------------------------------------------------------------------------
  
    /**
     * Constructs an instance of a <code>Log4JLogRecord</code>.
     */
    public Log4JLogRecord() {
    }
  
    //--------------------------------------------------------------------------
    //   Public Methods:
    //--------------------------------------------------------------------------
    /**
     * Determines which <code>Priority</code> levels will
     * be displayed in colored font when the <code>LogMonitorAppender</code>
     * renders this log message. By default, messages will be colored
     * red if they are of <code>Priority</code> ERROR or FATAL.
     *
     * @return true if the log level is ERROR or FATAL.
     */
    public boolean isSevereLevel() {
      boolean isSevere = false;
  
      if (LogLevel.ERROR.equals(getLevel()) ||
          LogLevel.FATAL.equals(getLevel())) {
        isSevere = true;
      }
  
      return isSevere;
    }
  
    /**
     * Set stack trace information associated with this Log4JLogRecord.
     * When this method is called, the stack trace in a
     * String-based format is made
     * available via the getThrownStackTrace() method.
     *
     * @param throwableInfo An org.apache.log4j.spi.ThrowableInformation to
     * associate with this Log4JLogRecord.
     * @see #getThrownStackTrace()
     */
    public void setThrownStackTrace(ThrowableInformation throwableInfo) {
      String[] stackTraceArray = throwableInfo.getThrowableStrRep();
  
      StringBuffer stackTrace = new StringBuffer();
      String nextLine;
  
      for (int i = 0; i < stackTraceArray.length; i++) {
        nextLine = stackTraceArray[i] + "\n";
        stackTrace.append(nextLine);
      }
  
      _thrownStackTrace = stackTrace.toString();
    }
  
    //--------------------------------------------------------------------------
    //   Protected Methods:
    //--------------------------------------------------------------------------
  
    //--------------------------------------------------------------------------
    //   Private Methods:
    //--------------------------------------------------------------------------
  
    //--------------------------------------------------------------------------
    //   Nested Top-Level Classes or Interfaces:
    //--------------------------------------------------------------------------
  
  }
  
  
  
  
  
  
  1.1                  jakarta-log4j/src/java/org/apache/log4j/lf5/LogLevel.java
  
  Index: LogLevel.java
  ===================================================================
  /*
   * Copyright (C) The Apache Software Foundation. All rights reserved.
   *
   * This software is published under the terms of the Apache Software
   * License version 1.1, a copy of which has been included with this
   * distribution in the LICENSE.txt file.
   */
  package org.apache.log4j.lf5;
  
  import java.awt.*;
  import java.util.*;
  import java.util.List;
  
  /**
   * The LogLevel class defines a set of standard logging levels.
   *
   * The logging Level objects are ordered and are specified by ordered
   * integers. Enabling logging at a given level also enables logging at all
   * higher levels.
   *
   * @author Michael J. Sikorsky
   * @author Robert Shaw
   * @author Brent Sprecher
   * @author Richard Hurst
   * @author Brad Marlborough
   */
  
  // Contributed by ThoughtWorks Inc.
  
  public class LogLevel implements java.io.Serializable {
    //--------------------------------------------------------------------------
    //   Constants:
    //--------------------------------------------------------------------------
  
    // log4j log levels.
    public final static LogLevel FATAL = new LogLevel("FATAL", 0);
    public final static LogLevel ERROR = new LogLevel("ERROR", 1);
    public final static LogLevel WARN = new LogLevel("WARN", 2);
    public final static LogLevel INFO = new LogLevel("INFO", 3);
    public final static LogLevel DEBUG = new LogLevel("DEBUG", 4);
  
    // jdk1.4 log levels NOTE: also includes INFO
    public final static LogLevel SEVERE = new LogLevel("SEVERE", 1);
    public final static LogLevel WARNING = new LogLevel("WARNING", 2);
    public final static LogLevel CONFIG = new LogLevel("CONFIG", 4);
    public final static LogLevel FINE = new LogLevel("FINE", 5);
    public final static LogLevel FINER = new LogLevel("FINER", 6);
    public final static LogLevel FINEST = new LogLevel("FINEST", 7);
  
    //--------------------------------------------------------------------------
    //   Protected Variables:
    //--------------------------------------------------------------------------
    protected String _label;
    protected int _precedence;
    //--------------------------------------------------------------------------
    //   Private Variables:
    //--------------------------------------------------------------------------
    private static LogLevel[] _log4JLevels;
    private static LogLevel[] _jdk14Levels;
    private static LogLevel[] _allDefaultLevels;
    private static Map _logLevelMap;
    private static Map _logLevelColorMap;
    private static Map _registeredLogLevelMap = new HashMap();
  
    //--------------------------------------------------------------------------
    //   Constructors:
    //--------------------------------------------------------------------------
    static {
      _log4JLevels = new LogLevel[]{FATAL, ERROR, WARN, INFO, DEBUG};
      _jdk14Levels = new LogLevel[]{SEVERE, WARNING, INFO,
                                    CONFIG, FINE, FINER, FINEST};
      _allDefaultLevels = new LogLevel[]{FATAL, ERROR, WARN, INFO, DEBUG,
                                         SEVERE, WARNING, CONFIG, FINE, FINER, FINEST};
  
      _logLevelMap = new HashMap();
      for (int i = 0; i < _allDefaultLevels.length; i++) {
        _logLevelMap.put(_allDefaultLevels[i].getLabel(), _allDefaultLevels[i]);
      }
  
      // prepopulate map with levels and text color of black
      _logLevelColorMap = new HashMap();
      for (int i = 0; i < _allDefaultLevels.length; i++) {
        _logLevelColorMap.put(_allDefaultLevels[i], Color.black);
      }
    }
  
    public LogLevel(String label, int precedence) {
      _label = label;
      _precedence = precedence;
    }
  
    //--------------------------------------------------------------------------
    //   Public Methods:
    //--------------------------------------------------------------------------
  
    /**
     * Return the Label of the LogLevel.
     */
    public String getLabel() {
      return _label;
    }
  
    /**
     * Returns true if the level supplied is encompassed by this level.
     * For example, LogLevel.SEVERE encompasses no other LogLevels and
     * LogLevel.FINE encompasses all other LogLevels.  By definition,
     * a LogLevel encompasses itself.
     */
    public boolean encompasses(LogLevel level) {
      if (level.getPrecedence() <= getPrecedence()) {
        return true;
      }
  
      return false;
    }
  
    /**
     * Convert a log level label into a LogLevel object.
     *
     * @param level The label of a level to be converted into a LogLevel.
     * @return LogLevel The LogLevel with a label equal to level.
     * @throws LogLevelFormatException Is thrown when the level can not be
     *         converted into a LogLevel.
     */
    public static LogLevel valueOf(String level)
        throws LogLevelFormatException {
      LogLevel logLevel = null;
      if (level != null) {
        level = level.trim().toUpperCase();
        logLevel = (LogLevel) _logLevelMap.get(level);
      }
  
      // Didn't match, Check for registered LogLevels
      if (logLevel == null && _registeredLogLevelMap.size() > 0) {
        logLevel = (LogLevel) _registeredLogLevelMap.get(level);
      }
  
      if (logLevel == null) {
        StringBuffer buf = new StringBuffer();
        buf.append("Error while trying to parse (" + level + ") into");
        buf.append(" a LogLevel.");
        throw new LogLevelFormatException(buf.toString());
      }
      return logLevel;
    }
  
    /**
     * Registers a used defined LogLevel.
     *
     * @param logLevel The log level to be registered. Cannot be a default LogLevel
     * @return LogLevel The replaced log level.
     */
    public static LogLevel register(LogLevel logLevel) {
      if (logLevel == null) return null;
  
      // ensure that this is not a default log level
      if (_logLevelMap.get(logLevel.getLabel()) == null) {
        return (LogLevel) _registeredLogLevelMap.put(logLevel.getLabel(), logLevel);
      }
  
      return null;
    }
  
    public static void register(LogLevel[] logLevels) {
      if (logLevels != null) {
        for (int i = 0; i < logLevels.length; i++) {
          register(logLevels[i]);
        }
      }
    }
  
    public static void register(List logLevels) {
      if (logLevels != null) {
        Iterator it = logLevels.iterator();
        while (it.hasNext()) {
          register((LogLevel) it.next());
        }
      }
    }
  
    public boolean equals(Object o) {
      boolean equals = false;
  
      if (o instanceof LogLevel) {
        if (this.getPrecedence() ==
            ((LogLevel) o).getPrecedence()) {
          equals = true;
        }
  
      }
  
      return equals;
    }
  
    public int hashCode() {
      return _label.hashCode();
    }
  
    public String toString() {
      return _label;
    }
  
    // set a text color for a specific log level
    public void setLogLevelColorMap(LogLevel level, Color color) {
      // remove the old entry
      _logLevelColorMap.remove(level);
      // add the new color entry
      if (color == null) {
        color = Color.black;
      }
      _logLevelColorMap.put(level, color);
    }
  
    public static void resetLogLevelColorMap() {
      // empty the map
      _logLevelColorMap.clear();
  
      // repopulate map and reset text color black
      for (int i = 0; i < _allDefaultLevels.length; i++) {
        _logLevelColorMap.put(_allDefaultLevels[i], Color.black);
      }
    }
  
    /**
     * @return A <code>List</code> of <code>LogLevel</code> objects that map
     * to log4j <code>Priority</code> objects.
     */
    public static List getLog4JLevels() {
      return Arrays.asList(_log4JLevels);
    }
  
    public static List getJdk14Levels() {
      return Arrays.asList(_jdk14Levels);
    }
  
    public static List getAllDefaultLevels() {
      return Arrays.asList(_allDefaultLevels);
    }
  
    public static Map getLogLevelColorMap() {
      return _logLevelColorMap;
    }
  
    //--------------------------------------------------------------------------
    //   Protected Methods:
    //--------------------------------------------------------------------------
  
    protected int getPrecedence() {
      return _precedence;
    }
  
    //--------------------------------------------------------------------------
    //   Private Methods:
    //--------------------------------------------------------------------------
  
    //--------------------------------------------------------------------------
    //   Nested Top-Level Classes or Interfaces:
    //--------------------------------------------------------------------------
  
  }
  
  
  
  
  
  
  
  
  
  1.1                  jakarta-log4j/src/java/org/apache/log4j/lf5/LogLevelFormatException.java
  
  Index: LogLevelFormatException.java
  ===================================================================
  /*
   * Copyright (C) The Apache Software Foundation. All rights reserved.
   *
   * This software is published under the terms of the Apache Software
   * License version 1.1, a copy of which has been included with this
   * distribution in the LICENSE.txt file.
   */
  package org.apache.log4j.lf5;
  
  /**
   * Thrown to indicate that the client has attempted to convert a string
   * to one the LogLevel types, but the string does not have the appropriate
   * format.
   *
   * @author Michael J. Sikorsky<
   * @author Robert Shaw
   */
  
  // Contributed by ThoughtWorks Inc.
  
  public class LogLevelFormatException extends Exception {
    //--------------------------------------------------------------------------
    //   Constants:
    //--------------------------------------------------------------------------
  
    //--------------------------------------------------------------------------
    //   Protected Variables:
    //--------------------------------------------------------------------------
  
    //--------------------------------------------------------------------------
    //   Private Variables:
    //--------------------------------------------------------------------------
  
    //--------------------------------------------------------------------------
    //   Constructors:
    //--------------------------------------------------------------------------
  
    public LogLevelFormatException(String message) {
      super(message);
    }
  
    //--------------------------------------------------------------------------
    //   Public Methods:
    //--------------------------------------------------------------------------
  
    //--------------------------------------------------------------------------
    //   Protected Methods:
    //--------------------------------------------------------------------------
  
    //--------------------------------------------------------------------------
    //   Private Methods:
    //--------------------------------------------------------------------------
  
    //--------------------------------------------------------------------------
    //   Nested Top-Level Classes or Interfaces:
    //--------------------------------------------------------------------------
  
  }
  
  
  
  
  
  
  
  
  
  1.1                  jakarta-log4j/src/java/org/apache/log4j/lf5/LogRecord.java
  
  Index: LogRecord.java
  ===================================================================
  /*
   * Copyright (C) The Apache Software Foundation. All rights reserved.
   *
   * This software is published under the terms of the Apache Software
   * License version 1.1, a copy of which has been included with this
   * distribution in the LICENSE.txt file.
   */
  package org.apache.log4j.lf5;
  
  import java.io.IOException;
  import java.io.PrintWriter;
  import java.io.StringWriter;
  
  /**
   * LogRecord.  A LogRecord encapsulates the details of your desired log
   * request.
   *
   * @author Michael J. Sikorsky
   * @author Robert Shaw
   */
  
  // Contributed by ThoughtWorks Inc.
  
  public abstract class LogRecord implements java.io.Serializable {
    //--------------------------------------------------------------------------
    //   Constants:
    //--------------------------------------------------------------------------
  
    //--------------------------------------------------------------------------
    //   Protected Variables:
    //--------------------------------------------------------------------------
    protected static long _seqCount = 0;
  
    protected LogLevel _level;
    protected String _message;
    protected long _sequenceNumber;
    protected long _millis;
    protected String _category;
    protected String _thread;
    protected String _thrownStackTrace;
    protected Throwable _thrown;
    protected String _ndc;
    protected String _location;
  
    //--------------------------------------------------------------------------
    //   Private Variables:
    //--------------------------------------------------------------------------
  
    //--------------------------------------------------------------------------
    //   Constructors:
    //--------------------------------------------------------------------------
  
    public LogRecord() {
      super();
  
      _millis = System.currentTimeMillis();
      _category = "Debug";
      _message = "";
      _level = LogLevel.INFO;
      _sequenceNumber = getNextId();
      _thread = Thread.currentThread().toString();
      _ndc = "";
      _location = "";
    }
  
    //--------------------------------------------------------------------------
    //   Public Methods:
    //--------------------------------------------------------------------------
  
    /**
     * Get the level of this LogRecord.
     *
     * @return The LogLevel of this record.
     * @see #setLevel(LogLevel)
     * @see LogLevel
     */
    public LogLevel getLevel() {
      return (_level);
    }
  
    /**
     * Set the level of this LogRecord.
     *
     * @param level The LogLevel for this record.
     * @see #getLevel()
     * @see LogLevel
     */
    public void setLevel(LogLevel level) {
      _level = level;
    }
  
    /**
     * Abstract method. Must be overridden to indicate what log level
     * to show in red.
     */
    public abstract boolean isSevereLevel();
  
    /**
     * @return true if getThrown().toString() is a non-empty string.
     */
    public boolean hasThrown() {
      Throwable thrown = getThrown();
      if (thrown == null) {
        return false;
      }
      String thrownString = thrown.toString();
      return thrownString != null && thrownString.trim().length() != 0;
    }
  
    /**
     * @return true if isSevereLevel() or hasThrown() returns true.
     */
    public boolean isFatal() {
      return isSevereLevel() || hasThrown();
    }
  
    /**
     * Get the category asscociated with this LogRecord.  For a more detailed
     * description of what a category is see setCategory().
     *
     * @return The category of this record.
     * @see #setCategory(String)
     */
    public String getCategory() {
      return (_category);
    }
  
    /**
     * Set the category associated with this LogRecord. A category represents
     * a hierarchical dot (".") separated namespace for messages.
     * The definition of a category is application specific, but a common convention
     * is as follows:
     *
     * <p>
     * When logging messages
     * for a particluar class you can use its class name:
     * com.thoughtworks.framework.servlet.ServletServiceBroker.<br><br>
     * Futhermore, to log a message for a particular method in a class
     * add the method name:
     * com.thoughtworks.framework.servlet.ServletServiceBroker.init().
     * </p>
     *
     * @param category The category for this record.
     * @see #getCategory()
     */
    public void setCategory(String category) {
      _category = category;
    }
  
    /**
     * Get the message asscociated with this LogRecord.
     *
     * @return The message of this record.
     * @see #setMessage(String)
     */
    public String getMessage() {
      return (_message);
    }
  
    /**
     * Set the message associated with this LogRecord.
     *
     * @param message The message for this record.
     * @see #getMessage()
     */
    public void setMessage(String message) {
      _message = message;
    }
  
    /**
     * Get the sequence number associated with this LogRecord.  Sequence numbers
     * are generally assigned when a LogRecord is constructed.  Sequence numbers
     * start at 0 and increase with each newly constructed LogRocord.
     *
     * @return The sequence number of this record.
     * @see #setSequenceNumber(long)
     */
    public long getSequenceNumber() {
      return (_sequenceNumber);
    }
  
    /**
     * Set the sequence number assocsiated with this LogRecord.  A sequence number
     * will automatically be assigned to evey newly constructed LogRecord, however,
     * this method can override the value.
     *
     * @param number The sequence number.
     * @see #getSequenceNumber()
     */
    public void setSequenceNumber(long number) {
      _sequenceNumber = number;
    }
  
    /**
     * Get the event time of this record in milliseconds from 1970.
     * When a LogRecord is constructed the event time is set but may be
     * overridden by calling setMillis();
     *
     * @return The event time of this record in milliseconds from 1970.
     * @see #setMillis(long)
     */
    public long getMillis() {
      return _millis;
    }
  
    /**
     * Set the event time of this record.  When a LogRecord is constructed
     * the event time is set but may be overridden by calling this method.
     *
     * @param millis The time in milliseconds from 1970.
     * @see #getMillis()
     */
    public void setMillis(long millis) {
      _millis = millis;
    }
  
    /**
     * Get the thread description asscociated with this LogRecord.  When a
     * LogRecord is constructed, the thread description is set by calling:
     * Thread.currentThread().toString().  You may supply a thread description
     * of your own by calling the setThreadDescription(String) method.
     *
     * @return The thread description of this record.
     * @see #setThreadDescription(String)
     */
    public String getThreadDescription() {
      return (_thread);
    }
  
    /**
     * Set the thread description associated with this LogRecord.  When a
     * LogRecord is constructed, the thread description is set by calling:
     * Thread.currentThread().toString().  You may supply a thread description
     * of your own by calling this method.
     *
     * @param threadDescription The description of the thread for this record.
     * @see #getThreadDescription()
     */
    public void setThreadDescription(String threadDescription) {
      _thread = threadDescription;
    }
  
    /**
     * Get the stack trace in a String-based format for the associated Throwable
     * of this LogRecord.  The stack trace in a String-based format is set
     * when the setThrown(Throwable) method is called.
     *
     * <p>
     * Why do we need this method considering that we
     * have the getThrown() and setThrown() methods?
     * A Throwable object may not be serializable, however, a String representation
     * of it is.  Users of LogRecords should generally call this method over
     * getThrown() for the reasons of serialization.
     * </p>
     *
     * @return The Stack Trace for the asscoiated Throwable of this LogRecord.
     * @see #setThrown(Throwable)
     * @see #getThrown()
     */
    public String getThrownStackTrace() {
      return (_thrownStackTrace);
    }
  
    /**
     * Set the ThrownStackTrace for the log record.
     *
     * @param trace A String to associate with this LogRecord
     * @see #getThrownStackTrace()
     */
    public void setThrownStackTrace(String trace) {
      _thrownStackTrace = trace;
    }
  
    /**
     * Get the Throwable associated with this LogRecord.
     *
     * @return The LogLevel of this record.
     * @see #setThrown(Throwable)
     * @see #getThrownStackTrace()
     */
    public Throwable getThrown() {
      return (_thrown);
    }
  
    /**
     * Set the Throwable associated with this LogRecord.  When this method
     * is called, the stack trace in a String-based format is made
     * available via the getThrownStackTrace() method.
     *
     * @param thrown A Throwable to associate with this LogRecord.
     * @see #getThrown()
     * @see #getThrownStackTrace()
     */
    public void setThrown(Throwable thrown) {
      if (thrown == null) {
        return;
      }
      _thrown = thrown;
      StringWriter sw = new StringWriter();
      PrintWriter out = new PrintWriter(sw);
      thrown.printStackTrace(out);
      out.flush();
      _thrownStackTrace = sw.toString();
      try {
        out.close();
        sw.close();
      } catch (IOException e) {
        // Do nothing, this should not happen as it is StringWriter.
      }
      out = null;
      sw = null;
    }
  
    /**
     * Return a String representation of this LogRecord.
     */
    public String toString() {
      StringBuffer buf = new StringBuffer();
      buf.append("LogRecord: [" + _level + ", " + _message + "]");
      return (buf.toString());
    }
  
    /**
     * Get the NDC (nested diagnostic context) for this record.
     *
     * @return The string representing the NDC.
     */
    public String getNDC() {
      return _ndc;
    }
  
    /**
     * Set the NDC (nested diagnostic context) for this record.
     *
     * @param ndc A string representing the NDC.
     */
    public void setNDC(String ndc) {
      _ndc = ndc;
    }
  
    /**
     * Get the location in code where this LogRecord originated.
     *
     * @return The string containing the location information.
     */
    public String getLocation() {
      return _location;
    }
  
    /**
     * Set the location in code where this LogRecord originated.
     *
     * @param ndc A string containing location information.
     */
    public void setLocation(String location) {
      _location = location;
    }
  
    /**
     * Resets that sequence number to 0.
     *
     */
    public static synchronized void resetSequenceNumber() {
      _seqCount = 0;
    }
  
    //--------------------------------------------------------------------------
    //   Protected Methods:
    //--------------------------------------------------------------------------
  
    protected static synchronized long getNextId() {
      _seqCount++;
      return _seqCount;
    }
    //--------------------------------------------------------------------------
    //   Private Methods:
    //--------------------------------------------------------------------------
  
    //--------------------------------------------------------------------------
    //   Nested Top-Level Classes or Interfaces:
    //--------------------------------------------------------------------------
  
  }
  
  
  
  
  
  
  1.1                  jakarta-log4j/src/java/org/apache/log4j/lf5/LogRecordFilter.java
  
  Index: LogRecordFilter.java
  ===================================================================
  /*
   * Copyright (C) The Apache Software Foundation. All rights reserved.
   *
   * This software is published under the terms of the Apache Software
   * License version 1.1, a copy of which has been included with this
   * distribution in the LICENSE.txt file.
   */
  package org.apache.log4j.lf5;
  
  
  /**
   * An interface for classes which filters LogRecords.  Implementations
   * represent a rule or condition which LogRecords may pass or fail.
   * @see LogRecord
   *
   * @author Richard Wan
   */
  
  // Contributed by ThoughtWorks Inc.
  
  public interface LogRecordFilter {
    //--------------------------------------------------------------------------
    //   Constants:
    //--------------------------------------------------------------------------
  
    //--------------------------------------------------------------------------
    //   Public Methods:
    //--------------------------------------------------------------------------
  
    /**
     * @return true if the specified LogRecord satisfies whatever condition
     * implementing class tests for.
     */
    public boolean passes(LogRecord record);
  
  }
  
  
  
  
  1.1                  jakarta-log4j/src/java/org/apache/log4j/lf5/PassingLogRecordFilter.java
  
  Index: PassingLogRecordFilter.java
  ===================================================================
  /*
   * Copyright (C) The Apache Software Foundation. All rights reserved.
   *
   * This software is published under the terms of the Apache Software
   * License version 1.1, a copy of which has been included with this
   * distribution in the LICENSE.txt file.
   */
  package org.apache.log4j.lf5;
  
  
  /**
   * An implementation of LogRecordFilter which always returns true.
   *
   * @author Richard Wan
   */
  
  // Contributed by ThoughtWorks Inc.
  
  public class PassingLogRecordFilter implements LogRecordFilter {
    //--------------------------------------------------------------------------
    //   Constants:
    //--------------------------------------------------------------------------
  
    //--------------------------------------------------------------------------
    //   Protected Variables:
    //--------------------------------------------------------------------------
  
    //--------------------------------------------------------------------------
    //   Private Variables:
    //--------------------------------------------------------------------------
  
    //--------------------------------------------------------------------------
    //   Constructors:
    //--------------------------------------------------------------------------
  
    //--------------------------------------------------------------------------
    //   Public Methods:
    //--------------------------------------------------------------------------
  
    /**
     * @return true;
     */
    public boolean passes(LogRecord record) {
      return true;
    }
  
    /**
     * Does nothing.
     */
    public void reset() {
      // do nothing
    }
    //--------------------------------------------------------------------------
    //   Protected Methods:
    //--------------------------------------------------------------------------
  
    //--------------------------------------------------------------------------
    //   Private Methods:
    //--------------------------------------------------------------------------
  
    //--------------------------------------------------------------------------
    //   Nested Top-Level Classes or Interfaces
    //--------------------------------------------------------------------------
  }
  
  
  
  
  1.1                  jakarta-log4j/src/java/org/apache/log4j/lf5/StartLogFactor5.java
  
  Index: StartLogFactor5.java
  ===================================================================
  /*
   * Copyright (C) The Apache Software Foundation. All rights reserved.
   *
   * This software is published under the terms of the Apache Software
   * License version 1.1, a copy of which has been included with this
   * distribution in the LICENSE.txt file.
   */
  package org.apache.log4j.lf5;
  
  import org.apache.log4j.lf5.viewer.LogBrokerMonitor;
  
  /**
   * Starts an instance of the LogFactor5 console for off-line viewing.
   *
   * @author Brad Marlborough
   * @author Richard Hurst
   */
  
  // Contributed by ThoughtWorks Inc.
  
  public class StartLogFactor5 {
    //--------------------------------------------------------------------------
    //   Constants:
    //--------------------------------------------------------------------------
  
    //--------------------------------------------------------------------------
    //   Protected Variables:
    //--------------------------------------------------------------------------
  
    //--------------------------------------------------------------------------
    //   Private Variables:
    //--------------------------------------------------------------------------
  
    //--------------------------------------------------------------------------
    //   Constructors:
    //--------------------------------------------------------------------------
  
    //--------------------------------------------------------------------------
    //   Public Methods:
    //--------------------------------------------------------------------------
  
    /**
     * Main - starts a an instance of the LogFactor5 console and configures
     * the console settings.
     */
    public final static void main(String[] args) {
  
      LogBrokerMonitor monitor = new LogBrokerMonitor(
          LogLevel.getLog4JLevels());
  
      monitor.setFrameSize(LF5Appender.getDefaultMonitorWidth(),
          LF5Appender.getDefaultMonitorHeight());
      monitor.setFontSize(12);
      monitor.show();
  
    }
  
    //--------------------------------------------------------------------------
    //   Protected Methods:
    //--------------------------------------------------------------------------
  
    //--------------------------------------------------------------------------
    //   Private Methods:
    //--------------------------------------------------------------------------
  
    //--------------------------------------------------------------------------
    //   Nested Top-Level Classes or Interfaces
    //--------------------------------------------------------------------------
  
  }
  
  
  
  
  
  1.1                  jakarta-log4j/src/java/org/apache/log4j/lf5/util/AdapterLogRecord.java
  
  Index: AdapterLogRecord.java
  ===================================================================
  /*
   * Copyright (C) The Apache Software Foundation. All rights reserved.
   *
   * This software is published under the terms of the Apache Software
   * License version 1.1, a copy of which has been included with this
   * distribution in the LICENSE.txt file.
   */
  package org.apache.log4j.lf5.util;
  
  import org.apache.log4j.lf5.LogLevel;
  import org.apache.log4j.lf5.LogRecord;
  
  import java.io.PrintWriter;
  import java.io.StringWriter;
  
  /**
   * <p>A LogRecord to be used with the LogMonitorAdapter</p>
   *
   * @author Richard Hurst
   */
  
  // Contributed by ThoughtWorks Inc.
  
  public class AdapterLogRecord extends LogRecord {
    //--------------------------------------------------------------------------
    //   Constants:
    //--------------------------------------------------------------------------
  
    //--------------------------------------------------------------------------
    //   Protected Variables:
    //--------------------------------------------------------------------------
  
    //--------------------------------------------------------------------------
    //   Private Variables:
    //--------------------------------------------------------------------------
    private static LogLevel severeLevel = null;
  
    private static StringWriter sw = new StringWriter();
    private static PrintWriter pw = new PrintWriter(sw);
  
    //--------------------------------------------------------------------------
    //   Constructors:
    //--------------------------------------------------------------------------
    public AdapterLogRecord() {
      super();
    }
  
    //--------------------------------------------------------------------------
    //   Public Methods:
    //--------------------------------------------------------------------------
    public void setCategory(String category) {
      super.setCategory(category);
      super.setLocation(getLocationInfo(category));
    }
  
    public boolean isSevereLevel() {
      if (severeLevel == null) return false;
      return severeLevel.equals(getLevel());
    }
  
    public static void setSevereLevel(LogLevel level) {
      severeLevel = level;
    }
  
    public static LogLevel getSevereLevel() {
      return severeLevel;
    }
  
    //--------------------------------------------------------------------------
    //   Protected Methods:
    //--------------------------------------------------------------------------
    protected String getLocationInfo(String category) {
      String stackTrace = stackTraceToString(new Throwable());
      String line = parseLine(stackTrace, category);
      return line;
    }
  
    protected String stackTraceToString(Throwable t) {
      String s = null;
  
      synchronized (sw) {
        t.printStackTrace(pw);
        s = sw.toString();
        sw.getBuffer().setLength(0);
      }
  
      return s;
    }
  
    protected String parseLine(String trace, String category) {
      int index = trace.indexOf(category);
      if (index == -1) return null;
      trace = trace.substring(index);
      trace = trace.substring(0, trace.indexOf(")") + 1);
      return trace;
    }
    //--------------------------------------------------------------------------
    //   Private Methods:
    //--------------------------------------------------------------------------
  
    //--------------------------------------------------------------------------
    //   Nested Top-Level Classes or Interfaces
    //--------------------------------------------------------------------------
  }
  
  
  
  
  1.1                  jakarta-log4j/src/java/org/apache/log4j/lf5/util/DateFormatManager.java
  
  Index: DateFormatManager.java
  ===================================================================
  /*
   * Copyright (C) The Apache Software Foundation. All rights reserved.
   *
   * This software is published under the terms of the Apache Software
   * License version 1.1, a copy of which has been included with this
   * distribution in the LICENSE.txt file.
   */
  package org.apache.log4j.lf5.util;
  
  import java.text.DateFormat;
  import java.text.ParseException;
  import java.text.SimpleDateFormat;
  import java.util.Date;
  import java.util.Locale;
  import java.util.TimeZone;
  
  /**
   * Date format manager.
   * Utility class to help manage consistent date formatting and parsing.
   * It may be advantageous to have multiple DateFormatManagers per
   * application.  For example, one for handling the output (formatting) of
   * dates, and another one for handling the input (parsing) of dates.
   *
   * @author Robert Shaw
   * @author Michael J. Sikorsky
   */
  
  // Contributed by ThoughtWorks Inc.
  public class DateFormatManager {
    //--------------------------------------------------------------------------
    //   Constants:
    //--------------------------------------------------------------------------
  
    //--------------------------------------------------------------------------
    //   Protected Variables:
    //--------------------------------------------------------------------------
  
    //--------------------------------------------------------------------------
    //   Private Variables:
    //--------------------------------------------------------------------------
    private TimeZone _timeZone = null;
    private Locale _locale = null;
  
    private String _pattern = null;
    private DateFormat _dateFormat = null;
  
    //--------------------------------------------------------------------------
    //   Constructors:
    //--------------------------------------------------------------------------
    public DateFormatManager() {
      super();
      configure();
    }
  
    public DateFormatManager(TimeZone timeZone) {
      super();
  
      _timeZone = timeZone;
      configure();
    }
  
    public DateFormatManager(Locale locale) {
      super();
  
      _locale = locale;
      configure();
    }
  
    public DateFormatManager(String pattern) {
      super();
  
      _pattern = pattern;
      configure();
    }
  
    public DateFormatManager(TimeZone timeZone, Locale locale) {
      super();
  
      _timeZone = timeZone;
      _locale = locale;
      configure();
    }
  
    public DateFormatManager(TimeZone timeZone, String pattern) {
      super();
  
      _timeZone = timeZone;
      _pattern = pattern;
      configure();
    }
  
    public DateFormatManager(Locale locale, String pattern) {
      super();
  
      _locale = locale;
      _pattern = pattern;
      configure();
    }
  
    public DateFormatManager(TimeZone timeZone, Locale locale, String pattern) {
      super();
  
      _timeZone = timeZone;
      _locale = locale;
      _pattern = pattern;
      configure();
    }
  
    //--------------------------------------------------------------------------
    //   Public Methods:
    //--------------------------------------------------------------------------
  
    public synchronized TimeZone getTimeZone() {
      if (_timeZone == null) {
        return TimeZone.getDefault();
      } else {
        return _timeZone;
      }
    }
  
    public synchronized void setTimeZone(TimeZone timeZone) {
      timeZone = timeZone;
      configure();
    }
  
    public synchronized Locale getLocale() {
      if (_locale == null) {
        return Locale.getDefault();
      } else {
        return _locale;
      }
    }
  
    public synchronized void setLocale(Locale locale) {
      _locale = locale;
      configure();
    }
  
    public synchronized String getPattern() {
      return _pattern;
    }
  
    /**
     * Set the pattern. i.e. "EEEEE, MMMMM d, yyyy hh:mm aaa"
     */
    public synchronized void setPattern(String pattern) {
      _pattern = pattern;
      configure();
    }
  
  
    /**
     * This method has been deprecated in favour of getPattern().
     * @deprecated Use getPattern().
     */
    public synchronized String getOutputFormat() {
      return _pattern;
    }
  
    /**
     * This method has been deprecated in favour of setPattern().
     * @deprecated Use setPattern().
     */
    public synchronized void setOutputFormat(String pattern) {
      _pattern = pattern;
      configure();
    }
  
    public synchronized DateFormat getDateFormatInstance() {
      return _dateFormat;
    }
  
    public synchronized void setDateFormatInstance(DateFormat dateFormat) {
      _dateFormat = dateFormat;
      // No reconfiguration necessary!
    }
  
    public String format(Date date) {
      return getDateFormatInstance().format(date);
    }
  
    public String format(Date date, String pattern) {
      DateFormat formatter = null;
      formatter = getDateFormatInstance();
      if (formatter instanceof SimpleDateFormat) {
        formatter = (SimpleDateFormat) (formatter.clone());
        ((SimpleDateFormat) formatter).applyPattern(pattern);
      }
      return formatter.format(date);
    }
  
    /**
     * @throws java.text.ParseException
     */
    public Date parse(String date) throws ParseException {
      return getDateFormatInstance().parse(date);
    }
  
    /**
     * @throws java.text.ParseException
     */
    public Date parse(String date, String pattern) throws ParseException {
      DateFormat formatter = null;
      formatter = getDateFormatInstance();
      if (formatter instanceof SimpleDateFormat) {
        formatter = (SimpleDateFormat) (formatter.clone());
        ((SimpleDateFormat) formatter).applyPattern(pattern);
      }
      return formatter.parse(date);
    }
  
    //--------------------------------------------------------------------------
    //   Protected Methods:
    //--------------------------------------------------------------------------
  
    //--------------------------------------------------------------------------
    //   Private Methods:
    //--------------------------------------------------------------------------
    private synchronized void configure() {
      _dateFormat = SimpleDateFormat.getDateTimeInstance(DateFormat.FULL,
          DateFormat.FULL,
          getLocale());
      _dateFormat.setTimeZone(getTimeZone());
  
      if (_pattern != null) {
        ((SimpleDateFormat) _dateFormat).applyPattern(_pattern);
      }
    }
  
    //--------------------------------------------------------------------------
    //   Nested Top-Level Classes or Interfaces:
    //--------------------------------------------------------------------------
  
  }
  
  
  
  1.1                  jakarta-log4j/src/java/org/apache/log4j/lf5/util/LogFileParser.java
  
  Index: LogFileParser.java
  ===================================================================
  /*
   * Copyright (C) The Apache Software Foundation. All rights reserved.
   *
   * This software is published under the terms of the Apache Software
   * License version 1.1, a copy of which has been included with this
   * distribution in the LICENSE.txt file.
   */
  package org.apache.log4j.lf5.util;
  
  import org.apache.log4j.lf5.Log4JLogRecord;
  import org.apache.log4j.lf5.LogLevel;
  import org.apache.log4j.lf5.LogLevelFormatException;
  import org.apache.log4j.lf5.LogRecord;
  import org.apache.log4j.lf5.viewer.LogBrokerMonitor;
  import org.apache.log4j.lf5.viewer.LogFactor5ErrorDialog;
  import org.apache.log4j.lf5.viewer.LogFactor5LoadingDialog;
  
  import javax.swing.*;
  import java.io.*;
  import java.text.ParseException;
  import java.text.SimpleDateFormat;
  import java.util.Date;
  
  /**
   * Provides utility methods for input and output streams.
   *
   * @author Brad Marlborough
   * @author Richard Hurst
   */
  
  // Contributed by ThoughtWorks Inc.
  
  public class LogFileParser implements Runnable {
    //--------------------------------------------------------------------------
    //   Constants:
    //--------------------------------------------------------------------------
    public static final String RECORD_DELIMITER = "[slf5s.start]";
    public static final String ATTRIBUTE_DELIMITER = "[slf5s.";
    public static final String DATE_DELIMITER = ATTRIBUTE_DELIMITER + "DATE]";
    public static final String THREAD_DELIMITER = ATTRIBUTE_DELIMITER + "THREAD]";
    public static final String CATEGORY_DELIMITER = ATTRIBUTE_DELIMITER + "CATEGORY]";
    public static final String LOCATION_DELIMITER = ATTRIBUTE_DELIMITER + "LOCATION]";
    public static final String MESSAGE_DELIMITER = ATTRIBUTE_DELIMITER + "MESSAGE]";
    public static final String PRIORITY_DELIMITER = ATTRIBUTE_DELIMITER + "PRIORITY]";
    public static final String NDC_DELIMITER = ATTRIBUTE_DELIMITER + "NDC]";
  
    //--------------------------------------------------------------------------
    //   Protected Variables:
    //--------------------------------------------------------------------------
  
    //--------------------------------------------------------------------------
    //   Private Variables:
    //--------------------------------------------------------------------------
    private static SimpleDateFormat _sdf = new SimpleDateFormat("dd MMM yyyy HH:mm:ss,S");
    private LogBrokerMonitor _monitor;
    LogFactor5LoadingDialog _loadDialog;
    private InputStream _in = null;
  
    //--------------------------------------------------------------------------
    //   Constructors:
    //--------------------------------------------------------------------------
    public LogFileParser(File file) throws IOException,
        FileNotFoundException {
      this(new FileInputStream(file));
    }
  
    public LogFileParser(InputStream stream) throws IOException {
      _in = stream;
    }
    //--------------------------------------------------------------------------
    //   Public Methods:
    //--------------------------------------------------------------------------
  
    /**
     * Starts a new thread to parse the log file and create a LogRecord.
     * See run().
     * @param LogBrokerMonitor
     */
    public void parse(LogBrokerMonitor monitor) throws RuntimeException {
      _monitor = monitor;
      Thread t = new Thread(this);
      t.start();
    }
  
    /**
     * Parses the file and creates new log records and adds the record
     * to the monitor.
     */
    public void run() {
  
      int index = 0;
      int counter = 0;
      LogRecord temp;
      boolean isLogFile = false;
  
      _loadDialog = new LogFactor5LoadingDialog(
          _monitor.getBaseFrame(), "Loading file...");
  
  
      try {
        String logRecords = loadLogFile(_in);
  
        while ((counter = logRecords.indexOf(RECORD_DELIMITER, index)) != -1) {
          temp = createLogRecord(logRecords.substring(index, counter));
          isLogFile = true;
  
          if (temp != null) {
            _monitor.addMessage(temp);
          }
  
          index = counter + RECORD_DELIMITER.length();
        }
  
        if (index < logRecords.length() && isLogFile) {
          temp = createLogRecord(logRecords.substring(index));
  
          if (temp != null) {
            _monitor.addMessage(temp);
          }
        }
  
        if (isLogFile == false) {
          throw new RuntimeException("Invalid log file format");
        }
        SwingUtilities.invokeLater(new Runnable() {
          public void run() {
            destroyDialog();
          }
        });
  
      } catch (RuntimeException e) {
        destroyDialog();
        displayError("Error - Invalid log file format.\nPlease see documentation"
            + " on how to load log files.");
      } catch (IOException e) {
        destroyDialog();
        displayError("Error - Unable to load log file!");
      }
  
      _in = null;
    }
  
    //--------------------------------------------------------------------------
    //   Protected Methods:
    //--------------------------------------------------------------------------
    protected void displayError(String message) {
      LogFactor5ErrorDialog error = new LogFactor5ErrorDialog(
          _monitor.getBaseFrame(), message);
  
    }
  
    //--------------------------------------------------------------------------
    //   Private Methods:
    //--------------------------------------------------------------------------
    private void destroyDialog() {
      _loadDialog.hide();
      _loadDialog.dispose();
    }
  
    /**
     * Loads a log file from a web server into the LogFactor5 GUI.
     */
    private String loadLogFile(InputStream stream) throws IOException {
      BufferedInputStream br = new BufferedInputStream(stream);
  
      int count = 0;
      int size = br.available();
  
      StringBuffer sb = null;
      if (size > 0) {
        sb = new StringBuffer(size);
      } else {
        sb = new StringBuffer(1024);
      }
  
      while ((count = br.read()) != -1) {
        sb.append((char) count);
      }
  
      br.close();
      br = null;
      return sb.toString();
  
    }
  
    private String parseAttribute(String name, String record) {
  
      int index = record.indexOf(name);
  
      if (index == -1) {
        return null;
      }
  
      return getAttribute(index, record);
    }
  
    private long parseDate(String record) {
      try {
        String s = parseAttribute(DATE_DELIMITER, record);
  
        if (s == null) {
          return 0;
        }
  
        Date d = _sdf.parse(s);
  
        return d.getTime();
      } catch (ParseException e) {
        return 0;
      }
    }
  
    private LogLevel parsePriority(String record) {
      String temp = parseAttribute(PRIORITY_DELIMITER, record);
  
      if (temp != null) {
        try {
          return LogLevel.valueOf(temp);
        } catch (LogLevelFormatException e) {
          return LogLevel.DEBUG;
        }
  
      }
  
      return LogLevel.DEBUG;
    }
  
    private String parseThread(String record) {
      return parseAttribute(THREAD_DELIMITER, record);
    }
  
    private String parseCategory(String record) {
      return parseAttribute(CATEGORY_DELIMITER, record);
    }
  
    private String parseLocation(String record) {
      return parseAttribute(LOCATION_DELIMITER, record);
    }
  
    private String parseMessage(String record) {
      return parseAttribute(MESSAGE_DELIMITER, record);
    }
  
    private String parseNDC(String record) {
      return parseAttribute(NDC_DELIMITER, record);
    }
  
    private String parseThrowable(String record) {
      return getAttribute(record.length(), record);
    }
  
    private LogRecord createLogRecord(String record) {
      if (record == null || record.trim().length() == 0) {
        return null;
      }
  
      LogRecord lr = new Log4JLogRecord();
      lr.setMillis(parseDate(record));
      lr.setLevel(parsePriority(record));
      lr.setCategory(parseCategory(record));
      lr.setLocation(parseLocation(record));
      lr.setThreadDescription(parseThread(record));
      lr.setNDC(parseNDC(record));
      lr.setMessage(parseMessage(record));
      lr.setThrownStackTrace(parseThrowable(record));
  
      return lr;
    }
  
  
    private String getAttribute(int index, String record) {
      int start = record.lastIndexOf(ATTRIBUTE_DELIMITER, index - 1);
  
      if (start == -1) {
        return record.substring(0, index);
      }
  
      start = record.indexOf("]", start);
  
      return record.substring(start + 1, index).trim();
    }
    //--------------------------------------------------------------------------
    //   Nested Top-Level Classes or Interfaces
    //--------------------------------------------------------------------------
  
  }
  
  
  
  1.1                  jakarta-log4j/src/java/org/apache/log4j/lf5/util/LogMonitorAdapter.java
  
  Index: LogMonitorAdapter.java
  ===================================================================
  /*
   * Copyright (C) The Apache Software Foundation. All rights reserved.
   *
   * This software is published under the terms of the Apache Software
   * License version 1.1, a copy of which has been included with this
   * distribution in the LICENSE.txt file.
   */
  package org.apache.log4j.lf5.util;
  
  import org.apache.log4j.lf5.LogLevel;
  import org.apache.log4j.lf5.LogRecord;
  import org.apache.log4j.lf5.viewer.LogBrokerMonitor;
  
  import java.awt.*;
  import java.util.Arrays;
  import java.util.List;
  
  /**
   * <p>LogMonitorAdapter facilitates the usage of the LogMonitor</p>
   *
   * @author Richard Hurst
   */
  
  // Contributed by ThoughtWorks Inc.
  
  public class LogMonitorAdapter {
    //--------------------------------------------------------------------------
    //   Constants:
    //--------------------------------------------------------------------------
    public static final int LOG4J_LOG_LEVELS = 0;
    public static final int JDK14_LOG_LEVELS = 1;
    //--------------------------------------------------------------------------
    //   Protected Variables:
    //--------------------------------------------------------------------------
  
    //--------------------------------------------------------------------------
    //   Private Variables:
    //--------------------------------------------------------------------------
    private LogBrokerMonitor _logMonitor;
    private LogLevel _defaultLevel = null;
  
    //--------------------------------------------------------------------------
    //   Constructors:
    //--------------------------------------------------------------------------
    private LogMonitorAdapter(List userDefinedLevels) {
      super();
      // set the default level to be the first entry in the list
      _defaultLevel = (LogLevel) userDefinedLevels.get(0);
      _logMonitor = new LogBrokerMonitor(userDefinedLevels);
  
      _logMonitor.setFrameSize(getDefaultMonitorWidth(),
          getDefaultMonitorHeight());
      _logMonitor.setFontSize(12);
      _logMonitor.show();
    }
    //--------------------------------------------------------------------------
    //   Public Methods:
    //--------------------------------------------------------------------------
    /**
     * <p>Creates an instance of LogMonitorAdapter using the
     * log levels inticated by the parameter. Log4J and JDK1.4 both have default
     * LogLevels which are set but these levels can be overriden.<p>
     *
     * @param loglevels An integer representing either Log4J or JDK1.4 logging levels
     * @return LogMonitorAdapter
     */
    public static LogMonitorAdapter newInstance(int loglevels) {
      LogMonitorAdapter adapter;
      if (loglevels == JDK14_LOG_LEVELS) {
        adapter = newInstance(LogLevel.getJdk14Levels());
        adapter.setDefaultLevel(LogLevel.FINEST);
        adapter.setSevereLevel(LogLevel.SEVERE);
      } else {
        adapter = newInstance(LogLevel.getLog4JLevels());
        adapter.setDefaultLevel(LogLevel.DEBUG);
        adapter.setSevereLevel(LogLevel.FATAL);
      }
      return adapter;
    }
  
    /**
     * <p>Creates an instance of LogMonitorAdapter using the specified LogLevels.
     * The first LogLevel in the array is used as the default LogLevel unless
     * changed using the setDefaultLevel method.<p>
     *
     * @param userDefined An array of user defined LogLevel objects.
     * @return LogMonitorAdapter
     */
    public static LogMonitorAdapter newInstance(LogLevel[] userDefined) {
      if (userDefined == null) {
        return null;
      }
      return newInstance(Arrays.asList(userDefined));
    }
  
    /**
     * <p>Creates an instance of LogMonitorAdapter using the specified LogLevels.
     * The first LogLevel in the List is used as the default LogLevel unless
     * changed using the setDefaultLevel method.<p>
     *
     * @param userDefined A list of user defined LogLevel objects.
     * @return LogMonitorAdapter
     */
    public static LogMonitorAdapter newInstance(List userDefinedLevels) {
      return new LogMonitorAdapter(userDefinedLevels);
    }
  
    /**
     * <p>Adds a LogRecord to the LogMonitor.<p>
     *
     * @param record The LogRecord object to be logged in the logging monitor.
     */
    public void addMessage(LogRecord record) {
      _logMonitor.addMessage(record);
    }
  
    /**
     * <p>Set the maximum number of records to be displayed in the monitor<p>
     *
     * @param maxNumberOfRecords
     */
    public void setMaxNumberOfRecords(int maxNumberOfRecords) {
      _logMonitor.setMaxNumberOfLogRecords(maxNumberOfRecords);
    }
  
    /**
     * <p>Set the default log level to be used when logging messages without
     * specifying a LogLevel.<p>
     *
     * @param level
     */
    public void setDefaultLevel(LogLevel level) {
      _defaultLevel = level;
    }
  
    /**
     * <p>Gets the default LogLevel for the Adapter.<p>
     *
     * @return LogLevel
     */
    public LogLevel getDefaultLevel() {
      return _defaultLevel;
    }
  
    /**
     * <p>Sets the Severe LogLevel.</p>
     *
     * @param level
     */
    public void setSevereLevel(LogLevel level) {
      AdapterLogRecord.setSevereLevel(level);
    }
  
    /**
     * <p>Gets the current Severe LogLevel <p>
     *
     * @return LogLevel
     */
    public LogLevel getSevereLevel() {
      return AdapterLogRecord.getSevereLevel();
    }
  
    /**
     * <p>Log a complete message to the Monitor.<p>
     *
     * @param category The category to be used
     * @param level The log level to apply to the message
     * @param message The message
     * @param t The throwable content of the message
     * @param NDC The NDC really only applies to Log4J and the parameter can
     *            usually be ignored.
     */
    public void log(String category, LogLevel level, String message,
        Throwable t, String NDC) {
      AdapterLogRecord record = new AdapterLogRecord();
      record.setCategory(category);
      record.setMessage(message);
      record.setNDC(NDC);
      record.setThrown(t);
  
      if (level == null) {
        record.setLevel(getDefaultLevel());
      } else {
        record.setLevel(level);
      }
  
      addMessage(record);
    }
  
    /**
     * <p>Log a message to the Monitor and use the default LogLevel.<p>
     *
     * @param category The category to be used
     * @param message The message
     */
    public void log(String category, String message) {
      log(category, null, message);
    }
  
    /**
     * <p>Log a message to the Monitor.<p>
     *
     * @param category The category to be used
     * @param level The log level to apply to the message
     * @param message The message
     * @param NDC
     */
    public void log(String category, LogLevel level, String message, String NDC) {
      log(category, level, message, null, NDC);
    }
  
    /**
     * <p>Log a message to the Monitor.<p>
     *
     * @param category The category to be used
     * @param level The log level to apply to the message
     * @param message The message
     * @param t The throwable content of the message
     */
    public void log(String category, LogLevel level, String message,
        Throwable t) {
      log(category, level, message, t, null);
    }
  
    /**
     * <p>Log a message to the Monitor.<p>
     *
     * @param category The category to be used
     * @param level The log level to apply to the message
     * @param message The message
     */
    public void log(String category, LogLevel level, String message) {
      log(category, level, message, null, null);
    }
  
    //--------------------------------------------------------------------------
    //   Protected Methods:
    //--------------------------------------------------------------------------
    /**
     * @return the screen width from Toolkit.getScreenSize()
     * if possible, otherwise returns 800
     * @see java.awt.Toolkit
     */
    protected static int getScreenWidth() {
      try {
        return Toolkit.getDefaultToolkit().getScreenSize().width;
      } catch (Throwable t) {
        return 800;
      }
    }
  
    /**
     * @return the screen height from Toolkit.getScreenSize()
     * if possible, otherwise returns 600
     * @see java.awt.Toolkit
     */
    protected static int getScreenHeight() {
      try {
        return Toolkit.getDefaultToolkit().getScreenSize().height;
      } catch (Throwable t) {
        return 600;
      }
    }
  
    protected static int getDefaultMonitorWidth() {
      return (3 * getScreenWidth()) / 4;
    }
  
    protected static int getDefaultMonitorHeight() {
      return (3 * getScreenHeight()) / 4;
    }
    //--------------------------------------------------------------------------
    //   Private Methods:
    //--------------------------------------------------------------------------
  
    //--------------------------------------------------------------------------
    //   Nested Top-Level Classes or Interfaces
    //--------------------------------------------------------------------------
  }
  
  
  
  
  1.1                  jakarta-log4j/src/java/org/apache/log4j/lf5/util/ProductProperties.java
  
  Index: ProductProperties.java
  ===================================================================
  /*
   * Copyright (C) The Apache Software Foundation. All rights reserved.
   *
   * This software is published under the terms of the Apache Software
   * License version 1.1, a copy of which has been included with this
   * distribution in the LICENSE.txt file.
   */
  package org.apache.log4j.lf5.util;
  
  import java.io.BufferedInputStream;
  import java.io.ByteArrayInputStream;
  import java.io.IOException;
  import java.io.InputStream;
  import java.util.Properties;
  
  /**
   * ProductProperties holds the properties dealing with
   * this product.  There is never a need
   * for multiple instances of this class, thus this class
   * is a singleton.
   *
   * The properties file format is as follows:
   *
   *  #Any arbitrary comments are denoted with a #
   *
   *  #Mandatory properties
   *  product.name=<Product name>
   *  product.version.number=<Product version number>
   *  product.release.date=<Product release date>
   *  product.release.type=<Product release type>
   *
   *
   * Note that this class will throw an ExceptionInInitializerError if
   * initialization fails, or if the required properties are absent.
   *
   * @author Robert Shaw
   * @author Michael J. Sikorsky
   * @author Brent Sprecher
   */
  
  // Contributed by ThoughtWorks Inc.
  
  public class ProductProperties {
    //--------------------------------------------------------------------------
    //   Constants:
    //--------------------------------------------------------------------------
  
    //--------------------------------------------------------------------------
    //   Protected Variables:
    //--------------------------------------------------------------------------
  
    /** Collection of properties. */
    protected Properties _productProperties;
    //protected final boolean _validFlag;
  
    //--------------------------------------------------------------------------
    //   Private Variables:
    //--------------------------------------------------------------------------
    private static ProductProperties _reference = null;
    private static Object _synchronizingObject = new Object();
  
    //--------------------------------------------------------------------------
    //   Constructors:
    //--------------------------------------------------------------------------
  
    /**
     * Construct an ProductProperties with the mandatory properties.
     * Use the constructor that configures a ProductProperties
     * off of a properties file if you wish to take advantage
     * of additional properties.
     *
     */
    private ProductProperties() {
      this(new Resource("org/apache/log4j/lf5/lf5.properties"));
    }
  
    private ProductProperties(Resource resource) {
      super();
  
      _productProperties = new Properties();
  
      try {
        InputStream source = getSource(resource);
        byte[] contents = StreamUtils.getBytes(source);
        _productProperties = getProperties(contents);
        source.close();
        validateProductProperties();
      } catch (Exception e) {
        String error = e.getMessage();
        throw new ExceptionInInitializerError(error);
      }
    }
  
  
    //--------------------------------------------------------------------------
    //   Public Methods:
    //--------------------------------------------------------------------------
  
    public static ProductProperties getInstance() {
      if (_reference == null) {
        synchronized (_synchronizingObject) {
          if (_reference == null) {
            _reference = new ProductProperties();
          }
        }
      }
      return _reference;
    }
  
    /**
     * Mandatory internally recognized property.
     */
    public static String getPropertyNameOfProductName() {
      return "product.name";
    }
  
    /**
     * Mandatory internally recognized property.
     */
    public static String getPropertyNameOfProductVersionNumber() {
      return "product.version.number";
    }
  
    /**
     * Mandatory internally recognized property.
     */
    public static String getPropertyNameOfProductReleaseDate() {
      return "product.release.date";
    }
  
    /**
     * Get the product name.
     */
    public String getProductName() {
      return _productProperties.getProperty(getPropertyNameOfProductName());
    }
  
    /**
     * Set the product name.
     */
    public void setProductName(String productName) {
      _productProperties.setProperty(getPropertyNameOfProductName(),
          productName);
    }
  
    /**
     * Get the product version number.
     */
    public String getProductVersionNumber() {
      return
          _productProperties.getProperty(getPropertyNameOfProductVersionNumber());
    }
  
    /**
     * Set the product version number.
     */
    public void setProductVersionNumber(String productVersionNumber) {
      _productProperties.setProperty(getPropertyNameOfProductVersionNumber(),
          productVersionNumber);
    }
  
    /**
     * Get the product release date.
     */
    public String getProductReleaseDate() {
      return
          _productProperties.getProperty(getPropertyNameOfProductReleaseDate());
    }
  
    /**
     * Set the product release date.
     */
    public void setProductReleaseDate(String productReleaseDate) {
      _productProperties.setProperty(getPropertyNameOfProductReleaseDate(),
          productReleaseDate);
    }
  
    /**
     * Retrieve any of the mandatory properties, or any additional
     * properties that were placed in the database configuration file.
     */
    public String get(String name) {
      return _productProperties.getProperty(name);
    }
  
    /**
     * Set any property.
     */
    public Object set(String name, String value) {
      return _productProperties.setProperty(name, value);
    }
  
    public String getLogFactor5() {
      return getString("lf5");
    }
  
    public String getString(String propertyName) {
      return String.valueOf(get(propertyName));
    }
  
    //--------------------------------------------------------------------------
    //   Protected Methods:
    //--------------------------------------------------------------------------
    /**
     * @throws java.lang.Exception
     */
    protected void validateProductProperties() throws Exception {
      String value = null;
  
      value = getProductVersionNumber();
      if ((value == null) || value.equals("")) {
        throw new Exception("Product version number is null.");
      }
  
      value = getProductReleaseDate();
      if ((value == null) || value.equals("")) {
        throw new Exception("Product release date is null.");
      }
  
    }
  
    //--------------------------------------------------------------------------
    //   Private Methods:
    //--------------------------------------------------------------------------
  
    private InputStream getSource(Resource resource) {
      return new BufferedInputStream(
          ResourceUtils.getResourceAsStream(this, resource));
    }
  
    private Properties getProperties(byte[] contents) throws IOException {
      ByteArrayInputStream source = new ByteArrayInputStream(contents);
      Properties result = new Properties();
      result.load(source);
      source.close();
      return result;
    }
  
    //--------------------------------------------------------------------------
    //   Nested Top-Level Classes or Interfaces
    //--------------------------------------------------------------------------
  }
  
  
  
  
  
  
  
  
  
  1.1                  jakarta-log4j/src/java/org/apache/log4j/lf5/util/Resource.java
  
  Index: Resource.java
  ===================================================================
  /*
   * Copyright (C) The Apache Software Foundation. All rights reserved.
   *
   * This software is published under the terms of the Apache Software
   * License version 1.1, a copy of which has been included with this
   * distribution in the LICENSE.txt file.
   */
  package org.apache.log4j.lf5.util;
  
  import java.io.InputStream;
  import java.io.InputStreamReader;
  import java.net.URL;
  
  /**
   * Resource encapsulates access to Resources via the Classloader.
   *
   * @author Michael J. Sikorsky
   * @author Robert Shaw
   */
  
  // Contributed by ThoughtWorks Inc.
  
  public class Resource {
    //--------------------------------------------------------------------------
    //   Constants:
    //--------------------------------------------------------------------------
  
    //--------------------------------------------------------------------------
    //   Protected Variables:
    //--------------------------------------------------------------------------
    protected String _name;
  
    //--------------------------------------------------------------------------
    //   Private Variables:
    //--------------------------------------------------------------------------
  
    //--------------------------------------------------------------------------
    //   Constructors:
    //--------------------------------------------------------------------------
  
    /**
     * Default, no argument constructor.
     */
    public Resource() {
      super();
    }
  
    /**
     * Construct a Resource given a name.
     *
     * @see #setName(String)
     */
    public Resource(String name) {
      _name = name;
    }
  
    //--------------------------------------------------------------------------
    //   Public Methods:
    //--------------------------------------------------------------------------
  
    /**
     * Set the name of the resource.
     * <p>
     * A resource is some data (images, audio, text, etc) that can be accessed
     * by class code in a way that is independent of the location of the code.
     * </p>
     * <p>
     * The name of a resource is a "/"-separated path name that identifies
     * the resource.
     * </p>
     *
     * @see #getName()
     */
    public void setName(String name) {
      _name = name;
    }
  
    /**
     * Get the name of the resource.  Set setName() for a description of
     * a resource.
     *
     * @see #setName
     */
    public String getName() {
      return (_name);
    }
  
    /**
     * Get the InputStream for this Resource.  Uses the classloader
     * from this Resource.
     *
     * @see #getInputStreamReader
     * @see ResourceUtils
     */
    public InputStream getInputStream() {
      InputStream in = ResourceUtils.getResourceAsStream(this, this);
  
      return (in);
    }
  
    /**
     * Get the InputStreamReader for this Resource. Uses the classloader from
     * this Resource.
     *
     * @see #getInputStream
     * @see ResourceUtils
     */
    public InputStreamReader getInputStreamReader() {
      InputStream in = ResourceUtils.getResourceAsStream(this, this);
  
      if (in == null) {
        return null;
      }
  
      InputStreamReader reader = new InputStreamReader(in);
  
      return reader;
    }
  
    /**
     * Get the URL of the Resource.  Uses the classloader from this Resource.
     *
     * @see ResourceUtils
     */
    public URL getURL() {
      return (ResourceUtils.getResourceAsURL(this, this));
    }
  
    //--------------------------------------------------------------------------
    //   Protected Methods:
    //--------------------------------------------------------------------------
  
    //--------------------------------------------------------------------------
    //   Private Methods:
    //--------------------------------------------------------------------------
  
    //--------------------------------------------------------------------------
    //   Nested Top-Level Classes or Interfaces:
    //--------------------------------------------------------------------------
  
  }
  
  
  
  
  
  
  
  
  
  1.1                  jakarta-log4j/src/java/org/apache/log4j/lf5/util/ResourceUtils.java
  
  Index: ResourceUtils.java
  ===================================================================
  /*
   * Copyright (C) The Apache Software Foundation. All rights reserved.
   *
   * This software is published under the terms of the Apache Software
   * License version 1.1, a copy of which has been included with this
   * distribution in the LICENSE.txt file.
   */
  package org.apache.log4j.lf5.util;
  
  import java.io.InputStream;
  import java.net.URL;
  
  /**
   * ResourceUtils.  Provide a set of convenience methods for working with
   * Resources.
   *
   * @see org.apache.log4j.lf5.util.Resource
   *
   * @author Michael J. Sikorsky
   * @author Robert Shaw
   */
  
  // Contributed by ThoughtWorks Inc.
  
  public class ResourceUtils {
    //--------------------------------------------------------------------------
    //   Constants:
    //--------------------------------------------------------------------------
  
    //--------------------------------------------------------------------------
    //   Protected Variables:
    //--------------------------------------------------------------------------
  
    //--------------------------------------------------------------------------
    //   Private Variables:
    //--------------------------------------------------------------------------
  
    //--------------------------------------------------------------------------
    //   Constructors:
    //--------------------------------------------------------------------------
  
    //--------------------------------------------------------------------------
    //   Public Methods:
    //--------------------------------------------------------------------------
  
    /**
     * Get the InputStream for this resource.  Note: to convert an InputStream
     * into an InputReader, use: new InputStreamReader(InputStream).
     *
     * @param object   The object to grab the Classloader from.
     *                 This parameter is quite important from a
     *                 visibility of resources standpoint as the
     *                 hierarchy of Classloaders plays a role.
     *
     * @param resource The resource to load.
     *
     * @return If the Resource was found, the InputStream, otherwise null.
     *
     * @see Resource
     * @see #getResourceAsURL(Object,Resource)
     * @see InputStream
     */
    public static InputStream getResourceAsStream(Object object, Resource resource) {
      ClassLoader loader = object.getClass().getClassLoader();
  
      InputStream in = null;
  
      if (loader != null) {
        in = loader.getResourceAsStream(resource.getName());
      } else {
        in = ClassLoader.getSystemResourceAsStream(resource.getName());
      }
  
      return in;
    }
  
    /**
     * Get the URL for this resource.
     *
     * @param object   The object to grab the Classloader from.
     *                 This parameter is quite important from a
     *                 visibility of resources standpoint as the
     *                 hierarchy of Classloaders plays a role.
     *
     * @param resource The resource to load.
     *
     * @return If the Resource was found, the URL, otherwise null.
     *
     * @see Resource
     * @see #getResourceAsStream(Object,Resource)
     */
    public static URL getResourceAsURL(Object object, Resource resource) {
      ClassLoader loader = object.getClass().getClassLoader();
  
      URL url = null;
  
      if (loader != null) {
        url = loader.getResource(resource.getName());
      } else {
        url = ClassLoader.getSystemResource(resource.getName());
      }
  
      return (url);
    }
  
    //--------------------------------------------------------------------------
    //   Protected Methods:
    //--------------------------------------------------------------------------
  
    //--------------------------------------------------------------------------
    //   Private Methods:
    //--------------------------------------------------------------------------
  
    //--------------------------------------------------------------------------
    //   Nested Top-Level Classes or Interfaces:
    //--------------------------------------------------------------------------
  
  }
  
  
  
  
  
  
  
  
  
  1.1                  jakarta-log4j/src/java/org/apache/log4j/lf5/util/StreamUtils.java
  
  Index: StreamUtils.java
  ===================================================================
  /*
   * Copyright (C) The Apache Software Foundation. All rights reserved.
   *
   * This software is published under the terms of the Apache Software
   * License version 1.1, a copy of which has been included with this
   * distribution in the LICENSE.txt file.
   */
  
  package org.apache.log4j.lf5.util;
  
  import java.io.ByteArrayOutputStream;
  import java.io.IOException;
  import java.io.InputStream;
  import java.io.OutputStream;
  
  /**
   * Provides utility methods for input and output streams.
   *
   * @author Richard Wan
   */
  
  // Contributed by ThoughtWorks Inc.
  
  public abstract class StreamUtils {
    //--------------------------------------------------------------------------
    //   Constants:
    //--------------------------------------------------------------------------
  
    /**
     * Default value is 2048.
     */
    public static final int DEFAULT_BUFFER_SIZE = 2048;
  
    //--------------------------------------------------------------------------
    //   Protected Variables:
    //--------------------------------------------------------------------------
  
    //--------------------------------------------------------------------------
    //   Private Variables:
    //--------------------------------------------------------------------------
  
    //--------------------------------------------------------------------------
    //   Constructors:
    //--------------------------------------------------------------------------
  
    //--------------------------------------------------------------------------
    //   Public Methods:
    //--------------------------------------------------------------------------
  
    /**
     * Copies information from the input stream to the output stream using
     * a default buffer size of 2048 bytes.
     * @throws java.io.IOException
     */
    public static void copy(InputStream input, OutputStream output)
        throws IOException {
      copy(input, output, DEFAULT_BUFFER_SIZE);
    }
  
    /**
     * Copies information from the input stream to the output stream using
     * the specified buffer size
     * @throws java.io.IOException
     */
    public static void copy(InputStream input,
        OutputStream output,
        int bufferSize)
        throws IOException {
      byte[] buf = new byte[bufferSize];
      int bytesRead = input.read(buf);
      while (bytesRead != -1) {
        output.write(buf, 0, bytesRead);
        bytesRead = input.read(buf);
      }
      output.flush();
    }
  
    /**
     * Copies information between specified streams and then closes
     * both of the streams.
     * @throws java.io.IOException
     */
    public static void copyThenClose(InputStream input, OutputStream output)
        throws IOException {
      copy(input, output);
      input.close();
      output.close();
    }
  
    /**
     * @returns a byte[] containing the information contained in the
     * specified InputStream.
     * @throws java.io.IOException
     */
    public static byte[] getBytes(InputStream input)
        throws IOException {
      ByteArrayOutputStream result = new ByteArrayOutputStream();
      copy(input, result);
      result.close();
      return result.toByteArray();
    }
  
    //--------------------------------------------------------------------------
    //   Protected Methods:
    //--------------------------------------------------------------------------
  
    //--------------------------------------------------------------------------
    //   Private Methods:
    //--------------------------------------------------------------------------
  
    //--------------------------------------------------------------------------
    //   Nested Top-Level Classes or Interfaces
    //--------------------------------------------------------------------------
  
  }
  
  
  
  1.1                  jakarta-log4j/src/java/org/apache/log4j/lf5/viewer/FilteredLogTableModel.java
  
  Index: FilteredLogTableModel.java
  ===================================================================
  /*
   * Copyright (C) The Apache Software Foundation. All rights reserved.
   *
   * This software is published under the terms of the Apache Software
   * License version 1.1, a copy of which has been included with this
   * distribution in the LICENSE.txt file.
   */
  package org.apache.log4j.lf5.viewer;
  
  import org.apache.log4j.lf5.LogRecord;
  import org.apache.log4j.lf5.LogRecordFilter;
  import org.apache.log4j.lf5.PassingLogRecordFilter;
  
  import javax.swing.table.AbstractTableModel;
  import java.util.ArrayList;
  import java.util.Date;
  import java.util.Iterator;
  import java.util.List;
  
  
  /**
   * A TableModel for LogRecords which includes filtering support.
   *
   * @author Richard Wan
   * @author Brent Sprecher
   */
  
  // Contributed by ThoughtWorks Inc.
  
  public class FilteredLogTableModel
      extends AbstractTableModel {
    //--------------------------------------------------------------------------
    //   Constants:
    //--------------------------------------------------------------------------
  
    //--------------------------------------------------------------------------
    //   Protected Variables:
    //--------------------------------------------------------------------------
  
    protected LogRecordFilter _filter = new PassingLogRecordFilter();
    protected List _allRecords = new ArrayList();
    protected List _filteredRecords;
    protected int _maxNumberOfLogRecords = 5000;
    protected String[] _colNames = {"Date",
                                    "Thread",
                                    "Message #",
                                    "Level",
                                    "NDC",
                                    "Category",
                                    "Message",
                                    "Location",
                                    "Thrown"};
  
    //--------------------------------------------------------------------------
    //   Private Variables:
    //--------------------------------------------------------------------------
  
    //--------------------------------------------------------------------------
    //   Constructors:
    //--------------------------------------------------------------------------
  
    public FilteredLogTableModel() {
      super();
    }
  
    //--------------------------------------------------------------------------
    //   Public Methods:
    //--------------------------------------------------------------------------
  
    public void setLogRecordFilter(LogRecordFilter filter) {
      _filter = filter;
    }
  
    public LogRecordFilter getLogRecordFilter() {
      return _filter;
    }
  
    public String getColumnName(int i) {
      return _colNames[i];
    }
  
    public int getColumnCount() {
      return _colNames.length;
    }
  
    public int getRowCount() {
      return getFilteredRecords().size();
    }
  
    public int getTotalRowCount() {
      return _allRecords.size();
    }
  
    public Object getValueAt(int row, int col) {
      LogRecord record = getFilteredRecord(row);
      return getColumn(col, record);
    }
  
    public void setMaxNumberOfLogRecords(int maxNumRecords) {
      if (maxNumRecords > 0) {
        _maxNumberOfLogRecords = maxNumRecords;
      }
  
    }
  
    public synchronized boolean addLogRecord(LogRecord record) {
  
      _allRecords.add(record);
  
      if (_filter.passes(record) == false) {
        return false;
      }
      getFilteredRecords().add(record);
      fireTableRowsInserted(getRowCount(), getRowCount());
      trimRecords();
      return true;
    }
  
    /**
     * Forces the LogTableModel to requery its filters to determine
     * which records to display.
     */
    public synchronized void refresh() {
      _filteredRecords = createFilteredRecordsList();
      fireTableDataChanged();
    }
  
    public synchronized void fastRefresh() {
      _filteredRecords.remove(0);
      fireTableRowsDeleted(0, 0);
    }
  
  
    /**
     * Clears all records from the LogTableModel
     */
    public synchronized void clear() {
      _allRecords.clear();
      _filteredRecords.clear();
      fireTableDataChanged();
    }
  
    //--------------------------------------------------------------------------
    //   Protected Methods:
    //--------------------------------------------------------------------------
  
    protected List getFilteredRecords() {
      if (_filteredRecords == null) {
        refresh();
      }
      return _filteredRecords;
    }
  
    protected List createFilteredRecordsList() {
      List result = new ArrayList();
      Iterator records = _allRecords.iterator();
      LogRecord current;
      while (records.hasNext()) {
        current = (LogRecord) records.next();
        if (_filter.passes(current)) {
          result.add(current);
        }
      }
      return result;
    }
  
    protected LogRecord getFilteredRecord(int row) {
      List records = getFilteredRecords();
      int size = records.size();
      if (row < size) {
        return (LogRecord) records.get(row);
      }
      // a minor problem has happened. JTable has asked for
      // a row outside the bounds, because the size of
      // _filteredRecords has changed while it was looping.
      // return the last row.
      return (LogRecord) records.get(size - 1);
  
    }
  
    protected Object getColumn(int col, LogRecord lr) {
      if (lr == null) {
        return "NULL Column";
      }
      String date = new Date(lr.getMillis()).toString();
      switch (col) {
        case 0:
          return date + " (" + lr.getMillis() + ")";
        case 1:
          return lr.getThreadDescription();
        case 2:
          return new Long(lr.getSequenceNumber());
        case 3:
          return lr.getLevel();
        case 4:
          return lr.getNDC();
        case 5:
          return lr.getCategory();
        case 6:
          return lr.getMessage();
        case 7:
          return lr.getLocation();
        case 8:
          return lr.getThrownStackTrace();
        default:
          String message = "The column number " + col + "must be between 0 and 8";
          throw new IllegalArgumentException(message);
      }
    }
  
    // We don't want the amount of rows to grow without bound,
    // leading to a out-of-memory-exception.  Especially not good
    // in a production environment :)
  
    // This method & clearLogRecords() are synchronized so we don't
    // delete rows that don't exist.
    protected void trimRecords() {
      if (needsTrimming()) {
        trimOldestRecords();
      }
    }
  
    protected boolean needsTrimming() {
      return (_allRecords.size() > _maxNumberOfLogRecords);
    }
  
    protected void trimOldestRecords() {
      synchronized (_allRecords) {
        int trim = numberOfRecordsToTrim();
        if (trim > 1) {
          List oldRecords =
              _allRecords.subList(0, trim);
          oldRecords.clear();
          refresh();
        } else {
          _allRecords.remove(0);
          fastRefresh();
        }
      }
  
    }
  
    //--------------------------------------------------------------------------
    //   Private Methods:
    //--------------------------------------------------------------------------
    private int numberOfRecordsToTrim() {
      return _allRecords.size() - _maxNumberOfLogRecords;
    }
  
    //--------------------------------------------------------------------------
    //   Nested Top-Level Classes or Interfaces
    //--------------------------------------------------------------------------
  }
  
  
  
  
  1.1                  jakarta-log4j/src/java/org/apache/log4j/lf5/viewer/LF5SwingUtils.java
  
  Index: LF5SwingUtils.java
  ===================================================================
  /*
   * Copyright (C) The Apache Software Foundation. All rights reserved.
   *
   * This software is published under the terms of the Apache Software
   * License version 1.1, a copy of which has been included with this
   * distribution in the LICENSE.txt file.
   */
  package org.apache.log4j.lf5.viewer;
  
  import javax.swing.*;
  import javax.swing.table.TableModel;
  import java.awt.*;
  
  /**
   * Provides methods to accomplish common yet non-trivial tasks
   * with Swing. Obvious implementations of these methods have been
   * tried and failed.
   *
   * @author Richard Wan
   */
  
  // Contributed by ThoughtWorks Inc.
  
  public class LF5SwingUtils {
    //--------------------------------------------------------------------------
    //   Constants:
    //--------------------------------------------------------------------------
  
    //--------------------------------------------------------------------------
    //   Protected Variables:
    //--------------------------------------------------------------------------
  
    //--------------------------------------------------------------------------
    //   Private Variables:
    //--------------------------------------------------------------------------
  
    //--------------------------------------------------------------------------
    //   Constructors:
    //--------------------------------------------------------------------------
  
    //--------------------------------------------------------------------------
    //   Public Methods:
    //--------------------------------------------------------------------------
  
    /**
     * Selects a the specified row in the specified JTable and scrolls
     * the specified JScrollpane to the newly selected row. More importantly,
     * the call to repaint() delayed long enough to have the table
     * properly paint the newly selected row which may be offscre
     * @param table should belong to the specified JScrollPane
     */
    public static void selectRow(int row, JTable table, JScrollPane pane) {
      if (table == null || pane == null) {
        return;
      }
      if (contains(row, table.getModel()) == false) {
        return;
      }
      moveAdjustable(row * table.getRowHeight(), pane.getVerticalScrollBar());
      selectRow(row, table.getSelectionModel());
      // repaint must be done later because moveAdjustable
      // posts requests to the swing thread which must execute before
      // the repaint logic gets executed.
      repaintLater(table);
    }
  
    /**
     * Makes the specified Adjustable track if the view area expands and
     * the specified Adjustable is located near the of the view.
     */
    public static void makeScrollBarTrack(Adjustable scrollBar) {
      if (scrollBar == null) {
        return;
      }
      scrollBar.addAdjustmentListener(new TrackingAdjustmentListener());
    }
  
    /**
     * Makes the vertical scroll bar of the specified JScrollPane
     * track if the view expands (e.g. if rows are added to an underlying
     * table).
     */
    public static void makeVerticalScrollBarTrack(JScrollPane pane) {
      if (pane == null) {
        return;
      }
      makeScrollBarTrack(pane.getVerticalScrollBar());
    }
  
    //--------------------------------------------------------------------------
    //   Protected Methods:
    //--------------------------------------------------------------------------
    protected static boolean contains(int row, TableModel model) {
      if (model == null) {
        return false;
      }
      if (row < 0) {
        return false;
      }
      if (row >= model.getRowCount()) {
        return false;
      }
      return true;
    }
  
    protected static void selectRow(int row, ListSelectionModel model) {
      if (model == null) {
        return;
      }
      model.setSelectionInterval(row, row);
    }
  
    protected static void moveAdjustable(int location, Adjustable scrollBar) {
      if (scrollBar == null) {
        return;
      }
      scrollBar.setValue(location);
    }
  
    /**
     * Work around for JTable/viewport bug.
     * @link http://developer.java.sun.com/developer/bugParade/bugs/4205145.html
     */
    protected static void repaintLater(final JComponent component) {
      SwingUtilities.invokeLater(new Runnable() {
        public void run() {
          component.repaint();
        }
      });
    }
    //--------------------------------------------------------------------------
    //   Private Methods:
    //--------------------------------------------------------------------------
  
    //--------------------------------------------------------------------------
    //   Nested Top-Level Classes or Interfaces
    //--------------------------------------------------------------------------
  }
  
  
  
  
  1.1                  jakarta-log4j/src/java/org/apache/log4j/lf5/viewer/LogBrokerMonitor.java
  
  Index: LogBrokerMonitor.java
  ===================================================================
  /*
   * Copyright (C) The Apache Software Foundation. All rights reserved.
   *
   * This software is published under the terms of the Apache Software
   * License version 1.1, a copy of which has been included with this
   * distribution in the LICENSE.txt file.
   */
  package org.apache.log4j.lf5.viewer;
  
  import org.apache.log4j.lf5.LogLevel;
  import org.apache.log4j.lf5.LogRecord;
  import org.apache.log4j.lf5.LogRecordFilter;
  import org.apache.log4j.lf5.util.DateFormatManager;
  import org.apache.log4j.lf5.util.LogFileParser;
  import org.apache.log4j.lf5.util.ProductProperties;
  import org.apache.log4j.lf5.util.StreamUtils;
  import org.apache.log4j.lf5.viewer.categoryexplorer.CategoryExplorerTree;
  import org.apache.log4j.lf5.viewer.categoryexplorer.CategoryPath;
  import org.apache.log4j.lf5.viewer.configure.ConfigurationManager;
  import org.apache.log4j.lf5.viewer.configure.MRUFileManager;
  
  import javax.swing.*;
  import java.awt.*;
  import java.awt.event.ActionEvent;
  import java.awt.event.ActionListener;
  import java.awt.event.WindowAdapter;
  import java.awt.event.WindowEvent;
  import java.io.File;
  import java.io.IOException;
  import java.io.InputStream;
  import java.net.MalformedURLException;
  import java.net.URL;
  import java.util.*;
  import java.util.List;
  
  /**
   * LogBrokerMonitor
   *.
   * @author Michael J. Sikorsky
   * @author Robert Shaw
   * @author Brad Marlborough
   * @author Richard Wan
   * @author Brent Sprecher
   * @author Richard Hurst
   */
  
  // Contributed by ThoughtWorks Inc.
  
  public class LogBrokerMonitor {
    //--------------------------------------------------------------------------
    //   Constants:
    //--------------------------------------------------------------------------
  
    public static final String DETAILED_VIEW = "Detailed";
  //    public static final String STANDARD_VIEW = "Standard";
  //    public static final String COMPACT_VIEW = "Compact";
    //--------------------------------------------------------------------------
    //   Protected Variables:
    //--------------------------------------------------------------------------
    protected JFrame _logMonitorFrame;
    protected int _logMonitorFrameWidth = 550;
    protected int _logMonitorFrameHeight = 500;
    protected LogTable _table;
    protected CategoryExplorerTree _categoryExplorerTree;
    protected String _searchText;
    protected String _NDCTextFilter = "";
    protected LogLevel _leastSevereDisplayedLogLevel = LogLevel.DEBUG;
  
    protected JScrollPane _logTableScrollPane;
    protected JLabel _statusLabel;
    protected Object _lock = new Object();
    protected JComboBox _fontSizeCombo;
  
    protected int _fontSize = 10;
    protected String _fontName = "Dialog";
    protected String _currentView = DETAILED_VIEW;
  
    protected boolean _loadSystemFonts = false;
    protected boolean _trackTableScrollPane = true;
    protected Dimension _lastTableViewportSize;
    protected boolean _callSystemExitOnClose = false;
    protected List _displayedLogBrokerProperties = new Vector();
  
    protected Map _logLevelMenuItems = new HashMap();
    protected Map _logTableColumnMenuItems = new HashMap();
  
    protected List _levels = null;
    protected List _columns = null;
    protected boolean _isDisposed = false;
  
    protected ConfigurationManager _configurationManager = null;
    protected MRUFileManager _mruFileManager = null;
    protected File _fileLocation = null;
  
    //--------------------------------------------------------------------------
    //   Private Variables:
    //--------------------------------------------------------------------------
  
    //--------------------------------------------------------------------------
    //   Constructors:
    //--------------------------------------------------------------------------
  
    /**
     * Construct a LogBrokerMonitor.
     */
    public LogBrokerMonitor(List logLevels) {
  
      _levels = logLevels;
      _columns = LogTableColumn.getLogTableColumns();
      // This allows us to use the LogBroker in command line tools and
      // have the option for it to shutdown.
  
      String callSystemExitOnClose =
          System.getProperty("monitor.exit");
      if (callSystemExitOnClose == null) {
        callSystemExitOnClose = "false";
      }
      callSystemExitOnClose = callSystemExitOnClose.trim().toLowerCase();
  
      if (callSystemExitOnClose.equals("true")) {
        _callSystemExitOnClose = true;
      }
  
      initComponents();
  
  
      _logMonitorFrame.addWindowListener(
          new LogBrokerMonitorWindowAdaptor(this));
  
    }
  
    //--------------------------------------------------------------------------
    //   Public Methods:
    //--------------------------------------------------------------------------
  
    /**
     * Show the frame for the LogBrokerMonitor. Dispatched to the
     * swing thread.
     */
    public void show(final int delay) {
      if (_logMonitorFrame.isVisible()) {
        return;
      }
      // This request is very low priority, let other threads execute first.
      SwingUtilities.invokeLater(new Runnable() {
        public void run() {
          Thread.yield();
          pause(delay);
          _logMonitorFrame.setVisible(true);
        }
      });
    }
  
    public void show() {
      show(0);
    }
  
    /**
     * Dispose of the frame for the LogBrokerMonitor.
     */
    public void dispose() {
      _logMonitorFrame.dispose();
      _isDisposed = true;
  
      if (_callSystemExitOnClose == true) {
        System.exit(0);
      }
    }
  
    /**
     * Hide the frame for the LogBrokerMonitor.
     */
    public void hide() {
      _logMonitorFrame.setVisible(false);
    }
  
    /**
     * Get the DateFormatManager for formatting dates.
     */
    public DateFormatManager getDateFormatManager() {
      return _table.getDateFormatManager();
    }
  
    /**
     * Set the date format manager for formatting dates.
     */
    public void setDateFormatManager(DateFormatManager dfm) {
      _table.setDateFormatManager(dfm);
    }
  
    /**
     * Get the value of whether or not System.exit() will be called
     * when the LogBrokerMonitor is closed.
     */
    public boolean getCallSystemExitOnClose() {
      return _callSystemExitOnClose;
    }
  
    /**
     * Set the value of whether or not System.exit() will be called
     * when the LogBrokerMonitor is closed.
     */
    public void setCallSystemExitOnClose(boolean callSystemExitOnClose) {
      _callSystemExitOnClose = callSystemExitOnClose;
    }
  
    /**
     * Add a log record message to be displayed in the LogTable.
     * This method is thread-safe as it posts requests to the SwingThread
     * rather than processing directly.
     */
    public void addMessage(final LogRecord lr) {
      if (_isDisposed == true) {
        // If the frame has been disposed of, do not log any more
        // messages.
        return;
      }
  
      SwingUtilities.invokeLater(new Runnable() {
        public void run() {
          _categoryExplorerTree.getExplorerModel().addLogRecord(lr);
          _table.getFilteredLogTableModel().addLogRecord(lr); // update table
          updateStatusLabel(); // show updated counts
        }
      });
    }
  
    public void setMaxNumberOfLogRecords(int maxNumberOfLogRecords) {
      _table.getFilteredLogTableModel().setMaxNumberOfLogRecords(maxNumberOfLogRecords);
    }
  
    public JFrame getBaseFrame() {
      return _logMonitorFrame;
    }
  
    public void setTitle(String title) {
      _logMonitorFrame.setTitle(title + " - LogFactor5");
    }
  
    public void setFrameSize(int width, int height) {
      Dimension screen = Toolkit.getDefaultToolkit().getScreenSize();
      if (0 < width && width < screen.width) {
        _logMonitorFrameWidth = width;
      }
      if (0 < height && height < screen.height) {
        _logMonitorFrameHeight = height;
      }
      updateFrameSize();
    }
  
    public void setFontSize(int fontSize) {
      changeFontSizeCombo(_fontSizeCombo, fontSize);
      // setFontSizeSilently(actualFontSize); - changeFontSizeCombo fires event
      // refreshDetailTextArea();
    }
  
    public void addDisplayedProperty(Object messageLine) {
      _displayedLogBrokerProperties.add(messageLine);
    }
  
    public Map getLogLevelMenuItems() {
      return _logLevelMenuItems;
    }
  
    public Map getLogTableColumnMenuItems() {
      return _logTableColumnMenuItems;
    }
  
    public JCheckBoxMenuItem getTableColumnMenuItem(LogTableColumn column) {
      return getLogTableColumnMenuItem(column);
    }
  
    public CategoryExplorerTree getCategoryExplorerTree() {
      return _categoryExplorerTree;
    }
  
    // Added in version 1.2 - gets the value of the NDC text filter
    // This value is set back to null each time the Monitor is initialized.
    public String getNDCTextFilter() {
      return _NDCTextFilter;
    }
  
    // Added in version 1.2 - sets the NDC Filter based on
    // a String passed in by the user.  This value is persisted
    // in the XML Configuration file.
    public void setNDCLogRecordFilter(String textFilter) {
      _table.getFilteredLogTableModel().
          setLogRecordFilter(createNDCLogRecordFilter(textFilter));
    }
    //--------------------------------------------------------------------------
    //   Protected Methods:
    //--------------------------------------------------------------------------
  
    protected void setSearchText(String text) {
      _searchText = text;
    }
  
    // Added in version 1.2 - Sets the text filter for the NDC
    protected void setNDCTextFilter(String text) {
      // if no value is set, set it to a blank string
      // otherwise use the value provided
      if (text == null) {
        _NDCTextFilter = "";
      } else {
        _NDCTextFilter = text;
      }
    }
  
    // Added in version 1.2 - Uses a different filter that sorts
    // based on an NDC string passed in by the user.  If the string
    // is null or is an empty string, we do nothing.
    protected void sortByNDC() {
      String text = _NDCTextFilter;
      if (text == null || text.length() == 0) {
        return;
      }
  
      // Use new NDC filter
      _table.getFilteredLogTableModel().
          setLogRecordFilter(createNDCLogRecordFilter(text));
    }
  
    protected void findSearchText() {
      String text = _searchText;
      if (text == null || text.length() == 0) {
        return;
      }
      int startRow = getFirstSelectedRow();
      int foundRow = findRecord(
          startRow,
          text,
          _table.getFilteredLogTableModel().getFilteredRecords()
      );
      selectRow(foundRow);
    }
  
    protected int getFirstSelectedRow() {
      return _table.getSelectionModel().getMinSelectionIndex();
    }
  
    protected void selectRow(int foundRow) {
      if (foundRow == -1) {
        String message = _searchText + " not found.";
        JOptionPane.showMessageDialog(
            _logMonitorFrame,
            message,
            "Text not found",
            JOptionPane.INFORMATION_MESSAGE
        );
        return;
      }
      LF5SwingUtils.selectRow(foundRow, _table, _logTableScrollPane);
    }
  
    protected int findRecord(
        int startRow,
        String searchText,
        List records
        ) {
      if (startRow < 0) {
        startRow = 0; // start at first element if no rows are selected
      } else {
        startRow++; // start after the first selected row
      }
      int len = records.size();
  
      for (int i = startRow; i < len; i++) {
        if (matches((LogRecord) records.get(i), searchText)) {
          return i; // found a record
        }
      }
      // wrap around to beginning if when we reach the end with no match
      len = startRow;
      for (int i = 0; i < len; i++) {
        if (matches((LogRecord) records.get(i), searchText)) {
          return i; // found a record
        }
      }
      // nothing found
      return -1;
    }
  
    /**
     * Check to see if the any records contain the search string.
     * Searching now supports NDC messages and date.
     */
    protected boolean matches(LogRecord record, String text) {
      String message = record.getMessage();
      String NDC = record.getNDC();
  
      if (message == null && NDC == null || text == null) {
        return false;
      }
      if (message.toLowerCase().indexOf(text.toLowerCase()) == -1 &&
          NDC.toLowerCase().indexOf(text.toLowerCase()) == -1) {
        return false;
      }
  
      return true;
    }
  
    /**
     * When the fontsize of a JTextArea is changed, the word-wrapped lines
     * may become garbled.  This method clears and resets the text of the
     * text area.
     */
    protected void refresh(JTextArea textArea) {
      String text = textArea.getText();
      textArea.setText("");
      textArea.setText(text);
    }
  
    protected void refreshDetailTextArea() {
      refresh(_table._detailTextArea);
    }
  
    protected void clearDetailTextArea() {
      _table._detailTextArea.setText("");
    }
  
    /**
     * Changes the font selection in the combo box and returns the
     * size actually selected.
     * @return -1 if unable to select an appropriate font
     */
    protected int changeFontSizeCombo(JComboBox box, int requestedSize) {
      int len = box.getItemCount();
      int currentValue;
      Object currentObject;
      Object selectedObject = box.getItemAt(0);
      int selectedValue = Integer.parseInt(String.valueOf(selectedObject));
      for (int i = 0; i < len; i++) {
        currentObject = box.getItemAt(i);
        currentValue = Integer.parseInt(String.valueOf(currentObject));
        if (selectedValue < currentValue && currentValue <= requestedSize) {
          selectedValue = currentValue;
          selectedObject = currentObject;
        }
      }
      box.setSelectedItem(selectedObject);
      return selectedValue;
    }
  
    /**
     * Does not update gui or cause any events to be fired.
     */
    protected void setFontSizeSilently(int fontSize) {
      _fontSize = fontSize;
      setFontSize(_table._detailTextArea, fontSize);
      selectRow(0);
      setFontSize(_table, fontSize);
    }
  
    protected void setFontSize(Component component, int fontSize) {
      Font oldFont = component.getFont();
      Font newFont =
          new Font(oldFont.getFontName(), oldFont.getStyle(), fontSize);
      component.setFont(newFont);
    }
  
    protected void updateFrameSize() {
      _logMonitorFrame.setSize(_logMonitorFrameWidth, _logMonitorFrameHeight);
      centerFrame(_logMonitorFrame);
    }
  
    protected void pause(int millis) {
      try {
        Thread.sleep(millis);
      } catch (InterruptedException e) {
  
      }
    }
  
    protected void initComponents() {
      //
      // Configure the Frame.
      //
      ProductProperties props = ProductProperties.getInstance();
  
      _logMonitorFrame = new JFrame("LogFactor5");
  
      _logMonitorFrame.setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE);
  
      String resource =
          "/org/apache/log4j/lf5/viewer/images/lf5_small_icon.gif";
      URL lf5IconURL = getClass().getResource(resource);
  
      if (lf5IconURL != null) {
        _logMonitorFrame.setIconImage(new ImageIcon(lf5IconURL).getImage());
      }
      updateFrameSize();
  
      //
      // Configure the LogTable.
      //
      JTextArea detailTA = createDetailTextArea();
      JScrollPane detailTAScrollPane = new JScrollPane(detailTA);
      _table = new LogTable(detailTA);
      setView(_currentView, _table);
      _table.setFont(new Font(_fontName, Font.PLAIN, _fontSize));
      _logTableScrollPane = new JScrollPane(_table);
  
      if (_trackTableScrollPane) {
        _logTableScrollPane.getVerticalScrollBar().addAdjustmentListener(
            new TrackingAdjustmentListener()
        );
      }
  
  
      // Configure the SplitPane between the LogTable & DetailTextArea
      //
  
      JSplitPane tableViewerSplitPane = new JSplitPane();
      tableViewerSplitPane.setOneTouchExpandable(true);
      tableViewerSplitPane.setOrientation(JSplitPane.VERTICAL_SPLIT);
      tableViewerSplitPane.setLeftComponent(_logTableScrollPane);
      tableViewerSplitPane.setRightComponent(detailTAScrollPane);
      // Make sure to do this last..
      //tableViewerSplitPane.setDividerLocation(1.0); Doesn't work
      //the same under 1.2.x & 1.3
      // "350" is a magic number that provides the correct default
      // behaviour under 1.2.x & 1.3.  For example, bumping this
      // number to 400, causes the pane to be completely open in 1.2.x
      // and closed in 1.3
      tableViewerSplitPane.setDividerLocation(350);
  
      //
      // Configure the CategoryExplorer
      //
  
      _categoryExplorerTree = new CategoryExplorerTree();
  
      _table.getFilteredLogTableModel().setLogRecordFilter(createLogRecordFilter());
  
      JScrollPane categoryExplorerTreeScrollPane =
          new JScrollPane(_categoryExplorerTree);
      categoryExplorerTreeScrollPane.setPreferredSize(new Dimension(130, 400));
  
      // Load most recently used file list
      _mruFileManager = new MRUFileManager();
  
      //
      // Configure the SplitPane between the CategoryExplorer & (LogTable/Detail)
      //
  
      JSplitPane splitPane = new JSplitPane();
      splitPane.setOneTouchExpandable(true);
      splitPane.setRightComponent(tableViewerSplitPane);
      splitPane.setLeftComponent(categoryExplorerTreeScrollPane);
      // Do this last.
      splitPane.setDividerLocation(130);
      //
      // Add the MenuBar, StatusArea, CategoryExplorer|LogTable to the
      // LogMonitorFrame.
      //
      _logMonitorFrame.getRootPane().setJMenuBar(createMenuBar());
      _logMonitorFrame.getContentPane().add(splitPane, BorderLayout.CENTER);
      _logMonitorFrame.getContentPane().add(createToolBar(),
          BorderLayout.NORTH);
      _logMonitorFrame.getContentPane().add(createStatusArea(),
          BorderLayout.SOUTH);
  
      makeLogTableListenToCategoryExplorer();
      addTableModelProperties();
  
      //
      // Configure ConfigurationManager
      //
      _configurationManager = new ConfigurationManager(this, _table);
  
    }
  
    protected LogRecordFilter createLogRecordFilter() {
      LogRecordFilter result = new LogRecordFilter() {
        public boolean passes(LogRecord record) {
          CategoryPath path = new CategoryPath(record.getCategory());
          return
              getMenuItem(record.getLevel()).isSelected() &&
              _categoryExplorerTree.getExplorerModel().isCategoryPathActive(path);
        }
      };
      return result;
    }
  
    // Added in version 1.2 - Creates a new filter that sorts records based on
    // an NDC string passed in by the user.
    protected LogRecordFilter createNDCLogRecordFilter(String text) {
      _NDCTextFilter = text;
      LogRecordFilter result = new LogRecordFilter() {
        public boolean passes(LogRecord record) {
          String NDC = record.getNDC();
          CategoryPath path = new CategoryPath(record.getCategory());
          if (NDC == null || _NDCTextFilter == null) {
            return false;
          } else if (NDC.toLowerCase().indexOf(_NDCTextFilter.toLowerCase()) == -1) {
            return false;
          } else {
            return getMenuItem(record.getLevel()).isSelected() &&
                _categoryExplorerTree.getExplorerModel().isCategoryPathActive(path);
          }
        }
      };
  
      return result;
    }
  
  
    protected void updateStatusLabel() {
      _statusLabel.setText(getRecordsDisplayedMessage());
    }
  
    protected String getRecordsDisplayedMessage() {
      FilteredLogTableModel model = _table.getFilteredLogTableModel();
      return getStatusText(model.getRowCount(), model.getTotalRowCount());
    }
  
    protected void addTableModelProperties() {
      final FilteredLogTableModel model = _table.getFilteredLogTableModel();
  
      addDisplayedProperty(new Object() {
        public String toString() {
          return getRecordsDisplayedMessage();
        }
      });
      addDisplayedProperty(new Object() {
        public String toString() {
          return "Maximum number of displayed LogRecords: "
              + model._maxNumberOfLogRecords;
        }
      });
    }
  
    protected String getStatusText(int displayedRows, int totalRows) {
      StringBuffer result = new StringBuffer();
      result.append("Displaying: ");
      result.append(displayedRows);
      result.append(" records out of a total of: ");
      result.append(totalRows);
      result.append(" records.");
      return result.toString();
    }
  
    protected void makeLogTableListenToCategoryExplorer() {
      ActionListener listener = new ActionListener() {
        public void actionPerformed(ActionEvent e) {
          _table.getFilteredLogTableModel().refresh();
          updateStatusLabel();
        }
      };
      _categoryExplorerTree.getExplorerModel().addActionListener(listener);
    }
  
    protected JPanel createStatusArea() {
      JPanel statusArea = new JPanel();
      JLabel status =
          new JLabel("No log records to display.");
      _statusLabel = status;
      status.setHorizontalAlignment(JLabel.LEFT);
  
      statusArea.setBorder(BorderFactory.createEtchedBorder());
      statusArea.setLayout(new FlowLayout(FlowLayout.LEFT, 0, 0));
      statusArea.add(status);
  
      return (statusArea);
    }
  
    protected JTextArea createDetailTextArea() {
      JTextArea detailTA = new JTextArea();
      detailTA.setFont(new Font("Monospaced", Font.PLAIN, 14));
      detailTA.setTabSize(3);
      detailTA.setLineWrap(true);
      detailTA.setWrapStyleWord(false);
      return (detailTA);
    }
  
    protected JMenuBar createMenuBar() {
      JMenuBar menuBar = new JMenuBar();
      menuBar.add(createFileMenu());
      menuBar.add(createEditMenu());
      menuBar.add(createLogLevelMenu());
      menuBar.add(createViewMenu());
      menuBar.add(createConfigureMenu());
      menuBar.add(createHelpMenu());
  
      return (menuBar);
    }
  
    protected JMenu createLogLevelMenu() {
      JMenu result = new JMenu("Log Level");
      result.setMnemonic('l');
      Iterator levels = getLogLevels();
      while (levels.hasNext()) {
        result.add(getMenuItem((LogLevel) levels.next()));
      }
  
      result.addSeparator();
      result.add(createAllLogLevelsMenuItem());
      result.add(createNoLogLevelsMenuItem());
      result.addSeparator();
      result.add(createLogLevelColorMenu());
      result.add(createResetLogLevelColorMenuItem());
  
      return result;
    }
  
    protected JMenuItem createAllLogLevelsMenuItem() {
      JMenuItem result = new JMenuItem("Show all LogLevels");
      result.setMnemonic('s');
      result.addActionListener(new ActionListener() {
        public void actionPerformed(ActionEvent e) {
          selectAllLogLevels(true);
          _table.getFilteredLogTableModel().refresh();
          updateStatusLabel();
        }
      });
      return result;
    }
  
    protected JMenuItem createNoLogLevelsMenuItem() {
      JMenuItem result = new JMenuItem("Hide all LogLevels");
      result.setMnemonic('h');
      result.addActionListener(new ActionListener() {
        public void actionPerformed(ActionEvent e) {
          selectAllLogLevels(false);
          _table.getFilteredLogTableModel().refresh();
          updateStatusLabel();
        }
      });
      return result;
    }
  
    protected JMenu createLogLevelColorMenu() {
      JMenu colorMenu = new JMenu("Configure LogLevel Colors");
      colorMenu.setMnemonic('c');
      Iterator levels = getLogLevels();
      while (levels.hasNext()) {
        colorMenu.add(createSubMenuItem((LogLevel) levels.next()));
      }
  
      return colorMenu;
    }
  
    protected JMenuItem createResetLogLevelColorMenuItem() {
      JMenuItem result = new JMenuItem("Reset LogLevel Colors");
      result.setMnemonic('r');
      result.addActionListener(new ActionListener() {
        public void actionPerformed(ActionEvent e) {
          // reset the level colors in the map
          LogLevel.resetLogLevelColorMap();
  
          // refresh the table
          _table.getFilteredLogTableModel().refresh();
        }
      });
      return result;
    }
  
    protected void selectAllLogLevels(boolean selected) {
      Iterator levels = getLogLevels();
      while (levels.hasNext()) {
        getMenuItem((LogLevel) levels.next()).setSelected(selected);
      }
    }
  
    protected JCheckBoxMenuItem getMenuItem(LogLevel level) {
      JCheckBoxMenuItem result = (JCheckBoxMenuItem) (_logLevelMenuItems.get(level));
      if (result == null) {
        result = createMenuItem(level);
        _logLevelMenuItems.put(level, result);
      }
      return result;
    }
  
    protected JMenuItem createSubMenuItem(LogLevel level) {
      final JMenuItem result = new JMenuItem(level.toString());
      final LogLevel logLevel = level;
      result.setMnemonic(level.toString().charAt(0));
      result.addActionListener(new ActionListener() {
        public void actionPerformed(ActionEvent e) {
          showLogLevelColorChangeDialog(result, logLevel);
        }
      });
  
      return result;
  
    }
  
    protected void showLogLevelColorChangeDialog(JMenuItem result, LogLevel level) {
      JMenuItem menuItem = result;
      Color newColor = JColorChooser.showDialog(
          _logMonitorFrame,
          "Choose LogLevel Color",
          result.getForeground());
  
      if (newColor != null) {
        // set the color for the record
        level.setLogLevelColorMap(level, newColor);
        _table.getFilteredLogTableModel().refresh();
      }
  
    }
  
    protected JCheckBoxMenuItem createMenuItem(LogLevel level) {
      JCheckBoxMenuItem result = new JCheckBoxMenuItem(level.toString());
      result.setSelected(true);
      result.setMnemonic(level.toString().charAt(0));
      result.addActionListener(new ActionListener() {
        public void actionPerformed(ActionEvent e) {
          _table.getFilteredLogTableModel().refresh();
          updateStatusLabel();
        }
      });
      return result;
    }
  
    // view menu
    protected JMenu createViewMenu() {
      JMenu result = new JMenu("View");
      result.setMnemonic('v');
      Iterator columns = getLogTableColumns();
      while (columns.hasNext()) {
        result.add(getLogTableColumnMenuItem((LogTableColumn) columns.next()));
      }
  
      result.addSeparator();
      result.add(createAllLogTableColumnsMenuItem());
      result.add(createNoLogTableColumnsMenuItem());
      return result;
    }
  
    protected JCheckBoxMenuItem getLogTableColumnMenuItem(LogTableColumn column) {
      JCheckBoxMenuItem result = (JCheckBoxMenuItem) (_logTableColumnMenuItems.get(column));
      if (result == null) {
        result = createLogTableColumnMenuItem(column);
        _logTableColumnMenuItems.put(column, result);
      }
      return result;
    }
  
    protected JCheckBoxMenuItem createLogTableColumnMenuItem(LogTableColumn column) {
      JCheckBoxMenuItem result = new JCheckBoxMenuItem(column.toString());
  
      result.setSelected(true);
      result.setMnemonic(column.toString().charAt(0));
      result.addActionListener(new ActionListener() {
        public void actionPerformed(ActionEvent e) {
          // update list of columns and reset the view
          List selectedColumns = updateView();
          _table.setView(selectedColumns);
        }
      });
      return result;
    }
  
    protected List updateView() {
      ArrayList updatedList = new ArrayList();
      Iterator columnIterator = _columns.iterator();
      while (columnIterator.hasNext()) {
        LogTableColumn column = (LogTableColumn) columnIterator.next();
        JCheckBoxMenuItem result = getLogTableColumnMenuItem(column);
        // check and see if the checkbox is checked
        if (result.isSelected()) {
          updatedList.add(column);
        }
      }
  
      return updatedList;
    }
  
    protected JMenuItem createAllLogTableColumnsMenuItem() {
      JMenuItem result = new JMenuItem("Show all Columns");
      result.setMnemonic('s');
      result.addActionListener(new ActionListener() {
        public void actionPerformed(ActionEvent e) {
          selectAllLogTableColumns(true);
          // update list of columns and reset the view
          List selectedColumns = updateView();
          _table.setView(selectedColumns);
        }
      });
      return result;
    }
  
    protected JMenuItem createNoLogTableColumnsMenuItem() {
      JMenuItem result = new JMenuItem("Hide all Columns");
      result.setMnemonic('h');
      result.addActionListener(new ActionListener() {
        public void actionPerformed(ActionEvent e) {
          selectAllLogTableColumns(false);
          // update list of columns and reset the view
          List selectedColumns = updateView();
          _table.setView(selectedColumns);
        }
      });
      return result;
    }
  
    protected void selectAllLogTableColumns(boolean selected) {
      Iterator columns = getLogTableColumns();
      while (columns.hasNext()) {
        getLogTableColumnMenuItem((LogTableColumn) columns.next()).setSelected(selected);
      }
    }
  
    protected JMenu createFileMenu() {
      JMenu fileMenu = new JMenu("File");
      fileMenu.setMnemonic('f');
      JMenuItem exitMI;
      fileMenu.add(createOpenMI());
      fileMenu.add(createOpenURLMI());
      fileMenu.addSeparator();
      fileMenu.add(createCloseMI());
      createMRUFileListMI(fileMenu);
      fileMenu.addSeparator();
      fileMenu.add(createExitMI());
      return fileMenu;
    }
  
    /**
     * Menu item added to allow log files to be opened with
     * the LF5 GUI.
     */
    protected JMenuItem createOpenMI() {
      JMenuItem result = new JMenuItem("Open...");
      result.setMnemonic('o');
      result.addActionListener(new ActionListener() {
        public void actionPerformed(ActionEvent e) {
          requestOpen();
        }
      });
      return result;
    }
  
    /**
     * Menu item added to allow log files loaded from a URL
     * to be opened by the LF5 GUI.
     */
    protected JMenuItem createOpenURLMI() {
      JMenuItem result = new JMenuItem("Open URL...");
      result.setMnemonic('u');
      result.addActionListener(new ActionListener() {
        public void actionPerformed(ActionEvent e) {
          requestOpenURL();
        }
      });
      return result;
    }
  
    protected JMenuItem createCloseMI() {
      JMenuItem result = new JMenuItem("Close");
      result.setMnemonic('c');
      result.setAccelerator(KeyStroke.getKeyStroke("control Q"));
      result.addActionListener(new ActionListener() {
        public void actionPerformed(ActionEvent e) {
          requestClose();
        }
      });
      return result;
    }
  
    /**
     * Creates a Most Recently Used file list to be
     * displayed in the File menu
     */
    protected void createMRUFileListMI(JMenu menu) {
  
      String[] files = _mruFileManager.getMRUFileList();
  
      if (files != null) {
        menu.addSeparator();
        for (int i = 0; i < files.length; i++) {
          JMenuItem result = new JMenuItem((i + 1) + " " + files[i]);
          result.setMnemonic(i + 1);
          result.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e) {
              requestOpenMRU(e);
            }
          });
          menu.add(result);
        }
      }
    }
  
    protected JMenuItem createExitMI() {
      JMenuItem result = new JMenuItem("Exit");
      result.setMnemonic('x');
      result.addActionListener(new ActionListener() {
        public void actionPerformed(ActionEvent e) {
          requestExit();
        }
      });
      return result;
    }
  
    protected JMenu createConfigureMenu() {
      JMenu configureMenu = new JMenu("Configure");
      configureMenu.setMnemonic('c');
      configureMenu.add(createConfigureSave());
      configureMenu.add(createConfigureReset());
      configureMenu.add(createConfigureMaxRecords());
  
      return configureMenu;
    }
  
    protected JMenuItem createConfigureSave() {
      JMenuItem result = new JMenuItem("Save");
      result.setMnemonic('s');
      result.addActionListener(new ActionListener() {
        public void actionPerformed(ActionEvent e) {
          saveConfiguration();
        }
      });
  
      return result;
    }
  
    protected JMenuItem createConfigureReset() {
      JMenuItem result = new JMenuItem("Reset");
      result.setMnemonic('r');
      result.addActionListener(new ActionListener() {
        public void actionPerformed(ActionEvent e) {
          resetConfiguration();
        }
      });
  
      return result;
    }
  
    protected JMenuItem createConfigureMaxRecords() {
      JMenuItem result = new JMenuItem("Set Max Number of Records");
      result.setMnemonic('m');
      result.addActionListener(new ActionListener() {
        public void actionPerformed(ActionEvent e) {
          setMaxRecordConfiguration();
        }
      });
  
      return result;
    }
  
  
    protected void saveConfiguration() {
      _configurationManager.save();
    }
  
    protected void resetConfiguration() {
      _configurationManager.reset();
    }
  
    protected void setMaxRecordConfiguration() {
      LogFactor5InputDialog inputDialog = new LogFactor5InputDialog(
          getBaseFrame(), "Set Max Number of Records", "", 10);
  
      String temp = inputDialog.getText();
  
      if (temp != null) {
        try {
          setMaxNumberOfLogRecords(Integer.parseInt(temp));
        } catch (NumberFormatException e) {
          LogFactor5ErrorDialog error = new LogFactor5ErrorDialog(
              getBaseFrame(),
              "'" + temp + "' is an invalid parameter.\nPlease try again.");
          setMaxRecordConfiguration();
        }
      }
    }
  
  
    protected JMenu createHelpMenu() {
      JMenu helpMenu = new JMenu("Help");
      helpMenu.setMnemonic('h');
      helpMenu.add(createHelpProperties());
      helpMenu.addSeparator();
      helpMenu.add(createHelpAbout());
      return helpMenu;
    }
  
    protected JMenuItem createHelpProperties() {
      final String title = "LogFactor5 Properties";
      final JMenuItem result = new JMenuItem(title);
      result.setMnemonic('l');
      result.addActionListener(new ActionListener() {
        public void actionPerformed(ActionEvent e) {
          showPropertiesDialog(title);
        }
      });
      return result;
    }
  
    protected void showPropertiesDialog(String title) {
      JOptionPane.showMessageDialog(
          _logMonitorFrame,
          _displayedLogBrokerProperties.toArray(),
          title,
          JOptionPane.PLAIN_MESSAGE
      );
    }
  
    protected JMenuItem createHelpAbout() {
      JMenuItem aboutMI = new JMenuItem("About LogFactor5...");
      aboutMI.setMnemonic('a');
      //aboutMI.setAccelerator( KeyStroke.getKeyStroke("control A") );
  
      aboutMI.addActionListener(
          new ActionListener() {
            protected LogFactor5AboutDialog dialog =
                new LogFactor5AboutDialog(_logMonitorFrame);
  
            public void actionPerformed(ActionEvent e) {
              dialog.show();
            }
          }
  
      );
      return aboutMI;
    }
  
    protected JMenu createEditMenu() {
      JMenu editMenu = new JMenu("Edit");
      editMenu.setMnemonic('e');
      editMenu.add(createEditFindMI());
      editMenu.add(createEditFindNextMI());
      editMenu.addSeparator();
      editMenu.add(createEditSortNDCMI());
      editMenu.add(createEditRestoreAllNDCMI());
      return editMenu;
    }
  
    protected JMenuItem createEditFindNextMI() {
      JMenuItem editFindNextMI = new JMenuItem("Find Next");
      editFindNextMI.setMnemonic('n');
      editFindNextMI.setAccelerator(KeyStroke.getKeyStroke("F3"));
      editFindNextMI.addActionListener(new ActionListener() {
        public void actionPerformed(ActionEvent e) {
          findSearchText();
        }
      });
      return editFindNextMI;
    }
  
    protected JMenuItem createEditFindMI() {
      JMenuItem editFindMI = new JMenuItem("Find");
      editFindMI.setMnemonic('f');
      editFindMI.setAccelerator(KeyStroke.getKeyStroke("control F"));
  
      editFindMI.addActionListener(
          new ActionListener() {
            public void actionPerformed(ActionEvent e) {
              String inputValue =
                  JOptionPane.showInputDialog(
                      _logMonitorFrame,
                      "Find text: ",
                      "Search Record Messages",
                      JOptionPane.QUESTION_MESSAGE
                  );
              setSearchText(inputValue);
              findSearchText();
            }
          }
  
      );
      return editFindMI;
    }
  
    // Added version 1.2 - Allows users to Sort Log Records by an
    // NDC text filter. A new LogRecordFilter was created to
    // sort the records.
    protected JMenuItem createEditSortNDCMI() {
      JMenuItem editSortNDCMI = new JMenuItem("Sort by NDC");
      editSortNDCMI.setMnemonic('s');
      editSortNDCMI.addActionListener(
          new ActionListener() {
            public void actionPerformed(ActionEvent e) {
              String inputValue =
                  JOptionPane.showInputDialog(
                      _logMonitorFrame,
                      "Sort by this NDC: ",
                      "Sort Log Records by NDC",
                      JOptionPane.QUESTION_MESSAGE
                  );
              setNDCTextFilter(inputValue);
              sortByNDC();
              _table.getFilteredLogTableModel().refresh();
              updateStatusLabel();
            }
          }
  
      );
      return editSortNDCMI;
    }
  
    // Added in version 1.2 - Resets the LogRecordFilter back to default
    // filter.
    protected JMenuItem createEditRestoreAllNDCMI() {
      JMenuItem editRestoreAllNDCMI = new JMenuItem("Restore all NDCs");
      editRestoreAllNDCMI.setMnemonic('r');
      editRestoreAllNDCMI.addActionListener(
          new ActionListener() {
            public void actionPerformed(ActionEvent e) {
              _table.getFilteredLogTableModel().setLogRecordFilter(createLogRecordFilter());
              // reset the text filter
              setNDCTextFilter("");
              _table.getFilteredLogTableModel().refresh();
              updateStatusLabel();
            }
          }
      );
      return editRestoreAllNDCMI;
    }
  
    protected JToolBar createToolBar() {
      JToolBar tb = new JToolBar();
      tb.putClientProperty("JToolBar.isRollover", Boolean.TRUE);
      JComboBox fontCombo = new JComboBox();
      JComboBox fontSizeCombo = new JComboBox();
      _fontSizeCombo = fontSizeCombo;
  
      ClassLoader cl = this.getClass().getClassLoader();
      URL newIconURL = cl.getResource("org/apache/log4j/viewer/" +
          "images/channelexplorer_new.gif");
  
      ImageIcon newIcon = null;
  
      if (newIconURL != null) {
        newIcon = new ImageIcon(newIconURL);
      }
  
      JButton newButton = new JButton("Clear Log Table");
  
      if (newIcon != null) {
        newButton.setIcon(newIcon);
      }
  
      newButton.setToolTipText("Clear Log Table.");
      //newButton.setBorder(BorderFactory.createEtchedBorder());
  
      newButton.addActionListener(
          new ActionListener() {
            public void actionPerformed(ActionEvent e) {
              _table.clearLogRecords();
              _categoryExplorerTree.getExplorerModel().resetAllNodeCounts();
              updateStatusLabel();
              clearDetailTextArea();
              LogRecord.resetSequenceNumber();
            }
          }
      );
  
      Toolkit tk = Toolkit.getDefaultToolkit();
      // This will actually grab all the fonts
  
      String[] fonts;
  
      if (_loadSystemFonts) {
        fonts = GraphicsEnvironment.
            getLocalGraphicsEnvironment().getAvailableFontFamilyNames();
      } else {
        fonts = tk.getFontList();
      }
  
      for (int j = 0; j < fonts.length; j++) {
        fontCombo.addItem(fonts[j]);
      }
  
      fontCombo.setSelectedItem(_fontName);
  
      fontCombo.addActionListener(
  
          new ActionListener() {
            public void actionPerformed(ActionEvent e) {
              JComboBox box = (JComboBox) e.getSource();
              String font = (String) box.getSelectedItem();
              _table.setFont(new Font(font, Font.PLAIN, _fontSize));
              _fontName = font;
            }
          }
      );
  
      fontSizeCombo.addItem("8");
      fontSizeCombo.addItem("9");
      fontSizeCombo.addItem("10");
      fontSizeCombo.addItem("12");
      fontSizeCombo.addItem("14");
      fontSizeCombo.addItem("16");
      fontSizeCombo.addItem("18");
      fontSizeCombo.addItem("24");
  
      fontSizeCombo.setSelectedItem(String.valueOf(_fontSize));
      fontSizeCombo.addActionListener(
          new ActionListener() {
            public void actionPerformed(ActionEvent e) {
              JComboBox box = (JComboBox) e.getSource();
              String size = (String) box.getSelectedItem();
              int s = Integer.valueOf(size).intValue();
  
              setFontSizeSilently(s);
              refreshDetailTextArea();
              _fontSize = s;
            }
          }
      );
  
      tb.add(new JLabel(" Font: "));
      tb.add(fontCombo);
      tb.add(fontSizeCombo);
      tb.addSeparator();
      tb.addSeparator();
      tb.add(newButton);
  
      newButton.setAlignmentY(0.5f);
      newButton.setAlignmentX(0.5f);
  
      fontCombo.setMaximumSize(fontCombo.getPreferredSize());
      fontSizeCombo.setMaximumSize(
          fontSizeCombo.getPreferredSize());
  
      return (tb);
    }
  
  //    protected void setView(String viewString, LogTable table) {
  //        if (STANDARD_VIEW.equals(viewString)) {
  //            table.setStandardView();
  //        } else if (COMPACT_VIEW.equals(viewString)) {
  //            table.setCompactView();
  //        } else if (DETAILED_VIEW.equals(viewString)) {
  //            table.setDetailedView();
  //        } else {
  //            String message = viewString + "does not match a supported view.";
  //            throw new IllegalArgumentException(message);
  //        }
  //        _currentView = viewString;
  //    }
  
    protected void setView(String viewString, LogTable table) {
      if (DETAILED_VIEW.equals(viewString)) {
        table.setDetailedView();
      } else {
        String message = viewString + "does not match a supported view.";
        throw new IllegalArgumentException(message);
      }
      _currentView = viewString;
    }
  
    protected JComboBox createLogLevelCombo() {
      JComboBox result = new JComboBox();
      Iterator levels = getLogLevels();
      while (levels.hasNext()) {
        result.addItem(levels.next());
      }
      result.setSelectedItem(_leastSevereDisplayedLogLevel);
  
      result.addActionListener(new ActionListener() {
        public void actionPerformed(ActionEvent e) {
          JComboBox box = (JComboBox) e.getSource();
          LogLevel level = (LogLevel) box.getSelectedItem();
          setLeastSevereDisplayedLogLevel(level);
        }
      });
      result.setMaximumSize(result.getPreferredSize());
      return result;
    }
  
    protected void setLeastSevereDisplayedLogLevel(LogLevel level) {
      if (level == null || _leastSevereDisplayedLogLevel == level) {
        return; // nothing to do
      }
      _leastSevereDisplayedLogLevel = level;
      _table.getFilteredLogTableModel().refresh();
      updateStatusLabel();
    }
  
    /**
     * Ensures that the Table's ScrollPane Viewport will "track" with updates
     * to the Table.  When the vertical scroll bar is at its bottom anchor
     * and tracking is enabled then viewport will stay at the bottom most
     * point of the component.  The purpose of this feature is to allow
     * a developer to watch the table as messages arrive and not have to
     * scroll after each new message arrives.  When the vertical scroll bar
     * is at any other location, then no tracking will happen.
     * @deprecated tracking is now done automatically.
     */
    protected void trackTableScrollPane() {
      // do nothing
    }
  
    protected void centerFrame(JFrame frame) {
      Dimension screen = Toolkit.getDefaultToolkit().getScreenSize();
      Dimension comp = frame.getSize();
  
      frame.setLocation(((screen.width - comp.width) / 2),
          ((screen.height - comp.height) / 2));
  
    }
  
    /**
     * Uses a JFileChooser to select a file to opened with the
     * LF5 GUI.
     */
    protected void requestOpen() {
      JFileChooser chooser;
  
      if (_fileLocation == null) {
        chooser = new JFileChooser();
      } else {
        chooser = new JFileChooser(_fileLocation);
      }
  
      int returnVal = chooser.showOpenDialog(_logMonitorFrame);
      if (returnVal == JFileChooser.APPROVE_OPTION) {
        File f = chooser.getSelectedFile();
        if (loadLogFile(f)) {
          _fileLocation = chooser.getSelectedFile();
          _mruFileManager.set(f);
          updateMRUList();
        }
      }
    }
  
    /**
     * Uses a Dialog box to accept a URL to a file to be opened
     * with the LF5 GUI.
     */
    protected void requestOpenURL() {
      LogFactor5InputDialog inputDialog = new LogFactor5InputDialog(
          getBaseFrame(), "Open URL", "URL:");
      String temp = inputDialog.getText();
  
      if (temp != null) {
        if (temp.indexOf("://") == -1) {
          temp = "http://" + temp;
        }
  
        try {
          URL url = new URL(temp);
          if (loadLogFile(url)) {
            _mruFileManager.set(url);
            updateMRUList();
          }
        } catch (MalformedURLException e) {
          LogFactor5ErrorDialog error = new LogFactor5ErrorDialog(
              getBaseFrame(), "Error reading URL.");
        }
      }
    }
  
    /**
     * Removes old file list and creates a new file list
     * with the updated MRU list.
     */
    protected void updateMRUList() {
      JMenu menu = _logMonitorFrame.getJMenuBar().getMenu(0);
      menu.removeAll();
      menu.add(createOpenMI());
      menu.add(createOpenURLMI());
      menu.addSeparator();
      menu.add(createCloseMI());
      createMRUFileListMI(menu);
      menu.addSeparator();
      menu.add(createExitMI());
    }
  
    protected void requestClose() {
      setCallSystemExitOnClose(false);
      closeAfterConfirm();
    }
  
    /**
     * Opens a file in the MRU list.
     */
    protected void requestOpenMRU(ActionEvent e) {
      String file = e.getActionCommand();
      StringTokenizer st = new StringTokenizer(file);
      String num = st.nextToken().trim();
      file = st.nextToken("\n");
  
      try {
        int index = Integer.parseInt(num) - 1;
  
        InputStream in = _mruFileManager.getInputStream(index);
        LogFileParser lfp = new LogFileParser(in);
        lfp.parse(this);
  
        _mruFileManager.moveToTop(index);
        updateMRUList();
  
      } catch (Exception me) {
        LogFactor5ErrorDialog error = new LogFactor5ErrorDialog(
            getBaseFrame(), "Unable to load file " + file);
      }
  
    }
  
    protected void requestExit() {
      _mruFileManager.save();
      setCallSystemExitOnClose(true);
      closeAfterConfirm();
    }
  
    protected void closeAfterConfirm() {
      StringBuffer message = new StringBuffer();
  
      if (_callSystemExitOnClose == false) {
        message.append("Are you sure you want to close the logging ");
        message.append("console?\n");
        message.append("(Note: This will not shut down the Virtual Machine,\n");
        message.append("or the Swing event thread.)");
      } else {
        message.append("Are you sure you want to exit?\n");
        message.append("This will shut down the Virtual Machine.\n");
      }
  
      String title =
          "Are you sure you want to dispose of the Logging Console?";
  
      if (_callSystemExitOnClose == true) {
        title = "Are you sure you want to exit?";
      }
      int value = JOptionPane.showConfirmDialog(
          _logMonitorFrame,
          message.toString(),
          title,
          JOptionPane.OK_CANCEL_OPTION,
          JOptionPane.QUESTION_MESSAGE,
          null
      );
  
      if (value == JOptionPane.OK_OPTION) {
        dispose();
      }
    }
  
    protected Iterator getLogLevels() {
      return _levels.iterator();
    }
  
    protected Iterator getLogTableColumns() {
      return _columns.iterator();
    }
  
    /**
     * Loads and parses a log file.
     */
    protected boolean loadLogFile(File file) {
      boolean ok = false;
      try {
        LogFileParser lfp = new LogFileParser(file);
        lfp.parse(this);
        ok = true;
      } catch (IOException e) {
        LogFactor5ErrorDialog error = new LogFactor5ErrorDialog(
            getBaseFrame(), "Error reading " + file.getName());
      }
  
      return ok;
    }
  
    /**
     * Loads a parses a log file running on a server.
     */
    protected boolean loadLogFile(URL url) {
      boolean ok = false;
      try {
        LogFileParser lfp = new LogFileParser(url.openStream());
        lfp.parse(this);
        ok = true;
      } catch (IOException e) {
        LogFactor5ErrorDialog error = new LogFactor5ErrorDialog(
            getBaseFrame(), "Error reading URL:" + url.getFile());
      }
      return ok;
    }
    //--------------------------------------------------------------------------
    //   Private Methods:
    //--------------------------------------------------------------------------
  
    //--------------------------------------------------------------------------
    //   Nested Top-Level Classes or Interfaces:
    //--------------------------------------------------------------------------
  
    class LogBrokerMonitorWindowAdaptor extends WindowAdapter {
      protected LogBrokerMonitor _monitor;
  
      public LogBrokerMonitorWindowAdaptor(LogBrokerMonitor monitor) {
        _monitor = monitor;
      }
  
      public void windowClosing(WindowEvent ev) {
        _monitor.requestClose();
      }
    }
  }
  
  
  
  
  
  1.1                  jakarta-log4j/src/java/org/apache/log4j/lf5/viewer/LogFactor5AboutDialog.java
  
  Index: LogFactor5AboutDialog.java
  ===================================================================
  /*
   * Copyright (C) The Apache Software Foundation. All rights reserved.
   *
   * This software is published under the terms of the Apache Software
   * License version 1.1, a copy of which has been included with this
   * distribution in the LICENSE.txt file.
   */
  package org.apache.log4j.lf5.viewer;
  
  import org.apache.log4j.lf5.util.ProductProperties;
  import org.apache.log4j.lf5.util.Resource;
  
  import javax.swing.*;
  import java.awt.*;
  import java.awt.event.ActionEvent;
  import java.awt.event.ActionListener;
  import java.net.URL;
  
  /**
   * LogFactor5AboutDialog
   *
   * @author Michael J. Sikorsky
   * @author Robert Shaw
   * @author Brent Sprecher
   * @author Brad Marlborough
   */
  
  // Contributed by ThoughtWorks Inc.
  
  public class LogFactor5AboutDialog extends JDialog {
    //--------------------------------------------------------------------------
    //   Constants:
    //--------------------------------------------------------------------------
  
    //--------------------------------------------------------------------------
    //   Protected Variables:
    //--------------------------------------------------------------------------
  
    //--------------------------------------------------------------------------
    //   Private Variables:
    //--------------------------------------------------------------------------
  
    //--------------------------------------------------------------------------
    //   Constructors:
    //--------------------------------------------------------------------------
  
    //--------------------------------------------------------------------------
    //   Public Methods:
    //--------------------------------------------------------------------------
  
    public LogFactor5AboutDialog(Frame owner) {
      super(owner, "About LogFactor5", true);
  
      ProductProperties props = ProductProperties.getInstance();
  
      setTitle("About LogFactor5");
  
      JPanel imagePanel = new JPanel();
      Resource aboutResource = new Resource("org/apache/log4j/lf5/viewer/images/" +
          "lf5_about.gif");
      URL aboutIconURL = aboutResource.getURL();
      ImageIcon aboutIcon = null;
      if (aboutIconURL != null) {
        aboutIcon = new ImageIcon(aboutIconURL);
      }
  
      JLabel imageLabel = new JLabel();
  
      if (aboutIcon != null) {
        imageLabel.setIcon(aboutIcon);
      }
      imagePanel.add(imageLabel);
  
      JPanel textPanel = new JPanel();
      textPanel.setLayout(new GridLayout(3, 1));
  
  
      int numberOfRows = 13;
      numberOfRows = 11; // we need less room for a registered user.
      JPanel mainPanel = new JPanel();
      mainPanel.setLayout(new GridLayout(numberOfRows, 1));
      JLabel aboutLF5 = new JLabel("LogFactor5 v" + props.getProductVersionNumber(), JLabel.CENTER);
      aboutLF5.setHorizontalAlignment(SwingConstants.CENTER);
      JLabel donate = new JLabel("Contributed by ThoughtWorks Inc.");
      donate.setHorizontalAlignment(SwingConstants.CENTER);
      mainPanel.add(aboutLF5);
      mainPanel.add(Box.createVerticalStrut(10));
      mainPanel.add(donate);
      mainPanel.add(Box.createVerticalStrut(10));
  
      JButton ok = new JButton("OK");
      JPanel southPanel = new JPanel();
      southPanel.setLayout(new FlowLayout());
      southPanel.add(ok);
      ok.addActionListener(
          new ActionListener() {
            public void actionPerformed(ActionEvent e) {
              hide();
            }
          }
  
      );
      getContentPane().add(imagePanel, BorderLayout.NORTH);
      getContentPane().add(mainPanel, BorderLayout.CENTER);
      getContentPane().add(southPanel, BorderLayout.SOUTH);
      setSize(414, 400);
      center();
    }
    //--------------------------------------------------------------------------
    //   Protected Methods:
    //--------------------------------------------------------------------------
  
    protected void center() {
      Dimension screen = Toolkit.getDefaultToolkit().getScreenSize();
      Dimension comp = getSize();
  
      setLocation(((screen.width - comp.width) / 2),
          ((screen.height - comp.height) / 2));
  
    }
  
    //--------------------------------------------------------------------------
    //   Private Methods:
    //--------------------------------------------------------------------------
  
    //--------------------------------------------------------------------------
    //   Nested Top-Level Classes or Interfaces:
    //--------------------------------------------------------------------------
  
  }
  
  
  
  
  
  
  
  
  
  1.1                  jakarta-log4j/src/java/org/apache/log4j/lf5/viewer/LogFactor5Dialog.java
  
  Index: LogFactor5Dialog.java
  ===================================================================
  /*
   * Copyright (C) The Apache Software Foundation. All rights reserved.
   *
   * This software is published under the terms of the Apache Software
   * License version 1.1, a copy of which has been included with this
   * distribution in the LICENSE.txt file.
   */
  package org.apache.log4j.lf5.viewer;
  
  import javax.swing.*;
  import java.awt.*;
  
  /**
   * LogFactor5Dialog
   *
   * @author Richard Hurst
   * @author Brad Marlborough
   */
  
  // Contributed by ThoughtWorks Inc.
  
  public abstract class LogFactor5Dialog extends JDialog {
    //--------------------------------------------------------------------------
    //   Constants:
    //--------------------------------------------------------------------------
    protected static final Font DISPLAY_FONT = new Font("Arial", Font.BOLD, 12);
    //--------------------------------------------------------------------------
    //   Protected Variables:
    //--------------------------------------------------------------------------
  
    //--------------------------------------------------------------------------
    //   Private Variables:
    //--------------------------------------------------------------------------
  
    //--------------------------------------------------------------------------
    //   Constructors:
    //--------------------------------------------------------------------------
    protected LogFactor5Dialog(JFrame jframe, String message, boolean modal) {
      super(jframe, message, modal);
    }
  
    //--------------------------------------------------------------------------
    //   Public Methods:
    //--------------------------------------------------------------------------
    public void show() {
      pack();
      minimumSizeDialog(this, 200, 100);
      centerWindow(this);
      super.show();
    }
  
    //--------------------------------------------------------------------------
    //   Protected Methods:
    //--------------------------------------------------------------------------
  
    //--------------------------------------------------------------------------
    //   Private Methods:
    //--------------------------------------------------------------------------
    protected void centerWindow(Window win) {
      Dimension screenDim = Toolkit.getDefaultToolkit().getScreenSize();
  
      // If larger than screen, reduce window width or height
      if (screenDim.width < win.getSize().width) {
        win.setSize(screenDim.width, win.getSize().height);
      }
  
      if (screenDim.height < win.getSize().height) {
        win.setSize(win.getSize().width, screenDim.height);
      }
  
      // Center Frame, Dialogue or Window on screen
      int x = (screenDim.width - win.getSize().width) / 2;
      int y = (screenDim.height - win.getSize().height) / 2;
      win.setLocation(x, y);
    }
  
    protected void wrapStringOnPanel(String message,
        Container container) {
      GridBagConstraints c = getDefaultConstraints();
      c.gridwidth = GridBagConstraints.REMAINDER;
      // Insets() args are top, left, bottom, right
      c.insets = new Insets(0, 0, 0, 0);
      GridBagLayout gbLayout = (GridBagLayout) container.getLayout();
  
  
      while (message.length() > 0) {
        int newLineIndex = message.indexOf('\n');
        String line;
        if (newLineIndex >= 0) {
          line = message.substring(0, newLineIndex);
          message = message.substring(newLineIndex + 1);
        } else {
          line = message;
          message = "";
        }
        Label label = new Label(line);
        label.setFont(DISPLAY_FONT);
        gbLayout.setConstraints(label, c);
        container.add(label);
      }
    }
  
    protected GridBagConstraints getDefaultConstraints() {
      GridBagConstraints constraints = new GridBagConstraints();
      constraints.weightx = 1.0;
      constraints.weighty = 1.0;
      constraints.gridheight = 1; // One row high
      // Insets() args are top, left, bottom, right
      constraints.insets = new Insets(4, 4, 4, 4);
      // fill of NONE means do not change size
      constraints.fill = GridBagConstraints.NONE;
      // WEST means align left
      constraints.anchor = GridBagConstraints.WEST;
  
      return constraints;
    }
  
    protected void minimumSizeDialog(Component component,
        int minWidth,
        int minHeight) {
      // set the min width
      if (component.getSize().width < minWidth)
        component.setSize(minWidth, component.getSize().height);
      // set the min height
      if (component.getSize().height < minHeight)
        component.setSize(component.getSize().width, minHeight);
    }
    //--------------------------------------------------------------------------
    //   Nested Top-Level Classes or Interfaces
    //--------------------------------------------------------------------------
  }
  
  
  1.1                  jakarta-log4j/src/java/org/apache/log4j/lf5/viewer/LogFactor5ErrorDialog.java
  
  Index: LogFactor5ErrorDialog.java
  ===================================================================
  /*
   * Copyright (C) The Apache Software Foundation. All rights reserved.
   *
   * This software is published under the terms of the Apache Software
   * License version 1.1, a copy of which has been included with this
   * distribution in the LICENSE.txt file.
   */
  package org.apache.log4j.lf5.viewer;
  
  import javax.swing.*;
  import java.awt.*;
  import java.awt.event.ActionEvent;
  import java.awt.event.ActionListener;
  
  /**
   * LogFactor5ErrorDialog
   *
   * @author Richard Hurst
   * @author Brad Marlborough
   */
  
  // Contributed by ThoughtWorks Inc.
  
  public class LogFactor5ErrorDialog extends LogFactor5Dialog {
    //--------------------------------------------------------------------------
    //   Constants:
    //--------------------------------------------------------------------------
  
    //--------------------------------------------------------------------------
    //   Protected Variables:
    //--------------------------------------------------------------------------
  
    //--------------------------------------------------------------------------
    //   Private Variables:
    //--------------------------------------------------------------------------
  
    //--------------------------------------------------------------------------
    //   Constructors:
    //--------------------------------------------------------------------------
    public LogFactor5ErrorDialog(JFrame jframe, String message) {
      super(jframe, "Error", true);
  
      JButton ok = new JButton("Ok");
      ok.addActionListener(new ActionListener() {
        public void actionPerformed(ActionEvent e) {
          hide();
        }
      });
  
      JPanel bottom = new JPanel();
      bottom.setLayout(new FlowLayout());
      bottom.add(ok);
  
      JPanel main = new JPanel();
      main.setLayout(new GridBagLayout());
      wrapStringOnPanel(message, main);
  
      getContentPane().add(main, BorderLayout.CENTER);
      getContentPane().add(bottom, BorderLayout.SOUTH);
      show();
  
    }
    //--------------------------------------------------------------------------
    //   Public Methods:
    //--------------------------------------------------------------------------
  
    //--------------------------------------------------------------------------
    //   Protected Methods:
    //--------------------------------------------------------------------------
  
    //--------------------------------------------------------------------------
    //   Private Methods:
    //--------------------------------------------------------------------------
  
    //--------------------------------------------------------------------------
    //   Nested Top-Level Classes or Interfaces
    //--------------------------------------------------------------------------
  }
  
  
  1.1                  jakarta-log4j/src/java/org/apache/log4j/lf5/viewer/LogFactor5InputDialog.java
  
  Index: LogFactor5InputDialog.java
  ===================================================================
  /*
   * Copyright (C) The Apache Software Foundation. All rights reserved.
   *
   * This software is published under the terms of the Apache Software
   * License version 1.1, a copy of which has been included with this
   * distribution in the LICENSE.txt file.
   */
  package org.apache.log4j.lf5.viewer;
  
  import javax.swing.*;
  import java.awt.*;
  import java.awt.event.ActionEvent;
  import java.awt.event.ActionListener;
  import java.awt.event.KeyAdapter;
  import java.awt.event.KeyEvent;
  
  /**
   * LogFactor5InputDialog
   *
   * Creates a popup input dialog box so that users can enter
   * a URL to open a log file from.
   *
   * @author Richard Hurst
   * @author Brad Marlborough
   */
  
  // Contributed by ThoughtWorks Inc.
  
  public class LogFactor5InputDialog extends LogFactor5Dialog {
    //--------------------------------------------------------------------------
    //   Constants:
    //--------------------------------------------------------------------------
    public static final int SIZE = 30;
    //--------------------------------------------------------------------------
    //   Protected Variables:
    //--------------------------------------------------------------------------
  
    //--------------------------------------------------------------------------
    //   Private Variables:
    //--------------------------------------------------------------------------
    private JTextField _textField;
    //--------------------------------------------------------------------------
    //   Constructors:
    //--------------------------------------------------------------------------
  
    /**
     * Configures an input dialog box using a defualt size for the text field.
     * param jframe the frame where the dialog will be loaded from.
     * param title the title of the dialog box.
     * param label the label to be put in the dialog box.
     */
    public LogFactor5InputDialog(JFrame jframe, String title, String label) {
      this(jframe, title, label, SIZE);
    }
  
    /**
     * Configures an input dialog box.
     * param jframe the frame where the dialog will be loaded from.
     * param title the title of the dialog box.
     * param label the label to be put in the dialog box.
     * param size the size of the text field.
     */
    public LogFactor5InputDialog(JFrame jframe, String title, String label,
        int size) {
      super(jframe, title, true);
  
      JPanel bottom = new JPanel();
      bottom.setLayout(new FlowLayout());
  
      JPanel main = new JPanel();
      main.setLayout(new FlowLayout());
      main.add(new JLabel(label));
      _textField = new JTextField(size);
      main.add(_textField);
  
      addKeyListener(new KeyAdapter() {
        public void keyPressed(KeyEvent e) {
          if (e.getKeyCode() == KeyEvent.VK_ENTER) {
            hide();
          }
        }
      });
  
      JButton ok = new JButton("Ok");
      ok.addActionListener(new ActionListener() {
        public void actionPerformed(ActionEvent e) {
          hide();
        }
      });
  
      JButton cancel = new JButton("Cancel");
      cancel.addActionListener(new ActionListener() {
        public void actionPerformed(ActionEvent e) {
          hide();
          // set the text field to blank just in case
          // a file was selected before the Cancel
          // button was pressed.
          _textField.setText("");
        }
      });
  
      bottom.add(ok);
      bottom.add(cancel);
      getContentPane().add(main, BorderLayout.CENTER);
      getContentPane().add(bottom, BorderLayout.SOUTH);
      pack();
      centerWindow(this);
      show();
    }
  
    //--------------------------------------------------------------------------
    //   Public Methods:
    //--------------------------------------------------------------------------
    public String getText() {
      String s = _textField.getText();
  
      if (s != null && s.trim().length() == 0) {
        return null;
      }
  
      return s;
  
    }
  
    //--------------------------------------------------------------------------
    //   Protected Methods:
    //--------------------------------------------------------------------------
  
    //--------------------------------------------------------------------------
    //   Private Methods:
    //--------------------------------------------------------------------------
  
    //--------------------------------------------------------------------------
    //   Nested Top-Level Classes or Interfaces
    //--------------------------------------------------------------------------
  }
  
  
  1.1                  jakarta-log4j/src/java/org/apache/log4j/lf5/viewer/LogFactor5LoadingDialog.java
  
  Index: LogFactor5LoadingDialog.java
  ===================================================================
  /*
   * Copyright (C) The Apache Software Foundation. All rights reserved.
   *
   * This software is published under the terms of the Apache Software
   * License version 1.1, a copy of which has been included with this
   * distribution in the LICENSE.txt file.
   */
  package org.apache.log4j.lf5.viewer;
  
  import javax.swing.*;
  import java.awt.*;
  
  /**
   * LogFactor5LoadingDialog
   *
   * @author Richard Hurst
   * @author Brad Marlborough
   */
  
  // Contributed by ThoughtWorks Inc.
  
  public class LogFactor5LoadingDialog extends LogFactor5Dialog {
    //--------------------------------------------------------------------------
    //   Constants:
    //--------------------------------------------------------------------------
  
    //--------------------------------------------------------------------------
    //   Protected Variables:
    //--------------------------------------------------------------------------
  
    //--------------------------------------------------------------------------
    //   Private Variables:
    //--------------------------------------------------------------------------
  
    //--------------------------------------------------------------------------
    //   Constructors:
    //--------------------------------------------------------------------------
  
    public LogFactor5LoadingDialog(JFrame jframe, String message) {
      super(jframe, "LogFactor5", false);
  
      JPanel bottom = new JPanel();
      bottom.setLayout(new FlowLayout());
  
      JPanel main = new JPanel();
      main.setLayout(new GridBagLayout());
      wrapStringOnPanel(message, main);
  
      getContentPane().add(main, BorderLayout.CENTER);
      getContentPane().add(bottom, BorderLayout.SOUTH);
      show();
  
    }
    //--------------------------------------------------------------------------
    //   Public Methods:
    //--------------------------------------------------------------------------
  
    //--------------------------------------------------------------------------
    //   Protected Methods:
    //--------------------------------------------------------------------------
  
    //--------------------------------------------------------------------------
    //   Private Methods:
    //--------------------------------------------------------------------------
  
    //--------------------------------------------------------------------------
    //   Nested Top-Level Classes or Interfaces
    //--------------------------------------------------------------------------
  }
  
  
  1.1                  jakarta-log4j/src/java/org/apache/log4j/lf5/viewer/LogTable.java
  
  Index: LogTable.java
  ===================================================================
  /*
   * Copyright (C) The Apache Software Foundation. All rights reserved.
   *
   * This software is published under the terms of the Apache Software
   * License version 1.1, a copy of which has been included with this
   * distribution in the LICENSE.txt file.
   */
  package org.apache.log4j.lf5.viewer;
  
  import org.apache.log4j.lf5.util.DateFormatManager;
  
  import javax.swing.*;
  import javax.swing.event.ListSelectionEvent;
  import javax.swing.event.ListSelectionListener;
  import javax.swing.table.TableColumn;
  import javax.swing.table.TableColumnModel;
  import java.awt.*;
  import java.util.Enumeration;
  import java.util.Iterator;
  import java.util.List;
  import java.util.Vector;
  
  /**
   * LogTable.
   *
   * @author Michael J. Sikorsky
   * @author Robert Shaw
   * @author Brad Marlborough
   * @author Brent Sprecher
   */
  
  // Contributed by ThoughtWorks Inc.
  
  public class LogTable extends JTable {
    //--------------------------------------------------------------------------
    //   Constants:
    //--------------------------------------------------------------------------
  
    //--------------------------------------------------------------------------
    //   Protected Variables:
    //--------------------------------------------------------------------------
    protected int _rowHeight = 30;
    protected JTextArea _detailTextArea;
  
    // For the columns:
    protected int _numCols = 9;
    protected TableColumn[] _tableColumns = new TableColumn[_numCols];
    protected int[] _colWidths = {40, 40, 40, 70, 70, 360, 440, 200, 60};
    protected LogTableColumn[] _colNames = LogTableColumn.getLogTableColumnArray();
    protected int _colDate = 0;
    protected int _colThread = 1;
    protected int _colMessageNum = 2;
    protected int _colLevel = 3;
    protected int _colNDC = 4;
    protected int _colCategory = 5;
    protected int _colMessage = 6;
    protected int _colLocation = 7;
    protected int _colThrown = 8;
  
    protected DateFormatManager _dateFormatManager = null;
  
    //--------------------------------------------------------------------------
    //   Private Variables:
    //--------------------------------------------------------------------------
  
    //--------------------------------------------------------------------------
    //   Constructors:
    //--------------------------------------------------------------------------
  
    public LogTable(JTextArea detailTextArea) {
      super();
  
      init();
  
      _detailTextArea = detailTextArea;
  
      setModel(new FilteredLogTableModel());
  
      Enumeration columns = getColumnModel().getColumns();
      int i = 0;
      while (columns.hasMoreElements()) {
        TableColumn col = (TableColumn) columns.nextElement();
        col.setCellRenderer(new LogTableRowRenderer());
        col.setPreferredWidth(_colWidths[i]);
  
        _tableColumns[i] = col;
        i++;
      }
  
      ListSelectionModel rowSM = getSelectionModel();
      rowSM.addListSelectionListener(new LogTableListSelectionListener(this));
  
      //setAutoResizeMode(JTable.AUTO_RESIZE_ALL_COLUMNS);
    }
  
    //--------------------------------------------------------------------------
    //   Public Methods:
    //--------------------------------------------------------------------------
  
    /**
     * Get the DateFormatManager for formatting dates.
     */
    public DateFormatManager getDateFormatManager() {
      return _dateFormatManager;
    }
  
    /**
     * Set the date format manager for formatting dates.
     */
    public void setDateFormatManager(DateFormatManager dfm) {
      _dateFormatManager = dfm;
    }
  
    public synchronized void clearLogRecords() {
      //For JDK1.3
      //((DefaultTableModel)getModel()).setRowCount(0);
  
      // For JDK1.2.x
      getFilteredLogTableModel().clear();
    }
  
    public FilteredLogTableModel getFilteredLogTableModel() {
      return (FilteredLogTableModel) getModel();
    }
  
    // default view if a view is not set and saved
    public void setDetailedView() {
      //TODO: Defineable Views.
      TableColumnModel model = getColumnModel();
      // Remove all the columns:
      for (int f = 0; f < _numCols; f++) {
        model.removeColumn(_tableColumns[f]);
      }
      // Add them back in the correct order:
      for (int i = 0; i < _numCols; i++) {
        model.addColumn(_tableColumns[i]);
      }
      //SWING BUG:
      sizeColumnsToFit(-1);
    }
  
    public void setView(List columns) {
      TableColumnModel model = getColumnModel();
  
      // Remove all the columns:
      for (int f = 0; f < _numCols; f++) {
        model.removeColumn(_tableColumns[f]);
      }
      Iterator selectedColumns = columns.iterator();
      Vector columnNameAndNumber = getColumnNameAndNumber();
      while (selectedColumns.hasNext()) {
        // add the column to the view
        model.addColumn(_tableColumns[columnNameAndNumber.indexOf(selectedColumns.next())]);
      }
  
      //SWING BUG:
      sizeColumnsToFit(-1);
    }
  
    public void setFont(Font font) {
      super.setFont(font);
      Graphics g = this.getGraphics();
      if (g != null) {
        FontMetrics fm = g.getFontMetrics(font);
        int height = fm.getHeight();
        _rowHeight = height + height / 3;
        setRowHeight(_rowHeight);
      }
  
  
    }
  
  
    //--------------------------------------------------------------------------
    //   Protected Methods:
    //--------------------------------------------------------------------------
  
    protected void init() {
      setRowHeight(_rowHeight);
      setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
    }
  
    // assign a column number to a column name
    protected Vector getColumnNameAndNumber() {
      Vector columnNameAndNumber = new Vector();
      for (int i = 0; i < _colNames.length; i++) {
        columnNameAndNumber.add(i, _colNames[i]);
      }
      return columnNameAndNumber;
    }
  
    //--------------------------------------------------------------------------
    //   Private Methods:
    //--------------------------------------------------------------------------
  
    //--------------------------------------------------------------------------
    //   Nested Top-Level Classes or Interfaces:
    //--------------------------------------------------------------------------
  
    class LogTableListSelectionListener implements ListSelectionListener {
      protected JTable _table;
  
      public LogTableListSelectionListener(JTable table) {
        _table = table;
      }
  
      public void valueChanged(ListSelectionEvent e) {
        //Ignore extra messages.
        if (e.getValueIsAdjusting()) {
          return;
        }
  
        ListSelectionModel lsm = (ListSelectionModel) e.getSource();
        if (lsm.isSelectionEmpty()) {
          //no rows are selected
        } else {
          StringBuffer buf = new StringBuffer();
          int selectedRow = lsm.getMinSelectionIndex();
  
          for (int i = 0; i < _numCols - 1; i++) {
            String value = "";
            Object obj = _table.getModel().getValueAt(selectedRow, i);
            if (obj != null) {
              value = obj.toString();
            }
  
            buf.append(_colNames[i] + ":");
            buf.append("\t");
  
            if (i == _colThread || i == _colMessage || i == _colLevel) {
              buf.append("\t"); // pad out the date.
            }
  
            if (i == _colDate || i == _colNDC) {
              buf.append("\t\t"); // pad out the date.
            }
  
  //               if( i == _colSequence)
  //               {
  //                  buf.append("\t\t\t"); // pad out the Sequnce.
  //               }
  
            buf.append(value);
            buf.append("\n");
          }
          buf.append(_colNames[_numCols - 1] + ":\n");
          Object obj = _table.getModel().getValueAt(selectedRow, _numCols - 1);
          if (obj != null) {
            buf.append(obj.toString());
          }
  
          _detailTextArea.setText(buf.toString());
        }
      }
    }
  }
  
  
  
  
  
  
  
  
  
  1.1                  jakarta-log4j/src/java/org/apache/log4j/lf5/viewer/LogTableColumn.java
  
  Index: LogTableColumn.java
  ===================================================================
  /*
   * Copyright (C) The Apache Software Foundation. All rights reserved.
   *
   * This software is published under the terms of the Apache Software
   * License version 1.1, a copy of which has been included with this
   * distribution in the LICENSE.txt file.
   */
  package org.apache.log4j.lf5.viewer;
  
  import java.util.Arrays;
  import java.util.HashMap;
  import java.util.List;
  import java.util.Map;
  
  /**
   * LogTableColumn
   *
   * @author Michael J. Sikorsky
   * @author Brad Marlborough
   */
  
  // Contributed by ThoughtWorks Inc.
  
  public class LogTableColumn implements java.io.Serializable {
  
    // log4j table columns.
    public final static LogTableColumn DATE = new LogTableColumn("Date");
    public final static LogTableColumn THREAD = new LogTableColumn("Thread");
    public final static LogTableColumn MESSAGE_NUM = new LogTableColumn("Message #");
    public final static LogTableColumn LEVEL = new LogTableColumn("Level");
    public final static LogTableColumn NDC = new LogTableColumn("NDC");
    public final static LogTableColumn CATEGORY = new LogTableColumn("Category");
    public final static LogTableColumn MESSAGE = new LogTableColumn("Message");
    public final static LogTableColumn LOCATION = new LogTableColumn("Location");
    public final static LogTableColumn THROWN = new LogTableColumn("Thrown");
  
  
    //--------------------------------------------------------------------------
    //   Protected Variables:
    //--------------------------------------------------------------------------
    protected String _label;
  
    //--------------------------------------------------------------------------
    //   Private Variables:
    //--------------------------------------------------------------------------
    private static LogTableColumn[] _log4JColumns;
    private static Map _logTableColumnMap;
  
    //--------------------------------------------------------------------------
    //   Constructors:
    //--------------------------------------------------------------------------
    static {
      _log4JColumns = new LogTableColumn[]{DATE, THREAD, MESSAGE_NUM, LEVEL, NDC, CATEGORY,
                                           MESSAGE, LOCATION, THROWN};
  
      _logTableColumnMap = new HashMap();
  
      for (int i = 0; i < _log4JColumns.length; i++) {
        _logTableColumnMap.put(_log4JColumns[i].getLabel(), _log4JColumns[i]);
      }
    }
  
  
    public LogTableColumn(String label) {
      _label = label;
    }
  
    //--------------------------------------------------------------------------
    //   Public Methods:
    //--------------------------------------------------------------------------
  
    /**
     * Return the Label of the LogLevel.
     */
    public String getLabel() {
      return _label;
    }
  
    /**
     * Convert a column label into a LogTableColumn object.
     *
     * @param level The label of a level to be converted into a LogTableColumn.
     * @return LogTableColumn The LogTableColumn with a label equal to column.
     * @throws LogTableColumnFormatException Is thrown when the column can not be
     *         converted into a LogTableColumn.
     */
    public static LogTableColumn valueOf(String column)
        throws LogTableColumnFormatException {
      LogTableColumn tableColumn = null;
      if (column != null) {
        column = column.trim();
        tableColumn = (LogTableColumn) _logTableColumnMap.get(column);
      }
  
      if (tableColumn == null) {
        StringBuffer buf = new StringBuffer();
        buf.append("Error while trying to parse (" + column + ") into");
        buf.append(" a LogTableColumn.");
        throw new LogTableColumnFormatException(buf.toString());
      }
      return tableColumn;
    }
  
  
    public boolean equals(Object o) {
      boolean equals = false;
  
      if (o instanceof LogTableColumn) {
        if (this.getLabel() ==
            ((LogTableColumn) o).getLabel()) {
          equals = true;
        }
      }
  
      return equals;
    }
  
    public int hashCode() {
      return _label.hashCode();
    }
  
    public String toString() {
      return _label;
    }
  
    /**
     * @return A <code>List</code> of <code>LogTableColumn/code> objects that map
     * to log4j <code>Column</code> objects.
     */
    public static List getLogTableColumns() {
      return Arrays.asList(_log4JColumns);
    }
  
    public static LogTableColumn[] getLogTableColumnArray() {
      return _log4JColumns;
    }
  
    //--------------------------------------------------------------------------
    //   Protected Methods:
    //--------------------------------------------------------------------------
  
    //--------------------------------------------------------------------------
    //   Private Methods:
    //--------------------------------------------------------------------------
  
    //--------------------------------------------------------------------------
    //   Nested Top-Level Classes or Interfaces:
    //--------------------------------------------------------------------------
  
  }
  
  
  
  
  
  
  
  
  
  1.1                  jakarta-log4j/src/java/org/apache/log4j/lf5/viewer/LogTableColumnFormatException.java
  
  Index: LogTableColumnFormatException.java
  ===================================================================
  /*
   * Copyright (C) The Apache Software Foundation. All rights reserved.
   *
   * This software is published under the terms of the Apache Software
   * License version 1.1, a copy of which has been included with this
   * distribution in the LICENSE.txt file.
   */
  package org.apache.log4j.lf5.viewer;
  
  /**
   * Thrown to indicate that the client has attempted to convert a string
   * to one the LogLevel types, but the string does not have the appropriate
   * format.
   *
   * @author Michael J. Sikorsky
   */
  
  // Contributed by ThoughtWorks Inc.
  
  public class LogTableColumnFormatException extends Exception {
  
    //--------------------------------------------------------------------------
    //   Constants:
    //--------------------------------------------------------------------------
  
    //--------------------------------------------------------------------------
    //   Protected Variables:
    //--------------------------------------------------------------------------
  
    //--------------------------------------------------------------------------
    //   Private Variables:
    //--------------------------------------------------------------------------
  
    //--------------------------------------------------------------------------
    //   Constructors:
    //--------------------------------------------------------------------------
  
    public LogTableColumnFormatException(String message) {
      super(message);
    }
  
    //--------------------------------------------------------------------------
    //   Public Methods:
    //--------------------------------------------------------------------------
  
    //--------------------------------------------------------------------------
    //   Protected Methods:
    //--------------------------------------------------------------------------
  
    //--------------------------------------------------------------------------
    //   Private Methods:
    //--------------------------------------------------------------------------
  
    //--------------------------------------------------------------------------
    //   Nested Top-Level Classes or Interfaces:
    //--------------------------------------------------------------------------
  
  }
  
  
  
  
  
  
  
  
  
  1.1                  jakarta-log4j/src/java/org/apache/log4j/lf5/viewer/LogTableModel.java
  
  Index: LogTableModel.java
  ===================================================================
  /*
   * Copyright (C) The Apache Software Foundation. All rights reserved.
   *
   * This software is published under the terms of the Apache Software
   * License version 1.1, a copy of which has been included with this
   * distribution in the LICENSE.txt file.
   */
  package org.apache.log4j.lf5.viewer;
  
  import javax.swing.table.DefaultTableModel;
  
  /**
   * LogTableModel
   *
   * @author Michael J. Sikorsky
   * @author Robert Shaw
   */
  
  // Contributed by ThoughtWorks Inc.
  
  public class LogTableModel extends DefaultTableModel {
    //--------------------------------------------------------------------------
    //   Constants:
    //--------------------------------------------------------------------------
  
    //--------------------------------------------------------------------------
    //   Protected Variables:
    //--------------------------------------------------------------------------
  
    //--------------------------------------------------------------------------
    //   Private Variables:
    //--------------------------------------------------------------------------
  
    //--------------------------------------------------------------------------
    //   Constructors:
    //--------------------------------------------------------------------------
  
    public LogTableModel(Object[] colNames, int numRows) {
      super(colNames, numRows);
    }
  
    //--------------------------------------------------------------------------
    //   Public Methods:
    //--------------------------------------------------------------------------
  
    public boolean isCellEditable(int row, int column) {
      return (false);
    }
    //--------------------------------------------------------------------------
    //   Protected Methods:
    //--------------------------------------------------------------------------
  
    //--------------------------------------------------------------------------
    //   Private Methods:
    //--------------------------------------------------------------------------
  
    //--------------------------------------------------------------------------
    //   Nested Top-Level Classes or Interfaces:
    //--------------------------------------------------------------------------
  
  }
  
  
  
  
  
  
  
  
  
  1.1                  jakarta-log4j/src/java/org/apache/log4j/lf5/viewer/LogTableRowRenderer.java
  
  Index: LogTableRowRenderer.java
  ===================================================================
  /*
   * Copyright (C) The Apache Software Foundation. All rights reserved.
   *
   * This software is published under the terms of the Apache Software
   * License version 1.1, a copy of which has been included with this
   * distribution in the LICENSE.txt file.
   */
  package org.apache.log4j.lf5.viewer;
  
  import org.apache.log4j.lf5.LogLevel;
  import org.apache.log4j.lf5.LogRecord;
  
  import javax.swing.*;
  import javax.swing.table.DefaultTableCellRenderer;
  import java.awt.*;
  
  /**
   * LogTableRowRenderer
   *
   * @author Michael J. Sikorsky
   * @author Robert Shaw
   * @author Brad Marlborough
   */
  
  // Contributed by ThoughtWorks Inc.
  
  public class LogTableRowRenderer extends DefaultTableCellRenderer {
    //--------------------------------------------------------------------------
    //   Constants:
    //--------------------------------------------------------------------------
  
    //--------------------------------------------------------------------------
    //   Protected Variables:
    //--------------------------------------------------------------------------
    protected boolean _highlightFatal = true;
    protected Color _color = new Color(230, 230, 230);
  
    //--------------------------------------------------------------------------
    //   Private Variables:
    //--------------------------------------------------------------------------
  
    //--------------------------------------------------------------------------
    //   Constructors:
    //--------------------------------------------------------------------------
  
    //--------------------------------------------------------------------------
    //   Public Methods:
    //--------------------------------------------------------------------------
  
    public Component getTableCellRendererComponent(JTable table,
        Object value,
        boolean isSelected,
        boolean hasFocus,
        int row,
        int col) {
  
      if ((row % 2) == 0) {
        setBackground(_color);
      } else {
        setBackground(Color.white);
      }
  
      FilteredLogTableModel model = (FilteredLogTableModel) table.getModel();
      LogRecord record = model.getFilteredRecord(row);
  
      setForeground(getLogLevelColor(record.getLevel()));
  
      return (super.getTableCellRendererComponent(table,
          value,
          isSelected,
          hasFocus,
          row, col));
    }
  
  
    //--------------------------------------------------------------------------
    //   Protected Methods:
    //--------------------------------------------------------------------------
    protected Color getLogLevelColor(LogLevel level) {
      return (Color) LogLevel.getLogLevelColorMap().get(level);
    }
  
    //--------------------------------------------------------------------------
    //   Private Methods:
    //--------------------------------------------------------------------------
  
    //--------------------------------------------------------------------------
    //   Nested Top-Level Classes or Interfaces:
    //--------------------------------------------------------------------------
  
  }
  
  
  
  
  
  
  
  
  
  1.1                  jakarta-log4j/src/java/org/apache/log4j/lf5/viewer/TrackingAdjustmentListener.java
  
  Index: TrackingAdjustmentListener.java
  ===================================================================
  /*
   * Copyright (C) The Apache Software Foundation. All rights reserved.
   *
   * This software is published under the terms of the Apache Software
   * License version 1.1, a copy of which has been included with this
   * distribution in the LICENSE.txt file.
   */
  package org.apache.log4j.lf5.viewer;
  
  import java.awt.*;
  import java.awt.event.AdjustmentEvent;
  import java.awt.event.AdjustmentListener;
  
  /**
   * An AdjustmentListener which ensures that an Adjustable (e.g. a Scrollbar)
   * will "track" when the Adjustable expands.
   * For example, when a vertical scroll bar is at its bottom anchor,
   * the scrollbar will remain at the bottom.  When the vertical scroll bar
   * is at any other location, then no tracking will happen.
   * An instance of this class should only listen to one Adjustable as
   * it retains state information about the Adjustable it listens to.
   *
   * @author Richard Wan
   */
  
  // Contributed by ThoughtWorks Inc.
  
  public class TrackingAdjustmentListener implements AdjustmentListener {
    //--------------------------------------------------------------------------
    //   Constants:
    //--------------------------------------------------------------------------
  
    //--------------------------------------------------------------------------
    //   Protected Variables:
    //--------------------------------------------------------------------------
  
    protected int _lastMaximum = -1;
  
    //--------------------------------------------------------------------------
    //   Private Variables:
    //--------------------------------------------------------------------------
  
    //--------------------------------------------------------------------------
    //   Constructors:
    //--------------------------------------------------------------------------
  
    //--------------------------------------------------------------------------
    //   Public Methods:
    //--------------------------------------------------------------------------
  
    public void adjustmentValueChanged(AdjustmentEvent e) {
      Adjustable bar = e.getAdjustable();
      int currentMaximum = bar.getMaximum();
      if (bar.getMaximum() == _lastMaximum) {
        return; // nothing to do, the adjustable has not expanded
      }
      int bottom = bar.getValue() + bar.getVisibleAmount();
  
      if (bottom + bar.getUnitIncrement() >= _lastMaximum) {
        bar.setValue(bar.getMaximum()); // use the most recent maximum
      }
      _lastMaximum = currentMaximum;
    }
  
    //--------------------------------------------------------------------------
    //   Protected Methods:
    //--------------------------------------------------------------------------
  
    //--------------------------------------------------------------------------
    //   Private Methods:
    //--------------------------------------------------------------------------
  
    //--------------------------------------------------------------------------
    //   Nested Top-Level Classes or Interfaces
    //--------------------------------------------------------------------------
  }
  
  
  
  
  1.1                  jakarta-log4j/src/java/org/apache/log4j/lf5/viewer/categoryexplorer/CategoryAbstractCellEditor.java
  
  Index: CategoryAbstractCellEditor.java
  ===================================================================
  /*
   * Copyright (C) The Apache Software Foundation. All rights reserved.
   *
   * This software is published under the terms of the Apache Software
   * License version 1.1, a copy of which has been included with this
   * distribution in the LICENSE.txt file.
   */
  package org.apache.log4j.lf5.viewer.categoryexplorer;
  
  import javax.swing.*;
  import javax.swing.event.CellEditorListener;
  import javax.swing.event.ChangeEvent;
  import javax.swing.event.EventListenerList;
  import javax.swing.table.TableCellEditor;
  import javax.swing.tree.TreeCellEditor;
  import java.awt.*;
  import java.awt.event.MouseEvent;
  import java.util.EventObject;
  
  /**
   * CategoryAbstractCellEditor.  Base class to handle the some common
   * details of cell editing.
   *
   * @author Michael J. Sikorsky
   * @author Robert Shaw
   */
  
  // Contributed by ThoughtWorks Inc.
  
  public class CategoryAbstractCellEditor implements TableCellEditor, TreeCellEditor {
    //--------------------------------------------------------------------------
    //   Constants:
    //--------------------------------------------------------------------------
  
    //--------------------------------------------------------------------------
    //   Protected Variables:
    //--------------------------------------------------------------------------
    protected EventListenerList _listenerList = new EventListenerList();
    protected Object _value;
    protected ChangeEvent _changeEvent = null;
    protected int _clickCountToStart = 1;
  
    //--------------------------------------------------------------------------
    //   Private Variables:
    //--------------------------------------------------------------------------
  
    //--------------------------------------------------------------------------
    //   Constructors:
    //--------------------------------------------------------------------------
  
    //--------------------------------------------------------------------------
    //   Public Methods:
    //--------------------------------------------------------------------------
  
    public Object getCellEditorValue() {
      return _value;
    }
  
    public void setCellEditorValue(Object value) {
      _value = value;
    }
  
    public void setClickCountToStart(int count) {
      _clickCountToStart = count;
    }
  
    public int getClickCountToStart() {
      return _clickCountToStart;
    }
  
    public boolean isCellEditable(EventObject anEvent) {
      if (anEvent instanceof MouseEvent) {
        if (((MouseEvent) anEvent).getClickCount() < _clickCountToStart) {
          return false;
        }
      }
      return true;
    }
  
    public boolean shouldSelectCell(EventObject anEvent) {
      if (this.isCellEditable(anEvent)) {
        if (anEvent == null ||
            ((MouseEvent) anEvent).getClickCount() >= _clickCountToStart) {
          return true;
        }
      }
      return false;
    }
  
    public boolean stopCellEditing() {
      fireEditingStopped();
      return true;
    }
  
    public void cancelCellEditing() {
      fireEditingCanceled();
    }
  
    public void addCellEditorListener(CellEditorListener l) {
      _listenerList.add(CellEditorListener.class, l);
    }
  
    public void removeCellEditorListener(CellEditorListener l) {
      _listenerList.remove(CellEditorListener.class, l);
    }
  
    public Component getTreeCellEditorComponent(
        JTree tree, Object value,
        boolean isSelected,
        boolean expanded,
        boolean leaf, int row) {
      return null;
    }
  
    public Component getTableCellEditorComponent(
        JTable table, Object value,
        boolean isSelected,
        int row, int column) {
      return null;
    }
  
    //--------------------------------------------------------------------------
    //   Protected Methods:
    //--------------------------------------------------------------------------
    protected void fireEditingStopped() {
      Object[] listeners = _listenerList.getListenerList();
  
      for (int i = listeners.length - 2; i >= 0; i -= 2) {
        if (listeners[i] == CellEditorListener.class) {
          if (_changeEvent == null) {
            _changeEvent = new ChangeEvent(this);
          }
  
          ((CellEditorListener) listeners[i + 1]).editingStopped(_changeEvent);
        }
      }
    }
  
    protected void fireEditingCanceled() {
      Object[] listeners = _listenerList.getListenerList();
  
      for (int i = listeners.length - 2; i >= 0; i -= 2) {
        if (listeners[i] == CellEditorListener.class) {
          if (_changeEvent == null) {
            _changeEvent = new ChangeEvent(this);
          }
  
          ((CellEditorListener) listeners[i + 1]).editingCanceled(_changeEvent);
        }
      }
    }
  
    //--------------------------------------------------------------------------
    //   Private Methods:
    //--------------------------------------------------------------------------
  
    //--------------------------------------------------------------------------
    //   Nested Top-Level Classes or Interfaces:
    //--------------------------------------------------------------------------
  
  }
  
  
  
  1.1                  jakarta-log4j/src/java/org/apache/log4j/lf5/viewer/categoryexplorer/CategoryElement.java
  
  Index: CategoryElement.java
  ===================================================================
  /*
   * Copyright (C) The Apache Software Foundation. All rights reserved.
   *
   * This software is published under the terms of the Apache Software
   * License version 1.1, a copy of which has been included with this
   * distribution in the LICENSE.txt file.
   */
  package org.apache.log4j.lf5.viewer.categoryexplorer;
  
  /**
   * CategoryElement represents a single element or part of a Category.
   *
   * @author Michael J. Sikorsky
   * @author Robert Shaw
   */
  
  // Contributed by ThoughtWorks Inc.
  
  public class CategoryElement {
    //--------------------------------------------------------------------------
    //   Constants:
    //--------------------------------------------------------------------------
  
    //--------------------------------------------------------------------------
    //   Protected Variables:
    //--------------------------------------------------------------------------
    protected String _categoryTitle;
  
    //--------------------------------------------------------------------------
    //   Private Variables:
    //--------------------------------------------------------------------------
  
    //--------------------------------------------------------------------------
    //   Constructors:
    //--------------------------------------------------------------------------
  
    public CategoryElement() {
      super();
    }
  
    public CategoryElement(String title) {
      _categoryTitle = title;
    }
  
    //--------------------------------------------------------------------------
    //   Public Methods:
    //--------------------------------------------------------------------------
  
    public String getTitle() {
      return (_categoryTitle);
    }
  
    public void setTitle(String title) {
      _categoryTitle = title;
    }
  
    //--------------------------------------------------------------------------
    //   Protected Methods:
    //--------------------------------------------------------------------------
  
    //--------------------------------------------------------------------------
    //   Private Methods:
    //--------------------------------------------------------------------------
  
    //--------------------------------------------------------------------------
    //   Nested Top-Level Classes or Interfaces:
    //--------------------------------------------------------------------------
  
  }
  
  
  
  
  
  
  
  
  
  1.1                  jakarta-log4j/src/java/org/apache/log4j/lf5/viewer/categoryexplorer/CategoryExplorerLogRecordFilter.java
  
  Index: CategoryExplorerLogRecordFilter.java
  ===================================================================
  /*
   * Copyright (C) The Apache Software Foundation. All rights reserved.
   *
   * This software is published under the terms of the Apache Software
   * License version 1.1, a copy of which has been included with this
   * distribution in the LICENSE.txt file.
   */
  package org.apache.log4j.lf5.viewer.categoryexplorer;
  
  import org.apache.log4j.lf5.LogRecord;
  import org.apache.log4j.lf5.LogRecordFilter;
  
  import java.util.Enumeration;
  
  /**
   * An implementation of LogRecordFilter based on a CategoryExplorerModel
   *
   * @author Richard Wan
   */
  
  // Contributed by ThoughtWorks Inc.
  
  public class CategoryExplorerLogRecordFilter implements LogRecordFilter {
    //--------------------------------------------------------------------------
    //   Constants:
    //--------------------------------------------------------------------------
  
    //--------------------------------------------------------------------------
    //   Protected Variables:
    //--------------------------------------------------------------------------
  
    protected CategoryExplorerModel _model;
  
    //--------------------------------------------------------------------------
    //   Private Variables:
    //--------------------------------------------------------------------------
  
    //--------------------------------------------------------------------------
    //   Constructors:
    //--------------------------------------------------------------------------
  
    public CategoryExplorerLogRecordFilter(CategoryExplorerModel model) {
      _model = model;
    }
  
    //--------------------------------------------------------------------------
    //   Public Methods:
    //--------------------------------------------------------------------------
  
    /**
     * @return true if the CategoryExplorer model specified at construction
     * is accepting the category of the specified LogRecord.  Has a side-effect
     * of adding the CategoryPath of the LogRecord to the explorer model
     * if the CategoryPath is new.
     */
    public boolean passes(LogRecord record) {
      CategoryPath path = new CategoryPath(record.getCategory());
      return _model.isCategoryPathActive(path);
    }
  
    /**
     * Resets the counters for the contained CategoryNodes to zero.
     */
    public void reset() {
      resetAllNodes();
    }
  
    //--------------------------------------------------------------------------
    //   Protected Methods:
    //--------------------------------------------------------------------------
  
    protected void resetAllNodes() {
      Enumeration nodes = _model.getRootCategoryNode().depthFirstEnumeration();
      CategoryNode current;
      while (nodes.hasMoreElements()) {
        current = (CategoryNode) nodes.nextElement();
        current.resetNumberOfContainedRecords();
        _model.nodeChanged(current);
      }
    }
    //--------------------------------------------------------------------------
    //   Private Methods:
    //--------------------------------------------------------------------------
  
    //--------------------------------------------------------------------------
    //   Nested Top-Level Classes or Interfaces
    //--------------------------------------------------------------------------
  }
  
  
  
  
  1.1                  jakarta-log4j/src/java/org/apache/log4j/lf5/viewer/categoryexplorer/CategoryExplorerModel.java
  
  Index: CategoryExplorerModel.java
  ===================================================================
  /*
   * Copyright (C) The Apache Software Foundation. All rights reserved.
   *
   * This software is published under the terms of the Apache Software
   * License version 1.1, a copy of which has been included with this
   * distribution in the LICENSE.txt file.
   */
  package org.apache.log4j.lf5.viewer.categoryexplorer;
  
  import org.apache.log4j.lf5.LogRecord;
  
  import javax.swing.*;
  import javax.swing.tree.DefaultTreeModel;
  import javax.swing.tree.TreeNode;
  import javax.swing.tree.TreePath;
  import java.awt.*;
  import java.awt.event.ActionEvent;
  import java.awt.event.ActionListener;
  import java.util.Enumeration;
  
  /**
   * CategoryExplorerModel
   *
   * @author Michael J. Sikorsky
   * @author Robert Shaw
   * @author Brent Sprecher
   * @author Richard Hurst
   */
  
  // Contributed by ThoughtWorks Inc.
  
  public class CategoryExplorerModel extends DefaultTreeModel {
    //--------------------------------------------------------------------------
    //   Constants:
    //--------------------------------------------------------------------------
  
    //--------------------------------------------------------------------------
    //   Protected Variables:
    //--------------------------------------------------------------------------
  
    protected boolean _renderFatal = true;
    protected ActionListener _listener = null;
    protected ActionEvent _event = new ActionEvent(this,
        ActionEvent.ACTION_PERFORMED,
        "Nodes Selection changed");
  
    //--------------------------------------------------------------------------
    //   Private Variables:
    //--------------------------------------------------------------------------
  
    //--------------------------------------------------------------------------
    //   Constructors:
    //--------------------------------------------------------------------------
  
    public CategoryExplorerModel(CategoryNode node) {
      super(node);
    }
    //--------------------------------------------------------------------------
    //   Public Methods:
    //--------------------------------------------------------------------------
  
    public void addLogRecord(LogRecord lr) {
      CategoryPath path = new CategoryPath(lr.getCategory());
      addCategory(path); // create category path if it is new
      CategoryNode node = getCategoryNode(path);
      node.addRecord(); // update category node
      if (_renderFatal && lr.isFatal()) {
        TreeNode[] nodes = getPathToRoot(node);
        int len = nodes.length;
        CategoryNode parent;
  
        // i = 0 gives root node
        // skip node and root, loop through "parents" in between
        for (int i = 1; i < len - 1; i++) {
          parent = (CategoryNode) nodes[i];
          parent.setHasFatalChildren(true);
          nodeChanged(parent);
        }
        node.setHasFatalRecords(true);
        nodeChanged(node);
      }
    }
  
    public CategoryNode getRootCategoryNode() {
      return (CategoryNode) getRoot();
    }
  
    public CategoryNode getCategoryNode(String category) {
      CategoryPath path = new CategoryPath(category);
      return (getCategoryNode(path));
    }
  
    /**
     * returns null if no CategoryNode exists.
     */
    public CategoryNode getCategoryNode(CategoryPath path) {
      CategoryNode root = (CategoryNode) getRoot();
      CategoryNode parent = root; // Start condition.
  
      for (int i = 0; i < path.size(); i++) {
        CategoryElement element = path.categoryElementAt(i);
  
        // If the two nodes have matching titles they are considered equal.
        Enumeration children = parent.children();
  
        boolean categoryAlreadyExists = false;
        while (children.hasMoreElements()) {
          CategoryNode node = (CategoryNode) children.nextElement();
          String title = node.getTitle().toLowerCase();
  
          String pathLC = element.getTitle().toLowerCase();
          if (title.equals(pathLC)) {
            categoryAlreadyExists = true;
            // This is now the new parent node.
            parent = node;
            break; // out of the while, and back to the for().
          }
        }
  
        if (categoryAlreadyExists == false) {
          return null; // Didn't find the Node.
        }
      }
  
      return (parent);
    }
  
    /**
     * @return true if all the nodes in the specified CategoryPath are
     * selected.
     */
    public boolean isCategoryPathActive(CategoryPath path) {
      CategoryNode root = (CategoryNode) getRoot();
      CategoryNode parent = root; // Start condition.
      boolean active = false;
  
      for (int i = 0; i < path.size(); i++) {
        CategoryElement element = path.categoryElementAt(i);
  
        // If the two nodes have matching titles they are considered equal.
        Enumeration children = parent.children();
  
        boolean categoryAlreadyExists = false;
        active = false;
  
        while (children.hasMoreElements()) {
          CategoryNode node = (CategoryNode) children.nextElement();
          String title = node.getTitle().toLowerCase();
  
          String pathLC = element.getTitle().toLowerCase();
          if (title.equals(pathLC)) {
            categoryAlreadyExists = true;
            // This is now the new parent node.
            parent = node;
  
            if (parent.isSelected()) {
              active = true;
            }
  
            break; // out of the while, and back to the for().
          }
        }
  
        if (active == false || categoryAlreadyExists == false) {
          return false;
        }
      }
  
      return (active);
    }
  
  
    /**
     * <p>Method altered by Richard Hurst such that it returns the CategoryNode
     * corresponding to the CategoryPath</p>
     *
     * @param CategoryPath
     * @returns CategoryNode
     */
    public CategoryNode addCategory(CategoryPath path) {
      CategoryNode root = (CategoryNode) getRoot();
      CategoryNode parent = root; // Start condition.
  
      for (int i = 0; i < path.size(); i++) {
        CategoryElement element = path.categoryElementAt(i);
  
        // If the two nodes have matching titles they are considered equal.
        Enumeration children = parent.children();
  
        boolean categoryAlreadyExists = false;
        while (children.hasMoreElements()) {
          CategoryNode node = (CategoryNode) children.nextElement();
          String title = node.getTitle().toLowerCase();
  
          String pathLC = element.getTitle().toLowerCase();
          if (title.equals(pathLC)) {
            categoryAlreadyExists = true;
            // This is now the new parent node.
            parent = node;
            break;
          }
        }
  
        if (categoryAlreadyExists == false) {
          // We need to add the node.
          CategoryNode newNode = new CategoryNode(element.getTitle());
  
          //This method of adding a new node cause parent roots to be
          // collapsed.
          //parent.add( newNode );
          //reload(parent);
  
          // This doesn't force the nodes to collapse.
          insertNodeInto(newNode, parent, parent.getChildCount());
          refresh(newNode);
  
          // The newly added node is now the parent.
          parent = newNode;
  
        }
      }
  
      return parent;
    }
  
    public void update(CategoryNode node, boolean selected) {
      if (node.isSelected() == selected) {
        return; // nothing was changed, nothing to do
      }
      // select parents or deselect children
      if (selected) {
        setParentSelection(node, true);
      } else {
        setDescendantSelection(node, false);
      }
    }
  
    public void setDescendantSelection(CategoryNode node, boolean selected) {
      Enumeration descendants = node.depthFirstEnumeration();
      CategoryNode current;
      while (descendants.hasMoreElements()) {
        current = (CategoryNode) descendants.nextElement();
        // does the current node need to be changed?
        if (current.isSelected() != selected) {
          current.setSelected(selected);
          nodeChanged(current);
        }
      }
      notifyActionListeners();
    }
  
    public void setParentSelection(CategoryNode node, boolean selected) {
      TreeNode[] nodes = getPathToRoot(node);
      int len = nodes.length;
      CategoryNode parent;
  
      // i = 0 gives root node, i=len-1 gives this node
      // skip the root node
      for (int i = 1; i < len; i++) {
        parent = (CategoryNode) nodes[i];
        if (parent.isSelected() != selected) {
          parent.setSelected(selected);
          nodeChanged(parent);
        }
      }
      notifyActionListeners();
    }
  
  
    public synchronized void addActionListener(ActionListener l) {
      _listener = AWTEventMulticaster.add(_listener, l);
    }
  
    public synchronized void removeActionListener(ActionListener l) {
      _listener = AWTEventMulticaster.remove(_listener, l);
    }
  
    public void resetAllNodeCounts() {
      Enumeration nodes = getRootCategoryNode().depthFirstEnumeration();
      CategoryNode current;
      while (nodes.hasMoreElements()) {
        current = (CategoryNode) nodes.nextElement();
        current.resetNumberOfContainedRecords();
        nodeChanged(current);
      }
    }
  
    /**
     * <p>Returns the CategoryPath to the specified CategoryNode</p>
     *
     * @param CategoryNode The target CategoryNode
     * @returns CategoryPath
     */
    public TreePath getTreePathToRoot(CategoryNode node) {
      if (node == null) {
        return null;
      }
      return (new TreePath(getPathToRoot(node)));
    }
  
    //--------------------------------------------------------------------------
    //   Protected Methods:
    //--------------------------------------------------------------------------
    protected void notifyActionListeners() {
      if (_listener != null) {
        _listener.actionPerformed(_event);
      }
    }
  
    /**
     * Fires a nodechanged event on the SwingThread.
     */
    protected void refresh(final CategoryNode node) {
      SwingUtilities.invokeLater(new Runnable() {
        public void run() {
          nodeChanged(node); // remind the tree to render the new node
        }
      });
    }
  
    //--------------------------------------------------------------------------
    //   Private Methods:
    //--------------------------------------------------------------------------
  
    //--------------------------------------------------------------------------
    //   Nested Top-Level Classes or Interfaces:
    //--------------------------------------------------------------------------
  
  }
  
  
  
  
  
  
  
  
  
  1.1                  jakarta-log4j/src/java/org/apache/log4j/lf5/viewer/categoryexplorer/CategoryExplorerTree.java
  
  Index: CategoryExplorerTree.java
  ===================================================================
  /*
   * Copyright (C) The Apache Software Foundation. All rights reserved.
   *
   * This software is published under the terms of the Apache Software
   * License version 1.1, a copy of which has been included with this
   * distribution in the LICENSE.txt file.
   */
  package org.apache.log4j.lf5.viewer.categoryexplorer;
  
  import javax.swing.*;
  import javax.swing.event.TreeModelEvent;
  import javax.swing.tree.TreePath;
  import java.awt.event.MouseEvent;
  
  /**
   * CategoryExplorerTree
   *
   * @author Michael J. Sikorsky
   * @author Robert Shaw
   * @author Brent Sprecher
   * @author Brad Marlborough
   */
  
  // Contributed by ThoughtWorks Inc.
  
  public class CategoryExplorerTree extends JTree {
    //--------------------------------------------------------------------------
    //   Constants:
    //--------------------------------------------------------------------------
  
    //--------------------------------------------------------------------------
    //   Protected Variables:
    //--------------------------------------------------------------------------
    protected CategoryExplorerModel _model;
    protected boolean _rootAlreadyExpanded = false;
  
    //--------------------------------------------------------------------------
    //   Private Variables:
    //--------------------------------------------------------------------------
  
    //--------------------------------------------------------------------------
    //   Constructors:
    //--------------------------------------------------------------------------
  
    /**
     * Construct a CategoryExplorerTree with a specific model.
     */
    public CategoryExplorerTree(CategoryExplorerModel model) {
      super(model);
  
      _model = model;
      init();
    }
  
    /**
     * Construct a CategoryExplorerTree and create a default CategoryExplorerModel.
     */
    public CategoryExplorerTree() {
      super();
  
      CategoryNode rootNode = new CategoryNode("Categories");
  
      _model = new CategoryExplorerModel(rootNode);
  
      setModel(_model);
  
      init();
    }
  
    //--------------------------------------------------------------------------
    //   Public Methods:
    //--------------------------------------------------------------------------
  
    public CategoryExplorerModel getExplorerModel() {
      return (_model);
    }
  
    public String getToolTipText(MouseEvent e) {
  
      try {
        return super.getToolTipText(e);
      } catch (Exception ex) {
        return "";
      }
  
    }
  
    //--------------------------------------------------------------------------
    //   Protected Methods:
    //--------------------------------------------------------------------------
  
    protected void init() {
      // Put visible lines on the JTree.
      putClientProperty("JTree.lineStyle", "Angled");
  
      // Configure the Tree with the appropriate Renderers and Editors.
  
      CategoryNodeRenderer renderer = new CategoryNodeRenderer();
      setEditable(true);
      setCellRenderer(renderer);
  
      CategoryNodeEditor editor = new CategoryNodeEditor(_model);
  
      setCellEditor(new CategoryImmediateEditor(this,
          new CategoryNodeRenderer(),
          editor));
      setShowsRootHandles(true);
  
      setToolTipText("");
  
      ensureRootExpansion();
  
    }
  
    protected void expandRootNode() {
      if (_rootAlreadyExpanded) {
        return;
      }
      _rootAlreadyExpanded = true;
      TreePath path = new TreePath(_model.getRootCategoryNode().getPath());
      expandPath(path);
    }
  
    protected void ensureRootExpansion() {
      _model.addTreeModelListener(new TreeModelAdapter() {
        public void treeNodesInserted(TreeModelEvent e) {
          expandRootNode();
        }
      });
    }
  
    //--------------------------------------------------------------------------
    //   Private Methods:
    //--------------------------------------------------------------------------
  
    //--------------------------------------------------------------------------
    //   Nested Top-Level Classes or Interfaces:
    //--------------------------------------------------------------------------
  
  }
  
  
  
  
  
  
  
  
  
  1.1                  jakarta-log4j/src/java/org/apache/log4j/lf5/viewer/categoryexplorer/CategoryImmediateEditor.java
  
  Index: CategoryImmediateEditor.java
  ===================================================================
  /*
   * Copyright (C) The Apache Software Foundation. All rights reserved.
   *
   * This software is published under the terms of the Apache Software
   * License version 1.1, a copy of which has been included with this
   * distribution in the LICENSE.txt file.
   */
  package org.apache.log4j.lf5.viewer.categoryexplorer;
  
  import javax.swing.*;
  import javax.swing.tree.DefaultTreeCellEditor;
  import javax.swing.tree.TreePath;
  import java.awt.*;
  import java.awt.event.MouseEvent;
  import java.util.EventObject;
  
  /**
   * CategoryImmediateEditor
   *
   * @author Michael J. Sikorsky
   * @author Robert Shaw
   */
  
  // Contributed by ThoughtWorks Inc.
  
  public class CategoryImmediateEditor extends DefaultTreeCellEditor {
    //--------------------------------------------------------------------------
    //   Constants:
    //--------------------------------------------------------------------------
  
    //--------------------------------------------------------------------------
    //   Protected Variables:
    //--------------------------------------------------------------------------
    private CategoryNodeRenderer renderer;
    protected Icon editingIcon = null;
  
    //--------------------------------------------------------------------------
    //   Private Variables:
    //--------------------------------------------------------------------------
  
    //--------------------------------------------------------------------------
    //   Constructors:
    //--------------------------------------------------------------------------
    public CategoryImmediateEditor(JTree tree,
        CategoryNodeRenderer renderer,
        CategoryNodeEditor editor) {
      super(tree, renderer, editor);
      this.renderer = renderer;
      renderer.setIcon(null);
      renderer.setLeafIcon(null);
      renderer.setOpenIcon(null);
      renderer.setClosedIcon(null);
  
      super.editingIcon = null;
    }
  
    //--------------------------------------------------------------------------
    //   Public Methods:
    //--------------------------------------------------------------------------
    public boolean shouldSelectCell(EventObject e) {
      boolean rv = false;  // only mouse events
  
      if (e instanceof MouseEvent) {
        MouseEvent me = (MouseEvent) e;
        TreePath path = tree.getPathForLocation(me.getX(),
            me.getY());
        CategoryNode node = (CategoryNode)
            path.getLastPathComponent();
  
        rv = node.isLeaf() /*|| !inCheckBoxHitRegion(me)*/;
      }
      return rv;
    }
  
    public boolean inCheckBoxHitRegion(MouseEvent e) {
      TreePath path = tree.getPathForLocation(e.getX(),
          e.getY());
      if (path == null) {
        return false;
      }
      CategoryNode node = (CategoryNode) path.getLastPathComponent();
      boolean rv = false;
  
      if (true) {
        // offset and lastRow DefaultTreeCellEditor
        // protected members
  
        Rectangle bounds = tree.getRowBounds(lastRow);
        Dimension checkBoxOffset =
            renderer.getCheckBoxOffset();
  
        bounds.translate(offset + checkBoxOffset.width,
            checkBoxOffset.height);
  
        rv = bounds.contains(e.getPoint());
      }
      return true;
    }
  
    //--------------------------------------------------------------------------
    //   Protected Methods:
    //--------------------------------------------------------------------------
  
    protected boolean canEditImmediately(EventObject e) {
      boolean rv = false;
  
      if (e instanceof MouseEvent) {
        MouseEvent me = (MouseEvent) e;
        rv = inCheckBoxHitRegion(me);
      }
  
      return rv;
    }
  
    protected void determineOffset(JTree tree, Object value,
        boolean isSelected, boolean expanded,
        boolean leaf, int row) {
      // Very important: means that the tree won't jump around.
      offset = 0;
    }
  
    //--------------------------------------------------------------------------
    //   Private Methods:
    //--------------------------------------------------------------------------
  
    //--------------------------------------------------------------------------
    //   Nested Top-Level Classes or Interfaces:
    //--------------------------------------------------------------------------
  
  }
  
  
  
  
  
  
  
  
  
  1.1                  jakarta-log4j/src/java/org/apache/log4j/lf5/viewer/categoryexplorer/CategoryNode.java
  
  Index: CategoryNode.java
  ===================================================================
  /*
   * Copyright (C) The Apache Software Foundation. All rights reserved.
   *
   * This software is published under the terms of the Apache Software
   * License version 1.1, a copy of which has been included with this
   * distribution in the LICENSE.txt file.
   */
  package org.apache.log4j.lf5.viewer.categoryexplorer;
  
  import javax.swing.tree.DefaultMutableTreeNode;
  import javax.swing.tree.TreeNode;
  import java.util.Enumeration;
  
  /**
   * CategoryNode
   *
   * @author Michael J. Sikorsky
   * @author Robert Shaw
   */
  
  // Contributed by ThoughtWorks Inc.
  
  public class CategoryNode extends DefaultMutableTreeNode {
    //--------------------------------------------------------------------------
    //   Constants:
    //--------------------------------------------------------------------------
  
    //--------------------------------------------------------------------------
    //   Protected Variables:
    //--------------------------------------------------------------------------
    protected boolean _selected = true;
    protected int _numberOfContainedRecords = 0;
    protected int _numberOfRecordsFromChildren = 0;
    protected boolean _hasFatalChildren = false;
    protected boolean _hasFatalRecords = false;
  
    //--------------------------------------------------------------------------
    //   Private Variables:
    //--------------------------------------------------------------------------
  
    //--------------------------------------------------------------------------
    //   Constructors:
    //--------------------------------------------------------------------------
  
    /**
     *
     */
    public CategoryNode(String title) {
      setUserObject(title);
    }
  
    //--------------------------------------------------------------------------
    //   Public Methods:
    //--------------------------------------------------------------------------
    public String getTitle() {
      return (String) getUserObject();
    }
  
    public void setSelected(boolean s) {
      if (s != _selected) {
        _selected = s;
      }
    }
  
    public boolean isSelected() {
      return _selected;
    }
  
    /**
     * @deprecated
     */
    public void setAllDescendantsSelected() {
      Enumeration children = children();
      while (children.hasMoreElements()) {
        CategoryNode node = (CategoryNode) children.nextElement();
        node.setSelected(true);
        node.setAllDescendantsSelected();
      }
    }
  
    /**
     * @deprecated
     */
    public void setAllDescendantsDeSelected() {
      Enumeration children = children();
      while (children.hasMoreElements()) {
        CategoryNode node = (CategoryNode) children.nextElement();
        node.setSelected(false);
        node.setAllDescendantsDeSelected();
      }
    }
  
    public String toString() {
      return (getTitle());
    }
  
    public boolean equals(Object obj) {
      if (obj instanceof CategoryNode) {
        CategoryNode node = (CategoryNode) obj;
        String tit1 = getTitle().toLowerCase();
        String tit2 = node.getTitle().toLowerCase();
  
        if (tit1.equals(tit2)) {
          return (true);
        }
      }
      return (false);
    }
  
    public int hashCode() {
      return (getTitle().hashCode());
    }
  
    public void addRecord() {
      _numberOfContainedRecords++;
      addRecordToParent();
    }
  
    public int getNumberOfContainedRecords() {
      return _numberOfContainedRecords;
    }
  
    public void resetNumberOfContainedRecords() {
      _numberOfContainedRecords = 0;
      _numberOfRecordsFromChildren = 0;
      _hasFatalRecords = false;
      _hasFatalChildren = false;
    }
  
    public boolean hasFatalRecords() {
      return _hasFatalRecords;
    }
  
    public boolean hasFatalChildren() {
      return _hasFatalChildren;
    }
  
    public void setHasFatalRecords(boolean flag) {
      _hasFatalRecords = flag;
    }
  
    public void setHasFatalChildren(boolean flag) {
      _hasFatalChildren = flag;
    }
  
    //--------------------------------------------------------------------------
    //   Protected Methods:
    //--------------------------------------------------------------------------
  
    protected int getTotalNumberOfRecords() {
      return getNumberOfRecordsFromChildren() + getNumberOfContainedRecords();
    }
  
    /**
     * Passes up the addition from child to parent
     */
    protected void addRecordFromChild() {
      _numberOfRecordsFromChildren++;
      addRecordToParent();
    }
  
    protected int getNumberOfRecordsFromChildren() {
      return _numberOfRecordsFromChildren;
    }
  
    protected void addRecordToParent() {
      TreeNode parent = getParent();
      if (parent == null) {
        return;
      }
      ((CategoryNode) parent).addRecordFromChild();
    }
    //--------------------------------------------------------------------------
    //   Private Methods:
    //--------------------------------------------------------------------------
  
    //--------------------------------------------------------------------------
    //   Nested Top-Level Classes or Interfaces:
    //--------------------------------------------------------------------------
  
  }
  
  
  
  
  
  
  
  
  
  1.1                  jakarta-log4j/src/java/org/apache/log4j/lf5/viewer/categoryexplorer/CategoryNodeEditor.java
  
  Index: CategoryNodeEditor.java
  ===================================================================
  /*
   * Copyright (C) The Apache Software Foundation. All rights reserved.
   *
   * This software is published under the terms of the Apache Software
   * License version 1.1, a copy of which has been included with this
   * distribution in the LICENSE.txt file.
   */
  package org.apache.log4j.lf5.viewer.categoryexplorer;
  
  import javax.swing.*;
  import javax.swing.tree.TreePath;
  import java.awt.*;
  import java.awt.event.ActionEvent;
  import java.awt.event.ActionListener;
  import java.awt.event.MouseAdapter;
  import java.awt.event.MouseEvent;
  import java.util.ArrayList;
  import java.util.Enumeration;
  
  /**
   * CategoryNodeEditor
   *
   * @author Michael J. Sikorsky
   * @author Robert Shaw
   */
  
  // Contributed by ThoughtWorks Inc.
  
  public class CategoryNodeEditor extends CategoryAbstractCellEditor {
    //--------------------------------------------------------------------------
    //   Constants:
    //--------------------------------------------------------------------------
  
    //--------------------------------------------------------------------------
    //   Protected Variables:
    //--------------------------------------------------------------------------
    protected CategoryNodeEditorRenderer _renderer;
    protected CategoryNode _lastEditedNode;
    protected JCheckBox _checkBox;
    protected CategoryExplorerModel _categoryModel;
    protected JTree _tree;
  
    //--------------------------------------------------------------------------
    //   Private Variables:
    //--------------------------------------------------------------------------
  
    //--------------------------------------------------------------------------
    //   Constructors:
    //--------------------------------------------------------------------------
  
    public CategoryNodeEditor(CategoryExplorerModel model) {
      _renderer = new CategoryNodeEditorRenderer();
      _checkBox = _renderer.getCheckBox();
      _categoryModel = model;
  
      _checkBox.addActionListener(new ActionListener() {
        public void actionPerformed(ActionEvent e) {
          _categoryModel.update(_lastEditedNode, _checkBox.isSelected());
          stopCellEditing();
        }
      });
  
      _renderer.addMouseListener(new MouseAdapter() {
        public void mousePressed(MouseEvent e) {
          if ((e.getModifiers() & MouseEvent.BUTTON3_MASK) != 0) {
            showPopup(_lastEditedNode, e.getX(), e.getY());
          }
          stopCellEditing();
        }
      });
    }
  
    //--------------------------------------------------------------------------
    //   Public Methods:
    //--------------------------------------------------------------------------
  
    public Component getTreeCellEditorComponent(JTree tree, Object value,
        boolean selected, boolean expanded,
        boolean leaf, int row) {
      _lastEditedNode = (CategoryNode) value;
      _tree = tree;
  
      return _renderer.getTreeCellRendererComponent(tree,
          value, selected, expanded,
          leaf, row, true);
      // hasFocus ignored
    }
  
    public Object getCellEditorValue() {
      return _lastEditedNode.getUserObject();
    }
    //--------------------------------------------------------------------------
    //   Protected Methods:
    //--------------------------------------------------------------------------
  
    protected JMenuItem createPropertiesMenuItem(final CategoryNode node) {
      JMenuItem result = new JMenuItem("Properties");
      result.addActionListener(new ActionListener() {
        public void actionPerformed(ActionEvent e) {
          showPropertiesDialog(node);
        }
      });
      return result;
    }
  
    protected void showPropertiesDialog(CategoryNode node) {
      JOptionPane.showMessageDialog(
          _tree,
          getDisplayedProperties(node),
          "Category Properties: " + node.getTitle(),
          JOptionPane.PLAIN_MESSAGE
      );
    }
  
    protected Object getDisplayedProperties(CategoryNode node) {
      ArrayList result = new ArrayList();
      result.add("Category: " + node.getTitle());
      if (node.hasFatalRecords()) {
        result.add("Contains at least one fatal LogRecord.");
      }
      if (node.hasFatalChildren()) {
        result.add("Contains descendants with a fatal LogRecord.");
      }
      result.add("LogRecords in this category alone: " +
          node.getNumberOfContainedRecords());
      result.add("LogRecords in descendant categories: " +
          node.getNumberOfRecordsFromChildren());
      result.add("LogRecords in this category including descendants: " +
          node.getTotalNumberOfRecords());
      return result.toArray();
    }
  
    protected void showPopup(CategoryNode node, int x, int y) {
      JPopupMenu popup = new JPopupMenu();
      popup.setSize(150, 400);
      //
      // Configure the Popup
      //
      if (node.getParent() == null) {
        popup.add(createRemoveMenuItem());
        popup.addSeparator();
      }
      popup.add(createSelectDescendantsMenuItem(node));
      popup.add(createUnselectDescendantsMenuItem(node));
      popup.addSeparator();
      popup.add(createExpandMenuItem(node));
      popup.add(createCollapseMenuItem(node));
      popup.addSeparator();
      popup.add(createPropertiesMenuItem(node));
      popup.show(_renderer, x, y);
    }
  
    protected JMenuItem createSelectDescendantsMenuItem(final CategoryNode node) {
      JMenuItem selectDescendants =
          new JMenuItem("Select All Descendant Categories");
      selectDescendants.addActionListener(
          new ActionListener() {
            public void actionPerformed(ActionEvent e) {
              _categoryModel.setDescendantSelection(node, true);
            }
          }
      );
      return selectDescendants;
    }
  
    protected JMenuItem createUnselectDescendantsMenuItem(final CategoryNode node) {
      JMenuItem unselectDescendants =
          new JMenuItem("Deselect All Descendant Categories");
      unselectDescendants.addActionListener(
  
          new ActionListener() {
            public void actionPerformed(ActionEvent e) {
              _categoryModel.setDescendantSelection(node, false);
            }
          }
  
      );
      return unselectDescendants;
    }
  
    protected JMenuItem createExpandMenuItem(final CategoryNode node) {
      JMenuItem result = new JMenuItem("Expand All Descendant Categories");
      result.addActionListener(new ActionListener() {
        public void actionPerformed(ActionEvent e) {
          expandDescendants(node);
        }
      });
      return result;
    }
  
    protected JMenuItem createCollapseMenuItem(final CategoryNode node) {
      JMenuItem result = new JMenuItem("Collapse All Descendant Categories");
      result.addActionListener(new ActionListener() {
        public void actionPerformed(ActionEvent e) {
          collapseDescendants(node);
        }
      });
      return result;
    }
  
    /**
     * This featured was moved from the LogBrokerMonitor class
     * to the CategoryNodeExplorer so that the Category tree
     * could be pruned from the Category Explorer popup menu.
     * This menu option only appears when a user right clicks on
     * the Category parent node.
     *
     * See removeUnusedNodes()
     */
    protected JMenuItem createRemoveMenuItem() {
      JMenuItem result = new JMenuItem("Remove All Empty Categories");
      result.addActionListener(new ActionListener() {
        public void actionPerformed(ActionEvent e) {
          while (removeUnusedNodes() > 0) ;
        }
      });
      return result;
    }
  
    protected void expandDescendants(CategoryNode node) {
      Enumeration descendants = node.depthFirstEnumeration();
      CategoryNode current;
      while (descendants.hasMoreElements()) {
        current = (CategoryNode) descendants.nextElement();
        expand(current);
      }
    }
  
    protected void collapseDescendants(CategoryNode node) {
      Enumeration descendants = node.depthFirstEnumeration();
      CategoryNode current;
      while (descendants.hasMoreElements()) {
        current = (CategoryNode) descendants.nextElement();
        collapse(current);
      }
    }
  
    /**
     * Removes any inactive nodes from the Category tree.
     */
    protected int removeUnusedNodes() {
      int count = 0;
      CategoryNode root = _categoryModel.getRootCategoryNode();
      Enumeration enum = root.depthFirstEnumeration();
      while (enum.hasMoreElements()) {
        CategoryNode node = (CategoryNode) enum.nextElement();
        if (node.isLeaf() && node.getNumberOfContainedRecords() == 0
            && node.getParent() != null) {
          _categoryModel.removeNodeFromParent(node);
          count++;
        }
      }
  
      return count;
    }
  
    protected void expand(CategoryNode node) {
      _tree.expandPath(getTreePath(node));
    }
  
    protected TreePath getTreePath(CategoryNode node) {
      return new TreePath(node.getPath());
    }
  
    protected void collapse(CategoryNode node) {
      _tree.collapsePath(getTreePath(node));
    }
  
    //-----------------------------------------------------------------------
    //   Private Methods:
    //--------------------------------------------------------------------------
  
    //--------------------------------------------------------------------------
    //   Nested Top-Level Classes or Interfaces:
    //--------------------------------------------------------------------------
  
  }
  
  
  
  1.1                  jakarta-log4j/src/java/org/apache/log4j/lf5/viewer/categoryexplorer/CategoryNodeEditorRenderer.java
  
  Index: CategoryNodeEditorRenderer.java
  ===================================================================
  /*
   * Copyright (C) The Apache Software Foundation. All rights reserved.
   *
   * This software is published under the terms of the Apache Software
   * License version 1.1, a copy of which has been included with this
   * distribution in the LICENSE.txt file.
   */
  package org.apache.log4j.lf5.viewer.categoryexplorer;
  
  import javax.swing.*;
  import java.awt.*;
  
  /**
   * CategoryNodeEditorRenderer
   *
   * @author Michael J. Sikorsky
   * @author Robert Shaw
   */
  
  // Contributed by ThoughtWorks Inc.
  
  public class CategoryNodeEditorRenderer extends CategoryNodeRenderer {
    //--------------------------------------------------------------------------
    //   Constants:
    //--------------------------------------------------------------------------
  
    //--------------------------------------------------------------------------
    //   Protected Variables:
    //--------------------------------------------------------------------------
  
    //--------------------------------------------------------------------------
    //   Private Variables:
    //--------------------------------------------------------------------------
  
    //--------------------------------------------------------------------------
    //   Constructors:
    //--------------------------------------------------------------------------
  
    //--------------------------------------------------------------------------
    //   Public Methods:
    //--------------------------------------------------------------------------
  
    public Component getTreeCellRendererComponent(
        JTree tree, Object value,
        boolean selected, boolean expanded,
        boolean leaf, int row,
        boolean hasFocus) {
      Component c = super.getTreeCellRendererComponent(tree,
          value, selected, expanded,
          leaf, row, hasFocus);
  
      return c;
    }
  
    public JCheckBox getCheckBox() {
      return _checkBox;
    }
  
    //--------------------------------------------------------------------------
    //   Protected Methods:
    //--------------------------------------------------------------------------
  
    //--------------------------------------------------------------------------
    //   Private Methods:
    //--------------------------------------------------------------------------
  
    //--------------------------------------------------------------------------
    //   Nested Top-Level Classes or Interfaces:
    //--------------------------------------------------------------------------
  
  }
  
  
  
  1.1                  jakarta-log4j/src/java/org/apache/log4j/lf5/viewer/categoryexplorer/CategoryNodeRenderer.java
  
  Index: CategoryNodeRenderer.java
  ===================================================================
  /*
   * Copyright (C) The Apache Software Foundation. All rights reserved.
   *
   * This software is published under the terms of the Apache Software
   * License version 1.1, a copy of which has been included with this
   * distribution in the LICENSE.txt file.
   */
  package org.apache.log4j.lf5.viewer.categoryexplorer;
  
  import javax.swing.*;
  import javax.swing.tree.DefaultTreeCellRenderer;
  import java.awt.*;
  import java.net.URL;
  
  /**
   * CategoryNodeRenderer
   *
   * @author Michael J. Sikorsky
   * @author Robert Shaw
   */
  
  // Contributed by ThoughtWorks Inc.
  
  public class CategoryNodeRenderer extends DefaultTreeCellRenderer {
    //--------------------------------------------------------------------------
    //   Constants:
    //--------------------------------------------------------------------------
  
    public static final Color FATAL_CHILDREN = new Color(189, 113, 0);
  
    //--------------------------------------------------------------------------
    //   Protected Variables:
    //--------------------------------------------------------------------------
    protected JCheckBox _checkBox = new JCheckBox();
    protected JPanel _panel = new JPanel();
    protected static ImageIcon _sat = null;
  //   protected JLabel              _label  = new JLabel();
  
    //--------------------------------------------------------------------------
    //   Private Variables:
    //--------------------------------------------------------------------------
  
    //--------------------------------------------------------------------------
    //   Constructors:
    //--------------------------------------------------------------------------
    public CategoryNodeRenderer() {
      _panel.setBackground(UIManager.getColor("Tree.textBackground"));
  
      if (_sat == null) {
        // Load the satellite image.
        String resource =
            "/org/apache/log4j/lf5/viewer/images/channelexplorer_satellite.gif";
        URL satURL = getClass().getResource(resource);
  
        _sat = new ImageIcon(satURL);
      }
  
      setOpaque(false);
      _checkBox.setOpaque(false);
      _panel.setOpaque(false);
  
      // The flowlayout set to LEFT is very important so that the editor
      // doesn't jump around.
      _panel.setLayout(new FlowLayout(FlowLayout.LEFT, 0, 0));
      _panel.add(_checkBox);
      _panel.add(this);
  
      setOpenIcon(_sat);
      setClosedIcon(_sat);
      setLeafIcon(_sat);
    }
  
    //--------------------------------------------------------------------------
    //   Public Methods:
    //--------------------------------------------------------------------------
    public Component getTreeCellRendererComponent(
        JTree tree, Object value,
        boolean selected, boolean expanded,
        boolean leaf, int row,
        boolean hasFocus) {
  
      CategoryNode node = (CategoryNode) value;
      //FileNode node = (FileNode)value;
      //String s = tree.convertValueToText(value, selected,
      //						   expanded, leaf, row, hasFocus);
  
      super.getTreeCellRendererComponent(
          tree, value, selected, expanded,
          leaf, row, hasFocus);
  
      if (row == 0) {
        // Root row -- no check box
        _checkBox.setVisible(false);
      } else {
        _checkBox.setVisible(true);
        _checkBox.setSelected(node.isSelected());
      }
      String toolTip = buildToolTip(node);
      _panel.setToolTipText(toolTip);
      if (node.hasFatalChildren()) {
        this.setForeground(FATAL_CHILDREN);
      }
      if (node.hasFatalRecords()) {
        this.setForeground(Color.red);
      }
  
      return _panel;
    }
  
    public Dimension getCheckBoxOffset() {
      return new Dimension(0, 0);
    }
  
    //--------------------------------------------------------------------------
    //   Protected Methods:
    //--------------------------------------------------------------------------
  
    protected String buildToolTip(CategoryNode node) {
      StringBuffer result = new StringBuffer();
      result.append(node.getTitle()).append(" contains a total of ");
      result.append(node.getTotalNumberOfRecords());
      result.append(" LogRecords.");
      result.append(" Right-click for more info.");
      return result.toString();
    }
    //--------------------------------------------------------------------------
    //   Private Methods:
    //--------------------------------------------------------------------------
  
    //--------------------------------------------------------------------------
    //   Nested Top-Level Classes or Interfaces:
    //--------------------------------------------------------------------------
  
  }
  
  
  
  
  
  
  
  
  
  1.1                  jakarta-log4j/src/java/org/apache/log4j/lf5/viewer/categoryexplorer/CategoryPath.java
  
  Index: CategoryPath.java
  ===================================================================
  /*
   * Copyright (C) The Apache Software Foundation. All rights reserved.
   *
   * This software is published under the terms of the Apache Software
   * License version 1.1, a copy of which has been included with this
   * distribution in the LICENSE.txt file.
   */
  package org.apache.log4j.lf5.viewer.categoryexplorer;
  
  import java.util.LinkedList;
  import java.util.StringTokenizer;
  
  /**
   * CategoryPath is a collection of CategoryItems which represent a
   * path of categories.
   *
   * @author Michael J. Sikorsky
   * @author Robert Shaw
   */
  
  // Contributed by ThoughtWorks Inc.
  
  public class CategoryPath {
    //--------------------------------------------------------------------------
    //   Constants:
    //--------------------------------------------------------------------------
  
    //--------------------------------------------------------------------------
    //   Protected Variables:
    //--------------------------------------------------------------------------
    protected LinkedList _categoryElements = new LinkedList();
  
    //--------------------------------------------------------------------------
    //   Private Variables:
    //--------------------------------------------------------------------------
  
    //--------------------------------------------------------------------------
    //   Constructors:
    //--------------------------------------------------------------------------
  
    public CategoryPath() {
      super();
    }
  
    /**
     * Construct a CategoryPath.  If the category is null, it defaults to "Debug".
     */
    public CategoryPath(String category) {
      String processedCategory = category;
  
      if (processedCategory == null) {
        processedCategory = "Debug";
      }
  
      processedCategory.replace('/', '.');
      processedCategory = processedCategory.replace('\\', '.');
  
      StringTokenizer st = new StringTokenizer(processedCategory, ".");
      while (st.hasMoreTokens()) {
        String element = st.nextToken();
        addCategoryElement(new CategoryElement(element));
      }
    }
  
    //--------------------------------------------------------------------------
    //   Public Methods:
    //--------------------------------------------------------------------------
  
    /**
     * returns the number of CategoryElements.
     */
    public int size() {
      int count = _categoryElements.size();
  
      return (count);
    }
  
    public boolean isEmpty() {
      boolean empty = false;
  
      if (_categoryElements.size() == 0) {
        empty = true;
      }
  
      return (empty);
    }
  
  
    /**
     * Removes all categoryElements.
     */
    public void removeAllCategoryElements() {
      _categoryElements.clear();
    }
  
    /**
     * Adds the specified categoryElement to the end of the categoryElement set.
     */
    public void addCategoryElement(CategoryElement categoryElement) {
      _categoryElements.addLast(categoryElement);
    }
  
    /**
     * Returns the CategoryElement at the specified index.
     */
    public CategoryElement categoryElementAt(int index) {
      return ((CategoryElement) _categoryElements.get(index));
    }
  
  
    public String toString() {
      StringBuffer out = new StringBuffer(100);
  
      out.append("\n");
      out.append("===========================\n");
      out.append("CategoryPath:                   \n");
      out.append("---------------------------\n");
  
      out.append("\nCategoryPath:\n\t");
  
      if (this.size() > 0) {
        for (int i = 0; i < this.size(); i++) {
          out.append(this.categoryElementAt(i).toString());
          out.append("\n\t");
        }
      } else {
        out.append("<<NONE>>");
      }
  
      out.append("\n");
      out.append("===========================\n");
  
      return (out.toString());
    }
  
    //--------------------------------------------------------------------------
    //   Protected Methods:
    //--------------------------------------------------------------------------
  
    //--------------------------------------------------------------------------
    //   Private Methods:
    //--------------------------------------------------------------------------
  
    //--------------------------------------------------------------------------
    //   Nested Top-Level Classes or Interfaces:
    //--------------------------------------------------------------------------
  
  }
  
  
  
  1.1                  jakarta-log4j/src/java/org/apache/log4j/lf5/viewer/categoryexplorer/TreeModelAdapter.java
  
  Index: TreeModelAdapter.java
  ===================================================================
  /*
   * Copyright (C) The Apache Software Foundation. All rights reserved.
   *
   * This software is published under the terms of the Apache Software
   * License version 1.1, a copy of which has been included with this
   * distribution in the LICENSE.txt file.
   */
  
  package org.apache.log4j.lf5.viewer.categoryexplorer;
  
  import javax.swing.event.TreeModelEvent;
  import javax.swing.event.TreeModelListener;
  
  /**
   * Default implementation of TreeModelListener which does nothing.
   *
   * @author Richard Wan
   */
  
  // Contributed by ThoughtWorks Inc.
  
  public class TreeModelAdapter implements TreeModelListener {
    //--------------------------------------------------------------------------
    //   Constants:
    //--------------------------------------------------------------------------
  
    //--------------------------------------------------------------------------
    //   Protected Variables:
    //--------------------------------------------------------------------------
  
    //--------------------------------------------------------------------------
    //   Private Variables:
    //--------------------------------------------------------------------------
  
    //--------------------------------------------------------------------------
    //   Constructors:
    //--------------------------------------------------------------------------
  
    //--------------------------------------------------------------------------
    //   Public Methods:
    //--------------------------------------------------------------------------
    public void treeNodesChanged(TreeModelEvent e) {
    }
  
    public void treeNodesInserted(TreeModelEvent e) {
    }
  
    public void treeNodesRemoved(TreeModelEvent e) {
    }
  
    public void treeStructureChanged(TreeModelEvent e) {
    }
  
    //--------------------------------------------------------------------------
    //   Protected Methods:
    //--------------------------------------------------------------------------
  
    //--------------------------------------------------------------------------
    //   Private Methods:
    //--------------------------------------------------------------------------
  
    //--------------------------------------------------------------------------
    //   Nested Top-Level Classes or Interfaces
    //--------------------------------------------------------------------------
  }
  
  
  
  
  1.1                  jakarta-log4j/src/java/org/apache/log4j/lf5/viewer/configure/ConfigurationManager.java
  
  Index: ConfigurationManager.java
  ===================================================================
  /*
   * Copyright (C) The Apache Software Foundation. All rights reserved.
   *
   * This software is published under the terms of the Apache Software
   * License version 1.1, a copy of which has been included with this
   * distribution in the LICENSE.txt file.
   */
  package org.apache.log4j.lf5.viewer.configure;
  
  import org.apache.log4j.lf5.LogLevel;
  import org.apache.log4j.lf5.LogLevelFormatException;
  import org.apache.log4j.lf5.viewer.LogBrokerMonitor;
  import org.apache.log4j.lf5.viewer.LogTable;
  import org.apache.log4j.lf5.viewer.categoryexplorer.CategoryExplorerModel;
  import org.apache.log4j.lf5.viewer.categoryexplorer.CategoryExplorerTree;
  import org.apache.log4j.lf5.viewer.categoryexplorer.CategoryNode;
  import org.apache.log4j.lf5.viewer.categoryexplorer.CategoryPath;
  import org.apache.log4j.lf5.viewer.LogTableColumn;
  import org.apache.log4j.lf5.viewer.LogTableColumnFormatException;
  import org.w3c.dom.Document;
  import org.w3c.dom.NamedNodeMap;
  import org.w3c.dom.Node;
  import org.w3c.dom.NodeList;
  
  import javax.swing.*;
  import javax.swing.tree.TreePath;
  import javax.xml.parsers.DocumentBuilder;
  import javax.xml.parsers.DocumentBuilderFactory;
  import java.awt.*;
  import java.io.File;
  import java.io.FileWriter;
  import java.io.IOException;
  import java.io.PrintWriter;
  import java.util.*;
  import java.util.List;
  
  /**
   * <p>ConfigurationManager handles the storage and retrival of the state of
   * the CategoryExplorer
   *
   * @author Richard Hurst
   * @author Brad Marlborough
   */
  
  // Contributed by ThoughtWorks Inc.
  
  public class ConfigurationManager extends Object {
    //--------------------------------------------------------------------------
    //   Constants:
    //--------------------------------------------------------------------------
    private static final String CONFIG_FILE_NAME = "lf5_configuration.xml";
    private static final String NAME = "name";
    private static final String PATH = "path";
    private static final String SELECTED = "selected";
    private static final String EXPANDED = "expanded";
    private static final String CATEGORY = "category";
    private static final String FIRST_CATEGORY_NAME = "Categories";
    private static final String LEVEL = "level";
    private static final String COLORLEVEL = "colorlevel";
    private static final String COLOR = "color";
    private static final String RED = "red";
    private static final String GREEN = "green";
    private static final String BLUE = "blue";
    private static final String COLUMN = "column";
    private static final String NDCTEXTFILTER = "searchtext";
    //--------------------------------------------------------------------------
    //   Protected Variables:
    //--------------------------------------------------------------------------
  
    //--------------------------------------------------------------------------
    //   Private Variables:
    //--------------------------------------------------------------------------
    private LogBrokerMonitor _monitor = null;
    private LogTable _table = null;
  
    //--------------------------------------------------------------------------
    //   Constructors:
    //--------------------------------------------------------------------------
    public ConfigurationManager(LogBrokerMonitor monitor, LogTable table) {
      super();
      _monitor = monitor;
      _table = table;
      load();
    }
    //--------------------------------------------------------------------------
    //   Public Methods:
    //--------------------------------------------------------------------------
  
    public void save() {
      CategoryExplorerModel model = _monitor.getCategoryExplorerTree().getExplorerModel();
      CategoryNode root = model.getRootCategoryNode();
  
      StringBuffer xml = new StringBuffer(2048);
      openXMLDocument(xml);
      openConfigurationXML(xml);
      processLogRecordFilter(_monitor.getNDCTextFilter(), xml);
      processLogLevels(_monitor.getLogLevelMenuItems(), xml);
      processLogLevelColors(_monitor.getLogLevelMenuItems(),
          LogLevel.getLogLevelColorMap(), xml);
      processLogTableColumns(LogTableColumn.getLogTableColumns(), xml);
      processConfigurationNode(root, xml);
      closeConfigurationXML(xml);
      store(xml.toString());
    }
  
    public void reset() {
      deleteConfigurationFile();
      collapseTree();
      selectAllNodes();
    }
  
    public static String treePathToString(TreePath path) {
      // count begins at one so as to not include the 'Categories' - root category
      StringBuffer sb = new StringBuffer();
      CategoryNode n = null;
      Object[] objects = path.getPath();
      for (int i = 1; i < objects.length; i++) {
        n = (CategoryNode) objects[i];
        if (i > 1) {
          sb.append(".");
        }
        sb.append(n.getTitle());
      }
      return sb.toString();
    }
  
    //--------------------------------------------------------------------------
    //   Protected Methods:
    //--------------------------------------------------------------------------
    protected void load() {
      File file = new File(getFilename());
      if (file.exists()) {
        try {
          DocumentBuilderFactory docBuilderFactory = DocumentBuilderFactory.
              newInstance();
          DocumentBuilder docBuilder = docBuilderFactory.newDocumentBuilder();
          Document doc = docBuilder.parse(file);
          processRecordFilter(doc);
          processCategories(doc);
          processLogLevels(doc);
          processLogLevelColors(doc);
          processLogTableColumns(doc);
        } catch (Exception e) {
          // ignore all error and just continue as if there was no
          // configuration xml file but do report a message
          System.err.println("Unable process configuration file at " +
              getFilename() + ". Error Message=" + e.getMessage());
        }
      }
  
    }
  
    // Added in version 1.2 - reads in the NDC text filter from the
    // xml configuration file.  If the value of the filter is not null
    // or an empty string ("") then the manager will set the LogBrokerMonitor's
    // LogRecordFilter to use the NDC LogRecordFilter.  Otherwise, the
    // LogBrokerMonitor will use the default LogRecordFilter.
    protected void processRecordFilter(Document doc) {
      NodeList nodeList = doc.getElementsByTagName(NDCTEXTFILTER);
  
      // there is only one value stored
      Node n = nodeList.item(0);
      // add check for backwards compatibility  as this feature was added in
      // version 1.2
      if (n == null) {
        return;
      }
  
      NamedNodeMap map = n.getAttributes();
      String text = getValue(map, NAME);
  
      if (text == null || text.equals("")) {
        return;
      }
      _monitor.setNDCLogRecordFilter(text);
    }
  
    protected void processCategories(Document doc) {
      CategoryExplorerTree tree = _monitor.getCategoryExplorerTree();
      CategoryExplorerModel model = tree.getExplorerModel();
      NodeList nodeList = doc.getElementsByTagName(CATEGORY);
  
      // determine where the starting node is
      NamedNodeMap map = nodeList.item(0).getAttributes();
      int j = (getValue(map, NAME).equalsIgnoreCase(FIRST_CATEGORY_NAME)) ? 1 : 0;
      // iterate backwards throught the nodeList so that expansion of the
      // list can occur
      for (int i = nodeList.getLength() - 1; i >= j; i--) {
        Node n = nodeList.item(i);
        map = n.getAttributes();
        CategoryNode chnode = model.addCategory(new CategoryPath(getValue(map, PATH)));
        chnode.setSelected((getValue(map, SELECTED).equalsIgnoreCase("true")) ? true : false);
        if (getValue(map, EXPANDED).equalsIgnoreCase("true")) ;
        tree.expandPath(model.getTreePathToRoot(chnode));
      }
  
    }
  
    protected void processLogLevels(Document doc) {
      NodeList nodeList = doc.getElementsByTagName(LEVEL);
      Map menuItems = _monitor.getLogLevelMenuItems();
  
      for (int i = 0; i < nodeList.getLength(); i++) {
        Node n = nodeList.item(i);
        NamedNodeMap map = n.getAttributes();
        String name = getValue(map, NAME);
        try {
          JCheckBoxMenuItem item =
              (JCheckBoxMenuItem) menuItems.get(LogLevel.valueOf(name));
          item.setSelected(getValue(map, SELECTED).equalsIgnoreCase("true"));
        } catch (LogLevelFormatException e) {
          // ignore it will be on by default.
        }
      }
    }
  
    protected void processLogLevelColors(Document doc) {
      NodeList nodeList = doc.getElementsByTagName(COLORLEVEL);
      Map logLevelColors = LogLevel.getLogLevelColorMap();
  
      for (int i = 0; i < nodeList.getLength(); i++) {
        Node n = nodeList.item(i);
        // check for backwards compatibility since this feature was added
        // in version 1.3
        if (n == null) {
          return;
        }
  
        NamedNodeMap map = n.getAttributes();
        String name = getValue(map, NAME);
        try {
          LogLevel level = LogLevel.valueOf(name);
          int red = Integer.parseInt(getValue(map, RED));
          int green = Integer.parseInt(getValue(map, GREEN));
          int blue = Integer.parseInt(getValue(map, BLUE));
          Color c = new Color(red, green, blue);
          if (level != null) {
            level.setLogLevelColorMap(level, c);
          }
  
        } catch (LogLevelFormatException e) {
          // ignore it will be on by default.
        }
      }
    }
  
    protected void processLogTableColumns(Document doc) {
      NodeList nodeList = doc.getElementsByTagName(COLUMN);
      Map menuItems = _monitor.getLogTableColumnMenuItems();
      List selectedColumns = new ArrayList();
      for (int i = 0; i < nodeList.getLength(); i++) {
        Node n = nodeList.item(i);
        // check for backwards compatibility since this feature was added
        // in version 1.3
        if (n == null) {
          return;
        }
        NamedNodeMap map = n.getAttributes();
        String name = getValue(map, NAME);
        try {
          LogTableColumn column = LogTableColumn.valueOf(name);
          JCheckBoxMenuItem item =
              (JCheckBoxMenuItem) menuItems.get(column);
          item.setSelected(getValue(map, SELECTED).equalsIgnoreCase("true"));
  
          if (item.isSelected()) {
            selectedColumns.add(column);
          }
        } catch (LogTableColumnFormatException e) {
          // ignore it will be on by default.
        }
  
        if (selectedColumns.isEmpty()) {
          _table.setDetailedView();
        } else {
          _table.setView(selectedColumns);
        }
  
      }
    }
  
    protected String getValue(NamedNodeMap map, String attr) {
      Node n = map.getNamedItem(attr);
      return n.getNodeValue();
    }
  
    protected void collapseTree() {
      // collapse everything except the first category
      CategoryExplorerTree tree = _monitor.getCategoryExplorerTree();
      for (int i = tree.getRowCount() - 1; i > 0; i--) {
        tree.collapseRow(i);
      }
    }
  
    protected void selectAllNodes() {
      CategoryExplorerModel model = _monitor.getCategoryExplorerTree().getExplorerModel();
      CategoryNode root = model.getRootCategoryNode();
      Enumeration all = root.breadthFirstEnumeration();
      CategoryNode n = null;
      while (all.hasMoreElements()) {
        n = (CategoryNode) all.nextElement();
        n.setSelected(true);
      }
    }
  
    protected void store(String s) {
  
      try {
        PrintWriter writer = new PrintWriter(new FileWriter(getFilename()));
        writer.print(s);
        writer.close();
      } catch (IOException e) {
        // do something with this error.
        e.printStackTrace();
      }
  
    }
  
    protected void deleteConfigurationFile() {
      try {
        File f = new File(getFilename());
        if (f.exists()) {
          f.delete();
        }
      } catch (SecurityException e) {
        System.err.println("Cannot delete " + getFilename() +
            " because a security violation occured.");
      }
    }
  
    protected String getFilename() {
      String home = System.getProperty("user.home");
      String sep = (home.startsWith(MRUFileManager.UNIX_SEPARATOR))
          ? MRUFileManager.UNIX_SEPARATOR : MRUFileManager.DOS_SEPARATOR;
  
      return home + sep + "lf5" + sep + CONFIG_FILE_NAME;
    }
  
    //--------------------------------------------------------------------------
    //   Private Methods:
    //--------------------------------------------------------------------------
    private void processConfigurationNode(CategoryNode node, StringBuffer xml) {
      CategoryExplorerModel model = _monitor.getCategoryExplorerTree().getExplorerModel();
  
      Enumeration all = node.breadthFirstEnumeration();
      CategoryNode n = null;
      while (all.hasMoreElements()) {
        n = (CategoryNode) all.nextElement();
        exportXMLElement(n, model.getTreePathToRoot(n), xml);
      }
  
    }
  
    private void processLogLevels(Map logLevelMenuItems, StringBuffer xml) {
      xml.append("\t<loglevels>\r\n");
      Iterator it = logLevelMenuItems.keySet().iterator();
      while (it.hasNext()) {
        LogLevel level = (LogLevel) it.next();
        JCheckBoxMenuItem item = (JCheckBoxMenuItem) logLevelMenuItems.get(level);
        exportLogLevelXMLElement(level.getLabel(), item.isSelected(), xml);
      }
  
      xml.append("\t</loglevels>\r\n");
    }
  
    private void processLogLevelColors(Map logLevelMenuItems, Map logLevelColors, StringBuffer xml) {
      xml.append("\t<loglevelcolors>\r\n");
      // iterate through the list of log levels being used (log4j, jdk1.4, custom levels)
      Iterator it = logLevelMenuItems.keySet().iterator();
      while (it.hasNext()) {
        LogLevel level = (LogLevel) it.next();
        // for each level, get the associated color from the log level color map
        Color color = (Color) logLevelColors.get(level);
        exportLogLevelColorXMLElement(level.getLabel(), color, xml);
      }
  
      xml.append("\t</loglevelcolors>\r\n");
    }
  
  
    private void processLogTableColumns(List logTableColumnMenuItems, StringBuffer xml) {
      xml.append("\t<logtablecolumns>\r\n");
      Iterator it = logTableColumnMenuItems.iterator();
      while (it.hasNext()) {
        LogTableColumn column = (LogTableColumn) it.next();
        JCheckBoxMenuItem item = _monitor.getTableColumnMenuItem(column);
        exportLogTableColumnXMLElement(column.getLabel(), item.isSelected(), xml);
      }
  
      xml.append("\t</logtablecolumns>\r\n");
    }
  
    // Added in version 1.2 - stores the NDC text filter in the xml file
    // for future use.
    private void processLogRecordFilter(String text, StringBuffer xml) {
      xml.append("\t<").append(NDCTEXTFILTER).append(" ");
      xml.append(NAME).append("=\"").append(text).append("\"");
      xml.append("/>\r\n");
    }
  
    private void openXMLDocument(StringBuffer xml) {
      xml.append("<?xml version=\"1.0\" encoding=\"UTF-8\" ?>\r\n");
    }
  
    private void openConfigurationXML(StringBuffer xml) {
      xml.append("<configuration>\r\n");
    }
  
    private void closeConfigurationXML(StringBuffer xml) {
      xml.append("</configuration>\r\n");
    }
  
    private void exportXMLElement(CategoryNode node, TreePath path, StringBuffer xml) {
      CategoryExplorerTree tree = _monitor.getCategoryExplorerTree();
  
      xml.append("\t<").append(CATEGORY).append(" ");
      xml.append(NAME).append("=\"").append(node.getTitle()).append("\" ");
      xml.append(PATH).append("=\"").append(treePathToString(path)).append("\" ");
      xml.append(EXPANDED).append("=\"").append(tree.isExpanded(path)).append("\" ");
      xml.append(SELECTED).append("=\"").append(node.isSelected()).append("\"/>\r\n");
    }
  
    private void exportLogLevelXMLElement(String label, boolean selected, StringBuffer xml) {
      xml.append("\t\t<").append(LEVEL).append(" ").append(NAME);
      xml.append("=\"").append(label).append("\" ");
      xml.append(SELECTED).append("=\"").append(selected);
      xml.append("\"/>\r\n");
    }
  
    private void exportLogLevelColorXMLElement(String label, Color color, StringBuffer xml) {
      xml.append("\t\t<").append(COLORLEVEL).append(" ").append(NAME);
      xml.append("=\"").append(label).append("\" ");
      xml.append(RED).append("=\"").append(color.getRed()).append("\" ");
      xml.append(GREEN).append("=\"").append(color.getGreen()).append("\" ");
      xml.append(BLUE).append("=\"").append(color.getBlue());
      xml.append("\"/>\r\n");
    }
  
    private void exportLogTableColumnXMLElement(String label, boolean selected, StringBuffer xml) {
      xml.append("\t\t<").append(COLUMN).append(" ").append(NAME);
      xml.append("=\"").append(label).append("\" ");
      xml.append(SELECTED).append("=\"").append(selected);
      xml.append("\"/>\r\n");
    }
    //--------------------------------------------------------------------------
    //   Nested Top-Level Classes or Interfaces:
    //--------------------------------------------------------------------------
  
  }
  
  
  
  
  
  
  
  
  
  1.1                  jakarta-log4j/src/java/org/apache/log4j/lf5/viewer/configure/MRUFileManager.java
  
  Index: MRUFileManager.java
  ===================================================================
  /*
   * Copyright (C) The Apache Software Foundation. All rights reserved.
   *
   * This software is published under the terms of the Apache Software
   * License version 1.1, a copy of which has been included with this
   * distribution in the LICENSE.txt file.
   */
  package org.apache.log4j.lf5.viewer.configure;
  
  import java.io.*;
  import java.net.URL;
  import java.util.Iterator;
  import java.util.LinkedList;
  
  
  /**
   * <p>MRUFileManager handles the storage and retrival the most
   * recently opened log files.
   *
   * @author Brad Marlborough
   * @author Richard Hurst
   */
  
  // Contributed by ThoughtWorks Inc.
  
  public class MRUFileManager {
    //--------------------------------------------------------------------------
    //   Constants:
    //--------------------------------------------------------------------------
    private static final String CONFIG_FILE_NAME = "mru_file_manager";
    private static final int DEFAULT_MAX_SIZE = 3;
    public static final String UNIX_SEPARATOR = "/";
    public static final String DOS_SEPARATOR = "\\";
  
    //--------------------------------------------------------------------------
    //   Protected Variables:
    //--------------------------------------------------------------------------
  
    //--------------------------------------------------------------------------
    //   Private Variables:
    //--------------------------------------------------------------------------
    private int _maxSize = 0;
    private LinkedList _mruFileList;
  
    //--------------------------------------------------------------------------
    //   Constructors:
    //--------------------------------------------------------------------------
    public MRUFileManager() {
      load();
      setMaxSize(DEFAULT_MAX_SIZE);
    }
  
    public MRUFileManager(int maxSize) {
      load();
      setMaxSize(maxSize);
    }
    //--------------------------------------------------------------------------
    //   Public Methods:
    //--------------------------------------------------------------------------
  
    /**
     * Saves a list of MRU files out to a file.
     */
    public void save() {
      File file = new File(getFilename());
  
      try {
        ObjectOutputStream oos = new ObjectOutputStream(new
            FileOutputStream(file));
        oos.writeObject(_mruFileList);
        oos.flush();
        oos.close();
      } catch (Exception e) {
        // do nothing
        e.printStackTrace();
      }
  
    }
  
    /**
     * Gets the size of the MRU file list.
     */
    public int size() {
      return _mruFileList.size();
    }
  
    /**
     * Returns a particular file name stored in a MRU file
     * list based on an index value.
     */
    public Object getFile(int index) {
      if (index < size()) {
        return _mruFileList.get(index);
      }
  
      return null;
    }
  
    /**
     * Returns a input stream to the resource at the specified index
     */
    public InputStream getInputStream(int index) throws IOException,
        FileNotFoundException {
      if (index < size()) {
        Object o = getFile(index);
        if (o instanceof File) {
          return getInputStream((File) o);
        } else {
          return getInputStream((URL) o);
        }
      }
      return null;
    }
  
  
    /**
     * Adds a file name to the MRU file list.
     */
    public void set(File file) {
      setMRU(file);
    }
  
    /**
     * Adds a url to the MRU file list.
     */
    public void set(URL url) {
      setMRU(url);
    }
  
    /**
     * Gets the list of files stored in the MRU file list.
     */
    public String[] getMRUFileList() {
      if (size() == 0) {
        return null;
      }
  
      String[] ss = new String[size()];
  
      for (int i = 0; i < size(); i++) {
        Object o = getFile(i);
        if (o instanceof File) {
          ss[i] = ((File) o).getAbsolutePath();
        } else // must be a url
        {
          ss[i] = o.toString();
        }
  
      }
  
      return ss;
    }
  
    /**
     * Moves the the index to the top of the MRU List
     *
     * @param index The index to be first in the mru list
     */
    public void moveToTop(int index) {
      _mruFileList.add(0, _mruFileList.remove(index));
    }
  
    /**
     * Creates the directory where the MRU file list will be written.
     * The "lf5" directory is created in the Documents and Settings
     * directory on Windows 2000 machines and where ever the user.home
     * variable points on all other platforms.
     */
    public static void createConfigurationDirectory() {
      String home = System.getProperty("user.home");
      String sep = (home.startsWith(UNIX_SEPARATOR)) ? UNIX_SEPARATOR : DOS_SEPARATOR;
      File f = new File(home + sep + "lf5");
      if (!f.exists()) {
        try {
          f.mkdir();
        } catch (SecurityException e) {
          e.printStackTrace();
        }
      }
  
    }
    //--------------------------------------------------------------------------
    //   Protected Methods:
    //--------------------------------------------------------------------------
    /**
     * Gets an input stream for the corresponding file.
     *
     * @param file The file to create the input stream from.
     * @return InputStream
     */
    protected InputStream getInputStream(File file) throws IOException,
        FileNotFoundException {
      BufferedInputStream reader =
          new BufferedInputStream(new FileInputStream(file));
  
      return reader;
    }
  
    /**
     * Gets an input stream for the corresponding URL.
     *
     * @param url The url to create the input stream from.
     * @return InputStream
     */
    protected InputStream getInputStream(URL url) throws IOException {
      return url.openStream();
    }
  
    /**
     * Adds an object to the mru.
     */
    protected void setMRU(Object o) {
      int index = _mruFileList.indexOf(o);
  
      if (index == -1) {
        _mruFileList.add(0, o);
        setMaxSize(_maxSize);
      } else {
        moveToTop(index);
      }
    }
  
    /**
     * Loads the MRU file list in from a file and stores it in a LinkedList.
     * If no file exists, a new LinkedList is created.
     */
    protected void load() {
      createConfigurationDirectory();
      File file = new File(getFilename());
      if (file.exists()) {
        try {
          ObjectInputStream ois = new ObjectInputStream(
              new FileInputStream(file));
          _mruFileList = (LinkedList) ois.readObject();
          ois.close();
  
          // check that only files and url are in linked list
          Iterator it = _mruFileList.iterator();
          while (it.hasNext()) {
            Object o = it.next();
            if (!(o instanceof File) && !(o instanceof URL)) {
              it.remove();
            }
          }
        } catch (Exception e) {
          _mruFileList = new LinkedList();
        }
      } else {
        _mruFileList = new LinkedList();
      }
  
    }
  
    protected String getFilename() {
      String home = System.getProperty("user.home");
      String sep = (home.startsWith(UNIX_SEPARATOR)) ? UNIX_SEPARATOR : DOS_SEPARATOR;
  
      return home + sep + "lf5" + sep + CONFIG_FILE_NAME;
    }
  
    /**
     * Ensures that the MRU list will have a MaxSize.
     */
    protected void setMaxSize(int maxSize) {
      if (maxSize < _mruFileList.size()) {
        for (int i = 0; i < _mruFileList.size() - maxSize; i++) {
          _mruFileList.removeFirst();
        }
      }
  
      _maxSize = maxSize;
    }
    //--------------------------------------------------------------------------
    //   Private Methods:
    //--------------------------------------------------------------------------
  
    //--------------------------------------------------------------------------
    //   Nested Top-Level Classes or Interfaces
    //--------------------------------------------------------------------------
  }
  
  
  1.1                  jakarta-log4j/src/java/org/apache/log4j/lf5/viewer/images/channelexplorer_new.gif
  
  	<<Binary file>>
  
  
  1.1                  jakarta-log4j/src/java/org/apache/log4j/lf5/viewer/images/channelexplorer_satellite.gif
  
  	<<Binary file>>
  
  
  1.1                  jakarta-log4j/src/java/org/apache/log4j/lf5/viewer/images/lf5_about.gif
  
  	<<Binary file>>
  
  
  1.1                  jakarta-log4j/src/java/org/apache/log4j/lf5/viewer/images/lf5_small_icon.gif
  
  	<<Binary file>>
  
  
  1.1                  jakarta-log4j/src/java/org/apache/log4j/lf5/viewer/images/lf5_small_icon.png
  
  	<<Binary file>>
  
  

--
To unsubscribe, e-mail:   <ma...@jakarta.apache.org>
For additional commands, e-mail: <ma...@jakarta.apache.org>