KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > netbeans > swing > tabcontrol > plaf > AbstractTabDisplayerUI


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  * AbstractTabDisplayerUI.java
21  *
22  * Created on March 16, 2004, 6:16 PM
23  */

24
25 package org.netbeans.swing.tabcontrol.plaf;
26
27 import org.netbeans.swing.tabcontrol.TabDisplayer;
28 import org.netbeans.swing.tabcontrol.TabDisplayerUI;
29 import org.netbeans.swing.tabcontrol.event.ComplexListDataEvent;
30 import org.netbeans.swing.tabcontrol.event.ComplexListDataListener;
31
32 import javax.swing.*;
33 import javax.swing.event.ChangeEvent JavaDoc;
34 import javax.swing.event.ChangeListener JavaDoc;
35 import javax.swing.event.ListDataEvent JavaDoc;
36 import java.awt.*;
37 import java.awt.event.*;
38 import java.beans.PropertyChangeEvent JavaDoc;
39 import java.beans.PropertyChangeListener JavaDoc;
40
41 /**
42  * Base class for the implementations of TabDisplayerUI in this package. Uses
43  * TabLayoutModel for managing the layout of the tabs. Defines an SPI for
44  * UI delegates for TabDisplayer.
45  * <p>
46  * For most use cases, it will make more sense to subclass BasicTabDisplayerUI or
47  * BasicScrollingTabDisplayerUI, which handle most of the logic any implementation
48  * will need.
49  *
50  *
51  * @see BasicTabDisplayerUI
52  * @see BasicScrollingTabDisplayerUI
53  *
54  * @author Tim Boudreau
55  */

