ComponentWithBrowseButton - optional remove listener on hide
[fedora-idea.git] / platform / platform-api / src / com / intellij / ui / tabs / impl / TabLabel.java
blob0dba93296ddd0602c6d04d62edd6470de43002c0
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.ui.tabs.impl;
18 import com.intellij.ide.DataManager;
19 import com.intellij.openapi.actionSystem.ActionGroup;
20 import com.intellij.openapi.actionSystem.ActionPlaces;
21 import com.intellij.openapi.actionSystem.DefaultActionGroup;
22 import com.intellij.openapi.util.Pass;
23 import com.intellij.openapi.util.SystemInfo;
24 import com.intellij.ui.LayeredIcon;
25 import com.intellij.ui.SimpleColoredComponent;
26 import com.intellij.ui.SimpleColoredText;
27 import com.intellij.ui.components.panels.Wrapper;
28 import com.intellij.ui.tabs.JBTabsPosition;
29 import com.intellij.ui.tabs.TabInfo;
30 import com.intellij.ui.tabs.UiDecorator;
31 import com.intellij.util.ui.Centerizer;
33 import javax.swing.*;
34 import javax.swing.border.EmptyBorder;
35 import java.awt.*;
36 import java.awt.event.MouseAdapter;
37 import java.awt.event.MouseEvent;
38 import java.awt.image.BufferedImage;
40 public class TabLabel extends JPanel {
41 private final SimpleColoredComponent myLabel = new SimpleColoredComponent();
42 private final LayeredIcon myIcon;
43 private Icon myOverlayedIcon;
45 private final TabInfo myInfo;
46 private ActionPanel myActionPanel;
47 private boolean myCentered;
49 private final Wrapper myLabelPlaceholder = new Wrapper();
50 private final JBTabsImpl myTabs;
52 private BufferedImage myImage;
54 private BufferedImage myInactiveStateImage;
55 private Rectangle myLastPaintedInactiveImageBounds;
57 public TabLabel(JBTabsImpl tabs, final TabInfo info) {
58 myTabs = tabs;
59 myInfo = info;
60 myLabel.setOpaque(false);
61 myLabel.setBorder(null);
62 myLabel.setIconTextGap(new JLabel().getIconTextGap());
63 myLabel.setIconOpaque(false);
64 myLabel.setIpad(new Insets(0, 0, 0, 0));
65 setOpaque(false);
66 setLayout(new BorderLayout());
69 myLabelPlaceholder.setOpaque(false);
70 add(myLabelPlaceholder, BorderLayout.CENTER);
72 setAligmentToCenter(true);
74 myIcon = new LayeredIcon(2);
75 myLabel.setIcon(myIcon);
77 addMouseListener(new MouseAdapter() {
78 public void mousePressed(final MouseEvent e) {
79 if (myTabs.isSelectionClick(e, false) && myInfo.isEnabled()) {
80 myTabs.select(info, true);
82 else {
83 handlePopup(e);
87 public void mouseClicked(final MouseEvent e) {
88 handlePopup(e);
91 public void mouseReleased(final MouseEvent e) {
92 handlePopup(e);
94 });
97 public void setAligmentToCenter(boolean toCenter) {
98 if (myCentered == toCenter && myLabel.getParent() != null) return;
100 myLabelPlaceholder.removeAll();
102 if (toCenter) {
103 final Centerizer center = new Centerizer(myLabel);
104 myLabelPlaceholder.setContent(center);
105 } else {
106 myLabelPlaceholder.setContent(myLabel);
109 myCentered = toCenter;
112 public void paint(final Graphics g) {
113 if (myTabs.getSelectedInfo() != myInfo) {
114 myImage = null;
115 doPaint(g);
116 } else if (!SystemInfo.isMac) {
117 myImage = new BufferedImage(getWidth(), getHeight(), BufferedImage.TYPE_INT_ARGB);
118 final Graphics2D lg = myImage.createGraphics();
119 doPaint(lg);
120 lg.dispose();
124 public void paintImage(Graphics g) {
125 final Rectangle b = getBounds();
126 if (myImage != null) {
127 g.drawImage(myImage, b.x, b.y, getWidth(), getHeight(), null);
128 } else {
129 final Graphics lG = g.create(b.x, b.y, b.width, b.height);
130 try {
131 lG.setColor(Color.red);
132 doPaint(lG);
134 finally {
135 lG.dispose();
140 private void doPaint(Graphics g) {
141 final JBTabsPosition pos = myTabs.getTabsPosition();
143 int dX = 0;
144 int dXs = 0;
145 int dY = 0;
146 int dYs = 0;
147 int selected = getSelectedOffset();
148 int plain = getNonSelectedOffset();
150 switch (pos) {
151 case bottom:
152 dY = -plain;
153 dYs = -selected;
154 break;
155 case left:
156 dX = plain;
157 dXs = selected;
158 break;
159 case right:
160 dX = -plain;
161 dXs = -selected;
162 break;
163 case top:
164 dY = plain;
165 dYs = selected;
166 break;
169 if (myTabs.getSelectedInfo() != myInfo) {
170 g.translate(dX, dY);
171 } else {
172 g.translate(dXs, dYs);
175 super.paint(g);
177 if (myTabs.getSelectedInfo() != myInfo) {
178 g.translate(-dX, -dY);
179 } else {
180 g.translate(-dXs, -dYs);
184 private int getNonSelectedOffset() {
185 return 2;
188 private int getSelectedOffset() {
189 return 1;
192 @Override
193 public Dimension getPreferredSize() {
194 final Dimension size = super.getPreferredSize();
196 final JBTabsPosition pos = myTabs.getTabsPosition();
197 switch (pos) {
198 case top: case bottom: size.height += getSelectedOffset(); break;
199 case left: case right: size.width += getSelectedOffset(); break;
202 return size;
205 private void handlePopup(final MouseEvent e) {
206 if (e.getClickCount() != 1 || !e.isPopupTrigger()) return;
208 if (e.getX() < 0 || e.getX() >= e.getComponent().getWidth() || e.getY() < 0 || e.getY() >= e.getComponent().getHeight()) return;
210 String place = myTabs.getPopupPlace();
211 place = place != null ? place : ActionPlaces.UNKNOWN;
212 myTabs.myPopupInfo = myInfo;
214 final DefaultActionGroup toShow = new DefaultActionGroup();
215 if (myTabs.getPopupGroup() != null) {
216 toShow.addAll(myTabs.getPopupGroup());
217 toShow.addSeparator();
220 JBTabsImpl tabs = JBTabsImpl.NAVIGATION_ACTIONS_KEY.getData(DataManager.getInstance().getDataContext(e.getComponent(), e.getX(), e.getY()));
221 if (tabs == myTabs && myTabs.myAddNavigationGroup) {
222 toShow.addAll(myTabs.myNavigationActions);
225 if (toShow.getChildrenCount() == 0) return;
227 myTabs.myActivePopup = myTabs.myActionManager.createActionPopupMenu(place, toShow).getComponent();
228 myTabs.myActivePopup.addPopupMenuListener(myTabs.myPopupListener);
230 myTabs.myActivePopup.addPopupMenuListener(myTabs);
231 myTabs.myActivePopup.show(e.getComponent(), e.getX(), e.getY());
232 myTabs.onPopup(myTabs.myPopupInfo);
236 public void setText(final SimpleColoredText text) {
237 myLabel.change(new Runnable() {
238 public void run() {
239 myLabel.clear();
240 myLabel.setIcon(myIcon);
242 if (text != null) {
243 text.appendToComponent(myLabel);
246 }, false);
249 invalidateIfNeeded();
253 private void invalidateIfNeeded() {
254 if (myLabel.getRootPane() == null) return;
256 if (myLabel.getSize() != null && myLabel.getSize().equals(myLabel.getPreferredSize())) return;
258 setInactiveStateImage(null);
260 myLabel.invalidate();
262 if (myActionPanel != null) {
263 myActionPanel.invalidate();
266 myTabs.revalidateAndRepaint(false);
269 public void setIcon(final Icon icon) {
270 getLayeredIcon().setIcon(icon, 0);
271 invalidateIfNeeded();
274 private LayeredIcon getLayeredIcon() {
275 return myIcon;
278 public void setAttraction(boolean enabled) {
279 getLayeredIcon().setLayerEnabled(1, enabled);
282 public boolean isAttractionEnabled() {
283 return getLayeredIcon().isLayerEnabled(1);
286 public TabInfo getInfo() {
287 return myInfo;
290 public void apply(UiDecorator.UiDecoration decoration) {
291 if (decoration.getLabelFont() != null) {
292 setFont(decoration.getLabelFont());
295 Insets insets = decoration.getLabelInsets();
296 if (insets != null) {
297 Insets current = JBTabsImpl.ourDefaultDecorator.getDecoration().getLabelInsets();
298 if (current != null) {
299 setBorder(
300 new EmptyBorder(getValue(current.top, insets.top), getValue(current.left, insets.left), getValue(current.bottom, insets.bottom),
301 getValue(current.right, insets.right)));
306 private static int getValue(int curentValue, int newValue) {
307 return newValue != -1 ? newValue : curentValue;
310 public void setTabActions(ActionGroup group) {
311 removeOldActionPanel();
313 if (group == null) return;
315 myActionPanel = new ActionPanel(myTabs, myInfo, new Pass<MouseEvent>() {
316 public void pass(final MouseEvent event) {
317 final MouseEvent me = SwingUtilities.convertMouseEvent(event.getComponent(), event, TabLabel.this);
318 processMouseEvent(me);
322 toggleShowActions(false);
324 add(myActionPanel, BorderLayout.EAST);
326 myTabs.revalidateAndRepaint(false);
329 @Override
330 protected void processMouseEvent(final MouseEvent e) {
331 super.processMouseEvent(e);
334 private void removeOldActionPanel() {
335 if (myActionPanel != null) {
336 myActionPanel.getParent().remove(myActionPanel);
337 myActionPanel = null;
341 public boolean updateTabActions() {
342 return myActionPanel != null && myActionPanel.update();
346 private void setAttractionIcon(Icon icon) {
347 if (myIcon.getIcon(0) == null) {
348 getLayeredIcon().setIcon(null, 1);
349 myOverlayedIcon = icon;
350 } else {
351 getLayeredIcon().setIcon(icon, 1);
352 myOverlayedIcon = null;
356 public boolean repaintAttraction() {
357 if (!myTabs.myAttractions.contains(myInfo)) {
358 if (getLayeredIcon().isLayerEnabled(1)) {
359 getLayeredIcon().setLayerEnabled(1, false);
360 setAttractionIcon(null);
361 invalidateIfNeeded();
362 return true;
364 return false;
367 boolean needsUpdate = false;
369 if (getLayeredIcon().getIcon(1) != myInfo.getAlertIcon()) {
370 setAttractionIcon(myInfo.getAlertIcon());
371 needsUpdate = true;
374 int maxInitialBlinkCount = 5;
375 int maxRefireBlinkCount = maxInitialBlinkCount + 2;
376 if (myInfo.getBlinkCount() < maxInitialBlinkCount && myInfo.isAlertRequested()) {
377 getLayeredIcon().setLayerEnabled(1, !getLayeredIcon().isLayerEnabled(1));
378 if (myInfo.getBlinkCount() == 0) {
379 needsUpdate = true;
381 myInfo.setBlinkCount(myInfo.getBlinkCount() + 1);
383 if (myInfo.getBlinkCount() == maxInitialBlinkCount) {
384 myInfo.resetAlertRequest();
387 repaint();
389 else {
390 if (myInfo.getBlinkCount() < maxRefireBlinkCount && myInfo.isAlertRequested()) {
391 getLayeredIcon().setLayerEnabled(1, !getLayeredIcon().isLayerEnabled(1));
392 myInfo.setBlinkCount(myInfo.getBlinkCount() + 1);
394 if (myInfo.getBlinkCount() == maxRefireBlinkCount) {
395 myInfo.setBlinkCount(maxInitialBlinkCount);
396 myInfo.resetAlertRequest();
399 repaint();
401 else {
402 needsUpdate = !getLayeredIcon().isLayerEnabled(1);
403 getLayeredIcon().setLayerEnabled(1, true);
407 invalidateIfNeeded();
409 return needsUpdate;
412 protected void paintChildren(final Graphics g) {
413 super.paintChildren(g);
415 if (myOverlayedIcon == null || myLabel.getParent() == null) return;
417 final Rectangle textBounds = SwingUtilities.convertRectangle(myLabel.getParent(), myLabel.getBounds(), this);
418 if (getLayeredIcon().isLayerEnabled(1)) {
420 final int top = (getSize().height - myOverlayedIcon.getIconHeight()) / 2;
422 myOverlayedIcon.paintIcon(this, g, textBounds.x - myOverlayedIcon.getIconWidth() / 2, top);
427 public void setTabActionsAutoHide(final boolean autoHide) {
428 if (myActionPanel == null || myActionPanel.isAutoHide() == autoHide) {
429 return;
432 myActionPanel.setAutoHide(autoHide);
435 public void toggleShowActions(boolean show) {
436 if (myActionPanel != null) {
437 myActionPanel.toggleShowActtions(show);
441 @Override
442 public String toString() {
443 return myInfo.getText();
446 public void setTabEnabled(boolean enabled) {
447 myLabel.setEnabled(enabled);
451 public BufferedImage getInactiveStateImage(Rectangle effectiveBounds) {
452 BufferedImage img = null;
453 if (myLastPaintedInactiveImageBounds != null && myLastPaintedInactiveImageBounds.getSize().equals(effectiveBounds.getSize())) {
454 img = myInactiveStateImage;
455 } else {
456 setInactiveStateImage(null);
458 myLastPaintedInactiveImageBounds = effectiveBounds;
459 return img;
462 public void setInactiveStateImage(BufferedImage img) {
463 if (myInactiveStateImage != null && img != myInactiveStateImage) {
464 myInactiveStateImage.flush();
466 myInactiveStateImage = img;