KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > javax > swing > ScrollPaneLayout


1 /*
2  * @(#)ScrollPaneLayout.java 1.60 04/05/18
3  *
4  * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
5  * SUN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
6  */

7
8 package javax.swing;
9
10
11 import javax.swing.border.*;
12
13 import java.awt.LayoutManager JavaDoc;
14 import java.awt.Component JavaDoc;
15 import java.awt.Container JavaDoc;
16 import java.awt.Rectangle JavaDoc;
17 import java.awt.Dimension JavaDoc;
18 import java.awt.Insets JavaDoc;
19 import java.io.Serializable JavaDoc;
20
21
22 /**
23  * The layout manager used by <code>JScrollPane</code>.
24  * <code>JScrollPaneLayout</code> is
25  * responsible for nine components: a viewport, two scrollbars,
26  * a row header, a column header, and four "corner" components.
27  * <p>
28  * <strong>Warning:</strong>
29  * Serialized objects of this class will not be compatible with
30  * future Swing releases. The current serialization support is
31  * appropriate for short term storage or RMI between applications running
32  * the same version of Swing. As of 1.4, support for long term storage
33  * of all JavaBeans<sup><font size="-2">TM</font></sup>
34  * has been added to the <code>java.beans</code> package.
35  * Please see {@link java.beans.XMLEncoder}.
36  *
37  * @see JScrollPane
38  * @see JViewport
39  *
40  * @version 1.60 05/18/04
41  * @author Hans Muller
42  */

