1 19 20 package org.openide.awt; 21 22 import java.awt.AWTEvent ; 23 import java.awt.Component ; 24 import java.awt.Container ; 25 import java.awt.Dimension ; 26 import java.awt.FocusTraversalPolicy ; 27 import java.awt.Graphics ; 28 import java.awt.Image ; 29 import java.awt.Point ; 30 import java.awt.Rectangle ; 31 import java.awt.Toolkit ; 32 import javax.swing.plaf.UIResource ; 33 import org.openide.util.Utilities; 34 import javax.swing.event.ChangeEvent ; 35 import javax.swing.event.ChangeListener ; 36 import java.awt.event.AWTEventListener ; 37 import java.awt.event.MouseEvent ; 38 import java.util.logging.Level ; 39 import java.util.logging.Logger ; 40 import javax.swing.JComponent ; 41 import javax.swing.JTabbedPane ; 42 import javax.swing.SwingUtilities ; 43 import javax.swing.UIManager ; 44 import org.openide.util.Exceptions; 45 46 54 final class CloseButtonTabbedPane extends JTabbedPane { 55 56 private Image closeTabImage; 57 private Image closeTabPressedImage; 58 private Image closeTabMouseOverImage; 59 60 static final String PROP_CLOSE = "close"; 61 62 CloseButtonTabbedPane() { 63 addChangeListener( new ChangeListener () { 64 public void stateChanged(ChangeEvent e) { 65 reset(); 66 } 67 }); 68 CloseButtonListener.install(); 69 setFocusable(false); 71 setBorder(javax.swing.BorderFactory.createEmptyBorder()); 72 setFocusCycleRoot(true); 73 setFocusTraversalPolicy(new CBTPPolicy()); 74 } 75 76 private Component sel() { 77 Component c = getSelectedComponent(); 78 return c == null ? this : c; 79 } 80 81 private class CBTPPolicy extends FocusTraversalPolicy { 82 public Component getComponentAfter(Container aContainer, Component aComponent) { 83 return sel(); 84 } 85 86 public Component getComponentBefore(Container aContainer, Component aComponent) { 87 return sel(); 88 } 89 90 public Component getFirstComponent(Container aContainer) { 91 return sel(); 92 } 93 94 public Component getLastComponent(Container aContainer) { 95 return sel(); 96 } 97 98 public Component getDefaultComponent(Container aContainer) { 99 return sel(); 100 } 101 } 102 103 private int pressedCloseButtonIndex = -1; 104 private int mouseOverCloseButtonIndex = -1; 105 private boolean draggedOut = false; 106 107 public Component add (Component c) { 108 Component result = super.add(c); 109 if (!(c instanceof UIResource )) { 112 String s = c.getName(); 113 if (s != null) { 114 s += " "; 115 } 116 setTitleAt (getComponentCount() - 1, s); 117 } 118 return result; 119 } 120 121 public void setTitleAt(int idx, String title) { 122 String nue = title.indexOf("</html>") != -1 ? Utilities.replaceString(title, "</html>", " </html>") : title + " "; 125 if (!title.equals(getTitleAt(idx))) { 126 super.setTitleAt(idx, nue); 127 } 128 } 129 130 private void reset() { 131 setMouseOverCloseButtonIndex(-1); 132 setPressedCloseButtonIndex(-1); 133 draggedOut = false; 134 } 135 136 private Rectangle getCloseButtonBoundsAt(int i) { 137 Rectangle b = getBoundsAt(i); 138 if (b == null) 139 return null; 140 else { 141 b = new Rectangle (b); 142 fixGetBoundsAt(b); 143 144 Dimension tabsz = getSize(); 145 if (b.x + b.width >= tabsz.width 146 || b.y + b.height >= tabsz.height) 147 return null; 148 149 if( (isWindowsVistaLaF() || isWindowsXPLaF() || isWindowsLaF()) && i == getSelectedIndex() ) { 150 b.x -= 3; 151 b.y -= 2; 152 } else if( isWindowsXPLaF() || isWindowsLaF() || isAquaLaF() ) { 153 b.x -= 2; 154 } 155 if( i == getTabCount()-1 ) { 156 if( isMetalLaF() ) 157 b.x--; 158 else if( isAquaLaF() ) 159 b.x -= 3; 160 } 161 return new Rectangle (b.x + b.width - 13, 162 b.y + b.height / 2 - 5, 163 12, 164 12); 165 } 166 } 167 168 169 private boolean isWindowsVistaLaF() { 170 String osName = System.getProperty ("os.name"); 171 return osName.indexOf("Vista") >= 0 172 || (osName.equals( "Windows NT (unknown)" ) && "6.0".equals( System.getProperty("os.version") )); 173 } 174 175 private boolean isWindowsXPLaF() { 176 Boolean isXP = (Boolean )Toolkit.getDefaultToolkit(). 177 getDesktopProperty("win.xpstyle.themeActive"); return isWindowsLaF() && (isXP == null ? false : isXP.booleanValue()); 179 } 180 181 private boolean isWindowsLaF () { 182 String lfID = UIManager.getLookAndFeel().getID(); 183 return lfID.endsWith("Windows"); } 185 186 private boolean isAquaLaF() { 187 return "Aqua".equals( UIManager.getLookAndFeel().getID() ); 188 } 189 190 private boolean isMetalLaF () { 191 String lfID = UIManager.getLookAndFeel().getID(); 192 return "Metal".equals( lfID ); } 194 195 public void paint(Graphics g) { 196 super.paint(g); 197 198 202 int selectedIndex = getSelectedIndex(); 203 for (int i = 0, n = getTabCount(); i < n; i++) { 204 Rectangle r = getCloseButtonBoundsAt(i); 205 if (r == null) 206 continue; 207 208 if (i == mouseOverCloseButtonIndex 209 || (i == pressedCloseButtonIndex && draggedOut)) { 210 g.drawImage(getCloseTabMouseOverImage(), r.x, r.y , this); 211 } else if (i == pressedCloseButtonIndex) { 212 g.drawImage(getCloseTabPressedImage(), r.x, r.y , this); 213 } else { 214 g.drawImage(getCloseTabImage(), r.x, r.y , this); 215 } 216 } 217 } 218 219 private Image getCloseTabImage() { 220 if( null == closeTabImage ) { 221 if( isWindowsVistaLaF() ) { 222 closeTabImage = org.openide.util.Utilities.loadImage("org/openide/awt/resources/vista_close_enabled.png"); } else if( isWindowsXPLaF() ) { 224 closeTabImage = org.openide.util.Utilities.loadImage("org/openide/awt/resources/xp_close_enabled.png"); } else if( isWindowsLaF() ) { 226 closeTabImage = org.openide.util.Utilities.loadImage("org/openide/awt/resources/win_close_enabled.png"); } else if( isAquaLaF() ) { 228 closeTabImage = org.openide.util.Utilities.loadImage("org/openide/awt/resources/mac_close_enabled.png"); } else { 230 closeTabImage = org.openide.util.Utilities.loadImage("org/openide/awt/resources/metal_close_enabled.png"); } 232 } 233 return closeTabImage; 234 } 235 236 private Image getCloseTabPressedImage() { 237 if( null == closeTabPressedImage ) { 238 if( isWindowsVistaLaF() ) { 239 closeTabPressedImage = org.openide.util.Utilities.loadImage("org/openide/awt/resources/vista_close_pressed.png"); } else if( isWindowsXPLaF() ) { 241 closeTabPressedImage = org.openide.util.Utilities.loadImage("org/openide/awt/resources/xp_close_pressed.png"); } else if( isWindowsLaF() ) { 243 closeTabPressedImage = org.openide.util.Utilities.loadImage("org/openide/awt/resources/win_close_pressed.png"); } else if( isAquaLaF() ) { 245 closeTabPressedImage = org.openide.util.Utilities.loadImage("org/openide/awt/resources/mac_close_pressed.png"); } else { 247 closeTabPressedImage = org.openide.util.Utilities.loadImage("org/openide/awt/resources/metal_close_pressed.png"); } 249 } 250 return closeTabPressedImage; 251 } 252 253 private Image getCloseTabMouseOverImage() { 254 if( null == closeTabMouseOverImage ) { 255 if( isWindowsVistaLaF() ) { 256 closeTabMouseOverImage = org.openide.util.Utilities.loadImage("org/openide/awt/resources/vista_close_rollover.png"); } else if( isWindowsXPLaF() ) { 258 closeTabMouseOverImage = org.openide.util.Utilities.loadImage("org/openide/awt/resources/xp_close_rollover.png"); } else if( isWindowsLaF() ) { 260 closeTabMouseOverImage = org.openide.util.Utilities.loadImage("org/openide/awt/resources/win_close_rollover.png"); } else if( isAquaLaF() ) { 262 closeTabMouseOverImage = org.openide.util.Utilities.loadImage("org/openide/awt/resources/mac_close_rollover.png"); } else { 264 closeTabMouseOverImage = org.openide.util.Utilities.loadImage("org/openide/awt/resources/metal_close_rollover.png"); } 266 } 267 return closeTabMouseOverImage; 268 } 269 270 private void setPressedCloseButtonIndex(int index) { 271 if (pressedCloseButtonIndex == index) 272 return; 273 274 if (pressedCloseButtonIndex >= 0 275 && pressedCloseButtonIndex < getTabCount()) { 276 Rectangle r = getCloseButtonBoundsAt(pressedCloseButtonIndex); 277 repaint(r.x, r.y, r.width + 2, r.height + 2); 278 279 JComponent c = (JComponent ) 280 getComponentAt(pressedCloseButtonIndex); 281 setToolTipTextAt(pressedCloseButtonIndex, c.getToolTipText()); 282 } 283 284 pressedCloseButtonIndex = index; 285 286 if (pressedCloseButtonIndex >= 0 287 && pressedCloseButtonIndex < getTabCount()) { 288 Rectangle r = getCloseButtonBoundsAt(pressedCloseButtonIndex); 289 repaint(r.x, r.y, r.width + 2, r.height + 2); 290 setMouseOverCloseButtonIndex(-1); 291 setToolTipTextAt(pressedCloseButtonIndex, null); 292 } 293 } 294 295 private void setMouseOverCloseButtonIndex(int index) { 296 if (mouseOverCloseButtonIndex == index) 297 return; 298 299 if (mouseOverCloseButtonIndex >= 0 300 && mouseOverCloseButtonIndex < getTabCount()) { 301 Rectangle r = getCloseButtonBoundsAt(mouseOverCloseButtonIndex); 302 repaint(r.x, r.y, r.width + 2, r.height + 2); 303 JComponent c = (JComponent ) 304 getComponentAt(mouseOverCloseButtonIndex); 305 setToolTipTextAt(mouseOverCloseButtonIndex, c.getToolTipText()); 306 } 307 308 mouseOverCloseButtonIndex = index; 309 310 if (mouseOverCloseButtonIndex >= 0 311 && mouseOverCloseButtonIndex < getTabCount()) { 312 Rectangle r = getCloseButtonBoundsAt(mouseOverCloseButtonIndex); 313 repaint(r.x, r.y, r.width + 2, r.height + 2); 314 setPressedCloseButtonIndex(-1); 315 setToolTipTextAt(mouseOverCloseButtonIndex, null); 316 } 317 } 318 319 private void fireCloseRequest(Component c) { 320 firePropertyChange(PROP_CLOSE, null, c); 321 } 322 323 static void fixGetBoundsAt(Rectangle b) { 324 if (b.y < 0) 325 b.y = -b.y; 326 if (b.x < 0) 327 b.x = -b.x; 328 } 329 330 static int findTabForCoordinate(JTabbedPane tab, int x, int y) { 331 for (int i = 0; i < tab.getTabCount(); i++) { 332 Rectangle b = tab.getBoundsAt(i); 333 if (b != null) { 334 b = new Rectangle (b); 335 fixGetBoundsAt(b); 336 337 if (b.contains(x, y)) { 338 return i; 339 } 340 } 341 } 342 return -1; 343 } 344 345 346 protected void processMouseEvent (MouseEvent me) { 347 try { 348 super.processMouseEvent (me); 349 } catch (ArrayIndexOutOfBoundsException aioobe) { 350 Exceptions.attachLocalizedMessage(aioobe, 354 "Suppressed AIOOBE bug in BasicTabbedPaneUI"); Logger.getAnonymousLogger().log(Level.WARNING, null, aioobe); 356 } 357 } 358 359 360 private static class CloseButtonListener implements AWTEventListener 361 { 362 private static boolean installed = false; 363 364 private CloseButtonListener() {} 365 366 private static synchronized void install() { 367 if (installed) 368 return; 369 370 installed = true; 371 Toolkit.getDefaultToolkit().addAWTEventListener( 372 new CloseButtonListener(), 373 AWTEvent.MOUSE_EVENT_MASK | AWTEvent.MOUSE_MOTION_EVENT_MASK); 374 } 375 376 public void eventDispatched (AWTEvent ev) { 377 MouseEvent e = (MouseEvent ) ev; 378 379 Component c = (Component ) e.getSource(); 380 while (c != null && !(c instanceof CloseButtonTabbedPane)) 381 c = c.getParent(); 382 if (c == null) 383 return; 384 final CloseButtonTabbedPane tab = (CloseButtonTabbedPane) c; 385 386 Point p = SwingUtilities.convertPoint((Component ) e.getSource(), 387 e.getPoint(), 388 tab); 389 390 if (e.getID() == MouseEvent.MOUSE_CLICKED) { 391 return; 393 } 394 395 int index = findTabForCoordinate(tab, p.x, p.y); 396 397 Rectangle r = null; 398 if (index >= 0) 399 r = tab.getCloseButtonBoundsAt(index); 400 if (r == null) 401 r = new Rectangle (0,0,0,0); 402 403 switch(e.getID()) { 404 case MouseEvent.MOUSE_PRESSED: 405 if (r.contains(p)) { 406 tab.setPressedCloseButtonIndex(index); 407 tab.draggedOut = false; 408 e.consume(); 409 return; 410 } 411 break; 412 413 case MouseEvent.MOUSE_RELEASED: 414 if (r.contains(p) && tab.pressedCloseButtonIndex >= 0) { 415 Component tc = 416 tab.getComponentAt(tab.pressedCloseButtonIndex); 417 tab.reset(); 418 419 tab.fireCloseRequest(tc); 420 e.consume(); 421 return; 422 } 423 else { 424 tab.reset(); 425 } 426 break; 427 428 case MouseEvent.MOUSE_ENTERED: 429 break; 430 431 case MouseEvent.MOUSE_EXITED: 432 434 441 break; 442 443 case MouseEvent.MOUSE_MOVED: 444 if (r.contains(p)) { 445 tab.setMouseOverCloseButtonIndex(index); 446 tab.draggedOut = false; 447 e.consume(); 448 return; 449 } 450 else if (tab.mouseOverCloseButtonIndex >= 0) { 451 tab.setMouseOverCloseButtonIndex(-1); 452 tab.draggedOut = false; 453 e.consume(); 454 } 455 break; 456 457 case MouseEvent.MOUSE_DRAGGED: 458 if (tab.pressedCloseButtonIndex >= 0) { 459 if (tab.draggedOut != !r.contains(p)) { 460 tab.draggedOut = !r.contains(p); 461 tab.repaint(r.x, r.y, r.width + 2+6, r.height + 2+6); 462 } 463 e.consume(); 464 return; 465 } 466 break; 467 } 468 } 469 } 470 } 471 | Popular Tags |