KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > netbeans > core > windows > view > ui > tabcontrol > TabbedAdapter


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.core.windows.view.ui.tabcontrol;
21
22 import java.beans.PropertyChangeEvent JavaDoc;
23 import java.beans.PropertyChangeListener JavaDoc;
24 import java.util.Iterator JavaDoc;
25 import java.util.List JavaDoc;
26 import java.util.logging.Logger JavaDoc;
27 import org.netbeans.core.windows.Constants;
28 import org.netbeans.core.windows.Debug;
29 import org.netbeans.core.windows.WindowManagerImpl;
30 import org.netbeans.core.windows.view.ui.Tabbed;
31 import org.netbeans.swing.tabcontrol.ComponentConverter;
32 import org.netbeans.swing.tabcontrol.TabData;
33 import org.netbeans.swing.tabcontrol.TabbedContainer;
34 import org.netbeans.swing.tabcontrol.plaf.EqualPolygon;
35 import org.openide.util.WeakListeners;
36 import org.openide.windows.TopComponent;
37 import java.awt.Image JavaDoc;
38 import org.netbeans.core.windows.view.ui.slides.SlideController;
39 import javax.swing.*;
40 import javax.swing.event.ChangeEvent JavaDoc;
41 import javax.swing.event.ChangeListener JavaDoc;
42 import java.awt.*;
43 import java.util.ArrayList JavaDoc;
44 import java.util.Arrays JavaDoc;
45 import org.netbeans.core.windows.ModeImpl;
46 import org.netbeans.core.windows.actions.ActionUtils;
47 import org.netbeans.swing.tabcontrol.LocationInformer;
48 import org.netbeans.swing.tabcontrol.TabDisplayer;
49 import org.netbeans.swing.tabcontrol.WinsysInfoForTabbed;
50 import org.netbeans.swing.tabcontrol.event.TabActionEvent;
51
52 /** Adapter class that implements a pseudo JTabbedPane API on top
53  * of the new tab control. This class should eventually be eliminated
54  * and the TabbedContainer's model-driven API should be used directly.
55  *
56  * @author Tim Boudreau
57  */

