diff --git a/platform/lang-impl/src/com/intellij/codeInsight/TargetElementUtilBase.java b/platform/lang-impl/src/com/intellij/codeInsight/TargetElementUtilBase.java index 0d5a094c5e71..cd9ada8bbbae 100644 --- a/platform/lang-impl/src/com/intellij/codeInsight/TargetElementUtilBase.java +++ b/platform/lang-impl/src/com/intellij/codeInsight/TargetElementUtilBase.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2009 JetBrains s.r.o. + * Copyright 2000-2012 JetBrains s.r.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -33,6 +33,7 @@ import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.components.ServiceManager; import com.intellij.openapi.editor.Document; import com.intellij.openapi.editor.Editor; +import com.intellij.openapi.editor.actions.EditorActionUtil; import com.intellij.openapi.editor.ex.util.EditorUtil; import com.intellij.openapi.project.Project; import com.intellij.openapi.util.TextRange; @@ -82,7 +83,14 @@ public class TargetElementUtilBase { @Nullable public static PsiReference findReference(Editor editor) { - return findReference(editor, editor.getCaretModel().getOffset()); + PsiReference result = findReference(editor, editor.getCaretModel().getOffset()); + if (result == null) { + final Integer offset = editor.getUserData(EditorActionUtil.EXPECTED_CARET_OFFSET); + if (offset != null) { + result = findReference(editor, offset); + } + } + return result; } @Nullable @@ -124,7 +132,15 @@ public class TargetElementUtilBase { public static PsiElement findTargetElement(Editor editor, int flags) { ApplicationManager.getApplication().assertIsDispatchThread(); - return getInstance().findTargetElement(editor, flags, editor.getCaretModel().getOffset()); + final PsiElement result = getInstance().findTargetElement(editor, flags, editor.getCaretModel().getOffset()); + if (result != null) { + return result; + } + final Integer offset = editor.getUserData(EditorActionUtil.EXPECTED_CARET_OFFSET); + if (offset != null) { + return getInstance().findTargetElement(editor, flags, offset); + } + return result; } public static boolean inVirtualSpace(Editor editor, int offset) { diff --git a/platform/lang-impl/src/com/intellij/ide/actions/CopyReferenceAction.java b/platform/lang-impl/src/com/intellij/ide/actions/CopyReferenceAction.java index 72e144cffe77..9627f6444924 100644 --- a/platform/lang-impl/src/com/intellij/ide/actions/CopyReferenceAction.java +++ b/platform/lang-impl/src/com/intellij/ide/actions/CopyReferenceAction.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2011 JetBrains s.r.o. + * Copyright 2000-2012 JetBrains s.r.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -26,6 +26,7 @@ import com.intellij.ide.IdeBundle; import com.intellij.ide.dnd.FileCopyPasteUtil; import com.intellij.openapi.actionSystem.*; import com.intellij.openapi.editor.Editor; +import com.intellij.openapi.editor.actions.EditorActionUtil; import com.intellij.openapi.editor.colors.EditorColors; import com.intellij.openapi.editor.colors.EditorColorsManager; import com.intellij.openapi.editor.markup.TextAttributes; @@ -109,7 +110,7 @@ public class CopyReferenceAction extends AnAction { private static PsiElement getElementToCopy(final Editor editor, final DataContext dataContext) { PsiElement element = null; if (editor != null) { - PsiReference reference = TargetElementUtilBase.findReference(editor, editor.getCaretModel().getOffset()); + PsiReference reference = TargetElementUtilBase.findReference(editor); if (reference != null) { element = reference.getElement(); } diff --git a/platform/platform-api/src/com/intellij/openapi/editor/event/EditorMouseListener.java b/platform/platform-api/src/com/intellij/openapi/editor/event/EditorMouseListener.java index 7aa1d8f8dc78..0e0eba4c0d87 100644 --- a/platform/platform-api/src/com/intellij/openapi/editor/event/EditorMouseListener.java +++ b/platform/platform-api/src/com/intellij/openapi/editor/event/EditorMouseListener.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2009 JetBrains s.r.o. + * Copyright 2000-2012 JetBrains s.r.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -25,8 +25,12 @@ import java.util.EventListener; * @see EditorMouseMotionListener */ public interface EditorMouseListener extends EventListener { + /** * Called when a mouse button is pressed over the editor. + *

+ * Note: this callback is assumed to be at the very start of 'mouse press' processing, i.e. common actions + * like 'caret position change', 'selection change' etc implied by the 'mouse press' have not been performed yet. * * @param e the event containing information about the mouse press. */ diff --git a/platform/platform-impl/src/com/intellij/openapi/editor/actions/EditorActionUtil.java b/platform/platform-impl/src/com/intellij/openapi/editor/actions/EditorActionUtil.java index 04582bc98034..7371f18b4a69 100644 --- a/platform/platform-impl/src/com/intellij/openapi/editor/actions/EditorActionUtil.java +++ b/platform/platform-impl/src/com/intellij/openapi/editor/actions/EditorActionUtil.java @@ -33,6 +33,7 @@ import com.intellij.openapi.actionSystem.ActionPopupMenu; import com.intellij.openapi.editor.*; import com.intellij.openapi.editor.event.EditorMouseEvent; import com.intellij.openapi.editor.event.EditorMouseEventArea; +import com.intellij.openapi.editor.event.EditorMouseListener; import com.intellij.openapi.editor.ex.EditorEx; import com.intellij.openapi.editor.ex.util.EditorUtil; import com.intellij.openapi.editor.impl.EditorImpl; @@ -49,6 +50,21 @@ import java.awt.event.MouseEvent; import java.util.List; public class EditorActionUtil { + + /** + * Editor actions may be invoked multiple ways - programmatically, via keyboard/mouse shortcut, main/context menu etc. + * Action processing may also interfere with standard editor behavior (caret position change, selection change etc). + *

+ * E.g. consider a situation when context menu is shown on right mouse click - + * {@link EditorMouseListener#mousePressed(EditorMouseEvent) the contract says} that no common actions have been performed yet. + * However, some actions may operate on an 'active element' (an element under caret), hence, they would incorrectly because the + * caret position has not been changed yet. + *

+ * We address that problem by providing a special key that is intended to hold 'expected caret offset', i.e. offset where we + * expect the caret to be located at the near future. + */ + public static final Key EXPECTED_CARET_OFFSET = Key.create("expectedEditorOffset"); + protected static final Object EDIT_COMMAND_GROUP = Key.create("EditGroup"); public static final Object DELETE_COMMAND_GROUP = Key.create("DeleteGroup"); diff --git a/platform/platform-impl/src/com/intellij/openapi/editor/impl/EditorImpl.java b/platform/platform-impl/src/com/intellij/openapi/editor/impl/EditorImpl.java index b44e8d539581..9179a8ce4f7d 100644 --- a/platform/platform-impl/src/com/intellij/openapi/editor/impl/EditorImpl.java +++ b/platform/platform-impl/src/com/intellij/openapi/editor/impl/EditorImpl.java @@ -41,6 +41,7 @@ import com.intellij.openapi.command.UndoConfirmationPolicy; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.editor.*; import com.intellij.openapi.editor.actionSystem.*; +import com.intellij.openapi.editor.actions.EditorActionUtil; import com.intellij.openapi.editor.colors.*; import com.intellij.openapi.editor.colors.impl.DelegateColorScheme; import com.intellij.openapi.editor.event.*; @@ -5078,6 +5079,10 @@ public final class EditorImpl extends UserDataHolderBase implements EditorEx, Hi TooltipController.getInstance().cancelTooltip(FOLDING_TOOLTIP_GROUP, e, true); } private void runMousePressedCommand(@NotNull final MouseEvent e) { + + final int clickOffset = logicalPositionToOffset(xyToLogicalPosition(e.getPoint())); + putUserData(EditorActionUtil.EXPECTED_CARET_OFFSET, clickOffset); + mySelectionTweaked = false; myMousePressedEvent = e; EditorMouseEvent event = new EditorMouseEvent(EditorImpl.this, e, getMouseEventArea(e));