summaryrefslogtreecommitdiff
path: root/libjava/classpath/javax/swing/plaf/metal/MetalTabbedPaneUI.java
diff options
context:
space:
mode:
Diffstat (limited to 'libjava/classpath/javax/swing/plaf/metal/MetalTabbedPaneUI.java')
-rw-r--r--libjava/classpath/javax/swing/plaf/metal/MetalTabbedPaneUI.java1269
1 files changed, 1269 insertions, 0 deletions
diff --git a/libjava/classpath/javax/swing/plaf/metal/MetalTabbedPaneUI.java b/libjava/classpath/javax/swing/plaf/metal/MetalTabbedPaneUI.java
new file mode 100644
index 000000000..77705ba0e
--- /dev/null
+++ b/libjava/classpath/javax/swing/plaf/metal/MetalTabbedPaneUI.java
@@ -0,0 +1,1269 @@
+/* MetalTabbedPaneUI.java
+ Copyright (C) 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.metal;
+
+import java.awt.Color;
+import java.awt.Graphics;
+import java.awt.LayoutManager;
+import java.awt.Rectangle;
+
+import javax.swing.JComponent;
+import javax.swing.JTabbedPane;
+import javax.swing.UIManager;
+import javax.swing.plaf.ComponentUI;
+import javax.swing.plaf.UIResource;
+import javax.swing.plaf.basic.BasicTabbedPaneUI;
+
+/**
+ * A UI delegate for the {@link JTabbedPane} component.
+ */
+public class MetalTabbedPaneUI extends BasicTabbedPaneUI
+{
+
+ /**
+ * A {@link LayoutManager} responsible for placing all the tabs and the
+ * visible component inside the {@link JTabbedPane}. This class is only used
+ * for {@link JTabbedPane#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
+ extends BasicTabbedPaneUI.TabbedPaneLayout
+ {
+ /**
+ * Creates a new instance of the layout manager.
+ */
+ public TabbedPaneLayout()
+ {
+ // Nothing to do here.
+ }
+
+ /**
+ * Overridden to do nothing, because tab runs are not rotated in the
+ * {@link MetalLookAndFeel}.
+ *
+ * @param tabPlacement the tab placement (one of {@link #TOP},
+ * {@link #BOTTOM}, {@link #LEFT} or {@link #RIGHT}).
+ * @param selectedRun the index of the selected run.
+ */
+ protected void rotateTabRuns(int tabPlacement, int selectedRun)
+ {
+ // do nothing, because tab runs are not rotated in the MetalLookAndFeel
+ }
+
+ /**
+ * Overridden to do nothing, because the selected tab does not have extra
+ * padding in the {@link MetalLookAndFeel}.
+ *
+ * @param tabPlacement the tab placement (one of {@link #TOP},
+ * {@link #BOTTOM}, {@link #LEFT} or {@link #RIGHT}).
+ * @param selectedIndex the index of the selected tab.
+ */
+ protected void padSelectedTab(int tabPlacement, int selectedIndex)
+ {
+ // do nothing, because the selected tab does not have extra padding in
+ // the MetalLookAndFeel
+ }
+
+ /**
+ * Overridden because tab runs are only normalized for TOP and BOTTOM
+ * tab placement in the Metal L&F.
+ */
+ protected void normalizeTabRuns(int tabPlacement, int tabCount, int start,
+ int max)
+ {
+ if (tabPlacement == TOP || tabPlacement == BOTTOM)
+ super.normalizeTabRuns(tabPlacement, tabCount, start, max);
+ }
+ }
+
+ /**
+ * The minimum tab width.
+ */
+ protected int minTabWidth;
+
+ /**
+ * The color for the selected tab.
+ */
+ protected Color selectColor;
+
+ /**
+ * The color for a highlighted selected tab.
+ */
+ protected Color selectHighlight;
+
+ /**
+ * The background color used for the tab area.
+ */
+ protected Color tabAreaBackground;
+
+ /** The graphics to draw the highlight below the tab. */
+ private Graphics hg;
+
+ /**
+ * Indicates if the tabs are having their background filled.
+ */
+ private boolean tabsOpaque;
+
+ /**
+ * Constructs a new instance of MetalTabbedPaneUI.
+ */
+ public MetalTabbedPaneUI()
+ {
+ super();
+ }
+
+ /**
+ * Returns an instance of MetalTabbedPaneUI.
+ *
+ * @param component the component for which we return an UI instance
+ *
+ * @return an instance of MetalTabbedPaneUI
+ */
+ public static ComponentUI createUI(JComponent component)
+ {
+ return new MetalTabbedPaneUI();
+ }
+
+ /**
+ * Creates and returns an instance of {@link TabbedPaneLayout}.
+ *
+ * @return A layout manager used by this UI delegate.
+ */
+ protected LayoutManager createLayoutManager()
+ {
+ return (tabPane.getTabLayoutPolicy() == JTabbedPane.WRAP_TAB_LAYOUT)
+ ? new MetalTabbedPaneUI.TabbedPaneLayout()
+ : super.createLayoutManager();
+ }
+
+ /**
+ * Paints the border for a single tab.
+ *
+ * @param g the graphics device.
+ * @param tabPlacement the tab placement ({@link #TOP}, {@link #LEFT},
+ * {@link #BOTTOM} or {@link #RIGHT}).
+ * @param tabIndex the index of the tab to draw the border for.
+ * @param x the x-coordinate for the tab's bounding rectangle.
+ * @param y the y-coordinate for the tab's bounding rectangle.
+ * @param w the width for the tab's bounding rectangle.
+ * @param h the height for the tab's bounding rectangle.
+ * @param isSelected indicates whether or not the tab is selected.
+ */
+ protected void paintTabBorder(Graphics g, int tabPlacement, int tabIndex,
+ int x, int y, int w, int h, boolean isSelected)
+ {
+ int bottom = y + h - 1;
+ int right = x + w - 1;
+
+ switch (tabPlacement)
+ {
+ case LEFT:
+ paintLeftTabBorder(tabIndex, g, x, y, w, h, bottom, right, isSelected);
+ break;
+ case BOTTOM:
+ paintBottomTabBorder(tabIndex, g, x, y, w, h, bottom, right, isSelected);
+ break;
+ case RIGHT:
+ paintRightTabBorder(tabIndex, g, x, y, w, h, bottom, right, isSelected);
+ break;
+ case TOP:
+ default:
+ paintTopTabBorder(tabIndex, g, x, y, w, h, bottom, right, isSelected);
+ }
+ }
+
+ /**
+ * Paints the border for a tab assuming that the tab position is at the top
+ * ({@link #TOP}).
+ *
+ * @param tabIndex the tab index.
+ * @param g the graphics device.
+ * @param x the x-coordinate for the tab's bounding rectangle.
+ * @param y the y-coordinate for the tab's bounding rectangle.
+ * @param w the width for the tab's bounding rectangle.
+ * @param h the height for the tab's bounding rectangle.
+ * @param btm the y coordinate of the bottom border
+ * @param rght the x coordinate of the right border
+ * @param isSelected indicates whether the tab is selected.
+ */
+ protected void paintTopTabBorder(int tabIndex, Graphics g, int x, int y,
+ int w, int h, int btm, int rght, boolean isSelected)
+ {
+ int tabCount = tabPane.getTabCount();
+ int currentRun = getRunForTab(tabCount, tabIndex);
+ int right = w - 1;
+ int bottom = h - 1;
+
+ // Paint gap.
+ if (shouldFillGap(currentRun, tabIndex, x, y))
+ {
+ g.translate(x, y);
+ g.setColor(getColorForGap(currentRun, x, y + 1));
+ g.fillRect(1, 0, 5, 3);
+ g.fillRect(1, 3, 2, 2);
+ g.translate(-x, -y);
+ }
+
+ g.translate(x, y);
+
+ boolean isOcean = MetalLookAndFeel.getCurrentTheme() instanceof OceanTheme;
+ Color oceanSelectedBorder =
+ UIManager.getColor("TabbedPane.borderHightlightColor");
+ if (isOcean && isSelected)
+ g.setColor(oceanSelectedBorder);
+ else
+ g.setColor(darkShadow);
+
+ // Slant
+ g.drawLine(1, 5, 6, 0);
+ // Top.
+ g.drawLine(6, 0, right, 0);
+ // Right.
+ int lastIndex = lastTabInRun(tabCount, currentRun);
+ if (tabIndex == lastIndex)
+ g.drawLine(right, 1, right, bottom);
+ // Left.
+ int selectedIndex = tabPane.getSelectedIndex();
+ if (isOcean && tabIndex - 1 == selectedIndex
+ && currentRun == getRunForTab(tabCount, selectedIndex))
+ {
+ g.setColor(oceanSelectedBorder);
+ }
+ if (tabIndex != tabRuns[runCount - 1])
+ {
+ if (isOcean && isSelected)
+ {
+ g.drawLine(0, 6, 0, bottom);
+ g.setColor(darkShadow);
+ g.drawLine(0, 0, 0, 5);
+ }
+ else
+ {
+ g.drawLine(0, 0, 0, bottom);
+ }
+ }
+ else
+ {
+ g.drawLine(0, 6, 0, bottom);
+ }
+
+ // Paint the highlight.
+ g.setColor(isSelected ? selectHighlight : highlight);
+ // Slant.
+ g.drawLine(1, 6, 6, 1);
+ // Top.
+ g.drawLine(6, 1, right, 1);
+ // Left.
+ g.drawLine(1, 6, 1, bottom);
+ int firstIndex = tabRuns[currentRun];
+ if (tabIndex == firstIndex && tabIndex != tabRuns[runCount - 1])
+ {
+ if (tabPane.getSelectedIndex() == tabRuns[currentRun + 1])
+ g.setColor(selectHighlight);
+ else
+ g.setColor(highlight);
+ g.drawLine(1, 0, 1, 4);
+ }
+
+ g.translate(-x, -y);
+ }
+
+ /**
+ * Paints the border for a tab assuming that the tab position is at the left
+ * ({@link #LEFT}).
+ *
+ * @param tabIndex the tab index.
+ * @param g the graphics device.
+ * @param x the x-coordinate for the tab's bounding rectangle.
+ * @param y the y-coordinate for the tab's bounding rectangle.
+ * @param w the width for the tab's bounding rectangle.
+ * @param h the height for the tab's bounding rectangle.
+ * @param btm ???
+ * @param rght ???
+ * @param isSelected indicates whether the tab is selected.
+ */
+ protected void paintLeftTabBorder(int tabIndex, Graphics g, int x, int y,
+ int w, int h, int btm, int rght, boolean isSelected)
+ {
+ g.translate(x, y);
+ int bottom = h - 1;
+ int right = w - 1;
+
+ int tabCount = tabPane.getTabCount();
+ int currentRun = getRunForTab(tabCount, tabIndex);
+ int firstIndex = tabRuns[currentRun];
+
+ // Paint the part of the above tab.
+ if (tabIndex != firstIndex && tabIndex > 0 && tabsOpaque)
+ {
+ Color c;
+ if (tabPane.getSelectedIndex() == tabIndex - 1)
+ c = selectColor;
+ else
+ c = getUnselectedBackground(tabIndex - 1);
+ g.setColor(c);
+ g.fillRect(2, 0, 4, 3);
+ g.drawLine(2, 3, 2, 3);
+ }
+
+ // Paint the highlight.
+ boolean isOcean = MetalLookAndFeel.getCurrentTheme() instanceof OceanTheme;
+ if (isOcean)
+ {
+ g.setColor(isSelected ? selectHighlight : MetalLookAndFeel.getWhite());
+ }
+ else
+ {
+ g.setColor(isSelected ? selectHighlight : highlight);
+ }
+ // Slant.
+ g.drawLine(1, 6, 6, 1);
+ // Left.
+ g.drawLine(1, 6, 1, bottom);
+ // Top.
+ g.drawLine(6, 1, right, 1);
+ if (tabIndex != firstIndex)
+ {
+ if (isOcean)
+ {
+ g.setColor(MetalLookAndFeel.getWhite());
+ }
+ g.drawLine(1, 0, 1, 4);
+ }
+
+ // Paint border.
+ Color oceanSelectedBorder =
+ UIManager.getColor("TabbedPane.borderHightlightColor");
+ if (isOcean && isSelected)
+ {
+ g.setColor(oceanSelectedBorder);
+ }
+ else
+ {
+ g.setColor(darkShadow);
+ }
+
+ // Slant.
+ g.drawLine(1, 5, 6, 0);
+ // Top.
+ g.drawLine(6, 0, right, 0);
+ // Bottom.
+ int lastIndex = lastTabInRun(tabCount, currentRun);
+ if (tabIndex == lastIndex)
+ {
+ g.drawLine(0, bottom, right, bottom);
+ }
+ // Left.
+ if (isOcean)
+ {
+ if (tabPane.getSelectedIndex() == tabIndex - 1)
+ {
+ g.drawLine(0, 6, 0, bottom);
+ if (tabIndex != firstIndex)
+ {
+ g.setColor(oceanSelectedBorder);
+ g.drawLine(0, 0, 0, 5);
+ }
+ }
+ else if (isSelected)
+ {
+ g.drawLine(0, 5, 0, bottom);
+ if (tabIndex != firstIndex)
+ {
+ g.setColor(darkShadow);
+ g.drawLine(0, 0, 0, 5);
+ }
+ }
+ else if (tabIndex != firstIndex)
+ {
+ g.drawLine(0, 0, 0, bottom);
+ }
+ else
+ {
+ g.drawLine(0, 6, 0, bottom);
+ }
+ }
+ else
+ {
+ if (tabIndex != firstIndex)
+ {
+ g.drawLine(0, 0, 0, bottom);
+ }
+ else
+ {
+ g.drawLine(0, 6, 0, bottom);
+ }
+ }
+
+ g.translate(-x, -y);
+ }
+
+ /**
+ * Paints the border for a tab assuming that the tab position is at the right
+ * ({@link #RIGHT}).
+ *
+ * @param tabIndex the tab index.
+ * @param g the graphics device.
+ * @param x the x-coordinate for the tab's bounding rectangle.
+ * @param y the y-coordinate for the tab's bounding rectangle.
+ * @param w the width for the tab's bounding rectangle.
+ * @param h the height for the tab's bounding rectangle.
+ * @param btm ???
+ * @param rght ???
+ * @param isSelected indicates whether the tab is selected.
+ */
+ protected void paintRightTabBorder(int tabIndex, Graphics g, int x, int y,
+ int w, int h, int btm, int rght, boolean isSelected)
+ {
+ g.translate(x, y);
+ int bottom = h - 1;
+ int right = w - 1;
+
+ int tabCount = tabPane.getTabCount();
+ int currentRun = getRunForTab(tabCount, tabIndex);
+ int firstIndex = tabRuns[currentRun];
+
+ // Paint part of the above tab.
+ if (tabIndex != firstIndex && tabIndex > 0 && tabsOpaque)
+ {
+ Color c;
+ if (tabPane.getSelectedIndex() == tabIndex - 1)
+ c = selectColor;
+ else
+ c = getUnselectedBackground(tabIndex - 1);
+ g.setColor(c);
+ g.fillRect(right - 5, 0, 5, 3);
+ g.fillRect(right - 2, 3, 2, 2);
+ }
+
+ // Paint highlight.
+ g.setColor(isSelected ? selectHighlight : highlight);
+
+ // Slant.
+ g.drawLine(right - 6, 1, right - 1, 6);
+ // Top.
+ g.drawLine(0, 1, right - 6, 1);
+ // Left.
+ if (! isSelected)
+ {
+ g.drawLine(0, 1, 0, bottom);
+ }
+
+ // Paint border.
+ boolean isOcean = MetalLookAndFeel.getCurrentTheme() instanceof OceanTheme;
+ Color oceanSelectedBorder =
+ UIManager.getColor("TabbedPane.borderHightlightColor");
+ if (isOcean && isSelected)
+ {
+ g.setColor(oceanSelectedBorder);
+ }
+ else
+ {
+ g.setColor(darkShadow);
+ }
+
+ // Bottom.
+ int lastIndex = lastTabInRun(tabCount, currentRun);
+ if (tabIndex == lastIndex)
+ {
+ g.drawLine(0, bottom, right, bottom);
+ }
+ // Slant.
+ if (isOcean && tabPane.getSelectedIndex() == tabIndex - 1)
+ {
+ g.setColor(oceanSelectedBorder);
+ }
+ g.drawLine(right - 6, 0, right, 6);
+ // Top.
+ g.drawLine(0, 0, right - 6, 0);
+ // Right.
+ if (isOcean && isSelected)
+ {
+ g.drawLine(right, 6, right, bottom);
+ if (tabIndex != firstIndex)
+ {
+ g.setColor(darkShadow);
+ g.drawLine(right, 0, right, 5);
+ }
+ }
+ else if (isOcean && tabPane.getSelectedIndex() == tabIndex - 1)
+ {
+ if (tabIndex != firstIndex)
+ {
+ g.setColor(oceanSelectedBorder);
+ g.drawLine(right, 0, right, 6);
+ }
+ g.setColor(darkShadow);
+ g.drawLine(right, 7, right, bottom);
+ }
+ else if (tabIndex != firstIndex)
+ {
+ g.drawLine(right, 0, right, bottom);
+ }
+ else
+ {
+ g.drawLine(right, 6, right, bottom);
+ }
+ g.translate(-x, -y);
+ }
+
+ /**
+ * Paints the border for a tab assuming that the tab position is at the bottom
+ * ({@link #BOTTOM}).
+ *
+ * @param tabIndex the tab index.
+ * @param g the graphics device.
+ * @param x the x-coordinate for the tab's bounding rectangle.
+ * @param y the y-coordinate for the tab's bounding rectangle.
+ * @param w the width for the tab's bounding rectangle.
+ * @param h the height for the tab's bounding rectangle.
+ * @param btm ???
+ * @param rght ???
+ * @param isSelected indicates whether the tab is selected.
+ */
+ protected void paintBottomTabBorder(int tabIndex, Graphics g, int x, int y,
+ int w, int h, int btm, int rght, boolean isSelected)
+ {
+ int bottom = h - 1;
+ int right = w - 1;
+
+ int tabCount = tabPane.getTabCount();
+ int currentRun = getRunForTab(tabCount, tabIndex);
+ // Paint gap if necessary.
+ if (shouldFillGap(currentRun, tabIndex, x, y))
+ {
+ g.translate(x, y);
+ g.setColor(getColorForGap(currentRun, x, y));
+ g.fillRect(1, bottom - 4, 3, 5);
+ g.fillRect(4, bottom - 1, 2, 2);
+ g.translate(-x, -y);
+ }
+
+ g.translate(x, y);
+
+ // Paint border.
+ boolean isOcean = MetalLookAndFeel.getCurrentTheme() instanceof OceanTheme;
+ Color oceanSelectedBorder =
+ UIManager.getColor("TabbedPane.borderHightlightColor");
+ if (isOcean && isSelected)
+ {
+ g.setColor(oceanSelectedBorder);
+ }
+ else
+ {
+ g.setColor(darkShadow);
+ }
+ // Slant.
+ g.drawLine(1, bottom - 5, 6, bottom);
+ // Bottom.
+ g.drawLine(6, bottom, right, bottom);
+ // Right.
+ int lastIndex = lastTabInRun(tabCount, currentRun);
+ if (tabIndex == lastIndex)
+ {
+ g.drawLine(right, 0, right, bottom);
+ }
+ // Left.
+ if (isOcean && isSelected)
+ {
+ g.drawLine(0, 0, 0, bottom - 5);
+
+ // Paint a connecting line to the tab below for all
+ // but the first tab in the last run.
+ if (tabIndex != tabRuns[runCount-1])
+ {
+ g.setColor(darkShadow);
+ g.drawLine(0, bottom - 5, 0, bottom);
+ }
+ }
+ else
+ {
+ if (isOcean && tabIndex == tabPane.getSelectedIndex() + 1)
+ {
+ g.setColor(oceanSelectedBorder);
+ }
+ if (tabIndex != tabRuns[runCount - 1])
+ {
+ g.drawLine(0, 0, 0, bottom);
+ }
+ else
+ {
+ g.drawLine(0, 0, 0, bottom - 6);
+ }
+ }
+
+ // Paint highlight.
+ g.setColor(isSelected ? selectHighlight : highlight);
+ // Slant.
+ g.drawLine(1, bottom - 6, 6, bottom - 1);
+ // Left.
+ g.drawLine(1, 0, 1, bottom - 6);
+
+ int firstIndex = tabRuns[currentRun];
+ if (tabIndex == firstIndex && tabIndex != tabRuns[runCount - 1])
+ {
+ if (tabPane.getSelectedIndex() == tabRuns[currentRun + 1])
+ {
+ g.setColor(selectHighlight);
+ }
+ else
+ {
+ g.setColor(highlight);
+ }
+ g.drawLine(1, bottom - 4, 1, bottom);
+ }
+
+ g.translate(-x, -y);
+ }
+
+ /**
+ * Paints the background for a tab.
+ *
+ * @param g the graphics device.
+ * @param tabPlacement the tab placement ({@link #TOP}, {@link #LEFT},
+ * {@link #BOTTOM} or {@link #RIGHT}).
+ * @param tabIndex the index of the tab to draw the border for.
+ * @param x the x-coordinate for the tab's bounding rectangle.
+ * @param y the y-coordinate for the tab's bounding rectangle.
+ * @param w the width for the tab's bounding rectangle.
+ * @param h the height for the tab's bounding rectangle.
+ * @param isSelected indicates whether or not the tab is selected.
+ */
+ protected void paintTabBackground(Graphics g, int tabPlacement,
+ int tabIndex, int x, int y, int w, int h, boolean isSelected)
+ {
+ if (isSelected)
+ g.setColor(selectColor);
+ else
+ g.setColor(getUnselectedBackground(tabIndex));
+
+ switch (tabPlacement)
+ {
+ case LEFT:
+ g.fillRect(x + 5, y + 1, w - 5, h - 1);
+ g.fillRect(x + 2, y + 4, 3, h - 4);
+ break;
+ case BOTTOM:
+ g.fillRect(x + 2, y, w - 2, h - 3);
+ g.fillRect(x + 5, y + h - 4, w - 5, 3);
+ break;
+ case RIGHT:
+ g.fillRect(x, y + 1, w - 4, h - 1);
+ g.fillRect(x + w - 4, y + 5, 3, h - 5);
+ break;
+ case TOP:
+ default:
+ g.fillRect(x + 4, y + 2, w - 4, h - 2);
+ g.fillRect(x + 2, y + 5, 2, h - 5);
+ }
+ }
+
+ /**
+ * 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];
+
+ g.setColor(focus);
+ g.translate(rect.x, rect.y);
+
+ switch (tabPlacement)
+ {
+ case LEFT:
+ // Top line
+ g.drawLine(7, 2, rect.width-2, 2);
+
+ // Right line
+ g.drawLine(rect.width-1, 2, rect.width-1, rect.height-3);
+
+ // Bottom line
+ g.drawLine(rect.width-2, rect.height-2, 3, rect.height-2);
+
+ // Left line
+ g.drawLine(2, rect.height-3, 2, 7);
+
+ // Slant
+ g.drawLine(2, 6, 6, 2);
+ break;
+ case RIGHT:
+ // Top line
+ g.drawLine(1, 2, rect.width-8, 2);
+
+ // Slant
+ g.drawLine(rect.width-7, 2, rect.width-3, 6);
+
+ // Right line
+ g.drawLine(rect.width-3, 7, rect.width-3, rect.height-3);
+
+ // Bottom line
+ g.drawLine(rect.width-3, rect.height-2, 2, rect.height-2);
+
+ // Left line
+ g.drawLine(1, rect.height-2, 1, 2);
+ break;
+ case BOTTOM:
+ // Top line
+ g.drawLine(2, 1, rect.width-2, 1);
+
+ // Right line
+ g.drawLine(rect.width-1, 2, rect.width-1, rect.height-3);
+
+ // Bottom line
+ g.drawLine(7, rect.height-3, rect.width-2, rect.height-3);
+
+ // Slant
+ g.drawLine(6, rect.height-3, 2, rect.height-7);
+
+ // Left line
+ g.drawLine(2, rect.height-8, 2, 2);
+
+ break;
+ case TOP:
+ default:
+ // Top line
+ g.drawLine(6, 2, rect.width-2, 2);
+
+ // Right line
+ g.drawLine(rect.width-1, 2, rect.width-1, rect.height-3);
+
+ // Bottom line
+ g.drawLine(3, rect.height-3, rect.width-2, rect.height-3);
+
+ // Left line
+ g.drawLine(2, rect.height-3, 2, 7);
+
+ // Slant
+ g.drawLine(2, 6, 6, 2);
+
+ }
+
+ g.translate(-rect.x, -rect.y);
+ }
+ }
+
+ /**
+ * Returns <code>true</code> if the tabs in the specified run should be
+ * padded to make the run fill the width/height of the {@link JTabbedPane}.
+ *
+ * @param tabPlacement the tab placement for the {@link JTabbedPane} (one of
+ * {@link #TOP}, {@link #BOTTOM}, {@link #LEFT} and {@link #RIGHT}).
+ * @param run the run index.
+ *
+ * @return A boolean.
+ */
+ protected boolean shouldPadTabRun(int tabPlacement, int run)
+ {
+ // as far as I can tell, all runs should be padded except the last run
+ // (which is drawn at the very top for tabPlacement == TOP)
+ return run < this.runCount - 1;
+ }
+
+ /**
+ * Installs the defaults for this UI. This method calls super.installDefaults
+ * and then loads the Metal specific defaults for TabbedPane.
+ */
+ protected void installDefaults()
+ {
+ super.installDefaults();
+ selectColor = UIManager.getColor("TabbedPane.selected");
+ selectHighlight = UIManager.getColor("TabbedPane.selectHighlight");
+ tabAreaBackground = UIManager.getColor("TabbedPane.tabAreaBackground");
+ tabsOpaque = UIManager.getBoolean("TabbedPane.tabsOpaque");
+ minTabWidth = 0;
+ }
+
+ /**
+ * Returns the color for the gap.
+ *
+ * @param currentRun - The current run to return the color for
+ * @param x - The x position of the current run
+ * @param y - The y position of the current run
+ *
+ * @return the color for the gap in the current run.
+ */
+ protected Color getColorForGap(int currentRun, int x, int y)
+ {
+ int index = tabForCoordinate(tabPane, x, y);
+ int selected = tabPane.getSelectedIndex();
+ if (selected == index)
+ return selectColor;
+ return tabAreaBackground;
+ }
+
+ /**
+ * Returns true if the gap should be filled in.
+ *
+ * @param currentRun - The current run
+ * @param tabIndex - The current tab
+ * @param x - The x position of the tab
+ * @param y - The y position of the tab
+ *
+ * @return true if the gap at the current run should be filled
+ */
+ protected boolean shouldFillGap(int currentRun, int tabIndex, int x, int y)
+ {
+ // As far as I can tell, the gap is never filled in.
+ return false;
+ }
+
+ /**
+ * Paints the highlight below the tab, if there is one.
+ */
+ protected void paintHighlightBelowTab()
+ {
+ int selected = tabPane.getSelectedIndex();
+ int tabPlacement = tabPane.getTabPlacement();
+ Rectangle bounds = getTabBounds(tabPane, selected);
+
+ hg.setColor(selectColor);
+ int x = bounds.x;
+ int y = bounds.y;
+ int w = bounds.width;
+ int h = bounds.height;
+
+ if (tabPlacement == TOP)
+ hg.fillRect(x, y + h - 2, w, 30);
+ else if (tabPlacement == LEFT)
+ hg.fillRect(x + w - 1, y, 20, h);
+ else if (tabPlacement == BOTTOM)
+ hg.fillRect(x, y - h + 2, w, 30);
+ else if (tabPlacement == RIGHT)
+ hg.fillRect(x - 18, y, 20, h);
+ else
+ throw new AssertionError("Unrecognised 'tabPlacement' argument.");
+ hg = null;
+ }
+
+ /**
+ * Returns true if we should rotate the tab runs.
+ *
+ * @param tabPlacement - The current tab placement.
+ * @param selectedRun - The selected run.
+ *
+ * @return true if the tab runs should be rotated.
+ */
+ protected boolean shouldRotateTabRuns(int tabPlacement,
+ int selectedRun)
+ {
+ // false because tab runs are not rotated in the MetalLookAndFeel
+ return false;
+ }
+
+ protected int calculateMaxTabHeight(int tabPlacement)
+ {
+ // FIXME: Why is this overridden?
+ return super.calculateMaxTabHeight(tabPlacement);
+ }
+
+ /**
+ * Returns the amount of overlay among the tabs. In
+ * the Metal L&F the overlay for LEFT and RIGHT placement
+ * is half of the maxTabHeight. For TOP and BOTTOM placement
+ * the tabs do not overlay.
+ *
+ * @param tabPlacement the placement
+ *
+ * @return the amount of overlay among the tabs
+ */
+ protected int getTabRunOverlay(int tabPlacement)
+ {
+ int overlay = 0;
+ if (tabPlacement == LEFT || tabPlacement == RIGHT)
+ {
+ int maxHeight = calculateMaxTabHeight(tabPlacement);
+ overlay = maxTabHeight / 2;
+ }
+ return overlay;
+ }
+
+ /**
+ * Paints the upper edge of the content border.
+ *
+ * @param g the graphics to use for painting
+ * @param tabPlacement the tab placement
+ * @param selectedIndex the index of the selected tab
+ * @param x the upper left coordinate of the content area
+ * @param y the upper left coordinate of 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 oceanSelectedBorder =
+ UIManager.getColor("TabbedPane.borderHightlightColor");
+ boolean isOcean = MetalLookAndFeel.getCurrentTheme() instanceof OceanTheme;
+ if (isOcean)
+ {
+ g.setColor(oceanSelectedBorder);
+ }
+ else
+ {
+ g.setColor(selectHighlight);
+ }
+
+ Rectangle rect = selectedIndex < 0 ? null :
+ getTabBounds(selectedIndex, calcRect);
+
+ // If tabs are not placed on TOP, or if the selected tab is not in the
+ // run directly above the content or the selected tab is not visible,
+ // then we draw an unbroken line.
+ if (tabPlacement != TOP || selectedIndex < 0
+ || rect.y + rect.height + 1 < y || rect.x < x || rect.x > x + w)
+ {
+ g.drawLine(x, y, x + w - 2, y);
+ if (isOcean && tabPlacement == TOP)
+ {
+ g.setColor(MetalLookAndFeel.getWhite());
+ g.drawLine(x, y + 1, x + w - 2, y + 1);
+ }
+ }
+ else
+ {
+ boolean isLast = isLastTabInRun(selectedIndex);
+ if (isLast)
+ {
+ g.drawLine(x, y, rect.x + 1, y);
+ }
+ else
+ {
+ g.drawLine(x, y, rect.x, y);
+ }
+
+ int right = x + w - 1;
+ if (rect.x + rect.width < right - 1)
+ {
+ if (isLast)
+ {
+ g.drawLine(rect.x + rect.width - 1, y, right - 1, y);
+ }
+ else
+ {
+ g.drawLine(rect.x + rect.width, y, right - 1, y);
+ }
+ }
+ else
+ {
+ g.setColor(shadow);
+ g.drawLine(x + w - 2, y, x + w - 2, y);
+ }
+
+ // When in OceanTheme, draw another white line.
+ if (isOcean)
+ {
+ g.setColor(MetalLookAndFeel.getWhite());
+ if (isLast)
+ {
+ g.drawLine(x, y + 1, rect.x + 1, y + 1);
+ }
+ else
+ {
+ g.drawLine(x, y + 1, rect.x, y + 1);
+ }
+
+ if (rect.x + rect.width < right - 1)
+ {
+ if (isLast)
+ {
+ g.drawLine(rect.x + rect.width - 1, y + 1, right - 1,
+ y + 1);
+ }
+ else
+ {
+ g.drawLine(rect.x + rect.width, y + 1, right - 1, y + 1);
+ }
+ }
+ else
+ {
+ g.setColor(shadow);
+ g.drawLine(x + w - 2, y + 1, x + w - 2, y + 1);
+ }
+ }
+ }
+ }
+
+ /**
+ * Paints the lower edge of the content border.
+ *
+ * @param g the graphics to use for painting
+ * @param tabPlacement the tab placement
+ * @param selectedIndex the index of the selected tab
+ * @param x the upper left coordinate of the content area
+ * @param y the upper left coordinate of 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)
+ {
+ g.setColor(darkShadow);
+
+ // If tabs are not placed on BOTTOM, or if the selected tab is not in the
+ // run directly below the content or the selected tab is not visible,
+ // then we draw an unbroken line.
+ Rectangle rect = selectedIndex < 0 ? null :
+ getTabBounds(selectedIndex, calcRect);
+ boolean isOcean = MetalLookAndFeel.getCurrentTheme() instanceof OceanTheme;
+ Color oceanSelectedBorder =
+ UIManager.getColor("TabbedPane.borderHightlightColor");
+ if (tabPlacement != BOTTOM || selectedIndex < 0 || rect.y - 1 > h
+ || rect.x < x || rect.x > x + w)
+ {
+ if (isOcean && tabPlacement == BOTTOM)
+ {
+ g.setColor(oceanSelectedBorder);
+ }
+ g.drawLine(x, y + h - 1, x + w - 1, y + h - 1);
+ }
+ else
+ {
+ boolean isLast = isLastTabInRun(selectedIndex);
+ if (isOcean)
+ {
+ g.setColor(oceanSelectedBorder);
+ }
+
+ int bottom = y + h - 1;
+ int right = x + w - 1;
+ if (isLast)
+ {
+ g.drawLine(x, bottom, rect.x, bottom);
+ }
+ else
+ {
+ g.drawLine(x, bottom, rect.x - 1, bottom);
+ }
+
+ if (rect.x + rect.width < x + w - 2)
+ {
+ if (isLast)
+ {
+ g.drawLine(rect.x + rect.width - 1, bottom, right, bottom);
+ }
+ else
+ {
+ g.drawLine(rect.x + rect.width, bottom, right, bottom);
+ }
+ }
+ }
+ }
+
+ /**
+ * Paints the left edge of the content border.
+ *
+ * @param g the graphics to use for painting
+ * @param tabPlacement the tab placement
+ * @param selectedIndex the index of the selected tab
+ * @param x the upper left coordinate of the content area
+ * @param y the upper left coordinate of 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)
+ {
+ boolean isOcean = MetalLookAndFeel.getCurrentTheme() instanceof OceanTheme;
+ Color oceanSelectedBorder =
+ UIManager.getColor("TabbedPane.borderHightlightColor");
+ Rectangle rect = selectedIndex < 0 ? null :
+ getTabBounds(selectedIndex, calcRect);
+
+ if (isOcean)
+ {
+ g.setColor(oceanSelectedBorder);
+ }
+ else
+ {
+ g.setColor(selectHighlight);
+ }
+
+ // If tabs are not placed on LEFT, or if the selected tab is not in the
+ // run directly left to the content or the selected tab is not visible,
+ // then we draw an unbroken line.
+ if (tabPlacement != LEFT || selectedIndex < 0
+ || rect.x + rect.width + 1 < x || rect.y < y || rect.y > y + h)
+ {
+ g.drawLine(x, y + 1, x, y + h - 2);
+ if (isOcean && tabPlacement == LEFT)
+ {
+ g.setColor(MetalLookAndFeel.getWhite());
+ g.drawLine(x, y + 1, x, y + h - 2);
+ }
+ }
+ else
+ {
+ g.drawLine(x, y, x, rect.y + 1);
+ if (rect.y + rect.height < y + h - 2)
+ {
+ g.drawLine(x, rect.y + rect.height + 1, x, y + h + 2);
+ }
+ if (isOcean)
+ {
+ g.setColor(MetalLookAndFeel.getWhite());
+ g.drawLine(x + 1, y + 1, x + 1, rect.y + 1);
+ if (rect.y + rect.height < y + h - 2)
+ {
+ g.drawLine(x + 1, rect.y + rect.height + 1, x + 1, y + h + 2);
+ }
+ }
+ }
+
+ }
+
+ /**
+ * Paints the right edge of the content border.
+ *
+ * @param g the graphics to use for painting
+ * @param tabPlacement the tab placement
+ * @param selectedIndex the index of the selected tab
+ * @param x the upper left coordinate of the content area
+ * @param y the upper left coordinate of 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)
+ {
+ g.setColor(darkShadow);
+ Rectangle rect = selectedIndex < 0 ? null :
+ getTabBounds(selectedIndex, calcRect);
+ boolean isOcean = MetalLookAndFeel.getCurrentTheme() instanceof OceanTheme;
+ Color oceanSelectedBorder =
+ UIManager.getColor("TabbedPane.borderHightlightColor");
+
+ // If tabs are not placed on RIGHT, or if the selected tab is not in the
+ // run directly right to the content or the selected tab is not visible,
+ // then we draw an unbroken line.
+ if (tabPlacement != RIGHT || selectedIndex < 0 || rect.x - 1 > w
+ || rect.y < y || rect.y > y + h)
+ {
+ if (isOcean && tabPlacement == RIGHT)
+ {
+ g.setColor(oceanSelectedBorder);
+ }
+ g.drawLine(x + w - 1, y, x + w - 1, y + h - 1);
+ }
+ else
+ {
+ if (isOcean)
+ {
+ g.setColor(oceanSelectedBorder);
+ }
+ g.drawLine(x + w - 1, y, x + w - 1, rect.y);
+
+ if (rect.y + rect.height < y + h - 2)
+ {
+ g.drawLine(x + w - 1, rect.y + rect.height, x + w - 1, y + h - 2);
+ }
+ }
+ }
+
+ /**
+ * Determines if the specified tab is the last tab in its tab run.
+ *
+ * @param tabIndex the index of the tab
+ *
+ * @return if the specified tab is the last tab in its tab run
+ */
+ private boolean isLastTabInRun(int tabIndex)
+ {
+ int count = tabPane.getTabCount();
+ int run = getRunForTab(count, tabIndex);
+ int lastIndex = lastTabInRun(count, run);
+ return tabIndex == lastIndex;
+ }
+
+ /**
+ * Returns the background for an unselected tab. This first asks the
+ * JTabbedPane for the background at the specified tab index, if this
+ * is an UIResource (that means, it is inherited from the JTabbedPane)
+ * and the TabbedPane.unselectedBackground UI property is not null,
+ * this returns the value of the TabbedPane.unselectedBackground property,
+ * otherwise the value returned by the JTabbedPane.
+ *
+ * @param tabIndex the index of the tab for which we query the background
+ *
+ * @return the background for an unselected tab
+ */
+ private Color getUnselectedBackground(int tabIndex)
+ {
+ Color bg = tabPane.getBackgroundAt(tabIndex);
+ Color unselectedBackground =
+ UIManager.getColor("TabbedPane.unselectedBackground");
+ if (bg instanceof UIResource && unselectedBackground != null)
+ bg = unselectedBackground;
+ return bg;
+ }
+
+ protected int getTabLabelShiftX(int tabPlacement,
+ int index,
+ boolean isSelected)
+ {
+ return 0;
+ }
+
+ protected int getTabLabelShiftY(int tabPlacement,
+ int index,
+ boolean isSelected)
+ {
+ return 0;
+ }
+
+}