Merge remote-tracking branch 'origin/master'
[idea/community.git] / platform / lang-impl / src / com / intellij / codeInspection / offlineViewer / OfflineInspectionRVContentProvider.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 /*
18  * User: anna
19  * Date: 10-Jan-2007
20  */
21 package com.intellij.codeInspection.offlineViewer;
22
23 import com.intellij.codeInspection.CommonProblemDescriptor;
24 import com.intellij.codeInspection.ex.*;
25 import com.intellij.codeInspection.offline.OfflineProblemDescriptor;
26 import com.intellij.codeInspection.reference.RefElement;
27 import com.intellij.codeInspection.reference.RefEntity;
28 import com.intellij.codeInspection.reference.SmartRefElementPointer;
29 import com.intellij.codeInspection.ui.*;
30 import com.intellij.openapi.project.Project;
31 import com.intellij.openapi.util.Comparing;
32 import com.intellij.util.containers.HashSet;
33 import com.intellij.util.ui.tree.TreeUtil;
34 import org.jetbrains.annotations.NotNull;
35 import org.jetbrains.annotations.Nullable;
36
37 import javax.swing.tree.TreeNode;
38 import javax.swing.tree.TreePath;
39 import java.util.*;
40
41 public class OfflineInspectionRVContentProvider extends InspectionRVContentProvider {
42   private final Map<String, Map<String, Set<OfflineProblemDescriptor>>> myContent;
43
44   public OfflineInspectionRVContentProvider(@NotNull Map<String, Map<String, Set<OfflineProblemDescriptor>>> content,
45                                             @NotNull Project project) {
46     super(project);
47     myContent = content;
48   }
49
50   @Override
51   public boolean checkReportedProblems(@NotNull GlobalInspectionContextImpl context,
52                                        @NotNull final InspectionToolWrapper toolWrapper) {
53     final Map<String, Set<OfflineProblemDescriptor>> content = getFilteredContent(context, toolWrapper);
54     return content != null && !content.values().isEmpty();
55   }
56
57   @Override
58   public Iterable<? extends ScopeToolState> getTools(Tools tools) {
59     return Collections.singletonList(tools.getDefaultState());
60   }
61
62   @Override
63   @Nullable
64   public QuickFixAction[] getQuickFixes(@NotNull final InspectionToolWrapper toolWrapper, @NotNull final InspectionTree tree) {
65     final TreePath[] treePaths = tree.getSelectionPaths();
66     if (treePaths == null) return QuickFixAction.EMPTY; 
67     final List<RefEntity> selectedElements = new ArrayList<RefEntity>();
68     final Map<RefEntity, CommonProblemDescriptor[]> actions = new HashMap<>();
69     for (TreePath selectionPath : treePaths) {
70       TreeUtil.traverseDepth((TreeNode)selectionPath.getLastPathComponent(), node -> {
71         if (!((InspectionTreeNode)node).isValid()) return true;
72         if (node instanceof OfflineProblemDescriptorNode) {
73           if (((OfflineProblemDescriptorNode)node).isQuickFixAppliedFromView()) return true;
74           final OfflineProblemDescriptorNode descriptorNode = (OfflineProblemDescriptorNode)node;
75           final RefEntity element = descriptorNode.getElement();
76           selectedElements.add(element);
77           CommonProblemDescriptor[] descriptors = actions.get(element);
78           final CommonProblemDescriptor descriptor = descriptorNode.getDescriptor();
79           final CommonProblemDescriptor[] descriptorAsArray = descriptor == null ? CommonProblemDescriptor.EMPTY_ARRAY
80                                                                                  : new CommonProblemDescriptor[]{descriptor};
81           actions.put(element, descriptors == null ?
82                                descriptorAsArray :
83                                DefaultInspectionToolPresentation.mergeDescriptors(descriptors, descriptorAsArray));
84         }
85         else if (node instanceof RefElementNode) {
86           selectedElements.add(((RefElementNode)node).getElement());
87         }
88         return true;
89       });
90     }
91
92     if (selectedElements.isEmpty()) return null;
93
94     final RefEntity[] selectedRefElements = selectedElements.toArray(new RefEntity[selectedElements.size()]);
95
96     GlobalInspectionContextImpl context = tree.getContext();
97     InspectionToolPresentation presentation = context.getPresentation(toolWrapper);
98     return presentation.extractActiveFixes(selectedRefElements, actions, tree.getSelectedDescriptors());
99   }
100
101   @Override
102   public boolean isContentLoaded() {
103     return false;
104   }
105
106   @Override
107   public void appendToolNodeContent(@NotNull GlobalInspectionContextImpl context,
108                                     @NotNull final InspectionNode toolNode,
109                                     @NotNull final InspectionTreeNode parentNode,
110                                     final boolean showStructure,
111                                     @NotNull final Map<String, Set<RefEntity>> contents,
112                                     @NotNull final Map<RefEntity, CommonProblemDescriptor[]> problems) {
113     InspectionToolWrapper toolWrapper = toolNode.getToolWrapper();
114     final Map<String, Set<OfflineProblemDescriptor>> filteredContent = getFilteredContent(context, toolWrapper);
115     if (filteredContent != null && !filteredContent.values().isEmpty()) {
116       parentNode.add(toolNode);
117       buildTree(context, filteredContent, false, toolWrapper, OfflineProblemDescriptorContainer::new, showStructure,
118                 (newChild) -> {
119                   toolNode.add(newChild);
120                   return newChild;
121                 });
122     }
123   }
124
125   @Nullable
126   @SuppressWarnings({"UnusedAssignment"})
127   private Map<String, Set<OfflineProblemDescriptor>> getFilteredContent(@NotNull GlobalInspectionContextImpl context,
128                                                                         @NotNull InspectionToolWrapper toolWrapper) {
129     Map<String, Set<OfflineProblemDescriptor>> content = myContent.get(toolWrapper.getShortName());
130     if (content == null) return null;
131     if (context.getUIOptions().FILTER_RESOLVED_ITEMS) {
132       final Map<String, Set<OfflineProblemDescriptor>> current = new HashMap<String, Set<OfflineProblemDescriptor>>(content);
133       content = null; //GC it
134       InspectionToolPresentation presentation = context.getPresentation(toolWrapper);
135       for (RefEntity refEntity : presentation.getIgnoredRefElements()) {
136         if (refEntity instanceof RefElement) {
137           excludeProblem(refEntity.getExternalName(), current);
138         }
139       }
140       return current;
141     }
142     return content;
143   }
144
145   private static void excludeProblem(final String externalName, final Map<String, Set<OfflineProblemDescriptor>> content) {
146     for (Iterator<String> iter = content.keySet().iterator(); iter.hasNext();) {
147       final String packageName = iter.next();
148       final Set<OfflineProblemDescriptor> excluded = new HashSet<OfflineProblemDescriptor>(content.get(packageName));
149       for (Iterator<OfflineProblemDescriptor> it = excluded.iterator(); it.hasNext();) {
150         final OfflineProblemDescriptor ex = it.next();
151         if (Comparing.strEqual(ex.getFQName(), externalName)) {
152           it.remove();
153         }
154       }
155       if (excluded.isEmpty()) {
156         iter.remove();
157       } else {
158         content.put(packageName, excluded);
159       }
160     }
161   }
162
163   @Override
164   protected void appendDescriptor(@NotNull GlobalInspectionContextImpl context,
165                                   @NotNull final InspectionToolWrapper toolWrapper,
166                                   @NotNull final UserObjectContainer container,
167                                   @NotNull final InspectionTreeNode packageNode,
168                                   final boolean canPackageRepeat) {
169     InspectionToolPresentation presentation = context.getPresentation(toolWrapper);
170     final RefElementNode elemNode = addNodeToParent(container, presentation, packageNode);
171     if (toolWrapper instanceof LocalInspectionToolWrapper) {
172       final OfflineProblemDescriptorNode child =
173         OfflineProblemDescriptorNode.create(((OfflineProblemDescriptorContainer)container).getUserObject(),
174                                             (LocalInspectionToolWrapper)toolWrapper, presentation);
175       elemNode.insertByOrder(child, true);
176     }
177   }
178
179
180   private static class OfflineProblemDescriptorContainer implements UserObjectContainer<OfflineProblemDescriptor> {
181     @NotNull
182     private final OfflineProblemDescriptor myDescriptor;
183
184     public OfflineProblemDescriptorContainer(@NotNull OfflineProblemDescriptor descriptor) {
185       myDescriptor = descriptor;
186     }
187
188     @Override
189     @Nullable
190     public OfflineProblemDescriptorContainer getOwner() {
191       final OfflineProblemDescriptor descriptor = myDescriptor.getOwner();
192       if (descriptor != null) {
193         final OfflineProblemDescriptorContainer container = new OfflineProblemDescriptorContainer(descriptor);
194         return container.supportStructure() ? container : null;
195       }
196       return null;
197     }
198
199     @NotNull
200     @Override
201     public RefElementNode createNode(@NotNull InspectionToolPresentation presentation) {
202       return new OfflineRefElementNode(myDescriptor, presentation);
203     }
204
205     @Override
206     @NotNull
207     public OfflineProblemDescriptor getUserObject() {
208       return myDescriptor;
209     }
210
211     @Override
212     public String getModule() {
213       return myDescriptor.getModuleName();
214     }
215
216     @Override
217     public boolean areEqual(final OfflineProblemDescriptor o1, final OfflineProblemDescriptor o2) {
218       if (o1 == null || o2 == null) {
219         return o1 == o2;
220       }
221
222       if (!Comparing.strEqual(o1.getFQName(), o2.getFQName())) return false;
223       if (!Comparing.strEqual(o1.getType(), o2.getType())) return false;
224
225       return true;
226     }
227
228     @Override
229     public boolean supportStructure() {
230       return !Comparing.strEqual(myDescriptor.getType(), SmartRefElementPointer.MODULE) &&
231              !Comparing.strEqual(myDescriptor.getType(), "package") &&
232              !Comparing.strEqual(myDescriptor.getType(), SmartRefElementPointer.PROJECT);
233     }
234   }
235 }