KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > javax > swing > JTabbedPane


1 /*
2  * @(#)JTabbedPane.java 1.140 04/04/02
3  *
4  * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
5  * SUN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
6  */

7  
8 package javax.swing;
9
10 import java.awt.*;
11 import java.awt.event.*;
12 import java.beans.*;
13 import java.util.*;
14 import javax.swing.event.*;
15 import javax.swing.plaf.*;
16 import javax.accessibility.*;
17
18 import java.io.Serializable JavaDoc;
19 import java.io.ObjectOutputStream JavaDoc;
20 import java.io.ObjectInputStream JavaDoc;
21 import java.io.IOException JavaDoc;
22
23 /**
24  * A component that lets the user switch between a group of components by
25  * clicking on a tab with a given title and/or icon.
26  * For examples and information on using tabbed panes see
27  * <a HREF="http://java.sun.com/docs/books/tutorial/uiswing/components/tabbedpane.html">How to Use Tabbed Panes</a>,
28  * a section in <em>The Java Tutorial</em>.
29  * <p>
30  * Tabs/components are added to a <code>TabbedPane</code> object by using the
31  * <code>addTab</code> and <code>insertTab</code> methods.
32  * A tab is represented by an index corresponding
33  * to the position it was added in, where the first tab has an index equal to 0
34  * and the last tab has an index equal to the tab count minus 1.
35  * <p>
36  * The <code>TabbedPane</code> uses a <code>SingleSelectionModel</code>
37  * to represent the set
38  * of tab indices and the currently selected index. If the tab count
39  * is greater than 0, then there will always be a selected index, which
40  * by default will be initialized to the first tab. If the tab count is
41  * 0, then the selected index will be -1.
42  * <p>
43  * <strong>Warning:</strong>
44  * Serialized objects of this class will not be compatible with
45  * future Swing releases. The current serialization support is
46  * appropriate for short term storage or RMI between applications running
47  * the same version of Swing. As of 1.4, support for long term storage
48  * of all JavaBeans<sup><font size="-2">TM</font></sup>
49  * has been added to the <code>java.beans</code> package.
50  * Please see {@link java.beans.XMLEncoder}.
51  *
52  * @beaninfo
53  * attribute: isContainer true
54  * description: A component which provides a tab folder metaphor for
55  * displaying one component from a set of components.
56  *
57  * @version 1.140 04/02/04
58  * @author Dave Moore
59  * @author Philip Milne
60  * @author Amy Fowler
61  *
62  * @see SingleSelectionModel
63  */

