IDEA-205739 Editor: Action is applied for the wrong line if invoked from menu

Changed API to configure editor popup handlers to 'install/uninstall' style. Now if multiple plugins want to adjust popup
behaviour calls to EditorPopupHandler.handlePopup won't be chained, and exception reporter won't erroneously blame plugins
which are present in that chain.

(following IDEA-CR-42434)
This commit is contained in:
Dmitry Batrak
2019-01-25 15:59:14 +03:00
parent d55e41b91c
commit 404b0f2bb1
11 changed files with 46 additions and 43 deletions
@@ -520,7 +520,7 @@ public class TextDiffViewerUtil {
myEditorPopupActions.isEmpty() ? null : new DefaultActionGroup(myEditorPopupActions)
);
for (EditorEx editor : editors) {
editor.setPopupHandler(handler);
editor.installPopupHandler(handler);
}
}
}
@@ -928,7 +928,7 @@ public class ConsoleViewImpl extends JPanel implements ConsoleView, ObservableCo
return ReadAction.compute(() -> {
EditorEx editor = doCreateConsoleEditor();
LOG.assertTrue(UndoUtil.isUndoDisabledFor(editor.getDocument()));
editor.setPopupHandler(new ContextMenuPopupHandler() {
editor.installPopupHandler(new ContextMenuPopupHandler() {
@Override
public ActionGroup getActionGroup(@NotNull EditorMouseEvent event) {
return getPopupGroup(event.getMouseEvent());
@@ -892,14 +892,13 @@ class EditorWindowImpl extends com.intellij.injected.editor.EditorWindowImpl imp
}
@Override
public void setPopupHandler(@NotNull EditorPopupHandler popupHandler) {
myDelegate.setPopupHandler(popupHandler);
public void installPopupHandler(@NotNull EditorPopupHandler popupHandler) {
myDelegate.installPopupHandler(popupHandler);
}
@NotNull
@Override
public EditorPopupHandler getPopupHandler() {
return myDelegate.getPopupHandler();
public void uninstallPopupHandler(@NotNull EditorPopupHandler popupHandler) {
myDelegate.installPopupHandler(popupHandler);
}
@Override
@@ -97,7 +97,7 @@ class EventLogConsole {
clearLog.registerCustomShortcutSet(ActionManager.getInstance().getAction(IdeActions.CONSOLE_CLEAR_ALL).getShortcutSet(),
editor.getContentComponent());
editor.setPopupHandler(new ContextMenuPopupHandler() {
editor.installPopupHandler(new ContextMenuPopupHandler() {
@Override
public ActionGroup getActionGroup(@NotNull EditorMouseEvent event) {
final ActionManager actionManager = ActionManager.getInstance();
@@ -796,7 +796,7 @@ public class EditorActionUtil {
/**
* @deprecated Use {@link EditorEx#setContextMenuGroupId(String)} or
* {@link EditorEx#setPopupHandler(com.intellij.openapi.editor.ex.EditorPopupHandler)} instead. To be removed in version 2020.2.
* {@link EditorEx#installPopupHandler(com.intellij.openapi.editor.ex.EditorPopupHandler)} instead. To be removed in version 2020.2.
*/
@Deprecated
public static EditorPopupHandler createEditorPopupHandler(@NotNull final String groupId) {
@@ -813,7 +813,7 @@ public class EditorActionUtil {
/**
* @deprecated Use {@link EditorEx#setContextMenuGroupId(String)} or
* {@link EditorEx#setPopupHandler(com.intellij.openapi.editor.ex.EditorPopupHandler)} instead. To be removed in version 2020.2.
* {@link EditorEx#installPopupHandler(com.intellij.openapi.editor.ex.EditorPopupHandler)} instead. To be removed in version 2020.2.
*/
@Deprecated
public static EditorPopupHandler createEditorPopupHandler(@NotNull final ActionGroup group) {
@@ -292,44 +292,44 @@ public interface EditorEx extends Editor {
int getExpectedCaretOffset();
/**
* Sets id of action group what will be used to construct context menu displayed on mouse right button's click. Setting this to
* {@code null} disables built-in logic for showing context menu (it can still be achieved by implementing corresponding mouse
* event listener). This method might have no effect if default editor's popup handler was overridden
* using {@link #setPopupHandler(EditorPopupHandler)}.
* Sets id of action group what will be used to construct context menu displayed by default editor popup handler on mouse right button's
* click (with {@code null} value disabling context menu). This method might have no effect if default editor's popup handler was
* overridden using {@link #installPopupHandler(EditorPopupHandler)}.
*
* @see #getContextMenuGroupId()
* @see #setPopupHandler(EditorPopupHandler)
*/
void setContextMenuGroupId(@Nullable String groupId);
/**
* Returns id of action group what will be used to construct context menu displayed on mouse right button's click. {@code null}
* value means built-in logic for showing context menu is disabled. Returned value might be meaningless if default editor's popup handler
* was overridden using {@link #setPopupHandler(EditorPopupHandler)}.
* Returns id of action group what will be used to construct context menu displayed by default editor popup handler on mouse right
* button's click ({@code null} value meaning no context menu). Returned value might be meaningless if default editor's popup handler
* was overridden using {@link #installPopupHandler(EditorPopupHandler)}.
*
* @see #setContextMenuGroupId(String)
* @see #getPopupHandler()
*/
@Nullable
String getContextMenuGroupId();
/**
* Allows to override default editor's context popup logic. Default logic shows a context menu corresponding to a certain action group
* Allows to override default editor's context popup logic.
* <p>
* Default handler shows a context menu corresponding to a certain action group
* registered in {@link ActionManager}. Group's id can be changed using {@link #setContextMenuGroupId(String)}. For inline custom visual
* elements (inlays) action group id is obtained from {@link EditorCustomElementRenderer#getContextMenuGroupId(Inlay)}.
* <p>
* If multiple handlers are installed, they are processed in order, starting from the most recently installed one. Processing stops when
* some handler returns {@code true} from {@link EditorPopupHandler#handlePopup(EditorMouseEvent)} method.
*
* @see #getPopupHandler()
* @since 2019.1
* @see #uninstallPopupHandler(EditorPopupHandler)
*/
void setPopupHandler(@NotNull EditorPopupHandler popupHandler);
void installPopupHandler(@NotNull EditorPopupHandler popupHandler);
/**
* Returns current editor's popup handler (see {@link #setPopupHandler(EditorPopupHandler)}).
* Removes previously installed {@link EditorPopupHandler}.
*
* @since 2019.1
* @see #installPopupHandler(EditorPopupHandler)
*/
@NotNull
EditorPopupHandler getPopupHandler();
void uninstallPopupHandler(@NotNull EditorPopupHandler popupHandler);
/**
* If {@code cursor} parameter value is not {@code null}, sets custom cursor to {@link #getContentComponent() editor's content component},
@@ -8,16 +8,17 @@ import org.jetbrains.annotations.NotNull;
/**
* Handler of popup trigger mouse events in editor
*
* @see EditorEx#setPopupHandler(EditorPopupHandler)
* @see EditorEx#installPopupHandler(EditorPopupHandler)
* @see ContextMenuPopupHandler default implementation
*
* @since 2019.1
*/
public interface EditorPopupHandler {
EditorPopupHandler NONE = event -> {};
EditorPopupHandler NONE = event -> true;
/**
* This method is called when a popup trigger mouse event is received by editor's main area.
*
* @return {@code true} if this handler has processed the event, {@code false} if previously installed (or the default one if there are
* none) handler should be invoked.
*/
void handlePopup(@NotNull EditorMouseEvent event);
boolean handlePopup(@NotNull EditorMouseEvent event);
}
@@ -26,7 +26,7 @@ public abstract class ContextMenuPopupHandler implements EditorPopupHandler {
public abstract ActionGroup getActionGroup(@NotNull EditorMouseEvent event);
@Override
public void handlePopup(@NotNull EditorMouseEvent event) {
public boolean handlePopup(@NotNull EditorMouseEvent event) {
ActionGroup group = getActionGroup(event);
if (group != null) {
ActionPopupMenu popupMenu = ActionManager.getInstance().createActionPopupMenu(ActionPlaces.EDITOR_POPUP, group);
@@ -39,6 +39,7 @@ public abstract class ContextMenuPopupHandler implements EditorPopupHandler {
event.consume();
}
}
return true;
}
private static void disableHoverPopupsWhileShowing(Editor editor, Component popupComponent) {
@@ -324,8 +324,7 @@ public final class EditorImpl extends UserDataHolderBase implements EditorEx, Hi
private boolean myErrorStripeNeedsRepaint;
private String myContextMenuGroupId = IdeActions.GROUP_BASIC_EDITOR_POPUP;
@NotNull
private EditorPopupHandler myPopupHandler = new DefaultPopupHandler();
private final List<EditorPopupHandler> myPopupHandlers = new ArrayList<>();
private boolean myUseEditorAntialiasing = true;
@@ -551,6 +550,7 @@ public final class EditorImpl extends UserDataHolderBase implements EditorEx, Hi
CodeStyleSettingsManager.getInstance(myProject).addListener(this);
myFocusModeModel = new FocusModeModel(this);
myPopupHandlers.add(new DefaultPopupHandler());
}
public void applyFocusMode() {
@@ -790,14 +790,13 @@ public final class EditorImpl extends UserDataHolderBase implements EditorEx, Hi
}
@Override
public void setPopupHandler(@NotNull EditorPopupHandler popupHandler) {
myPopupHandler = popupHandler;
public void installPopupHandler(@NotNull EditorPopupHandler popupHandler) {
myPopupHandlers.add(popupHandler);
}
@NotNull
@Override
public EditorPopupHandler getPopupHandler() {
return myPopupHandler;
public void uninstallPopupHandler(@NotNull EditorPopupHandler popupHandler) {
myPopupHandlers.remove(popupHandler);
}
@Nullable
@@ -3747,6 +3746,7 @@ public final class EditorImpl extends UserDataHolderBase implements EditorEx, Hi
for (EditorMouseListener mouseListener : myMouseListeners) {
boolean wasConsumed = event.isConsumed();
mouseListener.mousePressed(event);
//noinspection deprecation
if (!wasConsumed && event.isConsumed() && mouseListener instanceof com.intellij.util.EditorPopupHandler) {
// compatibility with legacy code, this logic should be removed along with EditorPopupHandler
forceProcessing = true;
@@ -4696,7 +4696,9 @@ public final class EditorImpl extends UserDataHolderBase implements EditorEx, Hi
private void invokePopupIfNeeded(EditorMouseEvent event) {
if (event.getArea() == EditorMouseEventArea.EDITING_AREA && event.getMouseEvent().isPopupTrigger() && !event.isConsumed()) {
myPopupHandler.handlePopup(event);
for (int i = myPopupHandlers.size() - 1; i >= 0; i--) {
if (myPopupHandlers.get(i).handlePopup(event)) break;
}
}
}
@@ -9,7 +9,7 @@ import org.jetbrains.annotations.NotNull;
/**
* @deprecated Use {@link EditorEx#setContextMenuGroupId(String)} or
* {@link EditorEx#setPopupHandler(com.intellij.openapi.editor.ex.EditorPopupHandler)} instead. To be removed in version 2020.2.
* {@link EditorEx#installPopupHandler(com.intellij.openapi.editor.ex.EditorPopupHandler)} instead. To be removed in version 2020.2.
*/
@SuppressWarnings("DeprecatedIsStillUsed")
@Deprecated
@@ -849,7 +849,7 @@ public class ResourceBundleEditor extends UserDataHolderBase implements Document
settings.setVirtualSpace(false);
editor.setHighlighter(new LexerEditorHighlighter(new PropertiesValueHighlighter(), scheme));
editor.setVerticalScrollbarVisible(true);
editor.setPopupHandler(new ContextMenuPopupHandler() {
editor.installPopupHandler(new ContextMenuPopupHandler() {
@Override
public ActionGroup getActionGroup(@NotNull EditorMouseEvent event) {
DefaultActionGroup group = new DefaultActionGroup();