001    /* JTabbedPane.java --
002       Copyright (C) 2002, 2004, 2005, 2006,  Free Software Foundation, Inc.
003    
004    This file is part of GNU Classpath.
005    
006    GNU Classpath is free software; you can redistribute it and/or modify
007    it under the terms of the GNU General Public License as published by
008    the Free Software Foundation; either version 2, or (at your option)
009    any later version.
010    
011    GNU Classpath is distributed in the hope that it will be useful, but
012    WITHOUT ANY WARRANTY; without even the implied warranty of
013    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
014    General Public License for more details.
015    
016    You should have received a copy of the GNU General Public License
017    along with GNU Classpath; see the file COPYING.  If not, write to the
018    Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
019    02110-1301 USA.
020    
021    Linking this library statically or dynamically with other modules is
022    making a combined work based on this library.  Thus, the terms and
023    conditions of the GNU General Public License cover the whole
024    combination.
025    
026    As a special exception, the copyright holders of this library give you
027    permission to link this library with independent modules to produce an
028    executable, regardless of the license terms of these independent
029    modules, and to copy and distribute the resulting executable under
030    terms of your choice, provided that you also meet, for each linked
031    independent module, the terms and conditions of the license of that
032    module.  An independent module is a module which is not derived from
033    or based on this library.  If you modify this library, you may extend
034    this exception to your version of the library, but you are not
035    obligated to do so.  If you do not wish to do so, delete this
036    exception statement from your version. */
037    
038    
039    package javax.swing;
040    
041    import gnu.java.lang.CPStringBuilder;
042    
043    import java.awt.Color;
044    import java.awt.Component;
045    import java.awt.Point;
046    import java.awt.Rectangle;
047    import java.awt.event.MouseEvent;
048    import java.io.Serializable;
049    import java.util.Locale;
050    import java.util.Vector;
051    
052    import javax.accessibility.Accessible;
053    import javax.accessibility.AccessibleContext;
054    import javax.accessibility.AccessibleRole;
055    import javax.accessibility.AccessibleSelection;
056    import javax.accessibility.AccessibleState;
057    import javax.accessibility.AccessibleStateSet;
058    import javax.swing.event.ChangeEvent;
059    import javax.swing.event.ChangeListener;
060    import javax.swing.plaf.TabbedPaneUI;
061    import javax.swing.plaf.UIResource;
062    
063    /**
064     * This is a container for components where only one component is displayed at
065     * a given time and the displayed component can be switched by clicking on
066     * tabs.
067     *
068     * <p>
069     * Tabs can be oriented in several ways. They can be above, below, left and
070     * right of the component. Tabs can either wrap around (by creating multiple
071     * rows of tabs) or they can be scrolled (where only a subset of the  tabs
072     * can be seen at once). More tabs can be added by calling the
073     * add/addTab/insertTab methods.
074     * </p>
075     */
076    public class JTabbedPane extends JComponent implements Serializable,
077                                                           Accessible,
078                                                           SwingConstants
079    {
080      /**
081       * Accessibility support for <code>JTabbedPane</code>.
082       */
083      protected class AccessibleJTabbedPane extends JComponent.AccessibleJComponent
084        implements AccessibleSelection, ChangeListener
085      {
086        /**
087         * The serialization UID.
088         */
089        private static final long serialVersionUID = 7610530885966830483L;
090    
091        /**
092         * Creates a new AccessibleJTabbedPane object.
093         */
094        public AccessibleJTabbedPane()
095        {
096          super();
097        }
098    
099        /**
100         * Receives notification when the selection state of the
101         * <code>JTabbedPane</code> changes and fires appropriate property change
102         * events to interested listeners.
103         *
104         * @param e the change event describing the change
105         */
106        public void stateChanged(ChangeEvent e)
107        {
108          // I couldn't figure out what else should be done here.
109          Object source = e.getSource();
110          firePropertyChange(AccessibleContext.ACCESSIBLE_SELECTION_PROPERTY,
111                             null, source);
112        }
113    
114        /**
115         * Returns the accessible role of the <code>JTabbedPane</code>, which is
116         * {@link AccessibleRole#PAGE_TAB_LIST}.
117         *
118         * @return the accessible role of the <code>JTabbedPane</code>
119         */
120        public AccessibleRole getAccessibleRole()
121        {
122          return AccessibleRole.PAGE_TAB_LIST;
123        }
124    
125        /**
126         * Returns the number of accessible child components of the
127         * <code>JTabbedPane</code>.
128         *
129         * @return the number of accessible child components of the
130         *         <code>JTabbedPane</code>
131         */
132        public int getAccessibleChildrenCount()
133        {
134          return getTabCount();
135        }
136    
137        /**
138         * Returns the accessible child component at the specified index.
139         *
140         * @param i the index of the child component to fetch
141         *
142         * @return the accessible child component at the specified index
143         */
144        public Accessible getAccessibleChild(int i)
145        {
146          // Testing shows that the reference implementation returns instances
147          // of page here.
148          Accessible child = null;
149          if (i >= 0 && i < tabs.size())
150            child = (Page) tabs.get(i);
151          return child;
152        }
153    
154        /**
155         * Returns the current selection state of the <code>JTabbedPane</code>
156         * as AccessibleSelection object.
157         *
158         * @return the current selection state of the <code>JTabbedPane</code>
159         */
160        public AccessibleSelection getAccessibleSelection()
161        {
162          return this;
163        }
164    
165        /**
166         * Returns the accessible child component at the specified coordinates.
167         * If there is no child component at this location, then return the
168         * currently selected tab.
169         *
170         * @param p the coordinates at which to look up the child component
171         *
172         * @return the accessible child component at the specified coordinates or
173         *         the currently selected tab if there is no child component at
174         *         this location
175         */
176        public Accessible getAccessibleAt(Point p)
177        {
178          int tabIndex = indexAtLocation(p.x, p.y);
179          if (tabIndex >= 0)
180            return getAccessibleChild(tabIndex);
181          else
182            return getAccessibleSelection(0);
183        }
184    
185        /**
186         * Returns the number of selected child components of the
187         * <code>JTabbedPane</code>. The reference implementation appears
188         * to return <code>1</code> always and we do the same.
189         *
190         * @return <code>1</code>
191         */
192        public int getAccessibleSelectionCount()
193        {
194          return 1;
195        }
196    
197        /**
198         * Returns the selected tab, or <code>null</code> if there is no
199         * selection.
200         *
201         * @param i  the selection index (ignored here).
202         *
203         * @return The selected tab, or <code>null</code>.
204         */
205        public Accessible getAccessibleSelection(int i)
206        {
207          Accessible result = null;
208          int selected = getSelectedIndex();
209          if (selected >= 0)
210            result = (Page) tabs.get(selected);
211          return result;
212        }
213    
214        /**
215         * Returns <code>true</code> if the specified child is selected,
216         * and <code>false</code> otherwise.
217         *
218         * @param i the child index.
219         *
220         * @return A boolean.
221         */
222        public boolean isAccessibleChildSelected(int i)
223        {
224          return i == getSelectedIndex();
225        }
226    
227        /**
228         * Selects the specified tab.
229         *
230         * @param i  the index of the item to select.
231         */
232        public void addAccessibleSelection(int i)
233        {
234          setSelectedIndex(i);
235        }
236    
237        /**
238         * Does nothing - it makes no sense to remove a selection for a
239         * tabbed pane, since one tab must always be selected.
240         *
241         * @param i  the item index.
242         *
243         * @see #addAccessibleSelection(int)
244         */
245        public void removeAccessibleSelection(int i)
246        {
247          // do nothing
248        }
249    
250        /**
251         * Does nothing - it makes no sense to clear the selection for
252         * a tabbed pane, since one tab must always be selected.
253         *
254         * @see #addAccessibleSelection(int)
255         */
256        public void clearAccessibleSelection()
257        {
258          // do nothing
259        }
260    
261        /**
262         * Does nothing - it makes no sense to select all for a tabbed
263         * pane, since only one tab can be selected at a time.
264         *
265         * @see #addAccessibleSelection(int)
266         */
267        public void selectAllAccessibleSelection()
268        {
269          // do nothing
270        }
271      }
272    
273      /**
274       * A helper class that listens for changes to the model.
275       */
276      protected class ModelListener implements ChangeListener, Serializable
277      {
278        private static final long serialVersionUID = 497359819958114132L;
279    
280        /**
281         * Creates a new ModelListener object.
282         */
283        protected ModelListener()
284        {
285          // Nothing to do here.
286        }
287    
288        /**
289         * This method is called whenever the model  is changed.
290         *
291         * @param e The ChangeEvent that is passed from the model.
292         */
293        public void stateChanged(ChangeEvent e)
294        {
295          // Propagate to our listeners.
296          fireStateChanged();
297        }
298      }
299    
300      /**
301       * A private class that holds all the information  for each tab.
302       */
303      private class Page
304        extends AccessibleContext
305        implements Accessible
306      {
307        /** The tooltip string. */
308        private String tip;
309    
310        /** The component associated with the tab. */
311        private Component component;
312    
313        /** The active icon associated with the tab. */
314        private transient Icon icon;
315    
316        /** The disabled icon associated with the tab. */
317        private transient Icon disabledIcon;
318    
319        /** The tab's enabled status. */
320        private transient boolean enabled = true;
321    
322        /** The string painted on the tab. */
323        private transient String title;
324    
325        /** The background color of the tab. */
326        private transient Color bg;
327    
328        /** The foreground color of the tab. */
329        private transient Color fg;
330    
331        /** The mnemonic associated with the tab. */
332        private transient int mnemonicKey;
333    
334        /** The index of the underlined character in the string. */
335        private transient int underlinedChar = -1;
336    
337        /**
338         * Creates a new data storage for the tab.
339         *
340         * @param title The string displayed on the tab.
341         * @param icon The active icon displayed on the tab.
342         * @param component The component associated with the tab.
343         * @param tip The tooltip associated with the tab.
344         */
345        protected Page(String title, Icon icon, Component component, String tip)
346        {
347          this.title = title;
348          this.icon = icon;
349          this.component = component;
350          this.tip = tip;
351        }
352    
353        /**
354         * This method returns the component associated with the tab.
355         *
356         * @return The component associated with the tab.
357         */
358        public Component getComponent()
359        {
360          return component;
361        }
362    
363        /**
364         * This method sets the component associated with the tab.
365         *
366         * @param c The component associated with the tab.
367         */
368        public void setComponent(Component c)
369        {
370          int i = indexOfComponent(component);
371          insertTab(title, icon, c, tip, i);
372          component = c;
373          removeTabAt(i);
374        }
375    
376        /**
377         * This method returns the tooltip string.
378         *
379         * @return The tooltip string.
380         */
381        public String getTip()
382        {
383          return tip;
384        }
385    
386        /**
387         * This method sets the tooltip string.
388         *
389         * @param tip The tooltip string.
390         */
391        public void setTip(String tip)
392        {
393          this.tip = tip;
394        }
395    
396        /**
397         * This method returns the background color.
398         *
399         * @return The background color.
400         */
401        public Color getBackground()
402        {
403          Color background;
404          if (bg == null)
405            background = JTabbedPane.this.getBackground();
406          else
407            background = bg;
408          return background;
409        }
410    
411        /**
412         * This method sets the background color.
413         *
414         * @param background The background color.
415         */
416        public void setBackground(Color background)
417        {
418          bg = background;
419        }
420    
421        /**
422         * This method returns the foreground color.
423         *
424         * @return The foreground color.
425         */
426        public Color getForeground()
427        {
428          Color foreground;
429          if (fg == null)
430            foreground = JTabbedPane.this.getForeground();
431          else
432            foreground = fg;
433          return foreground;
434        }
435    
436        /**
437         * This method sets the foreground color.
438         *
439         * @param foreground The foreground color.
440         */
441        public void setForeground(Color foreground)
442        {
443          fg = foreground;
444        }
445    
446        /**
447         * This method returns the title associated with the tab.
448         *
449         * @return The title of the tab.
450         */
451        public String getTitle()
452        {
453          return title;
454        }
455    
456        private static final long serialVersionUID = 1614381073220130939L;
457    
458        /**
459         * This method sets the title of the tab.
460         *
461         * @param text The title of the tab.
462         */
463        public void setTitle(String text)
464        {
465          title = text;
466          if (title != null && title.length() <= underlinedChar)
467            setDisplayedMnemonicIndex(title.length() - 1);
468        }
469    
470        /**
471         * This method returns the active icon.
472         *
473         * @return The active icon.
474         */
475        public Icon getIcon()
476        {
477          return icon;
478        }
479    
480        /**
481         * This method sets the active icon.
482         *
483         * @param icon The active icon.
484         */
485        public void setIcon(Icon icon)
486        {
487          this.icon = icon;
488        }
489    
490        /**
491         * This method returns the disabled icon.
492         *
493         * @return The disabled icon.
494         */
495        public Icon getDisabledIcon()
496        {
497          if (disabledIcon == null && icon instanceof ImageIcon)
498            setDisabledIcon(icon);
499          return disabledIcon;
500        }
501    
502        /**
503         * This method sets the disabled icon.
504         *
505         * @param disabledIcon The disabled icon.
506         */
507        public void setDisabledIcon(Icon disabledIcon)
508        {
509          this.disabledIcon = disabledIcon;
510        }
511    
512        /**
513         * This method returns whether the tab is enabled.
514         *
515         * @return Whether the tab is enabled.
516         */
517        public boolean isEnabled()
518        {
519          return enabled;
520        }
521    
522        /**
523         * This method sets whether the tab is enabled.
524         *
525         * @param enabled Whether this tab is enabled.
526         */
527        public void setEnabled(boolean enabled)
528        {
529          this.enabled = enabled;
530        }
531    
532        /**
533         * This method returns the mnemonic.
534         *
535         * @return The mnemonic.
536         */
537        public int getMnemonic()
538        {
539          return mnemonicKey;
540        }
541    
542        /**
543         * This method sets the mnemonic. If the title is set, it will update the
544         * mnemonicIndex.
545         *
546         * @param key The mnemonic.
547         */
548        public void setMnemonic(int key)
549        {
550          setMnemonic((char) key);
551        }
552    
553        /**
554         * This method sets the mnemonic. If the title is set, it will update the
555         * mnemonicIndex.
556         *
557         * @param aChar The mnemonic.
558         */
559        public void setMnemonic(char aChar)
560        {
561          mnemonicKey = aChar;
562          if (title != null)
563            setDisplayedMnemonicIndex(title.indexOf(mnemonicKey));
564        }
565    
566        /**
567         * This method returns the mnemonicIndex.
568         *
569         * @return The mnemonicIndex.
570         */
571        public int getDisplayedMnemonicIndex()
572        {
573          return underlinedChar;
574        }
575    
576        /**
577         * This method sets the mnemonicIndex.
578         *
579         * @param index The mnemonicIndex.
580         *
581         * @throws IllegalArgumentException If index less than -1 || index greater
582         *         or equal to title.length.
583         */
584        public void setDisplayedMnemonicIndex(int index)
585          throws IllegalArgumentException
586        {
587          if (index < -1 || title != null && index >= title.length())
588            throw new IllegalArgumentException();
589    
590          if (title == null || mnemonicKey == 0 || (index > -1 && title.charAt(index) != mnemonicKey))
591            index = -1;
592    
593          underlinedChar = index;
594        }
595    
596        /**
597         * Returns the accessible context, which is this object itself.
598         *
599         * @return the accessible context, which is this object itself
600         */
601        public AccessibleContext getAccessibleContext()
602        {
603          return this;
604        }
605    
606        /**
607         * Returns the accessible name for this tab.
608         *
609         * @return The accessible name.
610         */
611        public String getAccessibleName()
612        {
613          if (accessibleName != null)
614            return accessibleName;
615          else
616            return title;
617        }
618    
619        /**
620         * Returns the accessible role of this tab, which is always
621         * {@link AccessibleRole#PAGE_TAB}.
622         *
623         * @return the accessible role of this tab
624         */
625        public AccessibleRole getAccessibleRole()
626        {
627          return AccessibleRole.PAGE_TAB;
628        }
629    
630        /**
631         * Returns the accessible state set of this object.
632         *
633         * @return the accessible state set of this object
634         */
635        public AccessibleStateSet getAccessibleStateSet()
636        {
637          AccessibleContext parentCtx = JTabbedPane.this.getAccessibleContext();
638          AccessibleStateSet state = parentCtx.getAccessibleStateSet();
639          state.add(AccessibleState.SELECTABLE);
640          if (component == getSelectedComponent())
641            state.add(AccessibleState.SELECTED);
642          return state;
643        }
644    
645        /**
646         * Returns the index of this tab inside its parent.
647         *
648         * @return the index of this tab inside its parent
649         */
650        public int getAccessibleIndexInParent()
651        {
652          // TODO: Not sure if the title is unambiguous, but I can't figure
653          // another way of doing this.
654          return indexOfTab(title);
655        }
656    
657        /**
658         * Returns the number of accessible children, which is always one (the
659         * component of this tab).
660         *
661         * @return the number of accessible children
662         */
663        public int getAccessibleChildrenCount()
664        {
665          return 1;
666        }
667    
668        /**
669         * Returns the accessible child of this tab, which is the component
670         * displayed by the tab.
671         *
672         * @return the accessible child of this tab
673         */
674        public Accessible getAccessibleChild(int i)
675        {
676          // A quick test shows that this method always returns the component
677          // displayed by the tab, regardless of the index.
678          return (Accessible) component;
679        }
680    
681        /**
682         * Returns the locale of this accessible object.
683         *
684         * @return the locale of this accessible object
685         */
686        public Locale getLocale()
687        {
688          // TODO: Is this ok?
689          return Locale.getDefault();
690        }
691      }
692    
693      private static final long serialVersionUID = 1614381073220130939L;
694    
695      /** The changeEvent used to fire changes to listeners. */
696      protected ChangeEvent changeEvent;
697    
698      /** The listener that listens to the model. */
699      protected ChangeListener changeListener;
700    
701      /** The model that describes this JTabbedPane. */
702      protected SingleSelectionModel model;
703    
704      /** Indicates that the TabbedPane is in scrolling mode. */
705      public static final int SCROLL_TAB_LAYOUT = 1;
706    
707      /** Indicates that the TabbedPane is in wrap mode. */
708      public static final int WRAP_TAB_LAYOUT = 0;
709    
710      /** The current tabPlacement of the TabbedPane. */
711      protected int tabPlacement = SwingConstants.TOP;
712    
713      /** The current tabLayoutPolicy of the TabbedPane. */
714      private transient int layoutPolicy;
715    
716      /** The list of tabs associated with the TabbedPane. */
717      transient Vector tabs = new Vector();
718    
719      /**
720       * Creates a new JTabbedPane object with tabs on top and using wrap tab
721       * layout.
722       */
723      public JTabbedPane()
724      {
725        this(SwingConstants.TOP, WRAP_TAB_LAYOUT);
726      }
727    
728      /**
729       * Creates a new JTabbedPane object using wrap tab layout  and the given
730       * <code>tabPlacement</code>, where <code>tabPlacement</code> can be one
731       * of the following values: {@link #TOP}, {@link #BOTTOM}, {@link #LEFT} or
732       * {@link #RIGHT}.
733       *
734       * @param tabPlacement where the tabs will be placed
735       */
736      public JTabbedPane(int tabPlacement)
737      {
738        this(tabPlacement, WRAP_TAB_LAYOUT);
739      }
740    
741      /**
742       * Creates a new JTabbedPane object with the given <code>tabPlacement</code>
743       * and <code>tabLayoutPolicy</code>. The <code>tabPlacement</code> can be one
744       * of the following values: {@link #TOP}, {@link #BOTTOM}, {@link #LEFT} or
745       * {@link #RIGHT}. The <code>tabLayoutPolicy</code> can be either
746       * {@link #SCROLL_TAB_LAYOUT} or {@link #WRAP_TAB_LAYOUT}.
747       *
748       * @param tabPlacement where the tabs will be placed
749       * @param tabLayoutPolicy the way tabs will be placed
750       *
751       * @throws IllegalArgumentException If tabLayoutPolicy or tabPlacement are
752       *         not valid.
753       */
754      public JTabbedPane(int tabPlacement, int tabLayoutPolicy)
755      {
756        if (tabPlacement != TOP && tabPlacement != BOTTOM && tabPlacement != RIGHT
757            && tabPlacement != LEFT)
758          throw new IllegalArgumentException("tabPlacement is not valid.");
759        if (tabLayoutPolicy != SCROLL_TAB_LAYOUT
760            && tabLayoutPolicy != WRAP_TAB_LAYOUT)
761          throw new IllegalArgumentException("tabLayoutPolicy is not valid.");
762        this.tabPlacement = tabPlacement;
763        layoutPolicy = tabLayoutPolicy;
764    
765        setModel(new DefaultSingleSelectionModel());
766    
767        updateUI();
768      }
769    
770      /**
771       * This method returns the UI used to display the JTabbedPane.
772       *
773       * @return The UI used to display the JTabbedPane.
774       */
775      public TabbedPaneUI getUI()
776      {
777        return (TabbedPaneUI) ui;
778      }
779    
780      /**
781       * This method sets the UI used to display the JTabbedPane.
782       *
783       * @param ui The UI used to display the JTabbedPane.
784       */
785      public void setUI(TabbedPaneUI ui)
786      {
787        super.setUI(ui);
788      }
789    
790      /**
791       * This method restores the UI to the defaults given by the UIManager.
792       */
793      public void updateUI()
794      {
795        setUI((TabbedPaneUI) UIManager.getUI(this));
796      }
797    
798      /**
799       * This method returns a string identifier that  is used to determine which
800       * UI will be used with  the JTabbedPane.
801       *
802       * @return A string identifier for the UI.
803       */
804      public String getUIClassID()
805      {
806        return "TabbedPaneUI";
807      }
808    
809      /**
810       * This method creates a ChangeListener that is used to  listen to the model
811       * for events.
812       *
813       * @return A ChangeListener to listen to the model.
814       */
815      protected ChangeListener createChangeListener()
816      {
817        return new ModelListener();
818      }
819    
820      /**
821       * This method adds a ChangeListener to the JTabbedPane.
822       *
823       * @param l The ChangeListener to add.
824       */
825      public void addChangeListener(ChangeListener l)
826      {
827        listenerList.add(ChangeListener.class, l);
828      }
829    
830      /**
831       * This method removes a ChangeListener to the JTabbedPane.
832       *
833       * @param l The ChangeListener to remove.
834       */
835      public void removeChangeListener(ChangeListener l)
836      {
837        listenerList.remove(ChangeListener.class, l);
838      }
839    
840      /**
841       * This method fires a ChangeEvent to all the JTabbedPane's ChangeListeners.
842       */
843      protected void fireStateChanged()
844      {
845        Object[] changeListeners = listenerList.getListenerList();
846        if (changeEvent == null)
847          changeEvent = new ChangeEvent(this);
848        for (int i = changeListeners.length - 2; i >= 0; i -= 2)
849          {
850            if (changeListeners[i] == ChangeListener.class)
851              ((ChangeListener) changeListeners[i + 1]).stateChanged(changeEvent);
852          }
853      }
854    
855      /**
856       * This method returns all ChangeListeners registered with the JTabbedPane.
857       *
858       * @return The ChangeListeners registered with the JTabbedPane.
859       */
860      public ChangeListener[] getChangeListeners()
861      {
862        return (ChangeListener[]) super.getListeners(ChangeListener.class);
863      }
864    
865      /**
866       * This method returns the model used with the JTabbedPane.
867       *
868       * @return The JTabbedPane's model.
869       */
870      public SingleSelectionModel getModel()
871      {
872        return model;
873      }
874    
875      /**
876       * This method changes the model property of the JTabbedPane.
877       *
878       * @param m The new model to use with the JTabbedPane.
879       */
880      public void setModel(SingleSelectionModel m)
881      {
882        if (m != model)
883          {
884            SingleSelectionModel oldModel = this.model;
885            if (oldModel != null && changeListener != null)
886              oldModel.removeChangeListener(changeListener);
887    
888            model = m;
889    
890            if (model != null)
891              {
892                if (changeListener == null)
893                  changeListener = createChangeListener();
894                model.addChangeListener(changeListener);
895              }
896            firePropertyChange("model", oldModel, this.model);
897          }
898      }
899    
900      /**
901       * This method returns the tabPlacement.
902       *
903       * @return The tabPlacement used with the JTabbedPane.
904       */
905      public int getTabPlacement()
906      {
907        return tabPlacement;
908      }
909    
910      /**
911       * This method changes the tabPlacement property of the JTabbedPane.
912       *
913       * @param tabPlacement The tabPlacement to use.
914       *
915       * @throws IllegalArgumentException If tabPlacement is not one of TOP,
916       *         BOTTOM, LEFT, or RIGHT.
917       */
918      public void setTabPlacement(int tabPlacement)
919      {
920        if (tabPlacement != TOP && tabPlacement != BOTTOM && tabPlacement != RIGHT
921            && tabPlacement != LEFT)
922          throw new IllegalArgumentException("tabPlacement is not valid.");
923        if (tabPlacement != this.tabPlacement)
924          {
925            int oldPlacement = this.tabPlacement;
926            this.tabPlacement = tabPlacement;
927            firePropertyChange("tabPlacement", oldPlacement, this.tabPlacement);
928          }
929      }
930    
931      /**
932       * This method returns the tabLayoutPolicy.
933       *
934       * @return The tabLayoutPolicy.
935       */
936      public int getTabLayoutPolicy()
937      {
938        return layoutPolicy;
939      }
940    
941      /**
942       * This method changes the tabLayoutPolicy property of the JTabbedPane.
943       *
944       * @param tabLayoutPolicy The tabLayoutPolicy to use.
945       *
946       * @throws IllegalArgumentException If tabLayoutPolicy is not one of
947       *         SCROLL_TAB_LAYOUT or WRAP_TAB_LAYOUT.
948       */
949      public void setTabLayoutPolicy(int tabLayoutPolicy)
950      {
951        if (tabLayoutPolicy != SCROLL_TAB_LAYOUT
952            && tabLayoutPolicy != WRAP_TAB_LAYOUT)
953          throw new IllegalArgumentException("tabLayoutPolicy is not valid.");
954        if (tabLayoutPolicy != layoutPolicy)
955          {
956            int oldPolicy = layoutPolicy;
957            layoutPolicy = tabLayoutPolicy;
958            firePropertyChange("tabLayoutPolicy", oldPolicy, layoutPolicy);
959          }
960      }
961    
962      /**
963       * This method returns the index of the tab that is currently selected.
964       *
965       * @return The index of the selected tab.
966       */
967      public int getSelectedIndex()
968      {
969        return model.getSelectedIndex();
970      }
971    
972      /**
973       * This method checks the index.
974       *
975       * @param index The index to check.
976       * @param start DOCUMENT ME!
977       * @param end DOCUMENT ME!
978       *
979       * @throws IndexOutOfBoundsException DOCUMENT ME!
980       */
981      private void checkIndex(int index, int start, int end)
982      {
983        if (index < start || index >= end)
984          throw new IndexOutOfBoundsException("Index < " + start + " || Index >= "
985                                              + end);
986      }
987    
988      /**
989       * This method sets the selected index. This method will hide the old
990       * component and show the new component.
991       *
992       * @param index The index to set it at.
993       */
994      public void setSelectedIndex(int index)
995      {
996        checkIndex(index, -1, tabs.size());
997        if (index != getSelectedIndex())
998          {
999            // Hiding and showing the involved components
1000            // is done by the JTabbedPane's UI.
1001            model.setSelectedIndex(index);
1002          }
1003      }
1004    
1005      /**
1006       * This method returns the component at the selected index.
1007       *
1008       * @return The component at the selected index.
1009       */
1010      public Component getSelectedComponent()
1011      {
1012        int selectedIndex = getSelectedIndex();
1013        Component selected = null;
1014        if (selectedIndex >= 0)
1015          selected = getComponentAt(selectedIndex);
1016        return selected;
1017      }
1018    
1019      /**
1020       * This method sets the component at the selected index.
1021       *
1022       * @param c The component associated with the selected index.
1023       */
1024      public void setSelectedComponent(Component c)
1025      {
1026        if (c.getParent() == this)
1027          setSelectedIndex(indexOfComponent(c));
1028        else
1029          setComponentAt(getSelectedIndex(), c);
1030      }
1031    
1032      /**
1033       * This method inserts tabs into JTabbedPane. This includes adding the
1034       * component to the JTabbedPane and hiding it.
1035       *
1036       * @param title the title of the tab; may be <code>null</code>
1037       * @param icon the tab's icon; may be <code>null</code>
1038       * @param component the component associated with the tab
1039       * @param tip the tooltip for the tab
1040       * @param index the index to insert the tab at
1041       */
1042      public void insertTab(String title, Icon icon, Component component,
1043                            String tip, int index)
1044      {
1045        if (title == null)
1046          title = "";
1047        Page p = new Page(title, icon, component, tip);
1048        tabs.insertElementAt(p, index);
1049    
1050        // Hide the component so we don't see it. Do it before we parent it
1051        // so we don't trigger a repaint.
1052        if (component != null)
1053          {
1054            component.hide();
1055            super.add(component);
1056          }
1057    
1058        if (getSelectedIndex() == -1)
1059          {
1060            setSelectedIndex(0);
1061            fireStateChanged();
1062          }
1063    
1064        revalidate();
1065        repaint();
1066      }
1067    
1068      /**
1069       * This method adds a tab to the JTabbedPane.
1070       *
1071       * @param title the title of the tab; may be <code>null</code>
1072       * @param icon the icon for the tab; may be <code>null</code>
1073       * @param component the associated component
1074       * @param tip the associated tooltip
1075       */
1076      public void addTab(String title, Icon icon, Component component, String tip)
1077      {
1078        insertTab(title, icon, component, tip, tabs.size());
1079      }
1080    
1081      /**
1082       * This method adds a tab to the JTabbedPane.
1083       *
1084       * @param title the title of the tab; may be <code>null</code>
1085       * @param icon the icon for the tab; may be <code>null</code>
1086       * @param component the associated component
1087       */
1088      public void addTab(String title, Icon icon, Component component)
1089      {
1090        insertTab(title, icon, component, null, tabs.size());
1091      }
1092    
1093      /**
1094       * This method adds a tab to the JTabbedPane.
1095       *
1096       * @param title the title of the tab; may be <code>null</code>
1097       * @param component the associated component
1098       */
1099      public void addTab(String title, Component component)
1100      {
1101        insertTab(title, null, component, null, tabs.size());
1102      }
1103    
1104      /**
1105       * This method adds a tab to the JTabbedPane. The title of the tab is the
1106       * Component's name. If the Component is an instance of UIResource, it
1107       * doesn't add the tab and instead add the component directly to the
1108       * JTabbedPane.
1109       *
1110       * @param component The associated component.
1111       *
1112       * @return The Component that was added.
1113       */
1114      public Component add(Component component)
1115      {
1116        if (component instanceof UIResource)
1117          super.add(component);
1118        else
1119          insertTab(component.getName(), null, component, null, tabs.size());
1120    
1121        return component;
1122      }
1123    
1124      /**
1125       * This method adds a tab to the JTabbedPane. If the Component is an
1126       * instance of UIResource, it doesn't add the tab and instead add the
1127       * component directly to the JTabbedPane.
1128       *
1129       * @param title the title of the tab; may be <code>null</code>
1130       * @param component the associated component
1131       *
1132       * @return The Component that was added.
1133       */
1134      public Component add(String title, Component component)
1135      {
1136        if (component instanceof UIResource)
1137          super.add(component);
1138        else
1139          insertTab(title, null, component, null, tabs.size());
1140        return component;
1141      }
1142    
1143      /**
1144       * This method adds a tab to the JTabbedPane. If the Component is an
1145       * instance of UIResource, it doesn't add the tab and instead add the
1146       * component directly to the JTabbedPane.
1147       *
1148       * @param component The associated component.
1149       * @param index The index to insert the tab at.
1150       *
1151       * @return The Component that was added.
1152       */
1153      public Component add(Component component, int index)
1154      {
1155        if (component instanceof UIResource)
1156          super.add(component);
1157        else
1158          insertTab(component.getName(), null, component, null, index);
1159        return component;
1160      }
1161    
1162      /**
1163       * This method adds a tab to the JTabbedPane. If the Component is an
1164       * instance of UIResource, it doesn't add the tab and instead add the
1165       * component directly to the JTabbedPane. If the constraints object is an
1166       * icon, it will be used as the tab's icon. If the constraints object is a
1167       * string, we will use it as the title.
1168       *
1169       * @param component The associated component.
1170       * @param constraints The constraints object.
1171       */
1172      public void add(Component component, Object constraints)
1173      {
1174        add(component, constraints, tabs.size());
1175      }
1176    
1177      /**
1178       * This method adds a tab to the JTabbedPane. If the Component is an
1179       * instance of UIResource, it doesn't add the tab and instead add the
1180       * component directly to the JTabbedPane. If the constraints object is an
1181       * icon, it will be used as the tab's icon. If the constraints object is a
1182       * string, we will use it as the title.
1183       *
1184       * @param component The associated component.
1185       * @param constraints The constraints object.
1186       * @param index The index to insert the tab at.
1187       */
1188      public void add(Component component, Object constraints, int index)
1189      {
1190        if (component instanceof UIResource)
1191          super.add(component);
1192        else
1193          {
1194            if (constraints instanceof String)
1195              insertTab((String) constraints, null, component, null, index);
1196            else
1197              insertTab(component.getName(),
1198                        (constraints instanceof Icon) ? (Icon) constraints : null,
1199                        component, null, index);
1200          }
1201      }
1202    
1203      /**
1204       * Removes the tab at index. After the component associated with
1205       * index is removed, its visibility is reset to true to ensure it
1206       * will be visible if added to other containers.
1207       *
1208       * @param index The index of the tab to remove.
1209       */
1210      public void removeTabAt(int index)
1211      {
1212        checkIndex(index, 0, tabs.size());
1213    
1214        // We need to adjust the selection if we remove a tab that comes
1215        // before the selected tab or if the selected tab is removed.
1216        // This decrements the selected index by 1 if any of this is the case.
1217        // Note that this covers all cases:
1218        // - When the selected tab comes after the removed tab, this simply
1219        //   adjusts the selection so that after the removal the selected tab
1220        //   is still the same.
1221        // - When we remove the currently selected tab, then the tab before the
1222        //   selected tab gets selected.
1223        // - When the last tab is removed, then we have an index==0, which gets
1224        //   decremented to -1, which means no selection, which is 100% perfect.
1225        int selectedIndex = getSelectedIndex();
1226        if (selectedIndex >= index)
1227          setSelectedIndex(selectedIndex - 1);
1228    
1229        Component comp = getComponentAt(index);
1230    
1231        // Remove the tab object.
1232        tabs.remove(index);
1233    
1234        // Remove the component. I think we cannot assume that the tab order
1235        // is equal to the component order, so we iterate over the children
1236        // here to find the and remove the correct component.
1237        if (comp != null)
1238          {
1239            Component[] children = getComponents();
1240            for (int i = children.length - 1; i >= 0; --i)
1241              {
1242                if (children[i] == comp)
1243                  {
1244                    super.remove(i);
1245                    comp.setVisible(true);
1246                    break;
1247                  }
1248              }
1249          }
1250        revalidate();
1251        repaint();
1252      }
1253    
1254      /**
1255       * Removes the specified Component from the JTabbedPane.
1256       *
1257       * @param component The Component to remove.
1258       */
1259      public void remove(Component component)
1260      {
1261        // Since components implementing UIResource
1262        // are not added as regular tabs by the add()
1263        // methods we have to take special care when
1264        // removing these object. Especially
1265        // Container.remove(Component) cannot be used
1266        // because it will call JTabbedPane.remove(int)
1267        // later which is overridden and can only
1268        // handle tab components.
1269        // This implementation can even cope with a
1270        // situation that someone called insertTab()
1271        // with a component that implements UIResource.
1272        int index = indexOfComponent(component);
1273    
1274        // If the component is not a tab component
1275        // find out its Container-given index
1276        // and call that class' implementation
1277        // directly.
1278        if (index == -1)
1279          {
1280            Component[] cs = getComponents();
1281            for (int i = 0; i< cs.length; i++)
1282              if (cs[i] == component)
1283                super.remove(i);
1284          }
1285        else
1286          removeTabAt(index);
1287      }
1288    
1289      /**
1290       * Removes the tab and component which corresponds to the specified index.
1291       *
1292       * @param index The index of the tab to remove.
1293       */
1294      public void remove(int index)
1295      {
1296        removeTabAt(index);
1297      }
1298    
1299      /**
1300       * This method removes all tabs and associated components from the
1301       * JTabbedPane.
1302       */
1303      public void removeAll()
1304      {
1305        setSelectedIndex(-1);
1306        for (int i = getTabCount() - 1; i >= 0; i--)
1307          removeTabAt(i);
1308      }
1309    
1310      /**
1311       * This method returns how many tabs are in the JTabbedPane.
1312       *
1313       * @return The number of tabs in the JTabbedPane.
1314       */
1315      public int getTabCount()
1316      {
1317        return tabs.size();
1318      }
1319    
1320      /**
1321       * This method returns the number of runs used  to paint the JTabbedPane.
1322       *
1323       * @return The number of runs.
1324       */
1325      public int getTabRunCount()
1326      {
1327        return ((TabbedPaneUI) ui).getTabRunCount(this);
1328      }
1329    
1330      /**
1331       * This method returns the tab title given the index.
1332       *
1333       * @param index The index of the tab.
1334       *
1335       * @return The title for the tab.
1336       */
1337      public String getTitleAt(int index)
1338      {
1339        checkIndex(index, 0, tabs.size());
1340        return ((Page) tabs.elementAt(index)).getTitle();
1341      }
1342    
1343      /**
1344       * This method returns the active icon given the index.
1345       *
1346       * @param index The index of the tab.
1347       *
1348       * @return The active icon for the tab.
1349       */
1350      public Icon getIconAt(int index)
1351      {
1352        checkIndex(index, 0, tabs.size());
1353        return ((Page) tabs.elementAt(index)).getIcon();
1354      }
1355    
1356      /**
1357       * This method returns the disabled icon given the index.
1358       *
1359       * @param index The index of the tab.
1360       *
1361       * @return The disabled icon for the tab.
1362       */
1363      public Icon getDisabledIconAt(int index)
1364      {
1365        checkIndex(index, 0, tabs.size());
1366        return ((Page) tabs.elementAt(index)).getDisabledIcon();
1367      }
1368    
1369      /**
1370       * This method returns the tooltip string for the tab.
1371       *
1372       * @param index The index of the tab.
1373       *
1374       * @return The tooltip string for the tab.
1375       */
1376      public String getToolTipTextAt(int index)
1377      {
1378        checkIndex(index, 0, tabs.size());
1379        return ((Page) tabs.elementAt(index)).getTip();
1380      }
1381    
1382      /**
1383       * This method returns the foreground color for the tab.
1384       *
1385       * @param index The index of the tab.
1386       *
1387       * @return The foreground color for the tab.
1388       */
1389      public Color getForegroundAt(int index)
1390      {
1391        checkIndex(index, 0, tabs.size());
1392        return ((Page) tabs.elementAt(index)).getForeground();
1393      }
1394    
1395      /**
1396       * This method returns the background color for the tab.
1397       *
1398       * @param index The index of the tab.
1399       *
1400       * @return The background color for the tab.
1401       */
1402      public Color getBackgroundAt(int index)
1403      {
1404        checkIndex(index, 0, tabs.size());
1405        return ((Page) tabs.elementAt(index)).getBackground();
1406      }
1407    
1408      /**
1409       * This method returns the component associated with the tab.
1410       *
1411       * @param index The index of the tab.
1412       *
1413       * @return The component associated with the tab.
1414       */
1415      public Component getComponentAt(int index)
1416      {
1417        checkIndex(index, 0, tabs.size());
1418        return ((Page) tabs.elementAt(index)).getComponent();
1419      }
1420    
1421      /**
1422       * This method returns whether this tab is enabled. Disabled tabs cannot be
1423       * selected.
1424       *
1425       * @param index The index of the tab.
1426       *
1427       * @return Whether the tab is enabled.
1428       */
1429      public boolean isEnabledAt(int index)
1430      {
1431        checkIndex(index, 0, tabs.size());
1432        return ((Page) tabs.elementAt(index)).isEnabled();
1433      }
1434    
1435      /**
1436       * This method returns the mnemonic for the tab.
1437       *
1438       * @param tabIndex The index of the tab.
1439       *
1440       * @return The mnemonic for the tab.
1441       */
1442      public int getMnemonicAt(int tabIndex)
1443      {
1444        checkIndex(tabIndex, 0, tabs.size());
1445        return ((Page) tabs.elementAt(tabIndex)).getMnemonic();
1446      }
1447    
1448      /**
1449       * This method returns the mnemonic index for the tab.
1450       *
1451       * @param tabIndex The index of the tab.
1452       *
1453       * @return The mnemonic index for the tab.
1454       */
1455      public int getDisplayedMnemonicIndexAt(int tabIndex)
1456      {
1457        checkIndex(tabIndex, 0, tabs.size());
1458        return ((Page) tabs.elementAt(tabIndex)).getDisplayedMnemonicIndex();
1459      }
1460    
1461      /**
1462       * This method returns the bounds of the tab given the index.
1463       *
1464       * @param index The index of the tab.
1465       *
1466       * @return A rectangle describing the bounds of the tab.
1467       */
1468      public Rectangle getBoundsAt(int index)
1469      {
1470        checkIndex(index, 0, tabs.size());
1471        return ((TabbedPaneUI) ui).getTabBounds(this, index);
1472      }
1473    
1474      /**
1475       * This method sets the title of the tab.
1476       *
1477       * @param index The index of the tab.
1478       * @param title The new title.
1479       */
1480      public void setTitleAt(int index, String title)
1481      {
1482        checkIndex(index, 0, tabs.size());
1483        ((Page) tabs.elementAt(index)).setTitle(title);
1484      }
1485    
1486      /**
1487       * This method sets the icon of the tab.
1488       *
1489       * @param index The index of the tab.
1490       * @param icon The new icon.
1491       */
1492      public void setIconAt(int index, Icon icon)
1493      {
1494        checkIndex(index, 0, tabs.size());
1495        ((Page) tabs.elementAt(index)).setIcon(icon);
1496      }
1497    
1498      /**
1499       * This method sets the disabled icon of the tab.
1500       *
1501       * @param index The index of the tab.
1502       * @param disabledIcon The new disabled icon.
1503       */
1504      public void setDisabledIconAt(int index, Icon disabledIcon)
1505      {
1506        checkIndex(index, 0, tabs.size());
1507        ((Page) tabs.elementAt(index)).setDisabledIcon(disabledIcon);
1508      }
1509    
1510      /**
1511       * This method sets the tooltip text of the tab.
1512       *
1513       * @param index The index of the tab.
1514       * @param toolTipText The tooltip text.
1515       */
1516      public void setToolTipTextAt(int index, String toolTipText)
1517      {
1518        checkIndex(index, 0, tabs.size());
1519        ((Page) tabs.elementAt(index)).setTip(toolTipText);
1520      }
1521    
1522      /**
1523       * This method sets the background color of the tab.
1524       *
1525       * @param index The index of the tab.
1526       * @param background The background color of the tab.
1527       */
1528      public void setBackgroundAt(int index, Color background)
1529      {
1530        checkIndex(index, 0, tabs.size());
1531        ((Page) tabs.elementAt(index)).setBackground(background);
1532      }
1533    
1534      /**
1535       * This method sets the foreground color of the tab.
1536       *
1537       * @param index The index of the tab.
1538       * @param foreground The foreground color of the tab.
1539       */
1540      public void setForegroundAt(int index, Color foreground)
1541      {
1542        checkIndex(index, 0, tabs.size());
1543        ((Page) tabs.elementAt(index)).setForeground(foreground);
1544      }
1545    
1546      /**
1547       * This method sets whether the tab is enabled.
1548       *
1549       * @param index The index of the tab.
1550       * @param enabled Whether the tab is enabled.
1551       */
1552      public void setEnabledAt(int index, boolean enabled)
1553      {
1554        checkIndex(index, 0, tabs.size());
1555        ((Page) tabs.elementAt(index)).setEnabled(enabled);
1556      }
1557    
1558      /**
1559       * This method sets the component associated with the tab.
1560       *
1561       * @param index The index of the tab.
1562       * @param component The component associated with the tab.
1563       */
1564      public void setComponentAt(int index, Component component)
1565      {
1566        checkIndex(index, 0, tabs.size());
1567        ((Page) tabs.elementAt(index)).setComponent(component);
1568      }
1569    
1570      /**
1571       * This method sets the displayed mnemonic index of the tab.
1572       *
1573       * @param tabIndex The index of the tab.
1574       * @param mnemonicIndex The mnemonic index.
1575       */
1576      public void setDisplayedMnemonicIndexAt(int tabIndex, int mnemonicIndex)
1577      {
1578        checkIndex(tabIndex, 0, tabs.size());
1579        ((Page) tabs.elementAt(tabIndex)).setDisplayedMnemonicIndex(mnemonicIndex);
1580      }
1581    
1582      /**
1583       * This method sets the mnemonic for the tab.
1584       *
1585       * @param tabIndex The index of the tab.
1586       * @param mnemonic The mnemonic.
1587       */
1588      public void setMnemonicAt(int tabIndex, int mnemonic)
1589      {
1590        checkIndex(tabIndex, 0, tabs.size());
1591        ((Page) tabs.elementAt(tabIndex)).setMnemonic(mnemonic);
1592      }
1593    
1594      /**
1595       * This method finds the index of a tab given the title.
1596       *
1597       * @param title The title that belongs to a tab.
1598       *
1599       * @return The index of the tab that has the title or -1 if not found.
1600       */
1601      public int indexOfTab(String title)
1602      {
1603        int index = -1;
1604        for (int i = 0; i < tabs.size(); i++)
1605          {
1606            if (((Page) tabs.elementAt(i)).getTitle().equals(title))
1607              {
1608                index = i;
1609                break;
1610              }
1611          }
1612        return index;
1613      }
1614    
1615      /**
1616       * This method finds the index of a tab given the icon.
1617       *
1618       * @param icon The icon that belongs to a tab.
1619       *
1620       * @return The index of the tab that has the icon or -1 if not found.
1621       */
1622      public int indexOfTab(Icon icon)
1623      {
1624        int index = -1;
1625        for (int i = 0; i < tabs.size(); i++)
1626          {
1627            if (((Page) tabs.elementAt(i)).getIcon() == icon)
1628              {
1629                index = i;
1630                break;
1631              }
1632          }
1633        return index;
1634      }
1635    
1636      /**
1637       * This method finds the index of a tab given the component.
1638       *
1639       * @param component A component associated with a tab.
1640       *
1641       * @return The index of the tab that has this component or -1 if not found.
1642       */
1643      public int indexOfComponent(Component component)
1644      {
1645        int index = -1;
1646        for (int i = 0; i < tabs.size(); i++)
1647          {
1648            if (((Page) tabs.elementAt(i)).getComponent() == component)
1649              {
1650                index = i;
1651                break;
1652              }
1653          }
1654        return index;
1655      }
1656    
1657      /**
1658       * This method returns a tab index given an (x,y) location. The origin of
1659       * the (x,y) pair will be the JTabbedPane's top left position. The  tab
1660       * returned will be the one that contains the point. This method is
1661       * delegated to the UI.
1662       *
1663       * @param x The x coordinate of the point.
1664       * @param y The y coordinate of the point.
1665       *
1666       * @return The index of the tab that contains the point.
1667       */
1668      public int indexAtLocation(int x, int y)
1669      {
1670        return ((TabbedPaneUI) ui).tabForCoordinate(this, x, y);
1671      }
1672    
1673      /**
1674       * This method returns the tooltip text given a mouse event.
1675       *
1676       * @param event The mouse event.
1677       *
1678       * @return The tool tip text that is associated with this mouse event.
1679       */
1680      public String getToolTipText(MouseEvent event)
1681      {
1682        int index = indexAtLocation(event.getX(), event.getY());
1683        return ((Page) tabs.elementAt(index)).getTip();
1684      }
1685    
1686      /**
1687       * Returns a string describing the attributes for the
1688       * <code>JTabbedPane</code> component, for use in debugging.  The return
1689       * value is guaranteed to be non-<code>null</code>, but the format of the
1690       * string may vary between implementations.
1691       *
1692       * @return A string describing the attributes of the
1693       *     <code>JTabbedPane</code>.
1694       */
1695      protected String paramString()
1696      {
1697        CPStringBuilder sb = new CPStringBuilder(super.paramString());
1698        sb.append(",tabPlacement=");
1699        if (tabPlacement == TOP)
1700          sb.append("TOP");
1701        if (tabPlacement == BOTTOM)
1702          sb.append("BOTTOM");
1703        if (tabPlacement == LEFT)
1704          sb.append("LEFT");
1705        if (tabPlacement == RIGHT)
1706          sb.append("RIGHT");
1707        return sb.toString();
1708      }
1709    
1710      /**
1711       * Returns the object that provides accessibility features for this
1712       * <code>JTabbedPane</code> component.
1713       *
1714       * @return The accessible context (an instance of
1715       *         {@link AccessibleJTabbedPane}).
1716       */
1717      public AccessibleContext getAccessibleContext()
1718      {
1719        if (accessibleContext == null)
1720          {
1721            AccessibleJTabbedPane ctx = new AccessibleJTabbedPane();
1722            addChangeListener(ctx);
1723            accessibleContext = ctx;
1724          }
1725    
1726        return accessibleContext;
1727      }
1728    }