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
;
34 import javax
.swing
.border
.EmptyBorder
;
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
) {
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));
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);
87 public void mouseClicked(final MouseEvent e
) {
91 public void mouseReleased(final MouseEvent e
) {
97 public void setAligmentToCenter(boolean toCenter
) {
98 if (myCentered
== toCenter
&& myLabel
.getParent() != null) return;
100 myLabelPlaceholder
.removeAll();
103 final Centerizer center
= new Centerizer(myLabel
);
104 myLabelPlaceholder
.setContent(center
);
106 myLabelPlaceholder
.setContent(myLabel
);
109 myCentered
= toCenter
;
112 public void paint(final Graphics g
) {
113 if (myTabs
.getSelectedInfo() != myInfo
) {
116 } else if (!SystemInfo
.isMac
) {
117 myImage
= new BufferedImage(getWidth(), getHeight(), BufferedImage
.TYPE_INT_ARGB
);
118 final Graphics2D lg
= myImage
.createGraphics();
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);
129 final Graphics lG
= g
.create(b
.x
, b
.y
, b
.width
, b
.height
);
131 lG
.setColor(Color
.red
);
140 private void doPaint(Graphics g
) {
141 final JBTabsPosition pos
= myTabs
.getTabsPosition();
147 int selected
= getSelectedOffset();
148 int plain
= getNonSelectedOffset();
169 if (myTabs
.getSelectedInfo() != myInfo
) {
172 g
.translate(dXs
, dYs
);
177 if (myTabs
.getSelectedInfo() != myInfo
) {
178 g
.translate(-dX
, -dY
);
180 g
.translate(-dXs
, -dYs
);
184 private int getNonSelectedOffset() {
188 private int getSelectedOffset() {
193 public Dimension
getPreferredSize() {
194 final Dimension size
= super.getPreferredSize();
196 final JBTabsPosition pos
= myTabs
.getTabsPosition();
198 case top
: case bottom
: size
.height
+= getSelectedOffset(); break;
199 case left
: case right
: size
.width
+= getSelectedOffset(); break;
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() {
240 myLabel
.setIcon(myIcon
);
243 text
.appendToComponent(myLabel
);
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() {
278 public void setAttraction(boolean enabled
) {
279 getLayeredIcon().setLayerEnabled(1, enabled
);
282 public boolean isAttractionEnabled() {
283 return getLayeredIcon().isLayerEnabled(1);
286 public TabInfo
getInfo() {
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) {
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);
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
;
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();
367 boolean needsUpdate
= false;
369 if (getLayeredIcon().getIcon(1) != myInfo
.getAlertIcon()) {
370 setAttractionIcon(myInfo
.getAlertIcon());
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) {
381 myInfo
.setBlinkCount(myInfo
.getBlinkCount() + 1);
383 if (myInfo
.getBlinkCount() == maxInitialBlinkCount
) {
384 myInfo
.resetAlertRequest();
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();
402 needsUpdate
= !getLayeredIcon().isLayerEnabled(1);
403 getLayeredIcon().setLayerEnabled(1, true);
407 invalidateIfNeeded();
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
) {
432 myActionPanel
.setAutoHide(autoHide
);
435 public void toggleShowActions(boolean show
) {
436 if (myActionPanel
!= null) {
437 myActionPanel
.toggleShowActtions(show
);
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
;
456 setInactiveStateImage(null);
458 myLastPaintedInactiveImageBounds
= effectiveBounds
;
462 public void setInactiveStateImage(BufferedImage img
) {
463 if (myInactiveStateImage
!= null && img
!= myInactiveStateImage
) {
464 myInactiveStateImage
.flush();
466 myInactiveStateImage
= img
;