You are viewing a plain text version of this content. The canonical link for it is here.
Posted to general@logging.apache.org by sd...@apache.org on 2010/09/14 07:22:47 UTC

svn commit: r996758 - in /logging/chainsaw/trunk/src/main: java/org/apache/log4j/chainsaw/ java/org/apache/log4j/chainsaw/color/ resources/org/apache/log4j/chainsaw/help/ resources/org/apache/log4j/chainsaw/layout/ resources/org/apache/log4j/chainsaw/p...

Author: sdeboy
Date: Tue Sep 14 05:22:46 2010
New Revision: 996758

URL: http://svn.apache.org/viewvc?rev=996758&view=rev
Log:
- Added new 'Display timestamp delta between displayed events as space between rows' preference to log panel preferences screen - feature adds a gap between rows proportionate to the time delta between displayed events (off by default)
- Added 'millisdelta' dynamic property to events, which is always updated to represent the number of millis between this event and the displayed event in (thisrow-1) - this property can be used in color and find rules (but using it in a filtering rule will change the delta since the displayed rows are changing)
- Renamed 'log4j.marker' property to 'marker' (prop.marker can now be used in expression)

Modified:
    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/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/TableColorizingRenderer.java
    logging/chainsaw/trunk/src/main/java/org/apache/log4j/chainsaw/color/ColorPanel.java
    logging/chainsaw/trunk/src/main/java/org/apache/log4j/chainsaw/color/RuleColorizer.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/layout/DefaultDetailLayout.html
    logging/chainsaw/trunk/src/main/resources/org/apache/log4j/chainsaw/prefs/default.properties

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=996758&r1=996757&r2=996758&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 Tue Sep 14 05:22:46 2010
@@ -31,6 +31,8 @@ import java.net.URL;
 public class ChainsawConstants {
   private ChainsawConstants(){}
   
+  public static final String MILLIS_DELTA = "MILLISDELTA";
+
   public static final String DEFAULT_COLOR_RULE_NAME = "Default";
   public static final Color COLOR_DEFAULT_BACKGROUND = new Color(255,255,255);
   public static final Color COLOR_DEFAULT_FOREGROUND = Color.BLACK;
@@ -67,7 +69,7 @@ public class ChainsawConstants {
 
   //COLUMN NAMES
   static final String LOGGER_COL_NAME = "LOGGER";
-  static final String LOG4J_MARKER_COL_NAME_LOWERCASE = "log4j.marker"; //properties are case-sensitive-using lowercase for easier entry
+  static final String LOG4J_MARKER_COL_NAME_LOWERCASE = "marker";
   static final String TIMESTAMP_COL_NAME = "TIMESTAMP";
   static final String LEVEL_COL_NAME = "LEVEL";
   static final String THREAD_COL_NAME = "THREAD";

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=996758&r1=996757&r2=996758&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 Tue Sep 14 05:22:46 2010
@@ -135,20 +135,25 @@ class ChainsawCyclicBufferTableModel ext
             previousSize = filteredList.size();
             filteredList.clear();
             if (displayRule == null) {
+                LoggingEvent lastEvent = null;
                 for (Iterator iter = unfilteredList.iterator();iter.hasNext();) {
                     ExtendedLoggingEvent e = (ExtendedLoggingEvent)iter.next();
                     e.setDisplayed(true);
+                    updateEventMillisDelta(e, lastEvent);
                     filteredList.add(e);
+                    lastEvent = e;
                 }
             } else {
                 Iterator iter = unfilteredList.iterator();
-
+                LoggingEvent lastEvent = null;
                 while (iter.hasNext()) {
                   ExtendedLoggingEvent e = (ExtendedLoggingEvent) iter.next();
 
                   if (displayRule.evaluate(e, null)) {
                     e.setDisplayed(true);
                     filteredList.add(e);
+                    updateEventMillisDelta(e, lastEvent);
+                    lastEvent = e;
                   } else {
                     e.setDisplayed(false);
                   }
@@ -312,9 +317,12 @@ class ChainsawCyclicBufferTableModel ext
           sort = (sortEnabled && filteredListSize > 0);
         if (sort) {
             //reset display (used to ensure row height is updated)
+            LoggingEvent lastEvent = null;
             for (Iterator iter = filteredList.iterator();iter.hasNext();) {
                 ExtendedLoggingEvent e = (ExtendedLoggingEvent)iter.next();
                 e.setDisplayed(true);
+                updateEventMillisDelta(e, lastEvent);
+                lastEvent = e;
             }
             Collections.sort(
               filteredList,
@@ -620,9 +628,15 @@ class ChainsawCyclicBufferTableModel ext
                 reachedCapacity = true;
             }
         }
+        int unfilteredSize = unfilteredList.size();
+        LoggingEvent lastEvent = null;
+        if (unfilteredSize > 0) {
+            lastEvent = (LoggingEvent) unfilteredList.get(unfilteredSize - 1);
+        }
         unfilteredList.add(e);
         if ((displayRule == null) || (displayRule.evaluate(e, null))) {
             e.setDisplayed(true);
+            updateEventMillisDelta(e, lastEvent);
             filteredList.add(e);
             rowAdded = true;
         } else {
@@ -635,6 +649,15 @@ class ChainsawCyclicBufferTableModel ext
     return rowAdded;
   }
 
+    private void updateEventMillisDelta(ExtendedLoggingEvent e, LoggingEvent lastEvent) {
+      if (lastEvent != null) {
+        e.setPreviousDisplayedEventTimestamp(lastEvent.getTimeStamp());
+      } else {
+        //delta to same event = 0
+        e.setPreviousDisplayedEventTimestamp(e.getTimeStamp());
+      }
+    }
+
    private void checkForNewColumn(ExtendedLoggingEvent e)
    {
       /**

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=996758&r1=996757&r2=996758&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 Tue Sep 14 05:22:46 2010
@@ -101,10 +101,17 @@ public class ExtendedLoggingEvent extend
     {
         markerHeight = DEFAULT_HEIGHT;
         msgHeight = DEFAULT_HEIGHT;
+        if (!b) {
+            setProperty(ChainsawConstants.MILLIS_DELTA, "");
+        }
     }
 
     public String toString() {
         return "ExtendedLoggingEvent - id: " + getProperty("log4jid") + " background: " + getBackground() + ", foreground: " + getForeground() + ", msg: " + getMessage();
     }
 
+    public void setPreviousDisplayedEventTimestamp(long previousDisplayedEventTimeStamp)
+    {
+        setProperty(ChainsawConstants.MILLIS_DELTA, String.valueOf(timeStamp - previousDisplayedEventTimeStamp));
+    }
 }

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=996758&r1=996757&r2=996758&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 Tue Sep 14 05:22:46 2010
@@ -689,7 +689,7 @@ public class LogPanel extends DockablePa
               ((double) totalCount) / ((ChainsawCyclicBufferTableModel) tableModel)
               .getMaxSize();
             String msg = null;
-
+            boolean wasWarning = warning75 || warning100;
             if ((percent > 0.75) && (percent < 1.0) && !warning75) {
               msg =
                 "Warning :: " + formatter.format(percent) + " of the '"
@@ -708,7 +708,7 @@ public class LogPanel extends DockablePa
                 warning100 = false;
             }
 
-            if (msg != null) {
+            if (msg != null && wasWarning) {
               MessageCenter.getInstance().getLogger().info(msg);
             }
           }
@@ -891,7 +891,7 @@ public class LogPanel extends DockablePa
         }
       });
 
-    renderer = new TableColorizingRenderer(colorizer, applicationPreferenceModel, tableModel);
+    renderer = new TableColorizingRenderer(colorizer, applicationPreferenceModel, tableModel, preferenceModel);
     renderer.setToolTipsVisible(preferenceModel.isToolTips());
 
     table.setDefaultRenderer(Object.class, renderer);

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=996758&r1=996757&r2=996758&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 Tue Sep 14 05:22:46 2010
@@ -89,6 +89,7 @@ public class LogPanelPreferenceModel imp
   private String clearTableExpression;
   //default to cyclic mode
   private boolean cyclic = true;
+  private boolean showMillisDeltaAsGap;
 
     /**
    * Returns an <b>unmodifiable</b> list of the columns.
@@ -389,6 +390,10 @@ public class LogPanelPreferenceModel imp
     return scrollToBottom;
   }
 
+
+  public final boolean isShowMillisDeltaAsGap() {
+      return showMillisDeltaAsGap;
+  }
   /**
    * @param scrollToBottom
    */
@@ -399,6 +404,16 @@ public class LogPanelPreferenceModel imp
       "scrollToBottom", oldValue, this.scrollToBottom);
   }
 
+    /**
+     * @param showMillisDeltaAsGap
+     */
+    public final void setShowMillisDeltaAsGap(boolean showMillisDeltaAsGap) {
+      boolean oldValue = this.showMillisDeltaAsGap;
+      this.showMillisDeltaAsGap = showMillisDeltaAsGap;
+      propertySupport.firePropertyChange(
+        "showMillisDeltaAsGap", oldValue, this.showMillisDeltaAsGap);
+    }
+
   public final void setThumbnailBarToolTips(boolean thumbnailBarToolTips) {
       boolean oldValue = this.thumbnailBarToolTips;
       this.thumbnailBarToolTips = thumbnailBarToolTips;

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=996758&r1=996757&r2=996758&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 Tue Sep 14 05:22:46 2010
@@ -583,6 +583,8 @@ public class LogPanelPreferencePanel ext
       new JCheckBox("Show Logger Tree");
     private final JCheckBox scrollToBottom =
       new JCheckBox("Scroll to bottom (view tracks with new events)");
+    private final JCheckBox showMillisDeltaAsGap =
+      new JCheckBox("Display timestamp delta between displayed events as space between rows");
     private final JCheckBox toolTips =
       new JCheckBox("Show Event Detail Tooltips");
     private final JCheckBox thumbnailBarToolTips =
@@ -615,11 +617,13 @@ public class LogPanelPreferencePanel ext
       detailPanelVisible.setAlignmentX(Component.LEFT_ALIGNMENT);
       loggerTreePanel.setAlignmentX(Component.LEFT_ALIGNMENT);
       scrollToBottom.setAlignmentX(Component.LEFT_ALIGNMENT);
+      showMillisDeltaAsGap.setAlignmentX(Component.LEFT_ALIGNMENT);
       add(toolTips);
       add(thumbnailBarToolTips);
       add(detailPanelVisible);
       add(loggerTreePanel);
       add(scrollToBottom);
+      add(showMillisDeltaAsGap);
       JPanel clearPanel = new JPanel(new BorderLayout());
       clearPanel.setAlignmentX(Component.LEFT_ALIGNMENT);
       clearPanel.add(new JLabel("Clear all events if expression matches"), BorderLayout.NORTH);
@@ -707,6 +711,22 @@ public class LogPanelPreferencePanel ext
           }
         });
 
+      showMillisDeltaAsGap.addActionListener(new ActionListener()
+      {
+          public void actionPerformed(ActionEvent e)
+          {
+              preferenceModel.setShowMillisDeltaAsGap(showMillisDeltaAsGap.isSelected());
+          }
+      });
+
+      preferenceModel.addPropertyChangeListener("showMillisDeltaAsGap", new PropertyChangeListener()
+      {
+          public void propertyChange(PropertyChangeEvent evt)
+          {
+              boolean value = ((Boolean) evt.getNewValue()).booleanValue();
+              showMillisDeltaAsGap.setSelected(value);
+          }
+      });
       preferenceModel.addPropertyChangeListener(
         "scrollToBottom", new PropertyChangeListener()
         {

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=996758&r1=996757&r2=996758&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 Tue Sep 14 05:22:46 2010
@@ -100,13 +100,6 @@ public class TableColorizingRenderer ext
   private static int borderWidth = 2;
 
   private static Color borderColor = (Color)UIManager.get("Table.selectionBackground");
-  private static final Border LEFT_BORDER = BorderFactory.createMatteBorder(borderWidth, borderWidth, borderWidth, 0, borderColor);
-  private static final Border MIDDLE_BORDER = BorderFactory.createMatteBorder(borderWidth, 0, borderWidth, 0, borderColor);
-  private static final Border RIGHT_BORDER = BorderFactory.createMatteBorder(borderWidth, 0, borderWidth, borderWidth, borderColor);
-
-  private static final Border LEFT_EMPTY_BORDER = BorderFactory.createEmptyBorder(borderWidth, borderWidth, borderWidth, 0);
-  private static final Border MIDDLE_EMPTY_BORDER = BorderFactory.createEmptyBorder(borderWidth, 0, borderWidth, 0);
-  private static final Border RIGHT_EMPTY_BORDER = BorderFactory.createEmptyBorder(borderWidth, 0, borderWidth, borderWidth);
 
   private final JTextPane levelTextPane = new JTextPane();
   private JTextPane singleLineTextPane = new JTextPane();
@@ -121,12 +114,15 @@ public class TableColorizingRenderer ext
   private int maxHeight;
   private boolean useRelativeTimesToPrevious;
   private EventContainer eventContainer;
+  private LogPanelPreferenceModel logPanelPreferenceModel;
 
     /**
    * Creates a new TableColorizingRenderer object.
    */
-  public TableColorizingRenderer(RuleColorizer colorizer, ApplicationPreferenceModel applicationPreferenceModel, EventContainer eventContainer) {
+  public TableColorizingRenderer(RuleColorizer colorizer, ApplicationPreferenceModel applicationPreferenceModel,
+                                 EventContainer eventContainer, LogPanelPreferenceModel logPanelPreferenceModel) {
     this.applicationPreferenceModel = applicationPreferenceModel;
+    this.logPanelPreferenceModel = logPanelPreferenceModel;
     this.eventContainer = eventContainer;
     multiLinePanel.setLayout(new BoxLayout(multiLinePanel, BoxLayout.Y_AXIS));
     generalPanel.setLayout(new BoxLayout(generalPanel, BoxLayout.Y_AXIS));
@@ -172,7 +168,9 @@ public class TableColorizingRenderer ext
   public Component getTableCellRendererComponent(
     final JTable table, Object value, boolean isSelected, boolean hasFocus,
     int row, int col) {
-    value = formatField(value, row);
+    EventContainer container = (EventContainer) table.getModel();
+    ExtendedLoggingEvent loggingEvent = container.getRow(row);
+    value = formatField(value, row, loggingEvent);
     TableColumn tableColumn = table.getColumnModel().getColumn(col);
 
     JLabel label = (JLabel)super.getTableCellRendererComponent(table, value,
@@ -180,12 +178,17 @@ public class TableColorizingRenderer ext
     //chainsawcolumns uses one-based indexing
     int colIndex = tableColumn.getModelIndex() + 1;
 
-    EventContainer container = (EventContainer) table.getModel();
-    ExtendedLoggingEvent loggingEvent = container.getRow(row);
     //no event, use default renderer
     if (loggingEvent == null) {
         return super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, col);
     }
+    long delta = 0;
+    if (row > 0) {
+        LoggingEvent previous = eventContainer.getRow(row - 1);
+        float deltaFactor = .002F;
+        delta = (long) ((loggingEvent.getTimeStamp() - previous.getTimeStamp()) * deltaFactor);
+    }
+
     Map matches = loggingEvent.getSearchMatches();
 
     JComponent component;
@@ -400,26 +403,54 @@ public class TableColorizingRenderer ext
     updateColors(levelTextPane, background, foreground);
     updateColors(singleLineTextPane, background, foreground);
 
-    if (isSelected) {
-      if (col == 0) {
-        component.setBorder(LEFT_BORDER);
-      } else if (col == table.getColumnCount() - 1) {
-        component.setBorder(RIGHT_BORDER);
-      } else {
-        component.setBorder(MIDDLE_BORDER);
-      }
-    } else {
       if (col == 0) {
-        component.setBorder(LEFT_EMPTY_BORDER);
+        component.setBorder(getLeftBorder(isSelected, delta));
       } else if (col == table.getColumnCount() - 1) {
-        component.setBorder(RIGHT_EMPTY_BORDER);
+        component.setBorder(getRightBorder(isSelected, delta));
       } else {
-        component.setBorder(MIDDLE_EMPTY_BORDER);
+        component.setBorder(getMiddleBorder(isSelected, delta));
       }
-    }
+      
     return component;
   }
 
+    private Border getLeftBorder(boolean isSelected, long delta) {
+        Border LEFT_BORDER = BorderFactory.createMatteBorder(borderWidth, borderWidth, borderWidth, 0, borderColor);
+        Border LEFT_EMPTY_BORDER = BorderFactory.createEmptyBorder(borderWidth, borderWidth, borderWidth, 0);
+
+        Border innerBorder =isSelected?LEFT_BORDER : LEFT_EMPTY_BORDER;
+        if (delta == 0 || !wrap || !logPanelPreferenceModel.isShowMillisDeltaAsGap()) {
+            return innerBorder;
+        } else {
+            Border outerBorder = BorderFactory.createMatteBorder((int) Math.max(borderWidth, delta), 0, 0, 0, getDeltaColor());
+            return BorderFactory.createCompoundBorder(outerBorder, innerBorder);
+        }
+    }
+
+    private Border getRightBorder(boolean isSelected, long delta) {
+        Border RIGHT_BORDER = BorderFactory.createMatteBorder(borderWidth, 0, borderWidth, borderWidth, borderColor);
+        Border RIGHT_EMPTY_BORDER = BorderFactory.createEmptyBorder(borderWidth, 0, borderWidth, borderWidth);
+        Border innerBorder =isSelected?RIGHT_BORDER : RIGHT_EMPTY_BORDER;
+        if (delta == 0 || !wrap || !logPanelPreferenceModel.isShowMillisDeltaAsGap()) {
+            return innerBorder;
+        } else {
+            Border outerBorder = BorderFactory.createMatteBorder((int) Math.max(borderWidth, delta), 0, 0, 0, getDeltaColor());
+            return BorderFactory.createCompoundBorder(outerBorder, innerBorder);
+        }
+    }
+
+    private Border getMiddleBorder(boolean isSelected, long delta) {
+        Border MIDDLE_BORDER = BorderFactory.createMatteBorder(borderWidth, 0, borderWidth, 0, borderColor);
+        Border MIDDLE_EMPTY_BORDER = BorderFactory.createEmptyBorder(borderWidth, 0, borderWidth, 0);
+        Border innerBorder =isSelected ?MIDDLE_BORDER : MIDDLE_EMPTY_BORDER;
+        if (delta == 0 || !wrap || !logPanelPreferenceModel.isShowMillisDeltaAsGap()) {
+            return innerBorder;
+        } else {
+            Border outerBorder = BorderFactory.createMatteBorder((int)Math.max(borderWidth, delta), 0, 0, 0, getDeltaColor());
+            return BorderFactory.createCompoundBorder(outerBorder, innerBorder);
+        }
+    }
+
     private void updateColors(JTextPane textPane, Color background, Color foreground)
     {
         StyledDocument styledDocument = textPane.getStyledDocument();
@@ -429,7 +460,21 @@ public class TableColorizingRenderer ext
         textPane.setBackground(background);
     }
 
-    /**
+    //use a lighter version of search color as the delta color
+    private Color getDeltaColor() {
+        float factor = 1.3F;
+        Color search = applicationPreferenceModel.getSearchBackgroundColor();
+
+        return new Color(boundColorValue((int)(search.getRed() * factor)),
+                boundColorValue((int)(search.getGreen() * factor)),
+                boundColorValue((int)(search.getBlue() * factor)));
+    }
+
+    private int boundColorValue(int colorValue) {
+      return Math.min(Math.max(0, colorValue), 255);
+    }
+    
+  /**
    * Changes the Date Formatting object to be used for rendering dates.
    * @param formatter
    */
@@ -457,30 +502,25 @@ public class TableColorizingRenderer ext
   /**
    *Format date field
    *
-   * @param o object
+   * @param field object
    *
    * @param renderingRow
    * @return formatted object
    */
-  private Object formatField(Object o, int renderingRow) {
-    if (!(o instanceof Date)) {
-      return (o == null ? "" : o);
+  private Object formatField(Object field, int renderingRow, ExtendedLoggingEvent loggingEvent) {
+    if (!(field instanceof Date)) {
+      return (field == null ? "" : field);
     }
 
     //handle date field
     if (useRelativeTimesToFixedTime) {
-        return "" + (((Date)o).getTime() - relativeTimestampBase);
+        return "" + (((Date)field).getTime() - relativeTimestampBase);
     }
     if (useRelativeTimesToPrevious) {
-        if (renderingRow == 0) {
-            return "0";
-        } else {
-            LoggingEvent previous = eventContainer.getRow(renderingRow - 1);
-            return "" + (((Date)o).getTime() - previous.getTimeStamp());
-        }
+        return loggingEvent.getProperty(ChainsawConstants.MILLIS_DELTA);
     }
 
-    return dateFormatInUse.format((Date) o);
+    return dateFormatInUse.format((Date) field);
   }
 
     /**

Modified: logging/chainsaw/trunk/src/main/java/org/apache/log4j/chainsaw/color/ColorPanel.java
URL: http://svn.apache.org/viewvc/logging/chainsaw/trunk/src/main/java/org/apache/log4j/chainsaw/color/ColorPanel.java?rev=996758&r1=996757&r2=996758&view=diff
==============================================================================
--- logging/chainsaw/trunk/src/main/java/org/apache/log4j/chainsaw/color/ColorPanel.java (original)
+++ logging/chainsaw/trunk/src/main/java/org/apache/log4j/chainsaw/color/ColorPanel.java Tue Sep 14 05:22:46 2010
@@ -858,6 +858,9 @@ public class ColorPanel extends JPanel
     public Component getTableCellRendererComponent(
       JTable thisTable, Object value, boolean isSelected, boolean hasFocus, int row,
       int column) {
+      if (value == null) {
+          return panel;
+      }
 
       Vector v = tableModel.getDataVector();
       Vector r = (Vector) v.elementAt(row);

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=996758&r1=996757&r2=996758&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 Tue Sep 14 05:22:46 2010
@@ -69,7 +69,7 @@ public class RuleColorizer implements Co
 
   private final String DEFAULT_WARN_EXPRESSION = "level == WARN";
   private final String DEFAULT_FATAL_ERROR_EXCEPTION_EXPRESSION = "level == FATAL || level == ERROR || exception exists";
-  private final String DEFAULT_MARKER_EXPRESSION = "prop.log4j.marker exists";
+  private final String DEFAULT_MARKER_EXPRESSION = "prop.marker exists";
 
   public RuleColorizer() {
     List rulesList = new ArrayList();

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=996758&r1=996757&r2=996758&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 Tue Sep 14 05:22:46 2010
@@ -10,6 +10,12 @@
 <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>2.1</h1>
+<h2>13 Sep 2010</h2>
+<ul>
+<li>Added new 'Display timestamp delta between displayed events as space between rows' preference to log panel preferences screen - feature adds a gap between rows proportionate to the time delta between displayed events (off by default)</li>
+<li>Added 'millisdelta' dynamic property to events, which is always updated to represent the number of millis between this event and the displayed event in (thisrow-1) - this property can be used in color and find rules (but using it in a filtering rule will change the delta since the displayed rows are changing)</li>
+<li>Renamed 'log4j.marker' property to 'marker' (prop.marker can now be used in expression)</li>
+</ul>
 <h2>11 Sep 2010</h2>
 <ul>
 <li>Added 'Show times relative to previous rows' feature - displays millis to last displayed event in the timestamp field</li>

Modified: logging/chainsaw/trunk/src/main/resources/org/apache/log4j/chainsaw/layout/DefaultDetailLayout.html
URL: http://svn.apache.org/viewvc/logging/chainsaw/trunk/src/main/resources/org/apache/log4j/chainsaw/layout/DefaultDetailLayout.html?rev=996758&r1=996757&r2=996758&view=diff
==============================================================================
--- logging/chainsaw/trunk/src/main/resources/org/apache/log4j/chainsaw/layout/DefaultDetailLayout.html (original)
+++ logging/chainsaw/trunk/src/main/resources/org/apache/log4j/chainsaw/layout/DefaultDetailLayout.html Tue Sep 14 05:22:46 2010
@@ -21,6 +21,6 @@
 <TR><TD><B>Time</B><TD>%d</td></tr>
 <TR><TD><B>Thread</B><TD>%t</td></tr>
 <TR><TD><B>Message</B><TD>%m</td></tr>
-<TR><TD><B>Marker</B><TD>%X{log4j.marker}</td></tr>
+<TR><TD><B>Marker</B><TD>%X{marker}</td></tr>
 <TR><TD><B>Throwable</B><TD><pre>%throwable</pre></td></tr>
 </table></body></html>
\ No newline at end of file

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=996758&r1=996757&r2=996758&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 Tue Sep 14 05:22:46 2010
@@ -17,14 +17,14 @@
 # The Default Settings for Chainsaw
 # ====================================
 
-# These next settings define the location and dimenions of the main
+# These next settings define the location and dimensions of the main
 # window when it is first realized on startup
 main.window.x=0
 main.window.y=0
 main.window.width=1024
 main.window.height=768
 
-table.columns.order=ID,TIMESTAMP,LOG4J.MARKER,LEVEL,LOGGER,MESSAGE,THROWABLE,THREAD,NDC,CLASS,METHOD,FILE,LINE
+table.columns.order=ID,TIMESTAMP,MARKER,LEVEL,LOGGER,MESSAGE,THROWABLE,THREAD,NDC,CLASS,METHOD,FILE,LINE
 table.columns.widths=50,80,95,50,100,300,100,150,150,300,150,100,100
 
 SavedConfigs.Size=0