0001 /*
0002 * Copyright 1998-2006 Sun Microsystems, Inc. All Rights Reserved.
0003 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
0004 *
0005 * This code is free software; you can redistribute it and/or modify it
0006 * under the terms of the GNU General Public License version 2 only, as
0007 * published by the Free Software Foundation. Sun designates this
0008 * particular file as subject to the "Classpath" exception as provided
0009 * by Sun in the LICENSE file that accompanied this code.
0010 *
0011 * This code is distributed in the hope that it will be useful, but WITHOUT
0012 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
0013 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
0014 * version 2 for more details (a copy is included in the LICENSE file that
0015 * accompanied this code).
0016 *
0017 * You should have received a copy of the GNU General Public License version
0018 * 2 along with this work; if not, write to the Free Software Foundation,
0019 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
0020 *
0021 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
0022 * CA 95054 USA or visit www.sun.com if you need additional information or
0023 * have any questions.
0024 */
0025
0026 package javax.swing.plaf.metal;
0027
0028 import javax.swing.*;
0029 import javax.swing.event.*;
0030 import java.awt.*;
0031 import java.awt.event.*;
0032 import javax.swing.plaf.*;
0033 import java.io.Serializable;
0034 import javax.swing.plaf.basic.BasicTabbedPaneUI;
0035
0036 /**
0037 * The Metal subclass of BasicTabbedPaneUI.
0038 * <p>
0039 * <strong>Warning:</strong>
0040 * Serialized objects of this class will not be compatible with
0041 * future Swing releases. The current serialization support is
0042 * appropriate for short term storage or RMI between applications running
0043 * the same version of Swing. As of 1.4, support for long term storage
0044 * of all JavaBeans<sup><font size="-2">TM</font></sup>
0045 * has been added to the <code>java.beans</code> package.
0046 * Please see {@link java.beans.XMLEncoder}.
0047 *
0048 * @version 1.19 08/28/98
0049 * @author Tom Santos
0050 */
0051
0052 public class MetalTabbedPaneUI extends BasicTabbedPaneUI {
0053
0054 protected int minTabWidth = 40;
0055 // Background color for unselected tabs that don't have an explicitly
0056 // set color.
0057 private Color unselectedBackground;
0058 protected Color tabAreaBackground;
0059 protected Color selectColor;
0060 protected Color selectHighlight;
0061 private boolean tabsOpaque = true;
0062
0063 // Whether or not we're using ocean. This is cached as it is used
0064 // extensively during painting.
0065 private boolean ocean;
0066 // Selected border color for ocean.
0067 private Color oceanSelectedBorderColor;
0068
0069 public static ComponentUI createUI(JComponent x) {
0070 return new MetalTabbedPaneUI();
0071 }
0072
0073 protected LayoutManager createLayoutManager() {
0074 if (tabPane.getTabLayoutPolicy() == JTabbedPane.SCROLL_TAB_LAYOUT) {
0075 return super .createLayoutManager();
0076 }
0077 return new TabbedPaneLayout();
0078 }
0079
0080 protected void installDefaults() {
0081 super .installDefaults();
0082
0083 tabAreaBackground = UIManager
0084 .getColor("TabbedPane.tabAreaBackground");
0085 selectColor = UIManager.getColor("TabbedPane.selected");
0086 selectHighlight = UIManager
0087 .getColor("TabbedPane.selectHighlight");
0088 tabsOpaque = UIManager.getBoolean("TabbedPane.tabsOpaque");
0089 unselectedBackground = UIManager
0090 .getColor("TabbedPane.unselectedBackground");
0091 ocean = MetalLookAndFeel.usingOcean();
0092 if (ocean) {
0093 oceanSelectedBorderColor = UIManager
0094 .getColor("TabbedPane.borderHightlightColor");
0095 }
0096 }
0097
0098 protected void paintTabBorder(Graphics g, int tabPlacement,
0099 int tabIndex, int x, int y, int w, int h, boolean isSelected) {
0100 int bottom = y + (h - 1);
0101 int right = x + (w - 1);
0102
0103 switch (tabPlacement) {
0104 case LEFT:
0105 paintLeftTabBorder(tabIndex, g, x, y, w, h, bottom, right,
0106 isSelected);
0107 break;
0108 case BOTTOM:
0109 paintBottomTabBorder(tabIndex, g, x, y, w, h, bottom,
0110 right, isSelected);
0111 break;
0112 case RIGHT:
0113 paintRightTabBorder(tabIndex, g, x, y, w, h, bottom, right,
0114 isSelected);
0115 break;
0116 case TOP:
0117 default:
0118 paintTopTabBorder(tabIndex, g, x, y, w, h, bottom, right,
0119 isSelected);
0120 }
0121 }
0122
0123 protected void paintTopTabBorder(int tabIndex, Graphics g, int x,
0124 int y, int w, int h, int btm, int rght, boolean isSelected) {
0125 int currentRun = getRunForTab(tabPane.getTabCount(), tabIndex);
0126 int lastIndex = lastTabInRun(tabPane.getTabCount(), currentRun);
0127 int firstIndex = tabRuns[currentRun];
0128 boolean leftToRight = MetalUtils.isLeftToRight(tabPane);
0129 int selectedIndex = tabPane.getSelectedIndex();
0130 int bottom = h - 1;
0131 int right = w - 1;
0132
0133 //
0134 // Paint Gap
0135 //
0136
0137 if (shouldFillGap(currentRun, tabIndex, x, y)) {
0138 g.translate(x, y);
0139
0140 if (leftToRight) {
0141 g.setColor(getColorForGap(currentRun, x, y + 1));
0142 g.fillRect(1, 0, 5, 3);
0143 g.fillRect(1, 3, 2, 2);
0144 } else {
0145 g
0146 .setColor(getColorForGap(currentRun, x + w - 1,
0147 y + 1));
0148 g.fillRect(right - 5, 0, 5, 3);
0149 g.fillRect(right - 2, 3, 2, 2);
0150 }
0151
0152 g.translate(-x, -y);
0153 }
0154
0155 g.translate(x, y);
0156
0157 //
0158 // Paint Border
0159 //
0160
0161 if (ocean && isSelected) {
0162 g.setColor(oceanSelectedBorderColor);
0163 } else {
0164 g.setColor(darkShadow);
0165 }
0166
0167 if (leftToRight) {
0168
0169 // Paint slant
0170 g.drawLine(1, 5, 6, 0);
0171
0172 // Paint top
0173 g.drawLine(6, 0, right, 0);
0174
0175 // Paint right
0176 if (tabIndex == lastIndex) {
0177 // last tab in run
0178 g.drawLine(right, 1, right, bottom);
0179 }
0180
0181 if (ocean
0182 && tabIndex - 1 == selectedIndex
0183 && currentRun == getRunForTab(
0184 tabPane.getTabCount(), selectedIndex)) {
0185 g.setColor(oceanSelectedBorderColor);
0186 }
0187
0188 // Paint left
0189 if (tabIndex != tabRuns[runCount - 1]) {
0190 // not the first tab in the last run
0191 if (ocean && isSelected) {
0192 g.drawLine(0, 6, 0, bottom);
0193 g.setColor(darkShadow);
0194 g.drawLine(0, 0, 0, 5);
0195 } else {
0196 g.drawLine(0, 0, 0, bottom);
0197 }
0198 } else {
0199 // the first tab in the last run
0200 g.drawLine(0, 6, 0, bottom);
0201 }
0202 } else {
0203
0204 // Paint slant
0205 g.drawLine(right - 1, 5, right - 6, 0);
0206
0207 // Paint top
0208 g.drawLine(right - 6, 0, 0, 0);
0209
0210 // Paint left
0211 if (tabIndex == lastIndex) {
0212 // last tab in run
0213 g.drawLine(0, 1, 0, bottom);
0214 }
0215
0216 // Paint right
0217 if (ocean
0218 && tabIndex - 1 == selectedIndex
0219 && currentRun == getRunForTab(
0220 tabPane.getTabCount(), selectedIndex)) {
0221 g.setColor(oceanSelectedBorderColor);
0222 g.drawLine(right, 0, right, bottom);
0223 } else if (ocean && isSelected) {
0224 g.drawLine(right, 6, right, bottom);
0225 if (tabIndex != 0) {
0226 g.setColor(darkShadow);
0227 g.drawLine(right, 0, right, 5);
0228 }
0229 } else {
0230 if (tabIndex != tabRuns[runCount - 1]) {
0231 // not the first tab in the last run
0232 g.drawLine(right, 0, right, bottom);
0233 } else {
0234 // the first tab in the last run
0235 g.drawLine(right, 6, right, bottom);
0236 }
0237 }
0238 }
0239
0240 //
0241 // Paint Highlight
0242 //
0243
0244 g.setColor(isSelected ? selectHighlight : highlight);
0245
0246 if (leftToRight) {
0247
0248 // Paint slant
0249 g.drawLine(1, 6, 6, 1);
0250
0251 // Paint top
0252 g.drawLine(6, 1, (tabIndex == lastIndex) ? right - 1
0253 : right, 1);
0254
0255 // Paint left
0256 g.drawLine(1, 6, 1, bottom);
0257
0258 // paint highlight in the gap on tab behind this one
0259 // on the left end (where they all line up)
0260 if (tabIndex == firstIndex
0261 && tabIndex != tabRuns[runCount - 1]) {
0262 // first tab in run but not first tab in last run
0263 if (tabPane.getSelectedIndex() == tabRuns[currentRun + 1]) {
0264 // tab in front of selected tab
0265 g.setColor(selectHighlight);
0266 } else {
0267 // tab in front of normal tab
0268 g.setColor(highlight);
0269 }
0270 g.drawLine(1, 0, 1, 4);
0271 }
0272 } else {
0273
0274 // Paint slant
0275 g.drawLine(right - 1, 6, right - 6, 1);
0276
0277 // Paint top
0278 g.drawLine(right - 6, 1, 1, 1);
0279
0280 // Paint left
0281 if (tabIndex == lastIndex) {
0282 // last tab in run
0283 g.drawLine(1, 1, 1, bottom);
0284 } else {
0285 g.drawLine(0, 1, 0, bottom);
0286 }
0287 }
0288
0289 g.translate(-x, -y);
0290 }
0291
0292 protected boolean shouldFillGap(int currentRun, int tabIndex,
0293 int x, int y) {
0294 boolean result = false;
0295
0296 if (!tabsOpaque) {
0297 return false;
0298 }
0299
0300 if (currentRun == runCount - 2) { // If it's the second to last row.
0301 Rectangle lastTabBounds = getTabBounds(tabPane, tabPane
0302 .getTabCount() - 1);
0303 Rectangle tabBounds = getTabBounds(tabPane, tabIndex);
0304 if (MetalUtils.isLeftToRight(tabPane)) {
0305 int lastTabRight = lastTabBounds.x
0306 + lastTabBounds.width - 1;
0307
0308 // is the right edge of the last tab to the right
0309 // of the left edge of the current tab?
0310 if (lastTabRight > tabBounds.x + 2) {
0311 return true;
0312 }
0313 } else {
0314 int lastTabLeft = lastTabBounds.x;
0315 int currentTabRight = tabBounds.x + tabBounds.width - 1;
0316
0317 // is the left edge of the last tab to the left
0318 // of the right edge of the current tab?
0319 if (lastTabLeft < currentTabRight - 2) {
0320 return true;
0321 }
0322 }
0323 } else {
0324 // fill in gap for all other rows except last row
0325 result = currentRun != runCount - 1;
0326 }
0327
0328 return result;
0329 }
0330
0331 protected Color getColorForGap(int currentRun, int x, int y) {
0332 final int shadowWidth = 4;
0333 int selectedIndex = tabPane.getSelectedIndex();
0334 int startIndex = tabRuns[currentRun + 1];
0335 int endIndex = lastTabInRun(tabPane.getTabCount(),
0336 currentRun + 1);
0337 int tabOverGap = -1;
0338 // Check each tab in the row that is 'on top' of this row
0339 for (int i = startIndex; i <= endIndex; ++i) {
0340 Rectangle tabBounds = getTabBounds(tabPane, i);
0341 int tabLeft = tabBounds.x;
0342 int tabRight = (tabBounds.x + tabBounds.width) - 1;
0343 // Check to see if this tab is over the gap
0344 if (MetalUtils.isLeftToRight(tabPane)) {
0345 if (tabLeft <= x && tabRight - shadowWidth > x) {
0346 return selectedIndex == i ? selectColor
0347 : getUnselectedBackgroundAt(i);
0348 }
0349 } else {
0350 if (tabLeft + shadowWidth < x && tabRight >= x) {
0351 return selectedIndex == i ? selectColor
0352 : getUnselectedBackgroundAt(i);
0353 }
0354 }
0355 }
0356
0357 return tabPane.getBackground();
0358 }
0359
0360 protected void paintLeftTabBorder(int tabIndex, Graphics g, int x,
0361 int y, int w, int h, int btm, int rght, boolean isSelected) {
0362 int tabCount = tabPane.getTabCount();
0363 int currentRun = getRunForTab(tabCount, tabIndex);
0364 int lastIndex = lastTabInRun(tabCount, currentRun);
0365 int firstIndex = tabRuns[currentRun];
0366
0367 g.translate(x, y);
0368
0369 int bottom = h - 1;
0370 int right = w - 1;
0371
0372 //
0373 // Paint part of the tab above
0374 //
0375
0376 if (tabIndex != firstIndex && tabsOpaque) {
0377 g
0378 .setColor(tabPane.getSelectedIndex() == tabIndex - 1 ? selectColor
0379 : getUnselectedBackgroundAt(tabIndex - 1));
0380 g.fillRect(2, 0, 4, 3);
0381 g.drawLine(2, 3, 2, 3);
0382 }
0383
0384 //
0385 // Paint Highlight
0386 //
0387
0388 if (ocean) {
0389 g.setColor(isSelected ? selectHighlight : MetalLookAndFeel
0390 .getWhite());
0391 } else {
0392 g.setColor(isSelected ? selectHighlight : highlight);
0393 }
0394
0395 // Paint slant
0396 g.drawLine(1, 6, 6, 1);
0397
0398 // Paint left
0399 g.drawLine(1, 6, 1, bottom);
0400
0401 // Paint top
0402 g.drawLine(6, 1, right, 1);
0403
0404 if (tabIndex != firstIndex) {
0405 if (tabPane.getSelectedIndex() == tabIndex - 1) {
0406 g.setColor(selectHighlight);
0407 } else {
0408 g.setColor(ocean ? MetalLookAndFeel.getWhite()
0409 : highlight);
0410 }
0411
0412 g.drawLine(1, 0, 1, 4);
0413 }
0414
0415 //
0416 // Paint Border
0417 //
0418
0419 if (ocean) {
0420 if (isSelected) {
0421 g.setColor(oceanSelectedBorderColor);
0422 } else {
0423 g.setColor(darkShadow);
0424 }
0425 } else {
0426 g.setColor(darkShadow);
0427 }
0428
0429 // Paint slant
0430 g.drawLine(1, 5, 6, 0);
0431
0432 // Paint top
0433 g.drawLine(6, 0, right, 0);
0434
0435 // Paint bottom
0436 if (tabIndex == lastIndex) {
0437 g.drawLine(0, bottom, right, bottom);
0438 }
0439
0440 // Paint left
0441 if (ocean) {
0442 if (tabPane.getSelectedIndex() == tabIndex - 1) {
0443 g.drawLine(0, 5, 0, bottom);
0444 g.setColor(oceanSelectedBorderColor);
0445 g.drawLine(0, 0, 0, 5);
0446 } else if (isSelected) {
0447 g.drawLine(0, 6, 0, bottom);
0448 if (tabIndex != 0) {
0449 g.setColor(darkShadow);
0450 g.drawLine(0, 0, 0, 5);
0451 }
0452 } else if (tabIndex != firstIndex) {
0453 g.drawLine(0, 0, 0, bottom);
0454 } else {
0455 g.drawLine(0, 6, 0, bottom);
0456 }
0457 } else { // metal
0458 if (tabIndex != firstIndex) {
0459 g.drawLine(0, 0, 0, bottom);
0460 } else {
0461 g.drawLine(0, 6, 0, bottom);
0462 }
0463 }
0464
0465 g.translate(-x, -y);
0466 }
0467
0468 protected void paintBottomTabBorder(int tabIndex, Graphics g,
0469 int x, int y, int w, int h, int btm, int rght,
0470 boolean isSelected) {
0471 int tabCount = tabPane.getTabCount();
0472 int currentRun = getRunForTab(tabCount, tabIndex);
0473 int lastIndex = lastTabInRun(tabCount, currentRun);
0474 int firstIndex = tabRuns[currentRun];
0475 boolean leftToRight = MetalUtils.isLeftToRight(tabPane);
0476
0477 int bottom = h - 1;
0478 int right = w - 1;
0479
0480 //
0481 // Paint Gap
0482 //
0483
0484 if (shouldFillGap(currentRun, tabIndex, x, y)) {
0485 g.translate(x, y);
0486
0487 if (leftToRight) {
0488 g.setColor(getColorForGap(currentRun, x, y));
0489 g.fillRect(1, bottom - 4, 3, 5);
0490 g.fillRect(4, bottom - 1, 2, 2);
0491 } else {
0492 g.setColor(getColorForGap(currentRun, x + w - 1, y));
0493 g.fillRect(right - 3, bottom - 3, 3, 4);
0494 g.fillRect(right - 5, bottom - 1, 2, 2);
0495 g
0496 .drawLine(right - 1, bottom - 4, right - 1,
0497 bottom - 4);
0498 }
0499
0500 g.translate(-x, -y);
0501 }
0502
0503 g.translate(x, y);
0504
0505 //
0506 // Paint Border
0507 //
0508
0509 if (ocean && isSelected) {
0510 g.setColor(oceanSelectedBorderColor);
0511 } else {
0512 g.setColor(darkShadow);
0513 }
0514
0515 if (leftToRight) {
0516
0517 // Paint slant
0518 g.drawLine(1, bottom - 5, 6, bottom);
0519
0520 // Paint bottom
0521 g.drawLine(6, bottom, right, bottom);
0522
0523 // Paint right
0524 if (tabIndex == lastIndex) {
0525 g.drawLine(right, 0, right, bottom);
0526 }
0527
0528 // Paint left
0529 if (ocean && isSelected) {
0530 g.drawLine(0, 0, 0, bottom - 6);
0531 if ((currentRun == 0 && tabIndex != 0)
0532 || (currentRun > 0 && tabIndex != tabRuns[currentRun - 1])) {
0533 g.setColor(darkShadow);
0534 g.drawLine(0, bottom - 5, 0, bottom);
0535 }
0536 } else {
0537 if (ocean && tabIndex == tabPane.getSelectedIndex() + 1) {
0538 g.setColor(oceanSelectedBorderColor);
0539 }
0540 if (tabIndex != tabRuns[runCount - 1]) {
0541 g.drawLine(0, 0, 0, bottom);
0542 } else {
0543 g.drawLine(0, 0, 0, bottom - 6);
0544 }
0545 }
0546 } else {
0547
0548 // Paint slant
0549 g.drawLine(right - 1, bottom - 5, right - 6, bottom);
0550
0551 // Paint bottom
0552 g.drawLine(right - 6, bottom, 0, bottom);
0553
0554 // Paint left
0555 if (tabIndex == lastIndex) {
0556 // last tab in run
0557 g.drawLine(0, 0, 0, bottom);
0558 }
0559
0560 // Paint right
0561 if (ocean && tabIndex == tabPane.getSelectedIndex() + 1) {
0562 g.setColor(oceanSelectedBorderColor);
0563 g.drawLine(right, 0, right, bottom);
0564 } else if (ocean && isSelected) {
0565 g.drawLine(right, 0, right, bottom - 6);
0566 if (tabIndex != firstIndex) {
0567 g.setColor(darkShadow);
0568 g.drawLine(right, bottom - 5, right, bottom);
0569 }
0570 } else if (tabIndex != tabRuns[runCount - 1]) {
0571 // not the first tab in the last run
0572 g.drawLine(right, 0, right, bottom);
0573 } else {
0574 // the first tab in the last run
0575 g.drawLine(right, 0, right, bottom - 6);
0576 }
0577 }
0578
0579 //
0580 // Paint Highlight
0581 //
0582
0583 g.setColor(isSelected ? selectHighlight : highlight);
0584
0585 if (leftToRight) {
0586
0587 // Paint slant
0588 g.drawLine(1, bottom - 6, 6, bottom - 1);
0589
0590 // Paint left
0591 g.drawLine(1, 0, 1, bottom - 6);
0592
0593 // paint highlight in the gap on tab behind this one
0594 // on the left end (where they all line up)
0595 if (tabIndex == firstIndex
0596 && tabIndex != tabRuns[runCount - 1]) {
0597 // first tab in run but not first tab in last run
0598 if (tabPane.getSelectedIndex() == tabRuns[currentRun + 1]) {
0599 // tab in front of selected tab
0600 g.setColor(selectHighlight);
0601 } else {
0602 // tab in front of normal tab
0603 g.setColor(highlight);
0604 }
0605 g.drawLine(1, bottom - 4, 1, bottom);
0606 }
0607 } else {
0608
0609 // Paint left
0610 if (tabIndex == lastIndex) {
0611 // last tab in run
0612 g.drawLine(1, 0, 1, bottom - 1);
0613 } else {
0614 g.drawLine(0, 0, 0, bottom - 1);
0615 }
0616 }
0617
0618 g.translate(-x, -y);
0619 }
0620
0621 protected void paintRightTabBorder(int tabIndex, Graphics g, int x,
0622 int y, int w, int h, int btm, int rght, boolean isSelected) {
0623 int tabCount = tabPane.getTabCount();
0624 int currentRun = getRunForTab(tabCount, tabIndex);
0625 int lastIndex = lastTabInRun(tabCount, currentRun);
0626 int firstIndex = tabRuns[currentRun];
0627
0628 g.translate(x, y);
0629
0630 int bottom = h - 1;
0631 int right = w - 1;
0632
0633 //
0634 // Paint part of the tab above
0635 //
0636
0637 if (tabIndex != firstIndex && tabsOpaque) {
0638 g
0639 .setColor(tabPane.getSelectedIndex() == tabIndex - 1 ? selectColor
0640 : getUnselectedBackgroundAt(tabIndex - 1));
0641 g.fillRect(right - 5, 0, 5, 3);
0642 g.fillRect(right - 2, 3, 2, 2);
0643 }
0644
0645 //
0646 // Paint Highlight
0647 //
0648
0649 g.setColor(isSelected ? selectHighlight : highlight);
0650
0651 // Paint slant
0652 g.drawLine(right - 6, 1, right - 1, 6);
0653
0654 // Paint top
0655 g.drawLine(0, 1, right - 6, 1);
0656
0657 // Paint left
0658 if (!isSelected) {
0659 g.drawLine(0, 1, 0, bottom);
0660 }
0661
0662 //
0663 // Paint Border
0664 //
0665
0666 if (ocean && isSelected) {
0667 g.setColor(oceanSelectedBorderColor);
0668 } else {
0669 g.setColor(darkShadow);
0670 }
0671
0672 // Paint bottom
0673 if (tabIndex == lastIndex) {
0674 g.drawLine(0, bottom, right, bottom);
0675 }
0676
0677 // Paint slant
0678 if (ocean && tabPane.getSelectedIndex() == tabIndex - 1) {
0679 g.setColor(oceanSelectedBorderColor);
0680 }
0681 g.drawLine(right - 6, 0, right, 6);
0682
0683 // Paint top
0684 g.drawLine(0, 0, right - 6, 0);
0685
0686 // Paint right
0687 if (ocean && isSelected) {
0688 g.drawLine(right, 6, right, bottom);
0689 if (tabIndex != firstIndex) {
0690 g.setColor(darkShadow);
0691 g.drawLine(right, 0, right, 5);
0692 }
0693 } else if (ocean && tabPane.getSelectedIndex() == tabIndex - 1) {
0694 g.setColor(oceanSelectedBorderColor);
0695 g.drawLine(right, 0, right, 6);
0696 g.setColor(darkShadow);
0697 g.drawLine(right, 6, right, bottom);
0698 } else if (tabIndex != firstIndex) {
0699 g.drawLine(right, 0, right, bottom);
0700 } else {
0701 g.drawLine(right, 6, right, bottom);
0702 }
0703
0704 g.translate(-x, -y);
0705 }
0706
0707 public void update(Graphics g, JComponent c) {
0708 if (c.isOpaque()) {
0709 g.setColor(tabAreaBackground);
0710 g.fillRect(0, 0, c.getWidth(), c.getHeight());
0711 }
0712 paint(g, c);
0713 }
0714
0715 protected void paintTabBackground(Graphics g, int tabPlacement,
0716 int tabIndex, int x, int y, int w, int h, boolean isSelected) {
0717 int slantWidth = h / 2;
0718 if (isSelected) {
0719 g.setColor(selectColor);
0720 } else {
0721 g.setColor(getUnselectedBackgroundAt(tabIndex));
0722 }
0723
0724 if (MetalUtils.isLeftToRight(tabPane)) {
0725 switch (tabPlacement) {
0726 case LEFT:
0727 g.fillRect(x + 5, y + 1, w - 5, h - 1);
0728 g.fillRect(x + 2, y + 4, 3, h - 4);
0729 break;
0730 case BOTTOM:
0731 g.fillRect(x + 2, y, w - 2, h - 4);
0732 g.fillRect(x + 5, y + (h - 1) - 3, w - 5, 3);
0733 break;
0734 case RIGHT:
0735 g.fillRect(x, y + 2, w - 4, h - 2);
0736 g.fillRect(x + (w - 1) - 3, y + 5, 3, h - 5);
0737 break;
0738 case TOP:
0739 default:
0740 g.fillRect(x + 4, y + 2, (w - 1) - 3, (h - 1) - 1);
0741 g.fillRect(x + 2, y + 5, 2, h - 5);
0742 }
0743 } else {
0744 switch (tabPlacement) {
0745 case LEFT:
0746 g.fillRect(x + 5, y + 1, w - 5, h - 1);
0747 g.fillRect(x + 2, y + 4, 3, h - 4);
0748 break;
0749 case BOTTOM:
0750 g.fillRect(x, y, w - 5, h - 1);
0751 g.fillRect(x + (w - 1) - 4, y, 4, h - 5);
0752 g.fillRect(x + (w - 1) - 4, y + (h - 1) - 4, 2, 2);
0753 break;
0754 case RIGHT:
0755 g.fillRect(x + 1, y + 1, w - 5, h - 1);
0756 g.fillRect(x + (w - 1) - 3, y + 5, 3, h - 5);
0757 break;
0758 case TOP:
0759 default:
0760 g.fillRect(x, y + 2, (w - 1) - 3, (h - 1) - 1);
0761 g.fillRect(x + (w - 1) - 3, y + 5, 3, h - 3);
0762 }
0763 }
0764 }
0765
0766 /**
0767 * Overridden to do nothing for the Java L&F.
0768 */
0769 protected int getTabLabelShiftX(int tabPlacement, int tabIndex,
0770 boolean isSelected) {
0771 return 0;
0772 }
0773
0774 /**
0775 * Overridden to do nothing for the Java L&F.
0776 */
0777 protected int getTabLabelShiftY(int tabPlacement, int tabIndex,
0778 boolean isSelected) {
0779 return 0;
0780 }
0781
0782 /**
0783 * {@inheritDoc}
0784 *
0785 * @since 1.6
0786 */
0787 protected int getBaselineOffset() {
0788 return 0;
0789 }
0790
0791 public void paint(Graphics g, JComponent c) {
0792 int tabPlacement = tabPane.getTabPlacement();
0793
0794 Insets insets = c.getInsets();
0795 Dimension size = c.getSize();
0796
0797 // Paint the background for the tab area
0798 if (tabPane.isOpaque()) {
0799 Color bg = UIManager
0800 .getColor("TabbedPane.tabAreaBackground");
0801 if (bg != null) {
0802 g.setColor(bg);
0803 } else {
0804 g.setColor(c.getBackground());
0805 }
0806 switch (tabPlacement) {
0807 case LEFT:
0808 g.fillRect(insets.left, insets.top,
0809 calculateTabAreaWidth(tabPlacement, runCount,
0810 maxTabWidth), size.height
0811 - insets.bottom - insets.top);
0812 break;
0813 case BOTTOM:
0814 int totalTabHeight = calculateTabAreaHeight(
0815 tabPlacement, runCount, maxTabHeight);
0816 g.fillRect(insets.left, size.height - insets.bottom
0817 - totalTabHeight, size.width - insets.left
0818 - insets.right, totalTabHeight);
0819 break;
0820 case RIGHT:
0821 int totalTabWidth = calculateTabAreaWidth(tabPlacement,
0822 runCount, maxTabWidth);
0823 g.fillRect(size.width - insets.right - totalTabWidth,
0824 insets.top, totalTabWidth, size.height
0825 - insets.top - insets.bottom);
0826 break;
0827 case TOP:
0828 default:
0829 g.fillRect(insets.left, insets.top, size.width
0830 - insets.right - insets.left,
0831 calculateTabAreaHeight(tabPlacement, runCount,
0832 maxTabHeight));
0833 paintHighlightBelowTab();
0834 }
0835 }
0836
0837 super .paint(g, c);
0838 }
0839
0840 protected void paintHighlightBelowTab() {
0841
0842 }
0843
0844 protected void paintFocusIndicator(Graphics g, int tabPlacement,
0845 Rectangle[] rects, int tabIndex, Rectangle iconRect,
0846 Rectangle textRect, boolean isSelected) {
0847 if (tabPane.hasFocus() && isSelected) {
0848 Rectangle tabRect = rects[tabIndex];
0849 boolean lastInRun = isLastInRun(tabIndex);
0850 g.setColor(focus);
0851 g.translate(tabRect.x, tabRect.y);
0852 int right = tabRect.width - 1;
0853 int bottom = tabRect.height - 1;
0854 boolean leftToRight = MetalUtils.isLeftToRight(tabPane);
0855 switch (tabPlacement) {
0856 case RIGHT:
0857 g.drawLine(right - 6, 2, right - 2, 6); // slant
0858 g.drawLine(1, 2, right - 6, 2); // top
0859 g.drawLine(right - 2, 6, right - 2, bottom); // right
0860 g.drawLine(1, 2, 1, bottom); // left
0861 g.drawLine(1, bottom, right - 2, bottom); // bottom
0862 break;
0863 case BOTTOM:
0864 if (leftToRight) {
0865 g.drawLine(2, bottom - 6, 6, bottom - 2); // slant
0866 g.drawLine(6, bottom - 2, right, bottom - 2); // bottom
0867 g.drawLine(2, 0, 2, bottom - 6); // left
0868 g.drawLine(2, 0, right, 0); // top
0869 g.drawLine(right, 0, right, bottom - 2); // right
0870 } else {
0871 g.drawLine(right - 2, bottom - 6, right - 6,
0872 bottom - 2); // slant
0873 g.drawLine(right - 2, 0, right - 2, bottom - 6); // right
0874 if (lastInRun) {
0875 // last tab in run
0876 g
0877 .drawLine(2, bottom - 2, right - 6,
0878 bottom - 2); // bottom
0879 g.drawLine(2, 0, right - 2, 0); // top
0880 g.drawLine(2, 0, 2, bottom - 2); // left
0881 } else {
0882 g
0883 .drawLine(1, bottom - 2, right - 6,
0884 bottom - 2); // bottom
0885 g.drawLine(1, 0, right - 2, 0); // top
0886 g.drawLine(1, 0, 1, bottom - 2); // left
0887 }
0888 }
0889 break;
0890 case LEFT:
0891 g.drawLine(2, 6, 6, 2); // slant
0892 g.drawLine(2, 6, 2, bottom - 1); // left
0893 g.drawLine(6, 2, right, 2); // top
0894 g.drawLine(right, 2, right, bottom - 1); // right
0895 g.drawLine(2, bottom - 1, right, bottom - 1); // bottom
0896 break;
0897 case TOP:
0898 default:
0899 if (leftToRight) {
0900 g.drawLine(2, 6, 6, 2); // slant
0901 g.drawLine(2, 6, 2, bottom - 1); // left
0902 g.drawLine(6, 2, right, 2); // top
0903 g.drawLine(right, 2, right, bottom - 1); // right
0904 g.drawLine(2, bottom - 1, right, bottom - 1); // bottom
0905 } else {
0906 g.drawLine(right - 2, 6, right - 6, 2); // slant
0907 g.drawLine(right - 2, 6, right - 2, bottom - 1); // right
0908 if (lastInRun) {
0909 // last tab in run
0910 g.drawLine(right - 6, 2, 2, 2); // top
0911 g.drawLine(2, 2, 2, bottom - 1); // left
0912 g
0913 .drawLine(right - 2, bottom - 1, 2,
0914 bottom - 1); // bottom
0915 } else {
0916 g.drawLine(right - 6, 2, 1, 2); // top
0917 g.drawLine(1, 2, 1, bottom - 1); // left
0918 g
0919 .drawLine(right - 2, bottom - 1, 1,
0920 bottom - 1); // bottom
0921 }
0922 }
0923 }
0924 g.translate(-tabRect.x, -tabRect.y);
0925 }
0926 }
0927
0928 protected void paintContentBorderTopEdge(Graphics g,
0929 int tabPlacement, int selectedIndex, int x, int y, int w,
0930 int h) {
0931 boolean leftToRight = MetalUtils.isLeftToRight(tabPane);
0932 int right = x + w - 1;
0933 Rectangle selRect = selectedIndex < 0 ? null : getTabBounds(
0934 selectedIndex, calcRect);
0935 if (ocean) {
0936 g.setColor(oceanSelectedBorderColor);
0937 } else {
0938 g.setColor(selectHighlight);
0939 }
0940
0941 // Draw unbroken line if tabs are not on TOP, OR
0942 // selected tab is not in run adjacent to content, OR
0943 // selected tab is not visible (SCROLL_TAB_LAYOUT)
0944 //
0945 if (tabPlacement != TOP || selectedIndex < 0
0946 || (selRect.y + selRect.height + 1 < y)
0947 || (selRect.x < x || selRect.x > x + w)) {
0948 g.drawLine(x, y, x + w - 2, y);
0949 if (ocean && tabPlacement == TOP) {
0950 g.setColor(MetalLookAndFeel.getWhite());
0951 g.drawLine(x, y + 1, x + w - 2, y + 1);
0952 }
0953 } else {
0954 // Break line to show visual connection to selected tab
0955 boolean lastInRun = isLastInRun(selectedIndex);
0956
0957 if (leftToRight || lastInRun) {
0958 g.drawLine(x, y, selRect.x + 1, y);
0959 } else {
0960 g.drawLine(x, y, selRect.x, y);
0961 }
0962
0963 if (selRect.x + selRect.width < right - 1) {
0964 if (leftToRight && !lastInRun) {
0965 g.drawLine(selRect.x + selRect.width, y, right - 1,
0966 y);
0967 } else {
0968 g.drawLine(selRect.x + selRect.width - 1, y,
0969 right - 1, y);
0970 }
0971 } else {
0972 g.setColor(shadow);
0973 g.drawLine(x + w - 2, y, x + w - 2, y);
0974 }
0975
0976 if (ocean) {
0977 g.setColor(MetalLookAndFeel.getWhite());
0978
0979 if (leftToRight || lastInRun) {
0980 g.drawLine(x, y + 1, selRect.x + 1, y + 1);
0981 } else {
0982 g.drawLine(x, y + 1, selRect.x, y + 1);
0983 }
0984
0985 if (selRect.x + selRect.width < right - 1) {
0986 if (leftToRight && !lastInRun) {
0987 g.drawLine(selRect.x + selRect.width, y + 1,
0988 right - 1, y + 1);
0989 } else {
0990 g.drawLine(selRect.x + selRect.width - 1,
0991 y + 1, right - 1, y + 1);
0992 }
0993 } else {
0994 g.setColor(shadow);
0995 g.drawLine(x + w - 2, y + 1, x + w - 2, y + 1);
0996 }
0997 }
0998 }
0999 }
1000
1001 protected void paintContentBorderBottomEdge(Graphics g,
1002 int tabPlacement, int selectedIndex, int x, int y, int w,
1003 int h) {
1004 boolean leftToRight = MetalUtils.isLeftToRight(tabPane);
1005 int bottom = y + h - 1;
1006 int right = x + w - 1;
1007 Rectangle selRect = selectedIndex < 0 ? null : getTabBounds(
1008 selectedIndex, calcRect);
1009
1010 g.setColor(darkShadow);
1011
1012 // Draw unbroken line if tabs are not on BOTTOM, OR
1013 // selected tab is not in run adjacent to content, OR
1014 // selected tab is not visible (SCROLL_TAB_LAYOUT)
1015 //
1016 if (tabPlacement != BOTTOM || selectedIndex < 0
1017 || (selRect.y - 1 > h)
1018 || (selRect.x < x || selRect.x > x + w)) {
1019 if (ocean && tabPlacement == BOTTOM) {
1020 g.setColor(oceanSelectedBorderColor);
1021 }
1022 g.drawLine(x, y + h - 1, x + w - 1, y + h - 1);
1023 } else {
1024 // Break line to show visual connection to selected tab
1025 boolean lastInRun = isLastInRun(selectedIndex);
1026
1027 if (ocean) {
1028 g.setColor(oceanSelectedBorderColor);
1029 }
1030
1031 if (leftToRight || lastInRun) {
1032 g.drawLine(x, bottom, selRect.x, bottom);
1033 } else {
1034 g.drawLine(x, bottom, selRect.x - 1, bottom);
1035 }
1036
1037 if (selRect.x + selRect.width < x + w - 2) {
1038 if (leftToRight && !lastInRun) {
1039 g.drawLine(selRect.x + selRect.width, bottom,
1040 right, bottom);
1041 } else {
1042 g.drawLine(selRect.x + selRect.width - 1, bottom,
1043 right, bottom);
1044 }
1045 }
1046 }
1047 }
1048
1049 protected void paintContentBorderLeftEdge(Graphics g,
1050 int tabPlacement, int selectedIndex, int x, int y, int w,
1051 int h) {
1052 Rectangle selRect = selectedIndex < 0 ? null : getTabBounds(
1053 selectedIndex, calcRect);
1054 if (ocean) {
1055 g.setColor(oceanSelectedBorderColor);
1056 } else {
1057 g.setColor(selectHighlight);
1058 }
1059
1060 // Draw unbroken line if tabs are not on LEFT, OR
1061 // selected tab is not in run adjacent to content, OR
1062 // selected tab is not visible (SCROLL_TAB_LAYOUT)
1063 //
1064 if (tabPlacement != LEFT || selectedIndex < 0
1065 || (selRect.x + selRect.width + 1 < x)
1066 || (selRect.y < y || selRect.y > y + h)) {
1067 g.drawLine(x, y + 1, x, y + h - 2);
1068 if (ocean && tabPlacement == LEFT) {
1069 g.setColor(MetalLookAndFeel.getWhite());
1070 g.drawLine(x + 1, y, x + 1, y + h - 2);
1071 }
1072 } else {
1073 // Break line to show visual connection to selected tab
1074 g.drawLine(x, y, x, selRect.y + 1);
1075 if (selRect.y + selRect.height < y + h - 2) {
1076 g.drawLine(x, selRect.y + selRect.height + 1, x, y + h
1077 + 2);
1078 }
1079 if (ocean) {
1080 g.setColor(MetalLookAndFeel.getWhite());
1081 g.drawLine(x + 1, y + 1, x + 1, selRect.y + 1);
1082 if (selRect.y + selRect.height < y + h - 2) {
1083 g.drawLine(x + 1, selRect.y + selRect.height + 1,
1084 x + 1, y + h + 2);
1085 }
1086 }
1087 }
1088 }
1089
1090 protected void paintContentBorderRightEdge(Graphics g,
1091 int tabPlacement, int selectedIndex, int x, int y, int w,
1092 int h) {
1093 Rectangle selRect = selectedIndex < 0 ? null : getTabBounds(
1094 selectedIndex, calcRect);
1095
1096 g.setColor(darkShadow);
1097 // Draw unbroken line if tabs are not on RIGHT, OR
1098 // selected tab is not in run adjacent to content, OR
1099 // selected tab is not visible (SCROLL_TAB_LAYOUT)
1100 //
1101 if (tabPlacement != RIGHT || selectedIndex < 0
1102 || (selRect.x - 1 > w)
1103 || (selRect.y < y || selRect.y > y + h)) {
1104 if (ocean && tabPlacement == RIGHT) {
1105 g.setColor(oceanSelectedBorderColor);
1106 }
1107 g.drawLine(x + w - 1, y, x + w - 1, y + h - 1);
1108 } else {
1109 // Break line to show visual connection to selected tab
1110 if (ocean) {
1111 g.setColor(oceanSelectedBorderColor);
1112 }
1113 g.drawLine(x + w - 1, y, x + w - 1, selRect.y);
1114
1115 if (selRect.y + selRect.height < y + h - 2) {
1116 g.drawLine(x + w - 1, selRect.y + selRect.height, x + w
1117 - 1, y + h - 2);
1118 }
1119 }
1120 }
1121
1122 protected int calculateMaxTabHeight(int tabPlacement) {
1123 FontMetrics metrics = getFontMetrics();
1124 int height = metrics.getHeight();
1125 boolean tallerIcons = false;
1126
1127 for (int i = 0; i < tabPane.getTabCount(); ++i) {
1128 Icon icon = tabPane.getIconAt(i);
1129 if (icon != null) {
1130 if (icon.getIconHeight() > height) {
1131 tallerIcons = true;
1132 break;
1133 }
1134 }
1135 }
1136 return super .calculateMaxTabHeight(tabPlacement)
1137 - (tallerIcons ? (tabInsets.top + tabInsets.bottom) : 0);
1138 }
1139
1140 protected int getTabRunOverlay(int tabPlacement) {
1141 // Tab runs laid out vertically should overlap
1142 // at least as much as the largest slant
1143 if (tabPlacement == LEFT || tabPlacement == RIGHT) {
1144 int maxTabHeight = calculateMaxTabHeight(tabPlacement);
1145 return maxTabHeight / 2;
1146 }
1147 return 0;
1148 }
1149
1150 // Don't rotate runs!
1151 protected boolean shouldRotateTabRuns(int tabPlacement,
1152 int selectedRun) {
1153 return false;
1154 }
1155
1156 // Don't pad last run
1157 protected boolean shouldPadTabRun(int tabPlacement, int run) {
1158 return runCount > 1 && run < runCount - 1;
1159 }
1160
1161 private boolean isLastInRun(int tabIndex) {
1162 int run = getRunForTab(tabPane.getTabCount(), tabIndex);
1163 int lastIndex = lastTabInRun(tabPane.getTabCount(), run);
1164 return tabIndex == lastIndex;
1165 }
1166
1167 /**
1168 * Returns the color to use for the specified tab.
1169 */
1170 private Color getUnselectedBackgroundAt(int index) {
1171 Color color = tabPane.getBackgroundAt(index);
1172 if (color instanceof UIResource) {
1173 if (unselectedBackground != null) {
1174 return unselectedBackground;
1175 }
1176 }
1177 return color;
1178 }
1179
1180 /**
1181 * Returns the tab index of JTabbedPane the mouse is currently over
1182 */
1183 int getRolloverTabIndex() {
1184 return getRolloverTab();
1185 }
1186
1187 /**
1188 * This inner class is marked "public" due to a compiler bug.
1189 * This class should be treated as a "protected" inner class.
1190 * Instantiate it only within subclasses of MetalTabbedPaneUI.
1191 */
1192 public class TabbedPaneLayout extends
1193 BasicTabbedPaneUI.TabbedPaneLayout {
1194
1195 public TabbedPaneLayout() {
1196 MetalTabbedPaneUI.this .super ();
1197 }
1198
1199 protected void normalizeTabRuns(int tabPlacement, int tabCount,
1200 int start, int max) {
1201 // Only normalize the runs for top & bottom; normalizing
1202 // doesn't look right for Metal's vertical tabs
1203 // because the last run isn't padded and it looks odd to have
1204 // fat tabs in the first vertical runs, but slimmer ones in the
1205 // last (this effect isn't noticeable for horizontal tabs).
1206 if (tabPlacement == TOP || tabPlacement == BOTTOM) {
1207 super .normalizeTabRuns(tabPlacement, tabCount, start,
1208 max);
1209 }
1210 }
1211
1212 // Don't rotate runs!
1213 protected void rotateTabRuns(int tabPlacement, int selectedRun) {
1214 }
1215
1216 // Don't pad selected tab
1217 protected void padSelectedTab(int tabPlacement,
1218 int selectedIndex) {
1219 }
1220 }
1221
1222 }
|