blob: 022e4862dd54c783bd9989a60fb6f1e4f256ca94 [file] [log] [blame]
/*
* Copyright 2000-2009 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;
import com.intellij.openapi.Disposable;
import com.intellij.openapi.ui.popup.Balloon;
import com.intellij.openapi.util.Disposer;
import com.intellij.util.Alarm;
import org.jetbrains.annotations.NotNull;
import javax.swing.*;
import java.awt.*;
import java.awt.event.ComponentAdapter;
import java.awt.event.ComponentEvent;
import java.util.ArrayList;
import java.util.List;
public class BalloonLayoutImpl implements BalloonLayout {
private final JLayeredPane myParent;
private final Insets myInsets;
private final List<Balloon> myBalloons = new ArrayList<Balloon>();
private final Alarm myRelayoutAlarm = new Alarm();
private final Runnable myRelayoutRunnable = new Runnable() {
public void run() {
relayout();
}
};
public BalloonLayoutImpl(@NotNull JLayeredPane parent, @NotNull Insets insets) {
myParent = parent;
myInsets = insets;
myParent.addComponentListener(new ComponentAdapter() {
@Override
public void componentResized(ComponentEvent e) {
queueRelayout();
}
});
}
@Override
public void add(final Balloon balloon) {
myBalloons.add(balloon);
Disposer.register(balloon, new Disposable() {
public void dispose() {
myBalloons.remove(balloon);
queueRelayout();
}
});
relayout();
balloon.show(myParent);
}
private void queueRelayout() {
myRelayoutAlarm.cancelAllRequests();
myRelayoutAlarm.addRequest(myRelayoutRunnable, 200);
}
private void relayout() {
final Dimension size = myParent.getSize();
size.width -= myInsets.left + myInsets.right;
size.height -= myInsets.top + myInsets.bottom;
final Rectangle layoutRec = new Rectangle(new Point(myInsets.left, myInsets.top), size);
List<ArrayList<Balloon>> columns = createColumns(layoutRec);
while (columns.size() > 1) {
myBalloons.remove(0);
columns = createColumns(layoutRec);
}
List<Integer> columnWidths = computeWidths(columns);
int eachCoumnX = (int)layoutRec.getMaxX();
for (int i = 0; i < columns.size(); i++) {
final ArrayList<Balloon> eachColumn = columns.get(i);
final Integer eachWidth = columnWidths.get(i);
eachCoumnX -= eachWidth.intValue();
int eachY = layoutRec.y;
for (Balloon eachBalloon : eachColumn) {
final Rectangle eachRec = new Rectangle();
final Dimension eachPrefSize = eachBalloon.getPreferredSize();
eachRec.setSize(eachPrefSize);
eachRec.setLocation(eachCoumnX + eachWidth.intValue() - eachRec.width, eachY);
eachBalloon.setBounds(eachRec);
eachY += eachRec.height;
}
}
}
private static List<Integer> computeWidths(List<ArrayList<Balloon>> columns) {
List<Integer> columnWidths = new ArrayList<Integer>();
for (ArrayList<Balloon> eachColumn : columns) {
int maxWidth = 0;
for (Balloon each : eachColumn) {
maxWidth = Math.max(each.getPreferredSize().width, maxWidth);
}
columnWidths.add(maxWidth);
}
return columnWidths;
}
private List<ArrayList<Balloon>> createColumns(Rectangle layoutRec) {
List<ArrayList<Balloon>> columns = new ArrayList<ArrayList<Balloon>>();
ArrayList<Balloon> eachColumn = new ArrayList<Balloon>();
columns.add(eachColumn);
int eachColumnHeight = 0;
for (Balloon each : myBalloons) {
final Dimension eachSize = each.getPreferredSize();
if (eachColumnHeight + eachSize.height > layoutRec.getHeight()) {
eachColumn = new ArrayList<Balloon>();
columns.add(eachColumn);
eachColumnHeight = 0;
}
eachColumn.add(each);
eachColumnHeight += eachSize.height;
}
return columns;
}
}