8134116: Add more comprehensive fix and regression test for JDK-8133897
Summary: Use getTitleAt instead of Page.title field; add regression test
Reviewed-by: alexsch, serb
Contributed-by: peter.brunet@oracle.com
--- a/jdk/src/java.desktop/share/classes/javax/swing/JTabbedPane.java Tue Nov 10 13:46:45 2015 +0300
+++ b/jdk/src/java.desktop/share/classes/javax/swing/JTabbedPane.java Thu Nov 12 12:27:36 2015 -0600
@@ -2095,9 +2095,10 @@
*/
void setDisplayedMnemonicIndex(int mnemonicIndex) {
if (this.mnemonicIndex != mnemonicIndex) {
- if (mnemonicIndex != -1 && (title == null ||
+ String t = getTitle();
+ if (mnemonicIndex != -1 && (t == null ||
mnemonicIndex < 0 ||
- mnemonicIndex >= title.length())) {
+ mnemonicIndex >= t.length())) {
throw new IllegalArgumentException(
"Invalid mnemonic index: " + mnemonicIndex);
}
@@ -2116,7 +2117,7 @@
void updateDisplayedMnemonicIndex() {
setDisplayedMnemonicIndex(
- SwingUtilities.findDisplayedMnemonicIndex(title, mnemonic));
+ SwingUtilities.findDisplayedMnemonicIndex(getTitle(), mnemonic));
}
/////////////////
@@ -2133,10 +2134,9 @@
public String getAccessibleName() {
if (accessibleName != null) {
return accessibleName;
- } else if (title != null) {
- return title;
+ } else {
+ return getTitle();
}
- return null;
}
public String getAccessibleDescription() {
@@ -2156,7 +2156,7 @@
AccessibleStateSet states;
states = parent.getAccessibleContext().getAccessibleStateSet();
states.add(AccessibleState.SELECTABLE);
- int i = parent.indexOfTab(title);
+ int i = parent.indexOfTabComponent(tabComponent);
if (i == parent.getSelectedIndex()) {
states.add(AccessibleState.SELECTED);
}
@@ -2164,7 +2164,7 @@
}
public int getAccessibleIndexInParent() {
- return parent.indexOfTab(title);
+ return parent.indexOfTabComponent(tabComponent);
}
public int getAccessibleChildrenCount() {
@@ -2272,10 +2272,8 @@
}
public Rectangle getBounds() {
- int i = parent.indexOfTab(title);
- // Check for no title. Even though that's a bug in the app we should
- // inhibit an ArrayIndexOutOfBoundsException from getTabBounds.
- return (i == -1) ? null : parent.getUI().getTabBounds(parent, i);
+ return parent.getUI().
+ getTabBounds(parent, parent.indexOfTabComponent(tabComponent));
}
public void setBounds(Rectangle r) {
@@ -2343,6 +2341,11 @@
return null;
}
}
+
+ private String getTitle() {
+ return getTitleAt(parent.indexOfComponent(component));
+ }
+
}
/**
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/javax/swing/JTabbedPane/8134116/Bug8134116.java Thu Nov 12 12:27:36 2015 -0600
@@ -0,0 +1,130 @@
+
+import java.awt.*;
+import java.awt.event.KeyEvent;
+import java.util.ArrayList;
+import java.util.List;
+import javax.accessibility.Accessible;
+import javax.accessibility.AccessibleComponent;
+import javax.accessibility.AccessibleContext;
+import javax.accessibility.AccessibleState;
+import javax.accessibility.AccessibleStateSet;
+import javax.swing.*;
+import javax.swing.plaf.nimbus.NimbusLookAndFeel;
+
+/*
+ * @test
+ * @bug 8134116
+ * @summary JTabbedPane$Page.getBounds throws IndexOutOfBoundsException
+ * @run main Bug8134116
+ */
+public class Bug8134116 {
+
+ public static void main(String args[]) throws Exception {
+
+ try {
+ UIManager.setLookAndFeel(new NimbusLookAndFeel());
+ } catch (Exception e) {
+ throw new RuntimeException(e);
+ }
+
+ SwingUtilities.invokeAndWait(() -> {
+ JPanel panel0 = new JPanel();
+ BadPane badPane = new BadPane();
+ badPane.add("zero", panel0);
+ badPane.add("one", null);
+ JFrame frame = new JFrame();
+ frame.add(badPane);
+ frame.setSize(300, 300);
+ frame.setVisible(true);
+
+ AccessibleContext ac = badPane.getAccessibleContext();
+ Accessible page0 = ac.getAccessibleChild(0);
+ if (page0 == null) {
+ // Not something being tested, but checking anyway
+ throw new RuntimeException("getAccessibleChild(0) is null");
+ }
+ Accessible page1 = ac.getAccessibleChild(1);
+ if (page1 == null) {
+ // Not something being tested, but checking anyway
+ throw new RuntimeException("getAccessibleChild(1) is null");
+ }
+ // page0 and page1 are a JTabbedPane.Page, a private inner class
+ // and is an AccessibleContext
+ // and implements Accessible and AccessibleComponent
+ AccessibleContext pac0 = page0.getAccessibleContext();
+ AccessibleContext pac1 = page1.getAccessibleContext();
+
+ // the following would fail if JDK-8134116 fix not present
+
+ // test Page.getBounds
+ // ensure no IndexOutOfBoundsException
+ pac0.getAccessibleComponent().getBounds();
+
+ // test Page.getAccessibleStateSet
+ // At this point page 0 is selected
+ AccessibleStateSet accSS0 = pac0.getAccessibleStateSet();
+ if (!accSS0.contains(AccessibleState.SELECTED)) {
+ String msg = "Empty title -> AccessibleState.SELECTED not set";
+ throw new RuntimeException(msg);
+ }
+
+ // test Page.getAccessibleIndexInParent
+ if (pac0.getAccessibleIndexInParent() == -1) {
+ String msg = "Empty title -> negative AccessibleIndexInParent";
+ throw new RuntimeException(msg);
+ }
+
+ // test Page.getAccessibleName
+ String accName = pac0.getAccessibleName();
+ if (!accName.equals("zero")) {
+ String msg = "Empty title -> empty AccessibleName";
+ throw new RuntimeException(msg);
+ }
+ // test Page.getAccessibleName when component is null
+ accName = pac1.getAccessibleName();
+ if (!accName.equals("one")) {
+ String msg = "AccessibleName of null panel not 'one'";
+ throw new RuntimeException(msg);
+ }
+
+ // test Page.setDisplayedMnemonicIndex
+ // Empty title -> IllegalArgumnetException
+ badPane.setDisplayedMnemonicIndexAt(0, 1);
+
+ // test Page.updateDisplayedMnemonicIndex
+ badPane.setMnemonicAt(0, KeyEvent.VK_Z);
+ if (badPane.getDisplayedMnemonicIndexAt(0) == -1) {
+ String msg="Empty title -> getDisplayedMnemonicIndexAt failure";
+ throw new RuntimeException(msg);
+ }
+ });
+ }
+
+ // The following is likely what is being done in Burp Suite
+ // https://portswigger.net/burp/ which fails in the same way, i.e. the
+ // pages List in JTabbedPane is not being managed properly and thus
+ // Page.title is "" for each page. The overridden insertTab manages titles
+ // in the subclass passing a "" title to the superclass JTabbedPane through
+ // its insertTab. Later an overridden getTitleAt returns the titles as
+ // managed by the subclass.
+ static class BadPane extends JTabbedPane {
+ private List<String> titles;
+
+ BadPane() {
+ titles = new ArrayList<String>(1);
+ }
+
+ @Override
+ public void insertTab( String title, Icon icon, Component component,
+ String tip, int index ) {
+ titles.add(index, title);
+ super.insertTab("", icon, component, tip, index);
+ }
+
+ @Override
+ public String getTitleAt(int i) {
+ return titles.get(i);
+ }
+ }
+
+}