JDK-4722671 : Accessibility problem in JRE Finder
  • Type: Bug
  • Component: client-libs
  • Sub-Component: java.awt
  • Affected Version: 1.2.0,1.4.1
  • Priority: P4
  • Status: Resolved
  • Resolution: Fixed
  • OS: generic,windows_xp
  • CPU: generic,x86
  • Submitted: 2002-07-30
  • Updated: 2002-10-04
  • Resolved: 2002-10-04
The Version table provides details related to the release that this issue/RFE will be addressed.

Unresolved : Release in which this issue/RFE will be addressed.
Resolved: Release in which this issue/RFE has been resolved.
Fixed : Release in which this issue/RFE has been fixed. The release containing this fix may be available for download as an Early Access Release or a General Availability Release.

To download the current JDK release, click here.
Other
1.4.2 mantisFixed
Related Reports
Duplicate :  
Relates :  
Description
The following function does not work properly.

Alt + P, "Previous" button in JRE Finder:
  - Select "Java" tab in Preferences
  - Click "Find..." button to bring up JRE Finder
  - Click "Next" button to go to select a directory for search

Comments
CONVERTED DATA BugTraq+ Release Management Values COMMIT TO FIX: mantis FIXED IN: mantis INTEGRATED IN: mantis mantis-b03
24-08-2004

