Source for javax.swing.JTabbedPane

   1: /* JTabbedPane.java --
   2:    Copyright (C) 2002, 2004, 2005, 2006,  Free Software Foundation, Inc.
   3: 
   4: This file is part of GNU Classpath.
   5: 
   6: GNU Classpath is free software; you can redistribute it and/or modify
   7: it under the terms of the GNU General Public License as published by
   8: the Free Software Foundation; either version 2, or (at your option)
   9: any later version.
  10: 
  11: GNU Classpath is distributed in the hope that it will be useful, but
  12: WITHOUT ANY WARRANTY; without even the implied warranty of
  13: MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  14: General Public License for more details.
  15: 
  16: You should have received a copy of the GNU General Public License
  17: along with GNU Classpath; see the file COPYING.  If not, write to the
  18: Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
  19: 02110-1301 USA.
  20: 
  21: Linking this library statically or dynamically with other modules is
  22: making a combined work based on this library.  Thus, the terms and
  23: conditions of the GNU General Public License cover the whole
  24: combination.
  25: 
  26: As a special exception, the copyright holders of this library give you
  27: permission to link this library with independent modules to produce an
  28: executable, regardless of the license terms of these independent
  29: modules, and to copy and distribute the resulting executable under
  30: terms of your choice, provided that you also meet, for each linked
  31: independent module, the terms and conditions of the license of that
  32: module.  An independent module is a module which is not derived from
  33: or based on this library.  If you modify this library, you may extend
  34: this exception to your version of the library, but you are not
  35: obligated to do so.  If you do not wish to do so, delete this
  36: exception statement from your version. */
  37: 
  38: 
  39: package javax.swing;
  40: 
  41: import java.awt.Color;
  42: import java.awt.Component;
  43: import java.awt.Point;
  44: import java.awt.Rectangle;
  45: import java.awt.event.MouseEvent;
  46: import java.io.Serializable;
  47: import java.util.Locale;
  48: import java.util.Vector;
  49: 
  50: import javax.accessibility.Accessible;
  51: import javax.accessibility.AccessibleContext;
  52: import javax.accessibility.AccessibleRole;
  53: import javax.accessibility.AccessibleSelection;
  54: import javax.accessibility.AccessibleState;
  55: import javax.accessibility.AccessibleStateSet;
  56: import javax.swing.event.ChangeEvent;
  57: import javax.swing.event.ChangeListener;
  58: import javax.swing.plaf.TabbedPaneUI;
  59: import javax.swing.plaf.UIResource;
  60: 
  61: /**
  62:  * This is a container for components where only one component is displayed at
  63:  * a given time and the displayed component can be switched by clicking on
  64:  * tabs.
  65:  * 
  66:  * <p>
  67:  * Tabs can be oriented in several ways. They can be above, below, left and
  68:  * right of the component. Tabs can either wrap around (by creating multiple
  69:  * rows of tabs) or they can be scrolled (where only a subset of the  tabs
  70:  * can be seen at once). More tabs can be added by calling the
  71:  * add/addTab/insertTab methods.
  72:  * </p>
  73:  */
  74: public class JTabbedPane extends JComponent implements Serializable,
  75:                                                        Accessible,
  76:                                                        SwingConstants
  77: {
  78:   /**
  79:    * Accessibility support for <code>JTabbedPane</code>.
  80:    */
  81:   protected class AccessibleJTabbedPane extends JComponent.AccessibleJComponent
  82:     implements AccessibleSelection, ChangeListener
  83:   {
  84:     /**
  85:      * The serialization UID.
  86:      */
  87:     private static final long serialVersionUID = 7610530885966830483L;
  88: 
  89:     /**
  90:      * Creates a new AccessibleJTabbedPane object.
  91:      */
  92:     public AccessibleJTabbedPane()
  93:     {
  94:       super();
  95:     }
  96: 
  97:     /**
  98:      * Receives notification when the selection state of the
  99:      * <code>JTabbedPane</code> changes and fires appropriate property change
 100:      * events to interested listeners.
 101:      *
 102:      * @param e the change event describing the change
 103:      */
 104:     public void stateChanged(ChangeEvent e)
 105:     {
 106:       // I couldn't figure out what else should be done here.
 107:       Object source = e.getSource();
 108:       firePropertyChange(AccessibleContext.ACCESSIBLE_SELECTION_PROPERTY,
 109:                          null, source);
 110:     }
 111: 
 112:     /**
 113:      * Returns the accessible role of the <code>JTabbedPane</code>, which is
 114:      * {@link AccessibleRole#PAGE_TAB_LIST}.
 115:      *
 116:      * @return the accessible role of the <code>JTabbedPane</code>
 117:      */
 118:     public AccessibleRole getAccessibleRole()
 119:     {
 120:       return AccessibleRole.PAGE_TAB_LIST;
 121:     }
 122: 
 123:     /**
 124:      * Returns the number of accessible child components of the
 125:      * <code>JTabbedPane</code>.
 126:      *
 127:      * @return the number of accessible child components of the
 128:      *         <code>JTabbedPane</code>
 129:      */
 130:     public int getAccessibleChildrenCount()
 131:     {
 132:       return getTabCount();
 133:     }
 134: 
 135:     /**
 136:      * Returns the accessible child component at the specified index.
 137:      *
 138:      * @param i the index of the child component to fetch
 139:      *
 140:      * @return the accessible child component at the specified index
 141:      */
 142:     public Accessible getAccessibleChild(int i)
 143:     {
 144:       // Testing shows that the reference implementation returns instances
 145:       // of page here.
 146:       Accessible child = null;
 147:       if (i >= 0 && i < tabs.size())
 148:         child = (Page) tabs.get(i);
 149:       return child;
 150:     }
 151: 
 152:     /**
 153:      * Returns the current selection state of the <code>JTabbedPane</code>
 154:      * as AccessibleSelection object.
 155:      *
 156:      * @return the current selection state of the <code>JTabbedPane</code>
 157:      */
 158:     public AccessibleSelection getAccessibleSelection()
 159:     {
 160:       return this;
 161:     }
 162: 
 163:     /**
 164:      * Returns the accessible child component at the specified coordinates.
 165:      * If there is no child component at this location, then return the
 166:      * currently selected tab.
 167:      *
 168:      * @param p the coordinates at which to look up the child component
 169:      *
 170:      * @return the accessible child component at the specified coordinates or
 171:      *         the currently selected tab if there is no child component at
 172:      *         this location
 173:      */
 174:     public Accessible getAccessibleAt(Point p)
 175:     {
 176:       int tabIndex = indexAtLocation(p.x, p.y);
 177:       if (tabIndex >= 0)
 178:         return getAccessibleChild(tabIndex);
 179:       else
 180:         return getAccessibleSelection(0);
 181:     }
 182: 
 183:     /**
 184:      * Returns the number of selected child components of the
 185:      * <code>JTabbedPane</code>. The reference implementation appears
 186:      * to return <code>1</code> always and we do the same. 
 187:      *
 188:      * @return <code>1</code>
 189:      */
 190:     public int getAccessibleSelectionCount()
 191:     {
 192:       return 1;
 193:     }
 194: 
 195:     /**
 196:      * Returns the selected tab, or <code>null</code> if there is no 
 197:      * selection.
 198:      *
 199:      * @param i  the selection index (ignored here).
 200:      *
 201:      * @return The selected tab, or <code>null</code>.
 202:      */
 203:     public Accessible getAccessibleSelection(int i)
 204:     {
 205:       Accessible result = null;
 206:       int selected = getSelectedIndex();
 207:       if (selected >= 0)
 208:         result = (Page) tabs.get(selected);
 209:       return result;
 210:     }
 211: 
 212:     /**
 213:      * Returns <code>true</code> if the specified child is selected,
 214:      * and <code>false</code> otherwise.
 215:      *
 216:      * @param i the child index.
 217:      *
 218:      * @return A boolean.
 219:      */
 220:     public boolean isAccessibleChildSelected(int i)
 221:     {
 222:       return i == getSelectedIndex();
 223:     }
 224: 
 225:     /**
 226:      * Selects the specified tab.
 227:      *
 228:      * @param i  the index of the item to select.
 229:      */
 230:     public void addAccessibleSelection(int i)
 231:     {
 232:       setSelectedIndex(i);
 233:     }
 234: 
 235:     /**
 236:      * Does nothing - it makes no sense to remove a selection for a
 237:      * tabbed pane, since one tab must always be selected.
 238:      *
 239:      * @param i  the item index.
 240:      * 
 241:      * @see #addAccessibleSelection(int)
 242:      */
 243:     public void removeAccessibleSelection(int i)
 244:     {
 245:       // do nothing
 246:     }
 247: 
 248:     /**
 249:      * Does nothing - it makes no sense to clear the selection for
 250:      * a tabbed pane, since one tab must always be selected.
 251:      * 
 252:      * @see #addAccessibleSelection(int)
 253:      */
 254:     public void clearAccessibleSelection()
 255:     {
 256:       // do nothing
 257:     }
 258: 
 259:     /**
 260:      * Does nothing - it makes no sense to select all for a tabbed
 261:      * pane, since only one tab can be selected at a time.
 262:      * 
 263:      * @see #addAccessibleSelection(int)
 264:      */
 265:     public void selectAllAccessibleSelection()
 266:     {
 267:       // do nothing
 268:     }
 269:   }
 270: 
 271:   /**
 272:    * A helper class that listens for changes to the model.
 273:    */
 274:   protected class ModelListener implements ChangeListener, Serializable
 275:   {
 276:     private static final long serialVersionUID = 497359819958114132L;
 277: 
 278:     /**
 279:      * Creates a new ModelListener object.
 280:      */
 281:     protected ModelListener()
 282:     {
 283:       // Nothing to do here.
 284:     }
 285: 
 286:     /**
 287:      * This method is called whenever the model  is changed.
 288:      *
 289:      * @param e The ChangeEvent that is passed from the model.
 290:      */
 291:     public void stateChanged(ChangeEvent e)
 292:     {
 293:       // Propagate to our listeners.
 294:       fireStateChanged();
 295:     }
 296:   }
 297: 
 298:   /**
 299:    * A private class that holds all the information  for each tab.
 300:    */
 301:   private class Page
 302:     extends AccessibleContext
 303:     implements Accessible
 304:   {
 305:     /** The tooltip string. */
 306:     private String tip;
 307: 
 308:     /** The component associated with the tab. */
 309:     private Component component;
 310: 
 311:     /** The active icon associated with the tab. */
 312:     private transient Icon icon;
 313: 
 314:     /** The disabled icon associated with the tab. */
 315:     private transient Icon disabledIcon;
 316: 
 317:     /** The tab's enabled status. */
 318:     private transient boolean enabled = true;
 319: 
 320:     /** The string painted on the tab. */
 321:     private transient String title;
 322: 
 323:     /** The background color of the tab. */
 324:     private transient Color bg;
 325: 
 326:     /** The foreground color of the tab. */
 327:     private transient Color fg;
 328: 
 329:     /** The mnemonic associated with the tab. */
 330:     private transient int mnemonicKey;
 331: 
 332:     /** The index of the underlined character in the string. */
 333:     private transient int underlinedChar = -1;
 334: 
 335:     /**
 336:      * Creates a new data storage for the tab.
 337:      *
 338:      * @param title The string displayed on the tab.
 339:      * @param icon The active icon displayed on the tab.
 340:      * @param component The component associated with the tab.
 341:      * @param tip The tooltip associated with the tab.
 342:      */
 343:     protected Page(String title, Icon icon, Component component, String tip)
 344:     {
 345:       this.title = title;
 346:       this.icon = icon;
 347:       this.component = component;
 348:       this.tip = tip;
 349:     }
 350: 
 351:     /**
 352:      * This method returns the component associated with the tab.
 353:      *
 354:      * @return The component associated with the tab.
 355:      */
 356:     public Component getComponent()
 357:     {
 358:       return component;
 359:     }
 360: 
 361:     /**
 362:      * This method sets the component associated with the tab.
 363:      *
 364:      * @param c The component associated with the tab.
 365:      */
 366:     public void setComponent(Component c)
 367:     {
 368:       int i = indexOfComponent(component);
 369:       insertTab(title, icon, c, tip, i);
 370:       component = c;
 371:       removeTabAt(i);
 372:     }
 373: 
 374:     /**
 375:      * This method returns the tooltip string.
 376:      *
 377:      * @return The tooltip string.
 378:      */
 379:     public String getTip()
 380:     {
 381:       return tip;
 382:     }
 383: 
 384:     /**
 385:      * This method sets the tooltip string.
 386:      *
 387:      * @param tip The tooltip string.
 388:      */
 389:     public void setTip(String tip)
 390:     {
 391:       this.tip = tip;
 392:     }
 393: 
 394:     /**
 395:      * This method returns the background color.
 396:      *
 397:      * @return The background color.
 398:      */
 399:     public Color getBackground()
 400:     {
 401:       Color background;
 402:       if (bg == null)
 403:         background = JTabbedPane.this.getBackground();
 404:       else
 405:         background = bg;
 406:       return background;
 407:     }
 408: 
 409:     /**
 410:      * This method sets the background color.
 411:      *
 412:      * @param background The background color.
 413:      */
 414:     public void setBackground(Color background)
 415:     {
 416:       bg = background;
 417:     }
 418: 
 419:     /**
 420:      * This method returns the foreground color.
 421:      *
 422:      * @return The foreground color.
 423:      */
 424:     public Color getForeground()
 425:     {
 426:       Color foreground;
 427:       if (fg == null)
 428:         foreground = JTabbedPane.this.getForeground();
 429:       else
 430:         foreground = fg;
 431:       return foreground;
 432:     }
 433: 
 434:     /**
 435:      * This method sets the foreground color.
 436:      *
 437:      * @param foreground The foreground color.
 438:      */
 439:     public void setForeground(Color foreground)
 440:     {
 441:       fg = foreground;
 442:     }
 443: 
 444:     /**
 445:      * This method returns the title associated with the tab.
 446:      *
 447:      * @return The title of the tab.
 448:      */
 449:     public String getTitle()
 450:     {
 451:       return title;
 452:     }
 453: 
 454:     private static final long serialVersionUID = 1614381073220130939L;
 455: 
 456:     /**
 457:      * This method sets the title of the tab.
 458:      *
 459:      * @param text The title of the tab.
 460:      */
 461:     public void setTitle(String text)
 462:     {
 463:       title = text;
 464:       if (title != null && title.length() <= underlinedChar)
 465:     setDisplayedMnemonicIndex(title.length() - 1);
 466:     }
 467: 
 468:     /**
 469:      * This method returns the active icon.
 470:      *
 471:      * @return The active icon.
 472:      */
 473:     public Icon getIcon()
 474:     {
 475:       return icon;
 476:     }
 477: 
 478:     /**
 479:      * This method sets the active icon.
 480:      *
 481:      * @param icon The active icon.
 482:      */
 483:     public void setIcon(Icon icon)
 484:     {
 485:       this.icon = icon;
 486:     }
 487: 
 488:     /**
 489:      * This method returns the disabled icon.
 490:      *
 491:      * @return The disabled icon.
 492:      */
 493:     public Icon getDisabledIcon()
 494:     {
 495:       if (disabledIcon == null && icon instanceof ImageIcon)
 496:     setDisabledIcon(icon);
 497:       return disabledIcon;
 498:     }
 499: 
 500:     /**
 501:      * This method sets the disabled icon.
 502:      *
 503:      * @param disabledIcon The disabled icon.
 504:      */
 505:     public void setDisabledIcon(Icon disabledIcon)
 506:     {
 507:       this.disabledIcon = disabledIcon;
 508:     }
 509: 
 510:     /**
 511:      * This method returns whether the tab is enabled.
 512:      *
 513:      * @return Whether the tab is enabled.
 514:      */
 515:     public boolean isEnabled()
 516:     {
 517:       return enabled;
 518:     }
 519: 
 520:     /**
 521:      * This method sets whether the tab is enabled.
 522:      *
 523:      * @param enabled Whether this tab is enabled.
 524:      */
 525:     public void setEnabled(boolean enabled)
 526:     {
 527:       this.enabled = enabled;
 528:     }
 529: 
 530:     /**
 531:      * This method returns the mnemonic.
 532:      *
 533:      * @return The mnemonic.
 534:      */
 535:     public int getMnemonic()
 536:     {
 537:       return mnemonicKey;
 538:     }
 539: 
 540:     /**
 541:      * This method sets the mnemonic. If the title is set, it will update the
 542:      * mnemonicIndex.
 543:      *
 544:      * @param key The mnemonic.
 545:      */
 546:     public void setMnemonic(int key)
 547:     {
 548:       setMnemonic((char) key);
 549:     }
 550: 
 551:     /**
 552:      * This method sets the mnemonic. If the title is set, it will update the
 553:      * mnemonicIndex.
 554:      *
 555:      * @param aChar The mnemonic.
 556:      */
 557:     public void setMnemonic(char aChar)
 558:     {
 559:       mnemonicKey = aChar;
 560:       if (title != null)
 561:     setDisplayedMnemonicIndex(title.indexOf(mnemonicKey));
 562:     }
 563: 
 564:     /**
 565:      * This method returns the mnemonicIndex.
 566:      *
 567:      * @return The mnemonicIndex.
 568:      */
 569:     public int getDisplayedMnemonicIndex()
 570:     {
 571:       return underlinedChar;
 572:     }
 573: 
 574:     /**
 575:      * This method sets the mnemonicIndex.
 576:      *
 577:      * @param index The mnemonicIndex.
 578:      *
 579:      * @throws IllegalArgumentException If index less than -1 || index greater
 580:      *         or equal to title.length.
 581:      */
 582:     public void setDisplayedMnemonicIndex(int index)
 583:       throws IllegalArgumentException
 584:     {
 585:       if (index < -1 || title != null && index >= title.length())
 586:     throw new IllegalArgumentException();
 587: 
 588:       if (title == null || mnemonicKey == 0 || (index > -1 && title.charAt(index) != mnemonicKey))
 589:     index = -1;
 590: 
 591:       underlinedChar = index;
 592:     }
 593: 
 594:     /**
 595:      * Returns the accessible context, which is this object itself.
 596:      *
 597:      * @return the accessible context, which is this object itself
 598:      */
 599:     public AccessibleContext getAccessibleContext()
 600:     {
 601:       return this;
 602:     }
 603: 
 604:     /**
 605:      * Returns the accessible name for this tab.
 606:      * 
 607:      * @return The accessible name.
 608:      */
 609:     public String getAccessibleName()
 610:     {
 611:       if (accessibleName != null)
 612:         return accessibleName;
 613:       else
 614:         return title;
 615:     }
 616:     
 617:     /**
 618:      * Returns the accessible role of this tab, which is always
 619:      * {@link AccessibleRole#PAGE_TAB}.
 620:      *
 621:      * @return the accessible role of this tab
 622:      */
 623:     public AccessibleRole getAccessibleRole()
 624:     {
 625:       return AccessibleRole.PAGE_TAB;
 626:     }
 627: 
 628:     /**
 629:      * Returns the accessible state set of this object.
 630:      *
 631:      * @return the accessible state set of this object
 632:      */
 633:     public AccessibleStateSet getAccessibleStateSet()
 634:     {
 635:       AccessibleContext parentCtx = JTabbedPane.this.getAccessibleContext(); 
 636:       AccessibleStateSet state = parentCtx.getAccessibleStateSet();
 637:       state.add(AccessibleState.SELECTABLE);
 638:       if (component == getSelectedComponent())
 639:         state.add(AccessibleState.SELECTED);
 640:       return state;
 641:     }
 642: 
 643:     /**
 644:      * Returns the index of this tab inside its parent.
 645:      *
 646:      * @return the index of this tab inside its parent
 647:      */
 648:     public int getAccessibleIndexInParent()
 649:     {
 650:       // TODO: Not sure if the title is unambiguous, but I can't figure
 651:       // another way of doing this.
 652:       return indexOfTab(title);
 653:     }
 654: 
 655:     /**
 656:      * Returns the number of accessible children, which is always one (the
 657:      * component of this tab).
 658:      *
 659:      * @return the number of accessible children
 660:      */
 661:     public int getAccessibleChildrenCount()
 662:     {
 663:       return 1;
 664:     }
 665: 
 666:     /**
 667:      * Returns the accessible child of this tab, which is the component
 668:      * displayed by the tab.
 669:      *
 670:      * @return the accessible child of this tab
 671:      */
 672:     public Accessible getAccessibleChild(int i)
 673:     {
 674:       // A quick test shows that this method always returns the component
 675:       // displayed by the tab, regardless of the index.
 676:       return (Accessible) component;
 677:     }
 678: 
 679:     /**
 680:      * Returns the locale of this accessible object.
 681:      *
 682:      * @return the locale of this accessible object
 683:      */
 684:     public Locale getLocale()
 685:     {
 686:       // TODO: Is this ok?
 687:       return Locale.getDefault();
 688:     }
 689:   }
 690: 
 691:   private static final long serialVersionUID = 1614381073220130939L;
 692: 
 693:   /** The changeEvent used to fire changes to listeners. */
 694:   protected ChangeEvent changeEvent;
 695: 
 696:   /** The listener that listens to the model. */
 697:   protected ChangeListener changeListener;
 698: 
 699:   /** The model that describes this JTabbedPane. */
 700:   protected SingleSelectionModel model;
 701: 
 702:   /** Indicates that the TabbedPane is in scrolling mode. */
 703:   public static final int SCROLL_TAB_LAYOUT = 1;
 704: 
 705:   /** Indicates that the TabbedPane is in wrap mode. */
 706:   public static final int WRAP_TAB_LAYOUT = 0;
 707: 
 708:   /** The current tabPlacement of the TabbedPane. */
 709:   protected int tabPlacement = SwingConstants.TOP;
 710: 
 711:   /** The current tabLayoutPolicy of the TabbedPane. */
 712:   private transient int layoutPolicy;
 713: 
 714:   /** The list of tabs associated with the TabbedPane. */
 715:   transient Vector tabs = new Vector();
 716: 
 717:   /**
 718:    * Creates a new JTabbedPane object with tabs on top and using wrap tab
 719:    * layout.
 720:    */
 721:   public JTabbedPane()
 722:   {
 723:     this(SwingConstants.TOP, WRAP_TAB_LAYOUT);
 724:   }
 725: 
 726:   /**
 727:    * Creates a new JTabbedPane object using wrap tab layout  and the given
 728:    * <code>tabPlacement</code>, where <code>tabPlacement</code> can be one
 729:    * of the following values: {@link #TOP}, {@link #BOTTOM}, {@link #LEFT} or
 730:    * {@link #RIGHT}.
 731:    *
 732:    * @param tabPlacement where the tabs will be placed
 733:    */
 734:   public JTabbedPane(int tabPlacement)
 735:   {
 736:     this(tabPlacement, WRAP_TAB_LAYOUT);
 737:   }
 738: 
 739:   /**
 740:    * Creates a new JTabbedPane object with the given <code>tabPlacement</code>
 741:    * and <code>tabLayoutPolicy</code>. The <code>tabPlacement</code> can be one
 742:    * of the following values: {@link #TOP}, {@link #BOTTOM}, {@link #LEFT} or
 743:    * {@link #RIGHT}. The <code>tabLayoutPolicy</code> can be either
 744:    * {@link #SCROLL_TAB_LAYOUT} or {@link #WRAP_TAB_LAYOUT}.
 745:    *
 746:    * @param tabPlacement where the tabs will be placed
 747:    * @param tabLayoutPolicy the way tabs will be placed
 748:    *
 749:    * @throws IllegalArgumentException If tabLayoutPolicy or tabPlacement are
 750:    *         not valid.
 751:    */
 752:   public JTabbedPane(int tabPlacement, int tabLayoutPolicy)
 753:   {
 754:     if (tabPlacement != TOP && tabPlacement != BOTTOM && tabPlacement != RIGHT
 755:         && tabPlacement != LEFT)
 756:       throw new IllegalArgumentException("tabPlacement is not valid.");
 757:     if (tabLayoutPolicy != SCROLL_TAB_LAYOUT
 758:         && tabLayoutPolicy != WRAP_TAB_LAYOUT)
 759:       throw new IllegalArgumentException("tabLayoutPolicy is not valid.");
 760:     this.tabPlacement = tabPlacement;
 761:     layoutPolicy = tabLayoutPolicy;
 762:     
 763:     setModel(new DefaultSingleSelectionModel());
 764: 
 765:     updateUI();
 766:   }
 767: 
 768:   /**
 769:    * This method returns the UI used to display the JTabbedPane.
 770:    *
 771:    * @return The UI used to display the JTabbedPane.
 772:    */
 773:   public TabbedPaneUI getUI()
 774:   {
 775:     return (TabbedPaneUI) ui;
 776:   }
 777: 
 778:   /**
 779:    * This method sets the UI used to display the JTabbedPane.
 780:    *
 781:    * @param ui The UI used to display the JTabbedPane.
 782:    */
 783:   public void setUI(TabbedPaneUI ui)
 784:   {
 785:     super.setUI(ui);
 786:   }
 787: 
 788:   /**
 789:    * This method restores the UI to the defaults given by the UIManager.
 790:    */
 791:   public void updateUI()
 792:   {
 793:     setUI((TabbedPaneUI) UIManager.getUI(this));
 794:   }
 795: 
 796:   /**
 797:    * This method returns a string identifier that  is used to determine which
 798:    * UI will be used with  the JTabbedPane.
 799:    *
 800:    * @return A string identifier for the UI.
 801:    */
 802:   public String getUIClassID()
 803:   {
 804:     return "TabbedPaneUI";
 805:   }
 806: 
 807:   /**
 808:    * This method creates a ChangeListener that is used to  listen to the model
 809:    * for events.
 810:    *
 811:    * @return A ChangeListener to listen to the model.
 812:    */
 813:   protected ChangeListener createChangeListener()
 814:   {
 815:     return new ModelListener();
 816:   }
 817: 
 818:   /**
 819:    * This method adds a ChangeListener to the JTabbedPane.
 820:    *
 821:    * @param l The ChangeListener to add.
 822:    */
 823:   public void addChangeListener(ChangeListener l)
 824:   {
 825:     listenerList.add(ChangeListener.class, l);
 826:   }
 827: 
 828:   /**
 829:    * This method removes a ChangeListener to the JTabbedPane.
 830:    *
 831:    * @param l The ChangeListener to remove.
 832:    */
 833:   public void removeChangeListener(ChangeListener l)
 834:   {
 835:     listenerList.remove(ChangeListener.class, l);
 836:   }
 837: 
 838:   /**
 839:    * This method fires a ChangeEvent to all the JTabbedPane's ChangeListeners.
 840:    */
 841:   protected void fireStateChanged()
 842:   {
 843:     Object[] changeListeners = listenerList.getListenerList();
 844:     if (changeEvent == null)
 845:       changeEvent = new ChangeEvent(this);
 846:     for (int i = changeListeners.length - 2; i >= 0; i -= 2)
 847:       {
 848:     if (changeListeners[i] == ChangeListener.class)
 849:       ((ChangeListener) changeListeners[i + 1]).stateChanged(changeEvent);
 850:       }
 851:   }
 852: 
 853:   /**
 854:    * This method returns all ChangeListeners registered with the JTabbedPane.
 855:    *
 856:    * @return The ChangeListeners registered with the JTabbedPane.
 857:    */
 858:   public ChangeListener[] getChangeListeners()
 859:   {
 860:     return (ChangeListener[]) super.getListeners(ChangeListener.class);
 861:   }
 862: 
 863:   /**
 864:    * This method returns the model used with the JTabbedPane.
 865:    *
 866:    * @return The JTabbedPane's model.
 867:    */
 868:   public SingleSelectionModel getModel()
 869:   {
 870:     return model;
 871:   }
 872: 
 873:   /**
 874:    * This method changes the model property of the JTabbedPane.
 875:    *
 876:    * @param m The new model to use with the JTabbedPane.
 877:    */
 878:   public void setModel(SingleSelectionModel m)
 879:   {
 880:     if (m != model)
 881:       {
 882:     SingleSelectionModel oldModel = this.model;
 883:         if (oldModel != null && changeListener != null)
 884:           oldModel.removeChangeListener(changeListener);
 885: 
 886:     model = m;
 887: 
 888:         if (model != null)
 889:           {
 890:             if (changeListener == null)
 891:               changeListener = createChangeListener();
 892:             model.addChangeListener(changeListener);
 893:           }
 894:     firePropertyChange("model", oldModel, this.model);
 895:       }
 896:   }
 897: 
 898:   /**
 899:    * This method returns the tabPlacement.
 900:    *
 901:    * @return The tabPlacement used with the JTabbedPane.
 902:    */
 903:   public int getTabPlacement()
 904:   {
 905:     return tabPlacement;
 906:   }
 907: 
 908:   /**
 909:    * This method changes the tabPlacement property of the JTabbedPane.
 910:    *
 911:    * @param tabPlacement The tabPlacement to use.
 912:    *
 913:    * @throws IllegalArgumentException If tabPlacement is not one of TOP,
 914:    *         BOTTOM, LEFT, or RIGHT.
 915:    */
 916:   public void setTabPlacement(int tabPlacement)
 917:   {
 918:     if (tabPlacement != TOP && tabPlacement != BOTTOM && tabPlacement != RIGHT
 919:         && tabPlacement != LEFT)
 920:       throw new IllegalArgumentException("tabPlacement is not valid.");
 921:     if (tabPlacement != this.tabPlacement)
 922:       {
 923:     int oldPlacement = this.tabPlacement;
 924:     this.tabPlacement = tabPlacement;
 925:     firePropertyChange("tabPlacement", oldPlacement, this.tabPlacement);
 926:       }
 927:   }
 928: 
 929:   /**
 930:    * This method returns the tabLayoutPolicy.
 931:    *
 932:    * @return The tabLayoutPolicy.
 933:    */
 934:   public int getTabLayoutPolicy()
 935:   {
 936:     return layoutPolicy;
 937:   }
 938: 
 939:   /**
 940:    * This method changes the tabLayoutPolicy property of the JTabbedPane.
 941:    *
 942:    * @param tabLayoutPolicy The tabLayoutPolicy to use.
 943:    *
 944:    * @throws IllegalArgumentException If tabLayoutPolicy is not one of
 945:    *         SCROLL_TAB_LAYOUT or WRAP_TAB_LAYOUT.
 946:    */
 947:   public void setTabLayoutPolicy(int tabLayoutPolicy)
 948:   {
 949:     if (tabLayoutPolicy != SCROLL_TAB_LAYOUT
 950:         && tabLayoutPolicy != WRAP_TAB_LAYOUT)
 951:       throw new IllegalArgumentException("tabLayoutPolicy is not valid.");
 952:     if (tabLayoutPolicy != layoutPolicy)
 953:       {
 954:     int oldPolicy = layoutPolicy;
 955:     layoutPolicy = tabLayoutPolicy;
 956:     firePropertyChange("tabLayoutPolicy", oldPolicy, layoutPolicy);
 957:       }
 958:   }
 959: 
 960:   /**
 961:    * This method returns the index of the tab that is currently selected.
 962:    *
 963:    * @return The index of the selected tab.
 964:    */
 965:   public int getSelectedIndex()
 966:   {
 967:     return model.getSelectedIndex();
 968:   }
 969: 
 970:   /**
 971:    * This method checks the index.