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 @@ NOTE: 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.

2.1

+

15 Sep 2010

+

13 Sep 2010