logging-general mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From sde...@apache.org
Subject svn commit: r942512 - in /logging/chainsaw/trunk: ./ src/main/java/org/apache/log4j/chainsaw/ src/main/java/org/apache/log4j/chainsaw/color/ src/main/java/org/apache/log4j/chainsaw/layout/ src/main/resources/org/apache/log4j/chainsaw/help/ src/main/res...
Date Sun, 09 May 2010 08:30:01 GMT
Author: sdeboy
Date: Sun May  9 08:30:00 2010
New Revision: 942512

URL: http://svn.apache.org/viewvc?rev=942512&view=rev
Log:
Added ability to highlight search match text in the table (per-log panel preference, enabled by default)
 - modified the Rule.evaluate method to accept a Map argument.  If the map argument is not null, the map will be populated with text matches resulting from the rule evaluation - the keys are the field names containing text matches discovered during rule evaluation, the values are the (possibly multiple) text matches
- updated Chainsaw & receivers pom.xml to require log4j-extras 1.1 snapshot due to the change to the Rule API
 - renamed JEditorPaneFormatter to JTextComponentFormatter
 - modified the Search match color in the table from black background to grey background, from white foreground to black foreground
- reworked concurrency & use of event lists in ChainsawCyclicBufferTableModel
- added search matches to extendedloggingevent (used during rendering)
- updated findnext/previous logic to handle no selected row, better handling of wrapping forward & back 
- reworked tablecellrenderer logic to support bolding of search-match text in the table (required changing multiline fields to use a jtextpane)
- updated all Rules to accept a Map which is populated by String keys representing the fields providing a text match, and Set values containing the one or more text matches for that field (if the map is null, no collection of results is performed)
- updated And, Or and Not rules to correctly aggregate text match results of their child rules
- updated ExpressionRule to allow definition of expressions containing keywords as text (must be single-quoted)

Added:
    logging/chainsaw/trunk/src/main/java/org/apache/log4j/chainsaw/JTextComponentFormatter.java
      - copied, changed from r930795, logging/chainsaw/trunk/src/main/java/org/apache/log4j/chainsaw/JEditorPaneFormatter.java
Removed:
    logging/chainsaw/trunk/src/main/java/org/apache/log4j/chainsaw/JEditorPaneFormatter.java
Modified:
    logging/chainsaw/trunk/pom.xml
    logging/chainsaw/trunk/src/main/java/org/apache/log4j/chainsaw/ChainsawAbout.java
    logging/chainsaw/trunk/src/main/java/org/apache/log4j/chainsaw/ChainsawAppenderHandler.java
    logging/chainsaw/trunk/src/main/java/org/apache/log4j/chainsaw/ChainsawConstants.java
    logging/chainsaw/trunk/src/main/java/org/apache/log4j/chainsaw/ChainsawCyclicBufferTableModel.java
    logging/chainsaw/trunk/src/main/java/org/apache/log4j/chainsaw/EventContainer.java
    logging/chainsaw/trunk/src/main/java/org/apache/log4j/chainsaw/ExtendedLoggingEvent.java
    logging/chainsaw/trunk/src/main/java/org/apache/log4j/chainsaw/LogPanel.java
    logging/chainsaw/trunk/src/main/java/org/apache/log4j/chainsaw/LogPanelPreferenceModel.java
    logging/chainsaw/trunk/src/main/java/org/apache/log4j/chainsaw/LogPanelPreferencePanel.java
    logging/chainsaw/trunk/src/main/java/org/apache/log4j/chainsaw/LogUI.java
    logging/chainsaw/trunk/src/main/java/org/apache/log4j/chainsaw/LoggerNameTreePanel.java
    logging/chainsaw/trunk/src/main/java/org/apache/log4j/chainsaw/RuleMediator.java
    logging/chainsaw/trunk/src/main/java/org/apache/log4j/chainsaw/TableColorizingRenderer.java
    logging/chainsaw/trunk/src/main/java/org/apache/log4j/chainsaw/WelcomePanel.java
    logging/chainsaw/trunk/src/main/java/org/apache/log4j/chainsaw/color/RuleColorizer.java
    logging/chainsaw/trunk/src/main/java/org/apache/log4j/chainsaw/layout/LayoutEditorPane.java
    logging/chainsaw/trunk/src/main/resources/org/apache/log4j/chainsaw/help/release-notes.html
    logging/chainsaw/trunk/src/main/resources/org/apache/log4j/chainsaw/prefs/default.properties

Modified: logging/chainsaw/trunk/pom.xml
URL: http://svn.apache.org/viewvc/logging/chainsaw/trunk/pom.xml?rev=942512&r1=942511&r2=942512&view=diff
==============================================================================
--- logging/chainsaw/trunk/pom.xml (original)
+++ logging/chainsaw/trunk/pom.xml Sun May  9 08:30:00 2010
@@ -328,7 +328,7 @@
     <dependency>
       <groupId>log4j</groupId>
       <artifactId>apache-log4j-extras</artifactId>
-      <version>1.0</version>
+      <version>1.1-SNAPSHOT</version>
     </dependency>
     <dependency>
       <groupId>log4j</groupId>

Modified: logging/chainsaw/trunk/src/main/java/org/apache/log4j/chainsaw/ChainsawAbout.java
URL: http://svn.apache.org/viewvc/logging/chainsaw/trunk/src/main/java/org/apache/log4j/chainsaw/ChainsawAbout.java?rev=942512&r1=942511&r2=942512&view=diff
==============================================================================
--- logging/chainsaw/trunk/src/main/java/org/apache/log4j/chainsaw/ChainsawAbout.java (original)
+++ logging/chainsaw/trunk/src/main/java/org/apache/log4j/chainsaw/ChainsawAbout.java Sun May  9 08:30:00 2010
@@ -23,7 +23,6 @@ package org.apache.log4j.chainsaw;
 
 import java.awt.BorderLayout;
 import java.awt.Color;
-import java.awt.Font;
 import java.awt.Point;
 import java.awt.event.ActionEvent;
 import java.awt.event.ActionListener;
@@ -35,10 +34,8 @@ import javax.swing.JFrame;
 import javax.swing.JScrollPane;
 import javax.swing.ScrollPaneConstants;
 import javax.swing.SwingUtilities;
-import javax.swing.UIManager;
 import javax.swing.event.HyperlinkEvent;
 import javax.swing.event.HyperlinkListener;
-import javax.swing.text.html.HTMLDocument;
 
 import org.apache.log4j.Logger;
 import org.apache.log4j.chainsaw.help.HelpManager;
@@ -86,7 +83,7 @@ class ChainsawAbout extends JDialog {
         }
         getContentPane().add(scrollPane, BorderLayout.CENTER);
         getContentPane().add(closeButton, BorderLayout.SOUTH);
