SYNOPSIS
--------
Regression: Plugin: invalidate/validate issues in AWT applet
OPERATING SYSTEM
----------------
Tested on Windows, but probably platform independent
FULL JDK VERSION
----------------
JDK 7 b142.
Not reproducible on JDK 6u25.
REPRODUCTION INSTRUCTIONS
-------------------------
1. Install JDK 7
2. Ensure that the Next Generation Plugin is enabled
3. Place the provided HTML and Java files in the same folder, and
compiled the java file.
4. Load the given html file into a browser (the problem is reproducible
with both Firefox and IE)
5. Click the button
Observed bevaviour:
The "Logon" Button disappears, and the "Logoff" button does not appear.
Expected behaviour:
Clicking the button should toggle the label between "Logon" and "Logoff" (run with Java 6 to observe the correct behaviour).
The problem seems to be caused by inconsistent behaviour in this part of the testcase:
private void validateComponent(Component component) {
if (component == null)
return;
Component original = component;
//invalidating this component and all its ancestors
component.invalidate();
//getting to the top-most component in the hierarchy
while ( (component.getParent() != null) )
component = component.getParent();
//validating this top-most component
component.validate();
original.repaint();
}
When running on JDK 7, the top-level AWT component does not get invalidated (despite the fact that we call invalidate() on one of the components lower down the heirarchy). As a result, when we call validate() on the top level component immediately afterwards, nothing happens (because the top-level component is valid), and the Logoff button does not get painted.
TESTCASE
--------
import java.applet.Applet;
import java.awt.BorderLayout;
import java.awt.Button;
import java.awt.Component;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JPanel;
public class LogOffApplet extends Applet implements ActionListener {
private LogOffApplet appletInstance;
public void init() {
super.init();
appletInstance = this;
LogonPanel p = new LogonPanel();
setMainPanel(p);
}
private class LogonPanel extends JPanel implements ActionListener {
LogonPanel(){
Button logonBtn = new Button("Logon");
logonBtn.addActionListener(this);
setLayout(new BorderLayout());
add("Center",logonBtn);
}
public void actionPerformed(ActionEvent e) {
appletInstance.actionPerformed(new ActionEvent(this, 0, "logon"));
}
}
private class LogOffPanel extends JPanel implements ActionListener {
LogOffPanel(){
Button logoffBtn = new Button("LogOff");
logoffBtn.addActionListener(this);
setLayout(new BorderLayout());
add("Center",logoffBtn);
}
public void actionPerformed(ActionEvent e) {
appletInstance.actionPerformed(new ActionEvent(this,1,"logoff"));
}
}
public void actionPerformed(ActionEvent e) {
int ID = e.getID();
switch (ID) {
case 0:
setMainPanel(new LogOffPanel());
break;
case 1:
setMainPanel(new LogonPanel());
break;
default:
break;
}
}
private void setMainPanel(JPanel panel){
if (appletInstance != null) {
appletInstance.removeAll();
appletInstance.setLayout(new BorderLayout(0,0));
appletInstance.add("Center", panel);
validateComponent(panel);
} else
System.out.println("appletInstance is NULL");
}
private void validateComponent(Component component) {
if (component == null)
return;
Component original = component;
//invalidating this component and all its ancestors
component.invalidate();
//getting to the top-most component in the hierarchy
while ( (component.getParent() != null) )
component = component.getParent();
//validating this top-most component
component.validate();
original.repaint();
}
}
hangtest.html
-------------
<html>
<head>
<title>Hang demo</title>
</head>
<body>
<h1>Hang demo</h1>
<APPLET CODE="LogOffApplet.class" WIDTH=100 HEIGHT=50 />
</body>
</html>