inspection toolwindow: SuppressActionWrapper empty array cleanup
[idea/community.git] / platform / lang-impl / src / com / intellij / codeInspection / ui / actions / suppress / SuppressActionWrapper.java
1 /*
2  * Copyright 2000-2016 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 /*
18  * User: anna
19  * Date: 29-Jan-2007
20  */
21 package com.intellij.codeInspection.ui.actions.suppress;
22
23 import com.intellij.codeInsight.daemon.HighlightDisplayKey;
24 import com.intellij.codeInspection.InspectionManager;
25 import com.intellij.codeInspection.InspectionsBundle;
26 import com.intellij.codeInspection.SuppressIntentionAction;
27 import com.intellij.codeInspection.ex.GlobalInspectionContextImpl;
28 import com.intellij.codeInspection.ex.InspectionManagerEx;
29 import com.intellij.codeInspection.ex.InspectionToolWrapper;
30 import com.intellij.codeInspection.ui.InspectionResultsView;
31 import com.intellij.codeInspection.ui.InspectionTreeNode;
32 import com.intellij.codeInspection.ui.SuppressableInspectionTreeNode;
33 import com.intellij.codeInspection.ui.actions.KeyAwareInspectionViewAction;
34 import com.intellij.openapi.actionSystem.*;
35 import com.intellij.openapi.application.ApplicationManager;
36 import com.intellij.openapi.command.CommandProcessor;
37 import com.intellij.openapi.diagnostic.Logger;
38 import com.intellij.openapi.progress.ProgressManager;
39 import com.intellij.openapi.project.Project;
40 import com.intellij.util.SequentialModalProgressTask;
41 import com.intellij.util.containers.HashSet;
42 import com.intellij.util.ui.tree.TreeUtil;
43 import org.jetbrains.annotations.NotNull;
44 import org.jetbrains.annotations.Nullable;
45
46 import javax.swing.tree.TreeNode;
47 import javax.swing.tree.TreePath;
48 import java.util.Arrays;
49 import java.util.Collections;
50 import java.util.Comparator;
51 import java.util.Set;
52
53 import static com.intellij.codeInspection.ui.actions.InspectionViewActionBase.getView;
54
55 public class SuppressActionWrapper extends ActionGroup implements CompactActionGroup {
56   private final static Logger LOG = Logger.getInstance(SuppressActionWrapper.class);
57
58   public SuppressActionWrapper() {
59     super(InspectionsBundle.message("suppress.inspection.problem"), false);
60   }
61
62   @Override
63   @NotNull
64   public AnAction[] getChildren(@Nullable final AnActionEvent e) {
65     final InspectionResultsView view = getView(e);
66     if (view == null) return AnAction.EMPTY_ARRAY;
67     final InspectionToolWrapper wrapper = view.getTree().getSelectedToolWrapper();
68     if (wrapper == null) return AnAction.EMPTY_ARRAY;
69     final Set<SuppressIntentionAction> suppressActions = view.getSuppressActions(wrapper);
70
71     if (suppressActions.isEmpty()) return AnAction.EMPTY_ARRAY;
72     final AnAction[] actions = new AnAction[suppressActions.size() + 1];
73
74     int i = 0;
75     for (SuppressIntentionAction action : suppressActions) {
76       actions[i++] = new SuppressTreeAction(action);
77     }
78     actions[suppressActions.size()] = Separator.getInstance();
79
80     Arrays.sort(actions, new Comparator<AnAction>() {
81       @Override
82       public int compare(AnAction a1, AnAction a2) {
83         return getWeight(a1) - getWeight(a2);
84       }
85
86       public int getWeight(AnAction a) {
87         return a instanceof Separator ? 0 : ((SuppressTreeAction)a).isSuppressAll() ? 1 : -1;
88       }
89     });
90     return actions;
91   }
92
93   public static class SuppressTreeAction extends KeyAwareInspectionViewAction {
94     private final SuppressIntentionAction mySuppressAction;
95
96     public SuppressTreeAction(final SuppressIntentionAction suppressAction) {
97       super(suppressAction.getText());
98       mySuppressAction = suppressAction;
99     }
100
101     @Override
102     protected void actionPerformed(@NotNull InspectionResultsView view, @NotNull HighlightDisplayKey key) {
103       ApplicationManager.getApplication().invokeLater(new Runnable() {
104         @Override
105         public void run() {
106           Project project = view.getProject();
107           final String templatePresentationText = getTemplatePresentation().getText();
108           LOG.assertTrue(templatePresentationText != null);
109           final InspectionToolWrapper wrapper = view.getTree().getSelectedToolWrapper();
110           LOG.assertTrue(wrapper != null);
111           final Set<SuppressableInspectionTreeNode> nodesAsSet = getNodesToSuppress(view);
112           final SuppressableInspectionTreeNode[] nodes = nodesAsSet.toArray(new SuppressableInspectionTreeNode[nodesAsSet.size()]);
113           CommandProcessor.getInstance().executeCommand(project, new Runnable() {
114             @Override
115             public void run() {
116               CommandProcessor.getInstance().markCurrentCommandAsGlobal(project);
117               final SequentialModalProgressTask progressTask =
118                 new SequentialModalProgressTask(project, templatePresentationText, true);
119               progressTask.setMinIterationTime(200);
120               progressTask.setTask(new SuppressActionSequentialTask(nodes, mySuppressAction, wrapper, progressTask));
121               ProgressManager.getInstance().run(progressTask);
122             }
123           }, templatePresentationText, null);
124
125           final Set<GlobalInspectionContextImpl> globalInspectionContexts =
126             ((InspectionManagerEx)InspectionManager.getInstance(project)).getRunningContexts();
127           for (GlobalInspectionContextImpl context : globalInspectionContexts) {
128             context.refreshViews();
129           }
130           view.syncRightPanel();
131         }
132       });
133     }
134
135     @Override
136     protected boolean isEnabled(@NotNull InspectionResultsView view) {
137       for (SuppressableInspectionTreeNode node : getNodesToSuppress(view)) {
138         if (node.getAvailableSuppressActions().contains(mySuppressAction)) {
139           return true;
140         }
141       }
142       return false;
143     }
144
145     public boolean isSuppressAll() {
146       return mySuppressAction.isSuppressAll();
147     }
148   }
149
150   private static Set<SuppressableInspectionTreeNode> getNodesToSuppress(@NotNull InspectionResultsView view) {
151     final TreePath[] paths = view.getTree().getSelectionPaths();
152     if (paths == null) return Collections.emptySet();
153     final Set<SuppressableInspectionTreeNode> result = new HashSet<>();
154     for (TreePath path : paths) {
155       final Object node = path.getLastPathComponent();
156       if (!(node instanceof TreeNode)) continue;
157       TreeUtil.traverse((TreeNode)node, new TreeUtil.Traverse() {
158         @Override
159         public boolean accept(final Object node) {    //fetch leaves
160           final InspectionTreeNode n = (InspectionTreeNode)node;
161           if (n instanceof SuppressableInspectionTreeNode &&
162               ((SuppressableInspectionTreeNode)n).canSuppress() &&
163               !((SuppressableInspectionTreeNode)n).isAlreadySuppressedFromView() &&
164               n.isValid()) {
165             result.add((SuppressableInspectionTreeNode)n);
166           }
167           return true;
168         }
169       });
170     }
171     return result;
172   }
173 }