1 32 33 package it.businesslogic.ireport.gui.docking; 34 35 import it.businesslogic.ireport.gui.event.TabPaneChangedEvent; 36 import java.awt.Component ; 37 38 import javax.swing.*; 39 import javax.swing.event.ChangeEvent ; 40 import javax.swing.event.ChangeListener ; 41 import javax.swing.plaf.ColorUIResource ; 42 import javax.swing.plaf.basic.BasicTabbedPaneUI ; 43 import java.awt.*; 44 import java.awt.event.AWTEventListener ; 45 import java.awt.event.MouseEvent ; 46 import javax.swing.text.TabExpander ; 47 48 55 class ExtendedTabbedPane extends JTabbedPane implements ChangeListener , Runnable { 56 57 private final Image closeTabImage = (new javax.swing.ImageIcon (getClass().getResource("/it/businesslogic/ireport/icons/docking/tabclose.png"))).getImage() ; 58 private final Image closeTabInactiveImage = (new javax.swing.ImageIcon (getClass().getResource("/it/businesslogic/ireport/icons/docking/tabcloseinactive.png"))).getImage() ; 59 private final Image closeTabActiveImage = (new javax.swing.ImageIcon (getClass().getResource("/it/businesslogic/ireport/icons/docking/tabcloseactive.png"))).getImage() ; 60 61 private final Image minimizeTabImage = (new javax.swing.ImageIcon (getClass().getResource("/it/businesslogic/ireport/icons/docking/tabminimize.png"))).getImage() ; 62 private final Image minimizeTabInactiveImage = (new javax.swing.ImageIcon (getClass().getResource("/it/businesslogic/ireport/icons/docking/tabminimizeinactive.png"))).getImage() ; 63 private final Image minimizeTabActiveImage = (new javax.swing.ImageIcon (getClass().getResource("/it/businesslogic/ireport/icons/docking/tabminimizeactive.png"))).getImage() ; 64 65 private java.util.List disabledCloseButtons = new java.util.ArrayList (); 67 68 private int orientation = DockingContainer.POSITION_LEFT; 69 70 ExtendedTabbedPane() { 71 addChangeListener(this); 72 73 CloseButtonListener.install(); 74 MinimizeButtonListener.install(); 75 76 setFocusable(false); 78 setBorder(javax.swing.BorderFactory.createEmptyBorder()); 79 setFocusCycleRoot(true); 80 setFocusTraversalPolicy(new CBTPPolicy()); 81 } 82 83 private Component sel() { 84 Component c = getSelectedComponent(); 85 return c == null ? this : c; 86 } 87 88 private class CBTPPolicy extends FocusTraversalPolicy { 89 public Component getComponentAfter(Container aContainer, Component aComponent) { 90 return sel(); 91 } 92 93 public Component getComponentBefore(Container aContainer, Component aComponent) { 94 return sel(); 95 } 96 97 public Component getFirstComponent(Container aContainer) { 98 return sel(); 99 } 100 101 public Component getLastComponent(Container aContainer) { 102 return sel(); 103 } 104 105 public Component getDefaultComponent(Container aContainer) { 106 return sel(); 107 } 108 } 109 110 public int tabForCoordinate(int x, int y) { 111 return getUI().tabForCoordinate(this, x, y); 112 } 113 114 private int pressedCloseButtonIndex = -1; 115 private int mouseOverCloseButtonIndex = -1; 116 117 118 private int pressedMinimizeButtonIndex = -1; 119 private int mouseOverMinimizeButtonIndex = -1; 120 121 private boolean draggedOut = false; 122 private boolean draggedOutMinimize = false; 123 124 public boolean isClosable(int tabIndex) 125 { 126 return !disabledCloseButtons.contains( new Integer (tabIndex)); 127 } 128 129 public void stateChanged (ChangeEvent e) { 130 reset(); 131 resetMinimized(); 132 } 136 137 public Component add (Component c) { 138 Component result = super.add(c); 139 String s = c.getName(); 140 if (s != null) { 141 s += " "; 142 } 143 setTitleAt (getComponentCount() - 1, s); 144 return result; 145 } 146 147 public Component addTab(String s, Component c, boolean closeable) { 148 Component result = super.add(c); 149 if (!closeable) 150 { 151 disabledCloseButtons.add( new Integer (getComponentCount() - 1)); 152 } 153 setTitleAt (getComponentCount() - 1, s); 154 155 return result; 156 } 157 158 public void setTitleAt(int idx, String title) { 159 160 String s = title; 161 if (s == null) s = ""; 162 s = s.trim()+" "; 163 if (s != null) 164 { 165 s += " "; 166 } 167 168 if (isClosable(idx)) s += " "; 169 170 171 if (!s.equals(getTitleAt(idx))) { 172 super.setTitleAt(idx, s); 173 } 174 } 175 176 private void reset() { 177 setMouseOverCloseButtonIndex(-1); 178 setPressedCloseButtonIndex(-1); 179 180 draggedOut = false; 181 } 182 183 private void resetMinimized() { 184 185 setMouseOverMinimizeButtonIndex(-1); 186 setPressedMinimizeButtonIndex(-1); 187 draggedOutMinimize = false; 188 } 189 190 private Rectangle getCloseButtonBoundsAt(int i) { 191 Rectangle b = getBoundsAt(i); 192 if (b == null || disabledCloseButtons.contains(new Integer (i))) 193 return null; 194 else { 195 b = new Rectangle(b); 196 fixGetBoundsAt(b); 197 198 Dimension tabsz = getSize(); 199 if (b.x + b.width >= tabsz.width 200 || b.y + b.height >= tabsz.height) 201 return null; 202 203 return new Rectangle(b.x + b.width - 14, 204 b.y + b.height / 2 - 5, 205 8, 206 8); 207 } 208 } 209 210 private Rectangle getMinimizeButtonBoundsAt(int i) { 211 Rectangle b = getBoundsAt(i); 212 if (b == null) 213 return null; 214 else { 215 b = new Rectangle(b); 216 fixGetBoundsAt(b); 217 218 Dimension tabsz = getSize(); 219 if (b.x + b.width >= tabsz.width 220 || b.y + b.height >= tabsz.height) 221 return null; 222 223 return new Rectangle(b.x + b.width - ( (disabledCloseButtons.contains(new Integer (i))) ? 12 : 24), 224 b.y + b.height / 2 - 5, 225 8, 226 8); 227 } 228 } 229 230 231 233 private static void checkUIColors() { 234 if(UIManager.getColor("Button.shadow") == null) { 235 UIManager.put("Button.shadow", 236 new ColorUIResource (153, 153, 153)); 237 } 238 if(UIManager.getColor("Button.darkShadow") == null) { 239 UIManager.put("Button.darkShadow", 240 new ColorUIResource (102, 102, 102)); 241 } 242 if(UIManager.getColor("Button.highlight") == null) { 243 UIManager.put("Button.highlight", 244 new ColorUIResource (Color.white)); 245 } 246 if(UIManager.getColor("Button.background") == null) { 247 UIManager.put("Button.background", 248 new ColorUIResource (204, 204, 204)); 249 } 250 } 251 252 public void paint(Graphics g) { 253 super.paint(g); 254 255 checkUIColors(); 257 258 262 int selectedIndex = getSelectedIndex(); 263 for (int i = 0, n = getTabCount(); i < n; i++) { 264 265 drawButton( g, 266 getMinimizeButtonBoundsAt(i), 267 pressedMinimizeButtonIndex, 268 minimizeTabInactiveImage, 269 minimizeTabImage, 270 minimizeTabActiveImage, 271 selectedIndex == i, 272 mouseOverMinimizeButtonIndex, 273 i, draggedOutMinimize, getOrientation() == 0); 274 275 if (!disabledCloseButtons.contains(new Integer (i))) 276 { 277 drawButton( g, 278 getCloseButtonBoundsAt(i), 279 pressedCloseButtonIndex, 280 closeTabInactiveImage, 281 closeTabImage, 282 closeTabActiveImage, 283 selectedIndex == i, 284 mouseOverCloseButtonIndex, 285 i, draggedOut, false); 286 } 287 } 288 } 289 290 protected void drawButton( Graphics g, 291 Rectangle r, 292 int pressedButtonIndex, 293 Image tabInactiveImage, 294 Image tabImage, 295 Image tabActiveImage, 296 boolean selected, 297 int mouseOverButtonIndex, 298 int tabIndex, 299 boolean isDraggedOut, 300 boolean flipImage) 301 { 302 if (r == null) return; 303 304 if(tabIndex == pressedButtonIndex && !isDraggedOut) { 305 g.setColor(UIManager.getColor("Button.shadow")); g.fillRect(r.x , r.y, r.width, r.height); 307 } 308 309 int dx1 = (flipImage) ? r.x+r.width : r.x; 311 int dy1 = r.y; 312 int dx2 = (flipImage) ? r.x : r.x+r.width; 313 int dy2 = r.y+r.height; 314 315 int sx1 = 0; 316 int sy1 = 0; 317 int sx2 = r.width; 318 int sy2 = r.height; 319 320 321 if (selected) 322 g.drawImage(tabImage,dx1,dy1,dx2,dy2, sx1,sy1,sx2,sy2,this); 323 else 324 g.drawImage(tabInactiveImage, dx1,dy1,dx2,dy2, sx1,sy1,sx2,sy2, this); 325 326 if (tabIndex == mouseOverButtonIndex 327 || (tabIndex == pressedButtonIndex && isDraggedOut)) { 328 329 g.drawImage(tabActiveImage, dx1,dy1,dx2,dy2, sx1,sy1,sx2,sy2, this); 330 331 338 } else if (tabIndex == pressedButtonIndex) { 343 344 g.drawImage(tabImage, dx1,dy1,dx2,dy2, sx1,sy1,sx2,sy2, this); 345 346 366 } 367 } 368 private void setPressedCloseButtonIndex(int index) { 369 if (pressedCloseButtonIndex == index) 370 return; 371 372 if (pressedCloseButtonIndex >= 0 373 && pressedCloseButtonIndex < getTabCount()) { 374 Rectangle r = getCloseButtonBoundsAt(pressedCloseButtonIndex); 375 repaint(r.x, r.y, r.width + 2, r.height + 2); 376 377 JComponent c = (JComponent) 378 getComponentAt(pressedCloseButtonIndex); 379 setToolTipTextAt(pressedCloseButtonIndex, c.getToolTipText()); 380 } 381 382 pressedCloseButtonIndex = index; 383 384 if (pressedCloseButtonIndex >= 0 385 && pressedCloseButtonIndex < getTabCount()) { 386 Rectangle r = getCloseButtonBoundsAt(pressedCloseButtonIndex); 387 repaint(r.x, r.y, r.width + 2, r.height + 2); 388 setMouseOverCloseButtonIndex(-1); 389 setToolTipTextAt(pressedCloseButtonIndex, null); 390 } 391 } 392 393 private void setMouseOverCloseButtonIndex(int index) { 394 if (mouseOverCloseButtonIndex == index) 395 return; 396 397 if (mouseOverCloseButtonIndex >= 0 398 && mouseOverCloseButtonIndex < getTabCount()) { 399 Rectangle r = getCloseButtonBoundsAt(mouseOverCloseButtonIndex); 400 repaint(r.x, r.y, r.width + 2, r.height + 2); 401 JComponent c = (JComponent) 402 getComponentAt(mouseOverCloseButtonIndex); 403 setToolTipTextAt(mouseOverCloseButtonIndex, c.getToolTipText()); 404 } 405 406 mouseOverCloseButtonIndex = index; 407 408 if (mouseOverCloseButtonIndex >= 0 409 && mouseOverCloseButtonIndex < getTabCount()) { 410 Rectangle r = getCloseButtonBoundsAt(mouseOverCloseButtonIndex); 411 repaint(r.x, r.y, r.width + 2, r.height + 2); 412 setPressedCloseButtonIndex(-1); 413 setToolTipTextAt(mouseOverCloseButtonIndex, null); 414 } 415 } 416 417 private void setPressedMinimizeButtonIndex(int index) { 418 if (pressedMinimizeButtonIndex == index) 419 return; 420 421 if (pressedMinimizeButtonIndex >= 0 422 && pressedMinimizeButtonIndex < getTabCount()) { 423 Rectangle r = getMinimizeButtonBoundsAt(pressedMinimizeButtonIndex); 424 repaint(r.x, r.y, r.width + 2, r.height + 2); 425 426 JComponent c = (JComponent) 427 getComponentAt(pressedMinimizeButtonIndex); 428 setToolTipTextAt(pressedMinimizeButtonIndex, c.getToolTipText()); 429 } 430 431 pressedMinimizeButtonIndex = index; 432 433 if (pressedMinimizeButtonIndex >= 0 434 && pressedMinimizeButtonIndex < getTabCount()) { 435 Rectangle r = getMinimizeButtonBoundsAt(pressedMinimizeButtonIndex); 436 repaint(r.x, r.y, r.width + 2, r.height + 2); 437 setMouseOverMinimizeButtonIndex(-1); 438 setToolTipTextAt(pressedMinimizeButtonIndex, null); 439 } 440 } 441 442 private void setMouseOverMinimizeButtonIndex(int index) { 443 if (mouseOverMinimizeButtonIndex == index) 444 return; 445 446 if (mouseOverMinimizeButtonIndex >= 0 447 && mouseOverMinimizeButtonIndex < getTabCount()) { 448 Rectangle r = getMinimizeButtonBoundsAt(mouseOverMinimizeButtonIndex); 449 repaint(r.x, r.y, r.width + 2, r.height + 2); 450 JComponent c = (JComponent) 451 getComponentAt(mouseOverMinimizeButtonIndex); 452 setToolTipTextAt(mouseOverMinimizeButtonIndex, c.getToolTipText()); 453 } 454 455 mouseOverMinimizeButtonIndex = index; 456 457 if (mouseOverMinimizeButtonIndex >= 0 458 && mouseOverMinimizeButtonIndex < getTabCount()) { 459 Rectangle r = getMinimizeButtonBoundsAt(mouseOverMinimizeButtonIndex); 460 repaint(r.x, r.y, r.width + 2, r.height + 2); 461 setPressedMinimizeButtonIndex(-1); 462 setToolTipTextAt(mouseOverMinimizeButtonIndex, null); 463 } 464 } 465 466 private void fireCloseRequest(Component c) { 467 fireTabPaneChangedListenerTabPaneChanged(new TabPaneChangedEvent(TabPaneChangedEvent.CLOSED, c, indexOfComponent(c))); 469 } 470 471 private void fireMinimizeRequest(Component c) { 472 fireTabPaneChangedListenerTabPaneChanged(new TabPaneChangedEvent(TabPaneChangedEvent.MINIMIZED, c, indexOfComponent(c))); 473 } 474 475 public static void fixGetBoundsAt(Rectangle b) { 476 if (b.y < 0) 477 b.y = -b.y; 478 if (b.x < 0) 479 b.x = -b.x; 480 } 481 482 public static int findTabForCoordinate(JTabbedPane tab, int x, int y) { 483 for (int i = 0; i < tab.getTabCount(); i++) { 484 Rectangle b = tab.getBoundsAt(i); 485 if (b != null) { 486 b = new Rectangle(b); 487 fixGetBoundsAt(b); 488 489 if (b.contains(x, y)) { 490 return i; 491 } 492 } 493 } 494 return -1; 495 } 496 497 boolean closingTab = false; 498 boolean minimizingTab = false; 499 public void doLayout() { 500 if (closingTab || minimizingTab) { 503 SwingUtilities.invokeLater (this); 504 } else { 505 super.doLayout(); 506 } 507 } 508 509 public void run() { 510 doLayout(); 511 closingTab = false; 512 minimizingTab = false; 513 repaint(); 514 } 515 516 protected void processMouseEvent (MouseEvent me) { 517 try { 518 super.processMouseEvent (me); 519 } catch (ArrayIndexOutOfBoundsException aioobe) { 520 } 527 } 528 529 530 private static class CloseButtonListener implements AWTEventListener 531 { 532 private static boolean installed = false; 533 534 private CloseButtonListener() {} 535 536 private static synchronized void install() { 537 if (installed) 538 return; 539 540 installed = true; 541 Toolkit.getDefaultToolkit().addAWTEventListener( 542 new CloseButtonListener(), 543 AWTEvent.MOUSE_EVENT_MASK | AWTEvent.MOUSE_MOTION_EVENT_MASK); 544 } 545 546 public void eventDispatched (AWTEvent ev) { 547 MouseEvent e = (MouseEvent ) ev; 548 549 Component c = (Component ) e.getSource(); 550 while (c != null && !(c instanceof ExtendedTabbedPane)) 551 c = c.getParent(); 552 if (c == null) 553 return; 554 final ExtendedTabbedPane tab = (ExtendedTabbedPane) c; 555 556 Point p = SwingUtilities.convertPoint((Component ) e.getSource(), 557 e.getPoint(), 558 tab); 559 560 if (e.getID() == MouseEvent.MOUSE_CLICKED) { 561 return; 563 } 564 565 int index = findTabForCoordinate(tab, p.x, p.y); 566 567 Rectangle r = null; 568 if (index >= 0) 569 r = tab.getCloseButtonBoundsAt(index); 570 if (r == null) 571 r = new Rectangle(0,0,0,0); 572 573 switch(e.getID()) { 574 case MouseEvent.MOUSE_PRESSED: 575 if (r.contains(p)) { 576 tab.setPressedCloseButtonIndex(index); 577 tab.draggedOut = false; 578 e.consume(); 579 return; 580 } 581 break; 582 583 case MouseEvent.MOUSE_RELEASED: 584 if (r.contains(p) && tab.pressedCloseButtonIndex >= 0) { 585 tab.closingTab = true; 586 Component tc = 587 tab.getComponentAt(tab.pressedCloseButtonIndex); 588 tab.reset(); 589 590 tab.fireCloseRequest(tc); 591 e.consume(); 592 return; 593 } 594 else { 595 tab.reset(); 596 } 597 break; 598 599 case MouseEvent.MOUSE_ENTERED: 600 break; 601 602 case MouseEvent.MOUSE_EXITED: 603 605 612 break; 613 614 case MouseEvent.MOUSE_MOVED: 615 if (r.contains(p)) { 616 tab.setMouseOverCloseButtonIndex(index); 617 tab.draggedOut = false; 618 e.consume(); 619 return; 620 } 621 else if (tab.mouseOverCloseButtonIndex >= 0) { 622 tab.setMouseOverCloseButtonIndex(-1); 623 tab.draggedOut = false; 624 e.consume(); 625 } 626 break; 627 628 case MouseEvent.MOUSE_DRAGGED: 629 if (tab.pressedCloseButtonIndex >= 0) { 630 if (tab.draggedOut != !r.contains(p)) { 631 tab.draggedOut = !r.contains(p); 632 tab.repaint(r.x, r.y, r.width + 2, r.height + 2); 633 } 634 e.consume(); 635 return; 636 } 637 break; 638 } 639 } 640 } 641 642 643 private static class MinimizeButtonListener implements AWTEventListener 644 { 645 private static boolean installed = false; 646 647 private MinimizeButtonListener() {} 648 649 private static synchronized void install() { 650 if (installed) 651 return; 652 653 installed = true; 654 Toolkit.getDefaultToolkit().addAWTEventListener( 655 new MinimizeButtonListener(), 656 AWTEvent.MOUSE_EVENT_MASK | AWTEvent.MOUSE_MOTION_EVENT_MASK); 657 } 658 659 public void eventDispatched (AWTEvent ev) { 660 MouseEvent e = (MouseEvent ) ev; 661 662 Component c = (Component ) e.getSource(); 663 while (c != null && !(c instanceof ExtendedTabbedPane)) 664 c = c.getParent(); 665 if (c == null) 666 return; 667 final ExtendedTabbedPane tab = (ExtendedTabbedPane) c; 668 669 Point p = SwingUtilities.convertPoint((Component ) e.getSource(), 670 e.getPoint(), 671 tab); 672 673 if (e.getID() == MouseEvent.MOUSE_CLICKED) { 674 return; 676 } 677 678 int index = findTabForCoordinate(tab, p.x, p.y); 679 680 Rectangle r = null; 681 if (index >= 0) 682 r = tab.getMinimizeButtonBoundsAt(index); 683 if (r == null) 684 r = new Rectangle(0,0,0,0); 685 686 switch(e.getID()) { 687 case MouseEvent.MOUSE_PRESSED: 688 689 if (r.contains(p)) { 690 tab.setPressedMinimizeButtonIndex(index); 691 tab.draggedOutMinimize = false; 692 e.consume(); 693 return; 694 } 695 break; 696 697 case MouseEvent.MOUSE_RELEASED: 698 699 if (r.contains(p) && tab.pressedMinimizeButtonIndex >= 0) { 700 tab.minimizingTab = true; 701 Component tc = 702 tab.getComponentAt(tab.pressedMinimizeButtonIndex); 703 tab.resetMinimized(); 704 tab.fireMinimizeRequest(tc); 705 e.consume(); 706 return; 707 } 708 else { 709 tab.resetMinimized(); 710 } 711 break; 712 713 case MouseEvent.MOUSE_ENTERED: 714 break; 715 716 case MouseEvent.MOUSE_EXITED: 717 719 726 break; 727 728 case MouseEvent.MOUSE_MOVED: 729 if (r.contains(p)) { 730 tab.setMouseOverMinimizeButtonIndex(index); 731 tab.draggedOutMinimize = false; 732 e.consume(); 733 return; 734 } 735 else if (tab.mouseOverMinimizeButtonIndex >= 0) { 736 tab.setMouseOverMinimizeButtonIndex(-1); 737 tab.draggedOutMinimize = false; 738 e.consume(); 739 } 740 break; 741 742 case MouseEvent.MOUSE_DRAGGED: 743 if (tab.pressedMinimizeButtonIndex >= 0) { 744 if (tab.draggedOutMinimize != !r.contains(p)) { 745 tab.draggedOutMinimize = !r.contains(p); 746 tab.repaint(r.x, r.y, r.width + 2, r.height + 2); 747 } 748 e.consume(); 749 return; 750 } 751 break; 752 } 753 } 754 } 755 756 759 private javax.swing.event.EventListenerList listenerList = null; 760 761 765 public synchronized void addTabPaneChangedListener(it.businesslogic.ireport.gui.event.TabPaneChangedListener listener) { 766 767 if (listenerList == null ) { 768 listenerList = new javax.swing.event.EventListenerList (); 769 } 770 listenerList.add (it.businesslogic.ireport.gui.event.TabPaneChangedListener.class, listener); 771 } 772 773 777 public synchronized void removeTabPaneChangedListener(it.businesslogic.ireport.gui.event.TabPaneChangedListener listener) { 778 779 listenerList.remove (it.businesslogic.ireport.gui.event.TabPaneChangedListener.class, listener); 780 } 781 782 787 private void fireTabPaneChangedListenerTabPaneChanged(it.businesslogic.ireport.gui.event.TabPaneChangedEvent event) { 788 789 if (listenerList == null) return; 790 Object [] listeners = listenerList.getListenerList (); 791 for (int i = listeners.length - 2; i >= 0; i -= 2) { 792 if (listeners[i]==it.businesslogic.ireport.gui.event.TabPaneChangedListener.class) { 793 ((it.businesslogic.ireport.gui.event.TabPaneChangedListener)listeners[i+1]).tabPaneChanged (event); 794 } 795 } 796 } 797 798 public int getOrientation() { 799 return orientation; 800 } 801 802 public void setOrientation(int orientation) { 803 this.orientation = orientation; 804 } 805 } 806 807 808 | Popular Tags |