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
.diagnostic
.Logger
;
19 import com
.intellij
.openapi
.ui
.popup
.JBPopup
;
20 import com
.intellij
.openapi
.ui
.popup
.JBPopupFactory
;
21 import com
.intellij
.openapi
.util
.UserDataHolderBase
;
22 import com
.intellij
.openapi
.wm
.ex
.LayoutFocusTraversalPolicyExt
;
23 import com
.intellij
.ui
.awt
.RelativePoint
;
24 import com
.intellij
.ui
.popup
.AbstractPopup
;
25 import org
.jetbrains
.annotations
.NotNull
;
28 import javax
.swing
.event
.EventListenerList
;
30 import java
.awt
.event
.ActionEvent
;
31 import java
.awt
.event
.ActionListener
;
32 import java
.awt
.event
.KeyEvent
;
33 import java
.util
.EventListener
;
34 import java
.util
.EventObject
;
36 public class LightweightHint
extends UserDataHolderBase
implements Hint
{
37 private static final Logger LOG
= Logger
.getInstance("#com.intellij.ui.LightweightHint");
39 private final JComponent myComponent
;
40 private JComponent myFocusBackComponent
;
41 private final EventListenerList myListenerList
= new EventListenerList();
42 private MyEscListener myEscListener
;
43 private JBPopup myPopup
;
44 private JComponent myParentComponent
;
45 private boolean myIsRealPopup
= false;
46 private boolean myForceLightweightPopup
= false;
47 private boolean mySelectingHint
;
49 private boolean myForceShowAsPopup
= false;
50 private String myTitle
= null;
52 public LightweightHint(@NotNull final JComponent component
) {
53 myComponent
= component
;
56 public void setForceLightweightPopup(final boolean forceLightweightPopup
) {
57 myForceLightweightPopup
= forceLightweightPopup
;
61 public void setForceShowAsPopup(final boolean forceShowAsPopup
) {
62 myForceShowAsPopup
= forceShowAsPopup
;
65 public void setTitle(final String title
) {
69 public boolean isSelectingHint() {
70 return mySelectingHint
;
73 public void setSelectingHint(final boolean selectingHint
) {
74 mySelectingHint
= selectingHint
;
78 * Shows the hint in the layered pane. Coordinates <code>x</code> and <code>y</code>
79 * are in <code>parentComponent</code> coordinate system. Note that the component
80 * appears on 250 layer.
82 public void show(@NotNull final JComponent parentComponent
, final int x
, final int y
, final JComponent focusBackComponent
) {
83 myParentComponent
= parentComponent
;
85 myFocusBackComponent
= focusBackComponent
;
87 LOG
.assertTrue(myParentComponent
.isShowing());
88 myEscListener
= new MyEscListener();
89 myComponent
.registerKeyboardAction(myEscListener
, KeyStroke
.getKeyStroke(KeyEvent
.VK_ESCAPE
, 0),
90 JComponent
.WHEN_IN_FOCUSED_WINDOW
);
91 final JLayeredPane layeredPane
= parentComponent
.getRootPane().getLayeredPane();
92 if (!myForceShowAsPopup
&& (myForceLightweightPopup
|| fitsLayeredPane(layeredPane
, myComponent
, new RelativePoint(parentComponent
, new Point(x
, y
))))) {
93 final Dimension preferredSize
= myComponent
.getPreferredSize();
94 final Point layeredPanePoint
= SwingUtilities
.convertPoint(parentComponent
, x
, y
, layeredPane
);
96 myComponent
.setBounds(layeredPanePoint
.x
, layeredPanePoint
.y
, preferredSize
.width
, preferredSize
.height
);
98 layeredPane
.add(myComponent
, Integer
.valueOf(250 + layeredPane
.getComponentCount()));
100 myComponent
.validate();
101 myComponent
.repaint();
104 myIsRealPopup
= true;
105 myPopup
= JBPopupFactory
.getInstance().createComponentPopupBuilder(myComponent
, null)
106 .setRequestFocus(false)
107 .setResizable(myForceShowAsPopup
)
108 .setMovable(myForceShowAsPopup
)
111 myPopup
.show(new RelativePoint(myParentComponent
, new Point(x
, y
)));
115 private static boolean fitsLayeredPane(JLayeredPane pane
, JComponent component
, RelativePoint desiredLocation
) {
116 final Rectangle lpRect
= new Rectangle(pane
.getLocationOnScreen().x
, pane
.getLocationOnScreen().y
, pane
.getWidth(), pane
.getHeight());
117 Rectangle componentRect
= new Rectangle(desiredLocation
.getScreenPoint().x
,
118 desiredLocation
.getScreenPoint().y
,
119 component
.getPreferredSize().width
,
120 component
.getPreferredSize().height
);
121 return lpRect
.contains(componentRect
);
124 private void fireHintHidden() {
125 final EventListener
[] listeners
= myListenerList
.getListeners(HintListener
.class);
126 for (EventListener listener
: listeners
) {
127 ((HintListener
)listener
).hintHidden(new EventObject(this));
132 * Sets location of the hint in the layered pane coordinate system.
134 public final void setLocation(final int x
, final int y
) {
136 if (myPopup
== null) return;
137 ((AbstractPopup
)myPopup
).setLocation(new RelativePoint(myParentComponent
, new Point(x
, y
)));
140 myComponent
.setLocation(x
, y
);
142 final Dimension preferredSize
= myComponent
.getPreferredSize();
143 if (!preferredSize
.equals(myComponent
.getSize())) {
144 final JLayeredPane layeredPane
= myParentComponent
.getRootPane().getLayeredPane();
145 final Point layeredPanePoint
= SwingUtilities
.convertPoint(myParentComponent
, x
, y
, layeredPane
);
146 myComponent
.setBounds(layeredPanePoint
.x
, layeredPanePoint
.y
, preferredSize
.width
, preferredSize
.height
);
149 myComponent
.validate();
150 myComponent
.repaint();
155 * x and y are in layered pane coordinate system
157 public final void setBounds(final int x
, final int y
, final int width
, final int height
) {
162 myComponent
.setBounds(x
, y
, width
, height
);
163 myComponent
.setLocation(x
, y
);
164 myComponent
.validate();
165 myComponent
.repaint();
170 * @return bounds of hint component in the layered pane.
172 public final Rectangle
getBounds() {
173 return myComponent
.getBounds();
176 public boolean isVisible() {
177 return myIsRealPopup ? myPopup
!= null : myComponent
.isShowing();
187 final JRootPane rootPane
= myComponent
.getRootPane();
188 if (rootPane
!= null) {
189 final Rectangle bounds
= myComponent
.getBounds();
190 final JLayeredPane layeredPane
= rootPane
.getLayeredPane();
193 if(myFocusBackComponent
!= null){
194 LayoutFocusTraversalPolicyExt
.setOverridenDefaultComponent(myFocusBackComponent
);
196 layeredPane
.remove(myComponent
);
199 LayoutFocusTraversalPolicyExt
.setOverridenDefaultComponent(null);
202 layeredPane
.repaint(bounds
.x
, bounds
.y
, bounds
.width
, bounds
.height
);
206 if (myEscListener
!= null) {
207 myComponent
.unregisterKeyboardAction(KeyStroke
.getKeyStroke(KeyEvent
.VK_ESCAPE
, 0));
212 public final JComponent
getComponent() {
216 public final void addHintListener(final HintListener listener
) {
217 myListenerList
.add(HintListener
.class, listener
);
220 public final void removeHintListener(final HintListener listener
) {
221 myListenerList
.remove(HintListener
.class, listener
);
224 private final class MyEscListener
implements ActionListener
{
225 public final void actionPerformed(final ActionEvent e
) {
231 public String
toString() {
232 return getComponent().toString();