added internal action to dump all extensions
[idea/community.git] / platform / platform-impl / src / com / intellij / ide / IdeTooltipManager.java
1 /*
2  * Copyright 2000-2010 JetBrains s.r.o.
3  *
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
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
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.
15  */
16 package com.intellij.ide;
17
18 import com.intellij.openapi.application.ApplicationManager;
19 import com.intellij.openapi.components.ApplicationComponent;
20 import com.intellij.openapi.ui.popup.Balloon;
21 import com.intellij.openapi.ui.popup.BalloonBuilder;
22 import com.intellij.openapi.ui.popup.JBPopupFactory;
23 import com.intellij.openapi.util.registry.Registry;
24 import com.intellij.openapi.util.registry.RegistryValue;
25 import com.intellij.openapi.util.registry.RegistryValueListener;
26 import com.intellij.ui.awt.RelativePoint;
27 import com.intellij.util.Alarm;
28 import com.intellij.util.ui.UIUtil;
29 import org.jetbrains.annotations.NotNull;
30
31 import javax.swing.*;
32 import javax.swing.border.EmptyBorder;
33 import java.awt.*;
34 import java.awt.event.AWTEventListener;
35 import java.awt.event.MouseEvent;
36
37 public class IdeTooltipManager implements ApplicationComponent, AWTEventListener {
38
39   private RegistryValue myIsEnabled;
40
41   private Component myCurrentComponent;
42   private Balloon myCurrentTip;
43   private MouseEvent myCurrentEvent;
44
45   private JBPopupFactory myPopupFactory;
46   private JLabel myTipLabel;
47
48   private boolean myShowDelay = true;
49
50   private Alarm myShowAlarm = new Alarm();
51   private Alarm myHideAlarm = new Alarm();
52
53   private int myX;
54   private int myY;
55   private RegistryValue myMode;
56
57   @NotNull
58   @Override
59   public String getComponentName() {
60     return "IDE Tooltip Manager";
61   }
62
63   public IdeTooltipManager(JBPopupFactory popupFactory) {
64     myPopupFactory = popupFactory;
65   }
66
67   @Override
68   public void initComponent() {
69     myMode = Registry.get("ide.tooltip.mode");
70
71     myIsEnabled = Registry.get("ide.tooltip.callout");
72     myIsEnabled.addListener(new RegistryValueListener.Adapter() {
73       @Override
74       public void afterValueChanged(RegistryValue value) {
75         processEnabled();
76       }
77     }, ApplicationManager.getApplication());
78
79     Toolkit.getDefaultToolkit().addAWTEventListener(this, MouseEvent.MOUSE_EVENT_MASK | MouseEvent.MOUSE_MOTION_EVENT_MASK);
80     myTipLabel = new JLabel();
81     myTipLabel.setOpaque(false);
82
83     processEnabled();
84   }
85
86   @Override
87   public void eventDispatched(AWTEvent event) {
88     if (!myIsEnabled.asBoolean()) return;
89
90     MouseEvent me = (MouseEvent)event;
91     Component c = me.getComponent();
92     if (me.getID() == MouseEvent.MOUSE_ENTERED) {
93       if (me.getComponent() != myCurrentComponent) {
94         hideCurrent();
95       }
96       maybeShowFor(c, me);
97
98     } else if (me.getID() == MouseEvent.MOUSE_EXITED) {
99       if (me.getComponent() == myCurrentComponent) {
100         hideCurrent();
101       }
102     } else if (me.getID() == MouseEvent.MOUSE_MOVED) {
103       if (me.getComponent() == myCurrentComponent) {
104         if (myCurrentTip != null && myCurrentTip.wasFadedIn()) {
105           hideCurrent();
106         } else {
107           myX = me.getX();
108           myY = me.getY();
109         }
110       } else if (myCurrentComponent == null) {
111         maybeShowFor(c, me);
112       }
113     } else if (me.getID() == MouseEvent.MOUSE_PRESSED) {
114       if (me.getComponent() == myCurrentComponent) {
115         hideCurrent();
116       }
117     }
118   }
119
120   private void maybeShowFor(Component c, MouseEvent me) {
121     if (!(c instanceof JComponent)) return;
122
123     JComponent comp = (JComponent)c;
124
125     String tooltipText = comp.getToolTipText(me);
126     boolean toCenter = Boolean.TRUE.equals(comp.getClientProperty(UIUtil.CENTER_TOOLTIP));
127
128     if (tooltipText == null || tooltipText.trim().length() == 0) return;
129
130
131     queueShow(comp, me, toCenter);
132   }
133
134   private void queueShow(final JComponent c, MouseEvent me, final boolean toCenter) {
135     myShowAlarm.cancelAllRequests();
136     hideCurrent();
137
138     myCurrentComponent = c;
139     myCurrentEvent = me;
140     myX = me.getX();
141     myY = me.getY();
142     myShowAlarm.addRequest(new Runnable() {
143       @Override
144       public void run() {
145         show(c, toCenter);
146       }
147     }, myShowDelay ? 1500 : 900);
148   }
149
150   private void show(JComponent c, boolean toCenter) {
151     if (myCurrentComponent != c || !c.isShowing()) return;
152
153     String text = c.getToolTipText(myCurrentEvent);
154
155     if (text == null || text.trim().length() == 0) return;
156
157     myTipLabel.setText(text);
158
159     boolean useSystem;
160
161     if ("default".equalsIgnoreCase(myMode.asString())) {
162       useSystem = false;
163     } else if ("system".equalsIgnoreCase(myMode.asString())) {
164       useSystem = true;
165     } else if ("graphite".equalsIgnoreCase(myMode.asString())) {
166       useSystem = false;
167     } else {
168       useSystem = false;
169     }
170
171     Color bg = useSystem ? UIManager.getColor("ToolTip.background") : new Color(100, 100, 100, 230);
172     Color fg = useSystem ? UIManager.getColor("ToolTip.foreground") : Color.white;
173     Color border = useSystem ? Color.darkGray : bg.darker();
174
175     BalloonBuilder builder = myPopupFactory.createBalloonBuilder(myTipLabel)
176       .setPreferredPosition(Balloon.Position.above)
177       .setFillColor(bg)
178       .setBorderColor(border)
179       .setAnimationCycle(150)
180       .setShowCallout(true)
181       .setCalloutShift(0); //todo
182     myTipLabel.setForeground(fg);
183     myTipLabel.setBorder(new EmptyBorder(1, 3, 2, 3));
184     myTipLabel.setFont(UIManager.getFont("ToolTip.font"));
185     myCurrentTip = builder.createBalloon();
186
187     boolean toCenterX;
188     boolean toCenterY;
189
190     if (!toCenter) {
191       Dimension size = c.getSize();
192       toCenterX = size.width < 64;
193       toCenterY = size.height < 64;
194       toCenter = toCenterX || toCenterY;
195     } else {
196       toCenterX = true;
197       toCenterY = true;
198     }
199
200     Point point = new Point(myX, myY);
201     if (toCenter) {
202       Rectangle bounds = c.getBounds();
203       point.x = toCenterX ? bounds.width / 2 : point.x;
204       point.y = toCenterY ? (bounds.height / 2) : point.y;
205     }
206
207     myCurrentTip.show(new RelativePoint(c, point), Balloon.Position.above);
208   }
209
210   private void hideCurrent() {
211     if (myCurrentTip != null) {
212       myCurrentTip.hide();
213       myShowDelay = false;
214       myHideAlarm.addRequest(new Runnable() {
215         @Override
216         public void run() {
217           myShowDelay = true;
218         }
219       }, 1000);
220     }
221     myCurrentTip = null;
222     myCurrentComponent = null;
223     myCurrentEvent = null;
224     myX = -1;
225     myY = -1;
226   }
227
228   private void processEnabled() {
229     if (myIsEnabled.asBoolean()) {
230       ToolTipManager.sharedInstance().setEnabled(false);
231     } else {
232       ToolTipManager.sharedInstance().setEnabled(true);
233     }
234   }
235
236   @Override
237   public void disposeComponent() {
238   }
239 }