OSDN Git Service

Imported GNU Classpath 0.20
[pf3gnuchains/gcc-fork.git] / libjava / classpath / javax / swing / JTabbedPane.java
1 /* JTabbedPane.java --
2    Copyright (C) 2002, 2004, 2005  Free Software Foundation, Inc.
3
4 This file is part of GNU Classpath.
5
6 GNU Classpath is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2, or (at your option)
9 any later version.
10
11 GNU Classpath is distributed in the hope that it will be useful, but
12 WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14 General Public License for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with GNU Classpath; see the file COPYING.  If not, write to the
18 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
19 02110-1301 USA.
20
21 Linking this library statically or dynamically with other modules is
22 making a combined work based on this library.  Thus, the terms and
23 conditions of the GNU General Public License cover the whole
24 combination.
25
26 As a special exception, the copyright holders of this library give you
27 permission to link this library with independent modules to produce an
28 executable, regardless of the license terms of these independent
29 modules, and to copy and distribute the resulting executable under
30 terms of your choice, provided that you also meet, for each linked
31 independent module, the terms and conditions of the license of that
32 module.  An independent module is a module which is not derived from
33 or based on this library.  If you modify this library, you may extend
34 this exception to your version of the library, but you are not
35 obligated to do so.  If you do not wish to do so, delete this
36 exception statement from your version. */
37
38
39 package javax.swing;
40
41 import java.awt.Color;
42 import java.awt.Component;
43 import java.awt.Point;
44 import java.awt.Rectangle;
45 import java.awt.event.MouseEvent;
46 import java.io.Serializable;
47 import java.util.Vector;
48
49 import javax.accessibility.Accessible;
50 import javax.accessibility.AccessibleContext;
51 import javax.accessibility.AccessibleRole;
52 import javax.accessibility.AccessibleSelection;
53 import javax.swing.event.ChangeEvent;
54 import javax.swing.event.ChangeListener;
55 import javax.swing.plaf.TabbedPaneUI;
56 import javax.swing.plaf.UIResource;
57
58 /**
59  * This is a container for components where only one component is displayed at
60  * a given time and the displayed component can be switched by clicking on
61  * tabs.
62  * 
63  * <p>
64  * Tabs can be oriented in several ways. They can be above, below, left and
65  * right of the component. Tabs can either wrap around (by creating multiple
66  * rows of tabs) or they can be scrolled (where only a subset of the  tabs
67  * can be seen at once). More tabs can be added by calling the
68  * add/addTab/insertTab methods.
69  * </p>
70  */
71 public class JTabbedPane extends JComponent implements Serializable,
72                                                        Accessible,
73                                                        SwingConstants
74 {
75   /**
76    * Accessibility support for <code>JTabbedPane</code>.
77    */
78   // FIXME: This inner class is a complete stub and must be implemented
79   // properly.
80   protected class AccessibleJTabbedPane extends JComponent.AccessibleJComponent
81     implements AccessibleSelection, ChangeListener
82   {
83     /**
84      * The serialization UID.
85      */
86     private static final long serialVersionUID = 7610530885966830483L;
87
88     /**
89      * Creates a new AccessibleJTabbedPane object.
90      */
91     public AccessibleJTabbedPane()
92     {
93       super();
94     }
95
96     /**
97      * Receives notification when the selection state of the
98      * <code>JTabbedPane</code> changes.
99      *
100      * @param e the change event describing the change
101      */
102     public void stateChanged(ChangeEvent e)
103     {
104       // Implement this properly.
105     }
106
107     /**
108      * Returns the accessible role of the <code>JTabbedPane</code>, which is
109      * {@link AccessibleRole#PAGE_TAB_LIST}.
110      *
111      * @return the accessible role of the <code>JTabbedPane</code>
112      */
113     public AccessibleRole getAccessibleRole()
114     {
115       return null;
116     }
117
118     /**
119      * Returns the number of accessible child components of the
120      * <code>JTabbedPane</code>.
121      *
122      * @return the number of accessible child components of the
123      *         <code>JTabbedPane</code>
124      */
125     public int getAccessibleChildrenCount()
126     {
127       return 0;
128     }
129
130     /**
131      * Returns the accessible child component at the specified index.
132      *
133      * @param i the index of the child component to fetch
134      *
135      * @return the accessible child component at the specified index
136      */
137     public Accessible getAccessibleChild(int i)
138     {
139       return null;
140     }
141
142     /**
143      * Returns the current selection state of the <code>JTabbedPane</code>
144      * as AccessibleSelection object.
145      *
146      * @return the current selection state of the <code>JTabbedPane</code>
147      */
148     public AccessibleSelection getAccessibleSelection()
149     {
150       return null;
151     }
152
153     /**
154      * Returns the accessible child component at the specified coordinates.
155      * If there is no child component at this location, then return the
156      * currently selected tab.
157      *
158      * @param p the coordinates at which to look up the child component
159      *
160      * @return the accessible child component at the specified coordinates or
161      *         the currently selected tab if there is no child component at
162      *         this location
163      */
164     public Accessible getAccessibleAt(Point p)
165     {
166       return null;
167     }
168
169     /**
170      * The number of selected child components of the
171      * <code>JTabbedPane</code>. This will be <code>0</code> if the
172      * <code>JTabbedPane</code> has no children, or <code>1</code> otherwise,
173      * since there is always exactly one tab selected. 
174      *
175      * @return number of selected child components of the
176      *         <code>JTabbedPane</code>
177      */
178     public int getAccessibleSelectionCount()
179     {
180       return 0;
181     }
182
183     /**
184      * DOCUMENT ME!
185      *
186      * @param i DOCUMENT ME!
187      *
188      * @return DOCUMENT ME!
189      */
190     public Accessible getAccessibleSelection(int i)
191     {
192       return null;
193     }
194
195     /**
196      * DOCUMENT ME!
197      *
198      * @param i DOCUMENT ME!
199      *
200      * @return DOCUMENT ME!
201      */
202     public boolean isAccessibleChildSelected(int i)
203     {
204       return false;
205     }
206
207     /**
208      * DOCUMENT ME!
209      *
210      * @param i DOCUMENT ME!
211      */
212     public void addAccessibleSelection(int i)
213     {
214       // TODO: Implement this properly.
215     }
216
217     /**
218      * DOCUMENT ME!
219      *
220      * @param i DOCUMENT ME!
221      */
222     public void removeAccessibleSelection(int i)
223     {
224       // TODO: Implement this properly.
225     }
226
227     /**
228      * DOCUMENT ME!
229      */
230     public void clearAccessibleSelection()
231     {
232       // TODO: Implement this properly.
233     }
234
235     /**
236      * DOCUMENT ME!
237      */
238     public void selectAllAccessibleSelection()
239     {
240       // TODO: Implement this properly.
241     }
242   }
243
244   /**
245    * A helper class that listens for changes to the model.
246    */
247   protected class ModelListener implements ChangeListener, Serializable
248   {
249     /** DOCUMENT ME! */
250     private static final long serialVersionUID = 497359819958114132L;
251
252     /**
253      * Creates a new ModelListener object.
254      */
255     protected ModelListener()
256     {
257       // Nothing to do here.
258     }
259
260     /**
261      * This method is called whenever the model  is changed.
262      *
263      * @param e The ChangeEvent that is passed from the model.
264      */
265     public void stateChanged(ChangeEvent e)
266     {
267       // Propagate to our listeners.
268       fireStateChanged();
269     }
270   }
271
272   /**
273    * A private class that holds all the information  for each tab.
274    */
275   private class Page
276   {
277     /** The tooltip string. */
278     private String tip;
279
280     /** The component associated with the tab. */
281     private Component component;
282
283     /** The active icon associated with the tab. */
284     private transient Icon icon;
285
286     /** The disabled icon associated with the tab. */
287     private transient Icon disabledIcon;
288
289     /** The tab's enabled status. */
290     private transient boolean enabled = true;
291
292     /** The string painted on the tab. */
293     private transient String title;
294
295     /** The background color of the tab. */
296     private transient Color bg;
297
298     /** The foreground color of the tab. */
299     private transient Color fg;
300
301     /** The mnemonic associated with the tab. */
302     private transient int mnemonicKey;
303
304     /** The index of the underlined character in the string. */
305     private transient int underlinedChar = -1;
306
307     /**
308      * Creates a new data storage for the tab.
309      *
310      * @param title The string displayed on the tab.
311      * @param icon The active icon displayed on the tab.
312      * @param component The component associated with the tab.
313      * @param tip The tooltip associated with the tab.
314      */
315     protected Page(String title, Icon icon, Component component, String tip)
316     {
317       this.title = title;
318       this.icon = icon;
319       this.component = component;
320       this.tip = tip;
321     }
322
323     /**
324      * This method returns the component associated with the tab.
325      *
326      * @return The component associated with the tab.
327      */
328     public Component getComponent()
329     {
330       return component;
331     }
332
333     /**
334      * This method sets the component associated with the tab.
335      *
336      * @param c The component associated with the tab.
337      */
338     public void setComponent(Component c)
339     {
340       int i = indexOfComponent(component);
341       insertTab(title, icon, c, tip, i);
342       component = c;
343       removeTabAt(i);
344     }
345
346     /**
347      * This method returns the tooltip string.
348      *
349      * @return The tooltip string.
350      */
351     public String getTip()
352     {
353       return tip;
354     }
355
356     /**
357      * This method sets the tooltip string.
358      *
359      * @param tip The tooltip string.
360      */
361     public void setTip(String tip)
362     {
363       this.tip = tip;
364     }
365
366     /**
367      * This method returns the background color.
368      *
369      * @return The background color.
370      */
371     public Color getBackground()
372     {
373       return bg;
374     }
375
376     /**
377      * This method sets the background color.
378      *
379      * @param background The background color.
380      */
381     public void setBackground(Color background)
382     {
383       bg = background;
384     }
385
386     /**
387      * This method returns the foreground color.
388      *
389      * @return The foreground color.
390      */
391     public Color getForeground()
392     {
393       return fg;
394     }
395
396     /**
397      * This method sets the foreground color.
398      *
399      * @param foreground The foreground color.
400      */
401     public void setForeground(Color foreground)
402     {
403       fg = foreground;
404     }
405
406     /**
407      * This method returns the title associated with the tab.
408      *
409      * @return The title of the tab.
410      */
411     public String getTitle()
412     {
413       return title;
414     }
415
416     /** DOCUMENT ME! */
417     private static final long serialVersionUID = 1614381073220130939L;
418
419     /**
420      * This method sets the title of the tab.
421      *
422      * @param text The title of the tab.
423      */
424     public void setTitle(String text)
425     {
426       title = text;
427       if (title != null && title.length() <= underlinedChar)
428         setDisplayedMnemonicIndex(title.length() - 1);
429     }
430
431     /**
432      * This method returns the active icon.
433      *
434      * @return The active icon.
435      */
436     public Icon getIcon()
437     {
438       return icon;
439     }
440
441     /**
442      * This method sets the active icon.
443      *
444      * @param icon The active icon.
445      */
446     public void setIcon(Icon icon)
447     {
448       this.icon = icon;
449     }
450
451     /**
452      * This method returns the disabled icon.
453      *
454      * @return The disabled icon.
455      */
456     public Icon getDisabledIcon()
457     {
458       if (disabledIcon == null && icon instanceof ImageIcon)
459         setDisabledIcon(icon);
460       return disabledIcon;
461     }
462
463     /**
464      * This method sets the disabled icon.
465      *
466      * @param disabledIcon The disabled icon.
467      */
468     public void setDisabledIcon(Icon disabledIcon)
469     {
470       this.disabledIcon = disabledIcon;
471     }
472
473     /**
474      * This method returns whether the tab is enabled.
475      *
476      * @return Whether the tab is enabled.
477      */
478     public boolean isEnabled()
479     {
480       return enabled;
481     }
482
483     /**
484      * This method sets whether the tab is enabled.
485      *
486      * @param enabled Whether this tab is enabled.
487      */
488     public void setEnabled(boolean enabled)
489     {
490       this.enabled = enabled;
491     }
492
493     /**
494      * This method returns the mnemonic.
495      *
496      * @return The mnemonic.
497      */
498     public int getMnemonic()
499     {
500       return mnemonicKey;
501     }
502
503     /**
504      * This method sets the mnemonic. If the title is set, it will update the
505      * mnemonicIndex.
506      *
507      * @param key The mnemonic.
508      */
509     public void setMnemonic(int key)
510     {
511       setMnemonic((char) key);
512     }
513
514     /**
515      * This method sets the mnemonic. If the title is set, it will update the
516      * mnemonicIndex.
517      *
518      * @param aChar The mnemonic.
519      */
520     public void setMnemonic(char aChar)
521     {
522       mnemonicKey = aChar;
523       if (title != null)
524         setDisplayedMnemonicIndex(title.indexOf(mnemonicKey));
525     }
526
527     /**
528      * This method returns the mnemonicIndex.
529      *
530      * @return The mnemonicIndex.
531      */
532     public int getDisplayedMnemonicIndex()
533     {
534       return underlinedChar;
535     }
536
537     /**
538      * This method sets the mnemonicIndex.
539      *
540      * @param index The mnemonicIndex.
541      *
542      * @throws IllegalArgumentException If index less than -1 || index greater
543      *         or equal to title.length.
544      */
545     public void setDisplayedMnemonicIndex(int index)
546       throws IllegalArgumentException
547     {
548       if (index < -1 || title != null && index >= title.length())
549         throw new IllegalArgumentException();
550
551       if (title == null || mnemonicKey == 0 || (index > -1 && title.charAt(index) != mnemonicKey))
552         index = -1;
553
554       underlinedChar = index;
555     }
556   }
557
558   private static final long serialVersionUID = 1614381073220130939L;
559
560   /** The changeEvent used to fire changes to listeners. */
561   protected ChangeEvent changeEvent;
562
563   /** The listener that listens to the model. */
564   protected ChangeListener changeListener;
565
566   /** The model that describes this JTabbedPane. */
567   protected SingleSelectionModel model;
568
569   /** Indicates that the TabbedPane is in scrolling mode. */
570   public static final int SCROLL_TAB_LAYOUT = 1;
571
572   /** Indicates that the TabbedPane is in wrap mode. */
573   public static final int WRAP_TAB_LAYOUT = 0;
574
575   /** The current tabPlacement of the TabbedPane. */
576   protected int tabPlacement = SwingConstants.TOP;
577
578   /** The current tabLayoutPolicy of the TabbedPane. */
579   private transient int layoutPolicy;
580
581   /** The list of tabs associated with the TabbedPane. */
582   transient Vector tabs = new Vector();
583
584   /**
585    * Creates a new JTabbedPane object with tabs on top and using wrap tab
586    * layout.
587    */
588   public JTabbedPane()
589   {
590     this(SwingConstants.TOP, WRAP_TAB_LAYOUT);
591   }
592
593   /**
594    * Creates a new JTabbedPane object using wrap tab layout  and the given
595    * <code>tabPlacement</code>, where <code>tabPlacement</code> can be one
596    * of the following values: {@link #TOP}, {@link #BOTTOM}, {@link #LEFT} or
597    * {@link #RIGHT}.
598    *
599    * @param tabPlacement where the tabs will be placed
600    */
601   public JTabbedPane(int tabPlacement)
602   {
603     this(tabPlacement, WRAP_TAB_LAYOUT);
604   }
605
606   /**
607    * Creates a new JTabbedPane object with the given <code>tabPlacement</code>
608    * and <code>tabLayoutPolicy</code>. The <code>tabPlacement</code> can be one
609    * of the following values: {@link #TOP}, {@link #BOTTOM}, {@link #LEFT} or
610    * {@link #RIGHT}. The <code>tabLayoutPolicy</code> can be either
611    * {@link #SCROLL_TAB_LAYOUT} or {@link #WRAP_TAB_LAYOUT}.
612    *
613    * @param tabPlacement where the tabs will be placed
614    * @param tabLayoutPolicy the way tabs will be placed
615    *
616    * @throws IllegalArgumentException If tabLayoutPolicy or tabPlacement are
617    *         not valid.
618    */
619   public JTabbedPane(int tabPlacement, int tabLayoutPolicy)
620   {
621     if (tabPlacement != TOP && tabPlacement != BOTTOM && tabPlacement != RIGHT
622         && tabPlacement != LEFT)
623       throw new IllegalArgumentException("tabPlacement is not valid.");
624     if (tabLayoutPolicy != SCROLL_TAB_LAYOUT
625         && tabLayoutPolicy != WRAP_TAB_LAYOUT)
626       throw new IllegalArgumentException("tabLayoutPolicy is not valid.");
627     this.tabPlacement = tabPlacement;
628     layoutPolicy = tabLayoutPolicy;
629     
630     changeEvent = new ChangeEvent(this);
631     changeListener = createChangeListener();
632
633     model = new DefaultSingleSelectionModel();
634     model.addChangeListener(changeListener);
635
636     updateUI();
637   }
638
639   /**
640    * This method returns the UI used to display the JTabbedPane.
641    *
642    * @return The UI used to display the JTabbedPane.
643    */
644   public TabbedPaneUI getUI()
645   {
646     return (TabbedPaneUI) ui;
647   }
648
649   /**
650    * This method sets the UI used to display the JTabbedPane.
651    *
652    * @param ui The UI used to display the JTabbedPane.
653    */
654   public void setUI(TabbedPaneUI ui)
655   {
656     super.setUI(ui);
657   }
658
659   /**
660    * This method restores the UI to the defaults given by the UIManager.
661    */
662   public void updateUI()
663   {
664     setUI((TabbedPaneUI) UIManager.getUI(this));
665     invalidate();
666   }
667
668   /**
669    * This method returns a string identifier that  is used to determine which
670    * UI will be used with  the JTabbedPane.
671    *
672    * @return A string identifier for the UI.
673    */
674   public String getUIClassID()
675   {
676     return "TabbedPaneUI";
677   }
678
679   /**
680    * This method creates a ChangeListener that is used to  listen to the model
681    * for events.
682    *
683    * @return A ChangeListener to listen to the model.
684    */
685   protected ChangeListener createChangeListener()
686   {
687     return new ModelListener();
688   }
689
690   /**
691    * This method adds a ChangeListener to the JTabbedPane.
692    *
693    * @param l The ChangeListener to add.
694    */
695   public void addChangeListener(ChangeListener l)
696   {
697     listenerList.add(ChangeListener.class, l);
698   }
699
700   /**
701    * This method removes a ChangeListener to the JTabbedPane.
702    *
703    * @param l The ChangeListener to remove.
704    */
705   public void removeChangeListener(ChangeListener l)
706   {
707     listenerList.remove(ChangeListener.class, l);
708   }
709
710   /**
711    * This method fires a ChangeEvent to all the JTabbedPane's ChangeListeners.
712    */
713   protected void fireStateChanged()
714   {
715     Object[] changeListeners = listenerList.getListenerList();
716     if (changeEvent == null)
717       changeEvent = new ChangeEvent(this);
718     for (int i = changeListeners.length - 2; i >= 0; i -= 2)
719       {
720         if (changeListeners[i] == ChangeListener.class)
721           ((ChangeListener) changeListeners[i + 1]).stateChanged(changeEvent);
722       }
723   }
724
725   /**
726    * This method returns all ChangeListeners registered with the JTabbedPane.
727    *
728    * @return The ChangeListeners registered with the JTabbedPane.
729    */
730   public ChangeListener[] getChangeListeners()
731   {
732     return (ChangeListener[]) super.getListeners(ChangeListener.class);
733   }
734
735   /**
736    * This method returns the model used with the JTabbedPane.
737    *
738    * @return The JTabbedPane's model.
739    */
740   public SingleSelectionModel getModel()
741   {
742     return model;
743   }
744
745   /**
746    * This method changes the model property of the JTabbedPane.
747    *
748    * @param model The new model to use with the JTabbedPane.
749    */
750   public void setModel(SingleSelectionModel model)
751   {
752     if (model != this.model)
753       {
754         SingleSelectionModel oldModel = this.model;
755         this.model.removeChangeListener(changeListener);
756         this.model = model;
757         this.model.addChangeListener(changeListener);
758         firePropertyChange("model", oldModel, this.model);
759       }
760   }
761
762   /**
763    * This method returns the tabPlacement.
764    *
765    * @return The tabPlacement used with the JTabbedPane.
766    */
767   public int getTabPlacement()
768   {
769     return tabPlacement;
770   }
771
772   /**
773    * This method changes the tabPlacement property of the JTabbedPane.
774    *
775    * @param tabPlacement The tabPlacement to use.
776    *
777    * @throws IllegalArgumentException If tabPlacement is not one of TOP,
778    *         BOTTOM, LEFT, or RIGHT.
779    */
780   public void setTabPlacement(int tabPlacement)
781   {
782     if (tabPlacement != TOP && tabPlacement != BOTTOM && tabPlacement != RIGHT
783         && tabPlacement != LEFT)
784       throw new IllegalArgumentException("tabPlacement is not valid.");
785     if (tabPlacement != this.tabPlacement)
786       {
787         int oldPlacement = this.tabPlacement;
788         this.tabPlacement = tabPlacement;
789         firePropertyChange("tabPlacement", oldPlacement, this.tabPlacement);
790       }
791   }
792
793   /**
794    * This method returns the tabLayoutPolicy.
795    *
796    * @return The tabLayoutPolicy.
797    */
798   public int getTabLayoutPolicy()
799   {
800     return layoutPolicy;
801   }
802
803   /**
804    * This method changes the tabLayoutPolicy property of the JTabbedPane.
805    *
806    * @param tabLayoutPolicy The tabLayoutPolicy to use.
807    *
808    * @throws IllegalArgumentException If tabLayoutPolicy is not one of
809    *         SCROLL_TAB_LAYOUT or WRAP_TAB_LAYOUT.
810    */
811   public void setTabLayoutPolicy(int tabLayoutPolicy)
812   {
813     if (tabLayoutPolicy != SCROLL_TAB_LAYOUT
814         && tabLayoutPolicy != WRAP_TAB_LAYOUT)
815       throw new IllegalArgumentException("tabLayoutPolicy is not valid.");
816     if (tabLayoutPolicy != layoutPolicy)
817       {
818         int oldPolicy = layoutPolicy;
819         layoutPolicy = tabLayoutPolicy;
820         firePropertyChange("tabLayoutPolicy", oldPolicy, layoutPolicy);
821       }
822   }
823
824   /**
825    * This method returns the index of the tab that is currently selected.
826    *
827    * @return The index of the selected tab.
828    */
829   public int getSelectedIndex()
830   {
831     return model.getSelectedIndex();
832   }
833
834   /**
835    * This method checks the index.
836    *
837    * @param index The index to check.
838    * @param start DOCUMENT ME!
839    * @param end DOCUMENT ME!
840    *
841    * @throws IndexOutOfBoundsException DOCUMENT ME!
842    */
843   private void checkIndex(int index, int start, int end)
844   {
845     if (index < start || index >= end)
846       throw new IndexOutOfBoundsException("Index < " + start + " || Index >= "
847                                           + end);
848   }
849
850   /**
851    * This method sets the selected index. This method will hide the old
852    * component and show the new component.
853    *
854    * @param index The index to set it at.
855    */
856   public void setSelectedIndex(int index)
857   {
858     checkIndex(index, -1, tabs.size());
859     if (index != getSelectedIndex())
860       {
861         if (getSelectedIndex() != -1 && getSelectedComponent() != null)
862           getSelectedComponent().hide();
863         if (index != -1 && getComponentAt(index) != null)
864           getComponentAt(index).show();
865         model.setSelectedIndex(index);
866       }
867   }
868
869   /**
870    * This method returns the component at the selected index.
871    *
872    * @return The component at the selected index.
873    */
874   public Component getSelectedComponent()
875   {
876     return getComponentAt(getSelectedIndex());
877   }
878
879   /**
880    * This method sets the component at the selected index.
881    *
882    * @param c The component associated with the selected index.
883    */
884   public void setSelectedComponent(Component c)
885   {
886     if (c.getParent() == this)
887       setSelectedIndex(indexOfComponent(c));
888     else
889       setComponentAt(getSelectedIndex(), c);
890   }
891
892   /**
893    * This method inserts tabs into JTabbedPane. This includes adding the
894    * component to the JTabbedPane and hiding it.
895    *
896    * @param title the title of the tab; may be <code>null</code>
897    * @param icon the tab's icon; may be <code>null</code>
898    * @param component the component associated with the tab
899    * @param tip the tooltip for the tab
900    * @param index the index to insert the tab at
901    */
902   public void insertTab(String title, Icon icon, Component component,
903                         String tip, int index)
904   {
905     if (title == null)
906       title = "";
907     Page p = new Page(title, icon, component, tip);
908     tabs.insertElementAt(p, index);
909
910     // Hide the component so we don't see it. Do it before we parent it
911     // so we don't trigger a repaint.
912     if (component != null)
913       {
914         component.hide();
915         super.add(component);
916       }
917
918     if (getSelectedIndex() == -1)
919       setSelectedIndex(0);
920
921     revalidate();
922     repaint();
923   }
924
925   /**
926    * This method adds a tab to the JTabbedPane.
927    *
928    * @param title the title of the tab; may be <code>null</code>
929    * @param icon the icon for the tab; may be <code>null</code>
930    * @param component the associated component
931    * @param tip the associated tooltip
932    */
933   public void addTab(String title, Icon icon, Component component, String tip)
934   {
935     insertTab(title, icon, component, tip, tabs.size());
936   }
937
938   /**
939    * This method adds a tab to the JTabbedPane.
940    *
941    * @param title the title of the tab; may be <code>null</code>
942    * @param icon the icon for the tab; may be <code>null</code>
943    * @param component the associated component
944    */
945   public void addTab(String title, Icon icon, Component component)
946   {
947     insertTab(title, icon, component, null, tabs.size());
948   }
949
950   /**
951    * This method adds a tab to the JTabbedPane.
952    *
953    * @param title the title of the tab; may be <code>null</code>
954    * @param component the associated component
955    */
956   public void addTab(String title, Component component)
957   {
958     insertTab(title, null, component, null, tabs.size());
959   }
960
961   /**
962    * This method adds a tab to the JTabbedPane. The title of the tab is the
963    * Component's name. If the Component is an instance of UIResource, it
964    * doesn't add the tab and instead add the component directly to the
965    * JTabbedPane.
966    *
967    * @param component The associated component.
968    *
969    * @return The Component that was added.
970    */
971   public Component add(Component component)
972   {
973     if (component instanceof UIResource)
974       super.add(component);
975     else
976       insertTab(component.getName(), null, component, null, tabs.size());
977     
978     return component;
979   }
980
981   /**
982    * This method adds a tab to the JTabbedPane. If the Component is an
983    * instance of UIResource, it doesn't add the tab and instead add the
984    * component directly to the JTabbedPane.
985    *
986    * @param title the title of the tab; may be <code>null</code>
987    * @param component the associated component
988    *
989    * @return The Component that was added.
990    */
991   public Component add(String title, Component component)
992   {
993     if (component instanceof UIResource)
994       super.add(component);
995     else
996       insertTab(title, null, component, null, tabs.size());
997     return component;
998   }
999
1000   /**
1001    * This method adds a tab to the JTabbedPane. If the Component is an
1002    * instance of UIResource, it doesn't add the tab and instead add the
1003    * component directly to the JTabbedPane.
1004    *
1005    * @param component The associated component.
1006    * @param index The index to insert the tab at.
1007    *
1008    * @return The Component that was added.
1009    */
1010   public Component add(Component component, int index)
1011   {
1012     if (component instanceof UIResource)
1013       super.add(component);
1014     else
1015       insertTab(component.getName(), null, component, null, index);
1016     return component;
1017   }
1018
1019   /**
1020    * This method adds a tab to the JTabbedPane. If the Component is an
1021    * instance of UIResource, it doesn't add the tab and instead add the
1022    * component directly to the JTabbedPane. If the constraints object is an
1023    * icon, it will be used as the tab's icon. If the constraints object is a
1024    * string, we will use it as the title.
1025    *
1026    * @param component The associated component.
1027    * @param constraints The constraints object.
1028    */
1029   public void add(Component component, Object constraints)
1030   {
1031     add(component, constraints, tabs.size());
1032   }
1033
1034   /**
1035    * This method adds a tab to the JTabbedPane. If the Component is an
1036    * instance of UIResource, it doesn't add the tab and instead add the
1037    * component directly to the JTabbedPane. If the constraints object is an
1038    * icon, it will be used as the tab's icon. If the constraints object is a
1039    * string, we will use it as the title.
1040    *
1041    * @param component The associated component.
1042    * @param constraints The constraints object.
1043    * @param index The index to insert the tab at.
1044    */
1045   public void add(Component component, Object constraints, int index)
1046   {
1047     if (component instanceof UIResource)
1048       super.add(component);
1049     else
1050       {
1051         if (constraints instanceof String)
1052           insertTab((String) constraints, null, component, null, index);
1053         else
1054           insertTab(component.getName(),
1055                     (constraints instanceof Icon) ? (Icon) constraints : null,
1056                     component, null, index);
1057       }
1058   }
1059
1060   /**
1061    * Removes the tab at index. After the component associated with 
1062    * index is removed, its visibility is reset to true to ensure it 
1063    * will be visible if added to other containers.
1064    *
1065    * @param index The index of the tab to remove.
1066    */
1067   public void removeTabAt(int index)
1068   {
1069     checkIndex(index, 0, tabs.size());
1070     tabs.remove(index);
1071     getComponentAt(index).show();
1072   }
1073
1074   /**
1075    * Removes the specified Component from the JTabbedPane.
1076    *
1077    * @param component The Component to remove.
1078    */
1079   public void remove(Component component)
1080   {
1081     super.remove(component);
1082   }
1083
1084   /**
1085    * Removes the tab and component which corresponds to the specified index.
1086    *
1087    * @param index The index of the tab to remove.
1088    */
1089   public void remove(int index)
1090   {
1091     remove(getComponentAt(index));
1092     removeTabAt(index);
1093   }
1094
1095   /**
1096    * This method removes all tabs and associated components from the
1097    * JTabbedPane.
1098    */
1099   public void removeAll()
1100   {
1101     for (int i = tabs.size() - 1; i >= 0; i--)
1102       removeTabAt(i);
1103   }
1104
1105   /**
1106    * This method returns how many tabs are in the JTabbedPane.
1107    *
1108    * @return The number of tabs in the JTabbedPane.
1109    */
1110   public int getTabCount()
1111   {
1112     return tabs.size();
1113   }
1114
1115   /**
1116    * This method returns the number of runs used  to paint the JTabbedPane.
1117    *
1118    * @return The number of runs.
1119    */
1120   public int getTabRunCount()
1121   {
1122     return ((TabbedPaneUI) ui).getTabRunCount(this);
1123   }
1124
1125   /**
1126    * This method returns the tab title given the index.
1127    *
1128    * @param index The index of the tab.
1129    *
1130    * @return The title for the tab.
1131    */
1132   public String getTitleAt(int index)
1133   {
1134     checkIndex(index, 0, tabs.size());
1135     return ((Page) tabs.elementAt(index)).getTitle();
1136   }
1137
1138   /**
1139    * This method returns the active icon given the index.
1140    *
1141    * @param index The index of the tab.
1142    *
1143    * @return The active icon for the tab.
1144    */
1145   public Icon getIconAt(int index)
1146   {
1147     checkIndex(index, 0, tabs.size());
1148     return ((Page) tabs.elementAt(index)).getIcon();
1149   }
1150
1151   /**
1152    * This method returns the disabled icon given the index.
1153    *
1154    * @param index The index of the tab.
1155    *
1156    * @return The disabled icon for the tab.
1157    */
1158   public Icon getDisabledIconAt(int index)
1159   {
1160     checkIndex(index, 0, tabs.size());
1161     return ((Page) tabs.elementAt(index)).getDisabledIcon();
1162   }
1163
1164   /**
1165    * This method returns the tooltip string for the tab.
1166    *
1167    * @param index The index of the tab.
1168    *
1169    * @return The tooltip string for the tab.
1170    */
1171   public String getToolTipTextAt(int index)
1172   {
1173     checkIndex(index, 0, tabs.size());
1174     return ((Page) tabs.elementAt(index)).getTip();
1175   }
1176
1177   /**
1178    * This method returns the foreground color for the tab.
1179    *
1180    * @param index The index of the tab.
1181    *
1182    * @return The foreground color for the tab.
1183    */
1184   public Color getForegroundAt(int index)
1185   {
1186     checkIndex(index, 0, tabs.size());
1187     return ((Page) tabs.elementAt(index)).getForeground();
1188   }
1189
1190   /**
1191    * This method returns the background color for the tab.
1192    *
1193    * @param index The index of the tab.
1194    *
1195    * @return The background color for the tab.
1196    */
1197   public Color getBackgroundAt(int index)
1198   {
1199     checkIndex(index, 0, tabs.size());
1200     return ((Page) tabs.elementAt(index)).getBackground();
1201   }
1202
1203   /**
1204    * This method returns the component associated with the tab.
1205    *
1206    * @param index The index of the tab.
1207    *
1208    * @return The component associated with the tab.
1209    */
1210   public Component getComponentAt(int index)
1211   {
1212     checkIndex(index, 0, tabs.size());
1213     return ((Page) tabs.elementAt(index)).getComponent();
1214   }
1215
1216   /**
1217    * This method returns whether this tab is enabled. Disabled tabs cannot be
1218    * selected.
1219    *
1220    * @param index The index of the tab.
1221    *
1222    * @return Whether the tab is enabled.
1223    */
1224   public boolean isEnabledAt(int index)
1225   {
1226     checkIndex(index, 0, tabs.size());
1227     return ((Page) tabs.elementAt(index)).isEnabled();
1228   }
1229
1230   /**
1231    * This method returns the mnemonic for the tab.
1232    *
1233    * @param tabIndex The index of the tab.
1234    *
1235    * @return The mnemonic for the tab.
1236    */
1237   public int getMnemonicAt(int tabIndex)
1238   {
1239     checkIndex(tabIndex, 0, tabs.size());
1240     return ((Page) tabs.elementAt(tabIndex)).getMnemonic();
1241   }
1242
1243   /**
1244    * This method returns the mnemonic index for the tab.
1245    *
1246    * @param tabIndex The index of the tab.
1247    *
1248    * @return The mnemonic index for the tab.
1249    */
1250   public int getDisplayedMnemonicIndexAt(int tabIndex)
1251   {
1252     checkIndex(tabIndex, 0, tabs.size());
1253     return ((Page) tabs.elementAt(tabIndex)).getDisplayedMnemonicIndex();
1254   }
1255
1256   /**
1257    * This method returns the bounds of the tab given the index.
1258    *
1259    * @param index The index of the tab.
1260    *
1261    * @return A rectangle describing the bounds of the tab.
1262    */
1263   public Rectangle getBoundsAt(int index)
1264   {
1265     checkIndex(index, 0, tabs.size());
1266     return ((TabbedPaneUI) ui).getTabBounds(this, index);
1267   }
1268
1269   /**
1270    * This method sets the title of the tab.
1271    *
1272    * @param index The index of the tab.
1273    * @param title The new title.
1274    */
1275   public void setTitleAt(int index, String title)
1276   {
1277     checkIndex(index, 0, tabs.size());
1278     ((Page) tabs.elementAt(index)).setTitle(title);
1279   }
1280
1281   /**
1282    * This method sets the icon of the tab.
1283    *
1284    * @param index The index of the tab.
1285    * @param icon The new icon.
1286    */
1287   public void setIconAt(int index, Icon icon)
1288   {
1289     checkIndex(index, 0, tabs.size());
1290     ((Page) tabs.elementAt(index)).setIcon(icon);
1291   }
1292
1293   /**
1294    * This method sets the disabled icon of the tab.
1295    *
1296    * @param index The index of the tab.
1297    * @param disabledIcon The new disabled icon.
1298    */
1299   public void setDisabledIconAt(int index, Icon disabledIcon)
1300   {
1301     checkIndex(index, 0, tabs.size());
1302     ((Page) tabs.elementAt(index)).setDisabledIcon(disabledIcon);
1303   }
1304
1305   /**
1306    * This method sets the tooltip text of the tab.
1307    *
1308    * @param index The index of the tab.
1309    * @param toolTipText The tooltip text.
1310    */
1311   public void setToolTipTextAt(int index, String toolTipText)
1312   {
1313     checkIndex(index, 0, tabs.size());
1314     ((Page) tabs.elementAt(index)).setTip(toolTipText);
1315   }
1316
1317   /**
1318    * This method sets the background color of the tab.
1319    *
1320    * @param index The index of the tab.
1321    * @param background The background color of the tab.
1322    */
1323   public void setBackgroundAt(int index, Color background)
1324   {
1325     checkIndex(index, 0, tabs.size());
1326     ((Page) tabs.elementAt(index)).setBackground(background);
1327   }
1328
1329   /**
1330    * This method sets the foreground color of the tab.
1331    *
1332    * @param index The index of the tab.
1333    * @param foreground The foreground color of the tab.
1334    */
1335   public void setForegroundAt(int index, Color foreground)
1336   {
1337     checkIndex(index, 0, tabs.size());
1338     ((Page) tabs.elementAt(index)).setForeground(foreground);
1339   }
1340
1341   /**
1342    * This method sets whether the tab is enabled.
1343    *
1344    * @param index The index of the tab.
1345    * @param enabled Whether the tab is enabled.
1346    */
1347   public void setEnabledAt(int index, boolean enabled)
1348   {
1349     checkIndex(index, 0, tabs.size());
1350     ((Page) tabs.elementAt(index)).setEnabled(enabled);
1351   }
1352
1353   /**
1354    * This method sets the component associated with the tab.
1355    *
1356    * @param index The index of the tab.
1357    * @param component The component associated with the tab.
1358    */
1359   public void setComponentAt(int index, Component component)
1360   {
1361     checkIndex(index, 0, tabs.size());
1362     ((Page) tabs.elementAt(index)).setComponent(component);
1363   }
1364
1365   /**
1366    * This method sets the displayed mnemonic index of the tab.
1367    *
1368    * @param tabIndex The index of the tab.
1369    * @param mnemonicIndex The mnemonic index.
1370    */
1371   public void setDisplayedMnemonicIndexAt(int tabIndex, int mnemonicIndex)
1372   {
1373     checkIndex(tabIndex, 0, tabs.size());
1374     ((Page) tabs.elementAt(tabIndex)).setDisplayedMnemonicIndex(mnemonicIndex);
1375   }
1376
1377   /**
1378    * This method sets the mnemonic for the tab.
1379    *
1380    * @param tabIndex The index of the tab.
1381    * @param mnemonic The mnemonic.
1382    */
1383   public void setMnemonicAt(int tabIndex, int mnemonic)
1384   {
1385     checkIndex(tabIndex, 0, tabs.size());
1386     ((Page) tabs.elementAt(tabIndex)).setMnemonic(mnemonic);
1387   }
1388
1389   /**
1390    * This method finds the index of a tab given the title.
1391    *
1392    * @param title The title that belongs to a tab.
1393    *
1394    * @return The index of the tab that has the title or -1 if not found.
1395    */
1396   public int indexOfTab(String title)
1397   {
1398     int index = -1;
1399     for (int i = 0; i < tabs.size(); i++)
1400       {
1401         if (((Page) tabs.elementAt(i)).getTitle().equals(title))
1402           {
1403             index = i;
1404             break;
1405           }
1406       }
1407     return index;
1408   }
1409
1410   /**
1411    * This method finds the index of a tab given the icon.
1412    *
1413    * @param icon The icon that belongs to a tab.
1414    *
1415    * @return The index of the tab that has the icon or -1 if not found.
1416    */
1417   public int indexOfTab(Icon icon)
1418   {
1419     int index = -1;
1420     for (int i = 0; i < tabs.size(); i++)
1421       {
1422         if (((Page) tabs.elementAt(i)).getIcon() == icon)
1423           {
1424             index = i;
1425             break;
1426           }
1427       }
1428     return index;
1429   }
1430
1431   /**
1432    * This method finds the index of a tab given the component.
1433    *
1434    * @param component A component associated with a tab.
1435    *
1436    * @return The index of the tab that has this component or -1 if not found.
1437    */
1438   public int indexOfComponent(Component component)
1439   {
1440     int index = -1;
1441     for (int i = 0; i < tabs.size(); i++)
1442       {
1443         if (((Page) tabs.elementAt(i)).getComponent() == component)
1444           {
1445             index = i;
1446             break;
1447           }
1448       }
1449     return index;
1450   }
1451
1452   /**
1453    * This method returns a tab index given an (x,y) location. The origin of
1454    * the (x,y) pair will be the JTabbedPane's top left position. The  tab
1455    * returned will be the one that contains the point. This method is
1456    * delegated to the UI.
1457    *
1458    * @param x The x coordinate of the point.
1459    * @param y The y coordinate of the point.
1460    *
1461    * @return The index of the tab that contains the point.
1462    */
1463   public int indexAtLocation(int x, int y)
1464   {
1465     return ((TabbedPaneUI) ui).tabForCoordinate(this, x, y);
1466   }
1467
1468   /**
1469    * This method returns the tooltip text given a mouse event.
1470    *
1471    * @param event The mouse event.
1472    *
1473    * @return The tool tip text that is associated with this mouse event.
1474    */
1475   public String getToolTipText(MouseEvent event)
1476   {
1477     int index = indexAtLocation(event.getX(), event.getY());
1478     return ((Page) tabs.elementAt(index)).getTip();
1479   }
1480
1481   /**
1482    * This method returns a string representation of this JTabbedPane. It is
1483    * mainly used for debugging purposes.
1484    *
1485    * @return A string representation of this JTabbedPane.
1486    */
1487   protected String paramString()
1488   {
1489     return "JTabbedPane";
1490   }
1491
1492   /**
1493    * DOCUMENT ME!
1494    *
1495    * @return DOCUMENT ME!
1496    */
1497   public AccessibleContext getAccessibleContext()
1498   {
1499     if (accessibleContext == null)
1500       accessibleContext = new AccessibleJTabbedPane();
1501     return accessibleContext;
1502   }
1503 }