Uploaded image for project: 'JDK'
  1. JDK
  2. JDK-6439518

JTabbedPane and value properties in "tabComponentAt" PropertyChangeEvent

XMLWordPrintable

      A DESCRIPTION OF THE FIX :
      JTabbedPane new functionality misuses value properties in "tabComponentAt" PropertyChangeEvent

      Mustang allows components to be set within tabs. However, setTabComponentAt fires an incorrect PropertyChangeEvent. The newValue and oldValue properties of the property change event are of type Integer, which is not the type of the property. These should be removed from the event, and the associated code in BaseTabbedPaneUI corrected.

      JTabbedPane talks a lot about the lack of IndexedPropertyEvents. IndexedPropertyEvent was added in 1.5, but isn't used by AWT/Swing (other than an incorrect reference in SwingWorker) and doesn't seem particularly useful. A better long-term approach would be to use a ListModel (or a ListModel-like model) to represent the tabs, using an element type similar to JTabbedPane.Page.

      Diffs of j2se/src/share/classes/javax/swing/JTabbedPane.java and j2se/src/share/classes/javax/swing/plaf/basic/BasicTabbedPaneUI.java are against 1.6.0-rc-b87.

      --- /home/tackline/mustang/current/j2se/src/share/classes/javax/swing/JTabbedPane.java 2006-06-11 14:20:06.000000000 +0100
      +++ java/javax/swing/JTabbedPane.java 2006-06-14 23:36:02.000000000 +0100
      @@ -2344,7 +2344,7 @@
                       setTabComponentAt(tabComponentIndex, null);
                   }
                   ((Page) pages.elementAt(index)).tabComponent = component;
      - firePropertyChange("tabComponentAt", -1, index);
      + firePropertyChange("tabComponentAt", null, null);
               }
           }



      --- /home/tackline/mustang/current/j2se/src/share/classes/javax/swing/plaf/basic/BasicTabbedPaneUI.java 2006-06-11 14:20:15.000000000 +0100
      +++ java/javax/swing/plaf/basic/BasicTabbedPaneUI.java 2006-06-14 21:24:42.000000000 +0100
      @@ -259,27 +259,46 @@
                       tabPane.add(tabScroller.viewport);
                   }
               }
      - installTabContainer();
      + if (tabContainer == null) {
      + // updateTabContainer will install tabContainer if it is created.
      + updateTabContainer();
      + } else {
      + // Already had tabContainer - it will need to be installed.
      + updateTabContainer();
      + installTabContainer();
      + }
      + }
      +
      + private void updateTabContainer() {
      + if (tabContainer != null) {
      + tabContainer.removeUnusedTabComponents();
      + }
      +
      + // Add any new tab components.
      + int tabCount = tabPane.getTabCount();
      + for (int index=0; index<tabCount; ++index) {
      + Component c = tabPane.getTabComponentAt(index);
      + if (c != null) {
      + if (tabContainer == null) {
      + tabContainer = new TabContainer();
      + installTabContainer();
      + }
      + if (c.getParent() != tabContainer) {
      + tabContainer.add(c);
      + }
      + }
      + }
           }

           private void installTabContainer() {
      - for (int i = 0; i < tabPane.getTabCount(); i++) {
      - Component tabComponent = tabPane.getTabComponentAt(i);
      - if (tabComponent != null) {
      - if(tabContainer == null) {
      - tabContainer = new TabContainer();
      - }
      - tabContainer.add(tabComponent);
      - }
      - }
      - if(tabContainer == null) {
      - return;
      - }
      - if (scrollableTabLayoutEnabled()) {
      - tabScroller.tabPanel.add(tabContainer);
      - } else {
      - tabPane.add(tabContainer);
      - }
      + if (tabContainer == null) {
      + return;
      + }
      + if (scrollableTabLayoutEnabled()) {
      + tabScroller.tabPanel.add(tabContainer);
      + } else {
      + tabPane.add(tabContainer);
      + }
           }

           /**
      @@ -3528,18 +3547,7 @@
                       tabScroller.scrollForwardButton.setBackground(newColor);
                       tabScroller.scrollBackwardButton.setBackground(newColor);
                   } else if (name == "tabComponentAt") {
      - if (tabContainer != null) {
      - tabContainer.removeUnusedTabComponents();
      - }
      - Component c = tabPane.getTabComponentAt(
      - (Integer)e.getNewValue());
      - if (c != null) {
      - if (tabContainer == null) {
      - installTabContainer();
      - } else {
      - tabContainer.add(c);
      - }
      - }
      + updateTabContainer();
                       tabPane.revalidate();
                       tabPane.repaint();
                       calculatedBaseline = false;


      JUnit TESTCASE :
      public class TabComponentAtTest extends junit.framework.TestCase {
          public static void main(String[] args) {
              junit.textui.TestRunner.run(TabComponentAtTest.class);
          }
          public void testNewValueType() throws Exception {
              class Listener implements java.beans.PropertyChangeListener {
                  Class<?> oldType = void.class;
                  Class<?> newType = void.class;
                  public void propertyChange(java.beans.PropertyChangeEvent event) {
                      if (event.getPropertyName() == "tabComponentAt") {
                          oldType = getClassOf(event.getOldValue());
                          newType = getClassOf(event.getNewValue());
                      }
                  }
              }
              final Listener listener = new Listener();
              java.awt.EventQueue.invokeAndWait(new Runnable() { public void run() {
                          javax.swing.JTabbedPane tabbedPane =
                              new javax.swing.JTabbedPane();
                          tabbedPane.addTab("Tab", new javax.swing.JLabel("Content"));
                          tabbedPane.addPropertyChangeListener(listener);
                          tabbedPane.setTabComponentAt(
                              0, new javax.swing.JLabel("Tab component")
                          );
              }});
              localAssertNotSame(
                  "oldValue.getClass()", Integer.class, listener.oldType
              );
              localAssertNotSame(
                  "newValue.getClass()", Integer.class, listener.newType
              );
          }
          private static void localAssertNotSame(
              String message, Object notExpected, Object actual
          ) {
              // JUnit 4.0/4.1 bug... Assert.assertNotSame gives bogus message.
              if (notExpected != actual) {
                  // Good..
                  return;
              }
              fail(message+", did not expect same as <"+notExpected+">");
          }
          /**
           * Returns class of {@code obj},
           * or {@code null} if {@code obj} is {@code null}.
           */
          private static Class<?> getClassOf(Object obj) {
              return obj==null ? null : obj.getClass();
          }
      }

            Unassigned Unassigned
            tbell Tim Bell
            Votes:
            0 Vote for this issue
            Watchers:
            0 Start watching this issue

              Created:
              Updated:
              Resolved:
              Imported:
              Indexed: