KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > netbeans > modules > xml > refactoring > ui > j > ui > 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-2007 Sun
17  * Microsystems, Inc. All Rights Reserved.
18  */

19
20 package org.netbeans.modules.xml.refactoring.ui.j.ui;
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 public class CloseButtonTabbedPane extends JTabbedPane implements ChangeListener JavaDoc, Runnable JavaDoc {
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"); // NOI18N
53
private final Image closeTabInactiveImage =
54         org.openide.util.Utilities.loadImage("org/netbeans/modules/refactoring/resources/RefCloseTabInactive.gif"); // NOI18N
55

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

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

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

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

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

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