KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > netbeans > modules > refactoring > spi > impl > 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.netbeans.modules.refactoring.spi.impl;
21
22 import java.awt.Component JavaDoc;
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 JavaDoc;
29 import javax.swing.event.ChangeListener JavaDoc;
30 import javax.swing.plaf.ColorUIResource JavaDoc;
31 import javax.swing.plaf.basic.BasicTabbedPaneUI JavaDoc;
32 import java.awt.*;
33 import java.awt.event.AWTEventListener JavaDoc;
34 import java.awt.event.MouseEvent JavaDoc;
35
36 // #21380.
37
/**
38  * Copy of original CloseButtonTabbedPane from the NetBeans 3.4 winsys. Old code never dies.
39  *
40  * !!! jbecicka comment:
41  * !!! This class was copy/pasted from org.netbeans.core.output2.ui
42  * !!! See issue 44576
43  * !!! Remove this class as soon as issue 55845 is fixed
44  *
45  * @author Tran Duc Trung
46  *
47  */

48 final class CloseButtonTabbedPane extends JTabbedPane implements ChangeListener JavaDoc, Runnable JavaDoc {
49
50     private final Image closeTabImage =
51         org.openide.util.Utilities.loadImage("org/netbeans/modules/refactoring/api/resources/RefCloseTab.gif"); // NOI18N
52
private final Image closeTabInactiveImage =
53         org.openide.util.Utilities.loadImage("org/netbeans/modules/refactoring/api/resources/RefCloseTabInactive.gif"); // NOI18N
54

55     public static final String JavaDoc PROP_CLOSE = "close"; // NOI18N
56

57     CloseButtonTabbedPane() {
58         addChangeListener(this);
59         CloseButtonListener.install();
60         //Bugfix #28263: Disable focus.
61
setFocusable(false);
62         setBorder(javax.swing.BorderFactory.createEmptyBorder());
63         setFocusCycleRoot(true);
64         setFocusTraversalPolicy(new CBTPPolicy());
65     }
66
67     private Component JavaDoc sel() {
68         Component JavaDoc c = getSelectedComponent();
69         return c == null ? this : c;
70     }
71
72     private class CBTPPolicy extends FocusTraversalPolicy {
73         public Component JavaDoc getComponentAfter(Container aContainer, Component JavaDoc aComponent) {
74             return sel();
75         }
76
77         public Component JavaDoc getComponentBefore(Container aContainer, Component JavaDoc aComponent) {
78             return sel();
79         }
80
81         public Component JavaDoc getFirstComponent(Container aContainer) {
82             return sel();
83         }
84
85         public Component JavaDoc getLastComponent(Container aContainer) {
86             return sel();
87         }
88
89         public Component JavaDoc 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 JavaDoc e) {
103         reset();
104     }
105     
106     public Component JavaDoc add (Component JavaDoc c) {
107         Component JavaDoc result = super.add(c);
108         String JavaDoc s = c.getName();
109         if (s != null) {
110             s += " "; // NOI18N
111
}
112         setTitleAt (getComponentCount() - 1, s);
113         return result;
114     }
115
116     public void setTitleAt(int idx, String JavaDoc title) {
117         String JavaDoc nue = title.indexOf("</html>") != -1 ? //NOI18N
118
Utilities.replaceString(title, "</html>", "&nbsp;&nbsp;</html>") //NOI18N
119
: title + " "; // NOI18N
120
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     /** Checks whether current L&F sets used keys for colors.
153      * If not puts default values. */

154     private static void checkUIColors() {
155         if(UIManager.getColor("Button.shadow") == null) { // NOI18N
156
UIManager.put("Button.shadow", // NOI18N
157
new ColorUIResource JavaDoc(153, 153, 153));
158         }
159         if(UIManager.getColor("Button.darkShadow") == null) { // NOI18N
160
UIManager.put("Button.darkShadow", // NOI18N
161
new ColorUIResource JavaDoc(102, 102, 102));
162         }
163         if(UIManager.getColor("Button.highlight") == null) { // NOI18N
164
UIManager.put("Button.highlight", // NOI18N
165
new ColorUIResource JavaDoc(Color.white));
166         }
167         if(UIManager.getColor("Button.background") == null) { // NOI18N
168
UIManager.put("Button.background", // NOI18N
169
new ColorUIResource JavaDoc(204, 204, 204));
170         }
171     }
172     
173     public void paint(Graphics g) {
174         super.paint(g);
175
176         // #29181 All L&F doesn't support the colors used.
177
checkUIColors();
178
179         // Have a look at
180
// http://ui.netbeans.org/docs/ui/closeButton/closeButtonUISpec.html
181
// to see how the buttons are specified to be drawn.
182

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")); //NOI18N
191
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")); //NOI18N
202
g.drawRect(r.x, r.y, r.width, r.height);
203                 g.setColor(i == selectedIndex
204                     ? UIManager.getColor("Button.highlight") //NOI18N
205
: UIManager.getColor("Button.background")); //NOI18N
206
g.drawRect(r.x + 1, r.y + 1, r.width, r.height);
207                 
208                 // Draw the dots.
209
g.setColor (UIManager.getColor ("Button.highlight").brighter()); //NOI18N
210
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")); //NOI18N
214
g.drawRect(r.x, r.y, r.width, r.height);
215                 g.setColor(i == selectedIndex
216                     ? UIManager.getColor("Button.highlight") //NOI18N
217
: UIManager.getColor("Button.background")); //NOI18N
218
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                 // Draw the lines.
228
g.setColor(UIManager.getColor("Button.background")); //NOI18N
229
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 JavaDoc 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         //JDK 1.5, Win L&F - we cannot do the layout synchronously when we've
313
//just removed a tab - the layout will have out of sync cache data
314
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 JavaDoc me) {
328         try {
329             super.processMouseEvent (me);
330         } catch (ArrayIndexOutOfBoundsException JavaDoc aioobe) {
331             //Bug in BasicTabbedPaneUI$Handler: The focusIndex field is not
332
//updated when tabs are removed programmatically, so it will try to
333
//repaint a tab that's not there
334
ErrorManager.getDefault().annotate(aioobe, "Suppressed " + //NOI18N
335
"AIOOBE bug in BasicTabbedPaneUI"); //NOI18N
336
ErrorManager.getDefault().notify(ErrorManager.INFORMATIONAL, aioobe);
337         }
338     }
339
340
341     private static class CloseButtonListener implements AWTEventListener JavaDoc
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 JavaDoc e = (MouseEvent JavaDoc) ev;
359
360             Component JavaDoc c = (Component JavaDoc) 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 JavaDoc) e.getSource(),
368                                                   e.getPoint(),
369                                                   tab);
370
371             if (e.getID() == MouseEvent.MOUSE_CLICKED) {
372                 //Not interested in clicked, and it can cause an NPE
373
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 JavaDoc 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                     //tab.reset();
415

416                     // XXX(-ttran) when the user clicks on the close button on
417
// an unfocused (internal) frame the focus is transferred
418
// to the frame and an unexpected MOUSE_EXITED event is
419
// fired. If we call reset() at every MOUSE_EXITED event
420
// then when the mouse button is released the tab is not
421
// closed. See bug #24450
422

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