light bulb fixed for single line editors: placed at the editor corner + autohide if editor is a part of combobox and it's popup is invoked

This commit is contained in:
Alexey Pegov
2010-08-19 16:02:48 +04:00
parent a9f4b07fb2
commit 6a2a7efa85
@@ -20,7 +20,6 @@ import com.intellij.codeInsight.CodeInsightBundle;
import com.intellij.codeInsight.daemon.impl.HighlightInfo;
import com.intellij.codeInsight.daemon.impl.ShowIntentionsPass;
import com.intellij.codeInsight.hint.HintManagerImpl;
import com.intellij.codeInsight.hint.HintUtil;
import com.intellij.codeInsight.hint.PriorityQuestionAction;
import com.intellij.codeInsight.hint.ScrollAwareHint;
import com.intellij.codeInsight.intention.IntentionAction;
@@ -52,9 +51,9 @@ import org.jetbrains.annotations.TestOnly;
import javax.swing.*;
import javax.swing.border.Border;
import javax.swing.event.PopupMenuEvent;
import javax.swing.event.PopupMenuListener;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
@@ -76,29 +75,32 @@ public class IntentionHintComponent extends JPanel implements Disposable, Scroll
static final Icon ourQuickFixOffIcon = IconLoader.getIcon("/actions/quickfixOffBulb.png");
static final Icon ourArrowIcon = IconLoader.getIcon("/general/arrowDown.png");
static final Icon ourInactiveArrowIcon = new EmptyIcon(ourArrowIcon.getIconWidth(), ourArrowIcon.getIconHeight());
private static final Border INACTIVE_BORDER = BorderFactory.createEmptyBorder(1, 1, 1, 1);
private static final Insets INACTIVE_MARGIN = new Insets(0, 0, 0, 0);
private static final Insets ACTIVE_MARGIN = new Insets(0, 0, 0, 0);
private static final Border INACTIVE_BORDER = BorderFactory.createEmptyBorder(6, 6, 6, 6);
private static final Border ACTIVE_BORDER = BorderFactory.createCompoundBorder(BorderFactory.createLineBorder(Color.BLACK, 1), BorderFactory.createEmptyBorder(5, 5, 5, 5));
private static final Border INACTIVE_BORDER_SMALL = BorderFactory.createEmptyBorder(4, 4, 4, 4);
private static final Border ACTIVE_BORDER_SMALL = BorderFactory.createCompoundBorder(BorderFactory.createLineBorder(Color.BLACK, 1), BorderFactory.createEmptyBorder(3, 3, 3, 3));
private final Editor myEditor;
private static final Alarm myAlarm = new Alarm();
private final RowIcon myHighlightedIcon;
private final JButton myButton;
private final JLabel myIconLabel;
private final Icon mySmartTagIcon;
private final RowIcon myInactiveIcon;
private static final int DELAY = 500;
private final MyComponentHint myComponentHint;
private static final Color BACKGROUND_COLOR = new Color(255, 255, 255, 0);
private boolean myPopupShown = false;
private boolean myDisposed = false;
private ListPopup myPopup;
private final PsiFile myFile;
private static final int LIGHTBULB_OFFSET = 20;
private PopupMenuListener myOuterComboboxPopupListener;
public static IntentionHintComponent showIntentionHint(Project project, final PsiFile file, Editor editor, ShowIntentionsPass.IntentionsInfo intentions,
boolean showExpanded) {
final Point position = getHintPosition(editor);
@@ -136,6 +138,15 @@ public class IntentionHintComponent extends JPanel implements Disposable, Scroll
myDisposed = true;
myComponentHint.hide();
super.hide();
if (myOuterComboboxPopupListener != null) {
final Container ancestor = SwingUtilities.getAncestorOfClass(JComboBox.class, myEditor.getContentComponent());
if (ancestor != null) {
((JComboBox)ancestor).removePopupMenuListener(myOuterComboboxPopupListener);
}
myOuterComboboxPopupListener = null;
}
}
public void editorScrolled() {
@@ -192,18 +203,40 @@ public class IntentionHintComponent extends JPanel implements Disposable, Scroll
int line = pos.line;
final Point position = editor.logicalPositionToXY(new LogicalPosition(line, 0));
final int yShift = (ourIntentionIcon.getIconHeight() - editor.getLineHeight() - 1) / 2 - 1;
final int xShift = ourIntentionIcon.getIconWidth();
LOG.assertTrue(editor.getComponent().isDisplayable());
Rectangle visibleArea = editor.getScrollingModel().getVisibleArea();
Point realPoint = new Point(Math.max(0,visibleArea.x - xShift), position.y + yShift- LIGHTBULB_OFFSET);
Point location = SwingUtilities.convertPoint(editor.getContentComponent(), realPoint, editor.getComponent().getRootPane().getLayeredPane());
JComponent convertComponent = editor.getContentComponent();
Point realPoint;
final boolean oneLineEditor = editor.isOneLineMode();
if (oneLineEditor) {
// place bulb at the corner of the surrounding component
final JComponent contentComponent = editor.getContentComponent();
Container ancestorOfClass = SwingUtilities.getAncestorOfClass(JComboBox.class, contentComponent);
if (ancestorOfClass != null) {
convertComponent = (JComponent) ancestorOfClass;
} else {
ancestorOfClass = SwingUtilities.getAncestorOfClass(JTextField.class, contentComponent);
if (ancestorOfClass != null) {
convertComponent = (JComponent) ancestorOfClass;
}
}
realPoint = new Point(- (ourIntentionIcon.getIconWidth() / 2) - 4, - (ourIntentionIcon.getIconHeight() / 2));
} else {
final int yShift = (ourIntentionIcon.getIconHeight() - editor.getLineHeight() - 1) / 2 - 1;
final int xShift = ourIntentionIcon.getIconWidth();
Rectangle visibleArea = editor.getScrollingModel().getVisibleArea();
realPoint = new Point(Math.max(0,visibleArea.x - xShift), position.y + yShift- LIGHTBULB_OFFSET);
}
Point location = SwingUtilities.convertPoint(convertComponent, realPoint, editor.getComponent().getRootPane().getLayeredPane());
return new Point(location.x, location.y);
}
private IntentionHintComponent(@NotNull Project project, @NotNull PsiFile file, @NotNull Editor editor,
private IntentionHintComponent(@NotNull Project project, @NotNull PsiFile file, @NotNull final Editor editor,
@NotNull ShowIntentionsPass.IntentionsInfo intentions) {
ApplicationManager.getApplication().assertReadAccessAllowed();
myFile = file;
@@ -220,6 +253,7 @@ public class IntentionHintComponent extends JPanel implements Disposable, Scroll
break;
}
}
mySmartTagIcon = showFix ? ourQuickFixIcon : ourBulbIcon;
myHighlightedIcon = new RowIcon(2);
@@ -230,28 +264,29 @@ public class IntentionHintComponent extends JPanel implements Disposable, Scroll
myInactiveIcon.setIcon(mySmartTagIcon, 0);
myInactiveIcon.setIcon(ourInactiveArrowIcon, 1);
myButton = new JButton(myInactiveIcon);
myButton.setFocusable(false);
myButton.setMargin(INACTIVE_MARGIN);
myButton.setBorderPainted(false);
myButton.setContentAreaFilled(false);
myIconLabel = new JLabel(myInactiveIcon);
myIconLabel.setOpaque(false);
add(myButton, BorderLayout.CENTER);
setBorder(INACTIVE_BORDER);
add(myIconLabel, BorderLayout.CENTER);
myButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
showPopup();
setBorder(editor.isOneLineMode() ? INACTIVE_BORDER_SMALL : INACTIVE_BORDER);
myIconLabel.addMouseListener(new MouseAdapter() {
@Override
public void mousePressed(MouseEvent e) {
if (!e.isPopupTrigger() && e.getButton() == MouseEvent.BUTTON1) {
showPopup();
}
}
});
myButton.addMouseListener(new MouseAdapter() {
@Override
public void mouseEntered(MouseEvent e) {
onMouseEnter();
onMouseEnter(editor.isOneLineMode());
}
@Override
public void mouseExited(MouseEvent e) {
onMouseExit();
onMouseExit(editor.isOneLineMode());
}
});
@@ -264,36 +299,25 @@ public class IntentionHintComponent extends JPanel implements Disposable, Scroll
Disposer.dispose(this);
}
private void onMouseExit() {
private void onMouseExit(final boolean small) {
Window ancestor = SwingUtilities.getWindowAncestor(myPopup.getContent());
if (ancestor == null) {
myButton.setBackground(BACKGROUND_COLOR);
myButton.setIcon(myInactiveIcon);
setBorder(INACTIVE_BORDER);
myButton.setMargin(INACTIVE_MARGIN);
updateComponentHintSize();
myIconLabel.setIcon(myInactiveIcon);
setBorder(small ? INACTIVE_BORDER_SMALL : INACTIVE_BORDER);
}
}
private void onMouseEnter() {
myButton.setBackground(HintUtil.QUESTION_COLOR);
myButton.setIcon(myHighlightedIcon);
setBorder(BorderFactory.createLineBorder(Color.black));
myButton.setMargin(ACTIVE_MARGIN);
updateComponentHintSize();
private void onMouseEnter(final boolean small) {
myIconLabel.setIcon(myHighlightedIcon);
setBorder(small ? ACTIVE_BORDER_SMALL : ACTIVE_BORDER);
String acceleratorsText = KeymapUtil.getFirstKeyboardShortcutText(
ActionManager.getInstance().getAction(IdeActions.ACTION_SHOW_INTENTION_ACTIONS));
if (acceleratorsText.length() > 0) {
myButton.setToolTipText(CodeInsightBundle.message("lightbulb.tooltip", acceleratorsText));
myIconLabel.setToolTipText(CodeInsightBundle.message("lightbulb.tooltip", acceleratorsText));
}
}
private void updateComponentHintSize() {
Component component = myComponentHint.getComponent();
component.setSize(getPreferredSize().width, getHeight());
}
@TestOnly
public LightweightHint getComponentHint() {
return myComponentHint;
@@ -329,6 +353,31 @@ public class IntentionHintComponent extends JPanel implements Disposable, Scroll
myPopupShown = false;
}
});
if (myEditor.isOneLineMode()) {
// hide popup on combobox popup show
final Container ancestor = SwingUtilities.getAncestorOfClass(JComboBox.class, myEditor.getContentComponent());
if (ancestor != null) {
final JComboBox comboBox = (JComboBox)ancestor;
myOuterComboboxPopupListener = new PopupMenuListener() {
@Override
public void popupMenuWillBecomeVisible(PopupMenuEvent e) {
hide();
}
@Override
public void popupMenuWillBecomeInvisible(PopupMenuEvent e) {
}
@Override
public void popupMenuCanceled(PopupMenuEvent e) {
}
};
comboBox.addPopupMenuListener(myOuterComboboxPopupListener);
}
}
Disposer.register(this, myPopup);
Disposer.register(myPopup, new Disposable() {
public void dispose() {