58 public class TabbedAdapter extends TabbedContainer implements Tabbed, Tabbed.Accessor, SlideController {
59     
60     public static final int DOCUMENT = 1;
61     
62     /** Utility field holding list of ChangeListeners. */
63     private transient java.util.ArrayList JavaDoc<ChangeListener JavaDoc> changeListenerList;
64     
65     /** Debugging flag. */
66     private static final boolean DEBUG = Debug.isLoggable(TabbedAdapter.class);
67     private ChangeEvent JavaDoc changeEvent = new ChangeEvent JavaDoc(this);
68     
69     private PropertyChangeListener JavaDoc tooltipListener, weakTooltipListener;
70
71     /** Creates a new instance of TabbedAdapter */
72     public TabbedAdapter (int type) {
73         super (null, type, new WinsysInfo());
74         getSelectionModel().addChangeListener(new ChangeListener JavaDoc() {
75             public void stateChanged (ChangeEvent JavaDoc ce) {
76                 int idx = getSelectionModel().getSelectedIndex();
77                 if (idx != -1) {
78                     fireStateChanged();
79                 }
80             }
81         });
82 // Color fillC = (Color)UIManager.get("nb_workplace_fill"); //NOI18N
83
// if (fillC != null) setBackground (fillC);
84
}
85     
86     public void addTopComponent(String JavaDoc name, javax.swing.Icon JavaDoc icon, TopComponent tc, String JavaDoc toolTip) {
87         insertComponent (name, icon, tc, toolTip, getTabCount());
88     }
89     
90     public TopComponent getTopComponentAt(int index) {
91         if (index == -1) {
92             return null;
93         }
94         return (TopComponent)getModel().getTab(index).getComponent();
95     }
96     
97     public TopComponent getSelectedTopComponent() {
98         int i = getSelectionModel().getSelectedIndex();
99         return i == -1 ? null : getTopComponentAt(i);
100     }
101     
102     public void requestAttention (TopComponent tc) {
103         int idx = indexOf(tc);
104         if (idx >= 0) {
105             requestAttention(idx);
106         } else {
107             Logger.getAnonymousLogger().fine(
108                 "RequestAttention on component unknown to container: " + tc); //NOI18N
109
}
110     }
111     
112     public void cancelRequestAttention (TopComponent tc) {
113         int idx = indexOf(tc);
114         if (idx >= 0) {
115             cancelRequestAttention(idx);
116         } else {
117             throw new IllegalArgumentException JavaDoc ("TopComponent " + tc
118                 + " is not a child of this container"); //NOI18N
119
}
120     }
121
122     public void insertComponent(String JavaDoc name, javax.swing.Icon JavaDoc icon, Component comp, String JavaDoc toolTip, int position) {
123         TabData td = new TabData (comp, icon, name, toolTip);
124         
125         if(DEBUG) {
126             debugLog("InsertTab: " + name + " hash:" + System.identityHashCode(comp)); // NOI18N
127
}
128         
129         getModel().addTab(position, td);
130         comp.addPropertyChangeListener(JComponent.TOOL_TIP_TEXT_KEY, getTooltipListener(comp));
131     }
132  
133     public void setSelectedComponent(Component comp) {
134         int i = indexOf (comp);
135         if (i == -1) {
136             throw new IllegalArgumentException JavaDoc (
137                 "Component not a child of this control: " + comp); //NOI18N
138
} else {
139             getSelectionModel().setSelectedIndex(i);
140         }
141     }
142     
143     public TopComponent[] getTopComponents() {
144         ComponentConverter cc = getComponentConverter();
145         TabData[] td = (TabData[]) getModel().getTabs().toArray(new TabData[0]);
146         TopComponent[] result = new TopComponent[getModel().size()];
147         for (int i=0; i < td.length; i++) {
148             result[i] = (TopComponent) cc.getComponent(td[i]);
149         }
150         return result;
151     }
152     
153     public void removeComponent(Component comp) {
154         int i=indexOf(comp);
155         getModel().removeTab(i);
156         comp.removePropertyChangeListener(JComponent.TOOL_TIP_TEXT_KEY, getTooltipListener(comp));
157         if (getModel().size() == 0) {
158             revalidate();
159             repaint();
160         }
161     }
162
163     public void addComponents(Component[] comps, String JavaDoc[] names, javax.swing.Icon JavaDoc[] icons, String JavaDoc[] tips) {
164         ArrayList JavaDoc al = new ArrayList JavaDoc (comps.length);
165         TabData[] data = new TabData[comps.length];
166         for (int i=0; i < comps.length; i++) {
167             TabData td = new TabData (comps[i], icons[i], names[i], tips[i]);
168             data[i] = td;
169             comps[i].addPropertyChangeListener(JComponent.TOOL_TIP_TEXT_KEY, getTooltipListener(comps[i]));
170         }
171         getModel().addTabs (0, data);
172     }
173
174     public void setTopComponents(TopComponent[] tcs, TopComponent selected) {
175         assert selected != null : "Null passed as component to select";
176         int sizeBefore = getModel().size();
177
178         detachTooltipListeners(getModel().getTabs());
179         
180         TabData[] data = new TabData[tcs.length];
181         int toSelect=-1;
182         for(int i = 0; i < tcs.length; i++) {
183             TopComponent tc = tcs[i];
184             Image JavaDoc icon = tc.getIcon();
185             String JavaDoc displayName = WindowManagerImpl.getInstance().getTopComponentDisplayName(tc);
186             data[i] = new TabData(
187                 tc,
188                 icon == null ? null : new ImageIcon(icon),
189                 displayName == null ? "" : displayName, // NOI18N
190
tc.getToolTipText());
191             if (selected == tcs[i]) {
192                 toSelect = i;
193             }
194             tc.addPropertyChangeListener(JComponent.TOOL_TIP_TEXT_KEY, getTooltipListener(tc));
195         }
196
197         //DO NOT DELETE THIS ASSERTION AGAIN!
198
//If it triggered, it means there is a problem in the state of the
199
//window system's model. If it is just diagnostic logging, there
200
//*will* be an exception later, it just won't contain any useful
201
//information. See issue 39914 for what happens if it is deleted.
202
assert toSelect != -1 : "Tried to set a selected component that was " +
203             " not in the array of open components. ToSelect: " + selected + " ToSelectName=" + selected.getDisplayName() +
204             " ToSelectClass=" + selected.getClass() +
205             " open components: " + Arrays.asList(tcs);
206         
207         getModel().setTabs(data);
208         
209         
210         
211         if (toSelect != -1) {
212             getSelectionModel().setSelectedIndex(toSelect);
213         } else {
214             //Assertions are off
215
Logger.getAnonymousLogger().warning("Tried to" +
216             "set a selected component that was not in the array of open " +
217             "components. ToSelect: " + selected + " components: " +
218             Arrays.asList(tcs));
219         }
220         int sizeNow = getModel().size();
221         if (sizeBefore != 0 && sizeNow == 0) {
222             //issue 40076, ensure repaint if the control has been emptied.
223
revalidate();
224             repaint();
225         }
226     }
227
228     /** Removes tooltip listeners from given tabs */
229     private void detachTooltipListeners(List JavaDoc tabs) {
230         JComponent curComp;
231         for (Iterator JavaDoc iter = tabs.iterator(); iter.hasNext(); ) {
232             curComp = (JComponent)((TabData)iter.next()).getComponent();
233             curComp.removePropertyChangeListener(JComponent.TOOL_TIP_TEXT_KEY,
234                                                  getTooltipListener(curComp));
235         }
236     }
237     
238     // DnD>>
239
/** Finds tab which contains x coordinate of given location point.
240      * @param location The point for which a constraint is required
241      * @return Integer object representing found tab index. Returns null if
242      * no such tab can be found.
243      */

244     public Object JavaDoc getConstraintForLocation(Point location, boolean attachingPossible) {
245         //#47909
246
// first process the tabs when mouse is inside the tabs area..
247
int tab = tabForCoordinate(location);
248         if (tab != -1) {
249             int index = dropIndexOfPoint(location);
250             return index < 0 ? null : Integer.valueOf(index);
251         }
252         // ----
253
if(attachingPossible) {
254             String JavaDoc s = getSideForLocation(location);
255             if(s != null) {
256                 return s;
257             }
258         }
259         int index = dropIndexOfPoint(location);
260         return index < 0 ? null : Integer.valueOf(index);
261     }
262
263     /** Computes and returns feedback indication shape for given location
264      * point.
265      * TBD - extend for various feedback types
266      * @return Shape representing feedback indication
267      */

268     public Shape getIndicationForLocation(Point location,
269         TopComponent startingTransfer, Point startingPoint, boolean attachingPossible) {
270
271         Rectangle rect = getBounds();
272         rect.setLocation(0, 0);
273         
274         //#47909
275
int tab = tabForCoordinate(location);
276         // first process the tabs when mouse is inside the tabs area..
277
// need to process before the side resolution.
278
if (tab != -1) {
279             Shape s = getDropIndication(startingTransfer, location);
280             if(s != null) {
281                 return s;
282             }
283         }
284         
285         String JavaDoc side;
286         if(attachingPossible) {
287             side = getSideForLocation(location);
288         } else {
289             side = null;
290         }
291         
292         double ratio = Constants.DROP_TO_SIDE_RATIO;
293         if(side == Constants.TOP) {
294             return new Rectangle(0, 0, rect.width, (int)(rect.height * ratio));
295         } else if(side == Constants.LEFT) {
296             return new Rectangle(0, 0, (int)(rect.width * ratio), rect.height);
297         } else if(side == Constants.RIGHT) {
298             return new Rectangle(rect.width - (int)(rect.width * ratio), 0, (int)(rect.width * ratio), rect.height);
299         } else if(side == Constants.BOTTOM) {
300             return new Rectangle(0, rect.height - (int)(rect.height * ratio), rect.width, (int)(rect.height * ratio));
301         }
302
303         // #47909 now check shape again.. when no sides were checked, assume changing tabs when in component center.
304
Shape s = getDropIndication(startingTransfer, location);
305         if(s != null) {
306             return s;
307         }
308         
309         if(startingPoint != null
310             && indexOf(startingTransfer) != -1) {
311             return getStartingIndication(startingPoint, location);
312         }
313         
314         return rect;
315     }
316
317     private String JavaDoc getSideForLocation(Point location) {
318         Rectangle bounds = getBounds();
319         bounds.setLocation(0, 0);
320         
321         final int TOP_HEIGHT = 10;
322         final int BOTTOM_HEIGHT = (int)(0.25 * bounds.height);
323         
324         final int LEFT_WIDTH = Math.max (getWidth() / 8, 40);
325         final int RIGHT_WIDTH = LEFT_WIDTH;
326         
327         if(DEBUG) {
328             debugLog(""); // NOI18N
329
debugLog("TOP_HEIGHT =" + TOP_HEIGHT); // NOI18N
330
debugLog("BOTTOM_HEIGHT =" + BOTTOM_HEIGHT); // NOI18N
331
debugLog("LEFT_WIDTH =" + LEFT_WIDTH); // NOI18N
332
debugLog("RIGHT_WIDTH =" + RIGHT_WIDTH); // NOI18N
333
}
334         
335         // Size of area which indicates creation of new split.
336
// int delta = Constants.DROP_AREA_SIZE;
337
Rectangle top = new Rectangle(0, 0, bounds.width, BOTTOM_HEIGHT);
338         if(top.contains(location)) {
339             return Constants.TOP;
340         }
341         
342         Polygon left = new EqualPolygon(
343             new int[] {0, LEFT_WIDTH, LEFT_WIDTH, 0},
344             new int[] {TOP_HEIGHT, TOP_HEIGHT, bounds.height - BOTTOM_HEIGHT, bounds.height},
345             4
346         );
347         if(left.contains(location)) {
348             return Constants.LEFT;
349         }
350         
351         Polygon right = new EqualPolygon(
352             new int[] {bounds.width - RIGHT_WIDTH, bounds.width, bounds.width, bounds.width - RIGHT_WIDTH},
353             new int[] {TOP_HEIGHT, TOP_HEIGHT, bounds.height, bounds.height - BOTTOM_HEIGHT},
354             4
355         );
356         if(right.contains(location)) {
357             return Constants.RIGHT;
358         }
359
360         Polygon bottom = new EqualPolygon(
361             new int[] {LEFT_WIDTH, bounds.width - RIGHT_WIDTH, bounds.width, 0},
362             new int[] {bounds.height - BOTTOM_HEIGHT, bounds.height - BOTTOM_HEIGHT, bounds.height, bounds.height},
363             4
364         );
365         if(bottom.contains(location)) {
366             return Constants.BOTTOM;
367         }
368             
369         return null;
370     }
371
372     private Shape getStartingIndication(Point startingPoint, Point location) {
373         Rectangle rect = getBounds();
374         rect.setLocation(location.x - startingPoint.x, location.y - startingPoint.y);
375         return rect;
376     }
377     // DnD<<
378

379     
380     /** Registers ChangeListener to receive events.
381      * @param listener The listener to register.
382      *
383      */

384     public synchronized void addChangeListener(javax.swing.event.ChangeListener JavaDoc listener) {
385         if (changeListenerList == null ) {
386             changeListenerList = new java.util.ArrayList JavaDoc<ChangeListener JavaDoc>();
387         }
388         changeListenerList.add(listener);
389     }
390     
391     /** Removes ChangeListener from the list of listeners.
392      * @param listener The listener to remove.
393      *
394      */

395     public synchronized void removeChangeListener(javax.swing.event.ChangeListener JavaDoc listener) {
396         if (changeListenerList != null ) {
397             changeListenerList.remove(listener);
398         }
399     }
400     
401     /** Notifies all registered listeners about the event. */
402     private void fireStateChanged() {
403         java.util.ArrayList JavaDoc<ChangeListener JavaDoc> list;
404         synchronized (this) {
405             if (changeListenerList == null) return;
406             list = new ArrayList JavaDoc<ChangeListener JavaDoc>( changeListenerList );
407         }
408         //Note: Firing the events while holding the tree lock avoids many
409
//gratuitous repaints that slow down switching tabs. To demonstrate this,
410
//comment this code out and run the IDE with -J-Dawt.nativeDoubleBuffering=true
411
//so you'll really see every repaint. When switching between a form
412
//tab and an editor tab, you will see the property sheet get repainted
413
//8 times due to changes in the component hierarchy, before the
414
//selected node is even changed to the appropriate one for the new tab.
415
//Synchronizing here ensures that never happens.
416

417         if (!SwingUtilities.isEventDispatchThread()) {
418             Logger.getAnonymousLogger().warning(
419                 "All state changes to the tab component must happen on the event thread!"); //NOI18N
420
Exception JavaDoc e = new Exception JavaDoc();
421             e.fillInStackTrace();
422             Logger.getAnonymousLogger().warning(e.getStackTrace()[1].toString());
423         }
424         
425         synchronized (getTreeLock()) {
426             for (int i = 0; i < list.size(); i++) {
427                 ((javax.swing.event.ChangeListener JavaDoc)list.get(i)).stateChanged(changeEvent);
428             }
429         }
430     }
431     
432     private static void debugLog(String JavaDoc message) {
433         Debug.log(TabbedAdapter.class, message);
434     }
435     
436     public Component getComponent() {
437         return this;
438     }
439     
440     /** Add action for enabling auto hide of views */
441     public Action[] getPopupActions(Action[] defaultActions, int tabIndex) {
442         boolean isDocked = WindowManagerImpl.getInstance().isDocked(getTopComponentAt(tabIndex));
443         // no auto hide for editors and floating views
444
if (TabbedContainer.TYPE_EDITOR == getType() || !isDocked) {
445             return defaultActions;
446         }
447         int actionCount = defaultActions.length;
448         Action[] result = new Action[actionCount + 1];
449         System.arraycopy(defaultActions, 0, result, 0, actionCount);
450         // #82052: undock action as last item, auto hide as first before last
451
if (actionCount > 0) {
452             result[actionCount] = result[actionCount - 1];
453             result[actionCount - 1] = new ActionUtils.AutoHideWindowAction(this, tabIndex, false);
454         }
455         return result;
456     }
457
458     /** Finds out in what state is window system mode containing given component.
459      *
460      * @return true if given component is inside mode which is in maximized state,
461      * false otherwise
462      */

463     public static boolean isInMaximizedMode (Component comp) {
464         ModeImpl maxMode = WindowManagerImpl.getInstance().getCurrentMaximizedMode();
465         if (maxMode == null) {
466             return false;
467         }
468         return maxMode.containsTopComponent((TopComponent)comp);
469     }
470     
471     /********** implementation of SlideController *****************/
472     
473     public void userToggledAutoHide(int tabIndex, boolean enabled) {
474         postActionEvent(new TabActionEvent(this, TabbedContainer.COMMAND_ENABLE_AUTO_HIDE, tabIndex));
475     }
476     
477     /********* implementation of Tabbed.Accessor **************/
478     
479     public Tabbed getTabbed() {
480         return this;
481     }
482     
483     public Rectangle getTabBounds(int tabIndex) {
484         return getTabRect(tabIndex, new Rectangle());
485     }
486
487     /********* implementation of WinsysInfoForTabbed ********/
488     
489     static class WinsysInfo implements WinsysInfoForTabbed {
490     
491         public Object JavaDoc getOrientation (Component comp) {
492             WindowManagerImpl wmi = WindowManagerImpl.getInstance();
493             // don't show pin button in separate views
494
if (!wmi.isDocked((TopComponent)comp)) {
495                 return TabDisplayer.ORIENTATION_INVISIBLE;
496             }
497
498             String JavaDoc side = wmi.guessSlideSide((TopComponent)comp);
499             Object JavaDoc result = null;
500             if (side.equals(Constants.LEFT)) {
501                 result = TabDisplayer.ORIENTATION_WEST;
502             } else if (side.equals(Constants.RIGHT)) {
503                 result = TabDisplayer.ORIENTATION_EAST;
504             } else if (side.equals(Constants.BOTTOM)) {
505                 result = TabDisplayer.ORIENTATION_SOUTH;
506             } else {
507                 result = TabDisplayer.ORIENTATION_CENTER;
508             }
509             return result;
510         }
511
512         public boolean inMaximizedMode (Component comp) {
513             return isInMaximizedMode(comp);
514         }
515         
516     } // end of LocInfo
517

518     /** Returns instance of weak property change listener used to listen to
519      * tooltip changes. Weak listener is needed, in some situations (close of
520      * whole mode), our class is not notified from winsys.
521      */

522     private PropertyChangeListener JavaDoc getTooltipListener(Component comp) {
523         if (tooltipListener == null) {
524             tooltipListener = new ToolTipListener();
525             weakTooltipListener = WeakListeners.propertyChange(tooltipListener, comp);
526         }
527         return weakTooltipListener;
528     }
529
530     /** Listening to changes of tooltips of currently asociated top components */
531     private class ToolTipListener implements PropertyChangeListener JavaDoc {
532         
533         public void propertyChange(PropertyChangeEvent JavaDoc evt) {
534             if (JComponent.TOOL_TIP_TEXT_KEY.equals(evt.getPropertyName())) {
535                 List JavaDoc tabs = getModel().getTabs();
536                 JComponent curComp;
537                 int index = 0;
538                 for (Iterator JavaDoc iter = tabs.iterator(); iter.hasNext(); index++) {
539                     curComp = (JComponent)((TabData)iter.next()).getComponent();
540                     if (curComp == evt.getSource()) {
541                         setToolTipTextAt(index, (String JavaDoc)evt.getNewValue());
542                         break;
543                     }
544                 }
545             }
546         }
547         
548     }
549
550     
551 }
552
Popular Tags