KickJava   Java API By Example, From Geeks To Geeks.

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


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  * BasicScrollingTabDisplayerUI.java
21  *
22  * Created on March 19, 2004, 1:08 PM
23  */

24
25 package org.netbeans.swing.tabcontrol.plaf;
26
27 import org.netbeans.swing.tabcontrol.TabDisplayer;
28
29 import javax.swing.*;
30 import java.awt.*;
31 import java.awt.event.*;
32 import java.awt.image.BufferedImage JavaDoc;
33 import java.lang.ref.SoftReference JavaDoc;
34
35 /**
36  * Base class for tab displayers that have scrollable tabs.
37  *
38  * @author Tim Boudreau
39  */

40 public abstract class BasicScrollingTabDisplayerUI extends BasicTabDisplayerUI {
41     private Rectangle scratch = new Rectangle();
42     
43     private JPanel controlButtons;
44     
45     private TabControlButton btnScrollLeft;
46     private TabControlButton btnScrollRight;
47     private TabControlButton btnDropDown;
48     private TabControlButton btnMaximizeRestore;
49
50     /**
51      * Creates a new instance of BasicScrollingTabDisplayerUI
52      */

53     public BasicScrollingTabDisplayerUI(TabDisplayer displayer) {
54         super(displayer);
55     }
56
57     protected final TabLayoutModel createLayoutModel() {
58         DefaultTabLayoutModel dtlm = new DefaultTabLayoutModel(
59                 displayer.getModel(),
60                 displayer);
61         return new ScrollingTabLayoutModel(dtlm, selectionModel,
62                 displayer.getModel());
63     }
64
65     protected TabState createTabState() {
66         return new ScrollingTabState();
67     }
68     
69     protected HierarchyListener createHierarchyListener() {
70         return new ScrollingHierarchyListener();
71     }
72
73     public void makeTabVisible (int tab) {
74         if (scroll().makeVisible(tab, getTabsAreaWidth())) {
75             getTabsVisibleArea(scratch);
76             displayer.repaint(scratch.x, scratch.y, scratch.width, scratch.height);
77         }
78     }
79
80     /**
81      * Returns the width of the tabs area
82      */

83     protected final int getTabsAreaWidth() {
84         int result = displayer.getWidth();
85         Insets ins = getTabAreaInsets();
86         return result - (ins.left + ins.right);
87     }
88
89     public Insets getTabAreaInsets() {
90         return new Insets(0, 0, 0, getControlButtons().getPreferredSize().width + 5);
91     }
92
93     protected final int getLastVisibleTab() {
94         if (displayer.getModel().size() == 0) {
95             return -1;
96         }
97         return scroll().getLastVisibleTab(getTabsAreaWidth());
98     }
99
100     protected final int getFirstVisibleTab() {
101         if (displayer.getModel().size() == 0) {
102             return -1;
103         }
104         return scroll().getFirstVisibleTab(getTabsAreaWidth());
105     }
106
107     protected void install() {
108         super.install();
109         installControlButtons();
110         ((ScrollingTabLayoutModel) layoutModel).setPixelsToAddToSelection (
111                 defaultRenderer.getPixelsToAddToSelection());
112     }
113
114     protected void uninstall() {
115         super.uninstall();
116         displayer.setLayout(null);
117         displayer.removeAll();
118     }
119
120     protected LayoutManager createLayout() {
121         return new WCLayout();
122     }
123     
124     /**
125      * @return A component that holds control buttons (scroll left/right, drop down menu)
126      * that are displayed to right of the tab area.
127      */

128     protected Component getControlButtons() {
129         if( null == controlButtons ) {
130             JPanel buttonsPanel = new JPanel( null );
131             buttonsPanel.setOpaque( false );
132
133             int width = 0;
134             int height = 0;
135             
136             //create scroll-left button
137
Action a = scroll().getBackwardAction();
138             a.putValue( "control", displayer ); //NO18N
139
btnScrollLeft = TabControlButtonFactory.createScrollLeftButton( displayer, a );
140             buttonsPanel.add( btnScrollLeft );
141             Icon icon = btnScrollLeft.getIcon();
142             btnScrollLeft.setBounds( width, 0, icon.getIconWidth(), icon.getIconHeight() );
143             width += icon.getIconWidth();
144
145             //create scroll-right button
146
a = scroll().getForwardAction();
147             a.putValue( "control", displayer ); //NO18N
148
btnScrollRight = TabControlButtonFactory.createScrollRightButton( displayer, a );
149             buttonsPanel.add( btnScrollRight );
150             icon = btnScrollRight.getIcon();
151             btnScrollRight.setBounds( width, 0, icon.getIconWidth(), icon.getIconHeight() );
152             width += icon.getIconWidth();
153
154             //create drop down button
155
btnDropDown = TabControlButtonFactory.createDropDownButton( displayer );
156             buttonsPanel.add( btnDropDown );
157
158             icon = btnDropDown.getIcon();
159             width += 3;
160             btnDropDown.setBounds( width, 0, icon.getIconWidth(), icon.getIconHeight() );
161             width += icon.getIconWidth();
162             height = icon.getIconHeight();
163             
164             //maximize / restore button
165
if( null != displayer.getWinsysInfo() ) {
166                 width += 3;
167                 btnMaximizeRestore = TabControlButtonFactory.createMaximizeRestoreButton( displayer );
168                 buttonsPanel.add( btnMaximizeRestore );
169                 icon = btnMaximizeRestore.getIcon();
170                 btnMaximizeRestore.setBounds( width, 0, icon.getIconWidth(), icon.getIconHeight() );
171                 width += icon.getIconWidth();
172             }
173             
174             Dimension size = new Dimension( width, height );
175             buttonsPanel.setMinimumSize( size );
176             buttonsPanel.setSize( size );
177             buttonsPanel.setPreferredSize( size );
178             buttonsPanel.setMaximumSize( size );
179             
180             controlButtons = buttonsPanel;
181         }
182         return controlButtons;
183     }
184     
185     protected ComponentListener createComponentListener() {
186         return new ScrollingDisplayerComponentListener();
187     }
188
189     private int lastKnownModelSize = Integer.MAX_VALUE;
190     /** Overrides <code>modelChanged()</code> to clear the transient information in the
191      * state model, which may now contain tab indices that don't exist, and also
192      * to clear cached width/last-visible-tab data in the layout model, and ensure that
193      * the selected tab is visible.
194      */

195     protected void modelChanged() {
196         scroll().clearCachedData();
197         int index = selectionModel.getSelectedIndex();
198         
199         //If the user has intentionally scrolled the selected tab offscreen, do ensure space is
200
//optimally used, but don't volunteer to radically change the scroll point
201
if (index >= scroll().getCachedFirstVisibleTab() && index < scroll().getCachedLastVisibleTab()) {
202             makeTabVisible(selectionModel.getSelectedIndex());
203         }
204         
205         int modelSize = displayer.getModel().size();
206         if (modelSize < lastKnownModelSize) {
207             //When closing tabs, make sure we resync the state, so the
208
//user doesn't end up with a huge gap due to closed tabs
209
scroll().ensureAvailableSpaceUsed(true);
210         }
211         lastKnownModelSize = modelSize;
212         super.modelChanged();
213     }
214
215     protected void installControlButtons() {
216         displayer.setLayout(createLayout());
217         displayer.add(getControlButtons());
218     }
219
220     public Dimension getMinimumSize(JComponent c) {
221         return getPreferredSize(c);
222     }
223
224     /**
225      * Convenience getter for the layout model as an instance of
226      * ScrollingTabLayoutModel
227      */

228     protected final ScrollingTabLayoutModel scroll() {
229         return (ScrollingTabLayoutModel) layoutModel;
230     }
231
232     /**
233      * Overridden to update the offset of the ScrollingTabLayoutModel on mouse
234      * wheel events
235      */

236     protected void processMouseWheelEvent(MouseWheelEvent e) {
237         int i = e.getWheelRotation();
238         //clear the mouse-in-tab index so we don't occasionally have
239
//tabs the mouse is not in scrolling away looking as if the mouse
240
//is in them
241
tabState.clearTransientStates();
242         int offset = scroll().getOffset();
243         if (i > 0 && (offset < displayer.getModel().size() - 1)) {
244             if (scroll().isLastTabClipped()) {
245                 scroll().setOffset(offset + 1);
246             }
247         } else if (i < 0) {
248             if (offset >= 0) {
249                 scroll().setOffset(offset - 1);
250             }
251         } else {
252             return;
253         }
254         
255
256         //tabState.repaintAllTabs();
257
//XXX should optimize this - need to make sure the space below the tabs
258
//is painted on metal and win classic
259
displayer.repaint();
260     }
261
262
263     protected class ScrollingTabState extends BasicTabState {
264         public int getState(int tabIndex) {
265             int result = super.getState(tabIndex);
266             int first = getFirstVisibleTab();
267             int last = getLastVisibleTab();
268
269             if (tabIndex < first || tabIndex > last) {
270                 return TabState.NOT_ONSCREEN;
271             }
272             if (first == last && first == tabIndex
273                     && displayer.getModel().size() > 1) {
274                 //We have a very small area to fit tabs - smaller than even the
275
//minimum clip width, probably < 40 pixels. Definitely don't
276
//want to display a close button or much of anything else
277
result |= TabState.CLIP_LEFT | TabState.CLIP_RIGHT;
278
279             } else if (getTabsAreaWidth() < scroll()
280                     .getMinimumLeftClippedWidth()
281                     + scroll().getMinimumRightClippedWidth()
282                     && tabIndex == first && last == first - 1 && displayer.getModel()
283                     .size()
284                     > 1 && scroll().isLastTabClipped()) {
285                 //when we're displaying two tabs in less than enough room,
286
//make sure a truncated tab is never displayed with a close button
287
result |= TabState.CLIP_LEFT;
288             } else {
289                 if (tabIndex == first && scroll().getOffset() == first) {
290                     result |= TabState.CLIP_LEFT;
291                 }
292                 if (tabIndex == last && scroll().isLastTabClipped()) {
293                     result |= TabState.CLIP_RIGHT;
294                 }
295             }
296             return result;
297         }
298     }
299
300     protected class ScrollingDisplayerComponentListener extends ComponentAdapter {
301         public void componentResized(ComponentEvent e) {
302             //Notify the layout model that its cached sizes are invalid
303
makeTabVisible(selectionModel.getSelectedIndex());
304         }
305     }
306     
307     protected class ScrollingHierarchyListener extends DisplayerHierarchyListener {
308         public void hierarchyChanged(HierarchyEvent e) {
309             super.hierarchyChanged (e);
310             if ((e.getChangeFlags() & HierarchyEvent.SHOWING_CHANGED) != 0) {
311                 if (displayer.isShowing()) {
312                     //#47850 - for some reason, uninstall can be called on the Ui class, before this gets processed.
313
// check for null values just to be sure.
314
if (tabState != null && selectionModel != null) {
315                         tabState.setActive (displayer.isActive());
316                         makeTabVisible (selectionModel.getSelectedIndex());
317                     }
318                 }
319             }
320         }
321     }
322
323     static SoftReference JavaDoc<BufferedImage JavaDoc> ctx = null;
324
325     /**
326      * Provides an offscreen graphics context so that widths based on character
327      * size can be calculated correctly before the component is shown
328      */

329     public static Graphics2D getOffscreenGraphics() {
330         BufferedImage JavaDoc result = null;
331         //XXX multi-monitors w/ different resolution may have problems;
332
//Better to call Toolkit to create a screen graphics
333
if (ctx != null) {
334             result = ctx.get();
335         }
336         if (result == null) {
337             result = new BufferedImage JavaDoc(10, 10, BufferedImage.TYPE_INT_RGB);
338             ctx = new SoftReference JavaDoc<BufferedImage JavaDoc>(result);
339         }
340         return (Graphics2D) result.getGraphics();
341     }
342
343     /**
344      * @return Bounds for the control buttons in the tab displayer container.
345      */

346     protected Rectangle getControlButtonsRectangle( Container parent ) {
347         Component c = getControlButtons();
348         return new Rectangle( parent.getWidth()-c.getWidth(), 0, c.getWidth(), c.getHeight() );
349     }
350     
351     /**
352      * Layout manager for the tab displayer to make sure that control buttons
353      * are always displayed at the end of the tab list.
354      */

355     private class WCLayout implements LayoutManager {
356
357         public void addLayoutComponent(String JavaDoc name, Component comp) {
358         }
359
360         public void layoutContainer(java.awt.Container JavaDoc parent) {
361             
362             Rectangle r = getControlButtonsRectangle( parent );
363             Component c = getControlButtons();
364             c.setBounds( r );
365         }
366
367         public Dimension minimumLayoutSize(Container parent) {
368             return getPreferredSize((JComponent) parent);
369         }
370
371         public Dimension preferredLayoutSize(Container parent) {
372             return getPreferredSize((JComponent) parent);
373         }
374
375         public void removeLayoutComponent(java.awt.Component JavaDoc comp) {
376         }
377     }
378 }
379
Popular Tags