2 * Copyright 2000-2009 JetBrains s.r.o.
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
16 package com
.intellij
.openapi
.editor
.impl
;
19 import javax
.swing
.border
.Border
;
23 * This class is exact copy of javax.swing.ScrollPaneLayout except is does not ask component for orientation
24 * and always assumes right-to-left.
28 public class LeftHandScrollbarLayout
extends ScrollPaneLayout
{
30 * The scrollpane's viewport child.
31 * Default is an empty <code>JViewport</code>.
33 * @see JScrollPane#setViewport
35 protected JViewport viewport
;
39 * The scrollpane's vertical scrollbar child.
40 * Default is a <code>JScrollBar</code>.
42 * @see JScrollPane#setVerticalScrollBar
44 protected JScrollBar vsb
;
48 * The scrollpane's horizontal scrollbar child.
49 * Default is a <code>JScrollBar</code>.
51 * @see JScrollPane#setHorizontalScrollBar
53 protected JScrollBar hsb
;
57 * The row header child. Default is <code>null</code>.
59 * @see JScrollPane#setRowHeader
61 protected JViewport rowHead
;
65 * The column header child. Default is <code>null</code>.
67 * @see JScrollPane#setColumnHeader
69 protected JViewport colHead
;
73 * The component to display in the lower left corner.
74 * Default is <code>null</code>.
76 * @see JScrollPane#setCorner
78 protected Component lowerLeft
;
82 * The component to display in the lower right corner.
83 * Default is <code>null</code>.
85 * @see JScrollPane#setCorner
87 protected Component lowerRight
;
91 * The component to display in the upper left corner.
92 * Default is <code>null</code>.
94 * @see JScrollPane#setCorner
96 protected Component upperLeft
;
100 * The component to display in the upper right corner.
101 * Default is <code>null</code>.
103 * @see JScrollPane#setCorner
105 protected Component upperRight
;
109 * The display policy for the vertical scrollbar.
110 * The default is <code>JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED</code>.
112 * This field is obsolete, please use the <code>JScrollPane</code> field instead.
114 * @see JScrollPane#setVerticalScrollBarPolicy
116 protected int vsbPolicy
= VERTICAL_SCROLLBAR_AS_NEEDED
;
120 * The display policy for the horizontal scrollbar.
121 * The default is <code>JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED</code>.
123 * This field is obsolete, please use the <code>JScrollPane</code> field instead.
125 * @see JScrollPane#setHorizontalScrollBarPolicy
127 protected int hsbPolicy
= HORIZONTAL_SCROLLBAR_AS_NEEDED
;
131 * This method is invoked after the ScrollPaneLayout is set as the
132 * LayoutManager of a <code>JScrollPane</code>.
133 * It initializes all of the internal fields that
134 * are ordinarily set by <code>addLayoutComponent</code>. For example:
136 * ScrollPaneLayout mySPLayout = new ScrollPanelLayout() {
137 * public void layoutContainer(Container p) {
138 * super.layoutContainer(p);
139 * // do some extra work here ...
142 * scrollpane.setLayout(mySPLayout):
145 public void syncWithScrollPane(JScrollPane sp
) {
146 viewport
= sp
.getViewport();
147 vsb
= sp
.getVerticalScrollBar();
148 hsb
= sp
.getHorizontalScrollBar();
149 rowHead
= sp
.getRowHeader();
150 colHead
= sp
.getColumnHeader();
151 lowerLeft
= sp
.getCorner(LOWER_LEFT_CORNER
);
152 lowerRight
= sp
.getCorner(LOWER_RIGHT_CORNER
);
153 upperLeft
= sp
.getCorner(UPPER_LEFT_CORNER
);
154 upperRight
= sp
.getCorner(UPPER_RIGHT_CORNER
);
155 vsbPolicy
= sp
.getVerticalScrollBarPolicy();
156 hsbPolicy
= sp
.getHorizontalScrollBarPolicy();
161 * Removes an existing component. When a new component, such as
162 * the left corner, or vertical scrollbar, is added, the old one,
163 * if it exists, must be removed.
165 * This method returns <code>newC</code>. If <code>oldC</code> is
166 * not equal to <code>newC</code> and is non-<code>null</code>,
167 * it will be removed from its parent.
169 * @param oldC the <code>Component</code> to replace
170 * @param newC the <code>Component</code> to add
171 * @return the <code>newC</code>
173 protected Component
addSingletonComponent(Component oldC
, Component newC
) {
174 if ((oldC
!= null) && (oldC
!= newC
)) {
175 oldC
.getParent().remove(oldC
);
182 * Adds the specified component to the layout. The layout is
183 * identified using one of:
185 * <li>JScrollPane.VIEWPORT
186 * <li>JScrollPane.VERTICAL_SCROLLBAR
187 * <li>JScrollPane.HORIZONTAL_SCROLLBAR
188 * <li>JScrollPane.ROW_HEADER
189 * <li>JScrollPane.COLUMN_HEADER
190 * <li>JScrollPane.LOWER_LEFT_CORNER
191 * <li>JScrollPane.LOWER_RIGHT_CORNER
192 * <li>JScrollPane.UPPER_LEFT_CORNER
193 * <li>JScrollPane.UPPER_RIGHT_CORNER
196 * @param s the component identifier
197 * @param c the component to be added
198 * @throws IllegalArgumentException if <code>s</code> is an invalid key
200 public void addLayoutComponent(String s
, Component c
) {
201 if (s
.equals(VIEWPORT
)) {
202 viewport
= (JViewport
)addSingletonComponent(viewport
, c
);
204 else if (s
.equals(VERTICAL_SCROLLBAR
)) {
205 vsb
= (JScrollBar
)addSingletonComponent(vsb
, c
);
207 else if (s
.equals(HORIZONTAL_SCROLLBAR
)) {
208 hsb
= (JScrollBar
)addSingletonComponent(hsb
, c
);
210 else if (s
.equals(ROW_HEADER
)) {
211 rowHead
= (JViewport
)addSingletonComponent(rowHead
, c
);
213 else if (s
.equals(COLUMN_HEADER
)) {
214 colHead
= (JViewport
)addSingletonComponent(colHead
, c
);
216 else if (s
.equals(LOWER_LEFT_CORNER
)) {
217 lowerLeft
= addSingletonComponent(lowerLeft
, c
);
219 else if (s
.equals(LOWER_RIGHT_CORNER
)) {
220 lowerRight
= addSingletonComponent(lowerRight
, c
);
222 else if (s
.equals(UPPER_LEFT_CORNER
)) {
223 upperLeft
= addSingletonComponent(upperLeft
, c
);
225 else if (s
.equals(UPPER_RIGHT_CORNER
)) {
226 upperRight
= addSingletonComponent(upperRight
, c
);
229 throw new IllegalArgumentException("invalid layout key " + s
);
235 * Removes the specified component from the layout.
237 * @param c the component to remove
239 public void removeLayoutComponent(Component c
) {
249 else if (c
== rowHead
) {
252 else if (c
== colHead
) {
255 else if (c
== lowerLeft
) {
258 else if (c
== lowerRight
) {
261 else if (c
== upperLeft
) {
264 else if (c
== upperRight
) {
271 * Returns the vertical scrollbar-display policy.
273 * @return an integer giving the display policy
274 * @see #setVerticalScrollBarPolicy
276 public int getVerticalScrollBarPolicy() {
282 * Sets the vertical scrollbar-display policy. The options
285 * <li>JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED
286 * <li>JScrollPane.VERTICAL_SCROLLBAR_NEVER
287 * <li>JScrollPane.VERTICAL_SCROLLBAR_ALWAYS
289 * Note: Applications should use the <code>JScrollPane</code> version
290 * of this method. It only exists for backwards compatibility
291 * with the Swing 1.0.2 (and earlier) versions of this class.
293 * @param x an integer giving the display policy
294 * @throws IllegalArgumentException if <code>x</code> is an invalid
295 * vertical scroll bar policy, as listed above
297 public void setVerticalScrollBarPolicy(int x
) {
299 case VERTICAL_SCROLLBAR_AS_NEEDED
:
300 case VERTICAL_SCROLLBAR_NEVER
:
301 case VERTICAL_SCROLLBAR_ALWAYS
:
305 throw new IllegalArgumentException("invalid verticalScrollBarPolicy");
311 * Returns the horizontal scrollbar-display policy.
313 * @return an integer giving the display policy
314 * @see #setHorizontalScrollBarPolicy
316 public int getHorizontalScrollBarPolicy() {
321 * Sets the horizontal scrollbar-display policy.
322 * The options are:<ul>
323 * <li>JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED
324 * <li>JScrollPane.HOTRIZONTAL_SCROLLBAR_NEVER
325 * <li>JScrollPane.HORIZONTAL_SCROLLBAR_ALWAYS
327 * Note: Applications should use the <code>JScrollPane</code> version
328 * of this method. It only exists for backwards compatibility
329 * with the Swing 1.0.2 (and earlier) versions of this class.
331 * @param x an int giving the display policy
332 * @throws IllegalArgumentException if <code>x</code> is not a valid
333 * horizontal scrollbar policy, as listed above
335 public void setHorizontalScrollBarPolicy(int x
) {
337 case HORIZONTAL_SCROLLBAR_AS_NEEDED
:
338 case HORIZONTAL_SCROLLBAR_NEVER
:
339 case HORIZONTAL_SCROLLBAR_ALWAYS
:
343 throw new IllegalArgumentException("invalid horizontalScrollBarPolicy");
349 * Returns the <code>JViewport</code> object that displays the
350 * scrollable contents.
352 * @return the <code>JViewport</code> object that displays the scrollable contents
353 * @see JScrollPane#getViewport
355 public JViewport
getViewport() {
361 * Returns the <code>JScrollBar</code> object that handles horizontal scrolling.
363 * @return the <code>JScrollBar</code> object that handles horizontal scrolling
364 * @see JScrollPane#getHorizontalScrollBar
366 public JScrollBar
getHorizontalScrollBar() {
371 * Returns the <code>JScrollBar</code> object that handles vertical scrolling.
373 * @return the <code>JScrollBar</code> object that handles vertical scrolling
374 * @see JScrollPane#getVerticalScrollBar
376 public JScrollBar
getVerticalScrollBar() {
382 * Returns the <code>JViewport</code> object that is the row header.
384 * @return the <code>JViewport</code> object that is the row header
385 * @see JScrollPane#getRowHeader
387 public JViewport
getRowHeader() {
393 * Returns the <code>JViewport</code> object that is the column header.
395 * @return the <code>JViewport</code> object that is the column header
396 * @see JScrollPane#getColumnHeader
398 public JViewport
getColumnHeader() {
404 * Returns the <code>Component</code> at the specified corner.
406 * @param key the <code>String</code> specifying the corner
407 * @return the <code>Component</code> at the specified corner, as defined in
408 * {@link ScrollPaneConstants}; if <code>key</code> is not one of the
409 * four corners, <code>null</code> is returned
410 * @see JScrollPane#getCorner
412 public Component
getCorner(String key
) {
413 if (key
.equals(LOWER_LEFT_CORNER
)) {
416 else if (key
.equals(LOWER_RIGHT_CORNER
)) {
419 else if (key
.equals(UPPER_LEFT_CORNER
)) {
422 else if (key
.equals(UPPER_RIGHT_CORNER
)) {
432 * The preferred size of a <code>ScrollPane</code> is the size of the insets,
433 * plus the preferred size of the viewport, plus the preferred size of
434 * the visible headers, plus the preferred size of the scrollbars
435 * that will appear given the current view and the current
436 * scrollbar displayPolicies.
437 * <p>Note that the rowHeader is calculated as part of the preferred width
438 * and the colHeader is calculated as part of the preferred size.
440 * @param parent the <code>Container</code> that will be laid out
441 * @return a <code>Dimension</code> object specifying the preferred size of the
442 * viewport and any scrollbars
443 * @see ViewportLayout
446 public Dimension
preferredLayoutSize(Container parent
) {
447 /* Sync the (now obsolete) policy fields with the
450 JScrollPane scrollPane
= (JScrollPane
)parent
;
451 vsbPolicy
= scrollPane
.getVerticalScrollBarPolicy();
452 hsbPolicy
= scrollPane
.getHorizontalScrollBarPolicy();
454 Insets insets
= parent
.getInsets();
455 int prefWidth
= insets
.left
+ insets
.right
;
456 int prefHeight
= insets
.top
+ insets
.bottom
;
458 /* Note that viewport.getViewSize() is equivalent to
459 * viewport.getView().getPreferredSize() modulo a null
460 * view or a view whose size was explicitly set.
463 Dimension extentSize
= null;
464 Dimension viewSize
= null;
465 Component view
= null;
467 if (viewport
!= null) {
468 extentSize
= viewport
.getPreferredSize();
469 viewSize
= viewport
.getViewSize();
470 view
= viewport
.getView();
473 /* If there's a viewport add its preferredSize.
476 if (extentSize
!= null) {
477 prefWidth
+= extentSize
.width
;
478 prefHeight
+= extentSize
.height
;
481 /* If there's a JScrollPane.viewportBorder, add its insets.
484 Border viewportBorder
= scrollPane
.getViewportBorder();
485 if (viewportBorder
!= null) {
486 Insets vpbInsets
= viewportBorder
.getBorderInsets(parent
);
487 prefWidth
+= vpbInsets
.left
+ vpbInsets
.right
;
488 prefHeight
+= vpbInsets
.top
+ vpbInsets
.bottom
;
491 /* If a header exists and it's visible, factor its
495 if ((rowHead
!= null) && rowHead
.isVisible()) {
496 prefWidth
+= rowHead
.getPreferredSize().width
;
499 if ((colHead
!= null) && colHead
.isVisible()) {
500 prefHeight
+= colHead
.getPreferredSize().height
;
503 /* If a scrollbar is going to appear, factor its preferred size in.
504 * If the scrollbars policy is AS_NEEDED, this can be a little
507 * - If the view is a Scrollable then scrollableTracksViewportWidth
508 * and scrollableTracksViewportHeight can be used to effectively
509 * disable scrolling (if they're true) in their respective dimensions.
511 * - Assuming that a scrollbar hasn't been disabled by the
512 * previous constraint, we need to decide if the scrollbar is going
513 * to appear to correctly compute the JScrollPanes preferred size.
514 * To do this we compare the preferredSize of the viewport (the
515 * extentSize) to the preferredSize of the view. Although we're
516 * not responsible for laying out the view we'll assume that the
517 * JViewport will always give it its preferredSize.
520 if ((vsb
!= null) && (vsbPolicy
!= VERTICAL_SCROLLBAR_NEVER
)) {
521 if (vsbPolicy
== VERTICAL_SCROLLBAR_ALWAYS
) {
522 prefWidth
+= vsb
.getPreferredSize().width
;
524 else if ((viewSize
!= null) && (extentSize
!= null)) {
525 boolean canScroll
= true;
526 if (view
instanceof Scrollable
) {
527 canScroll
= !((Scrollable
)view
).getScrollableTracksViewportHeight();
529 if (canScroll
&& (viewSize
.height
> extentSize
.height
)) {
530 prefWidth
+= vsb
.getPreferredSize().width
;
535 if ((hsb
!= null) && (hsbPolicy
!= HORIZONTAL_SCROLLBAR_NEVER
)) {
536 if (hsbPolicy
== HORIZONTAL_SCROLLBAR_ALWAYS
) {
537 prefHeight
+= hsb
.getPreferredSize().height
;
539 else if ((viewSize
!= null) && (extentSize
!= null)) {
540 boolean canScroll
= true;
541 if (view
instanceof Scrollable
) {
542 canScroll
= !((Scrollable
)view
).getScrollableTracksViewportWidth();
544 if (canScroll
&& (viewSize
.width
> extentSize
.width
)) {
545 prefHeight
+= hsb
.getPreferredSize().height
;
550 return new Dimension(prefWidth
, prefHeight
);
555 * The minimum size of a <code>ScrollPane</code> is the size of the insets
556 * plus minimum size of the viewport, plus the scrollpane's
557 * viewportBorder insets, plus the minimum size
558 * of the visible headers, plus the minimum size of the
559 * scrollbars whose displayPolicy isn't NEVER.
561 * @param parent the <code>Container</code> that will be laid out
562 * @return a <code>Dimension</code> object specifying the minimum size
564 public Dimension
minimumLayoutSize(Container parent
) {
565 /* Sync the (now obsolete) policy fields with the
568 JScrollPane scrollPane
= (JScrollPane
)parent
;
569 vsbPolicy
= scrollPane
.getVerticalScrollBarPolicy();
570 hsbPolicy
= scrollPane
.getHorizontalScrollBarPolicy();
572 Insets insets
= parent
.getInsets();
573 int minWidth
= insets
.left
+ insets
.right
;
574 int minHeight
= insets
.top
+ insets
.bottom
;
576 /* If there's a viewport add its minimumSize.
579 if (viewport
!= null) {
580 Dimension size
= viewport
.getMinimumSize();
581 minWidth
+= size
.width
;
582 minHeight
+= size
.height
;
585 /* If there's a JScrollPane.viewportBorder, add its insets.
588 Border viewportBorder
= scrollPane
.getViewportBorder();
589 if (viewportBorder
!= null) {
590 Insets vpbInsets
= viewportBorder
.getBorderInsets(parent
);
591 minWidth
+= vpbInsets
.left
+ vpbInsets
.right
;
592 minHeight
+= vpbInsets
.top
+ vpbInsets
.bottom
;
595 /* If a header exists and it's visible, factor its
599 if ((rowHead
!= null) && rowHead
.isVisible()) {
600 Dimension size
= rowHead
.getMinimumSize();
601 minWidth
+= size
.width
;
602 minHeight
= Math
.max(minHeight
, size
.height
);
605 if ((colHead
!= null) && colHead
.isVisible()) {
606 Dimension size
= colHead
.getMinimumSize();
607 minWidth
= Math
.max(minWidth
, size
.width
);
608 minHeight
+= size
.height
;
611 /* If a scrollbar might appear, factor its minimum
615 if ((vsb
!= null) && (vsbPolicy
!= VERTICAL_SCROLLBAR_NEVER
)) {
616 Dimension size
= vsb
.getMinimumSize();
617 minWidth
+= size
.width
;
618 minHeight
= Math
.max(minHeight
, size
.height
);
621 if ((hsb
!= null) && (hsbPolicy
!= VERTICAL_SCROLLBAR_NEVER
)) {
622 Dimension size
= hsb
.getMinimumSize();
623 minWidth
= Math
.max(minWidth
, size
.width
);
624 minHeight
+= size
.height
;
627 return new Dimension(minWidth
, minHeight
);
632 * Lays out the scrollpane. The positioning of components depends on
633 * the following constraints:
635 * <li> The row header, if present and visible, gets its preferred
636 * width and the viewport's height.
638 * <li> The column header, if present and visible, gets its preferred
639 * height and the viewport's width.
641 * <li> If a vertical scrollbar is needed, i.e. if the viewport's extent
642 * height is smaller than its view height or if the <code>displayPolicy</code>
643 * is ALWAYS, it's treated like the row header with respect to its
644 * dimensions and is made visible.
646 * <li> If a horizontal scrollbar is needed, it is treated like the
647 * column header (see the paragraph above regarding the vertical scrollbar).
649 * <li> If the scrollpane has a non-<code>null</code>
650 * <code>viewportBorder</code>, then space is allocated for that.
652 * <li> The viewport gets the space available after accounting for
653 * the previous constraints.
655 * <li> The corner components, if provided, are aligned with the
656 * ends of the scrollbars and headers. If there is a vertical
657 * scrollbar, the right corners appear; if there is a horizontal
658 * scrollbar, the lower corners appear; a row header gets left
659 * corners, and a column header gets upper corners.
662 * @param parent the <code>Container</code> to lay out
664 public void layoutContainer(Container parent
) {
665 /* Sync the (now obsolete) policy fields with the
668 JScrollPane scrollPane
= (JScrollPane
)parent
;
669 vsbPolicy
= scrollPane
.getVerticalScrollBarPolicy();
670 hsbPolicy
= scrollPane
.getHorizontalScrollBarPolicy();
672 Rectangle availR
= scrollPane
.getBounds();
673 availR
.x
= availR
.y
= 0;
675 Insets insets
= parent
.getInsets();
676 availR
.x
= insets
.left
;
677 availR
.y
= insets
.top
;
678 availR
.width
-= insets
.left
+ insets
.right
;
679 availR
.height
-= insets
.top
+ insets
.bottom
;
681 /* Get the scrollPane's orientation.
683 boolean leftToRight
= false;
685 /* If there's a visible column header remove the space it
686 * needs from the top of availR. The column header is treated
687 * as if it were fixed height, arbitrary width.
690 Rectangle colHeadR
= new Rectangle(0, availR
.y
, 0, 0);
692 if ((colHead
!= null) && (colHead
.isVisible())) {
693 int colHeadHeight
= Math
.min(availR
.height
,
694 colHead
.getPreferredSize().height
);
695 colHeadR
.height
= colHeadHeight
;
696 availR
.y
+= colHeadHeight
;
697 availR
.height
-= colHeadHeight
;
700 /* If there's a visible row header remove the space it needs
701 * from the left or right of availR. The row header is treated
702 * as if it were fixed width, arbitrary height.
705 Rectangle rowHeadR
= new Rectangle(0, 0, 0, 0);
707 if ((rowHead
!= null) && (rowHead
.isVisible())) {
708 int rowHeadWidth
= Math
.min(availR
.width
,
709 rowHead
.getPreferredSize().width
);
710 rowHeadR
.width
= rowHeadWidth
;
711 availR
.width
-= rowHeadWidth
;
713 rowHeadR
.x
= availR
.x
;
714 availR
.x
+= rowHeadWidth
;
717 rowHeadR
.x
= availR
.x
+ availR
.width
;
721 /* If there's a JScrollPane.viewportBorder, remove the
722 * space it occupies for availR.
725 Border viewportBorder
= scrollPane
.getViewportBorder();
727 if (viewportBorder
!= null) {
728 vpbInsets
= viewportBorder
.getBorderInsets(parent
);
729 availR
.x
+= vpbInsets
.left
;
730 availR
.y
+= vpbInsets
.top
;
731 availR
.width
-= vpbInsets
.left
+ vpbInsets
.right
;
732 availR
.height
-= vpbInsets
.top
+ vpbInsets
.bottom
;
735 vpbInsets
= new Insets(0, 0, 0, 0);
739 /* At this point availR is the space available for the viewport
740 * and scrollbars. rowHeadR is correct except for its height and y
741 * and colHeadR is correct except for its width and x. Once we're
742 * through computing the dimensions of these three parts we can
743 * go back and set the dimensions of rowHeadR.height, rowHeadR.y,
744 * colHeadR.width, colHeadR.x and the bounds for the corners.
746 * We'll decide about putting up scrollbars by comparing the
747 * viewport views preferred size with the viewports extent
748 * size (generally just its size). Using the preferredSize is
749 * reasonable because layout proceeds top down - so we expect
750 * the viewport to be laid out next. And we assume that the
751 * viewports layout manager will give the view it's preferred
752 * size. One exception to this is when the view implements
753 * Scrollable and Scrollable.getViewTracksViewport{Width,Height}
754 * methods return true. If the view is tracking the viewports
755 * width we don't bother with a horizontal scrollbar, similarly
756 * if view.getViewTracksViewport(Height) is true we don't bother
757 * with a vertical scrollbar.
760 Component view
= (viewport
!= null) ? viewport
.getView() : null;
761 Dimension viewPrefSize
=
762 (view
!= null) ? view
.getPreferredSize()
763 : new Dimension(0, 0);
765 Dimension extentSize
=
766 (viewport
!= null) ? viewport
.toViewCoordinates(availR
.getSize())
767 : new Dimension(0, 0);
769 boolean viewTracksViewportWidth
= false;
770 boolean viewTracksViewportHeight
= false;
771 boolean isEmpty
= (availR
.width
< 0 || availR
.height
< 0);
773 // Don't bother checking the Scrollable methods if there is no room
774 // for the viewport, we aren't going to show any scrollbars in this
776 if (!isEmpty
&& view
instanceof Scrollable
) {
777 sv
= (Scrollable
)view
;
778 viewTracksViewportWidth
= sv
.getScrollableTracksViewportWidth();
779 viewTracksViewportHeight
= sv
.getScrollableTracksViewportHeight();
785 /* If there's a vertical scrollbar and we need one, allocate
786 * space for it (we'll make it visible later). A vertical
787 * scrollbar is considered to be fixed width, arbitrary height.
790 Rectangle vsbR
= new Rectangle(0, availR
.y
- vpbInsets
.top
, 0, 0);
796 else if (vsbPolicy
== VERTICAL_SCROLLBAR_ALWAYS
) {
799 else if (vsbPolicy
== VERTICAL_SCROLLBAR_NEVER
) {
802 else { // vsbPolicy == VERTICAL_SCROLLBAR_AS_NEEDED
803 vsbNeeded
= !viewTracksViewportHeight
&& (viewPrefSize
.height
> extentSize
.height
);
807 if ((vsb
!= null) && vsbNeeded
) {
808 adjustForVSB(true, availR
, vsbR
, vpbInsets
, leftToRight
);
809 extentSize
= viewport
.toViewCoordinates(availR
.getSize());
812 /* If there's a horizontal scrollbar and we need one, allocate
813 * space for it (we'll make it visible later). A horizontal
814 * scrollbar is considered to be fixed height, arbitrary width.
817 Rectangle hsbR
= new Rectangle(availR
.x
- vpbInsets
.left
, 0, 0, 0);
822 else if (hsbPolicy
== HORIZONTAL_SCROLLBAR_ALWAYS
) {
825 else if (hsbPolicy
== HORIZONTAL_SCROLLBAR_NEVER
) {
828 else { // hsbPolicy == HORIZONTAL_SCROLLBAR_AS_NEEDED
829 hsbNeeded
= !viewTracksViewportWidth
&& (viewPrefSize
.width
> extentSize
.width
);
832 if ((hsb
!= null) && hsbNeeded
) {
833 adjustForHSB(true, availR
, hsbR
, vpbInsets
);
835 /* If we added the horizontal scrollbar then we've implicitly
836 * reduced the vertical space available to the viewport.
837 * As a consequence we may have to add the vertical scrollbar,
838 * if that hasn't been done so already. Of course we
839 * don't bother with any of this if the vsbPolicy is NEVER.
841 if ((vsb
!= null) && !vsbNeeded
&&
842 (vsbPolicy
!= VERTICAL_SCROLLBAR_NEVER
)) {
844 extentSize
= viewport
.toViewCoordinates(availR
.getSize());
845 vsbNeeded
= viewPrefSize
.height
> extentSize
.height
;
848 adjustForVSB(true, availR
, vsbR
, vpbInsets
, leftToRight
);
853 /* Set the size of the viewport first, and then recheck the Scrollable
854 * methods. Some components base their return values for the Scrollable
855 * methods on the size of the Viewport, so that if we don't
856 * ask after resetting the bounds we may have gotten the wrong
860 if (viewport
!= null) {
861 viewport
.setBounds(availR
);
864 extentSize
= viewport
.toViewCoordinates(availR
.getSize());
866 boolean oldHSBNeeded
= hsbNeeded
;
867 boolean oldVSBNeeded
= vsbNeeded
;
868 viewTracksViewportWidth
= sv
.
869 getScrollableTracksViewportWidth();
870 viewTracksViewportHeight
= sv
.
871 getScrollableTracksViewportHeight();
872 if (vsb
!= null && vsbPolicy
== VERTICAL_SCROLLBAR_AS_NEEDED
) {
873 boolean newVSBNeeded
= !viewTracksViewportHeight
&&
874 (viewPrefSize
.height
> extentSize
.height
);
875 if (newVSBNeeded
!= vsbNeeded
) {
876 vsbNeeded
= newVSBNeeded
;
877 adjustForVSB(vsbNeeded
, availR
, vsbR
, vpbInsets
,
879 extentSize
= viewport
.toViewCoordinates
883 if (hsb
!= null && hsbPolicy
== HORIZONTAL_SCROLLBAR_AS_NEEDED
) {
884 boolean newHSBbNeeded
= !viewTracksViewportWidth
&&
885 (viewPrefSize
.width
> extentSize
.width
);
886 if (newHSBbNeeded
!= hsbNeeded
) {
887 hsbNeeded
= newHSBbNeeded
;
888 adjustForHSB(hsbNeeded
, availR
, hsbR
, vpbInsets
);
889 if ((vsb
!= null) && !vsbNeeded
&&
890 (vsbPolicy
!= VERTICAL_SCROLLBAR_NEVER
)) {
892 extentSize
= viewport
.toViewCoordinates
894 vsbNeeded
= viewPrefSize
.height
>
898 adjustForVSB(true, availR
, vsbR
, vpbInsets
,
904 if (oldHSBNeeded
!= hsbNeeded
||
905 oldVSBNeeded
!= vsbNeeded
) {
906 viewport
.setBounds(availR
);
907 // You could argue that we should recheck the
908 // Scrollable methods again until they stop changing,
909 // but they might never stop changing, so we stop here
910 // and don't do any additional checks.
915 /* We now have the final size of the viewport: availR.
916 * Now fixup the header and scrollbar widths/heights.
918 vsbR
.height
= availR
.height
+ vpbInsets
.top
+ vpbInsets
.bottom
;
919 hsbR
.width
= availR
.width
+ vpbInsets
.left
+ vpbInsets
.right
;
920 rowHeadR
.height
= availR
.height
+ vpbInsets
.top
+ vpbInsets
.bottom
;
921 rowHeadR
.y
= availR
.y
- vpbInsets
.top
;
922 colHeadR
.width
= availR
.width
+ vpbInsets
.left
+ vpbInsets
.right
;
923 colHeadR
.x
= availR
.x
- vpbInsets
.left
;
925 /* Set the bounds of the remaining components. The scrollbars
926 * are made invisible if they're not needed.
929 if (rowHead
!= null) {
930 rowHead
.setBounds(rowHeadR
);
933 if (colHead
!= null) {
934 colHead
.setBounds(colHeadR
);
939 vsb
.setVisible(true);
943 vsb
.setVisible(false);
949 hsb
.setVisible(true);
953 hsb
.setVisible(false);
957 if (lowerLeft
!= null) {
958 lowerLeft
.setBounds(leftToRight ? rowHeadR
.x
: vsbR
.x
,
960 leftToRight ? rowHeadR
.width
: vsbR
.width
,
964 if (lowerRight
!= null) {
965 lowerRight
.setBounds(leftToRight ? vsbR
.x
: rowHeadR
.x
,
967 leftToRight ? vsbR
.width
: rowHeadR
.width
,
971 if (upperLeft
!= null) {
972 upperLeft
.setBounds(leftToRight ? rowHeadR
.x
: vsbR
.x
,
974 leftToRight ? rowHeadR
.width
: vsbR
.width
,
978 if (upperRight
!= null) {
979 upperRight
.setBounds(leftToRight ? vsbR
.x
: rowHeadR
.x
,
981 leftToRight ? vsbR
.width
: rowHeadR
.width
,
987 * Adjusts the <code>Rectangle</code> <code>available</code> based on if
988 * the vertical scrollbar is needed (<code>wantsVSB</code>).
989 * The location of the vsb is updated in <code>vsbR</code>, and
990 * the viewport border insets (<code>vpbInsets</code>) are used to offset
991 * the vsb. This is only called when <code>wantsVSB</code> has
992 * changed, eg you shouldn't invoke adjustForVSB(true) twice.
994 private void adjustForVSB(boolean wantsVSB
, Rectangle available
,
995 Rectangle vsbR
, Insets vpbInsets
,
996 boolean leftToRight
) {
997 int oldWidth
= vsbR
.width
;
999 int vsbWidth
= Math
.max(0, Math
.min(vsb
.getPreferredSize().width
,
1002 available
.width
-= vsbWidth
;
1003 vsbR
.width
= vsbWidth
;
1006 vsbR
.x
= available
.x
+ available
.width
+ vpbInsets
.right
;
1009 vsbR
.x
= available
.x
- vpbInsets
.left
;
1010 available
.x
+= vsbWidth
;
1014 available
.width
+= oldWidth
;
1019 * Adjusts the <code>Rectangle</code> <code>available</code> based on if
1020 * the horizontal scrollbar is needed (<code>wantsHSB</code>).
1021 * The location of the hsb is updated in <code>hsbR</code>, and
1022 * the viewport border insets (<code>vpbInsets</code>) are used to offset
1023 * the hsb. This is only called when <code>wantsHSB</code> has
1024 * changed, eg you shouldn't invoked adjustForHSB(true) twice.
1026 private void adjustForHSB(boolean wantsHSB
, Rectangle available
,
1027 Rectangle hsbR
, Insets vpbInsets
) {
1028 int oldHeight
= hsbR
.height
;
1030 int hsbHeight
= Math
.max(0, Math
.min(available
.height
,
1031 hsb
.getPreferredSize().height
));
1033 available
.height
-= hsbHeight
;
1034 hsbR
.y
= available
.y
+ available
.height
+ vpbInsets
.bottom
;
1035 hsbR
.height
= hsbHeight
;
1038 available
.height
+= oldHeight
;
1044 * Returns the bounds of the border around the specified scroll pane's
1047 * @return the size and position of the viewport border
1048 * @deprecated As of JDK version Swing1.1
1049 * replaced by <code>JScrollPane.getViewportBorderBounds()</code>.
1051 public Rectangle
getViewportBorderBounds(JScrollPane scrollpane
) {
1052 return scrollpane
.getViewportBorderBounds();