Name: rmT116609 Date: 10/22/2003
FULL PRODUCT VERSION :
java version "1.4.2_01"
Java(TM) 2 Runtime Environment, Standard Edition (build 1.4.2_01-b06)
Java HotSpot(TM) Client VM (build 1.4.2_01-b06, mixed mode)
FULL OS VERSION :
Microsoft Windows 2000 [Version 5.00.2195]
A DESCRIPTION OF THE PROBLEM :
javax.swing.AutoScroller / JComponent has a problem when Autoscrolling in a JTextField when the JTextField has been hidden from another MouseListener.
STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
1) Compile the code below
2) run the code
3) click the button to bring up the window
4) with the mouse click in the JTextField and drag the mouse out of the window
EXPECTED VERSUS ACTUAL BEHAVIOR :
EXPECTED -
The window closes and no exception is raised.
ACTUAL -
the window closes and there are errors on the EventThread.
ERROR MESSAGES/STACK TRACES THAT OCCUR :
java.awt.IllegalComponentStateException: component must be showing on the screen
to determine its location
at java.awt.Component.getLocationOnScreen_NoTreeLock(Unknown Source)
at java.awt.Component.getLocationOnScreen(Unknown Source)
at javax.swing.Autoscroller.mouseDragged(Unknown Source)
at javax.swing.JComponent.processMouseMotionEvent(Unknown Source)
at java.awt.Component.processEvent(Unknown Source)
at java.awt.Container.processEvent(Unknown Source)
at java.awt.Component.dispatchEventImpl(Unknown Source)
at java.awt.Container.dispatchEventImpl(Unknown Source)
at java.awt.Component.dispatchEvent(Unknown Source)
at java.awt.LightweightDispatcher.retargetMouseEvent(Unknown Source)
at java.awt.LightweightDispatcher.processMouseEvent(Unknown Source)
at java.awt.LightweightDispatcher.dispatchEvent(Unknown Source)
at java.awt.Container.dispatchEventImpl(Unknown Source)
at java.awt.Window.dispatchEventImpl(Unknown Source)
at java.awt.Component.dispatchEvent(Unknown Source)
at java.awt.EventQueue.dispatchEvent(Unknown Source)
at java.awt.EventDispatchThread.pumpOneEventForHierarchy(Unknown Source)
at java.awt.EventDispatchThread.pumpEventsForHierarchy(Unknown Source)
at java.awt.EventDispatchThread.pumpEvents(Unknown Source)
at java.awt.EventDispatchThread.pumpEvents(Unknown Source)
at java.awt.EventDispatchThread.run(Unknown Source)
REPRODUCIBILITY :
This bug can be reproduced always.
---------- BEGIN SOURCE ----------
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class Whoops implements ActionListener, MouseListener {
private JWindow w;
private JPanel jp;
public Whoops() {
JFrame f = new JFrame("test");
JButton jb = new JButton("Show Window");
jb.addActionListener(this);
f.getContentPane().add(jb);
w = new JWindow(f);
JTextField tf = new JTextField("Hello");
jp = new JPanel(new GridBagLayout());
jp.add(tf, new GridBagConstraints(0,0,1,1,1.0,1.0,
GridBagConstraints.LINE_START,
GridBagConstraints.BOTH,
new Insets(10,10,10,10),
0,0));
jp.addMouseListener(this);
w.getContentPane().add(jp);
f.pack();
w.pack();
f.show();
}
public void mouseClicked(MouseEvent e){}
public void mousePressed(MouseEvent e){}
public void mouseReleased(MouseEvent e){}
public void mouseEntered(MouseEvent e){}
public void mouseExited(MouseEvent e){
Point p = e.getPoint();
if (!jp.getBounds().contains(p)) {
w.hide();
e.consume();
}
}
public void actionPerformed(ActionEvent e) {
w.setLocationRelativeTo((Component)e.getSource());
w.show();
}
public static void main(String[] args) {
new Whoops();
}
}
---------- END SOURCE ----------
CUSTOMER SUBMITTED WORKAROUND :
disable autoscrolling but that disables a usefull feature.
Fix could be to check isShowing inside MouseDragged.
(Incident Review ID: 216719)
======================================================================
Contribution by java.net member leouser:
A DESCRIPTION OF THE FIX :
BUGID: 4942216 javax.swing.Autoscroller doesn't check if the Component is showing
Files affected: javax.swing.Autoscroller
Autoscroller enhanced with java 6 version:
jdk-6-rc-bin-b64-linux-i586-15_dec_2005.bin
Discusion(embeded in test case as well):
/**
* BUGID: 4942216 javax.swing.Autoscroller doesn't check if the Component is showing
* Actually the Autoscroller does check if the component is showing, it just
* doesn't do it comprehensively. actionPerformed has a good check in place
* but _processMouseDragged does not, opening a window of opportunity for
* an exception to be tossed as the test case shows. I have refactored
* the test in actionPerformed into its own test method. This allows us
* to do the test/stop code in one place. It also simplifies the implementations
* of actionPerformed and _processMouseDragged(if the same code was going to
* be dropped into it). Also if the Autoscroller gains new behavior and we
* need to test for the exception condition then its just a matter of calling
* the testForStop method.
*
* TESTING STRATEGY
* To quote from the bug report since we use the code in it to show the problem:
* "1) Compile the code below
* 2) run the code
* 3) click the button to bring up the window
* 4) with the mouse click in the JTextField and drag the mouse out of the
* window
* EXPECTED VS ACTUAL BEHAVIOR:
* EXPECTED-
* The window closes and no exception is raised
* ACTUAL-
* the window closes and there are errors on the EventThread"
* Test without the patch and it will show the problem. Test with the patch
* and there isn't any problem.
*
* Files affected: javax.swing.Autoscroller
* Autoscroller enhanced with java 6 version:
* jdk-6-rc-bin-b64-linux-i586-15_dec_2005.bin
*
* test ran succesfully on a SUSE 7.3 Linux distribution
*
* Brian Harry
* ###@###.###
* Jan 20, 2006
*/
UNIFIED DIFF:
--- /home/nstuff/java6/jdk1.6.0/javax/swing/Autoscroller.java Thu Dec 15 02:17:33 2005
+++ /home/javarefs/javax/swing/Autoscroller.java Fri Jan 20 10:44:54 2006
@@ -115,11 +115,21 @@
return (c == component && timer != null && timer.isRunning());
}
+ private boolean testForStop(JComponent component){
+ if (component == null || !component.isShowing() || (event == null)) {
+ _stop(component);
+ return true;
+ }
+ return false;
+ }
+
/**
* MouseListener method, invokes start/stop as necessary.
*/
private void _processMouseDragged(MouseEvent e) {
JComponent component = (JComponent)e.getComponent();
+
+ if(testForStop(component)) return;
Rectangle visibleRect = component.getVisibleRect();
boolean contains = visibleRect.contains(e.getX(), e.getY());
@@ -140,10 +150,7 @@
public void actionPerformed(ActionEvent x) {
JComponent component = Autoscroller.component;
- if (component == null || !component.isShowing() || (event == null)) {
- _stop(component);
- return;
- }
+ if(testForStop(component)) return;
Point screenLocation = component.getLocationOnScreen();
MouseEvent e = new MouseEvent(component, event.getID(),
event.getWhen(), event.getModifiers(),
JUnit TESTCASE :
import java.awt.*;
import javax.swing.*;
import java.awt.event.*;
/**
* BUGID: 4942216 javax.swing.Autoscroller doesn't check if the Component is showing
* Actually the Autoscroller does check if the component is showing, it just
* doesn't do it comprehensively. actionPerformed has a good check in place
* but _processMouseDragged does not, opening a window of opportunity for
* an exception to be tossed as the test case shows. I have refactored
* the test in actionPerformed into its own test method. This allows us
* to do the test/stop code in one place. It also simplifies the implementations
* of actionPerformed and _processMouseDragged(if the same code was going to
* be dropped into it). Also if the Autoscroller gains new behavior and we
* need to test for the exception condition then its just a matter of calling
* the testForStop method.
*
* TESTING STRATEGY
* To quote from the bug report since we use the code in it to show the problem:
* "1) Compile the code below
* 2) run the code
* 3) click the button to bring up the window
* 4) with the mouse click in the JTextField and drag the mouse out of the
* window
* EXPECTED VS ACTUAL BEHAVIOR:
* EXPECTED-
* The window closes and no exception is raised
* ACTUAL-
* the window closes and there are errors on the EventThread"
* Test without the patch and it will show the problem. Test with the patch
* and there isn't any problem.
*
* Files affected: javax.swing.Autoscroller
* Autoscroller enhanced with java 6 version:
* jdk-6-rc-bin-b64-linux-i586-15_dec_2005.bin
*
* test ran succesfully on a SUSE 7.3 Linux distribution
*
* Brian Harry
* ###@###.###
* Jan 20, 2006
*/
public class TestAutoScroll extends MouseAdapter implements ActionListener{
private JWindow w;
private JPanel jp;
public TestAutoScroll(){
JFrame f = new JFrame("test");
JButton jb = new JButton("Show Window");
jb.addActionListener(this);
f.getContentPane().add(jb);
w = new JWindow(f);
JTextField tf = new JTextField("Hello");
jp = new JPanel(new GridBagLayout());
jp.add(tf, new GridBagConstraints(0,0,1,1,1.0,1.0,
GridBagConstraints.LINE_START,
GridBagConstraints.BOTH,
new Insets(10,10,10,10), 0,0));
jp.addMouseListener(this);
w.getContentPane().add(jp);
f.pack();
w.pack();
f.show();
}
public void mouseExited(MouseEvent me){
Point p = me.getPoint();
if(!jp.getBounds().contains(p)){
System.out.println("Hiding the window!");
w.hide();
me.consume();
}
}
public void actionPerformed(ActionEvent ae){
w.setLocationRelativeTo((Component)ae.getSource());
w.show();
}
public static void testAutoScroll(){
Runnable run = new Runnable(){
public void run(){
new TestAutoScroll();
}
};
SwingUtilities.invokeLater(run);
}
public static void main(String ... args){
testAutoScroll();
}
}
FIX FOR BUG NUMBER:
4942216