2 * Copyright 2000-2009 JetBrains s.r.o.
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
17 package com.intellij.codeInsight.intention.impl;
19 import com.intellij.codeInsight.CodeInsightActionHandler;
20 import com.intellij.codeInsight.daemon.DaemonCodeAnalyzer;
21 import com.intellij.codeInsight.daemon.impl.DaemonCodeAnalyzerImpl;
22 import com.intellij.codeInsight.daemon.impl.ShowIntentionsPass;
23 import com.intellij.codeInsight.hint.HintManagerImpl;
24 import com.intellij.codeInsight.intention.IntentionAction;
25 import com.intellij.codeInsight.intention.PsiElementBaseIntentionAction;
26 import com.intellij.codeInsight.template.impl.TemplateManagerImpl;
27 import com.intellij.codeInsight.template.impl.TemplateState;
28 import com.intellij.openapi.application.ApplicationManager;
29 import com.intellij.openapi.command.CommandProcessor;
30 import com.intellij.openapi.diagnostic.Logger;
31 import com.intellij.openapi.editor.Editor;
32 import com.intellij.openapi.project.IndexNotReadyException;
33 import com.intellij.openapi.project.Project;
34 import com.intellij.openapi.util.Pair;
35 import com.intellij.psi.PsiCodeFragment;
36 import com.intellij.psi.PsiDocumentManager;
37 import com.intellij.psi.PsiElement;
38 import com.intellij.psi.PsiFile;
39 import com.intellij.psi.impl.source.tree.injected.InjectedLanguageUtil;
40 import com.intellij.util.IncorrectOperationException;
41 import com.intellij.util.PairProcessor;
42 import org.jetbrains.annotations.NotNull;
43 import org.jetbrains.annotations.Nullable;
48 public class ShowIntentionActionsHandler implements CodeInsightActionHandler {
49 private static final Logger LOG = Logger.getInstance("#com.intellij.codeInsight.intention.impl.ShowIntentionActionsHandler");
51 public void invoke(@NotNull final Project project, @NotNull final Editor editor, @NotNull final PsiFile file) {
52 PsiDocumentManager.getInstance(project).commitAllDocuments();
54 if (HintManagerImpl.getInstanceImpl().performCurrentQuestionAction()) return;
56 //intentions check isWritable before modification: if (!file.isWritable()) return;
57 if (file instanceof PsiCodeFragment) return;
59 TemplateState state = TemplateManagerImpl.getTemplateState(editor);
60 if (state != null && !state.isFinished()) {
64 final DaemonCodeAnalyzerImpl codeAnalyzer = (DaemonCodeAnalyzerImpl)DaemonCodeAnalyzer.getInstance(project);
65 codeAnalyzer.autoImportReferenceAtCursor(editor, file); //let autoimport complete
67 ShowIntentionsPass.IntentionsInfo intentions = new ShowIntentionsPass.IntentionsInfo();
68 ShowIntentionsPass.getActionsToShow(editor, file, intentions, -1);
70 if (!intentions.isEmpty()) {
71 IntentionHintComponent.showIntentionHint(project, file, editor, intentions, true);
75 public boolean startInWriteAction() {
79 // returns editor,file where the action is available or null if there are none
80 public static boolean availableFor(@NotNull PsiFile file, @NotNull Editor editor, @NotNull IntentionAction action) {
81 if (!file.isValid()) return false;
83 int offset = editor.getCaretModel().getOffset();
84 PsiElement element = file.findElementAt(offset);
85 boolean inProject = file.getManager().isInProject(file);
86 return isAvailableHere(editor, file, element, inProject, action);
89 private static boolean isAvailableHere(Editor editor, PsiFile psiFile, PsiElement psiElement, boolean inProject, IntentionAction action) {
91 Project project = psiFile.getProject();
92 if (action instanceof PsiElementBaseIntentionAction) {
93 if (!inProject || psiElement == null || !((PsiElementBaseIntentionAction)action).isAvailable(project, editor, psiElement)) return false;
95 else if (!action.isAvailable(project, editor, psiFile)) {
99 catch (IndexNotReadyException e) {
106 public static Pair<PsiFile,Editor> chooseBetweenHostAndInjected(PsiFile hostFile, Editor hostEditor, PairProcessor<PsiFile, Editor> predicate) {
107 Editor editorToApply = null;
108 PsiFile fileToApply = null;
110 int offset = hostEditor.getCaretModel().getOffset();
111 PsiFile injectedFile = InjectedLanguageUtil.findInjectedPsiNoCommit(hostFile, offset);
112 if (injectedFile != null) {
113 Editor injectedEditor = InjectedLanguageUtil.getInjectedEditorForInjectedFile(hostEditor, injectedFile);
114 if (predicate.process(injectedFile, injectedEditor)) {
115 editorToApply = injectedEditor;
116 fileToApply = injectedFile;
120 if (editorToApply == null && predicate.process(hostFile, hostEditor)) {
121 editorToApply = hostEditor;
122 fileToApply = hostFile;
124 if (editorToApply == null) return null;
125 return Pair.create(fileToApply, editorToApply);
128 public static boolean chooseActionAndInvoke(PsiFile hostFile, final Editor hostEditor, final IntentionAction action, final String text) {
129 final Project project = hostFile.getProject();
131 Pair<PsiFile, Editor> pair = chooseBetweenHostAndInjected(hostFile, hostEditor, new PairProcessor<PsiFile, Editor>() {
132 public boolean process(PsiFile psiFile, Editor editor) {
133 return availableFor(psiFile, editor, action);
136 if (pair == null) return false;
137 final Editor editorToApply = pair.second;
138 final PsiFile fileToApply = pair.first;
140 Runnable runnable = new Runnable() {
143 action.invoke(project, editorToApply, fileToApply);
145 catch (IncorrectOperationException e) {
148 DaemonCodeAnalyzer.getInstance(project).updateVisibleHighlighters(hostEditor);
152 if (action.startInWriteAction()) {
153 final Runnable _runnable = runnable;
154 runnable = new Runnable() {
156 ApplicationManager.getApplication().runWriteAction(_runnable);
161 CommandProcessor.getInstance().executeCommand(project, runnable, text, null);