-        JEditorPaneFormatter.applySystemFontAndSize(editPane);
+        JTextComponentFormatter.applySystemFontAndSize(editPane);
 
         editPane.setEditable(false);
         editPane.addHyperlinkListener(

Modified: logging/chainsaw/trunk/src/main/java/org/apache/log4j/chainsaw/ChainsawAppenderHandler.java
URL: http://svn.apache.org/viewvc/logging/chainsaw/trunk/src/main/java/org/apache/log4j/chainsaw/ChainsawAppenderHandler.java?rev=942512&r1=942511&r2=942512&view=diff
==============================================================================
--- logging/chainsaw/trunk/src/main/java/org/apache/log4j/chainsaw/ChainsawAppenderHandler.java (original)
+++ logging/chainsaw/trunk/src/main/java/org/apache/log4j/chainsaw/ChainsawAppenderHandler.java Sun May  9 08:30:00 2010
@@ -26,7 +26,6 @@ import java.util.Map;
 import javax.swing.event.EventListenerList;
 import org.apache.log4j.AppenderSkeleton;
 import org.apache.log4j.LogManager;
-import org.apache.log4j.MDC;
 import org.apache.log4j.helpers.Constants;
 import org.apache.log4j.net.SocketReceiver;
 import org.apache.log4j.rule.ExpressionRule;
@@ -291,7 +290,7 @@ public class ChainsawAppenderHandler ext
                   .hasNext();) {
                 Map.Entry entry = (Map.Entry) itery.next();
                 Rule rule = (Rule) entry.getValue();
-                if (rule.evaluate(e)) {
+                if (rule.evaluate(e, null)) {
                   eventBatch.addEvent((String) entry.getKey(), e);
                 }
               }

Modified: logging/chainsaw/trunk/src/main/java/org/apache/log4j/chainsaw/ChainsawConstants.java
URL: http://svn.apache.org/viewvc/logging/chainsaw/trunk/src/main/java/org/apache/log4j/chainsaw/ChainsawConstants.java?rev=942512&r1=942511&r2=942512&view=diff
==============================================================================
--- logging/chainsaw/trunk/src/main/java/org/apache/log4j/chainsaw/ChainsawConstants.java (original)
+++ logging/chainsaw/trunk/src/main/java/org/apache/log4j/chainsaw/ChainsawConstants.java Sun May  9 08:30:00 2010
@@ -36,8 +36,8 @@ public class ChainsawConstants {
   public static final Color COLOR_DEFAULT_FOREGROUND = Color.BLACK;
 
   public static final int DEFAULT_ROW_HEIGHT = 20;
-  public static final Color FIND_LOGGER_BACKGROUND = new Color(40, 40, 40);
-  public static final Color FIND_LOGGER_FOREGROUND = Color.WHITE;
+  public static final Color FIND_LOGGER_BACKGROUND = new Color(197, 193, 170);
+  public static final Color FIND_LOGGER_FOREGROUND = Color.BLACK;
 
   public static final Color COLOR_ODD_ROW = new Color(215, 215, 215);
   public static final Color COLOR_EVEN_ROW = COLOR_DEFAULT_BACKGROUND;

Modified: logging/chainsaw/trunk/src/main/java/org/apache/log4j/chainsaw/ChainsawCyclicBufferTableModel.java
URL: http://svn.apache.org/viewvc/logging/chainsaw/trunk/src/main/java/org/apache/log4j/chainsaw/ChainsawCyclicBufferTableModel.java?rev=942512&r1=942511&r2=942512&view=diff
==============================================================================
--- logging/chainsaw/trunk/src/main/java/org/apache/log4j/chainsaw/ChainsawCyclicBufferTableModel.java (original)
+++ logging/chainsaw/trunk/src/main/java/org/apache/log4j/chainsaw/ChainsawCyclicBufferTableModel.java Sun May  9 08:30:00 2010
@@ -75,6 +75,7 @@ class ChainsawCyclicBufferTableModel ext
 
   //  protected final Object syncLock = new Object();
   private final LoggerNameModel loggerNameModelDelegate = new LoggerNameModelSupport();
+  private final Object mutex = new Object();
 
   //because we may be using a cyclic buffer, if an ID is not provided in the property, 
   //use and increment this row counter as the ID for each received row
@@ -103,17 +104,19 @@ class ChainsawCyclicBufferTableModel ext
   }
 
   public List getMatchingEvents(Rule rule) {
-    List list = new ArrayList();
 
-    synchronized (unfilteredList) {
-      Iterator iter = unfilteredList.iterator();
+    List list = new ArrayList();
+    List unfilteredCopy;
+    synchronized (mutex) {
+        unfilteredCopy = new ArrayList(unfilteredList);
+    }
+    Iterator iter = unfilteredCopy.iterator();
 
-      while (iter.hasNext()) {
-        LoggingEvent event = (LoggingEvent) iter.next();
+    while (iter.hasNext()) {
+      LoggingEvent event = (LoggingEvent) iter.next();
 
-        if (rule.evaluate(event)) {
-          list.add(event);
-        }
+      if (rule.evaluate(event, null)) {
+        list.add(event);
       }
     }
 
@@ -121,38 +124,43 @@ class ChainsawCyclicBufferTableModel ext
   }
 
   public void reFilter() {
-    synchronized (unfilteredList) {
-      final int previousSize = filteredList.size();
-      try {
-        filteredList.clear();
-
-        Iterator iter = unfilteredList.iterator();
+    final int previousSize;
+    final int newSize;
+          synchronized (mutex) {
+            previousSize = filteredList.size();
+            filteredList.clear();
+            if (displayRule == null) {
+                filteredList.addAll(unfilteredList);
+            } else {
+                Iterator iter = unfilteredList.iterator();
 
-        while (iter.hasNext()) {
-          LoggingEvent e = (LoggingEvent) iter.next();
+                while (iter.hasNext()) {
+                  LoggingEvent e = (LoggingEvent) iter.next();
 
-          if ((displayRule == null) || (displayRule.evaluate(e))) {
-            filteredList.add(e);
+                  if (displayRule.evaluate(e, null)) {
+                    filteredList.add(e);
+                  }
+                }
+            }
+            newSize = filteredList.size();
           }
-        }
-      } finally {
       	SwingHelper.invokeOnEDT(new Runnable() {
       		public void run() {
-      			if (filteredList.size() > 0) {
-	      			if (previousSize == filteredList.size()) {
+      			if (newSize > 0) {
+	      			if (previousSize == newSize) {
 	      				//same - update all
-	      				fireTableRowsUpdated(0, filteredList.size() - 1);
-	      			} else if (previousSize > filteredList.size()) {
+	      				fireTableRowsUpdated(0, newSize - 1);
+	      			} else if (previousSize > newSize) {
 	      				//less now..update and delete difference
-	      				fireTableRowsUpdated(0, filteredList.size() - 1);
+	      				fireTableRowsUpdated(0, newSize - 1);
                         //swing bug exposed by variable height rows when calling fireTableRowsDeleted..use tabledatacchanged
                         fireTableDataChanged();
-	      			} else if (previousSize < filteredList.size()) {
+	      			} else if (previousSize < newSize) {
 	      				//more now..update and insert difference
                         if (previousSize > 0) {
 	      				    fireTableRowsUpdated(0, previousSize - 1);
                         }
-	      				fireTableRowsInserted(Math.max(0, previousSize), filteredList.size() - 1);
+	      				fireTableRowsInserted(Math.max(0, previousSize), newSize - 1);
 	      			}
       			} else {
       				//no rows to show
@@ -160,38 +168,38 @@ class ChainsawCyclicBufferTableModel ext
       			}
 	      	notifyCountListeners();
       	}});
-      }
-    }
   }
 
-  public int find(Rule rule, int startLocation, boolean searchForward) {
-    synchronized (filteredList) {
+  public int locate(Rule rule, int startLocation, boolean searchForward) {
+    List filteredListCopy;
+    synchronized (mutex) {
+      filteredListCopy = new ArrayList(filteredList);
+    }
       if (searchForward) {
-        for (int i = startLocation; i < filteredList.size(); i++) {
-          if (rule.evaluate((LoggingEvent) filteredList.get(i))) {
+        for (int i = startLocation; i < filteredListCopy.size(); i++) {
+          if (rule.evaluate((LoggingEvent) filteredListCopy.get(i), null)) {
             return i;
           }
         }
         //if there was no match, start at row zero and go to startLocation
         for (int i = 0; i < startLocation; i++) {
-          if (rule.evaluate((LoggingEvent) filteredList.get(i))) {
+          if (rule.evaluate((LoggingEvent) filteredListCopy.get(i), null)) {
             return i;
           }
         }
       } else {
         for (int i = startLocation; i > -1; i--) {
-          if (rule.evaluate((LoggingEvent) filteredList.get(i))) {
+          if (rule.evaluate((LoggingEvent) filteredListCopy.get(i), null)) {
             return i;
           }
         }
         //if there was no match, start at row list.size() - 1 and go to startLocation
-        for (int i = filteredList.size() - 1; i > startLocation; i--) {
-          if (rule.evaluate((LoggingEvent) filteredList.get(i))) {
+        for (int i = filteredListCopy.size() - 1; i > startLocation; i--) {
+          if (rule.evaluate((LoggingEvent) filteredListCopy.get(i), null)) {
             return i;
           }
         }
       }
-    }
 
     return -1;
   }
@@ -238,9 +246,15 @@ class ChainsawCyclicBufferTableModel ext
       (EventCountListener[]) eventListenerList.getListeners(
         EventCountListener.class);
 
+    int filteredListSize;
+    int unfilteredListSize;
+    synchronized (mutex) {
+        filteredListSize = filteredList.size();
+        unfilteredListSize = unfilteredList.size();
+    }
     for (int i = 0; i < listeners.length; i++) {
       listeners[i].eventCountChanged(
-        filteredList.size(), unfilteredList.size());
+        filteredListSize, unfilteredListSize);
     }
   }
 
@@ -269,21 +283,26 @@ class ChainsawCyclicBufferTableModel ext
      * @see org.apache.log4j.chainsaw.EventContainer#sort()
      */
   public void sort() {
-    if (sortEnabled && filteredList.size() > 0) {
-      synchronized (filteredList) {
-        Collections.sort(
-          filteredList,
-          new ColumnComparator(
-            getColumnName(currentSortColumn), currentSortColumn,
-            currentSortAscending));
+      boolean sort;
+      final int filteredListSize;
+      synchronized (mutex) {
+          filteredListSize = filteredList.size();
+          sort = (sortEnabled && filteredListSize > 0);
+        if (sort) {
+            Collections.sort(
+              filteredList,
+              new ColumnComparator(
+                getColumnName(currentSortColumn), currentSortColumn,
+                currentSortAscending));
+        }
+      }
+      if (sort) {
+        SwingHelper.invokeOnEDT(new Runnable() {
+            public void run() {
+                fireTableRowsUpdated(0, Math.max(filteredListSize - 1, 0));
+            }
+        });
       }
-
-     	SwingHelper.invokeOnEDT(new Runnable() {
-     		public void run() {
-      			fireTableRowsUpdated(0, Math.max(filteredList.size() - 1, 0));
-      		}
-      	});
-    }
   }
 
   public boolean isSortEnabled() {
@@ -304,7 +323,7 @@ class ChainsawCyclicBufferTableModel ext
   public void clearModel() {
     reachedCapacity = false;
 
-    synchronized (unfilteredList) {
+    synchronized (mutex) {
       unfilteredList.clear();
       filteredList.clear();
       uniqueRow = 0;
@@ -320,43 +339,42 @@ class ChainsawCyclicBufferTableModel ext
   }
 
   public List getAllEvents() {
-    List list = new ArrayList(unfilteredList.size());
-
-    synchronized (unfilteredList) {
-      list.addAll(unfilteredList);
-    }
-
-    return list;
+      synchronized (mutex) {
+          return new ArrayList(unfilteredList);
+      }
   }
   
   
   public List getFilteredEvents() {
-  	List list = new ArrayList(filteredList.size());
-  	
-  	synchronized (filteredList) {
-  		list.addAll(filteredList);
+
+  	synchronized (mutex) {
+  		return new ArrayList(filteredList);
   	}
-  	
-  	return list;
   }
   
   public int getRowIndex(LoggingEvent e) {
-    synchronized (filteredList) {
+    synchronized (mutex) {
       return filteredList.indexOf(e);
     }
   }
 
     public void removePropertyFromEvents(String propName) {
         //first remove the event from any displayed events, so we can fire row updated event
-        for (int i=0;i<filteredList.size();i++) {
-            LoggingEvent event = (LoggingEvent)filteredList.get(i);
+        List filteredListCopy;
+        List unfilteredListCopy;
+        synchronized(mutex) {
+            filteredListCopy = new ArrayList(filteredList);
+            unfilteredListCopy = new ArrayList(unfilteredList);
+        }
+        for (int i=0;i<filteredListCopy.size();i++) {
+            LoggingEvent event = (LoggingEvent)filteredListCopy.get(i);
             Object result = event.removeProperty(propName);
             if (result != null) {
                 fireRowUpdated(i, false);
             }
         }
         //now remove the event from all events
-        for (Iterator iter = unfilteredList.iterator();iter.hasNext();) {
+        for (Iterator iter = unfilteredListCopy.iterator();iter.hasNext();) {
             LoggingEvent event = (LoggingEvent)iter.next();
             event.removeProperty(propName);
         }
@@ -364,7 +382,11 @@ class ChainsawCyclicBufferTableModel ext
 
     public int updateEventsWithFindRule(Rule findRule) {
         int count = 0;
-        for (Iterator iter = unfilteredList.iterator();iter.hasNext();) {
+        List unfilteredListCopy;
+        synchronized(mutex) {
+            unfilteredListCopy = new ArrayList(unfilteredList);
+        }
+        for (Iterator iter = unfilteredListCopy.iterator();iter.hasNext();) {
             ExtendedLoggingEvent extendedLoggingEvent = (ExtendedLoggingEvent) iter.next();
             extendedLoggingEvent.evaluateSearchRule(findRule);
             if (extendedLoggingEvent.isSearchMatch()) {
@@ -375,10 +397,13 @@ class ChainsawCyclicBufferTableModel ext
     }
 
     public int findColoredRow(int startLocation, boolean searchForward) {
-        synchronized (filteredList) {
+        List filteredListCopy;
+        synchronized (mutex) {
+            filteredListCopy = new ArrayList(filteredList);
+        }
         if (searchForward) {
-          for (int i = startLocation; i < filteredList.size(); i++) {
-            ExtendedLoggingEvent event = (ExtendedLoggingEvent)filteredList.get(i);
+          for (int i = startLocation; i < filteredListCopy.size(); i++) {
+            ExtendedLoggingEvent event = (ExtendedLoggingEvent)filteredListCopy.get(i);
             if (!event.getColorRuleBackground().equals(ChainsawConstants.COLOR_DEFAULT_BACKGROUND) ||
                     !event.getColorRuleForeground().equals(ChainsawConstants.COLOR_DEFAULT_FOREGROUND)) {
                 return i;
@@ -386,7 +411,7 @@ class ChainsawCyclicBufferTableModel ext
           }
           //searching forward, no colorized event was found - now start at row zero and go to startLocation
           for (int i = 0; i < startLocation; i++) {
-            ExtendedLoggingEvent event = (ExtendedLoggingEvent)filteredList.get(i);
+            ExtendedLoggingEvent event = (ExtendedLoggingEvent)filteredListCopy.get(i);
             if (!event.getColorRuleBackground().equals(ChainsawConstants.COLOR_DEFAULT_BACKGROUND) ||
                     !event.getColorRuleForeground().equals(ChainsawConstants.COLOR_DEFAULT_FOREGROUND)) {
                 return i;
@@ -394,22 +419,21 @@ class ChainsawCyclicBufferTableModel ext
           }
         } else {
           for (int i = startLocation; i > -1; i--) {
-              ExtendedLoggingEvent event = (ExtendedLoggingEvent)filteredList.get(i);
+              ExtendedLoggingEvent event = (ExtendedLoggingEvent)filteredListCopy.get(i);
               if (!event.getColorRuleBackground().equals(ChainsawConstants.COLOR_DEFAULT_BACKGROUND) ||
                       !event.getColorRuleForeground().equals(ChainsawConstants.COLOR_DEFAULT_FOREGROUND)) {
                   return i;
             }
           }
           //searching backward, no colorized event was found - now start at list.size() - 1 and go to startLocation
-          for (int i = filteredList.size() - 1; i > startLocation; i--) {
-              ExtendedLoggingEvent event = (ExtendedLoggingEvent)filteredList.get(i);
+          for (int i = filteredListCopy.size() - 1; i > startLocation; i--) {
+              ExtendedLoggingEvent event = (ExtendedLoggingEvent)filteredListCopy.get(i);
               if (!event.getColorRuleBackground().equals(ChainsawConstants.COLOR_DEFAULT_BACKGROUND) ||
                       !event.getColorRuleForeground().equals(ChainsawConstants.COLOR_DEFAULT_FOREGROUND)) {
                   return i;
             }
           }
         }
-      }
 
       return -1;
     }
@@ -423,7 +447,7 @@ class ChainsawCyclicBufferTableModel ext
   }
 
   public ExtendedLoggingEvent getRow(int row) {
-    synchronized (filteredList) {
+    synchronized (mutex) {
       if (row < filteredList.size()) {
         return (ExtendedLoggingEvent) filteredList.get(row);
       }
@@ -433,7 +457,7 @@ class ChainsawCyclicBufferTableModel ext
   }
 
   public int getRowCount() {
-    synchronized (filteredList) {
+    synchronized (mutex) {
       return filteredList.size();
     }
   }
@@ -441,7 +465,7 @@ class ChainsawCyclicBufferTableModel ext
   public Object getValueAt(int rowIndex, int columnIndex) {
     LoggingEvent event = null;
 
-    synchronized (filteredList) {
+    synchronized (mutex) {
       if (rowIndex < filteredList.size() && rowIndex > -1) {
         event = (LoggingEvent) filteredList.get(rowIndex);
       }
@@ -457,11 +481,6 @@ class ChainsawCyclicBufferTableModel ext
       info = event.getLocationInformation();
     }
 
-    if (event == null) {
-      logger.error("Invalid rowindex=" + rowIndex);
-      throw new NullPointerException("Invalid rowIndex=" + rowIndex);
-    }
-
     switch (columnIndex + 1) {
     case ChainsawColumns.INDEX_ID_COL_NAME:
 
@@ -499,25 +518,25 @@ class ChainsawCyclicBufferTableModel ext
 
     case ChainsawColumns.INDEX_CLASS_COL_NAME:
       return ((info == null)
-      || ((info != null) && "?".equals(info.getClassName()))) ? ""
+      || ("?".equals(info.getClassName()))) ? ""
                                                               : info
       .getClassName();
 
     case ChainsawColumns.INDEX_FILE_COL_NAME:
       return ((info == null)
-      || ((info != null) && "?".equals(info.getFileName()))) ? ""
+      || ("?".equals(info.getFileName()))) ? ""
                                                              : info
       .getFileName();
 
     case ChainsawColumns.INDEX_LINE_COL_NAME:
       return ((info == null)
-      || ((info != null) && "?".equals(info.getLineNumber()))) ? ""
+      || ("?".equals(info.getLineNumber()))) ? ""
                                                                : info
       .getLineNumber();
 
     case ChainsawColumns.INDEX_METHOD_COL_NAME:
       return ((info == null)
-      || ((info != null) && "?".equals(info.getMethodName()))) ? ""
+      || ("?".equals(info.getMethodName()))) ? ""
                                                                : info
       .getMethodName();
 
@@ -553,20 +572,18 @@ class ChainsawCyclicBufferTableModel ext
          * Set so we are not keeping track of IDs for all events ever received (we'd run out of
          * memory...)
          */
-    if (isCyclic()) {
+    synchronized(mutex) {
+        if (isCyclic()) {
             CyclicBufferList bufferList = (CyclicBufferList) unfilteredList;
             if (bufferList.size() == bufferList.getMaxSize()) {
-                ExtendedLoggingEvent aboutToBeDropped = (ExtendedLoggingEvent) unfilteredList.get(0);
                 reachedCapacity = true;
             }
-    }
-    unfilteredList.add(e);
-
-    if ((displayRule == null) || (displayRule.evaluate(e))) {
-      synchronized (filteredList) {
-        filteredList.add(e);
-        rowAdded = true;
-      }
+        }
+        unfilteredList.add(e);
+        if ((displayRule == null) || (displayRule.evaluate(e, null))) {
+            filteredList.add(e);
+            rowAdded = true;
+        }
     }
 
     checkForNewColumn(e);
@@ -601,18 +618,6 @@ class ChainsawCyclicBufferTableModel ext
       }
    }
 
-    public int getLastAdded() {
-    int last = 0;
-
-    if (cyclic) {
-      last = ((CyclicBufferList) filteredList).getLast() - 1;
-    } else {
-      last = filteredList.size() - 1;
-    }
-
-    return Math.max(0, last);
-  }
-
   public void fireTableEvent(final int begin, final int end, final int count) {
   	SwingHelper.invokeOnEDT(new Runnable() {
   		public void run() {
@@ -749,7 +754,9 @@ class ChainsawCyclicBufferTableModel ext
    * @see org.apache.log4j.chainsaw.EventContainer#size()
    */
   public int size() {
-    return unfilteredList.size();
+    synchronized(mutex) {
+      return unfilteredList.size();
+    }
   }
 
   private class ModelChanger implements PropertyChangeListener {
@@ -766,7 +773,7 @@ class ChainsawCyclicBufferTableModel ext
               int index = 0;
 
               try {
-                synchronized (unfilteredList) {
+                synchronized (mutex) {
                   monitor =
                     new ProgressMonitor(
                       null, "Switching models...",

Modified: logging/chainsaw/trunk/src/main/java/org/apache/log4j/chainsaw/EventContainer.java
URL: http://svn.apache.org/viewvc/logging/chainsaw/trunk/src/main/java/org/apache/log4j/chainsaw/EventContainer.java?rev=942512&r1=942511&r2=942512&view=diff
==============================================================================
--- logging/chainsaw/trunk/src/main/java/org/apache/log4j/chainsaw/EventContainer.java (original)
+++ logging/chainsaw/trunk/src/main/java/org/apache/log4j/chainsaw/EventContainer.java Sun May  9 08:30:00 2010
@@ -100,7 +100,7 @@ public interface EventContainer extends 
    * @param startRow
    * @param searchForward
    */
-  int find(Rule rule, int startRow, boolean searchForward);
+  int locate(Rule rule, int startRow, boolean searchForward);
 
   /**
    * Returns a copied list of all the event in the model.
@@ -124,11 +124,6 @@ public interface EventContainer extends 
   ExtendedLoggingEvent getRow(int row);
 
   /**
-   * Return the last added row.
-   */
-  int getLastAdded();
-
-  /**
    * Adds a row to the model.
    * @param e event
    * @return flag representing whether or not the row is being displayed (not filtered)

Modified: logging/chainsaw/trunk/src/main/java/org/apache/log4j/chainsaw/ExtendedLoggingEvent.java
URL: http://svn.apache.org/viewvc/logging/chainsaw/trunk/src/main/java/org/apache/log4j/chainsaw/ExtendedLoggingEvent.java?rev=942512&r1=942511&r2=942512&view=diff
==============================================================================
--- logging/chainsaw/trunk/src/main/java/org/apache/log4j/chainsaw/ExtendedLoggingEvent.java (original)
+++ logging/chainsaw/trunk/src/main/java/org/apache/log4j/chainsaw/ExtendedLoggingEvent.java Sun May  9 08:30:00 2010
@@ -17,6 +17,8 @@
 package org.apache.log4j.chainsaw;
 
 import java.awt.Color;
+import java.util.HashMap;
+import java.util.Map;
 
 import org.apache.log4j.rule.Rule;
 import org.apache.log4j.spi.LoggingEvent;
@@ -27,6 +29,8 @@ public class ExtendedLoggingEvent extend
     private Color colorRuleForeground = ChainsawConstants.COLOR_DEFAULT_FOREGROUND;
 
     private boolean searchMatch = false;
+    //a Map of event fields to Sets of string matches (can be used to render matches differently)
+    Map eventMatches = new HashMap();
 
     //copy constructor
     public ExtendedLoggingEvent(LoggingEvent e) {
@@ -44,9 +48,14 @@ public class ExtendedLoggingEvent extend
     }
 
     public void evaluateSearchRule(Rule searchRule) {
-        searchMatch = searchRule != null && searchRule.evaluate(this);
+        eventMatches.clear();
+        searchMatch = searchRule != null && searchRule.evaluate(this, eventMatches);
     }
 
+    public Map getSearchMatches() {
+        return eventMatches;
+    }
+    
     public Color getForeground() {
         return searchMatch ? ChainsawConstants.FIND_LOGGER_FOREGROUND : colorRuleForeground;
     }

Copied: logging/chainsaw/trunk/src/main/java/org/apache/log4j/chainsaw/JTextComponentFormatter.java (from r930795, logging/chainsaw/trunk/src/main/java/org/apache/log4j/chainsaw/JEditorPaneFormatter.java)
URL: http://svn.apache.org/viewvc/logging/chainsaw/trunk/src/main/java/org/apache/log4j/chainsaw/JTextComponentFormatter.java?p2=logging/chainsaw/trunk/src/main/java/org/apache/log4j/chainsaw/JTextComponentFormatter.java&p1=logging/chainsaw/trunk/src/main/java/org/apache/log4j/chainsaw/JEditorPaneFormatter.java&r1=930795&r2=942512&rev=942512&view=diff
==============================================================================
--- logging/chainsaw/trunk/src/main/java/org/apache/log4j/chainsaw/JEditorPaneFormatter.java (original)
+++ logging/chainsaw/trunk/src/main/java/org/apache/log4j/chainsaw/JTextComponentFormatter.java Sun May  9 08:30:00 2010
@@ -18,17 +18,18 @@ package org.apache.log4j.chainsaw;
 
 import java.awt.Font;
 
-import javax.swing.JEditorPane;
 import javax.swing.UIManager;
 import javax.swing.text.Document;
+import javax.swing.text.JTextComponent;
 import javax.swing.text.html.HTMLDocument;
 
 /**
  * Apply system font and size (normal size + 1) rule if the JEditorPane document contains html.
  */
-public class JEditorPaneFormatter {
-    public static void applySystemFontAndSize(JEditorPane editorPane) {
-        Document document = editorPane.getDocument();
+public class JTextComponentFormatter
+{
+    public static void applySystemFontAndSize(JTextComponent textComponent) {
+        Document document = textComponent.getDocument();
         if (document instanceof HTMLDocument) {
           Font font = UIManager.getFont("Label.font");
           String bodyRule = "body { font-family: " + font.getFamily() + "; font-size: " + (font.getSize() + 1) + "pt; }";

Modified: logging/chainsaw/trunk/src/main/java/org/apache/log4j/chainsaw/LogPanel.java
URL: http://svn.apache.org/viewvc/logging/chainsaw/trunk/src/main/java/org/apache/log4j/chainsaw/LogPanel.java?rev=942512&r1=942511&r2=942512&view=diff
==============================================================================
--- logging/chainsaw/trunk/src/main/java/org/apache/log4j/chainsaw/LogPanel.java (original)
+++ logging/chainsaw/trunk/src/main/java/org/apache/log4j/chainsaw/LogPanel.java Sun May  9 08:30:00 2010
@@ -439,6 +439,16 @@ public class LogPanel extends DockablePa
         }
       });
 
+      preferenceModel.addPropertyChangeListener(
+        "highlightSearchMatchText",
+        new PropertyChangeListener() {
+          public void propertyChange(PropertyChangeEvent evt) {
+            renderer.setHighlightSearchMatchText(
+              ((Boolean) evt.getNewValue()).booleanValue());
+            table.tableChanged(new TableModelEvent(tableModel));
+          }
+        });
+
     preferenceModel.addPropertyChangeListener(
       "detailPaneVisible",
       new PropertyChangeListener() {
@@ -1972,7 +1982,7 @@ public class LogPanel extends DockablePa
    * @return row number or -1 if row with log4jid property with that number was not found
    */
   int setSelectedEvent(int eventNumber) {
-      int row = tableModel.find(ExpressionRule.getRule("prop.log4jid == " + eventNumber), 0, true);
+      int row = tableModel.locate(ExpressionRule.getRule("prop.log4jid == " + eventNumber), 0, true);
       if (row > -1) {
         preferenceModel.setScrollToBottom(false);
 
@@ -2412,7 +2422,13 @@ public class LogPanel extends DockablePa
 
     if (findRule != null) {
       try {
-        int nextRow = tableModel.find(findRule, table.getSelectedRow() + 1, true);
+        int filteredEventsSize = getFilteredEvents().size();
+        int startRow = table.getSelectedRow() + 1;
+          if (startRow > filteredEventsSize - 1) {
+              startRow = 0;
+          }
+        //no selected row would return -1, so we'd start at row zero
+        int nextRow = tableModel.locate(findRule, startRow, true);
 
         if (nextRow > -1) {
           table.scrollToRow(nextRow);
@@ -2435,8 +2451,12 @@ public class LogPanel extends DockablePa
 
     if (findRule != null) {
       try {
-        final int previousRow =
-          tableModel.find(findRule, table.getSelectedRow() - 1, false);
+        int startRow = table.getSelectedRow() - 1;
+        int filteredEventsSize = getFilteredEvents().size();
+        if (startRow < 0) {
+            startRow = filteredEventsSize - 1;
+        }
+        final int previousRow = tableModel.locate(findRule, startRow, false);
 
         if (previousRow > -1) {
           table.scrollToRow(previousRow);
@@ -2504,6 +2524,7 @@ public class LogPanel extends DockablePa
     }
     preferenceModel.setDetailPaneVisible(event.asBoolean("detailPaneVisible"));
     preferenceModel.setLogTreePanelVisible(event.asBoolean("logTreePanelVisible"));
+    preferenceModel.setHighlightSearchMatchText(event.asBoolean("highlightSearchMatchText"));
     //re-add columns to the table in the order provided from the list
     for (Iterator iter = sortedColumnList.iterator(); iter.hasNext();) {
       TableColumn element = (TableColumn) iter.next();
@@ -2591,7 +2612,12 @@ public class LogPanel extends DockablePa
   }
 
     public void findNextMarker() {
-      final int nextRow = tableModel.find(findMarkerRule, table.getSelectedRow() + 1, true);
+      int startRow = table.getSelectedRow() + 1;
+      int filteredEventsSize = getFilteredEvents().size();
+      if (startRow > filteredEventsSize - 1) {
+          startRow = 0;
+      }
+      final int nextRow = tableModel.locate(findMarkerRule, startRow, true);
 
       if (nextRow > -1) {
         table.scrollToRow(nextRow);
@@ -2599,7 +2625,12 @@ public class LogPanel extends DockablePa
     }
 
     public void findPreviousMarker() {
-        final int previousRow = tableModel.find(findMarkerRule, table.getSelectedRow() - 1, false);
+        int startRow = table.getSelectedRow() - 1;
+        int filteredEventsSize = getFilteredEvents().size();
+        if (startRow < 0) {
+            startRow = filteredEventsSize - 1;
+        }
+        final int previousRow = tableModel.locate(findMarkerRule, startRow, false);
 
         if (previousRow > -1) {
           table.scrollToRow(previousRow);
@@ -2669,9 +2700,15 @@ public class LogPanel extends DockablePa
                   // they stopped typing recently, but have stopped for at least
                   // 1 sample period. lets apply the filter
                   //                logger.debug("Typed something recently applying filter");
-                  if (filterText != null && (!(filterText.getText().equals(lastFilterText)))) {
+                  if (!(filterText.getText().equals(lastFilterText))) {
                     lastFilterText = filterText.getText();
-                    setFilter();
+                    EventQueue.invokeLater(new Runnable()
+                    {
+                        public void run()
+                        {
+                            setFilter();
+                        }
+                    });
                   }
                 } else {
                   // they stopped typing a while ago, let's forget about it
@@ -2929,7 +2966,7 @@ public class LogPanel extends DockablePa
 				      	SwingHelper.invokeOnEDT(new Runnable() {
 				      		public void run() {
 				      			detail.setDocument(doc);
-                                JEditorPaneFormatter.applySystemFontAndSize(detail);
+                                JTextComponentFormatter.applySystemFontAndSize(detail);
 				      			detail.setCaretPosition(0);
                                 lastRow = selectedRow;
 				      		}
@@ -2946,7 +2983,7 @@ public class LogPanel extends DockablePa
 		      	SwingHelper.invokeOnEDT(new Runnable() {
 		      		public void run() {
 		      			detail.setDocument(doc);
-                        JEditorPaneFormatter.applySystemFontAndSize(detail);
+                        JTextComponentFormatter.applySystemFontAndSize(detail);
 		      			detail.setCaretPosition(0);
                         lastRow = selectedRow;
 		      		}

Modified: logging/chainsaw/trunk/src/main/java/org/apache/log4j/chainsaw/LogPanelPreferenceModel.java
URL: http://svn.apache.org/viewvc/logging/chainsaw/trunk/src/main/java/org/apache/log4j/chainsaw/LogPanelPreferenceModel.java?rev=942512&r1=942511&r2=942512&view=diff
==============================================================================
--- logging/chainsaw/trunk/src/main/java/org/apache/log4j/chainsaw/LogPanelPreferenceModel.java (original)
+++ logging/chainsaw/trunk/src/main/java/org/apache/log4j/chainsaw/LogPanelPreferenceModel.java Sun May  9 08:30:00 2010
@@ -81,6 +81,7 @@ public class LogPanelPreferenceModel imp
   private Collection hiddenLoggers = new HashSet();
   private String timeZone;
   private boolean wrapMsg;
+  private boolean highlightSearchMatchText;
 
     /**
    * Returns an <b>unmodifiable</b> list of the columns.
@@ -220,6 +221,7 @@ public class LogPanelPreferenceModel imp
     setDateFormatPattern(model.getDateFormatPattern());
     setLevelIcons(model.isLevelIcons());
     setWrapMessage(model.isWrapMessage());
+    setHighlightSearchMatchText(model.isHighlightSearchMatchText());
     setTimeZone(model.getTimeZone());
     setToolTips(model.isToolTips());
     setScrollToBottom(model.isScrollToBottom());
@@ -254,6 +256,10 @@ public class LogPanelPreferenceModel imp
     return wrapMsg;
   }
 
+  public boolean isHighlightSearchMatchText() {
+    return highlightSearchMatchText;
+  }
+
   /**
    * @param levelIcons
    */
@@ -269,6 +275,15 @@ public class LogPanelPreferenceModel imp
     this.wrapMsg = wrapMsg;
     propertySupport.firePropertyChange("wrapMessage", !wrapMsg, wrapMsg);
   }
+
+    /**
+     * @param highlightSearchMatchText
+     */
+    public void setHighlightSearchMatchText(boolean highlightSearchMatchText) {
+      this.highlightSearchMatchText = highlightSearchMatchText;
+      propertySupport.firePropertyChange("highlightSearchMatchText", !highlightSearchMatchText, highlightSearchMatchText);
+    }
+
   /**
    * @param loggerPrecision - an integer representing the number of packages to display, 
    * or an empty string representing 'display all packages' 

Modified: logging/chainsaw/trunk/src/main/java/org/apache/log4j/chainsaw/LogPanelPreferencePanel.java
URL: http://svn.apache.org/viewvc/logging/chainsaw/trunk/src/main/java/org/apache/log4j/chainsaw/LogPanelPreferencePanel.java?rev=942512&r1=942511&r2=942512&view=diff
==============================================================================
--- logging/chainsaw/trunk/src/main/java/org/apache/log4j/chainsaw/LogPanelPreferencePanel.java (original)
+++ logging/chainsaw/trunk/src/main/java/org/apache/log4j/chainsaw/LogPanelPreferencePanel.java Sun May  9 08:30:00 2010
@@ -244,6 +244,7 @@ public class LogPanelPreferencePanel ext
     private final JRadioButton rdLevelIcons = new JRadioButton("Icons");
     private final JRadioButton rdLevelText = new JRadioButton("Text");
     private final JCheckBox wrapMessage = new JCheckBox("Display entire message and marker text in the table (multi-line rows)");
+    private final JCheckBox highlightSearchMatchText = new JCheckBox("Highlight search match text");
     private JRadioButton rdLast;
 
     //~ Constructors ==========================================================
@@ -364,6 +365,7 @@ public class LogPanelPreferencePanel ext
 
       add(levelFormatPanel);
       add(wrapMessage);
+      add(highlightSearchMatchText);
 
       JPanel loggerFormatPanel = new JPanel();
       loggerFormatPanel.setLayout(
@@ -512,6 +514,17 @@ public class LogPanelPreferencePanel ext
       };
 
       wrapMessage.addActionListener(wrapMessageListener);
+
+      ActionListener highlightSearchMatchTextListener = new ActionListener()
+      {
+          public void actionPerformed(ActionEvent e)
+          {
+              preferenceModel.setHighlightSearchMatchText(highlightSearchMatchText.isSelected());
+          }
+      };
+
+      highlightSearchMatchText.addActionListener(highlightSearchMatchTextListener);
+
       rdLevelIcons.addActionListener(levelIconListener);
       rdLevelText.addActionListener(levelIconListener);
 
@@ -535,6 +548,17 @@ public class LogPanelPreferencePanel ext
               wrapMessage.setSelected(value);
             }
           });
+
+        preferenceModel.addPropertyChangeListener(
+          "highlightSearchMatchText", new PropertyChangeListener()
+          {
+            public void propertyChange(PropertyChangeEvent evt)
+            {
+              boolean value = ((Boolean) evt.getNewValue()).booleanValue();
+              highlightSearchMatchText.setSelected(value);
+            }
+          });
+
     }
   }
 

Modified: logging/chainsaw/trunk/src/main/java/org/apache/log4j/chainsaw/LogUI.java
URL: http://svn.apache.org/viewvc/logging/chainsaw/trunk/src/main/java/org/apache/log4j/chainsaw/LogUI.java?rev=942512&r1=942511&r2=942512&view=diff
==============================================================================
--- logging/chainsaw/trunk/src/main/java/org/apache/log4j/chainsaw/LogUI.java (original)
+++ logging/chainsaw/trunk/src/main/java/org/apache/log4j/chainsaw/LogUI.java Sun May  9 08:30:00 2010
@@ -1042,7 +1042,7 @@ public class LogUI extends JFrame implem
 
     try {
       tutorialArea.setPage(ChainsawConstants.TUTORIAL_URL);
-      JEditorPaneFormatter.applySystemFontAndSize(tutorialArea);
+      JTextComponentFormatter.applySystemFontAndSize(tutorialArea);
 
       container.add(new JScrollPane(tutorialArea), BorderLayout.CENTER);
     } catch (Exception e) {
@@ -1751,6 +1751,7 @@ public class LogUI extends JFrame implem
    *                    The FQN of the LookANdFeel
    */
   private static void applyLookAndFeel(String lookAndFeelClassName) {
+    UIManager.put("swing.boldMetal", Boolean.FALSE);
     if (
       UIManager.getLookAndFeel().getClass().getName().equals(
           lookAndFeelClassName)) {

Modified: logging/chainsaw/trunk/src/main/java/org/apache/log4j/chainsaw/LoggerNameTreePanel.java
URL: http://svn.apache.org/viewvc/logging/chainsaw/trunk/src/main/java/org/apache/log4j/chainsaw/LoggerNameTreePanel.java?rev=942512&r1=942511&r2=942512&view=diff
==============================================================================
--- logging/chainsaw/trunk/src/main/java/org/apache/log4j/chainsaw/LoggerNameTreePanel.java (original)
+++ logging/chainsaw/trunk/src/main/java/org/apache/log4j/chainsaw/LoggerNameTreePanel.java Sun May  9 08:30:00 2010
@@ -40,6 +40,7 @@ import java.util.Enumeration;
 import java.util.HashSet;
 import java.util.Iterator;
 import java.util.List;
+import java.util.Map;
 import java.util.Set;
 
 import javax.swing.AbstractAction;
@@ -158,7 +159,7 @@ final class LoggerNameTreePanel extends 
     setLayout(new BorderLayout());
 
     ruleDelegate = new AbstractRule() {
-    	public boolean evaluate(LoggingEvent e)
+    	public boolean evaluate(LoggingEvent e, Map matches)
         {
           String currentlySelectedLoggerName = getCurrentlySelectedLoggerName();
           boolean hidden = e.getLoggerName() != null && isHidden(e.getLoggerName());
@@ -180,7 +181,7 @@ final class LoggerNameTreePanel extends 
     colorRuleDelegate = 
         new AbstractRule()
         {
-          public boolean evaluate(LoggingEvent e)
+          public boolean evaluate(LoggingEvent e, Map matches)
           {
             boolean hidden = e.getLoggerName() != null && isHidden(e.getLoggerName());
             String currentlySelectedLoggerName = getCurrentlySelectedLoggerName();
@@ -380,11 +381,13 @@ final class LoggerNameTreePanel extends 
    *
    * @param e DOCUMENT ME!
    *
+   * @param matches
    * @return DOCUMENT ME!
    */
-  public boolean evaluate(LoggingEvent e)
+  public boolean evaluate(LoggingEvent e, Map matches)
   {
-    return ruleDelegate.evaluate(e);
+    //no need for logger to build matches
+    return ruleDelegate.evaluate(e, null);
   }
   
   public Rule getLoggerColorRule() {

Modified: logging/chainsaw/trunk/src/main/java/org/apache/log4j/chainsaw/RuleMediator.java
URL: http://svn.apache.org/viewvc/logging/chainsaw/trunk/src/main/java/org/apache/log4j/chainsaw/RuleMediator.java?rev=942512&r1=942511&r2=942512&view=diff
==============================================================================
--- logging/chainsaw/trunk/src/main/java/org/apache/log4j/chainsaw/RuleMediator.java (original)
+++ logging/chainsaw/trunk/src/main/java/org/apache/log4j/chainsaw/RuleMediator.java Sun May  9 08:30:00 2010
@@ -19,6 +19,7 @@ package org.apache.log4j.chainsaw;
 
 import java.beans.PropertyChangeEvent;
 import java.beans.PropertyChangeListener;
+import java.util.Map;
 
 import org.apache.log4j.rule.AbstractRule;
 import org.apache.log4j.rule.Rule;
@@ -56,11 +57,12 @@ public class RuleMediator extends Abstra
   /* (non-Javadoc)
    * @see org.apache.log4j.chainsaw.rule.Rule#evaluate(org.apache.log4j.spi.LoggingEvent)
    */
-  public boolean evaluate(LoggingEvent e) {
+  public boolean evaluate(LoggingEvent e, Map matches) {
     boolean accepts = true;
 
+    //no need to have rulemediator build matches
     if (inclusionRule != null) {
-      accepts = inclusionRule.evaluate(e);
+      accepts = inclusionRule.evaluate(e, null);
     }
 
     if (!accepts) {
@@ -68,7 +70,7 @@ public class RuleMediator extends Abstra
     }
 
     if (loggerRule != null) {
-      accepts = loggerRule.evaluate(e);
+      accepts = loggerRule.evaluate(e, null);
     }
 
     if (!accepts) {
@@ -76,7 +78,7 @@ public class RuleMediator extends Abstra
     }
 
     if (refinementRule != null) {
-      accepts = refinementRule.evaluate(e);
+      accepts = refinementRule.evaluate(e, null);
     }
 
     if (!accepts) {
@@ -84,7 +86,7 @@ public class RuleMediator extends Abstra
     }
 
     if (exclusionRule != null) {
-      accepts = exclusionRule.evaluate(e);
+      accepts = exclusionRule.evaluate(e, null);
     }
 
     return accepts;

Modified: logging/chainsaw/trunk/src/main/java/org/apache/log4j/chainsaw/TableColorizingRenderer.java
URL: http://svn.apache.org/viewvc/logging/chainsaw/trunk/src/main/java/org/apache/log4j/chainsaw/TableColorizingRenderer.java?rev=942512&r1=942511&r2=942512&view=diff
==============================================================================
--- logging/chainsaw/trunk/src/main/java/org/apache/log4j/chainsaw/TableColorizingRenderer.java (original)
+++ logging/chainsaw/trunk/src/main/java/org/apache/log4j/chainsaw/TableColorizingRenderer.java Sun May  9 08:30:00 2010
@@ -20,6 +20,7 @@ package org.apache.log4j.chainsaw;
 import java.awt.Color;
 import java.awt.Component;
 import java.awt.Dimension;
+import java.awt.Font;
 import java.awt.font.FontRenderContext;
 import java.awt.font.LineBreakMeasurer;
 import java.awt.font.TextAttribute;
@@ -42,17 +43,21 @@ import javax.swing.JComponent;
 import javax.swing.JLabel;
 import javax.swing.JPanel;
 import javax.swing.JTable;
-import javax.swing.JTextArea;
+import javax.swing.JTextPane;
 import javax.swing.SwingConstants;
 import javax.swing.UIManager;
 import javax.swing.border.Border;
 import javax.swing.table.DefaultTableCellRenderer;
 import javax.swing.table.TableColumn;
+import javax.swing.text.html.HTMLDocument;
+import javax.swing.text.html.HTMLEditorKit;
 
 import org.apache.log4j.chainsaw.color.RuleColorizer;
 import org.apache.log4j.chainsaw.icons.LevelIconFactory;
 import org.apache.log4j.helpers.Constants;
+import org.apache.log4j.helpers.Transform;
 import org.apache.log4j.rule.Rule;
+import org.apache.log4j.spi.LoggingEventFieldResolver;
 
 
 /**
@@ -70,6 +75,7 @@ public class TableColorizingRenderer ext
   private RuleColorizer colorizer;
   private boolean levelUseIcons = false;
   private boolean wrap = false;
+  private boolean highlightSearchMatchText;
   private DateFormat dateFormatInUse = DATE_FORMATTER;
   private int loggerPrecision = 0;
   private boolean toolTipsVisible;
@@ -89,11 +95,12 @@ public class TableColorizingRenderer ext
   private static final Border RIGHT_EMPTY_BORDER = BorderFactory.createEmptyBorder(borderWidth, 0, borderWidth, borderWidth);
 
   private final JLabel levelLabel = new JLabel();
-  private final JLabel generalLabel = new JLabel();
+  private JLabel generalLabel = new JLabel();
 
   private final JPanel multiLinePanel = new JPanel();
   private final JPanel generalPanel = new JPanel();
   private final JPanel levelPanel = new JPanel();
+
     /**
    * Creates a new TableColorizingRenderer object.
    */
@@ -128,7 +135,7 @@ public class TableColorizingRenderer ext
     TableColumn tableColumn = table.getColumnModel().getColumn(col);
 
     //null unless needed
-    JTextArea multiLineTextArea = null;
+    JTextPane multiLineTextPane = null;
     JLabel label = (JLabel)super.getTableCellRendererComponent(table, value,
         isSelected, hasFocus, row, col);
     //chainsawcolumns uses one-based indexing
@@ -140,12 +147,19 @@ public class TableColorizingRenderer ext
     if (loggingEvent == null) {
         return super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, col);
     }
+    Map matches = loggingEvent.getSearchMatches();
 
     JComponent component;
     switch (colIndex) {
     case ChainsawColumns.INDEX_THROWABLE_COL_NAME:
       if (value instanceof String[] && ((String[])value).length > 0){
-        generalLabel.setText(((String[]) value)[0]);
+          //exception string is split into an array..just highlight the first line completely if anything in the exception matches if we have a match for the exception field
+          Set exceptionMatches = (Set)matches.get(LoggingEventFieldResolver.EXCEPTION_FIELD);
+          if (exceptionMatches != null && exceptionMatches.size() > 0) {
+              generalLabel.setText(bold(((String[])value)[0]));
+          } else {
+              generalLabel.setText(((String[])value)[0]);
+          }
       } else {
         generalLabel.setText("");
       }
@@ -161,43 +175,80 @@ public class TableColorizingRenderer ext
           break;
         }
       }
-      generalLabel.setText(logger.substring(startPos + 1));
+      generalLabel.setText(buildHighlightString(matches.get(LoggingEventFieldResolver.LOGGER_FIELD), logger.substring(startPos + 1)));
       component = generalPanel;
       break;
     case ChainsawColumns.INDEX_ID_COL_NAME:
+        generalLabel.setText(buildHighlightString(matches.get(LoggingEventFieldResolver.PROP_FIELD + "LOG4JID"), value.toString()));
+        component = generalPanel;
+        break;
     case ChainsawColumns.INDEX_CLASS_COL_NAME:
+        generalLabel.setText(buildHighlightString(matches.get(LoggingEventFieldResolver.CLASS_FIELD), value.toString()));
+        component = generalPanel;
+        break;
     case ChainsawColumns.INDEX_FILE_COL_NAME:
+        generalLabel.setText(buildHighlightString(matches.get(LoggingEventFieldResolver.FILE_FIELD), value.toString()));
+        component = generalPanel;
+        break;
     case ChainsawColumns.INDEX_LINE_COL_NAME:
+        generalLabel.setText(buildHighlightString(matches.get(LoggingEventFieldResolver.LINE_FIELD), value.toString()));
+        component = generalPanel;
+        break;
     case ChainsawColumns.INDEX_NDC_COL_NAME:
+        generalLabel.setText(buildHighlightString(matches.get(LoggingEventFieldResolver.NDC_FIELD), value.toString()));
+        component = generalPanel;
+        break;
     case ChainsawColumns.INDEX_THREAD_COL_NAME:
+        generalLabel.setText(buildHighlightString(matches.get(LoggingEventFieldResolver.THREAD_FIELD), value.toString()));
+        component = generalPanel;
+        break;
     case ChainsawColumns.INDEX_TIMESTAMP_COL_NAME:
+        //timestamp matches contain the millis..not the display text..just highlight if we have a match for the timestamp field
+        Set timestampMatches = (Set)matches.get(LoggingEventFieldResolver.TIMESTAMP_FIELD);
+        if (timestampMatches != null && timestampMatches.size() > 0) {
+            generalLabel.setText(bold(value.toString()));
+        } else {
+            generalLabel.setText(value.toString());
+        }
+        component = generalPanel;
+        break;
     case ChainsawColumns.INDEX_METHOD_COL_NAME:
-      generalLabel.setText(value.toString());
-      component = generalPanel;
-      break;
-
+        generalLabel.setText(buildHighlightString(matches.get(LoggingEventFieldResolver.METHOD_FIELD), value.toString()));
+        component = generalPanel;
+        break;
     case ChainsawColumns.INDEX_LOG4J_MARKER_COL_NAME:
     case ChainsawColumns.INDEX_MESSAGE_COL_NAME:
         int width = tableColumn.getWidth();
 
-        String thisString = value.toString().trim();
+        String thisString;
+        if (colIndex == ChainsawColumns.INDEX_LOG4J_MARKER_COL_NAME) {
+            //property keys are set as all uppercase
+            thisString = buildHighlightString(matches.get(LoggingEventFieldResolver.PROP_FIELD + ChainsawConstants.LOG4J_MARKER_COL_NAME_LOWERCASE.toUpperCase()), value.toString().trim());
+        } else {
+            thisString = buildHighlightString(matches.get(LoggingEventFieldResolver.MSG_FIELD), value.toString().trim());
+        }
         int tableRowHeight = table.getRowHeight(row);
-        multiLineTextArea = new JTextArea();
-        multiLineTextArea.setMargin(null);
-        multiLineTextArea.setEditable(false);
-        multiLineTextArea.setLineWrap(wrap);
-        multiLineTextArea.setWrapStyleWord(wrap);
-        multiLineTextArea.setFont(label.getFont());
-        multiLineTextArea.setText(thisString);
+        multiLineTextPane = new JTextPane();
+        multiLineTextPane.setEditorKit(new HTMLEditorKit());
+        multiLineTextPane.setMargin(null);
+        multiLineTextPane.setEditable(false);
+        multiLineTextPane.setFont(label.getFont());
+        setText(thisString);
         multiLinePanel.removeAll();
-        multiLinePanel.add(multiLineTextArea);
+        multiLinePanel.add(multiLineTextPane);
+        HTMLDocument document = new HTMLDocument();
+        multiLineTextPane.setDocument(document);
+        Font font = label.getFont();
+        String bodyRule = "body { font-family: " + font.getFamily() + "; font-size: " + (font.getSize()) + "pt; }";
+        ((HTMLDocument)multiLineTextPane.getDocument()).getStyleSheet().addRule(bodyRule);
+        multiLineTextPane.setText(thisString);
         if (wrap) {
             Map paramMap = new HashMap();
-            paramMap.put(TextAttribute.FONT, multiLineTextArea.getFont());
+            paramMap.put(TextAttribute.FONT, multiLineTextPane.getFont());
 
             int calculatedHeight = calculateHeight(thisString, width, paramMap);
             //set preferred size to default height
-            multiLineTextArea.setSize(new Dimension(width, calculatedHeight));
+            multiLineTextPane.setSize(new Dimension(width, calculatedHeight));
 
             int multiLinePanelPrefHeight = multiLinePanel.getPreferredSize().height;
             if(tableRowHeight < multiLinePanelPrefHeight) {
@@ -218,7 +269,7 @@ public class TableColorizingRenderer ext
         }
       } else {
         levelLabel.setIcon(null);
-        levelLabel.setText(value.toString());
+        levelLabel.setText(buildHighlightString(matches.get(LoggingEventFieldResolver.LEVEL_FIELD), value.toString()));
         if (!toolTipsVisible) {
             levelLabel.setToolTipText(null);
         }
@@ -245,7 +296,9 @@ public class TableColorizingRenderer ext
             }
         }
         if (thisProp != null) {
-            generalLabel.setText(loggingEvent.getProperty(thisProp));
+            String propKey = LoggingEventFieldResolver.PROP_FIELD + thisProp.toUpperCase();
+            Set propKeyMatches = (Set)matches.get(propKey);
+            generalLabel.setText(buildHighlightString(propKeyMatches, loggingEvent.getProperty(thisProp)));
         } else {
             generalLabel.setText("");
         }
@@ -257,7 +310,7 @@ public class TableColorizingRenderer ext
     Color foreground;
     Rule loggerRule = colorizer.getLoggerRule();
     //use logger colors in table instead of event colors if event passes logger rule
-    if (loggerRule != null && loggerRule.evaluate(loggingEvent)) {
+    if (loggerRule != null && loggerRule.evaluate(loggingEvent, null)) {
         background = ChainsawConstants.FIND_LOGGER_BACKGROUND;
         foreground = ChainsawConstants.FIND_LOGGER_FOREGROUND;
     } else {
@@ -280,10 +333,10 @@ public class TableColorizingRenderer ext
     component.setForeground(foreground);
 
     //set the colors of the components inside 'component'
-    if (multiLineTextArea != null)
+    if (multiLineTextPane != null)
     {
-        multiLineTextArea.setBackground(background);
-        multiLineTextArea.setForeground(foreground);
+        multiLineTextPane.setBackground(background);
+        multiLineTextPane.setForeground(foreground);
     }
     levelLabel.setBackground(background);
     levelLabel.setForeground(foreground);
@@ -408,4 +461,78 @@ public class TableColorizingRenderer ext
      }
      return Math.max(ChainsawConstants.DEFAULT_ROW_HEIGHT, (int) height);
     }
+
+    private String buildHighlightString(Object matchSet, String input) {
+        if (!highlightSearchMatchText) {
+            return Transform.escapeTags(input);
+        }
+        if (matchSet instanceof Set) {
+            Set thisSet = (Set)matchSet;
+            //start with result as input and replace each time
+            String result = input;
+            for (Iterator iter = thisSet.iterator();iter.hasNext();) {
+                String thisEntry = iter.next().toString();
+                result = bold(result, thisEntry);
+            }
+            return "<html>" + escapeAllButBoldTags(result) + "</html>";
+        }
+        return Transform.escapeTags(input);
+    }
+
+    private String escapeAllButBoldTags(String input) {
+            if (!highlightSearchMatchText) {
+                return Transform.escapeTags(input);
+            }
+            String lowerInput = input.toLowerCase();
+            String lowerBoldStart = "<b>";
+            String lowerBoldEnd = "</b>";
+            int boldStartLength = lowerBoldStart.length();
+            int boldEndLength = lowerBoldEnd.length();
+            int firstIndex = 0;
+            int currentIndex = 0;
+            StringBuffer newString = new StringBuffer("");
+            while ((currentIndex = lowerInput.indexOf(lowerBoldStart, firstIndex)) > -1) {
+                newString.append(Transform.escapeTags(input.substring(firstIndex, currentIndex)));
+                newString.append(lowerBoldStart);
+                firstIndex = currentIndex + boldStartLength;
+                currentIndex = lowerInput.indexOf(lowerBoldEnd, firstIndex);
+                if (currentIndex > -1) {
+                    newString.append(Transform.escapeTags(input.substring(firstIndex, currentIndex)));
+                    newString.append(lowerBoldEnd);
+                    firstIndex = currentIndex + boldEndLength;
+                }
+            }
+            newString.append(Transform.escapeTags(input.substring(firstIndex, input.length())));
+            return newString.toString();
+        }
+
+    private String bold(String input) {
+        if (!highlightSearchMatchText) {
+            return Transform.escapeTags(input);
+        }
+        return "<html><b>" + Transform.escapeTags(input) + "</b></html>";
+    }
+    
+    private String bold(String input, String textToBold) {
+        String lowerInput = input.toLowerCase();
+        String lowerTextToBold = textToBold.toLowerCase();
+        int textToBoldLength = textToBold.length();
+        int firstIndex = 0;
+        int currentIndex = 0;
+        StringBuffer newString = new StringBuffer("");
+        while ((currentIndex = lowerInput.indexOf(lowerTextToBold, firstIndex)) > -1) {
+            newString.append(input.substring(firstIndex, currentIndex));
+            newString.append("<b>");
+            newString.append(input.substring(currentIndex, currentIndex + textToBoldLength));
+            newString.append("</b>");
+            firstIndex = currentIndex + textToBoldLength;
+        }
+        newString.append(input.substring(firstIndex, input.length()));
+        return newString.toString();
+    }
+
+    public void setHighlightSearchMatchText(boolean highlightSearchMatchText)
+    {
+        this.highlightSearchMatchText = highlightSearchMatchText;
+    }
 }

Modified: logging/chainsaw/trunk/src/main/java/org/apache/log4j/chainsaw/WelcomePanel.java
URL: http://svn.apache.org/viewvc/logging/chainsaw/trunk/src/main/java/org/apache/log4j/chainsaw/WelcomePanel.java?rev=942512&r1=942511&r2=942512&view=diff
==============================================================================
--- logging/chainsaw/trunk/src/main/java/org/apache/log4j/chainsaw/WelcomePanel.java (original)
+++ logging/chainsaw/trunk/src/main/java/org/apache/log4j/chainsaw/WelcomePanel.java Sun May  9 08:30:00 2010
@@ -74,7 +74,7 @@ public class WelcomePanel extends JPanel
         textInfo.setEditable(false);
         textInfo.setPreferredSize(new Dimension(320, 240));
         textInfo.setPage(helpURL);
-        JEditorPaneFormatter.applySystemFontAndSize(textInfo);
+        JTextComponentFormatter.applySystemFontAndSize(textInfo);
         textInfo.addHyperlinkListener(
           new HyperlinkListener() {
             public void hyperlinkUpdate(HyperlinkEvent e) {
@@ -104,7 +104,7 @@ public class WelcomePanel extends JPanel
             urlStack.push(textInfo.getPage());
             textInfo.setPage(url);
             //not all pages displayed in the Welcome Panel are html-based (example receiver config is an xml file)..
-            JEditorPaneFormatter.applySystemFontAndSize(textInfo);
+            JTextComponentFormatter.applySystemFontAndSize(textInfo);
             urlToolbar.updateToolbar();
           } catch (IOException e) {
             e.printStackTrace();

Modified: logging/chainsaw/trunk/src/main/java/org/apache/log4j/chainsaw/color/RuleColorizer.java
URL: http://svn.apache.org/viewvc/logging/chainsaw/trunk/src/main/java/org/apache/log4j/chainsaw/color/RuleColorizer.java?rev=942512&r1=942511&r2=942512&view=diff
==============================================================================
--- logging/chainsaw/trunk/src/main/java/org/apache/log4j/chainsaw/color/RuleColorizer.java (original)
+++ logging/chainsaw/trunk/src/main/java/org/apache/log4j/chainsaw/color/RuleColorizer.java Sun May  9 08:30:00 2010
@@ -182,7 +182,7 @@ public class RuleColorizer implements Co
       while (iter.hasNext()) {
         ColorRule rule = (ColorRule) iter.next();
 
-        if ((rule.getBackgroundColor() != null) && (rule.evaluate(event))) {
+        if ((rule.getBackgroundColor() != null) && (rule.evaluate(event, null))) {
           return rule.getBackgroundColor();
         }
       }
@@ -199,7 +199,7 @@ public class RuleColorizer implements Co
       while (iter.hasNext()) {
         ColorRule rule = (ColorRule) iter.next();
 
-        if ((rule.getForegroundColor() != null) && (rule.evaluate(event))) {
+        if ((rule.getForegroundColor() != null) && (rule.evaluate(event, null))) {
           return rule.getForegroundColor();
         }
       }

Modified: logging/chainsaw/trunk/src/main/java/org/apache/log4j/chainsaw/layout/LayoutEditorPane.java
URL: http://svn.apache.org/viewvc/logging/chainsaw/trunk/src/main/java/org/apache/log4j/chainsaw/layout/LayoutEditorPane.java?rev=942512&r1=942511&r2=942512&view=diff
==============================================================================
--- logging/chainsaw/trunk/src/main/java/org/apache/log4j/chainsaw/layout/LayoutEditorPane.java (original)
+++ logging/chainsaw/trunk/src/main/java/org/apache/log4j/chainsaw/layout/LayoutEditorPane.java Sun May  9 08:30:00 2010
@@ -44,7 +44,7 @@ import javax.swing.event.DocumentListene
 
 import org.apache.log4j.Logger;
 import org.apache.log4j.chainsaw.ChainsawConstants;
-import org.apache.log4j.chainsaw.JEditorPaneFormatter;
+import org.apache.log4j.chainsaw.JTextComponentFormatter;
 import org.apache.log4j.chainsaw.icons.ChainsawIcons;
 import org.apache.log4j.spi.LocationInfo;
 import org.apache.log4j.spi.LoggingEvent;
@@ -205,7 +205,7 @@ public final class LayoutEditorPane exte
     okButton.setToolTipText("Accepts the current Pattern layout and will apply it to the Log Panel");
     cancelButton.setToolTipText("Closes this dialog and discards your changes");
 
-    JEditorPaneFormatter.applySystemFontAndSize(previewer);
+    JTextComponentFormatter.applySystemFontAndSize(previewer);
       
     previewer.setEditable(false);
     patternEditor.setPreferredSize(new Dimension(240, 240));

Modified: logging/chainsaw/trunk/src/main/resources/org/apache/log4j/chainsaw/help/release-notes.html
URL: http://svn.apache.org/viewvc/logging/chainsaw/trunk/src/main/resources/org/apache/log4j/chainsaw/help/release-notes.html?rev=942512&r1=942511&r2=942512&view=diff
==============================================================================
--- logging/chainsaw/trunk/src/main/resources/org/apache/log4j/chainsaw/help/release-notes.html (original)
+++ logging/chainsaw/trunk/src/main/resources/org/apache/log4j/chainsaw/help/release-notes.html Sun May  9 08:30:00 2010
@@ -9,7 +9,11 @@
 <br>
 <b>NOTE:</b> The mechanism and format used to persist settings in Chainsaw is subject to change.  If you are experiencing problems displaying events in Chainsaw, please delete everything in the $user.dir/.chainsaw directory and restart Chainsaw.
 <br>
-<h1>1.99.99</h1>
+<h1>2.0</h1>
+<h2>9 May 2010</h2>
+<ul>
+<li>Added preference to display matching search text in the table as bold (on by default)</li>
+</ul>
 <h2>2 May 2010</h2>
 <ul>
 <li>Added preference to line wrap the marker field in the table (multi-line rows)</li>

Modified: logging/chainsaw/trunk/src/main/resources/org/apache/log4j/chainsaw/prefs/default.properties
URL: http://svn.apache.org/viewvc/logging/chainsaw/trunk/src/main/resources/org/apache/log4j/chainsaw/prefs/default.properties?rev=942512&r1=942511&r2=942512&view=diff
==============================================================================
--- logging/chainsaw/trunk/src/main/resources/org/apache/log4j/chainsaw/prefs/default.properties (original)
+++ logging/chainsaw/trunk/src/main/resources/org/apache/log4j/chainsaw/prefs/default.properties Sun May  9 08:30:00 2010
@@ -25,4 +25,5 @@ loggerPrecision=
 toolTips=false
 scrollToBottom=true
 logTreePanelVisible=true
-detailPaneVisible=true
\ No newline at end of file
+detailPaneVisible=true
+highlightSearchMatchText=true
\ No newline at end of file



Mime
View raw message