3d16648f29c5842f067621867765b3eb96ed6de5
[idea/community.git] / platform / lang-impl / src / com / intellij / codeInspection / actions / CleanupInspectionIntention.java
1 /*
2  * Copyright 2000-2013 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.codeInspection.actions;
18
19 import com.intellij.codeInsight.FileModificationService;
20 import com.intellij.codeInsight.hint.HintManager;
21 import com.intellij.codeInsight.intention.EmptyIntentionAction;
22 import com.intellij.codeInsight.intention.HighPriorityAction;
23 import com.intellij.codeInsight.intention.IntentionAction;
24 import com.intellij.codeInspection.*;
25 import com.intellij.codeInspection.ex.InspectionToolWrapper;
26 import com.intellij.codeInspection.ex.LocalInspectionToolWrapper;
27 import com.intellij.codeInspection.ex.PerformFixesModalTask;
28 import com.intellij.openapi.command.CommandProcessor;
29 import com.intellij.openapi.editor.Editor;
30 import com.intellij.openapi.progress.EmptyProgressIndicator;
31 import com.intellij.openapi.progress.ProgressManager;
32 import com.intellij.openapi.project.Project;
33 import com.intellij.openapi.util.Computable;
34 import com.intellij.psi.PsiElement;
35 import com.intellij.psi.PsiFile;
36 import com.intellij.util.IncorrectOperationException;
37 import com.intellij.util.SequentialModalProgressTask;
38 import org.jetbrains.annotations.NotNull;
39
40 import java.util.Collections;
41 import java.util.Comparator;
42 import java.util.List;
43
44 /**
45  * User: anna
46  * Date: 21-Feb-2006
47  */
48 public class CleanupInspectionIntention implements IntentionAction, HighPriorityAction {
49   private final InspectionToolWrapper myToolWrapper;
50   private final Class myQuickfixClass;
51   private final String myText;
52
53   public CleanupInspectionIntention(@NotNull InspectionToolWrapper toolWrapper, @NotNull Class quickFixClass, String text) {
54     myToolWrapper = toolWrapper;
55     myQuickfixClass = quickFixClass;
56     myText = text;
57   }
58
59   @Override
60   @NotNull
61   public String getText() {
62     return InspectionsBundle.message("fix.all.inspection.problems.in.file", myToolWrapper.getDisplayName());
63   }
64
65   @Override
66   @NotNull
67   public String getFamilyName() {
68     return getText();
69   }
70
71   @Override
72   public void invoke(@NotNull final Project project, final Editor editor, final PsiFile file) throws IncorrectOperationException {
73     if (!FileModificationService.getInstance().preparePsiElementForWrite(file)) return;
74     final List<ProblemDescriptor> descriptions =
75       ProgressManager.getInstance().runProcess(new Computable<List<ProblemDescriptor>>() {
76         @Override
77         public List<ProblemDescriptor> compute() {
78           InspectionManager inspectionManager = InspectionManager.getInstance(project);
79           return InspectionEngine.runInspectionOnFile(file, myToolWrapper, inspectionManager.createNewGlobalContext(false));
80         }
81       }, new EmptyProgressIndicator());
82
83     Collections.sort(descriptions, new Comparator<CommonProblemDescriptor>() {
84       @Override
85       public int compare(final CommonProblemDescriptor o1, final CommonProblemDescriptor o2) {
86         final ProblemDescriptorBase d1 = (ProblemDescriptorBase)o1;
87         final ProblemDescriptorBase d2 = (ProblemDescriptorBase)o2;
88         return d2.getTextRange().getStartOffset() - d1.getTextRange().getStartOffset();
89       }
90     });
91     
92     final String templatePresentationText = "Apply Fixes";
93     final SequentialModalProgressTask progressTask =
94       new SequentialModalProgressTask(project, templatePresentationText, false);
95     final PerformFixesTask fixesTask = new PerformFixesTask(project, descriptions.toArray(new CommonProblemDescriptor[descriptions.size()]), progressTask);
96     CommandProcessor.getInstance().executeCommand(project, new Runnable() {
97       @Override
98       public void run() {
99         CommandProcessor.getInstance().markCurrentCommandAsGlobal(project);
100         progressTask.setMinIterationTime(200);
101         progressTask.setTask(fixesTask);
102         ProgressManager.getInstance().run(progressTask);
103       }
104     }, templatePresentationText, null);
105
106     if (!fixesTask.isApplicableFixFound()) {
107       HintManager.getInstance().showErrorHint(editor, "Unfortunately '" + myText + "' is currently not available for batch mode");
108     }
109   }
110
111   @Override
112   public boolean isAvailable(@NotNull final Project project, final Editor editor, final PsiFile file) {
113     return myQuickfixClass != EmptyIntentionAction.class &&
114            !(myToolWrapper instanceof LocalInspectionToolWrapper && ((LocalInspectionToolWrapper)myToolWrapper).isUnfair());
115   }
116
117   @Override
118   public boolean startInWriteAction() {
119     return false;
120   }
121   
122   private class PerformFixesTask extends PerformFixesModalTask {
123     private boolean myApplicableFixFound = false;
124
125     public PerformFixesTask(@NotNull Project project,
126                             @NotNull CommonProblemDescriptor[] descriptors,
127                             @NotNull SequentialModalProgressTask task) {
128       super(project, descriptors, task);
129     }
130
131     @Override
132     protected void applyFix(Project project, CommonProblemDescriptor descriptor) {
133       final QuickFix[] fixes = descriptor.getFixes();
134       if (fixes != null && fixes.length > 0) {
135         for (final QuickFix<CommonProblemDescriptor> fix : fixes) {
136           if (fix != null && fix.getClass().isAssignableFrom(myQuickfixClass)) {
137             final PsiElement element = ((ProblemDescriptor)descriptor).getPsiElement();
138             if (element != null && element.isValid()) {
139               fix.applyFix(project, descriptor);
140               myApplicableFixFound = true;
141             }
142             break;
143           }
144         }
145       }
146     }
147
148     public boolean isApplicableFixFound() {
149       return myApplicableFixFound;
150     }
151   }
152 }