43 public class ScrollPaneLayout
44     implements LayoutManager JavaDoc, ScrollPaneConstants JavaDoc, Serializable JavaDoc
45 {
46
47     /**
48      * The scrollpane's viewport child.
49      * Default is an empty <code>JViewport</code>.
50      * @see JScrollPane#setViewport
51      */

52     protected JViewport JavaDoc viewport;
53
54
55     /**
56      * The scrollpane's vertical scrollbar child.
57      * Default is a <code>JScrollBar</code>.
58      * @see JScrollPane#setVerticalScrollBar
59      */

60     protected JScrollBar JavaDoc vsb;
61
62
63     /**
64      * The scrollpane's horizontal scrollbar child.
65      * Default is a <code>JScrollBar</code>.
66      * @see JScrollPane#setHorizontalScrollBar
67      */

68     protected JScrollBar JavaDoc hsb;
69
70
71     /**
72      * The row header child. Default is <code>null</code>.
73      * @see JScrollPane#setRowHeader
74      */

75     protected JViewport JavaDoc rowHead;
76
77
78     /**
79      * The column header child. Default is <code>null</code>.
80      * @see JScrollPane#setColumnHeader
81      */

82     protected JViewport JavaDoc colHead;
83
84
85     /**
86      * The component to display in the lower left corner.
87      * Default is <code>null</code>.
88      * @see JScrollPane#setCorner
89      */

90     protected Component JavaDoc lowerLeft;
91
92
93     /**
94      * The component to display in the lower right corner.
95      * Default is <code>null</code>.
96      * @see JScrollPane#setCorner
97      */

98     protected Component JavaDoc lowerRight;
99
100
101     /**
102      * The component to display in the upper left corner.
103      * Default is <code>null</code>.
104      * @see JScrollPane#setCorner
105      */

106     protected Component JavaDoc upperLeft;
107
108
109     /**
110      * The component to display in the upper right corner.
111      * Default is <code>null</code>.
112      * @see JScrollPane#setCorner
113      */

114     protected Component JavaDoc upperRight;
115
116
117     /**
118      * The display policy for the vertical scrollbar.
119      * The default is <code>JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED</code>.
120      * <p>
121      * This field is obsolete, please use the <code>JScrollPane</code> field instead.
122      *
123      * @see JScrollPane#setVerticalScrollBarPolicy
124      */

125     protected int vsbPolicy = VERTICAL_SCROLLBAR_AS_NEEDED;
126
127
128     /**
129      * The display policy for the horizontal scrollbar.
130      * The default is <code>JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED</code>.
131      * <p>
132      * This field is obsolete, please use the <code>JScrollPane</code> field instead.
133      *
134      * @see JScrollPane#setHorizontalScrollBarPolicy
135      */

136     protected int hsbPolicy = HORIZONTAL_SCROLLBAR_AS_NEEDED;
137
138
139     /**
140      * This method is invoked after the ScrollPaneLayout is set as the
141      * LayoutManager of a <code>JScrollPane</code>.
142      * It initializes all of the internal fields that
143      * are ordinarily set by <code>addLayoutComponent</code>. For example:
144      * <pre>
145      * ScrollPaneLayout mySPLayout = new ScrollPanelLayout() {
146      * public void layoutContainer(Container p) {
147      * super.layoutContainer(p);
148      * // do some extra work here ...
149      * }
150      * };
151      * scrollpane.setLayout(mySPLayout):
152      * </pre>
153      */

154     public void syncWithScrollPane(JScrollPane JavaDoc sp) {
155     viewport = sp.getViewport();
156     vsb = sp.getVerticalScrollBar();
157     hsb = sp.getHorizontalScrollBar();
158     rowHead = sp.getRowHeader();
159     colHead = sp.getColumnHeader();
160     lowerLeft = sp.getCorner(LOWER_LEFT_CORNER);
161     lowerRight = sp.getCorner(LOWER_RIGHT_CORNER);
162     upperLeft = sp.getCorner(UPPER_LEFT_CORNER);
163     upperRight = sp.getCorner(UPPER_RIGHT_CORNER);
164     vsbPolicy = sp.getVerticalScrollBarPolicy();
165     hsbPolicy = sp.getHorizontalScrollBarPolicy();
166     }
167
168
169     /**
170      * Removes an existing component. When a new component, such as
171      * the left corner, or vertical scrollbar, is added, the old one,
172      * if it exists, must be removed.
173      * <p>
174      * This method returns <code>newC</code>. If <code>oldC</code> is
175      * not equal to <code>newC</code> and is non-<code>null</code>,
176      * it will be removed from its parent.
177      *
178      * @param oldC the <code>Component</code> to replace
179      * @param newC the <code>Component</code> to add
180      * @return the <code>newC</code>
181      */

182     protected Component JavaDoc addSingletonComponent(Component JavaDoc oldC, Component JavaDoc newC)
183     {
184     if ((oldC != null) && (oldC != newC)) {
185         oldC.getParent().remove(oldC);
186     }
187     return newC;
188     }
189
190
191     /**
192      * Adds the specified component to the layout. The layout is
193      * identified using one of:
194      * <ul>
195      * <li>JScrollPane.VIEWPORT
196      * <li>JScrollPane.VERTICAL_SCROLLBAR
197      * <li>JScrollPane.HORIZONTAL_SCROLLBAR
198      * <li>JScrollPane.ROW_HEADER
199      * <li>JScrollPane.COLUMN_HEADER
200      * <li>JScrollPane.LOWER_LEFT_CORNER
201      * <li>JScrollPane.LOWER_RIGHT_CORNER
202      * <li>JScrollPane.UPPER_LEFT_CORNER
203      * <li>JScrollPane.UPPER_RIGHT_CORNER
204      * </ul>
205      *
206      * @param s the component identifier
207      * @param c the the component to be added
208      * @exception IllegalArgumentException if <code>s</code> is an invalid key
209      */

210     public void addLayoutComponent(String JavaDoc s, Component JavaDoc c)
211     {
212     if (s.equals(VIEWPORT)) {
213         viewport = (JViewport JavaDoc)addSingletonComponent(viewport, c);
214     }
215     else if (s.equals(VERTICAL_SCROLLBAR)) {
216         vsb = (JScrollBar JavaDoc)addSingletonComponent(vsb, c);
217     }
218     else if (s.equals(HORIZONTAL_SCROLLBAR)) {
219         hsb = (JScrollBar JavaDoc)addSingletonComponent(hsb, c);
220     }
221     else if (s.equals(ROW_HEADER)) {
222         rowHead = (JViewport JavaDoc)addSingletonComponent(rowHead, c);
223     }
224     else if (s.equals(COLUMN_HEADER)) {
225         colHead = (JViewport JavaDoc)addSingletonComponent(colHead, c);
226     }
227     else if (s.equals(LOWER_LEFT_CORNER)) {
228         lowerLeft = addSingletonComponent(lowerLeft, c);
229     }
230     else if (s.equals(LOWER_RIGHT_CORNER)) {
231         lowerRight = addSingletonComponent(lowerRight, c);
232     }
233     else if (s.equals(UPPER_LEFT_CORNER)) {
234         upperLeft = addSingletonComponent(upperLeft, c);
235     }
236     else if (s.equals(UPPER_RIGHT_CORNER)) {
237         upperRight = addSingletonComponent(upperRight, c);
238     }
239     else {
240         throw new IllegalArgumentException JavaDoc("invalid layout key " + s);
241     }
242     }
243
244
245     /**
246      * Removes the specified component from the layout.
247      *
248      * @param c the component to remove
249      */

250     public void removeLayoutComponent(Component JavaDoc c)
251     {
252     if (c == viewport) {
253         viewport = null;
254     }
255     else if (c == vsb) {
256         vsb = null;
257     }
258     else if (c == hsb) {
259         hsb = null;
260     }
261     else if (c == rowHead) {
262         rowHead = null;
263     }
264     else if (c == colHead) {
265         colHead = null;
266     }
267     else if (c == lowerLeft) {
268         lowerLeft = null;
269     }
270     else if (c == lowerRight) {
271         lowerRight = null;
272     }
273     else if (c == upperLeft) {
274         upperLeft = null;
275     }
276     else if (c == upperRight) {
277         upperRight = null;
278     }
279     }
280
281
282     /**
283      * Returns the vertical scrollbar-display policy.
284      *
285      * @return an integer giving the display policy
286      * @see #setVerticalScrollBarPolicy
287      */

288     public int getVerticalScrollBarPolicy() {
289     return vsbPolicy;
290     }
291
292
293     /**
294      * Sets the vertical scrollbar-display policy. The options
295      * are:
296      * <ul>
297      * <li>JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED
298      * <li>JScrollPane.VERTICAL_SCROLLBAR_NEVER
299      * <li>JScrollPane.VERTICAL_SCROLLBAR_ALWAYS
300      * </ul>
301      * Note: Applications should use the <code>JScrollPane</code> version
302      * of this method. It only exists for backwards compatibility
303      * with the Swing 1.0.2 (and earlier) versions of this class.
304      *
305      * @param x an integer giving the display policy
306      * @exception IllegalArgumentException if <code>x</code> is an invalid
307      * vertical scroll bar policy, as listed above
308      */

309     public void setVerticalScrollBarPolicy(int x) {
310     switch (x) {
311     case VERTICAL_SCROLLBAR_AS_NEEDED:
312     case VERTICAL_SCROLLBAR_NEVER:
313     case VERTICAL_SCROLLBAR_ALWAYS:
314             vsbPolicy = x;
315         break;
316     default:
317         throw new IllegalArgumentException JavaDoc("invalid verticalScrollBarPolicy");
318     }
319     }
320
321
322     /**
323      * Returns the horizontal scrollbar-display policy.
324      *
325      * @return an integer giving the display policy
326      * @see #setHorizontalScrollBarPolicy
327      */

328     public int getHorizontalScrollBarPolicy() {
329     return hsbPolicy;
330     }
331
332     /**
333      * Sets the horizontal scrollbar-display policy.
334      * The options are:<ul>
335      * <li>JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED
336      * <li>JScrollPane.HOTRIZONTAL_SCROLLBAR_NEVER
337      * <li>JScrollPane.HORIZONTAL_SCROLLBAR_ALWAYS
338      * </ul>
339      * Note: Applications should use the <code>JScrollPane</code> version
340      * of this method. It only exists for backwards compatibility
341      * with the Swing 1.0.2 (and earlier) versions of this class.
342      *
343      * @param x an int giving the display policy
344      * @exception IllegalArgumentException if <code>x</code> is not a valid
345      * horizontal scrollbar policy, as listed above
346      */

347     public void setHorizontalScrollBarPolicy(int x) {
348     switch (x) {
349     case HORIZONTAL_SCROLLBAR_AS_NEEDED:
350     case HORIZONTAL_SCROLLBAR_NEVER:
351     case HORIZONTAL_SCROLLBAR_ALWAYS:
352             hsbPolicy = x;
353         break;
354     default:
355         throw new IllegalArgumentException JavaDoc("invalid horizontalScrollBarPolicy");
356     }
357     }
358
359
360     /**
361      * Returns the <code>JViewport</code> object that displays the
362      * scrollable contents.
363      * @return the <code>JViewport</code> object that displays the scrollable contents
364      * @see JScrollPane#getViewport
365      */

366     public JViewport JavaDoc getViewport() {
367     return viewport;
368     }
369
370
371     /**
372      * Returns the <code>JScrollBar</code> object that handles horizontal scrolling.
373      * @return the <code>JScrollBar</code> object that handles horizontal scrolling
374      * @see JScrollPane#getHorizontalScrollBar
375      */

376     public JScrollBar JavaDoc getHorizontalScrollBar() {
377     return hsb;
378     }
379
380     /**
381      * Returns the <code>JScrollBar</code> object that handles vertical scrolling.
382      * @return the <code>JScrollBar</code> object that handles vertical scrolling
383      * @see JScrollPane#getVerticalScrollBar
384      */

385     public JScrollBar JavaDoc getVerticalScrollBar() {
386     return vsb;
387     }
388
389
390     /**
391      * Returns the <code>JViewport</code> object that is the row header.
392      * @return the <code>JViewport</code> object that is the row header
393      * @see JScrollPane#getRowHeader
394      */

395     public JViewport JavaDoc getRowHeader() {
396     return rowHead;
397     }
398
399
400     /**
401      * Returns the <code>JViewport</code> object that is the column header.
402      * @return the <code>JViewport</code> object that is the column header
403      * @see JScrollPane#getColumnHeader
404      */

405     public JViewport JavaDoc getColumnHeader() {
406     return colHead;
407     }
408
409
410     /**
411      * Returns the <code>Component</code> at the specified corner.
412      * @param key the <code>String</code> specifying the corner
413      * @return the <code>Component</code> at the specified corner, as defined in
414      * {@link ScrollPaneConstants}; if <code>key</code> is not one of the
415      * four corners, <code>null</code> is returned
416      * @see JScrollPane#getCorner
417      */

418     public Component JavaDoc getCorner(String JavaDoc key) {
419     if (key.equals(LOWER_LEFT_CORNER)) {
420         return lowerLeft;
421     }
422     else if (key.equals(LOWER_RIGHT_CORNER)) {
423         return lowerRight;
424     }
425     else if (key.equals(UPPER_LEFT_CORNER)) {
426         return upperLeft;
427     }
428     else if (key.equals(UPPER_RIGHT_CORNER)) {
429         return upperRight;
430     }
431     else {
432         return null;
433     }
434     }
435
436
437     /**
438      * The preferred size of a <code>ScrollPane</code> is the size of the insets,
439      * plus the preferred size of the viewport, plus the preferred size of
440      * the visible headers, plus the preferred size of the scrollbars
441      * that will appear given the current view and the current
442      * scrollbar displayPolicies.
443      * <p>Note that the rowHeader is calculated as part of the preferred width
444      * and the colHeader is calculated as part of the preferred size.
445      *
446      * @param parent the <code>Container</code> that will be laid out
447      * @return a <code>Dimension</code> object specifying the preferred size of the
448      * viewport and any scrollbars
449      * @see ViewportLayout
450      * @see LayoutManager
451      */

452     public Dimension JavaDoc preferredLayoutSize(Container JavaDoc parent)
453     {
454     /* Sync the (now obsolete) policy fields with the
455      * JScrollPane.
456      */

457     JScrollPane JavaDoc scrollPane = (JScrollPane JavaDoc)parent;
458     vsbPolicy = scrollPane.getVerticalScrollBarPolicy();
459     hsbPolicy = scrollPane.getHorizontalScrollBarPolicy();
460
461     Insets JavaDoc insets = parent.getInsets();
462     int prefWidth = insets.left + insets.right;
463     int prefHeight = insets.top + insets.bottom;
464
465     /* Note that viewport.getViewSize() is equivalent to
466      * viewport.getView().getPreferredSize() modulo a null
467      * view or a view whose size was explicitly set.
468      */

469
470     Dimension JavaDoc extentSize = null;
471     Dimension JavaDoc viewSize = null;
472     Component JavaDoc view = null;
473
474     if (viewport != null) {
475         extentSize = viewport.getPreferredSize();
476         viewSize = viewport.getViewSize();
477         view = viewport.getView();
478     }
479
480     /* If there's a viewport add its preferredSize.
481      */

482
483     if (extentSize != null) {
484         prefWidth += extentSize.width;
485         prefHeight += extentSize.height;
486     }
487
488     /* If there's a JScrollPane.viewportBorder, add its insets.
489      */

490
491     Border viewportBorder = scrollPane.getViewportBorder();
492     if (viewportBorder != null) {
493         Insets JavaDoc vpbInsets = viewportBorder.getBorderInsets(parent);
494         prefWidth += vpbInsets.left + vpbInsets.right;
495         prefHeight += vpbInsets.top + vpbInsets.bottom;
496     }
497
498     /* If a header exists and it's visible, factor its
499      * preferred size in.
500      */

501
502     if ((rowHead != null) && rowHead.isVisible()) {
503         prefWidth += rowHead.getPreferredSize().width;
504     }
505
506     if ((colHead != null) && colHead.isVisible()) {
507         prefHeight += colHead.getPreferredSize().height;
508     }
509
510     /* If a scrollbar is going to appear, factor its preferred size in.
511      * If the scrollbars policy is AS_NEEDED, this can be a little
512      * tricky:
513      *
514      * - If the view is a Scrollable then scrollableTracksViewportWidth
515      * and scrollableTracksViewportHeight can be used to effectively
516      * disable scrolling (if they're true) in their respective dimensions.
517      *
518      * - Assuming that a scrollbar hasn't been disabled by the
519      * previous constraint, we need to decide if the scrollbar is going
520      * to appear to correctly compute the JScrollPanes preferred size.
521      * To do this we compare the preferredSize of the viewport (the
522      * extentSize) to the preferredSize of the view. Although we're
523      * not responsible for laying out the view we'll assume that the
524      * JViewport will always give it its preferredSize.
525      */

526
527     if ((vsb != null) && (vsbPolicy != VERTICAL_SCROLLBAR_NEVER)) {
528         if (vsbPolicy == VERTICAL_SCROLLBAR_ALWAYS) {
529         prefWidth += vsb.getPreferredSize().width;
530         }
531         else if ((viewSize != null) && (extentSize != null)) {
532         boolean canScroll = true;
533         if (view instanceof Scrollable JavaDoc) {
534             canScroll = !((Scrollable JavaDoc)view).getScrollableTracksViewportHeight();
535         }
536         if (canScroll && (viewSize.height > extentSize.height)) {
537             prefWidth += vsb.getPreferredSize().width;
538         }
539         }
540     }
541
542     if ((hsb != null) && (hsbPolicy != HORIZONTAL_SCROLLBAR_NEVER)) {
543         if (hsbPolicy == HORIZONTAL_SCROLLBAR_ALWAYS) {
544         prefHeight += hsb.getPreferredSize().height;
545         }
546         else if ((viewSize != null) && (extentSize != null)) {
547         boolean canScroll = true;
548         if (view instanceof Scrollable JavaDoc) {
549             canScroll = !((Scrollable JavaDoc)view).getScrollableTracksViewportWidth();
550         }
551         if (canScroll && (viewSize.width > extentSize.width)) {
552             prefHeight += hsb.getPreferredSize().height;
553         }
554         }
555     }
556
557     return new Dimension JavaDoc(prefWidth, prefHeight);
558     }
559
560
561     /**
562      * The minimum size of a <code>ScrollPane</code> is the size of the insets
563      * plus minimum size of the viewport, plus the scrollpane's
564      * viewportBorder insets, plus the minimum size
565      * of the visible headers, plus the minimum size of the
566      * scrollbars whose displayPolicy isn't NEVER.
567      *
568      * @param parent the <code>Container</code> that will be laid out
569      * @return a <code>Dimension</code> object specifying the minimum size
570      */

571     public Dimension JavaDoc minimumLayoutSize(Container JavaDoc parent)
572     {
573     /* Sync the (now obsolete) policy fields with the
574      * JScrollPane.
575      */

576     JScrollPane JavaDoc scrollPane = (JScrollPane JavaDoc)parent;
577     vsbPolicy = scrollPane.getVerticalScrollBarPolicy();
578     hsbPolicy = scrollPane.getHorizontalScrollBarPolicy();
579
580     Insets JavaDoc insets = parent.getInsets();
581     int minWidth = insets.left + insets.right;
582     int minHeight = insets.top + insets.bottom;
583     
584     /* If there's a viewport add its minimumSize.
585      */

586     
587     if (viewport != null) {
588         Dimension JavaDoc size = viewport.getMinimumSize();
589         minWidth += size.width;
590         minHeight += size.height;
591     }
592
593     /* If there's a JScrollPane.viewportBorder, add its insets.
594      */

595
596     Border viewportBorder = scrollPane.getViewportBorder();
597     if (viewportBorder != null) {
598         Insets JavaDoc vpbInsets = viewportBorder.getBorderInsets(parent);
599         minWidth += vpbInsets.left + vpbInsets.right;
600         minHeight += vpbInsets.top + vpbInsets.bottom;
601     }
602
603     /* If a header exists and it's visible, factor its
604      * minimum size in.
605      */

606
607     if ((rowHead != null) && rowHead.isVisible()) {
608         Dimension JavaDoc size = rowHead.getMinimumSize();
609         minWidth += size.width;
610         minHeight = Math.max(minHeight, size.height);
611     }
612
613     if ((colHead != null) && colHead.isVisible()) {
614         Dimension JavaDoc size = colHead.getMinimumSize();
615         minWidth = Math.max(minWidth, size.width);
616         minHeight += size.height;
617     }
618
619     /* If a scrollbar might appear, factor its minimum
620      * size in.
621      */

622
623     if ((vsb != null) && (vsbPolicy != VERTICAL_SCROLLBAR_NEVER)) {
624         Dimension JavaDoc size = vsb.getMinimumSize();
625         minWidth += size.width;
626         minHeight = Math.max(minHeight, size.height);
627     }
628
629     if ((hsb != null) && (hsbPolicy != HORIZONTAL_SCROLLBAR_NEVER)) {
630         Dimension JavaDoc size = hsb.getMinimumSize();
631         minWidth = Math.max(minWidth, size.width);
632         minHeight += size.height;
633     }
634
635     return new Dimension JavaDoc(minWidth, minHeight);
636     }
637
638
639     /**
640      * Lays out the scrollpane. The positioning of components depends on
641      * the following constraints:
642      * <ul>
643      * <li> The row header, if present and visible, gets its preferred
644      * width and the viewport's height.
645      *
646      * <li> The column header, if present and visible, gets its preferred
647      * height and the viewport's width.
648      *
649      * <li> If a vertical scrollbar is needed, i.e. if the viewport's extent
650      * height is smaller than its view height or if the <code>displayPolicy</code>
651      * is ALWAYS, it's treated like the row header with respect to its
652      * dimensions and is made visible.
653      *
654      * <li> If a horizontal scrollbar is needed, it is treated like the
655      * column header (see the paragraph above regarding the vertical scrollbar).
656      *
657      * <li> If the scrollpane has a non-<code>null</code>
658      * <code>viewportBorder</code>, then space is allocated for that.
659      *
660      * <li> The viewport gets the space available after accounting for
661      * the previous constraints.
662      *
663      * <li> The corner components, if provided, are aligned with the
664      * ends of the scrollbars and headers. If there is a vertical
665      * scrollbar, the right corners appear; if there is a horizontal
666      * scrollbar, the lower corners appear; a row header gets left
667      * corners, and a column header gets upper corners.
668      * </ul>
669      *
670      * @param parent the <code>Container</code> to lay out
671      */

672     public void layoutContainer(Container JavaDoc parent)
673     {
674     /* Sync the (now obsolete) policy fields with the
675      * JScrollPane.
676      */

677     JScrollPane JavaDoc scrollPane = (JScrollPane JavaDoc)parent;
678     vsbPolicy = scrollPane.getVerticalScrollBarPolicy();
679     hsbPolicy = scrollPane.getHorizontalScrollBarPolicy();
680
681     Rectangle JavaDoc availR = scrollPane.getBounds();
682     availR.x = availR.y = 0;
683
684     Insets JavaDoc insets = parent.getInsets();
685     availR.x = insets.left;
686     availR.y = insets.top;
687     availR.width -= insets.left + insets.right;
688     availR.height -= insets.top + insets.bottom;
689
690         /* Get the scrollPane's orientation.
691          */

692         boolean leftToRight = SwingUtilities.isLeftToRight(scrollPane);
693
694     /* If there's a visible column header remove the space it
695      * needs from the top of availR. The column header is treated
696      * as if it were fixed height, arbitrary width.
697      */

698
699     Rectangle JavaDoc colHeadR = new Rectangle JavaDoc(0, availR.y, 0, 0);
700
701     if ((colHead != null) && (colHead.isVisible())) {
702         int colHeadHeight = Math.min(availR.height,
703                                          colHead.getPreferredSize().height);
704         colHeadR.height = colHeadHeight;
705         availR.y += colHeadHeight;
706         availR.height -= colHeadHeight;
707     }
708
709     /* If there's a visible row header remove the space it needs
710      * from the left or right of availR. The row header is treated
711      * as if it were fixed width, arbitrary height.
712      */

713
714     Rectangle JavaDoc rowHeadR = new Rectangle JavaDoc(0, 0, 0, 0);
715     
716     if ((rowHead != null) && (rowHead.isVisible())) {
717         int rowHeadWidth = Math.min(availR.width,
718                                         rowHead.getPreferredSize().width);
719         rowHeadR.width = rowHeadWidth;
720         availR.width -= rowHeadWidth;
721             if ( leftToRight ) {
722                 rowHeadR.x = availR.x;
723                 availR.x += rowHeadWidth;
724             } else {
725                 rowHeadR.x = availR.x + availR.width;
726             }
727     }
728
729     /* If there's a JScrollPane.viewportBorder, remove the
730      * space it occupies for availR.
731      */

732
733     Border viewportBorder = scrollPane.getViewportBorder();
734     Insets JavaDoc vpbInsets;
735     if (viewportBorder != null) {
736         vpbInsets = viewportBorder.getBorderInsets(parent);
737         availR.x += vpbInsets.left;
738         availR.y += vpbInsets.top;
739         availR.width -= vpbInsets.left + vpbInsets.right;
740         availR.height -= vpbInsets.top + vpbInsets.bottom;
741     }
742     else {
743         vpbInsets = new Insets JavaDoc(0,0,0,0);
744     }
745
746
747     /* At this point availR is the space available for the viewport
748      * and scrollbars. rowHeadR is correct except for its height and y
749          * and colHeadR is correct except for its width and x. Once we're
750      * through computing the dimensions of these three parts we can
751      * go back and set the dimensions of rowHeadR.height, rowHeadR.y,
752          * colHeadR.width, colHeadR.x and the bounds for the corners.
753      *
754          * We'll decide about putting up scrollbars by comparing the
755          * viewport views preferred size with the viewports extent
756      * size (generally just its size). Using the preferredSize is
757      * reasonable because layout proceeds top down - so we expect
758      * the viewport to be laid out next. And we assume that the
759      * viewports layout manager will give the view it's preferred
760      * size. One exception to this is when the view implements
761      * Scrollable and Scrollable.getViewTracksViewport{Width,Height}
762      * methods return true. If the view is tracking the viewports
763      * width we don't bother with a horizontal scrollbar, similarly
764      * if view.getViewTracksViewport(Height) is true we don't bother
765      * with a vertical scrollbar.
766      */

767
768     Component JavaDoc view = (viewport != null) ? viewport.getView() : null;
769     Dimension JavaDoc viewPrefSize =
770         (view != null) ? view.getPreferredSize()
771                            : new Dimension JavaDoc(0,0);
772
773     Dimension JavaDoc extentSize =
774         (viewport != null) ? viewport.toViewCoordinates(availR.getSize())
775                            : new Dimension JavaDoc(0,0);
776
777     boolean viewTracksViewportWidth = false;
778     boolean viewTracksViewportHeight = false;
779         boolean isEmpty = (availR.width < 0 || availR.height < 0);
780     Scrollable JavaDoc sv;
781         // Don't bother checking the Scrollable methods if there is no room
782
// for the viewport, we aren't going to show any scrollbars in this
783
// case anyway.
784
if (!isEmpty && view instanceof Scrollable JavaDoc) {
785         sv = (Scrollable JavaDoc)view;
786         viewTracksViewportWidth = sv.getScrollableTracksViewportWidth();
787         viewTracksViewportHeight = sv.getScrollableTracksViewportHeight();
788     }
789     else {
790         sv = null;
791     }
792
793     /* If there's a vertical scrollbar and we need one, allocate
794      * space for it (we'll make it visible later). A vertical
795      * scrollbar is considered to be fixed width, arbitrary height.
796      */

797
798     Rectangle JavaDoc vsbR = new Rectangle JavaDoc(0, availR.y - vpbInsets.top, 0, 0);
799
800     boolean vsbNeeded;
801         if (isEmpty) {
802             vsbNeeded = false;
803         }
804     else if (vsbPolicy == VERTICAL_SCROLLBAR_ALWAYS) {
805         vsbNeeded = true;
806     }
807     else if (vsbPolicy == VERTICAL_SCROLLBAR_NEVER) {
808         vsbNeeded = false;
809     }
810     else { // vsbPolicy == VERTICAL_SCROLLBAR_AS_NEEDED
811
vsbNeeded = !viewTracksViewportHeight && (viewPrefSize.height > extentSize.height);
812     }
813
814
815     if ((vsb != null) && vsbNeeded) {
816         adjustForVSB(true, availR, vsbR, vpbInsets, leftToRight);
817         extentSize = viewport.toViewCoordinates(availR.getSize());
818     }
819     
820     /* If there's a horizontal scrollbar and we need one, allocate
821      * space for it (we'll make it visible later). A horizontal
822      * scrollbar is considered to be fixed height, arbitrary width.
823      */

824
825     Rectangle JavaDoc hsbR = new Rectangle JavaDoc(availR.x - vpbInsets.left, 0, 0, 0);
826     boolean hsbNeeded;
827         if (isEmpty) {
828             hsbNeeded = false;
829         }
830     else if (hsbPolicy == HORIZONTAL_SCROLLBAR_ALWAYS) {
831         hsbNeeded = true;
832     }
833     else if (hsbPolicy == HORIZONTAL_SCROLLBAR_NEVER) {
834         hsbNeeded = false;
835     }
836     else { // hsbPolicy == HORIZONTAL_SCROLLBAR_AS_NEEDED
837
hsbNeeded = !viewTracksViewportWidth && (viewPrefSize.width > extentSize.width);
838     }
839
840     if ((hsb != null) && hsbNeeded) {
841         adjustForHSB(true, availR, hsbR, vpbInsets);
842
843         /* If we added the horizontal scrollbar then we've implicitly
844          * reduced the vertical space available to the viewport.
845          * As a consequence we may have to add the vertical scrollbar,
846          * if that hasn't been done so already. Of course we
847          * don't bother with any of this if the vsbPolicy is NEVER.
848          */

849         if ((vsb != null) && !vsbNeeded &&
850         (vsbPolicy != VERTICAL_SCROLLBAR_NEVER)) {
851
852         extentSize = viewport.toViewCoordinates(availR.getSize());
853         vsbNeeded = viewPrefSize.height > extentSize.height;
854
855         if (vsbNeeded) {
856             adjustForVSB(true, availR, vsbR, vpbInsets, leftToRight);
857         }
858         }
859     }
860
861     /* Set the size of the viewport first, and then recheck the Scrollable
862      * methods. Some components base their return values for the Scrollable
863      * methods on the size of the Viewport, so that if we don't
864      * ask after resetting the bounds we may have gotten the wrong
865      * answer.
866      */

867     
868     if (viewport != null) {
869         viewport.setBounds(availR);
870
871         if (sv != null) {
872         extentSize = viewport.toViewCoordinates(availR.getSize());
873
874         boolean oldHSBNeeded = hsbNeeded;
875         boolean oldVSBNeeded = vsbNeeded;
876         viewTracksViewportWidth = sv.
877                                   getScrollableTracksViewportWidth();
878         viewTracksViewportHeight = sv.
879                                   getScrollableTracksViewportHeight();
880         if (vsb != null && vsbPolicy == VERTICAL_SCROLLBAR_AS_NEEDED) {
881             boolean newVSBNeeded = !viewTracksViewportHeight &&
882                              (viewPrefSize.height > extentSize.height);
883             if (newVSBNeeded != vsbNeeded) {
884             vsbNeeded = newVSBNeeded;
885             adjustForVSB(vsbNeeded, availR, vsbR, vpbInsets,
886                      leftToRight);
887             extentSize = viewport.toViewCoordinates
888                                   (availR.getSize());
889             }
890         }
891         if (hsb != null && hsbPolicy ==HORIZONTAL_SCROLLBAR_AS_NEEDED){
892             boolean newHSBbNeeded = !viewTracksViewportWidth &&
893                            (viewPrefSize.width > extentSize.width);
894             if (newHSBbNeeded != hsbNeeded) {
895             hsbNeeded = newHSBbNeeded;
896             adjustForHSB(hsbNeeded, availR, hsbR, vpbInsets);
897             if ((vsb != null) && !vsbNeeded &&
898                 (vsbPolicy != VERTICAL_SCROLLBAR_NEVER)) {
899
900                 extentSize = viewport.toViewCoordinates
901                          (availR.getSize());
902                 vsbNeeded = viewPrefSize.height >
903                         extentSize.height;
904
905                 if (vsbNeeded) {
906                 adjustForVSB(true, availR, vsbR, vpbInsets,
907                          leftToRight);
908                 }
909             }
910             }
911         }
912         if (oldHSBNeeded != hsbNeeded ||
913             oldVSBNeeded != vsbNeeded) {
914             viewport.setBounds(availR);
915             // You could argue that we should recheck the
916
// Scrollable methods again until they stop changing,
917
// but they might never stop changing, so we stop here
918
// and don't do any additional checks.
919
}
920         }
921     }
922
923     /* We now have the final size of the viewport: availR.
924      * Now fixup the header and scrollbar widths/heights.
925      */

926     vsbR.height = availR.height + vpbInsets.top + vpbInsets.bottom;
927     hsbR.width = availR.width + vpbInsets.left + vpbInsets.right;
928     rowHeadR.height = availR.height + vpbInsets.top + vpbInsets.bottom;
929         rowHeadR.y = availR.y - vpbInsets.top;
930     colHeadR.width = availR.width + vpbInsets.left + vpbInsets.right;
931         colHeadR.x = availR.x - vpbInsets.left;
932
933     /* Set the bounds of the remaining components. The scrollbars
934      * are made invisible if they're not needed.
935      */

936     
937     if (rowHead != null) {
938         rowHead.setBounds(rowHeadR);
939     }
940
941     if (colHead != null) {
942         colHead.setBounds(colHeadR);
943     }
944
945     if (vsb != null) {
946         if (vsbNeeded) {
947         vsb.setVisible(true);
948         vsb.setBounds(vsbR);
949         }
950         else {
951         vsb.setVisible(false);
952         }
953     }
954
955     if (hsb != null) {
956         if (hsbNeeded) {
957         hsb.setVisible(true);
958         hsb.setBounds(hsbR);
959         }
960         else {
961         hsb.setVisible(false);
962         }
963     }
964
965     if (lowerLeft != null) {
966         lowerLeft.setBounds(leftToRight ? rowHeadR.x : vsbR.x,
967                                 hsbR.y,
968                                 leftToRight ? rowHeadR.width : vsbR.width,
969                                 hsbR.height);
970     }
971
972     if (lowerRight != null) {
973         lowerRight.setBounds(leftToRight ? vsbR.x : rowHeadR.x,
974                                  hsbR.y,
975                                  leftToRight ? vsbR.width : rowHeadR.width,
976                                  hsbR.height);
977     }
978
979     if (upperLeft != null) {
980         upperLeft.setBounds(leftToRight ? rowHeadR.x : vsbR.x,
981                                 colHeadR.y,
982                                 leftToRight ? rowHeadR.width : vsbR.width,
983                                 colHeadR.height);
984     }
985
986     if (upperRight != null) {
987         upperRight.setBounds(leftToRight ? vsbR.x : rowHeadR.x,
988                                  colHeadR.y,
989                                  leftToRight ? vsbR.width : rowHeadR.width,
990                                  colHeadR.height);
991     }
992     }
993
994     /**
995      * Adjusts the <code>Rectangle</code> <code>available</code> based on if
996      * the vertical scrollbar is needed (<code>wantsVSB</code>).
997      * The location of the vsb is updated in <code>vsbR</code>, and
998      * the viewport border insets (<code>vpbInsets</code>) are used to offset
999      * the vsb. This is only called when <code>wantsVSB</code> has
1000     * changed, eg you shouldn't invoke adjustForVSB(true) twice.
1001     */

1002    private void adjustForVSB(boolean wantsVSB, Rectangle JavaDoc available,
1003                  Rectangle JavaDoc vsbR, Insets JavaDoc vpbInsets,
1004                              boolean leftToRight) {
1005        int oldWidth = vsbR.width;
1006    if (wantsVSB) {
1007            int vsbWidth = Math.max(0, Math.min(vsb.getPreferredSize().width,
1008                                                available.width));
1009
1010        available.width -= vsbWidth;
1011        vsbR.width = vsbWidth;
1012            
1013            if( leftToRight ) {
1014                vsbR.x = available.x + available.width + vpbInsets.right;
1015            } else {
1016                vsbR.x = available.x - vpbInsets.left;
1017                available.x += vsbWidth;
1018            }
1019    }
1020    else {
1021        available.width += oldWidth;
1022    }
1023    }
1024
1025    /**
1026     * Adjusts the <code>Rectangle</code> <code>available</code> based on if
1027     * the horizontal scrollbar is needed (<code>wantsHSB</code>).
1028     * The location of the hsb is updated in <code>hsbR</code>, and
1029     * the viewport border insets (<code>vpbInsets</code>) are used to offset
1030     * the hsb. This is only called when <code>wantsHSB</code> has
1031     * changed, eg you shouldn't invoked adjustForHSB(true) twice.
1032     */

1033    private void adjustForHSB(boolean wantsHSB, Rectangle JavaDoc available,
1034                  Rectangle JavaDoc hsbR, Insets JavaDoc vpbInsets) {
1035        int oldHeight = hsbR.height;
1036    if (wantsHSB) {
1037            int hsbHeight = Math.max(0, Math.min(available.height,
1038                                              hsb.getPreferredSize().height));
1039
1040        available.height -= hsbHeight;
1041        hsbR.y = available.y + available.height + vpbInsets.bottom;
1042        hsbR.height = hsbHeight;
1043    }
1044    else {
1045        available.height += oldHeight;
1046    }
1047    }
1048
1049    
1050
1051    /**
1052     * Returns the bounds of the border around the specified scroll pane's
1053     * viewport.
1054     *
1055     * @return the size and position of the viewport border
1056     * @deprecated As of JDK version Swing1.1
1057     * replaced by <code>JScrollPane.getViewportBorderBounds()</code>.
1058     */

1059    @Deprecated JavaDoc
1060    public Rectangle JavaDoc getViewportBorderBounds(JScrollPane JavaDoc scrollpane) {
1061    return scrollpane.getViewportBorderBounds();
1062    }
1063
1064    /**
1065     * The UI resource version of <code>ScrollPaneLayout</code>.
1066     */

1067    public static class UIResource extends ScrollPaneLayout JavaDoc implements javax.swing.plaf.UIResource JavaDoc {}
1068}
1069
Popular Tags