IDEADEV-40882 add static imports when needed
[idea/community.git] / platform / lang-impl / src / com / intellij / codeInsight / intention / impl / ShowIntentionActionsHandler.java
1 /*
2  * Copyright 2000-2009 JetBrains s.r.o.
3  *
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
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
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.
15  */
16
17 package com.intellij.codeInsight.intention.impl;
18
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.HighlightInfo;
23 import com.intellij.codeInsight.daemon.impl.LocalInspectionsPass;
24 import com.intellij.codeInsight.daemon.impl.ShowIntentionsPass;
25 import com.intellij.codeInsight.hint.HintManagerImpl;
26 import com.intellij.codeInsight.intention.IntentionAction;
27 import com.intellij.codeInsight.intention.PsiElementBaseIntentionAction;
28 import com.intellij.codeInsight.template.impl.TemplateManagerImpl;
29 import com.intellij.codeInsight.template.impl.TemplateState;
30 import com.intellij.idea.ActionsBundle;
31 import com.intellij.lang.annotation.HighlightSeverity;
32 import com.intellij.lang.injection.InjectedLanguageManager;
33 import com.intellij.openapi.application.ApplicationManager;
34 import com.intellij.openapi.command.CommandProcessor;
35 import com.intellij.openapi.diagnostic.Logger;
36 import com.intellij.openapi.editor.Document;
37 import com.intellij.openapi.editor.Editor;
38 import com.intellij.openapi.fileEditor.FileDocumentManager;
39 import com.intellij.openapi.progress.ProgressIndicator;
40 import com.intellij.openapi.progress.ProgressManager;
41 import com.intellij.openapi.progress.Task;
42 import com.intellij.openapi.project.Project;
43 import com.intellij.openapi.util.Pair;
44 import com.intellij.openapi.util.TextRange;
45 import com.intellij.openapi.vfs.VirtualFile;
46 import com.intellij.psi.PsiCodeFragment;
47 import com.intellij.psi.PsiDocumentManager;
48 import com.intellij.psi.PsiElement;
49 import com.intellij.psi.PsiFile;
50 import com.intellij.psi.impl.source.tree.injected.InjectedLanguageUtil;
51 import com.intellij.util.IncorrectOperationException;
52 import org.jetbrains.annotations.NotNull;
53
54 import javax.swing.*;
55
56 /**
57  * @author mike
58  */
59 public class ShowIntentionActionsHandler implements CodeInsightActionHandler {
60   private static final Logger LOG = Logger.getInstance("#com.intellij.codeInsight.intention.impl.ShowIntentionActionsHandler");
61
62   public void invoke(@NotNull final Project project, @NotNull final Editor editor, @NotNull final PsiFile file) {
63     PsiDocumentManager.getInstance(project).commitAllDocuments();
64
65     if (HintManagerImpl.getInstanceImpl().performCurrentQuestionAction()) return;
66
67     //intentions check isWritable before modification: if (!file.isWritable()) return;
68     if (file instanceof PsiCodeFragment) return;
69
70     TemplateState state = TemplateManagerImpl.getTemplateState(editor);
71     if (state != null && !state.isFinished()) return;
72
73     final DaemonCodeAnalyzerImpl codeAnalyzer = (DaemonCodeAnalyzerImpl)DaemonCodeAnalyzer.getInstance(project);
74     codeAnalyzer.autoImportReferenceAtCursor(editor, file); //let autoimport complete
75
76     ShowIntentionsPass.IntentionsInfo intentions = new ShowIntentionsPass.IntentionsInfo();
77     ShowIntentionsPass.getActionsToShow(editor, file, intentions, -1);
78     
79     if (!codeAnalyzer.isAllAnalysisFinished(file)) {
80       runPassesAndShowIntentions(project, editor, file, intentions);
81     }
82     else if (!intentions.isEmpty()) {
83       IntentionHintComponent.showIntentionHint(project, file, editor, intentions, true);
84     }
85   }
86
87   private static void runPassesAndShowIntentions(final Project project, final Editor editor, final PsiFile file, final ShowIntentionsPass.IntentionsInfo intentions) {
88     intentions.errorFixesToShow.clear();
89     intentions.inspectionFixesToShow.clear();
90     final VirtualFile virtualFile = file.getVirtualFile();
91     if (virtualFile == null) return;
92     final Document document = FileDocumentManager.getInstance().getDocument(virtualFile);
93     final int offset = editor.getCaretModel().getOffset();
94     final PsiElement element = file.findElementAt(offset);
95     if (element == null) return;
96     final Task.Backgroundable task = new Task.Backgroundable(project, ActionsBundle.message("action.ShowIntentionActions.text"), true) {
97       public void run(@NotNull final ProgressIndicator indicator) {
98         ApplicationManager.getApplication().runReadAction(new Runnable() {
99           public void run() {
100             final TextRange textRange = element.getTextRange();
101             final LocalInspectionsPass pass = new LocalInspectionsPass(file, document, textRange.getStartOffset(), textRange.getEndOffset());
102             pass.collectInformation(indicator);
103             for (HighlightInfo info : pass.getHighlights()) {
104               if (info.quickFixActionRanges != null) {
105                 final boolean isError = info.getSeverity() == HighlightSeverity.ERROR;
106                 for (Pair<HighlightInfo.IntentionActionDescriptor, TextRange> actionRanges : info.quickFixActionRanges) {
107                   if (actionRanges.second.contains(offset)) {
108                     final IntentionAction action = actionRanges.first.getAction();
109                     boolean available = action instanceof PsiElementBaseIntentionAction ?
110                                         ((PsiElementBaseIntentionAction)action).isAvailable(project, editor, element) :
111                                         action.isAvailable(project, editor, file);
112                     if (available) {
113                       if (isError) {
114                         intentions.errorFixesToShow.add(actionRanges.first);
115                       }
116                       else {
117                         intentions.inspectionFixesToShow.add(actionRanges.first);
118                       }
119                     }
120                   }
121                 }
122               }
123             }
124
125           }
126         });
127         SwingUtilities.invokeLater(new Runnable(){
128           public void run() {
129             if (editor.getComponent().isDisplayable()) {
130               if (!intentions.isEmpty()) {
131                 IntentionHintComponent.showIntentionHint(project, file, editor, intentions, true);
132               }
133             }
134           }
135         });
136       }
137     };
138     ProgressManager.getInstance().run(task);
139   }
140
141   public boolean startInWriteAction() {
142     return false;
143   }
144
145   public static void chooseActionAndInvoke(PsiFile file, final Editor editor, final IntentionAction action, final String text) {
146     final Project project = file.getProject();
147
148     final Editor editorToApply;
149     final PsiFile fileToApply;
150
151     int offset = editor.getCaretModel().getOffset();
152     PsiElement injected = InjectedLanguageManager.getInstance(project).findInjectedElementAt(file, offset);
153     if (injected != null) {
154       PsiFile injectedFile = injected.getContainingFile();
155       Editor injectedEditor = InjectedLanguageUtil.getInjectedEditorForInjectedFile(editor, injectedFile);
156
157       if (action.isAvailable(project, injectedEditor, injectedFile)) {
158         editorToApply = injectedEditor;
159         fileToApply = injectedFile;
160       }
161       else if (!action.isAvailable(project, editor, file)) {
162         return;
163       }
164       else {
165         editorToApply = editor;
166         fileToApply = file;
167       }
168     }
169     else if (!action.isAvailable(project, editor, file)) {
170       return;
171     }
172     else {
173       editorToApply = editor;
174       fileToApply = file;
175     }
176
177     Runnable runnable = new Runnable() {
178       public void run() {
179         try {
180           action.invoke(project, editorToApply, fileToApply);
181         }
182         catch (IncorrectOperationException e) {
183           LOG.error(e);
184         }
185         DaemonCodeAnalyzer.getInstance(project).updateVisibleHighlighters(editor);
186       }
187     };
188
189     if (action.startInWriteAction()) {
190       final Runnable _runnable = runnable;
191       runnable = new Runnable() {
192         public void run() {
193           ApplicationManager.getApplication().runWriteAction(_runnable);
194         }
195       };
196     }
197
198     CommandProcessor.getInstance().executeCommand(project, runnable, text, null);
199   }
200 }