ComponentWithBrowseButton - optional remove listener on hide
[fedora-idea.git] / plugins / InspectionGadgets / src / com / siyeh / ig / BaseInspection.java
blobbcff227fce3ff62b72d638835a5724627ad6f11c
1 /*
2 * Copyright 2003-2008 Dave Griffith, Bas Leijdekkers
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
16 package com.siyeh.ig;
18 import com.intellij.codeInsight.daemon.GroupNames;
19 import com.intellij.codeInspection.BaseJavaLocalInspectionTool;
20 import com.intellij.codeInspection.LocalInspectionToolSession;
21 import com.intellij.codeInspection.ProblemsHolder;
22 import com.intellij.openapi.application.Application;
23 import com.intellij.openapi.application.ApplicationManager;
24 import com.intellij.openapi.diagnostic.Logger;
25 import com.intellij.openapi.util.text.StringUtil;
26 import com.intellij.psi.PsiElementVisitor;
27 import com.intellij.ui.DocumentAdapter;
28 import com.siyeh.ig.ui.FormattedTextFieldMacFix;
29 import org.jetbrains.annotations.Nls;
30 import org.jetbrains.annotations.NonNls;
31 import org.jetbrains.annotations.NotNull;
32 import org.jetbrains.annotations.Nullable;
34 import javax.swing.*;
35 import javax.swing.event.DocumentEvent;
36 import javax.swing.text.Document;
37 import java.lang.reflect.Field;
38 import java.lang.reflect.Method;
39 import java.text.NumberFormat;
40 import java.text.ParseException;
41 import java.util.HashMap;
42 import java.util.List;
43 import java.util.Map;
45 public abstract class BaseInspection extends BaseJavaLocalInspectionTool {
47 private static final Logger LOG = Logger.getInstance("#com.siyeh.ig.BaseInspection");
49 private InspectionRunListener listener = null;
50 @NonNls private static final String INSPECTION_GADGETS_COMPONENT_NAME =
51 "InspectionGadgets";
52 @NonNls private static final String INSPECTION = "Inspection";
53 @NonNls private static final Map<String, String> packageGroupDisplayNameMap = new HashMap<String, String>();
54 static {
55 packageGroupDisplayNameMap.put("abstraction", GroupNames.ABSTRACTION_GROUP_NAME);
56 packageGroupDisplayNameMap.put("assignment", GroupNames.ASSIGNMENT_GROUP_NAME);
57 packageGroupDisplayNameMap.put("bitwise", GroupNames.BITWISE_GROUP_NAME);
58 packageGroupDisplayNameMap.put("bugs", GroupNames.BUGS_GROUP_NAME);
59 packageGroupDisplayNameMap.put("classlayout", GroupNames.CLASSLAYOUT_GROUP_NAME);
60 packageGroupDisplayNameMap.put("classmetrics", GroupNames.CLASSMETRICS_GROUP_NAME);
61 packageGroupDisplayNameMap.put("cloneable", GroupNames.CLONEABLE_GROUP_NAME);
62 packageGroupDisplayNameMap.put("controlflow", GroupNames.CONTROL_FLOW_GROUP_NAME);
63 packageGroupDisplayNameMap.put("dataflow", GroupNames.DATA_FLOW_ISSUES);
64 packageGroupDisplayNameMap.put("dependency", GroupNames.DEPENDENCY_GROUP_NAME);
65 packageGroupDisplayNameMap.put("encapsulation", GroupNames.ENCAPSULATION_GROUP_NAME);
66 packageGroupDisplayNameMap.put("errorhandling", GroupNames.ERRORHANDLING_GROUP_NAME);
67 packageGroupDisplayNameMap.put("finalization", GroupNames.FINALIZATION_GROUP_NAME);
68 packageGroupDisplayNameMap.put("imports", GroupNames.IMPORTS_GROUP_NAME);
69 packageGroupDisplayNameMap.put("inheritance", GroupNames.INHERITANCE_GROUP_NAME);
70 packageGroupDisplayNameMap.put("initialization", GroupNames.INITIALIZATION_GROUP_NAME);
71 packageGroupDisplayNameMap.put("internationalization", GroupNames.INTERNATIONALIZATION_GROUP_NAME);
72 packageGroupDisplayNameMap.put("j2me", GroupNames.J2ME_GROUP_NAME);
73 packageGroupDisplayNameMap.put("javabeans", GroupNames.JAVABEANS_GROUP_NAME);
74 packageGroupDisplayNameMap.put("jdk", GroupNames.JDK_GROUP_NAME);
75 packageGroupDisplayNameMap.put("jdk15", GroupNames.JDK15_SPECIFIC_GROUP_NAME);
76 packageGroupDisplayNameMap.put("junit", GroupNames.JUNIT_GROUP_NAME);
77 packageGroupDisplayNameMap.put("logging", GroupNames.LOGGING_GROUP_NAME);
78 packageGroupDisplayNameMap.put("maturity", GroupNames.MATURITY_GROUP_NAME);
79 packageGroupDisplayNameMap.put("memory", GroupNames.MEMORY_GROUP_NAME);
80 packageGroupDisplayNameMap.put("methodmetrics", GroupNames.METHODMETRICS_GROUP_NAME);
81 packageGroupDisplayNameMap.put("modularization", GroupNames.MODULARIZATION_GROUP_NAME);
82 packageGroupDisplayNameMap.put("naming", GroupNames.NAMING_CONVENTIONS_GROUP_NAME);
83 packageGroupDisplayNameMap.put("numeric", GroupNames.NUMERIC_GROUP_NAME);
84 packageGroupDisplayNameMap.put("packaging", GroupNames.PACKAGING_GROUP_NAME);
85 packageGroupDisplayNameMap.put("performance", GroupNames.PERFORMANCE_GROUP_NAME);
86 packageGroupDisplayNameMap.put("portability", GroupNames.PORTABILITY_GROUP_NAME);
87 packageGroupDisplayNameMap.put("resources", GroupNames.RESOURCE_GROUP_NAME);
88 packageGroupDisplayNameMap.put("security", GroupNames.SECURITY_GROUP_NAME);
89 packageGroupDisplayNameMap.put("serialization", GroupNames.SERIALIZATION_GROUP_NAME);
90 packageGroupDisplayNameMap.put("style", GroupNames.STYLE_GROUP_NAME);
91 packageGroupDisplayNameMap.put("threading", GroupNames.THREADING_GROUP_NAME);
92 packageGroupDisplayNameMap.put("visibility", GroupNames.VISIBILITY_GROUP_NAME);
95 private String m_shortName = null;
96 private long timeStamp = -1;
98 @Override @NotNull
99 public final String getShortName() {
100 if (m_shortName == null) {
101 final Class<? extends BaseInspection> aClass = getClass();
102 final String name = aClass.getName();
103 assert name.endsWith(INSPECTION) :
104 "class name must end with 'Inspection' to correctly" +
105 " calculate the short name: " + name;
106 m_shortName = name.substring(name.lastIndexOf((int)'.') + 1,
107 name.length() - INSPECTION.length());
109 return m_shortName;
113 @Override @Nls @NotNull
114 public final String getGroupDisplayName() {
115 final Class<? extends BaseInspection> thisClass = getClass();
116 final Package thisPackage = thisClass.getPackage();
117 assert thisPackage != null : "need package to determine group display name";
118 final String name = thisPackage.getName();
119 assert name != null :
120 "inspection has default package, group display name cannot be determined";
121 final int index = name.lastIndexOf('.');
122 final String key = name.substring(index + 1);
123 final String groupDisplayName = packageGroupDisplayNameMap.get(key);
124 assert groupDisplayName != null : "No display name found for " + key;
125 return groupDisplayName;
128 @NotNull
129 protected abstract String buildErrorString(Object... infos);
131 protected boolean buildQuickFixesOnlyForOnTheFlyErrors() {
132 return false;
135 @Nullable
136 protected InspectionGadgetsFix buildFix(Object... infos) {
137 return null;
140 @NotNull
141 protected InspectionGadgetsFix[] buildFixes(Object... infos) {
142 return InspectionGadgetsFix.EMPTY_ARRAY;
145 public boolean hasQuickFix() {
146 final Class<? extends BaseInspection> aClass = getClass();
147 final Method[] methods = aClass.getDeclaredMethods();
148 for (final Method method : methods) {
149 @NonNls final String methodName = method.getName();
150 if ("buildFix".equals(methodName)) {
151 return true;
154 return false;
157 public abstract BaseInspectionVisitor buildVisitor();
159 @Override @NotNull
160 public PsiElementVisitor buildVisitor(@NotNull ProblemsHolder holder,
161 boolean isOnTheFly) {
162 final BaseInspectionVisitor visitor = buildVisitor();
163 visitor.setProblemsHolder(holder);
164 visitor.setOnTheFly(isOnTheFly);
165 visitor.setInspection(this);
166 return visitor;
170 protected JFormattedTextField prepareNumberEditor(@NonNls String fieldName) {
171 try {
172 final NumberFormat formatter = NumberFormat.getIntegerInstance();
173 formatter.setParseIntegerOnly(true);
174 final JFormattedTextField valueField = new JFormattedTextField(formatter);
175 final Field field = getClass().getField(fieldName);
176 valueField.setValue(field.get(this));
177 valueField.setColumns(4);
178 FormattedTextFieldMacFix.apply(valueField);
179 final Document document = valueField.getDocument();
180 document.addDocumentListener(new DocumentAdapter() {
181 @Override
182 public void textChanged(DocumentEvent evt) {
183 try {
184 valueField.commitEdit();
185 field.set(BaseInspection.this, ((Number) valueField.getValue()).intValue());
186 } catch (IllegalAccessException e) {
187 LOG.error(e);
188 } catch (ParseException e) {
189 // No luck this time. Will update the field when correct value is entered.
193 return valueField;
194 } catch (NoSuchFieldException e) {
195 LOG.error(e);
196 } catch (IllegalAccessException e) {
197 LOG.error(e);
199 return null;
202 protected static void parseString(String string, List<String>... outs){
203 final List<String> strings = StringUtil.split(string, ",");
204 for (List<String> out : outs) {
205 out.clear();
207 for (int i = 0, iMax = strings.size(); i < iMax; i += outs.length) {
208 for (int j = 0; j < outs.length; j++) {
209 final List<String> out = outs[j];
210 if (i + j >= iMax) {
211 out.add("");
212 } else {
213 out.add(strings.get(i + j));
219 protected static String formatString(List<String>... strings){
220 final StringBuilder buffer = new StringBuilder();
221 final int size = strings[0].size();
222 if (size > 0) {
223 formatString(strings, 0, buffer);
224 for (int i = 1; i < size; i++) {
225 buffer.append(',');
226 formatString(strings, i, buffer);
229 return buffer.toString();
232 private static void formatString(List<String>[] strings, int index,
233 StringBuilder out) {
234 out.append(strings[0].get(index));
235 for (int i = 1; i < strings.length; i++) {
236 out.append(',');
237 out.append(strings[i].get(index));
241 private void initializeTelemetryIfNecessary() {
242 if (InspectionGadgetsPlugin.TELEMETRY_ENABLED && listener == null) {
243 final Application application = ApplicationManager.getApplication();
244 final InspectionGadgetsPlugin plugin = (InspectionGadgetsPlugin)
245 application.getComponent(INSPECTION_GADGETS_COMPONENT_NAME);
246 listener = plugin.getTelemetry();
250 @Override
251 public void inspectionStarted(LocalInspectionToolSession session) {
252 super.inspectionStarted(session);
253 if (InspectionGadgetsPlugin.TELEMETRY_ENABLED) {
254 if (timeStamp > 0) {
255 System.out.println("start reported without corresponding finish");
257 initializeTelemetryIfNecessary();
258 timeStamp = System.currentTimeMillis();
262 @Override
263 public void inspectionFinished(LocalInspectionToolSession session) {
264 super.inspectionFinished(session);
265 if (InspectionGadgetsPlugin.TELEMETRY_ENABLED) {
266 if (timeStamp < 0) {
267 System.out.println("finish reported without corresponding start");
268 return;
270 final long end = System.currentTimeMillis();
271 final String displayName = getDisplayName();
272 listener.reportRun(displayName, end - timeStamp);
273 timeStamp = -1;