summaryrefslogtreecommitdiff
path: root/platform/platform-api/src/com/intellij/ui/components/JBScrollPane.java
diff options
context:
space:
mode:
Diffstat (limited to 'platform/platform-api/src/com/intellij/ui/components/JBScrollPane.java')
-rw-r--r--platform/platform-api/src/com/intellij/ui/components/JBScrollPane.java203
1 files changed, 98 insertions, 105 deletions
diff --git a/platform/platform-api/src/com/intellij/ui/components/JBScrollPane.java b/platform/platform-api/src/com/intellij/ui/components/JBScrollPane.java
index e0c326ad1edb..83944a51755d 100644
--- a/platform/platform-api/src/com/intellij/ui/components/JBScrollPane.java
+++ b/platform/platform-api/src/com/intellij/ui/components/JBScrollPane.java
@@ -33,7 +33,10 @@ import java.lang.reflect.Method;
public class JBScrollPane extends JScrollPane {
private int myViewportBorderWidth = -1;
- private JLayeredPane myLayeredPane;
+ private boolean myHasOverlayScrollbars;
+
+ private int myOverriddenVPolicy = -1;
+ private int myOverriddenHPolicy = -1;
public JBScrollPane(int viewportWidth) {
init(false);
@@ -64,89 +67,14 @@ public class JBScrollPane extends JScrollPane {
if (c == null) return null;
if (!(c instanceof JViewport)) {
- // if asked for a viewport child, take a viewport.
- // If not (e.g asked for a scrollbar), go straight to JLayeredPane
Container vp = c.getParent();
if (vp instanceof JViewport) c = vp;
}
c = c.getParent();
- if (c instanceof JLayeredPane) {
- c = c.getParent();
- }
- if (!(c instanceof JBScrollPane)) return null;
-
- return (JBScrollPane)c;
- }
-
- @Override
- public void setVerticalScrollBar(JScrollBar c) {
- JScrollBar old = getVerticalScrollBar();
- super.setVerticalScrollBar(c);
- transferToLayeredPane(old, c, ScrollPaneConstants.VERTICAL_SCROLLBAR);
- }
-
- @Override
- public void setHorizontalScrollBar(JScrollBar c) {
- JScrollBar old = getHorizontalScrollBar();
- super.setHorizontalScrollBar(c);
- transferToLayeredPane(old, c, ScrollPaneConstants.HORIZONTAL_SCROLLBAR);
- }
-
- @Override
- public void setColumnHeader(JViewport c) {
- JViewport old = getColumnHeader();
- super.setColumnHeader(c);
- transferToLayeredPane(old, c, ScrollPaneConstants.COLUMN_HEADER);
- }
+ if (!(c instanceof JScrollPane)) return null;
- @Override
- public void setRowHeader(JViewport c) {
- JViewport old = getRowHeader();
- super.setRowHeader(c);
- transferToLayeredPane(old, c, ScrollPaneConstants.ROW_HEADER);
- }
-
- @Override
- public void setViewport(JViewport c) {
- JViewport old = getViewport();
- super.setViewport(c);
- transferToLayeredPane(old, c, ScrollPaneConstants.VIEWPORT);
- }
-
- @Override
- public void setCorner(String key, Component c) {
- Component old = getCorner(key);
- super.setCorner(key, c);
- transferToLayeredPane(old, c, key);
- }
-
- private void transferToLayeredPane(Component old, Component c, String key) {
- if (!ButtonlessScrollBarUI.isMacOverlayScrollbarSupported()) return;
-
- JLayeredPane pane = getLayoutPane();
- LayoutManager layout = getLayout();
-
- if (old != null && old != c) {
- pane.remove(old);
- layout.removeLayoutComponent(old);
- }
-
- if (c != null) {
- if (ScrollPaneConstants.VERTICAL_SCROLLBAR.equals(key) || ScrollPaneConstants.HORIZONTAL_SCROLLBAR.equals(key)) {
- pane.setLayer(c, JLayeredPane.PALETTE_LAYER);
- }
- pane.add(c);
- layout.addLayoutComponent(key, c);
- }
- }
-
- @NotNull
- private JLayeredPane getLayoutPane() {
- if (myLayeredPane == null) {
- myLayeredPane = new JLayeredPane();
- }
- return myLayeredPane;
+ return (JScrollPane)c;
}
private void init() {
@@ -154,9 +82,6 @@ public class JBScrollPane extends JScrollPane {
}
private void init(boolean setupCorners) {
- if (ButtonlessScrollBarUI.isMacOverlayScrollbarSupported()) {
- add(getLayoutPane());
- }
setLayout(new ScrollPaneLayout());
if (setupCorners) {
@@ -178,6 +103,11 @@ public class JBScrollPane extends JScrollPane {
updateViewportBorder();
}
+ @Override
+ public boolean isOptimizedDrawingEnabled() {
+ return !myHasOverlayScrollbars;
+ }
+
private void updateViewportBorder() {
setViewportBorder(new ViewportBorder(myViewportBorderWidth >= 0 ? myViewportBorderWidth : 1));
}
@@ -201,24 +131,75 @@ public class JBScrollPane extends JScrollPane {
return new JBViewport();
}
+ @Override
+ public int getHorizontalScrollBarPolicy() {
+ // See layout() for explanation
+ //noinspection MagicConstant
+ return myOverriddenHPolicy != -1 ? myOverriddenHPolicy : super.getHorizontalScrollBarPolicy();
+ }
+
+ @Override
+ public int getVerticalScrollBarPolicy() {
+ // See layout() for explanation
+ //noinspection MagicConstant
+ return myOverriddenVPolicy != -1 ? myOverriddenVPolicy : super.getVerticalScrollBarPolicy();
+ }
+
@SuppressWarnings("deprecation")
@Override
public void layout() {
+ LayoutManager layout = getLayout();
+ ScrollPaneLayout scrollLayout = layout instanceof ScrollPaneLayout ? (ScrollPaneLayout)layout : null;
+
+ // Logic here is a workaround necessary to support OS X overlaid scrollbars.
+
+ int oldHPolicy = -1;
+ int oldVPolicy = -1;
+ if (scrollLayout != null) {
+ // First, we override scrollbar policy to HORIZONTAL_SCROLLBAR_AS_NEEDED so JScrollPane could correctly lay them out.
+ // We do so only when policy is ALWAYS so they could be hidden by JScrollPane when necessary.
+ // Also, we only override when scrollbar is an overlay scrollbar.
+ // (The related problem is IDEA-123688)
+ if (isOverlaidScrollbar(getHorizontalScrollBar())) {
+ oldHPolicy = scrollLayout.getHorizontalScrollBarPolicy();
+ if (oldHPolicy == HORIZONTAL_SCROLLBAR_ALWAYS) {
+ scrollLayout.setHorizontalScrollBarPolicy(myOverriddenHPolicy = HORIZONTAL_SCROLLBAR_AS_NEEDED);
+ }
+ }
+
+ if (isOverlaidScrollbar(getVerticalScrollBar())) {
+ oldVPolicy = scrollLayout.getVerticalScrollBarPolicy();
+ if (oldVPolicy == VERTICAL_SCROLLBAR_ALWAYS) {
+ scrollLayout.setVerticalScrollBarPolicy(myOverriddenVPolicy = VERTICAL_SCROLLBAR_AS_NEEDED);
+ }
+ }
+ }
+
+ // Now we let JScrollPane layout everything as necessary
super.layout();
- if (!ButtonlessScrollBarUI.isMacOverlayScrollbarSupported()) return;
-
- LayoutManager layout = getLayout();
- if (layout instanceof ScrollPaneLayout && myLayeredPane != null) {
- relayoutScrollbars(this, (ScrollPaneLayout)layout, myLayeredPane);
+ if (scrollLayout != null) {
+ // Now it's time to jump in and expand the viewport so it fits the whole area
+ // (taking into consideration corners, headers and other stuff).
+ myHasOverlayScrollbars = relayoutScrollbars(
+ this, scrollLayout,
+ myHasOverlayScrollbars // If last time we did relayouting, we should restore it back.
+ );
+
+ // Now we restore overridden policies as though nothing happened at all.
+ if (oldHPolicy != -1) scrollLayout.setHorizontalScrollBarPolicy(oldHPolicy);
+ if (oldVPolicy != -1) scrollLayout.setVerticalScrollBarPolicy(oldVPolicy);
+ myOverriddenHPolicy = -1;
+ myOverriddenVPolicy = -1;
+ }
+ else {
+ myHasOverlayScrollbars = false;
}
}
- private static void relayoutScrollbars(@NotNull JComponent container,
- @NotNull ScrollPaneLayout layout,
- @NotNull JLayeredPane layeredPane) {
+ private static boolean relayoutScrollbars(@NotNull JComponent container, @NotNull ScrollPaneLayout layout, boolean forceRelayout) {
JViewport viewport = layout.getViewport();
- if (viewport == null) return;
+ if (viewport == null) return false;
JScrollBar vsb = layout.getVerticalScrollBar();
JScrollBar hsb = layout.getHorizontalScrollBar();
@@ -227,22 +208,29 @@ public class JBScrollPane extends JScrollPane {
Rectangle viewportBounds = viewport.getBounds();
- boolean extendsViewportUnderVScrollbar = vsb != null && shouldExtendViewportUnderScrollbar(vsb);
- boolean extendsViewportUnderHScrollbar = hsb != null && shouldExtendViewportUnderScrollbar(hsb);
-
- if (extendsViewportUnderVScrollbar) {
+ boolean extendViewportUnderVScrollbar = vsb != null && shouldExtendViewportUnderScrollbar(vsb);
+ boolean extendViewportUnderHScrollbar = hsb != null && shouldExtendViewportUnderScrollbar(hsb);
+ boolean hasOverlayScrollbars = extendViewportUnderVScrollbar || extendViewportUnderHScrollbar;
+
+ if (!hasOverlayScrollbars && !forceRelayout) return false;
+
+ container.setComponentZOrder(viewport, container.getComponentCount() - 1);
+ if (vsb != null) container.setComponentZOrder(vsb, 0);
+ if (hsb != null) container.setComponentZOrder(hsb, 0);
+
+ if (extendViewportUnderVScrollbar) {
viewportBounds.x = Math.min(viewportBounds.x, vsb.getX());
- viewportBounds.width = Math.max(viewportBounds.width, vsb.getX() + vsb.getWidth());
+ viewportBounds.width = vsb.getX() + vsb.getWidth() - viewportBounds.x;
}
- if (extendsViewportUnderHScrollbar) {
+ if (extendViewportUnderHScrollbar) {
viewportBounds.y = Math.min(viewportBounds.y, hsb.getY());
- viewportBounds.height = Math.max(viewportBounds.height, hsb.getY() + hsb.getHeight());
+ viewportBounds.height = hsb.getY() + hsb.getHeight() - viewportBounds.y;
}
- if (extendsViewportUnderVScrollbar) {
+ if (extendViewportUnderVScrollbar) {
if (hsb != null) {
Rectangle scrollbarBounds = hsb.getBounds();
- scrollbarBounds.width = viewportBounds.width - scrollbarBounds.x;
+ scrollbarBounds.width = viewportBounds.x + viewportBounds.width - scrollbarBounds.x;
hsb.setBounds(scrollbarBounds);
}
if (colHead != null) {
@@ -253,10 +241,10 @@ public class JBScrollPane extends JScrollPane {
hideFromView(layout.getCorner(UPPER_RIGHT_CORNER));
hideFromView(layout.getCorner(LOWER_RIGHT_CORNER));
}
- if (extendsViewportUnderHScrollbar) {
+ if (extendViewportUnderHScrollbar) {
if (vsb != null) {
Rectangle scrollbarBounds = vsb.getBounds();
- scrollbarBounds.height = viewportBounds.height - scrollbarBounds.y;
+ scrollbarBounds.height = viewportBounds.y + viewportBounds.height - scrollbarBounds.y;
vsb.setBounds(scrollbarBounds);
}
if (rowHead != null) {
@@ -270,14 +258,19 @@ public class JBScrollPane extends JScrollPane {
}
viewport.setBounds(viewportBounds);
- Insets insets = container.getInsets();
- if (insets == null) insets = new Insets(0, 0, 0, 0);
- layeredPane.setBounds(0, 0, container.getWidth() - insets.right, container.getHeight() - insets.bottom);
+
+ return hasOverlayScrollbars;
}
private static boolean shouldExtendViewportUnderScrollbar(@Nullable JScrollBar scrollbar) {
if (scrollbar == null || !scrollbar.isVisible()) return false;
- ScrollBarUI vsbUI = scrollbar.getUI();
+ return isOverlaidScrollbar(scrollbar);
+ }
+
+ private static boolean isOverlaidScrollbar(@Nullable JScrollBar scrollbar) {
+ if (!ButtonlessScrollBarUI.isMacOverlayScrollbarSupported()) return false;
+
+ ScrollBarUI vsbUI = scrollbar == null ? null : scrollbar.getUI();
return vsbUI instanceof ButtonlessScrollBarUI && !((ButtonlessScrollBarUI)vsbUI).alwaysShowTrack();
}