You are viewing a plain text version of this content. The canonical link for it is here.
Posted to log4j-dev@logging.apache.org by sd...@apache.org on 2003/11/09 10:59:28 UTC

cvs commit: jakarta-log4j/src/java/org/apache/log4j/chainsaw/color ColorPanel.java RuleColorizer.java

sdeboy      2003/11/09 01:59:28

  Modified:    src/java/org/apache/log4j/net SocketReceiver.java
                        XMLSocketReceiver.java
               src/java/org/apache/log4j/chainsaw/rule InFixToPostFix.java
                        OrRule.java LikeRule.java ExpressionRule.java
                        LevelInequalityRule.java AndRule.java
                        InequalityRule.java NotEqualsRule.java
                        RuleFactory.java NotRule.java RuleTest.java
                        EqualsRule.java PartialTextMatchRule.java
               src/java/org/apache/log4j/chainsaw WelcomePanel.java
                        ChainsawSplash.java ChainsawToolBarAndMenus.java
                        LogUI.java LogPanel.java
                        TableColorizingRenderer.java
                        LogPanelPreferencePanel.java
  Added:       src/java/org/apache/log4j/chainsaw/rule ColorRule.java
                        ExpressionRuleContext.java
               src/java/org/apache/log4j/chainsaw/color ColorPanel.java
                        RuleColorizer.java
  Log:
  added color rule support to chainsaw
  
  * implemented support for expression-based color rules and a colorpanel UI for building the expressions and defining the colors.  Colors aren't yet written to disk so color support is a work in progress, but seems very usable.
  * updated welcomepanel load process to avoid null pointer in html load step
  * modified rules to clarify parameters, increased visibility where necessary
  * refactored expression rule context (a popup menu which assists in building rule expressions) and added support in colorpanel UI
  * made the chainsawsplash a child of the main window
  * modified tablecolorizingrenderer - changed colorizer (passed in now from logpanel)
  * removed socket exception throws from log output on socketreceiver/xmlsocketreceiver - logged as a warn without stack trace
  
  Revision  Changes    Path
  1.7       +2 -2      jakarta-log4j/src/java/org/apache/log4j/net/SocketReceiver.java
  
  Index: SocketReceiver.java
  ===================================================================
  RCS file: /home/cvs/jakarta-log4j/src/java/org/apache/log4j/net/SocketReceiver.java,v
  retrieving revision 1.6
  retrieving revision 1.7
  diff -u -r1.6 -r1.7
  --- SocketReceiver.java	20 Oct 2003 05:27:15 -0000	1.6
  +++ SocketReceiver.java	9 Nov 2003 09:59:27 -0000	1.7
  @@ -279,7 +279,7 @@
       } catch (Exception e) {
         LogLog.warn(
           "exception while watching socket server in SocketReceiver ("
  -        + this.getName() + "), stopping", e);
  +        + this.getName() + "), stopping");
       }
   
       LogLog.debug(getName() + " has exited the not interrupted loop");
  @@ -290,7 +290,7 @@
         try {
           socket.close();
         } catch (IOException e1) {
  -        e1.printStackTrace();
  +          LogLog.warn("socket exception caught - socket closed");
         }
       }
   
  
  
  
  1.5       +4 -3      jakarta-log4j/src/java/org/apache/log4j/net/XMLSocketReceiver.java
  
  Index: XMLSocketReceiver.java
  ===================================================================
  RCS file: /home/cvs/jakarta-log4j/src/java/org/apache/log4j/net/XMLSocketReceiver.java,v
  retrieving revision 1.4
  retrieving revision 1.5
  diff -u -r1.4 -r1.5
  --- XMLSocketReceiver.java	2 Nov 2003 19:53:47 -0000	1.4
  +++ XMLSocketReceiver.java	9 Nov 2003 09:59:27 -0000	1.5
  @@ -72,7 +72,9 @@
     appenders currently configured in the LoggerRespository.
   
     @author Mark Womack
  -  @since 1.3
  +  @author Scott Deboy <sd...@apache.org>
  +
  +    @since 1.3
   */
   public class XMLSocketReceiver extends Receiver implements Runnable, PortBased, Pauseable {
     protected int port;
  @@ -299,8 +301,7 @@
         }
       } catch (Exception e) {
         LogLog.warn(
  -        "exception while watching socket server in SocketReceiver ("
  -        + this.getName() + "), stopping", e);
  +        "socket server disconnected, stopping");
       }
     }
   
  
  
  
  1.4       +1 -1      jakarta-log4j/src/java/org/apache/log4j/chainsaw/rule/InFixToPostFix.java
  
  Index: InFixToPostFix.java
  ===================================================================
  RCS file: /home/cvs/jakarta-log4j/src/java/org/apache/log4j/chainsaw/rule/InFixToPostFix.java,v
  retrieving revision 1.3
  retrieving revision 1.4
  diff -u -r1.3 -r1.4
  --- InFixToPostFix.java	27 Oct 2003 08:22:15 -0000	1.3
  +++ InFixToPostFix.java	9 Nov 2003 09:59:27 -0000	1.4
  @@ -66,7 +66,7 @@
    * @author Scott Deboy <sd...@apache.org>
    */
   
  -class InFixToPostFix {
  +public class InFixToPostFix {
     private final Map precedenceMap = new HashMap();
     private final List operators = new Vector();
   
  
  
  
  1.3       +11 -11    jakarta-log4j/src/java/org/apache/log4j/chainsaw/rule/OrRule.java
  
  Index: OrRule.java
  ===================================================================
  RCS file: /home/cvs/jakarta-log4j/src/java/org/apache/log4j/chainsaw/rule/OrRule.java,v
  retrieving revision 1.2
  retrieving revision 1.3
  diff -u -r1.2 -r1.3
  --- OrRule.java	27 Oct 2003 08:22:15 -0000	1.2
  +++ OrRule.java	9 Nov 2003 09:59:27 -0000	1.3
  @@ -58,27 +58,27 @@
    * 
    * @author Scott Deboy <sd...@apache.org>
    */
  -class OrRule extends AbstractRule {
  -  Rule firstParam;
  -  Rule secondParam;
  +public class OrRule extends AbstractRule {
  +  private final Rule rule1;
  +  private final Rule rule2;
   
     private OrRule(Rule firstParam, Rule secondParam) {
  -    this.firstParam = firstParam;
  -    this.secondParam = secondParam;
  +    this.rule1 = firstParam;
  +    this.rule2 = secondParam;
     }
   
  +  public static Rule getRule(Rule firstParam, Rule secondParam) {
  +      return new OrRule(firstParam, secondParam);
  +  }
  +  
     public static Rule getRule(Stack stack) {
  -    Rule p1 = (Rule) stack.pop();
       Rule p2 = (Rule) stack.pop();
  +    Rule p1 = (Rule) stack.pop();
   
       return new OrRule(p1, p2);
     }
   
     public boolean evaluate(LoggingEvent event) {
  -
  -    boolean result =
  -      (firstParam.evaluate(event) || secondParam.evaluate(event));
  -
  -    return result;
  +    return (rule1.evaluate(event) || rule2.evaluate(event));
     }
   }
  
  
  
  1.3       +17 -16    jakarta-log4j/src/java/org/apache/log4j/chainsaw/rule/LikeRule.java
  
  Index: LikeRule.java
  ===================================================================
  RCS file: /home/cvs/jakarta-log4j/src/java/org/apache/log4j/chainsaw/rule/LikeRule.java,v
  retrieving revision 1.2
  retrieving revision 1.3
  diff -u -r1.2 -r1.3
  --- LikeRule.java	27 Oct 2003 08:22:15 -0000	1.2
  +++ LikeRule.java	9 Nov 2003 09:59:27 -0000	1.3
  @@ -64,36 +64,37 @@
    * 
    * @author Scott Deboy <sd...@apache.org>
    */
  -class LikeRule extends AbstractRule {
  -  LoggingEventFieldResolver resolver = LoggingEventFieldResolver.getInstance();
  -  Pattern pattern = null;
  -  Perl5Matcher matcher = new Perl5Matcher();
  -  String secondParam;
  +public class LikeRule extends AbstractRule {
  +  private static final LoggingEventFieldResolver resolver = LoggingEventFieldResolver.getInstance();
  +  private final Pattern pattern;
  +  private final Perl5Matcher matcher = new Perl5Matcher();
  +  private final String field;
   
  -  private LikeRule(Pattern pattern, String secondParam) {
  +  private LikeRule(String field, Pattern pattern) {
  +    this.field = field;
       this.pattern = pattern;
  -    this.secondParam = secondParam;
     }
   
     public static Rule getRule(Stack stack) {
  -    String p1 = stack.pop().toString();
  -    String p2 = stack.pop().toString();
  +      String p2 = stack.pop().toString();
  +      String p1 = stack.pop().toString();
  +      return getRule(p1, p2);
  +  }
  +
  +  public static Rule getRule(String field, String pattern) {
       Perl5Compiler compiler = new Perl5Compiler();
       Pattern pattern1 = null;
   
       try {
  -      pattern1 = compiler.compile(p1, Perl5Compiler.CASE_INSENSITIVE_MASK);
  +      pattern1 = compiler.compile(pattern, Perl5Compiler.CASE_INSENSITIVE_MASK);
       } catch (MalformedPatternException e) {
       }
   
  -    return new LikeRule(pattern1, p2);
  +    return new LikeRule(field, pattern1);
     }
   
     public boolean evaluate(LoggingEvent event) {
  -    String p2 = resolver.getValue(secondParam, event).toString();
  -
  -    boolean result = ((pattern != null) && matcher.matches(p2, pattern));
  -
  -    return result;
  +    String input = resolver.getValue(field, event).toString();
  +    return ((pattern != null) && matcher.matches(input, pattern));
     }
   }
  
  
  
  1.5       +47 -40    jakarta-log4j/src/java/org/apache/log4j/chainsaw/rule/ExpressionRule.java
  
  Index: ExpressionRule.java
  ===================================================================
  RCS file: /home/cvs/jakarta-log4j/src/java/org/apache/log4j/chainsaw/rule/ExpressionRule.java,v
  retrieving revision 1.4
  retrieving revision 1.5
  diff -u -r1.4 -r1.5
  --- ExpressionRule.java	27 Oct 2003 08:22:15 -0000	1.4
  +++ ExpressionRule.java	9 Nov 2003 09:59:27 -0000	1.5
  @@ -55,32 +55,35 @@
   import java.util.Stack;
   import java.util.StringTokenizer;
   
  +
   /**
  - * A Rule class supporting both infix and postfix expressions, accepting any rule which 
  + * A Rule class supporting both infix and postfix expressions, accepting any rule which
    * is supported by the <code>RuleFactory</code>.
  - * 
  - * NOTE: parsing is supported through the use of <code>StringTokenizer</code>, which 
  + *
  + * NOTE: parsing is supported through the use of <code>StringTokenizer</code>, which
    * implies two limitations:
    * 1: all tokens in the expression must be separated by spaces,
    * 2: operands which contain spaces in the value being evaluated are not supported
    *    (for example, attempting to perform 'msg == some other msg' will fail, since 'some other msg'
  - *    will be parsed as individual tokens in the expression instead of a single token (this is 
  - *    the next planned fix). 
  - * 
  + *    will be parsed as individual tokens in the expression instead of a single token (this is
  + *    the next planned fix).
  + *
    * @author Scott Deboy <sd...@apache.org>
    */
  -
   public class ExpressionRule extends AbstractRule {
  -  private static InFixToPostFix convertor = new InFixToPostFix();
  -  private static PostFixExpressionCompiler compiler =
  +  private static final InFixToPostFix convertor = new InFixToPostFix();
  +  private static final PostFixExpressionCompiler compiler =
       new PostFixExpressionCompiler();
  -  Rule rule = null;
  -  Stack stack = new Stack();
  +  private final Rule rule;
   
     private ExpressionRule(Rule rule) {
       this.rule = rule;
     }
   
  +  public static Rule getRule(String expression) {
  +      return getRule(expression, false);
  +  }
  +  
     public static Rule getRule(String expression, boolean isPostFix) {
       if (!isPostFix) {
         expression = convertor.convert(expression);
  @@ -90,40 +93,44 @@
     }
   
     public boolean evaluate(LoggingEvent event) {
  -      return rule.evaluate(event);
  +    return rule.evaluate(event);
  +  }
  +  
  +  public String toString() {
  +      return rule.toString();
     }
   }
   
   
  -  /**
  -   * Evaluate a boolean postfix expression.
  -   *
  -   */
  -  class PostFixExpressionCompiler {
  -
  -    Rule compileExpression(String expression) {
  -
  -      Stack stack = new Stack();
  -      Enumeration tokenizer = new StringTokenizer(expression);
  -
  -      while (tokenizer.hasMoreElements()) {
  -        //examine each token
  -        String nextToken = ((String) tokenizer.nextElement());
  -
  -        //if a symbol is found, pop 2 off the stack, evaluate and push the result 
  -        if (RuleFactory.isRule(nextToken)) {
  -          Rule r = (Rule) RuleFactory.getRule(nextToken, stack);
  -          stack.push(r);
  -        } else {
  -
  -          //variables or constants are pushed onto the stack
  -          stack.push(nextToken);
  -        }
  -      }
  -      if (!(stack.peek() instanceof Rule)) {
  -          throw new RuntimeException("invalid expression: " + expression);
  +/**
  + * Evaluate a boolean postfix expression.
  + *
  + */
  +class PostFixExpressionCompiler {
  +  Rule compileExpression(String expression) {
  +    RuleFactory factory = RuleFactory.getInstance();
  +
  +    Stack stack = new Stack();
  +    Enumeration tokenizer = new StringTokenizer(expression);
  +
  +    while (tokenizer.hasMoreElements()) {
  +      //examine each token
  +      String nextToken = ((String) tokenizer.nextElement());
  +
  +      //if a symbol is found, pop 2 off the stack, evaluate and push the result 
  +      if (factory.isRule(nextToken)) {
  +        Rule r = (Rule) factory.getRule(nextToken, stack);
  +        stack.push(r);
         } else {
  -        return (Rule)stack.pop();
  +        //variables or constants are pushed onto the stack
  +        stack.push(nextToken);
         }
       }
  +
  +    if (!(stack.peek() instanceof Rule)) {
  +      throw new RuntimeException("invalid expression: " + expression);
  +    } else {
  +      return (Rule) stack.pop();
  +    }
  +  }
   }
  
  
  
  1.4       +20 -16    jakarta-log4j/src/java/org/apache/log4j/chainsaw/rule/LevelInequalityRule.java
  
  Index: LevelInequalityRule.java
  ===================================================================
  RCS file: /home/cvs/jakarta-log4j/src/java/org/apache/log4j/chainsaw/rule/LevelInequalityRule.java,v
  retrieving revision 1.3
  retrieving revision 1.4
  diff -u -r1.3 -r1.4
  --- LevelInequalityRule.java	27 Oct 2003 08:22:15 -0000	1.3
  +++ LevelInequalityRule.java	9 Nov 2003 09:59:27 -0000	1.4
  @@ -65,16 +65,16 @@
    * 
    * @author Scott Deboy <sd...@apache.org>
    */
  -class LevelInequalityRule extends AbstractRule {
  -  LoggingEventFieldResolver resolver = LoggingEventFieldResolver.getInstance();
  -  Level levelFirstParam;
  -  String levelSecondParam;
  -  List utilList = new LinkedList();
  -  List levelList = new LinkedList();
  -  String inequalitySymbol;
  +public class LevelInequalityRule extends AbstractRule {
  +  private static final LoggingEventFieldResolver resolver = LoggingEventFieldResolver.getInstance();
  +  private final Level level;
  +  private final String value;
  +  private final List utilList = new LinkedList();
  +  private final List levelList = new LinkedList();
  +  private final String inequalitySymbol;
   
     private LevelInequalityRule(
  -    String inequalitySymbol, String levelFirstParam, String levelSecondParam) {
  +    String inequalitySymbol, String field, String value) {
       levelList.add(Level.FATAL.toString());
       levelList.add(Level.ERROR.toString());
       levelList.add(Level.WARN.toString());
  @@ -87,19 +87,23 @@
         utilList.add(((UtilLoggingLevel) iter.next()).toString());
       }
   
  -    if (levelList.contains(levelFirstParam)) {
  -      this.levelFirstParam = Level.toLevel(levelFirstParam);
  +    if (levelList.contains(value.toUpperCase())) {
  +      this.level = Level.toLevel(value.toUpperCase());
       } else {
  -      this.levelFirstParam = UtilLoggingLevel.toLevel(levelFirstParam);
  +      this.level = UtilLoggingLevel.toLevel(value.toUpperCase());
       }
   
       this.inequalitySymbol = inequalitySymbol;
  -    this.levelSecondParam = levelSecondParam;
  +    this.value = value;
     }
   
  +  public static Rule getRule(String inequalitySymbol, String field, String value) {
  +      return new LevelInequalityRule(inequalitySymbol, field, value);
  +  }
  +  
     public static Rule getRule(String inequalitySymbol, Stack stack) {
  -    String p1 = stack.pop().toString();
       String p2 = stack.pop().toString();
  +    String p1 = stack.pop().toString();
   
       return new LevelInequalityRule(inequalitySymbol, p1, p2);
     }
  @@ -107,12 +111,12 @@
     public boolean evaluate(LoggingEvent event) {
       //use the type of the first level to access the static toLevel method on the second param
       Level level2 =
  -      levelFirstParam.toLevel(
  -        resolver.getValue(levelSecondParam, event).toString());
  +      level.toLevel(
  +        resolver.getValue("LEVEL", event).toString());
   
       boolean result = false;
       int first = level2.toInt();
  -    int second = levelFirstParam.toInt();
  +    int second = level.toInt();
   
       if ("<".equals(inequalitySymbol)) {
         result = first < second;
  
  
  
  1.3       +12 -11    jakarta-log4j/src/java/org/apache/log4j/chainsaw/rule/AndRule.java
  
  Index: AndRule.java
  ===================================================================
  RCS file: /home/cvs/jakarta-log4j/src/java/org/apache/log4j/chainsaw/rule/AndRule.java,v
  retrieving revision 1.2
  retrieving revision 1.3
  diff -u -r1.2 -r1.3
  --- AndRule.java	27 Oct 2003 08:22:15 -0000	1.2
  +++ AndRule.java	9 Nov 2003 09:59:27 -0000	1.3
  @@ -53,14 +53,15 @@
   
   import java.util.Stack;
   
  +
   /**
  - * A Rule class implementing a logical 'and'. 
  - * 
  + * A Rule class implementing a logical 'and'.
  + *
    * @author Scott Deboy <sd...@apache.org>
    */
  -class AndRule extends AbstractRule {
  -  Rule firstParam;
  -  Rule secondParam;
  +public class AndRule extends AbstractRule {
  +  private final Rule firstParam;
  +  private final Rule secondParam;
   
     private AndRule(Rule firstParam, Rule secondParam) {
       this.firstParam = firstParam;
  @@ -68,17 +69,17 @@
     }
   
     public static Rule getRule(Stack stack) {
  -    Rule p1 = (Rule) stack.pop();
       Rule p2 = (Rule) stack.pop();
  +    Rule p1 = (Rule) stack.pop();
   
       return new AndRule(p1, p2);
     }
   
  -  public boolean evaluate(LoggingEvent event) {
  -
  -    boolean result =
  -      (firstParam.evaluate(event) && secondParam.evaluate(event));
  +  public static Rule getRule(Rule firstParam, Rule secondParam) {
  +    return new AndRule(firstParam, secondParam);
  +  }
   
  -    return result;
  +  public boolean evaluate(LoggingEvent event) {
  +    return (firstParam.evaluate(event) && secondParam.evaluate(event));
     }
   }
  
  
  
  1.4       +20 -20    jakarta-log4j/src/java/org/apache/log4j/chainsaw/rule/InequalityRule.java
  
  Index: InequalityRule.java
  ===================================================================
  RCS file: /home/cvs/jakarta-log4j/src/java/org/apache/log4j/chainsaw/rule/InequalityRule.java,v
  retrieving revision 1.3
  retrieving revision 1.4
  diff -u -r1.3 -r1.4
  --- InequalityRule.java	27 Oct 2003 08:22:15 -0000	1.3
  +++ InequalityRule.java	9 Nov 2003 09:59:27 -0000	1.4
  @@ -62,32 +62,32 @@
    *
    * @author Scott Deboy <sd...@apache.org>
    */
  -class InequalityRule extends AbstractRule {
  +public class InequalityRule extends AbstractRule {
     private static final String LEVEL = "LEVEL";
  -  LoggingEventFieldResolver resolver = LoggingEventFieldResolver.getInstance();
  -  String firstParam;
  -  String secondParam;
  -  String inequalitySymbol;
  +  private static final LoggingEventFieldResolver resolver = LoggingEventFieldResolver.getInstance();
  +  private final String field;
  +  private final String value;
  +  private final String inequalitySymbol;
   
     private InequalityRule(
  -    String inequalitySymbol, String firstParam, String secondParam) {
  +    String inequalitySymbol, String field, String value) {
       this.inequalitySymbol = inequalitySymbol;
  -    this.firstParam = firstParam;
  -    this.secondParam = secondParam;
  +    this.field = field;
  +    this.value = value;
     }
  -
  +  
     public static Rule getRule(String inequalitySymbol, Stack stack) {
  -    String p1 = stack.pop().toString();
  -    String p2 = stack.pop().toString();
  -
  -    if (p2.equalsIgnoreCase(LEVEL)) {
  +      String p2 = stack.pop().toString();
  +      String p1 = stack.pop().toString();
  +      return getRule(inequalitySymbol, p1, p2);
  +  }
  +  
  +  public static Rule getRule(String inequalitySymbol, String field, String value) {
  +    if (field.equalsIgnoreCase(LEVEL)) {
         //push the value back on the stack and allow the level-specific rule pop values
  -      stack.push(p2);
  -      stack.push(p1);
  -
  -      return LevelInequalityRule.getRule(inequalitySymbol, stack);
  +      return LevelInequalityRule.getRule(inequalitySymbol, field, value);
       } else {
  -      return new InequalityRule(inequalitySymbol, p1, p2);
  +      return new InequalityRule(inequalitySymbol, field, value);
       }
     }
   
  @@ -96,7 +96,7 @@
   
       try {
         first =
  -        new Long(resolver.getValue(secondParam, event).toString()).longValue();
  +        new Long(resolver.getValue(field, event).toString()).longValue();
       } catch (NumberFormatException nfe) {
         return false;
       }
  @@ -104,7 +104,7 @@
       long second = 0;
   
       try {
  -      second = new Long(firstParam).longValue();
  +      second = new Long(value).longValue();
       } catch (NumberFormatException nfe) {
         return false;
       }
  
  
  
  1.3       +15 -13    jakarta-log4j/src/java/org/apache/log4j/chainsaw/rule/NotEqualsRule.java
  
  Index: NotEqualsRule.java
  ===================================================================
  RCS file: /home/cvs/jakarta-log4j/src/java/org/apache/log4j/chainsaw/rule/NotEqualsRule.java,v
  retrieving revision 1.2
  retrieving revision 1.3
  diff -u -r1.2 -r1.3
  --- NotEqualsRule.java	27 Oct 2003 08:22:15 -0000	1.2
  +++ NotEqualsRule.java	9 Nov 2003 09:59:27 -0000	1.3
  @@ -59,28 +59,30 @@
    * 
    * @author Scott Deboy <sd...@apache.org>
    */
  -class NotEqualsRule extends AbstractRule {
  -  LoggingEventFieldResolver resolver = LoggingEventFieldResolver.getInstance();
  -  String firstParam;
  -  String secondParam;
  -
  -  private NotEqualsRule(String firstParam, String secondParam) {
  -    this.firstParam = firstParam;
  -    this.secondParam = secondParam;
  +public class NotEqualsRule extends AbstractRule {
  +  private static final LoggingEventFieldResolver resolver = LoggingEventFieldResolver.getInstance();
  +  private final String field;
  +  private final String value;
  +
  +  private NotEqualsRule(String field, String value) {
  +    this.field = field;
  +    this.value = value;
     }
   
  +  public static Rule getRule(String field, String value) {
  +      return new NotEqualsRule(field, value);
  +  }
  +  
     public static Rule getRule(Stack stack) {
  -    String p1 = stack.pop().toString();
       String p2 = stack.pop().toString();
  +    String p1 = stack.pop().toString();
   
       return new NotEqualsRule(p1, p2);
     }
   
     public boolean evaluate(LoggingEvent event) {
  -    String p2 = resolver.getValue(secondParam, event).toString();
  -
  -    boolean result = ((p2 != null) && !(p2.equals(firstParam)));
  +    String p2 = resolver.getValue(field, event).toString();
   
  -    return result;
  +    return ((p2 != null) && !(p2.equals(value)));
     }
   }
  
  
  
  1.5       +11 -4     jakarta-log4j/src/java/org/apache/log4j/chainsaw/rule/RuleFactory.java
  
  Index: RuleFactory.java
  ===================================================================
  RCS file: /home/cvs/jakarta-log4j/src/java/org/apache/log4j/chainsaw/rule/RuleFactory.java,v
  retrieving revision 1.4
  retrieving revision 1.5
  diff -u -r1.4 -r1.5
  --- RuleFactory.java	29 Oct 2003 08:50:36 -0000	1.4
  +++ RuleFactory.java	9 Nov 2003 09:59:27 -0000	1.5
  @@ -59,8 +59,9 @@
    * 
    * @author Scott Deboy <sd...@apache.org>
    */
  -class RuleFactory {
  -  static final Collection rules = new LinkedList();
  +public class RuleFactory {
  +  private static final RuleFactory factory_ = new RuleFactory(); 
  +  private static final Collection rules = new LinkedList();
     private static final String AND_RULE = "&&";
     private static final String OR_RULE = "||";
     private static final String NOT_RULE = "!";
  @@ -86,11 +87,17 @@
       rules.add(GREATER_THAN_EQUALS_RULE);
     }
   
  -  static boolean isRule(String symbol) {
  +  private RuleFactory() {}
  +  
  +  public static RuleFactory getInstance() {
  +      return factory_;
  +  }
  +  
  +  public boolean isRule(String symbol) {
       return ((symbol != null) && (rules.contains(symbol.toLowerCase())));
     }
   
  -  static Rule getRule(String symbol, Stack stack) {
  +  public Rule getRule(String symbol, Stack stack) {
       if (AND_RULE.equals(symbol)) {
         return AndRule.getRule(stack);
       }
  
  
  
  1.3       +8 -7      jakarta-log4j/src/java/org/apache/log4j/chainsaw/rule/NotRule.java
  
  Index: NotRule.java
  ===================================================================
  RCS file: /home/cvs/jakarta-log4j/src/java/org/apache/log4j/chainsaw/rule/NotRule.java,v
  retrieving revision 1.2
  retrieving revision 1.3
  diff -u -r1.2 -r1.3
  --- NotRule.java	27 Oct 2003 08:22:15 -0000	1.2
  +++ NotRule.java	9 Nov 2003 09:59:27 -0000	1.3
  @@ -58,13 +58,17 @@
    * 
    * @author Scott Deboy <sd...@apache.org>
    */
  -class NotRule extends AbstractRule {
  -  Rule firstParam;
  +public class NotRule extends AbstractRule {
  +  private final Rule rule;
   
     private NotRule(Rule firstParam) {
  -    this.firstParam = firstParam;
  +    this.rule = firstParam;
     }
   
  +  public static Rule getRule(Rule rule) {
  +      return new NotRule(rule);
  +  }
  +  
     public static Rule getRule(Stack stack) {
       Rule p1 = (Rule) stack.pop();
   
  @@ -72,9 +76,6 @@
     }
   
     public boolean evaluate(LoggingEvent event) {
  -
  -    boolean result = !(firstParam.evaluate(event));
  -
  -    return result;
  +    return !(rule.evaluate(event));
     }
   }
  
  
  
  1.16      +2 -267    jakarta-log4j/src/java/org/apache/log4j/chainsaw/rule/RuleTest.java
  
  Index: RuleTest.java
  ===================================================================
  RCS file: /home/cvs/jakarta-log4j/src/java/org/apache/log4j/chainsaw/rule/RuleTest.java,v
  retrieving revision 1.15
  retrieving revision 1.16
  diff -u -r1.15 -r1.16
  --- RuleTest.java	2 Nov 2003 19:53:48 -0000	1.15
  +++ RuleTest.java	9 Nov 2003 09:59:27 -0000	1.16
  @@ -59,26 +59,17 @@
   
   import java.awt.BorderLayout;
   import java.awt.GridLayout;
  -import java.awt.Point;
   import java.awt.event.ActionEvent;
  -import java.awt.event.KeyAdapter;
  -import java.awt.event.KeyEvent;
  -import java.awt.event.MouseAdapter;
  -import java.awt.event.MouseEvent;
   
   import java.util.ArrayList;
   import java.util.Iterator;
   import java.util.List;
   
   import javax.swing.AbstractAction;
  -import javax.swing.DefaultListModel;
   import javax.swing.JButton;
   import javax.swing.JFrame;
   import javax.swing.JLabel;
  -import javax.swing.JList;
   import javax.swing.JPanel;
  -import javax.swing.JPopupMenu;
  -import javax.swing.JScrollPane;
   import javax.swing.JTextArea;
   import javax.swing.JTextField;
   import javax.swing.WindowConstants;
  @@ -151,7 +142,8 @@
       final JTextField inFixTextField = new JTextField(inFixText);
       fieldPanel.add(inFixTextField);
   
  -    ContextListener listener = new ContextListener(inFixTextField);
  +    ExpressionRuleContext listener =
  +      new ExpressionRuleContext(filterModel, inFixTextField);
       inFixTextField.addKeyListener(listener);
   
       JButton inFixButton = new JButton("Convert InFix to PostFix");
  @@ -225,262 +217,5 @@
           "( level ~= deb ) && ( logger like logger[1-2] || MDC.entry1 >= 234 )");
       test.pack();
       test.setVisible(true);
  -  }
  -
  -  class ContextListener extends KeyAdapter {
  -    LoggingEventFieldResolver resolver =
  -      LoggingEventFieldResolver.getInstance();
  -    String lastField = null;
  -    JPopupMenu contextMenu = new JPopupMenu();
  -    JList list = new JList();
  - 
  -    JScrollPane scrollPane = new JScrollPane(list);
  -    final JTextField textField;
  -    private DefaultListModel fieldModel = new DefaultListModel();
  -    private DefaultListModel operatorModel = new DefaultListModel();
  -
  -    public ContextListener(final JTextField textField) {
  -      this.textField = textField;
  -      fieldModel.addElement("LOGGER");
  -      fieldModel.addElement("LEVEL");
  -      fieldModel.addElement("CLASS");
  -      fieldModel.addElement("FILE");
  -      fieldModel.addElement("LINE");
  -      fieldModel.addElement("METHOD");
  -      fieldModel.addElement("MSG");
  -      fieldModel.addElement("NDC");
  -      fieldModel.addElement("EXCEPTION");
  -      fieldModel.addElement("TIMESTAMP");
  -      fieldModel.addElement("THREAD");
  -      fieldModel.addElement("MDC");
  -      fieldModel.addElement("PROP");
  -
  -      operatorModel.addElement("&&");
  -      operatorModel.addElement("||");
  -      operatorModel.addElement("!");
  -      operatorModel.addElement("!=");
  -      operatorModel.addElement("==");
  -      operatorModel.addElement("~=");
  -      operatorModel.addElement("LIKE");
  -      operatorModel.addElement("<");
  -      operatorModel.addElement(">");
  -      operatorModel.addElement("<=");
  -      operatorModel.addElement(">=");
  -
  -      //make as large as operator list to avoid narrow list scrollbar issues
  -      list.setVisibleRowCount(11);
  -
  -      PopupListener popupListener = new PopupListener();
  -      textField.addMouseListener(popupListener);
  -
  -      list.addKeyListener(
  -        new KeyAdapter() {
  -          public void keyPressed(KeyEvent e) {
  -            if (e.getKeyCode() == KeyEvent.VK_ENTER) {
  -              updateField(list.getSelectedValue().toString());
  -              contextMenu.setVisible(false);
  -            }
  -          }
  -        });
  -
  -      list.addMouseListener(
  -        new MouseAdapter() {
  -          public void mouseClicked(MouseEvent e) {
  -            if (e.getClickCount() == 2) {
  -              updateField(list.getSelectedValue().toString());
  -              contextMenu.setVisible(false);
  -            }
  -          }
  -        });
  -
  -      contextMenu.insert(scrollPane, 0);
  -    }
  -
  -    private void updateField(String value) {
  -      String text = textField.getText();
  -      int startPosition = textField.getSelectionStart();
  -      int endPosition = textField.getSelectionEnd();
  -      String spacer = "";
  -
  -      if (startPosition == endPosition) {
  -        spacer = " ";
  -      }
  -
  -      textField.setText(
  -        text.substring(0, startPosition) + value + spacer
  -        + text.substring(endPosition));
  -      textField.setCaretPosition(
  -        startPosition + value.length() + spacer.length());
  -    }
  -
  -    public void keyPressed(KeyEvent e) {
  -      if (
  -        (e.getKeyCode() == KeyEvent.VK_SPACE)
  -          && (e.getModifiers() == KeyEvent.CTRL_MASK)) {
  -        displayContext();
  -      }
  -    }
  -
  -    public void displayContext() {
  -      String lastField = getContextKey();
  -
  -      if (lastField != null) {
  -        list.setModel(filterModel.getContainer().getModel(lastField));
  -        list.setSelectedIndex(0);
  -
  -        Point p = textField.getCaret().getMagicCaretPosition();
  -
  -        contextMenu.show(textField, p.x, (p.y + (textField.getHeight() - 5)));
  -        list.requestFocus();
  -      } else {
  -        if (isOperatorContextValid()) {
  -          list.setModel(operatorModel);
  -          list.setSelectedIndex(0);
  -
  -          Point p = textField.getCaret().getMagicCaretPosition();
  -          contextMenu.show(
  -            textField, p.x, (p.y + (textField.getHeight() - 5)));
  -          list.requestFocus();
  -        } else if (isFieldContextValid()) {
  -          list.setModel(fieldModel);
  -          list.setSelectedIndex(0);
  -
  -          Point p = textField.getCaret().getMagicCaretPosition();
  -
  -          if (p == null) {
  -            p = new Point(
  -                textField.getLocation().x,
  -                (textField.getLocation().y - textField.getHeight() + 5));
  -          }
  -
  -          contextMenu.show(
  -            textField, p.x, (p.y + (textField.getHeight() - 5)));
  -          list.requestFocus();
  -        }
  -      }
  -    }
  -
  -    private boolean isFieldContextValid() {
  -      String text = textField.getText();
  -      int currentPosition = textField.getSelectionStart();
  -
  -      return ((currentPosition == 0)
  -      || (text.charAt(currentPosition - 1) == ' '));
  -    }
  -
  -    private String getContextKey() {
  -      String field = getField();
  -
  -      if (field == null) {
  -        field = getSubField();
  -      }
  -
  -      return field;
  -    }
  -
  -    private boolean isOperatorContextValid() {
  -      String text = textField.getText();
  -
  -      int currentPosition = textField.getSelectionStart();
  -
  -      if ((currentPosition < 1) || (text.charAt(currentPosition - 1) != ' ')) {
  -        return false;
  -      }
  -
  -      int lastFieldPosition = text.lastIndexOf(" ", currentPosition - 1);
  -
  -      if (lastFieldPosition == -1) {
  -        return false;
  -      }
  -
  -      int lastFieldStartPosition =
  -        Math.max(0, text.lastIndexOf(" ", lastFieldPosition - 1));
  -      String field =
  -        text.substring(lastFieldStartPosition, lastFieldPosition).toUpperCase()
  -            .trim();
  -
  -      if (field.startsWith("MDC.")) {
  -        return true;
  -      }
  -
  -      if (resolver.isField(field)) {
  -        return true;
  -      }
  -
  -      return false;
  -    }
  -
  -    //returns the currently active field which can be used to display a context menu
  -    //the field returned is the left hand portion of an expression (for example, logger == )
  -    //logger is the field that is returned
  -    private String getField() {
  -      String text = textField.getText();
  -
  -      int currentPosition = textField.getSelectionStart();
  -
  -      if ((currentPosition < 1) || (text.charAt(currentPosition - 1) != ' ')) {
  -        return null;
  -      }
  -
  -      int symbolPosition = text.lastIndexOf(" ", currentPosition - 1);
  -
  -      if (symbolPosition < 0) {
  -        return null;
  -      }
  -
  -      int lastFieldPosition = text.lastIndexOf(" ", symbolPosition - 1);
  -
  -      if (lastFieldPosition < 0) {
  -        return null;
  -      }
  -
  -      int lastFieldStartPosition =
  -        Math.max(0, text.lastIndexOf(" ", lastFieldPosition - 1));
  -      String lastSymbol =
  -        text.substring(lastFieldPosition + 1, symbolPosition).trim();
  -
  -      String lastField =
  -        text.substring(lastFieldStartPosition, lastFieldPosition).trim();
  -
  -      if (
  -        RuleFactory.isRule(lastSymbol)
  -          && filterModel.getContainer().modelExists(lastField)) {
  -        return lastField;
  -      }
  -
  -      return null;
  -    }
  -
  -    //subfields allow the key portion of a field to provide context menu support
  -    //and are available after the fieldname and a . (for example, MDC.)
  -    private String getSubField() {
  -      int currentPosition = textField.getSelectionStart();
  -      String text = textField.getText();
  -
  -      if (text.substring(0, currentPosition).toUpperCase().endsWith("MDC.")) {
  -        return "MDC";
  -      }
  -
  -      return null;
  -    }
  -
  -    class PopupListener extends MouseAdapter {
  -      PopupListener() {
  -      }
  -
  -      public void mousePressed(MouseEvent e) {
  -        checkPopup(e);
  -      }
  -
  -      public void mouseReleased(MouseEvent e) {
  -        checkPopup(e);
  -      }
  -
  -      private void checkPopup(MouseEvent e) {
  -        if (e.isPopupTrigger()) {
  -          displayContext();
  -        }
  -      }
  -    }
     }
   }
  
  
  
  1.3       +15 -14    jakarta-log4j/src/java/org/apache/log4j/chainsaw/rule/EqualsRule.java
  
  Index: EqualsRule.java
  ===================================================================
  RCS file: /home/cvs/jakarta-log4j/src/java/org/apache/log4j/chainsaw/rule/EqualsRule.java,v
  retrieving revision 1.2
  retrieving revision 1.3
  diff -u -r1.2 -r1.3
  --- EqualsRule.java	27 Oct 2003 08:22:15 -0000	1.2
  +++ EqualsRule.java	9 Nov 2003 09:59:27 -0000	1.3
  @@ -60,28 +60,29 @@
    * @author Scott Deboy <sd...@apache.org>
    */
   
  -class EqualsRule extends AbstractRule {
  -  LoggingEventFieldResolver resolver = LoggingEventFieldResolver.getInstance();
  -  String firstParam;
  -  String secondParam;
  -
  -  private EqualsRule(String firstParam, String secondParam) {
  -    this.firstParam = firstParam;
  -    this.secondParam = secondParam;
  +public class EqualsRule extends AbstractRule {
  +  private static final LoggingEventFieldResolver resolver = LoggingEventFieldResolver.getInstance();
  +  private final String value;
  +  private final String field;
  +
  +  private EqualsRule(String field, String value) {
  +    this.field = field;
  +    this.value = value;
     }
   
     public static Rule getRule(Stack stack) {
  -    String p1 = stack.pop().toString();
       String p2 = stack.pop().toString();
  +    String p1 = stack.pop().toString();
   
       return new EqualsRule(p1, p2);
     }
  +  
  +  public static Rule getRule(String p1, String p2) {
  +      return new EqualsRule(p1, p2);
  +  }
   
     public boolean evaluate(LoggingEvent event) {
  -    String p2 = resolver.getValue(secondParam, event).toString();
  -
  -    boolean result = ((p2 != null) && p2.equals(firstParam));
  -
  -    return result;
  +    String p2 = resolver.getValue(field, event).toString();
  +    return ((p2 != null) && p2.equals(value));
     }
   }
  
  
  
  1.3       +16 -15    jakarta-log4j/src/java/org/apache/log4j/chainsaw/rule/PartialTextMatchRule.java
  
  Index: PartialTextMatchRule.java
  ===================================================================
  RCS file: /home/cvs/jakarta-log4j/src/java/org/apache/log4j/chainsaw/rule/PartialTextMatchRule.java,v
  retrieving revision 1.2
  retrieving revision 1.3
  diff -u -r1.2 -r1.3
  --- PartialTextMatchRule.java	27 Oct 2003 08:22:15 -0000	1.2
  +++ PartialTextMatchRule.java	9 Nov 2003 09:59:27 -0000	1.3
  @@ -59,30 +59,31 @@
    * 
    * @author Scott Deboy <sd...@apache.org>
    */
  -class PartialTextMatchRule extends AbstractRule {
  -  LoggingEventFieldResolver resolver = LoggingEventFieldResolver.getInstance();
  -  String firstParam;
  -  String secondParam;
  -
  -  private PartialTextMatchRule(String firstParam, String secondParam) {
  -    this.firstParam = firstParam;
  -    this.secondParam = secondParam;
  +public class PartialTextMatchRule extends AbstractRule {
  +  private static final LoggingEventFieldResolver resolver = LoggingEventFieldResolver.getInstance();
  +  private final String field;
  +  private final String value;
  +
  +  private PartialTextMatchRule(String field, String value) {
  +    this.field = field;
  +    this.value = value;
  +  }
  +  
  +  public static Rule getRule(String field, String value) {
  +      return new PartialTextMatchRule(field, value);
     }
   
     public static Rule getRule(Stack stack) {
  -    String p1 = stack.pop().toString();
       String p2 = stack.pop().toString();
  +    String p1 = stack.pop().toString();
   
       return new PartialTextMatchRule(p1, p2);
     }
   
     public boolean evaluate(LoggingEvent event) {
  -    String p2 = resolver.getValue(secondParam, event).toString();
  -
  -    boolean result =
  -      (((p2 != null) && (firstParam != null))
  -      && (p2.toLowerCase().indexOf(firstParam.toLowerCase()) > -1));
  +    String p2 = resolver.getValue(field, event).toString();
   
  -    return result;
  +    return (((p2 != null) && (value != null))
  +      && (p2.toLowerCase().indexOf(value.toLowerCase()) > -1));
     }
   }
  
  
  
  1.1                  jakarta-log4j/src/java/org/apache/log4j/chainsaw/rule/ColorRule.java
  
  Index: ColorRule.java
  ===================================================================
  /*
   * ============================================================================
   *                   The Apache Software License, Version 1.1
   * ============================================================================
   *
   *    Copyright (C) 1999 The Apache Software Foundation. All rights reserved.
   *
   * Redistribution and use in source and binary forms, with or without modifica-
   * tion, are permitted provided that the following conditions are met:
   *
   * 1. Redistributions of  source code must  retain the above copyright  notice,
   *    this list of conditions and the following disclaimer.
   *
   * 2. Redistributions in binary form must reproduce the above copyright notice,
   *    this list of conditions and the following disclaimer in the documentation
   *    and/or other materials provided with the distribution.
   *
   * 3. The end-user documentation included with the redistribution, if any, must
   *    include  the following  acknowledgment:  "This product includes  software
   *    developed  by the  Apache Software Foundation  (http://www.apache.org/)."
   *    Alternately, this  acknowledgment may  appear in the software itself,  if
   *    and wherever such third-party acknowledgments normally appear.
   *
   * 4. The names "log4j" and  "Apache Software Foundation"  must not be used to
   *    endorse  or promote  products derived  from this  software without  prior
   *    written permission. For written permission, please contact
   *    apache@apache.org.
   *
   * 5. Products  derived from this software may not  be called "Apache", nor may
   *    "Apache" appear  in their name,  without prior written permission  of the
   *    Apache Software Foundation.
   *
   * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES,
   * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
   * FITNESS  FOR A PARTICULAR  PURPOSE ARE  DISCLAIMED.  IN NO  EVENT SHALL  THE
   * APACHE SOFTWARE  FOUNDATION  OR ITS CONTRIBUTORS  BE LIABLE FOR  ANY DIRECT,
   * INDIRECT, INCIDENTAL, SPECIAL,  EXEMPLARY, OR CONSEQUENTIAL  DAMAGES (INCLU-
   * DING, BUT NOT LIMITED TO, PROCUREMENT  OF SUBSTITUTE GOODS OR SERVICES; LOSS
   * OF USE, DATA, OR  PROFITS; OR BUSINESS  INTERRUPTION)  HOWEVER CAUSED AND ON
   * ANY  THEORY OF LIABILITY,  WHETHER  IN CONTRACT,  STRICT LIABILITY,  OR TORT
   * (INCLUDING  NEGLIGENCE OR  OTHERWISE) ARISING IN  ANY WAY OUT OF THE  USE OF
   * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
   *
   * This software  consists of voluntary contributions made  by many individuals
   * on  behalf of the Apache Software  Foundation.  For more  information on the
   * Apache Software Foundation, please see <http://www.apache.org/>.
   *
   */
  
  package org.apache.log4j.chainsaw.rule;
  
  import org.apache.log4j.spi.LoggingEvent;
  
  import java.awt.Color;
  
  
  /**
   * A Rule class which also holds a color
   *
   * @author Scott Deboy <sd...@apache.org>
   */
  public class ColorRule extends AbstractRule {
    private final Rule rule;
    private final Color foregroundColor;
    private final Color backgroundColor;
  
    public ColorRule(Rule rule, Color backgroundColor) {
      this(rule, backgroundColor, null);
    }
  
    public ColorRule(Rule rule, Color backgroundColor, Color foregroundColor) {
      this.rule = rule;
      this.backgroundColor = backgroundColor;
      this.foregroundColor = foregroundColor;
    }
  
    public Color getForegroundColor() {
      return foregroundColor;
    }
  
    public Color getBackgroundColor() {
      return backgroundColor;
    }
  
    public boolean evaluate(LoggingEvent event) {
      return rule.evaluate(event);
    }
  }
  
  
  
  1.1                  jakarta-log4j/src/java/org/apache/log4j/chainsaw/rule/ExpressionRuleContext.java
  
  Index: ExpressionRuleContext.java
  ===================================================================
  /*
   * ============================================================================
   *                   The Apache Software License, Version 1.1
   * ============================================================================
   *
   *    Copyright (C) 1999 The Apache Software Foundation. All rights reserved.
   *
   * Redistribution and use in source and binary forms, with or without modifica-
   * tion, are permitted provided that the following conditions are met:
   *
   * 1. Redistributions of  source code must  retain the above copyright  notice,
   *    this list of conditions and the following disclaimer.
   *
   * 2. Redistributions in binary form must reproduce the above copyright notice,
   *    this list of conditions and the following disclaimer in the documentation
   *    and/or other materials provided with the distribution.
   *
   * 3. The end-user documentation included with the redistribution, if any, must
   *    include  the following  acknowledgment:  "This product includes  software
   *    developed  by the  Apache Software Foundation  (http://www.apache.org/)."
   *    Alternately, this  acknowledgment may  appear in the software itself,  if
   *    and wherever such third-party acknowledgments normally appear.
   *
   * 4. The names "log4j" and  "Apache Software Foundation"  must not be used to
   *    endorse  or promote  products derived  from this  software without  prior
   *    written permission. For written permission, please contact
   *    apache@apache.org.
   *
   * 5. Products  derived from this software may not  be called "Apache", nor may
   *    "Apache" appear  in their name,  without prior written permission  of the
   *    Apache Software Foundation.
   *
   * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES,
   * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
   * FITNESS  FOR A PARTICULAR  PURPOSE ARE  DISCLAIMED.  IN NO  EVENT SHALL  THE
   * APACHE SOFTWARE  FOUNDATION  OR ITS CONTRIBUTORS  BE LIABLE FOR  ANY DIRECT,
   * INDIRECT, INCIDENTAL, SPECIAL,  EXEMPLARY, OR CONSEQUENTIAL  DAMAGES (INCLU-
   * DING, BUT NOT LIMITED TO, PROCUREMENT  OF SUBSTITUTE GOODS OR SERVICES; LOSS
   * OF USE, DATA, OR  PROFITS; OR BUSINESS  INTERRUPTION)  HOWEVER CAUSED AND ON
   * ANY  THEORY OF LIABILITY,  WHETHER  IN CONTRACT,  STRICT LIABILITY,  OR TORT
   * (INCLUDING  NEGLIGENCE OR  OTHERWISE) ARISING IN  ANY WAY OUT OF THE  USE OF
   * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
   *
   * This software  consists of voluntary contributions made  by many individuals
   * on  behalf of the Apache Software  Foundation.  For more  information on the
   * Apache Software Foundation, please see <http://www.apache.org/>.
   *
   */
  
  package org.apache.log4j.chainsaw.rule;
  
  import org.apache.log4j.chainsaw.LoggingEventFieldResolver;
  import org.apache.log4j.chainsaw.filter.FilterModel;
  
  import java.awt.Point;
  import java.awt.event.KeyAdapter;
  import java.awt.event.KeyEvent;
  import java.awt.event.MouseAdapter;
  import java.awt.event.MouseEvent;
  
  import javax.swing.DefaultListModel;
  import javax.swing.JList;
  import javax.swing.JPopupMenu;
  import javax.swing.JScrollPane;
  import javax.swing.JTextField;
  
  /**
   * A popup menu which assists in building expression rules.  Completes event keywords, operators and 
   * context if available.
   * 
   * @author Scott Deboy <sd...@apache.org>
   */
  public class ExpressionRuleContext extends KeyAdapter {
    RuleFactory factory = RuleFactory.getInstance();
    LoggingEventFieldResolver resolver = LoggingEventFieldResolver.getInstance();
    String lastField = null;
    JPopupMenu contextMenu = new JPopupMenu();
    JList list = new JList();
    FilterModel filterModel;
    JScrollPane scrollPane = new JScrollPane(list);
    final JTextField textField;
    private DefaultListModel fieldModel = new DefaultListModel();
    private DefaultListModel operatorModel = new DefaultListModel();
  
    public ExpressionRuleContext(
      final FilterModel filterModel, final JTextField textField) {
      this.filterModel = filterModel;
      this.textField = textField;
      fieldModel.addElement("LOGGER");
      fieldModel.addElement("LEVEL");
      fieldModel.addElement("CLASS");
      fieldModel.addElement("FILE");
      fieldModel.addElement("LINE");
      fieldModel.addElement("METHOD");
      fieldModel.addElement("MSG");
      fieldModel.addElement("NDC");
      fieldModel.addElement("EXCEPTION");
      fieldModel.addElement("TIMESTAMP");
      fieldModel.addElement("THREAD");
      fieldModel.addElement("MDC");
      fieldModel.addElement("PROP");
  
      operatorModel.addElement("&&");
      operatorModel.addElement("||");
      operatorModel.addElement("!");
      operatorModel.addElement("!=");
      operatorModel.addElement("==");
      operatorModel.addElement("~=");
      operatorModel.addElement("LIKE");
      operatorModel.addElement("<");
      operatorModel.addElement(">");
      operatorModel.addElement("<=");
      operatorModel.addElement(">=");
  
      //make as large as operator list to avoid narrow list scrollbar issues
      list.setVisibleRowCount(11);
  
      PopupListener popupListener = new PopupListener();
      textField.addMouseListener(popupListener);
  
      list.addKeyListener(
        new KeyAdapter() {
          public void keyPressed(KeyEvent e) {
            if (e.getKeyCode() == KeyEvent.VK_ENTER) {
              updateField(list.getSelectedValue().toString());
              contextMenu.setVisible(false);
            }
          }
        });
  
      list.addMouseListener(
        new MouseAdapter() {
          public void mouseClicked(MouseEvent e) {
            if (e.getClickCount() == 2) {
              updateField(list.getSelectedValue().toString());
              contextMenu.setVisible(false);
            }
          }
        });
  
      contextMenu.insert(scrollPane, 0);
    }
  
    private void updateField(String value) {
      String text = textField.getText();
  
      if (textField.getSelectedText() == null) {
        value = value + " ";
      }
  
      textField.replaceSelection(value);
    }
  
    public void keyPressed(KeyEvent e) {
      if (
        (e.getKeyCode() == KeyEvent.VK_SPACE)
          && (e.getModifiers() == KeyEvent.CTRL_MASK)) {
        displayContext();
      }
    }
  
    public void displayContext() {
      String lastField = getContextKey();
  
      if (lastField != null) {
        list.setModel(filterModel.getContainer().getModel(lastField));
        list.setSelectedIndex(0);
  
        Point p = textField.getCaret().getMagicCaretPosition();
  
        contextMenu.show(textField, p.x, (p.y + (textField.getHeight() - 5)));
        list.requestFocus();
      } else {
        if (isOperatorContextValid()) {
          list.setModel(operatorModel);
          list.setSelectedIndex(0);
  
          Point p = textField.getCaret().getMagicCaretPosition();
          contextMenu.show(textField, p.x, (p.y + (textField.getHeight() - 5)));
          list.requestFocus();
        } else if (isFieldContextValid()) {
          list.setModel(fieldModel);
          list.setSelectedIndex(0);
  
          Point p = textField.getCaret().getMagicCaretPosition();
  
          if (p == null) {
            p = new Point(
                textField.getLocation().x,
                (textField.getLocation().y - textField.getHeight() + 5));
          }
  
          contextMenu.show(textField, p.x, (p.y + (textField.getHeight() - 5)));
          list.requestFocus();
        }
      }
    }
  
    private boolean isFieldContextValid() {
      String text = textField.getText();
      int currentPosition = textField.getSelectionStart();
  
      return ((currentPosition == 0)
      || (text.charAt(currentPosition - 1) == ' '));
    }
  
    private String getContextKey() {
      String field = getField();
  
      if (field == null) {
        field = getSubField();
      }
  
      return field;
    }
  
    private boolean isOperatorContextValid() {
      String text = textField.getText();
  
      int currentPosition = textField.getSelectionStart();
  
      if ((currentPosition < 1) || (text.charAt(currentPosition - 1) != ' ')) {
        return false;
      }
  
      int lastFieldPosition = text.lastIndexOf(" ", currentPosition - 1);
  
      if (lastFieldPosition == -1) {
        return false;
      }
  
      int lastFieldStartPosition =
        Math.max(0, text.lastIndexOf(" ", lastFieldPosition - 1));
      String field =
        text.substring(lastFieldStartPosition, lastFieldPosition).toUpperCase()
            .trim();
  
      if (field.startsWith("MDC.")) {
        return true;
      }
  
      if (resolver.isField(field)) {
        return true;
      }
  
      return false;
    }
  
    //returns the currently active field which can be used to display a context menu
    //the field returned is the left hand portion of an expression (for example, logger == )
    //logger is the field that is returned
    private String getField() {
      String text = textField.getText();
  
      int currentPosition = textField.getSelectionStart();
  
      if ((currentPosition < 1) || (text.charAt(currentPosition - 1) != ' ')) {
        return null;
      }
  
      int symbolPosition = text.lastIndexOf(" ", currentPosition - 1);
  
      if (symbolPosition < 0) {
        return null;
      }
  
      int lastFieldPosition = text.lastIndexOf(" ", symbolPosition - 1);
  
      if (lastFieldPosition < 0) {
        return null;
      }
  
      int lastFieldStartPosition =
        Math.max(0, text.lastIndexOf(" ", lastFieldPosition - 1));
      String lastSymbol =
        text.substring(lastFieldPosition + 1, symbolPosition).trim();
  
      String lastField =
        text.substring(lastFieldStartPosition, lastFieldPosition).trim();
  
      if (
        factory.isRule(lastSymbol)
          && filterModel.getContainer().modelExists(lastField)) {
        return lastField;
      }
  
      return null;
    }
  
    //subfields allow the key portion of a field to provide context menu support
    //and are available after the fieldname and a . (for example, MDC.)
    private String getSubField() {
      int currentPosition = textField.getSelectionStart();
      String text = textField.getText();
  
      if (text.substring(0, currentPosition).toUpperCase().endsWith("MDC.")) {
        return "MDC";
      }
  
      return null;
    }
  
    class PopupListener extends MouseAdapter {
      PopupListener() {
      }
  
      public void mousePressed(MouseEvent e) {
        checkPopup(e);
      }
  
      public void mouseReleased(MouseEvent e) {
        checkPopup(e);
      }
  
      private void checkPopup(MouseEvent e) {
        if (e.isPopupTrigger()) {
          displayContext();
        }
      }
    }
  }
  
  
  
  1.6       +6 -3      jakarta-log4j/src/java/org/apache/log4j/chainsaw/WelcomePanel.java
  
  Index: WelcomePanel.java
  ===================================================================
  RCS file: /home/cvs/jakarta-log4j/src/java/org/apache/log4j/chainsaw/WelcomePanel.java,v
  retrieving revision 1.5
  retrieving revision 1.6
  diff -u -r1.5 -r1.6
  --- WelcomePanel.java	22 Sep 2003 07:01:23 -0000	1.5
  +++ WelcomePanel.java	9 Nov 2003 09:59:28 -0000	1.6
  @@ -49,12 +49,17 @@
   
   package org.apache.log4j.chainsaw;
   
  +import org.apache.log4j.chainsaw.icons.ChainsawIcons;
  +
   import java.awt.BorderLayout;
   import java.awt.Color;
   import java.awt.Dimension;
   import java.awt.event.ActionEvent;
  +
   import java.io.IOException;
  +
   import java.net.URL;
  +
   import java.util.Stack;
   
   import javax.swing.AbstractAction;
  @@ -70,8 +75,6 @@
   import javax.swing.event.HyperlinkEvent;
   import javax.swing.event.HyperlinkListener;
   
  -import org.apache.log4j.chainsaw.icons.ChainsawIcons;
  -
   
   /**
    * An initial Welcome Panel that is used when Chainsaw starts up, displays
  @@ -91,7 +94,7 @@
     private LogUI logui;
   
     public WelcomePanel(LogUI logui) {
  -    setLayout(new BorderLayout());
  +    super(new BorderLayout());
       this.logui = logui;
       setBackground(Color.white);
       add(urlToolbar, BorderLayout.NORTH);
  
  
  
  1.2       +3 -2      jakarta-log4j/src/java/org/apache/log4j/chainsaw/ChainsawSplash.java
  
  Index: ChainsawSplash.java
  ===================================================================
  RCS file: /home/cvs/jakarta-log4j/src/java/org/apache/log4j/chainsaw/ChainsawSplash.java,v
  retrieving revision 1.1
  retrieving revision 1.2
  diff -u -r1.1 -r1.2
  --- ChainsawSplash.java	25 Jun 2003 04:05:22 -0000	1.1
  +++ ChainsawSplash.java	9 Nov 2003 09:59:28 -0000	1.2
  @@ -57,6 +57,7 @@
   import java.awt.Color;
   import java.awt.Container;
   import java.awt.Font;
  +import java.awt.Frame;
   import java.awt.GraphicsEnvironment;
   import java.util.HashSet;
   import java.util.Set;
  @@ -75,8 +76,8 @@
    *
    */
   class ChainsawSplash extends JWindow {
  -  ChainsawSplash() {
  -    super();
  +  ChainsawSplash(Frame owner) {
  +    super(owner);
   
       Container container = getContentPane();
       JPanel panel = new JPanel(new BorderLayout());
  
  
  
  1.19      +28 -8     jakarta-log4j/src/java/org/apache/log4j/chainsaw/ChainsawToolBarAndMenus.java
  
  Index: ChainsawToolBarAndMenus.java
  ===================================================================
  RCS file: /home/cvs/jakarta-log4j/src/java/org/apache/log4j/chainsaw/ChainsawToolBarAndMenus.java,v
  retrieving revision 1.18
  retrieving revision 1.19
  diff -u -r1.18 -r1.19
  --- ChainsawToolBarAndMenus.java	9 Oct 2003 04:05:46 -0000	1.18
  +++ ChainsawToolBarAndMenus.java	9 Nov 2003 09:59:28 -0000	1.19
  @@ -47,12 +47,6 @@
    *
    */
   
  -/*
  - * Created on May 3, 2003
  - *
  - * To change the template for this generated file go to
  - * Window>Preferences>Java>Code Generation>Code and Comments
  - */
   package org.apache.log4j.chainsaw;
   
   import org.apache.log4j.chainsaw.icons.ChainsawIcons;
  @@ -123,6 +117,7 @@
     private final Action lockToolbarAction;
     private final Action pauseAction;
     private final Action showPreferencesAction;
  +  private final Action showColorPanelAction;
     private final Action showReceiversAction;
     private final Action toggleLogTreeAction;
     private final Action toggleDetailPaneAction;
  @@ -176,6 +171,7 @@
       findTextField = createFindField();
       findNextAction = setupFindFieldsAndActions();
       showPreferencesAction = createShowPreferencesAction();
  +    showColorPanelAction = createShowColorPanelAction();
       lockToolbarAction = createLockableToolbarAction();
       toggleToolbarAction = createToggleToolbarAction();
       toggleLogTreeAction = createToggleLogTreeAction();
  @@ -232,8 +228,8 @@
       logPanelSpecificActions =
         new Action[] {
           pauseAction, findNextAction, clearAction, fileMenu.getFileSaveAction(),
  -        toggleDetailPaneAction, showPreferencesAction, undockAction,
  -        toggleLogTreeAction, changeModelAction,
  +        toggleDetailPaneAction, showPreferencesAction, showColorPanelAction,
  +        undockAction, toggleLogTreeAction, changeModelAction,
         };
     }
   
  @@ -481,6 +477,10 @@
       menuPrefs.setText(
         showPreferencesAction.getValue(Action.SHORT_DESCRIPTION).toString());
   
  +    JMenuItem menuShowColor = new JMenuItem(showColorPanelAction);
  +    menuShowColor.setText(
  +      showColorPanelAction.getValue(Action.SHORT_DESCRIPTION).toString());
  +
       JMenuItem menuUndock = new JMenuItem(undockAction);
   
       showTabs = new JMenu("Display tabs");
  @@ -518,6 +518,7 @@
       activeTabMenu.add(toggleLogTreeMenuItem);
       activeTabMenu.addSeparator();
       activeTabMenu.add(menuUndock);
  +    activeTabMenu.add(menuShowColor);
       activeTabMenu.add(menuPrefs);
   
       activeTabMenu.addSeparator();
  @@ -751,6 +752,25 @@
   
       // TODO think of good mnemonics and HotKey for this action
       return showPreferences;
  +  }
  +
  +  private Action createShowColorPanelAction() {
  +    Action showColorPanel =
  +      new AbstractAction("", ChainsawIcons.ICON_PREFERENCES) {
  +        public void actionPerformed(ActionEvent arg0) {
  +          LogPanel logPanel = logui.getCurrentLogPanel();
  +
  +          if (logPanel != null) {
  +            logPanel.showColorPanel();
  +          }
  +        }
  +      };
  +
  +    showColorPanel.putValue(
  +      Action.SHORT_DESCRIPTION, "LogPanel Color Filter...");
  +
  +    // TODO think of good mnemonics and HotKey for this action
  +    return showColorPanel;
     }
   
     /**
  
  
  
  1.40      +24 -28    jakarta-log4j/src/java/org/apache/log4j/chainsaw/LogUI.java
  
  Index: LogUI.java
  ===================================================================
  RCS file: /home/cvs/jakarta-log4j/src/java/org/apache/log4j/chainsaw/LogUI.java,v
  retrieving revision 1.39
  retrieving revision 1.40
  diff -u -r1.39 -r1.40
  --- LogUI.java	9 Oct 2003 04:05:46 -0000	1.39
  +++ LogUI.java	9 Nov 2003 09:59:28 -0000	1.40
  @@ -49,30 +49,12 @@
   
   package org.apache.log4j.chainsaw;
   
  -import org.apache.log4j.Level;
  -import org.apache.log4j.LogManager;
  -import org.apache.log4j.Priority;
  -import org.apache.log4j.UtilLoggingLevel;
  -import org.apache.log4j.chainsaw.help.Tutorial;
  -import org.apache.log4j.chainsaw.icons.ChainsawIcons;
  -import org.apache.log4j.chainsaw.prefs.LoadSettingsEvent;
  -import org.apache.log4j.chainsaw.prefs.SaveSettingsEvent;
  -import org.apache.log4j.chainsaw.prefs.SettingsListener;
  -import org.apache.log4j.chainsaw.prefs.SettingsManager;
  -import org.apache.log4j.helpers.LogLog;
  -import org.apache.log4j.helpers.OptionConverter;
  -import org.apache.log4j.net.SocketNodeEventListener;
  -import org.apache.log4j.plugins.Plugin;
  -import org.apache.log4j.plugins.PluginEvent;
  -import org.apache.log4j.plugins.PluginListener;
  -import org.apache.log4j.plugins.PluginRegistry;
  -import org.apache.log4j.plugins.Receiver;
  -
   import java.awt.BorderLayout;
   import java.awt.Component;
   import java.awt.Container;
   import java.awt.Dimension;
   import java.awt.Event;
  +import java.awt.Frame;
   import java.awt.Point;
   import java.awt.Toolkit;
   import java.awt.event.ActionEvent;
  @@ -83,20 +65,15 @@
   import java.awt.event.MouseEvent;
   import java.awt.event.WindowAdapter;
   import java.awt.event.WindowEvent;
  -
   import java.beans.PropertyChangeEvent;
   import java.beans.PropertyChangeListener;
  -
   import java.io.BufferedInputStream;
   import java.io.File;
   import java.io.FileInputStream;
   import java.io.IOException;
   import java.io.ObjectInputStream;
  -
   import java.lang.reflect.Method;
  -
   import java.net.URL;
  -
   import java.util.ArrayList;
   import java.util.HashMap;
   import java.util.Iterator;
  @@ -127,6 +104,25 @@
   import javax.swing.event.HyperlinkEvent;
   import javax.swing.event.HyperlinkListener;
   
  +import org.apache.log4j.Level;
  +import org.apache.log4j.LogManager;
  +import org.apache.log4j.Priority;
  +import org.apache.log4j.UtilLoggingLevel;
  +import org.apache.log4j.chainsaw.help.Tutorial;
  +import org.apache.log4j.chainsaw.icons.ChainsawIcons;
  +import org.apache.log4j.chainsaw.prefs.LoadSettingsEvent;
  +import org.apache.log4j.chainsaw.prefs.SaveSettingsEvent;
  +import org.apache.log4j.chainsaw.prefs.SettingsListener;
  +import org.apache.log4j.chainsaw.prefs.SettingsManager;
  +import org.apache.log4j.helpers.LogLog;
  +import org.apache.log4j.helpers.OptionConverter;
  +import org.apache.log4j.net.SocketNodeEventListener;
  +import org.apache.log4j.plugins.Plugin;
  +import org.apache.log4j.plugins.PluginEvent;
  +import org.apache.log4j.plugins.PluginListener;
  +import org.apache.log4j.plugins.PluginRegistry;
  +import org.apache.log4j.plugins.Receiver;
  +
   
   /**
    * The main entry point for Chainsaw, this class represents the first frame
  @@ -224,8 +220,8 @@
       }
     }
   
  -  private static final void showSplash() {
  -    splash = new ChainsawSplash();
  +  private static final void showSplash(Frame owner) {
  +    splash = new ChainsawSplash(owner);
   
       Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
       splash.setLocation(
  @@ -269,9 +265,9 @@
      * @param args
      */
     public static void main(String[] args) {
  -    showSplash();
   
       LogUI logUI = new LogUI();
  +    showSplash(logUI);
   
       logUI.handler = new ChainsawAppenderHandler();
       logUI.handler.addEventBatchListener(logUI.new NewTabEventBatchReceiver());
  @@ -568,8 +564,8 @@
           }
         });
   
  -    addWelcomePanel();
       panePanel.add(getTabbedPane());
  +    addWelcomePanel();
   
       getContentPane().add(toolbar, BorderLayout.NORTH);
       getContentPane().add(panePanel, BorderLayout.CENTER);
  
  
  
  1.24      +40 -2     jakarta-log4j/src/java/org/apache/log4j/chainsaw/LogPanel.java
  
  Index: LogPanel.java
  ===================================================================
  RCS file: /home/cvs/jakarta-log4j/src/java/org/apache/log4j/chainsaw/LogPanel.java,v
  retrieving revision 1.23
  retrieving revision 1.24
  diff -u -r1.23 -r1.24
  --- LogPanel.java	2 Nov 2003 19:53:47 -0000	1.23
  +++ LogPanel.java	9 Nov 2003 09:59:28 -0000	1.24
  @@ -146,6 +146,8 @@
   
   import org.apache.log4j.Layout;
   import org.apache.log4j.PatternLayout;
  +import org.apache.log4j.chainsaw.color.ColorPanel;
  +import org.apache.log4j.chainsaw.color.RuleColorizer;
   import org.apache.log4j.chainsaw.filter.FilterModel;
   import org.apache.log4j.chainsaw.icons.ChainsawIcons;
   import org.apache.log4j.chainsaw.icons.LineIconFactory;
  @@ -172,6 +174,7 @@
   public class LogPanel extends DockablePanel implements SettingsListener,
     EventBatchListener {
     private final JFrame preferencesFrame = new JFrame();
  +  private final JFrame colorFrame = new JFrame();
     private ThrowableRenderPanel throwableRenderPanel;
     private MouseFocusOnAdaptor mouseFocusOnAdaptor = new MouseFocusOnAdaptor();
     private boolean paused = false;
  @@ -192,11 +195,11 @@
       new LogPanelPreferenceModel();
     private final LogPanelPreferencePanel preferencesPanel =
       new LogPanelPreferencePanel(preferenceModel);
  +  private final ColorPanel colorPanel;
     private String profileName = null;
     private final JDialog detailDialog = new JDialog((JFrame) null, true);
     final JPanel detailPanel = new JPanel(new BorderLayout());
  -  private final TableColorizingRenderer renderer =
  -    new TableColorizingRenderer();
  +  private final TableColorizingRenderer renderer;
     String identifier;
     final Map columnDisplayMap = new HashMap();
     final Map colorDisplayMap = new HashMap();
  @@ -272,6 +275,25 @@
         });
       tableModel = new ChainsawCyclicBufferTableModel();
   
  +    colorFrame.setTitle("'" + ident + "' Color Filter");
  +    colorFrame.setIconImage(
  +      ((ImageIcon) ChainsawIcons.ICON_PREFERENCES).getImage());
  +    RuleColorizer colorizer = new RuleColorizer();
  +    colorizer.addPropertyChangeListener(new PropertyChangeListener() {
  +		public void propertyChange(PropertyChangeEvent evt) {
  +			if (evt.getPropertyName().equalsIgnoreCase("colorrule")) {
  +                if (table != null) {
  +                    table.repaint();
  +                }
  +            }
  +        }}
  +    );
  +    renderer = new TableColorizingRenderer(colorizer);
  +    colorPanel = new ColorPanel(colorizer, filterModel);
  +    colorFrame.getContentPane().add(colorPanel);
  +
  +    preferencesFrame.setSize(640, 480);
  +
       table = new JSortTable(tableModel);
       table.getColumnModel().addColumnModelListener(
         new ChainsawTableColumnModelListener(table));
  @@ -1022,6 +1044,16 @@
           }
         });
   
  +      JMenuItem menuItemColorPanel =
  +        new JMenuItem("LogPanel Color Filter...");
  +      menuItemColorPanel.addActionListener(
  +        new ActionListener() {
  +          public void actionPerformed(ActionEvent evt) {
  +            showColorPanel();
  +          }
  +        });
  +      menuItemColorPanel.setIcon(ChainsawIcons.ICON_PREFERENCES);
  +
       JMenuItem menuItemLogPanelPreferences =
         new JMenuItem("LogPanel Preferences...");
       menuItemLogPanelPreferences.addActionListener(
  @@ -1171,6 +1203,7 @@
       //	p.add(new JSeparator());
       //    p.add(menuDefineCustomFilter);
       p.add(new JSeparator());
  +    p.add(menuItemColorPanel);
       p.add(menuItemLogPanelPreferences);
   
       //    p.add(menuColumnDisplayFilter);
  @@ -1491,6 +1524,11 @@
     void showPreferences() {
       preferencesPanel.updateModel();
       preferencesFrame.show();
  +  }
  +
  +  void showColorPanel() {
  +    colorFrame.pack();
  +    colorFrame.show();
     }
   
     EventContainer getModel() {
  
  
  
  1.9       +39 -46    jakarta-log4j/src/java/org/apache/log4j/chainsaw/TableColorizingRenderer.java
  
  Index: TableColorizingRenderer.java
  ===================================================================
  RCS file: /home/cvs/jakarta-log4j/src/java/org/apache/log4j/chainsaw/TableColorizingRenderer.java,v
  retrieving revision 1.8
  retrieving revision 1.9
  diff -u -r1.8 -r1.9
  --- TableColorizingRenderer.java	29 Oct 2003 08:50:37 -0000	1.8
  +++ TableColorizingRenderer.java	9 Nov 2003 09:59:28 -0000	1.9
  @@ -50,7 +50,6 @@
   package org.apache.log4j.chainsaw;
   
   import org.apache.log4j.chainsaw.color.Colorizer;
  -import org.apache.log4j.chainsaw.color.DefaultColorizer;
   import org.apache.log4j.chainsaw.icons.LevelIconFactory;
   import org.apache.log4j.chainsaw.prefs.LoadSettingsEvent;
   import org.apache.log4j.chainsaw.prefs.SaveSettingsEvent;
  @@ -88,25 +87,22 @@
     implements SettingsListener {
     private static final DateFormat DATE_FORMATTER =
       new ISO8601DateFormat(Calendar.getInstance().getTimeZone());
  -  private Map iconMap = LevelIconFactory.getInstance().getLevelToIconMap();
  -
  -  //  private ColorFilter colorFilter;
  -  private JTable table;
  -  private Colorizer colorizer = new DefaultColorizer();
  -  private Color background = new Color(255, 255, 254);
  +  private static final Map iconMap =
  +    LevelIconFactory.getInstance().getLevelToIconMap();
  +  private Colorizer colorizer;
  +  private final Color background = new Color(255, 255, 254);
     private final Color COLOR_ODD = new Color(230, 230, 230);
     private final JLabel idComponent = new JLabel();
     private final JLabel levelComponent = new JLabel();
  -
  -  //  private String levelDisplay = ChainsawConstants.LEVEL_DISPLAY_ICONS;
     private boolean levelUseIcons = true;
     private DateFormat dateFormatInUse = DATE_FORMATTER;
  -  private String loggerPrecision = "";
  +  private int loggerPrecision = 0;
   
     /**
      * Creates a new TableColorizingRenderer object.
      */
  -  public TableColorizingRenderer() {
  +  public TableColorizingRenderer(Colorizer colorizer) {
  +    this.colorizer = colorizer;
       idComponent.setBorder(BorderFactory.createRaisedBevelBorder());
       idComponent.setBackground(Color.gray);
       idComponent.setHorizontalAlignment(JLabel.CENTER);
  @@ -125,8 +121,8 @@
     }
   
     public Component getTableCellRendererComponent(
  -    JTable table, Object value, boolean isSelected, boolean hasFocus, int row,
  -    int col) {
  +    final JTable table, Object value, boolean isSelected, boolean hasFocus,
  +    int row, int col) {
       value = formatField(value);
   
       Color backgroundColor = null;
  @@ -148,48 +144,44 @@
   
       case ChainsawColumns.INDEX_THROWABLE_COL_NAME:
   
  -      String[] ti = (String[]) value;
  -
  -      if (ti != null) {
  -        ((JLabel) c).setText(ti[0]);
  +      if (value instanceof String[]) {
  +        ((JLabel) c).setText(((String[]) value)[0]);
         } else {
           ((JLabel) c).setText("");
         }
   
         break;
   
  -      case ChainsawColumns.INDEX_LOGGER_COL_NAME:
  -        if (loggerPrecision.equals("")) {
  -            break;
  +    case ChainsawColumns.INDEX_LOGGER_COL_NAME:
  +
  +      if (loggerPrecision == 0) {
  +        break;
  +      } else {
  +        String logger = value.toString();
  +        int startPos = logger.length();
  +
  +        for (int i = 0; i < loggerPrecision; i++) {
  +          startPos = logger.lastIndexOf(".", startPos - 1);
  +        }
  +
  +        if (startPos < 0) {
  +          break;
           } else {
  -            String logger = value.toString();
  -            int precision = 0;
  -            try {
  -                precision = Integer.parseInt(loggerPrecision);
  -            } catch (NumberFormatException nfe){}
  -            if (precision < 1) {
  -                break;
  -            }
  -            int startPos = logger.length();
  -            for (int i=0;i<precision;i++) {
  -                startPos = logger.lastIndexOf(".", startPos - 1);
  -            }
  -            if (startPos < 0) {
  -                break;
  -            } else {
  -                ((JLabel)c).setText(logger.substring(startPos + 1));
  -            }
  +          ((JLabel) c).setText(logger.substring(startPos + 1));
           }
  +      }
   
  -        break;
  +      break;
   
       case ChainsawColumns.INDEX_LEVEL_COL_NAME:
   
  -      Icon icon = (Icon) iconMap.get(value.toString());
  +      if (levelUseIcons) {
  +        levelComponent.setIcon((Icon) iconMap.get(value.toString()));
  +
  +        if (levelComponent.getIcon() != null) {
  +          levelComponent.setText("");
  +        }
   
  -      if (levelUseIcons && (icon != null)) {
  -        levelComponent.setIcon(icon);
  -        levelComponent.setText("");
           levelComponent.setToolTipText(value.toString());
         } else {
           levelComponent.setIcon(null);
  @@ -210,8 +202,6 @@
         return c;
       }
   
  -    this.table = table;
  -
       if ((backgroundColor == null) && (getColorizer() != null)) {
         TableModel model = table.getModel();
         LoggingEvent event = null;
  @@ -267,8 +257,11 @@
      * Changes the Logger precision.
      * @param precision
      */
  -  void setLoggerPrecision(String loggerPrecision) {
  -    this.loggerPrecision = loggerPrecision;
  +  void setLoggerPrecision(String loggerPrecisionText) {
  +    try {
  +      loggerPrecision = Integer.parseInt(loggerPrecisionText);
  +    } catch (NumberFormatException nfe) {
  +    }
     }
   
     /**
  
  
  
  1.7       +1 -1      jakarta-log4j/src/java/org/apache/log4j/chainsaw/LogPanelPreferencePanel.java
  
  Index: LogPanelPreferencePanel.java
  ===================================================================
  RCS file: /home/cvs/jakarta-log4j/src/java/org/apache/log4j/chainsaw/LogPanelPreferencePanel.java,v
  retrieving revision 1.6
  retrieving revision 1.7
  diff -u -r1.6 -r1.7
  --- LogPanelPreferencePanel.java	29 Oct 2003 08:50:37 -0000	1.6
  +++ LogPanelPreferencePanel.java	9 Nov 2003 09:59:28 -0000	1.7
  @@ -405,7 +405,7 @@
             BorderFactory.createEtchedBorder(), "Logger"));
   
         final JLabel precisionLabel = new JLabel("Precision (package depth displayed)");
  -      final JLabel precisionLabel2 = new JLabel("leave blank to display full logger)");
  +      final JLabel precisionLabel2 = new JLabel("leave blank to display full logger");
   
         loggerFormatPanel.add(precisionLabel);
         loggerFormatPanel.add(precisionLabel2);
  
  
  
  1.1                  jakarta-log4j/src/java/org/apache/log4j/chainsaw/color/ColorPanel.java
  
  Index: ColorPanel.java
  ===================================================================
  /*
   * ============================================================================
   *                   The Apache Software License, Version 1.1
   * ============================================================================
   *
   *    Copyright (C) 1999 The Apache Software Foundation. All rights reserved.
   *
   * Redistribution and use in source and binary forms, with or without modifica-
   * tion, are permitted provided that the following conditions are met:
   *
   * 1. Redistributions of  source code must  retain the above copyright  notice,
   *    this list of conditions and the following disclaimer.
   *
   * 2. Redistributions in binary form must reproduce the above copyright notice,
   *    this list of conditions and the following disclaimer in the documentation
   *    and/or other materials provided with the distribution.
   *
   * 3. The end-user documentation included with the redistribution, if any, must
   *    include  the following  acknowledgment:  "This product includes  software
   *    developed  by the  Apache Software Foundation  (http://www.apache.org/)."
   *    Alternately, this  acknowledgment may  appear in the software itself,  if
   *    and wherever such third-party acknowledgments normally appear.
   *
   * 4. The names "log4j" and  "Apache Software Foundation"  must not be used to
   *    endorse  or promote  products derived  from this  software without  prior
   *    written permission. For written permission, please contact
   *    apache@apache.org.
   *
   * 5. Products  derived from this software may not  be called "Apache", nor may
   *    "Apache" appear  in their name,  without prior written permission  of the
   *    Apache Software Foundation.
   *
   * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES,
   * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
   * FITNESS  FOR A PARTICULAR  PURPOSE ARE  DISCLAIMED.  IN NO  EVENT SHALL  THE
   * APACHE SOFTWARE  FOUNDATION  OR ITS CONTRIBUTORS  BE LIABLE FOR  ANY DIRECT,
   * INDIRECT, INCIDENTAL, SPECIAL,  EXEMPLARY, OR CONSEQUENTIAL  DAMAGES (INCLU-
   * DING, BUT NOT LIMITED TO, PROCUREMENT  OF SUBSTITUTE GOODS OR SERVICES; LOSS
   * OF USE, DATA, OR  PROFITS; OR BUSINESS  INTERRUPTION)  HOWEVER CAUSED AND ON
   * ANY  THEORY OF LIABILITY,  WHETHER  IN CONTRACT,  STRICT LIABILITY,  OR TORT
   * (INCLUDING  NEGLIGENCE OR  OTHERWISE) ARISING IN  ANY WAY OUT OF THE  USE OF
   * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
   *
   * This software  consists of voluntary contributions made  by many individuals
   * on  behalf of the Apache Software  Foundation.  For more  information on the
   * Apache Software Foundation, please see <http://www.apache.org/>.
   *
   */
  
  package org.apache.log4j.chainsaw.color;
  
  import org.apache.log4j.chainsaw.filter.FilterModel;
  import org.apache.log4j.chainsaw.rule.ColorRule;
  import org.apache.log4j.chainsaw.rule.EqualsRule;
  import org.apache.log4j.chainsaw.rule.ExpressionRule;
  import org.apache.log4j.chainsaw.rule.ExpressionRuleContext;
  
  import java.awt.BorderLayout;
  import java.awt.Color;
  import java.awt.Component;
  import java.awt.Dimension;
  import java.awt.FlowLayout;
  import java.awt.Graphics;
  import java.awt.GridLayout;
  import java.awt.event.ActionEvent;
  
  import java.util.ArrayList;
  import java.util.List;
  
  import javax.swing.AbstractAction;
  import javax.swing.BoxLayout;
  import javax.swing.DefaultListCellRenderer;
  import javax.swing.DefaultListModel;
  import javax.swing.Icon;
  import javax.swing.JButton;
  import javax.swing.JColorChooser;
  import javax.swing.JLabel;
  import javax.swing.JList;
  import javax.swing.JPanel;
  import javax.swing.JScrollPane;
  import javax.swing.JTextField;
  import javax.swing.event.ChangeEvent;
  import javax.swing.event.ChangeListener;
  import javax.swing.event.ListSelectionEvent;
  import javax.swing.event.ListSelectionListener;
  
  /**
   * Panel which updates a RuleColorizer, allowing the user to build expression-based
   * color rules.
   * 
   * @author Scott Deboy <sd...@apache.org> 
   */
  public class ColorPanel extends JPanel {
    private static final String ADD_TEXT = "Add-->";
    private static final String UPDATE_TEXT = "Update-->";
    private final RuleColorizer colorizer;
    final DefaultListModel listModel;
    boolean addMode = true;
  
    public ColorPanel(
      final RuleColorizer colorizer, final FilterModel filterModel) {
      super();
      setLayout(new BoxLayout(this, BoxLayout.X_AXIS));
      this.colorizer = colorizer;
  
      final JColorChooser chooser = new JColorChooser();
  
      listModel = new DefaultListModel();
  
      final JList list = new JList(listModel);
      final JScrollPane scrollPane = new JScrollPane(list);
      scrollPane.setPreferredSize(new Dimension(400, 400));
  
      //apply a set of defaults for now, (eventually color rules will be loaded from disk)
      listModel.addElement(
        new ColorRuleHolder(
          "level == FATAL",
          new ColorRule(
            EqualsRule.getRule("level", "FATAL"), new Color(147, 22, 0),
            Color.white)));
      listModel.addElement(
        new ColorRuleHolder(
          "level == ERROR",
          new ColorRule(
            EqualsRule.getRule("level", "ERROR"), new Color(147, 22, 0),
            Color.white)));
      listModel.addElement(
        new ColorRuleHolder(
          "level == WARN",
          new ColorRule(
            EqualsRule.getRule("level", "WARN"), Color.yellow.brighter())));
      applyRules();
  
      JPanel leftPanel = new JPanel(new BorderLayout());
      JPanel leftCenterPanel = new JPanel();
      leftCenterPanel.setLayout(
        new BoxLayout(leftCenterPanel, BoxLayout.Y_AXIS));
  
      JPanel expressionClearPanel = new JPanel();
      expressionClearPanel.setLayout(
        new BoxLayout(expressionClearPanel, BoxLayout.Y_AXIS));
  
      JPanel expressionPanel = new JPanel();
      expressionPanel.setLayout(new FlowLayout(FlowLayout.LEFT));
  
      leftPanel.add(new JLabel("Rule:"), BorderLayout.NORTH);
  
      final JTextField expression = new JTextField(30);
      final Color defaultExpressionBackground = expression.getBackground();
      final Color defaultExpressionForeground = expression.getForeground();
  
      expression.addKeyListener(
        new ExpressionRuleContext(filterModel, expression));
      expressionPanel.add(expression);
  
      JPanel addUpdatePanel = new JPanel();
      addUpdatePanel.setLayout(new BoxLayout(addUpdatePanel, BoxLayout.X_AXIS));
  
      addUpdatePanel.add(new JLabel(" "));
  
      final JButton addUpdateButton = new JButton(ADD_TEXT);
      addUpdatePanel.add(addUpdateButton);
  
      expressionPanel.add(addUpdatePanel);
  
      expressionClearPanel.add(expressionPanel);
  
      JPanel clearPanel = new JPanel(new FlowLayout(FlowLayout.LEFT));
  
      JButton clearButton = new JButton("Clear");
      clearPanel.add(clearButton);
      clearButton.addActionListener(
        new AbstractAction() {
          public void actionPerformed(ActionEvent evt) {
            addMode = true;
            expression.setText("");
            addUpdateButton.setText(ADD_TEXT);
            expression.setBackground(defaultExpressionBackground);
            expression.setForeground(defaultExpressionForeground);
            list.getSelectionModel().clearSelection();
          }
        });
  
      expressionClearPanel.add(clearPanel);
  
      leftCenterPanel.add(expressionClearPanel);
  
      JPanel chooserPanel = new JPanel();
      chooserPanel.add(chooser);
  
      chooser.getSelectionModel().addChangeListener(
        new ChangeListener() {
          public void stateChanged(ChangeEvent evt) {
            expression.setBackground(chooser.getColor());
          }
        });
  
      leftCenterPanel.add(chooserPanel);
      leftPanel.add(leftCenterPanel);
      add(leftPanel);
  
      JPanel updownPanel = new JPanel();
      updownPanel.setLayout(new GridLayout(6, 1));
  
      JPanel removePanel = new JPanel();
      final JButton removeButton = new JButton("Remove");
  
      removeButton.addActionListener(
        new AbstractAction() {
          public void actionPerformed(ActionEvent evt) {
            int index = list.getSelectionModel().getMaxSelectionIndex();
  
            if (index > -1) {
              ColorRuleHolder holder = (ColorRuleHolder) listModel.get(index);
  
              listModel.remove(index);
  
              if (index > 0) {
                index = index - 1;
              }
  
              addUpdateButton.setText(ADD_TEXT);
              addMode = true;
  
              if (listModel.getSize() > 0) {
                list.getSelectionModel().setSelectionInterval(index, index);
              }
            }
          }
        });
  
      removePanel.add(removeButton);
  
      updownPanel.add(new JLabel(" "));
      updownPanel.add(new JLabel(" "));
  
      final JButton upButton = new JButton("Move Up");
      final JButton downButton = new JButton("Move Down");
      JPanel upPanel = new JPanel();
  
      updownPanel.add(removePanel);
  
      upPanel.add(upButton);
  
      JPanel downPanel = new JPanel();
      downPanel.add(downButton);
  
      updownPanel.add(upPanel);
  
      JPanel updownLabelPanel = new JPanel();
      updownLabelPanel.add(new JLabel("Move rule"));
      updownPanel.add(updownLabelPanel);
      updownPanel.add(downPanel);
  
      add(updownPanel);
  
      upButton.addActionListener(
        new AbstractAction() {
          public void actionPerformed(ActionEvent evt) {
            int index = list.getSelectionModel().getMaxSelectionIndex();
  
            if (index > 0) {
              ColorRuleHolder holder = (ColorRuleHolder) listModel.get(index);
              listModel.remove(index);
              index = index - 1;
              listModel.add(index, holder);
              list.getSelectionModel().setSelectionInterval(index, index);
            }
          }
        });
  
      downButton.addActionListener(
        new AbstractAction() {
          public void actionPerformed(ActionEvent evt) {
            int index = list.getSelectionModel().getMaxSelectionIndex();
  
            if ((index > -1) && (index < (listModel.getSize() - 1))) {
              ColorRuleHolder holder = (ColorRuleHolder) listModel.get(index);
              listModel.remove(index);
              index = index + 1;
              listModel.add(index, holder);
              list.getSelectionModel().setSelectionInterval(index, index);
            }
          }
        });
  
      list.setCellRenderer(new ColorRenderer());
      list.getSelectionModel().addListSelectionListener(
        new ListSelectionListener() {
          public void valueChanged(ListSelectionEvent e) {
            if (!e.getValueIsAdjusting()) {
              int index = list.getSelectionModel().getMaxSelectionIndex();
  
              if (index > -1) {
                addMode = false;
                addUpdateButton.setText(UPDATE_TEXT);
  
                ColorRuleHolder holder = (ColorRuleHolder) listModel.get(index);
                expression.setText(holder.ruleText);
                expression.setBackground(holder.colorRule.getBackgroundColor());
                expression.setForeground(holder.colorRule.getForegroundColor());
                chooser.setColor(holder.colorRule.getBackgroundColor());
              }
  
              if (index < 0) {
                removeButton.setEnabled(false);
                downButton.setEnabled(false);
                upButton.setEnabled(false);
              } else if ((index == 0) && (listModel.getSize() == 1)) {
                removeButton.setEnabled(true);
                downButton.setEnabled(false);
                upButton.setEnabled(false);
              } else if ((index == 0) && (listModel.getSize() > 1)) {
                removeButton.setEnabled(true);
                downButton.setEnabled(true);
                upButton.setEnabled(false);
              } else if (index == (listModel.getSize() - 1)) {
                removeButton.setEnabled(true);
                downButton.setEnabled(false);
                upButton.setEnabled(true);
              } else {
                removeButton.setEnabled(true);
                downButton.setEnabled(true);
                upButton.setEnabled(true);
              }
            }
          }
        });
  
      addUpdateButton.addActionListener(
        new AbstractAction() {
          public void actionPerformed(ActionEvent evt) {
            ColorRuleHolder holder =
              new ColorRuleHolder(
                expression.getText(),
                new ColorRule(
                  ExpressionRule.getRule(expression.getText()),
                  chooser.getColor()));
  
            if (addMode) {
              listModel.addElement(holder);
            } else {
              int index = list.getSelectionModel().getMaxSelectionIndex();
              listModel.remove(index);
              listModel.add(index, holder);
            }
  
            int index = listModel.indexOf(holder);
            list.getSelectionModel().setSelectionInterval(index, index);
          }
        });
  
      JPanel rightPanel = new JPanel(new BorderLayout());
  
      rightPanel.add(new JLabel("Rules:"), BorderLayout.NORTH);
      rightPanel.add(scrollPane, BorderLayout.CENTER);
  
      JPanel applyPanel = new JPanel();
      JButton apply = new JButton("Apply");
      applyPanel.add(apply);
      rightPanel.add(applyPanel, BorderLayout.SOUTH);
  
      apply.addActionListener(
        new AbstractAction() {
          public void actionPerformed(ActionEvent evt) {
            applyRules();
          }
        });
  
      add(rightPanel);
    }
  
    void applyRules() {
      colorizer.clear();
  
      List newList = new ArrayList();
  
      for (int i = 0, j = listModel.size(); i < j; i++) {
        newList.add(((ColorRuleHolder) listModel.get(i)).colorRule);
      }
  
      colorizer.addRules(newList);
    }
  
    class ColorRenderer extends DefaultListCellRenderer {
      public Component getListCellRendererComponent(
        JList list, Object value, int index, boolean isSelected,
        boolean cellHasFocus) {
        ColorRuleHolder h = (ColorRuleHolder) value;
        Component c =
          super.getListCellRendererComponent(
            list, value, index, isSelected, cellHasFocus);
        ((JLabel) c).setIcon(new SelectedIcon(isSelected));
        c.setBackground(h.colorRule.getBackgroundColor());
        c.setForeground(h.colorRule.getForegroundColor());
  
        return c;
      }
    }
  
    class SelectedIcon implements Icon {
      private boolean isSelected;
      private int width = 9;
      private int height = 18;
      private int[] xPoints = new int[4];
      private int[] yPoints = new int[4];
  
      public SelectedIcon(boolean isSelected) {
        this.isSelected = isSelected;
        xPoints[0] = 0;
        yPoints[0] = -1;
        xPoints[1] = 0;
        yPoints[1] = height;
        xPoints[2] = width;
        yPoints[2] = height / 2;
        xPoints[3] = width;
        yPoints[3] = (height / 2) - 1;
      }
  
      public int getIconHeight() {
        return height;
      }
  
      public int getIconWidth() {
        return width;
      }
  
      public void paintIcon(Component c, Graphics g, int x, int y) {
        if (isSelected) {
          int length = xPoints.length;
          int[] newXPoints = new int[length];
          int[] newYPoints = new int[length];
  
          for (int i = 0; i < length; i++) {
            newXPoints[i] = xPoints[i] + x;
            newYPoints[i] = yPoints[i] + y;
          }
  
          g.setColor(Color.black);
  
          g.fillPolygon(newXPoints, newYPoints, length);
        }
      }
    }
  }
  
  
  class ColorRuleHolder {
    String ruleText;
    ColorRule colorRule;
  
    ColorRuleHolder(String ruleText, ColorRule colorRule) {
      this.ruleText = ruleText;
      this.colorRule = colorRule;
    }
  
    public String toString() {
      return ruleText;
    }
  
    public int hashCode() {
      int result = 37;
  
      if (ruleText != null) {
        result = result + (37 * ruleText.hashCode());
      }
  
      return result;
    }
  
    //note: in order to perform 'contains' checks, we are only evaluating the string for equality,
    //not the colorrule.  This allows us to 'update' an existing rule with a new color.
    public boolean equals(Object o) {
      if (o instanceof ColorRuleHolder) {
        ColorRuleHolder h = (ColorRuleHolder) o;
  
        return (((ruleText == null) && (h.ruleText == null))
        || ((ruleText != null) && ruleText.equals(h.ruleText)));
      }
  
      return false;
    }
  }
  
  
  
  1.1                  jakarta-log4j/src/java/org/apache/log4j/chainsaw/color/RuleColorizer.java
  
  Index: RuleColorizer.java
  ===================================================================
  /*
   * ============================================================================
   *                   The Apache Software License, Version 1.1
   * ============================================================================
   *
   *    Copyright (C) 1999 The Apache Software Foundation. All rights reserved.
   *
   * Redistribution and use in source and binary forms, with or without modifica-
   * tion, are permitted provided that the following conditions are met:
   *
   * 1. Redistributions of  source code must  retain the above copyright  notice,
   *    this list of conditions and the following disclaimer.
   *
   * 2. Redistributions in binary form must reproduce the above copyright notice,
   *    this list of conditions and the following disclaimer in the documentation
   *    and/or other materials provided with the distribution.
   *
   * 3. The end-user documentation included with the redistribution, if any, must
   *    include  the following  acknowledgment:  "This product includes  software
   *    developed  by the  Apache Software Foundation  (http://www.apache.org/)."
   *    Alternately, this  acknowledgment may  appear in the software itself,  if
   *    and wherever such third-party acknowledgments normally appear.
   *
   * 4. The names "log4j" and  "Apache Software Foundation"  must not be used to
   *    endorse  or promote  products derived  from this  software without  prior
   *    written permission. For written permission, please contact
   *    apache@apache.org.
   *
   * 5. Products  derived from this software may not  be called "Apache", nor may
   *    "Apache" appear  in their name,  without prior written permission  of the
   *    Apache Software Foundation.
   *
   * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES,
   * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
   * FITNESS  FOR A PARTICULAR  PURPOSE ARE  DISCLAIMED.  IN NO  EVENT SHALL  THE
   * APACHE SOFTWARE  FOUNDATION  OR ITS CONTRIBUTORS  BE LIABLE FOR  ANY DIRECT,
   * INDIRECT, INCIDENTAL, SPECIAL,  EXEMPLARY, OR CONSEQUENTIAL  DAMAGES (INCLU-
   * DING, BUT NOT LIMITED TO, PROCUREMENT  OF SUBSTITUTE GOODS OR SERVICES; LOSS
   * OF USE, DATA, OR  PROFITS; OR BUSINESS  INTERRUPTION)  HOWEVER CAUSED AND ON
   * ANY  THEORY OF LIABILITY,  WHETHER  IN CONTRACT,  STRICT LIABILITY,  OR TORT
   * (INCLUDING  NEGLIGENCE OR  OTHERWISE) ARISING IN  ANY WAY OUT OF THE  USE OF
   * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
   *
   * This software  consists of voluntary contributions made  by many individuals
   * on  behalf of the Apache Software  Foundation.  For more  information on the
   * Apache Software Foundation, please see <http://www.apache.org/>.
   *
   */
  
  package org.apache.log4j.chainsaw.color;
  
  import org.apache.log4j.chainsaw.rule.ColorRule;
  import org.apache.log4j.spi.LoggingEvent;
  
  import java.awt.Color;
  
  import java.beans.PropertyChangeListener;
  import java.beans.PropertyChangeSupport;
  
  import java.util.LinkedList;
  import java.util.List;
  
  
  /**
   * A colorizer supporting an ordered collection of ColorRules, including support for notification of
   * color rule changes via a propertyChangeListener and the 'colorrule' property.
   *
   * @author Scott Deboy <sd...@apache.org>
   */
  public class RuleColorizer implements Colorizer {
    private final List ruleList = new LinkedList();
    private final PropertyChangeSupport colorChangeSupport =
      new PropertyChangeSupport(this);
  
    public RuleColorizer() {
    }
  
    public void addRules(List rules) {
      for (int i = 0, j = rules.size(); i < j; i++) {
        ruleList.add((ColorRule) rules.get(i));
      }
  
      colorChangeSupport.firePropertyChange("colorrule", false, true);
    }
  
    public void addRule(ColorRule rule) {
      ruleList.add(rule);
      colorChangeSupport.firePropertyChange("colorrule", false, true);
    }
  
    public void clear() {
      ruleList.clear();
    }
  
    public void removeRule(ColorRule rule) {
      ruleList.remove(rule);
    }
  
    public Color getBackgroundColor(LoggingEvent event) {
      for (int i = 0, j = ruleList.size(); i < j; i++) {
        ColorRule rule = (ColorRule) ruleList.get(i);
  
        if ((rule.getBackgroundColor() != null) && (rule.evaluate(event))) {
          return rule.getBackgroundColor();
        }
      }
  
      return null;
    }
  
    public Color getForegroundColor(LoggingEvent event) {
      for (int i = 0, j = ruleList.size(); i < j; i++) {
        ColorRule rule = (ColorRule) ruleList.get(i);
  
        if ((rule.getForegroundColor() != null) && (rule.evaluate(event))) {
          return rule.getForegroundColor();
        }
      }
  
      return null;
    }
  
    public void addPropertyChangeListener(PropertyChangeListener listener) {
      colorChangeSupport.addPropertyChangeListener(listener);
    }
  
    public void removePropertyChangeListener(PropertyChangeListener listener) {
      colorChangeSupport.removePropertyChangeListener(listener);
    }
  }
  
  
  

---------------------------------------------------------------------
To unsubscribe, e-mail: log4j-dev-unsubscribe@jakarta.apache.org
For additional commands, e-mail: log4j-dev-help@jakarta.apache.org