summaryrefslogtreecommitdiff
path: root/platform/platform-api/src/com/intellij/openapi/editor/actionSystem
diff options
context:
space:
mode:
Diffstat (limited to 'platform/platform-api/src/com/intellij/openapi/editor/actionSystem')
-rw-r--r--platform/platform-api/src/com/intellij/openapi/editor/actionSystem/CaretSpecificDataContext.java47
-rw-r--r--platform/platform-api/src/com/intellij/openapi/editor/actionSystem/EditorAction.java18
-rw-r--r--platform/platform-api/src/com/intellij/openapi/editor/actionSystem/EditorActionHandler.java128
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);
+ }
}