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