GNU Classpath (0.20) | |
Frames | No Frames |
1: /* MetalTabbedPaneUI.java 2: Copyright (C) 2005 Free Software Foundation, Inc. 3: 4: This file is part of GNU Classpath. 5: 6: GNU Classpath is free software; you can redistribute it and/or modify 7: it under the terms of the GNU General Public License as published by 8: the Free Software Foundation; either version 2, or (at your option) 9: any later version. 10: 11: GNU Classpath is distributed in the hope that it will be useful, but 12: WITHOUT ANY WARRANTY; without even the implied warranty of 13: MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14: General Public License for more details. 15: 16: You should have received a copy of the GNU General Public License 17: along with GNU Classpath; see the file COPYING. If not, write to the 18: Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 19: 02110-1301 USA. 20: 21: Linking this library statically or dynamically with other modules is 22: making a combined work based on this library. Thus, the terms and 23: conditions of the GNU General Public License cover the whole 24: combination. 25: 26: As a special exception, the copyright holders of this library give you 27: permission to link this library with independent modules to produce an 28: executable, regardless of the license terms of these independent 29: modules, and to copy and distribute the resulting executable under 30: terms of your choice, provided that you also meet, for each linked 31: independent module, the terms and conditions of the license of that 32: module. An independent module is a module which is not derived from 33: or based on this library. If you modify this library, you may extend 34: this exception to your version of the library, but you are not 35: obligated to do so. If you do not wish to do so, delete this 36: exception statement from your version. */ 37: 38: 39: package javax.swing.plaf.metal; 40: 41: import java.awt.Color; 42: import java.awt.Graphics; 43: import java.awt.LayoutManager; 44: import java.awt.Rectangle; 45: 46: import javax.swing.JComponent; 47: import javax.swing.JTabbedPane; 48: import javax.swing.UIManager; 49: import javax.swing.plaf.ComponentUI; 50: import javax.swing.plaf.basic.BasicTabbedPaneUI; 51: 52: /** 53: * A UI delegate for the {@link JTabbedPane} component. 54: */ 55: public class MetalTabbedPaneUI extends BasicTabbedPaneUI 56: { 57: 58: /** 59: * A {@link LayoutManager} responsible for placing all the tabs and the 60: * visible component inside the {@link JTabbedPane}. This class is only used 61: * for {@link JTabbedPane#WRAP_TAB_LAYOUT}. 62: * 63: * @specnote Apparently this class was intended to be protected, 64: * but was made public by a compiler bug and is now 65: * public for compatibility. 66: */ 67: public class TabbedPaneLayout 68: extends BasicTabbedPaneUI.TabbedPaneLayout 69: { 70: /** 71: * Creates a new instance of the layout manager. 72: */ 73: public TabbedPaneLayout() 74: { 75: // Nothing to do here. 76: } 77: 78: /** 79: * Overridden to do nothing, because tab runs are not rotated in the 80: * {@link MetalLookAndFeel}. 81: * 82: * @param tabPlacement the tab placement (one of {@link #TOP}, 83: * {@link #BOTTOM}, {@link #LEFT} or {@link #RIGHT}). 84: * @param selectedRun the index of the selected run. 85: */ 86: protected void rotateTabRuns(int tabPlacement, int selectedRun) 87: { 88: // do nothing, because tab runs are not rotated in the MetalLookAndFeel 89: } 90: 91: /** 92: * Overridden to do nothing, because the selected tab does not have extra 93: * padding in the {@link MetalLookAndFeel}. 94: * 95: * @param tabPlacement the tab placement (one of {@link #TOP}, 96: * {@link #BOTTOM}, {@link #LEFT} or {@link #RIGHT}). 97: * @param selectedIndex the index of the selected tab. 98: */ 99: protected void padSelectedTab(int tabPlacement, int selectedIndex) 100: { 101: // do nothing, because the selected tab does not have extra padding in 102: // the MetalLookAndFeel 103: } 104: } 105: 106: /** 107: * The minimum tab width. 108: */ 109: protected int minTabWidth; 110: 111: /** 112: * The color for the selected tab. 113: */ 114: protected Color selectColor; 115: 116: /** 117: * The color for a highlighted selected tab. 118: */ 119: protected Color selectHighlight; 120: 121: /** 122: * The background color used for the tab area. 123: */ 124: protected Color tabAreaBackground; 125: 126: /** The graphics to draw the highlight below the tab. */ 127: private Graphics hg; 128: 129: /** 130: * Constructs a new instance of MetalTabbedPaneUI. 131: */ 132: public MetalTabbedPaneUI() 133: { 134: super(); 135: } 136: 137: /** 138: * Returns an instance of MetalTabbedPaneUI. 139: * 140: * @param component the component for which we return an UI instance 141: * 142: * @return an instance of MetalTabbedPaneUI 143: */ 144: public static ComponentUI createUI(JComponent component) 145: { 146: return new MetalTabbedPaneUI(); 147: } 148: 149: /** 150: * Creates and returns an instance of {@link TabbedPaneLayout}. 151: * 152: * @return A layout manager used by this UI delegate. 153: */ 154: protected LayoutManager createLayoutManager() 155: { 156: return super.createLayoutManager(); 157: } 158: 159: /** 160: * Paints the border for a single tab. 161: * 162: * @param g the graphics device. 163: * @param tabPlacement the tab placement ({@link #TOP}, {@link #LEFT}, 164: * {@link #BOTTOM} or {@link #RIGHT}). 165: * @param tabIndex the index of the tab to draw the border for. 166: * @param x the x-coordinate for the tab's bounding rectangle. 167: * @param y the y-coordinate for the tab's bounding rectangle. 168: * @param w the width for the tab's bounding rectangle. 169: * @param h the height for the tab's bounding rectangle. 170: * @param isSelected indicates whether or not the tab is selected. 171: */ 172: protected void paintTabBorder(Graphics g, int tabPlacement, int tabIndex, 173: int x, int y, int w, int h, boolean isSelected) 174: { 175: if (tabPlacement == TOP) 176: paintTopTabBorder(tabIndex, g, x, y, w, h, 0, 0, isSelected); 177: else if (tabPlacement == LEFT) 178: paintLeftTabBorder(tabIndex, g, x, y, w, h, 0, 0, isSelected); 179: else if (tabPlacement == BOTTOM) 180: paintBottomTabBorder(tabIndex, g, x, y, w, h, 0, 0, isSelected); 181: else if (tabPlacement == RIGHT) 182: paintRightTabBorder(tabIndex, g, x, y, w, h, 0, 0, isSelected); 183: else 184: throw new AssertionError("Unrecognised 'tabPlacement' argument."); 185: } 186: 187: /** 188: * Paints the border for a tab assuming that the tab position is at the top 189: * ({@link #TOP}). 190: * 191: * @param tabIndex the tab index. 192: * @param g the graphics device. 193: * @param x the x-coordinate for the tab's bounding rectangle. 194: * @param y the y-coordinate for the tab's bounding rectangle. 195: * @param w the width for the tab's bounding rectangle. 196: * @param h the height for the tab's bounding rectangle. 197: * @param btm ??? 198: * @param rght ??? 199: * @param isSelected indicates whether the tab is selected. 200: */ 201: protected void paintTopTabBorder(int tabIndex, Graphics g, int x, int y, 202: int w, int h, int btm, int rght, boolean isSelected) 203: { 204: int currentRun = getRunForTab(tabPane.getTabCount(), tabIndex); 205: if (shouldFillGap(currentRun, tabIndex, x, y)) 206: { 207: g.translate(x, y); 208: g.setColor(getColorForGap(currentRun, x, y)); 209: g.fillRect(1, 0, 5, 3); 210: g.fillRect(1, 3, 2, 2); 211: g.translate(-x, -y); 212: } 213: 214: if (isSelected) 215: { 216: g.setColor(MetalLookAndFeel.getControlHighlight()); 217: g.drawLine(x + 1, y + h, x + 1, y + 6); 218: g.drawLine(x + 1, y + 6, x + 6, y + 1); 219: g.drawLine(x + 6, y + 1, x + w - 1, y + 1); 220: } 221: g.setColor(MetalLookAndFeel.getControlDarkShadow()); 222: g.drawLine(x, y + h - 1, x, y + 6); 223: g.drawLine(x, y + 6, x + 6, y); 224: g.drawLine(x + 6, y, x + w, y); 225: g.drawLine(x + w, y, x + w, y + h - 1); 226: } 227: 228: /** 229: * Paints the border for a tab assuming that the tab position is at the left 230: * ({@link #LEFT}). 231: * 232: * @param tabIndex the tab index. 233: * @param g the graphics device. 234: * @param x the x-coordinate for the tab's bounding rectangle. 235: * @param y the y-coordinate for the tab's bounding rectangle. 236: * @param w the width for the tab's bounding rectangle. 237: * @param h the height for the tab's bounding rectangle. 238: * @param btm ??? 239: * @param rght ??? 240: * @param isSelected indicates whether the tab is selected. 241: */ 242: protected void paintLeftTabBorder(int tabIndex, Graphics g, int x, int y, 243: int w, int h, int btm, int rght, boolean isSelected) 244: { 245: if (isSelected) 246: { 247: g.setColor(MetalLookAndFeel.getControlHighlight()); 248: g.drawLine(x + 1, y + h, x + 1, y + 6); 249: g.drawLine(x + 1, y + 6, x + 6, y + 1); 250: g.drawLine(x + 6, y + 1, x + w - 1, y + 1); 251: } 252: g.setColor(MetalLookAndFeel.getControlDarkShadow()); 253: g.drawLine(x, y + h, x, y + 6); 254: g.drawLine(x, y + 6, x + 6, y); 255: g.drawLine(x + 6, y, x + w - 1, y); 256: g.drawLine(x, y + h, x + w - 1, y + h); 257: } 258: 259: /** 260: * Paints the border for a tab assuming that the tab position is at the right 261: * ({@link #RIGHT}). 262: * 263: * @param tabIndex the tab index. 264: * @param g the graphics device. 265: * @param x the x-coordinate for the tab's bounding rectangle. 266: * @param y the y-coordinate for the tab's bounding rectangle. 267: * @param w the width for the tab's bounding rectangle. 268: * @param h the height for the tab's bounding rectangle. 269: * @param btm ??? 270: * @param rght ??? 271: * @param isSelected indicates whether the tab is selected. 272: */ 273: protected void paintRightTabBorder(int tabIndex, Graphics g, int x, int y, 274: int w, int h, int btm, int rght, boolean isSelected) 275: { 276: if (isSelected) 277: { 278: g.setColor(MetalLookAndFeel.getControlHighlight()); 279: g.drawLine(x, y + 1, x + w - 7, y + 1); 280: g.drawLine(x + w - 7, y + 1, x + w - 1, y + 7); 281: } 282: g.setColor(MetalLookAndFeel.getControlDarkShadow()); 283: g.drawLine(x, y, x + w - 7, y); 284: g.drawLine(x + w - 7, y, x + w - 1, y + 6); 285: g.drawLine(x + w - 1, y + 6, x + w - 1, y + h - 1); 286: g.drawLine(x + w - 1, y + h, x, y + h); 287: } 288: 289: /** 290: * Paints the border for a tab assuming that the tab position is at the bottom 291: * ({@link #BOTTOM}). 292: * 293: * @param tabIndex the tab index. 294: * @param g the graphics device. 295: * @param x the x-coordinate for the tab's bounding rectangle. 296: * @param y the y-coordinate for the tab's bounding rectangle. 297: * @param w the width for the tab's bounding rectangle. 298: * @param h the height for the tab's bounding rectangle. 299: * @param btm ??? 300: * @param rght ??? 301: * @param isSelected indicates whether the tab is selected. 302: */ 303: protected void paintBottomTabBorder(int tabIndex, Graphics g, int x, int y, 304: int w, int h, int btm, int rght, boolean isSelected) 305: { 306: int currentRun = getRunForTab(tabPane.getTabCount(), tabIndex); 307: if (shouldFillGap(currentRun, tabIndex, x, y)) 308: { 309: g.translate(x, y); 310: g.setColor(getColorForGap(currentRun, x, y)); 311: g.fillRect(1, h - 5, 3, 5); 312: g.fillRect(4, h - 2, 2, 2); 313: g.translate(-x, -y); 314: } 315: 316: if (isSelected) 317: { 318: g.setColor(MetalLookAndFeel.getControlHighlight()); 319: g.drawLine(x + 1, y, x + 1, y + h - 7); 320: g.drawLine(x + 1, y + h - 7, x + 7, y + h - 1); 321: } 322: g.setColor(MetalLookAndFeel.getControlDarkShadow()); 323: g.drawLine(x, y, x, y + h - 7); 324: g.drawLine(x, y + h - 7, x + 6, y + h - 1); 325: g.drawLine(x + 6, y + h - 1, x + w, y + h - 1); 326: g.drawLine(x + w, y + h - 1, x + w, y); 327: } 328: 329: /** 330: * Paints the background for a tab. 331: * 332: * @param g the graphics device. 333: * @param tabPlacement the tab placement ({@link #TOP}, {@link #LEFT}, 334: * {@link #BOTTOM} or {@link #RIGHT}). 335: * @param tabIndex the index of the tab to draw the border for. 336: * @param x the x-coordinate for the tab's bounding rectangle. 337: * @param y the y-coordinate for the tab's bounding rectangle. 338: * @param w the width for the tab's bounding rectangle. 339: * @param h the height for the tab's bounding rectangle. 340: * @param isSelected indicates whether or not the tab is selected. 341: */ 342: protected void paintTabBackground(Graphics g, int tabPlacement, 343: int tabIndex, int x, int y, int w, int h, boolean isSelected) 344: { 345: if (isSelected) 346: g.setColor(UIManager.getColor("TabbedPane.selected")); 347: else 348: { 349: // This is only present in the OceanTheme, so we must check if it 350: // is actually there 351: Color background = UIManager.getColor("TabbedPane.unselectedBackground"); 352: if (background == null) 353: background = UIManager.getColor("TabbedPane.background"); 354: g.setColor(background); 355: } 356: int[] px, py; 357: if (tabPlacement == TOP) 358: { 359: px = new int[] {x + 6, x + w - 1, x + w -1, x + 2, x + 2}; 360: py = new int[] {y + 2, y + 2, y + h - 1, y + h -1, y + 6}; 361: } 362: else if (tabPlacement == LEFT) 363: { 364: px = new int[] {x + 6, x + w - 1, x + w -1, x + 2, x + 2}; 365: py = new int[] {y + 2, y + 2, y + h - 1, y + h -1, y + 6}; 366: } 367: else if (tabPlacement == BOTTOM) 368: { 369: px = new int[] {x + 2, x + w - 1, x + w -1, x + 8, x + 2}; 370: py = new int[] {y, y, y + h - 1, y + h -1, y + h - 7}; 371: } 372: else if (tabPlacement == RIGHT) 373: { 374: px = new int[] {x + 2, x + w - 7, x + w - 1, x + w - 1, x + 2}; 375: py = new int[] {y + 2, y + 2, y + 7, y + h -1, y + h - 1}; 376: } 377: else 378: throw new AssertionError("Unrecognised 'tabPlacement' argument."); 379: g.fillPolygon(px, py, 5); 380: hg = g; 381: paintHighlightBelowTab(); 382: } 383: 384: /** 385: * Returns <code>true</code> if the tabs in the specified run should be 386: * padded to make the run fill the width/height of the {@link JTabbedPane}. 387: * 388: * @param tabPlacement the tab placement for the {@link JTabbedPane} (one of 389: * {@link #TOP}, {@link #BOTTOM}, {@link #LEFT} and {@link #RIGHT}). 390: * @param run the run index. 391: * 392: * @return A boolean. 393: */ 394: protected boolean shouldPadTabRun(int tabPlacement, int run) 395: { 396: // as far as I can tell, all runs should be padded except the last run 397: // (which is drawn at the very top for tabPlacement == TOP) 398: return run < this.runCount - 1; 399: } 400: 401: /** 402: * Installs the defaults for this UI. This method calls super.installDefaults 403: * and then loads the Metal specific defaults for TabbedPane. 404: */ 405: protected void installDefaults() 406: { 407: super.installDefaults(); 408: selectColor = UIManager.getColor("TabbedPane.selected"); 409: selectHighlight = UIManager.getColor("TabbedPane.selectHighlight"); 410: tabAreaBackground = UIManager.getColor("TabbedPane.tabAreaBackground"); 411: minTabWidth = 0; 412: } 413: 414: /** 415: * Returns the color for the gap. 416: * 417: * @param currentRun - The current run to return the color for 418: * @param x - The x position of the current run 419: * @param y - The y position of the current run 420: * 421: * @return the color for the gap in the current run. 422: */ 423: protected Color getColorForGap(int currentRun, int x, int y) 424: { 425: int index = tabForCoordinate(tabPane, x, y); 426: int selected = tabPane.getSelectedIndex(); 427: if (selected == index) 428: return selectColor; 429: return tabAreaBackground; 430: } 431: 432: /** 433: * Returns true if the gap should be filled in. 434: * 435: * @param currentRun - The current run 436: * @param tabIndex - The current tab 437: * @param x - The x position of the tab 438: * @param y - The y position of the tab 439: * 440: * @return true if the gap at the current run should be filled 441: */ 442: protected boolean shouldFillGap(int currentRun, int tabIndex, int x, int y) 443: { 444: // As far as I can tell, the gap is never filled in. 445: return false; 446: } 447: 448: /** 449: * Paints the highlight below the tab, if there is one. 450: */ 451: protected void paintHighlightBelowTab() 452: { 453: int selected = tabPane.getSelectedIndex(); 454: int tabPlacement = tabPane.getTabPlacement(); 455: Rectangle bounds = getTabBounds(tabPane, selected); 456: 457: hg.setColor(selectColor); 458: int x = bounds.x; 459: int y = bounds.y; 460: int w = bounds.width; 461: int h = bounds.height; 462: 463: if (tabPlacement == TOP) 464: hg.fillRect(x, y + h - 2, w, 30); 465: else if (tabPlacement == LEFT) 466: hg.fillRect(x + w - 1, y, 20, h); 467: else if (tabPlacement == BOTTOM) 468: hg.fillRect(x, y - h + 2, w, 30); 469: else if (tabPlacement == RIGHT) 470: hg.fillRect(x - 18, y, 20, h); 471: else 472: throw new AssertionError("Unrecognised 'tabPlacement' argument."); 473: hg = null; 474: } 475: 476: /** 477: * Returns true if we should rotate the tab runs. 478: * 479: * @param tabPlacement - The current tab placement. 480: * @param selectedRun - The selected run. 481: * 482: * @return true if the tab runs should be rotated. 483: */ 484: protected boolean shouldRotateTabRuns(int tabPlacement, 485: int selectedRun) 486: { 487: // false because tab runs are not rotated in the MetalLookAndFeel 488: return false; 489: } 490: }
GNU Classpath (0.20) |