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 int nudge = 0; 882 switch(tabPlacement) { 883 case LEFT: 884 nudge = isSelected? -1 : 1; 885 break; 886 case RIGHT: 887 nudge = isSelected? 1 : -1; 888 break; 889 case BOTTOM: 890 case TOP: 891 default: 892 nudge = tabRect.width % 2; 893 } 894 return nudge; 895 } 896 897 protected int getTabLabelShiftY(int tabPlacement, int tabIndex, boolean isSelected) { 898 Rectangle tabRect = rects[tabIndex]; 899 int nudge = 0; 900 switch(tabPlacement) { 901 case BOTTOM: 902 nudge = isSelected? 1 : -1; 903 break; 904 case LEFT: 905 case RIGHT: 906 nudge = tabRect.height % 2; 907 break; 908 case TOP: 909 default: 910 nudge = isSelected? -1 : 1;; 911 } 912 return nudge; 913 } 914 915 protected void paintFocusIndicator(Graphics g, int tabPlacement, 916 Rectangle[] rects, int tabIndex, 917 Rectangle iconRect, Rectangle textRect, 918 boolean isSelected) { 919 Rectangle tabRect = rects[tabIndex]; 920 if (tabPane.hasFocus() && isSelected) { 921 int x, y, w, h; 922 g.setColor(focus); 923 switch(tabPlacement) { 924 case LEFT: 925 x = tabRect.x + 3; 926 y = tabRect.y + 3; 927 w = tabRect.width - 5; 928 h = tabRect.height - 6; 929 break; 930 case RIGHT: 931 x = tabRect.x + 2; 932 y = tabRect.y + 3; 933 w = tabRect.width - 5; 934 h = tabRect.height - 6; 935 break; 936 case BOTTOM: 937 x = tabRect.x + 3; 938 y = tabRect.y + 2; 939 w = tabRect.width - 6; 940 h = tabRect.height - 5; 941 break; 942 case TOP: 943 default: 944 x = tabRect.x + 3; 945 y = tabRect.y + 3; 946 w = tabRect.width - 6; 947 h = tabRect.height - 5; 948 } 949 BasicGraphicsUtils.drawDashedRect(g, x, y, w, h); 950 } 951 } 952 953 958 protected void paintTabBorder(Graphics g, int tabPlacement, 959 int tabIndex, 960 int x, int y, int w, int h, 961 boolean isSelected ) { 962 g.setColor(lightHighlight); 963 964 switch (tabPlacement) { 965 case LEFT: 966 g.drawLine(x+1, y+h-2, x+1, y+h-2); g.drawLine(x, y+2, x, y+h-3); g.drawLine(x+1, y+1, x+1, y+1); g.drawLine(x+2, y, x+w-1, y); 971 g.setColor(shadow); 972 g.drawLine(x+2, y+h-2, x+w-1, y+h-2); 974 g.setColor(darkShadow); 975 g.drawLine(x+2, y+h-1, x+w-1, y+h-1); break; 977 case RIGHT: 978 g.drawLine(x, y, x+w-3, y); 980 g.setColor(shadow); 981 g.drawLine(x, y+h-2, x+w-3, y+h-2); g.drawLine(x+w-2, y+2, x+w-2, y+h-3); 984 g.setColor(darkShadow); 985 g.drawLine(x+w-2, y+1, x+w-2, y+1); g.drawLine(x+w-2, y+h-2, x+w-2, y+h-2); g.drawLine(x+w-1, y+2, x+w-1, y+h-3); g.drawLine(x, y+h-1, x+w-3, y+h-1); break; 990 case BOTTOM: 991 g.drawLine(x, y, x, y+h-3); g.drawLine(x+1, y+h-2, x+1, y+h-2); 994 g.setColor(shadow); 995 g.drawLine(x+2, y+h-2, x+w-3, y+h-2); g.drawLine(x+w-2, y, x+w-2, y+h-3); 998 g.setColor(darkShadow); 999 g.drawLine(x+2, y+h-1, x+w-3, y+h-1); g.drawLine(x+w-2, y+h-2, x+w-2, y+h-2); g.drawLine(x+w-1, y, x+w-1, y+h-3); break; 1003 case TOP: 1004 default: 1005 g.drawLine(x, y+2, x, y+h-1); g.drawLine(x+1, y+1, x+1, y+1); g.drawLine(x+2, y, x+w-3, y); 1009 g.setColor(shadow); 1010 g.drawLine(x+w-2, y+2, x+w-2, y+h-1); 1012 g.setColor(darkShadow); 1013 g.drawLine(x+w-1, y+2, x+w-1, y+h-1); g.drawLine(x+w-2, y+1, x+w-2, y+1); } 1016 } 1017 1018 protected void paintTabBackground(Graphics g, int tabPlacement, 1019 int tabIndex, 1020 int x, int y, int w, int h, 1021 boolean isSelected ) { 1022 g.setColor(!isSelected || selectedColor == null? 1023 tabPane.getBackgroundAt(tabIndex) : selectedColor); 1024 switch(tabPlacement) { 1025 case LEFT: 1026 g.fillRect(x+1, y+1, w-1, h-3); 1027 break; 1028 case RIGHT: 1029 g.fillRect(x, y+1, w-2, h-3); 1030 break; 1031 case BOTTOM: 1032 g.fillRect(x+1, y, w-3, h-1); 1033 break; 1034 case TOP: 1035 default: 1036 g.fillRect(x+1, y+1, w-3, h-1); 1037 } 1038 } 1039 1040 protected void paintContentBorder(Graphics g, int tabPlacement, int selectedIndex) { 1041 int width = tabPane.getWidth(); 1042 int height = tabPane.getHeight(); 1043 Insets insets = tabPane.getInsets(); 1044 Insets tabAreaInsets = getTabAreaInsets(tabPlacement); 1045 1046 int x = insets.left; 1047 int y = insets.top; 1048 int w = width - insets.right - insets.left; 1049 int h = height - insets.top - insets.bottom; 1050 1051 switch(tabPlacement) { 1052 case LEFT: 1053 x += calculateTabAreaWidth(tabPlacement, runCount, maxTabWidth); 1054 if (tabsOverlapBorder) { 1055 x -= tabAreaInsets.right; 1056 } 1057 w -= (x - insets.left); 1058 break; 1059 case RIGHT: 1060 w -= calculateTabAreaWidth(tabPlacement, runCount, maxTabWidth); 1061 if (tabsOverlapBorder) { 1062 w += tabAreaInsets.left; 1063 } 1064 break; 1065 case BOTTOM: 1066 h -= calculateTabAreaHeight(tabPlacement, runCount, maxTabHeight); 1067 if (tabsOverlapBorder) { 1068 h += tabAreaInsets.top; 1069 } 1070 break; 1071 case TOP: 1072 default: 1073 y += calculateTabAreaHeight(tabPlacement, runCount, maxTabHeight); 1074 if (tabsOverlapBorder) { 1075 y -= tabAreaInsets.bottom; 1076 } 1077 h -= (y - insets.top); 1078 } 1079 1080 if (contentOpaque || tabPane.isOpaque()) { 1081 Color color = UIManager.getColor("TabbedPane.contentAreaColor"); 1083 if (color != null) { 1084 g.setColor(color); 1085 } 1086 else if (selectedColor == null) { 1087 g.setColor(tabPane.getBackground()); 1088 } 1089 else { 1090 g.setColor(selectedColor); 1091 } 1092 g.fillRect(x,y,w,h); 1093 } 1094 1095 paintContentBorderTopEdge(g, tabPlacement, selectedIndex, x, y, w, h); 1096 paintContentBorderLeftEdge(g, tabPlacement, selectedIndex, x, y, w, h); 1097 paintContentBorderBottomEdge(g, tabPlacement, selectedIndex, x, y, w, h); 1098 paintContentBorderRightEdge(g, tabPlacement, selectedIndex, x, y, w, h); 1099 1100 } 1101 1102 protected void paintContentBorderTopEdge(Graphics g, int tabPlacement, 1103 int selectedIndex, 1104 int x, int y, int w, int h) { 1105 Rectangle selRect = selectedIndex < 0? null : 1106 getTabBounds(selectedIndex, calcRect); 1107 1108 g.setColor(lightHighlight); 1109 1110 if (tabPlacement != TOP || selectedIndex < 0 || 1115 (selRect.y + selRect.height + 1 < y) || 1116 (selRect.x < x || selRect.x > x + w)) { 1117 g.drawLine(x, y, x+w-2, y); 1118 } else { 1119 g.drawLine(x, y, selRect.x - 1, y); 1121 if (selRect.x + selRect.width < x + w - 2) { 1122 g.drawLine(selRect.x + selRect.width, y, 1123 x+w-2, y); 1124 } else { 1125 g.setColor(shadow); 1126 g.drawLine(x+w-2, y, x+w-2, y); 1127 } 1128 } 1129 } 1130 1131 protected void paintContentBorderLeftEdge(Graphics g, int tabPlacement, 1132 int selectedIndex, 1133 int x, int y, int w, int h) { 1134 Rectangle selRect = selectedIndex < 0? null : 1135 getTabBounds(selectedIndex, calcRect); 1136 1137 g.setColor(lightHighlight); 1138 1139 if (tabPlacement != LEFT || selectedIndex < 0 || 1144 (selRect.x + selRect.width + 1 < x) || 1145 (selRect.y < y || selRect.y > y + h)) { 1146 g.drawLine(x, y, x, y+h-2); 1147 } else { 1148 g.drawLine(x, y, x, selRect.y - 1); 1150 if (selRect.y + selRect.height < y + h - 2) { 1151 g.drawLine(x, selRect.y + selRect.height, 1152 x, y+h-2); 1153 } 1154 } 1155 } 1156 1157 protected void paintContentBorderBottomEdge(Graphics g, int tabPlacement, 1158 int selectedIndex, 1159 int x, int y, int w, int h) { 1160 Rectangle selRect = selectedIndex < 0? null : 1161 getTabBounds(selectedIndex, calcRect); 1162 1163 g.setColor(shadow); 1164 1165 if (tabPlacement != BOTTOM || selectedIndex < 0 || 1170 (selRect.y - 1 > h) || 1171 (selRect.x < x || selRect.x > x + w)) { 1172 g.drawLine(x+1, y+h-2, x+w-2, y+h-2); 1173 g.setColor(darkShadow); 1174 g.drawLine(x, y+h-1, x+w-1, y+h-1); 1175 } else { 1176 g.drawLine(x+1, y+h-2, selRect.x - 1, y+h-2); 1178 g.setColor(darkShadow); 1179 g.drawLine(x, y+h-1, selRect.x - 1, y+h-1); 1180 if (selRect.x + selRect.width < x + w - 2) { 1181 g.setColor(shadow); 1182 g.drawLine(selRect.x + selRect.width, y+h-2, x+w-2, y+h-2); 1183 g.setColor(darkShadow); 1184 g.drawLine(selRect.x + selRect.width, y+h-1, x+w-1, y+h-1); 1185 } 1186 } 1187 1188 } 1189 1190 protected void paintContentBorderRightEdge(Graphics g, int tabPlacement, 1191 int selectedIndex, 1192 int x, int y, int w, int h) { 1193 Rectangle selRect = selectedIndex < 0? null : 1194 getTabBounds(selectedIndex, calcRect); 1195 1196 g.setColor(shadow); 1197 1198 if (tabPlacement != RIGHT || selectedIndex < 0 || 1203 (selRect.x - 1 > w) || 1204 (selRect.y < y || selRect.y > y + h)) { 1205 g.drawLine(x+w-2, y+1, x+w-2, y+h-3); 1206 g.setColor(darkShadow); 1207 g.drawLine(x+w-1, y, x+w-1, y+h-1); 1208 } else { 1209 g.drawLine(x+w-2, y+1, x+w-2, selRect.y - 1); 1211 g.setColor(darkShadow); 1212 g.drawLine(x+w-1, y, x+w-1, selRect.y - 1); 1213 1214 if (selRect.y + selRect.height < y + h - 2) { 1215 g.setColor(shadow); 1216 g.drawLine(x+w-2, selRect.y + selRect.height, 1217 x+w-2, y+h-2); 1218 g.setColor(darkShadow); 1219 g.drawLine(x+w-1, selRect.y + selRect.height, 1220 x+w-1, y+h-2); 1221 } 1222 } 1223 } 1224 1225 private void ensureCurrentLayout() { 1226 if (!tabPane.isValid()) { 1227 tabPane.validate(); 1228 } 1229 1233 if (!tabPane.isValid()) { 1234 TabbedPaneLayout layout = (TabbedPaneLayout)tabPane.getLayout(); 1235 layout.calculateLayoutInfo(); 1236 } 1237 } 1238 1239 1240 1242 1246 public Rectangle getTabBounds(JTabbedPane pane, int i) { 1247 ensureCurrentLayout(); 1248 Rectangle tabRect = new Rectangle(); 1249 return getTabBounds(i, tabRect); 1250 } 1251 1252 public int getTabRunCount(JTabbedPane pane) { 1253 ensureCurrentLayout(); 1254 return runCount; 1255 } 1256 1257 1261 public int tabForCoordinate(JTabbedPane pane, int x, int y) { 1262 return tabForCoordinate(pane, x, y, true); 1263 } 1264 1265 private int tabForCoordinate(JTabbedPane pane, int x, int y, 1266 boolean validateIfNecessary) { 1267 if (validateIfNecessary) { 1268 ensureCurrentLayout(); 1269 } 1270 if (isRunsDirty) { 1271 return -1; 1274 } 1275 Point p = new Point(x, y); 1276 1277 if (scrollableTabLayoutEnabled()) { 1278 translatePointToTabPanel(x, y, p); 1279 Rectangle viewRect = tabScroller.viewport.getViewRect(); 1280 if (!viewRect.contains(p)) { 1281 return -1; 1282 } 1283 } 1284 int tabCount = tabPane.getTabCount(); 1285 for (int i = 0; i < tabCount; i++) { 1286 if (rects[i].contains(p.x, p.y)) { 1287 return i; 1288 } 1289 } 1290 return -1; 1291 } 1292 1293 1313 protected Rectangle getTabBounds(int tabIndex, Rectangle dest) { 1314 dest.width = rects[tabIndex].width; 1315 dest.height = rects[tabIndex].height; 1316 1317 if (scrollableTabLayoutEnabled()) { Point vpp = tabScroller.viewport.getLocation(); 1321 Point viewp = tabScroller.viewport.getViewPosition(); 1322 dest.x = rects[tabIndex].x + vpp.x - viewp.x; 1323 dest.y = rects[tabIndex].y + vpp.y - viewp.y; 1324 1325 } else { dest.x = rects[tabIndex].x; 1327 dest.y = rects[tabIndex].y; 1328 } 1329 return dest; 1330 } 1331 1332 1336 private int getClosestTab(int x, int y) { 1337 int min = 0; 1338 int tabCount = Math.min(rects.length, tabPane.getTabCount()); 1339 int max = tabCount; 1340 int tabPlacement = tabPane.getTabPlacement(); 1341 boolean useX = (tabPlacement == TOP || tabPlacement == BOTTOM); 1342 int want = (useX) ? x : y; 1343 1344 while (min != max) { 1345 int current = (max + min) / 2; 1346 int minLoc; 1347 int maxLoc; 1348 1349 if (useX) { 1350 minLoc = rects[current].x; 1351 maxLoc = minLoc + rects[current].width; 1352 } 1353 else { 1354 minLoc = rects[current].y; 1355 maxLoc = minLoc + rects[current].height; 1356 } 1357 if (want < minLoc) { 1358 max = current; 1359 if (min == max) { 1360 return Math.max(0, current - 1); 1361 } 1362 } 1363 else if (want >= maxLoc) { 1364 min = current; 1365 if (max - min <= 1) { 1366 return Math.max(current + 1, tabCount - 1); 1367 } 1368 } 1369 else { 1370 return current; 1371 } 1372 } 1373 return min; 1374 } 1375 1376 1381 private Point translatePointToTabPanel(int srcx, int srcy, Point dest) { 1382 Point vpp = tabScroller.viewport.getLocation(); 1383 Point viewp = tabScroller.viewport.getViewPosition(); 1384 dest.x = srcx - vpp.x + viewp.x; 1385 dest.y = srcy - vpp.y + viewp.y; 1386 return dest; 1387 } 1388 1389 1391 protected Component getVisibleComponent() { 1392 return visibleComponent; 1393 } 1394 1395 protected void setVisibleComponent(Component component) { 1396 if (visibleComponent != null && visibleComponent != component && 1397 visibleComponent.getParent() == tabPane) { 1398 visibleComponent.setVisible(false); 1399 } 1400 if (component != null && !component.isVisible()) { 1401 component.setVisible(true); 1402 } 1403 visibleComponent = component; 1404 } 1405 1406 protected void assureRectsCreated(int tabCount) { 1407 int rectArrayLen = rects.length; 1408 if (tabCount != rectArrayLen ) { 1409 Rectangle[] tempRectArray = new Rectangle[tabCount]; 1410 System.arraycopy(rects, 0, tempRectArray, 0, 1411 Math.min(rectArrayLen, tabCount)); 1412 rects = tempRectArray; 1413 for (int rectIndex = rectArrayLen; rectIndex < tabCount; rectIndex++) { 1414 rects[rectIndex] = new Rectangle(); 1415 } 1416 } 1417 1418 } 1419 1420 protected void expandTabRunsArray() { 1421 int rectLen = tabRuns.length; 1422 int[] newArray = new int[rectLen+10]; 1423 System.arraycopy(tabRuns, 0, newArray, 0, runCount); 1424 tabRuns = newArray; 1425 } 1426 1427 protected int getRunForTab(int tabCount, int tabIndex) { 1428 for (int i = 0; i < runCount; i++) { 1429 int first = tabRuns[i]; 1430 int last = lastTabInRun(tabCount, i); 1431 if (tabIndex >= first && tabIndex <= last) { 1432 return i; 1433 } 1434 } 1435 return 0; 1436 } 1437 1438 protected int lastTabInRun(int tabCount, int run) { 1439 if (runCount == 1) { 1440 return tabCount - 1; 1441 } 1442 int nextRun = (run == runCount - 1? 0 : run + 1); 1443 if (tabRuns[nextRun] == 0) { 1444 return tabCount - 1; 1445 } 1446 return tabRuns[nextRun]-1; 1447 } 1448 1449 protected int getTabRunOverlay(int tabPlacement) { 1450 return tabRunOverlay; 1451 } 1452 1453 protected int getTabRunIndent(int tabPlacement, int run) { 1454 return 0; 1455 } 1456 1457 protected boolean shouldPadTabRun(int tabPlacement, int run) { 1458 return runCount > 1; 1459 } 1460 1461 protected boolean shouldRotateTabRuns(int tabPlacement) { 1462 return true; 1463 } 1464 1465 protected Icon getIconForTab(int tabIndex) { 1466 return (!tabPane.isEnabled() || !tabPane.isEnabledAt(tabIndex))? 1467 tabPane.getDisabledIconAt(tabIndex) : tabPane.getIconAt(tabIndex); 1468 } 1469 1470 1481 protected View getTextViewForTab(int tabIndex) { 1482 if (htmlViews != null) { 1483 return (View )htmlViews.elementAt(tabIndex); 1484 } 1485 return null; 1486 } 1487 1488 protected int calculateTabHeight(int tabPlacement, int tabIndex, int fontHeight) { 1489 int height = 0; 1490 View v = getTextViewForTab(tabIndex); 1491 if (v != null) { 1492 height += (int)v.getPreferredSpan(View.Y_AXIS); 1494 } else { 1495 height += fontHeight; 1497 } 1498 Icon icon = getIconForTab(tabIndex); 1499 Insets tabInsets = getTabInsets(tabPlacement, tabIndex); 1500 1501 if (icon != null) { 1502 height = Math.max(height, icon.getIconHeight()); 1503 } 1504 height += tabInsets.top + tabInsets.bottom + 2; 1505 1506 return height; 1507 } 1508 1509 protected int calculateMaxTabHeight(int tabPlacement) { 1510 FontMetrics metrics = getFontMetrics(); 1511 int tabCount = tabPane.getTabCount(); 1512 int result = 0; 1513 int fontHeight = metrics.getHeight(); 1514 for(int i = 0; i < tabCount; i++) { 1515 result = Math.max(calculateTabHeight(tabPlacement, i, fontHeight), result); 1516 } 1517 return result; 1518 } 1519 1520 protected int calculateTabWidth(int tabPlacement, int tabIndex, FontMetrics metrics) { 1521 Icon icon = getIconForTab(tabIndex); 1522 Insets tabInsets = getTabInsets(tabPlacement, tabIndex); 1523 int width = tabInsets.left + tabInsets.right + 3; 1524 1525 if (icon != null) { 1526 width += icon.getIconWidth() + textIconGap; 1527 } 1528 View v = getTextViewForTab(tabIndex); 1529 if (v != null) { 1530 width += (int)v.getPreferredSpan(View.X_AXIS); 1532 } else { 1533 String title = tabPane.getTitleAt(tabIndex); 1535 width += SwingUtilities2.stringWidth(tabPane, metrics, title); 1536 } 1537 1538 return width; 1539 } 1540 1541 protected int calculateMaxTabWidth(int tabPlacement) { 1542 FontMetrics metrics = getFontMetrics(); 1543 int tabCount = tabPane.getTabCount(); 1544 int result = 0; 1545 for(int i = 0; i < tabCount; i++) { 1546 result = Math.max(calculateTabWidth(tabPlacement, i, metrics), result); 1547 } 1548 return result; 1549 } 1550 1551 protected int calculateTabAreaHeight(int tabPlacement, int horizRunCount, int maxTabHeight) { 1552 Insets tabAreaInsets = getTabAreaInsets(tabPlacement); 1553 int tabRunOverlay = getTabRunOverlay(tabPlacement); 1554 return (horizRunCount > 0? 1555 horizRunCount * (maxTabHeight-tabRunOverlay) + tabRunOverlay + 1556 tabAreaInsets.top + tabAreaInsets.bottom : 1557 0); 1558 } 1559 1560 protected int calculateTabAreaWidth(int tabPlacement, int vertRunCount, int maxTabWidth) { 1561 Insets tabAreaInsets = getTabAreaInsets(tabPlacement); 1562 int tabRunOverlay = getTabRunOverlay(tabPlacement); 1563 return (vertRunCount > 0? 1564 vertRunCount * (maxTabWidth-tabRunOverlay) + tabRunOverlay + 1565 tabAreaInsets.left + tabAreaInsets.right : 1566 0); 1567 } 1568 1569 protected Insets getTabInsets(int tabPlacement, int tabIndex) { 1570 return tabInsets; 1571 } 1572 1573 protected Insets getSelectedTabPadInsets(int tabPlacement) { 1574 rotateInsets(selectedTabPadInsets, currentPadInsets, tabPlacement); 1575 return currentPadInsets; 1576 } 1577 1578 protected Insets getTabAreaInsets(int tabPlacement) { 1579 rotateInsets(tabAreaInsets, currentTabAreaInsets, tabPlacement); 1580 return currentTabAreaInsets; 1581 } 1582 1583 protected Insets getContentBorderInsets(int tabPlacement) { 1584 return contentBorderInsets; 1585 } 1586 1587 protected FontMetrics getFontMetrics() { 1588 Font font = tabPane.getFont(); 1589 return tabPane.getFontMetrics(font); 1590 } 1591 1592 1593 1595 protected void navigateSelectedTab(int direction) { 1596 int tabPlacement = tabPane.getTabPlacement(); 1597 int current = DefaultLookup.getBoolean(tabPane, this, 1598 "TabbedPane.selectionFollowsFocus", true) ? 1599 tabPane.getSelectedIndex() : getFocusIndex(); 1600 int tabCount = tabPane.getTabCount(); 1601 boolean leftToRight = BasicGraphicsUtils.isLeftToRight(tabPane); 1602 1603 if (tabCount <= 0) { 1605 return; 1606 } 1607 1608 int offset; 1609 switch(tabPlacement) { 1610 case LEFT: 1611 case RIGHT: 1612 switch(direction) { 1613 case NEXT: 1614 selectNextTab(current); 1615 break; 1616 case PREVIOUS: 1617 selectPreviousTab(current); 1618 break; 1619 case NORTH: 1620 selectPreviousTabInRun(current); 1621 break; 1622 case SOUTH: 1623 selectNextTabInRun(current); 1624 break; 1625 case WEST: 1626 offset = getTabRunOffset(tabPlacement, tabCount, current, false); 1627 selectAdjacentRunTab(tabPlacement, current, offset); 1628 break; 1629 case EAST: 1630 offset = getTabRunOffset(tabPlacement, tabCount, current, true); 1631 selectAdjacentRunTab(tabPlacement, current, offset); 1632 break; 1633 default: 1634 } 1635 break; 1636 case BOTTOM: 1637 case TOP: 1638 default: 1639 switch(direction) { 1640 case NEXT: 1641 selectNextTab(current); 1642 break; 1643 case PREVIOUS: 1644 selectPreviousTab(current); 1645 break; 1646 case NORTH: 1647 offset = getTabRunOffset(tabPlacement, tabCount, current, false); 1648 selectAdjacentRunTab(tabPlacement, current, offset); 1649 break; 1650 case SOUTH: 1651 offset = getTabRunOffset(tabPlacement, tabCount, current, true); 1652 selectAdjacentRunTab(tabPlacement, current, offset); 1653 break; 1654 case EAST: 1655 if (leftToRight) { 1656 selectNextTabInRun(current); 1657 } else { 1658 selectPreviousTabInRun(current); 1659 } 1660 break; 1661 case WEST: 1662 if (leftToRight) { 1663 selectPreviousTabInRun(current); 1664 } else { 1665 selectNextTabInRun(current); 1666 } 1667 break; 1668 default: 1669 } 1670 } 1671 } 1672 1673 protected void selectNextTabInRun(int current) { 1674 int tabCount = tabPane.getTabCount(); 1675 int tabIndex = getNextTabIndexInRun(tabCount, current); 1676 1677 while(tabIndex != current && !tabPane.isEnabledAt(tabIndex)) { 1678 tabIndex = getNextTabIndexInRun(tabCount, tabIndex); 1679 } 1680 navigateTo(tabIndex); 1681 } 1682 1683 protected void selectPreviousTabInRun(int current) { 1684 int tabCount = tabPane.getTabCount(); 1685 int tabIndex = getPreviousTabIndexInRun(tabCount, current); 1686 1687 while(tabIndex != current && !tabPane.isEnabledAt(tabIndex)) { 1688 tabIndex = getPreviousTabIndexInRun(tabCount, tabIndex); 1689 } 1690 navigateTo(tabIndex); 1691 } 1692 1693 protected void selectNextTab(int current) { 1694 int tabIndex = getNextTabIndex(current); 1695 1696 while (tabIndex != current && !tabPane.isEnabledAt(tabIndex)) { 1697 tabIndex = getNextTabIndex(tabIndex); 1698 } 1699 navigateTo(tabIndex); 1700 } 1701 1702 protected void selectPreviousTab(int current) { 1703 int tabIndex = getPreviousTabIndex(current); 1704 1705 while (tabIndex != current && !tabPane.isEnabledAt(tabIndex)) { 1706 tabIndex = getPreviousTabIndex(tabIndex); 1707 } 1708 navigateTo(tabIndex); 1709 } 1710 1711 protected void selectAdjacentRunTab(int tabPlacement, 1712 int tabIndex, int offset) { 1713 if ( runCount < 2 ) { 1714 return; 1715 } 1716 int newIndex; 1717 Rectangle r = rects[tabIndex]; 1718 switch(tabPlacement) { 1719 case LEFT: 1720 case RIGHT: 1721 newIndex = tabForCoordinate(tabPane, r.x + r.width/2 + offset, 1722 r.y + r.height/2); 1723 break; 1724 case BOTTOM: 1725 case TOP: 1726 default: 1727 newIndex = tabForCoordinate(tabPane, r.x + r.width/2, 1728 r.y + r.height/2 + offset); 1729 } 1730 if (newIndex != -1) { 1731 while (!tabPane.isEnabledAt(newIndex) && newIndex != tabIndex) { 1732 newIndex = getNextTabIndex(newIndex); 1733 } 1734 navigateTo(newIndex); 1735 } 1736 } 1737 1738 private void navigateTo(int index) { 1739 if (DefaultLookup.getBoolean(tabPane, this, 1740 "TabbedPane.selectionFollowsFocus", true)) { 1741 tabPane.setSelectedIndex(index); 1742 } else { 1743 setFocusIndex(index, true); 1745 } 1746 } 1747 1748 void setFocusIndex(int index, boolean repaint) { 1749 if (repaint && !isRunsDirty) { 1750 repaintTab(focusIndex); 1751 focusIndex = index; 1752 repaintTab(focusIndex); 1753 } 1754 else { 1755 focusIndex = index; 1756 } 1757 } 1758 1759 1762 private void repaintTab(int index) { 1763 if (!isRunsDirty && index >= 0 && index < tabPane.getTabCount()) { 1766 tabPane.repaint(getTabBounds(tabPane, index)); 1767 } 1768 } 1769 1770 1773 private void validateFocusIndex() { 1774 if (focusIndex >= tabPane.getTabCount()) { 1775 setFocusIndex(tabPane.getSelectedIndex(), false); 1776 } 1777 } 1778 1779 1785 protected int getFocusIndex() { 1786 return focusIndex; 1787 } 1788 1789 protected int getTabRunOffset(int tabPlacement, int tabCount, 1790 int tabIndex, boolean forward) { 1791 int run = getRunForTab(tabCount, tabIndex); 1792 int offset; 1793 switch(tabPlacement) { 1794 case LEFT: { 1795 if (run == 0) { 1796 offset = (forward? 1797 -(calculateTabAreaWidth(tabPlacement, runCount, maxTabWidth)-maxTabWidth) : 1798 -maxTabWidth); 1799 1800 } else if (run == runCount - 1) { 1801 offset = (forward? 1802 maxTabWidth : 1803 calculateTabAreaWidth(tabPlacement, runCount, maxTabWidth)-maxTabWidth); 1804 } else { 1805 offset = (forward? maxTabWidth : -maxTabWidth); 1806 } 1807 break; 1808 } 1809 case RIGHT: { 1810 if (run == 0) { 1811 offset = (forward? 1812 maxTabWidth : 1813 calculateTabAreaWidth(tabPlacement, runCount, maxTabWidth)-maxTabWidth); 1814 } else if (run == runCount - 1) { 1815 offset = (forward? 1816 -(calculateTabAreaWidth(tabPlacement, runCount, maxTabWidth)-maxTabWidth) : 1817 -maxTabWidth); 1818 } else { 1819 offset = (forward? maxTabWidth : -maxTabWidth); 1820 } 1821 break; 1822 } 1823 case BOTTOM: { 1824 if (run == 0) { 1825 offset = (forward? 1826 maxTabHeight : 1827 calculateTabAreaHeight(tabPlacement, runCount, maxTabHeight)-maxTabHeight); 1828 } else if (run == runCount - 1) { 1829 offset = (forward? 1830 -(calculateTabAreaHeight(tabPlacement, runCount, maxTabHeight)-maxTabHeight) : 1831 -maxTabHeight); 1832 } else { 1833 offset = (forward? maxTabHeight : -maxTabHeight); 1834 } 1835 break; 1836 } 1837 case TOP: 1838 default: { 1839 if (run == 0) { 1840 offset = (forward? 1841 -(calculateTabAreaHeight(tabPlacement, runCount, maxTabHeight)-maxTabHeight) : 1842 -maxTabHeight); 1843 } else if (run == runCount - 1) { 1844 offset = (forward? 1845 maxTabHeight : 1846 calculateTabAreaHeight(tabPlacement, runCount, maxTabHeight)-maxTabHeight); 1847 } else { 1848 offset = (forward? maxTabHeight : -maxTabHeight); 1849 } 1850 } 1851 } 1852 return offset; 1853 } 1854 1855 protected int getPreviousTabIndex(int base) { 1856 int tabIndex = (base - 1 >= 0? base - 1 : tabPane.getTabCount() - 1); 1857 return (tabIndex >= 0? tabIndex : 0); 1858 } 1859 1860 protected int getNextTabIndex(int base) { 1861 return (base+1)%tabPane.getTabCount(); 1862 } 1863 1864 protected int getNextTabIndexInRun(int tabCount, int base) { 1865 if (runCount < 2) { 1866 return getNextTabIndex(base); 1867 } 1868 int currentRun = getRunForTab(tabCount, base); 1869 int next = getNextTabIndex(base); 1870 if (next == tabRuns[getNextTabRun(currentRun)]) { 1871 return tabRuns[currentRun]; 1872 } 1873 return next; 1874 } 1875 1876 protected int getPreviousTabIndexInRun(int tabCount, int base) { 1877 if (runCount < 2) { 1878 return getPreviousTabIndex(base); 1879 } 1880 int currentRun = getRunForTab(tabCount, base); 1881 if (base == tabRuns[currentRun]) { 1882 int previous = tabRuns[getNextTabRun(currentRun)]-1; 1883 return (previous != -1? previous : tabCount-1); 1884 } 1885 return getPreviousTabIndex(base); 1886 } 1887 1888 protected int getPreviousTabRun(int baseRun) { 1889 int runIndex = (baseRun - 1 >= 0? baseRun - 1 : runCount - 1); 1890 return (runIndex >= 0? runIndex : 0); 1891 } 1892 1893 protected int getNextTabRun(int baseRun) { 1894 return (baseRun+1)%runCount; 1895 } 1896 1897 protected static void rotateInsets(Insets topInsets, Insets targetInsets, int targetPlacement) { 1898 1899 switch(targetPlacement) { 1900 case LEFT: 1901 targetInsets.top = topInsets.left; 1902 targetInsets.left = topInsets.top; 1903 targetInsets.bottom = topInsets.right; 1904 targetInsets.right = topInsets.bottom; 1905 break; 1906 case BOTTOM: 1907 targetInsets.top = topInsets.bottom; 1908 targetInsets.left = topInsets.left; 1909 targetInsets.bottom = topInsets.top; 1910 targetInsets.right = topInsets.right; 1911 break; 1912 case RIGHT: 1913 targetInsets.top = topInsets.left; 1914 targetInsets.left = topInsets.bottom; 1915 targetInsets.bottom = topInsets.right; 1916 targetInsets.right = topInsets.top; 1917 break; 1918 case TOP: 1919 default: 1920 targetInsets.top = topInsets.top; 1921 targetInsets.left = topInsets.left; 1922 targetInsets.bottom = topInsets.bottom; 1923 targetInsets.right = topInsets.right; 1924 } 1925 } 1926 1927 boolean requestFocusForVisibleComponent() { 1932 Component visibleComponent = getVisibleComponent(); 1933 if (visibleComponent != null && visibleComponent.isFocusTraversable()) { 1934 BasicLookAndFeel.compositeRequestFocus(visibleComponent); 1935 return true; 1936 } else if (visibleComponent instanceof JComponent) { 1937 if (((JComponent)visibleComponent).requestDefaultFocus()) { 1938 return true; 1939 } 1940 } 1941 return false; 1942 } 1943 1944 private static class Actions extends UIAction { 1945 final static String NEXT = "navigateNext"; 1946 final static String PREVIOUS = "navigatePrevious"; 1947 final static String RIGHT = "navigateRight"; 1948 final static String LEFT = "navigateLeft"; 1949 final static String UP = "navigateUp"; 1950 final static String DOWN = "navigateDown"; 1951 final static String PAGE_UP = "navigatePageUp"; 1952 final static String PAGE_DOWN = "navigatePageDown"; 1953 final static String REQUEST_FOCUS = "requestFocus"; 1954 final static String REQUEST_FOCUS_FOR_VISIBLE = 1955 "requestFocusForVisibleComponent"; 1956 final static String SET_SELECTED = "setSelectedIndex"; 1957 final static String SELECT_FOCUSED = "selectTabWithFocus"; 1958 final static String SCROLL_FORWARD = "scrollTabsForwardAction"; 1959 final static String SCROLL_BACKWARD = "scrollTabsBackwardAction"; 1960 1961 Actions(String key) { 1962 super(key); 1963 } 1964 1965 public void actionPerformed(ActionEvent e) { 1966 String key = getName(); 1967 JTabbedPane pane = (JTabbedPane)e.getSource(); 1968 BasicTabbedPaneUI ui = (BasicTabbedPaneUI )BasicLookAndFeel. 1969 getUIOfType(pane.getUI(), BasicTabbedPaneUI .class); 1970 1971 if (ui == null) { 1972 return; 1973 } 1974 if (key == NEXT) { 1975 ui.navigateSelectedTab(SwingConstants.NEXT); 1976 } 1977 else if (key == PREVIOUS) { 1978 ui.navigateSelectedTab(SwingConstants.PREVIOUS); 1979 } 1980 else if (key == RIGHT) { 1981 ui.navigateSelectedTab(SwingConstants.EAST); 1982 } 1983 else if (key == LEFT) { 1984 ui.navigateSelectedTab(SwingConstants.WEST); 1985 } 1986 else if (key == UP) { 1987 ui.navigateSelectedTab(SwingConstants.NORTH); 1988 } 1989 else if (key == DOWN) { 1990 ui.navigateSelectedTab(SwingConstants.SOUTH); 1991 } 1992 else if (key == PAGE_UP) { 1993 int tabPlacement = pane.getTabPlacement(); 1994 if (tabPlacement == TOP|| tabPlacement == BOTTOM) { 1995 ui.navigateSelectedTab(SwingConstants.WEST); 1996 } else { 1997 ui.navigateSelectedTab(SwingConstants.NORTH); 1998 } 1999 } 2000 else if (key == PAGE_DOWN) { 2001 int tabPlacement = pane.getTabPlacement(); 2002 if (tabPlacement == TOP || tabPlacement == BOTTOM) { 2003 ui.navigateSelectedTab(SwingConstants.EAST); 2004 } else { 2005 ui.navigateSelectedTab(SwingConstants.SOUTH); 2006 } 2007 } 2008 else if (key == REQUEST_FOCUS) { 2009 pane.requestFocus(); 2010 } 2011 else if (key == REQUEST_FOCUS_FOR_VISIBLE) { 2012 ui.requestFocusForVisibleComponent(); 2013 } 2014 else if (key == SET_SELECTED) { 2015 String command = e.getActionCommand(); 2016 2017 if (command != null && command.length() > 0) { 2018 int mnemonic = (int)e.getActionCommand().charAt(0); 2019 if (mnemonic >= 'a' && mnemonic <='z') { 2020 mnemonic -= ('a' - 'A'); 2021 } 2022 Integer index = (Integer )ui.mnemonicToIndexMap. 2023 get(new Integer (mnemonic)); 2024 if (index != null && pane.isEnabledAt(index.intValue())) { 2025 pane.setSelectedIndex(index.intValue()); 2026 } 2027 } 2028 } 2029 else if (key == SELECT_FOCUSED) { 2030 int focusIndex = ui.getFocusIndex(); 2031 if (focusIndex != -1) { 2032 pane.setSelectedIndex(focusIndex); 2033 } 2034 } 2035 else if (key == SCROLL_FORWARD) { 2036 if (ui.scrollableTabLayoutEnabled()) { 2037 ui.tabScroller.scrollForward(pane.getTabPlacement()); 2038 } 2039 } 2040 else if (key == SCROLL_BACKWARD) { 2041 if (ui.scrollableTabLayoutEnabled()) { 2042 ui.tabScroller.scrollBackward(pane.getTabPlacement()); 2043 } 2044 } 2045 } 2046 } 2047 2048 2052 public class TabbedPaneLayout implements LayoutManager { 2053 2054 public void addLayoutComponent(String name, Component comp) {} 2055 2056 public void removeLayoutComponent(Component comp) {} 2057 2058 public Dimension preferredLayoutSize(Container parent) { 2059 return calculateSize(false); 2060 } 2061 2062 public Dimension minimumLayoutSize(Container parent) { 2063 return calculateSize(true); 2064 } 2065 2066 protected Dimension calculateSize(boolean minimum) { 2067 int tabPlacement = tabPane.getTabPlacement(); 2068 Insets insets = tabPane.getInsets(); 2069 Insets contentInsets = getContentBorderInsets(tabPlacement); 2070 Insets tabAreaInsets = getTabAreaInsets(tabPlacement); 2071 2072 Dimension zeroSize = new Dimension(0,0); 2073 int height = 0; 2074 int width = 0; 2075 int cWidth = 0; 2076 int cHeight = 0; 2077 2078 for (int i = 0; i < tabPane.getTabCount(); i++) { 2082 Component component = tabPane.getComponentAt(i); 2083 if (component != null) { 2084 Dimension size = zeroSize; 2085 size = minimum? component.getMinimumSize() : 2086 component.getPreferredSize(); 2087 2088 if (size != null) { 2089 cHeight = Math.max(size.height, cHeight); 2090 cWidth = Math.max(size.width, cWidth); 2091 } 2092 } 2093 } 2094 width += cWidth; 2096 height += cHeight; 2097 int tabExtent = 0; 2098 2099 switch(tabPlacement) { 2103 case LEFT: 2104 case RIGHT: 2105 height = Math.max(height, calculateMaxTabHeight(tabPlacement)); 2106 tabExtent = preferredTabAreaWidth(tabPlacement, height - tabAreaInsets.top - tabAreaInsets.bottom); 2107 width += tabExtent; 2108 break; 2109 case TOP: 2110 case BOTTOM: 2111 default: 2112 width = Math.max(width, calculateMaxTabWidth(tabPlacement)); 2113 tabExtent = preferredTabAreaHeight(tabPlacement, width - tabAreaInsets.left - tabAreaInsets.right); 2114 height += tabExtent; 2115 } 2116 return new Dimension(width + insets.left + insets.right + contentInsets.left + contentInsets.right, 2117 height + insets.bottom + insets.top + contentInsets.top + contentInsets.bottom); 2118 2119 } 2120 2121 protected int preferredTabAreaHeight(int tabPlacement, int width) { 2122 FontMetrics metrics = getFontMetrics(); 2123 int tabCount = tabPane.getTabCount(); 2124 int total = 0; 2125 if (tabCount > 0) { 2126 int rows = 1; 2127 int x = 0; 2128 2129 int maxTabHeight = calculateMaxTabHeight(tabPlacement); 2130 2131 for (int i = 0; i < tabCount; i++) { 2132 int tabWidth = calculateTabWidth(tabPlacement, i, metrics); 2133 2134 if (x != 0 && x + tabWidth > width) { 2135 rows++; 2136 x = 0; 2137 } 2138 x += tabWidth; 2139 } 2140 total = calculateTabAreaHeight(tabPlacement, rows, maxTabHeight); 2141 } 2142 return total; 2143 } 2144 2145 protected int preferredTabAreaWidth(int tabPlacement, int height) { 2146 FontMetrics metrics = getFontMetrics(); 2147 int tabCount = tabPane.getTabCount(); 2148 int total = 0; 2149 if (tabCount > 0) { 2150 int columns = 1; 2151 int y = 0; 2152 int fontHeight = metrics.getHeight(); 2153 2154 maxTabWidth = calculateMaxTabWidth(tabPlacement); 2155 2156 for (int i = 0; i < tabCount; i++) { 2157 int tabHeight = calculateTabHeight(tabPlacement, i, fontHeight); 2158 2159 if (y != 0 && y + tabHeight > height) { 2160 columns++; 2161 y = 0; 2162 } 2163 y += tabHeight; 2164 } 2165 total = calculateTabAreaWidth(tabPlacement, columns, maxTabWidth); 2166 } 2167 return total; 2168 } 2169 2170 public void layoutContainer(Container parent) { 2171 setRolloverTab(-1); 2172 2173 int tabPlacement = tabPane.getTabPlacement(); 2174 Insets insets = tabPane.getInsets(); 2175 int selectedIndex = tabPane.getSelectedIndex(); 2176 Component visibleComponent = getVisibleComponent(); 2177 2178 calculateLayoutInfo(); 2179 2180 if (selectedIndex < 0) { 2181 if (visibleComponent != null) { 2182 setVisibleComponent(null); 2184 } 2185 } else { 2186 int cx, cy, cw, ch; 2187 int totalTabWidth = 0; 2188 int totalTabHeight = 0; 2189 Insets contentInsets = getContentBorderInsets(tabPlacement); 2190 2191 Component selectedComponent = tabPane.getComponentAt(selectedIndex); 2192 boolean shouldChangeFocus = false; 2193 2194 if (selectedComponent != null) { 2202 if (selectedComponent != visibleComponent && 2203 visibleComponent != null) { 2204 if (SwingUtilities.findFocusOwner(visibleComponent) != null) { 2205 shouldChangeFocus = true; 2206 } 2207 } 2208 setVisibleComponent(selectedComponent); 2209 } 2210 2211 Rectangle bounds = tabPane.getBounds(); 2212 int numChildren = tabPane.getComponentCount(); 2213 2214 if (numChildren > 0) { 2215 2216 switch(tabPlacement) { 2217 case LEFT: 2218 totalTabWidth = calculateTabAreaWidth(tabPlacement, runCount, maxTabWidth); 2219 cx = insets.left + totalTabWidth + contentInsets.left; 2220 cy = insets.top + contentInsets.top; 2221 break; 2222 case RIGHT: 2223 totalTabWidth = calculateTabAreaWidth(tabPlacement, runCount, maxTabWidth); 2224 cx = insets.left + contentInsets.left; 2225 cy = insets.top + contentInsets.top; 2226 break; 2227 case BOTTOM: 2228 totalTabHeight = calculateTabAreaHeight(tabPlacement, runCount, maxTabHeight); 2229 cx = insets.left + contentInsets.left; 2230 cy = insets.top + contentInsets.top; 2231 break; 2232 case TOP: 2233 default: 2234 totalTabHeight = calculateTabAreaHeight(tabPlacement, runCount, maxTabHeight); 2235 cx = insets.left + contentInsets.left; 2236 cy = insets.top + totalTabHeight + contentInsets.top; 2237 } 2238 2239 cw = bounds.width - totalTabWidth - 2240 insets.left - insets.right - 2241 contentInsets.left - contentInsets.right; 2242 ch = bounds.height - totalTabHeight - 2243 insets.top - insets.bottom - 2244 contentInsets.top - contentInsets.bottom; 2245 2246 for (int i=0; i < numChildren; i++) { 2247 Component child = tabPane.getComponent(i); 2248 child.setBounds(cx, cy, cw, ch); 2249 } 2250 } 2251 2252 if (shouldChangeFocus) { 2253 if (!requestFocusForVisibleComponent()) { 2254 tabPane.requestFocus(); 2255 } 2256 } 2257 } 2258 } 2259 2260 public void calculateLayoutInfo() { 2261 int tabCount = tabPane.getTabCount(); 2262 assureRectsCreated(tabCount); 2263 calculateTabRects(tabPane.getTabPlacement(), tabCount); 2264 isRunsDirty = false; 2265 } 2266 2267 protected void calculateTabRects(int tabPlacement, int tabCount) { 2268 FontMetrics metrics = getFontMetrics(); 2269 Dimension size = tabPane.getSize(); 2270 Insets insets = tabPane.getInsets(); 2271 Insets tabAreaInsets = getTabAreaInsets(tabPlacement); 2272 int fontHeight = metrics.getHeight(); 2273 int selectedIndex = tabPane.getSelectedIndex(); 2274 int tabRunOverlay; 2275 int i, j; 2276 int x, y; 2277 int returnAt; 2278 boolean verticalTabRuns = (tabPlacement == LEFT || tabPlacement == RIGHT); 2279 boolean leftToRight = BasicGraphicsUtils.isLeftToRight(tabPane); 2280 2281 switch(tabPlacement) { 2285 case LEFT: 2286 maxTabWidth = calculateMaxTabWidth(tabPlacement); 2287 x = insets.left + tabAreaInsets.left; 2288 y = insets.top + tabAreaInsets.top; 2289 returnAt = size.height - (insets.bottom + tabAreaInsets.bottom); 2290 break; 2291 case RIGHT: 2292 maxTabWidth = calculateMaxTabWidth(tabPlacement); 2293 x = size.width - insets.right - tabAreaInsets.right - maxTabWidth; 2294 y = insets.top + tabAreaInsets.top; 2295 returnAt = size.height - (insets.bottom + tabAreaInsets.bottom); 2296 break; 2297 case BOTTOM: 2298 maxTabHeight = calculateMaxTabHeight(tabPlacement); 2299 x = insets.left + tabAreaInsets.left; 2300 y = size.height - insets.bottom - tabAreaInsets.bottom - maxTabHeight; 2301 returnAt = size.width - (insets.right + tabAreaInsets.right); 2302 break; 2303 case TOP: 2304 default: 2305 maxTabHeight = calculateMaxTabHeight(tabPlacement); 2306 x = insets.left + tabAreaInsets.left; 2307 y = insets.top + tabAreaInsets.top; 2308 returnAt = size.width - (insets.right + tabAreaInsets.right); 2309 break; 2310 } 2311 2312 tabRunOverlay = getTabRunOverlay(tabPlacement); 2313 2314 runCount = 0; 2315 selectedRun = -1; 2316 2317 if (tabCount == 0) { 2318 return; 2319 } 2320 2321 Rectangle rect; 2323 for (i = 0; i < tabCount; i++) { 2324 rect = rects[i]; 2325 2326 if (!verticalTabRuns) { 2327 if (i > 0) { 2329 rect.x = rects[i-1].x + rects[i-1].width; 2330 } else { 2331 tabRuns[0] = 0; 2332 runCount = 1; 2333 maxTabWidth = 0; 2334 rect.x = x; 2335 } 2336 rect.width = calculateTabWidth(tabPlacement, i, metrics); 2337 maxTabWidth = Math.max(maxTabWidth, rect.width); 2338 2339 if (rect.x != 2 + insets.left && rect.x + rect.width > returnAt) { 2343 if (runCount > tabRuns.length - 1) { 2344 expandTabRunsArray(); 2345 } 2346 tabRuns[runCount] = i; 2347 runCount++; 2348 rect.x = x; 2349 } 2350 rect.y = y; 2352 rect.height = maxTabHeight; 2353 2354 } else { 2355 if (i > 0) { 2357 rect.y = rects[i-1].y + rects[i-1].height; 2358 } else { 2359 tabRuns[0] = 0; 2360 runCount = 1; 2361 maxTabHeight = 0; 2362 rect.y = y; 2363 } 2364 rect.height = calculateTabHeight(tabPlacement, i, fontHeight); 2365 maxTabHeight = Math.max(maxTabHeight, rect.height); 2366 2367 if (rect.y != 2 + insets.top && rect.y + rect.height > returnAt) { 2371 if (runCount > tabRuns.length - 1) { 2372 expandTabRunsArray(); 2373 } 2374 tabRuns[runCount] = i; 2375 runCount++; 2376 rect.y = y; 2377 } 2378 rect.x = x; 2380 rect.width = maxTabWidth; 2381 2382 } 2383 if (i == selectedIndex) { 2384 selectedRun = runCount - 1; 2385 } 2386 } 2387 2388 if (runCount > 1) { 2389 normalizeTabRuns(tabPlacement, tabCount, verticalTabRuns? y : x, returnAt); 2391 2392 selectedRun = getRunForTab(tabCount, selectedIndex); 2393 2394 if (shouldRotateTabRuns(tabPlacement)) { 2396 rotateTabRuns(tabPlacement, selectedRun); 2397 } 2398 } 2399 2400 for (i = runCount - 1; i >= 0; i--) { 2403 int start = tabRuns[i]; 2404 int next = tabRuns[i == (runCount - 1)? 0 : i + 1]; 2405 int end = (next != 0? next - 1 : tabCount - 1); 2406 if (!verticalTabRuns) { 2407 for (j = start; j <= end; j++) { 2408 rect = rects[j]; 2409 rect.y = y; 2410 rect.x += getTabRunIndent(tabPlacement, i); 2411 } 2412 if (shouldPadTabRun(tabPlacement, i)) { 2413 padTabRun(tabPlacement, start, end, returnAt); 2414 } 2415 if (tabPlacement == BOTTOM) { 2416 y -= (maxTabHeight - tabRunOverlay); 2417 } else { 2418 y += (maxTabHeight - tabRunOverlay); 2419 } 2420 } else { 2421 for (j = start; j <= end; j++) { 2422 rect = rects[j]; 2423 rect.x = x; 2424 rect.y += getTabRunIndent(tabPlacement, i); 2425 } 2426 if (shouldPadTabRun(tabPlacement, i)) { 2427 padTabRun(tabPlacement, start, end, returnAt); 2428 } 2429 if (tabPlacement == RIGHT) { 2430 x -= (maxTabWidth - tabRunOverlay); 2431 } else { 2432 x += (maxTabWidth - tabRunOverlay); 2433 } 2434 } 2435 } 2436 2437 padSelectedTab(tabPlacement, selectedIndex); 2439 2440 if (!leftToRight && !verticalTabRuns) { 2443 int rightMargin = size.width 2444 - (insets.right + tabAreaInsets.right); 2445 for (i = 0; i < tabCount; i++) { 2446 rects[i].x = rightMargin - rects[i].x - rects[i].width; 2447 } 2448 } 2449 } 2450 2451 2452 2455 protected void rotateTabRuns(int tabPlacement, int selectedRun) { 2456 for (int i = 0; i < selectedRun; i++) { 2457 int save = tabRuns[0]; 2458 for (int j = 1; j < runCount; j++) { 2459 tabRuns[j - 1] = tabRuns[j]; 2460 } 2461 tabRuns[runCount-1] = save; 2462 } 2463 } 2464 2465 protected void normalizeTabRuns(int tabPlacement, int tabCount, 2466 int start, int max) { 2467 boolean verticalTabRuns = (tabPlacement == LEFT || tabPlacement == RIGHT); 2468 int run = runCount - 1; 2469 boolean keepAdjusting = true; 2470 double weight = 1.25; 2471 2472 while (keepAdjusting) { 2484 int last = lastTabInRun(tabCount, run); 2485 int prevLast = lastTabInRun(tabCount, run-1); 2486 int end; 2487 int prevLastLen; 2488 2489 if (!verticalTabRuns) { 2490 end = rects[last].x + rects[last].width; 2491 prevLastLen = (int)(maxTabWidth*weight); 2492 } else { 2493 end = rects[last].y + rects[last].height; 2494 prevLastLen = (int)(maxTabHeight*weight*2); 2495 } 2496 2497 if (max - end > prevLastLen) { 2500 2501 tabRuns[run] = prevLast; 2503 if (!verticalTabRuns) { 2504 rects[prevLast].x = start; 2505 } else { 2506 rects[prevLast].y = start; 2507 } 2508 for (int i = prevLast+1; i <= last; i++) { 2509 if (!verticalTabRuns) { 2510 rects[i].x = rects[i-1].x + rects[i-1].width; 2511 } else { 2512 rects[i].y = rects[i-1].y + rects[i-1].height; 2513 } 2514 } 2515 2516 } else if (run == runCount - 1) { 2517 keepAdjusting = false; 2519 } 2520 if (run - 1 > 0) { 2521 run -= 1; 2523 } else { 2524 run = runCount - 1; 2528 weight += .25; 2529 } 2530 } 2531 } 2532 2533 protected void padTabRun(int tabPlacement, int start, int end, int max) { 2534 Rectangle lastRect = rects[end]; 2535 if (tabPlacement == TOP || tabPlacement == BOTTOM) { 2536 int runWidth = (lastRect.x + lastRect.width) - rects[start].x; 2537 int deltaWidth = max - (lastRect.x + lastRect.width); 2538 float factor = (float)deltaWidth / (float)runWidth; 2539 2540 for (int j = start; j <= end; j++) { 2541 Rectangle pastRect = rects[j]; 2542 if (j > start) { 2543 pastRect.x = rects[j-1].x + rects[j-1].width; 2544 } 2545 pastRect.width += Math.round((float)pastRect.width * factor); 2546 } 2547 lastRect.width = max - lastRect.x; 2548 } else { 2549 int runHeight = (lastRect.y + lastRect.height) - rects[start].y; 2550 int deltaHeight = max - (lastRect.y + lastRect.height); 2551 float factor = (float)deltaHeight / (float)runHeight; 2552 2553 for (int j = start; j <= end; j++) { 2554 Rectangle pastRect = rects[j]; 2555 if (j > start) { 2556 pastRect.y = rects[j-1].y + rects[j-1].height; 2557 } 2558 pastRect.height += Math.round((float)pastRect.height * factor); 2559 } 2560 lastRect.height = max - lastRect.y; 2561 } 2562 } 2563 2564 protected void padSelectedTab(int tabPlacement, int selectedIndex) { 2565 2566 if (selectedIndex >= 0) { 2567 Rectangle selRect = rects[selectedIndex]; 2568 Insets padInsets = getSelectedTabPadInsets(tabPlacement); 2569 selRect.x -= padInsets.left; 2570 selRect.width += (padInsets.left + padInsets.right); 2571 selRect.y -= padInsets.top; 2572 selRect.height += (padInsets.top + padInsets.bottom); 2573 } 2574 } 2575 } 2576 2577 private class TabbedPaneScrollLayout extends TabbedPaneLayout { 2578 2579 protected int preferredTabAreaHeight(int tabPlacement, int width) { 2580 return calculateMaxTabHeight(tabPlacement); 2581 } 2582 2583 protected int preferredTabAreaWidth(int tabPlacement, int height) { 2584 return calculateMaxTabWidth(tabPlacement); 2585 } 2586 2587 public void layoutContainer(Container parent) { 2588 setRolloverTab(-1); 2589 2590 int tabPlacement = tabPane.getTabPlacement(); 2591 int tabCount = tabPane.getTabCount(); 2592 Insets insets = tabPane.getInsets(); 2593 int selectedIndex = tabPane.getSelectedIndex(); 2594 Component visibleComponent = getVisibleComponent(); 2595 2596 calculateLayoutInfo(); 2597 2598 if (selectedIndex < 0) { 2599 if (visibleComponent != null) { 2600 setVisibleComponent(null); 2602 } 2603 } else { 2604 Component selectedComponent = tabPane.getComponentAt(selectedIndex); 2605 boolean shouldChangeFocus = false; 2606 2607 if (selectedComponent != null) { 2615 if (selectedComponent != visibleComponent && 2616 visibleComponent != null) { 2617 if (SwingUtilities.findFocusOwner(visibleComponent) != null) { 2618 shouldChangeFocus = true; 2619 } 2620 } 2621 setVisibleComponent(selectedComponent); 2622 } 2623 int tx, ty, tw, th; int cx, cy, cw, ch; Insets contentInsets = getContentBorderInsets(tabPlacement); 2626 Rectangle bounds = tabPane.getBounds(); 2627 int numChildren = tabPane.getComponentCount(); 2628 2629 if (numChildren > 0) { 2630 switch(tabPlacement) { 2631 case LEFT: 2632 tw = calculateTabAreaWidth(tabPlacement, runCount, maxTabWidth); 2634 th = bounds.height - insets.top - insets.bottom; 2635 tx = insets.left; 2636 ty = insets.top; 2637 2638 cx = tx + tw + contentInsets.left; 2640 cy = ty + contentInsets.top; 2641 cw = bounds.width - insets.left - insets.right - tw - 2642 contentInsets.left - contentInsets.right; 2643 ch = bounds.height - insets.top - insets.bottom - 2644 contentInsets.top - contentInsets.bottom; 2645 break; 2646 case RIGHT: 2647 tw = calculateTabAreaWidth(tabPlacement, runCount, maxTabWidth); 2649 th = bounds.height - insets.top - insets.bottom; 2650 tx = bounds.width - insets.right - tw; 2651 ty = insets.top; 2652 2653 cx = insets.left + contentInsets.left; 2655 cy = insets.top + contentInsets.top; 2656 cw = bounds.width - insets.left - insets.right - tw - 2657 contentInsets.left - contentInsets.right; 2658 ch = bounds.height - insets.top - insets.bottom - 2659 contentInsets.top - contentInsets.bottom; 2660 break; 2661 case BOTTOM: 2662 tw = bounds.width - insets.left - insets.right; 2664 th = calculateTabAreaHeight(tabPlacement, runCount, maxTabHeight); 2665 tx = insets.left; 2666 ty = bounds.height - insets.bottom - th; 2667 2668 cx = insets.left + contentInsets.left; 2670 cy = insets.top + contentInsets.top; 2671 cw = bounds.width - insets.left - insets.right - 2672 contentInsets.left - contentInsets.right; 2673 ch = bounds.height - insets.top - insets.bottom - th - 2674 contentInsets.top - contentInsets.bottom; 2675 break; 2676 case TOP: 2677 default: 2678 tw = bounds.width - insets.left - insets.right; 2680 th = calculateTabAreaHeight(tabPlacement, runCount, maxTabHeight); 2681 tx = insets.left; 2682 ty = insets.top; 2683 2684 cx = tx + contentInsets.left; 2686 cy = ty + th + contentInsets.top; 2687 cw = bounds.width - insets.left - insets.right - 2688 contentInsets.left - contentInsets.right; 2689 ch = bounds.height - insets.top - insets.bottom - th - 2690 contentInsets.top - contentInsets.bottom; 2691 } 2692 2693 for (int i=0; i < numChildren; i++) { 2694 Component child = tabPane.getComponent(i); 2695 2696 if (tabScroller != null && child == tabScroller.viewport) { 2697 JViewport viewport = (JViewport)child; 2698 Rectangle viewRect = viewport.getViewRect(); 2699 int vw = tw; 2700 int vh = th; 2701 Dimension butSize = tabScroller.scrollForwardButton.getPreferredSize(); 2702 switch(tabPlacement) { 2703 case LEFT: 2704 case RIGHT: 2705 int totalTabHeight = rects[tabCount-1].y + rects[tabCount-1].height; 2706 if (totalTabHeight > th) { 2707 vh = (th > 2*butSize.height) ? th - 2*butSize.height : 0; 2709 if (totalTabHeight - viewRect.y <= vh) { 2710 vh = totalTabHeight - viewRect.y; 2713 } 2714 } 2715 break; 2716 case BOTTOM: 2717 case TOP: 2718 default: 2719 int totalTabWidth = rects[tabCount-1].x + rects[tabCount-1].width; 2720 if (totalTabWidth > tw) { 2721 vw = (tw > 2*butSize.width) ? tw - 2*butSize.width : 0 ; 2723 if (totalTabWidth - viewRect.x <= vw) { 2724 vw = totalTabWidth - viewRect.x; 2727 } 2728 } 2729 } 2730 child.setBounds(tx, ty, vw, vh); 2731 2732 } else if (tabScroller != null && 2733 (child == tabScroller.scrollForwardButton || 2734 child == tabScroller.scrollBackwardButton)) { 2735 Component scrollbutton = child; 2736 Dimension bsize = scrollbutton.getPreferredSize(); 2737 int bx = 0; 2738 int by = 0; 2739 int bw = bsize.width; 2740 int bh = bsize.height; 2741 boolean visible = false; 2742 2743 switch(tabPlacement) { 2744 case LEFT: 2745 case RIGHT: 2746 int totalTabHeight = rects[tabCount-1].y + rects[tabCount-1].height; 2747 if (totalTabHeight > th) { 2748 visible = true; 2749 bx = (tabPlacement == LEFT? tx + tw - bsize.width : tx); 2750 by = (child == tabScroller.scrollForwardButton)? 2751 bounds.height - insets.bottom - bsize.height : 2752 bounds.height - insets.bottom - 2*bsize.height; 2753 } 2754 break; 2755 2756 case BOTTOM: 2757 case TOP: 2758 default: 2759 int totalTabWidth = rects[tabCount-1].x + rects[tabCount-1].width; 2760 2761 if (totalTabWidth > tw) { 2762 visible = true; 2763 bx = (child == tabScroller.scrollForwardButton)? 2764 bounds.width - insets.left - bsize.width : 2765 bounds.width - insets.left - 2*bsize.width; 2766 by = (tabPlacement == TOP? ty + th - bsize.height : ty); 2767 } 2768 } 2769 child.setVisible(visible); 2770 if (visible) { 2771 child.setBounds(bx, by, bw, bh); 2772 } 2773 2774 } else { 2775 child.setBounds(cx, cy, cw, ch); 2777 } 2778 } 2779 if (shouldChangeFocus) { 2780 if (!requestFocusForVisibleComponent()) { 2781 tabPane.requestFocus(); 2782 } 2783 } 2784 } 2785 } 2786 } 2787 2788 protected void calculateTabRects(int tabPlacement, int tabCount) { 2789 FontMetrics metrics = getFontMetrics(); 2790 Dimension size = tabPane.getSize(); 2791 Insets insets = tabPane.getInsets(); 2792 Insets tabAreaInsets = getTabAreaInsets(tabPlacement); 2793 int fontHeight = metrics.getHeight(); 2794 int selectedIndex = tabPane.getSelectedIndex(); 2795 int i, j; 2796 boolean verticalTabRuns = (tabPlacement == LEFT || tabPlacement == RIGHT); 2797 boolean leftToRight = BasicGraphicsUtils.isLeftToRight(tabPane); 2798 int x = tabAreaInsets.left; 2799 int y = tabAreaInsets.top; 2800 int totalWidth = 0; 2801 int totalHeight = 0; 2802 2803 switch(tabPlacement) { 2807 case LEFT: 2808 case RIGHT: 2809 maxTabWidth = calculateMaxTabWidth(tabPlacement); 2810 break; 2811 case BOTTOM: 2812 case TOP: 2813 default: 2814 maxTabHeight = calculateMaxTabHeight(tabPlacement); 2815 } 2816 2817 runCount = 0; 2818 selectedRun = -1; 2819 2820 if (tabCount == 0) { 2821 return; 2822 } 2823 2824 selectedRun = 0; 2825 runCount = 1; 2826 2827 Rectangle rect; 2829 for (i = 0; i < tabCount; i++) { 2830 rect = rects[i]; 2831 2832 if (!verticalTabRuns) { 2833 if (i > 0) { 2835 rect.x = rects[i-1].x + rects[i-1].width; 2836 } else { 2837 tabRuns[0] = 0; 2838 maxTabWidth = 0; 2839 totalHeight += maxTabHeight; 2840 rect.x = x; 2841 } 2842 rect.width = calculateTabWidth(tabPlacement, i, metrics); 2843 totalWidth = rect.x + rect.width; 2844 maxTabWidth = Math.max(maxTabWidth, rect.width); 2845 2846 rect.y = y; 2847 rect.height = maxTabHeight; 2848 2849 } else { 2850 if (i > 0) { 2852 rect.y = rects[i-1].y + rects[i-1].height; 2853 } else { 2854 tabRuns[0] = 0; 2855 maxTabHeight = 0; 2856 totalWidth = maxTabWidth; 2857 rect.y = y; 2858 } 2859 rect.height = calculateTabHeight(tabPlacement, i, fontHeight); 2860 totalHeight = rect.y + rect.height; 2861 maxTabHeight = Math.max(maxTabHeight, rect.height); 2862 2863 rect.x = x; 2864 rect.width = maxTabWidth; 2865 2866 } 2867 } 2868 2869 if (tabsOverlapBorder) { 2870 padSelectedTab(tabPlacement, selectedIndex); 2872 } 2873 2874 if (!leftToRight && !verticalTabRuns) { 2877 int rightMargin = size.width 2878 - (insets.right + tabAreaInsets.right); 2879 for (i = 0; i < tabCount; i++) { 2880 rects[i].x = rightMargin - rects[i].x - rects[i].width; 2881 } 2882 } 2883 tabScroller.tabPanel.setPreferredSize(new Dimension(totalWidth, totalHeight)); 2885 } 2886 } 2887 2888 private class ScrollableTabSupport implements ActionListener, 2889 ChangeListener { 2890 public ScrollableTabViewport viewport; 2891 public ScrollableTabPanel tabPanel; 2892 public JButton scrollForwardButton; 2893 public JButton scrollBackwardButton; 2894 public int leadingTabIndex; 2895 2896 private Point tabViewPosition = new Point(0,0); 2897 2898 ScrollableTabSupport(int tabPlacement) { 2899 viewport = new ScrollableTabViewport(); 2900 tabPanel = new ScrollableTabPanel(); 2901 viewport.setView(tabPanel); 2902 viewport.addChangeListener(this); 2903 createButtons(); 2904 } 2905 2906 2909 void createButtons() { 2910 if (scrollForwardButton != null) { 2911 tabPane.remove(scrollForwardButton); 2912 scrollForwardButton.removeActionListener(this); 2913 tabPane.remove(scrollBackwardButton); 2914 scrollBackwardButton.removeActionListener(this); 2915 } 2916 int tabPlacement = tabPane.getTabPlacement(); 2917 if (tabPlacement == TOP || tabPlacement == BOTTOM) { 2918 scrollForwardButton = createScrollButton(EAST); 2919 scrollBackwardButton = createScrollButton(WEST); 2920 2921 } else { scrollForwardButton = createScrollButton(SOUTH); 2923 scrollBackwardButton = createScrollButton(NORTH); 2924 } 2925 scrollForwardButton.addActionListener(this); 2926 scrollBackwardButton.addActionListener(this); 2927 tabPane.add(scrollForwardButton); 2928 tabPane.add(scrollBackwardButton); 2929 } 2930 2931 public void scrollForward(int tabPlacement) { 2932 Dimension viewSize = viewport.getViewSize(); 2933 Rectangle viewRect = viewport.getViewRect(); 2934 2935 if (tabPlacement == TOP || tabPlacement == BOTTOM) { 2936 if (viewRect.width >= viewSize.width - viewRect.x) { 2937 return; } 2939 } else { if (viewRect.height >= viewSize.height - viewRect.y) { 2941 return; 2942 } 2943 } 2944 setLeadingTabIndex(tabPlacement, leadingTabIndex+1); 2945 } 2946 2947 public void scrollBackward(int tabPlacement) { 2948 if (leadingTabIndex == 0) { 2949 return; } 2951 setLeadingTabIndex(tabPlacement, leadingTabIndex-1); 2952 } 2953 2954 public void setLeadingTabIndex(int tabPlacement, int index) { 2955 leadingTabIndex = index; 2956 Dimension viewSize = viewport.getViewSize(); 2957 Rectangle viewRect = viewport.getViewRect(); 2958 2959 switch(tabPlacement) { 2960 case TOP: 2961 case BOTTOM: 2962 tabViewPosition.x = leadingTabIndex == 0? 0 : rects[leadingTabIndex].x; 2963 2964 if ((viewSize.width - tabViewPosition.x) < viewRect.width) { 2965 Dimension extentSize = new Dimension(viewSize.width - tabViewPosition.x, 2968 viewRect.height); 2969 viewport.setExtentSize(extentSize); 2970 } 2971 break; 2972 case LEFT: 2973 case RIGHT: 2974 tabViewPosition.y = leadingTabIndex == 0? 0 : rects[leadingTabIndex].y; 2975 2976 if ((viewSize.height - tabViewPosition.y) < viewRect.height) { 2977 Dimension extentSize = new Dimension(viewRect.width, 2980 viewSize.height - tabViewPosition.y); 2981 viewport.setExtentSize(extentSize); 2982 } 2983 } 2984 viewport.setViewPosition(tabViewPosition); 2985 } 2986 2987 public void stateChanged(ChangeEvent e) { 2988 JViewport viewport = (JViewport)e.getSource(); 2989 int tabPlacement = tabPane.getTabPlacement(); 2990 int tabCount = tabPane.getTabCount(); 2991 Rectangle vpRect = viewport.getBounds(); 2992 Dimension viewSize = viewport.getViewSize(); 2993 Rectangle viewRect = viewport.getViewRect(); 2994 2995 leadingTabIndex = getClosestTab(viewRect.x, viewRect.y); 2996 2997 if (leadingTabIndex + 1 < tabCount) { 2999 switch (tabPlacement) { 3000 case TOP: 3001 case BOTTOM: 3002 if (rects[leadingTabIndex].x < viewRect.x) { 3003 leadingTabIndex++; 3004 } 3005 break; 3006 case LEFT: 3007 case RIGHT: 3008 if (rects[leadingTabIndex].y < viewRect.y) { 3009 leadingTabIndex++; 3010 } 3011 break; 3012 } 3013 } 3014 Insets contentInsets = getContentBorderInsets(tabPlacement); 3015 switch(tabPlacement) { 3016 case LEFT: 3017 tabPane.repaint(vpRect.x+vpRect.width, vpRect.y, 3018 contentInsets.left, vpRect.height); 3019 scrollBackwardButton.setEnabled( 3020 viewRect.y > 0 && leadingTabIndex > 0); 3021 scrollForwardButton.setEnabled( 3022 leadingTabIndex < tabCount-1 && 3023 viewSize.height-viewRect.y > viewRect.height); 3024 break; 3025 case RIGHT: 3026 tabPane.repaint(vpRect.x-contentInsets.right, vpRect.y, 3027 contentInsets.right, vpRect.height); 3028 scrollBackwardButton.setEnabled( 3029 viewRect.y > 0 && leadingTabIndex > 0); 3030 scrollForwardButton.setEnabled( 3031 leadingTabIndex < tabCount-1 && 3032 viewSize.height-viewRect.y > viewRect.height); 3033 break; 3034 case BOTTOM: 3035 tabPane.repaint(vpRect.x, vpRect.y-contentInsets.bottom, 3036 vpRect.width, contentInsets.bottom); 3037 scrollBackwardButton.setEnabled( 3038 viewRect.x > 0 && leadingTabIndex > 0); 3039 scrollForwardButton.setEnabled( 3040 leadingTabIndex < tabCount-1 && 3041 viewSize.width-viewRect.x > viewRect.width); 3042 break; 3043 case TOP: 3044 default: 3045 tabPane.repaint(vpRect.x, vpRect.y+vpRect.height, 3046 vpRect.width, contentInsets.top); 3047 scrollBackwardButton.setEnabled( 3048 viewRect.x > 0 && leadingTabIndex > 0); 3049 scrollForwardButton.setEnabled( 3050 leadingTabIndex < tabCount-1 && 3051 viewSize.width-viewRect.x > viewRect.width); 3052 } 3053 } 3054 3055 3058 public void actionPerformed(ActionEvent e) { 3059 ActionMap map = tabPane.getActionMap(); 3060 3061 if (map != null) { 3062 String actionKey; 3063 3064 if (e.getSource() == scrollForwardButton) { 3065 actionKey = "scrollTabsForwardAction"; 3066 } 3067 else { 3068 actionKey = "scrollTabsBackwardAction"; 3069 } 3070 Action action = map.get(actionKey); 3071 3072 if (action != null && action.isEnabled()) { 3073 action.actionPerformed(new ActionEvent(tabPane, 3074 ActionEvent.ACTION_PERFORMED, null, e.getWhen(), 3075 e.getModifiers())); 3076 } 3077 } 3078 } 3079 3080 public String toString() { 3081 return new String ("viewport.viewSize="+viewport.getViewSize()+"\n"+ 3082 "viewport.viewRectangle="+viewport.getViewRect()+"\n"+ 3083 "leadingTabIndex="+leadingTabIndex+"\n"+ 3084 "tabViewPosition="+tabViewPosition); 3085 } 3086 3087 } 3088 3089 private class ScrollableTabViewport extends JViewport implements UIResource { 3090 public ScrollableTabViewport() { 3091 super(); 3092 setName("TabbedPane.scrollableViewport"); 3093 setScrollMode(SIMPLE_SCROLL_MODE); 3094 setOpaque(tabPane.isOpaque()); 3095 Color bgColor = UIManager.getColor("TabbedPane.tabAreaBackground"); 3096 if (bgColor == null) { 3097 bgColor = tabPane.getBackground(); 3098 } 3099 setBackground(bgColor); 3100 } 3101 } 3102 3103 private class ScrollableTabPanel extends JPanel implements UIResource { 3104 public ScrollableTabPanel() { 3105 setLayout(null); 3106 setOpaque(tabPane.isOpaque()); 3107 Color bgColor = UIManager.getColor("TabbedPane.tabAreaBackground"); 3108 if (bgColor == null) { 3109 bgColor = tabPane.getBackground(); 3110 } 3111 setBackground(bgColor); 3112 } 3113 public void paintComponent(Graphics g) { 3114 super.paintComponent(g); 3115 BasicTabbedPaneUI.this.paintTabArea(g, tabPane.getTabPlacement(), 3116 tabPane.getSelectedIndex()); 3117 3118 } 3119 } 3120 3121 private class ScrollableTabButton extends BasicArrowButton implements UIResource, 3122 SwingConstants { 3123 public ScrollableTabButton(int direction) { 3124 super(direction, 3125 UIManager.getColor("TabbedPane.selected"), 3126 UIManager.getColor("TabbedPane.shadow"), 3127 UIManager.getColor("TabbedPane.darkShadow"), 3128 UIManager.getColor("TabbedPane.highlight")); 3129 } 3130 } 3131 3132 3133 3135 private class Handler implements ChangeListener , ContainerListener, 3136 FocusListener, MouseListener, MouseMotionListener, 3137 PropertyChangeListener { 3138 public void propertyChange(PropertyChangeEvent e) { 3142 JTabbedPane pane = (JTabbedPane)e.getSource(); 3143 String name = e.getPropertyName(); 3144 boolean isScrollLayout = scrollableTabLayoutEnabled(); 3145 if (name == "mnemonicAt") { 3146 updateMnemonics(); 3147 pane.repaint(); 3148 } 3149 else if (name == "displayedMnemonicIndexAt") { 3150 pane.repaint(); 3151 } 3152 else if (name =="indexForTitle") { 3153 int index = ((Integer )e.getNewValue()).intValue(); 3154 String title = tabPane.getTitleAt(index); 3155 if (BasicHTML.isHTMLString(title)) { 3156 if (htmlViews==null) { htmlViews = createHTMLVector(); 3158 } else { View v = BasicHTML.createHTMLView(tabPane, title); 3160 htmlViews.setElementAt(v, index); 3161 } 3162 } else { 3163 if (htmlViews != null && htmlViews.elementAt(index) != null) { 3164 htmlViews.setElementAt(null, index); 3165 } 3166 } 3167 updateMnemonics(); 3168 } else if (name == "tabLayoutPolicy") { 3169 BasicTabbedPaneUI.this.uninstallUI(pane); 3170 BasicTabbedPaneUI.this.installUI(pane); 3171 } else if (name == "tabPlacement") { 3172 if (scrollableTabLayoutEnabled()) { 3173 tabScroller.createButtons(); 3174 } 3175 } else if (name == "opaque" && isScrollLayout) { 3176 boolean newVal = ((Boolean )e.getNewValue()).booleanValue(); 3177 tabScroller.tabPanel.setOpaque(newVal); 3178 tabScroller.viewport.setOpaque(newVal); 3179 } else if (name == "background" && isScrollLayout) { 3180 Color newVal = (Color)e.getNewValue(); 3181 tabScroller.tabPanel.setBackground(newVal); 3182 tabScroller.viewport.setBackground(newVal); 3183 Color newColor = selectedColor == null ? newVal : selectedColor; 3184 tabScroller.scrollForwardButton.setBackground(newColor); 3185 tabScroller.scrollBackwardButton.setBackground(newColor); 3186 } 3187 } 3188 3189 3190 public void stateChanged(ChangeEvent e) { 3194 JTabbedPane tabPane = (JTabbedPane)e.getSource(); 3195 tabPane.revalidate(); 3196 tabPane.repaint(); 3197 3198 setFocusIndex(tabPane.getSelectedIndex(), false); 3199 3200 if (scrollableTabLayoutEnabled()) { 3201 int index = tabPane.getSelectedIndex(); 3202 if (index < rects.length && index != -1) { 3203 tabScroller.tabPanel.scrollRectToVisible( 3204 (Rectangle)rects[index].clone()); 3205 } 3206 } 3207 } 3208 3209 public void mouseClicked(MouseEvent e) { 3213 } 3214 3215 public void mouseReleased(MouseEvent e) { 3216 } 3217 3218 public void mouseEntered(MouseEvent e) { 3219 setRolloverTab(e.getX(), e.getY()); 3220 } 3221 3222 public void mouseExited(MouseEvent e) { 3223 setRolloverTab(-1); 3224 } 3225 3226 public void mousePressed(MouseEvent e) { 3227 if (!tabPane.isEnabled()) { 3228 return; 3229 } 3230 int tabIndex = tabForCoordinate(tabPane, e.getX(), e.getY()); 3231 if (tabIndex >= 0 && tabPane.isEnabledAt(tabIndex)) { 3232 if (tabIndex != tabPane.getSelectedIndex()) { 3233 tabPane.setSelectedIndex(tabIndex); 3238 } 3239 else if (tabPane.isRequestFocusEnabled()) { 3240 tabPane.requestFocus(); 3243 } 3244 } 3245 } 3246 3247 public void mouseDragged(MouseEvent e) { 3251 } 3252 3253 public void mouseMoved(MouseEvent e) { 3254 setRolloverTab(e.getX(), e.getY()); 3255 } 3256 3257 public void focusGained(FocusEvent e) { 3261 setFocusIndex(tabPane.getSelectedIndex(), true); 3262 } 3263 public void focusLost(FocusEvent e) { 3264 repaintTab(focusIndex); 3265 } 3266 3267 3268 3300 3301 public void componentAdded(ContainerEvent e) { 3302 JTabbedPane tp = (JTabbedPane)e.getContainer(); 3303 Component child = e.getChild(); 3304 if (child instanceof UIResource) { 3305 return; 3306 } 3307 int index = tp.indexOfComponent(child); 3308 String title = tp.getTitleAt(index); 3309 boolean isHTML = BasicHTML.isHTMLString(title); 3310 if (isHTML) { 3311 if (htmlViews==null) { htmlViews = createHTMLVector(); 3313 } else { View v = BasicHTML.createHTMLView(tp, title); 3315 htmlViews.insertElementAt(v, index); 3316 } 3317 } else { if (htmlViews!=null) { htmlViews.insertElementAt(null, index); 3320 } } 3322 isRunsDirty = true; 3323 updateMnemonics(); 3324 } 3325 public void componentRemoved(ContainerEvent e) { 3326 JTabbedPane tp = (JTabbedPane)e.getContainer(); 3327 Component child = e.getChild(); 3328 if (child instanceof UIResource) { 3329 return; 3330 } 3331 3332 Integer indexObj = 3338 (Integer )tp.getClientProperty("__index_to_remove__"); 3339 if (indexObj != null) { 3340 int index = indexObj.intValue(); 3341 if (htmlViews != null && htmlViews.size() > index) { 3342 htmlViews.removeElementAt(index); 3343 } 3344 tp.putClientProperty("__index_to_remove__", null); 3345 } 3346 isRunsDirty = true; 3347 updateMnemonics(); 3348 3349 validateFocusIndex(); 3350 } 3351 } 3352 3353 3357 public class PropertyChangeHandler implements PropertyChangeListener { 3358 public void propertyChange(PropertyChangeEvent e) { 3363 getHandler().propertyChange(e); 3364 } 3365 } 3366 3367 3371 public class TabSelectionHandler implements ChangeListener { 3372 public void stateChanged(ChangeEvent e) { 3377 getHandler().stateChanged(e); 3378 } 3379 } 3380 3381 3385 public class MouseHandler extends MouseAdapter { 3386 public void mousePressed(MouseEvent e) { 3391 getHandler().mousePressed(e); 3392 } 3393 } 3394 3395 3399 public class FocusHandler extends FocusAdapter { 3400 public void focusGained(FocusEvent e) { 3405 getHandler().focusGained(e); 3406 } 3407 public void focusLost(FocusEvent e) { 3408 getHandler().focusLost(e); 3409 } 3410 } 3411 3412 private Vector createHTMLVector() { 3413 Vector htmlViews = new Vector (); 3414 int count = tabPane.getTabCount(); 3415 if (count>0) { 3416 for (int i=0 ; i<count; i++) { 3417 String title = tabPane.getTitleAt(i); 3418 if (BasicHTML.isHTMLString(title)) { 3419 htmlViews.addElement(BasicHTML.createHTMLView(tabPane, title)); 3420 } else { 3421 htmlViews.addElement(null); 3422 } 3423 } 3424 } 3425 return htmlViews; 3426 } 3427} 3428 | Popular Tags |