56 public abstract class AbstractTabDisplayerUI extends TabDisplayerUI {
57     /**
58      * Layout model, which will be initialized in <code>installUI()</code> by calling
59      * <code>createLayoutModel</code>. The layout model provides tab coordinates.
60      */

61     protected TabLayoutModel layoutModel = null;
62     /**
63      * Mouse listener (which may optionally implement MouseWheelListener and MouseMotionListener),
64      * which handles mouse events over the tab, triggering selection model changes, repaints, etc.
65      */

66     protected MouseListener mouseListener = null;
67     /**
68      * Component listener - mainly used to detach listeners when the component is hidden,
69      * and reattach them when it is shown. Also used by BasicScrollingTabDisplayerUI to
70      * trigger re-layouts of scrolled tabs when the size of the component changes.
71      */

72     protected ComponentListener componentListener = null;
73     /**
74      * A property change listener to listen on any changes from the component which should
75      * trigger repainting or other operations. The default implementation simply listens for
76      * changes in the <code>active</code> property to trigger a repaint.
77      */

78     protected PropertyChangeListener JavaDoc propertyChangeListener = null;
79     /**
80      * Listener on the TabDataModel. Responsible for repainting on model changes. Note that
81      * DefaultTabSelectionModel also listens on the model and automatically updates the
82      * selected index if, say, tabs are inserted before the currently selected tab.
83      */

84     protected ModelListener modelListener = null;
85     /**
86      * A change listener which listens on the selection model and repaints as needed when
87      * the selection changes.
88      */

89     protected ChangeListener JavaDoc selectionListener = null;
90     
91     protected HierarchyListener hierarchyListener = null;
92
93     /**
94      * Creates a new instance of AbstractTabDisplayerUI
95      */

96     public AbstractTabDisplayerUI(TabDisplayer displayer) {
97         super(displayer);
98     }
99
100     /** installUI is final to ensure listeners, etc. are created and attached. Subclasses that
101      * need to perform initialization on install should override <code>install()</code>,
102      * and refer to the <code>displayer</code> instance field, which will be initialized here.
103      *
104      * @param c An instance of TabDisplayer
105      */

106     public final void installUI(JComponent c) {
107         assert c == displayer;
108         super.installUI(c); //installs the selection model
109
ToolTipManager.sharedInstance().registerComponent(displayer);
110         layoutModel = createLayoutModel();
111         mouseListener = createMouseListener();
112         componentListener = createComponentListener();
113         modelListener = createModelListener();
114         propertyChangeListener = createPropertyChangeListener();
115         selectionListener = createSelectionListener();
116         hierarchyListener = createHierarchyListener();
117         install();
118         installListeners();
119         displayer.setFont(createFont());
120     }
121
122     /** This method is final - subclasses that need to deinitialize should override
123      * <code>uninstall()</code>, and remove any listeners, null any unneeded references, etc.
124      *
125      * @param c
126      */

127     public final void uninstallUI(JComponent c) {
128         assert c == displayer;
129         ToolTipManager.sharedInstance().unregisterComponent(displayer);
130         super.uninstallUI(c);
131         // #47644 - first uninstallListeners, then uninstall, so that tabState can't be null while
132
// listeners are active. Only probable fix, but certainly right thing to do.
133
uninstallListeners();
134         uninstall();
135         layoutModel = null;
136         mouseListener = null;
137         selectionModel = null;
138         componentListener = null;
139         selectionListener = null;
140     }
141
142     /**
143      * Called after creating the layout model, selection model and mouse
144      * listener, but before installing the mouse listener and selection model.
145      * Subclasses may use this method to do anything they need to do at ui
146      * install time.
147      */

148     protected void install() {
149         //do nothing
150
}
151
152     /**
153      * Called after uninstalling the mouse listener and selection model, but
154      * before references to that or the layout model or displayer have been
155      * nulled. Subclasses may use this method to do any cleanup they need to do
156      * at uninstall time.
157      */

158     protected void uninstall() {
159         //do nothing
160
}
161
162     /**
163      * Installs the mouse listener returned by createMouseListener into the
164      * control. If the mouse listener implements MouseMotionListener or
165      * MouseWheelListener, it will be installed as such as well.
166      */

167     protected final void installListeners() {
168         displayer.addHierarchyListener (hierarchyListener);
169         displayer.addPropertyChangeListener(propertyChangeListener);
170         if (componentListener != null) {
171             displayer.addComponentListener(componentListener);
172         }
173         displayer.getModel().addComplexListDataListener(modelListener);
174         displayer.getModel().addChangeListener(modelListener);
175         if (mouseListener != null) {
176             displayer.addMouseListener(mouseListener);
177             if (mouseListener instanceof MouseMotionListener) {
178                 displayer.addMouseMotionListener(
179                         (MouseMotionListener) mouseListener);
180             }
181             if (mouseListener instanceof MouseWheelListener) {
182                 displayer.addMouseWheelListener((MouseWheelListener) mouseListener);
183             }
184         }
185         selectionModel.addChangeListener(selectionListener);
186     }
187
188     /**
189      * Installs the mouse listener returned by createMouseListener into the
190      * control. If the mouse listener implements MouseMotionListener or
191      * MouseWheelListener, it will be removed as such as well.
192      */

193     protected final void uninstallListeners() {
194         if (mouseListener instanceof MouseMotionListener) {
195             displayer.removeMouseMotionListener(
196                     (MouseMotionListener) mouseListener);
197         }
198         if (mouseListener instanceof MouseWheelListener) {
199             displayer.removeMouseWheelListener(
200                     (MouseWheelListener) mouseListener);
201         }
202         if (mouseListener != null) {
203             displayer.removeMouseListener(mouseListener);
204         }
205         if (componentListener != null) {
206             displayer.removeComponentListener(componentListener);
207         }
208         displayer.getModel().removeComplexListDataListener(modelListener);
209         displayer.getModel().removeChangeListener(modelListener);
210         displayer.removePropertyChangeListener(propertyChangeListener);
211         displayer.removeHierarchyListener(hierarchyListener);
212         selectionModel.removeChangeListener(selectionListener);
213         mouseListener = null;
214         componentListener = null;
215         propertyChangeListener = null;
216         selectionListener = null;
217         modelListener = null;
218         hierarchyListener = null;
219     }
220     
221     protected HierarchyListener createHierarchyListener() {
222         return new DisplayerHierarchyListener();
223     }
224
225     /**
226      * Create an instance of TabLayoutModel which will provide coordinates for
227      * tabs
228      */

229     protected abstract TabLayoutModel createLayoutModel(); //XXX move this to BasicTabDisplayerUI
230

231     /**
232      * Create the mouse listener that will be responsible for changing the
233      * selection on mouse events, triggering repaints on mouse enter/exit/motion, etc.
234      * The installation code will detect if the resulting listener also implements
235      * MouseWheelListener or MouseMotionListener, and if so, will add it as such.
236      *
237      * @return A mouse listener, which may also implement MouseMotionListener and/or
238      * MouseWheelListener
239      */

240     protected abstract MouseListener createMouseListener();
241
242     /**
243      * Create a <code>ChangeListener</code> to be attached to the selection model. This
244      * listener will be responsible for repainting the appropriate areas on selection changes.
245      *
246      * @return A changeListener that will be notified of selection changes
247      */

248     protected abstract ChangeListener JavaDoc createSelectionListener();
249
250     protected Font createFont() {
251         return UIManager.getFont("controlFont"); //NOI18N
252
}
253
254     /**
255      * Create a listener on the data model that triggers repaints on appropriate
256      * changes.
257      */

258     protected ModelListener createModelListener() {
259         return new ModelListener();
260     }
261
262     /**
263      * Create a ComponentListener that may be needed to handle resize, show,
264      * hide, etc. Returns null by default.
265      */

266     protected ComponentListener createComponentListener() {
267         return null;
268     }
269
270     /**
271      * Create a PropertyChangeListener which listens on any interesting
272      * properties of the control
273      */

274     protected PropertyChangeListener JavaDoc createPropertyChangeListener() {
275         return new DisplayerPropertyChangeListener();
276     }
277
278     /** Creates an instance of <code>DefaultTabSelectionModel</code> */
279     protected SingleSelectionModel createSelectionModel() {
280         return new DefaultTabSelectionModel(displayer.getModel());
281     }
282
283     /**
284      * A very basic implementation of dropIndexOfPoint, which simply iterates
285      * all of the tab rectangles to see if they contain the point. It is
286      * preferred to override this and provide a more efficient implementation
287      * unless the UI is not designed to display more than a few tabs.
288      *
289      * @param p A point
290      * @return The index, or -1 if none
291      */

292     public int dropIndexOfPoint(Point p) {
293         Point p2 = toDropPoint(p);
294         int max = displayer.getModel().size();
295         for (int i=0; i < max; i++) {
296             Rectangle r = getTabRect (i, null);
297             if (r.contains(p2)) {
298                 return i;
299             }
300         }
301         return -1;
302     }
303
304     /** Convenience method called by ModelListener.stateChanged() when the data model changes.
305      * Eliminates the need for custom subclasses where the only purpose is to discard some
306      * small amount of cached data. The default implementation simply calls <code>displayer.repaint()</code>.
307      */

308     protected void modelChanged() {
309         displayer.repaint();
310     }
311
312     private Point scratchPoint = new Point();
313     /** Converts a point into a point in the coordinate space of the tabs area, for
314      * determining what index a drop operation should affect.
315      *
316      * @param location A point in the coordinate space of the container
317      * @return A point in the coordinate space of the tab display area
318      */

319     protected Point toDropPoint (Point location) {
320         //Construct a point within the tabs area retaining the relevant coordinate that
321
//will allow it to work
322
if (displayer.getWidth() > displayer.getHeight()) {
323             //horizontal tabs area
324
scratchPoint.setLocation(location.x, (displayer.getHeight() / 2));
325         } else {
326             //vertical tabs area
327
scratchPoint.setLocation (displayer.getWidth() / 2, location.y);
328         }
329         return scratchPoint;
330     }
331
332     /** Does nothing, no shortcuts */
333     public void unregisterShortcuts(JComponent comp) {
334         // no operation
335
}
336     
337     /** Does nothing, no shortcuts */
338     public void registerShortcuts(JComponent comp) {
339         // no operation
340
}
341     
342     /**
343      * A property change listener which will repaint the selected tab when the
344      * &quot;active&quot; property changes on the tab displayer
345      */

346     protected class DisplayerPropertyChangeListener
347             implements PropertyChangeListener JavaDoc {
348         public void propertyChange(PropertyChangeEvent JavaDoc e) {
349             if (displayer.isShowing()
350                     && TabDisplayer.PROP_ACTIVE.equals(e.getPropertyName())) {
351                 activationChanged();
352             }
353         }
354
355         /**
356          * Called if PROP_ACTIVE on the displayer changes
357          */

358         protected void activationChanged() {
359             int i = selectionModel.getSelectedIndex();
360             if (i != -1) {
361                 Rectangle r = new Rectangle();
362                 getTabRect(i, r);
363                 if (r.width != 0 && r.height != 0) {
364                     displayer.repaint(r.x, r.y, r.width, r.height);
365                 }
366             }
367         }
368     }
369
370     /**
371      * A hierarchy listener which registers the component with ToolTipManager
372      * when displayed, and de-registers it when hidden
373      */

374     protected class DisplayerHierarchyListener implements HierarchyListener {
375         public DisplayerHierarchyListener() {
376             
377         }
378         
379         public void hierarchyChanged(HierarchyEvent e) {
380             if (e.getChanged() == displayer && (e.getChangeFlags() & HierarchyEvent.SHOWING_CHANGED) != 0) {
381                 if (displayer.isShowing()) {
382                     ToolTipManager.sharedInstance().registerComponent(displayer);
383                 } else {
384                     ToolTipManager.sharedInstance().unregisterComponent(displayer);
385                 }
386             }
387         }
388     }
389
390     /**
391      * Simple implementation of a listener on a TabDataModel. The default implementation
392      * simply does a full repaint of the tabs area on a ChangeEvent. More optimized
393      * implementations are possible by handling ListDataEvents.
394      */

395     protected class ModelListener implements ComplexListDataListener,
396             ChangeListener JavaDoc {
397
398         private boolean checkVisible = false;
399         /**
400          * No-op implementation
401          */

402         public void contentsChanged(ListDataEvent e) {
403             //do nothing
404
}
405
406         /**
407          * No-op implementation
408          */

409         public void indicesAdded(ComplexListDataEvent e) {
410             //do nothing
411
}
412
413         /**
414          * No-op implementation
415          */

416         public void indicesChanged(ComplexListDataEvent e) {
417             //do nothing
418
}
419
420         /**
421          * No-op implementation
422          */

423         public void indicesRemoved(ComplexListDataEvent e) {
424             //do nothing
425
}
426
427         /**
428          * No-op implementation
429          */

430         public void intervalAdded(ListDataEvent e) {
431             //do nothing
432
}
433
434         /**
435          * No-op implementation
436          */

437         public void intervalRemoved(ListDataEvent e) {
438             //do nothing
439
}
440
441         /**
442          * Called whenever any change happens in the data model (one of the above methods will also
443          * be called with specific data about the change). This method is final, and simply calls
444          * <code>modelChanged()</code>. To discard some cached data when the model changes, simply
445          * override that.
446          */

447         public final void stateChanged(ChangeEvent JavaDoc e) {
448             modelChanged();
449         }
450     }
451
452 }
453
Popular Tags