mirror of git://gcc.gnu.org/git/gcc.git
				
				
				
			
		
			
				
	
	
		
			4004 lines
		
	
	
		
			122 KiB
		
	
	
	
		
			Java
		
	
	
	
			
		
		
	
	
			4004 lines
		
	
	
		
			122 KiB
		
	
	
	
		
			Java
		
	
	
	
| /* BasicTabbedPaneUI.java --
 | |
|    Copyright (C) 2002, 2004, 2005, 2006  Free Software Foundation, Inc.
 | |
| 
 | |
| This file is part of GNU Classpath.
 | |
| 
 | |
| GNU Classpath is free software; you can redistribute it and/or modify
 | |
| it under the terms of the GNU General Public License as published by
 | |
| the Free Software Foundation; either version 2, or (at your option)
 | |
| any later version.
 | |
| 
 | |
| GNU Classpath is distributed in the hope that it will be useful, but
 | |
| WITHOUT ANY WARRANTY; without even the implied warranty of
 | |
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 | |
| General Public License for more details.
 | |
| 
 | |
| You should have received a copy of the GNU General Public License
 | |
| along with GNU Classpath; see the file COPYING.  If not, write to the
 | |
| Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
 | |
| 02110-1301 USA.
 | |
| 
 | |
| Linking this library statically or dynamically with other modules is
 | |
| making a combined work based on this library.  Thus, the terms and
 | |
| conditions of the GNU General Public License cover the whole
 | |
| combination.
 | |
| 
 | |
| As a special exception, the copyright holders of this library give you
 | |
| permission to link this library with independent modules to produce an
 | |
| executable, regardless of the license terms of these independent
 | |
| modules, and to copy and distribute the resulting executable under
 | |
| terms of your choice, provided that you also meet, for each linked
 | |
| independent module, the terms and conditions of the license of that
 | |
| module.  An independent module is a module which is not derived from
 | |
| or based on this library.  If you modify this library, you may extend
 | |
| this exception to your version of the library, but you are not
 | |
| obligated to do so.  If you do not wish to do so, delete this
 | |
| exception statement from your version. */
 | |
| 
 | |
| 
 | |
| package javax.swing.plaf.basic;
 | |
| 
 | |
| import java.awt.Color;
 | |
| import java.awt.Component;
 | |
| import java.awt.Container;
 | |
| import java.awt.Dimension;
 | |
| import java.awt.Font;
 | |
| import java.awt.FontMetrics;
 | |
| import java.awt.Graphics;
 | |
| import java.awt.Insets;
 | |
| import java.awt.LayoutManager;
 | |
| import java.awt.Point;
 | |
| import java.awt.Rectangle;
 | |
| import java.awt.event.ActionEvent;
 | |
| import java.awt.event.FocusAdapter;
 | |
| import java.awt.event.FocusEvent;
 | |
| import java.awt.event.FocusListener;
 | |
| import java.awt.event.MouseAdapter;
 | |
| import java.awt.event.MouseEvent;
 | |
| import java.awt.event.MouseListener;
 | |
| import java.beans.PropertyChangeEvent;
 | |
| import java.beans.PropertyChangeListener;
 | |
| 
 | |
| import javax.swing.AbstractAction;
 | |
| import javax.swing.ActionMap;
 | |
| import javax.swing.Icon;
 | |
| import javax.swing.InputMap;
 | |
| import javax.swing.JComponent;
 | |
| import javax.swing.JPanel;
 | |
| import javax.swing.JTabbedPane;
 | |
| import javax.swing.JViewport;
 | |
| import javax.swing.KeyStroke;
 | |
| import javax.swing.LookAndFeel;
 | |
| import javax.swing.SwingConstants;
 | |
| import javax.swing.SwingUtilities;
 | |
| import javax.swing.UIManager;
 | |
| import javax.swing.event.ChangeEvent;
 | |
| import javax.swing.event.ChangeListener;
 | |
| import javax.swing.plaf.ActionMapUIResource;
 | |
| import javax.swing.plaf.ComponentUI;
 | |
| import javax.swing.plaf.TabbedPaneUI;
 | |
| import javax.swing.plaf.UIResource;
 | |
| import javax.swing.text.View;
 | |
| 
 | |
| /**
 | |
|  * This is the Basic Look and Feel's UI delegate for JTabbedPane.
 | |
|  *
 | |
|  * @author Lillian Angel (langel@redhat.com)
 | |
|  * @author Kim Ho (kho@redhat.com)
 | |
|  * @author Roman Kennke (kennke@aicas.com)
 | |
|  * @author Robert Schuster (robertschuster@fsfe.org)
 | |
|  */
 | |
| public class BasicTabbedPaneUI extends TabbedPaneUI implements SwingConstants
 | |
