| 1 7 8 package javax.swing.plaf.basic; 9 10 import com.sun.java.swing.SwingUtilities2; 11 12 import javax.swing.*; 13 import javax.swing.event.*; 14 import javax.swing.plaf.*; 15 import javax.swing.text.View ; 16 17 import java.awt.*; 18 import java.awt.event.*; 19 import java.beans.PropertyChangeListener ; 20 import java.beans.PropertyChangeEvent ; 21 import java.util.Vector ; 22 import java.util.Hashtable ; 23 24 import sun.swing.DefaultLookup; 25 import sun.swing.UIAction; 26 27 37 public class BasicTabbedPaneUI extends TabbedPaneUI implements SwingConstants { 38 39 40 42 protected JTabbedPane tabPane; 43 44 protected Color highlight; 45 protected Color lightHighlight; 46 protected Color shadow; 47 protected Color darkShadow; 48 protected Color focus; 49 private Color selectedColor; 50 51 protected int textIconGap; 52 53 protected int tabRunOverlay; 54 55 protected Insets tabInsets; 56 protected Insets selectedTabPadInsets; 57 protected Insets tabAreaInsets; 58 protected Insets contentBorderInsets; 59 private boolean tabsOverlapBorder; 60 private boolean tabsOpaque = true; 61 private boolean contentOpaque = true; 62 63 71 @Deprecated  72 protected KeyStroke upKey; 73 81 @Deprecated  82 protected KeyStroke downKey; 83 91 @Deprecated  92 protected KeyStroke leftKey; 93 101 @Deprecated  102 protected KeyStroke rightKey; 103 104 105 107 protected int tabRuns[] = new int[10]; 108 protected int runCount = 0; 109 protected int selectedRun = -1; 110 protected Rectangle rects[] = new Rectangle[0]; 111 protected int maxTabHeight; 112 protected int maxTabWidth; 113 114 116 protected ChangeListener tabChangeListener; 117 protected PropertyChangeListener propertyChangeListener; 118 protected MouseListener mouseListener; 119 protected FocusListener focusListener; 120 121 123 private Insets currentPadInsets = new Insets(0,0,0,0); 124 private Insets currentTabAreaInsets = new Insets(0,0,0,0); 125 126 private Component visibleComponent; 127 private Vector htmlViews; 129 130 private Hashtable mnemonicToIndexMap; 131 132 136 private InputMap mnemonicInputMap; 137 138 private ScrollableTabSupport tabScroller; 140 141 145 protected transient Rectangle calcRect = new Rectangle(0,0,0,0); 146 147 150 private int focusIndex; 151 152 155 private Handler handler; 156 157 160 private int rolloverTabIndex; 161 162 167 private boolean isRunsDirty; 168 169 171 public static ComponentUI createUI(JComponent c) { 172 return new BasicTabbedPaneUI (); 173 } 174 175 static void loadActionMap(LazyActionMap map) { 176 map.put(new Actions(Actions.NEXT)); 177 map.put(new Actions(Actions.PREVIOUS)); 178 map.put(new Actions(Actions.RIGHT)); 179 map.put(new Actions(Actions.LEFT)); 180 map.put(new Actions(Actions.UP)); 181 map.put(new Actions(Actions.DOWN)); 182 map.put(new Actions(Actions.PAGE_UP)); 183 map.put(new Actions(Actions.PAGE_DOWN)); 184 map.put(new Actions(Actions.REQUEST_FOCUS)); 185 map.put(new Actions(Actions.REQUEST_FOCUS_FOR_VISIBLE)); 186 map.put(new Actions(Actions.SET_SELECTED)); 187 map.put(new Actions(Actions.SELECT_FOCUSED)); 188 map.put(new Actions(Actions.SCROLL_FORWARD)); 189 map.put(new Actions(Actions.SCROLL_BACKWARD)); 190 } 191 192 194 public void installUI(JComponent c) { 195 this.tabPane = (JTabbedPane)c; 196 197 rolloverTabIndex = -1; 198 focusIndex = -1; 199 c.setLayout(createLayoutManager()); 200 installComponents(); 201 installDefaults(); 202 installListeners(); 203 installKeyboardActions(); 204 } 205 206 public void uninstallUI(JComponent c) { 207 uninstallKeyboardActions(); 208 uninstallListeners(); 209 uninstallDefaults(); 210 uninstallComponents(); 211 c.setLayout(null); 212 213 this.tabPane = null; 214 } 215 216 226 protected LayoutManager createLayoutManager() { 227 if (tabPane.getTabLayoutPolicy() == JTabbedPane.SCROLL_TAB_LAYOUT) { 228 return new TabbedPaneScrollLayout(); 229 } else { 230 return new TabbedPaneLayout(); 231 } 232 } 233 234 239 private boolean scrollableTabLayoutEnabled() { 240 return (tabPane.getLayout() instanceof TabbedPaneScrollLayout); 241 } 242 243 249 protected void installComponents() { 250 if (scrollableTabLayoutEnabled()) { 251 if (tabScroller == null) { 252 tabScroller = new ScrollableTabSupport(tabPane.getTabPlacement()); 253 tabPane.add(tabScroller.viewport); 254 } 255 } 256 } 257 258 272 protected JButton createScrollButton(int direction) { 273 if (direction != SOUTH && direction != NORTH && direction != EAST && 274 direction != WEST) { 275 throw new IllegalArgumentException ("Direction must be one of: " + 276 "SOUTH, NORTH, EAST or WEST"); 277 } 278 return new ScrollableTabButton(direction); 279 } 280 281 287 protected void uninstallComponents() { 288 if (scrollableTabLayoutEnabled()) { 289 tabPane.remove(tabScroller.viewport); 290 tabPane.remove(tabScroller.scrollForwardButton); 291 tabPane.remove(tabScroller.scrollBackwardButton); 292 tabScroller = null; 293 } 294 } 295 296 protected void installDefaults() { 297 LookAndFeel.installColorsAndFont(tabPane, "TabbedPane.background", 298 "TabbedPane.foreground", "TabbedPane.font"); 299 highlight = UIManager.getColor("TabbedPane.light"); 300 lightHighlight = UIManager.getColor("TabbedPane.highlight"); 301 shadow = UIManager.getColor("TabbedPane.shadow"); 302 darkShadow = UIManager.getColor("TabbedPane.darkShadow"); 303 focus = UIManager.getColor("TabbedPane.focus"); 304 selectedColor = UIManager.getColor("TabbedPane.selected"); 305 306 textIconGap = UIManager.getInt("TabbedPane.textIconGap"); 307 tabInsets = UIManager.getInsets("TabbedPane.tabInsets"); 308 selectedTabPadInsets = UIManager.getInsets("TabbedPane.selectedTabPadInsets"); 309 tabAreaInsets = UIManager.getInsets("TabbedPane.tabAreaInsets"); 310 tabsOverlapBorder = UIManager.getBoolean("TabbedPane.tabsOverlapBorder"); 311 contentBorderInsets = UIManager.getInsets("TabbedPane.contentBorderInsets"); 312 tabRunOverlay = UIManager.getInt("TabbedPane.tabRunOverlay"); 313 tabsOpaque = UIManager.getBoolean("TabbedPane.tabsOpaque"); 314 contentOpaque = UIManager.getBoolean("TabbedPane.contentOpaque"); 315 Object opaque = UIManager.get("TabbedPane.opaque"); 316 if (opaque == null) { 317 opaque = Boolean.FALSE; 318 } 319 LookAndFeel.installProperty(tabPane, "opaque", opaque); 320 } 321 322 protected void uninstallDefaults() { 323 highlight = null; 324 lightHighlight = null; 325 shadow = null; 326 darkShadow = null; 327 focus = null; 328 tabInsets = null; 329 selectedTabPadInsets = null; 330 tabAreaInsets = null; 331 contentBorderInsets = null; 332 } 333 334 protected void installListeners() { 335 if ((propertyChangeListener = createPropertyChangeListener()) != null) { 336 tabPane.addPropertyChangeListener(propertyChangeListener); 337 } 338 if ((tabChangeListener = createChangeListener()) != null) { 339 tabPane.addChangeListener(tabChangeListener); 340 } 341 if ((mouseListener = createMouseListener()) != null) { 342 tabPane.addMouseListener(mouseListener); 343 } 344 tabPane.addMouseMotionListener(getHandler()); 345 if ((focusListener = createFocusListener()) != null) { 346 tabPane.addFocusListener(focusListener); 347 } 348 tabPane.addContainerListener(getHandler()); 349 if (tabPane.getTabCount()>0) { 350 htmlViews = createHTMLVector(); 351 } 352 } 353 354 protected void uninstallListeners() { 355 if (mouseListener != null) { 356 tabPane.removeMouseListener(mouseListener); 357 mouseListener = null; 358 } 359 tabPane.removeMouseMotionListener(getHandler()); 360 if (focusListener != null) { 361 tabPane.removeFocusListener(focusListener); 362 focusListener = null; 363 } 364 365 tabPane.removeContainerListener(getHandler()); 366 if (htmlViews!=null) { 367 htmlViews.removeAllElements(); 368 htmlViews = null; 369 } 370 if (tabChangeListener != null) { 371 tabPane.removeChangeListener(tabChangeListener); 372 tabChangeListener = null; 373 } 374 if (propertyChangeListener != null) { 375 tabPane.removePropertyChangeListener(propertyChangeListener); 376 propertyChangeListener = null; 377 } 378 handler = null; 379 } 380 381 protected MouseListener createMouseListener() { 382 return getHandler(); 383 } 384 385 protected FocusListener createFocusListener() { 386 return getHandler(); 387 } 388 389 protected ChangeListener createChangeListener() { 390 return getHandler(); 391 } 392 393 protected PropertyChangeListener createPropertyChangeListener() { 394 return getHandler(); 395 } 396 397 private Handler getHandler() { 398 if (handler == null) { 399 handler = new Handler(); 400 } 401 return handler; 402 } 403 404 protected void installKeyboardActions() { 405 InputMap km = getInputMap(JComponent. 406 WHEN_ANCESTOR_OF_FOCUSED_COMPONENT); 407 408 SwingUtilities.replaceUIInputMap(tabPane, JComponent. 409 WHEN_ANCESTOR_OF_FOCUSED_COMPONENT, 410 km); 411 km = getInputMap(JComponent.WHEN_FOCUSED); 412 SwingUtilities.replaceUIInputMap(tabPane, JComponent.WHEN_FOCUSED, km); 413 414 LazyActionMap.installLazyActionMap(tabPane, BasicTabbedPaneUI .class, 415 "TabbedPane.actionMap"); 416 } 417 418 InputMap getInputMap(int condition) { 419 if (condition == JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT) { 420 return (InputMap)DefaultLookup.get(tabPane, this, 421 "TabbedPane.ancestorInputMap"); 422 } 423 else if (condition == JComponent.WHEN_FOCUSED) { 424 return (InputMap)DefaultLookup.get(tabPane, this, 425 "TabbedPane.focusInputMap"); 426 } 427 return null; 428 } 429 430 protected void uninstallKeyboardActions() { 431 SwingUtilities.replaceUIActionMap(tabPane, null); 432 SwingUtilities.replaceUIInputMap(tabPane, JComponent. 433 WHEN_ANCESTOR_OF_FOCUSED_COMPONENT, 434 null); 435 SwingUtilities.replaceUIInputMap(tabPane, JComponent.WHEN_FOCUSED, 436 null); 437 } 438 439 443 private void updateMnemonics() { 444 resetMnemonics(); 445 for (int counter = tabPane.getTabCount() - 1; counter >= 0; 446 counter--) { 447 int mnemonic = tabPane.getMnemonicAt(counter); 448 449 if (mnemonic > 0) { 450 addMnemonic(counter, mnemonic); 451 } 452 } 453 } 454 455 458 private void resetMnemonics() { 459 if (mnemonicToIndexMap != null) { 460 mnemonicToIndexMap.clear(); 461 mnemonicInputMap.clear(); 462 } 463 } 464 465 468 private void addMnemonic(int index, int mnemonic) { 469 if (mnemonicToIndexMap == null) { 470 initMnemonics(); 471 } 472 mnemonicInputMap.put(KeyStroke.getKeyStroke(mnemonic, Event.ALT_MASK), 473 "setSelectedIndex"); 474 mnemonicToIndexMap.put(new Integer (mnemonic), new Integer (index)); 475 } 476 477 480 private void initMnemonics() { 481 mnemonicToIndexMap = new Hashtable (); 482 mnemonicInputMap = new ComponentInputMapUIResource(tabPane); 483 mnemonicInputMap.setParent(SwingUtilities.getUIInputMap(tabPane, 484 JComponent.WHEN_IN_FOCUSED_WINDOW)); 485 SwingUtilities.replaceUIInputMap(tabPane, 486 JComponent.WHEN_IN_FOCUSED_WINDOW, 487 mnemonicInputMap); 488 } 489 490 494 private void setRolloverTab(int x, int y) { 495 setRolloverTab(tabForCoordinate(tabPane, x, y, false)); 500 } 501 502 511 protected void setRolloverTab(int index) { 512 rolloverTabIndex = index; 513 } 514 515 522 protected int getRolloverTab() { 523 return rolloverTabIndex; 524 } 525 526 public Dimension getMinimumSize(JComponent c) { 527 return null; 529 } 530 531 public Dimension getMaximumSize(JComponent c) { 532 return null; 534 } 535 536 538 public void paint(Graphics g, JComponent c) { 539 int selectedIndex = tabPane.getSelectedIndex(); 540 int tabPlacement = tabPane.getTabPlacement(); 541 542 ensureCurrentLayout(); 543 544 if (tabsOverlapBorder) { 546 paintContentBorder(g, tabPlacement, selectedIndex); 547 } 548 if (!scrollableTabLayoutEnabled()) { paintTabArea(g, tabPlacement, selectedIndex); 553 } 554 if (!tabsOverlapBorder) { 555 paintContentBorder(g, tabPlacement, selectedIndex); 556 } 557 } 558 559 576 protected void paintTabArea(Graphics g, int tabPlacement, int selectedIndex) { 577 int tabCount = tabPane.getTabCount(); 578 579 Rectangle iconRect = new Rectangle(), 580 textRect = new Rectangle(); 581 Rectangle clipRect = g.getClipBounds(); 582 583 for (int i = runCount - 1; i >= 0; i--) { 585 int start = tabRuns[i]; 586 int next = tabRuns[(i == runCount - 1)? 0 : i + 1]; 587 int end = (next != 0? next - 1: tabCount - 1); 588 for (int j = start; j <= end; j++) { 589 if (j != selectedIndex && rects[j].intersects(clipRect)) { 590 paintTab(g, tabPlacement, rects, j, iconRect, textRect); 591 } 592 } 593 } 594 595 if (selectedIndex >= 0 && rects[selectedIndex].intersects(clipRect)) { 598 paintTab(g, tabPlacement, rects, selectedIndex, iconRect, textRect); 599 } 600 } 601 602 protected void paintTab(Graphics g, int tabPlacement, 603 Rectangle[] rects, int tabIndex, 604 Rectangle iconRect, Rectangle textRect) { 605 Rectangle tabRect = rects[tabIndex]; 606 int selectedIndex = tabPane.getSelectedIndex(); 607 boolean isSelected = selectedIndex == tabIndex; 608 Graphics2D g2 = null; 609 Polygon cropShape = null; 610 Shape save = null; 611 int cropx = 0; 612 int cropy = 0; 613 614 if (scrollableTabLayoutEnabled()) { 615 if (g instanceof Graphics2D) { 616 g2 = (Graphics2D)g; 617 618 Rectangle viewRect = tabScroller.viewport.getViewRect(); 620 int cropline; 621 switch(tabPlacement) { 622 case LEFT: 623 case RIGHT: 624 cropline = viewRect.y + viewRect.height; 625 if ((tabRect.y < cropline) && (tabRect.y + tabRect.height > cropline)) { 626 cropShape = createCroppedTabClip(tabPlacement, tabRect, cropline); 627 cropx = tabRect.x; 628 cropy = cropline-1; 629 } 630 break; 631 case TOP: 632 case BOTTOM: 633 default: 634 cropline = viewRect.x + viewRect.width; 635 if ((tabRect.x < cropline) && (tabRect.x + tabRect.width > cropline)) { 636 cropShape = createCroppedTabClip(tabPlacement, tabRect, cropline); 637 cropx = cropline-1; 638 cropy = tabRect.y; 639 } 640 } 641 if (cropShape != null) { 642 save = g2.getClip(); 643 g2.clip(cropShape); 644 } 645 } 646 } 647 648 if (tabsOpaque || tabPane.isOpaque()) { 649 paintTabBackground(g, tabPlacement, tabIndex, tabRect.x, tabRect.y, 650 tabRect.width, tabRect.height, isSelected); 651 } 652 653 paintTabBorder(g, tabPlacement, tabIndex, tabRect.x, tabRect.y, 654 tabRect.width, tabRect.height, isSelected); 655 656 String title = tabPane.getTitleAt(tabIndex); 657 Font font = tabPane.getFont(); 658 FontMetrics metrics = SwingUtilities2.getFontMetrics(tabPane, g, font); 659 Icon icon = getIconForTab(tabIndex); 660 661 layoutLabel(tabPlacement, metrics, tabIndex, title, icon, 662 tabRect, iconRect, textRect, isSelected); 663 664 paintText(g, tabPlacement, font, metrics, 665 tabIndex, title, textRect, isSelected); 666 667 paintIcon(g, tabPlacement, tabIndex, icon, iconRect, isSelected); 668 669 paintFocusIndicator(g, tabPlacement, rects, tabIndex, 670 iconRect, textRect, isSelected); 671 672 if (cropShape != null) { 673 paintCroppedTabEdge(g, tabPlacement, tabIndex, isSelected, cropx, cropy); 674 g2.setClip(save); 675 } 676 } 677 678 679 701 private int xCropLen[] = {1,1,0,0,1,1,2,2}; 702 private int yCropLen[] = {0,3,3,6,6,9,9,12}; 703 private static final int CROP_SEGMENT = 12; 704 705 private Polygon createCroppedTabClip(int tabPlacement, Rectangle tabRect, int cropline) { 706 int rlen = 0; 707 int start = 0; 708 int end = 0; 709 int ostart = 0; 710 711 switch(tabPlacement) { 712 case LEFT: 713 case RIGHT: 714 rlen = tabRect.width; 715 start = tabRect.x; 716 end = tabRect.x + tabRect.width; 717 ostart = tabRect.y; 718 break; 719 case TOP: 720 case BOTTOM: 721 default: 722 rlen = tabRect.height; 723 start = tabRect.y; 724 end = tabRect.y + tabRect.height; 725 ostart = tabRect.x; 726 } 727 int rcnt = rlen/CROP_SEGMENT; 728 if (rlen%CROP_SEGMENT > 0) { 729 rcnt++; 730 } 731 int npts = 2 + (rcnt*8); 732 int xp[] = new int[npts]; 733 int yp[] = new int[npts]; 734 int pcnt = 0; 735 736 xp[pcnt] = ostart; 737 yp[pcnt++] = end; 738 xp[pcnt] = ostart; 739 yp[pcnt++] = start; 740 for(int i = 0; i < rcnt; i++) { 741 for(int j = 0; j < xCropLen.length; j++) { 742 xp[pcnt] = cropline - xCropLen[j]; 743 yp[pcnt] = start + (i*CROP_SEGMENT) + yCropLen[j]; 744 if (yp[pcnt] >= end) { 745 yp[pcnt] = end; 746 pcnt++; 747 break; 748 } 749 pcnt++; 750 } 751 } 752 if (tabPlacement == JTabbedPane.TOP || tabPlacement == JTabbedPane.BOTTOM) { 753 return new Polygon(xp, yp, pcnt); 754 755 } else { return new Polygon(yp, xp, pcnt); 757 } 758 } 759 760 763 private void paintCroppedTabEdge(Graphics g, int tabPlacement, int tabIndex, 764 boolean isSelected, 765 int x, int y) { 766 switch(tabPlacement) { 767 case LEFT: 768 case RIGHT: 769 int xx = x; 770 g.setColor(shadow); 771 while(xx <= x+rects[tabIndex].width) { 772 for (int i=0; i < xCropLen.length; i+=2) { 773 g.drawLine(xx+yCropLen[i],y-xCropLen[i], 774 xx+yCropLen[i+1]-1,y-xCropLen[i+1]); 775 } 776 xx+=CROP_SEGMENT; 777 } 778 break; 779 case TOP: 780 case BOTTOM: 781 default: 782 int yy = y; 783 g.setColor(shadow); 784 while(yy <= y+rects[tabIndex].height) { 785 for (int i=0; i < xCropLen.length; i+=2) { 786 g.drawLine(x-xCropLen[i],yy+yCropLen[i], 787 x-xCropLen[i+1],yy+yCropLen[i+1]-1); 788 } 789 yy+=CROP_SEGMENT; 790 } 791 } 792 } 793 794 protected void layoutLabel(int tabPlacement, 795 FontMetrics metrics, int tabIndex, 796 String title, Icon icon, 797 Rectangle tabRect, Rectangle iconRect, 798 Rectangle textRect, boolean isSelected ) { 799 textRect.x = textRect.y = iconRect.x = iconRect.y = 0; 800 801 View v = getTextViewForTab(tabIndex); 802 if (v != null) { 803 tabPane.putClientProperty("html", v); 804 } 805 806 SwingUtilities.layoutCompoundLabel((JComponent) tabPane, 807 metrics, title, icon, 808 SwingUtilities.CENTER, 809 SwingUtilities.CENTER, 810 SwingUtilities.CENTER, 811 SwingUtilities.TRAILING, 812 tabRect, 813 iconRect, 814 textRect, 815 textIconGap); 816 817 tabPane.putClientProperty("html", null); 818 819 int xNudge = getTabLabelShiftX(tabPlacement, tabIndex, isSelected); 820 int yNudge = getTabLabelShiftY(tabPlacement, tabIndex, isSelected); 821 iconRect.x += xNudge; 822 iconRect.y += yNudge; 823 textRect.x += xNudge; 824 textRect.y += yNudge; 825 } 826 827 protected void paintIcon(Graphics g, int tabPlacement, 828 int tabIndex, Icon icon, Rectangle iconRect, 829 boolean isSelected ) { 830 if (icon != null) { 831 icon.paintIcon(tabPane, g, iconRect.x, iconRect.y); 832 } 833 } 834 835 protected void paintText(Graphics g, int tabPlacement, 836 Font font, FontMetrics metrics, int tabIndex, 837 String title, Rectangle textRect, 838 boolean isSelected) { 839 840 g.setFont(font); 841 842 View v = getTextViewForTab(tabIndex); 843 if (v != null) { 844 v.paint(g, textRect); 846 } else { 847 int mnemIndex = tabPane.getDisplayedMnemonicIndexAt(tabIndex); 849 850 if (tabPane.isEnabled() && tabPane.isEnabledAt(tabIndex)) { 851 Color fg = tabPane.getForegroundAt(tabIndex); 852 if (isSelected && (fg instanceof UIResource)) { 853 Color selectedFG = UIManager.getColor( 854 "TabbedPane.selectedForeground"); 855 if (selectedFG != null) { 856 fg = selectedFG; 857 } 858 } 859 g.setColor(fg); 860 SwingUtilities2.drawStringUnderlineCharAt(tabPane, g, 861 title, mnemIndex, 862 textRect.x, textRect.y + metrics.getAscent()); 863 864 } else { g.setColor(tabPane.getBackgroundAt(tabIndex).brighter()); 866 SwingUtilities2.drawStringUnderlineCharAt(tabPane, g, 867 title, mnemIndex, 868 textRect.x, textRect.y + metrics.getAscent()); 869 g.setColor(tabPane.getBackgroundAt(tabIndex).darker()); 870 SwingUtilities2.drawStringUnderlineCharAt(tabPane, g, 871 title, mnemIndex, 872 textRect.x - 1, textRect.y + metrics.getAscent() - 1); 873 874 } 875 } 876 } 877 878 879 protected int getTabLabelShiftX(int tabPlacement, int tabIndex, boolean isSelected) { 880 Rectangle tabRect = rects[tabIndex]; 881 &nb
|