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