tool window combo - show content action
[fedora-idea.git] / platform / platform-impl / src / com / intellij / openapi / wm / impl / content / TabContentLayout.java
blob4ea6f2906d8e3fb89afbfa0ba2ea1280f4192772
1 /*
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.openapi.wm.impl.content;
18 import com.intellij.openapi.ui.popup.ListPopup;
19 import com.intellij.openapi.wm.impl.TitlePanel;
20 import com.intellij.ui.content.Content;
21 import com.intellij.ui.content.ContentManager;
22 import com.intellij.ui.content.ContentManagerEvent;
23 import com.intellij.ui.tabs.impl.singleRow.MoreIcon;
24 import com.intellij.util.ui.BaseButtonBehavior;
26 import javax.swing.*;
27 import javax.swing.event.PopupMenuEvent;
28 import javax.swing.event.PopupMenuListener;
29 import java.awt.*;
30 import java.awt.event.ActionEvent;
31 import java.awt.event.ActionListener;
32 import java.awt.event.MouseEvent;
33 import java.awt.geom.GeneralPath;
34 import java.util.ArrayList;
35 import java.util.HashMap;
36 import java.util.Map;
38 class TabContentLayout extends ContentLayout {
40 static final int MORE_ICON_BORDER = 6;
41 LayoutData myLastLayout;
43 JPopupMenu myPopup;
44 final PopupMenuListener myPopupListener;
46 ArrayList<ContentTabLabel> myTabs = new ArrayList<ContentTabLabel>();
47 final Map<Content, ContentTabLabel> myContent2Tabs = new HashMap<Content, ContentTabLabel>();
49 BaseLabel myIdLabel;
51 private final MoreIcon myMoreIcon = new MoreIcon() {
52 protected Rectangle getIconRec() {
53 return myLastLayout.moreRect;
56 protected boolean isActive() {
57 return myUi.myWindow.isActive();
60 protected int getIconY(final Rectangle iconRec) {
61 return iconRec.height / TAB_ARC - getIconHeight() / TAB_ARC + TitlePanel.STRUT;
65 TabContentLayout(ToolWindowContentUi ui) {
66 super(ui);
68 myPopupListener = new MyPopupListener();
70 new BaseButtonBehavior(myUi) {
71 protected void execute(final MouseEvent e) {
72 if (!myUi.isCurrent(TabContentLayout.this)) return;
74 if (myLastLayout != null) {
75 final Rectangle moreRect = myLastLayout.moreRect;
76 if (moreRect != null && moreRect.contains(e.getPoint())) {
77 showPopup();
84 @Override
85 public void init() {
86 reset();
88 myIdLabel = new BaseLabel(myUi, false);
89 for (int i = 0; i < myUi.myManager.getContentCount(); i++) {
90 contentAdded(new ContentManagerEvent(this, myUi.myManager.getContent(i), i));
94 @Override
95 public void reset() {
96 myTabs.clear();
97 myContent2Tabs.clear();
98 myIdLabel = null;
101 private void showPopup() {
102 myPopup = new JPopupMenu();
103 myPopup.addPopupMenuListener(myPopupListener);
105 ArrayList<ContentTabLabel> tabs = myTabs;
107 for (final ContentTabLabel each : tabs) {
108 final JCheckBoxMenuItem item = new JCheckBoxMenuItem(each.getText());
109 if (myUi.myManager.isSelected(each.myContent)) {
110 item.setSelected(true);
112 item.addActionListener(new ActionListener() {
113 public void actionPerformed(final ActionEvent e) {
114 myUi.myManager.setSelectedContent(each.myContent, true);
117 myPopup.add(item);
119 myPopup.show(myUi, myLastLayout.moreRect.x, myLastLayout.moreRect.y);
123 private class MyPopupListener implements PopupMenuListener {
124 public void popupMenuWillBecomeVisible(final PopupMenuEvent e) {
127 public void popupMenuWillBecomeInvisible(final PopupMenuEvent e) {
128 if (myPopup != null) {
129 myPopup.removePopupMenuListener(this);
131 myPopup = null;
134 public void popupMenuCanceled(final PopupMenuEvent e) {
138 @Override
139 public void layout() {
140 Rectangle bounds = myUi.getBounds();
141 ContentManager manager = myUi.myManager;
142 LayoutData data = new LayoutData(myUi);
144 data.eachX = 0;
145 data.eachY = TitlePanel.STRUT;
147 myIdLabel.setBounds(data.eachX, data.eachY, myIdLabel.getPreferredSize().width, bounds.height);
148 data.eachX += myIdLabel.getPreferredSize().width;
149 int tabsStart = data.eachX;
151 if (manager.getContentCount() == 0) return;
153 Content selected = manager.getSelectedContent();
154 if (selected == null) {
155 selected = manager.getContents()[0];
158 if (myLastLayout != null &&
159 myLastLayout.layoutSize.equals(bounds.getSize()) &&
160 myLastLayout.contentCount == manager.getContentCount()) {
161 for (ContentTabLabel each : myTabs) {
162 if (!each.isValid()) break;
163 if (each.myContent == selected && each.getBounds().width != 0) {
164 data = myLastLayout;
165 data.fullLayout = false;
171 if (data.fullLayout) {
172 for (ContentTabLabel eachTab : myTabs) {
173 final Dimension eachSize = eachTab.getPreferredSize();
174 data.requiredWidth += eachSize.width;
175 data.requiredWidth++;
176 data.toLayout.add(eachTab);
180 data.moreRectWidth = myMoreIcon.getIconWidth() + MORE_ICON_BORDER * TAB_ARC;
181 data.toFitWidth = bounds.getSize().width - data.eachX;
183 final ContentTabLabel selectedTab = myContent2Tabs.get(selected);
184 while (true) {
185 if (data.requiredWidth <= data.toFitWidth) break;
186 if (data.toLayout.size() <= 1) break;
188 if (data.toLayout.get(0) != selectedTab) {
189 dropTab(data, data.toLayout.remove(0));
191 else if (data.toLayout.get(data.toLayout.size() - 1) != selectedTab) {
192 dropTab(data, data.toLayout.remove(data.toLayout.size() - 1));
194 else {
195 break;
199 boolean reachedBounds = false;
200 data.moreRect = null;
201 for (ContentTabLabel each : data.toLayout) {
202 if (isToDrawTabs()) {
203 data.eachY = 0;
205 else {
206 data.eachY = TitlePanel.STRUT;
208 final Dimension eachSize = each.getPreferredSize();
209 if (data.eachX + eachSize.width < data.toFitWidth + tabsStart) {
210 each.setBounds(data.eachX, data.eachY, eachSize.width, bounds.height - data.eachY);
211 data.eachX += eachSize.width;
212 data.eachX++;
214 else {
215 if (!reachedBounds) {
216 final int width = bounds.width - data.eachX - data.moreRectWidth;
217 each.setBounds(data.eachX, data.eachY, width, bounds.height - data.eachY);
218 data.eachX += width;
219 data.eachX++;
221 else {
222 each.setBounds(0, 0, 0, 0);
224 reachedBounds = true;
228 for (ContentTabLabel each : data.toDrop) {
229 each.setBounds(0, 0, 0, 0);
233 if (data.toDrop.size() > 0) {
234 data.moreRect = new Rectangle(data.eachX + MORE_ICON_BORDER, 0, myMoreIcon.getIconWidth(), bounds.height);
235 final int selectedIndex = manager.getIndexOfContent(manager.getSelectedContent());
236 if (selectedIndex == 0) {
237 myMoreIcon.setPaintedIcons(false, true);
239 else if (selectedIndex == manager.getContentCount() - 1) {
240 myMoreIcon.setPaintedIcons(true, false);
242 else {
243 myMoreIcon.setPaintedIcons(true, true);
246 else {
247 data.moreRect = null;
250 myLastLayout = data;
254 void dropTab(final LayoutData data, final ContentTabLabel toDropLabel) {
255 data.requiredWidth -= (toDropLabel.getPreferredSize().width + 1);
256 data.toDrop.add(toDropLabel);
257 if (data.toDrop.size() == 1) {
258 data.toFitWidth -= data.moreRectWidth;
262 boolean isToDrawTabs() {
263 return myTabs.size() > 1;
266 static class LayoutData {
267 int toFitWidth;
268 int requiredWidth;
269 Dimension layoutSize;
270 boolean fullLayout = true;
272 int moreRectWidth;
274 ArrayList<ContentTabLabel> toLayout = new ArrayList<ContentTabLabel>();
275 ArrayList<ContentTabLabel> toDrop = new ArrayList<ContentTabLabel>();
277 Rectangle moreRect;
279 public int eachX;
280 public int eachY;
281 public int contentCount;
283 LayoutData(ToolWindowContentUi ui) {
284 layoutSize = ui.getSize();
285 contentCount = ui.myManager.getContentCount();
289 @Override
290 public void paintComponent(Graphics g) {
291 if (!isToDrawTabs()) return;
293 final Graphics2D g2d = (Graphics2D)g;
295 final GraphicsConfig c = new GraphicsConfig(g);
296 c.setAntialiasing(true);
298 for (ContentTabLabel each : myTabs) {
299 fillTabShape(g2d, each, getShapeFor(each), each.isSelected());
302 c.restore();
306 private Shape getShapeFor(ContentTabLabel label) {
307 final Rectangle bounds = label.getBounds();
309 if (bounds.width <= 0 || bounds.height <= 0) return new GeneralPath();
311 if (!label.isSelected()) {
312 bounds.y += TAB_SHIFT;
315 bounds.width += 1;
317 int arc = TAB_ARC;
319 final GeneralPath path = new GeneralPath();
320 path.moveTo(bounds.x, bounds.y + bounds.height);
321 path.lineTo(bounds.x, bounds.y + arc);
322 path.quadTo(bounds.x, bounds.y, bounds.x + arc, bounds.y);
323 path.lineTo(bounds.x + bounds.width - arc, bounds.y);
324 path.quadTo(bounds.x + bounds.width, bounds.y, bounds.x + bounds.width, bounds.y + arc);
325 path.lineTo(bounds.x + bounds.width, bounds.y + bounds.height);
326 path.closePath();
328 return path;
331 @Override
332 public void paintChildren(Graphics g) {
333 if (!isToDrawTabs()) return;
335 final GraphicsConfig c = new GraphicsConfig(g);
336 c.setAntialiasing(true);
338 final Graphics2D g2d = (Graphics2D)g;
340 final Color edges = myUi.myWindow.isActive() ? TAB_BORDER_ACTIVE_WINDOW : TAB_BORDER_PASSIVE_WINDOW;
341 g2d.setColor(edges);
342 for (int i = 0; i < myTabs.size(); i++) {
343 ContentTabLabel each = myTabs.get(i);
344 final Shape shape = getShapeFor(each);
345 g2d.draw(shape);
348 c.restore();
350 if (myLastLayout != null && myLastLayout.moreRect != null) {
351 myMoreIcon.paintIcon(myUi, g);
355 @Override
356 public void update() {
357 for (ContentTabLabel each : myTabs) {
358 each.update();
361 updateIdLabel(myIdLabel);
364 @Override
365 public void rebuild() {
366 myUi.removeAll();
368 myUi.add(myIdLabel);
369 myUi.initMouseListeners(myIdLabel, myUi);
371 for (ContentTabLabel each : myTabs) {
372 myUi.add(each);
373 myUi.initMouseListeners(each, myUi);
377 @Override
378 public void contentAdded(ContentManagerEvent event) {
379 final ContentTabLabel tab = new ContentTabLabel(event.getContent(), this);
380 myTabs.add(event.getIndex(), tab);
381 myContent2Tabs.put(event.getContent(), tab);
384 @Override
385 public void contentRemoved(ContentManagerEvent event) {
386 final ContentTabLabel tab = myContent2Tabs.get(event.getContent());
387 if (tab != null) {
388 myTabs.remove(tab);
389 myContent2Tabs.remove(event.getContent());
393 @Override
394 public void showContentPopup(ListPopup listPopup) {
395 Content selected = myUi.myManager.getSelectedContent();
396 if (selected != null) {
397 ContentTabLabel tab = myContent2Tabs.get(selected);
398 listPopup.showUnderneathOf(tab);
399 } else {
400 listPopup.showUnderneathOf(myIdLabel);