home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Chip 1998 November
/
Chip_1998-11_cd.bin
/
tema
/
Cafe
/
jfc.bin
/
BasicTabbedPaneUI.java
< prev
next >
Wrap
Text File
|
1998-02-26
|
61KB
|
1,625 lines
/*
* @(#)BasicTabbedPaneUI.java 1.51 98/02/02
*
* Copyright (c) 1997 Sun Microsystems, Inc. All Rights Reserved.
*
* This software is the confidential and proprietary information of Sun
* Microsystems, Inc. ("Confidential Information"). You shall not
* disclose such Confidential Information and shall use it only in
* accordance with the terms of the license agreement you entered into
* with Sun.
*
* SUN MAKES NO REPRESENTATIONS OR WARRANTIES ABOUT THE SUITABILITY OF THE
* SOFTWARE, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
* IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
* PURPOSE, OR NON-INFRINGEMENT. SUN SHALL NOT BE LIABLE FOR ANY DAMAGES
* SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING OR DISTRIBUTING
* THIS SOFTWARE OR ITS DERIVATIVES.
*
*/
package com.sun.java.swing.plaf.basic;
import com.sun.java.swing.*;
import com.sun.java.swing.event.*;
import java.awt.*;
import java.awt.event.*;
import com.sun.java.swing.plaf.*;
import java.io.Serializable;
/**
* A Windows L&F implementation of TabbedPaneUI.
* <p>
* Warning: serialized objects of this class will not be compatible with
* future swing releases. The current serialization support is appropriate
* for short term storage or RMI between Swing1.0 applications. It will
* not be possible to load serialized Swing1.0 objects with future releases
* of Swing. The JDK1.2 release of Swing will be the compatibility
* baseline for the serialized form of Swing objects.
*
* @version 1.51 02/02/98
* @author Dave Moore
* @author Philip Milne
* @author Steve Wilson
* @author Tom Santos
* @author Amy Fowler
*/
public class BasicTabbedPaneUI extends TabbedPaneUI
implements LayoutManager, ChangeListener, Serializable, SwingConstants {
// Class variables
protected static int spacingHeight = 2;
protected static int spacingWidth = 4;
protected static int iconSpacingWidth = 4;
protected static int selectedTabRaisePad = 3;
protected static int selectedTabWidenPad = 4;
protected static Insets contentBorderInsets = new Insets(2,2,3,3);
protected static Insets tabsOnTopTabInsets = new Insets(3,2,0,2);
protected static Insets tabsOnLeftTabInsets = new Insets(2,3,2,0);
protected static Insets tabsOnBottomTabInsets = new Insets(0,2,3,2);
protected static Insets tabsOnRightTabInsets = new Insets(2,0,2,3);
// Instance variables
protected int overlay = 2;
protected int xNudge = 0;
protected int yNudge = 0;
protected Color tabHighlight;
protected Color tabShadow;
protected Color tabDarkShadow;
protected Color focus;
// Transient variables (recalculated as events arrive)
protected int tabRuns[] = new int[10];
protected int runCount;
protected int selectedRun;
protected Rectangle rects[] = new Rectangle[0];
protected int maxTabHeight;
protected int maxTabWidth;
protected Component visibleComponent;
// Listeners
protected MouseListener mouseGetter;
protected FocusListener focusGetter;
protected ChangeListener tabChangeListener;
// UI creation
public static ComponentUI createUI(JComponent c) {
return new BasicTabbedPaneUI();
}
// UI Installation/De-installation
public void installUI(JComponent c) {
c.setLayout(this);
installDefaults(c);
installListeners(c);
installKeyboardActions(c);
}
public void uninstallUI(JComponent c) {
uninstallKeyboardActions(c);
uninstallListeners(c);
uninstallDefaults(c);
c.setLayout(null);
}
protected void installDefaults(JComponent c) {
LookAndFeel.installColorsAndFont(c, "TabbedPane.tabBackground",
"TabbedPane.tabForeground", "TabbedPane.font");
tabHighlight = UIManager.getColor("TabbedPane.tabHighlight");
tabShadow = UIManager.getColor("TabbedPane.tabShadow");
tabDarkShadow = UIManager.getColor("TabbedPane.tabDarkShadow");
focus = UIManager.getColor("TabbedPane.focus");
}
protected void uninstallDefaults(JComponent c) {
}
protected void installListeners(JComponent c) {
if ((mouseGetter = createMouseListener(c)) != null) {
c.addMouseListener(mouseGetter);
}
if ((focusGetter = createFocusListener(c)) != null) {
c.addFocusListener(focusGetter);
}
if ((tabChangeListener = createChangeListener(c)) != null) {
((JTabbedPane)c).addChangeListener(tabChangeListener);
}
}
protected void uninstallListeners(JComponent c) {
if (mouseGetter != null) {
c.removeMouseListener(mouseGetter);
mouseGetter = null;
}
if (focusGetter != null) {
c.removeFocusListener(focusGetter);
focusGetter = null;
}
if (tabChangeListener != null) {
((JTabbedPane)c).removeChangeListener(tabChangeListener);
}
}
protected MouseListener createMouseListener(JComponent c) {
return new MouseGetter();
}
protected FocusListener createFocusListener(JComponent c) {
return new FocusGetter();
}
protected ChangeListener createChangeListener(JComponent c) {
return this;
}
protected void installKeyboardActions(JComponent c) {
final JTabbedPane pane = (JTabbedPane)c;
c.registerKeyboardAction(
new AbstractAction() {
public void actionPerformed(ActionEvent e) {
navigateSelectedTab(pane, pane.getTabPlacement(), EAST);
}
public boolean isEnabled() {
return true;
}
},
KeyStroke.getKeyStroke(KeyEvent.VK_RIGHT,0),
JComponent.WHEN_FOCUSED);
c.registerKeyboardAction(
new AbstractAction() {
public void actionPerformed(ActionEvent e) {
navigateSelectedTab(pane, pane.getTabPlacement(), WEST);
}
public boolean isEnabled() {
return true;
}
},
KeyStroke.getKeyStroke(KeyEvent.VK_LEFT,0),
JComponent.WHEN_FOCUSED);
c.registerKeyboardAction(
new AbstractAction() {
public void actionPerformed(ActionEvent e) {
navigateSelectedTab(pane, pane.getTabPlacement(), NORTH);
}
public boolean isEnabled() {
return true;
}
},
KeyStroke.getKeyStroke(KeyEvent.VK_UP,0),
JComponent.WHEN_FOCUSED);
c.registerKeyboardAction(
new AbstractAction() {
public void actionPerformed(ActionEvent e) {
navigateSelectedTab(pane, pane.getTabPlacement(), SOUTH);
}
public boolean isEnabled() {
return true;
}
},
KeyStroke.getKeyStroke(KeyEvent.VK_DOWN,0),
JComponent.WHEN_FOCUSED);
}
protected void uninstallKeyboardActions(JComponent c) {
c.resetKeyboardActions();
}
// UI Rendering
public void paint(Graphics g, JComponent c) {
JTabbedPane pane = (JTabbedPane)c;
int selectedIndex = pane.getSelectedIndex();
int tabPlacement = pane.getTabPlacement();
int tabCount = pane.getTabCount();
if (tabCount != rects.length) {
calculateLayoutInfo(pane);
}
Rectangle iconRect = new Rectangle(),
textRect = new Rectangle();
Rectangle clipRect = g.getClipBounds();
Insets insets = pane.getInsets();
//g.translate(insets.left, insets.top);
// Paint tabRuns of tabs from back to front
for (int i = runCount - 1; i >= 0; i--) {
int start = tabRuns[i];
int next = tabRuns[(i == runCount - 1)? 0 : i + 1];
int end = (next != 0? next - 1: tabCount - 1);
for (int j = start; j <= end; j++) {
if (rects[j].intersects(clipRect)) {
paintTab(g, pane, tabPlacement, rects, j, iconRect, textRect);
}
}
}
// Paint selected tab if its in the front run
// since it may overlap other tabs
if (selectedIndex >= 0 && getRunForTab(pane, tabCount, selectedIndex) == 0) {
if (rects[selectedIndex].intersects(clipRect)) {
paintTab(g, pane, tabPlacement, rects, selectedIndex, iconRect, textRect);
}
}
// Paint content border
paintContentBorder(g, pane, tabPlacement, selectedIndex);
//g.translate(-insets.left, -insets.top);
}
protected void paintTab(Graphics g, JTabbedPane pane, int tabPlacement,
Rectangle[] rects, int tabIndex,
Rectangle iconRect, Rectangle textRect) {
Rectangle tabRect = rects[tabIndex];
int selectedIndex = pane.getSelectedIndex();
boolean isSelected = selectedIndex == tabIndex;
xNudge = calculateXNudge(pane, tabPlacement, tabIndex, isSelected);
yNudge = calculateYNudge(pane, tabPlacement, tabIndex, isSelected);
paintTabBackground(g, pane, tabPlacement, tabIndex, tabRect.x, tabRect.y,
tabRect.width, tabRect.height, isSelected);
paintTabBorder(g, pane, tabPlacement, tabIndex, tabRect.x, tabRect.y,
tabRect.width, tabRect.height, isSelected);
String title = pane.getTitleAt(tabIndex);
Font font = pane.getFont();
FontMetrics metrics = g.getFontMetrics(font);
Icon icon = getIconForTab(pane, tabIndex);
layoutLabel(tabPlacement, metrics, title, icon,
tabRect, iconRect, textRect, isSelected);
paintText(g, pane, tabPlacement, font, metrics,
tabIndex, title, textRect, isSelected);
paintIcon(g, pane, tabPlacement, tabIndex, icon, iconRect, isSelected );
paintFocusIndicator(g, pane, tabPlacement, rects, tabIndex, iconRect, textRect, isSelected);
}
protected void layoutLabel(int tabPlacement, FontMetrics metrics,
String title, Icon icon,
Rectangle tabRect, Rectangle iconRect,
Rectangle textRect, boolean isSelected ) {
textRect.x = textRect.y = iconRect.x = iconRect.y = 0;
SwingUtilities.layoutCompoundLabel(metrics, title, icon,
SwingUtilities.CENTER,
SwingUtilities.CENTER,
SwingUtilities.CENTER,
SwingUtilities.RIGHT,
tabRect,
iconRect,
textRect,
iconSpacingWidth);
}
protected void paintIcon(Graphics g, JTabbedPane pane, int tabPlacement,
int tabIndex, Icon icon, Rectangle iconRect,
boolean isSelected ) {
if (icon != null) {
icon.paintIcon(pane, g, iconRect.x + xNudge, iconRect.y + yNudge);
}
}
protected void paintText(Graphics g, JTabbedPane pane, int tabPlacement,
Font font, FontMetrics metrics, int tabIndex,
String title, Rectangle textRect,
boolean isSelected) {
g.setFont(font);
if (pane.isEnabledAt(tabIndex)) {
g.setColor(pane.getForegroundAt(tabIndex));
g.drawString(title,
textRect.x + xNudge,
textRect.y + metrics.getAscent() + yNudge);
} else { // tab disabled
g.setColor(pane.getBackgroundAt(tabIndex).brighter());
g.drawString(title,
textRect.x + xNudge, textRect.y + metrics.getAscent() + yNudge);
g.setColor(pane.getBackgroundAt(tabIndex).darker());
g.drawString(title,
textRect.x + xNudge - 1, textRect.y + metrics.getAscent() + yNudge - 1);
}
}
protected int calculateXNudge(JTabbedPane pane, int tabPlacement,
int tabIndex, boolean isSelected) {
Rectangle tabRect = rects[tabIndex];
int nudge = 0;
switch(tabPlacement) {
case LEFT:
nudge = isSelected? -1 : 1;
break;
case RIGHT:
nudge = isSelected? 1 : -1;
break;
case BOTTOM:
case TOP:
default:
nudge = tabRect.width % 2;
}
return nudge;
}
protected int calculateYNudge(JTabbedPane pane, int tabPlacement,
int tabIndex, boolean isSelected) {
Rectangle tabRect = rects[tabIndex];
int nudge = 0;
switch(tabPlacement) {
case BOTTOM:
nudge = isSelected? 1 : -1;
break;
case LEFT:
case RIGHT:
nudge = tabRect.height % 2;
break;
case TOP:
default:
nudge = isSelected? -1 : 1;;
}
return nudge;
}
protected void paintFocusIndicator(Graphics g, JTabbedPane pane, int tabPlacement,
Rectangle[] rects, int tabIndex,
Rectangle iconRect, Rectangle textRect,
boolean isSelected) {
Rectangle tabRect = rects[tabIndex];
if (pane.hasFocus() && isSelected) {
int x, y, w, h;
g.setColor(focus);
switch(tabPlacement) {
case LEFT:
x = tabRect.x + 3;
y = tabRect.y + 3;
w = tabRect.width - 5;
h = tabRect.height - 6;
break;
case RIGHT:
x = tabRect.x + 2;
y = tabRect.y + 3;
w = tabRect.width - 5;
h = tabRect.height - 6;
break;
case BOTTOM:
x = tabRect.x + 3;
y = tabRect.y + 2;
w = tabRect.width - 6;
h = tabRect.height - 5;
break;
case TOP:
default:
x = tabRect.x + 3;
y = tabRect.y + 3;
w = tabRect.width - 6;
h = tabRect.height - 5;
}
BasicGraphicsUtils.drawDashedRect(g, x, y, w, h);
}
}
Rectangle getFocusedTabBounds(JTabbedPane tp) {
if(rects.length != tp.getTabCount())
calculateLayoutInfo(tp);
return rects[tp.getSelectedIndex()];
}
/**
* this function draws the border around each tab
* note that this function does now draw the background of the tab.
* that is done elsewhere
*/
protected void paintTabBorder(Graphics g, JTabbedPane pane, int tabPlacement,
int tabIndex,
int x, int y, int w, int h,
boolean isSelected ) {
g.setColor(tabHighlight);
switch (tabPlacement) {
case LEFT:
g.drawLine(x+1, y+h-2, x+1, y+h-2); // bottom-left highlight
g.drawLine(x, y+2, x, y+h-3); // left highlight
g.drawLine(x+1, y+1, x+1, y+1); // top-left highlight
g.drawLine(x+2, y, x+w-1, y); // top highlight
g.setColor(tabShadow);
g.drawLine(x+2, y+h-2, x+w-1, y+h-2); // bottom shadow
g.setColor(tabDarkShadow);
g.drawLine(x+2, y+h-1, x+w-1, y+h-1); // bottom dark shadow
break;
case RIGHT:
g.drawLine(x, y, x+w-3, y); // top highlight
g.setColor(tabShadow);
g.drawLine(x, y+h-2, x+w-3, y+h-2); // bottom shadow
g.drawLine(x+w-2, y+2, x+w-2, y+h-3); // right shadow
g.setColor(tabDarkShadow);
g.drawLine(x+w-2, y+1, x+w-2, y+1); // top-right dark shadow
g.drawLine(x+w-2, y+h-2, x+w-2, y+h-2); // bottom-right dark shadow
g.drawLine(x+w-1, y+2, x+w-1, y+h-3); // right dark shadow
g.drawLine(x, y+h-1, x+w-3, y+h-1); // bottom dark shadow
break;
case BOTTOM:
g.drawLine(x, y, x, y+h-3); // left highlight
g.drawLine(x+1, y+h-2, x+1, y+h-2); // bottom-left highlight
g.setColor(tabShadow);
g.drawLine(x+2, y+h-2, x+w-3, y+h-2); // bottom shadow
g.drawLine(x+w-2, y, x+w-2, y+h-3); // right shadow
g.setColor(tabDarkShadow);
g.drawLine(x+2, y+h-1, x+w-3, y+h-1); // bottom dark shadow
g.drawLine(x+w-2, y+h-2, x+w-2, y+h-2); // bottom-right dark shadow
g.drawLine(x+w-1, y, x+w-1, y+h-3); // right dark shadow
break;
case TOP:
default:
g.drawLine(x, y+2, x, y+h-1); // left highlight
g.drawLine(x+1, y+1, x+1, y+1); // top-left highlight
g.drawLine(x+2, y, x+w-3, y); // top highlight
g.setColor(tabShadow);
g.drawLine(x+w-2, y+2, x+w-2, y+h-1); // right shadow
g.setColor(tabDarkShadow);
g.drawLine(x+w-1, y+2, x+w-1, y+h-1); // right dark-shadow
g.drawLine(x+w-2, y+1, x+w-2, y+1); // top-right shadow
}
}
protected void paintTabBackground(Graphics g, JTabbedPane pane, int tabPlacement,
int tabIndex,
int x, int y, int w, int h,
boolean isSelected ) {
g.setColor(pane.getBackgroundAt(tabIndex));
switch(tabPlacement) {
case LEFT:
g.fillRect(x+1, y+1, w-2, h-3);
break;
case RIGHT:
g.fillRect(x, y+1, w-2, h-3);
break;
case BOTTOM:
g.fillRect(x+1, y, w-3, h-1);
break;
case TOP:
default:
g.fillRect(x+1, y+1, w-3, h-1);
}
}
protected void paintContentBorder(Graphics g, JTabbedPane pane, int tabPlacement,
int selectedIndex) {
Rectangle bounds = pane.getBounds();
Insets insets = pane.getInsets();
int height = bounds.height - (insets.top + insets.bottom);
int width = bounds.width - (insets.left + insets.right);
int x = 0;
int y = 0;
int w = width;
int h = height;
switch(tabPlacement) {
case LEFT:
x = totalTabWidth(pane, tabPlacement, runCount);
w -= x;
break;
case RIGHT:
w -= totalTabWidth(pane, tabPlacement, runCount);
break;
case BOTTOM:
h -= totalTabHeight(pane, tabPlacement, runCount);
break;
case TOP:
default:
y = totalTabHeight(pane, tabPlacement, runCount);
h -= y;
}
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);
}
protected void paintContentBorderTopEdge(Graphics g, int tabPlacement,
int selectedIndex,
int x, int y, int w, int h) {
g.setColor(tabHighlight);
if (tabPlacement != TOP || selectedIndex < 0 ||
(rects[selectedIndex].y + rects[selectedIndex].height + 1 < y)) {
g.drawLine(x, y, x+w-2, y);
} else {
Rectangle selRect = rects[selectedIndex];
g.drawLine(x, y, selRect.x - 1, y);
if (selRect.x + selRect.width < x + w - 2) {
g.drawLine(selRect.x + selRect.width, y,
x+w-2, y);
} else {
g.setColor(tabShadow);
g.drawLine(x+w-2, y, x+w-2, y);
}
}
}
protected void paintContentBorderLeftEdge(Graphics g, int tabPlacement,
int selectedIndex,
int x, int y, int w, int h) {
g.setColor(tabHighlight);
if (tabPlacement != LEFT || selectedIndex < 0 ||
(rects[selectedIndex].x + rects[selectedIndex].width + 1< x)) {
g.drawLine(x, y, x, y+h-2);
} else {
Rectangle selRect = rects[selectedIndex];
g.drawLine(x, y, x, selRect.y - 1);
if (selRect.y + selRect.height < y + h - 2) {
g.drawLine(x, selRect.y + selRect.height,
x, y+h-2);
}
}
}
protected void paintContentBorderBottomEdge(Graphics g, int tabPlacement,
int selectedIndex,
int x, int y, int w, int h) {
g.setColor(tabShadow);
if (tabPlacement != BOTTOM || selectedIndex < 0 ||
(rects[selectedIndex].y - 1 > h)) {
g.drawLine(x+1, y+h-2, x+w-2, y+h-2);
g.setColor(tabDarkShadow);
g.drawLine(x, y+h-1, x+w-1, y+h-1);
} else {
Rectangle selRect = rects[selectedIndex];
g.drawLine(x+1, y+h-2, selRect.x - 1, y+h-2);
g.setColor(tabDarkShadow);
g.drawLine(x, y+h-1, selRect.x - 1, y+h-1);
if (selRect.x + selRect.width < x + w - 2) {
g.setColor(tabShadow);
g.drawLine(selRect.x + selRect.width, y+h-2, x+w-2, y+h-2);
g.setColor(tabDarkShadow);
g.drawLine(selRect.x + selRect.width, y+h-1, x+w-1, y+h-1);
}
}
}
protected void paintContentBorderRightEdge(Graphics g, int tabPlacement,
int selectedIndex,
int x, int y, int w, int h) {
g.setColor(tabShadow);
if (tabPlacement != RIGHT || selectedIndex < 0 ||
rects[selectedIndex].x - 1 > w) {
g.drawLine(x+w-2, y+1, x+w-2, y+h-3);
g.setColor(tabDarkShadow);
g.drawLine(x+w-1, y, x+w-1, y+h-1);
} else {
Rectangle selRect = rects[selectedIndex];
g.drawLine(x+w-2, y+1, x+w-2, selRect.y - 1);
g.setColor(tabDarkShadow);
g.drawLine(x+w-1, y, x+w-1, selRect.y - 1);
if (selRect.y + selRect.height < y + h - 2) {
g.setColor(tabShadow);
g.drawLine(x+w-2, selRect.y + selRect.height,
x+w-2, y+h-2);
g.setColor(tabDarkShadow);
g.drawLine(x+w-1, selRect.y + selRect.height,
x+w-1, y+h-2);
}
}
}
// LayoutManager methods
public Dimension getPreferredSize(JComponent c) {
JTabbedPane pane = (JTabbedPane)c;
return calculateSize(pane, pane.getTabPlacement(), false);
}
/* It is difficfult to find useful minima for the Tab dimensions. If
we try to answer the question "how much room is required to draw all
of the Tabs" then the answer is a minimumm *area* and this cannot be
written as a minimum height or width. If we could assume or be passed
a maximum height then we could compute a minimum width and vice versa
but neither of these are useful as they both prevent certain useful
arranngements from being displayed even when the drawing code would be
able to render them. Instead, we return "the minimum height and width
needed to display the largest of all of the buttons above the largest
of all the components". */
public Dimension getMinimumSize(JComponent c) {
JTabbedPane pane = (JTabbedPane)c;
return calculateSize(pane, pane.getTabPlacement(), true);
}
protected Dimension calculateSize(JTabbedPane pane, int tabPlacement, boolean minimum) {
Insets insets = pane.getInsets();
Insets borderInsets = getContentBorderInsets(pane, tabPlacement);
Dimension zeroSize = new Dimension(0,0);
int height = borderInsets.top + borderInsets.bottom;
int width = borderInsets.left + borderInsets.right;
int cWidth = 0;
int cHeight = 0;
for(int i = 0; i < pane.getTabCount(); i++) {
Component component = pane.getComponentAt(i);
Dimension size = zeroSize;
if (component instanceof JComponent) {
/* There is currently some question over what
Components should do when asked for sizing
information in the case where the Component has no
mechanism to find it's font. As of 9.1.97, some
Components throw NullPointer exceptions when sent
getMinimumSize(). Normally a component can ask
it's parent for it's font but the TabbedPane
currently does not add these components to their
superview: so they are orphans unless they are the
selected item. JComponents have the right behavior
anyway, but for those that might not, set the fonts
of all children to our Font when their Font is
null.
*/
if (component.getFont() == null) {
component.setFont(pane.getFont());
}
size = minimum? component.getMinimumSize() :
component.getPreferredSize();
if (size != null) {
cHeight = Math.max(size.height, cHeight);
cWidth = Math.max(size.width, cWidth);
}
}
}
width += cWidth;
height += cHeight;
int tabExtent = 0;
switch(tabPlacement) {
case LEFT:
case RIGHT:
tabExtent = preferredTotalTabWidth(pane, tabPlacement,
getMetrics(pane), height);
width += tabExtent;
break;
case TOP:
case BOTTOM:
default:
tabExtent = preferredTotalTabHeight(pane, tabPlacement,
getMetrics(pane), width);
height += tabExtent;
break;
}
/*
System.out.println("calculateSize: cSize="+cWidth+"x"+cHeight+
" insets="+insets+" borderInsets="+borderInsets+" tabExtent="+tabExtent+
" TOTAL="+(width + insets.left + insets.right)+"x"+(height + insets.bottom + insets.top));
*/
return new Dimension(width + insets.left + insets.right,
height + insets.bottom + insets.top);
}
public Dimension getMaximumSize(JComponent c) {
return new Dimension(Integer.MAX_VALUE, Integer.MAX_VALUE);
}
public void addLayoutComponent(String name, Component comp) {}
public void removeLayoutComponent(Component comp) {}
public Dimension preferredLayoutSize(Container parent) {
return new Dimension(parent.getBounds().width,
parent.getBounds().height);
}
public Dimension minimumLayoutSize(Container parent) {
return new Dimension(0,0);
}
public void layoutContainer(Container parent) {
JTabbedPane pane = (JTabbedPane)parent;
layoutTabbedPane(pane, pane.getTabPlacement());
}
protected void layoutTabbedPane(JTabbedPane pane, int tabPlacement) {
Insets insets = pane.getInsets();
Insets borderInsets = getContentBorderInsets(pane, tabPlacement);
int selectedIndex = pane.getSelectedIndex();
Window window = null;
Component focusedComponent;
if (selectedIndex < 0) {
if (visibleComponent != null) {
// The last tab was removed, so remove teh component
setVisibleComponent(pane, null);
}
} else {
int cx, cy, cw, ch;
int totalTabWidth = 0;
int totalTabHeight = 0;
Component selectedComponent = pane.getComponentAt(selectedIndex);
boolean shouldChangeFocus = false;
if (selectedComponent != null) {
if (selectedComponent.getParent() == null) {
if(visibleComponent != null) {
if (SwingUtilities.findFocusOwner(visibleComponent) != null) {
shouldChangeFocus = true;
}
}
}
calculateLayoutInfo(pane);
Rectangle bounds = pane.getBounds();
setVisibleComponent(pane, selectedComponent);
switch(tabPlacement) {
case LEFT:
totalTabWidth = totalTabWidth(pane, tabPlacement, runCount);
cx = insets.left + totalTabWidth + borderInsets.left;
cy = insets.top + borderInsets.top;
break;
case RIGHT:
totalTabWidth = totalTabWidth(pane, tabPlacement, runCount);
cx = insets.left + borderInsets.left;
cy = insets.top + borderInsets.top;
break;
case BOTTOM:
totalTabHeight = totalTabHeight(pane, tabPlacement, runCount);
cx = insets.left + borderInsets.left;
cy = insets.top + borderInsets.top;
break;
case TOP:
default:
totalTabHeight = totalTabHeight(pane, tabPlacement, runCount);
cx = insets.left + borderInsets.left;
cy = insets.top + totalTabHeight + borderInsets.top;
}
cw = bounds.width - totalTabWidth -
insets.left - insets.right -
borderInsets.left - borderInsets.right;
ch = bounds.height - totalTabHeight -
insets.top - insets.bottom -
borderInsets.top - borderInsets.bottom;
selectedComponent.setBounds(cx, cy, cw, ch);
selectedComponent.validate();
if (shouldChangeFocus) {
if (selectedComponent.isFocusTraversable()) {
selectedComponent.requestFocus();
shouldChangeFocus = false;
} else if (selectedComponent instanceof JComponent) {
if (((JComponent)selectedComponent).requestDefaultFocus())
shouldChangeFocus = false;
}
if (shouldChangeFocus) {
/* Need to change the focus but we have no candidate.
* Let's set the focus on the tabbed pane itself
*/
pane.requestFocus();
}
}
}
}
}
// TabbedPaneUI methods
public void stateChanged(ChangeEvent e) {
JTabbedPane pane = (JTabbedPane)e.getSource();
pane.doLayout();
pane.repaint();
}
protected Component getVisibleComponent(JTabbedPane pane) {
int count = pane.getTabCount();
while (count-- > 0) {
Component component = pane.getComponentAt(count);
if (component != null && component.getParent() == pane) {
return component;
}
}
return null;
}
protected void setVisibleComponent(JTabbedPane pane, Component component) {
if (visibleComponent == component) {
return;
}
if (visibleComponent != null) {
pane.remove(visibleComponent);
}
if (component != null) {
pane.add(component);
}
visibleComponent = component;
}
protected void calculateLayoutInfo(JTabbedPane pane) {
calculateLayoutInfo(pane, pane.getTabPlacement());
}
protected void calculateLayoutInfo(JTabbedPane pane, int tabPlacement) {
Font font = pane.getFont();
int tabCount = pane.getTabCount();
int selectedIndex = pane.getSelectedIndex();
assureRectsCreated(tabCount);
arrangeTabs(pane, tabPlacement, tabCount, font);
padSelectedTab(pane, tabPlacement, selectedIndex);
}
protected void assureRectsCreated(int tabCount) {
int rectArrayLen = rects.length;
if (tabCount != rectArrayLen ) {
Rectangle[] tempRectArray = new Rectangle[tabCount];
System.arraycopy(rects, 0, tempRectArray, 0,
Math.min(rectArrayLen, tabCount));
rects = tempRectArray;
for (int rectIndex = rectArrayLen; rectIndex < tabCount; rectIndex++) {
rects[rectIndex] = new Rectangle();
}
}
}
protected void expandTabRunsArray() {
int rectLen = tabRuns.length;
int[] newArray = new int[rectLen+10];
System.arraycopy(tabRuns, 0, newArray, 0, runCount);
tabRuns = newArray;
}
protected void arrangeTabs(JTabbedPane pane, int tabPlacement, int tabCount,
Font font) {
FontMetrics metrics = Toolkit.getDefaultToolkit().getFontMetrics(font);
Dimension size = pane.getSize();
Insets insets = pane.getInsets();
Insets tabInsets = getTabAreaInsets(pane, tabPlacement);
int fontHeight = metrics.getHeight();
int selectedIndex = pane.getSelectedIndex();
int overlay;
int i, j;
int x, y;
int returnAt;
boolean verticalTabRuns = (tabPlacement == LEFT || tabPlacement == RIGHT);
switch(tabPlacement) {
case LEFT:
maxTabWidth = maxTabWidth(pane, metrics);
x = insets.left + tabInsets.left;
y = insets.top + tabInsets.top;
returnAt = size.height - (insets.bottom + tabInsets.bottom);
break;
case RIGHT:
maxTabWidth = maxTabWidth(pane, metrics);
x = size.width - insets.right - tabInsets.right - maxTabWidth;
y = insets.top + tabInsets.top;
returnAt = size.height - (insets.bottom + tabInsets.bottom);
break;
case BOTTOM:
maxTabHeight = maxTabHeight(pane, metrics);
x = insets.left + tabInsets.left;
y = size.height - insets.bottom - tabInsets.bottom - maxTabHeight;
returnAt = size.width - (insets.right + tabInsets.right);
break;
case TOP:
default:
maxTabHeight = maxTabHeight(pane, metrics);
x = insets.left + tabInsets.left;
y = insets.top + tabInsets.top;
returnAt = size.width - (insets.right + tabInsets.right);
}
overlay = getTabOverlay(pane, tabPlacement);
runCount = 0;
selectedRun = -1;
Rectangle rect;
// Run through tabs and partition them into runs
for (i = 0; i < tabCount; i++) {
rect = rects[i];
if (!verticalTabRuns) {
// Tabs on TOP or BOTTOM....
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 = tabWidth(pane, i, metrics);
maxTabWidth = Math.max(maxTabWidth, rect.width);
// Never move a TAB down a run if it is in the first column.
// Even if there isn't enough room, moving it to a fresh
// line won't help.
if (rect.x != 2 + insets.left && rect.x + rect.width > returnAt) {
if (runCount > tabRuns.length - 1) {
expandTabRunsArray();
}
tabRuns[runCount] = i;
runCount++;
rect.x = x;
}
// Initialize y position in case there's just one run
rect.y = y;
rect.height = maxTabHeight/* - 2*/;
} else {
// Tabs on LEFT or RIGHT...
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 = tabHeight(pane, i, fontHeight);
maxTabHeight = Math.max(maxTabHeight, rect.height);
// Never move a TAB over a run if it is in the first run.
// Even if there isn't enough room, moving it to a fresh
// column won't help.
if (rect.y != 2 + insets.top && rect.y + rect.height > returnAt) {
if (runCount > tabRuns.length - 1) {
expandTabRunsArray();
}
tabRuns[runCount] = i;
runCount++;
rect.y = y;
}
// Initialize x position in case there's just one column
rect.x = x;
rect.width = maxTabWidth/* - 2*/;
}
if (i == selectedIndex) {
selectedRun = runCount - 1;
}
}
if (runCount > 1) {
// Re-distribute tabs in case last run has leftover space
normalizeTabRuns(pane, tabPlacement, tabCount, verticalTabRuns? y : x, returnAt);
selectedRun = getRunForTab(pane, tabCount, selectedIndex);
// Rotate run array so that selected run is first
rotateTabRuns(pane, tabPlacement, selectedRun);
}
// Step through runs from back to front to calculate
// tab y locations and to pad runs appropriately
for (i = runCount - 1; i >= 0; i--) {
int start = tabRuns[i];
int next = tabRuns[i == (runCount - 1)? 0 : i + 1];
int end = (next != 0? next - 1 : tabCount - 1);
if (!verticalTabRuns) {
for (j = start; j <= end; j++) {
rect = rects[j];
rect.y = y;
rect.x += getRunIndent(pane, tabPlacement, i);
}
if (shouldPadRun(pane, tabPlacement, i)) {
padRun(pane, tabPlacement, start, end, returnAt);
}
if (tabPlacement == BOTTOM) {
y -= (maxTabHeight - overlay);
} else {
y += (maxTabHeight - overlay);
}
} else {
for (j = start; j <= end; j++) {
rect = rects[j];
rect.x = x;
rect.y += getRunIndent(pane, tabPlacement, i);
}
if (shouldPadRun(pane, tabPlacement, i)) {
padRun(pane, tabPlacement, start, end, returnAt);
}
if (tabPlacement == RIGHT) {
x -= (maxTabWidth - overlay);
} else {
x += (maxTabWidth - overlay);
}
}
}
}
protected int getTabOverlay(JTabbedPane pane, int tabPlacement) {
return overlay;
}
protected int getRunForTab(JTabbedPane pane, int tabCount, int tabIndex) {
for (int i = 0; i < runCount; i++) {
int first = tabRuns[i];
int last = lastIndexInRun(i, tabCount);
if (tabIndex >= first && tabIndex <= last) {
return i;
}
}
return 0;
}
/*
* Rotates the run-index array so that the selected run is run[0]
*/
protected void rotateTabRuns(JTabbedPane pane, int tabPlacement, int selectedRun) {
for (int i = 0; i < selectedRun; i++) {
int save = tabRuns[0];
for (int j = 1; j < runCount; j++) {
tabRuns[j - 1] = tabRuns[j];
}
tabRuns[runCount-1] = save;
}
}
protected int getRunIndent(JTabbedPane pane, int tabPlacement, int run) {
return 0;
}
protected void normalizeTabRuns(JTabbedPane pane, int tabPlacement, int tabCount,
int start, int max) {
boolean verticalTabRuns = (tabPlacement == LEFT || tabPlacement == RIGHT);
int run = runCount - 1;
boolean keepAdjusting = true;
double weight = 1.25;
// At this point the tab runs are packed to fit as many
// tabs as possible, which can leave the last run with a lot
// of extra space (resulting in very fat tabs on the last run).
// So we'll attempt to distribute this extra space more evenly
// across the runs in order to make the runs look more consistent.
//
// Starting with the last run, determine whether the last tab in
// the previous run would fit (generously) in this run; if so,
// move tab to current run and shift tabs accordingly. Cycle
// through remaining runs using the same algorithm.
//
while (keepAdjusting) {
int last = lastIndexInRun(run, tabCount);
int prevLast = lastIndexInRun(run-1, tabCount);
int end;
int prevLastLen;
if (!verticalTabRuns) {
end = rects[last].x + rects[last].width;
prevLastLen = (int)(maxTabWidth*weight);
} else {
end = rects[last].y + rects[last].height;
prevLastLen = (int)(maxTabHeight*weight*2);
}
// Check if the run has enough extra space to fit the last tab
// from the previous row...
if (max - end > prevLastLen) {
// Insert tab from previous row and shift rest over
tabRuns[run] = prevLast;
if (!verticalTabRuns) {
rects[prevLast].x = start;
} else {
rects[prevLast].y = start;
}
for (int i = prevLast+1; i <= last; i++) {
if (!verticalTabRuns) {
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 (run == runCount - 1) {
// no more room left in last run, so we're done!
keepAdjusting = false;
}
if (run - 1 > 0) {
// check previous run next...
run -= 1;
} else {
// check last run again...but require a higher ratio
// of extraspace-to-tabsize because we don't want to
// end up with too many tabs on the last run!
run = runCount - 1;
weight += .25;
}
}
}
protected int lastIndexInRun(int run, int tabCount) {
if (runCount == 1) {
return tabCount - 1;
}
int nextRun = (run == runCount - 1? 0 : run + 1);
if (tabRuns[nextRun] == 0) {
return tabCount - 1;
}
return tabRuns[nextRun]-1;
}
protected boolean shouldPadRun(JTabbedPane pane, int tabPlacement, int run) {
return runCount > 1;
}
protected void padRun(JTabbedPane pane, int tabPlacement,
int start, int end, int max) {
Rectangle lastRect = rects[end];
if (tabPlacement == TOP || tabPlacement == BOTTOM) {
int runWidth = (lastRect.x + lastRect.width) - rects[start].x;
int deltaWidth = max - (lastRect.x + lastRect.width);
float factor = (float)deltaWidth / (float)runWidth;
for (int j = start; j <= end; j++) {
Rectangle pastRect = rects[j];
if (j > start) {
pastRect.x = rects[j-1].x + rects[j-1].width;
}
pastRect.width += Math.round((float)pastRect.width * factor);
}
lastRect.width = max - lastRect.x;
} else {
int runHeight = (lastRect.y + lastRect.height) - rects[start].y;
int deltaHeight = max - (lastRect.y + lastRect.height);
float factor = (float)deltaHeight / (float)runHeight;
for (int j = start; j <= end; j++) {
Rectangle pastRect = rects[j];
if (j > start) {
pastRect.y = rects[j-1].y + rects[j-1].height;
}
pastRect.height += Math.round((float)pastRect.height * factor);
}
lastRect.height = max - lastRect.y;
}
}
protected void padSelectedTab(JTabbedPane pane, int tabPlacement, int selectedIndex) {
if (selectedIndex >= 0) {
Rectangle selRect = rects[selectedIndex];
switch(tabPlacement) {
case LEFT:
selRect.x -= (selectedTabRaisePad-1);
selRect.width += selectedTabRaisePad;
selRect.y -= (selectedTabWidenPad/2);
selRect.height += selectedTabWidenPad;
break;
case RIGHT:
selRect.x -= 1;
selRect.width += selectedTabRaisePad;
selRect.y -= (selectedTabWidenPad/2);
selRect.height += selectedTabWidenPad;
break;
case BOTTOM:
selRect.y -= 1;
selRect.height += selectedTabRaisePad;
selRect.x -= (selectedTabWidenPad/2);
selRect.width += selectedTabWidenPad;
break;
case TOP:
default:
selRect.y -= (selectedTabRaisePad-1);
selRect.height += selectedTabRaisePad;
selRect.x -= (selectedTabWidenPad/2);
selRect.width += selectedTabWidenPad;
}
}
}
protected int tabHeight(JTabbedPane pane, int tabIndex, int fontHeight) {
int height = fontHeight;
Icon icon = getIconForTab(pane, tabIndex);
if (icon != null) {
height = Math.max(height, icon.getIconHeight());
}
height += 2*spacingHeight+2;
return height;
}
protected int maxTabHeight(JTabbedPane pane) {
return maxTabHeight(pane, getMetrics(pane));
}
protected int maxTabHeight(JTabbedPane pane, FontMetrics metrics) {
int tabCount = pane.getTabCount();
int result = 0;
int fontHeight = metrics.getHeight();
for(int i = 0; i < tabCount; i++) {
result = Math.max(tabHeight(pane, i, fontHeight), result);
}
return result;
}
protected int tabWidth(JTabbedPane pane, int tabIndex, FontMetrics metrics) {
String title = pane.getTitleAt(tabIndex);
Icon icon = getIconForTab(pane, tabIndex);
int width = 2*spacingWidth + 3;
if (icon != null) {
width += icon.getIconWidth() + iconSpacingWidth;
}
width += metrics.stringWidth(title);
return width;
}
protected int maxTabWidth(JTabbedPane pane) {
return maxTabWidth(pane, getMetrics(pane));
}
protected int maxTabWidth(JTabbedPane pane, FontMetrics metrics) {
int tabCount = pane.getTabCount();
int result = 0;
for(int i = 0; i < tabCount; i++) {
result = Math.max(tabWidth(pane, i, metrics), result);
}
return result;
}
protected Icon getIconForTab(JTabbedPane pane, int tabIndex) {
return (!pane.isEnabledAt(tabIndex) &&
pane.getDisabledIconAt(tabIndex) != null)?
pane.getDisabledIconAt(tabIndex) : pane.getIconAt(tabIndex);
}
protected Insets getContentBorderInsets(JTabbedPane pane, int tabPlacement) {
return contentBorderInsets;
}
protected Insets getTabAreaInsets(JTabbedPane pane, int tabPlacement) {
Insets insets;
switch(tabPlacement) {
case LEFT:
insets = tabsOnLeftTabInsets;
break;
case BOTTOM:
insets = tabsOnBottomTabInsets;
break;
case RIGHT:
insets = tabsOnRightTabInsets;
break;
case TOP:
default:
insets = tabsOnTopTabInsets;
}
return insets;
}
protected FontMetrics getMetrics(JTabbedPane pane) {
Font font = pane.getFont();
return Toolkit.getDefaultToolkit().getFontMetrics(font);
}
public Rectangle getTabBounds(JTabbedPane pane, int i) {
calculateLayoutInfo(pane);
return rects[i];
}
public int getTabRunCount(JTabbedPane pane) {
return runCount;
}
protected int totalTabHeight(JTabbedPane pane, int tabPlacement, int rowCount) {
Insets tabInsets = getTabAreaInsets(pane, tabPlacement);
int overlay = getTabOverlay(pane, tabPlacement);
return rowCount * (maxTabHeight-overlay) + overlay +
tabInsets.top + tabInsets.bottom;
}
protected int totalTabWidth(JTabbedPane pane, int tabPlacement, int columnCount) {
Insets tabInsets = getTabAreaInsets(pane, tabPlacement);
int overlay = getTabOverlay(pane, tabPlacement);
return columnCount * (maxTabWidth-overlay) + overlay +
tabInsets.left + tabInsets.right;
}
protected int preferredTotalTabHeight(JTabbedPane pane, int tabPlacement,
FontMetrics metrics, int width) {
int tabCount = pane.getTabCount();
int total = 0;
if (tabCount > 0) {
int rows = 1;
int x = 0;
maxTabHeight = maxTabHeight(pane, metrics);
for (int i = 0; i < tabCount; i++) {
int tabWidth = tabWidth(pane, i, metrics);
if (x != 0 && x + tabWidth > width) {
rows++;
x = 0;
}
}
total = totalTabHeight(pane, tabPlacement, rows);
}
return total;
}
protected int preferredTotalTabWidth(JTabbedPane pane, int tabPlacement,
FontMetrics metrics, int height) {
int tabCount = pane.getTabCount();
int total = 0;
if (tabCount > 0) {
int columns = 1;
int y = 0;
int fontHeight = metrics.getHeight();
maxTabWidth = maxTabWidth(pane, metrics);
for (int i = 0; i < tabCount; i++) {
int tabHeight = tabHeight(pane, i, fontHeight);
if (y != 0 && y + tabHeight > height) {
columns++;
y = 0;
}
}
total = totalTabWidth(pane, tabPlacement, columns);
}
return total;
}
// Tab Navigation methods
protected void navigateSelectedTab(JTabbedPane pane, int tabPlacement, int direction) {
int current = pane.getSelectedIndex();
int tabCount = pane.getTabCount();
int offset;
switch(tabPlacement) {
case LEFT:
case RIGHT:
switch(direction) {
case NORTH:
selectPrevTab(pane, current);
break;
case SOUTH:
selectNextTab(pane, current);
break;
case WEST:
offset = getTabRunOffset(pane, tabPlacement, tabCount, current, false);
selectAdjacentRunTab(pane, tabPlacement, current, offset);
break;
case EAST:
offset = getTabRunOffset(pane, tabPlacement, tabCount, current, true);
selectAdjacentRunTab(pane, tabPlacement, current, offset);
break;
default:
}
break;
case BOTTOM:
case TOP:
default:
switch(direction) {
case NORTH:
offset = getTabRunOffset(pane, tabPlacement, tabCount, current, false);
selectAdjacentRunTab(pane, tabPlacement, current, offset);
break;
case SOUTH:
offset = getTabRunOffset(pane, tabPlacement, tabCount, current, true);
selectAdjacentRunTab(pane, tabPlacement, current, offset);
break;
case EAST:
selectNextTab(pane, current);
break;
case WEST:
selectPrevTab(pane, current);
break;
default:
}
}
}
public int getPrevTabIndex(JTabbedPane pane, int base) {
int tabIndex = base - 1;
if (tabIndex < 0) {
tabIndex = pane.getTabCount() - 1;
}
return tabIndex;
}
public int getNextTabIndex(JTabbedPane pane, int base) {
return (base+1)%pane.getTabCount();
}
public void selectNextTab(JTabbedPane pane, int current) {
int tabIndex = getNextTabIndex(pane, current);
while (!pane.isEnabledAt(tabIndex) && tabIndex != current) {
tabIndex = getNextTabIndex(pane, tabIndex);
}
pane.setSelectedIndex(tabIndex);
}
public void selectPrevTab(JTabbedPane pane, int current) {
int tabIndex = getPrevTabIndex(pane, current);
while (!pane.isEnabledAt(tabIndex) && tabIndex != current) {
tabIndex = getPrevTabIndex(pane, tabIndex);
}
pane.setSelectedIndex(tabIndex);
}
protected void selectAdjacentRunTab(JTabbedPane pane, int tabPlacement,
int tabIndex, int offset) {
if ( runCount < 2 ) {
return;
}
int newIndex;
Rectangle r = rects[tabIndex];
switch(tabPlacement) {
case LEFT:
case RIGHT:
newIndex = tabForCoordinate(pane, r.x + r.width/2 + offset,
r.y + r.height/2);
break;
case BOTTOM:
case TOP:
default:
newIndex = tabForCoordinate(pane, r.x + r.width/2,
r.y + r.height/2 + offset);
}
if (newIndex != -1) {
while (!pane.isEnabledAt(newIndex) && newIndex != tabIndex) {
newIndex = getNextTabIndex(pane, newIndex);
}
pane.setSelectedIndex(newIndex);
}
}
protected int getTabRunOffset(JTabbedPane pane, int tabPlacement, int tabCount,
int tabIndex, boolean forward) {
int run = getRunForTab(pane, tabCount, tabIndex);
int offset;
switch(tabPlacement) {
case LEFT:
if (run == 0) {
offset = (forward?
-(totalTabWidth(pane, tabPlacement, runCount)-maxTabWidth(pane)) :
-(maxTabWidth(pane)));
} else if (run == runCount - 1) {
offset = (forward?
maxTabWidth(pane) :
totalTabWidth(pane, tabPlacement, runCount)-maxTabWidth(pane));
} else {
offset = (forward? maxTabWidth(pane) : -(maxTabWidth(pane)));
}
break;
case RIGHT:
if (run == 0) {
offset = (forward?
maxTabWidth(pane) :
totalTabWidth(pane, tabPlacement, runCount)-maxTabWidth(pane));
} else if (run == runCount - 1) {
offset = (forward?
-(totalTabWidth(pane, tabPlacement, runCount)-maxTabWidth(pane)) :
-(maxTabWidth(pane)));
} else {
offset = (forward? maxTabWidth(pane) : -(maxTabWidth(pane)));
}
break;
case BOTTOM:
if (run == 0) {
offset = (forward?
maxTabHeight(pane) :
totalTabHeight(pane, tabPlacement, runCount)-maxTabHeight(pane));
} else if (run == runCount - 1) {
offset = (forward?
-(totalTabHeight(pane, tabPlacement, runCount)-maxTabHeight(pane)) :
-(maxTabHeight(pane)));
} else {
offset = (forward? maxTabHeight(pane) : -(maxTabHeight(pane)));
}
break;
case TOP:
default:
if (run == 0) {
offset = (forward?
-(totalTabHeight(pane, tabPlacement, runCount)-maxTabHeight(pane)) :
-(maxTabHeight(pane)));
} else if (run == runCount - 1) {
offset = (forward?
maxTabHeight(pane) :
totalTabHeight(pane, tabPlacement, runCount)-maxTabHeight(pane));
} else {
offset = (forward? maxTabHeight(pane) : -(maxTabHeight(pane)));
}
}
return offset;
}
public int tabForCoordinate(JTabbedPane pane, int x, int y) {
int tabCount = pane.getTabCount();
if (tabCount != rects.length) {
calculateLayoutInfo(pane);
}
for (int i = 0; i < tabCount; i++) {
if (rects[i].contains(x, y)) {
return i;
}
}
return -1;
}
// Controller: event listeners
class MouseGetter extends MouseAdapter implements Serializable {
public void mousePressed(MouseEvent e) {
JTabbedPane pane = (JTabbedPane)e.getSource();
int tabIndex = tabForCoordinate(pane, e.getX(), e.getY());
if (tabIndex >= 0 && pane.isEnabledAt(tabIndex)) {
if (tabIndex == pane.getSelectedIndex()) {
pane.requestFocus();
pane.repaint(rects[tabIndex]);
} else {
pane.setSelectedIndex(tabIndex);
}
}
}
}
// Focus control
class FocusGetter extends FocusAdapter implements Serializable {
public void focusGained(FocusEvent e) {
((JTabbedPane)e.getSource()).repaint(getFocusedTabBounds((JTabbedPane)e.getSource()));
}
public void focusLost(FocusEvent e) {
((JTabbedPane)e.getSource()).repaint(getFocusedTabBounds((JTabbedPane)e.getSource()));
}
}
}