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 java.awt.Color;
042    import java.awt.Component;
043    import java.awt.Point;
044    import java.awt.Rectangle;
045    import java.awt.event.MouseEvent;
046    import java.io.Serializable;
047    import java.util.Locale;
048    import java.util.Vector;
049    
050    import javax.accessibility.Accessible;
051    import javax.accessibility.AccessibleContext;
052    import javax.accessibility.AccessibleRole;
053    import javax.accessibility.AccessibleSelection;
054    import javax.accessibility.AccessibleState;
055    import javax.accessibility.AccessibleStateSet;
056    import javax.swing.event.ChangeEvent;
057    import javax.swing.event.ChangeListener;
058    import javax.swing.plaf.TabbedPaneUI;
059    import javax.swing.plaf.UIResource;
060    
061    /**
062     * This is a container for components where only one component is displayed at
063     * a given time and the displayed component can be switched by clicking on
064     * tabs.
065     * 
066     * <p>
067     * Tabs can be oriented in several ways. They can be above, below, left and
068     * right of the component. Tabs can either wrap around (by creating multiple
069     * rows of tabs) or they can be scrolled (where only a subset of the  tabs
070     * can be seen at once). More tabs can be added by calling the
071     * add/addTab/insertTab methods.
072     * </p>
073     */
074    public class JTabbedPane extends JComponent implements Serializable,
075                                                           Accessible,
076                                                           SwingConstants
077    {
078      /**
079       * Accessibility support for <code>JTabbedPane</code>.
080       */
081      protected class AccessibleJTabbedPane extends JComponent.AccessibleJComponent
082        implements AccessibleSelection, ChangeListener
083      {
084        /**
085         * The serialization UID.
086         */
087        private static final long serialVersionUID = 7610530885966830483L;
088    
089        /**
090         * Creates a new AccessibleJTabbedPane object.
091         */
092        public AccessibleJTabbedPane()
093        {
094          super();
095        }
096    
097        /**
098         * Receives notification when the selection state of the
099         * <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.
972       *
973       * @param index The index to check.
974       * @param start DOCUMENT ME!
975       * @param end DOCUMENT ME!
976       *
977       * @throws IndexOutOfBoundsException DOCUMENT ME!
978       */
979      private void checkIndex(int index, int start, int end)
980      {
981        if (index < start || index >= end)
982          throw new IndexOutOfBoundsException("Index < " + start + " || Index >= "
983                                              + end);
984      }
985    
986      /**
987       * This method sets the selected index. This method will hide the old
988       * component and show the new component.
989       *
990       * @param index The index to set it at.
991       */
992      public void setSelectedIndex(int index)
993      {
994        checkIndex(index, -1, tabs.size());
995        if (index != getSelectedIndex())
996          {
997            // Hiding and showing the involved components
998            // is done by the JTabbedPane's UI.
999            model.setSelectedIndex(index);
1000          }
1001      }
1002    
1003      /**
1004       * This method returns the component at the selected index.
1005       *
1006       * @return The component at the selected index.
1007       */
1008      public Component getSelectedComponent()
1009      {
1010        int selectedIndex = getSelectedIndex();
1011        Component selected = null;
1012        if (selectedIndex >= 0)
1013          selected = getComponentAt(selectedIndex);
1014        return selected;
1015      }
1016    
1017      /**
1018       * This method sets the component at the selected index.
1019       *
1020       * @param c The component associated with the selected index.
1021       */
1022      public void setSelectedComponent(Component c)
1023      {
1024        if (c.getParent() == this)
1025          setSelectedIndex(indexOfComponent(c));
1026        else
1027          setComponentAt(getSelectedIndex(), c);
1028      }
1029    
1030      /**
1031       * This method inserts tabs into JTabbedPane. This includes adding the
1032       * component to the JTabbedPane and hiding it.
1033       *
1034       * @param title the title of the tab; may be <code>null</code>
1035       * @param icon the tab's icon; may be <code>null</code>
1036       * @param component the component associated with the tab
1037       * @param tip the tooltip for the tab
1038       * @param index the index to insert the tab at
1039       */
1040      public void insertTab(String title, Icon icon, Component component,
1041                            String tip, int index)
1042      {
1043        if (title == null)
1044          title = "";
1045        Page p = new Page(title, icon, component, tip);
1046        tabs.insertElementAt(p, index);
1047    
1048        // Hide the component so we don't see it. Do it before we parent it
1049        // so we don't trigger a repaint.
1050        if (component != null)
1051          {
1052            component.hide();
1053            super.add(component);
1054          }
1055    
1056        if (getSelectedIndex() == -1)
1057          {
1058            setSelectedIndex(0);
1059            fireStateChanged();
1060          }
1061    
1062        revalidate();
1063        repaint();
1064      }
1065    
1066      /**
1067       * This method adds a tab to the JTabbedPane.
1068       *
1069       * @param title the title of the tab; may be <code>null</code>
1070       * @param icon the icon for the tab; may be <code>null</code>
1071       * @param component the associated component
1072       * @param tip the associated tooltip
1073       */
1074      public void addTab(String title, Icon icon, Component component, String tip)
1075      {
1076        insertTab(title, icon, component, tip, tabs.size());
1077      }
1078    
1079      /**
1080       * This method adds a tab to the JTabbedPane.
1081       *
1082       * @param title the title of the tab; may be <code>null</code>
1083       * @param icon the icon for the tab; may be <code>null</code>
1084       * @param component the associated component
1085       */
1086      public void addTab(String title, Icon icon, Component component)
1087      {
1088        insertTab(title, icon, component, null, tabs.size());
1089      }
1090    
1091      /**
1092       * This method adds a tab to the JTabbedPane.
1093       *
1094       * @param title the title of the tab; may be <code>null</code>
1095       * @param component the associated component
1096       */
1097      public void addTab(String title, Component component)
1098      {
1099        insertTab(title, null, component, null, tabs.size());
1100      }
1101    
1102      /**
1103       * This method adds a tab to the JTabbedPane. The title of the tab is the
1104       * Component's name. If the Component is an instance of UIResource, it
1105       * doesn't add the tab and instead add the component directly to the
1106       * JTabbedPane.
1107       *
1108       * @param component The associated component.
1109       *
1110       * @return The Component that was added.
1111       */
1112      public Component add(Component component)
1113      {
1114        if (component instanceof UIResource)
1115          super.add(component);
1116        else
1117          insertTab(component.getName(), null, component, null, tabs.size());
1118        
1119        return component;
1120      }
1121    
1122      /**
1123       * This method adds a tab to the JTabbedPane. If the Component is an
1124       * instance of UIResource, it doesn't add the tab and instead add the
1125       * component directly to the JTabbedPane.
1126       *
1127       * @param title the title of the tab; may be <code>null</code>
1128       * @param component the associated component
1129       *
1130       * @return The Component that was added.
1131       */
1132      public Component add(String title, Component component)
1133      {
1134        if (component instanceof UIResource)
1135          super.add(component);
1136        else
1137          insertTab(title, null, component, null, tabs.size());
1138        return component;
1139      }
1140    
1141      /**
1142       * This method adds a tab to the JTabbedPane. If the Component is an
1143       * instance of UIResource, it doesn't add the tab and instead add the
1144       * component directly to the JTabbedPane.
1145       *
1146       * @param component The associated component.
1147       * @param index The index to insert the tab at.
1148       *
1149       * @return The Component that was added.
1150       */
1151      public Component add(Component component, int index)
1152      {
1153        if (component instanceof UIResource)
1154          super.add(component);
1155        else
1156          insertTab(component.getName(), null, component, null, index);
1157        return component;
1158      }
1159    
1160      /**
1161       * This method adds a tab to the JTabbedPane. If the Component is an
1162       * instance of UIResource, it doesn't add the tab and instead add the
1163       * component directly to the JTabbedPane. If the constraints object is an
1164       * icon, it will be used as the tab's icon. If the constraints object is a
1165       * string, we will use it as the title.
1166       *
1167       * @param component The associated component.
1168       * @param constraints The constraints object.
1169       */
1170      public void add(Component component, Object constraints)
1171      {
1172        add(component, constraints, tabs.size());
1173      }
1174    
1175      /**
1176       * This method adds a tab to the JTabbedPane. If the Component is an
1177       * instance of UIResource, it doesn't add the tab and instead add the
1178       * component directly to the JTabbedPane. If the constraints object is an
1179       * icon, it will be used as the tab's icon. If the constraints object is a
1180       * string, we will use it as the title.
1181       *
1182       * @param component The associated component.
1183       * @param constraints The constraints object.
1184       * @param index The index to insert the tab at.
1185       */
1186      public void add(Component component, Object constraints, int index)
1187      {
1188        if (component instanceof UIResource)
1189          super.add(component);
1190        else
1191          {
1192            if (constraints instanceof String)
1193              insertTab((String) constraints, null, component, null, index);
1194            else
1195              insertTab(component.getName(),
1196                        (constraints instanceof Icon) ? (Icon) constraints : null,
1197                        component, null, index);
1198          }
1199      }
1200    
1201      /**
1202       * Removes the tab at index. After the component associated with 
1203       * index is removed, its visibility is reset to true to ensure it 
1204       * will be visible if added to other containers.
1205       *
1206       * @param index The index of the tab to remove.
1207       */
1208      public void removeTabAt(int index)
1209      {
1210        checkIndex(index, 0, tabs.size());
1211    
1212        // We need to adjust the selection if we remove a tab that comes
1213        // before the selected tab or if the selected tab is removed.
1214        // This decrements the selected index by 1 if any of this is the case.
1215        // Note that this covers all cases:
1216        // - When the selected tab comes after the removed tab, this simply
1217        //   adjusts the selection so that after the removal the selected tab
1218        //   is still the same.
1219        // - When we remove the currently selected tab, then the tab before the
1220        //   selected tab gets selected.
1221        // - When the last tab is removed, then we have an index==0, which gets
1222        //   decremented to -1, which means no selection, which is 100% perfect.
1223        int selectedIndex = getSelectedIndex();
1224        if (selectedIndex >= index)
1225          setSelectedIndex(selectedIndex - 1);
1226    
1227        Component comp = getComponentAt(index);
1228    
1229        // Remove the tab object.
1230        tabs.remove(index);
1231    
1232        // Remove the component. I think we cannot assume that the tab order
1233        // is equal to the component order, so we iterate over the children
1234        // here to find the and remove the correct component.
1235        if (comp != null)
1236          {
1237            Component[] children = getComponents();
1238            for (int i = children.length - 1; i >= 0; --i)
1239              {
1240                if (children[i] == comp)
1241                  {
1242                    super.remove(i);
1243                    comp.setVisible(true);
1244                    break;
1245                  }
1246              }
1247          }
1248        revalidate();
1249        repaint();
1250      }
1251    
1252      /**
1253       * Removes the specified Component from the JTabbedPane.
1254       *
1255       * @param component The Component to remove.
1256       */
1257      public void remove(Component component)
1258      {
1259        // Since components implementing UIResource
1260        // are not added as regular tabs by the add()
1261        // methods we have to take special care when
1262        // removing these object. Especially 
1263        // Container.remove(Component) cannot be used
1264        // because it will call JTabbedPane.remove(int)
1265        // later which is overridden and can only
1266        // handle tab components.
1267        // This implementation can even cope with a
1268        // situation that someone called insertTab()
1269        // with a component that implements UIResource.
1270        int index = indexOfComponent(component);
1271        
1272        // If the component is not a tab component
1273        // find out its Container-given index
1274        // and call that class' implementation
1275        // directly.
1276        if (index == -1)
1277          {
1278            Component[] cs = getComponents();
1279            for (int i = 0; i< cs.length; i++)
1280              if (cs[i] == component)
1281                super.remove(i);
1282          }
1283        else
1284          removeTabAt(index);
1285      }
1286    
1287      /**
1288       * Removes the tab and component which corresponds to the specified index.
1289       *
1290       * @param index The index of the tab to remove.
1291       */
1292      public void remove(int index)
1293      {
1294        removeTabAt(index);
1295      }
1296    
1297      /**
1298       * This method removes all tabs and associated components from the
1299       * JTabbedPane.
1300       */
1301      public void removeAll()
1302      {
1303        setSelectedIndex(-1);
1304        for (int i = getTabCount() - 1; i >= 0; i--)
1305          removeTabAt(i);
1306      }
1307    
1308      /**
1309       * This method returns how many tabs are in the JTabbedPane.
1310       *
1311       * @return The number of tabs in the JTabbedPane.
1312       */
1313      public int getTabCount()
1314      {
1315        return tabs.size();
1316      }
1317    
1318      /**
1319       * This method returns the number of runs used  to paint the JTabbedPane.
1320       *
1321       * @return The number of runs.
1322       */
1323      public int getTabRunCount()
1324      {
1325        return ((TabbedPaneUI) ui).getTabRunCount(this);
1326      }
1327    
1328      /**
1329       * This method returns the tab title given the index.
1330       *
1331       * @param index The index of the tab.
1332       *
1333       * @return The title for the tab.
1334       */
1335      public String getTitleAt(int index)
1336      {
1337        checkIndex(index, 0, tabs.size());
1338        return ((Page) tabs.elementAt(index)).getTitle();
1339      }
1340    
1341      /**
1342       * This method returns the active icon given the index.
1343       *
1344       * @param index The index of the tab.
1345       *
1346       * @return The active icon for the tab.
1347       */
1348      public Icon getIconAt(int index)
1349      {
1350        checkIndex(index, 0, tabs.size());
1351        return ((Page) tabs.elementAt(index)).getIcon();
1352      }
1353    
1354      /**
1355       * This method returns the disabled icon given the index.
1356       *
1357       * @param index The index of the tab.
1358       *
1359       * @return The disabled icon for the tab.
1360       */
1361      public Icon getDisabledIconAt(int index)
1362      {
1363        checkIndex(index, 0, tabs.size());
1364        return ((Page) tabs.elementAt(index)).getDisabledIcon();
1365      }
1366    
1367      /**
1368       * This method returns the tooltip string for the tab.
1369       *
1370       * @param index The index of the tab.
1371       *
1372       * @return The tooltip string for the tab.
1373       */
1374      public String getToolTipTextAt(int index)
1375      {
1376        checkIndex(index, 0, tabs.size());
1377        return ((Page) tabs.elementAt(index)).getTip();
1378      }
1379    
1380      /**
1381       * This method returns the foreground color for the tab.
1382       *
1383       * @param index The index of the tab.
1384       *
1385       * @return The foreground color for the tab.
1386       */
1387      public Color getForegroundAt(int index)
1388      {
1389        checkIndex(index, 0, tabs.size());
1390        return ((Page) tabs.elementAt(index)).getForeground();
1391      }
1392    
1393      /**
1394       * This method returns the background color for the tab.
1395       *
1396       * @param index The index of the tab.
1397       *
1398       * @return The background color for the tab.
1399       */
1400      public Color getBackgroundAt(int index)
1401      {
1402        checkIndex(index, 0, tabs.size());
1403        return ((Page) tabs.elementAt(index)).getBackground();
1404      }
1405    
1406      /**
1407       * This method returns the component associated with the tab.
1408       *
1409       * @param index The index of the tab.
1410       *
1411       * @return The component associated with the tab.
1412       */
1413      public Component getComponentAt(int index)
1414      {
1415        checkIndex(index, 0, tabs.size());
1416        return ((Page) tabs.elementAt(index)).getComponent();
1417      }
1418    
1419      /**
1420       * This method returns whether this tab is enabled. Disabled tabs cannot be
1421       * selected.
1422       *
1423       * @param index The index of the tab.
1424       *
1425       * @return Whether the tab is enabled.
1426       */
1427      public boolean isEnabledAt(int index)
1428      {
1429        checkIndex(index, 0, tabs.size());
1430        return ((Page) tabs.elementAt(index)).isEnabled();
1431      }
1432    
1433      /**
1434       * This method returns the mnemonic for the tab.
1435       *
1436       * @param tabIndex The index of the tab.
1437       *
1438       * @return The mnemonic for the tab.
1439       */
1440      public int getMnemonicAt(int tabIndex)
1441      {
1442        checkIndex(tabIndex, 0, tabs.size());
1443        return ((Page) tabs.elementAt(tabIndex)).getMnemonic();
1444      }
1445    
1446      /**
1447       * This method returns the mnemonic index for the tab.
1448       *
1449       * @param tabIndex The index of the tab.
1450       *
1451       * @return The mnemonic index for the tab.
1452       */
1453      public int getDisplayedMnemonicIndexAt(int tabIndex)
1454      {
1455        checkIndex(tabIndex, 0, tabs.size());
1456        return ((Page) tabs.elementAt(tabIndex)).getDisplayedMnemonicIndex();
1457      }
1458    
1459      /**
1460       * This method returns the bounds of the tab given the index.
1461       *
1462       * @param index The index of the tab.
1463       *
1464       * @return A rectangle describing the bounds of the tab.
1465       */
1466      public Rectangle getBoundsAt(int index)
1467      {
1468        checkIndex(index, 0, tabs.size());
1469        return ((TabbedPaneUI) ui).getTabBounds(this, index);
1470      }
1471    
1472      /**
1473       * This method sets the title of the tab.
1474       *
1475       * @param index The index of the tab.
1476       * @param title The new title.
1477       */
1478      public void setTitleAt(int index, String title)
1479      {
1480        checkIndex(index, 0, tabs.size());
1481        ((Page) tabs.elementAt(index)).setTitle(title);
1482      }
1483    
1484      /**
1485       * This method sets the icon of the tab.
1486       *
1487       * @param index The index of the tab.
1488       * @param icon The new icon.
1489       */
1490      public void setIconAt(int index, Icon icon)
1491      {
1492        checkIndex(index, 0, tabs.size());
1493        ((Page) tabs.elementAt(index)).setIcon(icon);
1494      }
1495    
1496      /**
1497       * This method sets the disabled icon of the tab.
1498       *
1499       * @param index The index of the tab.
1500       * @param disabledIcon The new disabled icon.
1501       */
1502      public void setDisabledIconAt(int index, Icon disabledIcon)
1503      {
1504        checkIndex(index, 0, tabs.size());
1505        ((Page) tabs.elementAt(index)).setDisabledIcon(disabledIcon);
1506      }
1507    
1508      /**
1509       * This method sets the tooltip text of the tab.
1510       *
1511       * @param index The index of the tab.
1512       * @param toolTipText The tooltip text.
1513       */
1514      public void setToolTipTextAt(int index, String toolTipText)
1515      {
1516        checkIndex(index, 0, tabs.size());
1517        ((Page) tabs.elementAt(index)).setTip(toolTipText);
1518      }
1519    
1520      /**
1521       * This method sets the background color of the tab.
1522       *
1523       * @param index The index of the tab.
1524       * @param background The background color of the tab.
1525       */
1526      public void setBackgroundAt(int index, Color background)
1527      {
1528        checkIndex(index, 0, tabs.size());
1529        ((Page) tabs.elementAt(index)).setBackground(background);
1530      }
1531    
1532      /**
1533       * This method sets the foreground color of the tab.
1534       *
1535       * @param index The index of the tab.
1536       * @param foreground The foreground color of the tab.
1537       */
1538      public void setForegroundAt(int index, Color foreground)
1539      {
1540        checkIndex(index, 0, tabs.size());
1541        ((Page) tabs.elementAt(index)).setForeground(foreground);
1542      }
1543    
1544      /**
1545       * This method sets whether the tab is enabled.
1546       *
1547       * @param index The index of the tab.
1548       * @param enabled Whether the tab is enabled.
1549       */
1550      public void setEnabledAt(int index, boolean enabled)
1551      {
1552        checkIndex(index, 0, tabs.size());
1553        ((Page) tabs.elementAt(index)).setEnabled(enabled);
1554      }
1555    
1556      /**
1557       * This method sets the component associated with the tab.
1558       *
1559       * @param index The index of the tab.
1560       * @param component The component associated with the tab.
1561       */
1562      public void setComponentAt(int index, Component component)
1563      {
1564        checkIndex(index, 0, tabs.size());
1565        ((Page) tabs.elementAt(index)).setComponent(component);
1566      }
1567    
1568      /**
1569       * This method sets the displayed mnemonic index of the tab.
1570       *
1571       * @param tabIndex The index of the tab.
1572       * @param mnemonicIndex The mnemonic index.
1573       */
1574      public void setDisplayedMnemonicIndexAt(int tabIndex, int mnemonicIndex)
1575      {
1576        checkIndex(tabIndex, 0, tabs.size());
1577        ((Page) tabs.elementAt(tabIndex)).setDisplayedMnemonicIndex(mnemonicIndex);
1578      }
1579    
1580      /**
1581       * This method sets the mnemonic for the tab.
1582       *
1583       * @param tabIndex The index of the tab.
1584       * @param mnemonic The mnemonic.
1585       */
1586      public void setMnemonicAt(int tabIndex, int mnemonic)
1587      {
1588        checkIndex(tabIndex, 0, tabs.size());
1589        ((Page) tabs.elementAt(tabIndex)).setMnemonic(mnemonic);
1590      }
1591    
1592      /**
1593       * This method finds the index of a tab given the title.
1594       *
1595       * @param title The title that belongs to a tab.
1596       *
1597       * @return The index of the tab that has the title or -1 if not found.
1598       */
1599      public int indexOfTab(String title)
1600      {
1601        int index = -1;
1602        for (int i = 0; i < tabs.size(); i++)
1603          {
1604            if (((Page) tabs.elementAt(i)).getTitle().equals(title))
1605              {
1606                index = i;
1607                break;
1608              }
1609          }
1610        return index;
1611      }
1612    
1613      /**
1614       * This method finds the index of a tab given the icon.
1615       *
1616       * @param icon The icon that belongs to a tab.
1617       *
1618       * @return The index of the tab that has the icon or -1 if not found.
1619       */
1620      public int indexOfTab(Icon icon)
1621      {
1622        int index = -1;
1623        for (int i = 0; i < tabs.size(); i++)
1624          {
1625            if (((Page) tabs.elementAt(i)).getIcon() == icon)
1626              {
1627                index = i;
1628                break;
1629              }
1630          }
1631        return index;
1632      }
1633    
1634      /**
1635       * This method finds the index of a tab given the component.
1636       *
1637       * @param component A component associated with a tab.
1638       *
1639       * @return The index of the tab that has this component or -1 if not found.
1640       */
1641      public int indexOfComponent(Component component)
1642      {
1643        int index = -1;
1644        for (int i = 0; i < tabs.size(); i++)
1645          {
1646            if (((Page) tabs.elementAt(i)).getComponent() == component)
1647              {
1648                index = i;
1649                break;
1650              }
1651          }
1652        return index;
1653      }
1654    
1655      /**
1656       * This method returns a tab index given an (x,y) location. The origin of
1657       * the (x,y) pair will be the JTabbedPane's top left position. The  tab
1658       * returned will be the one that contains the point. This method is
1659       * delegated to the UI.
1660       *
1661       * @param x The x coordinate of the point.
1662       * @param y The y coordinate of the point.
1663       *
1664       * @return The index of the tab that contains the point.
1665       */
1666      public int indexAtLocation(int x, int y)
1667      {
1668        return ((TabbedPaneUI) ui).tabForCoordinate(this, x, y);
1669      }
1670    
1671      /**
1672       * This method returns the tooltip text given a mouse event.
1673       *
1674       * @param event The mouse event.
1675       *
1676       * @return The tool tip text that is associated with this mouse event.
1677       */
1678      public String getToolTipText(MouseEvent event)
1679      {
1680        int index = indexAtLocation(event.getX(), event.getY());
1681        return ((Page) tabs.elementAt(index)).getTip();
1682      }
1683    
1684      /**
1685       * Returns a string describing the attributes for the 
1686       * <code>JTabbedPane</code> component, for use in debugging.  The return 
1687       * value is guaranteed to be non-<code>null</code>, but the format of the 
1688       * string may vary between implementations.
1689       *
1690       * @return A string describing the attributes of the 
1691       *     <code>JTabbedPane</code>.
1692       */
1693      protected String paramString()
1694      {
1695        StringBuffer sb = new StringBuffer(super.paramString());
1696        sb.append(",tabPlacement=");
1697        if (tabPlacement == TOP)
1698          sb.append("TOP");
1699        if (tabPlacement == BOTTOM)
1700          sb.append("BOTTOM");
1701        if (tabPlacement == LEFT)
1702          sb.append("LEFT");
1703        if (tabPlacement == RIGHT)
1704          sb.append("RIGHT");
1705        return sb.toString();
1706      }
1707    
1708      /**
1709       * Returns the object that provides accessibility features for this
1710       * <code>JTabbedPane</code> component.
1711       *
1712       * @return The accessible context (an instance of 
1713       *         {@link AccessibleJTabbedPane}).
1714       */
1715      public AccessibleContext getAccessibleContext()
1716      {
1717        if (accessibleContext == null)
1718          {
1719            AccessibleJTabbedPane ctx = new AccessibleJTabbedPane();
1720            addChangeListener(ctx);
1721            accessibleContext = ctx;
1722          }
1723    
1724        return accessibleContext;
1725      }
1726    }