diff --git a/platform/platform-api/src/com/intellij/ui/components/panels/HorizontalLayout.java b/platform/platform-api/src/com/intellij/ui/components/panels/HorizontalLayout.java
index 63f982b806f3..9652562b6d2a 100644
--- a/platform/platform-api/src/com/intellij/ui/components/panels/HorizontalLayout.java
+++ b/platform/platform-api/src/com/intellij/ui/components/panels/HorizontalLayout.java
@@ -20,13 +20,20 @@ import java.awt.Component;
import java.awt.Container;
import java.awt.Dimension;
import java.awt.Insets;
-import java.awt.LayoutManager;
+import java.awt.LayoutManager2;
import java.util.ArrayList;
/**
+ * This class is intended to lay out added components horizontally.
+ * It allows to add them into the LEFT, CENTER, or RIGHT group, which are aligned separately.
+ * Every group can contain any amount of components. The specified gap is added between components,
+ * and the double gap is added between groups of components.
+ *
NB!: this class must be modified together with the VerticalLayout class accordingly
+ *
* @author Sergey.Malenkov
+ * @see VerticalLayout
*/
-public final class HorizontalLayout implements LayoutManager {
+public final class HorizontalLayout implements LayoutManager2 {
public static final String LEFT = "LEFT";
public static final String RIGHT = "RIGHT";
public static final String CENTER = "CENTER";
@@ -73,6 +80,35 @@ public final class HorizontalLayout implements LayoutManager {
}
}
+ @Override
+ public void addLayoutComponent(Component component, Object constraints) {
+ if ((constraints == null) || (constraints instanceof String)) {
+ addLayoutComponent((String)constraints, component);
+ }
+ else {
+ throw new IllegalArgumentException("unsupported constraints: " + constraints);
+ }
+ }
+
+ @Override
+ public Dimension maximumLayoutSize(Container target) {
+ return new Dimension(Integer.MAX_VALUE, Integer.MAX_VALUE);
+ }
+
+ @Override
+ public float getLayoutAlignmentX(Container target) {
+ return .5f;
+ }
+
+ @Override
+ public float getLayoutAlignmentY(Container target) {
+ return .5f;
+ }
+
+ @Override
+ public void invalidateLayout(Container target) {
+ }
+
@Override
public void addLayoutComponent(String name, Component component) {
synchronized (component.getTreeLock()) {
@@ -154,19 +190,21 @@ public final class HorizontalLayout implements LayoutManager {
private int layout(ArrayList list, int x, int height, Insets insets) {
for (Component component : list) {
- Dimension size = component.getPreferredSize();
- int y = 0;
- if (myAlignment == -1) {
- size.height = height;
- }
- else if (myAlignment != SwingConstants.TOP) {
- y = height - size.height;
- if (myAlignment == SwingConstants.CENTER) {
- y /= 2;
+ if (component.isVisible()) {
+ Dimension size = component.getPreferredSize();
+ int y = 0;
+ if (myAlignment == -1) {
+ size.height = height;
}
+ else if (myAlignment != SwingConstants.TOP) {
+ y = height - size.height;
+ if (myAlignment == SwingConstants.CENTER) {
+ y /= 2;
+ }
+ }
+ component.setBounds(x + insets.left, y + insets.top, size.width, size.height);
+ x += size.width + myGap;
}
- component.setBounds(x + insets.left, y + insets.top, size.width, size.height);
- x += size.width + myGap;
}
return x;
}
@@ -188,7 +226,9 @@ public final class HorizontalLayout implements LayoutManager {
private Dimension getPreferredSize(ArrayList list) {
Dimension result = null;
for (Component component : list) {
- result = join(result, myGap, component.getPreferredSize());
+ if (component.isVisible()) {
+ result = join(result, myGap, component.getPreferredSize());
+ }
}
return result;
}
diff --git a/platform/platform-api/src/com/intellij/ui/components/panels/VerticalLayout.java b/platform/platform-api/src/com/intellij/ui/components/panels/VerticalLayout.java
new file mode 100644
index 000000000000..7b9fdd0242ba
--- /dev/null
+++ b/platform/platform-api/src/com/intellij/ui/components/panels/VerticalLayout.java
@@ -0,0 +1,256 @@
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.intellij.ui.components.panels;
+
+import javax.swing.SwingConstants;
+import java.awt.Component;
+import java.awt.Container;
+import java.awt.Dimension;
+import java.awt.Insets;
+import java.awt.LayoutManager2;
+import java.util.ArrayList;
+
+/**
+ * This class is intended to lay out added components vertically.
+ * It allows to add them into the TOP, CENTER, or BOTTOM group, which are aligned separately.
+ * Every group can contain any amount of components. The specified gap is added between components,
+ * and the double gap is added between groups of components.
+ * NB!: this class must be modified together with the HorizontalLayout class accordingly
+ *
+ * @author Sergey.Malenkov
+ * @see HorizontalLayout
+ */
+public final class VerticalLayout implements LayoutManager2 {
+ public static final String TOP = "TOP";
+ public static final String BOTTOM = "BOTTOM";
+ public static final String CENTER = "CENTER";
+
+ private final ArrayList myTop = new ArrayList();
+ private final ArrayList myBottom = new ArrayList();
+ private final ArrayList myCenter = new ArrayList();
+ private final int myAlignment;
+ private final int myGap;
+
+ /**
+ * Creates a layout with the specified gap.
+ * All components will have preferred widths,
+ * but their widths will be set according to the container.
+ *
+ * @param gap vertical gap between components
+ */
+ public VerticalLayout(int gap) {
+ myGap = gap;
+ myAlignment = -1;
+ }
+
+ /**
+ * Creates a layout with the specified gap and vertical alignment.
+ * All components will have preferred sizes.
+ *
+ * @param gap vertical gap between components
+ * @param alignment horizontal alignment for components
+ *
+ * @see SwingConstants#LEFT
+ * @see SwingConstants#RIGHT
+ * @see SwingConstants#CENTER
+ */
+ public VerticalLayout(int gap, int alignment) {
+ myGap = gap;
+ switch (alignment) {
+ case SwingConstants.LEFT:
+ case SwingConstants.RIGHT:
+ case SwingConstants.CENTER:
+ myAlignment = alignment;
+ break;
+ default:
+ throw new IllegalArgumentException("unsupported alignment: " + alignment);
+ }
+ }
+
+ @Override
+ public void addLayoutComponent(Component component, Object constraints) {
+ if ((constraints == null) || (constraints instanceof String)) {
+ addLayoutComponent((String)constraints, component);
+ }
+ else {
+ throw new IllegalArgumentException("unsupported constraints: " + constraints);
+ }
+ }
+
+ @Override
+ public Dimension maximumLayoutSize(Container target) {
+ return new Dimension(Integer.MAX_VALUE, Integer.MAX_VALUE);
+ }
+
+ @Override
+ public float getLayoutAlignmentX(Container target) {
+ return .5f;
+ }
+
+ @Override
+ public float getLayoutAlignmentY(Container target) {
+ return .5f;
+ }
+
+ @Override
+ public void invalidateLayout(Container target) {
+ }
+
+ @Override
+ public void addLayoutComponent(String name, Component component) {
+ synchronized (component.getTreeLock()) {
+ if (name == null || CENTER.equalsIgnoreCase(name)) {
+ myCenter.add(component);
+ }
+ else if (TOP.equalsIgnoreCase(name)) {
+ myTop.add(component);
+ }
+ else if (BOTTOM.equalsIgnoreCase(name)) {
+ myBottom.add(component);
+ }
+ else {
+ throw new IllegalArgumentException("unsupported name: " + name);
+ }
+ }
+ }
+
+ @Override
+ public void removeLayoutComponent(Component component) {
+ myTop.remove(component);
+ myBottom.remove(component);
+ myCenter.remove(component);
+ }
+
+ @Override
+ public Dimension preferredLayoutSize(Container container) {
+ return getPreferredSize(container, true);
+ }
+
+ @Override
+ public Dimension minimumLayoutSize(Container container) {
+ return getPreferredSize(container, false);
+ }
+
+ @Override
+ public void layoutContainer(Container container) {
+ synchronized (container.getTreeLock()) {
+ Dimension top = getPreferredSize(myTop);
+ Dimension bottom = getPreferredSize(myBottom);
+ Dimension center = getPreferredSize(myCenter);
+
+ Insets insets = container.getInsets();
+ int width = container.getWidth() - insets.left - insets.right;
+ int height = container.getHeight() - insets.top - insets.bottom;
+
+ int topY = 0;
+ if (top != null) {
+ topY = myGap + layout(myTop, 0, width, insets);
+ }
+ int bottomY = height;
+ if (bottom != null) {
+ bottomY -= bottom.height;
+ }
+ if (bottomY < topY) {
+ bottomY = topY;
+ }
+ if (center != null) {
+ int centerY = (height - center.height) / 2;
+ if (centerY > topY) {
+ int centerBottomY = centerY + center.height + myGap + myGap;
+ if (centerBottomY > bottomY) {
+ centerY = bottomY - center.height - myGap - myGap;
+ }
+ }
+ if (centerY < topY) {
+ centerY = topY;
+ }
+ centerY = myGap + layout(myCenter, centerY, width, insets);
+ if (bottomY < centerY) {
+ bottomY = centerY;
+ }
+ }
+ if (bottom != null) {
+ layout(myBottom, bottomY, width, insets);
+ }
+ }
+ }
+
+ private int layout(ArrayList list, int y, int width, Insets insets) {
+ for (Component component : list) {
+ if (component.isVisible()) {
+ Dimension size = component.getPreferredSize();
+ int x = 0;
+ if (myAlignment == -1) {
+ size.width = width;
+ }
+ else if (myAlignment != SwingConstants.LEFT) {
+ x = width - size.width;
+ if (myAlignment == SwingConstants.CENTER) {
+ x /= 2;
+ }
+ }
+ component.setBounds(x + insets.left, y + insets.top, size.width, size.height);
+ y += size.height + myGap;
+ }
+ }
+ return y;
+ }
+
+ private static Dimension join(Dimension result, int gap, Dimension size) {
+ if (size == null) {
+ return result;
+ }
+ if (result == null) {
+ return new Dimension(size);
+ }
+ result.height += gap + size.height;
+ if (result.width < size.width) {
+ result.width = size.width;
+ }
+ return result;
+ }
+
+ private Dimension getPreferredSize(ArrayList list) {
+ Dimension result = null;
+ for (Component component : list) {
+ if (component.isVisible()) {
+ result = join(result, myGap, component.getPreferredSize());
+ }
+ }
+ return result;
+ }
+
+ private Dimension getPreferredSize(Container container, boolean aligned) {
+ synchronized (container.getTreeLock()) {
+ Dimension top = getPreferredSize(myTop);
+ Dimension bottom = getPreferredSize(myBottom);
+ Dimension center = getPreferredSize(myCenter);
+ Dimension result = join(join(join(null, myGap + myGap, top), myGap + myGap, center), myGap + myGap, bottom);
+ if (result == null) {
+ result = new Dimension();
+ }
+ else if (aligned) {
+ int topHeight = top == null ? 0 : top.height;
+ int bottomHeight = bottom == null ? 0 : bottom.height;
+ result.width += Math.abs(topHeight - bottomHeight);
+ }
+ Insets insets = container.getInsets();
+ result.width += insets.left + insets.right;
+ result.height += insets.top + insets.bottom;
+ return result;
+ }
+ }
+}