From 041e6f9a12fd23e1b9f9206fe9b4af68fad69714 Mon Sep 17 00:00:00 2001 From: Konstantin Bulenkov Date: Wed, 6 Jun 2012 09:44:53 +0200 Subject: [PATCH] fix completion extender blinking --- .../lookup/impl/CompletionExtender.java | 136 +++++------------- .../lookup/impl/LookupCellRenderer.java | 56 ++++++-- .../codeInsight/lookup/impl/LookupImpl.java | 34 ++--- .../ui/AbstractExpandableItemsHandler.java | 36 +++-- 4 files changed, 115 insertions(+), 147 deletions(-) diff --git a/platform/lang-impl/src/com/intellij/codeInsight/lookup/impl/CompletionExtender.java b/platform/lang-impl/src/com/intellij/codeInsight/lookup/impl/CompletionExtender.java index 4704342565d0..801942040b3b 100644 --- a/platform/lang-impl/src/com/intellij/codeInsight/lookup/impl/CompletionExtender.java +++ b/platform/lang-impl/src/com/intellij/codeInsight/lookup/impl/CompletionExtender.java @@ -15,122 +15,56 @@ */ package com.intellij.codeInsight.lookup.impl; -import com.intellij.codeInsight.lookup.LookupElement; -import com.intellij.openapi.util.SystemInfo; -import com.intellij.ui.HintHint; -import com.intellij.ui.LightweightHint; -import com.intellij.ui.ScreenUtil; -import com.intellij.ui.awt.RelativePoint; -import com.intellij.util.ui.UIUtil; +import com.intellij.ui.ListExpandableItemsHandler; import org.jetbrains.annotations.NotNull; import javax.swing.*; -import java.awt.*; -import java.awt.event.ComponentAdapter; -import java.awt.event.ComponentEvent; +import java.awt.event.*; /** * @author Konstantin Bulenkov */ -public class CompletionExtender extends LightweightHint { - private LookupElement myElement; - private LookupImpl myLookup; - private int myIndex; +public class CompletionExtender extends ListExpandableItemsHandler { - public CompletionExtender(@NotNull LookupElement element, @NotNull LookupImpl lookup) { - super(createComponent(element, lookup)); - setForceHideShadow(true); - myElement = element; - myLookup = lookup; - myIndex = myLookup.getList().getSelectedIndex(); - myLookup.getComponent().addComponentListener(new ComponentAdapter() { + public CompletionExtender(@NotNull final JList list) { + super(list); + list.addComponentListener(new ComponentAdapter() { @Override - public void componentResized(ComponentEvent e) { - recalculateLocation(); - } + public void componentShown(ComponentEvent e) { + if (myComponent.getParent() != null && myComponent.getParent().getParent() instanceof JScrollPane) { + final JScrollBar verticalScrollBar = ((JScrollPane)myComponent.getParent().getParent()).getVerticalScrollBar(); + final JScrollBar horizontalScrollBar = ((JScrollPane)myComponent.getParent().getParent()).getVerticalScrollBar(); + final AdjustmentListener listener = new AdjustmentListener() { + @Override + public void adjustmentValueChanged(AdjustmentEvent e) { + updateCurrentSelection(); + } + }; + if (verticalScrollBar != null) verticalScrollBar.addAdjustmentListener(listener); + if (horizontalScrollBar != null) horizontalScrollBar.addAdjustmentListener(listener); - @Override - public void componentMoved(ComponentEvent e) { - recalculateLocation(); + list.removeComponentListener(this); + } } }); } - - public LookupElement getLookupElement() { - return myElement; - } - - public boolean sameAsFor(LookupElement item) { - return getLookupElement().equals(item) - && myIndex == myLookup.getList().getSelectedIndex(); - } - - private static JComponent createComponent(LookupElement element, LookupImpl lookup) { - final LookupCellRenderer renderer = ((LookupCellRenderer)lookup.getList().getCellRenderer()).createExtenderRenderer(); - final JComponent component = (JComponent)renderer.getListCellRendererComponent(lookup.getList(), element, - lookup.getList().getSelectedIndex(), - true, false); - component.setSize(component.getPreferredSize()); - return component; - } - - public boolean show() { - if (SystemInfo.isUnix) { - //TODO[kb]: fix shadow. This hint is always heavyweight window and has a shadow - hide(); - return false; - } - if (!checkComponentBounds()) { - hide(); - return false; - } - final JList list = myLookup.getList(); - if (getComponent().getWidth() > list.getWidth()) { - final JComponent rootPane = myLookup.myLayeredPane; - - final Point p = list.getLocationOnScreen(); - p.y += list.indexToLocation(list.getSelectedIndex()).y; - SwingUtilities.convertPointFromScreen(p, rootPane); - - if (rootPane != null) { - final HintHint hint = new HintHint(); - show(rootPane, p.x, p.y, null, hint); - return true; - } - } - return false; - } - - private boolean checkComponentBounds() { - final Dimension size = getComponent().getPreferredSize(); - final JList list = myLookup.getList(); - final Point p = list.getLocationOnScreen(); - p.y += list.indexToLocation(list.getSelectedIndex()).y; - final Rectangle rectangle = new Rectangle(p, size); - return !ScreenUtil.isOutsideOnTheRightOFScreen(rectangle); - } - - void recalculateLocation() { - if (!isVisible()) return; - final JList list = myLookup.getList(); - final Point p = list.getLocationOnScreen(); - final Point point = list.indexToLocation(list.getSelectedIndex()); - if (point != null) { - p.y += point.y; - final JComponent rootPane = UIUtil.getRootPane(myLookup.getEditor().getContentComponent()); - if (rootPane != null) { - SwingUtilities.convertPointFromScreen(p, rootPane); - setLocation(new RelativePoint(rootPane, p)); - return; - } - } - hide(); + @Override + protected void handleSelectionChange(Integer selected, boolean processIfUnfocused) { + super.handleSelectionChange(myComponent.getSelectedIndex(), true); } @Override - public void hide() { - super.hide(); - myLookup = null; - myElement = null; + protected void onFocusLost() { + //don't hide hint + } + + @Override + protected void handleMouseEvent(MouseEvent e, boolean forceUpdate) { + // don't show or hide hint on mouse events + } + + @Override + protected boolean isPaintBorder() { + return false; } } diff --git a/platform/lang-impl/src/com/intellij/codeInsight/lookup/impl/LookupCellRenderer.java b/platform/lang-impl/src/com/intellij/codeInsight/lookup/impl/LookupCellRenderer.java index 3e9b529ad131..a1b26f55b199 100644 --- a/platform/lang-impl/src/com/intellij/codeInsight/lookup/impl/LookupCellRenderer.java +++ b/platform/lang-impl/src/com/intellij/codeInsight/lookup/impl/LookupCellRenderer.java @@ -37,6 +37,8 @@ import org.jetbrains.annotations.Nullable; import javax.swing.*; import javax.swing.border.EmptyBorder; import java.awt.*; +import java.util.HashMap; +import java.util.Map; /** * @author peter @@ -68,15 +70,13 @@ public class LookupCellRenderer implements ListCellRenderer { private final SimpleColoredComponent myNameComponent; private final SimpleColoredComponent myTailComponent; private final SimpleColoredComponent myTypeLabel; - private final JPanel myPanel; + private final LookupPanel myPanel; + private final Map mySelected = new HashMap(); private static final String ELLIPSIS = "\u2026"; - private final boolean myFullSize; private int myMaxWidth = -1; - public LookupCellRenderer(LookupImpl lookup, boolean fullSize) { - myFullSize = fullSize; - + public LookupCellRenderer(LookupImpl lookup) { EditorColorsScheme scheme = lookup.getEditor().getColorsScheme(); myNormalFont = scheme.getFont(EditorFontType.PLAIN); myBoldFont = scheme.getFont(EditorFontType.BOLD); @@ -124,7 +124,7 @@ public class LookupCellRenderer implements ListCellRenderer { final Color background = isSelected ? SELECTED_BACKGROUND_COLOR : BACKGROUND_COLOR; int allowedWidth = list.getWidth() - AFTER_TAIL - AFTER_TYPE - getIconIndent(); - final LookupElementPresentation presentation = new RealLookupElementPresentation(myFullSize ? getMaxWidth() : allowedWidth, myNormalMetrics, myBoldMetrics, myLookup); + final LookupElementPresentation presentation = new RealLookupElementPresentation(isSelected ? getMaxWidth() : allowedWidth, myNormalMetrics, myBoldMetrics, myLookup); if (item.isValid()) { item.renderElement(presentation); } else { @@ -139,13 +139,37 @@ public class LookupCellRenderer implements ListCellRenderer { myTypeLabel.clear(); if (allowedWidth > 0) { - allowedWidth -= setTypeTextLabel(item, background, foreground, presentation, myFullSize ? getMaxWidth() : allowedWidth, isSelected); + allowedWidth -= setTypeTextLabel(item, background, foreground, presentation, isSelected ? getMaxWidth() : allowedWidth, isSelected); } myTailComponent.clear(); myTailComponent.setBackground(background); - if (myFullSize || allowedWidth >= 0) { - setTailTextLabel(isSelected, presentation, foreground, myFullSize ? getMaxWidth() : allowedWidth); + if (isSelected || allowedWidth >= 0) { + setTailTextLabel(isSelected, presentation, foreground, isSelected ? getMaxWidth() : allowedWidth); + } + + if (mySelected.containsKey(index)) { + if (!isSelected && mySelected.get(index)) { + myPanel.setUpdateExtender(true); + } + } + mySelected.put(index, isSelected); + + final double w = myNameComponent.getPreferredSize().getWidth() + + myTailComponent.getPreferredSize().getWidth() + + myTypeLabel.getPreferredSize().getWidth(); + + myPanel.removeAll(); + if (isSelected && w > list.getWidth()) { + myPanel.setLayout(new BoxLayout(myPanel, BoxLayout.X_AXIS)); + myPanel.add(myNameComponent); + myPanel.add(myTailComponent); + myPanel.add(myTypeLabel); + } else { + myPanel.setLayout(new BorderLayout()); + myPanel.add(myNameComponent, BorderLayout.WEST); + myPanel.add(myTailComponent, BorderLayout.CENTER); + myPanel.add(myTypeLabel, BorderLayout.EAST); } return myPanel; @@ -327,12 +351,6 @@ public class LookupCellRenderer implements ListCellRenderer { return RealLookupElementPresentation.calculateWidth(p, myNormalMetrics, myBoldMetrics) + AFTER_TAIL + AFTER_TYPE; } - public LookupCellRenderer createExtenderRenderer() { - LookupCellRenderer renderer = new LookupCellRenderer(myLookup, true); - renderer.myEmptyIcon = myEmptyIcon; - return renderer; - } - public int getIconIndent() { return myNameComponent.getIconTextGap() + myEmptyIcon.getIconWidth(); } @@ -350,15 +368,23 @@ public class LookupCellRenderer implements ListCellRenderer { } private class LookupPanel extends JPanel { + boolean myUpdateExtender; public LookupPanel() { super(new BorderLayout()); } + public void setUpdateExtender(boolean updateExtender) { + myUpdateExtender = updateExtender; + } + public void paint(Graphics g){ if (!myLookup.isFocused() && myLookup.isCompletion()) { ((Graphics2D)g).setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 0.6f)); } super.paint(g); + //if (myUpdateExtender) { + // myLookup.updateExtender(); + //} } } } diff --git a/platform/lang-impl/src/com/intellij/codeInsight/lookup/impl/LookupImpl.java b/platform/lang-impl/src/com/intellij/codeInsight/lookup/impl/LookupImpl.java index 45903bca721d..19ff809c8012 100644 --- a/platform/lang-impl/src/com/intellij/codeInsight/lookup/impl/LookupImpl.java +++ b/platform/lang-impl/src/com/intellij/codeInsight/lookup/impl/LookupImpl.java @@ -41,6 +41,7 @@ import com.intellij.openapi.command.WriteCommandAction; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.editor.*; import com.intellij.openapi.editor.event.*; +import com.intellij.openapi.editor.event.DocumentAdapter; import com.intellij.openapi.keymap.KeymapUtil; import com.intellij.openapi.project.Project; import com.intellij.openapi.ui.popup.JBPopup; @@ -56,9 +57,7 @@ import com.intellij.psi.PsiDocumentManager; import com.intellij.psi.PsiElement; import com.intellij.psi.PsiFile; import com.intellij.psi.impl.DebugUtil; -import com.intellij.ui.LightweightHint; -import com.intellij.ui.ListScrollingUtil; -import com.intellij.ui.ScreenUtil; +import com.intellij.ui.*; import com.intellij.ui.awt.RelativePoint; import com.intellij.ui.components.JBList; import com.intellij.ui.components.JBScrollPane; @@ -97,12 +96,11 @@ public class LookupImpl extends LightweightHint implements LookupEx, Disposable private final Project myProject; private final Editor myEditor; - private CompletionExtender extender; private String myInitialPrefix; private boolean myStableStart; private RangeMarker myLookupStartMarker; - private final JList myList = new JBList(new DefaultListModel()) { + private final JBList myList = new JBList(new DefaultListModel()) { @Override protected void processKeyEvent(final KeyEvent e) { final char keyChar = e.getKeyChar(); @@ -118,6 +116,13 @@ public class LookupImpl extends LightweightHint implements LookupEx, Disposable super.processKeyEvent(e); } + + ExpandableItemsHandler myExtender = new CompletionExtender(this); + @NotNull + @Override + public ExpandableItemsHandler getExpandableItemsHandler() { + return myExtender; + } }; private final LookupCellRenderer myCellRenderer; private Boolean myPositionedAbove = null; @@ -165,7 +170,7 @@ public class LookupImpl extends LightweightHint implements LookupEx, Disposable myPresentableArranger = arranger; myIconPanel.setVisible(false); - myCellRenderer = new LookupCellRenderer(this, false); + myCellRenderer = new LookupCellRenderer(this); myList.setCellRenderer(myCellRenderer); myList.setFocusable(false); @@ -174,6 +179,8 @@ public class LookupImpl extends LightweightHint implements LookupEx, Disposable myList.setSelectionMode(ListSelectionModel.SINGLE_SELECTION); myList.setBackground(LookupCellRenderer.BACKGROUND_COLOR); + myList.getExpandableItemsHandler(); + myScrollBarIncreaseButton = new JButton(); myScrollBarIncreaseButton.setFocusable(false); myScrollBarIncreaseButton.setRequestFocusEnabled(false); @@ -188,7 +195,6 @@ public class LookupImpl extends LightweightHint implements LookupEx, Disposable return myScrollBarIncreaseButton; } }); - getComponent().add(myLayeredPane, BorderLayout.CENTER); //IDEA-82111 @@ -886,16 +892,6 @@ public class LookupImpl extends LightweightHint implements LookupEx, Disposable updateHint(item); } oldItem = item; - - if (item != null && LookupImpl.this.isVisible() && LookupImpl.this.isFocused()) { - if (extender == null || !extender.isVisible() || !extender.sameAsFor(item)) { - if (extender != null) extender.hide(); - extender = new CompletionExtender(item, LookupImpl.this); - if (!extender.show()) { - extender.hide(); - } - } - } } }); @@ -1231,9 +1227,6 @@ public class LookupImpl extends LightweightHint implements LookupEx, Disposable } Disposer.dispose(myProcessIcon); Disposer.dispose(myHintAlarm); - if (extender != null) { - extender.hide(); - } myDisposed = true; disposeTrace = DebugUtil.currentStackTrace() + "\n============"; //noinspection AssignmentToStaticFieldFromInstanceMethod @@ -1458,5 +1451,4 @@ public class LookupImpl extends LightweightHint implements LookupEx, Disposable return myPresentableArranger.getRelevanceStrings(); } } - } diff --git a/platform/platform-impl/src/com/intellij/ui/AbstractExpandableItemsHandler.java b/platform/platform-impl/src/com/intellij/ui/AbstractExpandableItemsHandler.java index 31bb933bfea0..95ad1d46b940 100644 --- a/platform/platform-impl/src/com/intellij/ui/AbstractExpandableItemsHandler.java +++ b/platform/platform-impl/src/com/intellij/ui/AbstractExpandableItemsHandler.java @@ -89,7 +89,7 @@ abstract public class AbstractExpandableItemsHandler