-
Bug
-
Resolution: Won't Fix
-
P3
-
1.1.7, 6
-
generic, x86
-
generic, windows_nt
Name: mf23781 Date: 09/24/98
Clarify in documentation that no 2 tabs in a JTabbedPane can have
the same component assigned to them.. causes
java.lang.ArrayIndexOutOfBoundsException: 1 > 0
at java.util.Vector.insertElementAt(Vector.java:434)
at com.sun.java.swing.JTabbedPane.insertTab(JTabbedPane.java:425)
at com.sun.java.swing.JTabbedPane.addTab(JTabbedPane.java:473)
This restriction seems part of design since there is a method
remove(Component) which implies the strict one to one association.
Here is code demonstrating exception and comment line to correct.
import java.awt.*;
import java.awt.event.*;
import com.sun.java.swing.*;
import com.sun.java.swing.event.*;
public class TabTest extends JPanel implements ActionListener {
public static int INITIAL_WIDTH = 400;
public static int INITIAL_HEIGHT = 200;
BorderLayout bdl = new BorderLayout();
JFrame jf = new JFrame("Tab Pane Test");
JButton jb = new JButton("Button");
JTabbedPane jtab = new JTabbedPane();
// Create the GUI
//
public TabTest() {
jb.addActionListener(this);
System.out.println("Starting...");
JCheckBox jch1 = new JCheckBox("check 1!");
JCheckBox jch2 = new JCheckBox("check 2!");
jtab.addTab("first", null,jch1);
//jtab.addTab("second", null,jch2); // this works
jtab.addTab("second", null,jch1); // same component causes exception
setLayout(bdl);
WindowListener l = new WindowAdapter() {
public void windowClosing(WindowEvent e) {System.exit(0);}
public void windowIconified(WindowEvent e) {System.exit(0);}
};
jf.addWindowListener(l);
add("North", jb);
add("Center",jtab);
jf.getContentPane().add(this);
jf.setSize(INITIAL_WIDTH, INITIAL_HEIGHT);
Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
jf.setLocation(screenSize.width/2 - INITIAL_WIDTH/2,
screenSize.height/2 - INITIAL_HEIGHT/2);
jf.show();
}
static public void main(String args[]) {
new TabTest();
}
public void actionPerformed(ActionEvent e) {
}
}
======================================================================
Suggested fix by java.net member leouser
A DESCRIPTION OF THE FIX :
BUGID 4176095 Clarification that no 2 Tabs in JTabbedPane can have the same component
FILES AFFECTED: javax.swing.JTabbedPane
JDK VERSION
jdk-6-rc-bin-b64-linux-i586-15_dec_2005.bin
Discusion(embeded in test case as well):
/**
* BUGID 4176095 Clarification that no 2 Tabs in JTabbedPane can have the same component
* This interesting rfe after being reviewed by the engineer appears to have
* turned into an investigation as to whether or not the JTabbedPane can handle
* multiple instances of the same component into the JTabbedPane. It appears
* the research never reached fruition. The enhancement I have put together
* explores the issue and it appears successfully to have done so.
* I have added 3 new methods to JTabbedPane:
* setAllowsMultiTabComponent
* getAllowsMultiTabComponent
* indexesOfComponent
* I have also enhanced a couple methods, remove(Component),insertTabAt,
* setSelectedComponent and setComponentAt.
* so they are adjusted to this new reality. remove removes all instances
* of the component. setSelectedComponent will cycle to the next index of
* the same component if the Component being selected is the current selection.
*
* These methods are what I see as the 'issues', they need to be sophisticated
* enought to work with a component being added multiple times, if configured
* to allow it.
*
* ANTI-RATIONALE:
* 1. JTabbedPane is not final, uncertain if new methods will collide with
* a subclass.
* 2. Questionable use case. Do people really want this? I can't come up
* with one at the top of my head, but it appears someone wanted it back in 98.
* Anyway, even if I can't come up with a use case the new capability is somewhat
* exciting to witness.
*
* TESTING STRATEGY:
* 1. Exercise all methods that have been changed to see if they work in the
* mult-component reality.
* 2. Exercise the new methods... they get exercised in the altered ones so
* this is already happening.
* 3. Look at the visuals, see how one of the JTabbedPane's bring up the
* same component many times... success? :)
*
* FILES AFFECTED: javax.swing.JTabbedPane
*
* JDK VERSION
* jdk-6-rc-bin-b64-linux-i586-15_dec_2005.bin
*
* test ran succesfully on a SUSE 7.3 Linux distribution
*
* Brian Harry
* ###@###.###
* Jan 25, 2006
*/
UNIFIED DIFF:
--- /home/nstuff/java6/jdk1.6.0/javax/swing/JTabbedPane.java Thu Dec 15 02:17:37 2005
+++ /home/javarefs/javax/swing/JTabbedPane.java Wed Jan 25 13:58:21 2006
@@ -452,6 +452,27 @@
}
/**
+ * Sets whether a {@code Component} instance can be added
+ * to the {@code JTabbedPane} multiple times. When allowed
+ * each addition will create a new tab.
+ *
+ * @param allows whether or not to allow a {@code Component}
+ * multiple times
+ */
+ public void setAllowsMultiTabComponent(boolean allows){
+ putClientProperty("allowsMultiTabComponents", allows);
+ }
+
+ /**
+ * Returns if a {@code Component} can be added multiple times.
+ *
+ * @return if a {@code Component} can be added multiple times
+ */
+ public boolean getAllowsMultiTabComponent(){
+ return Boolean.TRUE.equals(getClientProperty("allowsMultiTabComponents"));
+ }
+
+ /**
* Returns the currently selected index for this tabbedpane.
* Returns -1 if there is no currently selected tab.
*
@@ -561,10 +582,23 @@
* description: The tabbedpane's selected component.
*/
public void setSelectedComponent(Component c) {
- int index = indexOfComponent(c);
- if (index != -1) {
- setSelectedIndex(index);
- } else {
+ int[] indexes = indexesOfComponent(c);
+ int sindex = getSelectedIndex();
+ int ind = -1;
+ for(int i = 0; i < indexes.length; i++){
+ if(indexes[i] == sindex){
+ ind = i;
+ break;
+ }
+ }
+ if(indexes.length != 0){
+ if(ind == -1 || (ind + 1) == indexes.length)
+ setSelectedIndex(indexes[0]);
+ else{
+ setSelectedIndex(indexes[ind + 1]);
+ }
+ }
+ else {
throw new IllegalArgumentException("component not found in tabbed pane");
}
}
@@ -594,12 +628,14 @@
// but we really should throw an exception because much of the
// rest of the JTabbedPane implementation isn't designed to deal
// with null components for tabs.
- int removeIndex = indexOfComponent(component);
- if (component != null && removeIndex != -1) {
- removeTabAt(removeIndex);
- if (newIndex > removeIndex) {
- newIndex--;
- }
+ if(!getAllowsMultiTabComponent()){
+ int removeIndex = indexOfComponent(component);
+ if (component != null && removeIndex != -1) {
+ removeTabAt(removeIndex);
+ if (newIndex > removeIndex) {
+ newIndex--;
+ }
+ }
}
int selectedIndex = getSelectedIndex();
@@ -609,8 +645,10 @@
if (component != null) {
- addImpl(component, null, -1);
- component.setVisible(false);
+ if(!(component.getParent() == this) || !getAllowsMultiTabComponent()){
+ addImpl(component, null, -1);
+ component.setVisible(false);
+ }
}
if (pages.size() == 1) {
@@ -875,7 +913,10 @@
public void remove(Component component) {
int index = indexOfComponent(component);
if (index != -1) {
- removeTabAt(index);
+ while(index != -1){
+ removeTabAt(index);
+ index = indexOfComponent(component);
+ }
} else {
// Container#remove(comp) invokes Container#remove(int)
// so make sure JTabbedPane#remove(int) isn't called here
@@ -1387,13 +1428,10 @@
// REMIND(aim): this is really silly;
// why not if (page.component.getParent() == this) remove(component)
synchronized(getTreeLock()) {
- int count = getComponentCount();
- Component children[] = getComponents();
- for (int i = 0; i < count; i++) {
- if (children[i] == page.component) {
- super.remove(i);
- }
- }
+ Component c = getComponentAt(index);
+ if(c == page.component
+ && indexesOfComponent(c).length == 1)
+ super.remove(index);
}
component.setVisible(page.component.isVisible());
} else {
@@ -1402,7 +1440,8 @@
component.setVisible(false);
}
page.component = component;
- addImpl(component, null, -1);
+ if(!getAllowsMultiTabComponent() || component.getParent() != this)
+ addImpl(component, null, -1);
revalidate();
}
@@ -1548,6 +1587,29 @@
}
}
return -1;
+ }
+
+ /**
+ * Returns the indexes of the tabs for the specified component.
+ * Returns an empty array if there are no tabs for this component.
+ *
+ * @param component the component for the tabs
+ * @return the tabs which match the component, or an
+ * empty array if none are found.
+ */
+ public int[] indexesOfComponent(Component component){
+ java.util.List<Integer> indexes = new ArrayList<Integer>();
+ for(int i = 0; i < getTabCount(); i++) {
+ Component c = getComponentAt(i);
+ if ((c != null && c.equals(component)) ||
+ (c == null && c == component)) {
+ indexes.add(i);
+ }
+ }
+ int[] rv = new int[indexes.size()];
+ for(int i = 0; i < rv.length; i++)
+ rv[i] = indexes.get(i);
+ return rv;
}
/**
JUnit TESTCASE :
import javax.swing.*;
import junit.framework.TestCase;
import junit.textui.TestRunner;
import static java.lang.System.out;
/**
* BUGID 4176095 Clarification that no 2 Tabs in JTabbedPane can have the same component
* This interesting rfe after being reviewed by the engineer appears to have
* turned into an investigation as to whether or not the JTabbedPane can handle
* multiple instances of the same component into the JTabbedPane. It appears
* the research never reached fruition. The enhancement I have put together
* explores the issue and it appears successfully to have done so.
* I have added 3 new methods to JTabbedPane:
* setAllowsMultiTabComponent
* getAllowsMultiTabComponent
* indexesOfComponent
* I have also enhanced a couple methods, remove(Component),insertTabAt,
* setSelectedComponent and setComponentAt.
* so they are adjusted to this new reality. remove removes all instances
* of the component. setSelectedComponent will cycle to the next index of
* the same component if the Component being selected is the current selection.
*
* These methods are what I see as the 'issues', they need to be sophisticated
* enought to work with a component being added multiple times, if configured
* to allow it.
*
* ANTI-RATIONALE:
* 1. JTabbedPane is not final, uncertain if new methods will collide with
* a subclass.
* 2. Questionable use case. Do people really want this? I can't come up
* with one at the top of my head, but it appears someone wanted it back in 98.
* Anyway, even if I can't come up with a use case the new capability is somewhat
* exciting to witness.
*
* TESTING STRATEGY:
* 1. Exercise all methods that have been changed to see if they work in the
* mult-component reality.
* 2. Exercise the new methods... they get exercised in the altered ones so
* this is already happening.
* 3. Look at the visuals, see how one of the JTabbedPane's bring up the
* same component many times... success? :)
*
* FILES AFFECTED: javax.swing.JTabbedPane
*
* JDK VERSION
* jdk-6-rc-bin-b64-linux-i586-15_dec_2005.bin
*
* test ran succesfully on a SUSE 7.3 Linux distribution
*
* Brian Harry
* ###@###.###
* Jan 25, 2006
*/
public class JTPane4176095 extends TestCase{
public void createTab(JPanel parent, boolean multi){
JTabbedPane jtp = new JTabbedPane();
jtp.setAllowsMultiTabComponent(multi);
parent.add(jtp);
JButton zero = new JButton( "I wont show up in multi!");
JButton jb1 = new JButton("Hi1!");
JButton jb2 = new JButton("Hi2!");
jtp.addTab( "zero", zero);
jtp.addTab("first", jb1);
jtp.addTab("second", jb2);
jtp.addTab("third", jb1);
for(int i : jtp.indexesOfComponent(jb1))
out.println(i);
JTextPane jte = new JTextPane();
jte.setText( "Java is Coolll....");
for(int i = 0; i < 5; i++)
jtp.addTab(String.valueOf(i), jte);
if(multi)
jtp.setComponentAt(0, jte);
}
public void testGUI(){
JFrame jf = new JFrame();
JPanel jp = new JPanel();
JPanel multi = new JPanel();
multi.setBorder(BorderFactory.createTitledBorder(multi.getBorder(), "Multi"));
createTab(multi, true);
jp.add(multi);
JPanel single = new JPanel();
single.setBorder(BorderFactory.createTitledBorder(single.getBorder(), "Single"));
createTab(single, false);
jp.add(single);
jf.add(jp);
jf.pack();
jf.setVisible(true);
}
public void testRemove(){
JTabbedPane jtp = new JTabbedPane();
jtp.setAllowsMultiTabComponent(true);
JButton jb1 = new JButton("Hi!");
for(int i = 0; i < 5; i++)
jtp.addTab(String.valueOf(i), jb1);
assertEquals(jtp.indexesOfComponent(jb1).length, 5);
jtp.removeTabAt(0);
assertEquals(jtp.indexesOfComponent(jb1).length, 4);
jtp.remove(jb1);
assertEquals(jtp.indexesOfComponent(jb1).length,0);
}
public void testRemove2(){
JTabbedPane jtp = new JTabbedPane();
jtp.setAllowsMultiTabComponent(false);
JButton jb1 = new JButton("Hi!");
jtp.addTab( "MOO", jb1);
assertEquals(jtp.indexesOfComponent(jb1).length, 1);
jtp.removeTabAt(0);
assertEquals(jtp.indexesOfComponent(jb1).length,0);
}
public void testSelect(){
JTabbedPane jtp = new JTabbedPane();
jtp.setAllowsMultiTabComponent(true);
JButton jb1 = new JButton("Hi!");
for(int i = 0; i < 5; i++)
jtp.addTab(String.valueOf(i), jb1);
// jtp.setSelectedIndex(0);
for(int i = 0; i < 5; i++){
out.println( "i is " + i + " should be " + jtp.getSelectedIndex());
assertEquals(i, jtp.getSelectedIndex());
jtp.setSelectedComponent(jb1);
}
int[] indexes = new int[]{ 1,2,3,4,0};
jtp.setSelectedIndex(1);
for(int i: indexes){
out.println( "i is " + i + " should be " + jtp.getSelectedIndex());
assertEquals(i, jtp.getSelectedIndex());
jtp.setSelectedComponent(jb1);
}
}
public void testSelect2(){
JTabbedPane jtp = new JTabbedPane();
jtp.setAllowsMultiTabComponent(false);
JButton jb1 = new JButton("Hi!");
jtp.addTab("yeah", jb1);
for(int i = 0; i < 5; i++){
jtp.setSelectedComponent(jb1);
assertEquals(jb1, jtp.getSelectedComponent());
}
}
public static void main(String ... args){
Runnable run = new Runnable(){
public void run(){
JTPane4176095 jtp = new JTPane4176095();
jtp.testGUI();
jtp.testRemove();
jtp.testRemove2();
jtp.testSelect();
jtp.testSelect2();
}
};
SwingUtilities.invokeLater(run);
}
}
FIX FOR BUG NUMBER:
4176095
Clarify in documentation that no 2 tabs in a JTabbedPane can have
the same component assigned to them.. causes
java.lang.ArrayIndexOutOfBoundsException: 1 > 0
at java.util.Vector.insertElementAt(Vector.java:434)
at com.sun.java.swing.JTabbedPane.insertTab(JTabbedPane.java:425)
at com.sun.java.swing.JTabbedPane.addTab(JTabbedPane.java:473)
This restriction seems part of design since there is a method
remove(Component) which implies the strict one to one association.
Here is code demonstrating exception and comment line to correct.
import java.awt.*;
import java.awt.event.*;
import com.sun.java.swing.*;
import com.sun.java.swing.event.*;
public class TabTest extends JPanel implements ActionListener {
public static int INITIAL_WIDTH = 400;
public static int INITIAL_HEIGHT = 200;
BorderLayout bdl = new BorderLayout();
JFrame jf = new JFrame("Tab Pane Test");
JButton jb = new JButton("Button");
JTabbedPane jtab = new JTabbedPane();
// Create the GUI
//
public TabTest() {
jb.addActionListener(this);
System.out.println("Starting...");
JCheckBox jch1 = new JCheckBox("check 1!");
JCheckBox jch2 = new JCheckBox("check 2!");
jtab.addTab("first", null,jch1);
//jtab.addTab("second", null,jch2); // this works
jtab.addTab("second", null,jch1); // same component causes exception
setLayout(bdl);
WindowListener l = new WindowAdapter() {
public void windowClosing(WindowEvent e) {System.exit(0);}
public void windowIconified(WindowEvent e) {System.exit(0);}
};
jf.addWindowListener(l);
add("North", jb);
add("Center",jtab);
jf.getContentPane().add(this);
jf.setSize(INITIAL_WIDTH, INITIAL_HEIGHT);
Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
jf.setLocation(screenSize.width/2 - INITIAL_WIDTH/2,
screenSize.height/2 - INITIAL_HEIGHT/2);
jf.show();
}
static public void main(String args[]) {
new TabTest();
}
public void actionPerformed(ActionEvent e) {
}
}
======================================================================
Suggested fix by java.net member leouser
A DESCRIPTION OF THE FIX :
BUGID 4176095 Clarification that no 2 Tabs in JTabbedPane can have the same component
FILES AFFECTED: javax.swing.JTabbedPane
JDK VERSION
jdk-6-rc-bin-b64-linux-i586-15_dec_2005.bin
Discusion(embeded in test case as well):
/**
* BUGID 4176095 Clarification that no 2 Tabs in JTabbedPane can have the same component
* This interesting rfe after being reviewed by the engineer appears to have
* turned into an investigation as to whether or not the JTabbedPane can handle
* multiple instances of the same component into the JTabbedPane. It appears
* the research never reached fruition. The enhancement I have put together
* explores the issue and it appears successfully to have done so.
* I have added 3 new methods to JTabbedPane:
* setAllowsMultiTabComponent
* getAllowsMultiTabComponent
* indexesOfComponent
* I have also enhanced a couple methods, remove(Component),insertTabAt,
* setSelectedComponent and setComponentAt.
* so they are adjusted to this new reality. remove removes all instances
* of the component. setSelectedComponent will cycle to the next index of
* the same component if the Component being selected is the current selection.
*
* These methods are what I see as the 'issues', they need to be sophisticated
* enought to work with a component being added multiple times, if configured
* to allow it.
*
* ANTI-RATIONALE:
* 1. JTabbedPane is not final, uncertain if new methods will collide with
* a subclass.
* 2. Questionable use case. Do people really want this? I can't come up
* with one at the top of my head, but it appears someone wanted it back in 98.
* Anyway, even if I can't come up with a use case the new capability is somewhat
* exciting to witness.
*
* TESTING STRATEGY:
* 1. Exercise all methods that have been changed to see if they work in the
* mult-component reality.
* 2. Exercise the new methods... they get exercised in the altered ones so
* this is already happening.
* 3. Look at the visuals, see how one of the JTabbedPane's bring up the
* same component many times... success? :)
*
* FILES AFFECTED: javax.swing.JTabbedPane
*
* JDK VERSION
* jdk-6-rc-bin-b64-linux-i586-15_dec_2005.bin
*
* test ran succesfully on a SUSE 7.3 Linux distribution
*
* Brian Harry
* ###@###.###
* Jan 25, 2006
*/
UNIFIED DIFF:
--- /home/nstuff/java6/jdk1.6.0/javax/swing/JTabbedPane.java Thu Dec 15 02:17:37 2005
+++ /home/javarefs/javax/swing/JTabbedPane.java Wed Jan 25 13:58:21 2006
@@ -452,6 +452,27 @@
}
/**
+ * Sets whether a {@code Component} instance can be added
+ * to the {@code JTabbedPane} multiple times. When allowed
+ * each addition will create a new tab.
+ *
+ * @param allows whether or not to allow a {@code Component}
+ * multiple times
+ */
+ public void setAllowsMultiTabComponent(boolean allows){
+ putClientProperty("allowsMultiTabComponents", allows);
+ }
+
+ /**
+ * Returns if a {@code Component} can be added multiple times.
+ *
+ * @return if a {@code Component} can be added multiple times
+ */
+ public boolean getAllowsMultiTabComponent(){
+ return Boolean.TRUE.equals(getClientProperty("allowsMultiTabComponents"));
+ }
+
+ /**
* Returns the currently selected index for this tabbedpane.
* Returns -1 if there is no currently selected tab.
*
@@ -561,10 +582,23 @@
* description: The tabbedpane's selected component.
*/
public void setSelectedComponent(Component c) {
- int index = indexOfComponent(c);
- if (index != -1) {
- setSelectedIndex(index);
- } else {
+ int[] indexes = indexesOfComponent(c);
+ int sindex = getSelectedIndex();
+ int ind = -1;
+ for(int i = 0; i < indexes.length; i++){
+ if(indexes[i] == sindex){
+ ind = i;
+ break;
+ }
+ }
+ if(indexes.length != 0){
+ if(ind == -1 || (ind + 1) == indexes.length)
+ setSelectedIndex(indexes[0]);
+ else{
+ setSelectedIndex(indexes[ind + 1]);
+ }
+ }
+ else {
throw new IllegalArgumentException("component not found in tabbed pane");
}
}
@@ -594,12 +628,14 @@
// but we really should throw an exception because much of the
// rest of the JTabbedPane implementation isn't designed to deal
// with null components for tabs.
- int removeIndex = indexOfComponent(component);
- if (component != null && removeIndex != -1) {
- removeTabAt(removeIndex);
- if (newIndex > removeIndex) {
- newIndex--;
- }
+ if(!getAllowsMultiTabComponent()){
+ int removeIndex = indexOfComponent(component);
+ if (component != null && removeIndex != -1) {
+ removeTabAt(removeIndex);
+ if (newIndex > removeIndex) {
+ newIndex--;
+ }
+ }
}
int selectedIndex = getSelectedIndex();
@@ -609,8 +645,10 @@
if (component != null) {
- addImpl(component, null, -1);
- component.setVisible(false);
+ if(!(component.getParent() == this) || !getAllowsMultiTabComponent()){
+ addImpl(component, null, -1);
+ component.setVisible(false);
+ }
}
if (pages.size() == 1) {
@@ -875,7 +913,10 @@
public void remove(Component component) {
int index = indexOfComponent(component);
if (index != -1) {
- removeTabAt(index);
+ while(index != -1){
+ removeTabAt(index);
+ index = indexOfComponent(component);
+ }
} else {
// Container#remove(comp) invokes Container#remove(int)
// so make sure JTabbedPane#remove(int) isn't called here
@@ -1387,13 +1428,10 @@
// REMIND(aim): this is really silly;
// why not if (page.component.getParent() == this) remove(component)
synchronized(getTreeLock()) {
- int count = getComponentCount();
- Component children[] = getComponents();
- for (int i = 0; i < count; i++) {
- if (children[i] == page.component) {
- super.remove(i);
- }
- }
+ Component c = getComponentAt(index);
+ if(c == page.component
+ && indexesOfComponent(c).length == 1)
+ super.remove(index);
}
component.setVisible(page.component.isVisible());
} else {
@@ -1402,7 +1440,8 @@
component.setVisible(false);
}
page.component = component;
- addImpl(component, null, -1);
+ if(!getAllowsMultiTabComponent() || component.getParent() != this)
+ addImpl(component, null, -1);
revalidate();
}
@@ -1548,6 +1587,29 @@
}
}
return -1;
+ }
+
+ /**
+ * Returns the indexes of the tabs for the specified component.
+ * Returns an empty array if there are no tabs for this component.
+ *
+ * @param component the component for the tabs
+ * @return the tabs which match the component, or an
+ * empty array if none are found.
+ */
+ public int[] indexesOfComponent(Component component){
+ java.util.List<Integer> indexes = new ArrayList<Integer>();
+ for(int i = 0; i < getTabCount(); i++) {
+ Component c = getComponentAt(i);
+ if ((c != null && c.equals(component)) ||
+ (c == null && c == component)) {
+ indexes.add(i);
+ }
+ }
+ int[] rv = new int[indexes.size()];
+ for(int i = 0; i < rv.length; i++)
+ rv[i] = indexes.get(i);
+ return rv;
}
/**
JUnit TESTCASE :
import javax.swing.*;
import junit.framework.TestCase;
import junit.textui.TestRunner;
import static java.lang.System.out;
/**
* BUGID 4176095 Clarification that no 2 Tabs in JTabbedPane can have the same component
* This interesting rfe after being reviewed by the engineer appears to have
* turned into an investigation as to whether or not the JTabbedPane can handle
* multiple instances of the same component into the JTabbedPane. It appears
* the research never reached fruition. The enhancement I have put together
* explores the issue and it appears successfully to have done so.
* I have added 3 new methods to JTabbedPane:
* setAllowsMultiTabComponent
* getAllowsMultiTabComponent
* indexesOfComponent
* I have also enhanced a couple methods, remove(Component),insertTabAt,
* setSelectedComponent and setComponentAt.
* so they are adjusted to this new reality. remove removes all instances
* of the component. setSelectedComponent will cycle to the next index of
* the same component if the Component being selected is the current selection.
*
* These methods are what I see as the 'issues', they need to be sophisticated
* enought to work with a component being added multiple times, if configured
* to allow it.
*
* ANTI-RATIONALE:
* 1. JTabbedPane is not final, uncertain if new methods will collide with
* a subclass.
* 2. Questionable use case. Do people really want this? I can't come up
* with one at the top of my head, but it appears someone wanted it back in 98.
* Anyway, even if I can't come up with a use case the new capability is somewhat
* exciting to witness.
*
* TESTING STRATEGY:
* 1. Exercise all methods that have been changed to see if they work in the
* mult-component reality.
* 2. Exercise the new methods... they get exercised in the altered ones so
* this is already happening.
* 3. Look at the visuals, see how one of the JTabbedPane's bring up the
* same component many times... success? :)
*
* FILES AFFECTED: javax.swing.JTabbedPane
*
* JDK VERSION
* jdk-6-rc-bin-b64-linux-i586-15_dec_2005.bin
*
* test ran succesfully on a SUSE 7.3 Linux distribution
*
* Brian Harry
* ###@###.###
* Jan 25, 2006
*/
public class JTPane4176095 extends TestCase{
public void createTab(JPanel parent, boolean multi){
JTabbedPane jtp = new JTabbedPane();
jtp.setAllowsMultiTabComponent(multi);
parent.add(jtp);
JButton zero = new JButton( "I wont show up in multi!");
JButton jb1 = new JButton("Hi1!");
JButton jb2 = new JButton("Hi2!");
jtp.addTab( "zero", zero);
jtp.addTab("first", jb1);
jtp.addTab("second", jb2);
jtp.addTab("third", jb1);
for(int i : jtp.indexesOfComponent(jb1))
out.println(i);
JTextPane jte = new JTextPane();
jte.setText( "Java is Coolll....");
for(int i = 0; i < 5; i++)
jtp.addTab(String.valueOf(i), jte);
if(multi)
jtp.setComponentAt(0, jte);
}
public void testGUI(){
JFrame jf = new JFrame();
JPanel jp = new JPanel();
JPanel multi = new JPanel();
multi.setBorder(BorderFactory.createTitledBorder(multi.getBorder(), "Multi"));
createTab(multi, true);
jp.add(multi);
JPanel single = new JPanel();
single.setBorder(BorderFactory.createTitledBorder(single.getBorder(), "Single"));
createTab(single, false);
jp.add(single);
jf.add(jp);
jf.pack();
jf.setVisible(true);
}
public void testRemove(){
JTabbedPane jtp = new JTabbedPane();
jtp.setAllowsMultiTabComponent(true);
JButton jb1 = new JButton("Hi!");
for(int i = 0; i < 5; i++)
jtp.addTab(String.valueOf(i), jb1);
assertEquals(jtp.indexesOfComponent(jb1).length, 5);
jtp.removeTabAt(0);
assertEquals(jtp.indexesOfComponent(jb1).length, 4);
jtp.remove(jb1);
assertEquals(jtp.indexesOfComponent(jb1).length,0);
}
public void testRemove2(){
JTabbedPane jtp = new JTabbedPane();
jtp.setAllowsMultiTabComponent(false);
JButton jb1 = new JButton("Hi!");
jtp.addTab( "MOO", jb1);
assertEquals(jtp.indexesOfComponent(jb1).length, 1);
jtp.removeTabAt(0);
assertEquals(jtp.indexesOfComponent(jb1).length,0);
}
public void testSelect(){
JTabbedPane jtp = new JTabbedPane();
jtp.setAllowsMultiTabComponent(true);
JButton jb1 = new JButton("Hi!");
for(int i = 0; i < 5; i++)
jtp.addTab(String.valueOf(i), jb1);
// jtp.setSelectedIndex(0);
for(int i = 0; i < 5; i++){
out.println( "i is " + i + " should be " + jtp.getSelectedIndex());
assertEquals(i, jtp.getSelectedIndex());
jtp.setSelectedComponent(jb1);
}
int[] indexes = new int[]{ 1,2,3,4,0};
jtp.setSelectedIndex(1);
for(int i: indexes){
out.println( "i is " + i + " should be " + jtp.getSelectedIndex());
assertEquals(i, jtp.getSelectedIndex());
jtp.setSelectedComponent(jb1);
}
}
public void testSelect2(){
JTabbedPane jtp = new JTabbedPane();
jtp.setAllowsMultiTabComponent(false);
JButton jb1 = new JButton("Hi!");
jtp.addTab("yeah", jb1);
for(int i = 0; i < 5; i++){
jtp.setSelectedComponent(jb1);
assertEquals(jb1, jtp.getSelectedComponent());
}
}
public static void main(String ... args){
Runnable run = new Runnable(){
public void run(){
JTPane4176095 jtp = new JTPane4176095();
jtp.testGUI();
jtp.testRemove();
jtp.testRemove2();
jtp.testSelect();
jtp.testSelect2();
}
};
SwingUtilities.invokeLater(run);
}
}
FIX FOR BUG NUMBER:
4176095
- relates to
-
JDK-4286825 Adding Same component to JTabbedPane throws ArrayIndexOutOfBoundsException
-
- Resolved
-