1 
   2 import java.awt.*;
   3 import java.awt.event.KeyEvent;
   4 import java.util.ArrayList;
   5 import java.util.List;
   6 import javax.accessibility.Accessible;
   7 import javax.accessibility.AccessibleContext;
   8 import javax.accessibility.AccessibleState;
   9 import javax.accessibility.AccessibleStateSet;
  10 import javax.swing.*;
  11 import javax.swing.plaf.nimbus.NimbusLookAndFeel;
  12 
  13 /*
  14  * @test
  15  * @bug 8134116
  16  * @summary JTabbedPane$Page.getBounds throws IndexOutOfBoundsException
  17  * @run main Bug8134116
  18  */
  19 public class Bug8134116 {
  20 
  21     private static volatile Exception exception = null;
  22 
  23     public static void main(String args[]) throws Exception {
  24 
  25         try {
  26             UIManager.setLookAndFeel(new NimbusLookAndFeel());
  27         } catch (Exception e) {
  28             throw new RuntimeException(e);
  29         }
  30 
  31         SwingUtilities.invokeAndWait(() -> {
  32             JPanel panel0 = new JPanel();
  33             JPanel panel2 = new JPanel();
  34             BadPane badPane = new BadPane();
  35             badPane.add("zero", panel0);
  36             badPane.add("one", null);  // no component
  37             badPane.add("", panel2);  // no title
  38             badPane.add("", null); // no component, no title
  39             // but give it that via a tabComponent
  40             JPanel tabComponent = new JPanel();
  41             JLabel tabComponentLabel = new JLabel("three");
  42             tabComponent.add(tabComponentLabel);
  43             badPane.setTabComponentAt(3, tabComponent);
  44             JFrame frame = new JFrame();
  45             frame.add(badPane);
  46             frame.setSize(300, 300);
  47             frame.setVisible(true);
  48 
  49             try {
  50                 AccessibleContext ac = badPane.getAccessibleContext();
  51                 Accessible page0 = ac.getAccessibleChild(0);
  52                 if (page0 == null) {
  53                     // Not something being tested, but checking anyway
  54                     throw new RuntimeException("getAccessibleChild(0) is null");
  55                 }
  56                 Accessible page1 = ac.getAccessibleChild(1);
  57                 if (page1 == null) {
  58                     // Not something being tested, but checking anyway
  59                     throw new RuntimeException("getAccessibleChild(1) is null");
  60                 }
  61                 Accessible page2 = ac.getAccessibleChild(2);
  62                 Accessible page3 = ac.getAccessibleChild(3);
  63                 // page0 - page3 are JTabbedPane.Page, a private inner class
  64                 // and is an AccessibleContext
  65                 // and implements Accessible and AccessibleComponent
  66                 AccessibleContext pac0 = page0.getAccessibleContext();
  67                 AccessibleContext pac1 = page1.getAccessibleContext();
  68                 AccessibleContext pac2 = page2.getAccessibleContext();
  69                 AccessibleContext pac3 = page3.getAccessibleContext();
  70 
  71                 // test Page.getBounds
  72                 // ensure no IndexOutOfBoundsException
  73                 Rectangle r0 = pac0.getAccessibleComponent().getBounds();
  74                 // make sure second Bounds is different than first
  75                 Rectangle r1  = pac1.getAccessibleComponent().getBounds();
  76                 if (r1.equals(r0)) {
  77                     String msg = "Second tab should not have same bounds as first tab";
  78                     throw new RuntimeException(msg);
  79                 }
  80 
  81                 // test Page.getAccessibleStateSet
  82                 // At this point page 0 is selected
  83                 AccessibleStateSet accSS0 = pac0.getAccessibleStateSet();
  84                 if (!accSS0.contains(AccessibleState.SELECTED)) {
  85                     String msg = "Empty title -> AccessibleState.SELECTED not set";
  86                     throw new RuntimeException(msg);
  87                 }
  88                 // select second tab
  89                 badPane.setSelectedIndex(1);
  90                 AccessibleStateSet accSS1 = pac1.getAccessibleStateSet();
  91                 if (!accSS1.contains(AccessibleState.SELECTED)) {
  92                     String msg = "Second tab selected but AccessibleState.SELECTED not set";
  93                     throw new RuntimeException(msg);
  94                 }
  95                 // select third tab
  96                 badPane.setSelectedIndex(2);
  97                 AccessibleStateSet accSS2 = pac2.getAccessibleStateSet();
  98                 if (!accSS1.contains(AccessibleState.SELECTED)) {
  99                     String msg = "Third tab selected but AccessibleState.SELECTED not set";
 100                     throw new RuntimeException(msg);
 101                 }
 102                 // select fourth tab
 103                 badPane.setSelectedIndex(3);
 104                 AccessibleStateSet accSS3 = pac3.getAccessibleStateSet();
 105                 if (!accSS1.contains(AccessibleState.SELECTED)) {
 106                     String msg = "Fourth tab selected but AccessibleState.SELECTED not set";
 107                     throw new RuntimeException(msg);
 108                 }
 109 
 110                 // test Page.getAccessibleIndexInParent
 111                 if (pac0.getAccessibleIndexInParent() == -1) {
 112                     String msg = "Empty title -> negative AccessibleIndexInParent";
 113                     throw new RuntimeException(msg);
 114                 }
 115                 if (pac0.getAccessibleIndexInParent() != 0) {
 116                     String msg = "first tab is not at index 0 in parent";
 117                     throw new RuntimeException(msg);
 118                 }
 119                 if (pac1.getAccessibleIndexInParent() != 1) {
 120                     String msg = "second tab (null component) is not at index 1 in parent";
 121                     throw new RuntimeException(msg);
 122                 }
 123                 if (pac2.getAccessibleIndexInParent() != 2) {
 124                     String msg = "third tab (empty title) string is not at index 2 in parent";
 125                     throw new RuntimeException(msg);
 126                 }
 127                 if (pac3.getAccessibleIndexInParent() != 3) {
 128                     String msg = "fourth tab (empty title, null component, has tabComponent) string is not at index 3 in parent";
 129                     throw new RuntimeException(msg);
 130                 }
 131 
 132                 // test Page.getAccessibleName
 133                 String accName = pac0.getAccessibleName();
 134                 if (!accName.equals("zero")) {
 135                     String msg = "Empty title -> empty AccessibleName";
 136                     throw new RuntimeException(msg);
 137                 }
 138                 // test Page.getAccessibleName when component is null
 139                 accName = pac1.getAccessibleName();
 140                 if (!accName.equals("one")) {
 141                     String msg = "AccessibleName of null panel not 'one'";
 142                     throw new RuntimeException(msg);
 143                 }
 144 
 145                 // test Page.setDisplayedMnemonicIndex
 146                 //  Empty title -> IllegalArgumnetException
 147                 badPane.setDisplayedMnemonicIndexAt(0, 1);
 148 
 149                 // test Page.updateDisplayedMnemonicIndex
 150                 badPane.setMnemonicAt(0, KeyEvent.VK_Z);
 151                 if (badPane.getDisplayedMnemonicIndexAt(0) == -1) {
 152                     String msg="Empty title -> getDisplayedMnemonicIndexAt failure";
 153                     throw new RuntimeException(msg);
 154                 }
 155             } catch (Exception e) {
 156                 exception = e;
 157             }
 158         });
 159         if (exception != null) {
 160             System.out.println("Test failed: " + exception.getMessage());
 161             throw exception;
 162         } else {
 163             System.out.println("Test passed.");
 164         }
 165     }
 166 
 167     // The following is likely what is being done in Burp Suite
 168     // https://portswigger.net/burp/ which fails in the same way, i.e. the
 169     // pages List in JTabbedPane is not being managed properly and thus
 170     // Page.title is "" for each page.  The overridden insertTab manages titles
 171     // in the subclass passing a "" title to the superclass JTabbedPane through
 172     // its insertTab.  Later an overridden getTitleAt returns the titles as
 173     // managed by the subclass.
 174     static class BadPane extends JTabbedPane {
 175         private List<String> titles;
 176 
 177         BadPane() {
 178             titles = new ArrayList<String>(1);
 179         }
 180 
 181         @Override
 182         public void insertTab( String title, Icon icon, Component component,
 183                                String tip, int index ) {
 184             titles.add(index, title);
 185             super.insertTab("", icon, component, tip, index);
 186         }
 187 
 188         @Override
 189         public String getTitleAt(int i) {
 190             return titles.get(i);
 191         }
 192     }
 193 
 194 }