KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > openide > awt > CloseButtonTabbedPane


1 /*
2  * The contents of this file are subject to the terms of the Common Development
3  * and Distribution License (the License). You may not use this file except in
4  * compliance with the License.
5  *
6  * You can obtain a copy of the License at http://www.netbeans.org/cddl.html
7  * or http://www.netbeans.org/cddl.txt.
8  *
9  * When distributing Covered Code, include this CDDL Header Notice in each file
10  * and include the License file at http://www.netbeans.org/cddl.txt.
11  * If applicable, add the following below the CDDL Header, with the fields
12  * enclosed by brackets [] replaced by your own identifying information:
13  * "Portions Copyrighted [year] [name of copyright owner]"
14  *
15  * The Original Software is NetBeans. The Initial Developer of the Original
16  * Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun
17  * Microsystems, Inc. All Rights Reserved.
18  */

19
20 package org.openide.awt;
21
22 import java.awt.AWTEvent JavaDoc;
23 import java.awt.Component JavaDoc;
24 import java.awt.Container JavaDoc;
25 import java.awt.Dimension JavaDoc;
26 import java.awt.FocusTraversalPolicy JavaDoc;
27 import java.awt.Graphics JavaDoc;
28 import java.awt.Image JavaDoc;
29 import java.awt.Point JavaDoc;
30 import java.awt.Rectangle JavaDoc;
31 import java.awt.Toolkit JavaDoc;
32 import javax.swing.plaf.UIResource JavaDoc;
33 import org.openide.util.Utilities;
34 import javax.swing.event.ChangeEvent JavaDoc;
35 import javax.swing.event.ChangeListener JavaDoc;
36 import java.awt.event.AWTEventListener JavaDoc;
37 import java.awt.event.MouseEvent JavaDoc;
38 import java.util.logging.Level JavaDoc;
39 import java.util.logging.Logger JavaDoc;
40 import javax.swing.JComponent JavaDoc;
41 import javax.swing.JTabbedPane JavaDoc;
42 import javax.swing.SwingUtilities JavaDoc;
43 import javax.swing.UIManager JavaDoc;
44 import org.openide.util.Exceptions;
45
46 /**
47  * Copy of original CloseButtonTabbedPane from the NetBeans 3.4 winsys. Old code never dies.
48  *
49  * @author Tran Duc Trung
50  * @author S. Aubrecht
51  * @since 6.10.0
52  *
53  */

