IDEA-51739
[fedora-idea.git] / platform / platform-impl / src / com / intellij / openapi / editor / impl / LeftHandScrollbarLayout.java
blob9145e2e61c7b76d8f2df1781d1fde6a9199806e6
1 /*
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;
18 import javax.swing.*;
19 import javax.swing.border.Border;
20 import java.awt.*;
22 /**
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.
26 * @author max
28 public class LeftHandScrollbarLayout extends ScrollPaneLayout {
29 /**
30 * The scrollpane's viewport child.
31 * Default is an empty <code>JViewport</code>.
33 * @see JScrollPane#setViewport
35 protected JViewport viewport;
38 /**
39 * The scrollpane's vertical scrollbar child.
40 * Default is a <code>JScrollBar</code>.
42 * @see JScrollPane#setVerticalScrollBar
44 protected JScrollBar vsb;
47 /**
48 * The scrollpane's horizontal scrollbar child.
49 * Default is a <code>JScrollBar</code>.
51 * @see JScrollPane#setHorizontalScrollBar
53 protected JScrollBar hsb;
56 /**
57 * The row header child. Default is <code>null</code>.
59 * @see JScrollPane#setRowHeader
61 protected JViewport rowHead;
64 /**
65 * The column header child. Default is <code>null</code>.
67 * @see JScrollPane#setColumnHeader
69 protected JViewport colHead;
72 /**
73 * The component to display in the lower left corner.
74 * Default is <code>null</code>.
76 * @see JScrollPane#setCorner
78 protected Component lowerLeft;
81 /**
82 * The component to display in the lower right corner.
83 * Default is <code>null</code>.
85 * @see JScrollPane#setCorner
87 protected Component lowerRight;
90 /**
91 * The component to display in the upper left corner.
92 * Default is <code>null</code>.
94 * @see JScrollPane#setCorner
96 protected Component upperLeft;
99 /**
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>.
111 * <p/>
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>.
122 * <p/>
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:
135 * <pre>
136 * ScrollPaneLayout mySPLayout = new ScrollPanelLayout() {
137 * public void layoutContainer(Container p) {
138 * super.layoutContainer(p);
139 * // do some extra work here ...
141 * };
142 * scrollpane.setLayout(mySPLayout):
143 * </pre>
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.
164 * <p/>
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);
177 return newC;
182 * Adds the specified component to the layout. The layout is
183 * identified using one of:
184 * <ul>
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
194 * </ul>
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);
228 else {
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) {
240 if (c == viewport) {
241 viewport = null;
243 else if (c == vsb) {
244 vsb = null;
246 else if (c == hsb) {
247 hsb = null;
249 else if (c == rowHead) {
250 rowHead = null;
252 else if (c == colHead) {
253 colHead = null;
255 else if (c == lowerLeft) {
256 lowerLeft = null;
258 else if (c == lowerRight) {
259 lowerRight = null;
261 else if (c == upperLeft) {
262 upperLeft = null;
264 else if (c == upperRight) {
265 upperRight = null;
271 * Returns the vertical scrollbar-display policy.
273 * @return an integer giving the display policy
274 * @see #setVerticalScrollBarPolicy
276 public int getVerticalScrollBarPolicy() {
277 return vsbPolicy;
282 * Sets the vertical scrollbar-display policy. The options
283 * are:
284 * <ul>
285 * <li>JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED
286 * <li>JScrollPane.VERTICAL_SCROLLBAR_NEVER
287 * <li>JScrollPane.VERTICAL_SCROLLBAR_ALWAYS
288 * </ul>
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) {
298 switch (x) {
299 case VERTICAL_SCROLLBAR_AS_NEEDED:
300 case VERTICAL_SCROLLBAR_NEVER:
301 case VERTICAL_SCROLLBAR_ALWAYS:
302 vsbPolicy = x;
303 break;
304 default:
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() {
317 return hsbPolicy;
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
326 * </ul>
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) {
336 switch (x) {
337 case HORIZONTAL_SCROLLBAR_AS_NEEDED:
338 case HORIZONTAL_SCROLLBAR_NEVER:
339 case HORIZONTAL_SCROLLBAR_ALWAYS:
340 hsbPolicy = x;
341 break;
342 default:
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() {
356 return viewport;
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() {
367 return hsb;
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() {
377 return vsb;
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() {
388 return rowHead;
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() {
399 return colHead;
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)) {
414 return lowerLeft;
416 else if (key.equals(LOWER_RIGHT_CORNER)) {
417 return lowerRight;
419 else if (key.equals(UPPER_LEFT_CORNER)) {
420 return upperLeft;
422 else if (key.equals(UPPER_RIGHT_CORNER)) {
423 return upperRight;
425 else {
426 return null;
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
444 * @see LayoutManager
446 public Dimension preferredLayoutSize(Container parent) {
447 /* Sync the (now obsolete) policy fields with the
448 * JScrollPane.
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
492 * preferred size in.
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
505 * tricky:
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
566 * JScrollPane.
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
596 * minimum size in.
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
612 * size in.
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:
634 * <ul>
635 * <li> The row header, if present and visible, gets its preferred
636 * width and the viewport's height.
637 * <p/>
638 * <li> The column header, if present and visible, gets its preferred
639 * height and the viewport's width.
640 * <p/>
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.
645 * <p/>
646 * <li> If a horizontal scrollbar is needed, it is treated like the
647 * column header (see the paragraph above regarding the vertical scrollbar).
648 * <p/>
649 * <li> If the scrollpane has a non-<code>null</code>
650 * <code>viewportBorder</code>, then space is allocated for that.
651 * <p/>
652 * <li> The viewport gets the space available after accounting for
653 * the previous constraints.
654 * <p/>
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.
660 * </ul>
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
666 * JScrollPane.
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;
712 if (leftToRight) {
713 rowHeadR.x = availR.x;
714 availR.x += rowHeadWidth;
716 else {
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();
726 Insets vpbInsets;
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;
734 else {
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);
772 Scrollable sv;
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
775 // case anyway.
776 if (!isEmpty && view instanceof Scrollable) {
777 sv = (Scrollable)view;
778 viewTracksViewportWidth = sv.getScrollableTracksViewportWidth();
779 viewTracksViewportHeight = sv.getScrollableTracksViewportHeight();
781 else {
782 sv = null;
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);
792 boolean vsbNeeded;
793 if (isEmpty) {
794 vsbNeeded = false;
796 else if (vsbPolicy == VERTICAL_SCROLLBAR_ALWAYS) {
797 vsbNeeded = true;
799 else if (vsbPolicy == VERTICAL_SCROLLBAR_NEVER) {
800 vsbNeeded = false;
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);
818 boolean hsbNeeded;
819 if (isEmpty) {
820 hsbNeeded = false;
822 else if (hsbPolicy == HORIZONTAL_SCROLLBAR_ALWAYS) {
823 hsbNeeded = true;
825 else if (hsbPolicy == HORIZONTAL_SCROLLBAR_NEVER) {
826 hsbNeeded = false;
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;
847 if (vsbNeeded) {
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
857 * answer.
860 if (viewport != null) {
861 viewport.setBounds(availR);
863 if (sv != null) {
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,
878 leftToRight);
879 extentSize = viewport.toViewCoordinates
880 (availR.getSize());
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
893 (availR.getSize());
894 vsbNeeded = viewPrefSize.height >
895 extentSize.height;
897 if (vsbNeeded) {
898 adjustForVSB(true, availR, vsbR, vpbInsets,
899 leftToRight);
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);
937 if (vsb != null) {
938 if (vsbNeeded) {
939 vsb.setVisible(true);
940 vsb.setBounds(vsbR);
942 else {
943 vsb.setVisible(false);
947 if (hsb != null) {
948 if (hsbNeeded) {
949 hsb.setVisible(true);
950 hsb.setBounds(hsbR);
952 else {
953 hsb.setVisible(false);
957 if (lowerLeft != null) {
958 lowerLeft.setBounds(leftToRight ? rowHeadR.x : vsbR.x,
959 hsbR.y,
960 leftToRight ? rowHeadR.width : vsbR.width,
961 hsbR.height);
964 if (lowerRight != null) {
965 lowerRight.setBounds(leftToRight ? vsbR.x : rowHeadR.x,
966 hsbR.y,
967 leftToRight ? vsbR.width : rowHeadR.width,
968 hsbR.height);
971 if (upperLeft != null) {
972 upperLeft.setBounds(leftToRight ? rowHeadR.x : vsbR.x,
973 colHeadR.y,
974 leftToRight ? rowHeadR.width : vsbR.width,
975 colHeadR.height);
978 if (upperRight != null) {
979 upperRight.setBounds(leftToRight ? vsbR.x : rowHeadR.x,
980 colHeadR.y,
981 leftToRight ? vsbR.width : rowHeadR.width,
982 colHeadR.height);
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;
998 if (wantsVSB) {
999 int vsbWidth = Math.max(0, Math.min(vsb.getPreferredSize().width,
1000 available.width));
1002 available.width -= vsbWidth;
1003 vsbR.width = vsbWidth;
1005 if (leftToRight) {
1006 vsbR.x = available.x + available.width + vpbInsets.right;
1008 else {
1009 vsbR.x = available.x - vpbInsets.left;
1010 available.x += vsbWidth;
1013 else {
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;
1029 if (wantsHSB) {
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;
1037 else {
1038 available.height += oldHeight;
1044 * Returns the bounds of the border around the specified scroll pane's
1045 * viewport.
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();