| {
 | |
| 
 | |
|   static class NavigateAction extends AbstractAction
 | |
|   {
 | |
|     int direction;
 | |
| 
 | |
|     NavigateAction(String name, int dir)
 | |
|     {
 | |
|       super(name);
 | |
|       direction = dir;
 | |
|     }
 | |
| 
 | |
|     public void actionPerformed(ActionEvent event)
 | |
|     {
 | |
|       JTabbedPane tp = (JTabbedPane) event.getSource();
 | |
|       BasicTabbedPaneUI ui = (BasicTabbedPaneUI) tp.getUI();
 | |
| 
 | |
|       ui.navigateSelectedTab(direction);
 | |
|     }
 | |
| 
 | |
|   }
 | |
| 
 | |
|   static class NavigatePageDownAction extends AbstractAction
 | |
|   {
 | |
| 
 | |
|     public NavigatePageDownAction()
 | |
|     {
 | |
|       super("navigatePageDown");
 | |
|     }
 | |
| 
 | |
|     public void actionPerformed(ActionEvent event)
 | |
|     {
 | |
|       JTabbedPane tp = (JTabbedPane) event.getSource();
 | |
|       BasicTabbedPaneUI ui = (BasicTabbedPaneUI) tp.getUI();
 | |
| 
 | |
|       int i = tp.getSelectedIndex();
 | |
| 
 | |
|       if (i < 0)
 | |
|         i = 0;
 | |
| 
 | |
|       ui.selectNextTabInRun(i);
 | |
|     }
 | |
| 
 | |
|   }
 | |
| 
 | |
|   static class NavigatePageUpAction extends AbstractAction
 | |
|   {
 | |
| 
 | |
|     public NavigatePageUpAction()
 | |
|     {
 | |
|       super("navigatePageUp");
 | |
|     }
 | |
| 
 | |
|     public void actionPerformed(ActionEvent event)
 | |
|     {
 | |
|       JTabbedPane tp = (JTabbedPane) event.getSource();
 | |
|       BasicTabbedPaneUI ui = (BasicTabbedPaneUI) tp.getUI();
 | |
| 
 | |
|       int i = tp.getSelectedIndex();
 | |
| 
 | |
|       if (i < 0)
 | |
|         i = 0;
 | |
| 
 | |
|       ui.selectPreviousTabInRun(i);
 | |
| 
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   static class RequestFocusAction extends AbstractAction
 | |
|   {
 | |
| 
 | |
|     public RequestFocusAction()
 | |
|     {
 | |
|       super("requestFocus");
 | |
|     }
 | |
| 
 | |
|     public void actionPerformed(ActionEvent event)
 | |
|     {
 | |
|       ((JTabbedPane) event.getSource()).requestFocus();
 | |
|     }
 | |
| 
 | |
|   }
 | |
| 
 | |
|   static class RequestFocusForVisibleComponentAction extends AbstractAction
 | |
|   {
 | |
| 
 | |
|     public RequestFocusForVisibleComponentAction()
 | |
|     {
 | |
|       super("requestFocusForVisibleComponent");
 | |
|     }
 | |
| 
 | |
|     public void actionPerformed(ActionEvent event)
 | |
|     {
 | |
|       JTabbedPane tp = (JTabbedPane) event.getSource();
 | |
| 
 | |
|       // FIXME: This should select a suitable component within
 | |
|       // the tab content. However I dont know whether we have
 | |
|       // to search for this component or wether the called is
 | |
|       // supposed to do that.
 | |
|       tp.getSelectedComponent().requestFocus();
 | |
|     }
 | |
| 
 | |
|   }
 | |
| 
 | |
|   /**
 | |
|    * A helper class that handles focus.
 | |
|    * <p>The purpose of this class is to implement a more flexible focus
 | |
|    * handling for the tabbed pane, which is used to determine whether the
 | |
|    * focus indicator should be painted or not. When in scrolling layout
 | |
|    * mode the area containing the tabs is a scrollpane, so simply testing
 | |
|    * whether the tabbed pane has the focus does not work.</p>
 | |
|    * <p>The <code>FocusHandler</code> is installed on the scrollpane and
 | |
|    * the tabbed pane and sets the variable <code>hasFocus</code> to
 | |
|    * <code>false</code> only when both components do not hold the focus.</p>
 | |
|    *
 | |
|    * @specnote Apparently this class was intended to be protected,
 | |
|    *           but was made public by a compiler bug and is now
 | |
|    *           public for compatibility.
 | |
|    */
 | |
|   public class FocusHandler extends FocusAdapter
 | |
|   {
 | |
|     /**
 | |
|      * This method is called when the component gains focus.
 | |
|      *
 | |
|      * @param e The FocusEvent.
 | |
|      */
 | |
|     public void focusGained(FocusEvent e)
 | |
|     {
 | |
|       Object source = e.getSource();
 | |
|       if (source == panel )
 | |
|         tabPane.requestFocus();
 | |
|       else if (source == tabPane)
 | |
|         tabPane.repaint();
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * This method is called when the component loses focus.
 | |
|      *
 | |
|      * @param e The FocusEvent.
 | |
|      */
 | |
|     public void focusLost(FocusEvent e)
 | |
|     {
 | |
|       if (e.getOppositeComponent() == tabPane.getSelectedComponent())
 | |
|         tabPane.requestFocus();
 | |
|       else if (e.getSource() == tabPane)
 | |
|         tabPane.repaint();
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   /**
 | |
|    * A helper class for determining if mouse presses occur inside tabs and
 | |
|    * sets the index appropriately. In SCROLL_TAB_MODE, this class also
 | |
|    * handles the mouse clicks on the scrolling buttons.
 | |
|    *
 | |
|    * @specnote Apparently this class was intended to be protected,
 | |
|    *           but was made public by a compiler bug and is now
 | |
|    *           public for compatibility.
 | |
|    */
 | |
|   public class MouseHandler extends MouseAdapter
 | |
|   {
 | |
|     public void mouseReleased(MouseEvent e)
 | |
|     {
 | |
|       Object s = e.getSource();
 | |
| 
 | |
|       // Event may originate from the viewport in
 | |
|       // SCROLL_TAB_LAYOUT mode. It is redisptached
 | |
|       // through the tabbed pane then.
 | |
|       if (tabPane != e.getSource())
 | |
|         {
 | |
|           redispatchEvent(e);
 | |
|           e.setSource(s);
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * This method is called when the mouse is pressed. The index cannot
 | |
|      * change to a tab that is  not enabled.
 | |
|      *
 | |
|      * @param e The MouseEvent.
 | |
|      */
 | |
|     public void mousePressed(MouseEvent e)
 | |
|     {
 | |
|       Object s = e.getSource();
 | |
| 
 | |
|       // Event may originate from the viewport in
 | |
|       // SCROLL_TAB_LAYOUT mode. It is redisptached
 | |
|       // through the tabbed pane then.
 | |
|       if (tabPane != e.getSource())
 | |
|         {
 | |
|           redispatchEvent(e);
 | |
|           e.setSource(s);
 | |
|         }
 | |
| 
 | |
|       int placement = tabPane.getTabPlacement();
 | |
| 
 | |
|       if (s == incrButton)
 | |
|         {
 | |
|           if(!incrButton.isEnabled())
 | |
|             return;
 | |
| 
 | |
|           currentScrollLocation++;
 | |
| 
 | |
|           switch (placement)
 | |
|             {
 | |
|               case JTabbedPane.TOP:
 | |
|               case JTabbedPane.BOTTOM:
 | |
|                 currentScrollOffset = getTabAreaInsets(placement).left;
 | |
|                 for (int i = 0; i < currentScrollLocation; i++)
 | |
|                   currentScrollOffset += rects[i].width;
 | |
|                 break;
 | |
|               default:
 | |
|                 currentScrollOffset = getTabAreaInsets(placement).top;
 | |
|                 for (int i = 0; i < currentScrollLocation; i++)
 | |
|                   currentScrollOffset += rects[i].height;
 | |
|                 break;
 | |
|             }
 | |
| 
 | |
|           updateViewPosition();
 | |
|           updateButtons();
 | |
| 
 | |
|           tabPane.repaint();
 | |
|         }
 | |
|       else if (s == decrButton)
 | |
|         {
 | |
|           if(!decrButton.isEnabled())
 | |
|             return;
 | |
| 
 | |
|            // The scroll location may be zero but the offset
 | |
|            // greater than zero because of an adjustement to
 | |
|            // make a partially visible tab completely visible.
 | |
|            if (currentScrollLocation > 0)
 | |
|              currentScrollLocation--;
 | |
| 
 | |
|            // Set the offset back to 0 and recompute it.
 | |
|            currentScrollOffset = 0;
 | |
| 
 | |
|            switch (placement)
 | |
|              {
 | |
|                case JTabbedPane.TOP:
 | |
|                case JTabbedPane.BOTTOM:
 | |
|                  // Take the tab area inset into account.
 | |
|                  if (currentScrollLocation > 0)
 | |
|                    currentScrollOffset = getTabAreaInsets(placement).left;
 | |
|                  // Recompute scroll offset.
 | |
|                  for (int i = 0; i < currentScrollLocation; i++)
 | |
|                    currentScrollOffset += rects[i].width;
 | |
|                  break;
 | |
|                default:
 | |
|                  // Take the tab area inset into account.
 | |
|                  if (currentScrollLocation > 0)
 | |
|                    currentScrollOffset = getTabAreaInsets(placement).top;
 | |
| 
 | |
|                  for (int i = 0; i < currentScrollLocation; i++)
 | |
|                    currentScrollOffset += rects[i].height;
 | |
|              }
 | |
| 
 | |
|            updateViewPosition();
 | |
|            updateButtons();
 | |
| 
 | |
|            tabPane.repaint();
 | |
|         }
 | |
|       else if (tabPane.isEnabled())
 | |
|         {
 | |
|           int index = tabForCoordinate(tabPane, e.getX(), e.getY());
 | |
|           if (!tabPane.isEnabledAt(index))
 | |
|             return;
 | |
| 
 | |
|           if (tabPane.getTabLayoutPolicy() == JTabbedPane.SCROLL_TAB_LAYOUT
 | |
|               && s == panel)
 | |
|             {
 | |
|               scrollTab(index, placement);
 | |
| 
 | |
|               tabPane.setSelectedIndex(index);
 | |
|               tabPane.repaint();
 | |
|             }
 | |
|           else
 | |
|             {
 | |
|               tabPane.setSelectedIndex(index);
 | |
|               tabPane.revalidate();
 | |
|               tabPane.repaint();
 | |
|             }
 | |
| 
 | |
|         }
 | |
| 
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * Receives notification when the mouse pointer has entered the tabbed
 | |
|      * pane.
 | |
|      *
 | |
|      * @param e the mouse event
 | |
|      */
 | |
|     public void mouseEntered(MouseEvent e)
 | |
|     {
 | |
|       Object s = e.getSource();
 | |
| 
 | |
|       // Event may originate from the viewport in
 | |
|       // SCROLL_TAB_LAYOUT mode. It is redisptached
 | |
|       // through the tabbed pane then.
 | |
|       if (tabPane != e.getSource())
 | |
|         {
 | |
|           redispatchEvent(e);
 | |
|           e.setSource(s);
 | |
|         }
 | |
| 
 | |
|       int tabIndex = tabForCoordinate(tabPane, e.getX(), e.getY());
 | |
|       setRolloverTab(tabIndex);
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * Receives notification when the mouse pointer has exited the tabbed
 | |
|      * pane.
 | |
|      *
 | |
|      * @param e the mouse event
 | |
|      */
 | |
|     public void mouseExited(MouseEvent e)
 | |
|     {
 | |
|       Object s = e.getSource();
 | |
| 
 | |
|       // Event may originate from the viewport in
 | |
|       // SCROLL_TAB_LAYOUT mode. It is redisptached
 | |
|       // through the tabbed pane then.
 | |
|       if (tabPane != e.getSource())
 | |
|         {
 | |
|           redispatchEvent(e);
 | |
|           e.setSource(s);
 | |
|         }
 | |
| 
 | |
|       setRolloverTab(-1);
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * Receives notification when the mouse pointer has moved over the tabbed
 | |
|      * pane.
 | |
|      *
 | |
|      * @param ev the mouse event
 | |
|      */
 | |
|     public void mouseMoved(MouseEvent ev)
 | |
|     {
 | |
|       Object s = ev.getSource();
 | |
| 
 | |
|       if (tabPane != ev.getSource())
 | |
|         {
 | |
|           ev.setSource(tabPane);
 | |
|           tabPane.dispatchEvent(ev);
 | |
| 
 | |
|           ev.setSource(s);
 | |
|         }
 | |
| 
 | |
|       int tabIndex = tabForCoordinate(tabPane, ev.getX(), ev.getY());
 | |
|       setRolloverTab(tabIndex);
 | |
|     }
 | |
| 
 | |
|     /** Modifies the mouse event to originate from
 | |
|      * the tabbed pane and redispatches it.
 | |
|      *
 | |
|      * @param me
 | |
|      */
 | |
|     void redispatchEvent(MouseEvent me)
 | |
|     {
 | |
|       me.setSource(tabPane);
 | |
|       Point viewPos = viewport.getViewPosition();
 | |
|       viewPos.x -= viewport.getX();
 | |
|       viewPos.y -= viewport.getY();
 | |
|       me.translatePoint(-viewPos.x, -viewPos.y);
 | |
|       tabPane.dispatchEvent(me);
 | |
| 
 | |
|       me.translatePoint(viewPos.x, viewPos.y);
 | |
|     }
 | |
| 
 | |
|   }
 | |
| 
 | |
|   /**
 | |
|    * This class handles PropertyChangeEvents fired from the JTabbedPane.
 | |
|    *
 | |
|    * @specnote Apparently this class was intended to be protected,
 | |
|    *           but was made public by a compiler bug and is now
 | |
|    *           public for compatibility.
 | |
|    */
 | |
|   public class PropertyChangeHandler implements PropertyChangeListener
 | |
|   {
 | |
|     /**
 | |
|      * This method is called whenever one of the properties of the JTabbedPane
 | |
|      * changes.
 | |
|      *
 | |
|      * @param e The PropertyChangeEvent.
 | |
|      */
 | |
|     public void propertyChange(PropertyChangeEvent e)
 | |
|     {
 | |
|       out:
 | |
|         {
 | |
|           if (e.getPropertyName().equals("tabLayoutPolicy"))
 | |
|             {
 | |
|               currentScrollLocation = currentScrollOffset = 0;
 | |
| 
 | |
|               layoutManager = createLayoutManager();
 | |
| 
 | |
|               tabPane.setLayout(layoutManager);
 | |
|             }
 | |
|           else if (e.getPropertyName().equals("tabPlacement")
 | |
|                    && tabPane.getTabLayoutPolicy()
 | |
|                    == JTabbedPane.SCROLL_TAB_LAYOUT)
 | |
|             {
 | |
|               incrButton = createIncreaseButton();
 | |
|               decrButton = createDecreaseButton();
 | |
| 
 | |
|               // If the tab placement value was changed of a tabbed pane
 | |
|               // in SCROLL_TAB_LAYOUT mode we investigate the change to
 | |
|               // implement the following behavior which was observed in
 | |
|               // the RI:
 | |
|               // The scrolling offset will be reset if we change to
 | |
|               // a direction which is orthogonal to the current
 | |
|               // direction and stays the same if it is parallel.
 | |
| 
 | |
|               int oldPlacement = ((Integer) e.getOldValue()).intValue();
 | |
|               int newPlacement = ((Integer) e.getNewValue()).intValue();
 | |
|               switch (newPlacement)
 | |
|                 {
 | |
|                   case JTabbedPane.TOP:
 | |
|                   case JTabbedPane.BOTTOM:
 | |
|                     if (oldPlacement == JTabbedPane.TOP
 | |
|                         || oldPlacement == JTabbedPane.BOTTOM)
 | |
|                       break out;
 | |
| 
 | |
|                     currentScrollOffset = getTabAreaInsets(newPlacement).left;
 | |
|                     break;
 | |
|                   default:
 | |
|                     if (oldPlacement == JTabbedPane.LEFT
 | |
|                        || oldPlacement == JTabbedPane.RIGHT)
 | |
|                       break out;
 | |
| 
 | |
|                     currentScrollOffset = getTabAreaInsets(newPlacement).top;
 | |
|                 }
 | |
| 
 | |
|               updateViewPosition();
 | |
|               updateButtons();
 | |
|             }
 | |
|         }
 | |
| 
 | |
|       tabPane.revalidate();
 | |
|       tabPane.repaint();
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   /**
 | |
|    * A LayoutManager responsible for placing all the tabs and the visible
 | |
|    * component inside the JTabbedPane. This class is only used for
 | |
|    * WRAP_TAB_LAYOUT.
 | |
|    *
 | |
|    * @specnote Apparently this class was intended to be protected,
 | |
|    *           but was made public by a compiler bug and is now
 | |
|    *           public for compatibility.
 | |
|    */
 | |
|   public class TabbedPaneLayout implements LayoutManager
 | |
|   {
 | |
|     /**
 | |
|      * This method is called when a component is added to the JTabbedPane.
 | |
|      *
 | |
|      * @param name The name of the component.
 | |
|      * @param comp The component being added.
 | |
|      */
 | |
|     public void addLayoutComponent(String name, Component comp)
 | |
|     {
 | |
|       // Do nothing.
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * This method is called when the rectangles need to be calculated. It
 | |
|      * also fixes the size of the visible component.
 | |
|      */
 | |
|     public void calculateLayoutInfo()
 | |
|     {
 | |
|       int count = tabPane.getTabCount();
 | |
|       assureRectsCreated(count);
 | |
|       calculateTabRects(tabPane.getTabPlacement(), count);
 | |
|       tabRunsDirty = false;
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * This method calculates the size of the the JTabbedPane.
 | |
|      *
 | |
|      * @param minimum Whether the JTabbedPane will try to be as small as it
 | |
|      *        can.
 | |
|      *
 | |
|      * @return The desired size of the JTabbedPane.
 | |
|      */
 | |
|     protected Dimension calculateSize(boolean minimum)
 | |
|     {
 | |
|       int tabPlacement = tabPane.getTabPlacement();
 | |
| 
 | |
|       int width = 0;
 | |
|       int height = 0;
 | |
|       Component c;
 | |
|       Dimension dims;
 | |
| 
 | |
|       // Find out the minimum/preferred size to display the largest child
 | |
|       // of the tabbed pane.
 | |
|       int count = tabPane.getTabCount();
 | |
|       for (int i = 0; i < count; i++)
 | |
|         {
 | |
|           c = tabPane.getComponentAt(i);
 | |
|           if (c == null)
 | |
|             continue;
 | |
|           dims = minimum ? c.getMinimumSize() : c.getPreferredSize();
 | |
|           if (dims != null)
 | |
|             {
 | |
|               height = Math.max(height, dims.height);
 | |
|               width = Math.max(width, dims.width);
 | |
|             }
 | |
|         }
 | |
| 
 | |
|       Insets tabAreaInsets = getTabAreaInsets(tabPlacement);
 | |
|       if (tabPlacement == SwingConstants.TOP
 | |
|           || tabPlacement == SwingConstants.BOTTOM)
 | |
|         {
 | |
|           width = Math.max(calculateMaxTabWidth(tabPlacement), width);
 | |
| 
 | |
|           height += preferredTabAreaHeight(tabPlacement,
 | |
|                                            width - tabAreaInsets.left
 | |
|                                            - tabAreaInsets.right);
 | |
|         }
 | |
|       else
 | |
|         {
 | |
|           height = Math.max(calculateMaxTabHeight(tabPlacement), height);
 | |
| 
 | |
|           width += preferredTabAreaWidth(tabPlacement,
 | |
|                                          height - tabAreaInsets.top
 | |
|                                          - tabAreaInsets.bottom);
 | |
|         }
 | |
| 
 | |
|       Insets tabPaneInsets = tabPane.getInsets();
 | |
|       return new Dimension(width + tabPaneInsets.left + tabPaneInsets.right,
 | |
|                            height + tabPaneInsets.top + tabPaneInsets.bottom);
 | |
|     }
 | |
| 
 | |
|     // if tab placement is LEFT OR RIGHT, they share width.
 | |
|     // if tab placement is TOP OR BOTTOM, they share height
 | |
|     // PRE STEP: finds the default sizes for the labels as well as their
 | |
|     // locations.
 | |
|     // AND where they will be placed within the run system.
 | |
|     // 1. calls normalizeTab Runs.
 | |
|     // 2. calls rotate tab runs.
 | |
|     // 3. pads the tab runs.
 | |
|     // 4. pads the selected tab.
 | |
| 
 | |
|     /**
 | |
|      * This method is called to calculate the tab rectangles.  This method
 | |
|      * will calculate the size and position of all  rectangles (taking into
 | |
|      * account which ones should be in which tab run). It will pad them and
 | |
|      * normalize them  as necessary.
 | |
|      *
 | |
|      * @param tabPlacement The JTabbedPane's tab placement.
 | |
|      * @param tabCount The run the current selection is in.
 | |
|      */
 | |
|     protected void calculateTabRects(int tabPlacement, int tabCount)
 | |
|     {
 | |
|       Insets insets = tabPane.getInsets();
 | |
|       Insets tabAreaInsets = getTabAreaInsets(tabPlacement);
 | |
|       Dimension size = tabPane.getSize();
 | |
| 
 | |
|       // The coordinates of the upper left corner of the tab area.
 | |
|       int x;
 | |
|       int y;
 | |
|       // The location at which the runs must be broken.
 | |
|       int breakAt;
 | |
| 
 | |
|       // Calculate the bounds for the tab area.
 | |
|       switch (tabPlacement)
 | |
|       {
 | |
|         case LEFT:
 | |
|           maxTabWidth = calculateMaxTabWidth(tabPlacement);
 | |
|           x = insets.left + tabAreaInsets.left;
 | |
|           y = insets.top + tabAreaInsets.top;
 | |
|           breakAt = size.height - (insets.bottom + tabAreaInsets.bottom);
 | |
|           break;
 | |
|         case RIGHT:
 | |
|           maxTabWidth = calculateMaxTabWidth(tabPlacement);
 | |
|           x = size.width - (insets.right + tabAreaInsets.right)
 | |
|               - maxTabWidth - 1;
 | |
|           y = insets.top + tabAreaInsets.top;
 | |
|           breakAt = size.height - (insets.bottom + tabAreaInsets.bottom);
 | |
|           break;
 | |
|         case BOTTOM:
 | |
|           maxTabHeight = calculateMaxTabHeight(tabPlacement);
 | |
|           x = insets.left + tabAreaInsets.left;
 | |
|           y = size.height - (insets.bottom + tabAreaInsets.bottom)
 | |
|               - maxTabHeight - 1;
 | |
|           breakAt = size.width - (insets.right + tabAreaInsets.right);
 | |
|           break;
 | |
|         case TOP:
 | |
|         default:
 | |
|           maxTabHeight = calculateMaxTabHeight(tabPlacement);
 | |
|           x = insets.left + tabAreaInsets.left;
 | |
|           y = insets.top + tabAreaInsets.top;
 | |
|           breakAt = size.width - (insets.right + tabAreaInsets.right);
 | |
|           break;
 | |
|       }
 | |
| 
 | |
|       if (tabCount == 0)
 | |
|         return;
 | |
| 
 | |
|       FontMetrics fm = getFontMetrics();
 | |
|       runCount = 0;
 | |
|       selectedRun = -1;
 | |
|       int selectedIndex = tabPane.getSelectedIndex();
 | |
|       if (selectedIndex < 0)
 | |
|           selectedIndex = 0;
 | |
| 
 | |
|       Rectangle rect;
 | |
| 
 | |
|       // Go through all the tabs and build the tab runs.
 | |
|       if (tabPlacement == SwingConstants.TOP
 | |
|           || tabPlacement == SwingConstants.BOTTOM)
 | |
|         {
 | |
|           for (int i = 0; i < tabCount; i++)
 | |
|             {
 | |
|               rect = rects[i];
 | |
|               if (i > 0)
 | |
|                 {
 | |
|                   rect.x = rects[i - 1].x + rects[i - 1].width;
 | |
|                 }
 | |
|               else
 | |
|                 {
 | |
|                   tabRuns[0] = 0;
 | |
|                   runCount = 1;
 | |
|                   maxTabWidth = 0;
 | |
|                   rect.x = x;
 | |
|                 }
 | |
|               rect.width = calculateTabWidth(tabPlacement, i, fm);
 | |
|               maxTabWidth = Math.max(maxTabWidth, rect.width);
 | |
| 
 | |
|               if (rect.x != 2 + insets.left && rect.x + rect.width > breakAt)
 | |
|                 {
 | |
|                   if (runCount > tabRuns.length - 1)
 | |
|                     expandTabRunsArray();
 | |
|                   tabRuns[runCount] = i;
 | |
|                   runCount++;
 | |
|                   rect.x = x;
 | |
|                 }
 | |
| 
 | |
|               rect.y = y;
 | |
|               rect.height = maxTabHeight;
 | |
|               if (i == selectedIndex)
 | |
|                 selectedRun = runCount - 1;
 | |
|             }
 | |
|         }
 | |
|       else
 | |
|         {
 | |
|           for (int i = 0; i < tabCount; i++)
 | |
|             {
 | |
|               rect = rects[i];
 | |
|               if (i > 0)
 | |
|                 {
 | |
|                   rect.y = rects[i - 1].y + rects[i - 1].height;
 | |
|                 }
 | |
|               else
 | |
|                 {
 | |
|                   tabRuns[0] = 0;
 | |
|                   runCount = 1;
 | |
|                   maxTabHeight = 0;
 | |
|                   rect.y = y;
 | |
|                 }
 | |
|               rect.height = calculateTabHeight(tabPlacement, i,
 | |
|                                                fm.getHeight());
 | |
|               maxTabHeight = Math.max(maxTabHeight, rect.height);
 | |
| 
 | |
|               if (rect.y != 2 + insets.top && rect.y + rect.height > breakAt)
 | |
|                 {
 | |
|                   if (runCount > tabRuns.length - 1)
 | |
|                     expandTabRunsArray();
 | |
|                   tabRuns[runCount] = i;
 | |
|                   runCount++;
 | |
|                   rect.y = y;
 | |
|                 }
 | |
| 
 | |
|               rect.x = x;
 | |
|               rect.width = maxTabWidth;
 | |
| 
 | |
|               if (i == selectedIndex)
 | |
|                 selectedRun = runCount - 1;
 | |
|             }
 | |
|         }
 | |
| 
 | |
|       if (runCount > 1)
 | |
|         {
 | |
|           int start;
 | |
|           if  (tabPlacement == SwingConstants.TOP
 | |
|               || tabPlacement == SwingConstants.BOTTOM)
 | |
|             start = x;
 | |
|           else
 | |
|             start = y;
 | |
|           normalizeTabRuns(tabPlacement, tabCount, start, breakAt);
 | |
|           selectedRun = getRunForTab(tabCount, selectedIndex);
 | |
|           if (shouldRotateTabRuns(tabPlacement))
 | |
|             {
 | |
|               rotateTabRuns(tabPlacement, selectedRun);
 | |
|             }
 | |
|         }
 | |
| 
 | |
|       // Suppress padding if we have only one tab run.
 | |
|       if (runCount == 1)
 | |
|         return;
 | |
| 
 | |
|       // Pad the runs.
 | |
|       int tabRunOverlay = getTabRunOverlay(tabPlacement);
 | |
|       for (int i = runCount - 1; i >= 0; --i)
 | |
|         {
 | |
|           int start = tabRuns[i];
 | |
|           int nextIndex;
 | |
|           if (i == runCount - 1)
 | |
|             nextIndex = 0;
 | |
|           else
 | |
|             nextIndex = i + 1;
 | |
|           int next = tabRuns[nextIndex];
 | |
|           int end = next != 0 ? next - 1 : tabCount - 1;
 | |
|           if (tabPlacement == SwingConstants.TOP
 | |
|               || tabPlacement == SwingConstants.BOTTOM)
 | |
|             {
 | |
|               for (int j = start; j <= end; ++j)
 | |
|                 {
 | |
|                   rect = rects[j];
 | |
|                   rect.y = y;
 | |
|                   rect.x += getTabRunIndent(tabPlacement, i);
 | |
|                 }
 | |
|               if (shouldPadTabRun(tabPlacement, i))
 | |
|                 {
 | |
|                   padTabRun(tabPlacement, start, end, breakAt);
 | |
|                 }
 | |
|               if (tabPlacement == BOTTOM)
 | |
|                 y -= maxTabHeight - tabRunOverlay;
 | |
|               else
 | |
|                 y += maxTabHeight - tabRunOverlay;
 | |
|             }
 | |
|           else
 | |
|             {
 | |
|               for (int j = start; j <= end; ++j)
 | |
|                 {
 | |
|                   rect = rects[j];
 | |
|                   rect.x = x;
 | |
|                   rect.y += getTabRunIndent(tabPlacement, i);
 | |
|                 }
 | |
|               if (shouldPadTabRun(tabPlacement, i))
 | |
|                 {
 | |
|                   padTabRun(tabPlacement, start, end, breakAt);
 | |
|                 }
 | |
|               if (tabPlacement == RIGHT)
 | |
|                 x -= maxTabWidth - tabRunOverlay;
 | |
|               else
 | |
|                 x += maxTabWidth - tabRunOverlay;
 | |
| 
 | |
|             }
 | |
|         }
 | |
|       padSelectedTab(tabPlacement, selectedIndex);
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * This method is called when the JTabbedPane is laid out in
 | |
|      * WRAP_TAB_LAYOUT. It calls calculateLayoutInfo to  find the positions
 | |
|      * of all its components.
 | |
|      *
 | |
|      * @param parent The Container to lay out.
 | |
|      */
 | |
|     public void layoutContainer(Container parent)
 | |
|     {
 | |
|       calculateLayoutInfo();
 | |
| 
 | |
|       int tabPlacement = tabPane.getTabPlacement();
 | |
|       Insets insets = tabPane.getInsets();
 | |
| 
 | |
|       int selectedIndex = tabPane.getSelectedIndex();
 | |
| 
 | |
|       Component selectedComponent = null;
 | |
|       if (selectedIndex >= 0)
 | |
|         selectedComponent = tabPane.getComponentAt(selectedIndex);
 | |
|       // The RI doesn't seem to change the component if the new selected
 | |
|       // component == null. This is probably so that applications can add
 | |
|       // one single component for every tab.
 | |
|       if (selectedComponent != null)
 | |
|         {
 | |
|           setVisibleComponent(selectedComponent);
 | |
|         }
 | |
| 
 | |
|       int childCount = tabPane.getComponentCount();
 | |
|       if (childCount > 0)
 | |
|         {
 | |
|           int compX;
 | |
|           int compY;
 | |
|           int tabAreaWidth = 0;
 | |
|           int tabAreaHeight = 0;
 | |
|           switch (tabPlacement)
 | |
|           {
 | |
|             case LEFT:
 | |
|               tabAreaWidth = calculateTabAreaWidth(tabPlacement, runCount,
 | |
|                                                    maxTabWidth);
 | |
|               compX = tabAreaWidth + insets.left + contentBorderInsets.left;
 | |
|               compY = insets.top + contentBorderInsets.top;
 | |
|               break;
 | |
|             case RIGHT:
 | |
|               tabAreaWidth = calculateTabAreaWidth(tabPlacement, runCount,
 | |
|                                                    maxTabWidth);
 | |
|               compX = insets.left + contentBorderInsets.left;
 | |
|               compY = insets.top + contentBorderInsets.top;
 | |
|               break;
 | |
|             case BOTTOM:
 | |
|               tabAreaHeight = calculateTabAreaHeight(tabPlacement, runCount,
 | |
|                                                      maxTabHeight);
 | |
|               compX = insets.left + contentBorderInsets.left;
 | |
|               compY = insets.top + contentBorderInsets.top;
 | |
|               break;
 | |
|             case TOP:
 | |
|             default:
 | |
|               tabAreaHeight = calculateTabAreaHeight(tabPlacement, runCount,
 | |
|                                                      maxTabHeight);
 | |
| 
 | |
|               compX = insets.left + contentBorderInsets.left;
 | |
|               compY = tabAreaHeight + insets.top + contentBorderInsets.top;
 | |
|           }
 | |
|           Rectangle bounds = tabPane.getBounds();
 | |
|           int compWidth = bounds.width - tabAreaWidth - insets.left
 | |
|                           - insets.right - contentBorderInsets.left
 | |
|                           - contentBorderInsets.right;
 | |
|           int compHeight = bounds.height - tabAreaHeight - insets.top
 | |
|                            - insets.bottom - contentBorderInsets.top
 | |
|                            - contentBorderInsets.bottom;
 | |
| 
 | |
| 
 | |
|           for (int i = 0; i < childCount; ++i)
 | |
|             {
 | |
|               Component c = tabPane.getComponent(i);
 | |
|               c.setBounds(compX, compY, compWidth, compHeight);
 | |
|             }
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * This method returns the minimum layout size for the given container.
 | |
|      *
 | |
|      * @param parent The container that is being sized.
 | |
|      *
 | |
|      * @return The minimum size.
 | |
|      */
 | |
|     public Dimension minimumLayoutSize(Container parent)
 | |
|     {
 | |
|       return calculateSize(true);
 | |
|     }
 | |
| 
 | |
|     // If there is more free space in an adjacent run AND the tab
 | |
|     // in the run can fit in the adjacent run, move it. This method
 | |
|     // is not perfect, it is merely an approximation.
 | |
|     // If you play around with Sun's JTabbedPane, you'll see that
 | |
|     // it does do some pretty strange things with regards to not moving tabs
 | |
|     // that should be moved.
 | |
|     // start = the x position where the tabs will begin
 | |
|     // max = the maximum position of where the tabs can go to
 | |
|     // (tabAreaInsets.left + the width of the tab area)
 | |
| 
 | |
|     /**
 | |
|      * This method tries to "even out" the number of tabs in each run based on
 | |
|      * their widths.
 | |
|      *
 | |
|      * @param tabPlacement The JTabbedPane's tab placement.
 | |
|      * @param tabCount The number of tabs.
 | |
|      * @param start The x position where the tabs will begin.
 | |
|      * @param max The maximum x position where the tab can run to.
 | |
|      */
 | |
|     protected void normalizeTabRuns(int tabPlacement, int tabCount, int start,
 | |
|                                     int max)
 | |
|     {
 | |
|       boolean horizontal = tabPlacement == TOP || tabPlacement == BOTTOM;
 | |
|       int currentRun = runCount - 1;
 | |
|       double weight = 1.25;
 | |
|       for (boolean adjust = true; adjust == true;)
 | |
|         {
 | |
|           int last = lastTabInRun(tabCount, currentRun);
 | |
|           int prevLast = lastTabInRun(tabCount, currentRun - 1);
 | |
|           int end;
 | |
|           int prevLength;
 | |
|           if (horizontal)
 | |
|             {
 | |
|               end = rects[last].x + rects[last].width;
 | |
|               prevLength = (int) (maxTabWidth * weight);
 | |
|             }
 | |
|           else
 | |
|             {
 | |
|               end = rects[last].y + rects[last].height;
 | |
|               prevLength = (int) (maxTabWidth * weight * 2);
 | |
|             }
 | |
|           if (max - end > prevLength)
 | |
|             {
 | |
|               tabRuns[currentRun] = prevLast;
 | |
|               if (horizontal)
 | |
|                 rects[prevLast].x = start;
 | |
|               else
 | |
|                 rects[prevLast].y = start;
 | |
|               for (int i = prevLast + 1; i <= last; i++)
 | |
|                 {
 | |
|                   if (horizontal)
 | |
|                     rects[i].x = rects[i - 1].x + rects[i - 1].width;
 | |
|                   else
 | |
|                     rects[i].y = rects[i - 1].y + rects[i - 1].height;
 | |
|                 }
 | |
|             }
 | |
|           else if (currentRun == runCount - 1)
 | |
|             adjust = false;
 | |
|           if (currentRun - 1 > 0)
 | |
|             currentRun -= 1;
 | |
|           else
 | |
|             {
 | |
|               // Check again, but with higher ratio to avoid
 | |
|               // clogging up the last run.
 | |
|               currentRun = runCount - 1;
 | |
|               weight += 0.25;
 | |
|             }
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * This method pads the tab at the selected index by the  selected tab pad
 | |
|      * insets (so that it looks larger).
 | |
|      *
 | |
|      * @param tabPlacement The placement of the tabs.
 | |
|      * @param selectedIndex The selected index.
 | |
|      */
 | |
|     protected void padSelectedTab(int tabPlacement, int selectedIndex)
 | |
|     {
 | |
|       Insets insets = getSelectedTabPadInsets(tabPlacement);
 | |
|       rects[selectedIndex].x -= insets.left;
 | |
|       rects[selectedIndex].y -= insets.top;
 | |
|       rects[selectedIndex].width += insets.left + insets.right;
 | |
|       rects[selectedIndex].height += insets.top + insets.bottom;
 | |
|     }
 | |
| 
 | |
|     // If the tabs on the run don't fill the width of the window, make it
 | |
|     // fit now.
 | |
|     // start = starting index of the run
 | |
|     // end = last index of the run
 | |
|     // max = tabAreaInsets.left + width (or equivalent)
 | |
|     // assert start <= end.
 | |
| 
 | |
|     /**
 | |
|      * This method makes each tab in the run larger so that the  tabs expand
 | |
|      * to fill the runs width/height (depending on tabPlacement).
 | |
|      *
 | |
|      * @param tabPlacement The placement of the tabs.
 | |
|      * @param start The index of the first tab.
 | |
|      * @param end The last index of the tab
 | |
|      * @param max The amount of space in the run (width for TOP and BOTTOM
 | |
|      *        tabPlacement).
 | |
|      */
 | |
|     protected void padTabRun(int tabPlacement, int start, int end, int max)
 | |
|     {
 | |
|       if (tabPlacement == SwingConstants.TOP
 | |
|           || tabPlacement == SwingConstants.BOTTOM)
 | |
|         {
 | |
|           int runWidth = rects[end].x + rects[end].width;
 | |
|           int spaceRemaining = max - runWidth;
 | |
|           int numTabs = end - start + 1;
 | |
| 
 | |
|           // now divvy up the space.
 | |
|           int spaceAllocated = spaceRemaining / numTabs;
 | |
|           int currX = rects[start].x;
 | |
|           for (int i = start; i <= end; i++)
 | |
|             {
 | |
|               rects[i].x = currX;
 | |
|               rects[i].width += spaceAllocated;
 | |
| 
 | |
|               currX += rects[i].width;
 | |
|               // This is used because since the spaceAllocated
 | |
|               // variable is an int, it rounds down. Sometimes,
 | |
|               // we don't fill an entire row, so we make it do
 | |
|               // so now.
 | |
| 
 | |
|               if (i == end && rects[i].x + rects[i].width != max)
 | |
|                 rects[i].width = max - rects[i].x;
 | |
|             }
 | |
|         }
 | |
|       else
 | |
|         {
 | |
|           int runHeight = rects[end].y + rects[end].height;
 | |
|           int spaceRemaining = max - runHeight;
 | |
|           int numTabs = end - start + 1;
 | |
| 
 | |
|           int spaceAllocated = spaceRemaining / numTabs;
 | |
|           int currY = rects[start].y;
 | |
|           for (int i = start; i <= end; i++)
 | |
|             {
 | |
|               rects[i].y = currY;
 | |
|               rects[i].height += spaceAllocated;
 | |
|               currY += rects[i].height;
 | |
|               if (i == end && rects[i].y + rects[i].height != max)
 | |
|                 rects[i].height = max - rects[i].y;
 | |
|             }
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * This method returns the preferred layout size for the given container.
 | |
|      *
 | |
|      * @param parent The container to size.
 | |
|      *
 | |
|      * @return The preferred layout size.
 | |
|      */
 | |
|     public Dimension preferredLayoutSize(Container parent)
 | |
|     {
 | |
|       return calculateSize(false);
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * This method returns the preferred tab height given a tabPlacement and
 | |
|      * width.
 | |
|      *
 | |
|      * @param tabPlacement The JTabbedPane's tab placement.
 | |
|      * @param width The expected width.
 | |
|      *
 | |
|      * @return The preferred tab area height.
 | |
|      */
 | |
|     protected int preferredTabAreaHeight(int tabPlacement, int width)
 | |
|     {
 | |
|       if (tabPane.getTabCount() == 0)
 | |
|         return calculateTabAreaHeight(tabPlacement, 0, 0);
 | |
| 
 | |
|       int runs = 0;
 | |
|       int runWidth = 0;
 | |
|       int tabWidth = 0;
 | |
| 
 | |
|       FontMetrics fm = getFontMetrics();
 | |
| 
 | |
|       Insets tabAreaInsets = getTabAreaInsets(tabPlacement);
 | |
|       Insets insets = tabPane.getInsets();
 | |
| 
 | |
|       // Only interested in width, this is a messed up rectangle now.
 | |
|       width -= tabAreaInsets.left + tabAreaInsets.right + insets.left
 | |
|       + insets.right;
 | |
| 
 | |
|       // The reason why we can't use runCount:
 | |
|       // This method is only called to calculate the size request
 | |
|       // for the tabbedPane. However, this size request is dependent on
 | |
|       // our desired width. We need to find out what the height would
 | |
|       // be IF we got our desired width.
 | |
|       for (int i = 0; i < tabPane.getTabCount(); i++)
 | |
|         {
 | |
|           tabWidth = calculateTabWidth(tabPlacement, i, fm);
 | |
|           if (runWidth + tabWidth > width)
 | |
|             {
 | |
|               runWidth = tabWidth;
 | |
|               runs++;
 | |
|             }
 | |
|           else
 | |
|             runWidth += tabWidth;
 | |
|         }
 | |
|       runs++;
 | |
| 
 | |
|       int maxTabHeight = calculateMaxTabHeight(tabPlacement);
 | |
|       int tabAreaHeight = calculateTabAreaHeight(tabPlacement, runs,
 | |
|                                                  maxTabHeight);
 | |
|       return tabAreaHeight;
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * This method calculates the preferred tab area width given a tab
 | |
|      * placement and height.
 | |
|      *
 | |
|      * @param tabPlacement The JTabbedPane's tab placement.
 | |
|      * @param height The expected height.
 | |
|      *
 | |
|      * @return The preferred tab area width.
 | |
|      */
 | |
|     protected int preferredTabAreaWidth(int tabPlacement, int height)
 | |
|     {
 | |
|       if (tabPane.getTabCount() == 0)
 | |
|         return calculateTabAreaHeight(tabPlacement, 0, 0);
 | |
| 
 | |
|       int runs = 0;
 | |
|       int runHeight = 0;
 | |
|       int tabHeight = 0;
 | |
| 
 | |
|       FontMetrics fm = getFontMetrics();
 | |
| 
 | |
|       Insets tabAreaInsets = getTabAreaInsets(tabPlacement);
 | |
|       Insets insets = tabPane.getInsets();
 | |
| 
 | |
|       height -= tabAreaInsets.top + tabAreaInsets.bottom + insets.top
 | |
|       + insets.bottom;
 | |
|       int fontHeight = fm.getHeight();
 | |
| 
 | |
|       for (int i = 0; i < tabPane.getTabCount(); i++)
 | |
|         {
 | |
|           tabHeight = calculateTabHeight(tabPlacement, i, fontHeight);
 | |
|           if (runHeight + tabHeight > height)
 | |
|             {
 | |
|               runHeight = tabHeight;
 | |
|               runs++;
 | |
|             }
 | |
|           else
 | |
|             runHeight += tabHeight;
 | |
|         }
 | |
|       runs++;
 | |
| 
 | |
|       int maxTabWidth = calculateMaxTabWidth(tabPlacement);
 | |
|       int tabAreaWidth = calculateTabAreaWidth(tabPlacement, runs,
 | |
|                                                maxTabWidth);
 | |
|       return tabAreaWidth;
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * This method rotates the places each run in the correct place  the
 | |
|      * tabRuns array. See the comment for tabRuns for how the runs are placed
 | |
|      * in the array.
 | |
|      *
 | |
|      * @param tabPlacement The JTabbedPane's tab placement.
 | |
|      * @param selectedRun The run the current selection is in.
 | |
|      */
 | |
|     protected void rotateTabRuns(int tabPlacement, int selectedRun)
 | |
|     {
 | |
|       if (runCount == 1 || selectedRun == 0 || selectedRun == -1)
 | |
|         return;
 | |
|       int[] newTabRuns = new int[tabRuns.length];
 | |
|       int currentRun = selectedRun;
 | |
|       int i = 0;
 | |
|       do
 | |
|         {
 | |
|           newTabRuns[i] = tabRuns[currentRun];
 | |
|           currentRun = getNextTabRun(currentRun);
 | |
|           i++;
 | |
|         }
 | |
|       while (i < runCount);
 | |
| 
 | |
|       tabRuns = newTabRuns;
 | |
|       BasicTabbedPaneUI.this.selectedRun = 1;
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * This method is called when a component is removed  from the
 | |
|      * JTabbedPane.
 | |
|      *
 | |
|      * @param comp The component removed.
 | |
|      */
 | |
|     public void removeLayoutComponent(Component comp)
 | |
|     {
 | |
|       // Do nothing.
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   /**
 | |
|    * This class acts as the LayoutManager for the JTabbedPane in
 | |
|    * SCROLL_TAB_MODE.
 | |
|    */
 | |
|   private class TabbedPaneScrollLayout extends TabbedPaneLayout
 | |
|   {
 | |
|     /**
 | |
|      * This method returns the preferred layout size for the given container.
 | |
|      *
 | |
|      * @param parent The container to calculate a size for.
 | |
|      *
 | |
|      * @return The preferred layout size.
 | |
|      */
 | |
|     public Dimension preferredLayoutSize(Container parent)
 | |
|     {
 | |
|       return super.calculateSize(false);
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * This method returns the minimum layout size for the given container.
 | |
|      *
 | |
|      * @param parent The container to calculate a size for.
 | |
|      *
 | |
|      * @return The minimum layout size.
 | |
|      */
 | |
|     public Dimension minimumLayoutSize(Container parent)
 | |
|     {
 | |
|       return super.calculateSize(true);
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * This method calculates the tab area height given  a desired width.
 | |
|      *
 | |
|      * @param tabPlacement The JTabbedPane's tab placement.
 | |
|      * @param width The expected width.
 | |
|      *
 | |
|      * @return The tab area height given the width.
 | |
|      */
 | |
|     protected int preferredTabAreaHeight(int tabPlacement, int width)
 | |
|     {
 | |
|       if (tabPane.getTabCount() == 0)
 | |
|         return calculateTabAreaHeight(tabPlacement, 0, 0);
 | |
| 
 | |
|       int runs = 1;
 | |
| 
 | |
|       int maxTabHeight = calculateMaxTabHeight(tabPlacement);
 | |
|       int tabAreaHeight = calculateTabAreaHeight(tabPlacement, runs,
 | |
|                                                  maxTabHeight);
 | |
|       return tabAreaHeight;
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * This method calculates the tab area width given a desired height.
 | |
|      *
 | |
|      * @param tabPlacement The JTabbedPane's tab placement.
 | |
|      * @param height The expected height.
 | |
|      *
 | |
|      * @return The tab area width given the height.
 | |
|      */
 | |
|     protected int preferredTabAreaWidth(int tabPlacement, int height)
 | |
|     {
 | |
|       if (tabPane.getTabCount() == 0)
 | |
|         return calculateTabAreaHeight(tabPlacement, 0, 0);
 | |
| 
 | |
|       int runs = 1;
 | |
| 
 | |
|       int maxTabWidth = calculateMaxTabWidth(tabPlacement);
 | |
|       int tabAreaWidth = calculateTabAreaWidth(tabPlacement, runs, maxTabWidth);
 | |
|       return tabAreaWidth;
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * This method is called to calculate the tab rectangles.  This method
 | |
|      * will calculate the size and position of all  rectangles (taking into
 | |
|      * account which ones should be in which tab run). It will pad them and
 | |
|      * normalize them  as necessary.
 | |
|      *
 | |
|      * @param tabPlacement The JTabbedPane's tab placement.
 | |
|      * @param tabCount The number of tabs.
 | |
|      */
 | |
|     protected void calculateTabRects(int tabPlacement, int tabCount)
 | |
|     {
 | |
|       if (tabCount == 0)
 | |
|         return;
 | |
| 
 | |
|       FontMetrics fm = getFontMetrics();
 | |
|       SwingUtilities.calculateInnerArea(tabPane, calcRect);
 | |
|       Insets tabAreaInsets = getTabAreaInsets(tabPlacement);
 | |
|       Insets insets = tabPane.getInsets();
 | |
|       if (tabPlacement == SwingConstants.TOP
 | |
|           || tabPlacement == SwingConstants.BOTTOM)
 | |
|         {
 | |
|           int maxHeight = calculateMaxTabHeight(tabPlacement);
 | |
|           calcRect.width -= tabAreaInsets.left + tabAreaInsets.right;
 | |
|           int width = 0;
 | |
|           int runWidth = tabAreaInsets.left + insets.left;
 | |
|           int top = insets.top + tabAreaInsets.top;
 | |
|           for (int i = 0; i < tabCount; i++)
 | |
|             {
 | |
|               width = calculateTabWidth(tabPlacement, i, fm);
 | |
| 
 | |
|               // The proper instances should exists because
 | |
|               //  assureRectsCreated() was being run already.
 | |
|               rects[i].setBounds(runWidth, top, width, maxHeight);
 | |
| 
 | |
|               runWidth += width;
 | |
|             }
 | |
|           tabAreaRect.width = tabPane.getWidth() - insets.left - insets.right;
 | |
|           tabAreaRect.height = maxTabHeight + tabAreaInsets.top
 | |
|                                + tabAreaInsets.bottom;
 | |
|           contentRect.width = tabAreaRect.width;
 | |
|           contentRect.height = tabPane.getHeight() - insets.top
 | |
|           - insets.bottom - tabAreaRect.height;
 | |
|           contentRect.x = insets.left;
 | |
|           tabAreaRect.x = insets.left;
 | |
|           if (tabPlacement == SwingConstants.BOTTOM)
 | |
|             {
 | |
|               contentRect.y = insets.top;
 | |
|               tabAreaRect.y = contentRect.y + contentRect.height;
 | |
|             }
 | |
|           else
 | |
|             {
 | |
|               tabAreaRect.y = insets.top;
 | |
|               contentRect.y = tabAreaRect.y + tabAreaRect.height;
 | |
|             }
 | |
|         }
 | |
|       else
 | |
|         {
 | |
|           int maxWidth = calculateMaxTabWidth(tabPlacement);
 | |
| 
 | |
|           calcRect.height -= tabAreaInsets.top + tabAreaInsets.bottom;
 | |
|           int height = 0;
 | |
|           int runHeight = tabAreaInsets.top + insets.top;
 | |
|           int fontHeight = fm.getHeight();
 | |
|           int left = insets.left + tabAreaInsets.left;
 | |
|           for (int i = 0; i < tabCount; i++)
 | |
|             {
 | |
|               height = calculateTabHeight(tabPlacement, i, fontHeight);
 | |
| 
 | |
|               // The proper instances should exists because
 | |
|               //  assureRectsCreated() was being run already.
 | |
|               rects[i].setBounds(left, runHeight, maxWidth, height);
 | |
|               runHeight += height;
 | |
|             }
 | |
|           tabAreaRect.width = maxTabWidth + tabAreaInsets.left
 | |
|                               + tabAreaInsets.right;
 | |
|           tabAreaRect.height = tabPane.getHeight() - insets.top
 | |
|                                - insets.bottom;
 | |
|           tabAreaRect.y = insets.top;
 | |
|           contentRect.width = tabPane.getWidth() - insets.left - insets.right
 | |
|                               - tabAreaRect.width;
 | |
|           contentRect.height = tabAreaRect.height;
 | |
|           contentRect.y = insets.top;
 | |
|           if (tabPlacement == SwingConstants.LEFT)
 | |
|             {
 | |
|               tabAreaRect.x = insets.left;
 | |
|               contentRect.x = tabAreaRect.x + tabAreaRect.width;
 | |
|             }
 | |
|           else
 | |
|             {
 | |
|               contentRect.x = insets.left;
 | |
|               tabAreaRect.x = contentRect.x + contentRect.width;
 | |
|             }
 | |
|         }
 | |
| 
 | |
|       // Unlike the behavior in the WRAP_TAB_LAYOUT the selected
 | |
|       // tab is not padded specially.
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * This method is called when the JTabbedPane is laid out in
 | |
|      * SCROLL_TAB_LAYOUT. It finds the position for all components in the
 | |
|      * JTabbedPane.
 | |
|      *
 | |
|      * @param pane The JTabbedPane to be laid out.
 | |
|      */
 | |
|     public void layoutContainer(Container pane)
 | |
|     {
 | |
|       super.layoutContainer(pane);
 | |
|       int tabCount = tabPane.getTabCount();
 | |
|       if (tabCount == 0)
 | |
|         return;
 | |
|       int tabPlacement = tabPane.getTabPlacement();
 | |
| 
 | |
|       if (tabPlacement == SwingConstants.TOP
 | |
|           || tabPlacement == SwingConstants.BOTTOM)
 | |
|         {
 | |
|           if (tabAreaRect.x + tabAreaRect.width < rects[tabCount - 1].x
 | |
|               + rects[tabCount - 1].width)
 | |
|             {
 | |
|               Dimension incrDims = incrButton.getPreferredSize();
 | |
|               Dimension decrDims = decrButton.getPreferredSize();
 | |
| 
 | |
|               if (tabPlacement == SwingConstants.BOTTOM)
 | |
|                 {
 | |
|                   // Align scroll buttons with the bottom border of the tabbed
 | |
|                   // pane's content area.
 | |
|                   decrButton.setBounds(tabAreaRect.x + tabAreaRect.width
 | |
|                                        - incrDims.width - decrDims.width,
 | |
|                                        tabAreaRect.y, decrDims.width,
 | |
|                                        decrDims.height);
 | |
|                   incrButton.setBounds(tabAreaRect.x + tabAreaRect.width
 | |
|                                        - incrDims.width, tabAreaRect.y,
 | |
|                                        incrDims.width, incrDims.height);
 | |
|                 }
 | |
|               else
 | |
|                 {
 | |
|                   // Align scroll buttons with the top border of the tabbed
 | |
|                   // pane's content area.
 | |
|                   decrButton.setBounds(tabAreaRect.x + tabAreaRect.width
 | |
|                                        - incrDims.width - decrDims.width,
 | |
|                                        tabAreaRect.y + tabAreaRect.height
 | |
|                                        - decrDims.height, decrDims.width,
 | |
|                                        decrDims.height);
 | |
|                   incrButton.setBounds(tabAreaRect.x + tabAreaRect.width
 | |
|                                        - incrDims.width,
 | |
|                                        tabAreaRect.y + tabAreaRect.height
 | |
|                                        - incrDims.height,
 | |
|                                        incrDims.width, incrDims.height);
 | |
|                 }
 | |
| 
 | |
|               tabAreaRect.width -= decrDims.width + incrDims.width;
 | |
| 
 | |
|               updateButtons();
 | |
| 
 | |
|               incrButton.setVisible(true);
 | |
|               decrButton.setVisible(true);
 | |
|             }
 | |
|           else
 | |
|             {
 | |
|               incrButton.setVisible(false);
 | |
|               decrButton.setVisible(false);
 | |
| 
 | |
|               currentScrollOffset = 0;
 | |
|               currentScrollLocation = 0;
 | |
|             }
 | |
|         }
 | |
| 
 | |
|       if (tabPlacement == SwingConstants.LEFT
 | |
|           || tabPlacement == SwingConstants.RIGHT)
 | |
|         {
 | |
|           if (tabAreaRect.y + tabAreaRect.height < rects[tabCount - 1].y
 | |
|               + rects[tabCount - 1].height)
 | |
|             {
 | |
|               Dimension incrDims = incrButton.getPreferredSize();
 | |
|               Dimension decrDims = decrButton.getPreferredSize();
 | |
| 
 | |
|               if (tabPlacement == SwingConstants.RIGHT)
 | |
|                 {
 | |
|                   // Align scroll buttons with the right border of the tabbed
 | |
|                   // pane's content area.
 | |
|                   decrButton.setBounds(tabAreaRect.x,
 | |
|                                        tabAreaRect.y + tabAreaRect.height
 | |
|                                        - incrDims.height - decrDims.height,
 | |
|                                        decrDims.width, decrDims.height);
 | |
|                   incrButton.setBounds(tabAreaRect.x,
 | |
|                                        tabAreaRect.y + tabAreaRect.height
 | |
|                                        - incrDims.height, incrDims.width,
 | |
|                                        incrDims.height);
 | |
|                 }
 | |
|               else
 | |
|                 {
 | |
|                   // Align scroll buttons with the left border of the tabbed
 | |
|                   // pane's content area.
 | |
|                   decrButton.setBounds(tabAreaRect.x + tabAreaRect.width
 | |
|                                        - decrDims.width,
 | |
|                                        tabAreaRect.y + tabAreaRect.height
 | |
|                                        - incrDims.height - decrDims.height,
 | |
|                                        decrDims.width, decrDims.height);
 | |
|                   incrButton.setBounds(tabAreaRect.x + tabAreaRect.width
 | |
|                                        - incrDims.width,
 | |
|                                        tabAreaRect.y + tabAreaRect.height
 | |
|                                        - incrDims.height, incrDims.width,
 | |
|                                        incrDims.height);
 | |
|                 }
 | |
| 
 | |
|               tabAreaRect.height -= decrDims.height + incrDims.height;
 | |
| 
 | |
|               incrButton.setVisible(true);
 | |
|               decrButton.setVisible(true);
 | |
|             }
 | |
|           else
 | |
|             {
 | |
|               incrButton.setVisible(false);
 | |
|               decrButton.setVisible(false);
 | |
| 
 | |
|               currentScrollOffset = 0;
 | |
|               currentScrollLocation = 0;
 | |
|             }
 | |
|         }
 | |
|       viewport.setBounds(tabAreaRect.x, tabAreaRect.y, tabAreaRect.width,
 | |
|                          tabAreaRect.height);
 | |
| 
 | |
|       updateViewPosition();
 | |
| 
 | |
|       viewport.repaint();
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   /**
 | |
|    * This class handles ChangeEvents from the JTabbedPane.
 | |
|    *
 | |
|    * @specnote Apparently this class was intended to be protected,
 | |
|    *           but was made public by a compiler bug and is now
 | |
|    *           public for compatibility.
 | |
|    */
 | |
|   public class TabSelectionHandler implements ChangeListener
 | |
|   {
 | |
|     /**
 | |
|      * This method is called whenever a ChangeEvent is fired from the
 | |
|      * JTabbedPane.
 | |
|      *
 | |
|      * @param e The ChangeEvent fired.
 | |
|      */
 | |
|     public void stateChanged(ChangeEvent e)
 | |
|     {
 | |
|       selectedRun = getRunForTab(tabPane.getTabCount(),
 | |
|                                  tabPane.getSelectedIndex());
 | |
| 
 | |
|       if (tabPane.getTabLayoutPolicy() == JTabbedPane.WRAP_TAB_LAYOUT)
 | |
|         tabPane.revalidate();
 | |
|       tabPane.repaint();
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   /**
 | |
|    * This helper class is a JPanel that fits inside the ScrollViewport. This
 | |
|    * panel's sole job is to paint the tab rectangles inside the  viewport so
 | |
|    * that it's clipped correctly.
 | |
|    */
 | |
|   private class ScrollingPanel extends JPanel
 | |
|   {
 | |
|     /**
 | |
|      * This is a private UI class for our panel.
 | |
|      */
 | |
|     private class ScrollingPanelUI extends BasicPanelUI
 | |
|     {
 | |
|       /**
 | |
|        * This method overrides the default paint method. It paints the tab
 | |
|        * rectangles for the JTabbedPane in the panel.
 | |
|        *
 | |
|        * @param g The Graphics object to paint with.
 | |
|        * @param c The JComponent to paint.
 | |
|        */
 | |
|       public void paint(Graphics g, JComponent c)
 | |
|       {
 | |
|         int placement = tabPane.getTabPlacement();
 | |
|         g.setColor(highlight);
 | |
|         if (placement == SwingUtilities.TOP
 | |
|             || placement == SwingUtilities.BOTTOM)
 | |
|           g.fillRect(currentScrollOffset, 0,
 | |
|                      tabAreaRect.width, tabAreaRect.height);
 | |
|         else
 | |
|           g.fillRect(0, currentScrollOffset,
 | |
|                      tabAreaRect.width, tabAreaRect.height);
 | |
| 
 | |
|         paintTabArea(g, placement, tabPane.getSelectedIndex());
 | |
|       }
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * This method overrides the updateUI method. It makes the default UI for
 | |
|      * this ScrollingPanel to be  a ScrollingPanelUI.
 | |
|      */
 | |
|     public void updateUI()
 | |
|     {
 | |
|       setUI(new ScrollingPanelUI());
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   /**
 | |
|    * This is a helper class that paints the panel that paints tabs. This
 | |
|    * custom JViewport is used so that the tabs painted in the panel will be
 | |
|    * clipped. This class implements UIResource so tabs are not added when
 | |
|    * this objects of this class are added to the  JTabbedPane.
 | |
|    */
 | |
|   private class ScrollingViewport extends JViewport implements UIResource
 | |
|   {
 | |
|     // TODO: Maybe remove this inner class.
 | |
|   }
 | |
| 
 | |
|   /**
 | |
|    * This is a helper class that implements UIResource so it is not added as a
 | |
|    * tab when an object of this class is added to the JTabbedPane.
 | |
|    */
 | |
|   private class ScrollingButton extends BasicArrowButton implements UIResource
 | |
|   {
 | |
|     /**
 | |
|      * Creates a ScrollingButton given the direction.
 | |
|      *
 | |
|      * @param dir The direction to point in.
 | |
|      */
 | |
|     public ScrollingButton(int dir)
 | |
|     {
 | |
|       super(dir);
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   /** The button that increments the current scroll location.
 | |
|    * This is package-private to avoid an accessor method.  */
 | |
|   transient ScrollingButton incrButton;
 | |
| 
 | |
|   /** The button that decrements the current scroll location.
 | |
|    * This is package-private to avoid an accessor method.  */
 | |
|   transient ScrollingButton decrButton;
 | |
| 
 | |
|   /** The viewport used to display the tabs.
 | |
|    * This is package-private to avoid an accessor method.  */
 | |
|   transient ScrollingViewport viewport;
 | |
| 
 | |
|   /** The panel inside the viewport that paints the tabs.
 | |
|    * This is package-private to avoid an accessor method.  */
 | |
|   transient ScrollingPanel panel;
 | |
| 
 | |
|   /** The starting visible tab in the run in SCROLL_TAB_MODE.
 | |
|    * This is package-private to avoid an accessor method.  */
 | |
|   transient int currentScrollLocation;
 | |
| 
 | |
|   transient int currentScrollOffset;
 | |
| 
 | |
|   /** A reusable rectangle. */
 | |
|   protected Rectangle calcRect;
 | |
| 
 | |
|   /** An array of Rectangles keeping track of the tabs' area and position. */
 | |
|   protected Rectangle[] rects;
 | |
| 
 | |
|   /** The insets around the content area. */
 | |
|   protected Insets contentBorderInsets;
 | |
| 
 | |
|   /** The extra insets around the selected tab. */
 | |
|   protected Insets selectedTabPadInsets;
 | |
| 
 | |
|   /** The insets around the tab area. */
 | |
|   protected Insets tabAreaInsets;
 | |
| 
 | |
|   /** The insets around each and every tab. */
 | |
|   protected Insets tabInsets;
 | |
| 
 | |
|   /**
 | |
|    * The outer bottom and right edge color for both the tab and content
 | |
|    * border.
 | |
|    */
 | |
|   protected Color darkShadow;
 | |
| 
 | |
|   /** The color of the focus outline on the selected tab. */
 | |
|   protected Color focus;
 | |
| 
 | |
|   /** FIXME: find a use for this. */
 | |
|   protected Color highlight;
 | |
| 
 | |
|   /** The top and left edge color for both the tab and content border. */
 | |
|   protected Color lightHighlight;
 | |
| 
 | |
|   /** The inner bottom and right edge color for the tab and content border. */
 | |
|   protected Color shadow;
 | |
| 
 | |
|   /** The maximum tab height. */
 | |
|   protected int maxTabHeight;
 | |
| 
 | |
|   /** The maximum tab width. */
 | |
|   protected int maxTabWidth;
 | |
| 
 | |
|   /** The number of runs in the JTabbedPane. */
 | |
|   protected int runCount;
 | |
| 
 | |
|   /** The index of the run that the selected index is in. */
 | |
|   protected int selectedRun;
 | |
| 
 | |
|   /** The amount of space each run overlaps the previous by. */
 | |
|   protected int tabRunOverlay;
 | |
| 
 | |
|   /** The gap between text and label */
 | |
|   protected int textIconGap;
 | |
| 
 | |
|   /** This array keeps track of which tabs are in which run.
 | |
|    * <p>The value at index i denotes the index of the first tab in run i.</p>
 | |
|    * <p>If the value for any index (i > 0) is 0 then (i - 1) is the last
 | |
|    * run.</p>
 | |
|    */
 | |
|   protected int[] tabRuns;
 | |
| 
 | |
|   /**
 | |
|    * Indicates if the layout of the tab runs is ok or not. This is package
 | |
|    * private to avoid a synthetic accessor method.
 | |
|    */
 | |
|   boolean tabRunsDirty;
 | |
| 
 | |
|   /**
 | |
|    * This is the keystroke for moving down.
 | |
|    *
 | |
|    * @deprecated 1.3
 | |
|    */
 | |
|   protected KeyStroke downKey;
 | |
| 
 | |
|   /**
 | |
|    * This is the keystroke for moving left.
 | |
|    *
 | |
|    * @deprecated 1.3
 | |
|    */
 | |
|   protected KeyStroke leftKey;
 | |
| 
 | |
|   /**
 | |
|    * This is the keystroke for moving right.
 | |
|    *
 | |
|    * @deprecated 1.3
 | |
|    */
 | |
|   protected KeyStroke rightKey;
 | |
| 
 | |
|   /**
 | |
|    * This is the keystroke for moving up.
 | |
|    *
 | |
|    * @deprecated 1.3
 | |
|    */
 | |
|   protected KeyStroke upKey;
 | |
| 
 | |
|   /** The listener that listens for focus events. */
 | |
|   protected FocusListener focusListener;
 | |
| 
 | |
|   /** The listener that listens for mouse events. */
 | |
|   protected MouseListener mouseListener;
 | |
| 
 | |
|   /** The listener that listens for property change events. */
 | |
|   protected PropertyChangeListener propertyChangeListener;
 | |
| 
 | |
|   /** The listener that listens for change events. */
 | |
|   protected ChangeListener tabChangeListener;
 | |
| 
 | |
|   /** The tab pane that this UI paints. */
 | |
|   protected JTabbedPane tabPane;
 | |
| 
 | |
|   /** The current layout manager for the tabPane.
 | |
|    * This is package-private to avoid an accessor method.  */
 | |
|   transient LayoutManager layoutManager;
 | |
| 
 | |
|   /** The rectangle that describes the tab area's position and size.
 | |
|    * This is package-private to avoid an accessor method.  */
 | |
|   transient Rectangle tabAreaRect;
 | |
| 
 | |
|   /** The rectangle that describes the content area's position and
 | |
|    * size.  This is package-private to avoid an accessor method.  */
 | |
|   transient Rectangle contentRect;
 | |
| 
 | |
|   /**
 | |
|    * The index over which the mouse is currently moving.
 | |
|    */
 | |
|   private int rolloverTab;
 | |
| 
 | |
|   /**
 | |
|    * Determines if tabs are painted opaque or not. This can be adjusted using
 | |
|    * the UIManager property 'TabbedPane.tabsOpaque'.
 | |
|    */
 | |
|   private boolean tabsOpaque;
 | |
| 
 | |
|   /**
 | |
|    * The currently visible component.
 | |
|    */
 | |
|   private Component visibleComponent;
 | |
| 
 | |
|   private Color selectedColor;
 | |
| 
 | |
|   private Rectangle tempTextRect = new Rectangle();
 | |
| 
 | |
|   private Rectangle tempIconRect = new Rectangle();
 | |
| 
 | |
|   /**
 | |
|    * Creates a new BasicTabbedPaneUI object.
 | |
|    */
 | |
|   public BasicTabbedPaneUI()
 | |
|   {
 | |
|     super();
 | |
|     rects = new Rectangle[0];
 | |
|     tabRuns = new int[10];
 | |
|   }
 | |
| 
 | |
|   /**
 | |
|    * This method creates a ScrollingButton that  points in the appropriate
 | |
|    * direction for an increasing button.
 | |
|    * This is package-private to avoid an accessor method.
 | |
|    *
 | |
|    * @return The increase ScrollingButton.
 | |
|    */
 | |
|   ScrollingButton createIncreaseButton()
 | |
|   {
 | |
|     if (incrButton == null)
 | |
|       incrButton = new ScrollingButton(SwingConstants.NORTH);
 | |
|     if (tabPane.getTabPlacement() == SwingConstants.TOP
 | |
|         || tabPane.getTabPlacement() == SwingConstants.BOTTOM)
 | |
|       incrButton.setDirection(SwingConstants.EAST);
 | |
|     else
 | |
|       incrButton.setDirection(SwingConstants.SOUTH);
 | |
|     return incrButton;
 | |
|   }
 | |
| 
 | |
|   /**
 | |
|    * This method creates a ScrollingButton that points in the appropriate
 | |
|    * direction for a decreasing button.
 | |
|    * This is package-private to avoid an accessor method.
 | |
|    *
 | |
|    * @return The decrease ScrollingButton.
 | |
|    */
 | |
|   ScrollingButton createDecreaseButton()
 | |
|   {
 | |
|     if (decrButton == null)
 | |
|       decrButton = new ScrollingButton(SwingConstants.SOUTH);
 | |
|     if (tabPane.getTabPlacement() == SwingConstants.TOP
 | |
|         || tabPane.getTabPlacement() == SwingConstants.BOTTOM)
 | |
|       decrButton.setDirection(SwingConstants.WEST);
 | |
|     else
 | |
|       decrButton.setDirection(SwingConstants.NORTH);
 | |
|     return decrButton;
 | |
|   }
 | |
| 
 | |
|   /**
 | |
|    * This method finds the point to set the view  position at given the index
 | |
|    * of a tab. The tab will be the first visible tab in the run.
 | |
|    * This is package-private to avoid an accessor method.
 | |
|    *
 | |
|    * @param index The index of the first visible tab.
 | |
|    *
 | |
|    * @return The position of the first visible tab.
 | |
|    */
 | |
|   Point findPointForIndex(int index)
 | |
|   {
 | |
|     int tabPlacement = tabPane.getTabPlacement();
 | |
|     int selectedIndex = tabPane.getSelectedIndex();
 | |
|     Insets insets = getSelectedTabPadInsets(tabPlacement);
 | |
|     int w = 0;
 | |
|     int h = 0;
 | |
| 
 | |
|     if (tabPlacement == TOP || tabPlacement == BOTTOM)
 | |
|       {
 | |
|         if (index > 0)
 | |
|           {
 | |
|             w += rects[index - 1].x + rects[index - 1].width;
 | |
|             if (index > selectedIndex)
 | |
|               w -= insets.left + insets.right;
 | |
|           }
 | |
|       }
 | |
| 
 | |
|     else
 | |
|       {
 | |
|         if (index > 0)
 | |
|           {
 | |
|             h += rects[index - 1].y + rects[index - 1].height;
 | |
|             if (index > selectedIndex)
 | |
|               h -= insets.top + insets.bottom;
 | |
|           }
 | |
|       }
 | |
| 
 | |
|     Point p = new Point(w, h);
 | |
|     return p;
 | |
|   }
 | |
| 
 | |
|   /** TabbedPanes in scrolling mode should use this method to
 | |
|    * scroll properly to the tab given by the index argument.
 | |
|    *
 | |
|    * @param index The tab to scroll to.
 | |
|    * @param placement The tab's placement.
 | |
|    */
 | |
|   final void scrollTab(int index, int placement)
 | |
|   {
 | |
|     int diff;
 | |
|     if (index >= 0 && tabPane.isEnabledAt(index))
 | |
|       {
 | |
|         // If the user clicked on the last tab and that one was
 | |
|         // only partially visible shift the scroll offset to make
 | |
|         // it completely visible.
 | |
|         switch (placement)
 | |
|           {
 | |
|             case JTabbedPane.TOP:
 | |
|             case JTabbedPane.BOTTOM:
 | |
|               if ((diff = rects[index].x
 | |
|                   + rects[index].width
 | |
|                   - decrButton.getX() - currentScrollOffset) > 0)
 | |
|                 currentScrollOffset += diff;
 | |
|               else if ((diff = rects[index].x - currentScrollOffset) < 0)
 | |
|                 {
 | |
|                   if (index == 0)
 | |
|                     currentScrollOffset = 0;
 | |
|                   else
 | |
|                     currentScrollOffset += diff;
 | |
|                 }
 | |
| 
 | |
|               currentScrollLocation = tabForCoordinate(tabPane,
 | |
|                                                        currentScrollOffset,
 | |
|                                                        rects[index].y);
 | |
|               break;
 | |
|             default:
 | |
|               if ((diff = rects[index].y + rects[index].height
 | |
|                   - decrButton.getY() - currentScrollOffset) > 0)
 | |
|                 currentScrollOffset += diff;
 | |
|               else if ((diff = rects[index].y - currentScrollOffset) < 0)
 | |
|                 {
 | |
|                   if (index == 0)
 | |
|                     currentScrollOffset = 0;
 | |
|                   else
 | |
|                     currentScrollOffset += diff;
 | |
|                 }
 | |
| 
 | |
|               currentScrollLocation = tabForCoordinate(tabPane,
 | |
|                                                        rects[index].x,
 | |
|                                                        currentScrollOffset);
 | |
|           }
 | |
| 
 | |
|         updateViewPosition();
 | |
|         updateButtons();
 | |
|       }
 | |
|   }
 | |
| 
 | |
|   /** Sets the enabled state of the increase and decrease button
 | |
|    * according to the current scrolling offset and tab pane width
 | |
|    * (or height in TOP/BOTTOM placement).
 | |
|    */
 | |
|   final void updateButtons()
 | |
|   {
 | |
|     int tc = tabPane.getTabCount();
 | |
| 
 | |
|     // The increase button should be enabled as long as the
 | |
|     // right/bottom border of the last tab is under the left/top
 | |
|     // border of the decrease button.
 | |
|     switch (tabPane.getTabPlacement())
 | |
|     {
 | |
|       case JTabbedPane.BOTTOM:
 | |
|       case JTabbedPane.TOP:
 | |
|         incrButton.setEnabled(currentScrollLocation + 1 < tc
 | |
|                               && rects[tc-1].x + rects[tc-1].width
 | |
|                               - currentScrollOffset > decrButton.getX());
 | |
|         break;
 | |
|       default:
 | |
|         incrButton.setEnabled(currentScrollLocation + 1 < tc
 | |
|                               && rects[tc-1].y + rects[tc-1].height
 | |
|                               - currentScrollOffset > decrButton.getY());
 | |
|     }
 | |
| 
 | |
|     // The decrease button is enabled when the tab pane is scrolled in any way.
 | |
|     decrButton.setEnabled(currentScrollOffset > 0);
 | |
| 
 | |
|   }
 | |
| 
 | |
|   /**
 | |
|    * Updates the position of the scrolling viewport's view
 | |
|    * according to the current scroll offset.
 | |
|    */
 | |
|   final void updateViewPosition()
 | |
|   {
 | |
|     Point p = viewport.getViewPosition();
 | |
| 
 | |
|     // The unneeded coordinate must be set to zero
 | |
|     // in order to correctly handle placement changes.
 | |
|     switch (tabPane.getTabPlacement())
 | |
|     {
 | |
|       case JTabbedPane.LEFT:
 | |
|       case JTabbedPane.RIGHT:
 | |
|         p.x = 0;
 | |
|         p.y = currentScrollOffset;
 | |
|         break;
 | |
|       default:
 | |
|         p.x = currentScrollOffset;
 | |
|         p.y = 0;
 | |
|     }
 | |
| 
 | |
|     viewport.setViewPosition(p);
 | |
|   }
 | |
| 
 | |
|   /**
 | |
|    * This method creates a new BasicTabbedPaneUI.
 | |
|    *
 | |
|    * @param c The JComponent to create a UI for.
 | |
|    *
 | |
|    * @return A new BasicTabbedPaneUI.
 | |
|    */
 | |
|   public static ComponentUI createUI(JComponent c)
 | |
|   {
 | |
|     return new BasicTabbedPaneUI();
 | |
|   }
 | |
| 
 | |
|   /**
 | |
|    * This method installs the UI for the given JComponent.
 | |
|    *
 | |
|    * @param c The JComponent to install the UI for.
 | |
|    */
 | |
|   public void installUI(JComponent c)
 | |
|   {
 | |
|     super.installUI(c);
 | |
|     if (c instanceof JTabbedPane)
 | |
|       {
 | |
|         tabPane = (JTabbedPane) c;
 | |
| 
 | |
|         installComponents();
 | |
|         installDefaults();
 | |
|         installListeners();
 | |
|         installKeyboardActions();
 | |
| 
 | |
|         layoutManager = createLayoutManager();
 | |
|         tabPane.setLayout(layoutManager);
 | |
|       }
 | |
|   }
 | |
| 
 | |
|   /**
 | |
|    * This method uninstalls the UI for the  given JComponent.
 | |
|    *
 | |
|    * @param c The JComponent to uninstall the UI for.
 | |
|    */
 | |
|   public void uninstallUI(JComponent c)
 | |
|   {
 | |
|     layoutManager = null;
 | |
| 
 | |
|     uninstallKeyboardActions();
 | |
|     uninstallListeners();
 | |
|     uninstallDefaults();
 | |
|     uninstallComponents();
 | |
| 
 | |
|     tabPane = null;
 | |
|   }
 | |
| 
 | |
|   /**
 | |
|    * This method creates the appropriate layout manager for the JTabbedPane's
 | |
|    * current tab layout policy. If the tab layout policy is
 | |
|    * SCROLL_TAB_LAYOUT, then all the associated components that need to be
 | |
|    * created will be done so now.
 | |
|    *
 | |
|    * @return A layout manager given the tab layout policy.
 | |
|    */
 | |
|   protected LayoutManager createLayoutManager()
 | |
|   {
 | |
|     if (tabPane.getTabLayoutPolicy() == JTabbedPane.WRAP_TAB_LAYOUT)
 | |
|       return new TabbedPaneLayout();
 | |
|     else
 | |
|       {
 | |
|         runCount = 1;
 | |
|         tabRuns[0] = 0;
 | |
| 
 | |
|         incrButton = createIncreaseButton();
 | |
|         incrButton.addMouseListener(mouseListener);
 | |
| 
 | |
|         decrButton = createDecreaseButton();
 | |
|         decrButton.addMouseListener(mouseListener);
 | |
|         decrButton.setEnabled(false);
 | |
| 
 | |
|         panel = new ScrollingPanel();
 | |
|         panel.setSize(Integer.MAX_VALUE, Integer.MAX_VALUE);
 | |
|         panel.addMouseListener(mouseListener);
 | |
|         panel.addFocusListener(focusListener);
 | |
| 
 | |
|         viewport = new ScrollingViewport();
 | |
|         viewport.setBackground(Color.LIGHT_GRAY);
 | |
|         viewport.setView(panel);
 | |
|         viewport.setLayout(null);
 | |
| 
 | |
|         tabPane.add(incrButton);
 | |
|         tabPane.add(decrButton);
 | |
|         tabPane.add(viewport);
 | |
| 
 | |
|         return new TabbedPaneScrollLayout();
 | |
|       }
 | |
|   }
 | |
| 
 | |
|   /**
 | |
|    * This method installs components for this JTabbedPane.
 | |
|    */
 | |
|   protected void installComponents()
 | |
|   {
 | |
|     // Nothing to be done.
 | |
|   }
 | |
| 
 | |
|   /**
 | |
|    * This method uninstalls components for this JTabbedPane.
 | |
|    */
 | |
|   protected void uninstallComponents()
 | |
|   {
 | |
|     if (incrButton != null)
 | |
|       tabPane.remove(incrButton);
 | |
| 
 | |
|     if (decrButton != null)
 | |
|       tabPane.remove(decrButton);
 | |
| 
 | |
|     if (viewport != null)
 | |
|       tabPane.remove(viewport);
 | |
|   }
 | |
| 
 | |
|   /**
 | |
|    * This method installs defaults for the Look and Feel.
 | |
|    */
 | |
|   protected void installDefaults()
 | |
|   {
 | |
|     LookAndFeel.installColorsAndFont(tabPane, "TabbedPane.background",
 | |
|                                      "TabbedPane.foreground",
 | |
|                                      "TabbedPane.font");
 | |
|     tabPane.setOpaque(false);
 | |
| 
 | |
|     lightHighlight = UIManager.getColor("TabbedPane.highlight");
 | |
|     highlight = UIManager.getColor("TabbedPane.light");
 | |
| 
 | |
|     shadow = UIManager.getColor("TabbedPane.shadow");
 | |
|     darkShadow = UIManager.getColor("TabbedPane.darkShadow");
 | |
| 
 | |
|     focus = UIManager.getColor("TabbedPane.focus");
 | |
| 
 | |
|     textIconGap = UIManager.getInt("TabbedPane.textIconGap");
 | |
|     tabRunOverlay = UIManager.getInt("TabbedPane.tabRunOverlay");
 | |
| 
 | |
|     tabInsets = UIManager.getInsets("TabbedPane.tabInsets");
 | |
|     selectedTabPadInsets
 | |
|       = UIManager.getInsets("TabbedPane.selectedTabPadInsets");
 | |
|     tabAreaInsets = UIManager.getInsets("TabbedPane.tabAreaInsets");
 | |
|     contentBorderInsets
 | |
|       = UIManager.getInsets("TabbedPane.contentBorderInsets");
 | |
|     tabsOpaque = UIManager.getBoolean("TabbedPane.tabsOpaque");
 | |
| 
 | |
|     // Although 'TabbedPane.contentAreaColor' is not defined in the defaults
 | |
|     // of BasicLookAndFeel it is used by this class.
 | |
|     selectedColor = UIManager.getColor("TabbedPane.contentAreaColor");
 | |
|     if (selectedColor == null)
 | |
|       selectedColor = UIManager.getColor("control");
 | |
| 
 | |
|     calcRect = new Rectangle();
 | |
|     tabRuns = new int[10];
 | |
|     tabAreaRect = new Rectangle();
 | |
|     contentRect = new Rectangle();
 | |
|   }
 | |
| 
 | |
|   /**
 | |
|    * This method uninstalls defaults for the Look and Feel.
 | |
|    */
 | |
|   protected void uninstallDefaults()
 | |
|   {
 | |
|     calcRect = null;
 | |
|     tabAreaRect = null;
 | |
|     contentRect = null;
 | |
|     tabRuns = null;
 | |
| 
 | |
|     tempIconRect = null;
 | |
|     tempTextRect = null;
 | |
| 
 | |
|     contentBorderInsets = null;
 | |
|     tabAreaInsets = null;
 | |
|     selectedTabPadInsets = null;
 | |
|     tabInsets = null;
 | |
| 
 | |
|     focus = null;
 | |
|     darkShadow = null;
 | |
|     shadow = null;
 | |
|     lightHighlight = null;
 | |
|     highlight = null;
 | |
| 
 | |
|     selectedColor = null;
 | |
|   }
 | |
| 
 | |
|   /**
 | |
|    * This method creates and installs the listeners for this UI.
 | |
|    */
 | |
|   protected void installListeners()
 | |
|   {
 | |
|     mouseListener = createMouseListener();
 | |
|     tabChangeListener = createChangeListener();
 | |
|     propertyChangeListener = createPropertyChangeListener();
 | |
|     focusListener = createFocusListener();
 | |
| 
 | |
|     tabPane.addMouseListener(mouseListener);
 | |
|     tabPane.addChangeListener(tabChangeListener);
 | |
|     tabPane.addPropertyChangeListener(propertyChangeListener);
 | |
|     tabPane.addFocusListener(focusListener);
 | |
|   }
 | |
| 
 | |
|   /**
 | |
|    * This method removes and nulls the listeners for this UI.
 | |
|    */
 | |
|   protected void uninstallListeners()
 | |
|   {
 | |
|     tabPane.removeFocusListener(focusListener);
 | |
|     tabPane.removePropertyChangeListener(propertyChangeListener);
 | |
|     tabPane.removeChangeListener(tabChangeListener);
 | |
|     tabPane.removeMouseListener(mouseListener);
 | |
| 
 | |
|     if (incrButton != null)
 | |
|       incrButton.removeMouseListener(mouseListener);
 | |
| 
 | |
|     if (decrButton != null)
 | |
|       decrButton.removeMouseListener(mouseListener);
 | |
| 
 | |
|     if (panel != null)
 | |
|       {
 | |
|         panel.removeMouseListener(mouseListener);
 | |
|         panel.removeFocusListener(focusListener);
 | |
|       }
 | |
| 
 | |
|     focusListener = null;
 | |
|     propertyChangeListener = null;
 | |
|     tabChangeListener = null;
 | |
|     mouseListener = null;
 | |
|   }
 | |
| 
 | |
|   /**
 | |
|    * This method creates a new MouseListener.
 | |
|    *
 | |
|    * @return A new MouseListener.
 | |
|    */
 | |
|   protected MouseListener createMouseListener()
 | |
|   {
 | |
|     return new MouseHandler();
 | |
|   }
 | |
| 
 | |
|   /**
 | |
|    * This method creates a new FocusListener.
 | |
|    *
 | |
|    * @return A new FocusListener.
 | |
|    */
 | |
|   protected FocusListener createFocusListener()
 | |
|   {
 | |
|     return new FocusHandler();
 | |
|   }
 | |
| 
 | |
|   /**
 | |
|    * This method creates a new ChangeListener.
 | |
|    *
 | |
|    * @return A new ChangeListener.
 | |
|    */
 | |
|   protected ChangeListener createChangeListener()
 | |
|   {
 | |
|     return new TabSelectionHandler();
 | |
|   }
 | |
| 
 | |
|   /**
 | |
|    * This method creates a new PropertyChangeListener.
 | |
|    *
 | |
|    * @return A new PropertyChangeListener.
 | |
|    */
 | |
|   protected PropertyChangeListener createPropertyChangeListener()
 | |
|   {
 | |
|     return new PropertyChangeHandler();
 | |
|   }
 | |
| 
 | |
|   /**
 | |
|    * This method installs keyboard actions for the JTabbedPane.
 | |
|    */
 | |
|   protected void installKeyboardActions()
 | |
|   {
 | |
|     InputMap keyMap = (InputMap) UIManager.get("TabbedPane.focusInputMap");
 | |
|     SwingUtilities.replaceUIInputMap(tabPane, JComponent.WHEN_FOCUSED, keyMap);
 | |
| 
 | |
|     keyMap = (InputMap) UIManager.get("TabbedPane.ancestorInputMap");
 | |
|     SwingUtilities
 | |
|       .replaceUIInputMap(tabPane,
 | |
|                          JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT,
 | |
|                          keyMap);
 | |
| 
 | |
|     ActionMap map = getActionMap();
 | |
|     SwingUtilities.replaceUIActionMap(tabPane, map);
 | |
|   }
 | |
| 
 | |
|   /**
 | |
|    * This method uninstalls keyboard actions for the JTabbedPane.
 | |
|    */
 | |
|   protected void uninstallKeyboardActions()
 | |
|   {
 | |
|     SwingUtilities.replaceUIActionMap(tabPane, null);
 | |
|     SwingUtilities.replaceUIInputMap(tabPane, JComponent.WHEN_FOCUSED, null);
 | |
|     SwingUtilities
 | |
|       .replaceUIInputMap(tabPane,
 | |
|                          JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT,
 | |
|                          null);
 | |
|   }
 | |
| 
 | |
|   /**
 | |
|    * This method returns the minimum size of the JTabbedPane.
 | |
|    *
 | |
|    * @param c The JComponent to find a size for.
 | |
|    *
 | |
|    * @return The minimum size.
 | |
|    */
 | |
|   public Dimension getMinimumSize(JComponent c)
 | |
|   {
 | |
|     return layoutManager.minimumLayoutSize(tabPane);
 | |
|   }
 | |
| 
 | |
|   /**
 | |
|    * This method returns the maximum size of the JTabbedPane.
 | |
|    *
 | |
|    * @param c The JComponent to find a size for.
 | |
|    *
 | |
|    * @return The maximum size.
 | |
|    */
 | |
|   public Dimension getMaximumSize(JComponent c)
 | |
|   {
 | |
|     return new Dimension(Short.MAX_VALUE, Short.MAX_VALUE);
 | |
|   }
 | |
| 
 | |
|   /**
 | |
|    * This method paints the JTabbedPane.
 | |
|    *
 | |
|    * @param g The Graphics object to paint with.
 | |
|    * @param c The JComponent to paint.
 | |
|    */
 | |
|   public void paint(Graphics g, JComponent c)
 | |
|   {
 | |
|     if (!tabPane.isValid())
 | |
|       tabPane.validate();
 | |
| 
 | |
|     if (tabPane.getTabCount() == 0)
 | |
|       return;
 | |
| 
 | |
|     int index = tabPane.getSelectedIndex();
 | |
|     if (index < 0)
 | |
|       index = 0;
 | |
| 
 | |
|     int tabPlacement = tabPane.getTabPlacement();
 | |
| 
 | |
|     // Paint the tab area only in WRAP_TAB_LAYOUT Mode from this method
 | |
|     // because it is done through the ScrollingViewport.paint() method
 | |
|     // for the SCROLL_TAB_LAYOUT mode.
 | |
|     if (tabPane.getTabLayoutPolicy() == JTabbedPane.WRAP_TAB_LAYOUT)
 | |
|       {
 | |
|         g.setColor(highlight);
 | |
|         g.fillRect(tabAreaRect.x, tabAreaRect.y,
 | |
|                    tabAreaRect.width, tabAreaRect.height);
 | |
|         paintTabArea(g, tabPlacement, index);
 | |
|       }
 | |
| 
 | |
|     paintContentBorder(g, tabPlacement, index);
 | |
|   }
 | |
| 
 | |
|   /**
 | |
|    * This method paints the tab area. This includes painting the rectangles
 | |
|    * that make up the tabs.
 | |
|    *
 | |
|    * @param g The Graphics object to paint with.
 | |
|    * @param tabPlacement The JTabbedPane's tab placement.
 | |
|    * @param selectedIndex The selected index.
 | |
|    */
 | |
|   protected void paintTabArea(Graphics g, int tabPlacement, int selectedIndex)
 | |
|   {
 | |
|     // Please note: the ordering of the painting is important.
 | |
|     // we WANT to paint the outermost run first and then work our way in.
 | |
| 
 | |
|     // The following drawing code works for both tab layouts.
 | |
|     int tabCount = tabPane.getTabCount();
 | |
| 
 | |
|     for (int i = runCount - 1; i >= 0; --i)
 | |
|       {
 | |
|         int start = tabRuns[i];
 | |
|         int next;
 | |
|         if (i == runCount - 1)
 | |
|           next = tabRuns[0];
 | |
|         else
 | |
|           next = tabRuns[i + 1];
 | |
|         int end = next != 0 ? next - 1 : tabCount - 1;
 | |
|         for (int j = start; j <= end; ++j)
 | |
|           {
 | |
|             if (j != selectedIndex)
 | |
|               {
 | |
|                 paintTab(g, tabPlacement, rects, j,
 | |
|                          tempIconRect, tempTextRect);
 | |
|               }
 | |
|           }
 | |
|       }
 | |
| 
 | |
|     // Paint selected tab in front of every other tab.
 | |
|     if (selectedIndex >= 0)
 | |
|       paintTab(g, tabPlacement, rects, selectedIndex,
 | |
|                tempIconRect, tempTextRect);
 | |
|   }
 | |
| 
 | |
|   /**
 | |
|    * This method paints an individual tab.
 | |
|    *
 | |
|    * @param g The Graphics object to paint with.
 | |
|    * @param tabPlacement The JTabbedPane's tab placement.
 | |
|    * @param rects The array of rectangles that keep the size and position of
 | |
|    *        the tabs.
 | |
|    * @param tabIndex The tab index to paint.
 | |
|    * @param iconRect The rectangle to use for the icon.
 | |
|    * @param textRect The rectangle to use for the text.
 | |
|    */
 | |
|   protected void paintTab(Graphics g, int tabPlacement, Rectangle[] rects,
 | |
|                           int tabIndex, Rectangle iconRect, Rectangle textRect)
 | |
|   {
 | |
|     Rectangle rect = rects[tabIndex];
 | |
|     boolean isSelected = tabIndex == tabPane.getSelectedIndex();
 | |
|     // Paint background if necessary.
 | |
|     if (tabsOpaque || tabPane.isOpaque())
 | |
|       {
 | |
|         paintTabBackground(g, tabPlacement, tabIndex, rect.x, rect.y,
 | |
|                            rect.width, rect.height, isSelected);
 | |
|       }
 | |
| 
 | |
|     // Paint border.
 | |
|     paintTabBorder(g, tabPlacement, tabIndex, rect.x, rect.y, rect.width,
 | |
|                    rect.height, isSelected);
 | |
| 
 | |
|     // Layout label.
 | |
|     FontMetrics fm = getFontMetrics();
 | |
|     Icon icon = getIconForTab(tabIndex);
 | |
|     String title = tabPane.getTitleAt(tabIndex);
 | |
|     layoutLabel(tabPlacement, fm, tabIndex, title, icon, rect, iconRect,
 | |
|                 textRect, isSelected);
 | |
|     // Paint the text.
 | |
|     paintText(g, tabPlacement, tabPane.getFont(), fm, tabIndex, title,
 | |
|               textRect, isSelected);
 | |
| 
 | |
|     // Paint icon if necessary.
 | |
|     paintIcon(g, tabPlacement, tabIndex, icon, iconRect, isSelected);
 | |
| 
 | |
|     // Paint focus indicator.
 | |
|     paintFocusIndicator(g, tabPlacement, rects, tabIndex, iconRect, textRect,
 | |
|                         isSelected);
 | |
|   }
 | |
| 
 | |
|   /**
 | |
|    * This method lays out the tab and finds the location to paint the  icon
 | |
|    * and text.
 | |
|    *
 | |
|    * @param tabPlacement The JTabbedPane's tab placement.
 | |
|    * @param metrics The font metrics for the font to paint with.
 | |
|    * @param tabIndex The tab index to paint.
 | |
|    * @param title The string painted.
 | |
|    * @param icon The icon painted.
 | |
|    * @param tabRect The tab bounds.
 | |
|    * @param iconRect The calculated icon bounds.
 | |
|    * @param textRect The calculated text bounds.
 | |
|    * @param isSelected Whether this tab is selected.
 | |
|    */
 | |
|   protected void layoutLabel(int tabPlacement, FontMetrics metrics,
 | |
|                              int tabIndex, String title, Icon icon,
 | |
|                              Rectangle tabRect, Rectangle iconRect,
 | |
|                              Rectangle textRect, boolean isSelected)
 | |
|   {
 | |
|     // Reset the icon and text rectangles, as the result is not specified
 | |
|     // when the locations are not (0,0).
 | |
|     textRect.x = 0;
 | |
|     textRect.y = 0;
 | |
|     textRect.width = 0;
 | |
|     textRect.height = 0;
 | |
|     iconRect.x = 0;
 | |
|     iconRect.y = 0;
 | |
|     iconRect.width = 0;
 | |
|     iconRect.height = 0;
 | |
|     SwingUtilities.layoutCompoundLabel(tabPane, metrics, title, icon,
 | |
|                                        SwingConstants.CENTER,
 | |
|                                        SwingConstants.CENTER,
 | |
|                                        SwingConstants.CENTER,
 | |
|                                        SwingConstants.RIGHT, tabRect,
 | |
|                                        iconRect, textRect, textIconGap);
 | |
| 
 | |
|     int shiftX = getTabLabelShiftX(tabPlacement, tabIndex, isSelected);
 | |
|     int shiftY = getTabLabelShiftY(tabPlacement, tabIndex, isSelected);
 | |
| 
 | |
|     iconRect.x += shiftX;
 | |
|     iconRect.y += shiftY;
 | |
| 
 | |
|     textRect.x += shiftX;
 | |
|     textRect.y += shiftY;
 | |
|   }
 | |
| 
 | |
|   /**
 | |
|    * This method paints the icon.
 | |
|    *
 | |
|    * @param g The Graphics object to paint.
 | |
|    * @param tabPlacement The JTabbedPane's tab placement.
 | |
|    * @param tabIndex The tab index to paint.
 | |
|    * @param icon The icon to paint.
 | |
|    * @param iconRect The bounds of the icon.
 | |
|    * @param isSelected Whether this tab is selected.
 | |
|    */
 | |
|   protected void paintIcon(Graphics g, int tabPlacement, int tabIndex,
 | |
|                            Icon icon, Rectangle iconRect, boolean isSelected)
 | |
|   {
 | |
|     if (icon != null)
 | |
|       icon.paintIcon(tabPane, g, iconRect.x, iconRect.y);
 | |
|   }
 | |
| 
 | |
|   /**
 | |
|    * This method paints the text for the given tab.
 | |
|    *
 | |
|    * @param g The Graphics object to paint with.
 | |
|    * @param tabPlacement The JTabbedPane's tab placement.
 | |
|    * @param font The font to paint with.
 | |
|    * @param metrics The fontmetrics of the given font.
 | |
|    * @param tabIndex The tab index.
 | |
|    * @param title The string to paint.
 | |
|    * @param textRect The bounds of the string.
 | |
|    * @param isSelected Whether this tab is selected.
 | |
|    */
 | |
|   protected void paintText(Graphics g, int tabPlacement, Font font,
 | |
|                            FontMetrics metrics, int tabIndex, String title,
 | |
|                            Rectangle textRect, boolean isSelected)
 | |
|   {
 | |
|     g.setFont(font);
 | |
|     View textView = getTextViewForTab(tabIndex);
 | |
|     if (textView != null)
 | |
|       {
 | |
|         textView.paint(g, textRect);
 | |
|         return;
 | |
|       }
 | |
| 
 | |
|     int ascent = metrics.getAscent();
 | |
| 
 | |
|     int mnemIndex = tabPane.getDisplayedMnemonicIndexAt(tabIndex);
 | |
|     if (tabPane.isEnabled() && tabPane.isEnabledAt(tabIndex))
 | |
|       {
 | |
|         Color fg = tabPane.getForegroundAt(tabIndex);
 | |
|         if (isSelected && (fg instanceof UIResource))
 | |
|           {
 | |
|             Color selectionForeground =
 | |
|               UIManager.getColor("TabbedPane.selectionForeground");
 | |
|             if (selectionForeground != null)
 | |
|               fg = selectionForeground;
 | |
|           }
 | |
|         g.setColor(fg);
 | |
| 
 | |
|         if (mnemIndex != -1)
 | |
|           BasicGraphicsUtils.drawStringUnderlineCharAt(g, title, mnemIndex,
 | |
|                                                        textRect.x,
 | |
|                                                        textRect.y + ascent);
 | |
|         else
 | |
|           g.drawString(title, textRect.x, textRect.y + ascent);
 | |
|       }
 | |
|     else
 | |
|       {
 | |
|         Color bg = tabPane.getBackgroundAt(tabIndex);
 | |
|         g.setColor(bg.brighter());
 | |
|         if (mnemIndex != -1)
 | |
|           BasicGraphicsUtils.drawStringUnderlineCharAt(g, title, mnemIndex,
 | |
|                                                        textRect.x, textRect.y
 | |
|                                                        + ascent);
 | |
|         else
 | |
|           g.drawString(title, textRect.x, textRect.y + ascent);
 | |
| 
 | |
|         g.setColor(bg.darker());
 | |
|         if (mnemIndex != -1)
 | |
|           BasicGraphicsUtils.drawStringUnderlineCharAt(g, title, mnemIndex,
 | |
|                                                        textRect.x + 1,
 | |
|                                                        textRect.y + 1
 | |
|                                                        + ascent);
 | |
|         else
 | |
|           g.drawString(title, textRect.x + 1, textRect.y + 1 + ascent);
 | |
|       }
 | |
|   }
 | |
| 
 | |
|   /**
 | |
|    * This method returns how much the label for the tab should shift in the X
 | |
|    * direction.
 | |
|    *
 | |
|    * @param tabPlacement The JTabbedPane's tab placement.
 | |
|    * @param tabIndex The tab index being painted.
 | |
|    * @param isSelected Whether this tab is selected.
 | |
|    *
 | |
|    * @return The amount the label should shift by in the X direction.
 | |
|    */
 | |
|   protected int getTabLabelShiftX(int tabPlacement, int tabIndex,
 | |
|                                   boolean isSelected)
 | |
|   {
 | |
|     switch (tabPlacement)
 | |
|     {
 | |
|       default:
 | |
|       case SwingUtilities.TOP:
 | |
|       case SwingUtilities.BOTTOM:
 | |
|         return 1;
 | |
|       case SwingUtilities.LEFT:
 | |
|         return (isSelected) ? -1 : 1;
 | |
|       case SwingUtilities.RIGHT:
 | |
|         return (isSelected) ? 1 : -1;
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   /**
 | |
|    * This method returns how much the label for the tab should shift in the Y
 | |
|    * direction.
 | |
|    *
 | |
|    * @param tabPlacement The JTabbedPane's tab placement.
 | |
|    * @param tabIndex The tab index being painted.
 | |
|    * @param isSelected Whether this tab is selected.
 | |
|    *
 | |
|    * @return The amount the label should shift by in the Y direction.
 | |
|    */
 | |
|   protected int getTabLabelShiftY(int tabPlacement, int tabIndex,
 | |
|                                   boolean isSelected)
 | |
|   {
 | |
|     switch (tabPlacement)
 | |
|     {
 | |
|       default:
 | |
|       case SwingUtilities.TOP:
 | |
|         return (isSelected) ? -1 : 1;
 | |
|       case SwingUtilities.BOTTOM:
 | |
|         return (isSelected) ? 1 : -1;
 | |
|       case SwingUtilities.LEFT:
 | |
|       case SwingUtilities.RIGHT:
 | |
|         return 0;
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   /**
 | |
|    * This method paints the focus rectangle around the selected tab.
 | |
|    *
 | |
|    * @param g The Graphics object to paint with.
 | |
|    * @param tabPlacement The JTabbedPane's tab placement.
 | |
|    * @param rects The array of rectangles keeping track of size and position.
 | |
|    * @param tabIndex The tab index.
 | |
|    * @param iconRect The icon bounds.
 | |
|    * @param textRect The text bounds.
 | |
|    * @param isSelected Whether this tab is selected.
 | |
|    */
 | |
|   protected void paintFocusIndicator(Graphics g, int tabPlacement,
 | |
|                                      Rectangle[] rects, int tabIndex,
 | |
|                                      Rectangle iconRect, Rectangle textRect,
 | |
|                                      boolean isSelected)
 | |
|   {
 | |
|     if (tabPane.hasFocus() && isSelected)
 | |
|       {
 | |
|         Rectangle rect = rects[tabIndex];
 | |
|         // The focus rectangle.
 | |
|         int x;
 | |
|         int y;
 | |
|         int w;
 | |
|         int h;
 | |
| 
 | |
|         g.setColor(focus);
 | |
|         switch (tabPlacement)
 | |
|           {
 | |
|           case LEFT:
 | |
|             x = rect.x + 3;
 | |
|             y = rect.y + 3;
 | |
|             w = rect.width - 5;
 | |
|             h = rect.height - 6;
 | |
|             break;
 | |
|           case RIGHT:
 | |
|             x = rect.x + 2;
 | |
|             y = rect.y + 3;
 | |
|             w = rect.width - 6;
 | |
|             h = rect.height - 5;
 | |
|             break;
 | |
|           case BOTTOM:
 | |
|             x = rect.x + 3;
 | |
|             y = rect.y + 2;
 | |
|             w = rect.width - 6;
 | |
|             h = rect.height - 5;
 | |
|             break;
 | |
|           case TOP:
 | |
|           default:
 | |
|             x = rect.x + 3;
 | |
|             y = rect.y + 3;
 | |
|             w = rect.width - 6;
 | |
|             h = rect.height - 5;
 | |
|           }
 | |
| 
 | |
|         BasicGraphicsUtils.drawDashedRect(g, x, y, w, h);
 | |
|       }
 | |
|   }
 | |
| 
 | |
|   /**
 | |
|    * This method paints the border for an individual tab.
 | |
|    *
 | |
|    * @param g The Graphics object to paint with.
 | |
|    * @param tabPlacement The JTabbedPane's tab placement.
 | |
|    * @param tabIndex The tab index.
 | |
|    * @param x The x position of the tab.
 | |
|    * @param y The y position of the tab.
 | |
|    * @param w The width of the tab.
 | |
|    * @param h The height of the tab.
 | |
|    * @param isSelected Whether the tab is selected.
 | |
|    */
 | |
|   protected void paintTabBorder(Graphics g, int tabPlacement, int tabIndex,
 | |
|                                 int x, int y, int w, int h, boolean isSelected)
 | |
|   {
 | |
|     Color saved = g.getColor();
 | |
| 
 | |
|     switch (tabPlacement)
 | |
|     {
 | |
|       case SwingConstants.TOP:
 | |
|         g.setColor(shadow);
 | |
|         // Inner right line.
 | |
|         g.drawLine(x + w - 2, y + 2, x + w - 2, y + h);
 | |
| 
 | |
|         g.setColor(darkShadow);
 | |
|         // Outer right line.
 | |
|         g.drawLine(x + w - 1, y + 2, x + w - 1, y + h);
 | |
| 
 | |
|         // Upper right corner.
 | |
|         g.drawLine(x + w - 2, y + 1, x + w - 1, y + 2);
 | |
| 
 | |
|         g.setColor(lightHighlight);
 | |
| 
 | |
|         // Left line.
 | |
|         g.drawLine(x, y + 3, x, y + h);
 | |
| 
 | |
|         // Upper line.
 | |
|         g.drawLine(x + 3, y, x + w - 3, y);
 | |
| 
 | |
|         // Upper left corner.
 | |
|         g.drawLine(x, y + 2, x + 2, y);
 | |
| 
 | |
|         break;
 | |
|       case SwingConstants.LEFT:
 | |
|         g.setColor(lightHighlight);
 | |
|         // Top line.
 | |
|         g.drawLine(x + 3, y, x + w - 1, y);
 | |
| 
 | |
|         // Top left border.
 | |
|         g.drawLine(x + 2, y, x, y + 2);
 | |
| 
 | |
|         // Left line.
 | |
|         g.drawLine(x, y + 3, x, y + h - 4);
 | |
| 
 | |
|         // Bottom left corner.
 | |
|         g.drawLine(x, y + h - 3, x + 1, y + h - 2);
 | |
| 
 | |
|         g.setColor(darkShadow);
 | |
|         // Outer bottom line.
 | |
|         g.drawLine(x + 2, y + h - 1, x + w - 1, y + h - 1);
 | |
| 
 | |
|         g.setColor(shadow);
 | |
|         // Inner bottom line.
 | |
|         g.drawLine(x + 2, y + h - 2,  x + w - 1, y + h - 2);
 | |
| 
 | |
|         break;
 | |
|       case SwingConstants.BOTTOM:
 | |
|         g.setColor(shadow);
 | |
|         // Inner right line.
 | |
|         g.drawLine(x + w - 2, y, x + w - 2, y + h - 2);
 | |
| 
 | |
|         // Inner bottom line.
 | |
|         g.drawLine(x + 2, y + h - 1, x + w - 3, y + h - 1);
 | |
| 
 | |
|         g.setColor(darkShadow);
 | |
|         // Outer right line.
 | |
|         g.drawLine(x + w - 1, y, x + w - 1, y + h - 3);
 | |
| 
 | |
|         // Bottom right corner.
 | |
|         g.drawLine(x + w - 1, y + h - 2, x + w - 3, y + h);
 | |
| 
 | |
|         // Bottom line.
 | |
|         g.drawLine(x + 2, y + h, x + w - 4, y + h);
 | |
| 
 | |
|         g.setColor(lightHighlight);
 | |
|         // Left line.
 | |
|         g.drawLine(x, y, x, y + h - 3);
 | |
| 
 | |
|         // Bottom left corner.
 | |
|         g.drawLine(x, y + h - 2, x + 1, y + h - 1);
 | |
|         break;
 | |
|       case SwingConstants.RIGHT:
 | |
|         g.setColor(lightHighlight);
 | |
|         // Top line.
 | |
|         g.drawLine(x, y, x + w - 3, y);
 | |
| 
 | |
|         g.setColor(darkShadow);
 | |
|         // Top right corner.
 | |
|         g.drawLine(x + w - 2, y + 1, x + w - 1, y + 2);
 | |
| 
 | |
|         // Outer right line.
 | |
|         g.drawLine(x + w - 1, y + 3, x + w - 1, y + h - 3);
 | |
| 
 | |
|         // Bottom right corner.
 | |
|         g.drawLine(x + w - 2, y + h - 2, x + w - 3, y + h - 1);
 | |
| 
 | |
|         // Bottom line.
 | |
|         g.drawLine(x, y + h - 1, x + w - 4, y + h - 1);
 | |
| 
 | |
|         g.setColor(shadow);
 | |
| 
 | |
|         // Inner right line.
 | |
|         g.drawLine(x + w - 2, y + 2, x + w - 2, y + h - 3);
 | |
| 
 | |
|         // Inner bottom line.
 | |
|         g.drawLine(x, y + h - 2, x + w - 3, y + h - 2);
 | |
| 
 | |
|         break;
 | |
|     }
 | |
| 
 | |
|     g.setColor(saved);
 | |
|   }
 | |
| 
 | |
|   /**
 | |
|    * This method paints the background for an individual tab.
 | |
|    *
 | |
|    * @param g The Graphics object to paint with.
 | |
|    * @param tabPlacement The JTabbedPane's tab placement.
 | |
|    * @param tabIndex The tab index.
 | |
|    * @param x The x position of the tab.
 | |
|    * @param y The y position of the tab.
 | |
|    * @param w The width of the tab.
 | |
|    * @param h The height of the tab.
 | |
|    * @param isSelected Whether the tab is selected.
 | |
|    */
 | |
|   protected void paintTabBackground(Graphics g, int tabPlacement,
 | |
|                                     int tabIndex, int x, int y, int w, int h,
 | |
|                                     boolean isSelected)
 | |
|   {
 | |
|     Color saved = g.getColor();
 | |
| 
 | |
|     if (isSelected)
 | |
|       g.setColor(selectedColor);
 | |
|     else
 | |
|       {
 | |
|         Color bg = tabPane.getBackgroundAt(tabIndex);
 | |
|         if (bg == null)
 | |
|           bg = Color.LIGHT_GRAY;
 | |
|         g.setColor(bg);
 | |
|       }
 | |
| 
 | |
|     switch (tabPlacement)
 | |
|       {
 | |
|         case SwingConstants.TOP:
 | |
|           g.fillRect(x + 1, y + 1, w - 1, h - 1);
 | |
|           break;
 | |
|         case SwingConstants.BOTTOM:
 | |
|           g.fillRect(x, y, w - 1, h - 1);
 | |
|           break;
 | |
|         case SwingConstants.LEFT:
 | |
|           g.fillRect(x + 1, y + 1, w - 1, h - 2);
 | |
|           break;
 | |
|         case SwingConstants.RIGHT:
 | |
|           g.fillRect(x, y + 1, w - 1, h - 2);
 | |
|           break;
 | |
|       }
 | |
| 
 | |
|     g.setColor(saved);
 | |
|   }
 | |
| 
 | |
|   /**
 | |
|    * This method paints the border around the content area.
 | |
|    *
 | |
|    * @param g The Graphics object to paint with.
 | |
|    * @param tabPlacement The JTabbedPane's tab placement.
 | |
|    * @param selectedIndex The index of the selected tab.
 | |
|    */
 | |
|   protected void paintContentBorder(Graphics g, int tabPlacement,
 | |
|                                     int selectedIndex)
 | |
|   {
 | |
|     int width = tabPane.getWidth();
 | |
|     int height = tabPane.getHeight();
 | |
|     Insets insets = tabPane.getInsets();
 | |
| 
 | |
|     // Calculate coordinates of content area.
 | |
|     int x = insets.left;
 | |
|     int y = insets.top;
 | |
|     int w = width - insets.left - insets.right;
 | |
|     int h = height - insets.top - insets.bottom;
 | |
| 
 | |
|     switch (tabPlacement)
 | |
|     {
 | |
|     case LEFT:
 | |
|       x += calculateTabAreaWidth(tabPlacement, runCount, maxTabWidth);
 | |
|       w -= x - insets.left;
 | |
|       break;
 | |
|     case RIGHT:
 | |
|       w -= calculateTabAreaWidth(tabPlacement, runCount, maxTabWidth);
 | |
|       break;
 | |
|     case BOTTOM:
 | |
|       h -= calculateTabAreaHeight(tabPlacement, runCount, maxTabHeight);
 | |
|       break;
 | |
|     case TOP:
 | |
|     default:
 | |
|       y += calculateTabAreaHeight(tabPlacement, runCount, maxTabHeight);
 | |
|       h -= y - insets.top;
 | |
|     }
 | |
| 
 | |
|     // Fill background if necessary.
 | |
|     if (tabPane.isOpaque())
 | |
|       {
 | |
|         Color bg = UIManager.getColor("TabbedPane.contentAreaColor");
 | |
|         g.setColor(bg);
 | |
|         g.fillRect(x, y, w, h);
 | |
|       }
 | |
| 
 | |
|     // Paint border.
 | |
|     paintContentBorderTopEdge(g, tabPlacement, selectedIndex, x, y, w, h);
 | |
|     paintContentBorderLeftEdge(g, tabPlacement, selectedIndex, x, y, w, h);
 | |
|     paintContentBorderBottomEdge(g, tabPlacement, selectedIndex, x, y, w, h);
 | |
|     paintContentBorderRightEdge(g, tabPlacement, selectedIndex, x, y, w, h);
 | |
|   }
 | |
| 
 | |
|   /**
 | |
|    * This method paints the top edge of the content border.
 | |
|    *
 | |
|    * @param g The Graphics object to paint with.
 | |
|    * @param tabPlacement The JTabbedPane's tab placement.
 | |
|    * @param selectedIndex The selected tab index.
 | |
|    * @param x The x coordinate for the content area.
 | |
|    * @param y The y coordinate for the content area.
 | |
|    * @param w The width of the content area.
 | |
|    * @param h The height of the content area.
 | |
|    */
 | |
|   protected void paintContentBorderTopEdge(Graphics g, int tabPlacement,
 | |
|                                            int selectedIndex, int x, int y,
 | |
|                                            int w, int h)
 | |
|   {
 | |
|     Color saved = g.getColor();
 | |
|     g.setColor(lightHighlight);
 | |
| 
 | |
|     int startgap = rects[selectedIndex].x - currentScrollOffset;
 | |
|     int endgap = rects[selectedIndex].x + rects[selectedIndex].width
 | |
|                  - currentScrollOffset;
 | |
| 
 | |
|     // Paint the highlight line with a gap if the tabs are at the top
 | |
|     // and the selected tab is inside the visible area.
 | |
|     if (tabPlacement == SwingConstants.TOP && startgap >= 0)
 | |
|       {
 | |
|         g.drawLine(x, y, startgap, y);
 | |
|         g.drawLine(endgap, y, x + w - 1, y);
 | |
| 
 | |
|         g.setColor(selectedColor);
 | |
|         g.drawLine(startgap, y, endgap - 1, y);
 | |
|       }
 | |
|     else
 | |
|       g.drawLine(x, y, x + w, y);
 | |
| 
 | |
|     g.setColor(selectedColor);
 | |
|     g.drawLine(x, y + 1, x + w - 1, y + 1);
 | |
|     g.drawLine(x, y + 2, x + w - 1, y + 2);
 | |
| 
 | |
|     g.setColor(saved);
 | |
|   }
 | |
| 
 | |
|   /**
 | |
|    * This method paints the left edge of the content border.
 | |
|    *
 | |
|    * @param g The Graphics object to paint with.
 | |
|    * @param tabPlacement The JTabbedPane's tab placement.
 | |
|    * @param selectedIndex The selected tab index.
 | |
|    * @param x The x coordinate for the content area.
 | |
|    * @param y The y coordinate for the content area.
 | |
|    * @param w The width of the content area.
 | |
|    * @param h The height of the content area.
 | |
|    */
 | |
|   protected void paintContentBorderLeftEdge(Graphics g, int tabPlacement,
 | |
|                                             int selectedIndex, int x, int y,
 | |
|                                             int w, int h)
 | |
|   {
 | |
|     Color saved = g.getColor();
 | |
|     g.setColor(lightHighlight);
 | |
| 
 | |
|     int startgap = rects[selectedIndex].y - currentScrollOffset;
 | |
|     int endgap = rects[selectedIndex].y + rects[selectedIndex].height
 | |
|                  - currentScrollOffset;
 | |
| 
 | |
|     if (tabPlacement == SwingConstants.LEFT && startgap >= 0)
 | |
|       {
 | |
|         g.drawLine(x, y, x, startgap);
 | |
|         g.drawLine(x, endgap, x, y + h - 1);
 | |
| 
 | |
|         g.setColor(selectedColor);
 | |
|         g.drawLine(x, startgap, x, endgap - 1);
 | |
|       }
 | |
|     else
 | |
|       g.drawLine(x, y, x, y + h - 1);
 | |
| 
 | |
|     g.setColor(selectedColor);
 | |
|     g.drawLine(x + 1, y + 1, x + 1, y + h - 4);
 | |
| 
 | |
|     g.setColor(saved);
 | |
|   }
 | |
| 
 | |
|   /**
 | |
|    * This method paints the bottom edge of the content border.
 | |
|    *
 | |
|    * @param g The Graphics object to paint with.
 | |
|    * @param tabPlacement The JTabbedPane's tab placement.
 | |
|    * @param selectedIndex The selected tab index.
 | |
|    * @param x The x coordinate for the content area.
 | |
|    * @param y The y coordinate for the content area.
 | |
|    * @param w The width of the content area.
 | |
|    * @param h The height of the content area.
 | |
|    */
 | |
|   protected void paintContentBorderBottomEdge(Graphics g, int tabPlacement,
 | |
|                                               int selectedIndex, int x, int y,
 | |
|                                               int w, int h)
 | |
|   {
 | |
|     Color saved = g.getColor();
 | |
| 
 | |
|     int startgap = rects[selectedIndex].x - currentScrollOffset;
 | |
|     int endgap = rects[selectedIndex].x + rects[selectedIndex].width
 | |
|                  - currentScrollOffset;
 | |
| 
 | |
|     if (tabPlacement == SwingConstants.BOTTOM && startgap >= 0)
 | |
|       {
 | |
|         g.setColor(shadow);
 | |
|         g.drawLine(x + 1, y + h - 2, startgap, y + h - 2);
 | |
|         g.drawLine(endgap, y + h - 2, x + w - 2, y + h - 2);
 | |
| 
 | |
|         g.setColor(darkShadow);
 | |
|         g.drawLine(x, y + h - 1, startgap , y + h - 1);
 | |
|         g.drawLine(endgap, y + h - 1, x + w - 1, y + h - 1);
 | |
| 
 | |
|         g.setColor(selectedColor);
 | |
|         g.drawLine(startgap, y + h - 1, endgap - 1, y + h - 1);
 | |
|         g.drawLine(startgap, y + h - 2, endgap - 1, y + h - 2);
 | |
|       }
 | |
|     else
 | |
|       {
 | |
|         g.setColor(shadow);
 | |
|         g.drawLine(x + 1, y + h - 2, x + w - 1, y + h - 2);
 | |
|         g.setColor(darkShadow);
 | |
|         g.drawLine(x, y + h - 1, x + w - 1, y + h - 1);
 | |
|       }
 | |
| 
 | |
|     g.setColor(selectedColor);
 | |
|     g.drawLine(x + 1, y + h - 3, x + w - 2, y + h - 3);
 | |
| 
 | |
|     g.setColor(saved);
 | |
|   }
 | |
| 
 | |
|   /**
 | |
|    * This method paints the right edge of the content border.
 | |
|    *
 | |
|    * @param g The Graphics object to paint with.
 | |
|    * @param tabPlacement The JTabbedPane's tab placement.
 | |
|    * @param selectedIndex The selected tab index.
 | |
|    * @param x The x coordinate for the content area.
 | |
|    * @param y The y coordinate for the content area.
 | |
|    * @param w The width of the content area.
 | |
|    * @param h The height of the content area.
 | |
|    */
 | |
|   protected void paintContentBorderRightEdge(Graphics g, int tabPlacement,
 | |
|                                              int selectedIndex, int x, int y,
 | |
|                                              int w, int h)
 | |
|   {
 | |
|     Color saved = g.getColor();
 | |
|     int startgap = rects[selectedIndex].y - currentScrollOffset;
 | |
|     int endgap = rects[selectedIndex].y + rects[selectedIndex].height
 | |
|                  - currentScrollOffset;
 | |
| 
 | |
|     if (tabPlacement == SwingConstants.RIGHT && startgap >= 0)
 | |
|       {
 | |
|         g.setColor(shadow);
 | |
|         g.drawLine(x + w - 2, y + 1, x + w - 2, startgap);
 | |
|         g.drawLine(x + w - 2, endgap, x + w - 2, y + h - 2);
 | |
| 
 | |
|         g.setColor(darkShadow);
 | |
|         g.drawLine(x + w - 1, y, x + w - 1, startgap);
 | |
|         g.drawLine(x + w - 1, endgap, x + w - 1, y + h - 2);
 | |
| 
 | |
|         g.setColor(selectedColor);
 | |
|         g.drawLine(x + w - 2, startgap, x + w - 2, endgap - 1);
 | |
|         g.drawLine(x + w - 1, startgap, x + w - 1, endgap - 1);
 | |
|       }
 | |
|     else
 | |
|       {
 | |
|         g.setColor(shadow);
 | |
|         g.drawLine(x + w - 2, y + 1, x + w - 2, y + h - 2);
 | |
|         g.setColor(darkShadow);
 | |
|         g.drawLine(x + w - 1, y, x + w - 1, y + h - 2);
 | |
|       }
 | |
| 
 | |
|     g.setColor(selectedColor);
 | |
|     g.drawLine(x + w - 3, y + 1, x + w - 3, y + h - 4);
 | |
| 
 | |
|     g.setColor(saved);
 | |
|   }
 | |
| 
 | |
|   /**
 | |
|    * <p>This method returns the bounds of a tab for the given index
 | |
|    * and shifts it by the current scrolling offset if the tabbed
 | |
|    * pane is in scrolling tab layout mode.</p>
 | |
|    *
 | |
|    * <p>Subclassses should retrievs a tab's bounds by this method
 | |
|    * if they want to find out whether the tab is currently visible.</p>
 | |
|    *
 | |
|    * @param pane The JTabbedPane.
 | |
|    * @param i The index to look for.
 | |
|    *
 | |
|    * @return The bounds of the tab with the given index.
 | |
|    */
 | |
|   public Rectangle getTabBounds(JTabbedPane pane, int i)
 | |
|   {
 | |
|     // Need to re-layout container if tab does not exist.
 | |
|     if (i >= rects.length)
 | |
|       layoutManager.layoutContainer(pane);
 | |
| 
 | |
|     // Properly shift coordinates if scrolling has taken
 | |
|     // place.
 | |
|     if (pane.getTabLayoutPolicy() == JTabbedPane.SCROLL_TAB_LAYOUT)
 | |
|       {
 | |
|         Rectangle r = new Rectangle(rects[i]);
 | |
| 
 | |
|         switch(pane.getTabPlacement())
 | |
|         {
 | |
|           case SwingConstants.TOP:
 | |
|           case SwingConstants.BOTTOM:
 | |
|             r.x -= currentScrollOffset;
 | |
|             break;
 | |
|           default:
 | |
|             r.y -= currentScrollOffset;
 | |
|         }
 | |
| 
 | |
|         return r;
 | |
|       }
 | |
| 
 | |
|     return rects[i];
 | |
|   }
 | |
| 
 | |
|   /**
 | |
|    * This method returns the number of runs.
 | |
|    *
 | |
|    * @param pane The JTabbedPane.
 | |
|    *
 | |
|    * @return The number of runs.
 | |
|    */
 | |
|   public int getTabRunCount(JTabbedPane pane)
 | |
|   {
 | |
|     return runCount;
 | |
|   }
 | |
| 
 | |
|   /**
 | |
|    * This method returns the tab index given a coordinate.
 | |
|    *
 | |
|    * @param pane The JTabbedPane.
 | |
|    * @param x The x coordinate.
 | |
|    * @param y The y coordinate.
 | |
|    *
 | |
|    * @return The tab index that the coordinate lands in.
 | |
|    */
 | |
|   public int tabForCoordinate(JTabbedPane pane, int x, int y)
 | |
|   {
 | |
|     // Note: This code is tab layout mode agnostic.
 | |
|     if (! tabPane.isValid())
 | |
|       tabPane.validate();
 | |
| 
 | |
|     int tabCount = tabPane.getTabCount();
 | |
| 
 | |
|     // If the user clicked outside of any tab rect the
 | |
|     // selection should not change.
 | |
|     int index = tabPane.getSelectedIndex();
 | |
|     for (int i = 0; i < tabCount; ++i)
 | |
|       {
 | |
|         if (rects[i].contains(x, y))
 | |
|           {
 | |
|             index = i;
 | |
|             break;
 | |
|           }
 | |
|       }
 | |
| 
 | |
|     return index;
 | |
|   }
 | |
| 
 | |
|   /**
 | |
|    * <p>This method returns the tab bounds in the given rectangle.</p>
 | |
|    *
 | |
|    * <p>The returned rectangle will be shifted by the current scroll
 | |
|    * offset if the tabbed pane is in scrolling tab layout mode.</p>.
 | |
|    *
 | |
|    * @param tabIndex The index to get bounds for.
 | |
|    * @param dest The rectangle to store bounds in.
 | |
|    *
 | |
|    * @return The rectangle passed in.
 | |
|    */
 | |
|   protected Rectangle getTabBounds(int tabIndex, Rectangle dest)
 | |
|   {
 | |
|     dest.setBounds(getTabBounds(tabPane, tabIndex));
 | |
|     return dest;
 | |
|   }
 | |
| 
 | |
|   /**
 | |
|    * This method returns the component that is shown in  the content area.
 | |
|    *
 | |
|    * @return The component that is shown in the content area.
 | |
|    */
 | |
|   protected Component getVisibleComponent()
 | |
|   {
 | |
|     return visibleComponent;
 | |
|   }
 | |
| 
 | |
|   /**
 | |
|    * This method sets the visible component.
 | |
|    *
 | |
|    * @param component The component to be set visible.
 | |
|    */
 | |
|   protected void setVisibleComponent(Component component)
 | |
|   {
 | |
|     // Make old component invisible.
 | |
|     if (visibleComponent != null && visibleComponent != component
 | |
|         && visibleComponent.getParent() == tabPane)
 | |
|       {
 | |
|         visibleComponent.setVisible(false);
 | |
|       }
 | |
| 
 | |
|     // Make new component visible.
 | |
|     if (component != null && ! component.isVisible())
 | |
|       {
 | |
|         component.setVisible(true);
 | |
|       }
 | |
|     visibleComponent = component;
 | |
|   }
 | |
| 
 | |
|   /**
 | |
|    * This method assures that enough rectangles are created given the
 | |
|    * tabCount. The old array is copied to the  new one.
 | |
|    *
 | |
|    * @param tabCount The number of tabs.
 | |
|    */
 | |
|   protected void assureRectsCreated(int tabCount)
 | |
|   {
 | |
|     if (rects.length < tabCount)
 | |
|       {
 | |
|         Rectangle[] old = rects;
 | |
|         rects = new Rectangle[tabCount];
 | |
|         System.arraycopy(old, 0, rects, 0, old.length);
 | |
|         for (int i = old.length; i < rects.length; i++)
 | |
|           rects[i] = new Rectangle();
 | |
|       }
 | |
|   }
 | |
| 
 | |
|   /**
 | |
|    * This method expands the tabRuns array to give it more room. The old array
 | |
|    * is copied to the new one.
 | |
|    */
 | |
|   protected void expandTabRunsArray()
 | |
|   {
 | |
|     // This method adds another 10 index positions to the tabRuns array.
 | |
|     if (tabRuns == null)
 | |
|       tabRuns = new int[10];
 | |
|     else
 | |
|       {
 | |
|         int[] newRuns = new int[tabRuns.length + 10];
 | |
|         System.arraycopy(tabRuns, 0, newRuns, 0, tabRuns.length);
 | |
|         tabRuns = newRuns;
 | |
|       }
 | |
|   }
 | |
| 
 | |
|   /**
 | |
|    * This method returns which run a particular tab belongs to.
 | |
|    *
 | |
|    * @param tabCount The number of tabs.
 | |
|    * @param tabIndex The tab to find.
 | |
|    *
 | |
|    * @return The tabRuns index that it belongs to.
 | |
|    */
 | |
|   protected int getRunForTab(int tabCount, int tabIndex)
 | |
|   {
 | |
|     if (runCount == 1 && tabIndex < tabCount && tabIndex >= 0)
 | |
|       return 0;
 | |
|     for (int i = 0; i < runCount; i++)
 | |
|       {
 | |
|         int first = lastTabInRun(tabCount, getPreviousTabRun(i)) + 1;
 | |
|         if (first == tabCount)
 | |
|           first = 0;
 | |
|         int last = lastTabInRun(tabCount, i);
 | |
|         if (last >= tabIndex && first <= tabIndex)
 | |
|           return i;
 | |
|       }
 | |
|     return -1;
 | |
|   }
 | |
| 
 | |
|   /**
 | |
|    * This method returns the index of the last tab in  a run.
 | |
|    *
 | |
|    * @param tabCount The number of tabs.
 | |
|    * @param run The run to check.
 | |
|    *
 | |
|    * @return The last tab in the given run.
 | |
|    */
 | |
|   protected int lastTabInRun(int tabCount, int run)
 | |
|   {
 | |
|     int lastTab;
 | |
|     if (runCount == 1)
 | |
|       lastTab = tabCount - 1;
 | |
|     else
 | |
|       {
 | |
|         int nextRun;
 | |
|         if (run == runCount - 1)
 | |
|           nextRun = 0;
 | |
|         else
 | |
|           nextRun = run + 1;
 | |
| 
 | |
|         if (tabRuns[nextRun] == 0)
 | |
|           lastTab = tabCount - 1;
 | |
|         else
 | |
|           lastTab = tabRuns[nextRun] - 1;
 | |
|       }
 | |
|     return lastTab;
 | |
|   }
 | |
| 
 | |
|   /**
 | |
|    * This method returns the tab run overlay.
 | |
|    *
 | |
|    * @param tabPlacement The JTabbedPane's tab placement.
 | |
|    *
 | |
|    * @return The tab run overlay.
 | |
|    */
 | |
|   protected int getTabRunOverlay(int tabPlacement)
 | |
|   {
 | |
|     return tabRunOverlay;
 | |
|   }
 | |
| 
 | |
|   /**
 | |
|    * This method returns the tab run indent. It is used in WRAP_TAB_LAYOUT and
 | |
|    * makes each tab run start indented by a certain amount.
 | |
|    *
 | |
|    * @param tabPlacement The JTabbedPane's tab placement.
 | |
|    * @param run The run to get indent for.
 | |
|    *
 | |
|    * @return The amount a run should be indented.
 | |
|    */
 | |
|   protected int getTabRunIndent(int tabPlacement, int run)
 | |
|   {
 | |
|     return 0;
 | |
|   }
 | |
| 
 | |
|   /**
 | |
|    * This method returns whether a tab run should be padded.
 | |
|    *
 | |
|    * @param tabPlacement The JTabbedPane's tab placement.
 | |
|    * @param run The run to check.
 | |
|    *
 | |
|    * @return Whether the given run should be padded.
 | |
|    */
 | |
|   protected boolean shouldPadTabRun(int tabPlacement, int run)
 | |
|   {
 | |
|     return true;
 | |
|   }
 | |
| 
 | |
|   /**
 | |
|    * This method returns whether the tab runs should be rotated.
 | |
|    *
 | |
|    * @param tabPlacement The JTabbedPane's tab placement.
 | |
|    *
 | |
|    * @return Whether runs should be rotated.
 | |
|    */
 | |
|   protected boolean shouldRotateTabRuns(int tabPlacement)
 | |
|   {
 | |
|     return true;
 | |
|   }
 | |
| 
 | |
|   /**
 | |
|    * This method returns an icon for the tab. If the tab is disabled, it
 | |
|    * should return the disabledIcon. If it is enabled, then it should return
 | |
|    * the default icon.
 | |
|    *
 | |
|    * @param tabIndex The tab index to get an icon for.
 | |
|    *
 | |
|    * @return The icon for the tab index.
 | |
|    */
 | |
|   protected Icon getIconForTab(int tabIndex)
 | |
|   {
 | |
|     if (tabPane.isEnabledAt(tabIndex))
 | |
|       return tabPane.getIconAt(tabIndex);
 | |
|     else
 | |
|       return tabPane.getDisabledIconAt(tabIndex);
 | |
|   }
 | |
| 
 | |
|   /**
 | |
|    * This method returns a view that can paint the text for the label.
 | |
|    *
 | |
|    * @param tabIndex The tab index to get a view for.
 | |
|    *
 | |
|    * @return The view for the tab index.
 | |
|    */
 | |
|   protected View getTextViewForTab(int tabIndex)
 | |
|   {
 | |
|     // FIXME: When the label contains HTML this should return something
 | |
|     // non-null.
 | |
|     return null;
 | |
|   }
 | |
| 
 | |
|   /**
 | |
|    * This method returns the tab height, including insets, for the given index
 | |
|    * and fontheight.
 | |
|    *
 | |
|    * @param tabPlacement The JTabbedPane's tab placement.
 | |
|    * @param tabIndex The index of the tab to calculate.
 | |
|    * @param fontHeight The font height.
 | |
|    *
 | |
|    * @return This tab's height.
 | |
|    */
 | |
|   protected int calculateTabHeight(int tabPlacement, int tabIndex,
 | |
|                                    int fontHeight)
 | |
|   {
 | |
|     // FIXME: Handle HTML by using the view (see getTextViewForTab).
 | |
| 
 | |
|     int height = fontHeight;
 | |
|     Icon icon = getIconForTab(tabIndex);
 | |
|     Insets tabInsets = getTabInsets(tabPlacement, tabIndex);
 | |
|     if (icon != null)
 | |
|       height = Math.max(height, icon.getIconHeight());
 | |
|     height += tabInsets.top + tabInsets.bottom + 2;
 | |
|     return height;
 | |
|   }
 | |
| 
 | |
|   /**
 | |
|    * This method returns the max tab height.
 | |
|    *
 | |
|    * @param tabPlacement The JTabbedPane's tab placement.
 | |
|    *
 | |
|    * @return The maximum tab height.
 | |
|    */
 | |
|   protected int calculateMaxTabHeight(int tabPlacement)
 | |
|   {
 | |
|     maxTabHeight = 0;
 | |
| 
 | |
|     FontMetrics fm = getFontMetrics();
 | |
|     int fontHeight = fm.getHeight();
 | |
| 
 | |
|     for (int i = 0; i < tabPane.getTabCount(); i++)
 | |
|       maxTabHeight = Math.max(calculateTabHeight(tabPlacement, i, fontHeight),
 | |
|                               maxTabHeight);
 | |
| 
 | |
|     return maxTabHeight;
 | |
|   }
 | |
| 
 | |
|   /**
 | |
|    * This method calculates the tab width, including insets, for the given tab
 | |
|    * index and font metrics.
 | |
|    *
 | |
|    * @param tabPlacement The JTabbedPane's tab placement.
 | |
|    * @param tabIndex The tab index to calculate for.
 | |
|    * @param metrics The font's metrics.
 | |
|    *
 | |
|    * @return The tab width for the given index.
 | |
|    */
 | |
|   protected int calculateTabWidth(int tabPlacement, int tabIndex,
 | |
|                                   FontMetrics metrics)
 | |
|   {
 | |
|     Icon icon = getIconForTab(tabIndex);
 | |
|     Insets insets = getTabInsets(tabPlacement, tabIndex);
 | |
| 
 | |
|     int width = insets.bottom + insets.right + 3;
 | |
|     if (icon != null)
 | |
|       {
 | |
|         width += icon.getIconWidth() + textIconGap;
 | |
|       }
 | |
| 
 | |
|     View v = getTextViewForTab(tabIndex);
 | |
|     if (v != null)
 | |
|       width += v.getPreferredSpan(View.X_AXIS);
 | |
|     else
 | |
|       {
 | |
|         String label = tabPane.getTitleAt(tabIndex);
 | |
|         width += metrics.stringWidth(label);
 | |
|       }
 | |
|     return width;
 | |
|   }
 | |
| 
 | |
|   /**
 | |
|    * This method calculates the max tab width.
 | |
|    *
 | |
|    * @param tabPlacement The JTabbedPane's tab placement.
 | |
|    *
 | |
|    * @return The maximum tab width.
 | |
|    */
 | |
|   protected int calculateMaxTabWidth(int tabPlacement)
 | |
|   {
 | |
|     maxTabWidth = 0;
 | |
| 
 | |
|     FontMetrics fm = getFontMetrics();
 | |
| 
 | |
|     for (int i = 0; i < tabPane.getTabCount(); i++)
 | |
|       maxTabWidth = Math.max(calculateTabWidth(tabPlacement, i, fm),
 | |
|                              maxTabWidth);
 | |
| 
 | |
|     return maxTabWidth;
 | |
|   }
 | |
| 
 | |
|   /**
 | |
|    * This method calculates the tab area height, including insets, for the
 | |
|    * given amount of runs and tab height.
 | |
|    *
 | |
|    * @param tabPlacement The JTabbedPane's tab placement.
 | |
|    * @param horizRunCount The number of runs.
 | |
|    * @param maxTabHeight The max tab height.
 | |
|    *
 | |
|    * @return The tab area height.
 | |
|    */
 | |
|   protected int calculateTabAreaHeight(int tabPlacement, int horizRunCount,
 | |
|                                        int maxTabHeight)
 | |
|   {
 | |
|     Insets insets = getTabAreaInsets(tabPlacement);
 | |
|     int tabAreaHeight = horizRunCount * maxTabHeight
 | |
|                         - (horizRunCount - 1)
 | |
|                         * getTabRunOverlay(tabPlacement);
 | |
| 
 | |
|     tabAreaHeight += insets.top + insets.bottom;
 | |
| 
 | |
|     return tabAreaHeight;
 | |
|   }
 | |
| 
 | |
|   /**
 | |
|    * This method calculates the tab area width, including insets, for the
 | |
|    * given amount of runs and tab width.
 | |
|    *
 | |
|    * @param tabPlacement The JTabbedPane's tab placement.
 | |
|    * @param vertRunCount The number of runs.
 | |
|    * @param maxTabWidth The max tab width.
 | |
|    *
 | |
|    * @return The tab area width.
 | |
|    */
 | |
|   protected int calculateTabAreaWidth(int tabPlacement, int vertRunCount,
 | |
|                                       int maxTabWidth)
 | |
|   {
 | |
|     Insets insets = getTabAreaInsets(tabPlacement);
 | |
|     int tabAreaWidth = vertRunCount * maxTabWidth
 | |
|                        - (vertRunCount - 1)
 | |
|                        * getTabRunOverlay(tabPlacement);
 | |
| 
 | |
|     tabAreaWidth += insets.left + insets.right;
 | |
| 
 | |
|     return tabAreaWidth;
 | |
|   }
 | |
| 
 | |
|   /**
 | |
|    * This method returns the tab insets appropriately rotated.
 | |
|    *
 | |
|    * @param tabPlacement The JTabbedPane's tab placement.
 | |
|    * @param tabIndex The tab index.
 | |
|    *
 | |
|    * @return The tab insets for the given index.
 | |
|    */
 | |
|   protected Insets getTabInsets(int tabPlacement, int tabIndex)
 | |
|   {
 | |
|     return tabInsets;
 | |
|   }
 | |
| 
 | |
|   /**
 | |
|    * This method returns the selected tab pad insets appropriately rotated.
 | |
|    *
 | |
|    * @param tabPlacement The JTabbedPane's tab placement.
 | |
|    *
 | |
|    * @return The selected tab pad insets.
 | |
|    */
 | |
|   protected Insets getSelectedTabPadInsets(int tabPlacement)
 | |
|   {
 | |
|     Insets target = new Insets(0, 0, 0, 0);
 | |
|     rotateInsets(selectedTabPadInsets, target, tabPlacement);
 | |
|     return target;
 | |
|   }
 | |
| 
 | |
|   /**
 | |
|    * This method returns the tab area insets appropriately rotated.
 | |
|    *
 | |
|    * @param tabPlacement The JTabbedPane's tab placement.
 | |
|    *
 | |
|    * @return The tab area insets.
 | |
|    */
 | |
|   protected Insets getTabAreaInsets(int tabPlacement)
 | |
|   {
 | |
|     Insets target = new Insets(0, 0, 0, 0);
 | |
|     rotateInsets(tabAreaInsets, target, tabPlacement);
 | |
|     return target;
 | |
|   }
 | |
| 
 | |
|   /**
 | |
|    * This method returns the content border insets appropriately rotated.
 | |
|    *
 | |
|    * @param tabPlacement The JTabbedPane's tab placement.
 | |
|    *
 | |
|    * @return The content border insets.
 | |
|    */
 | |
|   protected Insets getContentBorderInsets(int tabPlacement)
 | |
|   {
 | |
|     Insets target = new Insets(0, 0, 0, 0);
 | |
|     rotateInsets(contentBorderInsets, target, tabPlacement);
 | |
|     return target;
 | |
|   }
 | |
| 
 | |
|   /**
 | |
|    * This method returns the fontmetrics for the font of the JTabbedPane.
 | |
|    *
 | |
|    * @return The font metrics for the JTabbedPane.
 | |
|    */
 | |
|   protected FontMetrics getFontMetrics()
 | |
|   {
 | |
|     FontMetrics fm = tabPane.getFontMetrics(tabPane.getFont());
 | |
|     return fm;
 | |
|   }
 | |
| 
 | |
|   /**
 | |
|    * This method navigates from the selected tab into the given direction. As
 | |
|    * a result, a new tab will be selected (if possible).
 | |
|    *
 | |
|    * @param direction The direction to navigate in.
 | |
|    */
 | |
|   protected void navigateSelectedTab(int direction)
 | |
|   {
 | |
|     int tabPlacement = tabPane.getTabPlacement();
 | |
|     if (tabPlacement == SwingConstants.TOP
 | |
|         || tabPlacement == SwingConstants.BOTTOM)
 | |
|       {
 | |
|         if (direction == SwingConstants.WEST)
 | |
|           selectPreviousTabInRun(tabPane.getSelectedIndex());
 | |
|         else if (direction == SwingConstants.EAST)
 | |
|           selectNextTabInRun(tabPane.getSelectedIndex());
 | |
| 
 | |
|         else
 | |
|           {
 | |
|             int offset = getTabRunOffset(tabPlacement, tabPane.getTabCount(),
 | |
|                                          tabPane.getSelectedIndex(),
 | |
|                                          (tabPlacement == SwingConstants.TOP)
 | |
|                                          ? direction == SwingConstants.NORTH
 | |
|                                          : direction == SwingConstants.SOUTH);
 | |
|             selectAdjacentRunTab(tabPlacement, tabPane.getSelectedIndex(),
 | |
|                                  offset);
 | |
|           }
 | |
|       }
 | |
|     if (tabPlacement == SwingConstants.LEFT
 | |
|         || tabPlacement == SwingConstants.RIGHT)
 | |
|       {
 | |
|         if (direction == SwingConstants.NORTH)
 | |
|           selectPreviousTabInRun(tabPane.getSelectedIndex());
 | |
|         else if (direction == SwingConstants.SOUTH)
 | |
|           selectNextTabInRun(tabPane.getSelectedIndex());
 | |
|         else
 | |
|           {
 | |
|             int offset = getTabRunOffset(tabPlacement, tabPane.getTabCount(),
 | |
|                                          tabPane.getSelectedIndex(),
 | |
|                                          (tabPlacement == SwingConstants.LEFT)
 | |
|                                          ? direction == SwingConstants.WEST
 | |
|                                          : direction == SwingConstants.EAST);
 | |
|             selectAdjacentRunTab(tabPlacement, tabPane.getSelectedIndex(),
 | |
|                                  offset);
 | |
|           }
 | |
|       }
 | |
|   }
 | |
| 
 | |
|   /**
 | |
|    * This method selects the next tab in the run.
 | |
|    *
 | |
|    * @param current The current selected index.
 | |
|    */
 | |
|   protected void selectNextTabInRun(int current)
 | |
|   {
 | |
|     current = getNextTabIndexInRun(tabPane.getTabCount(),
 | |
|                                    current);
 | |
| 
 | |
|     if (tabPane.getTabLayoutPolicy() == JTabbedPane.SCROLL_TAB_LAYOUT)
 | |
|       scrollTab(current, tabPane.getTabPlacement());
 | |
| 
 | |
|     tabPane.setSelectedIndex(current);
 | |
|   }
 | |
| 
 | |
|   /**
 | |
|    * This method selects the previous tab in the run.
 | |
|    *
 | |
|    * @param current The current selected index.
 | |
|    */
 | |
|   protected void selectPreviousTabInRun(int current)
 | |
|   {
 | |
|     current = getPreviousTabIndexInRun(tabPane.getTabCount(),
 | |
|                                        current);
 | |
| 
 | |
|     if (tabPane.getTabLayoutPolicy() == JTabbedPane.SCROLL_TAB_LAYOUT)
 | |
|       scrollTab(current, tabPane.getTabPlacement());
 | |
| 
 | |
|     tabPane.setSelectedIndex(current);
 | |
|   }
 | |
| 
 | |
|   /**
 | |
|    * This method selects the next tab (regardless of runs).
 | |
|    *
 | |
|    * @param current The current selected index.
 | |
|    */
 | |
|   protected void selectNextTab(int current)
 | |
|   {
 | |
|     current = getNextTabIndex(current);
 | |
| 
 | |
|     if (tabPane.getTabLayoutPolicy() == JTabbedPane.SCROLL_TAB_LAYOUT)
 | |
|       scrollTab(current, tabPane.getTabPlacement());
 | |
| 
 | |
|     tabPane.setSelectedIndex(current);
 | |
|   }
 | |
| 
 | |
|   /**
 | |
|    * This method selects the previous tab (regardless of runs).
 | |
|    *
 | |
|    * @param current The current selected index.
 | |
|    */
 | |
|   protected void selectPreviousTab(int current)
 | |
|   {
 | |
|     current = getPreviousTabIndex(current);
 | |
| 
 | |
|     if (tabPane.getTabLayoutPolicy() == JTabbedPane.SCROLL_TAB_LAYOUT)
 | |
|       scrollTab(current, tabPane.getTabPlacement());
 | |
| 
 | |
|     tabPane.setSelectedIndex(current);
 | |
|   }
 | |
| 
 | |
|   /**
 | |
|    * This method selects the correct tab given an offset from the current tab
 | |
|    * index. If the tab placement is TOP or BOTTOM, the offset will be in the
 | |
|    * y direction, otherwise, it will be in the x direction. A new coordinate
 | |
|    * will be found by adding the offset to the current location of the tab.
 | |
|    * The tab that the new location will be selected.
 | |
|    *
 | |
|    * @param tabPlacement The JTabbedPane's tab placement.
 | |
|    * @param tabIndex The tab to start from.
 | |
|    * @param offset The coordinate offset.
 | |
|    */
 | |
|   protected void selectAdjacentRunTab(int tabPlacement, int tabIndex,
 | |
|                                       int offset)
 | |
|   {
 | |
|     int x = rects[tabIndex].x + rects[tabIndex].width / 2;
 | |
|     int y = rects[tabIndex].y + rects[tabIndex].height / 2;
 | |
| 
 | |
|     switch (tabPlacement)
 | |
|     {
 | |
|     case SwingConstants.TOP:
 | |
|     case SwingConstants.BOTTOM:
 | |
|       y += offset;
 | |
|       break;
 | |
|     case SwingConstants.RIGHT:
 | |
|     case SwingConstants.LEFT:
 | |
|       x += offset;
 | |
|       break;
 | |
|     }
 | |
| 
 | |
|     int index = tabForCoordinate(tabPane, x, y);
 | |
|     if (index != -1)
 | |
|       {
 | |
|         if (tabPane.getTabLayoutPolicy() == JTabbedPane.SCROLL_TAB_LAYOUT)
 | |
|           scrollTab(index, tabPlacement);
 | |
|         tabPane.setSelectedIndex(index);
 | |
|       }
 | |
|   }
 | |
| 
 | |
|   // This method is called when you press up/down to cycle through tab runs.
 | |
|   // it returns the distance (between the two runs' x/y position.
 | |
|   // where one run is the current selected run and the other run is the run in the
 | |
|   // direction of the scroll (dictated by the forward flag)
 | |
|   // the offset is an absolute value of the difference
 | |
| 
 | |
|   /**
 | |
|    * This method calculates the offset distance for use in
 | |
|    * selectAdjacentRunTab. The offset returned will be a difference in the y
 | |
|    * coordinate between the run in  the desired direction and the current run
 | |
|    * (for tabPlacement in TOP or BOTTOM). Use x coordinate for LEFT and
 | |
|    * RIGHT.
 | |
|    *
 | |
|    * @param tabPlacement The JTabbedPane's tab placement.
 | |
|    * @param tabCount The number of tabs.
 | |
|    * @param tabIndex The starting index.
 | |
|    * @param forward If forward, the run in the desired direction will be the
 | |
|    *        next run.
 | |
|    *
 | |
|    * @return The offset between the two runs.
 | |
|    */
 | |
|   protected int getTabRunOffset(int tabPlacement, int tabCount, int tabIndex,
 | |
|                                 boolean forward)
 | |
|   {
 | |
|     int currRun = getRunForTab(tabCount, tabIndex);
 | |
|     int offset;
 | |
|     int nextRun = forward ? getNextTabRun(currRun) : getPreviousTabRun(currRun);
 | |
|     if (tabPlacement == SwingConstants.TOP
 | |
|         || tabPlacement == SwingConstants.BOTTOM)
 | |
|       offset = rects[lastTabInRun(tabCount, nextRun)].y
 | |
|                - rects[lastTabInRun(tabCount, currRun)].y;
 | |
|     else
 | |
|       offset = rects[lastTabInRun(tabCount, nextRun)].x
 | |
|                - rects[lastTabInRun(tabCount, currRun)].x;
 | |
| 
 | |
|     return offset;
 | |
|   }
 | |
| 
 | |
|   /**
 | |
|    * This method returns the previous tab index.
 | |
|    *
 | |
|    * @param base The index to start from.
 | |
|    *
 | |
|    * @return The previous tab index.
 | |
|    */
 | |
|   protected int getPreviousTabIndex(int base)
 | |
|   {
 | |
|     base--;
 | |
|     if (base < 0)
 | |
|       return tabPane.getTabCount() - 1;
 | |
|     return base;
 | |
|   }
 | |
| 
 | |
|   /**
 | |
|    * This method returns the next tab index.
 | |
|    *
 | |
|    * @param base The index to start from.
 | |
|    *
 | |
|    * @return The next tab index.
 | |
|    */
 | |
|   protected int getNextTabIndex(int base)
 | |
|   {
 | |
|     base++;
 | |
|     if (base == tabPane.getTabCount())
 | |
|       return 0;
 | |
|     return base;
 | |
|   }
 | |
| 
 | |
|   /**
 | |
|    * This method returns the next tab index in the run. If the next index is
 | |
|    * out of this run, it will return the starting tab index for the run.
 | |
|    *
 | |
|    * @param tabCount The number of tabs.
 | |
|    * @param base The index to start from.
 | |
|    *
 | |
|    * @return The next tab index in the run.
 | |
|    */
 | |
|   protected int getNextTabIndexInRun(int tabCount, int base)
 | |
|   {
 | |
|     int index = getNextTabIndex(base);
 | |
|     int run = getRunForTab(tabCount, base);
 | |
|     if (base == lastTabInRun(tabCount, run))
 | |
|       index = (run > 0)
 | |
|               ? lastTabInRun(tabCount, getPreviousTabRun(run)) + 1
 | |
|               : 0;
 | |
| 
 | |
|     return index;
 | |
|   }
 | |
| 
 | |
|   /**
 | |
|    * This method returns the previous tab index in the run. If the previous
 | |
|    * index is out of this run, it will return the last index for the run.
 | |
|    *
 | |
|    * @param tabCount The number of tabs.
 | |
|    * @param base The index to start from.
 | |
|    *
 | |
|    * @return The previous tab index in the run.
 | |
|    */
 | |
|   protected int getPreviousTabIndexInRun(int tabCount, int base)
 | |
|   {
 | |
|     int index = getPreviousTabIndex(base);
 | |
|     int run = getRunForTab(tabCount, base);
 | |
|     if (index == lastTabInRun(tabCount, getPreviousTabRun(run)))
 | |
|       index = lastTabInRun(tabCount, run);
 | |
| 
 | |
|     return index;
 | |
|   }
 | |
| 
 | |
|   /**
 | |
|    * This method returns the index of the previous run.
 | |
|    *
 | |
|    * @param baseRun The run to start from.
 | |
|    *
 | |
|    * @return The index of the previous run.
 | |
|    */
 | |
|   protected int getPreviousTabRun(int baseRun)
 | |
|   {
 | |
|     if (getTabRunCount(tabPane) == 1)
 | |
|       return 1;
 | |
| 
 | |
|     int prevRun = --baseRun;
 | |
|     if (prevRun < 0)
 | |
|       prevRun = getTabRunCount(tabPane) - 1;
 | |
|     return prevRun;
 | |
|   }
 | |
| 
 | |
|   /**
 | |
|    * This method returns the index of the next run.
 | |
|    *
 | |
|    * @param baseRun The run to start from.
 | |
|    *
 | |
|    * @return The index of the next run.
 | |
|    */
 | |
|   protected int getNextTabRun(int baseRun)
 | |
|   {
 | |
|     if (getTabRunCount(tabPane) == 1)
 | |
|       return 1;
 | |
| 
 | |
|     int nextRun = ++baseRun;
 | |
|     if (nextRun == getTabRunCount(tabPane))
 | |
|       nextRun = 0;
 | |
|     return nextRun;
 | |
|   }
 | |
| 
 | |
|   /**
 | |
|    * This method rotates the insets given a direction to rotate them in.
 | |
|    * Target placement should be one of TOP, LEFT, BOTTOM, RIGHT. The  rotated
 | |
|    * insets will be stored in targetInsets. Passing in TOP as  the direction
 | |
|    * does nothing. Passing in LEFT switches top and left, right and bottom.
 | |
|    * Passing in BOTTOM switches top and bottom. Passing in RIGHT switches top
 | |
|    * for left, left for bottom, bottom for right, and right for top.
 | |
|    *
 | |
|    * @param topInsets The reference insets.
 | |
|    * @param targetInsets An Insets object to store the new insets.
 | |
|    * @param targetPlacement The rotation direction.
 | |
|    */
 | |
|   protected static void rotateInsets(Insets topInsets, Insets targetInsets,
 | |
|                                      int targetPlacement)
 | |
|   {
 | |
|     // Sun's version will happily throw an NPE if params are null,
 | |
|     // so I won't check it either.
 | |
|     switch (targetPlacement)
 | |
|     {
 | |
|     default:
 | |
|     case SwingConstants.TOP:
 | |
|       targetInsets.top = topInsets.top;
 | |
|       targetInsets.left = topInsets.left;
 | |
|       targetInsets.right = topInsets.right;
 | |
|       targetInsets.bottom = topInsets.bottom;
 | |
|       break;
 | |
|     case SwingConstants.LEFT:
 | |
|       targetInsets.left = topInsets.top;
 | |
|       targetInsets.top = topInsets.left;
 | |
|       targetInsets.right = topInsets.bottom;
 | |
|       targetInsets.bottom = topInsets.right;
 | |
|       break;
 | |
|     case SwingConstants.BOTTOM:
 | |
|       targetInsets.top = topInsets.bottom;
 | |
|       targetInsets.bottom = topInsets.top;
 | |
|       targetInsets.left = topInsets.left;
 | |
|       targetInsets.right = topInsets.right;
 | |
|       break;
 | |
|     case SwingConstants.RIGHT:
 | |
|       targetInsets.top = topInsets.left;
 | |
|       targetInsets.left = topInsets.bottom;
 | |
|       targetInsets.bottom = topInsets.right;
 | |
|       targetInsets.right = topInsets.top;
 | |
|       break;
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   ActionMap getActionMap()
 | |
|   {
 | |
|     ActionMap map = (ActionMap) UIManager.get("TabbedPane.actionMap");
 | |
| 
 | |
|     if (map == null) // first time here
 | |
|       {
 | |
|         map = createActionMap();
 | |
|         if (map != null)
 | |
|           UIManager.put("TabbedPane.actionMap", map);
 | |
|       }
 | |
|     return map;
 | |
|   }
 | |
| 
 | |
|   ActionMap createActionMap()
 | |
|   {
 | |
|     ActionMap map = new ActionMapUIResource();
 | |
| 
 | |
|     map.put("navigatePageDown", new NavigatePageDownAction());
 | |
|     map.put("navigatePageUp", new NavigatePageUpAction());
 | |
|     map.put("navigateDown",
 | |
|             new NavigateAction("navigateDown", SwingConstants.SOUTH));
 | |
| 
 | |
|     map.put("navigateUp",
 | |
|             new NavigateAction("navigateUp", SwingConstants.NORTH));
 | |
| 
 | |
|     map.put("navigateLeft",
 | |
|             new NavigateAction("navigateLeft", SwingConstants.WEST));
 | |
| 
 | |
|     map.put("navigateRight",
 | |
|             new NavigateAction("navigateRight", SwingConstants.EAST));
 | |
| 
 | |
|     map.put("requestFocusForVisibleComponent",
 | |
|             new RequestFocusForVisibleComponentAction());
 | |
|     map.put("requestFocus", new RequestFocusAction());
 | |
| 
 | |
|     return map;
 | |
|   }
 | |
| 
 | |
|   /**
 | |
|    * Sets the tab which should be highlighted when in rollover mode. And
 | |
|    * <code>index</code> of <code>-1</code> means that the rollover tab
 | |
|    * is deselected (i.e. the mouse is outside of the tabarea).
 | |
|    *
 | |
|    * @param index the index of the tab that is under the mouse, <code>-1</code>
 | |
|    *        for no tab
 | |
|    *
 | |
|    * @since 1.5
 | |
|    */
 | |
|   protected void setRolloverTab(int index)
 | |
|   {
 | |
|     rolloverTab = index;
 | |
|   }
 | |
| 
 | |
|   /**
 | |
|    * Retunrs the index of the tab over which the mouse is currently moving,
 | |
|    * or <code>-1</code> for no tab.
 | |
|    *
 | |
|    * @return the index of the tab over which the mouse is currently moving,
 | |
|    *         or <code>-1</code> for no tab
 | |
|    *
 | |
|    * @since 1.5
 | |
|    */
 | |
|   protected int getRolloverTab()
 | |
|   {
 | |
|     return rolloverTab;
 | |
|   }
 | |
| }
 |