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/15 10:20:35 UTC

svn commit: r997222 - in /logging/chainsaw/trunk/src/main: java/org/apache/log4j/chainsaw/ resources/org/apache/log4j/chainsaw/help/

Author: sdeboy
Date: Wed Sep 15 08:20:34 2010
New Revision: 997222

URL: http://svn.apache.org/viewvc?rev=997222&view=rev
Log:
Updated table rendering logic when in line-wrap mode
Updated row selection logic (goto/search) to make sure event is on the screen
Capped the event time delta rendering in the table to a max of 50 pixels tall

Modified:
    logging/chainsaw/trunk/src/main/java/org/apache/log4j/chainsaw/JSortTable.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/TableColorizingRenderer.java
    logging/chainsaw/trunk/src/main/resources/org/apache/log4j/chainsaw/help/release-notes.html

Modified: logging/chainsaw/trunk/src/main/java/org/apache/log4j/chainsaw/JSortTable.java
URL: http://svn.apache.org/viewvc/logging/chainsaw/trunk/src/main/java/org/apache/log4j/chainsaw/JSortTable.java?rev=997222&r1=997221&r2=997222&view=diff
==============================================================================
--- logging/chainsaw/trunk/src/main/java/org/apache/log4j/chainsaw/JSortTable.java (original)
+++ logging/chainsaw/trunk/src/main/java/org/apache/log4j/chainsaw/JSortTable.java Wed Sep 15 08:20:34 2010
@@ -41,6 +41,7 @@ public class JSortTable extends JTable i
   protected int sortedColumnIndex = -1;
   protected boolean sortedColumnAscending = true;
   private String sortedColumn;
+  private int lastSelectedColumn = -1;
 
   public JSortTable() {
     super();
@@ -63,6 +64,19 @@ public class JSortTable extends JTable i
     initSortHeader();
   }
 
