8322239: [macos] a11y : java.lang.NullPointerException is thrown when focus is moved on the JTabbedPane#17736
8322239: [macos] a11y : java.lang.NullPointerException is thrown when focus is moved on the JTabbedPane#17736azuev-java wants to merge 6 commits intoopenjdk:masterfrom
Conversation
… focus is moved on the JTabbedPane Add null check for the Aqua LnF situation when tab is hidden die to the tabs overflow.
|
👋 Welcome back kizune! A progress list of the required criteria for merging this PR into |
|
@azuev-java The following label will be automatically applied to this pull request:
When this pull request is ready to be reviewed, an "RFR" email will be sent to the corresponding mailing list. If you would like to change these labels, use the /label pull request command. |
Webrevs
|
kumarabhi006
left a comment
There was a problem hiding this comment.
Verified the fix on MacOS 13.6.3. Looks good to me.
|
I wonder if it's appropriate that location or dimension become If a tab becomes hidden because of the overflow, it is appropriate to return What about the number of tabs reported? Is the original count still reported? The accessibility software should be able to “see” the number of tabs hasn't reduced. |
It is appropriate with the Aqua L&F since control is not showing on the screen but active and should be available for the accessibility subsystem. The accessible description of the jtabbedpane does mention correct number of tabs. Returning dimension(0,0,0,0) or location (0,0) is incorrect because in this case accessibility logic will move accessibility cursor to the wrong location and the order of navigation will be affected. This fix does not affect any other OS aside ow Mac OS because Aqua L&F only available on OS X. |
| @@ -2339,13 +2339,16 @@ public boolean contains(Point p) { | |||
| public Point getLocationOnScreen() { | |||
| Point parentLocation = parent.getLocationOnScreen(); | |||
There was a problem hiding this comment.
possibly the "parent.getLocationOnScreen()" should be wrapped by the "try/catch IllegalComponentStateException"? If some parent is not visible then that exception will be thrown, but per the spec, the null should be returned.
I think this could be covered by the test since the change is in the public shared code.
There was a problem hiding this comment.
Sure. I have added the handler ICSE and a regression test.
Added regression test
| import javax.swing.JPanel; | ||
| import javax.swing.JTabbedPane; | ||
| import javax.swing.SwingUtilities; | ||
| import java.awt.BorderLayout; |
There was a problem hiding this comment.
suggestion: awt imports may be moved before swing and a11y imports.
| try { | ||
| SwingUtilities.invokeAndWait(me::test); | ||
| } finally { | ||
| if(mainFrame != null) { |
There was a problem hiding this comment.
| if(mainFrame != null) { | |
| if (mainFrame != null) { |
| AccessibleComponent component = (AccessibleComponent) accessible; | ||
| Point p = component.getLocationOnScreen(); | ||
| Rectangle r = component.getBounds(); | ||
| } catch(NullPointerException npe){ |
There was a problem hiding this comment.
| } catch(NullPointerException npe){ | |
| } catch (NullPointerException npe) { |
| try { | ||
| SwingUtilities.invokeAndWait(me::test); | ||
| } finally { | ||
| if (mainFrame != null) { |
There was a problem hiding this comment.
should be disposed on EDT.
There was a problem hiding this comment.
This is not thread-safe, the condition if (mainFrame != null) should also be inside invokeAndWait.
Maybe create a method to use method reference: invokeAndWait(me::dispose)? In this case, mainFrame could be made instance field.
| try { | ||
| SwingUtilities.invokeAndWait(me::test); | ||
| } finally { | ||
| if (mainFrame != null) { |
There was a problem hiding this comment.
This is not thread-safe, the condition if (mainFrame != null) should also be inside invokeAndWait.
Maybe create a method to use method reference: invokeAndWait(me::dispose)? In this case, mainFrame could be made instance field.
| throw new RuntimeException("Unexpected NullPointerException " + | ||
| "while getting accessible component bounds: " + npe); |
There was a problem hiding this comment.
| throw new RuntimeException("Unexpected NullPointerException " + | |
| "while getting accessible component bounds: " + npe); | |
| throw new RuntimeException("Unexpected NullPointerException " + | |
| "while getting accessible component bounds", npe); |
Preserve the full context of NPE for analysing the failure if it ever occurs.
| AccessibleComponent component = (AccessibleComponent) accessible; | ||
| Point p = component.getLocationOnScreen(); | ||
| Rectangle r = component.getBounds(); | ||
| } catch (NullPointerException npe){ |
There was a problem hiding this comment.
| } catch (NullPointerException npe){ | |
| } catch (NullPointerException npe) { |
Missing space.
| if (accessible instanceof AccessibleComponent) { | ||
| try { | ||
| AccessibleComponent component = (AccessibleComponent) accessible; |
There was a problem hiding this comment.
You can you pattern matching if you like:
| if (accessible instanceof AccessibleComponent) { | |
| try { | |
| AccessibleComponent component = (AccessibleComponent) accessible; | |
| if (accessible instanceof AccessibleComponent component) { | |
| try { |
There was a problem hiding this comment.
Since this fix can be backported to the previous releases where this nice feature is not available i prefer not to use it. I guess backporting is why we can't get nice things for ourselves.
There was a problem hiding this comment.
Yeah, it's a consideration. Pattern matching for instanceof is available since Java 16, so only 11 and below will need slight modification.
|
@azuev-java This change now passes all automated pre-integration checks. ℹ️ This project also has non-automated pre-integration requirements. Please see the file CONTRIBUTING.md for details. After integration, the commit message for the final commit will be: You can use pull request commands such as /summary, /contributor and /issue to adjust it as needed. At the time when this comment was updated there had been 214 new commits pushed to the
As there are no conflicts, your changes will automatically be rebased on top of these commits when integrating. If you prefer to avoid this automatic rebasing, please check the documentation for the /integrate command for further details. ➡️ To integrate this PR with the above commit message to the |
|
/integrate |
|
Going to push as commit 3b1062d.
Your commit was automatically rebased without conflicts. |
|
@azuev-java Pushed as commit 3b1062d. 💡 You may see a message that your pull request was closed with unmerged commits. This can be safely ignored. |
Add null check for the Aqua LnF situation when tab is hidden die to the tabs overflow.
Progress
Issue
Reviewers
Reviewing
Using
gitCheckout this PR locally:
$ git fetch https://git.openjdk.org/jdk.git pull/17736/head:pull/17736$ git checkout pull/17736Update a local copy of the PR:
$ git checkout pull/17736$ git pull https://git.openjdk.org/jdk.git pull/17736/headUsing Skara CLI tools
Checkout this PR locally:
$ git pr checkout 17736View PR using the GUI difftool:
$ git pr show -t 17736Using diff file
Download this PR as a diff file:
https://git.openjdk.org/jdk/pull/17736.diff
Webrev
Link to Webrev Comment