diff options
Diffstat (limited to 'platform/platform-api/src/com/intellij/openapi/editor/actionSystem')
3 files changed, 178 insertions, 15 deletions
diff --git a/platform/platform-api/src/com/intellij/openapi/editor/actionSystem/CaretSpecificDataContext.java b/platform/platform-api/src/com/intellij/openapi/editor/actionSystem/CaretSpecificDataContext.java new file mode 100644 index 000000000000..e53cc48e4d5a --- /dev/null +++ b/platform/platform-api/src/com/intellij/openapi/editor/actionSystem/CaretSpecificDataContext.java @@ -0,0 +1,47 @@ +/* + * Copyright 2000-2014 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. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.intellij.openapi.editor.actionSystem; + +import com.intellij.openapi.actionSystem.CommonDataKeys; +import com.intellij.openapi.actionSystem.DataContext; +import com.intellij.openapi.actionSystem.DataContextWrapper; +import com.intellij.openapi.editor.Caret; +import com.intellij.openapi.fileEditor.FileEditorManager; +import com.intellij.openapi.project.Project; +import org.jetbrains.annotations.NonNls; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +public class CaretSpecificDataContext extends DataContextWrapper { + private final Caret myCaret; + + public CaretSpecificDataContext(@NotNull DataContext delegate, @NotNull Caret caret) { + super(delegate); + myCaret = caret; + } + + @Nullable + @Override + public Object getData(@NonNls String dataId) { + Project project = (Project)super.getData(CommonDataKeys.PROJECT.getName()); + if (project == null) { + return null; + } + FileEditorManager fm = FileEditorManager.getInstance(project); + Object data = fm == null ? null : fm.getData(dataId, myCaret.getEditor(), myCaret); + return data == null ? super.getData(dataId) : data; + } +} diff --git a/platform/platform-api/src/com/intellij/openapi/editor/actionSystem/EditorAction.java b/platform/platform-api/src/com/intellij/openapi/editor/actionSystem/EditorAction.java index 945c52022984..d93a508f97bd 100644 --- a/platform/platform-api/src/com/intellij/openapi/editor/actionSystem/EditorAction.java +++ b/platform/platform-api/src/com/intellij/openapi/editor/actionSystem/EditorAction.java @@ -26,13 +26,14 @@ import org.jetbrains.annotations.Nullable; import java.awt.event.KeyEvent; +import static com.intellij.openapi.actionSystem.CommonDataKeys.EDITOR; import static com.intellij.openapi.actionSystem.CommonDataKeys.PROJECT; public abstract class EditorAction extends AnAction implements DumbAware { private EditorActionHandler myHandler; private boolean myHandlersLoaded; - public EditorActionHandler getHandler() { + public final EditorActionHandler getHandler() { ensureHandlersLoaded(); return myHandler; } @@ -46,6 +47,7 @@ public abstract class EditorAction extends AnAction implements DumbAware { ensureHandlersLoaded(); EditorActionHandler tmp = myHandler; myHandler = newHandler; + myHandler.setWorksInInjected(isInInjectedContext()); return tmp; } @@ -58,12 +60,22 @@ public abstract class EditorAction extends AnAction implements DumbAware { final EditorActionHandlerBean handlerBean = extensions[i]; if (handlerBean.action.equals(id)) { myHandler = handlerBean.getHandler(myHandler); + myHandler.setWorksInInjected(isInInjectedContext()); } } } } @Override + public void setInjectedContext(boolean worksInInjected) { + super.setInjectedContext(worksInInjected); + // we assume that this method is called in constructor at the point + // where the chain of handlers is not initialized yet + // and it's enough to pass the flag to the default handler only + myHandler.setWorksInInjected(isInInjectedContext()); + } + + @Override public final void actionPerformed(AnActionEvent e) { DataContext dataContext = e.getDataContext(); Editor editor = getEditor(dataContext); @@ -72,7 +84,7 @@ public abstract class EditorAction extends AnAction implements DumbAware { @Nullable protected Editor getEditor(@NotNull DataContext dataContext) { - return CommonDataKeys.EDITOR.getData(dataContext); + return EDITOR.getData(dataContext); } public final void actionPerformed(final Editor editor, @NotNull final DataContext dataContext) { @@ -102,7 +114,7 @@ public abstract class EditorAction extends AnAction implements DumbAware { } public void update(Editor editor, Presentation presentation, DataContext dataContext) { - presentation.setEnabled(getHandler().isEnabled(editor, dataContext)); + presentation.setEnabled(getHandler().isEnabled(editor, null, dataContext)); } public void updateForKeyboardAccess(Editor editor, Presentation presentation, DataContext dataContext) { diff --git a/platform/platform-api/src/com/intellij/openapi/editor/actionSystem/EditorActionHandler.java b/platform/platform-api/src/com/intellij/openapi/editor/actionSystem/EditorActionHandler.java index c43fd13d8bef..294622ce1916 100644 --- a/platform/platform-api/src/com/intellij/openapi/editor/actionSystem/EditorActionHandler.java +++ b/platform/platform-api/src/com/intellij/openapi/editor/actionSystem/EditorActionHandler.java @@ -15,7 +15,7 @@ */ package com.intellij.openapi.editor.actionSystem; -import com.intellij.openapi.actionSystem.DataContext; +import com.intellij.openapi.actionSystem.*; import com.intellij.openapi.editor.Caret; import com.intellij.openapi.editor.CaretAction; import com.intellij.openapi.editor.Editor; @@ -35,7 +35,9 @@ import org.jetbrains.annotations.Nullable; */ public abstract class EditorActionHandler { private final boolean myRunForEachCaret; + private boolean myWorksInInjected; private boolean inExecution; + private boolean inCheck; protected EditorActionHandler() { this(false); @@ -46,17 +48,92 @@ public abstract class EditorActionHandler { } /** - * Checks if the action handler is currently enabled. - * - * @param editor the editor in which the action is invoked. - * @param dataContext the data context for the action. - * @return true if the action is enabled, false otherwise + * @deprecated Implementations should override + * {@link #isEnabledForCaret(com.intellij.openapi.editor.Editor, com.intellij.openapi.editor.Caret, com.intellij.openapi.actionSystem.DataContext)} + * instead, + * client code should invoke + * {@link #isEnabled(com.intellij.openapi.editor.Editor, com.intellij.openapi.editor.Caret, com.intellij.openapi.actionSystem.DataContext)} + * instead. */ - public boolean isEnabled(Editor editor, DataContext dataContext) { - return true; + public boolean isEnabled(Editor editor, final DataContext dataContext) { + if (inCheck) { + return true; + } + inCheck = true; + try { + if (editor == null) { + return false; + } + Editor hostEditor = dataContext == null ? null : CommonDataKeys.HOST_EDITOR.getData(dataContext); + if (hostEditor == null) { + hostEditor = editor; + } + final boolean[] result = new boolean[1]; + final CaretTask check = new CaretTask() { + @Override + public void perform(@NotNull Caret caret, @Nullable DataContext dataContext) { + result[0] = true; + } + }; + if (myRunForEachCaret) { + hostEditor.getCaretModel().runForEachCaret(new CaretAction() { + @Override + public void perform(Caret caret) { + doIfEnabled(caret, dataContext, check); + } + }); + } + else { + doIfEnabled(hostEditor.getCaretModel().getCurrentCaret(), dataContext, check); + } + return result[0]; + } + finally { + inCheck = false; + } + } + + private void doIfEnabled(@NotNull Caret hostCaret, @Nullable DataContext context, @NotNull CaretTask task) { + DataContext caretContext = context == null ? null : new CaretSpecificDataContext(context, hostCaret); + if (myWorksInInjected && caretContext != null) { + DataContext injectedCaretContext = AnActionEvent.getInjectedDataContext(caretContext); + Caret injectedCaret = CommonDataKeys.CARET.getData(injectedCaretContext); + if (injectedCaret != null && injectedCaret != hostCaret && isEnabledForCaret(injectedCaret.getEditor(), injectedCaret, injectedCaretContext)) { + task.perform(injectedCaret, injectedCaretContext); + return; + } + } + if (isEnabledForCaret(hostCaret.getEditor(), hostCaret, caretContext)) { + task.perform(hostCaret, caretContext); + } } /** + * Implementations can override this method to define whether handler is enabled for a specific caret in a given editor. + */ + protected boolean isEnabledForCaret(@NotNull Editor editor, @NotNull Caret caret, DataContext dataContext) { + if (inCheck) { + return true; + } + inCheck = true; + try { + //noinspection deprecation + return isEnabled(editor, dataContext); + } + finally { + inCheck = false; + } + } + + /** + * If <code>caret</code> is <code>null</code>, checks whether handler is enabled in general (i.e. enabled for at least one caret in editor), + * if <code>caret</code> is not <code>null</code>, checks whether it's enabled for specified caret. + */ + public final boolean isEnabled(@NotNull Editor editor, @Nullable Caret caret, DataContext dataContext) { + //noinspection deprecation + return caret == null ? isEnabled(editor, dataContext) : isEnabledForCaret(editor, caret, dataContext); + } + /** * @deprecated To implement action logic, override * {@link #doExecute(com.intellij.openapi.editor.Editor, com.intellij.openapi.editor.Caret, com.intellij.openapi.actionSystem.DataContext)}, * to invoke the handler, call @@ -112,22 +189,49 @@ public abstract class EditorActionHandler { * @param editor the editor in which the action is invoked. * @param dataContext the data context for the action. */ - public final void execute(@NotNull final Editor editor, @Nullable Caret contextCaret, final DataContext dataContext) { + public final void execute(@NotNull Editor editor, @Nullable final Caret contextCaret, final DataContext dataContext) { + Editor hostEditor = dataContext == null ? null : CommonDataKeys.HOST_EDITOR.getData(dataContext); + if (hostEditor == null) { + hostEditor = editor; + } if (contextCaret == null && runForAllCarets()) { - editor.getCaretModel().runForEachCaret(new CaretAction() { + hostEditor.getCaretModel().runForEachCaret(new CaretAction() { @Override public void perform(Caret caret) { - doExecute(editor, caret, dataContext); + doIfEnabled(caret, dataContext, new CaretTask() { + @Override + public void perform(@NotNull Caret caret, @Nullable DataContext dataContext) { + doExecute(caret.getEditor(), caret, dataContext); + } + }); } }, true); } else { - doExecute(editor, contextCaret, dataContext); + if (contextCaret == null) { + doIfEnabled(hostEditor.getCaretModel().getCurrentCaret(), dataContext, new CaretTask() { + @Override + public void perform(@NotNull Caret caret, @Nullable DataContext dataContext) { + doExecute(caret.getEditor(), null, dataContext); + } + }); + } + else { + doExecute(editor, contextCaret, dataContext); + } } } + void setWorksInInjected(boolean worksInInjected) { + myWorksInInjected = worksInInjected; + } + public DocCommandGroupId getCommandGroupId(Editor editor) { // by default avoid merging two consequential commands, and, in the same time, pass along the Document return DocCommandGroupId.noneGroupId(editor.getDocument()); } + + private interface CaretTask { + void perform(@NotNull Caret caret, @Nullable DataContext dataContext); + } } |