+  public void changeSelection(int rowIndex, int columnIndex, boolean toggle, boolean extend) {
+    //selection of the msg field causes rendering to flash...skip over it
+    int colToSelect = columnIndex;
+    //CHAINSAW columns are 1-based indexes
+    if (columnIndex + 1 == ChainsawColumns.INDEX_MESSAGE_COL_NAME) {
+        colToSelect = lastSelectedColumn < columnIndex ? columnIndex + 1 : columnIndex - 1;
+        super.changeSelection(rowIndex, colToSelect, toggle, extend);
+    } else {
+        super.changeSelection(rowIndex, columnIndex, toggle, extend);
+    }
+    lastSelectedColumn = colToSelect;
+  }
+
   protected void initSortHeader() {
     JTableHeader header = getTableHeader();
     header.setDefaultRenderer(new SortHeaderRenderer());
@@ -95,13 +109,14 @@ public class JSortTable extends JTable i
 
   //Allow synchronous updates if already on the EDT
   public void scrollTo(final int row, final int col) {
+    final int currentRow = getSelectedRow();
     SwingHelper.invokeOnEDT(new Runnable() {
       public void run() {
         if ((row > -1) && (row < getRowCount())) {
           try {
             //get the requested row off of the bottom and top of the screen by making the 5 rows around the requested row visible
-            int currentRow = getSelectedRow();
-            //if new past current row, scroll to display the 5th row past new selected row
+            //if new past current row, scroll to display the 20th row past new selected row
+            scrollRectToVisible(getCellRect(row, col, true));
             if (row > currentRow) {
                 scrollRectToVisible(getCellRect(row + 5, col, true));
             }

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=997222&r1=997221&r2=997222&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 Wed Sep 15 08:20:34 2010
@@ -644,6 +644,8 @@ public class LogPanel extends DockablePa
      */
     tableModel = new ChainsawCyclicBufferTableModel(cyclicBufferSize, colorizer);
     table = new JSortTable(tableModel);
+    table.setColumnSelectionAllowed(false);
+    table.setRowSelectionAllowed(true);
 
     //we've mapped f2, shift f2 and ctrl-f2 to marker-related actions, unmap them from the table
     table.getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT).put(KeyStroke.getKeyStroke("F2"), "none");
@@ -3276,6 +3278,7 @@ public class LogPanel extends DockablePa
         JTextField textField = new JTextField();
         Set cellEditorListeners = new HashSet();
         private ExtendedLoggingEvent currentEvent;
+        private final Object mutex = new Object();
 
         public Object getCellEditorValue()
         {
@@ -3302,7 +3305,12 @@ public class LogPanel extends DockablePa
             }
             tableModel.fireRowUpdated(table.getSelectedRow(), true);
             ChangeEvent event = new ChangeEvent(table);
-            for (Iterator iter = cellEditorListeners.iterator();iter.hasNext();) {
+            Set cellEditorListenersCopy;
+            synchronized(mutex) {
+                cellEditorListenersCopy = new HashSet(cellEditorListeners);
+            }
+
+            for (Iterator iter = cellEditorListenersCopy.iterator();iter.hasNext();) {
                 ((CellEditorListener)iter.next()).editingStopped(event);
             }
             return true;
@@ -3310,20 +3318,29 @@ public class LogPanel extends DockablePa
 
         public void cancelCellEditing()
         {
+            Set cellEditorListenersCopy;
+            synchronized(mutex) {
+                cellEditorListenersCopy = new HashSet(cellEditorListeners);
+            }
+
            ChangeEvent event = new ChangeEvent(table);
-           for (Iterator iter = cellEditorListeners.iterator();iter.hasNext();) {
+           for (Iterator iter = cellEditorListenersCopy.iterator();iter.hasNext();) {
                ((CellEditorListener)iter.next()).editingCanceled(event);
            }
         }
 
         public void addCellEditorListener(CellEditorListener l)
         {
-            cellEditorListeners.add(l);
+            synchronized(mutex) {
+                cellEditorListeners.add(l);
+            }
         }
 
         public void removeCellEditorListener(CellEditorListener l)
         {
-            cellEditorListeners.remove(l);
+            synchronized(mutex) {
+                cellEditorListeners.remove(l);
+            }
         }
 
         public Component getTableCellEditorComponent(JTable table, Object value, boolean isSelected, int row, int column)

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=997222&r1=997221&r2=997222&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 Wed Sep 15 08:20:34 2010
@@ -254,6 +254,7 @@ public class LogPanelPreferenceModel imp
     setVisibleColumns(model.getVisibleColumns());
     setHiddenLoggers(model.getHiddenLoggers());
     setHiddenExpression(model.getHiddenExpression());
+    setShowMillisDeltaAsGap(model.isShowMillisDeltaAsGap());
     setClearTableExpression(model.getClearTableExpression());
   }
 

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=997222&r1=997221&r2=997222&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 Wed Sep 15 08:20:34 2010
@@ -17,6 +17,7 @@
 
 package org.apache.log4j.chainsaw;
 
+import java.awt.BorderLayout;
 import java.awt.Color;
 import java.awt.Component;
 import java.awt.Dimension;
@@ -104,9 +105,9 @@ public class TableColorizingRenderer ext
   private final JTextPane levelTextPane = new JTextPane();
   private JTextPane singleLineTextPane = new JTextPane();
 
-  private final JPanel multiLinePanel = new JPanel();
-  private final JPanel generalPanel = new JPanel();
-  private final JPanel levelPanel = new JPanel();
+  private final JPanel multiLinePanel = new JPanel(new BorderLayout());
+  private final JPanel generalPanel = new JPanel(new BorderLayout());
+  private final JPanel levelPanel = new JPanel(new BorderLayout());
   private ApplicationPreferenceModel applicationPreferenceModel;
   private JTextPane multiLineTextPane;
   private MutableAttributeSet boldAttributeSet;
@@ -143,7 +144,6 @@ public class TableColorizingRenderer ext
     levelTextPane.setOpaque(true);
     levelTextPane.setText("");
 
-    generalPanel.add(singleLineTextPane);
     levelPanel.add(levelTextPane);
 
     this.colorizer = colorizer;
@@ -172,6 +172,7 @@ public class TableColorizingRenderer ext
     ExtendedLoggingEvent loggingEvent = container.getRow(row);
     value = formatField(value, row, loggingEvent);
     TableColumn tableColumn = table.getColumnModel().getColumn(col);
+    int width = tableColumn.getWidth();
 
     JLabel label = (JLabel)super.getTableCellRendererComponent(table, value,
         isSelected, hasFocus, row, col);
@@ -186,7 +187,7 @@ public class TableColorizingRenderer ext
     if (row > 0) {
         LoggingEvent previous = eventContainer.getRow(row - 1);
         float deltaFactor = .002F;
-        delta = (long) ((loggingEvent.getTimeStamp() - previous.getTimeStamp()) * deltaFactor);
+        delta = Math.min(50, Math.max(0, (long) ((loggingEvent.getTimeStamp() - previous.getTimeStamp()) * deltaFactor)));
     }
 
     Map matches = loggingEvent.getSearchMatches();
@@ -210,6 +211,7 @@ public class TableColorizingRenderer ext
       } else {
         singleLineTextPane.setText("");
       }
+      layoutRenderingPanel(generalPanel, singleLineTextPane, delta, isSelected, width, col, table);
       component = generalPanel;
       break;
     case ChainsawColumns.INDEX_LOGGER_COL_NAME:
@@ -222,38 +224,45 @@ public class TableColorizingRenderer ext
           break;
         }
       }
-      singleLineTextPane.setText(logger.substring(startPos + 1));
-      setHighlightAttributesInternal(matches.get(LoggingEventFieldResolver.LOGGER_FIELD), (StyledDocument) singleLineTextPane.getDocument());
-      component = generalPanel;
+        singleLineTextPane.setText(logger.substring(startPos + 1));
+        setHighlightAttributesInternal(matches.get(LoggingEventFieldResolver.LOGGER_FIELD), (StyledDocument) singleLineTextPane.getDocument());
+        layoutRenderingPanel(generalPanel, singleLineTextPane, delta, isSelected, width, col, table);
+        component = generalPanel;
       break;
     case ChainsawColumns.INDEX_ID_COL_NAME:
         singleLineTextPane.setText(value.toString());
         setHighlightAttributesInternal(matches.get(LoggingEventFieldResolver.PROP_FIELD + "LOG4JID"), (StyledDocument) singleLineTextPane.getDocument());
+        layoutRenderingPanel(generalPanel, singleLineTextPane, delta, isSelected, width, col, table);
         component = generalPanel;
         break;
     case ChainsawColumns.INDEX_CLASS_COL_NAME:
         singleLineTextPane.setText(value.toString());
         setHighlightAttributesInternal(matches.get(LoggingEventFieldResolver.CLASS_FIELD), (StyledDocument) singleLineTextPane.getDocument());
+        layoutRenderingPanel(generalPanel, singleLineTextPane, delta, isSelected, width, col, table);
         component = generalPanel;
         break;
     case ChainsawColumns.INDEX_FILE_COL_NAME:
         singleLineTextPane.setText(value.toString());
         setHighlightAttributesInternal(matches.get(LoggingEventFieldResolver.FILE_FIELD), (StyledDocument) singleLineTextPane.getDocument());
+        layoutRenderingPanel(generalPanel, singleLineTextPane, delta, isSelected, width, col, table);
         component = generalPanel;
         break;
     case ChainsawColumns.INDEX_LINE_COL_NAME:
         singleLineTextPane.setText(value.toString());
         setHighlightAttributesInternal(matches.get(LoggingEventFieldResolver.LINE_FIELD), (StyledDocument) singleLineTextPane.getDocument());
+        layoutRenderingPanel(generalPanel, singleLineTextPane, delta, isSelected, width, col, table);
         component = generalPanel;
         break;
     case ChainsawColumns.INDEX_NDC_COL_NAME:
         singleLineTextPane.setText(value.toString());
         setHighlightAttributesInternal(matches.get(LoggingEventFieldResolver.NDC_FIELD), (StyledDocument) singleLineTextPane.getDocument());
+        layoutRenderingPanel(generalPanel, singleLineTextPane, delta, isSelected, width, col, table);
         component = generalPanel;
         break;
     case ChainsawColumns.INDEX_THREAD_COL_NAME:
         singleLineTextPane.setText(value.toString());
         setHighlightAttributesInternal(matches.get(LoggingEventFieldResolver.THREAD_FIELD), (StyledDocument) singleLineTextPane.getDocument());
+        layoutRenderingPanel(generalPanel, singleLineTextPane, delta, isSelected, width, col, table);
         component = generalPanel;
         break;
     case ChainsawColumns.INDEX_TIMESTAMP_COL_NAME:
@@ -265,18 +274,19 @@ public class TableColorizingRenderer ext
         } else {
             singleLineTextPane.setText(value.toString());
         }
+        layoutRenderingPanel(generalPanel, singleLineTextPane, delta, isSelected, width, col, table);
         component = generalPanel;
         break;
     case ChainsawColumns.INDEX_METHOD_COL_NAME:
         singleLineTextPane.setText(value.toString());
         setHighlightAttributesInternal(matches.get(LoggingEventFieldResolver.METHOD_FIELD), (StyledDocument) singleLineTextPane.getDocument());
+        layoutRenderingPanel(generalPanel, singleLineTextPane, delta, isSelected, width, col, table);
         component = generalPanel;
         break;
     case ChainsawColumns.INDEX_LOG4J_MARKER_COL_NAME:
     case ChainsawColumns.INDEX_MESSAGE_COL_NAME:
         String thisString = value.toString().trim();
         multiLineTextPane.setText(thisString);
-        int width = tableColumn.getWidth();
 
         if (colIndex == ChainsawColumns.INDEX_LOG4J_MARKER_COL_NAME) {
             //property keys are set as all uppercase
@@ -285,7 +295,36 @@ public class TableColorizingRenderer ext
             setHighlightAttributesInternal(matches.get(LoggingEventFieldResolver.MSG_FIELD), (StyledDocument) multiLineTextPane.getDocument());
         }
         multiLinePanel.removeAll();
-        multiLinePanel.add(multiLineTextPane);
+        if (delta > 0 && logPanelPreferenceModel.isShowMillisDeltaAsGap()) {
+            JPanel newPanel = new JPanel();
+            newPanel.setOpaque(true);
+            newPanel.setBackground(getDeltaColor());
+            newPanel.setPreferredSize(new Dimension(width, (int) delta));
+            multiLinePanel.add(newPanel, BorderLayout.NORTH);
+        }
+        multiLinePanel.add(multiLineTextPane, BorderLayout.SOUTH);
+
+        if (delta == 0 || !logPanelPreferenceModel.isShowMillisDeltaAsGap()) {
+          if (col == 0) {
+            multiLineTextPane.setBorder(getLeftBorder(isSelected, delta));
+          } else if (col == table.getColumnCount() - 1) {
+            multiLineTextPane.setBorder(getRightBorder(isSelected, delta));
+          } else {
+            multiLineTextPane.setBorder(getMiddleBorder(isSelected, delta));
+          }
+        } else {
+            if (col == 0) {
+              multiLineTextPane.setBorder(getLeftBorder(isSelected, 0));
+            } else if (col == table.getColumnCount() - 1) {
+              multiLineTextPane.setBorder(getRightBorder(isSelected, 0));
+            } else {
+              multiLineTextPane.setBorder(getMiddleBorder(isSelected, 0));
+            }
+        }
+        int currentMarkerHeight = loggingEvent.getMarkerHeight();
+        int currentMsgHeight = loggingEvent.getMsgHeight();
+        int newRowHeight = ChainsawConstants.DEFAULT_ROW_HEIGHT;
+        boolean setHeight = false;
 
         if (wrap) {
             /*
@@ -298,29 +337,32 @@ public class TableColorizingRenderer ext
              */
             //instead, set size to max height
             multiLineTextPane.setSize(new Dimension(width, maxHeight));
-            boolean setHeight = false;
             int multiLinePanelPrefHeight = multiLinePanel.getPreferredSize().height;
-            int newRowHeight = Math.max(ChainsawConstants.DEFAULT_ROW_HEIGHT, multiLinePanelPrefHeight);
-            if (colIndex == ChainsawColumns.INDEX_LOG4J_MARKER_COL_NAME) {
-                int currentMarkerHeight = loggingEvent.getMarkerHeight();
-                loggingEvent.setMarkerHeight(newRowHeight);
-                if (newRowHeight != currentMarkerHeight && newRowHeight >= loggingEvent.getMsgHeight()) {
-                    setHeight = true;
-                }
-            }
+            newRowHeight = Math.max(ChainsawConstants.DEFAULT_ROW_HEIGHT, multiLinePanelPrefHeight);
 
-            if (colIndex == ChainsawColumns.INDEX_MESSAGE_COL_NAME) {
-                int currentMsgHeight = loggingEvent.getMsgHeight();
-                loggingEvent.setMsgHeight(newRowHeight);
-                if (newRowHeight != currentMsgHeight && newRowHeight >= loggingEvent.getMarkerHeight()) {
-                    setHeight = true;
-                }
-            }
-            if (setHeight) {
-                table.setRowHeight(row, newRowHeight);
+        }
+        if (!wrap && logPanelPreferenceModel.isShowMillisDeltaAsGap()) {
+            multiLineTextPane.setSize(new Dimension(Integer.MAX_VALUE, ChainsawConstants.DEFAULT_ROW_HEIGHT));
+            newRowHeight = (int) (ChainsawConstants.DEFAULT_ROW_HEIGHT + delta);
+        }
+
+        if (colIndex == ChainsawColumns.INDEX_LOG4J_MARKER_COL_NAME) {
+            loggingEvent.setMarkerHeight(newRowHeight);
+            if (newRowHeight != currentMarkerHeight && newRowHeight >= loggingEvent.getMsgHeight()) {
+                setHeight = true;
             }
+        }
 
+        if (colIndex == ChainsawColumns.INDEX_MESSAGE_COL_NAME) {
+            loggingEvent.setMsgHeight(newRowHeight);
+            if (newRowHeight != currentMsgHeight && newRowHeight >= loggingEvent.getMarkerHeight()) {
+                setHeight = true;
+            }
         }
+        if (setHeight) {
+            table.setRowHeight(row, newRowHeight);
+        }
+
         component = multiLinePanel;
         break;
     case ChainsawColumns.INDEX_LEVEL_COL_NAME:
@@ -342,6 +384,7 @@ public class TableColorizingRenderer ext
       }
       levelTextPane.setForeground(label.getForeground());
       levelTextPane.setBackground(label.getBackground());
+      layoutRenderingPanel(levelPanel, levelTextPane, delta, isSelected, width, col, table);
       component = levelPanel;
       break;
 
@@ -366,6 +409,7 @@ public class TableColorizingRenderer ext
         } else {
             singleLineTextPane.setText("");
         }
+        layoutRenderingPanel(generalPanel, singleLineTextPane, delta, isSelected, width, col, table);
         component = generalPanel;
         break;
     }
@@ -403,17 +447,38 @@ public class TableColorizingRenderer ext
     updateColors(levelTextPane, background, foreground);
     updateColors(singleLineTextPane, background, foreground);
 
-      if (col == 0) {
-        component.setBorder(getLeftBorder(isSelected, delta));
-      } else if (col == table.getColumnCount() - 1) {
-        component.setBorder(getRightBorder(isSelected, delta));
-      } else {
-        component.setBorder(getMiddleBorder(isSelected, delta));
-      }
-      
     return component;
   }
 