54 final class CloseButtonTabbedPane extends JTabbedPane JavaDoc {
55
56     private Image JavaDoc closeTabImage;
57     private Image JavaDoc closeTabPressedImage;
58     private Image JavaDoc closeTabMouseOverImage;
59
60     static final String JavaDoc PROP_CLOSE = "close";
61
62     CloseButtonTabbedPane() {
63         addChangeListener( new ChangeListener JavaDoc() {
64             public void stateChanged(ChangeEvent JavaDoc e) {
65                 reset();
66             }
67         });
68         CloseButtonListener.install();
69         //Bugfix #28263: Disable focus.
70
setFocusable(false);
71         setBorder(javax.swing.BorderFactory.createEmptyBorder());
72         setFocusCycleRoot(true);
73         setFocusTraversalPolicy(new CBTPPolicy());
74     }
75
76     private Component JavaDoc sel() {
77         Component JavaDoc c = getSelectedComponent();
78         return c == null ? this : c;
79     }
80
81     private class CBTPPolicy extends FocusTraversalPolicy JavaDoc {
82         public Component JavaDoc getComponentAfter(Container JavaDoc aContainer, Component JavaDoc aComponent) {
83             return sel();
84         }
85
86         public Component JavaDoc getComponentBefore(Container JavaDoc aContainer, Component JavaDoc aComponent) {
87             return sel();
88         }
89
90         public Component JavaDoc getFirstComponent(Container JavaDoc aContainer) {
91             return sel();
92         }
93
94         public Component JavaDoc getLastComponent(Container JavaDoc aContainer) {
95             return sel();
96         }
97
98         public Component JavaDoc getDefaultComponent(Container JavaDoc 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 JavaDoc add (Component JavaDoc c) {
108         Component JavaDoc result = super.add(c);
109         // #75317 - don't try to set the title if LF (such as Substance LF)
110
// is adding some custom UI components into tabbed pane
111
if (!(c instanceof UIResource JavaDoc)) {
112             String JavaDoc 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 JavaDoc title) {
122         String JavaDoc nue = title.indexOf("</html>") != -1 ? //NOI18N
123
Utilities.replaceString(title, "</html>", "&nbsp;&nbsp;</html>") //NOI18N
124
: 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 JavaDoc getCloseButtonBoundsAt(int i) {
137         Rectangle JavaDoc b = getBoundsAt(i);
138         if (b == null)
139             return null;
140         else {
141             b = new Rectangle JavaDoc(b);
142             fixGetBoundsAt(b);
143
144             Dimension JavaDoc 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 JavaDoc(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 JavaDoc 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 JavaDoc isXP = (Boolean JavaDoc)Toolkit.getDefaultToolkit().
177                         getDesktopProperty("win.xpstyle.themeActive"); //NOI18N
178
return isWindowsLaF() && (isXP == null ? false : isXP.booleanValue());
179     }
180     
181     private boolean isWindowsLaF () {
182         String JavaDoc lfID = UIManager.getLookAndFeel().getID();
183         return lfID.endsWith("Windows"); //NOI18N
184
}
185     
186     private boolean isAquaLaF() {
187         return "Aqua".equals( UIManager.getLookAndFeel().getID() );
188     }
189     
190     private boolean isMetalLaF () {
191         String JavaDoc lfID = UIManager.getLookAndFeel().getID();
192         return "Metal".equals( lfID ); //NOI18N
193
}
194     
195     public void paint(Graphics JavaDoc g) {
196         super.paint(g);
197
198         // Have a look at
199
// http://ui.netbeans.org/docs/ui/closeButton/closeButtonUISpec.html
200
// to see how the buttons are specified to be drawn.
201

202         int selectedIndex = getSelectedIndex();
203         for (int i = 0, n = getTabCount(); i < n; i++) {
204             Rectangle JavaDoc 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 JavaDoc getCloseTabImage() {
220         if( null == closeTabImage ) {
221             if( isWindowsVistaLaF() ) {
222                 closeTabImage = org.openide.util.Utilities.loadImage("org/openide/awt/resources/vista_close_enabled.png"); // NOI18N
223
} else if( isWindowsXPLaF() ) {
224                 closeTabImage = org.openide.util.Utilities.loadImage("org/openide/awt/resources/xp_close_enabled.png"); // NOI18N
225
} else if( isWindowsLaF() ) {
226                 closeTabImage = org.openide.util.Utilities.loadImage("org/openide/awt/resources/win_close_enabled.png"); // NOI18N
227
} else if( isAquaLaF() ) {
228                 closeTabImage = org.openide.util.Utilities.loadImage("org/openide/awt/resources/mac_close_enabled.png"); // NOI18N
229
} else {
230                 closeTabImage = org.openide.util.Utilities.loadImage("org/openide/awt/resources/metal_close_enabled.png"); // NOI18N
231
}
232         }
233         return closeTabImage;
234     }
235     
236     private Image JavaDoc getCloseTabPressedImage() {
237         if( null == closeTabPressedImage ) {
238             if( isWindowsVistaLaF() ) {
239                 closeTabPressedImage = org.openide.util.Utilities.loadImage("org/openide/awt/resources/vista_close_pressed.png"); // NOI18N
240
} else if( isWindowsXPLaF() ) {
241                 closeTabPressedImage = org.openide.util.Utilities.loadImage("org/openide/awt/resources/xp_close_pressed.png"); // NOI18N
242
} else if( isWindowsLaF() ) {
243                 closeTabPressedImage = org.openide.util.Utilities.loadImage("org/openide/awt/resources/win_close_pressed.png"); // NOI18N
244
} else if( isAquaLaF() ) {
245                 closeTabPressedImage = org.openide.util.Utilities.loadImage("org/openide/awt/resources/mac_close_pressed.png"); // NOI18N
246
} else {
247                 closeTabPressedImage = org.openide.util.Utilities.loadImage("org/openide/awt/resources/metal_close_pressed.png"); // NOI18N
248
}
249         }
250         return closeTabPressedImage;
251     }
252     
253     private Image JavaDoc getCloseTabMouseOverImage() {
254         if( null == closeTabMouseOverImage ) {
255             if( isWindowsVistaLaF() ) {
256                 closeTabMouseOverImage = org.openide.util.Utilities.loadImage("org/openide/awt/resources/vista_close_rollover.png"); // NOI18N
257
} else if( isWindowsXPLaF() ) {
258                 closeTabMouseOverImage = org.openide.util.Utilities.loadImage("org/openide/awt/resources/xp_close_rollover.png"); // NOI18N
259
} else if( isWindowsLaF() ) {
260                 closeTabMouseOverImage = org.openide.util.Utilities.loadImage("org/openide/awt/resources/win_close_rollover.png"); // NOI18N
261
} else if( isAquaLaF() ) {
262                 closeTabMouseOverImage = org.openide.util.Utilities.loadImage("org/openide/awt/resources/mac_close_rollover.png"); // NOI18N
263
} else {
264                 closeTabMouseOverImage = org.openide.util.Utilities.loadImage("org/openide/awt/resources/metal_close_rollover.png"); // NOI18N
265
}
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 JavaDoc r = getCloseButtonBoundsAt(pressedCloseButtonIndex);
277             repaint(r.x, r.y, r.width + 2, r.height + 2);
278
279             JComponent JavaDoc c = (JComponent JavaDoc)
280                 getComponentAt(pressedCloseButtonIndex);
281             setToolTipTextAt(pressedCloseButtonIndex, c.getToolTipText());
282         }
283
284         pressedCloseButtonIndex = index;
285
286         if (pressedCloseButtonIndex >= 0
287         && pressedCloseButtonIndex < getTabCount()) {
288             Rectangle JavaDoc 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 JavaDoc r = getCloseButtonBoundsAt(mouseOverCloseButtonIndex);
302             repaint(r.x, r.y, r.width + 2, r.height + 2);
303             JComponent JavaDoc c = (JComponent JavaDoc)
304                 getComponentAt(mouseOverCloseButtonIndex);
305             setToolTipTextAt(mouseOverCloseButtonIndex, c.getToolTipText());
306         }
307
308         mouseOverCloseButtonIndex = index;
309
310         if (mouseOverCloseButtonIndex >= 0
311         && mouseOverCloseButtonIndex < getTabCount()) {
312             Rectangle JavaDoc 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 JavaDoc c) {
320         firePropertyChange(PROP_CLOSE, null, c);
321     }
322
323     static void fixGetBoundsAt(Rectangle JavaDoc 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 JavaDoc tab, int x, int y) {
331         for (int i = 0; i < tab.getTabCount(); i++) {
332             Rectangle JavaDoc b = tab.getBoundsAt(i);
333             if (b != null) {
334                 b = new Rectangle JavaDoc(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 JavaDoc me) {
347         try {
348             super.processMouseEvent (me);
349         } catch (ArrayIndexOutOfBoundsException JavaDoc aioobe) {
350             //Bug in BasicTabbedPaneUI$Handler: The focusIndex field is not
351
//updated when tabs are removed programmatically, so it will try to
352
//repaint a tab that's not there
353
Exceptions.attachLocalizedMessage(aioobe,
354                                               "Suppressed AIOOBE bug in BasicTabbedPaneUI"); //NOI18N
355
Logger.getAnonymousLogger().log(Level.WARNING, null, aioobe);
356         }
357     }
358
359
360     private static class CloseButtonListener implements AWTEventListener JavaDoc
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 JavaDoc ev) {
377             MouseEvent JavaDoc e = (MouseEvent JavaDoc) ev;
378
379             Component JavaDoc c = (Component JavaDoc) 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 JavaDoc p = SwingUtilities.convertPoint((Component JavaDoc) e.getSource(),
387                                                   e.getPoint(),
388                                                   tab);
389
390             if (e.getID() == MouseEvent.MOUSE_CLICKED) {
391                 //Not interested in clicked, and it can cause an NPE
392
return;
393             }
394             
395             int index = findTabForCoordinate(tab, p.x, p.y);
396
397             Rectangle JavaDoc r = null;
398             if (index >= 0)
399                 r = tab.getCloseButtonBoundsAt(index);
400             if (r == null)
401                 r = new Rectangle JavaDoc(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 JavaDoc 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                     //tab.reset();
433

434                     // XXX(-ttran) when the user clicks on the close button on
435
// an unfocused (internal) frame the focus is transferred
436
// to the frame and an unexpected MOUSE_EXITED event is
437
// fired. If we call reset() at every MOUSE_EXITED event
438
// then when the mouse button is released the tab is not
439
// closed. See bug #24450
440

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