1 19 20 package org.netbeans.modules.refactoring.spi.impl; 21 22 import java.awt.Component ; 23 import org.openide.windows.TopComponent; 24 import org.openide.util.Utilities; 25 import org.openide.ErrorManager; 26 27 import javax.swing.*; 28 import javax.swing.event.ChangeEvent ; 29 import javax.swing.event.ChangeListener ; 30 import javax.swing.plaf.ColorUIResource ; 31 import javax.swing.plaf.basic.BasicTabbedPaneUI ; 32 import java.awt.*; 33 import java.awt.event.AWTEventListener ; 34 import java.awt.event.MouseEvent ; 35 36 48 final class CloseButtonTabbedPane extends JTabbedPane implements ChangeListener , Runnable { 49 50 private final Image closeTabImage = 51 org.openide.util.Utilities.loadImage("org/netbeans/modules/refactoring/api/resources/RefCloseTab.gif"); private final Image closeTabInactiveImage = 53 org.openide.util.Utilities.loadImage("org/netbeans/modules/refactoring/api/resources/RefCloseTabInactive.gif"); 55 public static final String PROP_CLOSE = "close"; 57 CloseButtonTabbedPane() { 58 addChangeListener(this); 59 CloseButtonListener.install(); 60 setFocusable(false); 62 setBorder(javax.swing.BorderFactory.createEmptyBorder()); 63 setFocusCycleRoot(true); 64 setFocusTraversalPolicy(new CBTPPolicy()); 65 } 66 67 private Component sel() { 68 Component c = getSelectedComponent(); 69 return c == null ? this : c; 70 } 71 72 private class CBTPPolicy extends FocusTraversalPolicy { 73 public Component getComponentAfter(Container aContainer, Component aComponent) { 74 return sel(); 75 } 76 77 public Component getComponentBefore(Container aContainer, Component aComponent) { 78 return sel(); 79 } 80 81 public Component getFirstComponent(Container aContainer) { 82 return sel(); 83 } 84 85 public Component getLastComponent(Container aContainer) { 86 return sel(); 87 } 88 89 public Component getDefaultComponent(Container aContainer) { 90 return sel(); 91 } 92 } 93 94 public int tabForCoordinate(int x, int y) { 95 return getUI().tabForCoordinate(this, x, y); 96 } 97 98 private int pressedCloseButtonIndex = -1; 99 private int mouseOverCloseButtonIndex = -1; 100 private boolean draggedOut = false; 101 102 public void stateChanged (ChangeEvent e) { 103 reset(); 104 } 105 106 public Component add (Component c) { 107 Component result = super.add(c); 108 String s = c.getName(); 109 if (s != null) { 110 s += " "; } 112 setTitleAt (getComponentCount() - 1, s); 113 return result; 114 } 115 116 public void setTitleAt(int idx, String title) { 117 String nue = title.indexOf("</html>") != -1 ? Utilities.replaceString(title, "</html>", " </html>") : title + " "; if (!title.equals(getTitleAt(idx))) { 121 super.setTitleAt(idx, nue); 122 } 123 } 124 125 private void reset() { 126 setMouseOverCloseButtonIndex(-1); 127 setPressedCloseButtonIndex(-1); 128 draggedOut = false; 129 } 130 131 private Rectangle getCloseButtonBoundsAt(int i) { 132 Rectangle b = getBoundsAt(i); 133 if (b == null) 134 return null; 135 else { 136 b = new Rectangle(b); 137 fixGetBoundsAt(b); 138 139 Dimension tabsz = getSize(); 140 if (b.x + b.width >= tabsz.width 141 || b.y + b.height >= tabsz.height) 142 return null; 143 144 return new Rectangle(b.x + b.width - 13, 145 b.y + b.height / 2 - 5, 146 8, 147 8); 148 } 149 } 150 151 152 154 private static void checkUIColors() { 155 if(UIManager.getColor("Button.shadow") == null) { UIManager.put("Button.shadow", new ColorUIResource (153, 153, 153)); 158 } 159 if(UIManager.getColor("Button.darkShadow") == null) { UIManager.put("Button.darkShadow", new ColorUIResource (102, 102, 102)); 162 } 163 if(UIManager.getColor("Button.highlight") == null) { UIManager.put("Button.highlight", new ColorUIResource (Color.white)); 166 } 167 if(UIManager.getColor("Button.background") == null) { UIManager.put("Button.background", new ColorUIResource (204, 204, 204)); 170 } 171 } 172 173 public void paint(Graphics g) { 174 super.paint(g); 175 176 checkUIColors(); 178 179 183 int selectedIndex = getSelectedIndex(); 184 for (int i = 0, n = getTabCount(); i < n; i++) { 185 Rectangle r = getCloseButtonBoundsAt(i); 186 if (r == null) 187 continue; 188 189 if(i == pressedCloseButtonIndex && !draggedOut) { 190 g.setColor(UIManager.getColor("Button.shadow")); g.fillRect(r.x , r.y, r.width, r.height); 192 } 193 194 if (i != selectedIndex) 195 g.drawImage(closeTabInactiveImage, r.x + 2, r.y + 2, this); 196 else 197 g.drawImage(closeTabImage, r.x + 2, r.y + 2, this); 198 199 if (i == mouseOverCloseButtonIndex 200 || (i == pressedCloseButtonIndex && draggedOut)) { 201 g.setColor(UIManager.getColor("Button.darkShadow")); g.drawRect(r.x, r.y, r.width, r.height); 203 g.setColor(i == selectedIndex 204 ? UIManager.getColor("Button.highlight") : UIManager.getColor("Button.background")); g.drawRect(r.x + 1, r.y + 1, r.width, r.height); 207 208 g.setColor (UIManager.getColor ("Button.highlight").brighter()); g.drawLine(r.x + r.width, r.y + 1, r.x + r.width, r.y + 1); 211 g.drawLine(r.x + 1, r.y + r.height, r.x + 1, r.y + r.height); 212 } else if (i == pressedCloseButtonIndex) { 213 g.setColor(UIManager.getColor("Button.shadow")); g.drawRect(r.x, r.y, r.width, r.height); 215 g.setColor(i == selectedIndex 216 ? UIManager.getColor("Button.highlight") : UIManager.getColor("Button.background")); g.drawLine(r.x + 1, 219 r.y + r.height + 1, 220 r.x + r.width + 1, 221 r.y + r.height + 1); 222 g.drawLine(r.x + r.width + 1, 223 r.y + 1, 224 r.x + r.width + 1, 225 r.y + r.height + 1); 226 227 g.setColor(UIManager.getColor("Button.background")); g.drawLine(r.x + 1, r.y + 1, r.x + r.width, r.y + 1); 230 g.drawLine(r.x + 1, r.y + 1, r.x + 1, r.y + r.height); 231 } 232 } 233 } 234 235 private void setPressedCloseButtonIndex(int index) { 236 if (pressedCloseButtonIndex == index) 237 return; 238 239 if (pressedCloseButtonIndex >= 0 240 && pressedCloseButtonIndex < getTabCount()) { 241 Rectangle r = getCloseButtonBoundsAt(pressedCloseButtonIndex); 242 repaint(r.x, r.y, r.width + 2, r.height + 2); 243 244 JComponent c = (JComponent) 245 getComponentAt(pressedCloseButtonIndex); 246 setToolTipTextAt(pressedCloseButtonIndex, c.getToolTipText()); 247 } 248 249 pressedCloseButtonIndex = index; 250 251 if (pressedCloseButtonIndex >= 0 252 && pressedCloseButtonIndex < getTabCount()) { 253 Rectangle r = getCloseButtonBoundsAt(pressedCloseButtonIndex); 254 repaint(r.x, r.y, r.width + 2, r.height + 2); 255 setMouseOverCloseButtonIndex(-1); 256 setToolTipTextAt(pressedCloseButtonIndex, null); 257 } 258 } 259 260 private void setMouseOverCloseButtonIndex(int index) { 261 if (mouseOverCloseButtonIndex == index) 262 return; 263 264 if (mouseOverCloseButtonIndex >= 0 265 && mouseOverCloseButtonIndex < getTabCount()) { 266 Rectangle r = getCloseButtonBoundsAt(mouseOverCloseButtonIndex); 267 repaint(r.x, r.y, r.width + 2, r.height + 2); 268 JComponent c = (JComponent) 269 getComponentAt(mouseOverCloseButtonIndex); 270 setToolTipTextAt(mouseOverCloseButtonIndex, c.getToolTipText()); 271 } 272 273 mouseOverCloseButtonIndex = index; 274 275 if (mouseOverCloseButtonIndex >= 0 276 && mouseOverCloseButtonIndex < getTabCount()) { 277 Rectangle r = getCloseButtonBoundsAt(mouseOverCloseButtonIndex); 278 repaint(r.x, r.y, r.width + 2, r.height + 2); 279 setPressedCloseButtonIndex(-1); 280 setToolTipTextAt(mouseOverCloseButtonIndex, null); 281 } 282 } 283 284 private void fireCloseRequest(Component c) { 285 firePropertyChange(PROP_CLOSE, null, c); 286 } 287 288 public static void fixGetBoundsAt(Rectangle b) { 289 if (b.y < 0) 290 b.y = -b.y; 291 if (b.x < 0) 292 b.x = -b.x; 293 } 294 295 public static int findTabForCoordinate(JTabbedPane tab, int x, int y) { 296 for (int i = 0; i < tab.getTabCount(); i++) { 297 Rectangle b = tab.getBoundsAt(i); 298 if (b != null) { 299 b = new Rectangle(b); 300 fixGetBoundsAt(b); 301 302 if (b.contains(x, y)) { 303 return i; 304 } 305 } 306 } 307 return -1; 308 } 309 310 boolean closingTab = false; 311 public void doLayout() { 312 if (closingTab) { 315 SwingUtilities.invokeLater (this); 316 } else { 317 super.doLayout(); 318 } 319 } 320 321 public void run() { 322 doLayout(); 323 closingTab = false; 324 repaint(); 325 } 326 327 protected void processMouseEvent (MouseEvent me) { 328 try { 329 super.processMouseEvent (me); 330 } catch (ArrayIndexOutOfBoundsException aioobe) { 331 ErrorManager.getDefault().annotate(aioobe, "Suppressed " + "AIOOBE bug in BasicTabbedPaneUI"); ErrorManager.getDefault().notify(ErrorManager.INFORMATIONAL, aioobe); 337 } 338 } 339 340 341 private static class CloseButtonListener implements AWTEventListener 342 { 343 private static boolean installed = false; 344 345 private CloseButtonListener() {} 346 347 private static synchronized void install() { 348 if (installed) 349 return; 350 351 installed = true; 352 Toolkit.getDefaultToolkit().addAWTEventListener( 353 new CloseButtonListener(), 354 AWTEvent.MOUSE_EVENT_MASK | AWTEvent.MOUSE_MOTION_EVENT_MASK); 355 } 356 357 public void eventDispatched (AWTEvent ev) { 358 MouseEvent e = (MouseEvent ) ev; 359 360 Component c = (Component ) e.getSource(); 361 while (c != null && !(c instanceof CloseButtonTabbedPane)) 362 c = c.getParent(); 363 if (c == null) 364 return; 365 final CloseButtonTabbedPane tab = (CloseButtonTabbedPane) c; 366 367 Point p = SwingUtilities.convertPoint((Component ) e.getSource(), 368 e.getPoint(), 369 tab); 370 371 if (e.getID() == MouseEvent.MOUSE_CLICKED) { 372 return; 374 } 375 376 int index = findTabForCoordinate(tab, p.x, p.y); 377 378 Rectangle r = null; 379 if (index >= 0) 380 r = tab.getCloseButtonBoundsAt(index); 381 if (r == null) 382 r = new Rectangle(0,0,0,0); 383 384 switch(e.getID()) { 385 case MouseEvent.MOUSE_PRESSED: 386 if (r.contains(p)) { 387 tab.setPressedCloseButtonIndex(index); 388 tab.draggedOut = false; 389 e.consume(); 390 return; 391 } 392 break; 393 394 case MouseEvent.MOUSE_RELEASED: 395 if (r.contains(p) && tab.pressedCloseButtonIndex >= 0) { 396 tab.closingTab = true; 397 Component tc = 398 tab.getComponentAt(tab.pressedCloseButtonIndex); 399 tab.reset(); 400 401 tab.fireCloseRequest(tc); 402 e.consume(); 403 return; 404 } 405 else { 406 tab.reset(); 407 } 408 break; 409 410 case MouseEvent.MOUSE_ENTERED: 411 break; 412 413 case MouseEvent.MOUSE_EXITED: 414 416 423 break; 424 425 case MouseEvent.MOUSE_MOVED: 426 if (r.contains(p)) { 427 tab.setMouseOverCloseButtonIndex(index); 428 tab.draggedOut = false; 429 e.consume(); 430 return; 431 } 432 else if (tab.mouseOverCloseButtonIndex >= 0) { 433 tab.setMouseOverCloseButtonIndex(-1); 434 tab.draggedOut = false; 435 e.consume(); 436 } 437 break; 438 439 case MouseEvent.MOUSE_DRAGGED: 440 if (tab.pressedCloseButtonIndex >= 0) { 441 if (tab.draggedOut != !r.contains(p)) { 442 tab.draggedOut = !r.contains(p); 443 tab.repaint(r.x, r.y, r.width + 2, r.height + 2); 444 } 445 e.consume(); 446 return; 447 } 448 break; 449 } 450 } 451 } 452 } 453 | Popular Tags |