+    private void layoutRenderingPanel(JComponent container, JComponent bottomComponent, long delta, boolean isSelected,
+                                      int width, int col, JTable table) {
+        container.removeAll();
+        if (delta == 0 || !logPanelPreferenceModel.isShowMillisDeltaAsGap()) {
+          if (col == 0) {
+            bottomComponent.setBorder(getLeftBorder(isSelected, delta));
+          } else if (col == table.getColumnCount() - 1) {
+            bottomComponent.setBorder(getRightBorder(isSelected, delta));
+          } else {
+            bottomComponent.setBorder(getMiddleBorder(isSelected, delta));
+          }
+        } else {
+            JPanel newPanel = new JPanel();
+            newPanel.setOpaque(true);
+            newPanel.setBackground(getDeltaColor());
+            newPanel.setPreferredSize(new Dimension(width, (int) delta));
+            container.add(newPanel, BorderLayout.NORTH);
+            if (col == 0) {
+              bottomComponent.setBorder(getLeftBorder(isSelected, 0));
+            } else if (col == table.getColumnCount() - 1) {
+              bottomComponent.setBorder(getRightBorder(isSelected, 0));
+            } else {
+              bottomComponent.setBorder(getMiddleBorder(isSelected, 0));
+            }
+        }
+
+        container.add(bottomComponent, BorderLayout.SOUTH);
+    }
+
     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);

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=997222&r1=997221&r2=997222&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 Wed Sep 15 08:20:34 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>15 Sep 2010</h2>
+<ul>
+<li>Updated table rendering logic when in line-wrap mode</li>
+<li>Updated row selection logic (goto/search) to make sure event is on the screen</li>
+<li>Capped the event time delta rendering in the table to a max of 50 pixels tall</li>
+</ul>
 <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>