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
.ui
;
18 import com
.intellij
.openapi
.Disposable
;
19 import com
.intellij
.openapi
.ui
.popup
.Balloon
;
20 import com
.intellij
.openapi
.util
.Disposer
;
21 import com
.intellij
.util
.Alarm
;
22 import org
.jetbrains
.annotations
.NotNull
;
26 import java
.awt
.event
.ComponentAdapter
;
27 import java
.awt
.event
.ComponentEvent
;
28 import java
.util
.ArrayList
;
29 import java
.util
.List
;
31 public class BalloonLayout
{
33 private final JLayeredPane myParent
;
34 private final Insets myInsets
;
36 private final List
<Balloon
> myBalloons
= new ArrayList
<Balloon
>();
38 private final Alarm myRelayoutAlarm
= new Alarm();
39 private final Runnable myRelayoutRunnable
= new Runnable() {
45 public BalloonLayout(@NotNull JLayeredPane parent
, @NotNull Insets insets
) {
48 myParent
.addComponentListener(new ComponentAdapter() {
50 public void componentResized(ComponentEvent e
) {
56 public void add(final Balloon balloon
) {
57 myBalloons
.add(balloon
);
58 Disposer
.register(balloon
, new Disposable() {
59 public void dispose() {
60 myBalloons
.remove(balloon
);
66 balloon
.show(myParent
);
70 private void queueRelayout() {
71 myRelayoutAlarm
.cancelAllRequests();
72 myRelayoutAlarm
.addRequest(myRelayoutRunnable
, 200);
75 private void relayout() {
76 final Dimension size
= myParent
.getSize();
78 size
.width
-= myInsets
.left
+ myInsets
.right
;
79 size
.height
-= myInsets
.top
+ myInsets
.bottom
;
81 final Rectangle layoutRec
= new Rectangle(new Point(myInsets
.left
, myInsets
.top
), size
);
83 List
<ArrayList
<Balloon
>> columns
= createColumns(layoutRec
);
84 List
<Integer
> columnWidths
= computeWidths(columns
);
86 int eachCoumnX
= (int)layoutRec
.getMaxX();
87 for (int i
= 0; i
< columns
.size(); i
++) {
88 final ArrayList
<Balloon
> eachColumn
= columns
.get(i
);
89 final Integer eachWidth
= columnWidths
.get(i
);
90 eachCoumnX
-= eachWidth
.intValue();
91 int eachY
= layoutRec
.y
;
92 for (Balloon eachBalloon
: eachColumn
) {
93 final Rectangle eachRec
= new Rectangle();
94 final Dimension eachPrefSize
= eachBalloon
.getPreferredSize();
95 eachRec
.setSize(eachPrefSize
);
96 eachRec
.setLocation(eachCoumnX
+ eachWidth
.intValue() - eachRec
.width
, eachY
);
97 eachBalloon
.setBounds(eachRec
);
98 eachY
+= eachRec
.height
;
105 private static List
<Integer
> computeWidths(List
<ArrayList
<Balloon
>> columns
) {
106 List
<Integer
> columnWidths
= new ArrayList
<Integer
>();
107 for (ArrayList
<Balloon
> eachColumn
: columns
) {
109 for (Balloon each
: eachColumn
) {
110 maxWidth
= Math
.max(each
.getPreferredSize().width
, maxWidth
);
112 columnWidths
.add(maxWidth
);
117 private List
<ArrayList
<Balloon
>> createColumns(Rectangle layoutRec
) {
118 List
<ArrayList
<Balloon
>> columns
= new ArrayList
<ArrayList
<Balloon
>>();
120 ArrayList
<Balloon
> eachColumn
= new ArrayList
<Balloon
>();
121 columns
.add(eachColumn
);
123 int eachColumnHeight
= 0;
124 for (Balloon each
: myBalloons
) {
125 final Dimension eachSize
= each
.getPreferredSize();
126 if (eachColumnHeight
+ eachSize
.height
> layoutRec
.getHeight()) {
127 eachColumn
= new ArrayList
<Balloon
>();
128 columns
.add(eachColumn
);
129 eachColumnHeight
= 0;
131 eachColumn
.add(each
);
132 eachColumnHeight
+= eachSize
.height
;