64 public class JTabbedPane extends JComponent JavaDoc
65        implements Serializable JavaDoc, Accessible, SwingConstants JavaDoc {
66
67    /**
68     * The tab layout policy for wrapping tabs in multiple runs when all
69     * tabs will not fit within a single run.
70     */

71     public static final int WRAP_TAB_LAYOUT = 0;
72
73    /**
74     * Tab layout policy for providing a subset of available tabs when all
75     * the tabs will not fit within a single run. If all the tabs do
76     * not fit within a single run the look and feel will provide a way
77     * to navigate to hidden tabs.
78     */

79     public static final int SCROLL_TAB_LAYOUT = 1;
80
81
82     /**
83      * @see #getUIClassID
84      * @see #readObject
85      */

86     private static final String JavaDoc uiClassID = "TabbedPaneUI";
87
88     /**
89      * Where the tabs are placed.
90      * @see #setTabPlacement
91      */

92     protected int tabPlacement = TOP;
93
94     private int tabLayoutPolicy;
95
96     /** The default selection model */
97     protected SingleSelectionModel JavaDoc model;
98
99     private boolean haveRegistered;
100
101     /**
102      * The <code>changeListener</code> is the listener we add to the
103      * model.
104      */

105     protected ChangeListener changeListener = null;
106
107     Vector pages;
108
109     /**
110      * Only one <code>ChangeEvent</code> is needed per <code>TabPane</code>
111      * instance since the
112      * event's only (read-only) state is the source property. The source
113      * of events generated here is always "this".
114      */

115     protected transient ChangeEvent changeEvent = null;
116
117     /**
118      * Creates an empty <code>TabbedPane</code> with a default
119      * tab placement of <code>JTabbedPane.TOP</code>.
120      * @see #addTab
121      */

122     public JTabbedPane() {
123         this(TOP, WRAP_TAB_LAYOUT);
124     }
125
126     /**
127      * Creates an empty <code>TabbedPane</code> with the specified tab placement
128      * of either: <code>JTabbedPane.TOP</code>, <code>JTabbedPane.BOTTOM</code>,
129      * <code>JTabbedPane.LEFT</code>, or <code>JTabbedPane.RIGHT</code>.
130      *
131      * @param tabPlacement the placement for the tabs relative to the content
132      * @see #addTab
133      */

134     public JTabbedPane(int tabPlacement) {
135     this(tabPlacement, WRAP_TAB_LAYOUT);
136     }
137
138     /**
139      * Creates an empty <code>TabbedPane</code> with the specified tab placement
140      * and tab layout policy. Tab placement may be either:
141      * <code>JTabbedPane.TOP</code>, <code>JTabbedPane.BOTTOM</code>,
142      * <code>JTabbedPane.LEFT</code>, or <code>JTabbedPane.RIGHT</code>.
143      * Tab layout policy may be either: <code>JTabbedPane.WRAP_TAB_LAYOUT</code>
144      * or <code>JTabbedPane.SCROLL_TAB_LAYOUT</code>.
145      *
146      * @param tabPlacement the placement for the tabs relative to the content
147      * @param tabLayoutPolicy the policy for laying out tabs when all tabs will not fit on one run
148      * @exception IllegalArgumentException if tab placement or tab layout policy are not
149      * one of the above supported values
150      * @see #addTab
151      * @since 1.4
152      */

153     public JTabbedPane(int tabPlacement, int tabLayoutPolicy) {
154         setTabPlacement(tabPlacement);
155     setTabLayoutPolicy(tabLayoutPolicy);
156         pages = new Vector(1);
157         setModel(new DefaultSingleSelectionModel JavaDoc());
158         updateUI();
159     }
160
161     /**
162      * Returns the UI object which implements the L&F for this component.
163      *
164      * @return a <code>TabbedPaneUI</code> object
165      * @see #setUI
166      */

167     public TabbedPaneUI getUI() {
168         return (TabbedPaneUI)ui;
169     }
170
171     /**
172      * Sets the UI object which implements the L&F for this component.
173      *
174      * @param ui the new UI object
175      * @see UIDefaults#getUI
176      * @beaninfo
177      * bound: true
178      * hidden: true
179      * attribute: visualUpdate true
180      * description: The UI object that implements the tabbedpane's LookAndFeel
181      */

182     public void setUI(TabbedPaneUI ui) {
183         super.setUI(ui);
184         // disabled icons are generated by LF so they should be unset here
185
for (int i = 0; i < getTabCount(); i++) {
186             Icon JavaDoc icon = ((Page)pages.elementAt(i)).disabledIcon;
187             if (icon instanceof UIResource) {
188                 setDisabledIconAt(i, null);
189             }
190         }
191     }
192
193     /**
194      * Resets the UI property to a value from the current look and feel.
195      *
196      * @see JComponent#updateUI
197      */

198     public void updateUI() {
199         setUI((TabbedPaneUI)UIManager.getUI(this));
200     }
201
202
203     /**
204      * Returns the name of the UI class that implements the
205      * L&F for this component.
206      *
207      * @return the string "TabbedPaneUI"
208      * @see JComponent#getUIClassID
209      * @see UIDefaults#getUI
210      */

211     public String JavaDoc getUIClassID() {
212         return uiClassID;
213     }
214
215
216     /**
217      * We pass <code>ModelChanged</code> events along to the listeners with
218      * the tabbedpane (instead of the model itself) as the event source.
219      */

220     protected class ModelListener implements ChangeListener, Serializable JavaDoc {
221         public void stateChanged(ChangeEvent e) {
222             fireStateChanged();
223         }
224     }
225
226     /**
227      * Subclasses that want to handle <code>ChangeEvents</code> differently
228      * can override this to return a subclass of <code>ModelListener</code> or
229      * another <code>ChangeListener</code> implementation.
230      *
231      * @see #fireStateChanged
232      */

233     protected ChangeListener createChangeListener() {
234         return new ModelListener();
235     }
236
237     /**
238      * Adds a <code>ChangeListener</code> to this tabbedpane.
239      *
240      * @param l the <code>ChangeListener</code> to add
241      * @see #fireStateChanged
242      * @see #removeChangeListener
243      */

244     public void addChangeListener(ChangeListener l) {
245         listenerList.add(ChangeListener.class, l);
246     }
247     
248     /**
249      * Removes a <code>ChangeListener</code> from this tabbedpane.
250      *
251      * @param l the <code>ChangeListener</code> to remove
252      * @see #fireStateChanged
253      * @see #addChangeListener
254      */

255     public void removeChangeListener(ChangeListener l) {
256         listenerList.remove(ChangeListener.class, l);
257     }
258         
259    /**
260      * Returns an array of all the <code>ChangeListener</code>s added
261      * to this <code>JTabbedPane</code> with <code>addChangeListener</code>.
262      *
263      * @return all of the <code>ChangeListener</code>s added or an empty
264      * array if no listeners have been added
265      * @since 1.4
266      */

267     public ChangeListener[] getChangeListeners() {
268         return (ChangeListener[])listenerList.getListeners(
269                 ChangeListener.class);
270     }
271
272     /**
273      * Sends a <code>ChangeEvent</code>, whose source is this tabbedpane,
274      * to each listener. This method method is called each time
275      * a <code>ChangeEvent</code> is received from the model.
276      *
277      * @see #addChangeListener
278      * @see EventListenerList
279      */

280     protected void fireStateChanged() {
281         // Guaranteed to return a non-null array
282
Object JavaDoc[] listeners = listenerList.getListenerList();
283         // Process the listeners last to first, notifying
284
// those that are interested in this event
285
for (int i = listeners.length-2; i>=0; i-=2) {
286             if (listeners[i]==ChangeListener.class) {
287                 // Lazily create the event:
288
if (changeEvent == null)
289                     changeEvent = new ChangeEvent(this);
290                 ((ChangeListener)listeners[i+1]).stateChanged(changeEvent);
291             }
292         }
293     }
294
295     /**
296      * Returns the model associated with this tabbedpane.
297      *
298      * @see #setModel
299      */

300     public SingleSelectionModel JavaDoc getModel() {
301         return model;
302     }
303
304     /**
305      * Sets the model to be used with this tabbedpane.
306      *
307      * @param model the model to be used
308      * @see #getModel
309      * @beaninfo
310      * bound: true
311      * description: The tabbedpane's SingleSelectionModel.
312      */

313     public void setModel(SingleSelectionModel JavaDoc model) {
314         SingleSelectionModel JavaDoc oldModel = getModel();
315
316         if (oldModel != null) {
317             oldModel.removeChangeListener(changeListener);
318             changeListener = null;
319         }
320
321         this.model = model;
322
323         if (model != null) {
324             changeListener = createChangeListener();
325             model.addChangeListener(changeListener);
326         }
327
328         firePropertyChange("model", oldModel, model);
329         repaint();
330     }
331
332     /**
333      * Returns the placement of the tabs for this tabbedpane.
334      * @see #setTabPlacement
335      */

336     public int getTabPlacement() {
337         return tabPlacement;
338     }
339
340     /**
341      * Sets the tab placement for this tabbedpane.
342      * Possible values are:<ul>
343      * <li><code>JTabbedPane.TOP</code>
344      * <li><code>JTabbedPane.BOTTOM</code>
345      * <li><code>JTabbedPane.LEFT</code>
346      * <li><code>JTabbedPane.RIGHT</code>
347      * </ul>
348      * The default value, if not set, is <code>SwingConstants.TOP</code>.
349      *
350      * @param tabPlacement the placement for the tabs relative to the content
351      * @exception IllegalArgumentException if tab placement value isn't one
352      * of the above valid values
353      *
354      * @beaninfo
355      * preferred: true
356      * bound: true
357      * attribute: visualUpdate true
358      * enum: TOP JTabbedPane.TOP
359      * LEFT JTabbedPane.LEFT
360      * BOTTOM JTabbedPane.BOTTOM
361      * RIGHT JTabbedPane.RIGHT
362      * description: The tabbedpane's tab placement.
363      *
364      */

365     public void setTabPlacement(int tabPlacement) {
366         if (tabPlacement != TOP && tabPlacement != LEFT &&
367             tabPlacement != BOTTOM && tabPlacement != RIGHT) {
368             throw new IllegalArgumentException JavaDoc("illegal tab placement: must be TOP, BOTTOM, LEFT, or RIGHT");
369         }
370         if (this.tabPlacement != tabPlacement) {
371             int oldValue = this.tabPlacement;
372             this.tabPlacement = tabPlacement;
373             firePropertyChange("tabPlacement", oldValue, tabPlacement);
374             revalidate();
375             repaint();
376         }
377     }
378
379     /**
380      * Returns the policy used by the tabbedpane to layout the tabs when all the
381      * tabs will not fit within a single run.
382      * @see #setTabLayoutPolicy
383      * @since 1.4
384      */

385     public int getTabLayoutPolicy() {
386         return tabLayoutPolicy;
387     }
388
389    /**
390      * Sets the policy which the tabbedpane will use in laying out the tabs
391      * when all the tabs will not fit within a single run.
392      * Possible values are:
393      * <ul>
394      * <li><code>JTabbedPane.WRAP_TAB_LAYOUT</code>
395      * <li><code>JTabbedPane.SCROLL_TAB_LAYOUT</code>
396      * </ul>
397      *
398      * The default value, if not set by the UI, is <code>JTabbedPane.WRAP_TAB_LAYOUT</code>.
399      * <p>
400      * Some look and feels might only support a subset of the possible
401      * layout policies, in which case the value of this property may be
402      * ignored.
403      *
404      * @param tabLayoutPolicy the policy used to layout the tabs
405      * @exception IllegalArgumentException if layoutPolicy value isn't one
406      * of the above valid values
407      * @see #getTabLayoutPolicy
408      * @since 1.4
409      *
410      * @beaninfo
411      * preferred: true
412      * bound: true
413      * attribute: visualUpdate true
414      * enum: WRAP_TAB_LAYOUT JTabbedPane.WRAP_TAB_LAYOUT
415      * SCROLL_TAB_LAYOUT JTabbedPane.SCROLL_TAB_LAYOUT
416      * description: The tabbedpane's policy for laying out the tabs
417      *
418      */

419     public void setTabLayoutPolicy(int tabLayoutPolicy) {
420         if (tabLayoutPolicy != WRAP_TAB_LAYOUT && tabLayoutPolicy != SCROLL_TAB_LAYOUT) {
421             throw new IllegalArgumentException JavaDoc("illegal tab layout policy: must be WRAP_TAB_LAYOUT or SCROLL_TAB_LAYOUT");
422         }
423         if (this.tabLayoutPolicy != tabLayoutPolicy) {
424             int oldValue = this.tabLayoutPolicy;
425             this.tabLayoutPolicy = tabLayoutPolicy;
426             firePropertyChange("tabLayoutPolicy", oldValue, tabLayoutPolicy);
427             revalidate();
428             repaint();
429         }
430     }
431
432     /**
433      * Returns the currently selected index for this tabbedpane.
434      * Returns -1 if there is no currently selected tab.
435      *
436      * @return the index of the selected tab
437      * @see #setSelectedIndex
438      */

439     public int getSelectedIndex() {
440         return model.getSelectedIndex();
441     }
442
443     /**
444      * Sets the selected index for this tabbedpane. The index must be
445      * a valid tab index or -1, which indicates that no tab should be selected
446      * (can also be used when there are no tabs in the tabbedpane). If a -1
447      * value is specified when the tabbedpane contains one or more tabs, then
448      * the results will be implementation defined.
449      *
450      * @param index the index to be selected
451      * @exception IndexOutOfBoundsException if index is out of range
452      * (index < -1 || index >= tab count)
453      *
454      * @see #getSelectedIndex
455      * @see SingleSelectionModel#setSelectedIndex
456      * @beaninfo
457      * preferred: true
458      * description: The tabbedpane's selected tab index.
459      */

460     public void setSelectedIndex(int index) {
461     if (index != -1) {
462         checkIndex(index);
463     }
464     setSelectedIndexImpl(index);
465     }
466
467
468     private void setSelectedIndexImpl(int index) {
469         int oldIndex = model.getSelectedIndex();
470         Page oldPage = null, newPage = null;
471         if ((oldIndex >= 0) && (oldIndex != index)) {
472             oldPage = (Page) pages.elementAt(oldIndex);
473         }
474         if ((index >= 0) && (oldIndex != index)) {
475             newPage = (Page) pages.elementAt(index);
476         }
477
478         model.setSelectedIndex(index);
479
480         String JavaDoc oldName = null;
481         String JavaDoc newName = null;
482
483         if (oldPage != null) {
484             oldPage.firePropertyChange(
485                 AccessibleContext.ACCESSIBLE_STATE_PROPERTY,
486                 AccessibleState.SELECTED, null);
487             // TIGER - 4840667
488
AccessibleContext ac = oldPage.getAccessibleContext();
489             if (ac != null) {
490                 oldName = ac.getAccessibleName();
491             }
492
493         }
494         if (newPage != null) {
495             newPage.firePropertyChange(
496                 AccessibleContext.ACCESSIBLE_STATE_PROPERTY,
497                 null, AccessibleState.SELECTED);
498             // TIGER - 4840667
499
AccessibleContext ac = newPage.getAccessibleContext();
500             if (ac != null) {
501                 newName = ac.getAccessibleName();
502             }
503
504         }
505
506         // TIGER - 4840667
507
if (newName != null) {
508             getAccessibleContext().firePropertyChange(
509                 AccessibleContext.ACCESSIBLE_NAME_PROPERTY, oldName, newName);
510         }
511
512     }
513
514     /**
515      * Returns the currently selected component for this tabbedpane.
516      * Returns <code>null</code> if there is no currently selected tab.
517      *
518      * @return the component corresponding to the selected tab
519      * @see #setSelectedComponent
520      */

521     public Component getSelectedComponent() {
522         int index = getSelectedIndex();
523         if (index == -1) {
524             return null;
525         }
526         return getComponentAt(index);
527     }
528
529     /**
530      * Sets the selected component for this tabbedpane. This
531      * will automatically set the <code>selectedIndex</code> to the index
532      * corresponding to the specified component.
533      *
534      * @exception IllegalArgumentException if component not found in tabbed
535      * pane
536      * @see #getSelectedComponent
537      * @beaninfo
538      * preferred: true
539      * description: The tabbedpane's selected component.
540      */

541     public void setSelectedComponent(Component c) {
542         int index = indexOfComponent(c);
543         if (index != -1) {
544             setSelectedIndex(index);
545         } else {
546             throw new IllegalArgumentException JavaDoc("component not found in tabbed pane");
547         }
548     }
549
550     /**
551      * Inserts a <code>component</code>, at <code>index</code>,
552      * represented by a <code>title</code> and/or <code>icon</code>,
553      * either of which may be <code>null</code>.
554      * Uses java.util.Vector internally, see <code>insertElementAt</code>
555      * for details of insertion conventions.
556      *
557      * @param title the title to be displayed in this tab
558      * @param icon the icon to be displayed in this tab
559      * @param component The component to be displayed when this tab is clicked.
560      * @param tip the tooltip to be displayed for this tab
561      * @param index the position to insert this new tab
562      *
563      * @see #addTab
564      * @see #removeTabAt
565      */

566     public void insertTab(String JavaDoc title, Icon JavaDoc icon, Component component, String JavaDoc tip, int index) {
567     int newIndex = index;
568
569         // If component already exists, remove corresponding
570
// tab so that new tab gets added correctly
571
// Note: we are allowing component=null because of compatibility,
572
// but we really should throw an exception because much of the
573
// rest of the JTabbedPane implementation isn't designed to deal
574
// with null components for tabs.
575
int removeIndex = indexOfComponent(component);
576         if (component != null && removeIndex != -1) {
577             removeTabAt(removeIndex);
578         if (newIndex > removeIndex) {
579         newIndex--;
580         }
581         }
582
583         int selectedIndex = getSelectedIndex();
584
585         pages.insertElementAt(new Page(this, title != null? title : "", icon, null,
586                                        component, tip), newIndex);
587
588
589         if (component != null) {
590             addImpl(component, null, -1);
591             component.setVisible(false);
592         }
593
594         if (pages.size() == 1) {
595             setSelectedIndex(0);
596         }
597
598         if (selectedIndex >= newIndex) {
599             setSelectedIndex(selectedIndex + 1);
600         }
601
602         if (!haveRegistered && tip != null) {
603             ToolTipManager.sharedInstance().registerComponent(this);
604             haveRegistered = true;
605         }
606
607         if (accessibleContext != null) {
608             accessibleContext.firePropertyChange(
609                     AccessibleContext.ACCESSIBLE_VISIBLE_DATA_PROPERTY,
610                     null, component);
611         }
612         revalidate();
613         repaint();
614     }
615
616     /**
617      * Adds a <code>component</code> and <code>tip</code>
618      * represented by a <code>title</code> and/or <code>icon</code>,
619      * either of which can be <code>null</code>.
620      * Cover method for <code>insertTab</code>.
621      *
622      * @param title the title to be displayed in this tab
623      * @param icon the icon to be displayed in this tab
624      * @param component the component to be displayed when this tab is clicked
625      * @param tip the tooltip to be displayed for this tab
626      *
627      * @see #insertTab
628      * @see #removeTabAt
629      */

630     public void addTab(String JavaDoc title, Icon JavaDoc icon, Component component, String JavaDoc tip) {
631         insertTab(title, icon, component, tip, pages.size());
632     }
633
634     /**
635      * Adds a <code>component</code> represented by a <code>title</code>
636      * and/or <code>icon</code>, either of which can be <code>null</code>.
637      * Cover method for <code>insertTab</code>.
638      *
639      * @param title the title to be displayed in this tab
640      * @param icon the icon to be displayed in this tab
641      * @param component the component to be displayed when this tab is clicked
642      *
643      * @see #insertTab
644      * @see #removeTabAt
645      */

646     public void addTab(String JavaDoc title, Icon JavaDoc icon, Component component) {
647         insertTab(title, icon, component, null, pages.size());
648     }
649
650     /**
651      * Adds a <code>component</code> represented by a <code>title</code>
652      * and no icon.
653      * Cover method for <code>insertTab</code>.
654      *
655      * @param title the title to be displayed in this tab
656      * @param component the component to be displayed when this tab is clicked
657      *
658      * @see #insertTab
659      * @see #removeTabAt
660      */

661     public void addTab(String JavaDoc title, Component component) {
662         insertTab(title, null, component, null, pages.size());
663     }
664
665     /**
666      * Adds a <code>component</code> with a tab title defaulting to
667      * the name of the component which is the result of calling
668      * <code>component.getName</code>.
669      * Cover method for <code>insertTab</code>.
670      *
671      * @param component the component to be displayed when this tab is clicked
672      * @return the component
673      *
674      * @see #insertTab
675      * @see #removeTabAt
676      */

677     public Component add(Component component) {
678     if (!(component instanceof UIResource)) {
679             addTab(component.getName(), component);
680     } else {
681         super.add(component);
682     }
683         return component;
684     }
685
686     /**
687      * Adds a <code>component</code> with the specified tab title.
688      * Cover method for <code>insertTab</code>.
689      *
690      * @param title the title to be displayed in this tab
691      * @param component the component to be displayed when this tab is clicked
692      * @return the component
693      *
694      * @see #insertTab
695      * @see #removeTabAt
696      */

697     public Component add(String JavaDoc title, Component component) {
698     if (!(component instanceof UIResource)) {
699             addTab(title, component);
700     } else {
701         super.add(title, component);
702     }
703         return component;
704     }
705
706     /**
707      * Adds a <code>component</code> at the specified tab index with a tab
708      * title defaulting to the name of the component.
709      * Cover method for <code>insertTab</code>.
710      *
711      * @param component the component to be displayed when this tab is clicked
712      * @param index the position to insert this new tab
713      * @return the component
714      *
715      * @see #insertTab
716      * @see #removeTabAt
717      */

718     public Component add(Component component, int index) {
719     if (!(component instanceof UIResource)) {
720             // Container.add() interprets -1 as "append", so convert
721
// the index appropriately to be handled by the vector
722
insertTab(component.getName(), null, component, null,
723                       index == -1? getTabCount() : index);
724     } else {
725         super.add(component, index);
726     }
727         return component;
728     }
729
730     /**
731      * Adds a <code>component</code> to the tabbed pane.
732      * If <code>constraints</code> is a <code>String</code> or an
733      * <code>Icon</code>, it will be used for the tab title,
734      * otherwise the component's name will be used as the tab title.
735      * Cover method for <code>insertTab</code>.
736      *
737      * @param component the component to be displayed when this tab is clicked
738      * @param constraints the object to be displayed in the tab
739      *
740      * @see #insertTab
741      * @see #removeTabAt
742      */

743     public void add(Component component, Object JavaDoc constraints) {
744     if (!(component instanceof UIResource)) {
745             if (constraints instanceof String JavaDoc) {
746                 addTab((String JavaDoc)constraints, component);
747             } else if (constraints instanceof Icon JavaDoc) {
748                 addTab(null, (Icon JavaDoc)constraints, component);
749             } else {
750                 add(component);
751         }
752         } else {
753         super.add(component, constraints);
754     }
755     }
756
757     /**
758      * Adds a <code>component</code> at the specified tab index.
759      * If <code>constraints</code> is a <code>String</code> or an
760      * <code>Icon</code>, it will be used for the tab title,
761      * otherwise the component's name will be used as the tab title.
762      * Cover method for <code>insertTab</code>.
763      *
764      * @param component the component to be displayed when this tab is clicked
765      * @param constraints the object to be displayed in the tab
766      * @param index the position to insert this new tab
767      *
768      * @see #insertTab
769      * @see #removeTabAt
770      */

771     public void add(Component component, Object JavaDoc constraints, int index) {
772     if (!(component instanceof UIResource)) {
773
774             Icon JavaDoc icon = constraints instanceof Icon JavaDoc? (Icon JavaDoc)constraints : null;
775             String JavaDoc title = constraints instanceof String JavaDoc? (String JavaDoc)constraints : null;
776             // Container.add() interprets -1 as "append", so convert
777
// the index appropriately to be handled by the vector
778
insertTab(title, icon, component, null, index == -1? getTabCount() : index);
779     } else {
780         super.add(component, constraints, index);
781     }
782     }
783
784     /**
785      * Removes the tab at <code>index</code>.
786      * After the component associated with <code>index</code> is removed,
787      * its visibility is reset to true to ensure it will be visible
788      * if added to other containers.
789      * @param index the index of the tab to be removed
790      * @exception IndexOutOfBoundsException if index is out of range
791      * (index < 0 || index >= tab count)
792      *
793      * @see #addTab
794      * @see #insertTab
795      */

796     public void removeTabAt(int index) {
797         checkIndex(index);
798
799         // If we are removing the currently selected tab AND
800
// it happens to be the last tab in the bunch, then
801
// select the previous tab
802
int tabCount = getTabCount();
803         int selected = getSelectedIndex();
804         if (selected >= (tabCount - 1)) {
805             setSelectedIndexImpl(selected - 1);
806         }
807
808         Component component = getComponentAt(index);
809
810         if (accessibleContext != null) {
811             accessibleContext.firePropertyChange(
812                     AccessibleContext.ACCESSIBLE_VISIBLE_DATA_PROPERTY,
813                     component, null);
814         }
815
816         pages.removeElementAt(index);
817
818         // NOTE 4/15/2002 (joutwate):
819
// This fix is implemented using client properties since there is
820
// currently no IndexPropertyChangeEvent. Once
821
// IndexPropertyChangeEvents have been added this code should be
822
// modified to use it.
823
putClientProperty("__index_to_remove__", new Integer JavaDoc(index));
824
825         // We can't assume the tab indices correspond to the
826
// container's children array indices, so make sure we
827
// remove the correct child!
828
if (component != null) {
829         Component components[] = getComponents();
830         for (int i = components.length; --i >= 0; ) {
831         if (components[i] == component) {
832                     super.remove(i);
833                     component.setVisible(true);
834                     break;
835         }
836         }
837         }
838
839         revalidate();
840         repaint();
841     }
842
843     /**
844      * Removes the specified <code>Component</code> from the
845      * <code>JTabbedPane</code>. The method does nothing
846      * if the <code>component</code> is null.
847      *
848      * @param component the component to remove from the tabbedpane
849      * @see #addTab
850      * @see #removeTabAt
851      */

852     public void remove(Component component) {
853         int index = indexOfComponent(component);
854         if (index != -1) {
855             removeTabAt(index);
856         } else {
857         // Container#remove(comp) invokes Container#remove(int)
858
// so make sure JTabbedPane#remove(int) isn't called here
859
Component children[] = getComponents();
860         for (int i=0; i < children.length; i++) {
861         if (component == children[i]) {
862             super.remove(i);
863             break;
864         }
865         }
866         }
867     }
868
869     /**
870      * Removes the tab and component which corresponds to the specified index.
871      *
872      * @param index the index of the component to remove from the
873      * <code>tabbedpane</code>
874      * @exception IndexOutOfBoundsException if index is out of range
875      * (index < 0 || index >= tab count)
876      * @see #addTab
877      * @see #removeTabAt
878      */

879     public void remove(int index) {
880         removeTabAt(index);
881     }
882
883     /**
884      * Removes all the tabs and their corresponding components
885      * from the <code>tabbedpane</code>.
886      *
887      * @see #addTab
888      * @see #removeTabAt
889      */

890     public void removeAll() {
891         setSelectedIndexImpl(-1);
892
893         int tabCount = getTabCount();
894         // We invoke removeTabAt for each tab, otherwise we may end up
895
// removing Components added by the UI.
896
while (tabCount-- > 0) {
897             removeTabAt(tabCount);
898         }
899     }
900
901     /**
902      * Returns the number of tabs in this <code>tabbedpane</code>.
903      *
904      * @return an integer specifying the number of tabbed pages
905      */

906     public int getTabCount() {
907         return pages.size();
908     }
909
910     /**
911      * Returns the number of tab runs currently used to display
912      * the tabs.
913      * @return an integer giving the number of rows if the
914      * <code>tabPlacement</code>
915      * is <code>TOP</code> or <code>BOTTOM</code>
916      * and the number of columns if
917      * <code>tabPlacement</code>
918      * is <code>LEFT</code> or <code>RIGHT</code>,
919      * or 0 if there is no UI set on this <code>tabbedpane</code>
920      */

921     public int getTabRunCount() {
922         if (ui != null) {
923             return ((TabbedPaneUI)ui).getTabRunCount(this);
924         }
925         return 0;
926     }
927
928
929 // Getters for the Pages
930

931     /**
932      * Returns the tab title at <code>index</code>.
933      *
934      * @param index the index of the item being queried
935      * @return the title at <code>index</code>
936      * @exception IndexOutOfBoundsException if index is out of range
937      * (index < 0 || index >= tab count)
938      * @see #setTitleAt
939      */

940     public String JavaDoc getTitleAt(int index) {
941         return ((Page)pages.elementAt(index)).title;
942     }
943
944     /**
945      * Returns the tab icon at <code>index</code>.
946      *
947      * @param index the index of the item being queried
948      * @return the icon at <code>index</code>
949      * @exception IndexOutOfBoundsException if index is out of range
950      * (index < 0 || index >= tab count)
951      *
952      * @see #setIconAt
953      */

954     public Icon JavaDoc getIconAt(int index) {
955         return ((Page)pages.elementAt(index)).icon;
956     }
957
958     /**
959      * Returns the tab disabled icon at <code>index</code>.
960      * If the tab disabled icon doesn't exist at <code>index</code>
961      * this will forward the call to the look and feel to construct
962      * an appropriate disabled Icon from the corresponding enabled
963      * Icon. Some look and feels might not render the disabled Icon,
964      * in which case it won't be created.
965      *
966      * @param index the index of the item being queried
967      * @return the icon at <code>index</code>
968      * @exception IndexOutOfBoundsException if index is out of range
969      * (index < 0 || index >= tab count)
970      *
971      * @see #setDisabledIconAt
972      */

973     public Icon JavaDoc getDisabledIconAt(int index) {
974         Page page = ((Page)pages.elementAt(index));
975         if (page.disabledIcon == null) {
976             page.disabledIcon = UIManager.getLookAndFeel().getDisabledIcon(this, page.icon);
977         }
978         return page.disabledIcon;
979     }
980
981     /**
982      * Returns the tab tooltip text at <code>index</code>.
983      *
984      * @param index the index of the item being queried
985      * @return a string containing the tool tip text at <code>index</code>
986      * @exception IndexOutOfBoundsException if index is out of range
987      * (index < 0 || index >= tab count)
988      *
989      * @see #setToolTipTextAt
990      */

991     public String JavaDoc getToolTipTextAt(int index) {
992         return ((Page)pages.elementAt(index)).tip;
993     }
994
995     /**
996      * Returns the tab background color at <code>index</code>.
997      *
998      * @param index the index of the item being queried
999      * @return the <code>Color</code> of the tab background at
1000     * <code>index</code>
1001     * @exception IndexOutOfBoundsException if index is out of range
1002     * (index < 0 || index >= tab count)
1003     *
1004     * @see #setBackgroundAt
1005     */

1006    public Color getBackgroundAt(int index) {
1007        return ((Page)pages.elementAt(index)).getBackground();
1008    }
1009
1010    /**
1011     * Returns the tab foreground color at <code>index</code>.
1012     *
1013     * @param index the index of the item being queried
1014     * @return the <code>Color</code> of the tab foreground at
1015     * <code>index</code>
1016     * @exception IndexOutOfBoundsException if index is out of range
1017     * (index < 0 || index >= tab count)
1018     *
1019     * @see #setForegroundAt
1020     */

1021    public Color getForegroundAt(int index) {
1022        return ((Page)pages.elementAt(index)).getForeground();
1023    }
1024
1025    /**
1026     * Returns whether or not the tab at <code>index</code> is
1027     * currently enabled.
1028     *
1029     * @param index the index of the item being queried
1030     * @return true if the tab at <code>index</code> is enabled;
1031     * false otherwise
1032     * @exception IndexOutOfBoundsException if index is out of range
1033     * (index < 0 || index >= tab count)
1034     *
1035     * @see #setEnabledAt
1036     */

1037    public boolean isEnabledAt(int index) {
1038        return ((Page)pages.elementAt(index)).isEnabled();
1039    }
1040
1041    /**
1042     * Returns the component at <code>index</code>.
1043     *
1044     * @param index the index of the item being queried
1045     * @return the <code>Component</code> at <code>index</code>
1046     * @exception IndexOutOfBoundsException if index is out of range
1047     * (index < 0 || index >= tab count)
1048     *
1049     * @see #setComponentAt
1050     */

1051    public Component getComponentAt(int index) {
1052        return ((Page)pages.elementAt(index)).component;
1053    }
1054
1055    /**
1056     * Returns the keyboard mnemonic for accessing the specified tab.
1057     * The mnemonic is the key which when combined with the look and feel's
1058     * mouseless modifier (usually Alt) will activate the specified
1059     * tab.
1060     *
1061     * @since 1.4
1062     * @param tabIndex the index of the tab that the mnemonic refers to
1063     * @return the key code which represents the mnemonic;
1064     * -1 if a mnemonic is not specified for the tab
1065     * @exception IndexOutOfBoundsException if index is out of range
1066     * (<code>tabIndex</code> &lt; 0 ||
1067     * <code>tabIndex</code> &gt;= tab count)
1068     * @see #setDisplayedMnemonicIndexAt(int,int)
1069     * @see #setMnemonicAt(int,int)
1070     */

1071    public int getMnemonicAt(int tabIndex) {
1072    checkIndex(tabIndex);
1073
1074        Page page = (Page)pages.elementAt(tabIndex);
1075    return page.getMnemonic();
1076    }
1077
1078    /**
1079     * Returns the character, as an index, that the look and feel should
1080     * provide decoration for as representing the mnemonic character.
1081     *
1082     * @since 1.4
1083     * @param tabIndex the index of the tab that the mnemonic refers to
1084     * @return index representing mnemonic character if one exists;
1085     * otherwise returns -1
1086     * @exception IndexOutOfBoundsException if index is out of range
1087     * (<code>tabIndex</code> &lt; 0 ||
1088     * <code>tabIndex</code> &gt;= tab count)
1089     * @see #setDisplayedMnemonicIndexAt(int,int)
1090     * @see #setMnemonicAt(int,int)
1091     */

1092    public int getDisplayedMnemonicIndexAt(int tabIndex) {
1093    checkIndex(tabIndex);
1094
1095        Page page = (Page)pages.elementAt(tabIndex);
1096    return page.getDisplayedMnemonicIndex();
1097    }
1098
1099    /**
1100     * Returns the tab bounds at <code>index</code>. If the tab at
1101     * this index is not currently visible in the UI, then returns
1102     * <code>null</code>.
1103     * If there is no UI set on this <code>tabbedpane</code>,
1104     * then returns <code>null</code>.
1105     *
1106     * @param index the index to be queried
1107     * @return a <code>Rectangle</code> containing the tab bounds at
1108     * <code>index</code>, or <code>null</code> if tab at
1109     * <code>index</code> is not currently visible in the UI,
1110     * or if there is no UI set on this <code>tabbedpane</code>
1111     * @exception IndexOutOfBoundsException if index is out of range
1112     * (index &lt; 0 || index &gt;= tab count)
1113     */

1114    public Rectangle getBoundsAt(int index) {
1115    checkIndex(index);
1116        if (ui != null) {
1117            return ((TabbedPaneUI)ui).getTabBounds(this, index);
1118        }
1119        return null;
1120    }
1121
1122
1123// Setters for the Pages
1124

1125    /**
1126     * Sets the title at <code>index</code> to <code>title</code> which
1127     * can be <code>null</code>.
1128     * An internal exception is raised if there is no tab at that index.
1129     *
1130     * @param index the tab index where the title should be set
1131     * @param title the title to be displayed in the tab
1132     * @exception IndexOutOfBoundsException if index is out of range
1133     * (index &lt; 0 || index &gt;= tab count)
1134     *
1135     * @see #getTitleAt
1136     * @beaninfo
1137     * preferred: true
1138     * attribute: visualUpdate true
1139     * description: The title at the specified tab index.
1140     */

1141    public void setTitleAt(int index, String JavaDoc title) {
1142        Page page = (Page)pages.elementAt(index);
1143        String JavaDoc oldTitle =page.title;
1144        page.title = title;
1145        
1146    if (oldTitle != title) {
1147        firePropertyChange("indexForTitle", -1, index);
1148    }
1149        page.updateDisplayedMnemonicIndex();
1150        if ((oldTitle != title) && (accessibleContext != null)) {
1151            accessibleContext.firePropertyChange(
1152                    AccessibleContext.ACCESSIBLE_VISIBLE_DATA_PROPERTY,
1153                    oldTitle, title);
1154        }
1155        if (title == null || oldTitle == null ||
1156            !title.equals(oldTitle)) {
1157            revalidate();
1158            repaint();
1159        }
1160    }
1161
1162    /**
1163     * Sets the icon at <code>index</code> to <code>icon</code> which can be
1164     * <code>null</code>. This does not set disabled icon at <code>icon</code>.
1165     * If the new Icon is different than the current Icon and disabled icon
1166     * is not explicitly set, the LookAndFeel will be asked to generate a disabled
1167     * Icon. To explicitly set disabled icon, use <code>setDisableIconAt()</code>.
1168     * An internal exception is raised if there is no tab at that index.
1169     *
1170     * @param index the tab index where the icon should be set
1171     * @param icon the icon to be displayed in the tab
1172     * @exception IndexOutOfBoundsException if index is out of range
1173     * (index < 0 || index >= tab count)
1174     *
1175     * @see #setDisabledIconAt
1176     * @see #getIconAt
1177     * @see #getDisabledIconAt
1178     * @beaninfo
1179     * preferred: true
1180     * attribute: visualUpdate true
1181     * description: The icon at the specified tab index.
1182     */

1183    public void setIconAt(int index, Icon JavaDoc icon) {
1184        Page page = (Page)pages.elementAt(index);
1185        Icon JavaDoc oldIcon = page.icon;
1186        if (icon != oldIcon) {
1187            page.icon = icon;
1188    
1189            /* If the default icon has really changed and we had
1190             * generated the disabled icon for this page, then
1191             * clear the disabledIcon field of the page.
1192             */

1193            if (page.disabledIcon instanceof UIResource) {
1194                page.disabledIcon = null;
1195            }
1196    
1197            // Fire the accessibility Visible data change
1198
if (accessibleContext != null) {
1199                accessibleContext.firePropertyChange(
1200                        AccessibleContext.ACCESSIBLE_VISIBLE_DATA_PROPERTY,
1201                        oldIcon, icon);
1202            }
1203            revalidate();
1204            repaint();
1205        }
1206    }
1207
1208    /**
1209     * Sets the disabled icon at <code>index</code> to <code>icon</code>
1210     * which can be <code>null</code>.
1211     * An internal exception is raised if there is no tab at that index.
1212     *
1213     * @param index the tab index where the disabled icon should be set
1214     * @param disabledIcon the icon to be displayed in the tab when disabled
1215     * @exception IndexOutOfBoundsException if index is out of range
1216     * (index &lt; 0 || index &gt;= tab count)
1217     *
1218     * @see #getDisabledIconAt
1219     * @beaninfo
1220     * preferred: true
1221     * attribute: visualUpdate true
1222     * description: The disabled icon at the specified tab index.
1223     */

1224    public void setDisabledIconAt(int index, Icon JavaDoc disabledIcon) {
1225        Icon JavaDoc oldIcon = ((Page)pages.elementAt(index)).disabledIcon;
1226        ((Page)pages.elementAt(index)).disabledIcon = disabledIcon;
1227        if (disabledIcon != oldIcon && !isEnabledAt(index)) {
1228            revalidate();
1229            repaint();
1230        }
1231    }
1232
1233    /**
1234     * Sets the tooltip text at <code>index</code> to <code>toolTipText</code>
1235     * which can be <code>null</code>.
1236     * An internal exception is raised if there is no tab at that index.
1237     *
1238     * @param index the tab index where the tooltip text should be set
1239     * @param toolTipText the tooltip text to be displayed for the tab
1240     * @exception IndexOutOfBoundsException if index is out of range
1241     * (index &lt; 0 || index &gt;= tab count)
1242     *
1243     * @see #getToolTipTextAt
1244     * @beaninfo
1245     * preferred: true
1246     * description: The tooltip text at the specified tab index.
1247     */

1248    public void setToolTipTextAt(int index, String JavaDoc toolTipText) {
1249        String JavaDoc oldToolTipText =((Page)pages.elementAt(index)).tip;
1250        ((Page)pages.elementAt(index)).tip = toolTipText;
1251
1252        if ((oldToolTipText != toolTipText) && (accessibleContext != null)) {
1253            accessibleContext.firePropertyChange(
1254                    AccessibleContext.ACCESSIBLE_VISIBLE_DATA_PROPERTY,
1255                    oldToolTipText, toolTipText);
1256        }
1257        if (!haveRegistered && toolTipText != null) {
1258            ToolTipManager.sharedInstance().registerComponent(this);
1259            haveRegistered = true;
1260        }
1261    }
1262
1263    /**
1264     * Sets the background color at <code>index</code> to
1265     * <code>background</code>
1266     * which can be <code>null</code>, in which case the tab's background color
1267     * will default to the background color of the <code>tabbedpane</code>.
1268     * An internal exception is raised if there is no tab at that index.
1269     * @param index the tab index where the background should be set
1270     * @param background the color to be displayed in the tab's background
1271     * @exception IndexOutOfBoundsException if index is out of range
1272     * (index &lt; 0 || index &gt;= tab count)
1273     *
1274     * @see #getBackgroundAt
1275     * @beaninfo
1276     * preferred: true
1277     * attribute: visualUpdate true
1278     * description: The background color at the specified tab index.
1279     */

1280    public void setBackgroundAt(int index, Color background) {
1281        Color oldBg = ((Page)pages.elementAt(index)).background;
1282        ((Page)pages.elementAt(index)).setBackground(background);
1283        if (background == null || oldBg == null ||
1284            !background.equals(oldBg)) {
1285            Rectangle tabBounds = getBoundsAt(index);
1286            if (tabBounds != null) {
1287                repaint(tabBounds);
1288            }
1289        }
1290    }
1291
1292    /**
1293     * Sets the foreground color at <code>index</code> to
1294     * <code>foreground</code> which can be
1295     * <code>null</code>, in which case the tab's foreground color
1296     * will default to the foreground color of this <code>tabbedpane</code>.
1297     * An internal exception is raised if there is no tab at that index.
1298     *
1299     * @param index the tab index where the foreground should be set
1300     * @param foreground the color to be displayed as the tab's foreground
1301     * @exception IndexOutOfBoundsException if index is out of range
1302     * (index &lt; 0 || index &gt;= tab count)
1303     *
1304     * @see #getForegroundAt
1305     * @beaninfo
1306     * preferred: true
1307     * attribute: visualUpdate true
1308     * description: The foreground color at the specified tab index.
1309     */

1310    public void setForegroundAt(int index, Color foreground) {
1311        Color oldFg = ((Page)pages.elementAt(index)).foreground;
1312        ((Page)pages.elementAt(index)).setForeground(foreground);
1313        if (foreground == null || oldFg == null ||
1314            !foreground.equals(oldFg)) {
1315            Rectangle tabBounds = getBoundsAt(index);
1316            if (tabBounds != null) {
1317                repaint(tabBounds);
1318            }
1319        }
1320    }
1321
1322    /**
1323     * Sets whether or not the tab at <code>index</code> is enabled.
1324     * An internal exception is raised if there is no tab at that index.
1325     *
1326     * @param index the tab index which should be enabled/disabled
1327     * @param enabled whether or not the tab should be enabled
1328     * @exception IndexOutOfBoundsException if index is out of range
1329     * (index &lt; 0 || index &gt;= tab count)
1330     *
1331     * @see #isEnabledAt
1332     */

1333    public void setEnabledAt(int index, boolean enabled) {
1334        boolean oldEnabled = ((Page)pages.elementAt(index)).isEnabled();
1335        ((Page)pages.elementAt(index)).setEnabled(enabled);
1336        if (enabled != oldEnabled) {
1337            revalidate();
1338            repaint();
1339        }
1340    }
1341
1342    /**
1343     * Sets the component at <code>index</code> to <code>component</code>.
1344     * An internal exception is raised if there is no tab at that index.
1345     *
1346     * @param index the tab index where this component is being placed
1347     * @param component the component for the tab
1348     * @exception IndexOutOfBoundsException if index is out of range
1349     * (index &lt; 0 || index &gt;= tab count)
1350     *
1351     * @see #getComponentAt
1352     * @beaninfo
1353     * attribute: visualUpdate true
1354     * description: The component at the specified tab index.
1355     */

1356    public void setComponentAt(int index, Component component) {
1357        Page page = (Page)pages.elementAt(index);
1358        if (component != page.component) {
1359            if (page.component != null) {
1360                // REMIND(aim): this is really silly;
1361
// why not if (page.component.getParent() == this) remove(component)
1362
synchronized(getTreeLock()) {
1363                    int count = getComponentCount();
1364                    Component children[] = getComponents();
1365                    for (int i = 0; i < count; i++) {
1366                        if (children[i] == page.component) {
1367                            super.remove(i);
1368                        }
1369                    }
1370                }
1371            }
1372            page.component = component;
1373            component.setVisible(getSelectedIndex() == index);
1374            addImpl(component, null, -1);
1375            
1376            revalidate();
1377        }
1378    }
1379
1380    /**
1381     * Provides a hint to the look and feel as to which character in the
1382     * text should be decorated to represent the mnemonic. Not all look and
1383     * feels may support this. A value of -1 indicates either there is
1384     * no mnemonic for this tab, or you do not wish the mnemonic to be
1385     * displayed for this tab.
1386     * <p>
1387     * The value of this is updated as the properties relating to the
1388     * mnemonic change (such as the mnemonic itself, the text...).
1389     * You should only ever have to call this if
1390     * you do not wish the default character to be underlined. For example, if
1391     * the text at tab index 3 was 'Apple Price', with a mnemonic of 'p',
1392     * and you wanted the 'P'
1393     * to be decorated, as 'Apple <u>P</u>rice', you would have to invoke
1394     * <code>setDisplayedMnemonicIndex(3, 6)</code> after invoking
1395     * <code>setMnemonicAt(3, KeyEvent.VK_P)</code>.
1396     * <p>Note that it is the programmer's responsibility to ensure
1397     * that each tab has a unique mnemonic or unpredictable results may
1398     * occur.
1399     *
1400     * @since 1.4
1401     * @param tabIndex the index of the tab that the mnemonic refers to
1402     * @param mnemonicIndex index into the <code>String</code> to underline
1403     * @exception IndexOutOfBoundsException if <code>tabIndex</code> is
1404     * out of range (<code>tabIndex < 0 || tabIndex >= tab
1405     * count</code>)
1406     * @exception IllegalArgumentException will be thrown if
1407     * <code>mnemonicIndex</code> is &gt;= length of the tab
1408     * title , or &lt; -1
1409     * @see #setMnemonicAt(int,int)
1410     * @see #getDisplayedMnemonicIndexAt(int)
1411     *
1412     * @beaninfo
1413     * bound: true
1414     * attribute: visualUpdate true
1415     * description: the index into the String to draw the keyboard character
1416     * mnemonic at
1417     */

1418    public void setDisplayedMnemonicIndexAt(int tabIndex, int mnemonicIndex) {
1419    checkIndex(tabIndex);
1420
1421        Page page = (Page)pages.elementAt(tabIndex);
1422
1423        page.setDisplayedMnemonicIndex(mnemonicIndex);
1424    }
1425
1426    /**
1427     * Sets the keyboard mnemonic for accessing the specified tab.
1428     * The mnemonic is the key which when combined with the look and feel's
1429     * mouseless modifier (usually Alt) will activate the specified
1430     * tab.
1431     * <p>
1432     * A mnemonic must correspond to a single key on the keyboard
1433     * and should be specified using one of the <code>VK_XXX</code>
1434     * keycodes defined in <code>java.awt.event.KeyEvent</code>.
1435     * Mnemonics are case-insensitive, therefore a key event
1436     * with the corresponding keycode would cause the button to be
1437     * activated whether or not the Shift modifier was pressed.
1438     * <p>
1439     * This will update the displayed mnemonic property for the specified
1440     * tab.
1441     *
1442     * @since 1.4
1443     * @param tabIndex the index of the tab that the mnemonic refers to
1444     * @param mnemonic the key code which represents the mnemonic
1445     * @exception IndexOutOfBoundsException if <code>tabIndex</code> is out
1446     * of range (<code>tabIndex < 0 || tabIndex >= tab count</code>)
1447     * @see #getMnemonicAt(int)
1448     * @see #setDisplayedMnemonicIndexAt(int,int)
1449     *
1450     * @beaninfo
1451     * bound: true
1452     * attribute: visualUpdate true
1453     * description: The keyboard mnenmonic, as a KeyEvent VK constant,
1454     * for the specified tab
1455     */

1456    public void setMnemonicAt(int tabIndex, int mnemonic) {
1457    checkIndex(tabIndex);
1458
1459        Page page = (Page)pages.elementAt(tabIndex);
1460    page.setMnemonic(mnemonic);
1461
1462        firePropertyChange("mnemonicAt", null, null);
1463    }
1464
1465// end of Page setters
1466

1467    /**
1468     * Returns the first tab index with a given <code>title</code>, or
1469     * -1 if no tab has this title.
1470     *
1471     * @param title the title for the tab
1472     * @return the first tab index which matches <code>title</code>, or
1473     * -1 if no tab has this title
1474     */

1475    public int indexOfTab(String JavaDoc title) {
1476        for(int i = 0; i < getTabCount(); i++) {
1477            if (getTitleAt(i).equals(title == null? "" : title)) {
1478                return i;
1479            }
1480        }
1481        return -1;
1482    }
1483
1484    /**
1485     * Returns the first tab index with a given <code>icon</code>,
1486     * or -1 if no tab has this icon.
1487     *
1488     * @param icon the icon for the tab
1489     * @return the first tab index which matches <code>icon</code>,
1490     * or -1 if no tab has this icon
1491     */

1492    public int indexOfTab(Icon JavaDoc icon) {
1493        for(int i = 0; i < getTabCount(); i++) {
1494            Icon JavaDoc tabIcon = getIconAt(i);
1495            if ((tabIcon != null && tabIcon.equals(icon)) ||
1496                (tabIcon == null && tabIcon == icon)) {
1497                return i;
1498            }
1499        }
1500        return -1;
1501    }
1502
1503    /**
1504     * Returns the index of the tab for the specified component.
1505     * Returns -1 if there is no tab for this component.
1506     *
1507     * @param component the component for the tab
1508     * @return the first tab which matches this component, or -1
1509     * if there is no tab for this component
1510     */

1511    public int indexOfComponent(Component component) {
1512        for(int i = 0; i < getTabCount(); i++) {
1513            Component c = getComponentAt(i);
1514            if ((c != null && c.equals(component)) ||
1515                (c == null && c == component)) {
1516                return i;
1517            }
1518        }
1519        return -1;
1520    }
1521
1522    /**
1523     * Returns the tab index corresponding to the tab whose bounds
1524     * intersect the specified location. Returns -1 if no tab
1525     * intersects the location.
1526     *
1527     * @param x the x location relative to this tabbedpane
1528     * @param y the y location relative to this tabbedpane
1529     * @return the tab index which intersects the location, or
1530     * -1 if no tab intersects the location
1531     * @since 1.4
1532     */

1533    public int indexAtLocation(int x, int y) {
1534        if (ui != null) {
1535            return ((TabbedPaneUI)ui).tabForCoordinate(this, x, y);
1536        }
1537        return -1;
1538    }
1539 
1540
1541    /**
1542     * Returns the tooltip text for the component determined by the
1543     * mouse event location.
1544     *
1545     * @param event the <code>MouseEvent</code> that tells where the
1546     * cursor is lingering
1547     * @return the <code>String</code> containing the tooltip text
1548     */

1549    public String JavaDoc getToolTipText(MouseEvent event) {
1550        if (ui != null) {
1551            int index = ((TabbedPaneUI)ui).tabForCoordinate(this, event.getX(), event.getY());
1552
1553            if (index != -1) {
1554                return ((Page)pages.elementAt(index)).tip;
1555            }
1556        }
1557        return super.getToolTipText(event);
1558    }
1559
1560    private void checkIndex(int index) {
1561    if (index < 0 || index >= pages.size()) {
1562        throw new IndexOutOfBoundsException JavaDoc("Index: "+index+", Tab count: "+pages.size());
1563    }
1564    }
1565
1566
1567    /**
1568     * See <code>readObject</code> and <code>writeObject</code> in
1569     * <code>JComponent</code> for more
1570     * information about serialization in Swing.
1571     */

1572    private void writeObject(ObjectOutputStream JavaDoc s) throws IOException JavaDoc {
1573        s.defaultWriteObject();
1574        if (getUIClassID().equals(uiClassID)) {
1575            byte count = JComponent.getWriteObjCounter(this);
1576            JComponent.setWriteObjCounter(this, --count);
1577            if (count == 0 && ui != null) {
1578                ui.installUI(this);
1579            }
1580        }
1581    }
1582
1583    /* Called from the <code>JComponent</code>'s
1584     * <code>EnableSerializationFocusListener</code> to
1585     * do any Swing-specific pre-serialization configuration.
1586     */

1587    void compWriteObjectNotify() {
1588        super.compWriteObjectNotify();
1589        // If ToolTipText != null, then the tooltip has already been
1590
// unregistered by JComponent.compWriteObjectNotify()
1591
if (getToolTipText() == null && haveRegistered) {
1592            ToolTipManager.sharedInstance().unregisterComponent(this);
1593        }
1594    }
1595
1596    /**
1597     * See <code>readObject</code> and <code>writeObject</code> in
1598     * <code>JComponent</code> for more
1599     * information about serialization in Swing.
1600     */

1601    private void readObject(ObjectInputStream JavaDoc s)
1602        throws IOException JavaDoc, ClassNotFoundException JavaDoc
1603    {
1604        s.defaultReadObject();
1605    if ((ui != null) && (getUIClassID().equals(uiClassID))) {
1606        ui.installUI(this);
1607    }
1608        // If ToolTipText != null, then the tooltip has already been
1609
// registered by JComponent.readObject()
1610
if (getToolTipText() == null && haveRegistered) {
1611            ToolTipManager.sharedInstance().registerComponent(this);
1612        }
1613    }
1614
1615
1616    /**
1617     * Returns a string representation of this <code>JTabbedPane</code>.
1618     * This method
1619     * is intended to be used only for debugging purposes, and the
1620     * content and format of the returned string may vary between
1621     * implementations. The returned string may be empty but may not
1622     * be <code>null</code>.
1623     *
1624     * @return a string representation of this JTabbedPane.
1625     */

1626    protected String JavaDoc paramString() {
1627        String JavaDoc tabPlacementString;
1628        if (tabPlacement == TOP) {
1629            tabPlacementString = "TOP";
1630        } else if (tabPlacement == BOTTOM) {
1631            tabPlacementString = "BOTTOM";
1632        } else if (tabPlacement == LEFT) {
1633            tabPlacementString = "LEFT";
1634        } else if (tabPlacement == RIGHT) {
1635            tabPlacementString = "RIGHT";
1636        } else tabPlacementString = "";
1637        String JavaDoc haveRegisteredString = (haveRegistered ?
1638                       "true" : "false");
1639
1640    return super.paramString() +
1641        ",haveRegistered=" + haveRegisteredString +
1642        ",tabPlacement=" + tabPlacementString;
1643    }
1644
1645/////////////////
1646
// Accessibility support
1647
////////////////
1648

1649    /**
1650     * Gets the AccessibleContext associated with this JTabbedPane.
1651     * For tabbed panes, the AccessibleContext takes the form of an
1652     * AccessibleJTabbedPane.
1653     * A new AccessibleJTabbedPane instance is created if necessary.
1654     *
1655     * @return an AccessibleJTabbedPane that serves as the
1656     * AccessibleContext of this JTabbedPane
1657     */

1658    public AccessibleContext getAccessibleContext() {
1659        if (accessibleContext == null) {
1660            accessibleContext = new AccessibleJTabbedPane();
1661        }
1662        return accessibleContext;
1663    }
1664
1665    /**
1666     * This class implements accessibility support for the
1667     * <code>JTabbedPane</code> class. It provides an implementation of the
1668     * Java Accessibility API appropriate to tabbed pane user-interface
1669     * elements.
1670     * <p>
1671     * <strong>Warning:</strong>
1672     * Serialized objects of this class will not be compatible with
1673     * future Swing releases. The current serialization support is
1674     * appropriate for short term storage or RMI between applications running
1675     * the same version of Swing. As of 1.4, support for long term storage
1676     * of all JavaBeans<sup><font size="-2">TM</font></sup>
1677     * has been added to the <code>java.beans</code> package.
1678     * Please see {@link java.beans.XMLEncoder}.
1679     */

1680    protected class AccessibleJTabbedPane extends AccessibleJComponent
1681        implements AccessibleSelection, ChangeListener {
1682
1683        /**
1684         * Constructs an AccessibleJTabbedPane
1685         */

1686        public AccessibleJTabbedPane() {
1687            super();
1688            JTabbedPane.this.model.addChangeListener(this);
1689        }
1690
1691        public void stateChanged(ChangeEvent e) {
1692            Object JavaDoc o = e.getSource();
1693            firePropertyChange(AccessibleContext.ACCESSIBLE_SELECTION_PROPERTY,
1694                               null, o);
1695        }
1696
1697        /**
1698         * Get the role of this object.
1699         *
1700         * @return an instance of AccessibleRole describing the role of
1701         * the object
1702         */

1703        public AccessibleRole getAccessibleRole() {
1704            return AccessibleRole.PAGE_TAB_LIST;
1705        }
1706
1707        /**
1708         * Returns the number of accessible children in the object.
1709         *
1710         * @return the number of accessible children in the object.
1711         */

1712        public int getAccessibleChildrenCount() {
1713            return getTabCount();
1714        }
1715
1716        /**
1717         * Return the specified Accessible child of the object.
1718         *
1719         * @param i zero-based index of child
1720         * @return the Accessible child of the object
1721         * @exception IllegalArgumentException if index is out of bounds
1722         */

1723        public Accessible getAccessibleChild(int i) {
1724            if (i < 0 || i >= getTabCount()) {
1725                return null;
1726            }
1727            return (Accessible) pages.elementAt(i);
1728        }
1729
1730        /**
1731         * Gets the <code>AccessibleSelection</code> associated with
1732         * this object. In the implementation of the Java
1733         * Accessibility API for this class,
1734     * returns this object, which is responsible for implementing the
1735         * <code>AccessibleSelection</code> interface on behalf of itself.
1736     *
1737     * @return this object
1738         */

1739        public AccessibleSelection getAccessibleSelection() {
1740           return this;
1741        }
1742
1743        /**
1744         * Returns the <code>Accessible</code> child contained at
1745         * the local coordinate <code>Point</code>, if one exists.
1746         * Otherwise returns the currently selected tab.
1747         *
1748         * @return the <code>Accessible</code> at the specified
1749         * location, if it exists
1750         */

1751        public Accessible getAccessibleAt(Point p) {
1752            int tab = ((TabbedPaneUI) ui).tabForCoordinate(JTabbedPane.this,
1753                                                           p.x, p.y);
1754            if (tab == -1) {
1755                tab = getSelectedIndex();
1756            }
1757            return getAccessibleChild(tab);
1758        }
1759
1760        public int getAccessibleSelectionCount() {
1761            return 1;
1762        }
1763
1764        public Accessible getAccessibleSelection(int i) {
1765            int index = getSelectedIndex();
1766            if (index == -1) {
1767                return null;
1768            }
1769            return (Accessible) pages.elementAt(index);
1770        }
1771
1772        public boolean isAccessibleChildSelected(int i) {
1773            return (i == getSelectedIndex());
1774        }
1775
1776        public void addAccessibleSelection(int i) {
1777           setSelectedIndex(i);
1778        }
1779
1780        public void removeAccessibleSelection(int i) {
1781           // can't do
1782
}
1783
1784        public void clearAccessibleSelection() {
1785           // can't do
1786
}
1787
1788        public void selectAllAccessibleSelection() {
1789           // can't do
1790
}
1791    }
1792
1793    private class Page extends AccessibleContext
1794        implements Serializable JavaDoc, Accessible, AccessibleComponent {
1795        String JavaDoc title;
1796        Color background;
1797        Color foreground;
1798        Icon JavaDoc icon;
1799        Icon JavaDoc disabledIcon;
1800        JTabbedPane JavaDoc parent;
1801        Component component;
1802        String JavaDoc tip;
1803        boolean enabled = true;
1804        boolean needsUIUpdate;
1805        int mnemonic = -1;
1806        int mnemonicIndex = -1;
1807
1808        Page(JTabbedPane JavaDoc parent,
1809             String JavaDoc title, Icon JavaDoc icon, Icon JavaDoc disabledIcon, Component component, String JavaDoc tip) {
1810            this.title = title;
1811            this.icon = icon;
1812            this.disabledIcon = disabledIcon;
1813            this.parent = parent;
1814            this.setAccessibleParent(parent);
1815            this.component = component;
1816            this.tip = tip;
1817            if (component instanceof Accessible) {
1818                AccessibleContext ac;
1819                ac = ((Accessible) component).getAccessibleContext();
1820                if (ac != null) {
1821                    ac.setAccessibleParent(this);
1822                }
1823            }
1824        }
1825
1826        void setMnemonic(int mnemonic) {
1827            this.mnemonic = mnemonic;
1828            updateDisplayedMnemonicIndex();
1829        }
1830
1831        int getMnemonic() {
1832            return mnemonic;
1833        }
1834
1835    /*
1836     * Sets the page displayed mnemonic index
1837     */

1838    void setDisplayedMnemonicIndex(int mnemonicIndex) {
1839            if (this.mnemonicIndex != mnemonicIndex) {
1840                if (mnemonicIndex != -1 && (title == null ||
1841                        mnemonicIndex < 0 ||
1842                        mnemonicIndex >= title.length())) {
1843                    throw new IllegalArgumentException JavaDoc(
1844                                "Invalid mnemonic index: " + mnemonicIndex);
1845                }
1846                this.mnemonicIndex = mnemonicIndex;
1847                JTabbedPane.this.firePropertyChange("displayedMnemonicIndexAt",
1848                                                    null, null);
1849            }
1850    }
1851 
1852    /*
1853     * Returns the page displayed mnemonic index
1854     */

1855    int getDisplayedMnemonicIndex() {
1856        return this.mnemonicIndex;
1857    }
1858  
1859        void updateDisplayedMnemonicIndex() {
1860            setDisplayedMnemonicIndex(
1861                SwingUtilities.findDisplayedMnemonicIndex(title, mnemonic));
1862        }
1863
1864        /////////////////
1865
// Accessibility support
1866
////////////////
1867

1868        public AccessibleContext getAccessibleContext() {
1869            return this;
1870        }
1871
1872
1873        // AccessibleContext methods
1874

1875        public String JavaDoc getAccessibleName() {
1876            if (accessibleName != null) {
1877                return accessibleName;
1878            } else if (title != null) {
1879                return title;
1880            }
1881            return null;
1882        }
1883
1884        public String JavaDoc getAccessibleDescription() {
1885            if (accessibleDescription != null) {
1886                return accessibleDescription;
1887            } else if (tip != null) {
1888                return tip;
1889            }
1890            return null;
1891        }
1892
1893        public AccessibleRole getAccessibleRole() {
1894            return AccessibleRole.PAGE_TAB;
1895        }
1896
1897        public AccessibleStateSet getAccessibleStateSet() {
1898            AccessibleStateSet states;
1899            states = parent.getAccessibleContext().getAccessibleStateSet();
1900            states.add(AccessibleState.SELECTABLE);
1901            int i = parent.indexOfTab(title);
1902            if (i == parent.getSelectedIndex()) {
1903                states.add(AccessibleState.SELECTED);
1904            }
1905            return states;
1906        }
1907
1908        public int getAccessibleIndexInParent() {
1909            return parent.indexOfTab(title);
1910        }
1911
1912        public int getAccessibleChildrenCount() {
1913            if (component instanceof Accessible) {
1914                return 1;
1915            } else {
1916                return 0;
1917            }
1918        }
1919
1920        public Accessible getAccessibleChild(int i) {
1921            if (component instanceof Accessible) {
1922                return (Accessible) component;
1923            } else {
1924                return null;
1925            }
1926        }
1927
1928        public Locale getLocale() {
1929            return parent.getLocale();
1930        }
1931
1932        public AccessibleComponent getAccessibleComponent() {
1933            return this;
1934        }
1935
1936
1937        // AccessibleComponent methods
1938

1939        public Color getBackground() {
1940            return background != null? background : parent.getBackground();
1941        }
1942
1943        public void setBackground(Color c) {
1944            background = c;
1945        }
1946
1947        public Color getForeground() {
1948            return foreground != null? foreground : parent.getForeground();
1949        }
1950
1951        public void setForeground(Color c) {
1952            foreground = c;
1953        }
1954
1955        public Cursor getCursor() {
1956            return parent.getCursor();
1957        }
1958
1959        public void setCursor(Cursor c) {
1960            parent.setCursor(c);
1961        }
1962
1963        public Font getFont() {
1964            return parent.getFont();
1965        }
1966
1967        public void setFont(Font f) {
1968            parent.setFont(f);
1969        }
1970
1971        public FontMetrics getFontMetrics(Font f) {
1972            return parent.getFontMetrics(f);
1973        }
1974
1975        public boolean isEnabled() {
1976            return enabled;
1977        }
1978
1979        public void setEnabled(boolean b) {
1980            enabled = b;
1981        }
1982
1983        public boolean isVisible() {
1984            return parent.isVisible();
1985        }
1986
1987        public void setVisible(boolean b) {
1988            parent.setVisible(b);
1989        }
1990
1991        public boolean isShowing() {
1992            return parent.isShowing();
1993        }
1994
1995        public boolean contains(Point p) {
1996            Rectangle r = getBounds();
1997            return r.contains(p);
1998        }
1999
2000        public Point getLocationOnScreen() {
2001             Point parentLocation = parent.getLocationOnScreen();
2002             Point componentLocation = getLocation();
2003             componentLocation.translate(parentLocation.x, parentLocation.y);
2004             return componentLocation;
2005        }
2006    
2007        public Point getLocation() {
2008             Rectangle r = getBounds();
2009             return new Point(r.x, r.y);
2010        }
2011    
2012        public void setLocation(Point p) {
2013            // do nothing
2014
}
2015
2016        public Rectangle getBounds() {
2017            return parent.getUI().getTabBounds(parent,
2018                                               parent.indexOfTab(title));
2019        }
2020
2021        public void setBounds(Rectangle r) {
2022            // do nothing
2023
}
2024
2025        public Dimension getSize() {
2026            Rectangle r = getBounds();
2027            return new Dimension(r.width, r.height);
2028        }
2029
2030        public void setSize(Dimension d) {
2031            // do nothing
2032
}
2033
2034        public Accessible getAccessibleAt(Point p) {
2035            if (component instanceof Accessible) {
2036                return (Accessible) component;
2037            } else {
2038                return null;
2039            }
2040        }
2041
2042        public boolean isFocusTraversable() {
2043            return false;
2044        }
2045
2046        public void requestFocus() {
2047            // do nothing
2048
}
2049
2050        public void addFocusListener(FocusListener l) {
2051            // do nothing
2052
}
2053
2054        public void removeFocusListener(FocusListener l) {
2055            // do nothing
2056
}
2057
2058    // TIGER - 4732339
2059
/**
2060     * Returns an AccessibleIcon
2061     *
2062     * @return the enabled icon if one exists and the page
2063     * is enabled. Otherwise, returns the disabled icon if
2064     * one exists and the page is disabled. Otherwise, null
2065     * is returned.
2066     */

2067    public AccessibleIcon [] getAccessibleIcon() {
2068        AccessibleIcon accessibleIcon = null;
2069        if (enabled && icon instanceof ImageIcon JavaDoc) {
2070        AccessibleContext ac =
2071            ((ImageIcon JavaDoc)icon).getAccessibleContext();
2072        accessibleIcon = (AccessibleIcon)ac;
2073        } else if (!enabled && disabledIcon instanceof ImageIcon JavaDoc) {
2074        AccessibleContext ac =
2075            ((ImageIcon JavaDoc)disabledIcon).getAccessibleContext();
2076        accessibleIcon = (AccessibleIcon)ac;
2077        }
2078        if (accessibleIcon != null) {
2079        AccessibleIcon [] returnIcons = new AccessibleIcon[1];
2080        returnIcons[0] = accessibleIcon;
2081        return returnIcons;
2082        } else {
2083        return null;
2084        }
2085    }
2086    }
2087}
2088
Popular Tags