Author: sdeboy
Date: Fri Nov 16 15:31:40 2007
New Revision: 595870
URL: http://svn.apache.org/viewvc?rev=595870&view=rev
Log:
Scroll-to-bottom now works as expected:
- Click of the scroll to bottom button works for cyclic, filtered, etc
- Click on any row deselects scroll to bottom button and maintains selection as
long as the row isn't filtered out or nuked from cyclic buffer
- Ensure that updates to the table model cause selection changes within the
same call (table model update is on EDT, selection change is made while still
in same call)
- Goto-line now scrolls to first column of row (was going to 2nd)
Much thanks to Jeff Kinzer for the help in getting selection working (and lots
of testing!)
Modified:
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/JSortTable.java
logging/chainsaw/trunk/src/main/java/org/apache/log4j/chainsaw/LogPanel.java
logging/chainsaw/trunk/src/main/java/org/apache/log4j/chainsaw/helper/SwingHelper.java
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=595870&r1=595869&r2=595870&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
Fri Nov 16 15:31:40 2007
@@ -28,6 +28,7 @@
import java.util.Iterator;
import java.util.List;
import java.util.Set;
+import java.awt.EventQueue;
import javax.swing.ProgressMonitor;
import javax.swing.SwingUtilities;
@@ -36,6 +37,7 @@
import org.apache.log4j.LogManager;
import org.apache.log4j.Logger;
+import org.apache.log4j.chainsaw.helper.SwingHelper;
import org.apache.log4j.helpers.Constants;
import org.apache.log4j.rule.Rule;
import org.apache.log4j.spi.LoggingEvent;
@@ -135,7 +137,7 @@
}
}
} finally {
- SwingUtilities.invokeLater(new Runnable() {
+ SwingHelper.invokeOnEDT(new Runnable() {
public void run() {
if (filteredList.size() > 0) {
if (previousSize == filteredList.size()) {
@@ -262,7 +264,7 @@
currentSortAscending));
}
- SwingUtilities.invokeLater(new Runnable() {
+ SwingHelper.invokeOnEDT(new Runnable() {
public void run() {
fireTableRowsUpdated(0, Math.max(filteredList.size() -
1, 0));
}
@@ -295,7 +297,7 @@
uniqueRow = 0;
}
- SwingUtilities.invokeLater(new Runnable() {
+ SwingHelper.invokeOnEDT(new Runnable() {
public void run() {
fireTableDataChanged();
}
@@ -445,7 +447,7 @@
return "";
}
- public boolean isAddRow(LoggingEvent e, boolean valueIsAdjusting) {
+ public boolean isAddRow(LoggingEvent e) {
boolean rowAdded = false;
Object id = e.getProperty(Constants.LOG4J_ID_KEY);
@@ -494,7 +496,7 @@
}
}
- if (!valueIsAdjusting) {
+ if (rowAdded) {
int lastAdded = getLastAdded();
fireTableEvent(lastAdded, lastAdded, 1);
}
@@ -506,16 +508,16 @@
int last = 0;
if (cyclic) {
- last = ((CyclicBufferList) filteredList).getLast();
+ last = ((CyclicBufferList) filteredList).getLast() - 1;
} else {
- last = filteredList.size();
+ last = filteredList.size() - 1;
}
- return last;
+ return Math.max(0, last);
}
public void fireTableEvent(final int begin, final int end, final int count) {
- SwingUtilities.invokeLater(new Runnable() {
+ SwingHelper.invokeOnEDT(new Runnable() {
public void run() {
if (cyclic) {
if (!reachedCapacity) {
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=595870&r1=595869&r2=595870&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
Fri Nov 16 15:31:40 2007
@@ -17,13 +17,12 @@
package org.apache.log4j.chainsaw;
-import org.apache.log4j.rule.Rule;
-import org.apache.log4j.spi.LoggingEvent;
-
import java.beans.PropertyChangeListener;
-
import java.util.List;
+import org.apache.log4j.rule.Rule;
+import org.apache.log4j.spi.LoggingEvent;
+
/**
* To allow pluggable TableModel implementations for Chainsaw, this interface
has been factored out.
@@ -132,10 +131,9 @@
/**
* Adds a row to the model.
* @param e event
- * @param valueIsAdjusting
* @return flag representing whether or not the row is being displayed (not
filtered)
*/
- boolean isAddRow(LoggingEvent e, boolean valueIsAdjusting);
+ boolean isAddRow(LoggingEvent e);
/**
* Fire appropriate table update events for the range.
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=595870&r1=595869&r2=595870&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
Fri Nov 16 15:31:40 2007
@@ -23,10 +23,11 @@
import javax.swing.JTable;
import javax.swing.ListSelectionModel;
-import javax.swing.SwingUtilities;
import javax.swing.table.JTableHeader;
import javax.swing.table.TableColumnModel;
+import org.apache.log4j.chainsaw.helper.SwingHelper;
+
/**
* A Sortable JTable implementation that allows a user to click on a
@@ -92,36 +93,23 @@
getTableHeader().resizeAndRepaint();
}
- public void scrollToRow(final int row, final int col) {
- SwingUtilities.invokeLater(
- new Runnable() {
- public void run() {
- if ((row > -1) && (row < getRowCount())) {
- try {
- setRowSelectionInterval(row, row);
- scrollRectToVisible(getCellRect(row, col +1, true));
- } catch (IllegalArgumentException iae) {
- }
- //ignore..out of bounds
- }
- }
- });
- }
-
- public void scrollToBottom(final int col) {
- SwingUtilities.invokeLater(
- new Runnable() {
- public void run() {
- int row = getRowCount() - 1;
-
+ public void scrollTo(final int row, final int col) {
+ SwingHelper.invokeOnEDT(new Runnable() {
+ public void run() {
+ if ((row > -1) && (row < getRowCount())) {
try {
setRowSelectionInterval(row, row);
- scrollRectToVisible(getCellRect(row, col + 1, true));
+ scrollRectToVisible(getCellRect(row, col, true));
} catch (IllegalArgumentException iae) {
+ //ignore..out of bounds
}
- //ignore..out of bounds
}
- });
+ }
+ });
+ }
+
+ public void scrollToRow(int row) {
+ scrollTo(row, columnAtPoint(getVisibleRect().getLocation()));
}
public boolean isSortedColumnAscending() {
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=595870&r1=595869&r2=595870&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
Fri Nov 16 15:31:40 2007
@@ -112,6 +112,9 @@
import javax.swing.table.TableColumnModel;
import javax.swing.text.Document;
+import com.thoughtworks.xstream.XStream;
+import com.thoughtworks.xstream.io.xml.DomDriver;
+
import org.apache.log4j.LogManager;
import org.apache.log4j.Logger;
import org.apache.log4j.PatternLayout;
@@ -129,15 +132,13 @@
import org.apache.log4j.chainsaw.prefs.SaveSettingsEvent;
import org.apache.log4j.chainsaw.prefs.SettingsManager;
import org.apache.log4j.chainsaw.xstream.TableColumnConverter;
+import org.apache.log4j.chainsaw.helper.SwingHelper;
import org.apache.log4j.helpers.Constants;
import org.apache.log4j.rule.ExpressionRule;
import org.apache.log4j.rule.Rule;
import org.apache.log4j.spi.LoggingEvent;
import org.apache.log4j.spi.LoggingEventFieldResolver;
-import com.thoughtworks.xstream.XStream;
-import com.thoughtworks.xstream.io.xml.DomDriver;
-
/**
* A LogPanel provides a view to a collection of LoggingEvents.<br>
@@ -533,7 +534,7 @@
boolean value = ((Boolean) evt.getNewValue()).booleanValue();
menuItemScrollBottom.setSelected(value);
if (value) {
-
table.scrollToBottom(table.columnAtPoint(table.getVisibleRect().getLocation()));
+ scrollToBottom();
}
}
});
@@ -690,33 +691,42 @@
table.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
+ table.getSelectionModel().addListSelectionListener(new
ListSelectionListener() {
+ public void valueChanged(ListSelectionEvent evt) {
+ if (((evt.getFirstIndex() == evt.getLastIndex())
+ && (evt.getFirstIndex() > 0)) || (evt.getValueIsAdjusting())) {
+ return;
+ }
+ boolean lastIndexOnLastRow = (evt.getLastIndex() ==
(table.getRowCount() - 1));
+ boolean lastIndexSame = (previousLastIndex == evt.getLastIndex());
+
+ /*
+ * when scroll-to-bottom is active, here is what events look like:
+ * rowcount-1: 227, last: 227, previous last: 191..first: 191
+ *
+ * when the user has unselected the bottom row, here is what the
events look like:
+ * rowcount-1: 227, last: 227, previous last: 227..first: 222
+ *
+ * note: previouslast is set after it is evaluated in the bypass
scroll check
+ */
+ //System.out.println("rowcount: " + (table.getRowCount() - 1) + ",
last: " + evt.getLastIndex() +", previous last: " + previousLastIndex +
"..first: " + evt.getFirstIndex() + ", isadjusting: " +
evt.getValueIsAdjusting());
+
+ boolean disableScrollToBottom = (lastIndexOnLastRow &&
lastIndexSame && previousLastIndex != evt.getFirstIndex());
+ if (disableScrollToBottom && isScrollToBottom() &&
table.getRowCount() > 0) {
+ preferenceModel.setScrollToBottom(false);
+ }
+ previousLastIndex = evt.getLastIndex();
+ }
+ }
+ );
+
table.getSelectionModel().addListSelectionListener(
new ListSelectionListener() {
public void valueChanged(ListSelectionEvent evt) {
- if (
- ((evt.getFirstIndex() == evt.getLastIndex())
+ if (((evt.getFirstIndex() == evt.getLastIndex())
&& (evt.getFirstIndex() > 0)) || (evt.getValueIsAdjusting())) {
return;
}
- boolean lastIndexOnLastRow = (evt.getLastIndex() ==
(table.getRowCount() - 1));
- boolean lastIndexSame = (previousLastIndex == evt.getLastIndex());
-
- /*
- * when scroll-to-bottom is active, here is what events look like:
- * rowcount-1: 227, last: 227, previous last: 191..first: 191
- *
- * when the user has unselected the bottom row, here is what the
events look like:
- * rowcount-1: 227, last: 227, previous last: 227..first: 222
- *
- * note: previouslast is set after it is evaluated in the bypass
scroll check
- */
- //System.out.println("rowcount: " + (table.getRowCount() - 1) + ",
last: " + evt.getLastIndex() +", previous last: " + previousLastIndex +
"..first: " + evt.getFirstIndex() + ", isadjusting: " +
evt.getValueIsAdjusting());
-
- boolean disableScrollToBottom = (lastIndexOnLastRow && lastIndexSame
&& previousLastIndex != evt.getFirstIndex());
- if (disableScrollToBottom && isScrollToBottom() &&
table.getRowCount() > 0) {
- preferenceModel.setScrollToBottom(false);
- }
- previousLastIndex = evt.getLastIndex();
final ListSelectionModel lsm = (ListSelectionModel) evt.getSource();
@@ -798,8 +808,7 @@
}
detailDialog.setLocation(lowerPanel.getLocationOnScreen());
- SwingUtilities.invokeLater(
- new Runnable() {
+ SwingHelper.invokeOnEDT(new Runnable() {
public void run() {
detailDialog.setVisible(true);
}
@@ -814,7 +823,7 @@
tableModel.addNewKeyListener(
new NewKeyListener() {
public void newKeyAdded(final NewKeyEvent e) {
- SwingUtilities.invokeLater(new Runnable() {
+ SwingHelper.invokeOnEDT(new Runnable() {
public void run() {
// don't add the column if we already know about it, this could be
if we've seen it before and saved the column preferences
//this may throw an illegalargexception - ignore it because we
need to add only if not already added
@@ -1347,6 +1356,10 @@
preferenceModel.setScrollToBottom(!preferenceModel.isScrollToBottom());
}
+ private void scrollToBottom() {
+ table.scrollToRow(tableModel.getRowCount() - 1);
+ }
+
/**
* Accessor
*
@@ -1376,51 +1389,60 @@
* @param ident identifier shared by events
* @param events list of LoggingEvent objects
*/
- public void receiveEventBatch(String ident, List events) {
- /*
- * if this panel is paused, we totally ignore events
- */
- if (isPaused()) {
- return;
- }
+ public void receiveEventBatch(String ident, final List events) {
- //table.getSelectionModel().setValueIsAdjusting(true);
- boolean rowAdded = false;
+ SwingHelper.invokeOnEDT(new Runnable() {
+ public void run() {
+ /*
+ * if this panel is paused, we totally ignore events
+ */
+ if (isPaused()) {
+ return;
+ }
- int first = tableModel.getLastAdded() + 1;
+ final int selectedRow = table.getSelectedRow();
+ final LoggingEvent selectedEvent;
+ if (selectedRow >= 0) {
+ selectedEvent = tableModel.getRow(selectedRow);
+ } else {
+ selectedEvent = null;
+ }
- for (Iterator iter = events.iterator(); iter.hasNext();) {
- LoggingEvent event = (LoggingEvent) iter.next();
+ boolean rowAdded = false;
- updateOtherModels(event);
+ for (Iterator iter = events.iterator(); iter.hasNext();) {
+ LoggingEvent event = (LoggingEvent) iter.next();
- boolean isCurrentRowAdded = tableModel.isAddRow(event, true);
- rowAdded = rowAdded ? true : isCurrentRowAdded;
- }
+ updateOtherModels(event);
- table.getSelectionModel().setValueIsAdjusting(false);
+ rowAdded = rowAdded || tableModel.isAddRow(event);
+ }
- //tell the model to notify the count listeners
- tableModel.notifyCountListeners();
+ //tell the model to notify the count listeners
+ tableModel.notifyCountListeners();
- if (rowAdded) {
- if (tableModel.isSortEnabled()) {
- tableModel.sort();
- }
+ if (rowAdded) {
+ if (tableModel.isSortEnabled()) {
+ tableModel.sort();
+ }
- tableModel.fireTableEvent(
- first, tableModel.getLastAdded(), events.size());
+ //always update detail pane (since we may be using a cyclic buffer
which is full)
+ detailPaneUpdater.setSelectedRow(table.getSelectedRow());
+ }
- if (isScrollToBottom()) {
- table.scrollToBottom(
- table.columnAtPoint(table.getVisibleRect().getLocation()));
+ if (isScrollToBottom()) {
+ scrollToBottom();
+ } else if (selectedEvent != null) {
+ final int newIndex = tableModel.getRowIndex(selectedEvent);
+ if (newIndex >= 0) {
+ // Don't scroll, just maintain selection...
+ table.setRowSelectionInterval(newIndex, newIndex);
+ }
+ }
}
-
- //always update detail pane (since we may be using a cyclic buffer which
is full)
- detailPaneUpdater.setSelectedRow(table.getSelectedRow());
- }
+ });
}
-
+
/**
* Load settings from the panel preference model
*
@@ -1676,7 +1698,7 @@
dockingAction.putValue(Action.NAME, "Dock");
dockingAction.putValue(Action.SMALL_ICON, ChainsawIcons.ICON_DOCK);
if (row > -1) {
- table.scrollToRow(row,
table.columnAtPoint(table.getVisibleRect().getLocation()));
+ table.scrollToRow(row);
}
}
@@ -1715,7 +1737,7 @@
* @param eventNumber
*/
void setSelectedEvent(int eventNumber){
- table.scrollToRow(eventNumber - 1, 0);
+ table.scrollTo(eventNumber - 1, 0);
}
/**
@@ -2053,7 +2075,7 @@
* Update the status bar with current selected row and row count
*/
private void updateStatusBar() {
- SwingUtilities.invokeLater(
+ SwingHelper.invokeOnEDT(
new Runnable() {
public void run() {
statusBar.setSelectedLine(
@@ -2113,8 +2135,7 @@
tableModel.find(findRule, table.getSelectedRow() + 1, true);
if (nextRow > -1) {
- table.scrollToRow(
- nextRow,
table.columnAtPoint(table.getVisibleRect().getLocation()));
+ table.scrollToRow(nextRow);
findField.setToolTipText("Enter an expression");
}
} catch (IllegalArgumentException iae) {
@@ -2138,9 +2159,7 @@
tableModel.find(findRule, table.getSelectedRow() - 1, false);
if (previousRow > -1) {
- table.scrollToRow(
- previousRow,
- table.columnAtPoint(table.getVisibleRect().getLocation()));
+ table.scrollToRow(previousRow);
findField.setToolTipText("Enter an expression");
}
} catch (IllegalArgumentException iae) {
@@ -2165,7 +2184,7 @@
dockingAction.putValue(Action.NAME, "Undock");
dockingAction.putValue(Action.SMALL_ICON, ChainsawIcons.ICON_UNDOCK);
if (row > -1) {
- table.scrollToRow(row,
table.columnAtPoint(table.getVisibleRect().getLocation()));
+ table.scrollToRow(row);
}
}
@@ -2612,7 +2631,7 @@
try {
final Document doc =
detail.getEditorKit().createDefaultDocument();
detail.getEditorKit().read(new
StringReader(buf.toString()), doc, 0);
- SwingUtilities.invokeLater(new
Runnable() {
+ SwingHelper.invokeOnEDT(new Runnable() {
public void run() {
detail.setDocument(doc);
detail.setCaretPosition(0);
@@ -2627,7 +2646,7 @@
try {
final Document doc =
detail.getEditorKit().createDefaultDocument();
detail.getEditorKit().read(new
StringReader("<html>Nothing selected</html>"), doc, 0);
- SwingUtilities.invokeLater(new Runnable() {
+ SwingHelper.invokeOnEDT(new Runnable() {
public void run() {
detail.setDocument(doc);
detail.setCaretPosition(0);
Modified:
logging/chainsaw/trunk/src/main/java/org/apache/log4j/chainsaw/helper/SwingHelper.java
URL:
http://svn.apache.org/viewvc/logging/chainsaw/trunk/src/main/java/org/apache/log4j/chainsaw/helper/SwingHelper.java?rev=595870&r1=595869&r2=595870&view=diff
==============================================================================
---
logging/chainsaw/trunk/src/main/java/org/apache/log4j/chainsaw/helper/SwingHelper.java
(original)
+++
logging/chainsaw/trunk/src/main/java/org/apache/log4j/chainsaw/helper/SwingHelper.java
Fri Nov 16 15:31:40 2007
@@ -20,6 +20,7 @@
import java.awt.Component;
import java.awt.Dimension;
import java.awt.Toolkit;
+import java.awt.EventQueue;
import java.awt.event.ActionEvent;
import java.awt.event.KeyEvent;
@@ -72,5 +73,13 @@
cancelButton.setAction(closeAction);
dialog.getRootPane().getActionMap().put(CANCEL_ACTION_KEY, closeAction);
+ }
+
+ public static void invokeOnEDT(Runnable runnable) {
+ if (EventQueue.isDispatchThread()) {
+ runnable.run();
+ } else {
+ EventQueue.invokeLater(runnable);
+ }
}
}