SUGGESTED FIX FocusEvent)event); + break; + } + case FocusEvent.FOCUS_LOST: { + event = retargetFocusLost((FocusEvent)event); + break; + } + default: + /* do nothing */ + } + return event; } + static boolean removeFirstRequest() { KeyboardFocusManager manager = KeyboardFocusManager.getCurrentKeyboardFocusManager(); *************** *** 2726,2732 **** return (Window)comp; } private static Component getHeavyweight(Component comp) { ! if (comp == null) { return null; } else if (comp.getPeer() instanceof LightweightPeer) { return comp.getNativeContainer(); --- 2785,2791 ---- return (Window)comp; } private static Component getHeavyweight(Component comp) { ! if (comp == null || comp.getPeer() == null) { return null; } else if (comp.getPeer() instanceof LightweightPeer) { return comp.getNativeContainer(); ======================================================================
24-08-2004

SUGGESTED FIX Name: osR10079 Date: 09/23/2002 ###@###.### 2002-09-24 ------- KeyboardFocusManager.java ------- *** /tmp/dAvaG45 Tue Sep 24 08:58:14 2002 --- KeyboardFocusManager.java Tue Sep 24 08:50:34 2002 *************** *** 1987,1992 **** --- 1987,1999 ---- return false; } } + + LightweightFocusRequest getFirstLightweightRequest() { + if (this == CLEAR_GLOBAL_FOCUS_OWNER) { + return null; + } + return (LightweightFocusRequest)lightweightRequests.getFirst(); + } public String toString() { boolean first = true; String str = "HeavyweightFocusRequest[heavweight=" + heavyweight + *************** *** 2401,2453 **** } } ! static AWTEvent retargetFocusEvent(AWTEvent event) { ! if (clearingCurrentLightweightRequests) { ! return event; ! } ! KeyboardFocusManager manager = getCurrentKeyboardFocusManager(); ! synchronized(heavyweightRequests) { ! /* ! * This code handles FOCUS_LOST event which is generated by ! * DefaultKeyboardFocusManager for FOCUS_GAINED. ! * ! * This code based on knowledge of DefaultKeyboardFocusManager's ! * implementation and might be not applicable for another ! * KeyboardFocusManager. ! * ! * Fix for 4472032 ! */ ! if (newFocusOwner != null && ! event.getID() == FocusEvent.FOCUS_LOST) { ! FocusEvent fe = (FocusEvent)event; ! ! if (manager.getGlobalFocusOwner() == fe.getComponent() && ! fe.getOppositeComponent() == newFocusOwner) ! { ! newFocusOwner = null; ! return event; ! } } } ! processCurrentLightweightRequests(); ! int id = event.getID(); ! ! if (id != FocusEvent.FOCUS_GAINED && id != FocusEvent.FOCUS_LOST) { ! return event; ! } ! ! FocusEvent fe = (FocusEvent)event; ! ! Component currentFocusOwner = manager.getGlobalFocusOwner(); Component source = fe.getComponent(); Component opposite = fe.getOppositeComponent(); Component nativeSource = getHeavyweight(source); - Component nativeOpposite = getHeavyweight(opposite); synchronized (heavyweightRequests) { HeavyweightFocusRequest hwFocusRequest = (HeavyweightFocusRequest) --- 2408,2443 ---- } } ! static FocusEvent retargetUnexpectedFocusEvent(FocusEvent fe) { ! synchronized (heavyweightRequests) { ! // Any other case represents a failure condition which we did ! // not expect. We need to clearFocusRequestList() and patch up ! // the event as best as possible. ! if (removeFirstRequest()) { ! return (FocusEvent)retargetFocusEvent(fe); ! } ! Component source = fe.getComponent(); ! Component opposite = fe.getOppositeComponent(); ! boolean temporary = false; ! if (fe.getID() == FocusEvent.FOCUS_LOST && ! (opposite == null || focusedWindowChanged(source, opposite))) { ! temporary = true; } + return new FocusEvent(source, fe.getID(), temporary, opposite); } + } ! static FocusEvent retargetFocusGained(FocusEvent fe) { ! assert (fe.getID() == FocusEvent.FOCUS_GAINED); ! Component currentFocusOwner = getCurrentKeyboardFocusManager(). ! getGlobalFocusOwner(); Component source = fe.getComponent(); Component opposite = fe.getOppositeComponent(); Component nativeSource = getHeavyweight(source); synchronized (heavyweightRequests) { HeavyweightFocusRequest hwFocusRequest = (HeavyweightFocusRequest) *************** *** 2454,2511 **** ((heavyweightRequests.size() > 0) ? heavyweightRequests.getFirst() : null); ! if (hwFocusRequest == ! HeavyweightFocusRequest.CLEAR_GLOBAL_FOCUS_OWNER) { ! if (id == FocusEvent.FOCUS_LOST && currentFocusOwner != null) { ! // Call to KeyboardFocusManager.clearGlobalFocusOwner() ! heavyweightRequests.removeFirst(); ! return new FocusEvent(currentFocusOwner, ! FocusEvent.FOCUS_LOST, false, null); ! } ! // Otherwise, fall through to failure case below ! ! } else if (id == FocusEvent.FOCUS_LOST && opposite == null) ! { ! // Focus leaving application ! if (currentFocusOwner != null) { ! return new FocusEvent(currentFocusOwner, ! FocusEvent.FOCUS_LOST, ! true, null); ! } else { ! return fe; } ! } else if (id == FocusEvent.FOCUS_LOST && hwFocusRequest != null && ! nativeOpposite == hwFocusRequest.heavyweight) { - if (currentFocusOwner == null) { - return fe; - } // Focus change as a result of a known call to requestFocus(), - // or click on a peer focusable heavyweight Component. - - // If a focus transfer is made across top-levels, then the - // FOCUS_LOST event is always temporary, and the FOCUS_GAINED - // event is always permanent. Otherwise, the stored temporary - // value is honored. - - LightweightFocusRequest lwFocusRequest = - (LightweightFocusRequest)hwFocusRequest. - lightweightRequests.getFirst(); - - boolean temporary = focusedWindowChanged(opposite, - currentFocusOwner) - ? true - : lwFocusRequest.temporary; - - return new FocusEvent(currentFocusOwner, FocusEvent.FOCUS_LOST, - temporary, lwFocusRequest.component); - } else if (id == FocusEvent.FOCUS_GAINED && - hwFocusRequest != null && - nativeSource == hwFocusRequest.heavyweight) - { - // Focus change as a result of a known call to requestFocus(), // or known click on a peer focusable heavyweight Component. heavyweightRequests.removeFirst(); --- 2444,2468 ---- ((heavyweightRequests.size() > 0) ? heavyweightRequests.getFirst() : null); ! if (hwFocusRequest == HeavyweightFocusRequest.CLEAR_GLOBAL_FOCUS_OWNER) { ! return retargetUnexpectedFocusEvent(fe); ! } ! if (source != null && nativeSource == null && hwFocusRequest != null) { ! // if source w/o peer and ! // if source is equal to first lightweight ! // then we should correct source and nativeSource ! if (source == hwFocusRequest.getFirstLightweightRequest().component) ! { ! source = hwFocusRequest.heavyweight; ! nativeSource = source; // source is heavuweight itself } ! } ! if (hwFocusRequest != null && ! nativeSource == hwFocusRequest.heavyweight) { // Focus change as a result of a known call to requestFocus(), // or known click on a peer focusable heavyweight Component. heavyweightRequests.removeFirst(); *************** *** 2552,2559 **** opposite); } ! if (id == FocusEvent.FOCUS_GAINED ! && currentFocusOwner != null && getContainingWindow(currentFocusOwner) == source && (hwFocusRequest == null || source != hwFocusRequest.heavyweight)) { --- 2509,2515 ---- opposite); } ! if (currentFocusOwner != null && getContainingWindow(currentFocusOwner) == source && (hwFocusRequest == null || source != hwFocusRequest.heavyweight)) { *************** *** 2561,2586 **** // If it arrives as the result of activation we should skip it // This event will not have appropriate request record and // on arrival there will be already some focus owner set. ! return new FocusEvent(currentFocusOwner, id, false, null); } ! // Any other case represents a failure condition which we did ! // not expect. We need to clearFocusRequestList() and patch up ! // the event as best as possible. ! if (removeFirstRequest()) { ! return retargetFocusEvent(event); ! } ! boolean temporary = false; ! if (id == FocusEvent.FOCUS_LOST && ! (opposite == null || focusedWindowChanged(source, opposite))) { ! temporary = true; } - return new FocusEvent(source, id, temporary, opposite); } } static boolean removeFirstRequest() { KeyboardFocusManager manager = KeyboardFocusManager.getCurrentKeyboardFocusManager(); --- 2517,2645 ---- // If it arrives as the result of activation we should skip it // This event will not have appropriate request record and // on arrival there will be already some focus owner set. ! return new FocusEvent(currentFocusOwner, FocusEvent.FOCUS_GAINED, false, null); } ! return retargetUnexpectedFocusEvent(fe); ! } // end synchronized(heavyweightRequests) ! } ! static FocusEvent retargetFocusLost(FocusEvent fe) { ! assert (fe.getID() == FocusEvent.FOCUS_LOST); ! Component currentFocusOwner = getCurrentKeyboardFocusManager(). ! getGlobalFocusOwner(); ! Component opposite = fe.getOppositeComponent(); ! Component nativeOpposite = getHeavyweight(opposite); ! ! synchronized (heavyweightRequests) { ! HeavyweightFocusRequest hwFocusRequest = (HeavyweightFocusRequest) ! ((heavyweightRequests.size() > 0) ! ? heavyweightRequests.getFirst() : null); ! ! if (hwFocusRequest == HeavyweightFocusRequest.CLEAR_GLOBAL_FOCUS_OWNER) { ! if (currentFocusOwner != null) { ! // Call to KeyboardFocusManager.clearGlobalFocusOwner() ! heavyweightRequests.removeFirst(); ! return new FocusEvent(currentFocusOwner, ! FocusEvent.FOCUS_LOST, false, null); ! } ! ! // Otherwise, fall through to failure case below ! ! } else if (opposite == null) ! { ! // Focus leaving application ! if (currentFocusOwner != null) { ! return new FocusEvent(currentFocusOwner, ! FocusEvent.FOCUS_LOST, ! true, null); ! } else { ! return fe; ! } ! } else if (hwFocusRequest != null && ! (nativeOpposite == hwFocusRequest.heavyweight || ! nativeOpposite == null && ! opposite == hwFocusRequest.getFirstLightweightRequest().component)) ! { ! if (currentFocusOwner == null) { ! return fe; ! } ! // Focus change as a result of a known call to requestFocus(), ! // or click on a peer focusable heavyweight Component. ! ! // If a focus transfer is made across top-levels, then the ! // FOCUS_LOST event is always temporary, and the FOCUS_GAINED ! // event is always permanent. Otherwise, the stored temporary ! // value is honored. ! ! LightweightFocusRequest lwFocusRequest = ! (LightweightFocusRequest)hwFocusRequest. ! lightweightRequests.getFirst(); ! ! boolean temporary = focusedWindowChanged(opposite, ! currentFocusOwner) ! ? true ! : lwFocusRequest.temporary; ! ! return new FocusEvent(currentFocusOwner, FocusEvent.FOCUS_LOST, ! temporary, lwFocusRequest.component); ! } ! ! return retargetUnexpectedFocusEvent(fe); ! } // end synchronized(heavyweightRequests) ! } ! ! static AWTEvent retargetFocusEvent(AWTEvent event) { ! if (clearingCurrentLightweightRequests) { ! return event; ! } ! ! KeyboardFocusManager manager = getCurrentKeyboardFocusManager(); ! ! synchronized(heavyweightRequests) { ! /* ! * This code handles FOCUS_LOST event which is generated by ! * DefaultKeyboardFocusManager for FOCUS_GAINED. ! * ! * This code based on knowledge of DefaultKeyboardFocusManager's ! * implementation and might be not applicable for another ! * KeyboardFocusManager. ! * ! * Fix for 4472032 ! */ ! if (newFocusOwner != null && ! event.getID() == FocusEvent.FOCUS_LOST) ! { ! FocusEvent fe = (FocusEvent)event; ! ! if (manager.getGlobalFocusOwner() == fe.getComponent() && ! fe.getOppositeComponent() == newFocusOwner) ! { ! newFocusOwner = null; ! return event; ! } } } + + processCurrentLightweightRequests(); + + switch (event.getID()) { + case FocusEvent.FOCUS_GAINED: { + event = retargetFocusGained((
24-08-2004

EVALUATION This works with javaws1.2 on Java 1.4.0, and is broken with javaws 1.0.1_02 with java 1.4.1. This is a regression in awt from 1.4.0 to 1.4.1 ###@###.### 2002-07-30 I discussed this briefly with ###@###.### today, and he thought it probably would not be a showstopper for Hopper. I'll commit it to Mantis. ###@###.### 2002-07-30 4718813 may be related or the same issue. ###@###.### 2002-07-30 Name: osR10079 Date: 08/12/2002 The problem is reproducible with JaWS 1.2 on both 1.4.0 and 1.4.1 (at least on WinNT). ###@###.### Aug 12, 2002 ====================================================================== This appears to be a well-known issue. This is a flaw in focus machinery, and it was there in 1.4, too. There is a race condition involved, so on some machines it doesn't happen with 1.4. What causes the bug: When user clicks "Next" on SimpleController window, JaWS disables the "Next" button and then immediately removes the JTextArea from the Dialog (the button is disabled in PathController.start() method if the directory in JFileChooser is null, which only happens first time it is shown). Unfortunately, it happens so that the JTextArea is next component in the same focus cycle as "Next" button. When the button is clicked, it receives focus, then it is disabled and focus autotransfers to JTextArea. However, after that happens (i.e. appropriate event is posted to the queue), but before the focus actually arrives, JTextArea is removed from the Dialog. The focus arrives to it later, when it is already invisible. That's why mnemonic keyevents aren't delivered properly. Below is a reduced testcase. When the program starts, click "Next" button. After JFileChooser appears, notice that mnemonics don't work on "Next" and "Previous" buttons. Then click on some part of JFileChooser (file textfield, for example) and notice that mnemonics on the buttons start working again. ===== import javax.swing.*; import java.awt.*; import java.awt.event.*; public class FocusTest extends WindowAdapter implements ActionListener { public static int FIRST_SCREEN = 0; public static int SECOND_SCREEN = 1; JDialog frame; JPanel buttonPanel; JPanel justPanel; JButton cancelButton; JButton previousButton; JButton nextButton; JLabel label; JFileChooser fc; JTextArea ta; int state = FIRST_SCREEN; private void initComps() { frame = new JDialog(new JFrame(), "Let's test it"); frame.addWindowListener(this); frame.getContentPane().setLayout(new BorderLayout()); label = new JLabel("Ok, so I am a label..."); buttonPanel = new JPanel(); buttonPanel.setLayout(new FlowLayout()); cancelButton = new JButton("Cancel"); cancelButton.addActionListener(this); nextButton = new JButton("Next"); nextButton.setMnemonic('x'); nextButton.addActionListener(this); previousButton = new JButton("Previous"); previousButton.setMnemonic('p'); previousButton.setEnabled(false); previousButton.addActionListener(this); buttonPanel.add(cancelButton); buttonPanel.add(previousButton); buttonPanel.add(nextButton); justPanel = new JPanel(); justPanel.setLayout(new BorderLayout()); ta = new JTextArea(); ta.setEditable(false); ta.setText("Ehhehe! TextArea!!!!"); justPanel.add(ta, "Center"); frame.getContentPane().add(justPanel, "Center"); frame.getContentPane().add(label, "North"); frame.getContentPane().add(buttonPanel, "South"); } public static void main(String[] args) { FocusTest ft = new FocusTest(); ft.initComps(); ft.frame.setSize(600, 400); ft.frame.setVisible(true); } public void actionPerformed(ActionEvent evt) { if (evt.getSource() == cancelButton) { System.exit(0); } if (evt.getSource() == previousButton) { previousButton.setEnabled(false); justPanel.remove(fc); justPanel.add(ta); state = FIRST_SCREEN; frame.validate(); frame.repaint(); } if (evt.getSource() == nextButton) { if (state == SECOND_SCREEN) { return; } state = SECOND_SCREEN; if (fc == null) { fc = new JFileChooser(); } nextButton.setEnabled(false); justPanel.remove(ta); justPanel.add(fc, "Center"); previousButton.setEnabled(true); nextButton.setEnabled(true); frame.validate(); frame.repaint(); } } public void windowClosing(WindowEvent evt) { System.exit(0); } } ===== ###@###.### 2002-08-30 Name: osR10079 Date: 09/23/2002 The cause of this bronble is that KeyboardFocusManager.retargetFocusEvent() is not prepared for focus events which arrive on peerless components. The problem is a regression for fix for 4511021 (Revisit how KeyboardFocusManager clears its fields). ###@###.### 2002-09-24 ======================================================================
24-09-2002