/* * Copyright 2000-2012 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.util.ui; import org.intellij.lang.annotations.JdkConstants; import javax.swing.*; import java.awt.*; /** * Flow layout calculates necessary size assuming that all components are laid out within a single row. * That may cause troubles during initial space calculation, i.e. panel with flow layout is represented as a * single wide row inside a scroll pane. This panel fixes that by calculating necessary size on its own. * It fixes the width to use as a minimum between a width offered by default flow layout and customizable value * and calculates the height. If the user has an ability to manually change panel size (e.g. indirectly via changing * size of the dialog that serves as a container for the panel), that width is used as a maximum width. * * @author Denis Zhdanov * @since Jul 28, 2008 */ public class MultiRowFlowPanel extends JPanel { private final int maximumWidth = GraphicsEnvironment.isHeadless() ? 400 : GraphicsEnvironment.getLocalGraphicsEnvironment().getDefaultScreenDevice().getDefaultConfiguration().getBounds().width / 2; private int myForcedWidth; public MultiRowFlowPanel(@JdkConstants.FlowLayoutAlignment int align, int hGap, int vGap) { super(new FlowLayout(align, hGap, vGap)); } /** * Calculates a preferred size assuming that the maximum row width is a value returned from * {@link #getMaxRowWidth()}. */ @Override public Dimension getPreferredSize() { return calculateSize(getMaxRowWidth()); } /** * Calculates a preferred size assuming that the maximum row width is a value returned from * {@link #getMaxRowWidth()}. */ @Override public Dimension getMinimumSize() { return calculateSize(getMaxRowWidth()); } /** * @return current representation width if the component is already showed; minimum of default preferred * width (when all components are layed in a single row) and half screen width */ private int getMaxRowWidth() { if (myForcedWidth > 0) { return myForcedWidth; } int result = getSize().width; if (result == 0) { result = Math.min(super.getPreferredSize().width, maximumWidth); } return result; } public void setForcedWidth(int forcedWidth) { myForcedWidth = forcedWidth; } /** * Iterates all child components and calculates the space enough to keep all of them assuming that the width is * fixed. */ private Dimension calculateSize(int maxRowWidth) { FlowLayout layout = (FlowLayout)getLayout(); int height = 0; int currentRowWidth = 0; int currentRowHeight = 0; for (int i = 0, count = getComponentCount(); i < count; ++i) { Component comp = getComponent(i); Dimension bounds = comp.getPreferredSize(); if (!comp.isVisible()) { continue; } currentRowHeight = Math.max(currentRowHeight, bounds.height); if (currentRowWidth + layout.getHgap() + bounds.width <= maxRowWidth) { if (bounds.width != 0) { currentRowWidth += bounds.width + layout.getHgap(); } continue; } height += currentRowHeight + layout.getVgap(); currentRowWidth = bounds.width; currentRowHeight = bounds.height; } return new Dimension(maxRowWidth, height + currentRowHeight + 2 * layout.getVgap()); } }