-
Bug
-
Resolution: Unresolved
-
P4
-
None
-
6
-
x86
-
windows_2000
FULL PRODUCT VERSION :
java version "1.6.0_07"
Java(TM) SE Runtime Environment (build 1.6.0_07-b06)
Java HotSpot(TM) Client VM (build 10.0-b23, mixed mode, sharing)
ADDITIONAL OS VERSION INFORMATION :
Windows
A DESCRIPTION OF THE PROBLEM :
The FocusTraversalPolicy of a JOptionPane (JDialog) "reports" that the 1st focusable component in the message Object passed to a JOptionPane, should get the initial focus. This however doesn't always happen, as the text field's FocusListener methods (gainedFocus and lostFocus) are not always invoked.
If for instance JTextFields are passed in a JPanel to a JOptionPane as the message Object then the following methods of FocusTraversalPolicy:
getFirstComponent(), getInitialComponent(), getDefaultComponent()
report that the 1st JTextField should have the first or initial focus. This however does not occur except in 1.4.2 and only when pane.createDialog is used and not the static methods.
STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
To reproduce the bug see test case below.
EXPECTED VERSUS ACTUAL BEHAVIOR :
EXPECTED -
The expected result is that the 1st focusable component as reported by the FocusTraversalPolicy should receive the first or initial focus or that a focusLost event be issued.
ACTUAL -
The actual result is that the default button receives the focus and that the 1st focusable component as reported by the FocusTraversalPolicy only has its FocusListener method's invoked when pane.createDialog is used to display the JOptionPane.
REPRODUCIBILITY :
This bug can be reproduced always.
---------- BEGIN SOURCE ----------
import java.awt.*;
import javax.swing.*;
import java.awt.event.*;
public class DiagTest extends JFrame
{
public DiagTest()
{
super( "Diag Test" );
setDefaultCloseOperation( EXIT_ON_CLOSE );
JButton b1 = new JButton( new StaticOptionPane() );
JButton b2 = new JButton( new CreateDialogOptionPane() );
getContentPane().setLayout( new FlowLayout() );
getContentPane().add( b1 );
getContentPane().add( b2 );
KeyboardFocusManager fm = KeyboardFocusManager.getCurrentKeyboardFocusManager();
fm.addPropertyChangeListener( new DiagChangeListener() );
pack();
setVisible( true );
}
private class DiagChangeListener implements java.beans.PropertyChangeListener
{
private JDialog diag;
public void propertyChange( java.beans.PropertyChangeEvent e )
{
String prop = e.getPropertyName();
if ( "currentFocusCycleRoot".equals(prop) )
{
if ( e.getNewValue() instanceof JDialog )
{
diag = (JDialog) e.getNewValue();
System.out.println( "------------------------------" );
System.out.println( prop +" changed to JDialog" );
printFocusPolicy();
//ftp.getDefaultComponent( diag ).requestFocusInWindow(); // hangs / stalls
}
}
else if ( "focusOwner".equals(prop) && diag != null )
{
if ( e.getNewValue() instanceof JButton )
{
System.out.println( prop +" changed to JButton but:" );
printFocusPolicy();
}
}
else if ( "permanentFocusOwner".equals(prop) && diag != null )
{
if ( e.getNewValue() instanceof JButton )
{
System.out.println( prop +" changed to JButton but:" );
printFocusPolicy();
diag = null;
}
}
}
private void printFocusPolicy()
{
FocusTraversalPolicy ftp = diag.getFocusTraversalPolicy();
System.out.println( "getFirstComponent: "+ getDescription( ftp.getFirstComponent( diag )) );
System.out.println( "getInitialComponent: "+ getDescription( ftp.getInitialComponent( diag )) );
System.out.println( "getDefaultComponent: "+ getDescription( ftp.getDefaultComponent( diag )) );
System.out.println();
}
private String getDescription( Component comp )
{
return comp.getClass() +", "+ comp.getName();
}
}
private class StaticOptionPane extends AbstractAction
{
public StaticOptionPane() { super("StaticOptionPane"); }
public void actionPerformed( ActionEvent AE )
{
JPanel panel = new JPanel( new GridLayout(0,2) );
panel.add( new JLabel("Text 1:") );
JTextField text1 = new JTextField("Focus should be here");
text1.addFocusListener( new MyFocusListener() );
text1.setName( "TEXT ONE" );
panel.add( text1 );
panel.add( new JLabel("Text 2:") );
JTextField text2 = new JTextField("according to the");
panel.add( text2 );
panel.add( new JLabel("Text 3:") );
JTextField text3 = new JTextField("FocusTraversalPolicy");
panel.add( text3 );
System.out.println(" StaticOptionPane");
JOptionPane.showConfirmDialog( DiagTest.this, panel, "Test !", // Focus doesn't honour Focus Traversal Policy
JOptionPane.OK_CANCEL_OPTION, JOptionPane.WARNING_MESSAGE );
}
}
private class CreateDialogOptionPane extends AbstractAction
{
public CreateDialogOptionPane() { super("CreateDialogOptionPane"); }
public void actionPerformed( ActionEvent AE )
{
JPanel panel2 = new JPanel( new GridLayout(0,2) );
panel2.add( new JLabel("Text 4:") );
JTextField text4 = new JTextField("Focus should be here");
text4.addFocusListener( new MyFocusListener() );
text4.setName( "TEXT FOUR" );
panel2.add( text4 );
panel2.add( new JLabel("Text 5:") );
JTextField text5 = new JTextField("according to the");
panel2.add( text5 );
panel2.add( new JLabel("Text 6:") );
JTextField text6 = new JTextField("FocusTraversalPolicy");
panel2.add( text6 );
System.out.println(" CreateDialogOptionPane");
JOptionPane pane2 = new JOptionPane( panel2, JOptionPane.WARNING_MESSAGE, JOptionPane.OK_CANCEL_OPTION );
pane2.setInitialValue( text5 ); // Doesn't Work
JDialog dialog = pane2.createDialog( DiagTest.this, "Test !" ); // Focus Correct in 1.4.2
dialog.setVisible( true );
}
}
private class MyFocusListener implements FocusListener
{
public void focusGained( FocusEvent FE )
{
System.out.println( "This doesn't happen when JOptionPane static methods are used." );
System.out.println( "focusGained: "+ FE.getComponent().getName() );
}
public void focusLost( FocusEvent FE )
{
System.out.println( "focusLost: "+ FE.getComponent().getName() );
}
}
public static void main( String[] args )
{
DiagTest dt = new DiagTest();
}
}
---------- END SOURCE ----------
CUSTOMER SUBMITTED WORKAROUND :
Some thoughts:
1. If the FocusTraversalPolicy is correct then the JOptionPane should at least give the initial focus to the first or initial component, reported by FocusTraversalPolicy, before moving it to the default button. This doesn't happen when using the static JOptionPane methods. This will then honour the FocusTraversalPolicy and should also cause any FocusListeners on the component to be fired alerting the component to this affect.
2. Some require the default button on a JOptionPane to have the initial focus while others want the 1st focusable component in the message Object to have the focus. To resolve this dilemma pane.get/setInitialValue, which doesn't seem to have any affect currently with regards to the above, should be honoured to change the default component to receive focus.
java version "1.6.0_07"
Java(TM) SE Runtime Environment (build 1.6.0_07-b06)
Java HotSpot(TM) Client VM (build 10.0-b23, mixed mode, sharing)
ADDITIONAL OS VERSION INFORMATION :
Windows
A DESCRIPTION OF THE PROBLEM :
The FocusTraversalPolicy of a JOptionPane (JDialog) "reports" that the 1st focusable component in the message Object passed to a JOptionPane, should get the initial focus. This however doesn't always happen, as the text field's FocusListener methods (gainedFocus and lostFocus) are not always invoked.
If for instance JTextFields are passed in a JPanel to a JOptionPane as the message Object then the following methods of FocusTraversalPolicy:
getFirstComponent(), getInitialComponent(), getDefaultComponent()
report that the 1st JTextField should have the first or initial focus. This however does not occur except in 1.4.2 and only when pane.createDialog is used and not the static methods.
STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
To reproduce the bug see test case below.
EXPECTED VERSUS ACTUAL BEHAVIOR :
EXPECTED -
The expected result is that the 1st focusable component as reported by the FocusTraversalPolicy should receive the first or initial focus or that a focusLost event be issued.
ACTUAL -
The actual result is that the default button receives the focus and that the 1st focusable component as reported by the FocusTraversalPolicy only has its FocusListener method's invoked when pane.createDialog is used to display the JOptionPane.
REPRODUCIBILITY :
This bug can be reproduced always.
---------- BEGIN SOURCE ----------
import java.awt.*;
import javax.swing.*;
import java.awt.event.*;
public class DiagTest extends JFrame
{
public DiagTest()
{
super( "Diag Test" );
setDefaultCloseOperation( EXIT_ON_CLOSE );
JButton b1 = new JButton( new StaticOptionPane() );
JButton b2 = new JButton( new CreateDialogOptionPane() );
getContentPane().setLayout( new FlowLayout() );
getContentPane().add( b1 );
getContentPane().add( b2 );
KeyboardFocusManager fm = KeyboardFocusManager.getCurrentKeyboardFocusManager();
fm.addPropertyChangeListener( new DiagChangeListener() );
pack();
setVisible( true );
}
private class DiagChangeListener implements java.beans.PropertyChangeListener
{
private JDialog diag;
public void propertyChange( java.beans.PropertyChangeEvent e )
{
String prop = e.getPropertyName();
if ( "currentFocusCycleRoot".equals(prop) )
{
if ( e.getNewValue() instanceof JDialog )
{
diag = (JDialog) e.getNewValue();
System.out.println( "------------------------------" );
System.out.println( prop +" changed to JDialog" );
printFocusPolicy();
//ftp.getDefaultComponent( diag ).requestFocusInWindow(); // hangs / stalls
}
}
else if ( "focusOwner".equals(prop) && diag != null )
{
if ( e.getNewValue() instanceof JButton )
{
System.out.println( prop +" changed to JButton but:" );
printFocusPolicy();
}
}
else if ( "permanentFocusOwner".equals(prop) && diag != null )
{
if ( e.getNewValue() instanceof JButton )
{
System.out.println( prop +" changed to JButton but:" );
printFocusPolicy();
diag = null;
}
}
}
private void printFocusPolicy()
{
FocusTraversalPolicy ftp = diag.getFocusTraversalPolicy();
System.out.println( "getFirstComponent: "+ getDescription( ftp.getFirstComponent( diag )) );
System.out.println( "getInitialComponent: "+ getDescription( ftp.getInitialComponent( diag )) );
System.out.println( "getDefaultComponent: "+ getDescription( ftp.getDefaultComponent( diag )) );
System.out.println();
}
private String getDescription( Component comp )
{
return comp.getClass() +", "+ comp.getName();
}
}
private class StaticOptionPane extends AbstractAction
{
public StaticOptionPane() { super("StaticOptionPane"); }
public void actionPerformed( ActionEvent AE )
{
JPanel panel = new JPanel( new GridLayout(0,2) );
panel.add( new JLabel("Text 1:") );
JTextField text1 = new JTextField("Focus should be here");
text1.addFocusListener( new MyFocusListener() );
text1.setName( "TEXT ONE" );
panel.add( text1 );
panel.add( new JLabel("Text 2:") );
JTextField text2 = new JTextField("according to the");
panel.add( text2 );
panel.add( new JLabel("Text 3:") );
JTextField text3 = new JTextField("FocusTraversalPolicy");
panel.add( text3 );
System.out.println(" StaticOptionPane");
JOptionPane.showConfirmDialog( DiagTest.this, panel, "Test !", // Focus doesn't honour Focus Traversal Policy
JOptionPane.OK_CANCEL_OPTION, JOptionPane.WARNING_MESSAGE );
}
}
private class CreateDialogOptionPane extends AbstractAction
{
public CreateDialogOptionPane() { super("CreateDialogOptionPane"); }
public void actionPerformed( ActionEvent AE )
{
JPanel panel2 = new JPanel( new GridLayout(0,2) );
panel2.add( new JLabel("Text 4:") );
JTextField text4 = new JTextField("Focus should be here");
text4.addFocusListener( new MyFocusListener() );
text4.setName( "TEXT FOUR" );
panel2.add( text4 );
panel2.add( new JLabel("Text 5:") );
JTextField text5 = new JTextField("according to the");
panel2.add( text5 );
panel2.add( new JLabel("Text 6:") );
JTextField text6 = new JTextField("FocusTraversalPolicy");
panel2.add( text6 );
System.out.println(" CreateDialogOptionPane");
JOptionPane pane2 = new JOptionPane( panel2, JOptionPane.WARNING_MESSAGE, JOptionPane.OK_CANCEL_OPTION );
pane2.setInitialValue( text5 ); // Doesn't Work
JDialog dialog = pane2.createDialog( DiagTest.this, "Test !" ); // Focus Correct in 1.4.2
dialog.setVisible( true );
}
}
private class MyFocusListener implements FocusListener
{
public void focusGained( FocusEvent FE )
{
System.out.println( "This doesn't happen when JOptionPane static methods are used." );
System.out.println( "focusGained: "+ FE.getComponent().getName() );
}
public void focusLost( FocusEvent FE )
{
System.out.println( "focusLost: "+ FE.getComponent().getName() );
}
}
public static void main( String[] args )
{
DiagTest dt = new DiagTest();
}
}
---------- END SOURCE ----------
CUSTOMER SUBMITTED WORKAROUND :
Some thoughts:
1. If the FocusTraversalPolicy is correct then the JOptionPane should at least give the initial focus to the first or initial component, reported by FocusTraversalPolicy, before moving it to the default button. This doesn't happen when using the static JOptionPane methods. This will then honour the FocusTraversalPolicy and should also cause any FocusListeners on the component to be fired alerting the component to this affect.
2. Some require the default button on a JOptionPane to have the initial focus while others want the 1st focusable component in the message Object to have the focus. To resolve this dilemma pane.get/setInitialValue, which doesn't seem to have any affect currently with regards to the above, should be honoured to change the default component to receive focus.