mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
Merge remote-tracking branch 'origin/master'
This commit is contained in:
+5
-4
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2000-2015 JetBrains s.r.o.
|
||||
* Copyright 2000-2016 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -40,6 +40,7 @@ import com.intellij.psi.infos.MethodCandidateInfo;
|
||||
import com.intellij.psi.util.*;
|
||||
import com.intellij.refactoring.util.RefactoringChangeUtil;
|
||||
import com.intellij.ui.ColorUtil;
|
||||
import com.intellij.util.VisibilityUtil;
|
||||
import com.intellij.util.containers.MostlySingularMultiMap;
|
||||
import com.intellij.util.ui.UIUtil;
|
||||
import com.intellij.xml.util.XmlStringUtil;
|
||||
@@ -100,9 +101,9 @@ public class HighlightMethodUtil {
|
||||
int superAccessLevel = PsiUtil.getAccessLevel(superMethod.getModifierList());
|
||||
if (accessLevel < superAccessLevel) {
|
||||
String description = JavaErrorMessages.message("weaker.privileges",
|
||||
createClashMethodMessage(method, superMethod, true),
|
||||
accessModifier,
|
||||
PsiUtil.getAccessModifier(superAccessLevel));
|
||||
createClashMethodMessage(method, superMethod, true),
|
||||
VisibilityUtil.toPresentableText(accessModifier),
|
||||
PsiUtil.getAccessModifier(superAccessLevel));
|
||||
TextRange textRange;
|
||||
if (includeRealPositionInfo) {
|
||||
if (modifierList.hasModifierProperty(PsiModifier.PACKAGE_LOCAL)) {
|
||||
|
||||
+6
-3
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2000-2015 JetBrains s.r.o.
|
||||
* Copyright 2000-2016 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -32,6 +32,7 @@ import com.intellij.psi.util.PsiTreeUtil;
|
||||
import com.intellij.psi.util.PsiUtil;
|
||||
import com.intellij.usageView.UsageInfo;
|
||||
import com.intellij.util.Processor;
|
||||
import com.intellij.util.VisibilityUtil;
|
||||
import com.intellij.util.containers.ContainerUtil;
|
||||
import com.siyeh.ig.fixes.ChangeModifierFix;
|
||||
import com.siyeh.ig.psiutils.MethodUtils;
|
||||
@@ -185,12 +186,14 @@ class AccessCanBeTightenedInspection extends BaseJavaBatchLocalInspectionTool {
|
||||
log(member.getName() + " unused; ignore");
|
||||
return; // do not propose private for unused method
|
||||
}
|
||||
|
||||
int max = maxLevel.get();
|
||||
if (max == PsiUtil.ACCESS_LEVEL_PRIVATE && memberClass == null) {
|
||||
max = suggestPackageLocal(member);
|
||||
}
|
||||
|
||||
log(member.getName()+": effective level is '" + PsiUtil.getAccessModifier(max) + "'");
|
||||
String maxModifier = PsiUtil.getAccessModifier(max);
|
||||
log(member.getName() + ": effective level is '" + maxModifier + "'");
|
||||
|
||||
if (max < currentLevel) {
|
||||
if (max == PsiUtil.ACCESS_LEVEL_PACKAGE_LOCAL && member instanceof PsiClass && childMembersAreUsedOutsideMyPackage.contains(member)) {
|
||||
@@ -205,7 +208,7 @@ class AccessCanBeTightenedInspection extends BaseJavaBatchLocalInspectionTool {
|
||||
}
|
||||
});
|
||||
assert toHighlight != null : member +" ; " + ((PsiNameIdentifierOwner)member).getNameIdentifier() + "; "+ memberModifierList.getText();
|
||||
myHolder.registerProblem(toHighlight, "Access can be "+PsiUtil.getAccessModifier(max), new ChangeModifierFix(PsiUtil.getAccessModifier(max)));
|
||||
myHolder.registerProblem(toHighlight, "Access can be " + VisibilityUtil.toPresentableText(maxModifier), new ChangeModifierFix(maxModifier));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+2
-1
@@ -15,6 +15,7 @@
|
||||
*/
|
||||
package com.intellij.codeInspection.deadCode;
|
||||
|
||||
import com.intellij.codeInspection.CommonProblemDescriptor;
|
||||
import com.intellij.codeInspection.GlobalJavaInspectionContext;
|
||||
import com.intellij.codeInspection.InspectionsBundle;
|
||||
import com.intellij.codeInspection.ex.*;
|
||||
@@ -39,7 +40,7 @@ public class DummyEntryPointsPresentation extends UnusedDeclarationPresentation
|
||||
}
|
||||
|
||||
@Override
|
||||
public QuickFixAction[] getQuickFixes(@NotNull final RefEntity[] refElements) {
|
||||
public QuickFixAction[] getQuickFixes(@NotNull final RefEntity[] refElements, CommonProblemDescriptor[] allowedDescriptors) {
|
||||
if (myQuickFixActions == null) {
|
||||
myQuickFixActions = new QuickFixAction[]{new MoveEntriesToSuspicious(getToolWrapper())};
|
||||
}
|
||||
|
||||
+1
-1
@@ -145,7 +145,7 @@ public class UnusedDeclarationPresentation extends DefaultInspectionToolPresenta
|
||||
}
|
||||
|
||||
@Override
|
||||
public QuickFixAction[] getQuickFixes(@NotNull final RefEntity[] refElements) {
|
||||
public QuickFixAction[] getQuickFixes(@NotNull final RefEntity[] refElements, CommonProblemDescriptor[] allowedDescriptors) {
|
||||
return myQuickFixActions;
|
||||
}
|
||||
|
||||
|
||||
+3
-10
@@ -143,7 +143,7 @@ public class MoveJavaMemberHandler implements MoveMemberHandler {
|
||||
}
|
||||
|
||||
protected static boolean hasMethod(PsiClass targetClass, PsiMethod method) {
|
||||
PsiMethod[] targetClassMethods = targetClass.getMethods();
|
||||
PsiMethod[] targetClassMethods = targetClass.findMethodsByName(method.getName(), true);
|
||||
for (PsiMethod candidate : targetClassMethods) {
|
||||
if (candidate != method &&
|
||||
MethodSignatureUtil.areSignaturesEqual(method.getSignature(PsiSubstitutor.EMPTY),
|
||||
@@ -155,15 +155,8 @@ public class MoveJavaMemberHandler implements MoveMemberHandler {
|
||||
}
|
||||
|
||||
protected static boolean hasField(PsiClass targetClass, PsiField field) {
|
||||
String fieldName = field.getName();
|
||||
PsiField[] targetClassFields = targetClass.getFields();
|
||||
for (PsiField candidate : targetClassFields) {
|
||||
if (candidate != field &&
|
||||
fieldName.equals(candidate.getName())) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
final PsiField fieldByName = targetClass.findFieldByName(field.getName(), true);
|
||||
return fieldByName != null && fieldByName != field;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2000-2015 JetBrains s.r.o.
|
||||
* Copyright 2000-2016 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -24,6 +24,7 @@ import com.intellij.openapi.roots.LanguageLevelProjectExtension;
|
||||
import com.intellij.openapi.util.Comparing;
|
||||
import com.intellij.openapi.util.Key;
|
||||
import com.intellij.openapi.util.TextRange;
|
||||
import com.intellij.openapi.util.text.StringUtil;
|
||||
import com.intellij.openapi.vfs.VfsUtilCore;
|
||||
import com.intellij.openapi.vfs.VirtualFile;
|
||||
import com.intellij.pom.java.LanguageLevel;
|
||||
@@ -123,7 +124,11 @@ public final class PsiUtil extends PsiUtilCore {
|
||||
if (type instanceof PsiCapturedWildcardType) {
|
||||
final PsiType upperBound = ((PsiCapturedWildcardType)type).getUpperBound();
|
||||
if (upperBound instanceof PsiClassType) {
|
||||
String classText = "class I<T extends " + upperBound.getCanonicalText() + "> {}";
|
||||
final PsiClass resolved = ((PsiClassType)upperBound).resolve();
|
||||
final PsiFile containingFile = resolved != null ? resolved.getContainingFile() : null;
|
||||
final String packageName = containingFile instanceof PsiClassOwner ? ((PsiClassOwner)containingFile).getPackageName() : null;
|
||||
String classText = StringUtil.isEmptyOrSpaces(packageName) ? "" : "package " +packageName + ";\n ";
|
||||
classText += "class I<T extends " + upperBound.getCanonicalText() + "> {}";
|
||||
final PsiJavaFile file =
|
||||
(PsiJavaFile)PsiFileFactory.getInstance(expression.getProject()).createFileFromText("inference_dummy.java", JavaLanguage.INSTANCE, classText);
|
||||
final PsiTypeParameter freshParameter = file.getClasses()[0].getTypeParameters()[0];
|
||||
@@ -348,10 +353,11 @@ public final class PsiUtil extends PsiUtilCore {
|
||||
}
|
||||
|
||||
@PsiModifier.ModifierConstant
|
||||
@Nullable
|
||||
@NotNull
|
||||
public static String getAccessModifier(@AccessLevel int accessLevel) {
|
||||
assert accessLevel > 0 && accessLevel <= accessModifiers.length : accessLevel;
|
||||
@SuppressWarnings("UnnecessaryLocalVariable") @PsiModifier.ModifierConstant
|
||||
final String modifier = accessLevel > accessModifiers.length ? null : accessModifiers[accessLevel - 1];
|
||||
final String modifier = accessModifiers[accessLevel - 1];
|
||||
return modifier;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2000-2009 JetBrains s.r.o.
|
||||
* Copyright 2000-2016 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -31,6 +31,7 @@ import com.intellij.psi.util.PsiTreeUtil;
|
||||
import com.intellij.psi.util.PsiUtil;
|
||||
import org.jetbrains.annotations.Nls;
|
||||
import org.jetbrains.annotations.NonNls;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
|
||||
public class VisibilityUtil {
|
||||
@@ -107,7 +108,8 @@ public class VisibilityUtil {
|
||||
}
|
||||
|
||||
@Nls
|
||||
public static String getVisibilityStringToDisplay(PsiMember member) {
|
||||
@NotNull
|
||||
public static String getVisibilityStringToDisplay(@NotNull PsiMember member) {
|
||||
if (member.hasModifierProperty(PsiModifier.PUBLIC)) {
|
||||
return toPresentableText(PsiModifier.PUBLIC);
|
||||
}
|
||||
@@ -120,7 +122,8 @@ public class VisibilityUtil {
|
||||
return toPresentableText(PsiModifier.PACKAGE_LOCAL);
|
||||
}
|
||||
|
||||
public static String toPresentableText(@PsiModifier.ModifierConstant String modifier) {
|
||||
@NotNull
|
||||
public static String toPresentableText(@PsiModifier.ModifierConstant @NotNull String modifier) {
|
||||
return PsiBundle.visibilityPresentation(modifier);
|
||||
}
|
||||
|
||||
|
||||
+2
-1
@@ -150,7 +150,8 @@ public class StrictSubtypingConstraint implements ConstraintFormula {
|
||||
final PsiType tSubstituted = tSubstitutor.substitute(parameter);
|
||||
final PsiType sSubstituted = sSubstitutor.substituteWithBoundsPromotion(parameter);
|
||||
if (tSubstituted == null ^ sSubstituted == null) {
|
||||
return false;
|
||||
session.setErased();
|
||||
return true;
|
||||
}
|
||||
constraints.add(new SubtypingConstraint(tSubstituted, sSubstituted));
|
||||
}
|
||||
|
||||
+1
-1
@@ -75,7 +75,7 @@ public class TypeCompatibilityConstraint implements ConstraintFormula {
|
||||
final PsiClassType.ClassResolveResult sResult = ((PsiClassType)s).resolveGenerics();
|
||||
final PsiClass tClass = tResult.getElement();
|
||||
final PsiClass sClass = sResult.getElement();
|
||||
if (tClass != null && sClass != null) {
|
||||
if (tClass != null && sClass != null && !(sClass instanceof InferenceVariable)) {
|
||||
final PsiSubstitutor sSubstitutor = TypeConversionUtil.getClassSubstitutor(tClass, sClass, sResult.getSubstitutor());
|
||||
if (sSubstitutor != null) {
|
||||
if (PsiUtil.isRawSubstitutor(tClass, sSubstitutor)) {
|
||||
|
||||
+1
-1
@@ -4,7 +4,7 @@ interface i {
|
||||
}
|
||||
|
||||
public class a implements i {
|
||||
void <error descr="'ff()' in 'a' clashes with 'ff()' in 'i'; attempting to assign weaker access privileges ('packageLocal'); was 'public'">ff</error>() {}
|
||||
void <error descr="'ff()' in 'a' clashes with 'ff()' in 'i'; attempting to assign weaker access privileges ('package local'); was 'public'">ff</error>() {}
|
||||
}
|
||||
class ai implements i {
|
||||
public <error descr="'ff()' in 'ai' clashes with 'ff()' in 'i'; attempting to use incompatible return type">int</error> ff() { return 0;}
|
||||
|
||||
+1
-1
@@ -34,7 +34,7 @@ interface i2 {
|
||||
class weak {
|
||||
void f1() {}
|
||||
}
|
||||
<error descr="'f1()' in 'weak' clashes with 'f1()' in 'i'; attempting to assign weaker access privileges ('packageLocal'); was 'public'">class a2 extends weak implements i</error> {
|
||||
<error descr="'f1()' in 'weak' clashes with 'f1()' in 'i'; attempting to assign weaker access privileges ('package local'); was 'public'">class a2 extends weak implements i</error> {
|
||||
}
|
||||
|
||||
class a3 {
|
||||
|
||||
+8
@@ -0,0 +1,8 @@
|
||||
import java.util.Map;
|
||||
|
||||
class Test {
|
||||
void f() {}
|
||||
void m(Map<String, ? extends Test> map, String name) {
|
||||
map.get(name).f();
|
||||
}
|
||||
}
|
||||
+1
-1
@@ -1,5 +1,5 @@
|
||||
class Foo<T extends Enum> {
|
||||
public T bar(Class<? extends T> type, String str) {
|
||||
return Enum.valueOf<error descr="'valueOf(java.lang.Class<T>, java.lang.String)' in 'java.lang.Enum' cannot be applied to '(java.lang.Class<capture<? extends T>>, java.lang.String)'">(type, str)</error>;
|
||||
<error descr="Incompatible types. Found: 'java.lang.Enum', required: 'T'">return Enum.valueOf(type, str);</error>
|
||||
}
|
||||
}
|
||||
+11
@@ -0,0 +1,11 @@
|
||||
abstract class Issue {
|
||||
private void enumUsage(Class<? extends Enum> enumClass) {
|
||||
passEnumClass(enumClass);
|
||||
}
|
||||
|
||||
abstract <E extends Enum<E>> void passEnumClass(Class<E> var1);
|
||||
|
||||
void a(Enum<?> enumValue) {
|
||||
Enum constant = Enum.valueOf(enumValue.getClass(), "name");
|
||||
}
|
||||
}
|
||||
+11
@@ -0,0 +1,11 @@
|
||||
import java.util.List;
|
||||
|
||||
class Test {
|
||||
void m(Class<List> clazz){
|
||||
List<Object[]> data = foo(clazz);
|
||||
}
|
||||
|
||||
public static <T> T foo(Class<? super T> clazz) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
+21
@@ -0,0 +1,21 @@
|
||||
import java.util.List;
|
||||
|
||||
interface FacetId<T extends List> {}
|
||||
|
||||
abstract class One {
|
||||
public abstract <F extends List<C>, C extends One> void findFacetType(FacetId<F> typeId);
|
||||
private void addSubFacet(FacetId<?> underlyingType) {
|
||||
findFacetType(underlyingType);
|
||||
}
|
||||
}
|
||||
|
||||
class Bar<X extends Foo> {}
|
||||
class Foo<C> {}
|
||||
class Main {
|
||||
void foo(Bar<?> a) {
|
||||
m(a);
|
||||
}
|
||||
|
||||
<X extends Foo<C>, C> void m(Bar<X> a) {
|
||||
}
|
||||
}
|
||||
+4
-1
@@ -12,7 +12,10 @@ class Test {
|
||||
SuperFoo<String> ls = foo(<error descr="no instance(s) of type variable(s) exist so that String conforms to Number
|
||||
inference variable R has incompatible bounds:
|
||||
equality constraints: String
|
||||
upper bounds: Object, Number">() -> new Foo<>()</error>);
|
||||
upper bounds: Object, Number
|
||||
inference variable X has incompatible bounds:
|
||||
equality constraints: R
|
||||
upper bounds: Number">() -> new Foo<>()</error>);
|
||||
SuperFoo<Integer> li = foo(() -> new Foo<>());
|
||||
SuperFoo<?> lw = foo(() -> new Foo<>());
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
class One {
|
||||
static boolean truth = true;
|
||||
static void important() {
|
||||
System.out.println(1);
|
||||
}
|
||||
}
|
||||
class A extends One {
|
||||
Two() {
|
||||
important();
|
||||
System.out.println(truth);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
public class B {
|
||||
static boolean truth = false;
|
||||
static void important() {
|
||||
System.out.println(2);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
class One {
|
||||
static boolean truth = true;
|
||||
static void important() {
|
||||
System.out.println(1);
|
||||
}
|
||||
}
|
||||
class A extends One {
|
||||
Two() {
|
||||
important();
|
||||
System.out.println(truth);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
public class B {
|
||||
static boolean truth = false;
|
||||
static void important() {
|
||||
System.out.println(2);
|
||||
}
|
||||
}
|
||||
+4
@@ -966,4 +966,8 @@ public class GenericsHighlighting8Test extends LightDaemonAnalyzerTestCase {
|
||||
public void testCapturedWildcardWithPrimitiveTypesChecks() throws Exception {
|
||||
doTest();
|
||||
}
|
||||
|
||||
public void testCapturedWildcardPackageLocalAccess() throws Exception {
|
||||
doTest();
|
||||
}
|
||||
}
|
||||
|
||||
+12
@@ -379,6 +379,18 @@ public class GraphInferenceHighlightingTest extends LightDaemonAnalyzerTestCase
|
||||
doTest();
|
||||
}
|
||||
|
||||
public void testUncheckedWarningConvertingToInferenceVariable() throws Exception {
|
||||
doTest();
|
||||
}
|
||||
|
||||
public void testUncheckedWarningDuringStrictSubtyping() throws Exception {
|
||||
doTest();
|
||||
}
|
||||
|
||||
public void testIDEA150688() throws Exception {
|
||||
doTest();
|
||||
}
|
||||
|
||||
private void doTest() throws Exception {
|
||||
doTest(false);
|
||||
}
|
||||
|
||||
@@ -154,6 +154,17 @@ public class MoveMembersTest extends MultiFileTestCase {
|
||||
}
|
||||
}
|
||||
|
||||
public void testExistingFieldInSuper() throws Exception {
|
||||
try {
|
||||
doTest("B", "A", 0, 1);
|
||||
fail("conflict expected");
|
||||
}
|
||||
catch (BaseRefactoringProcessor.ConflictsInTestsException e) {
|
||||
assertEquals("Field <b><code>truth</code></b> already exists in the target class.\n" +
|
||||
"Method <b><code>important()</code></b> already exists in the target class.", e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
public void testInnerToInterface() throws Exception {
|
||||
doTest("A", "B", 0);
|
||||
}
|
||||
|
||||
@@ -19,7 +19,6 @@ import com.intellij.JavaTestUtil;
|
||||
import com.intellij.lang.java.JavaLanguage;
|
||||
import com.intellij.openapi.extensions.Extensions;
|
||||
import com.intellij.openapi.fileEditor.FileDocumentManager;
|
||||
import com.intellij.openapi.vfs.VirtualFile;
|
||||
import com.intellij.psi.JavaPsiFacade;
|
||||
import com.intellij.psi.PsiClass;
|
||||
import com.intellij.psi.PsiDocumentManager;
|
||||
@@ -71,9 +70,9 @@ public class RenameMethodMultiTest extends MultiFileTestCase {
|
||||
doTest("p.B", "void method()", "finalMethod");
|
||||
}
|
||||
catch (BaseRefactoringProcessor.ConflictsInTestsException e) {
|
||||
Assert.assertEquals("Renaming method will override final \"method <b><code>A.finalMethod()</code></b>\"\n" +
|
||||
"Method finalMethod() will override \n" +
|
||||
"a method of the base class <b><code>p.A</code></b>", e.getMessage());
|
||||
Assert.assertEquals("Method finalMethod() will override \n" +
|
||||
"a method of the base class <b><code>p.A</code></b>\n" +
|
||||
"Renaming method will override final \"method <b><code>A.finalMethod()</code></b>\"", e.getMessage());
|
||||
return;
|
||||
}
|
||||
fail("Conflicts were not found");
|
||||
|
||||
@@ -18,6 +18,7 @@ package org.jetbrains.jps.incremental;
|
||||
import com.intellij.openapi.util.io.FileUtil;
|
||||
import com.intellij.util.Consumer;
|
||||
import com.intellij.util.SmartList;
|
||||
import com.intellij.util.containers.ContainerUtil;
|
||||
import gnu.trove.THashSet;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
@@ -135,6 +136,7 @@ public final class ModuleBuildTarget extends JVMModuleBuildTarget<JavaSourceRoot
|
||||
Iterable<ExcludedJavaSourceRootProvider> excludedRootProviders = JpsServiceManager.getInstance().getExtensions(ExcludedJavaSourceRootProvider.class);
|
||||
final Set<File> moduleExcludes = new THashSet<File>(FileUtil.FILE_HASHING_STRATEGY);
|
||||
moduleExcludes.addAll(index.getModuleExcludes(myModule));
|
||||
final JpsJavaCompilerConfiguration compilerConfig = JpsJavaExtensionService.getInstance().getOrCreateCompilerConfiguration(myModule.getProject());
|
||||
|
||||
roots_loop:
|
||||
for (JpsTypedModuleSourceRoot<JavaSourceRootProperties> sourceRoot : myModule.getSourceRoots(type)) {
|
||||
@@ -147,8 +149,19 @@ public final class ModuleBuildTarget extends JVMModuleBuildTarget<JavaSourceRoot
|
||||
}
|
||||
}
|
||||
final String packagePrefix = sourceRoot.getProperties().getPackagePrefix();
|
||||
roots.add(new JavaSourceRootDescriptor(sourceRoot.getFile(), this, false, false, packagePrefix,
|
||||
computeRootExcludes(sourceRoot.getFile(), index)));
|
||||
|
||||
// consider annotation processors output for generated sources, if contained under some source root
|
||||
Set<File> excludes = computeRootExcludes(sourceRoot.getFile(), index);
|
||||
final ProcessorConfigProfile profile = compilerConfig.getAnnotationProcessingProfile(myModule);
|
||||
if (profile.isEnabled()) {
|
||||
final File outputDir = ProjectPaths.getAnnotationProcessorGeneratedSourcesOutputDir(myModule, JavaSourceRootType.TEST_SOURCE == sourceRoot.getRootType(), profile);
|
||||
if (outputDir != null && FileUtil.isAncestor(sourceRoot.getFile(), outputDir, true)) {
|
||||
excludes = ContainerUtil.newTroveSet(FileUtil.FILE_HASHING_STRATEGY, excludes);
|
||||
excludes.add(outputDir);
|
||||
}
|
||||
}
|
||||
|
||||
roots.add(new JavaSourceRootDescriptor(sourceRoot.getFile(), this, false, false, packagePrefix, excludes));
|
||||
}
|
||||
return roots;
|
||||
}
|
||||
|
||||
@@ -138,11 +138,18 @@ public class BuildFSState {
|
||||
return false;
|
||||
}
|
||||
final CompileScope scope = context.getScope();
|
||||
final BuildRootIndex rootIndex = context.getProjectDescriptor().getBuildRootIndex();
|
||||
try {
|
||||
delta.lockData();
|
||||
for (Set<File> files : delta.getSourcesToRecompile().values()) {
|
||||
files_loop:
|
||||
for (File file : files) {
|
||||
if ((getEventRegistrationStamp(file) > targetBuildStart || FileSystemUtil.lastModified(file) > targetBuildStart) && scope.isAffected(target, file)) {
|
||||
for (BuildRootDescriptor rd : rootIndex.findAllParentDescriptors(file, context)) {
|
||||
if (rd.isGenerated()) { // do not send notification for generated sources
|
||||
continue files_loop;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -37,3 +37,6 @@ quickfix.add.double.quotes.desc=Wrap with double quotes
|
||||
|
||||
surround.with.object.literal.desc=object literal
|
||||
json.template.context.type=JSON
|
||||
|
||||
#json schema
|
||||
json.schema.add.schema.chooser.title=Select JSON Schema File
|
||||
@@ -2,11 +2,11 @@ package com.jetbrains.jsonSchema;
|
||||
|
||||
import com.intellij.openapi.options.ConfigurationException;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.ui.MessageType;
|
||||
import com.intellij.openapi.ui.NamedConfigurable;
|
||||
import com.intellij.openapi.util.Comparing;
|
||||
import com.intellij.openapi.util.io.FileUtil;
|
||||
import com.intellij.openapi.util.text.StringUtil;
|
||||
import com.intellij.openapi.vfs.VirtualFile;
|
||||
import com.intellij.util.CollectConsumer;
|
||||
import com.jetbrains.jsonSchema.impl.JsonSchemaReader;
|
||||
import org.jetbrains.annotations.Nls;
|
||||
@@ -22,18 +22,18 @@ import java.io.IOException;
|
||||
*/
|
||||
public class JsonSchemaConfigurable extends NamedConfigurable<JsonSchemaMappingsConfigurationBase.SchemaInfo> {
|
||||
private final Project myProject;
|
||||
@NotNull private final VirtualFile myFile;
|
||||
@NotNull private final String mySchemaFilePath;
|
||||
@NotNull private final JsonSchemaMappingsConfigurationBase.SchemaInfo mySchema;
|
||||
@Nullable private final Runnable myTree;
|
||||
private JsonSchemaMappingsView myView;
|
||||
private String myDisplayName;
|
||||
|
||||
public JsonSchemaConfigurable(Project project,
|
||||
@NotNull VirtualFile schemaFile, @NotNull JsonSchemaMappingsConfigurationBase.SchemaInfo schema,
|
||||
@NotNull String schemaFilePath, @NotNull JsonSchemaMappingsConfigurationBase.SchemaInfo schema,
|
||||
@Nullable Runnable updateTree) {
|
||||
super(true, updateTree);
|
||||
myProject = project;
|
||||
myFile = schemaFile;
|
||||
mySchemaFilePath = schemaFilePath;
|
||||
mySchema = schema;
|
||||
myTree = updateTree;
|
||||
myDisplayName = mySchema.getName();
|
||||
@@ -98,27 +98,32 @@ public class JsonSchemaConfigurable extends NamedConfigurable<JsonSchemaMappings
|
||||
private void doValidation() throws ConfigurationException {
|
||||
if (StringUtil.isEmptyOrSpaces(myDisplayName)) throw new ConfigurationException("Schema name is empty");
|
||||
if (StringUtil.isEmptyOrSpaces(myView.getSchemaSubPath())) throw new ConfigurationException("Schema path is empty");
|
||||
if (!Comparing.equal(myView.getSchemaSubPath(), mySchema.getRelativePathToSchema())) {
|
||||
final CollectConsumer<String> collectConsumer = new CollectConsumer<>();
|
||||
final File file = new File(myProject.getBasePath(), myView.getSchemaSubPath());
|
||||
try {
|
||||
if (!JsonSchemaReader.isJsonSchema(FileUtil.loadFile(file), collectConsumer)) {
|
||||
final String message;
|
||||
if (collectConsumer.getResult().isEmpty()) message = "Can not read JSON schema from file (Unknown reason)";
|
||||
else message = "Can not read JSON schema from file: " + StringUtil.join(collectConsumer.getResult(), "; ");
|
||||
throw new ConfigurationException(message);
|
||||
}
|
||||
}
|
||||
catch (IOException e) {
|
||||
throw new ConfigurationException("Can not read JSON schema from file: " + e.getMessage());
|
||||
final CollectConsumer<String> collectConsumer = new CollectConsumer<>();
|
||||
final File file = new File(myProject.getBasePath(), myView.getSchemaSubPath());
|
||||
try {
|
||||
if (!JsonSchemaReader.isJsonSchema(FileUtil.loadFile(file), collectConsumer)) {
|
||||
final String message;
|
||||
if (collectConsumer.getResult().isEmpty()) message = "Can not read JSON schema from file (Unknown reason)";
|
||||
else message = "Can not read JSON schema from file: " + StringUtil.join(collectConsumer.getResult(), "; ");
|
||||
logErrorForUser(message);
|
||||
throw new ConfigurationException(message);
|
||||
}
|
||||
}
|
||||
catch (IOException e) {
|
||||
final String message = "Can not read JSON schema from file: " + e.getMessage();
|
||||
logErrorForUser(message);
|
||||
throw new ConfigurationException(message);
|
||||
}
|
||||
}
|
||||
|
||||
private void logErrorForUser(@NotNull final String error) {
|
||||
JsonSchemaReader.ERRORS_NOTIFICATION.createNotification(error, MessageType.ERROR).notify(myProject);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void reset() {
|
||||
if (myView == null) return;
|
||||
myView.setItems(myFile, mySchema.getPatterns());
|
||||
myView.setItems(mySchemaFilePath, mySchema.getPatterns());
|
||||
setDisplayName(mySchema.getName());
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
package com.jetbrains.jsonSchema;
|
||||
|
||||
import com.intellij.json.JsonBundle;
|
||||
import com.intellij.openapi.Disposable;
|
||||
import com.intellij.openapi.actionSystem.AnAction;
|
||||
import com.intellij.openapi.actionSystem.AnActionEvent;
|
||||
@@ -12,6 +13,7 @@ import com.intellij.openapi.project.DumbAwareAction;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.project.ProjectManager;
|
||||
import com.intellij.openapi.ui.MasterDetailsComponent;
|
||||
import com.intellij.openapi.ui.MessageType;
|
||||
import com.intellij.openapi.ui.Messages;
|
||||
import com.intellij.openapi.util.io.FileUtil;
|
||||
import com.intellij.openapi.util.text.StringUtil;
|
||||
@@ -130,7 +132,8 @@ public class JsonSchemaMappingsConfigurable extends MasterDetailsComponent imple
|
||||
|
||||
private void addProjectSchema() {
|
||||
final VirtualFile file =
|
||||
FileChooser.chooseFile(FileChooserDescriptorFactory.createSingleFileNoJarsDescriptor(), myProject, null);
|
||||
FileChooser.chooseFile(FileChooserDescriptorFactory.createSingleFileNoJarsDescriptor().withTitle(
|
||||
JsonBundle.message("json.schema.add.schema.chooser.title")), myProject, null);
|
||||
if (file != null) {
|
||||
final String relativePath = VfsUtil.getRelativePath(file, myProject.getBaseDir());
|
||||
if (relativePath == null) {
|
||||
@@ -140,6 +143,7 @@ public class JsonSchemaMappingsConfigurable extends MasterDetailsComponent imple
|
||||
final JsonSchemaChecker importer = new JsonSchemaChecker(file, true);
|
||||
if (!importer.checkSchemaFile()) {
|
||||
if (!StringUtil.isEmptyOrSpaces(importer.getError())) {
|
||||
JsonSchemaReader.ERRORS_NOTIFICATION.createNotification(importer.getError(), MessageType.ERROR).notify(myProject);
|
||||
Messages.showErrorDialog(myProject, importer.getError(), READ_JSON_SCHEMA);
|
||||
}
|
||||
return;
|
||||
@@ -194,7 +198,8 @@ public class JsonSchemaMappingsConfigurable extends MasterDetailsComponent imple
|
||||
}*/
|
||||
|
||||
private void addCreatedMappings(@NotNull VirtualFile schemaFile, @NotNull final JsonSchemaMappingsConfigurationBase.SchemaInfo info) {
|
||||
final MyNode node = new MyNode(new JsonSchemaConfigurable(myProject, schemaFile, info, myTreeUpdater), info.isApplicationLevel());
|
||||
final MyNode node = new MyNode(new JsonSchemaConfigurable(myProject, FileUtil.toSystemDependentName(schemaFile.getPath()),
|
||||
info, myTreeUpdater), info.isApplicationLevel());
|
||||
addNode(node, myRoot);
|
||||
selectNodeInTree(node, true);
|
||||
}
|
||||
@@ -206,11 +211,8 @@ public class JsonSchemaMappingsConfigurable extends MasterDetailsComponent imple
|
||||
|
||||
final List<JsonSchemaMappingsConfigurationBase.SchemaInfo> list = getStoredList();
|
||||
for (JsonSchemaMappingsConfigurationBase.SchemaInfo info : list) {
|
||||
final String[] parts = info.getRelativePathToSchema().replace('\\', '/').split("/");
|
||||
final VirtualFile schemaFile = VfsUtil.findRelativeFile(myProject.getBaseDir(), parts);
|
||||
if (schemaFile != null) {
|
||||
myRoot.add(new MyNode(new JsonSchemaConfigurable(myProject, schemaFile, info, myTreeUpdater), info.isApplicationLevel()));
|
||||
}
|
||||
myRoot.add(new MyNode(new JsonSchemaConfigurable(myProject, new File(myProject.getBasePath(), info.getRelativePathToSchema()).getPath(),
|
||||
info, myTreeUpdater), info.isApplicationLevel()));
|
||||
}
|
||||
((DefaultTreeModel) myTree.getModel()).reload(myRoot);
|
||||
if (myRoot.children().hasMoreElements()) {
|
||||
|
||||
@@ -2,9 +2,16 @@ package com.jetbrains.jsonSchema;
|
||||
|
||||
import com.intellij.openapi.components.*;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.util.io.FileUtil;
|
||||
import com.intellij.openapi.vfs.VfsUtil;
|
||||
import com.intellij.openapi.vfs.VirtualFile;
|
||||
import com.intellij.util.xmlb.annotations.Transient;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* @author Irina.Chernushina on 2/2/2016.
|
||||
@@ -17,6 +24,8 @@ import java.io.File;
|
||||
)
|
||||
public class JsonSchemaMappingsProjectConfiguration extends JsonSchemaMappingsConfigurationBase {
|
||||
private Project myProject;
|
||||
@Transient
|
||||
private final Map<VirtualFile, SchemaInfo> mySchemaFiles = new HashMap<>();
|
||||
|
||||
public static JsonSchemaMappingsProjectConfiguration getInstance(@NotNull final Project project) {
|
||||
return ServiceManager.getService(project, JsonSchemaMappingsProjectConfiguration.class);
|
||||
@@ -33,4 +42,48 @@ public class JsonSchemaMappingsProjectConfiguration extends JsonSchemaMappingsCo
|
||||
public File convertToAbsoluteFile(@NotNull String path) {
|
||||
return myProject.getBasePath() == null ? new File(path) : new File(myProject.getBasePath(), path);
|
||||
}
|
||||
|
||||
public boolean isRegisteredSchemaFile(@NotNull VirtualFile file) {
|
||||
return mySchemaFiles.containsKey(file);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setState(@NotNull Map<String, SchemaInfo> state) {
|
||||
super.setState(state);
|
||||
recalculateSchemaFiles();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addSchema(@NotNull SchemaInfo info) {
|
||||
super.addSchema(info);
|
||||
recalculateSchemaFiles();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeSchema(@NotNull SchemaInfo info) {
|
||||
super.removeSchema(info);
|
||||
recalculateSchemaFiles();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void loadState(JsonSchemaMappingsConfigurationBase state) {
|
||||
super.loadState(state);
|
||||
recalculateSchemaFiles();
|
||||
}
|
||||
|
||||
private void recalculateSchemaFiles() {
|
||||
mySchemaFiles.clear();
|
||||
if (myProject == null || myProject.getBaseDir() == null) return;
|
||||
|
||||
for (JsonSchemaMappingsConfigurationBase.SchemaInfo info : myState.values()) {
|
||||
final String pathToSchema = FileUtil.toSystemIndependentName(info.getRelativePathToSchema());
|
||||
final VirtualFile schemaFile = VfsUtil.findRelativeFile(myProject.getBaseDir(), pathToSchema);
|
||||
if (schemaFile != null) mySchemaFiles.put(schemaFile, info);
|
||||
}
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public SchemaInfo getSchemaBySchemaFile(@NotNull final VirtualFile file) {
|
||||
return mySchemaFiles.get(file);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
package com.jetbrains.jsonSchema;
|
||||
|
||||
import com.intellij.json.JsonBundle;
|
||||
import com.intellij.openapi.actionSystem.AnActionEvent;
|
||||
import com.intellij.openapi.actionSystem.CommonShortcuts;
|
||||
import com.intellij.openapi.application.ModalityState;
|
||||
@@ -81,7 +82,7 @@ public class JsonSchemaMappingsView {
|
||||
final JPanel wrapper = new JPanel(new BorderLayout());
|
||||
final JPanel wrapper2 = new JPanel(new BorderLayout());
|
||||
mySchemaField = new TextFieldWithBrowseButton();
|
||||
SwingHelper.installFileCompletionAndBrowseDialog(myProject, mySchemaField, "Select JSON Schema File",
|
||||
SwingHelper.installFileCompletionAndBrowseDialog(myProject, mySchemaField, JsonBundle.message("json.schema.add.schema.chooser.title"),
|
||||
FileChooserDescriptorFactory.createSingleFileDescriptor());
|
||||
attachNavigateToSchema();
|
||||
final JBLabel label = new JBLabel("JSON schema file:");
|
||||
@@ -127,7 +128,7 @@ public class JsonSchemaMappingsView {
|
||||
return items;
|
||||
}
|
||||
|
||||
public void setItems(VirtualFile schemaFile, final List<JsonSchemaMappingsConfigurationBase.Item> data) {
|
||||
public void setItems(String schemaFilePath, final List<JsonSchemaMappingsConfigurationBase.Item> data) {
|
||||
/*final ArrayList<JsonSchemaMappingsConfigurationBase.Item> copy = new ArrayList<JsonSchemaMappingsConfigurationBase.Item>();
|
||||
if (myProject != null && myProject.getBasePath() != null) {
|
||||
for (JsonSchemaMappingsConfigurationBase.Item item : copy) {
|
||||
@@ -141,8 +142,9 @@ public class JsonSchemaMappingsView {
|
||||
} else {
|
||||
copy.addAll(data);
|
||||
}*/
|
||||
mySchemaField.setText(FileUtil.toSystemDependentName(schemaFile.getPath()));
|
||||
myTableView.setModelAndUpdateColumns(new ListTableModel<JsonSchemaMappingsConfigurationBase.Item>(createColumns(), new ArrayList<JsonSchemaMappingsConfigurationBase.Item>(data)));
|
||||
mySchemaField.setText(schemaFilePath);
|
||||
myTableView.setModelAndUpdateColumns(
|
||||
new ListTableModel<JsonSchemaMappingsConfigurationBase.Item>(createColumns(), new ArrayList<JsonSchemaMappingsConfigurationBase.Item>(data)));
|
||||
}
|
||||
|
||||
public String getSchemaSubPath() {
|
||||
|
||||
@@ -0,0 +1,66 @@
|
||||
/*
|
||||
* Copyright 2000-2016 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.jetbrains.jsonSchema;
|
||||
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.vfs.VfsUtil;
|
||||
import com.intellij.openapi.vfs.VirtualFile;
|
||||
import com.intellij.psi.PsiElement;
|
||||
import com.intellij.psi.util.PsiUtilBase;
|
||||
import com.intellij.refactoring.listeners.RefactoringElementListener;
|
||||
import com.intellij.refactoring.listeners.RefactoringElementListenerProvider;
|
||||
import com.intellij.refactoring.listeners.UndoRefactoringElementAdapter;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
/**
|
||||
* @author Irina.Chernushina on 2/17/2016.
|
||||
*/
|
||||
public class JsonSchemaRefactoringListenerProvider implements RefactoringElementListenerProvider {
|
||||
@Nullable
|
||||
@Override
|
||||
public RefactoringElementListener getListener(PsiElement element) {
|
||||
if (element == null) {
|
||||
return null;
|
||||
}
|
||||
VirtualFile fileAtElement = PsiUtilBase.asVirtualFile(element);
|
||||
if (fileAtElement == null) {
|
||||
return null;
|
||||
}
|
||||
Project project = element.getProject();
|
||||
final JsonSchemaMappingsProjectConfiguration configuration = JsonSchemaMappingsProjectConfiguration.getInstance(project);
|
||||
final JsonSchemaMappingsConfigurationBase.SchemaInfo schemaInfo = configuration.getSchemaBySchemaFile(fileAtElement);
|
||||
if (schemaInfo != null && project.getBaseDir() != null) {
|
||||
return new UndoRefactoringElementAdapter() {
|
||||
@Override
|
||||
protected void refactored(@NotNull PsiElement element, @Nullable String oldQualifiedName) {
|
||||
VirtualFile newFile = PsiUtilBase.asVirtualFile(element);
|
||||
if (newFile != null) {
|
||||
final String relativePath = VfsUtil.getRelativePath(newFile, project.getBaseDir());
|
||||
if (relativePath != null) {
|
||||
configuration.removeSchema(schemaInfo);
|
||||
final JsonSchemaMappingsConfigurationBase.SchemaInfo newSchema =
|
||||
new JsonSchemaMappingsConfigurationBase.SchemaInfo(schemaInfo.getName(), relativePath, schemaInfo.isApplicationLevel(),
|
||||
schemaInfo.getPatterns());
|
||||
configuration.addSchema(newSchema);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -18,11 +18,8 @@ package com.jetbrains.jsonSchema.extension;
|
||||
import com.intellij.json.JsonFileType;
|
||||
import com.intellij.openapi.diagnostic.Logger;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.util.io.FileUtil;
|
||||
import com.intellij.openapi.vfs.VfsUtil;
|
||||
import com.intellij.openapi.vfs.VirtualFile;
|
||||
import com.intellij.util.ResourceUtil;
|
||||
import com.jetbrains.jsonSchema.JsonSchemaMappingsConfigurationBase;
|
||||
import com.jetbrains.jsonSchema.JsonSchemaMappingsProjectConfiguration;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
@@ -31,7 +28,6 @@ import java.io.IOException;
|
||||
import java.io.Reader;
|
||||
import java.io.StringReader;
|
||||
import java.net.URL;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* @author Irina.Chernushina on 2/16/2016.
|
||||
@@ -46,15 +42,7 @@ public class JsonSchemaSelfProviderFactory implements JsonSchemaProviderFactory
|
||||
@Override
|
||||
public boolean isAvailable(@NotNull VirtualFile file) {
|
||||
if (project == null || !JsonFileType.INSTANCE.equals(file.getFileType())) return false;
|
||||
final JsonSchemaMappingsProjectConfiguration configuration = JsonSchemaMappingsProjectConfiguration.getInstance(project);
|
||||
final Map<String, JsonSchemaMappingsConfigurationBase.SchemaInfo> map = configuration.getStateMap();
|
||||
for (JsonSchemaMappingsConfigurationBase.SchemaInfo info : map.values()) {
|
||||
final String pathToSchema = FileUtil.toSystemIndependentName(info.getRelativePathToSchema());
|
||||
if (! file.getPath().endsWith(pathToSchema)) continue;
|
||||
final VirtualFile schemaFile = VfsUtil.findRelativeFile(project.getBaseDir(), pathToSchema);
|
||||
if (file.equals(schemaFile)) return true;
|
||||
}
|
||||
return false;
|
||||
return JsonSchemaMappingsProjectConfiguration.getInstance(project).isRegisteredSchemaFile(file);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
|
||||
@@ -4,6 +4,7 @@ import com.google.gson.TypeAdapter;
|
||||
import com.google.gson.stream.JsonReader;
|
||||
import com.google.gson.stream.JsonToken;
|
||||
import com.google.gson.stream.JsonWriter;
|
||||
import com.intellij.notification.NotificationGroup;
|
||||
import com.intellij.util.Consumer;
|
||||
import com.intellij.util.ThrowablePairConsumer;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
@@ -17,6 +18,8 @@ import java.util.*;
|
||||
* @author Irina.Chernushina on 8/27/2015.
|
||||
*/
|
||||
public class JsonSchemaReader {
|
||||
public static final NotificationGroup ERRORS_NOTIFICATION = NotificationGroup.logOnlyGroup("JSON Schema");
|
||||
|
||||
public JsonSchemaObject read(@NotNull final Reader reader) throws IOException {
|
||||
final JsonReader in = new JsonReader(reader);
|
||||
|
||||
|
||||
@@ -180,7 +180,9 @@ public class HighlightDisplayLevel {
|
||||
@Override
|
||||
public void paintIcon(Component c, Graphics g, int x, int y) {
|
||||
g.setColor(getColor());
|
||||
g.fillRect(x + 2, y + 2, 10, 10);
|
||||
int shift = JBUI.scale(2);
|
||||
int size = JBUI.scale(10);
|
||||
g.fillRect(x + shift, y + shift, size, size);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -100,6 +100,10 @@ public abstract class SuppressIntentionAction implements Iconable, IntentionActi
|
||||
*/
|
||||
public abstract boolean isAvailable(@NotNull Project project, Editor editor, @NotNull PsiElement element);
|
||||
|
||||
public boolean isSuppressAll() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private static PsiElement getElement(@NotNull Editor editor, @NotNull PsiFile file) {
|
||||
CaretModel caretModel = editor.getCaretModel();
|
||||
|
||||
@@ -22,4 +22,6 @@ import org.jetbrains.annotations.NotNull;
|
||||
public interface SuppressQuickFix extends LocalQuickFix {
|
||||
SuppressQuickFix[] EMPTY_ARRAY = new SuppressQuickFix[0];
|
||||
boolean isAvailable(@NotNull final Project project, @NotNull final PsiElement context);
|
||||
|
||||
boolean isSuppressAll();
|
||||
}
|
||||
|
||||
@@ -48,6 +48,7 @@ public interface RefEntity extends UserDataHolder {
|
||||
*
|
||||
* @return the list of children.
|
||||
*/
|
||||
@Nullable
|
||||
List<RefEntity> getChildren();
|
||||
|
||||
/**
|
||||
|
||||
+5
@@ -106,6 +106,11 @@ public abstract class AbstractBatchSuppressByNoInspectionCommentFix implements C
|
||||
invoke(project, element);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isSuppressAll() {
|
||||
return SuppressionUtil.ALL.equals(myID);
|
||||
}
|
||||
|
||||
protected final void replaceSuppressionComment(@NotNull final PsiElement comment) {
|
||||
SuppressionUtil.replaceSuppressionComment(comment, myID, myReplaceOtherSuppressionIds, getCommentLanguage(comment));
|
||||
}
|
||||
|
||||
+4
@@ -85,4 +85,8 @@ public class SuppressIntentionActionFromFix extends SuppressIntentionAction {
|
||||
public String getFamilyName() {
|
||||
return myFix.getFamilyName();
|
||||
}
|
||||
|
||||
public boolean isSuppressAll() {
|
||||
return myFix.isSuppressAll();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -203,7 +203,7 @@ class StateMap private constructor(private val names: Array<String>, private val
|
||||
}
|
||||
|
||||
val currentState = states.get(index)
|
||||
LOG.assertTrue(currentState is Element)
|
||||
LOG.assertTrue(currentState is Element, currentState?.let { it.javaClass.name } ?: "null")
|
||||
states.set(index, if (state == null) null else archiveState(state).toByteArray())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -56,7 +56,7 @@ class StateGetter<S : Any, T : Any>(private val component: PersistentStateCompon
|
||||
try {
|
||||
stateAfterLoad = component.state
|
||||
}
|
||||
catch(e: Throwable) {
|
||||
catch (e: Throwable) {
|
||||
LOG.error("Cannot get state after load", e)
|
||||
stateAfterLoad = null
|
||||
}
|
||||
|
||||
@@ -226,7 +226,7 @@ fun save(states: StateMap, rootElementName: String, newLiveStates: Map<String, E
|
||||
return rootElement
|
||||
}
|
||||
|
||||
fun Element.normalizeRootName(): Element {
|
||||
internal fun Element.normalizeRootName(): Element {
|
||||
if (parent != null) {
|
||||
LOG.warn("State element must not have parent ${JDOMUtil.writeElement(this)}")
|
||||
detach()
|
||||
|
||||
@@ -0,0 +1,63 @@
|
||||
/*
|
||||
* Copyright 2000-2016 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.intellij.openapi.editor;
|
||||
|
||||
/**
|
||||
* Allows to suppress stripping spaces from some lines or from entire document when the document is being saved and
|
||||
* "Strip spaces on Save" option is not "None".
|
||||
*
|
||||
* @see StripTrailingSpacesFilterFactory
|
||||
*/
|
||||
public interface StripTrailingSpacesFilter {
|
||||
|
||||
/**
|
||||
* The filter which completely prohibits removing trailing spaces from a document regardless of other filters.
|
||||
*/
|
||||
StripTrailingSpacesFilter NOT_ALLOWED = new StripTrailingSpacesFilter() {
|
||||
@Override
|
||||
public boolean isStripSpacesAllowedForLine(int line) {
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Tells that strip trailing spaces is not currently possible since some conditions are not met for proper document processing.
|
||||
* The filter will force another attempt to strip trailing spaces later regardless of other filters.
|
||||
*/
|
||||
StripTrailingSpacesFilter POSTPONED = new StripTrailingSpacesFilter() {
|
||||
@Override
|
||||
public boolean isStripSpacesAllowedForLine(int line) {
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* The filter which does not put any restrictions on trailing spaces removal. Other filters may be taken into account.
|
||||
*/
|
||||
StripTrailingSpacesFilter ALL_LINES = new StripTrailingSpacesFilter() {
|
||||
@Override
|
||||
public boolean isStripSpacesAllowedForLine(int line) {
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* @param line The document line.
|
||||
* @return True if trailing spaces can be removed from the line, false otherwise.
|
||||
*/
|
||||
boolean isStripSpacesAllowedForLine(int line);
|
||||
|
||||
}
|
||||
+42
@@ -0,0 +1,42 @@
|
||||
/*
|
||||
* Copyright 2000-2016 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.intellij.openapi.editor;
|
||||
|
||||
import com.intellij.openapi.extensions.ExtensionPointName;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
/**
|
||||
* An extension point to create filters which may put restrictions on how trailing spaces will be handled in a document.
|
||||
*/
|
||||
public abstract class StripTrailingSpacesFilterFactory {
|
||||
public static final ExtensionPointName<StripTrailingSpacesFilterFactory> EXTENSION_POINT
|
||||
= new ExtensionPointName<StripTrailingSpacesFilterFactory>("com.intellij.stripTrailingSpacesFilterFactory");
|
||||
|
||||
/**
|
||||
* Creates a filter which may restrict trailing spaces removal.
|
||||
*
|
||||
* @param project The current project or null if there is no project context.
|
||||
* @param document The document to be processed.
|
||||
* @return The filter as defined in {@link StripTrailingSpacesFilter}. The factory may return one of the several predefined filters:
|
||||
* {@link StripTrailingSpacesFilter#NOT_ALLOWED}, {@link StripTrailingSpacesFilter#POSTPONED} or
|
||||
* {@link StripTrailingSpacesFilter#ALL_LINES}. The latter can be returned, for example, if a language-specific logic is not
|
||||
* applicable to the document.
|
||||
*/
|
||||
@NotNull
|
||||
public abstract StripTrailingSpacesFilter createFilter(@Nullable Project project, @NotNull Document document);
|
||||
}
|
||||
@@ -1,53 +0,0 @@
|
||||
/*
|
||||
* Copyright 2000-2016 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.intellij.openapi.editor;
|
||||
|
||||
import com.intellij.openapi.extensions.ExtensionPointName;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* Allows to suppress stripping spaces from some lines when a document is being saved and "Strip spaces on Save" option is not "None".
|
||||
*/
|
||||
public abstract class StripTrailingSpacesLineFilter {
|
||||
public static final ExtensionPointName<StripTrailingSpacesLineFilter> LINE_FILTER_EXTENSION_POINT
|
||||
= new ExtensionPointName<StripTrailingSpacesLineFilter>("com.intellij.stripTrailingSpacesLineFilter");
|
||||
|
||||
/**
|
||||
* Tells if spaces can be stripped from the document. Returns <code>false</code> if trailing spaces should be preserved regardless of
|
||||
* the editor settings and other filters.
|
||||
*
|
||||
* @param project The current project or <code>null</code> if there is no project context.
|
||||
* @param document The document.
|
||||
* @return True if it's OK to strip spaces, false otherwise.
|
||||
*/
|
||||
public abstract boolean isStripSpacesAllowed(@Nullable Project project, @NotNull Document document);
|
||||
|
||||
/**
|
||||
* Processes a document and sets bits to 1 (true) for lines which should remain untouched when trailing spaces are removed.
|
||||
*
|
||||
* @param project The current project or null if there is no project context.
|
||||
* @param document The document to process.
|
||||
* @param disabledLinesBitSet The bit set which can be modified by the <code>apply()</code> method. Each bit index corresponds to a line
|
||||
*
|
||||
* @return True if successful, false if can't be applied now, probably later.
|
||||
*/
|
||||
public abstract boolean apply(@Nullable Project project, @NotNull Document document, @NotNull BitSet disabledLinesBitSet);
|
||||
|
||||
}
|
||||
@@ -51,10 +51,9 @@ import java.beans.PropertyChangeListener;
|
||||
import java.beans.PropertyChangeSupport;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.BitSet;
|
||||
import java.util.List;
|
||||
|
||||
import static com.intellij.openapi.editor.StripTrailingSpacesLineFilter.LINE_FILTER_EXTENSION_POINT;
|
||||
import static com.intellij.openapi.editor.StripTrailingSpacesFilterFactory.EXTENSION_POINT;
|
||||
|
||||
public class DocumentImpl extends UserDataHolderBase implements DocumentEx {
|
||||
private static final Logger LOG = Logger.getInstance("#com.intellij.openapi.editor.impl.DocumentImpl");
|
||||
@@ -199,13 +198,18 @@ public class DocumentImpl extends UserDataHolderBase implements DocumentEx {
|
||||
if (!isStripTrailingSpacesEnabled) {
|
||||
return true;
|
||||
}
|
||||
StripTrailingSpacesLineFilter[] filters = LINE_FILTER_EXTENSION_POINT.getExtensions();
|
||||
for (StripTrailingSpacesLineFilter filter : filters) {
|
||||
if (!filter.isStripSpacesAllowed(project, this)) return true;
|
||||
}
|
||||
BitSet disabledLinesBitSet = new BitSet(getLineCount());
|
||||
for (StripTrailingSpacesLineFilter filter : filters) {
|
||||
if (!filter.apply(project, this, disabledLinesBitSet)) return false;
|
||||
List<StripTrailingSpacesFilter> filters = new ArrayList<StripTrailingSpacesFilter>();
|
||||
for (StripTrailingSpacesFilterFactory filterFactory : EXTENSION_POINT.getExtensions()) {
|
||||
StripTrailingSpacesFilter filter = filterFactory.createFilter(project, this);
|
||||
if (filter == StripTrailingSpacesFilter.NOT_ALLOWED) {
|
||||
return true;
|
||||
}
|
||||
else if (filter == StripTrailingSpacesFilter.POSTPONED) {
|
||||
return false;
|
||||
}
|
||||
else {
|
||||
filters.add(filter);
|
||||
}
|
||||
}
|
||||
|
||||
boolean markAsNeedsStrippingLater = false;
|
||||
@@ -230,7 +234,7 @@ public class DocumentImpl extends UserDataHolderBase implements DocumentEx {
|
||||
lineLoop:
|
||||
for (int line = 0; line < getLineCount(); line++) {
|
||||
LineSet lineSet = getLineSet();
|
||||
if (inChangedLinesOnly && !lineSet.isModified(line) || disabledLinesBitSet.get(line)) continue;
|
||||
if (inChangedLinesOnly && !lineSet.isModified(line) || !canStripSpacesFrom(line, filters)) continue;
|
||||
int whiteSpaceStart = -1;
|
||||
final int lineEnd = lineSet.getLineEnd(line) - lineSet.getSeparatorLength(line);
|
||||
int lineStart = lineSet.getLineStart(line);
|
||||
@@ -288,6 +292,13 @@ public class DocumentImpl extends UserDataHolderBase implements DocumentEx {
|
||||
return markAsNeedsStrippingLater;
|
||||
}
|
||||
|
||||
private static boolean canStripSpacesFrom(int line, @NotNull List<StripTrailingSpacesFilter> filters) {
|
||||
for (StripTrailingSpacesFilter filter : filters) {
|
||||
if (!filter.isStripSpacesAllowedForLine(line)) return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setReadOnly(boolean isReadOnly) {
|
||||
if (myIsReadOnly != isReadOnly) {
|
||||
|
||||
+42
-17
@@ -18,9 +18,11 @@ package com.intellij.openapi.editor.impl;
|
||||
import com.intellij.lang.Language;
|
||||
import com.intellij.lang.LanguageUtil;
|
||||
import com.intellij.openapi.editor.Document;
|
||||
import com.intellij.openapi.editor.StripTrailingSpacesLineFilter;
|
||||
import com.intellij.openapi.editor.StripTrailingSpacesFilter;
|
||||
import com.intellij.openapi.editor.StripTrailingSpacesFilterFactory;
|
||||
import com.intellij.openapi.fileEditor.FileDocumentManager;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.util.TextRange;
|
||||
import com.intellij.openapi.vfs.VirtualFile;
|
||||
import com.intellij.psi.PsiDocumentManager;
|
||||
import com.intellij.psi.PsiFile;
|
||||
@@ -29,28 +31,45 @@ import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.BitSet;
|
||||
|
||||
public abstract class PsiBasedStripTrailingSpacesLineFilter extends StripTrailingSpacesLineFilter {
|
||||
@Override
|
||||
public boolean isStripSpacesAllowed(@Nullable Project project, @NotNull Document document) {
|
||||
return true;
|
||||
public abstract class PsiBasedStripTrailingSpacesFilter implements StripTrailingSpacesFilter {
|
||||
private final @NotNull BitSet myDisabledLinesBitSet;
|
||||
private final @NotNull Document myDocument;
|
||||
|
||||
public abstract static class Factory extends StripTrailingSpacesFilterFactory {
|
||||
@NotNull
|
||||
@Override
|
||||
public final StripTrailingSpacesFilter createFilter(@Nullable Project project, @NotNull Document document) {
|
||||
Language language = getDocumentLanguage(document);
|
||||
if (language != null && isApplicableTo(language)) {
|
||||
PsiFile psiFile = getPsiFile(project, document);
|
||||
if (psiFile != null) {
|
||||
PsiBasedStripTrailingSpacesFilter filter = createFilter(document);
|
||||
filter.process(psiFile);
|
||||
return filter;
|
||||
}
|
||||
return POSTPONED;
|
||||
}
|
||||
return ALL_LINES;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
protected abstract PsiBasedStripTrailingSpacesFilter createFilter(@NotNull Document document);
|
||||
|
||||
protected abstract boolean isApplicableTo(@NotNull Language language);
|
||||
}
|
||||
|
||||
protected PsiBasedStripTrailingSpacesFilter(@NotNull Document document) {
|
||||
myDocument = document;
|
||||
myDisabledLinesBitSet = new BitSet(document.getLineCount());
|
||||
}
|
||||
|
||||
@Override
|
||||
public final boolean apply(@Nullable Project project, @NotNull Document document, @NotNull BitSet disabledLinesBitSet) {
|
||||
Language language = getDocumentLanguage(document);
|
||||
if (language != null && isApplicableTo(language)) {
|
||||
PsiFile psiFile = getPsiFile(project, document);
|
||||
if (psiFile != null) {
|
||||
return apply(document, psiFile, disabledLinesBitSet);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
public boolean isStripSpacesAllowedForLine(int line) {
|
||||
return !myDisabledLinesBitSet.get(line);
|
||||
}
|
||||
|
||||
protected abstract boolean isApplicableTo(@NotNull Language language);
|
||||
|
||||
protected abstract boolean apply(@NotNull Document document, @NotNull PsiFile psiFile, BitSet disabledLinesBitSet);
|
||||
protected abstract void process(@NotNull PsiFile psiFile);
|
||||
|
||||
@Nullable
|
||||
private static Language getDocumentLanguage(@NotNull Document document) {
|
||||
@@ -72,4 +91,10 @@ public abstract class PsiBasedStripTrailingSpacesLineFilter extends StripTrailin
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
protected final void disableRange(@NotNull TextRange range) {
|
||||
int startLine = myDocument.getLineNumber(range.getStartOffset());
|
||||
int endLine = myDocument.getLineNumber(range.getEndOffset());
|
||||
myDisabledLinesBitSet.set(startLine, endLine);
|
||||
}
|
||||
}
|
||||
+54
-53
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2000-2015 JetBrains s.r.o.
|
||||
* Copyright 2000-2016 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -38,9 +38,7 @@ import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.annotations.TestOnly;
|
||||
|
||||
import javax.swing.*;
|
||||
import java.util.Collection;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.*;
|
||||
import java.util.concurrent.Future;
|
||||
import java.util.concurrent.ScheduledFuture;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
@@ -406,66 +404,69 @@ public class CoreProgressManager extends ProgressManager implements Disposable {
|
||||
}
|
||||
|
||||
private void registerIndicatorAndRun(@NotNull ProgressIndicator indicator,
|
||||
@NotNull Thread currentThread,
|
||||
ProgressIndicator oldIndicator,
|
||||
@NotNull Runnable process) {
|
||||
Set<Thread> underIndicator;
|
||||
boolean alreadyUnder;
|
||||
boolean isStandard;
|
||||
@NotNull Thread currentThread,
|
||||
ProgressIndicator oldIndicator,
|
||||
@NotNull Runnable process) {
|
||||
List<Set<Thread>> threadsUnderThisIndicator = new ArrayList<Set<Thread>>();
|
||||
synchronized (threadsUnderIndicator) {
|
||||
underIndicator = threadsUnderIndicator.get(indicator);
|
||||
if (underIndicator == null) {
|
||||
underIndicator = new SmartHashSet<Thread>();
|
||||
threadsUnderIndicator.put(indicator, underIndicator);
|
||||
}
|
||||
alreadyUnder = !underIndicator.add(currentThread);
|
||||
isStandard = indicator instanceof StandardProgressIndicator;
|
||||
if (!isStandard) {
|
||||
nonStandardIndicators.add(indicator);
|
||||
if (myCheckCancelledFuture == null) {
|
||||
myCheckCancelledFuture = startBackgroundIndicatorPing();
|
||||
for (ProgressIndicator thisIndicator = indicator; thisIndicator != null; thisIndicator = thisIndicator instanceof WrappedProgressIndicator ? ((WrappedProgressIndicator)thisIndicator).getOriginalProgressIndicator() : null) {
|
||||
Set<Thread> underIndicator = threadsUnderIndicator.get(thisIndicator);
|
||||
if (underIndicator == null) {
|
||||
underIndicator = new SmartHashSet<Thread>();
|
||||
threadsUnderIndicator.put(thisIndicator, underIndicator);
|
||||
}
|
||||
}
|
||||
boolean alreadyUnder = !underIndicator.add(currentThread);
|
||||
threadsUnderThisIndicator.add(alreadyUnder ? null : underIndicator);
|
||||
|
||||
if (indicator.isCanceled()) {
|
||||
threadsUnderCanceledIndicator.add(currentThread);
|
||||
}
|
||||
else {
|
||||
threadsUnderCanceledIndicator.remove(currentThread);
|
||||
}
|
||||
thereIsProcessUnderCanceledIndicator = !threadsUnderCanceledIndicator.isEmpty();
|
||||
}
|
||||
|
||||
try {
|
||||
if (indicator instanceof WrappedProgressIndicator) {
|
||||
ProgressIndicator wrappee = ((WrappedProgressIndicator)indicator).getOriginalProgressIndicator();
|
||||
if (wrappee == indicator) throw new IllegalArgumentException(indicator + " wraps itself");
|
||||
registerIndicatorAndRun(wrappee, currentThread, oldIndicator, process);
|
||||
}
|
||||
else {
|
||||
process.run();
|
||||
}
|
||||
}
|
||||
finally {
|
||||
synchronized (threadsUnderIndicator) {
|
||||
boolean removed = alreadyUnder || underIndicator.remove(currentThread);
|
||||
if (removed && underIndicator.isEmpty()) {
|
||||
threadsUnderIndicator.remove(indicator);
|
||||
}
|
||||
boolean isStandard = thisIndicator instanceof StandardProgressIndicator;
|
||||
if (!isStandard) {
|
||||
nonStandardIndicators.remove(indicator);
|
||||
if (nonStandardIndicators.isEmpty()) {
|
||||
myCheckCancelledFuture.cancel(true);
|
||||
myCheckCancelledFuture = null;
|
||||
nonStandardIndicators.add(thisIndicator);
|
||||
if (myCheckCancelledFuture == null) {
|
||||
myCheckCancelledFuture = startBackgroundIndicatorPing();
|
||||
}
|
||||
}
|
||||
// by this time oldIndicator may have been canceled
|
||||
if (oldIndicator != null && oldIndicator.isCanceled()) {
|
||||
|
||||
if (thisIndicator.isCanceled()) {
|
||||
threadsUnderCanceledIndicator.add(currentThread);
|
||||
}
|
||||
else {
|
||||
threadsUnderCanceledIndicator.remove(currentThread);
|
||||
}
|
||||
}
|
||||
|
||||
thereIsProcessUnderCanceledIndicator = !threadsUnderCanceledIndicator.isEmpty();
|
||||
}
|
||||
|
||||
try {
|
||||
process.run();
|
||||
}
|
||||
finally {
|
||||
synchronized (threadsUnderIndicator) {
|
||||
ProgressIndicator thisIndicator = null;
|
||||
// order doesn't matter
|
||||
for (int i = 0; i < threadsUnderThisIndicator.size(); i++) {
|
||||
thisIndicator = i == 0 ? indicator : ((WrappedProgressIndicator)thisIndicator).getOriginalProgressIndicator();
|
||||
Set<Thread> underIndicator = threadsUnderThisIndicator.get(i);
|
||||
boolean removed = underIndicator != null && underIndicator.remove(currentThread);
|
||||
if (removed && underIndicator.isEmpty()) {
|
||||
threadsUnderIndicator.remove(thisIndicator);
|
||||
}
|
||||
boolean isStandard = thisIndicator instanceof StandardProgressIndicator;
|
||||
if (!isStandard) {
|
||||
nonStandardIndicators.remove(thisIndicator);
|
||||
if (nonStandardIndicators.isEmpty()) {
|
||||
myCheckCancelledFuture.cancel(true);
|
||||
myCheckCancelledFuture = null;
|
||||
}
|
||||
}
|
||||
// by this time oldIndicator may have been canceled
|
||||
if (oldIndicator != null && oldIndicator.isCanceled()) {
|
||||
threadsUnderCanceledIndicator.add(currentThread);
|
||||
}
|
||||
else {
|
||||
threadsUnderCanceledIndicator.remove(currentThread);
|
||||
}
|
||||
}
|
||||
thereIsProcessUnderCanceledIndicator = !threadsUnderCanceledIndicator.isEmpty();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2000-2015 JetBrains s.r.o.
|
||||
* Copyright 2000-2016 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -43,12 +43,13 @@ public class ProgressWrapper extends AbstractProgressIndicatorBase implements Wr
|
||||
}
|
||||
|
||||
protected ProgressWrapper(@NotNull ProgressIndicator original, boolean checkCanceledForMe) {
|
||||
assert original instanceof StandardProgressIndicator : "Original indicator must be StandardProcessIndicator";
|
||||
myOriginal = original;
|
||||
myCheckCanceledForMe = checkCanceledForMe;
|
||||
nested = 1 + (original instanceof ProgressWrapper ? ((ProgressWrapper)original).nested : -1);
|
||||
if (nested > 50) {
|
||||
LOG.error("Too many wrapped indicators");
|
||||
}
|
||||
//if (nested > 50) {
|
||||
// LOG.error("Too many wrapped indicators");
|
||||
//}
|
||||
ProgressManager.assertNotCircular(original);
|
||||
}
|
||||
|
||||
@@ -60,13 +61,36 @@ public class ProgressWrapper extends AbstractProgressIndicatorBase implements Wr
|
||||
|
||||
@Override
|
||||
public final boolean isCanceled() {
|
||||
return myOriginal.isCanceled() || myCheckCanceledForMe && super.isCanceled();
|
||||
ProgressWrapper current = this;
|
||||
while (true) {
|
||||
if (current.myCheckCanceledForMe && current.isCanceledRaw()) return true;
|
||||
ProgressIndicator original = current.getOriginalProgressIndicator();
|
||||
if (original instanceof ProgressWrapper) {
|
||||
current = (ProgressWrapper)original;
|
||||
}
|
||||
else {
|
||||
return original.isCanceled();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private boolean isCanceledRaw() { return super.isCanceled(); }
|
||||
private void checkCanceledRaw() { super.checkCanceled(); }
|
||||
|
||||
@Override
|
||||
public final void checkCanceled() {
|
||||
myOriginal.checkCanceled();
|
||||
super.checkCanceled();
|
||||
ProgressWrapper current = this;
|
||||
while (true) {
|
||||
current.checkCanceledRaw();
|
||||
ProgressIndicator original = current.getOriginalProgressIndicator();
|
||||
if (original instanceof ProgressWrapper) {
|
||||
current = (ProgressWrapper)original;
|
||||
}
|
||||
else {
|
||||
original.checkCanceled();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -24,6 +24,7 @@ import com.intellij.diff.util.Side;
|
||||
import com.intellij.openapi.progress.ProgressIndicator;
|
||||
import com.intellij.openapi.util.registry.Registry;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
@@ -82,6 +83,9 @@ abstract class ChunkOptimizer<T> {
|
||||
int equalForward = expandForward(myData1, myData2, range1.end1, range1.end2, range1.end1 + count2, range1.end2 + count2);
|
||||
int equalBackward = expandBackward(myData1, myData2, range2.start1 - count1, range2.start2 - count1, range2.start1, range2.start2);
|
||||
|
||||
// nothing to do
|
||||
if (equalForward == 0 && equalBackward == 0) return;
|
||||
|
||||
// merge chunks left [A]B[B] -> [AB]B
|
||||
if (equalForward == count2) {
|
||||
myRanges.remove(myRanges.size() - 1);
|
||||
@@ -223,31 +227,81 @@ abstract class ChunkOptimizer<T> {
|
||||
|
||||
@Override
|
||||
protected int getShift(@NotNull Side touchSide, int equalForward, int equalBackward, @NotNull Range range1, @NotNull Range range2) {
|
||||
Integer shift;
|
||||
|
||||
shift = getUnchangedBoundaryShift(touchSide, equalForward, equalBackward, range1, range2, 0);
|
||||
if (shift != null) return shift;
|
||||
|
||||
shift = getChangedBoundaryShift(touchSide, equalForward, equalBackward, range1, range2, 0);
|
||||
if (shift != null) return shift;
|
||||
|
||||
shift = getUnchangedBoundaryShift(touchSide, equalForward, equalBackward, range1, range2, myThreshold);
|
||||
if (shift != null) return shift;
|
||||
|
||||
shift = getChangedBoundaryShift(touchSide, equalForward, equalBackward, range1, range2, myThreshold);
|
||||
if (shift != null) return shift;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* search for an empty line boundary in unchanged lines
|
||||
* ie: we want insertion/deletion to go right before/after of an empty line
|
||||
*/
|
||||
@Nullable
|
||||
private Integer getUnchangedBoundaryShift(@NotNull Side touchSide,
|
||||
int equalForward, int equalBackward,
|
||||
@NotNull Range range1, @NotNull Range range2,
|
||||
int threshold) {
|
||||
List<Line> touchLines = touchSide.select(myData1, myData2);
|
||||
int touchStart = touchSide.select(range2.start1, range2.start2);
|
||||
|
||||
int shiftForward = findUnimportantLineShift(touchLines, touchStart, equalForward, true, 0);
|
||||
int shiftBackward = findUnimportantLineShift(touchLines, touchStart - 1, equalBackward, false, 0);
|
||||
int shiftForward = findNextUnimportantLine(touchLines, touchStart, equalForward + 1, threshold);
|
||||
int shiftBackward = findPrevUnimportantLine(touchLines, touchStart - 1, equalBackward + 1, threshold);
|
||||
|
||||
if (shiftForward == -1 && shiftBackward == -1 && myThreshold != 0) {
|
||||
shiftForward = findUnimportantLineShift(touchLines, touchStart, equalForward, true, myThreshold);
|
||||
shiftBackward = findUnimportantLineShift(touchLines, touchStart - 1, equalBackward, false, myThreshold);
|
||||
}
|
||||
|
||||
if (shiftForward == 0 || shiftBackward == 0) return 0;
|
||||
if (shiftForward == -1 && shiftBackward == -1) return 0;
|
||||
|
||||
return shiftForward != -1 ? shiftForward : -shiftBackward;
|
||||
return getShift(shiftForward, shiftBackward);
|
||||
}
|
||||
|
||||
private static int findUnimportantLineShift(@NotNull List<Line> lines, int offset, int count, boolean leftToRight, int threshold) {
|
||||
/**
|
||||
* search for an empty line boundary in changed lines
|
||||
* ie: we want insertion/deletion to start/end with an empty line
|
||||
*/
|
||||
@Nullable
|
||||
private Integer getChangedBoundaryShift(@NotNull Side touchSide,
|
||||
int equalForward, int equalBackward,
|
||||
@NotNull Range range1, @NotNull Range range2,
|
||||
int threshold) {
|
||||
Side nonTouchSide = touchSide.other();
|
||||
List<Line> nonTouchLines = nonTouchSide.select(myData1, myData2);
|
||||
int changeStart = nonTouchSide.select(range1.end1, range1.end2);
|
||||
int changeEnd = nonTouchSide.select(range2.start1, range2.start2);
|
||||
|
||||
int shiftForward = findNextUnimportantLine(nonTouchLines, changeStart, equalForward + 1, threshold);
|
||||
int shiftBackward = findPrevUnimportantLine(nonTouchLines, changeEnd - 1, equalBackward + 1, threshold);
|
||||
|
||||
return getShift(shiftForward, shiftBackward);
|
||||
}
|
||||
|
||||
private static int findNextUnimportantLine(@NotNull List<Line> lines, int offset, int count, int threshold) {
|
||||
for (int i = 0; i < count; i++) {
|
||||
int index = leftToRight ? offset + i : offset - i;
|
||||
if (lines.get(index).getNonSpaceChars() <= threshold) {
|
||||
return i;
|
||||
}
|
||||
if (lines.get(offset + i).getNonSpaceChars() <= threshold) return i;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
private static int findPrevUnimportantLine(@NotNull List<Line> lines, int offset, int count, int threshold) {
|
||||
for (int i = 0; i < count; i++) {
|
||||
if (lines.get(offset - i).getNonSpaceChars() <= threshold) return i;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private static Integer getShift(int shiftForward, int shiftBackward) {
|
||||
if (shiftForward == -1 && shiftBackward == -1) return null;
|
||||
if (shiftForward == 0 || shiftBackward == 0) return 0;
|
||||
|
||||
return shiftForward != -1 ? shiftForward : -shiftBackward;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -100,10 +100,6 @@ abstract class DiffTestCase : UsefulTestCase() {
|
||||
|
||||
fun parseSource(string: CharSequence): String = string.toString().replace('_', '\n')
|
||||
|
||||
fun parseMatching(before: String, after: String): Couple<BitSet> {
|
||||
return Couple.of(parseMatching(before), parseMatching(after))
|
||||
}
|
||||
|
||||
fun parseMatching(matching: String): BitSet {
|
||||
val set = BitSet()
|
||||
matching.filterNot { it == '.' }.forEachIndexed { i, c -> if (c != ' ') set.set(i) }
|
||||
|
||||
@@ -25,9 +25,10 @@ import com.intellij.util.containers.ContainerUtil
|
||||
import java.util.*
|
||||
|
||||
abstract class ComparisonUtilTestBase : DiffTestCase() {
|
||||
private fun doLineTest(before: Document, after: Document, expected: List<Change>?, policy: ComparisonPolicy) {
|
||||
private fun doLineTest(before: Document, after: Document, matchings: Couple<BitSet>?, expected: List<Change>?, policy: ComparisonPolicy) {
|
||||
val fragments = MANAGER.compareLines(before.charsSequence, after.charsSequence, policy, INDICATOR)
|
||||
checkConsistency(fragments, before, after)
|
||||
if (matchings != null) checkLineMatching(fragments, matchings)
|
||||
if (expected != null) checkLineChanges(fragments, expected)
|
||||
}
|
||||
|
||||
@@ -111,6 +112,18 @@ abstract class ComparisonUtilTestBase : DiffTestCase() {
|
||||
assertOrderedEquals(changes, expected)
|
||||
}
|
||||
|
||||
private fun checkLineMatching(fragments: List<LineFragment>, matchings: Couple<BitSet>) {
|
||||
val set1 = BitSet()
|
||||
val set2 = BitSet()
|
||||
for (fragment in fragments) {
|
||||
set1.set(fragment.startLine1, fragment.endLine1)
|
||||
set2.set(fragment.startLine2, fragment.endLine2)
|
||||
}
|
||||
|
||||
assertEquals(matchings.first, set1)
|
||||
assertEquals(matchings.second, set2)
|
||||
}
|
||||
|
||||
private fun checkDiffMatching(fragments: List<DiffFragment>, matchings: Couple<BitSet>) {
|
||||
val set1 = BitSet()
|
||||
val set2 = BitSet()
|
||||
@@ -201,7 +214,7 @@ abstract class ComparisonUtilTestBase : DiffTestCase() {
|
||||
assertTrue(change != null || matchings != null)
|
||||
|
||||
when (type) {
|
||||
TestType.LINE -> doLineTest(before!!, after!!, change, policy)
|
||||
TestType.LINE -> doLineTest(before!!, after!!, matchings, change, policy)
|
||||
TestType.WORD -> doWordTest(before!!, after!!, matchings, change, policy)
|
||||
TestType.CHAR -> doCharTest(before!!, after!!, matchings, change, policy)
|
||||
TestType.SPLITTER -> {
|
||||
@@ -267,6 +280,47 @@ abstract class ComparisonUtilTestBase : DiffTestCase() {
|
||||
fun ignore() {
|
||||
ignoreMatching = parseMatching(before, after)
|
||||
}
|
||||
|
||||
private fun parseMatching(before: String, after: String): Couple<BitSet> {
|
||||
if (type == TestType.LINE) {
|
||||
val builder = this@TestBuilder
|
||||
return Couple.of(parseLineMatching(before, builder.before!!), parseLineMatching(after, builder.after!!))
|
||||
}
|
||||
else {
|
||||
return Couple.of(parseMatching(before), parseMatching(after))
|
||||
}
|
||||
}
|
||||
|
||||
fun parseLineMatching(matching: String, document: Document): BitSet {
|
||||
assertEquals(matching.length, document.textLength)
|
||||
|
||||
val lines1 = matching.split('_', '*')
|
||||
val lines2 = document.charsSequence.split('\n')
|
||||
assertEquals(lines1.size, lines2.size)
|
||||
for (i in 0..lines1.size - 1) {
|
||||
assertEquals(lines1[i].length, lines2[i].length, "line $i")
|
||||
}
|
||||
|
||||
|
||||
val set = BitSet()
|
||||
|
||||
var index = 0
|
||||
var lineNumber = 0
|
||||
while (index < matching.length) {
|
||||
var end = matching.indexOfAny(listOf("_", "*"), index) + 1
|
||||
if (end == 0) end = matching.length
|
||||
|
||||
val line = matching.subSequence(index, end)
|
||||
if (line.find { it != ' ' && it != '_' } != null) {
|
||||
assert(!line.contains(' '))
|
||||
set.set(lineNumber)
|
||||
}
|
||||
lineNumber++
|
||||
index = end
|
||||
}
|
||||
|
||||
return set
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -257,7 +257,7 @@ class LineComparisonUtilTest : ComparisonUtilTestBase() {
|
||||
fun `test regression - shifted similar lines should be matched as a single change, not insertion-deletion`() {
|
||||
lines {
|
||||
(" X_ X" - " X_ X")
|
||||
default(mod(0, 0, 2, 2))
|
||||
("--_---" - "---_----").default()
|
||||
testDefault()
|
||||
}
|
||||
}
|
||||
@@ -265,19 +265,59 @@ class LineComparisonUtilTest : ComparisonUtilTestBase() {
|
||||
fun `test prefer chunks bounded by empty line`() {
|
||||
lines {
|
||||
("A_B_o_o_Y_Z_ _A_B_z_z_Y_Z" - "A_B_o_o_Y_Z_ _A_B_u_u_Y_Z_ _A_B_z_z_Y_Z")
|
||||
default(ins(7, 7, 7))
|
||||
(" _ _ _ _ _ _ _ _ _ _ _ _ " - " _ _ _ _ _ _ _-_-_-_-_-_-_-_ _ _ _ _ _ ").default()
|
||||
testAll()
|
||||
}
|
||||
|
||||
lines {
|
||||
("A_B_o_o_Y_Z_ _A_B_ _ _Y_Z" - "A_B_o_o_Y_Z_ _A_B_u_u_Y_Z_ _A_B_ _ _Y_Z")
|
||||
(" _ _ _ _ _ _ _ _ _ _ _ _ " - " _ _ _ _ _ _ _ _ _-_-_-_-_-_-_-_ _ _ _ ").default()
|
||||
testAll()
|
||||
}
|
||||
|
||||
lines {
|
||||
("A_B_o_o_ _A_B_z_z" - "A_B_o_o_ _A_B_u_u_ _A_B_z_z")
|
||||
default(ins(5, 5, 5))
|
||||
(" _ _ _ _ _ _ _ _ " - " _ _ _ _ _-_-_-_-_-_ _ _ _ ").default()
|
||||
testAll()
|
||||
}
|
||||
|
||||
lines {
|
||||
("o_o_Y_Z_ _z_z_Y_Z" - "o_o_Y_Z_ _u_u_Y_Z_ _z_z_Y_Z")
|
||||
default(ins(5, 5, 5))
|
||||
(" _ _ _ _ _ _ _ _ " - " _ _ _ _ _-_-_-_-_-_ _ _ _ ").default()
|
||||
testAll()
|
||||
}
|
||||
}
|
||||
|
||||
fun `test prefer chunks bounded by short line`() {
|
||||
lines {
|
||||
("A====_B====_o====_o====_Y====_Z====_!_A====_B====_z====_z====_Y====_Z====" -
|
||||
"A====_B====_o====_o====_Y====_Z====_!_A====_B====_u====_u====_Y====_Z====_!_A====_B====_z====_z====_Y====_Z====")
|
||||
(" _ _ _ _ _ _ _ _ _ _ _ _ " -
|
||||
" _ _ _ _ _ _ _-----_-----_-----_-----_-----_-----_-_ _ _ _ _ _ ").default()
|
||||
testAll()
|
||||
}
|
||||
|
||||
lines {
|
||||
("A====_B====_o====_o====_Y====_Z====_ _A====_B====_!_!_Y====_Z====" -
|
||||
"A====_B====_o====_o====_Y====_Z====_ _A====_B====_u====_u====_Y====_Z====_ _A====_B====_!_!_Y====_Z====")
|
||||
(" _ _ _ _ _ _ _ _ _ _ _ _ " -
|
||||
" _ _ _ _ _ _ _-----_-----_-----_-----_-----_-----_-_ _ _ _ _ _ ").default()
|
||||
testAll()
|
||||
}
|
||||
|
||||
lines {
|
||||
("A====_B====_o====_o====_Y====_Z====_!_A====_B====_ _ _Y====_Z====" -
|
||||
"A====_B====_o====_o====_Y====_Z====_!_A====_B====_u====_u====_Y====_Z====_!_A====_B====_ _ _Y====_Z====")
|
||||
(" _ _ _ _ _ _ _ _ _ _ _ _ " -
|
||||
" _ _ _ _ _ _ _ _ _-----_-----_-----_-----_-_-----_-----_ _ _ _ ").default()
|
||||
testAll()
|
||||
}
|
||||
}
|
||||
|
||||
fun `test prefer chunks bounded by empty line - using inserted content`() {
|
||||
lines {
|
||||
("e_x_A_B_z" - "x_A_B_ _q_A_B_z")
|
||||
("-_ _ _ _ " - " _ _ _-_-_-_-_ ").default()
|
||||
testAll()
|
||||
}
|
||||
}
|
||||
@@ -285,12 +325,13 @@ class LineComparisonUtilTest : ComparisonUtilTestBase() {
|
||||
fun `test prefer smaller amount of chunks`() {
|
||||
lines() {
|
||||
("X_A_X_Y_" - "X_Y_")
|
||||
default(del(0, 0, 2))
|
||||
("-_-_ _ _" - " _ _").default()
|
||||
testAll()
|
||||
}
|
||||
|
||||
lines() {
|
||||
(" __x___y" - "__y")
|
||||
("-**-*__ " - "__ ").default()
|
||||
default(del(0, 0, 3))
|
||||
testAll()
|
||||
}
|
||||
@@ -298,7 +339,8 @@ class LineComparisonUtilTest : ComparisonUtilTestBase() {
|
||||
lines {
|
||||
("U======_X======_Y======_z======_X======_Y======_X======_U======_X======_z======" -
|
||||
"U======_Y======_X======_U======_X======")
|
||||
default(del(1, 1, 4), del(9, 5, 1))
|
||||
(" _-------_-------_-------_-------_ _ _ _ _-------" -
|
||||
" _ _ _ _ ").default()
|
||||
testAll()
|
||||
}
|
||||
}
|
||||
@@ -306,7 +348,7 @@ class LineComparisonUtilTest : ComparisonUtilTestBase() {
|
||||
fun `test regression - can trim chunks after 'compareTwoSteps'`() {
|
||||
lines {
|
||||
("q__7_ 6_ 7" - "_7")
|
||||
default(del(0, 0, 1), del(3, 2, 2))
|
||||
("-*_ _--*--" - "_ ").default()
|
||||
testDefault()
|
||||
}
|
||||
}
|
||||
@@ -314,7 +356,7 @@ class LineComparisonUtilTest : ComparisonUtilTestBase() {
|
||||
fun `test regression - can trim chunks after 'optimizeLineChunks'`() {
|
||||
lines {
|
||||
("A=====_ B=====_ }_}_B=====_" - "A=====_ }_}_B=====_")
|
||||
default(del(1, 1, 1))
|
||||
(" _-------_ _ _ _" - " _ _ _ _").default()
|
||||
testAll()
|
||||
}
|
||||
}
|
||||
@@ -322,26 +364,26 @@ class LineComparisonUtilTest : ComparisonUtilTestBase() {
|
||||
fun `test bad cases caused by 'compareTwoStep' logic`() {
|
||||
lines {
|
||||
("x_!" - "!_x_y")
|
||||
default(del(0, 0, 1), ins(2, 1, 2))
|
||||
("-_ " - " _-_-").default()
|
||||
testAll()
|
||||
}
|
||||
|
||||
lines {
|
||||
("!_x_y" - "x_!")
|
||||
default(del(0, 0, 1), mod(2, 1, 1, 1))
|
||||
("-_ _-" - " _-").default()
|
||||
testAll()
|
||||
}
|
||||
|
||||
lines {
|
||||
("x_! " - "!_x_y")
|
||||
default(mod(0, 0, 2, 3))
|
||||
trim(del(0, 0, 1), ins(2, 1, 2))
|
||||
("-_--" - "-_-_-").default()
|
||||
("-_ " - " _-_-").trim()
|
||||
testAll()
|
||||
}
|
||||
|
||||
lines {
|
||||
("!_x_y" - "x_! ")
|
||||
default(del(0, 0, 1), mod(2, 1, 1, 1))
|
||||
("-_ _-" - " _--").default()
|
||||
testAll()
|
||||
}
|
||||
|
||||
@@ -356,16 +398,16 @@ class LineComparisonUtilTest : ComparisonUtilTestBase() {
|
||||
fun `test bad cases caused by 'compareSmart' logic`() {
|
||||
lines {
|
||||
("A=====_ B=====_ }_}_B=====" - "A=====_ }_}_B=====")
|
||||
// TODO trim(del(1, 1, 1))
|
||||
default(del(1, 1, 1))
|
||||
trim(ins(1, 1, 2), del(2, 4, 3))
|
||||
// TODO (" _-------_ _ _ " - " _ _ _ ").trim()
|
||||
(" _-------_ _ _ " - " _ _ _ ").default()
|
||||
(" _ _--_-_------" - " _--_-_ ").trim()
|
||||
testAll()
|
||||
}
|
||||
|
||||
lines {
|
||||
("A=====_ B=====_X_ }_}_Z_B=====_" - "A=====_ }_}_B=====_")
|
||||
// TODO default(del(1, 1, 2), del(5, 3, 1))
|
||||
default(mod(1, 1, 5, 2))
|
||||
// TODO (" _-------_-_ _ _-_ _" - " _ _ _ _").default()
|
||||
(" _-------_-_--_-_-_ _" - " _--_-_ _").default()
|
||||
testAll()
|
||||
}
|
||||
}
|
||||
@@ -373,17 +415,16 @@ class LineComparisonUtilTest : ComparisonUtilTestBase() {
|
||||
fun `test trim changed blocks after second step correction`() {
|
||||
lines() {
|
||||
("====}_==== }_Y_====}" - "====}_Y_====}")
|
||||
default(del(1, 1, 1)) // result after second step correction
|
||||
ignore(mod(1, 1, 2, 1)) // result looks strange because of 'diff.unimportant.line.char.count'
|
||||
testDefault()
|
||||
testTrim()
|
||||
(" _------_ _ " - " _ _ ").default() // result after second step correction
|
||||
(" _ _-_-----" - " _-_ ").ignore() // result looks strange because of 'diff.unimportant.line.char.count'
|
||||
testAll()
|
||||
}
|
||||
}
|
||||
|
||||
fun `test second step correction processes all confusing lines`() {
|
||||
lines {
|
||||
("====}_==== }_Y_==== }_====}" - "==== }_Y_==== }")
|
||||
default(del(0, 0, 1), del(4, 3, 1))
|
||||
("-----_ _ _ _-----" - " _ _ ").default()
|
||||
testDefault()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -916,7 +916,7 @@ public class CommonCodeStyleSettings {
|
||||
public int WRAP_ON_TYPING = WrapOnTyping.DEFAULT.intValue;
|
||||
|
||||
//-------------------------Indent options-------------------------------------------------
|
||||
public static class IndentOptions implements Cloneable {
|
||||
public static class IndentOptions implements Cloneable, JDOMExternalizable {
|
||||
public int INDENT_SIZE = 4;
|
||||
public int CONTINUATION_INDENT_SIZE = 8;
|
||||
public int TAB_SIZE = 4;
|
||||
@@ -931,10 +931,12 @@ public class CommonCodeStyleSettings {
|
||||
private static final Key<CommonCodeStyleSettings.IndentOptions> INDENT_OPTIONS_KEY = Key.create("INDENT_OPTIONS_KEY");
|
||||
private boolean myInaccurate;
|
||||
|
||||
@Override
|
||||
public void readExternal(Element element) throws InvalidDataException {
|
||||
DefaultJDOMExternalizer.readExternal(this, element);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeExternal(Element element) throws WriteExternalException {
|
||||
DefaultJDOMExternalizer.writeExternal(this, element, field -> {
|
||||
if ("KEEP_INDENTS_ON_EMPTY_LINES".equals(field.getName())) {
|
||||
|
||||
@@ -50,7 +50,7 @@ public class AnalysisUIOptions implements PersistentStateComponent<AnalysisUIOpt
|
||||
public boolean SHOW_ONLY_DIFF = false;
|
||||
public boolean SHOW_STRUCTURE = false;
|
||||
|
||||
public boolean ANALYSIS_IN_BACKGROUND = false;
|
||||
public boolean ANALYSIS_IN_BACKGROUND = true;
|
||||
|
||||
public AnalysisUIOptions() {
|
||||
myAutoScrollToSourceHandler = new AutoScrollToSourceHandler() {
|
||||
|
||||
+5
-1
@@ -377,9 +377,13 @@ public class IntentionListStep implements ListPopupStep<IntentionActionWithTextC
|
||||
if (myCachedGutters.contains(action)) {
|
||||
return 5;
|
||||
}
|
||||
if (action.getAction() instanceof EmptyIntentionAction) {
|
||||
final IntentionAction underlyingAction = action.getAction();
|
||||
if (underlyingAction instanceof EmptyIntentionAction) {
|
||||
return -10;
|
||||
}
|
||||
if (underlyingAction instanceof SuppressIntentionActionFromFix && ((SuppressIntentionActionFromFix)underlyingAction).isSuppressAll()) {
|
||||
return -15;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
+1
-1
@@ -80,7 +80,7 @@ public class IntentionDescriptionPanel {
|
||||
}
|
||||
}
|
||||
|
||||
// TODO 134099: see SingleInspectionProfilePanel#toHTML
|
||||
// TODO 134099: see SingleInspectionProfilePanel#setHTML
|
||||
private String toHTML(String text) {
|
||||
final HintHint hintHint = new HintHint(myDescriptionBrowser, new Point(0, 0));
|
||||
hintHint.setFont(UIUtil.getLabelFont());
|
||||
|
||||
@@ -75,13 +75,13 @@ public class DescriptorComposer extends HTMLComposerImpl {
|
||||
}
|
||||
|
||||
public static String[] quickFixTexts(RefEntity where, @NotNull InspectionToolPresentation toolPresentation){
|
||||
QuickFixAction[] quickFixes = toolPresentation.getQuickFixes(new RefEntity[] {where});
|
||||
QuickFixAction[] quickFixes = toolPresentation.getQuickFixes(new RefEntity[] {where}, null);
|
||||
if (quickFixes == null) {
|
||||
return null;
|
||||
}
|
||||
List<String> texts = new ArrayList<String>();
|
||||
for (QuickFixAction quickFix : quickFixes) {
|
||||
String text = quickFix.getText(where);
|
||||
String text = quickFix.getText();
|
||||
if (text == null) continue;
|
||||
texts.add(escapeQuickFixText(text));
|
||||
}
|
||||
|
||||
+1
-1
@@ -83,7 +83,7 @@ public class InspectionRVContentProviderImpl extends InspectionRVContentProvider
|
||||
public QuickFixAction[] getQuickFixes(@NotNull final InspectionToolWrapper toolWrapper, @NotNull final InspectionTree tree) {
|
||||
final RefEntity[] refEntities = tree.getSelectedElements();
|
||||
InspectionToolPresentation presentation = tree.getContext().getPresentation(toolWrapper);
|
||||
return refEntities.length == 0 ? null : presentation.getQuickFixes(refEntities);
|
||||
return refEntities.length == 0 ? null : presentation.getQuickFixes(refEntities, tree.getSelectedDescriptors());
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -40,28 +40,20 @@ import java.util.Set;
|
||||
*/
|
||||
public class LocalQuickFixWrapper extends QuickFixAction {
|
||||
private final QuickFix myFix;
|
||||
private String myText;
|
||||
|
||||
public LocalQuickFixWrapper(@NotNull QuickFix fix, @NotNull InspectionToolWrapper toolWrapper) {
|
||||
super(fix.getName(), toolWrapper);
|
||||
myFix = fix;
|
||||
myText = myFix.getName();
|
||||
setText(myFix.getName());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void update(AnActionEvent e) {
|
||||
super.update(e);
|
||||
getTemplatePresentation().setText(myText);
|
||||
e.getPresentation().setText(myText);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getText(RefEntity where) {
|
||||
return myText;
|
||||
}
|
||||
|
||||
public void setText(@NotNull String text) {
|
||||
myText = text;
|
||||
getTemplatePresentation().setText(text);
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -41,7 +41,6 @@ import com.intellij.psi.PsiDocumentManager;
|
||||
import com.intellij.psi.PsiElement;
|
||||
import com.intellij.psi.PsiFile;
|
||||
import com.intellij.psi.util.PsiUtilCore;
|
||||
import com.intellij.util.ArrayUtil;
|
||||
import com.intellij.util.SequentialModalProgressTask;
|
||||
import gnu.trove.THashSet;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
@@ -102,7 +101,7 @@ public class QuickFixAction extends AnAction {
|
||||
return false;
|
||||
}
|
||||
|
||||
public String getText(RefEntity where) {
|
||||
public String getText() {
|
||||
return getTemplatePresentation().getText();
|
||||
}
|
||||
|
||||
@@ -110,15 +109,13 @@ public class QuickFixAction extends AnAction {
|
||||
public void actionPerformed(final AnActionEvent e) {
|
||||
final InspectionResultsView view = getInvoker(e);
|
||||
final InspectionTree tree = view.getTree();
|
||||
if (isProblemDescriptorsAcceptable()) {
|
||||
final CommonProblemDescriptor[] descriptors = tree.getSelectedDescriptors();
|
||||
if (descriptors.length > 0) {
|
||||
doApplyFix(view.getProject(), descriptors, tree.getContext());
|
||||
return;
|
||||
}
|
||||
final CommonProblemDescriptor[] descriptors;
|
||||
if (isProblemDescriptorsAcceptable() && (descriptors = tree.getSelectedDescriptors()).length > 0) {
|
||||
doApplyFix(view.getProject(), descriptors, tree.getContext());
|
||||
} else {
|
||||
doApplyFix(getSelectedElements(e), view);
|
||||
}
|
||||
|
||||
doApplyFix(getSelectedElements(e), view);
|
||||
view.updateRightPanel();
|
||||
}
|
||||
|
||||
|
||||
|
||||
+6
-16
@@ -21,7 +21,6 @@
|
||||
package com.intellij.codeInspection.offlineViewer;
|
||||
|
||||
import com.intellij.codeInspection.CommonProblemDescriptor;
|
||||
import com.intellij.codeInspection.QuickFix;
|
||||
import com.intellij.codeInspection.ex.*;
|
||||
import com.intellij.codeInspection.offline.OfflineProblemDescriptor;
|
||||
import com.intellij.codeInspection.reference.RefElement;
|
||||
@@ -31,7 +30,6 @@ import com.intellij.codeInspection.ui.*;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.util.Comparing;
|
||||
import com.intellij.util.Function;
|
||||
import com.intellij.util.containers.ContainerUtil;
|
||||
import com.intellij.util.containers.HashSet;
|
||||
import com.intellij.util.ui.tree.TreeUtil;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
@@ -69,7 +67,7 @@ public class OfflineInspectionRVContentProvider extends InspectionRVContentProvi
|
||||
final TreePath[] treePaths = tree.getSelectionPaths();
|
||||
if (treePaths == null) return QuickFixAction.EMPTY;
|
||||
final List<RefEntity> selectedElements = new ArrayList<RefEntity>();
|
||||
final Map<RefEntity, Set<QuickFix>> actions = new HashMap<RefEntity, Set<QuickFix>>();
|
||||
final Map<RefEntity, CommonProblemDescriptor[]> actions = new HashMap<>();
|
||||
for (TreePath selectionPath : treePaths) {
|
||||
TreeUtil.traverseDepth((TreeNode)selectionPath.getLastPathComponent(), new TreeUtil.Traverse() {
|
||||
@Override
|
||||
@@ -79,18 +77,10 @@ public class OfflineInspectionRVContentProvider extends InspectionRVContentProvi
|
||||
final OfflineProblemDescriptorNode descriptorNode = (OfflineProblemDescriptorNode)node;
|
||||
final RefEntity element = descriptorNode.getElement();
|
||||
selectedElements.add(element);
|
||||
Set<QuickFix> quickFixes = actions.get(element);
|
||||
if (quickFixes == null) {
|
||||
quickFixes = new HashSet<QuickFix>();
|
||||
actions.put(element, quickFixes);
|
||||
}
|
||||
final CommonProblemDescriptor descriptor = descriptorNode.getDescriptor();
|
||||
if (descriptor != null) {
|
||||
final QuickFix[] fixes = descriptor.getFixes();
|
||||
if (fixes != null) {
|
||||
ContainerUtil.addAll(quickFixes, fixes);
|
||||
}
|
||||
}
|
||||
CommonProblemDescriptor[] quickFixes = actions.get(element);
|
||||
actions.put(element, quickFixes == null ?
|
||||
new CommonProblemDescriptor[]{descriptorNode.getDescriptor()} :
|
||||
DefaultInspectionToolPresentation.mergeDescriptors(quickFixes, new CommonProblemDescriptor[]{descriptorNode.getDescriptor()}));
|
||||
}
|
||||
else if (node instanceof RefElementNode) {
|
||||
selectedElements.add(((RefElementNode)node).getElement());
|
||||
@@ -106,7 +96,7 @@ public class OfflineInspectionRVContentProvider extends InspectionRVContentProvi
|
||||
|
||||
GlobalInspectionContextImpl context = tree.getContext();
|
||||
InspectionToolPresentation presentation = context.getPresentation(toolWrapper);
|
||||
return presentation.extractActiveFixes(selectedRefElements, actions);
|
||||
return presentation.extractActiveFixes(selectedRefElements, actions, tree.getSelectedDescriptors());
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -1,532 +0,0 @@
|
||||
/*
|
||||
* Copyright 2000-2009 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.intellij.codeInspection.ui;
|
||||
|
||||
import com.intellij.codeInsight.FileModificationService;
|
||||
import com.intellij.codeInsight.daemon.HighlightDisplayKey;
|
||||
import com.intellij.codeInspection.*;
|
||||
import com.intellij.codeInspection.ex.*;
|
||||
import com.intellij.codeInspection.reference.RefElement;
|
||||
import com.intellij.codeInspection.reference.RefEntity;
|
||||
import com.intellij.codeInspection.ui.actions.SuppressActionWrapper;
|
||||
import com.intellij.ide.BrowserUtil;
|
||||
import com.intellij.openapi.actionSystem.AnAction;
|
||||
import com.intellij.openapi.application.ApplicationManager;
|
||||
import com.intellij.openapi.command.CommandProcessor;
|
||||
import com.intellij.openapi.editor.colors.EditorColorsManager;
|
||||
import com.intellij.openapi.editor.colors.EditorColorsScheme;
|
||||
import com.intellij.openapi.util.TextRange;
|
||||
import com.intellij.openapi.vfs.VfsUtil;
|
||||
import com.intellij.openapi.vfs.VirtualFile;
|
||||
import com.intellij.openapi.vfs.VirtualFileManager;
|
||||
import com.intellij.profile.codeInspection.InspectionProjectProfileManagerImpl;
|
||||
import com.intellij.psi.PsiElement;
|
||||
import com.intellij.psi.PsiManager;
|
||||
import com.intellij.psi.util.PsiModificationTracker;
|
||||
import com.intellij.ui.ScrollPaneFactory;
|
||||
import com.intellij.util.containers.ContainerUtil;
|
||||
import com.intellij.util.ui.UIUtil;
|
||||
import com.intellij.xml.util.XmlStringUtil;
|
||||
import org.jetbrains.annotations.NonNls;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import javax.swing.*;
|
||||
import javax.swing.event.HyperlinkEvent;
|
||||
import javax.swing.event.HyperlinkListener;
|
||||
import javax.swing.text.Document;
|
||||
import javax.swing.text.Style;
|
||||
import javax.swing.text.StyleConstants;
|
||||
import javax.swing.text.StyledDocument;
|
||||
import javax.swing.text.html.HTMLDocument;
|
||||
import javax.swing.text.html.HTMLFrameHyperlinkEvent;
|
||||
import java.awt.*;
|
||||
import java.io.IOException;
|
||||
import java.io.StringReader;
|
||||
import java.net.URL;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
class Browser extends JPanel {
|
||||
private static final String UNDER_CONSTRUCTION = InspectionsBundle.message("inspection.tool.description.under.construction.text");
|
||||
private final List<ClickListener> myClickListeners = ContainerUtil.createLockFreeCopyOnWriteList();
|
||||
private RefEntity myCurrentEntity;
|
||||
private JEditorPane myHTMLViewer;
|
||||
private final InspectionResultsView myView;
|
||||
private final HyperlinkListener myHyperLinkListener;
|
||||
private CommonProblemDescriptor myCurrentDescriptor;
|
||||
|
||||
public static class ClickEvent {
|
||||
public static final int REF_ELEMENT = 1;
|
||||
public static final int FILE_OFFSET = 2;
|
||||
private final VirtualFile myFile;
|
||||
private final int myStartPosition;
|
||||
private final int myEndPosition;
|
||||
private final RefElement refElement;
|
||||
private final int myEventType;
|
||||
|
||||
public ClickEvent(VirtualFile myFile, int myStartPosition, int myEndPosition) {
|
||||
this.myFile = myFile;
|
||||
this.myStartPosition = myStartPosition;
|
||||
this.myEndPosition = myEndPosition;
|
||||
myEventType = FILE_OFFSET;
|
||||
refElement = null;
|
||||
}
|
||||
|
||||
public int getEventType() {
|
||||
return myEventType;
|
||||
}
|
||||
|
||||
public VirtualFile getFile() {
|
||||
return myFile;
|
||||
}
|
||||
|
||||
public int getStartOffset() {
|
||||
return myStartPosition;
|
||||
}
|
||||
|
||||
public int getEndOffset() {
|
||||
return myEndPosition;
|
||||
}
|
||||
|
||||
public RefElement getClickedElement() {
|
||||
return refElement;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public void dispose(){
|
||||
removeAll();
|
||||
if (myHTMLViewer != null) {
|
||||
myHTMLViewer.removeHyperlinkListener(myHyperLinkListener);
|
||||
myHTMLViewer = null;
|
||||
}
|
||||
myClickListeners.clear();
|
||||
}
|
||||
|
||||
public interface ClickListener {
|
||||
void referenceClicked(ClickEvent e);
|
||||
}
|
||||
|
||||
private void showPageFromHistory(@NotNull RefEntity newEntity) {
|
||||
InspectionToolWrapper toolWrapper = getToolWrapper(newEntity);
|
||||
try {
|
||||
String html = generateHTML(newEntity, toolWrapper);
|
||||
myHTMLViewer.read(new StringReader(html), null);
|
||||
setupStyle();
|
||||
myHTMLViewer.setCaretPosition(0);
|
||||
}
|
||||
catch (Exception e) {
|
||||
showEmpty();
|
||||
}
|
||||
finally {
|
||||
myCurrentEntity = newEntity;
|
||||
myCurrentDescriptor = null;
|
||||
}
|
||||
}
|
||||
|
||||
public void showPageFor(RefEntity refEntity, CommonProblemDescriptor descriptor) {
|
||||
try {
|
||||
String html = generateHTML(refEntity, descriptor);
|
||||
myHTMLViewer.read(new StringReader(html), null);
|
||||
setupStyle();
|
||||
myHTMLViewer.setCaretPosition(0);
|
||||
}
|
||||
catch (Exception e) {
|
||||
showEmpty();
|
||||
}
|
||||
finally {
|
||||
myCurrentEntity = refEntity;
|
||||
myCurrentDescriptor = descriptor;
|
||||
}
|
||||
}
|
||||
|
||||
public void showPageFor(RefEntity newEntity) {
|
||||
if (newEntity == null) {
|
||||
showEmpty();
|
||||
return;
|
||||
}
|
||||
//multiple problems for one entity -> refresh browser
|
||||
showPageFromHistory(newEntity.getRefManager().getRefinedElement(newEntity));
|
||||
}
|
||||
|
||||
public Browser(@NotNull InspectionResultsView view) {
|
||||
super(new BorderLayout());
|
||||
myView = view;
|
||||
|
||||
myCurrentEntity = null;
|
||||
myCurrentDescriptor = null;
|
||||
|
||||
myHTMLViewer = new JEditorPane(UIUtil.HTML_MIME, InspectionsBundle.message("inspection.offline.view.empty.browser.text"));
|
||||
myHTMLViewer.setEditable(false);
|
||||
myHyperLinkListener = new HyperlinkListener() {
|
||||
@Override
|
||||
public void hyperlinkUpdate(HyperlinkEvent e) {
|
||||
Browser.this.hyperlinkUpdate(e);
|
||||
}
|
||||
};
|
||||
myHTMLViewer.addHyperlinkListener(myHyperLinkListener);
|
||||
|
||||
final JScrollPane pane = ScrollPaneFactory.createScrollPane(myHTMLViewer);
|
||||
pane.setBorder(null);
|
||||
add(pane, BorderLayout.CENTER);
|
||||
setupStyle();
|
||||
}
|
||||
|
||||
private void hyperlinkUpdate(HyperlinkEvent e) {
|
||||
if (e.getEventType() != HyperlinkEvent.EventType.ACTIVATED) {
|
||||
return;
|
||||
}
|
||||
JEditorPane pane = (JEditorPane)e.getSource();
|
||||
if (e instanceof HTMLFrameHyperlinkEvent) {
|
||||
HTMLFrameHyperlinkEvent evt = (HTMLFrameHyperlinkEvent)e;
|
||||
HTMLDocument doc = (HTMLDocument)pane.getDocument();
|
||||
doc.processHTMLFrameHyperlinkEvent(evt);
|
||||
return;
|
||||
}
|
||||
URL url = null;
|
||||
try {
|
||||
url = e.getURL();
|
||||
@NonNls String ref = url.getRef();
|
||||
if (ref.startsWith("pos:")) {
|
||||
int delimeterPos = ref.indexOf(':', "pos:".length() + 1);
|
||||
String startPosition = ref.substring("pos:".length(), delimeterPos);
|
||||
String endPosition = ref.substring(delimeterPos + 1);
|
||||
Integer textStartOffset = new Integer(startPosition);
|
||||
Integer textEndOffset = new Integer(endPosition);
|
||||
String fileURL = url.toExternalForm();
|
||||
fileURL = fileURL.substring(0, fileURL.indexOf('#'));
|
||||
VirtualFile vFile = VirtualFileManager.getInstance().findFileByUrl(fileURL);
|
||||
if (vFile != null) {
|
||||
fireClickEvent(vFile, textStartOffset.intValue(), textEndOffset.intValue());
|
||||
}
|
||||
}
|
||||
else if (ref.startsWith("descr:")) {
|
||||
if (myCurrentDescriptor instanceof ProblemDescriptor) {
|
||||
PsiElement psiElement = ((ProblemDescriptor)myCurrentDescriptor).getPsiElement();
|
||||
if (psiElement == null) return;
|
||||
VirtualFile vFile = psiElement.getContainingFile().getVirtualFile();
|
||||
if (vFile != null) {
|
||||
TextRange range = ((ProblemDescriptorBase)myCurrentDescriptor).getTextRange();
|
||||
fireClickEvent(vFile, range.getStartOffset(), range.getEndOffset());
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (ref.startsWith("invoke:")) {
|
||||
int actionNumber = Integer.parseInt(ref.substring("invoke:".length()));
|
||||
InspectionToolWrapper toolWrapper = getToolWrapper();
|
||||
InspectionToolPresentation presentation = myView.getGlobalInspectionContext().getPresentation(toolWrapper);
|
||||
QuickFixAction fixAction = presentation.getQuickFixes(new RefElement[]{(RefElement)myCurrentEntity})[actionNumber];
|
||||
fixAction.doApplyFix(new RefElement[]{(RefElement)myCurrentEntity}, myView);
|
||||
}
|
||||
else if (ref.startsWith("invokelocal:")) {
|
||||
int actionNumber = Integer.parseInt(ref.substring("invokelocal:".length()));
|
||||
if (actionNumber > -1) {
|
||||
invokeLocalFix(actionNumber);
|
||||
}
|
||||
} else if (ref.startsWith("suppress:")){
|
||||
final SuppressActionWrapper.SuppressTreeAction[] suppressTreeActions =
|
||||
new SuppressActionWrapper(myView.getProject(), getToolWrapper(), myView.getTree().getSelectionPaths()).getChildren(null);
|
||||
final List<AnAction> activeActions = new ArrayList<AnAction>();
|
||||
for (SuppressActionWrapper.SuppressTreeAction suppressTreeAction : suppressTreeActions) {
|
||||
if (suppressTreeAction.isAvailable()) activeActions.add(suppressTreeAction);
|
||||
}
|
||||
if (!activeActions.isEmpty()) {
|
||||
int actionNumber = Integer.parseInt(ref.substring("suppress:".length()));
|
||||
if (actionNumber > -1 && activeActions.size() > actionNumber) {
|
||||
activeActions.get(actionNumber).actionPerformed(null);
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
int offset = Integer.parseInt(ref);
|
||||
String fileURL = url.toExternalForm();
|
||||
fileURL = fileURL.substring(0, fileURL.indexOf('#'));
|
||||
VirtualFile vFile = VirtualFileManager.getInstance().findFileByUrl(fileURL);
|
||||
if (vFile == null) {
|
||||
vFile = VfsUtil.findFileByURL(url);
|
||||
}
|
||||
if (vFile != null) {
|
||||
fireClickEvent(vFile, offset, offset);
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Throwable t) {
|
||||
if (url != null) {
|
||||
BrowserUtil.browse(url);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void setupStyle() {
|
||||
Document document = myHTMLViewer.getDocument();
|
||||
if (!(document instanceof StyledDocument)) {
|
||||
return;
|
||||
}
|
||||
|
||||
StyledDocument styledDocument = (StyledDocument)document;
|
||||
|
||||
EditorColorsManager colorsManager = EditorColorsManager.getInstance();
|
||||
EditorColorsScheme scheme = colorsManager.getGlobalScheme();
|
||||
|
||||
Style style = styledDocument.addStyle("active", null);
|
||||
StyleConstants.setFontFamily(style, scheme.getEditorFontName());
|
||||
StyleConstants.setFontSize(style, scheme.getEditorFontSize());
|
||||
styledDocument.setCharacterAttributes(0, document.getLength(), style, false);
|
||||
}
|
||||
|
||||
public void addClickListener(ClickListener listener) {
|
||||
myClickListeners.add(listener);
|
||||
}
|
||||
|
||||
private void fireClickEvent(VirtualFile file, int startPosition, int endPosition) {
|
||||
ClickEvent e = new ClickEvent(file, startPosition, endPosition);
|
||||
|
||||
for (ClickListener listener : myClickListeners) {
|
||||
listener.referenceClicked(e);
|
||||
}
|
||||
}
|
||||
|
||||
private String generateHTML(final RefEntity refEntity, @NotNull final InspectionToolWrapper toolWrapper) {
|
||||
final StringBuffer buf = new StringBuffer();
|
||||
final HTMLComposerImpl htmlComposer = getPresentation(toolWrapper).getComposer();
|
||||
if (refEntity instanceof RefElement) {
|
||||
ApplicationManager.getApplication().runReadAction(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
htmlComposer.compose(buf, refEntity);
|
||||
}
|
||||
});
|
||||
}
|
||||
else {
|
||||
htmlComposer.compose(buf, refEntity);
|
||||
}
|
||||
|
||||
uppercaseFirstLetter(buf);
|
||||
|
||||
if (refEntity instanceof RefElement){
|
||||
appendSuppressSection(buf);
|
||||
}
|
||||
|
||||
insertHeaderFooter(buf);
|
||||
|
||||
return buf.toString();
|
||||
}
|
||||
|
||||
private InspectionToolPresentation getPresentation(@NotNull InspectionToolWrapper toolWrapper) {
|
||||
return myView.getGlobalInspectionContext().getPresentation(toolWrapper);
|
||||
}
|
||||
|
||||
@SuppressWarnings({"HardCodedStringLiteral"})
|
||||
private static void insertHeaderFooter(final StringBuffer buf) {
|
||||
buf.insert(0, "<HTML><BODY>");
|
||||
buf.append("</BODY></HTML>");
|
||||
}
|
||||
|
||||
private String generateHTML(final RefEntity refEntity, final CommonProblemDescriptor descriptor) {
|
||||
final StringBuffer buf = new StringBuffer();
|
||||
final Runnable action = new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
InspectionToolWrapper toolWrapper = getToolWrapper(refEntity);
|
||||
getPresentation(toolWrapper).getComposer().compose(buf, refEntity, descriptor);
|
||||
}
|
||||
};
|
||||
ApplicationManager.getApplication().runReadAction(action);
|
||||
|
||||
uppercaseFirstLetter(buf);
|
||||
|
||||
if (refEntity instanceof RefElement) {
|
||||
appendSuppressSection(buf);
|
||||
}
|
||||
|
||||
insertHeaderFooter(buf);
|
||||
return buf.toString();
|
||||
}
|
||||
|
||||
private InspectionToolWrapper getToolWrapper(final RefEntity refEntity) {
|
||||
InspectionToolWrapper toolWrapper = getToolWrapper();
|
||||
assert toolWrapper != null;
|
||||
final GlobalInspectionContextImpl context = myView.getGlobalInspectionContext();
|
||||
if (refEntity instanceof RefElement){
|
||||
PsiElement element = ((RefElement)refEntity).getElement();
|
||||
if (element == null) return toolWrapper;
|
||||
InspectionProfileWrapper profileWrapper = InspectionProjectProfileManagerImpl.getInstanceImpl(context.getProject()).getProfileWrapper();
|
||||
toolWrapper = profileWrapper.getInspectionTool(toolWrapper.getShortName(), element);
|
||||
}
|
||||
return toolWrapper;
|
||||
}
|
||||
|
||||
private void appendSuppressSection(final StringBuffer buf) {
|
||||
final InspectionToolWrapper toolWrapper = getToolWrapper();
|
||||
if (toolWrapper != null) {
|
||||
final HighlightDisplayKey key = HighlightDisplayKey.find(toolWrapper.getShortName());
|
||||
if (key != null){//dummy entry points
|
||||
final SuppressActionWrapper.SuppressTreeAction[] suppressActions = new SuppressActionWrapper(myView.getProject(), toolWrapper, myView.getTree().getSelectionPaths()).getChildren(null);
|
||||
if (suppressActions.length > 0) {
|
||||
final List<AnAction> activeSuppressActions = new ArrayList<AnAction>();
|
||||
for (SuppressActionWrapper.SuppressTreeAction suppressAction : suppressActions) {
|
||||
if (suppressAction.isAvailable()) {
|
||||
activeSuppressActions.add(suppressAction);
|
||||
}
|
||||
}
|
||||
if (!activeSuppressActions.isEmpty()) {
|
||||
int idx = 0;
|
||||
@NonNls final String br = "<br>";
|
||||
buf.append(br);
|
||||
HTMLComposerImpl.appendHeading(buf, InspectionsBundle.message("inspection.export.results.suppress"));
|
||||
for (AnAction suppressAction : activeSuppressActions) {
|
||||
buf.append(br);
|
||||
if (idx == activeSuppressActions.size() - 1) {
|
||||
buf.append(br);
|
||||
}
|
||||
HTMLComposer.appendAfterHeaderIndention(buf);
|
||||
@NonNls final String href = "<a HREF=\"file://bred.txt#suppress:" + idx + "\">" + suppressAction.getTemplatePresentation().getText() + "</a>";
|
||||
buf.append(href);
|
||||
idx++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void uppercaseFirstLetter(final StringBuffer buf) {
|
||||
if (buf.length() > 1) {
|
||||
char[] firstLetter = new char[1];
|
||||
buf.getChars(0, 1, firstLetter, 0);
|
||||
buf.setCharAt(0, Character.toUpperCase(firstLetter[0]));
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings({"HardCodedStringLiteral"})
|
||||
public void showEmpty() {
|
||||
myCurrentEntity = null;
|
||||
try {
|
||||
myHTMLViewer.read(new StringReader(InspectionsBundle.message("inspection.offline.view.empty.browser.text")), null);
|
||||
}
|
||||
catch (IOException e) {
|
||||
//can't be
|
||||
}
|
||||
}
|
||||
|
||||
public void showDescription(@NotNull InspectionToolWrapper toolWrapper){
|
||||
if (toolWrapper.getShortName().isEmpty()){
|
||||
showEmpty();
|
||||
return;
|
||||
}
|
||||
@NonNls StringBuffer page = new StringBuffer();
|
||||
page.append("<table border='0' cellspacing='0' cellpadding='0' width='100%'>");
|
||||
page.append("<tr><td colspan='2'>");
|
||||
HTMLComposer.appendHeading(page, InspectionsBundle.message("inspection.tool.in.browser.id.title"));
|
||||
page.append("</td></tr>");
|
||||
page.append("<tr><td width='37'></td>" +
|
||||
"<td>");
|
||||
page.append(toolWrapper.getShortName());
|
||||
page.append("</td></tr>");
|
||||
page.append("<tr height='10'></tr>");
|
||||
page.append("<tr><td colspan='2'>");
|
||||
HTMLComposer.appendHeading(page, InspectionsBundle.message("inspection.tool.in.browser.description.title"));
|
||||
page.append("</td></tr>");
|
||||
page.append("<tr><td width='37'></td>" +
|
||||
"<td>");
|
||||
@NonNls final String underConstruction = "<b>" + UNDER_CONSTRUCTION + "</b></html>";
|
||||
try {
|
||||
@NonNls String description = toolWrapper.loadDescription();
|
||||
if (description == null) {
|
||||
description = underConstruction;
|
||||
}
|
||||
page.append(DefaultInspectionToolPresentation.stripUIRefsFromInspectionDescription(UIUtil.getHtmlBody(description)));
|
||||
|
||||
page.append("</td></tr></table>");
|
||||
myHTMLViewer.setText(XmlStringUtil.wrapInHtml(page));
|
||||
setupStyle();
|
||||
}
|
||||
finally {
|
||||
myCurrentEntity = null;
|
||||
}
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private InspectionToolWrapper getToolWrapper() {
|
||||
return myView.getTree().getSelectedToolWrapper();
|
||||
}
|
||||
|
||||
public void invokeLocalFix(int idx) {
|
||||
if (myView.getTree().getSelectionCount() != 1) return;
|
||||
final InspectionTreeNode node = (InspectionTreeNode)myView.getTree().getSelectionPath().getLastPathComponent();
|
||||
if (node instanceof ProblemDescriptionNode) {
|
||||
final ProblemDescriptionNode problemNode = (ProblemDescriptionNode)node;
|
||||
final CommonProblemDescriptor descriptor = problemNode.getDescriptor();
|
||||
final RefEntity element = problemNode.getElement();
|
||||
invokeFix(element, descriptor, idx);
|
||||
}
|
||||
else if (node instanceof RefElementNode) {
|
||||
RefElementNode elementNode = (RefElementNode)node;
|
||||
RefEntity element = elementNode.getElement();
|
||||
CommonProblemDescriptor descriptor = elementNode.getProblem();
|
||||
if (descriptor != null) {
|
||||
invokeFix(element, descriptor, idx);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void invokeFix(final RefEntity element, final CommonProblemDescriptor descriptor, final int idx) {
|
||||
final QuickFix[] fixes = descriptor.getFixes();
|
||||
if (fixes != null && fixes.length > idx && fixes[idx] != null) {
|
||||
if (element instanceof RefElement) {
|
||||
PsiElement psiElement = ((RefElement)element).getElement();
|
||||
if (psiElement != null && psiElement.isValid()) {
|
||||
if (!FileModificationService.getInstance().preparePsiElementForWrite(psiElement)) return;
|
||||
performFix(element, descriptor, idx, fixes[idx]);
|
||||
}
|
||||
}
|
||||
else {
|
||||
performFix(element, descriptor, idx, fixes[idx]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void performFix(final RefEntity element, final CommonProblemDescriptor descriptor, final int idx, final QuickFix fix) {
|
||||
final Runnable command = new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
ApplicationManager.getApplication().runWriteAction(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
final PsiModificationTracker tracker = PsiManager.getInstance(myView.getProject()).getModificationTracker();
|
||||
final long startCount = tracker.getModificationCount();
|
||||
CommandProcessor.getInstance().markCurrentCommandAsGlobal(myView.getProject());
|
||||
//CCE here means QuickFix was incorrectly inherited
|
||||
fix.applyFix(myView.getProject(), descriptor);
|
||||
if (startCount != tracker.getModificationCount()) {
|
||||
InspectionToolWrapper toolWrapper = myView.getTree().getSelectedToolWrapper();
|
||||
if (toolWrapper != null) {
|
||||
InspectionToolPresentation presentation =
|
||||
myView.getGlobalInspectionContext().getPresentation(toolWrapper);
|
||||
presentation.ignoreProblem(element, descriptor, idx);
|
||||
}
|
||||
myView.updateView(false);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
CommandProcessor.getInstance().executeCommand(myView.getProject(), command, fix.getName(), null);
|
||||
}
|
||||
}
|
||||
|
||||
+60
-24
@@ -267,7 +267,7 @@ public class DefaultInspectionToolPresentation implements ProblemDescriptionsPro
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private static CommonProblemDescriptor[] mergeDescriptors(@NotNull CommonProblemDescriptor[] problems1,
|
||||
public static CommonProblemDescriptor[] mergeDescriptors(@NotNull CommonProblemDescriptor[] problems1,
|
||||
@NotNull CommonProblemDescriptor[] problems2) {
|
||||
CommonProblemDescriptor[] out = new CommonProblemDescriptor[problems1.length + problems2.length];
|
||||
int o = problems1.length;
|
||||
@@ -641,41 +641,77 @@ public class DefaultInspectionToolPresentation implements ProblemDescriptionsPro
|
||||
|
||||
@Override
|
||||
@Nullable
|
||||
public QuickFixAction[] getQuickFixes(@NotNull final RefEntity[] refElements) {
|
||||
return extractActiveFixes(refElements, getQuickFixActions());
|
||||
public QuickFixAction[] getQuickFixes(@NotNull final RefEntity[] refElements, CommonProblemDescriptor[] allowedDescriptors) {
|
||||
return extractActiveFixes(refElements, getProblemElements(), allowedDescriptors);
|
||||
}
|
||||
|
||||
@Override
|
||||
@Nullable
|
||||
public QuickFixAction[] extractActiveFixes(@NotNull RefEntity[] refElements, @NotNull Map<RefEntity, Set<QuickFix>> actions) {
|
||||
Map<Class, QuickFixAction> result = new com.intellij.util.containers.HashMap<Class, QuickFixAction>();
|
||||
public QuickFixAction[] extractActiveFixes(@NotNull RefEntity[] refElements,
|
||||
@NotNull Map<RefEntity, CommonProblemDescriptor[]> descriptorMap,
|
||||
@Nullable CommonProblemDescriptor[] allowedDescriptors) {
|
||||
final Set<CommonProblemDescriptor> allowedDescriptorSet = allowedDescriptors == null ? null : ContainerUtil.newHashSet(allowedDescriptors);
|
||||
Map<Class, QuickFixAction> result = new com.intellij.util.containers.HashMap<>();
|
||||
boolean isFirst = true;
|
||||
for (RefEntity refElement : refElements) {
|
||||
final Set<QuickFix> localQuickFixes = actions.get(refElement);
|
||||
if (localQuickFixes == null) continue;
|
||||
for (QuickFix fix : localQuickFixes) {
|
||||
if (fix == null) continue;
|
||||
final Class klass = fix instanceof ActionClassHolder ? ((ActionClassHolder ) fix).getActionClass() : fix.getClass();
|
||||
final QuickFixAction quickFixAction = result.get(klass);
|
||||
if (quickFixAction != null) {
|
||||
try {
|
||||
String familyName = fix.getFamilyName();
|
||||
familyName = !familyName.isEmpty() ? "\'" + familyName + "\'" : familyName;
|
||||
((LocalQuickFixWrapper)quickFixAction).setText(InspectionsBundle.message("inspection.descriptor.provider.apply.fix", familyName));
|
||||
}
|
||||
catch (AbstractMethodError e) {
|
||||
//for plugin compatibility
|
||||
((LocalQuickFixWrapper)quickFixAction).setText(InspectionsBundle.message("inspection.descriptor.provider.apply.fix", ""));
|
||||
}
|
||||
final CommonProblemDescriptor[] descriptors = descriptorMap.get(refElement);
|
||||
if (descriptors == null) continue;
|
||||
for (CommonProblemDescriptor d : descriptors) {
|
||||
if (allowedDescriptorSet != null && !allowedDescriptorSet.contains(d)) {
|
||||
continue;
|
||||
}
|
||||
else {
|
||||
LocalQuickFixWrapper quickFixWrapper = new LocalQuickFixWrapper(fix, myToolWrapper);
|
||||
result.put(klass, quickFixWrapper);
|
||||
QuickFix[] fixes = d.getFixes();
|
||||
if (fixes != null) {
|
||||
if (isFirst) {
|
||||
for (QuickFix fix : fixes) {
|
||||
if (fix == null) continue;
|
||||
final Class klass = getFixClass(fix);
|
||||
LocalQuickFixWrapper quickFixWrapper = new LocalQuickFixWrapper(fix, myToolWrapper);
|
||||
result.put(klass, quickFixWrapper);
|
||||
}
|
||||
isFirst = false;
|
||||
}
|
||||
else {
|
||||
for (Class clazz : new ArrayList<>(result.keySet())) {
|
||||
boolean isFound = false;
|
||||
for (QuickFix fix : fixes) {
|
||||
if (fix == null) continue;
|
||||
final Class klass = getFixClass(fix);
|
||||
if (clazz.equals(klass)) {
|
||||
isFound = true;
|
||||
final QuickFixAction quickFixAction = result.get(clazz);
|
||||
try {
|
||||
String familyName = fix.getFamilyName();
|
||||
familyName = !familyName.isEmpty() ? "\'" + familyName + "\'" : familyName;
|
||||
((LocalQuickFixWrapper)quickFixAction)
|
||||
.setText(InspectionsBundle.message("inspection.descriptor.provider.apply.fix", familyName));
|
||||
}
|
||||
catch (AbstractMethodError e) {
|
||||
//for plugin compatibility
|
||||
((LocalQuickFixWrapper)quickFixAction)
|
||||
.setText(InspectionsBundle.message("inspection.descriptor.provider.apply.fix", ""));
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!isFound) {
|
||||
result.remove(clazz);
|
||||
if (result.isEmpty()) {
|
||||
return QuickFixAction.EMPTY;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return result.values().isEmpty() ? null : result.values().toArray(new QuickFixAction[result.size()]);
|
||||
}
|
||||
|
||||
private static Class getFixClass(QuickFix fix) {
|
||||
return fix instanceof ActionClassHolder ? ((ActionClassHolder)fix).getActionClass() : fix.getClass();
|
||||
}
|
||||
|
||||
@Override
|
||||
public RefEntity getElement(@NotNull CommonProblemDescriptor descriptor) {
|
||||
return getProblemToElements().get(descriptor);
|
||||
|
||||
@@ -23,7 +23,6 @@ import com.intellij.util.IconUtil;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import javax.swing.*;
|
||||
import java.util.Enumeration;
|
||||
|
||||
/**
|
||||
* @author max
|
||||
@@ -51,19 +50,9 @@ public class InspectionNode extends InspectionTreeNode {
|
||||
}
|
||||
|
||||
public boolean isTooBigForOnlineRefresh() {
|
||||
if(!myTooBigForOnlineRefresh) myTooBigForOnlineRefresh = getProblemCount()>1000;
|
||||
if (!myTooBigForOnlineRefresh) {
|
||||
myTooBigForOnlineRefresh = getProblemCount() > 1000;
|
||||
}
|
||||
return myTooBigForOnlineRefresh;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getProblemCount() {
|
||||
int sum = 0;
|
||||
Enumeration children = children();
|
||||
while (children.hasMoreElements()) {
|
||||
InspectionTreeNode child = (InspectionTreeNode)children.nextElement();
|
||||
if (child instanceof InspectionNode) continue;
|
||||
sum += child.getProblemCount();
|
||||
}
|
||||
return sum;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,109 @@
|
||||
/*
|
||||
* Copyright 2000-2016 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.intellij.codeInspection.ui;
|
||||
|
||||
import com.intellij.codeInsight.daemon.HighlightDisplayKey;
|
||||
import com.intellij.codeInspection.ex.DisableInspectionToolAction;
|
||||
import com.intellij.codeInspection.ex.InspectionProfileImpl;
|
||||
import com.intellij.codeInspection.ex.InspectionToolWrapper;
|
||||
import com.intellij.openapi.diagnostic.Logger;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.profile.codeInspection.InspectionProjectProfileManager;
|
||||
import com.intellij.profile.codeInspection.ui.SingleInspectionProfilePanel;
|
||||
import com.intellij.ui.*;
|
||||
import com.intellij.ui.components.JBScrollPane;
|
||||
import com.intellij.util.ui.JBInsets;
|
||||
import com.intellij.util.ui.UIUtil;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import javax.swing.*;
|
||||
import java.awt.*;
|
||||
import java.awt.event.MouseEvent;
|
||||
|
||||
/**
|
||||
* @author Dmitry Batkovich
|
||||
*/
|
||||
public class InspectionNodeInfo extends JPanel {
|
||||
private final static Logger LOG = Logger.getInstance(InspectionNodeInfo.class);
|
||||
|
||||
private final JButton myButton;
|
||||
private final SimpleColoredComponent myTitle;
|
||||
private final HighlightDisplayKey myKey;
|
||||
private final InspectionProfileImpl myCurrentProfile;
|
||||
private final String myName;
|
||||
private final Project myProject;
|
||||
|
||||
public InspectionNodeInfo(final InspectionToolWrapper toolWrapper, Project project) {
|
||||
setLayout(new GridBagLayout());
|
||||
setBorder(IdeBorderFactory.createEmptyBorder(0, 3, 0, 0));
|
||||
myProject = project;
|
||||
myTitle = new SimpleColoredComponent();
|
||||
myCurrentProfile = (InspectionProfileImpl)InspectionProjectProfileManager.getInstance(project).getProjectProfileImpl();
|
||||
myKey = HighlightDisplayKey.find(toolWrapper.getID());
|
||||
myName = toolWrapper.getDisplayName();
|
||||
myButton = new JButton();
|
||||
|
||||
add(myTitle,
|
||||
new GridBagConstraints(0, 0, 1, 1, 0, 0, GridBagConstraints.NORTHWEST, GridBagConstraints.NONE, new JBInsets(0, 2, 0, 0),
|
||||
0, 0));
|
||||
|
||||
JEditorPane description = new JEditorPane();
|
||||
description.setContentType(UIUtil.HTML_MIME);
|
||||
description.setEditable(false);
|
||||
description.setOpaque(false);
|
||||
description.addHyperlinkListener(BrowserHyperlinkListener.INSTANCE);
|
||||
final String toolDescription = toolWrapper.loadDescription();
|
||||
SingleInspectionProfilePanel.readHTML(description, SingleInspectionProfilePanel.toHTML(description, toolDescription == null ? "" : toolDescription, true));
|
||||
|
||||
add(ScrollPaneFactory.createScrollPane(description, true),
|
||||
new GridBagConstraints(0, 1, 1, 1, 0, 1.0, GridBagConstraints.NORTHWEST, GridBagConstraints.BOTH,
|
||||
new JBInsets(5, 5, 0, 0), 0, 0));
|
||||
add(myButton,
|
||||
new GridBagConstraints(0, 2, 1, 1, 1.0, 0.0, GridBagConstraints.NORTHWEST, GridBagConstraints.NONE,
|
||||
new JBInsets(15, 0, 0, 0), 0, 0));
|
||||
updateEnableButtonText(false);
|
||||
|
||||
new ClickListener() {
|
||||
@Override
|
||||
public boolean onClick(@NotNull MouseEvent event, int clickCount) {
|
||||
updateEnableButtonText(true);
|
||||
return true;
|
||||
}
|
||||
}.installOn(myButton);
|
||||
}
|
||||
|
||||
private void updateEnableButtonText(boolean revert) {
|
||||
boolean isEnabled = myCurrentProfile.isToolEnabled(myKey);
|
||||
if (revert) {
|
||||
final boolean isEnabledAsFinal = isEnabled;
|
||||
DisableInspectionToolAction.modifyAndCommitProjectProfile(model -> {
|
||||
if (isEnabledAsFinal) {
|
||||
model.disableTool(myKey.getID(), myProject);
|
||||
}
|
||||
else {
|
||||
((InspectionProfileImpl)model).enableTool(myKey.getID(), myProject);
|
||||
}
|
||||
}, myProject);
|
||||
isEnabled = !isEnabled;
|
||||
}
|
||||
myButton.setText((isEnabled ? "Disable" : "Enable") + " inspection");
|
||||
myTitle.clear();
|
||||
myTitle.append(myName);
|
||||
if (!isEnabled) {
|
||||
myTitle.append(" Disabled", SimpleTextAttributes.GRAYED_ATTRIBUTES);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -21,7 +21,6 @@ import com.intellij.analysis.AnalysisScope;
|
||||
import com.intellij.analysis.AnalysisUIOptions;
|
||||
import com.intellij.codeHighlighting.HighlightDisplayLevel;
|
||||
import com.intellij.codeInsight.daemon.HighlightDisplayKey;
|
||||
import com.intellij.codeInsight.highlighting.HighlightManager;
|
||||
import com.intellij.codeInspection.*;
|
||||
import com.intellij.codeInspection.ex.*;
|
||||
import com.intellij.codeInspection.reference.RefElement;
|
||||
@@ -36,30 +35,31 @@ import com.intellij.injected.editor.VirtualFileWindow;
|
||||
import com.intellij.openapi.Disposable;
|
||||
import com.intellij.openapi.actionSystem.*;
|
||||
import com.intellij.openapi.application.ApplicationManager;
|
||||
import com.intellij.openapi.editor.Editor;
|
||||
import com.intellij.openapi.editor.colors.EditorColors;
|
||||
import com.intellij.openapi.editor.colors.EditorColorsManager;
|
||||
import com.intellij.openapi.editor.markup.TextAttributes;
|
||||
import com.intellij.openapi.fileEditor.FileEditorManager;
|
||||
import com.intellij.openapi.application.ModalityState;
|
||||
import com.intellij.openapi.diagnostic.Logger;
|
||||
import com.intellij.openapi.editor.*;
|
||||
import com.intellij.openapi.fileEditor.OpenFileDescriptor;
|
||||
import com.intellij.openapi.project.DumbAware;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.ui.Splitter;
|
||||
import com.intellij.openapi.ui.popup.JBPopup;
|
||||
import com.intellij.openapi.util.Key;
|
||||
import com.intellij.openapi.util.TextRange;
|
||||
import com.intellij.openapi.vfs.VirtualFile;
|
||||
import com.intellij.openapi.wm.ToolWindowId;
|
||||
import com.intellij.openapi.wm.ToolWindowManager;
|
||||
import com.intellij.pom.Navigatable;
|
||||
import com.intellij.profile.codeInspection.InspectionProjectProfileManager;
|
||||
import com.intellij.psi.PsiElement;
|
||||
import com.intellij.psi.PsiFile;
|
||||
import com.intellij.psi.*;
|
||||
import com.intellij.psi.util.PsiUtilCore;
|
||||
import com.intellij.ui.*;
|
||||
import com.intellij.ui.components.JBLabel;
|
||||
import com.intellij.usageView.UsageInfo;
|
||||
import com.intellij.usages.impl.UsagePreviewPanel;
|
||||
import com.intellij.util.ConcurrencyUtil;
|
||||
import com.intellij.util.EditSourceOnDoubleClickHandler;
|
||||
import com.intellij.util.OpenSourceUtil;
|
||||
import com.intellij.util.containers.ContainerUtil;
|
||||
import com.intellij.util.containers.*;
|
||||
import com.intellij.util.ui.UIUtil;
|
||||
import com.intellij.util.ui.tree.TreeUtil;
|
||||
import org.jetbrains.annotations.NonNls;
|
||||
@@ -67,8 +67,6 @@ import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import javax.swing.*;
|
||||
import javax.swing.event.TreeSelectionEvent;
|
||||
import javax.swing.event.TreeSelectionListener;
|
||||
import javax.swing.tree.DefaultMutableTreeNode;
|
||||
import javax.swing.tree.MutableTreeNode;
|
||||
import javax.swing.tree.TreePath;
|
||||
@@ -77,9 +75,8 @@ import java.awt.event.InputEvent;
|
||||
import java.awt.event.KeyAdapter;
|
||||
import java.awt.event.KeyEvent;
|
||||
import java.awt.event.MouseEvent;
|
||||
import java.beans.PropertyChangeEvent;
|
||||
import java.beans.PropertyChangeListener;
|
||||
import java.util.*;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.ConcurrentMap;
|
||||
|
||||
@@ -87,11 +84,13 @@ import java.util.concurrent.ConcurrentMap;
|
||||
* @author max
|
||||
*/
|
||||
public class InspectionResultsView extends JPanel implements Disposable, OccurenceNavigator, DataProvider {
|
||||
private static final Logger LOG = Logger.getInstance(InspectionResultsView.class);
|
||||
|
||||
public static final DataKey<InspectionResultsView> DATA_KEY = DataKey.create("inspectionView");
|
||||
private static final Key<Boolean> PREVIEW_EDITOR_IS_REUSED_KEY = Key.create("inspection.tool.window.preview.editor.is.reused.");
|
||||
|
||||
private final Project myProject;
|
||||
private final InspectionTree myTree;
|
||||
private final Browser myBrowser;
|
||||
private final ConcurrentMap<HighlightDisplayLevel, ConcurrentMap<String, InspectionGroupNode>> myGroups = ContainerUtil.newConcurrentMap();
|
||||
private final OccurenceNavigator myOccurenceNavigator;
|
||||
private volatile InspectionProfile myInspectionProfile;
|
||||
@@ -110,6 +109,7 @@ public class InspectionResultsView extends JPanel implements Disposable, Occuren
|
||||
private final InspectionRVContentProvider myProvider;
|
||||
private AnAction myIncludeAction;
|
||||
private AnAction myExcludeAction;
|
||||
private Editor myPreviewEditor;
|
||||
|
||||
public InspectionResultsView(@NotNull final Project project,
|
||||
final InspectionProfile inspectionProfile,
|
||||
@@ -129,59 +129,26 @@ public class InspectionResultsView extends JPanel implements Disposable, Occuren
|
||||
|
||||
myOccurenceNavigator = initOccurenceNavigator();
|
||||
|
||||
myBrowser = new Browser(this);
|
||||
|
||||
mySplitter = new OnePixelSplitter(false, AnalysisUIOptions.getInstance(myProject).SPLITTER_PROPORTION);
|
||||
|
||||
mySplitter.setFirstComponent(ScrollPaneFactory.createScrollPane(myTree, SideBorder.LEFT | SideBorder.RIGHT));
|
||||
mySplitter.setSecondComponent(myBrowser);
|
||||
|
||||
mySplitter.addPropertyChangeListener(new PropertyChangeListener() {
|
||||
@Override
|
||||
public void propertyChange(PropertyChangeEvent evt) {
|
||||
if (Splitter.PROP_PROPORTION.equals(evt.getPropertyName())) {
|
||||
myGlobalInspectionContext.setSplitterProportion(((Float)evt.getNewValue()).floatValue());
|
||||
}
|
||||
mySplitter.addPropertyChangeListener(evt -> {
|
||||
if (Splitter.PROP_PROPORTION.equals(evt.getPropertyName())) {
|
||||
myGlobalInspectionContext.setSplitterProportion(((Float)evt.getNewValue()).floatValue());
|
||||
}
|
||||
});
|
||||
add(mySplitter, BorderLayout.CENTER);
|
||||
|
||||
myBrowser.addClickListener(new Browser.ClickListener() {
|
||||
@Override
|
||||
public void referenceClicked(final Browser.ClickEvent e) {
|
||||
if (e.getEventType() == Browser.ClickEvent.REF_ELEMENT) {
|
||||
final RefElement refElement = e.getClickedElement();
|
||||
final OpenFileDescriptor descriptor = getOpenFileDescriptor(refElement);
|
||||
if (descriptor != null) {
|
||||
FileEditorManager.getInstance(project).openTextEditor(descriptor, false);
|
||||
}
|
||||
}
|
||||
else if (e.getEventType() == Browser.ClickEvent.FILE_OFFSET) {
|
||||
final VirtualFile file = e.getFile();
|
||||
final OpenFileDescriptor descriptor = new OpenFileDescriptor(project, file, e.getStartOffset());
|
||||
final Editor editor = FileEditorManager.getInstance(project).openTextEditor(descriptor, true);
|
||||
if (editor != null) {
|
||||
final TextAttributes selectionAttributes =
|
||||
EditorColorsManager.getInstance().getGlobalScheme().getAttributes(EditorColors.SEARCH_RESULT_ATTRIBUTES);
|
||||
HighlightManager.getInstance(project)
|
||||
.addRangeHighlight(editor, e.getStartOffset(), e.getEndOffset(), selectionAttributes, true, null);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
createActionsToolbar();
|
||||
TreeUtil.selectFirstNode(myTree);
|
||||
}
|
||||
|
||||
private void initTreeListeners() {
|
||||
myTree.getSelectionModel().addTreeSelectionListener(new TreeSelectionListener() {
|
||||
@Override
|
||||
public void valueChanged(TreeSelectionEvent e) {
|
||||
syncBrowser();
|
||||
if (isAutoScrollMode()) {
|
||||
OpenSourceUtil.openSourcesFrom(DataManager.getInstance().getDataContext(InspectionResultsView.this), false);
|
||||
}
|
||||
myTree.getSelectionModel().addTreeSelectionListener(e -> {
|
||||
syncRightPanel();
|
||||
if (isAutoScrollMode()) {
|
||||
OpenSourceUtil.openSourcesFrom(DataManager.getInstance().getDataContext(InspectionResultsView.this), false);
|
||||
}
|
||||
});
|
||||
|
||||
@@ -364,9 +331,9 @@ public class InspectionResultsView extends JPanel implements Disposable, Occuren
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dispose(){
|
||||
public void dispose() {
|
||||
releaseEditor(myPreviewEditor);
|
||||
mySplitter.dispose();
|
||||
myBrowser.dispose();
|
||||
myInspectionProfile = null;
|
||||
myDisposed = true;
|
||||
}
|
||||
@@ -406,9 +373,18 @@ public class InspectionResultsView extends JPanel implements Disposable, Occuren
|
||||
return null;
|
||||
}
|
||||
|
||||
private void syncBrowser() {
|
||||
private void syncRightPanel() {
|
||||
final Editor oldEditor = myPreviewEditor;
|
||||
if (myTree.getSelectionModel().getSelectionCount() != 1) {
|
||||
myBrowser.showEmpty();
|
||||
if (myTree.getSelectedToolWrapper() == null) {
|
||||
final JLabel multipleSelectionLabel = new JBLabel(InspectionViewNavigationPanel.getTitleText(false, false));
|
||||
multipleSelectionLabel.setVerticalAlignment(SwingConstants.TOP);
|
||||
multipleSelectionLabel.setBorder(IdeBorderFactory.createEmptyBorder(5, 7, 0, 0));
|
||||
mySplitter.setSecondComponent(multipleSelectionLabel);
|
||||
}
|
||||
else {
|
||||
showInRightPanel(myTree.getCommonSelectedElement());
|
||||
}
|
||||
}
|
||||
else {
|
||||
TreePath pathSelected = myTree.getSelectionModel().getLeadSelectionPath();
|
||||
@@ -416,48 +392,111 @@ public class InspectionResultsView extends JPanel implements Disposable, Occuren
|
||||
final InspectionTreeNode node = (InspectionTreeNode)pathSelected.getLastPathComponent();
|
||||
if (node instanceof RefElementNode) {
|
||||
final RefElementNode refElementNode = (RefElementNode)node;
|
||||
final CommonProblemDescriptor problem = refElementNode.getProblem();
|
||||
final RefEntity refSelected = refElementNode.getElement();
|
||||
if (problem != null) {
|
||||
showInBrowser(refSelected, problem);
|
||||
}
|
||||
else {
|
||||
showInBrowser(refSelected);
|
||||
}
|
||||
showInRightPanel(refSelected);
|
||||
}
|
||||
else if (node instanceof ProblemDescriptionNode) {
|
||||
final ProblemDescriptionNode problemNode = (ProblemDescriptionNode)node;
|
||||
showInBrowser(problemNode.getElement(), problemNode.getDescriptor());
|
||||
showInRightPanel(problemNode.getElement());
|
||||
}
|
||||
else if (node instanceof InspectionNode) {
|
||||
showInBrowser(((InspectionNode)node).getToolWrapper());
|
||||
else if (node instanceof InspectionNode || node instanceof InspectionPackageNode || node instanceof InspectionModuleNode) {
|
||||
showInRightPanel(null);
|
||||
}
|
||||
else if (node instanceof InspectionRootNode || node instanceof InspectionGroupNode || node instanceof InspectionSeverityGroupNode) {
|
||||
mySplitter.setSecondComponent(new InspectionViewNavigationPanel(node, myTree));
|
||||
}
|
||||
else {
|
||||
myBrowser.showEmpty();
|
||||
LOG.error("Unexpected node: " + node.getClass());
|
||||
}
|
||||
}
|
||||
}
|
||||
if (oldEditor != null) {
|
||||
if (Boolean.TRUE.equals(oldEditor.getUserData(PREVIEW_EDITOR_IS_REUSED_KEY))) {
|
||||
oldEditor.putUserData(PREVIEW_EDITOR_IS_REUSED_KEY, null);
|
||||
}
|
||||
else {
|
||||
releaseEditor(oldEditor);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void showInBrowser(final RefEntity refEntity) {
|
||||
private void showInRightPanel(@Nullable final RefEntity refEntity) {
|
||||
Cursor currentCursor = getCursor();
|
||||
setCursor(new Cursor(Cursor.WAIT_CURSOR));
|
||||
myBrowser.showPageFor(refEntity);
|
||||
setCursor(currentCursor);
|
||||
try {
|
||||
setCursor(new Cursor(Cursor.WAIT_CURSOR));
|
||||
final JPanel editorPanel = new JPanel();
|
||||
editorPanel.setLayout(new BorderLayout());
|
||||
CommonProblemDescriptor[] descriptors = myTree.getSelectedDescriptors();
|
||||
editorPanel.add(createBaseRightComponentFor(descriptors, refEntity), BorderLayout.CENTER);
|
||||
if (descriptors.length > 0) {
|
||||
final InspectionToolWrapper tool = myTree.getSelectedToolWrapper();
|
||||
LOG.assertTrue(tool != null);
|
||||
editorPanel.add(new QuickFixToolbar(myTree,
|
||||
myProject,
|
||||
myPreviewEditor,
|
||||
myProvider.getQuickFixes(tool, myTree)),
|
||||
BorderLayout.NORTH);
|
||||
}
|
||||
mySplitter.setSecondComponent(editorPanel);
|
||||
}
|
||||
finally {
|
||||
setCursor(currentCursor);
|
||||
}
|
||||
}
|
||||
|
||||
private void showInBrowser(@NotNull InspectionToolWrapper toolWrapper) {
|
||||
Cursor currentCursor = getCursor();
|
||||
setCursor(new Cursor(Cursor.WAIT_CURSOR));
|
||||
myBrowser.showDescription(toolWrapper);
|
||||
setCursor(currentCursor);
|
||||
private boolean reuseEditorFor(Document document) {
|
||||
return myPreviewEditor != null && !myPreviewEditor.isDisposed() && myPreviewEditor.getDocument() == document;
|
||||
}
|
||||
|
||||
private void showInBrowser(final RefEntity refEntity, CommonProblemDescriptor descriptor) {
|
||||
Cursor currentCursor = getCursor();
|
||||
setCursor(new Cursor(Cursor.WAIT_CURSOR));
|
||||
myBrowser.showPageFor(refEntity, descriptor);
|
||||
setCursor(currentCursor);
|
||||
private JComponent createBaseRightComponentFor(CommonProblemDescriptor[] descriptors,
|
||||
RefEntity selectedEntity) {
|
||||
final int count = descriptors.length;
|
||||
if (selectedEntity instanceof RefElement && !(((RefElement)selectedEntity).getElement() instanceof PsiDirectory)) {
|
||||
PsiElement selectedElement = ((RefElement)selectedEntity).getElement();
|
||||
if (count == 1) {
|
||||
final CommonProblemDescriptor descriptor = descriptors[0];
|
||||
if (descriptor instanceof ProblemDescriptorBase) {
|
||||
final PsiElement element = ((ProblemDescriptorBase)descriptor).getPsiElement();
|
||||
if (element != null) {
|
||||
selectedElement = element;
|
||||
}
|
||||
}
|
||||
}
|
||||
final PsiFile file = selectedElement.getContainingFile();
|
||||
final Document document = PsiDocumentManager.getInstance(file.getProject()).getDocument(file);
|
||||
|
||||
if (reuseEditorFor(document)) {
|
||||
myPreviewEditor.putUserData(PREVIEW_EDITOR_IS_REUSED_KEY, true);
|
||||
}
|
||||
else {
|
||||
myPreviewEditor = EditorFactory.getInstance().createEditor(document, myProject, file.getVirtualFile(), true);
|
||||
final EditorSettings settings = myPreviewEditor.getSettings();
|
||||
settings.setLineNumbersShown(false);
|
||||
settings.setLineMarkerAreaShown(false);
|
||||
settings.setAdditionalColumnsCount(0);
|
||||
settings.setAdditionalLinesCount(0);
|
||||
settings.setLeadingWhitespaceShown(true);
|
||||
settings.setRightMarginShown(true);
|
||||
settings.setRightMargin(60);
|
||||
UsagePreviewPanel.highlight(Collections.emptyList(), myPreviewEditor, myProject);
|
||||
}
|
||||
|
||||
if (count == 1) {
|
||||
final PsiElement finalSelectedElement = selectedElement;
|
||||
ApplicationManager.getApplication().invokeLater(() -> {
|
||||
if (myPreviewEditor != null && !myPreviewEditor.isDisposed()) {
|
||||
PsiDocumentManager.getInstance(myProject).commitAllDocuments();
|
||||
myPreviewEditor.getCaretModel().moveToOffset(finalSelectedElement.getTextOffset());
|
||||
myPreviewEditor.getScrollingModel().scrollToCaret(ScrollType.CENTER);
|
||||
}
|
||||
}, ModalityState.NON_MODAL);
|
||||
}
|
||||
return myPreviewEditor.getComponent();
|
||||
}
|
||||
else if (selectedEntity == null) {
|
||||
return new InspectionNodeInfo(myTree.getSelectedToolWrapper(), myProject);
|
||||
}
|
||||
return new JPanel();
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@@ -477,7 +516,7 @@ public class InspectionResultsView extends JPanel implements Disposable, Occuren
|
||||
}
|
||||
|
||||
private void registerActionShortcuts(@NotNull InspectionToolPresentation presentation) {
|
||||
final QuickFixAction[] fixes = presentation.getQuickFixes(RefEntity.EMPTY_ELEMENTS_ARRAY);
|
||||
final QuickFixAction[] fixes = presentation.getQuickFixes(RefEntity.EMPTY_ELEMENTS_ARRAY, null);
|
||||
if (fixes != null) {
|
||||
for (QuickFixAction fix : fixes) {
|
||||
fix.registerCustomShortcutSet(fix.getShortcutSet(), this);
|
||||
@@ -833,6 +872,10 @@ public class InspectionResultsView extends JPanel implements Disposable, Occuren
|
||||
return myScope;
|
||||
}
|
||||
|
||||
public void updateRightPanel() {
|
||||
syncRightPanel();
|
||||
}
|
||||
|
||||
private class CloseAction extends AnAction implements DumbAware {
|
||||
private CloseAction() {
|
||||
super(CommonBundle.message("action.close"), null, AllIcons.Actions.Cancel);
|
||||
@@ -905,4 +948,10 @@ public class InspectionResultsView extends JPanel implements Disposable, Occuren
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void releaseEditor(@Nullable Editor editor) {
|
||||
if (editor != null && !editor.isDisposed()) {
|
||||
EditorFactory.getInstance().releaseEditor(editor);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+4
-2
@@ -67,7 +67,7 @@ public interface InspectionToolPresentation extends ProblemDescriptionsProcessor
|
||||
@NotNull
|
||||
Set<RefModule> getModuleProblems();
|
||||
@Nullable
|
||||
QuickFixAction[] getQuickFixes(@NotNull final RefEntity[] refElements);
|
||||
QuickFixAction[] getQuickFixes(@NotNull final RefEntity[] refElements, @Nullable CommonProblemDescriptor[] descriptors);
|
||||
@NotNull
|
||||
Map<RefEntity, CommonProblemDescriptor[]> getProblemElements();
|
||||
@NotNull
|
||||
@@ -86,6 +86,8 @@ public interface InspectionToolPresentation extends ProblemDescriptionsProcessor
|
||||
GlobalInspectionContextImpl getContext();
|
||||
void ignoreProblem(RefEntity refEntity, CommonProblemDescriptor problem, int idx);
|
||||
@Nullable
|
||||
QuickFixAction[] extractActiveFixes(@NotNull RefEntity[] refElements, @NotNull Map<RefEntity, Set<QuickFix>> actions);
|
||||
QuickFixAction[] extractActiveFixes(@NotNull RefEntity[] refElements,
|
||||
@NotNull Map<RefEntity, CommonProblemDescriptor[]> descriptorMap,
|
||||
@Nullable CommonProblemDescriptor[] allowedDescriptors);
|
||||
void exportResults(@NotNull final Element parentNode);
|
||||
}
|
||||
|
||||
@@ -109,6 +109,9 @@ public class InspectionTree extends Tree {
|
||||
Object[] nodes = path.getPath();
|
||||
for (int j = nodes.length - 1; j >= 0; j--) {
|
||||
Object node = nodes[j];
|
||||
if (node instanceof InspectionGroupNode) {
|
||||
return null;
|
||||
}
|
||||
if (node instanceof InspectionNode) {
|
||||
InspectionToolWrapper wrapper = ((InspectionNode)node).getToolWrapper();
|
||||
if (toolWrapper == null) {
|
||||
@@ -125,6 +128,36 @@ public class InspectionTree extends Tree {
|
||||
return toolWrapper;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public RefEntity getCommonSelectedElement() {
|
||||
final Object node = getCommonSelectedNode();
|
||||
return node instanceof RefElementNode ? ((RefElementNode)node).getElement() : null;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private Object getCommonSelectedNode() {
|
||||
final TreePath[] paths = getSelectionPaths();
|
||||
if (paths == null) return null;
|
||||
final Object[][] resolvedPaths = new Object[paths.length][];
|
||||
for (int i = 0; i < paths.length; i++) {
|
||||
TreePath path = paths[i];
|
||||
resolvedPaths[i] = path.getPath();
|
||||
}
|
||||
|
||||
Object currentCommonNode = null;
|
||||
for (int i = 0; i < resolvedPaths[0].length; i++) {
|
||||
final Object currentNode = resolvedPaths[0][i];
|
||||
for (int j = 1; j < resolvedPaths.length; j++) {
|
||||
final Object o = resolvedPaths[j][i];
|
||||
if (!o.equals(currentNode)) {
|
||||
return currentCommonNode;
|
||||
}
|
||||
}
|
||||
currentCommonNode = currentNode;
|
||||
}
|
||||
return currentCommonNode;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public RefEntity[] getSelectedElements() {
|
||||
TreePath[] selectionPaths = getSelectionPaths();
|
||||
@@ -164,7 +197,6 @@ public class InspectionTree extends Tree {
|
||||
}
|
||||
|
||||
public CommonProblemDescriptor[] getSelectedDescriptors() {
|
||||
final InspectionToolWrapper toolWrapper = getSelectedToolWrapper();
|
||||
if (getSelectionCount() == 0) return EMPTY_DESCRIPTORS;
|
||||
final TreePath[] paths = getSelectionPaths();
|
||||
final LinkedHashSet<CommonProblemDescriptor> descriptors = new LinkedHashSet<CommonProblemDescriptor>();
|
||||
@@ -177,7 +209,9 @@ public class InspectionTree extends Tree {
|
||||
|
||||
private static void traverseDescriptors(InspectionTreeNode node, LinkedHashSet<CommonProblemDescriptor> descriptors){
|
||||
if (node instanceof ProblemDescriptionNode) {
|
||||
descriptors.add(((ProblemDescriptionNode)node).getDescriptor());
|
||||
if (node.isValid() && !node.isResolved()) {
|
||||
descriptors.add(((ProblemDescriptionNode)node).getDescriptor());
|
||||
}
|
||||
}
|
||||
for(int i = node.getChildCount() - 1; i >= 0; i--){
|
||||
traverseDescriptors((InspectionTreeNode)node.getChildAt(i), descriptors);
|
||||
|
||||
+60
@@ -0,0 +1,60 @@
|
||||
/*
|
||||
* Copyright 2000-2016 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.intellij.codeInspection.ui;
|
||||
|
||||
import com.intellij.ui.IdeBorderFactory;
|
||||
import com.intellij.ui.components.JBLabel;
|
||||
import com.intellij.ui.components.labels.LinkLabel;
|
||||
import com.intellij.util.ui.JBUI;
|
||||
import com.intellij.util.ui.tree.TreeUtil;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import javax.swing.*;
|
||||
import javax.swing.tree.DefaultMutableTreeNode;
|
||||
import javax.swing.tree.TreeNode;
|
||||
import java.awt.*;
|
||||
|
||||
/**
|
||||
* @author Dmitry Batkovich
|
||||
*/
|
||||
public class InspectionViewNavigationPanel extends JPanel {
|
||||
public InspectionViewNavigationPanel(InspectionTreeNode node, InspectionTree tree) {
|
||||
setLayout(new BorderLayout());
|
||||
setBorder(IdeBorderFactory.createEmptyBorder(5, 7, 0, 0));
|
||||
final String titleLabelText = getTitleText(node instanceof InspectionRootNode, true);
|
||||
add(new JBLabel(titleLabelText), BorderLayout.NORTH);
|
||||
final JPanel links = new JPanel();
|
||||
links.setLayout(new BoxLayout(links, BoxLayout.Y_AXIS));
|
||||
links.add(Box.createVerticalStrut(JBUI.scale(10)));
|
||||
add(BorderLayout.CENTER, links);
|
||||
for (int i = 0; i < node.getChildCount(); i++) {
|
||||
final TreeNode child = node.getChildAt(i);
|
||||
final LinkLabel link = new LinkLabel(child.toString(), null) {
|
||||
@Override
|
||||
public void doClick() {
|
||||
TreeUtil.selectInTree((DefaultMutableTreeNode)child, true, tree);
|
||||
}
|
||||
};
|
||||
link.setBorder(IdeBorderFactory.createEmptyBorder(1, 17, 3, 1));
|
||||
links.add(link);
|
||||
}
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public static String getTitleText(boolean addGroupWord, boolean addColon) {
|
||||
return "Select inspection " + (addGroupWord ? "group" : "") + " to see problems" + (addColon ? ":" : ".");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,230 @@
|
||||
/*
|
||||
* Copyright 2000-2016 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.intellij.codeInspection.ui;
|
||||
|
||||
import com.intellij.codeInspection.CommonProblemDescriptor;
|
||||
import com.intellij.codeInspection.QuickFix;
|
||||
import com.intellij.codeInspection.ex.InspectionToolWrapper;
|
||||
import com.intellij.codeInspection.ex.QuickFixAction;
|
||||
import com.intellij.codeInspection.reference.RefElement;
|
||||
import com.intellij.codeInspection.ui.actions.SuppressActionWrapper;
|
||||
import com.intellij.codeInspection.ui.actions.occurrences.GoToSubsequentOccurrenceAction;
|
||||
import com.intellij.icons.AllIcons;
|
||||
import com.intellij.ide.DataManager;
|
||||
import com.intellij.openapi.actionSystem.*;
|
||||
import com.intellij.openapi.actionSystem.ex.ComboBoxAction;
|
||||
import com.intellij.openapi.actionSystem.ex.CustomComponentAction;
|
||||
import com.intellij.openapi.editor.Editor;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.psi.PsiElement;
|
||||
import com.intellij.psi.PsiNamedElement;
|
||||
import com.intellij.ui.ClickListener;
|
||||
import com.intellij.ui.IdeBorderFactory;
|
||||
import com.intellij.ui.SimpleColoredComponent;
|
||||
import com.intellij.ui.SimpleTextAttributes;
|
||||
import com.intellij.ui.components.JBLabel;
|
||||
import com.intellij.util.ui.JBUI;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import javax.swing.*;
|
||||
import javax.swing.tree.TreePath;
|
||||
import java.awt.*;
|
||||
import java.awt.event.MouseEvent;
|
||||
import java.util.*;
|
||||
import java.util.List;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
/**
|
||||
* @author Dmitry Batkovich
|
||||
*/
|
||||
public class QuickFixToolbar extends JPanel {
|
||||
private static final int MAX_FIX_COUNT = 2;
|
||||
|
||||
public QuickFixToolbar(@NotNull InspectionTree tree,
|
||||
@NotNull Project project,
|
||||
@Nullable Editor editor,
|
||||
@Nullable QuickFixAction[] fixes) {
|
||||
final boolean hasFixes = fixes != null && fixes.length != 0;
|
||||
CommonProblemDescriptor[] descriptors = tree.getSelectedDescriptors();
|
||||
int problemCount = descriptors.length;
|
||||
final boolean multipleDescriptors = problemCount > 1;
|
||||
|
||||
setLayout(new BoxLayout(this, BoxLayout.PAGE_AXIS));
|
||||
List<JPanel> panels = new ArrayList<>();
|
||||
for (int i = 0; i < (multipleDescriptors ? 2 : 1); i++) {
|
||||
final JPanel line = new JPanel();
|
||||
line.setLayout(new FlowLayout(FlowLayout.LEFT, 0, 0));
|
||||
panels.add((JPanel)add(line));
|
||||
}
|
||||
if (multipleDescriptors || !hasFixes) {
|
||||
panels.get(0).setBorder(IdeBorderFactory.createEmptyBorder(5, 0, 0, 0));
|
||||
}
|
||||
|
||||
//fill(getBulbPlacement(hasFixes), QuickFixToolbar::createBulbIcon, panels);
|
||||
fill(getDescriptionLabelPlacement(multipleDescriptors),
|
||||
() -> getLabel(fixes, tree.getSelectionCount() == 1 ? (InspectionTreeNode)tree.getSelectionPath().getLastPathComponent() : null, problemCount), panels);
|
||||
fill(getFixesPlacement(hasFixes, multipleDescriptors), () -> createFixPanel(fixes), panels);
|
||||
fill(getSuppressPlacement(multipleDescriptors), () -> createSuppressionCombo(tree.getSelectedToolWrapper()
|
||||
, tree.getSelectionPath(), project), panels);
|
||||
fill(multipleDescriptors && editor != null ? 1 : -1, () -> ActionManager.getInstance().createActionToolbar("", GoToSubsequentOccurrenceAction.createNextPreviousActions(
|
||||
editor, descriptors), true).getComponent(), panels);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private static JComponent getLabel(QuickFixAction[] fixes, InspectionTreeNode targetNode, int problemsCount) {
|
||||
final String targetName = targetNode instanceof RefElementNode ? ((RefElementNode)targetNode).getElement().getName() : null;
|
||||
SimpleColoredComponent label = new SimpleColoredComponent();
|
||||
boolean hasFixesNonIntersectedFixes = fixes != null && fixes.length == 0;
|
||||
boolean hasFixes = fixes != null && fixes.length != 0;
|
||||
label.append((hasFixes ? " Fix " : " ") + problemsCount + " problems" + (targetName == null ? "" : (" in " + targetName)) + (
|
||||
hasFixesNonIntersectedFixes
|
||||
? ":" : ""), SimpleTextAttributes.REGULAR_BOLD_ATTRIBUTES);
|
||||
if (hasFixesNonIntersectedFixes) {
|
||||
label.append(" select a single problem to see its quick fixes");
|
||||
}
|
||||
|
||||
if (!hasFixes) {
|
||||
label.setBorder(IdeBorderFactory.createEmptyBorder(0, 3, 6, 0));
|
||||
}
|
||||
return label;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private static JLabel createBulbIcon() {
|
||||
final JLabel label = new JLabel(AllIcons.Actions.IntentionBulb);
|
||||
label.setBorder(IdeBorderFactory.createEmptyBorder(0, 10, 0, 0));
|
||||
return label;
|
||||
}
|
||||
|
||||
private static JComponent createSuppressionCombo(@NotNull final InspectionToolWrapper toolWrapper,
|
||||
@NotNull final TreePath path,
|
||||
@NotNull final Project project) {
|
||||
final ComboBoxAction action = new ComboBoxAction() {
|
||||
{
|
||||
getTemplatePresentation().setText("Suppress");
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
protected ActionGroup createPopupActionGroup(JComponent button) {
|
||||
return new SuppressActionWrapper(project, toolWrapper, path);
|
||||
}
|
||||
};
|
||||
action.setSmallVariant(false);
|
||||
return action.createCustomComponent(action.getTemplatePresentation());
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private static JPanel createFixPanel(QuickFixAction[] fixes) {
|
||||
JPanel fixPanel = new JPanel(new FlowLayout(FlowLayout.LEFT, JBUI.scale(3), JBUI.scale(5)));
|
||||
if (fixes.length > MAX_FIX_COUNT) {
|
||||
final ComboBoxAction fixComboBox = new ComboBoxAction() {
|
||||
{
|
||||
getTemplatePresentation().setText("Apply quick fixes");
|
||||
getTemplatePresentation().setIcon(AllIcons.Actions.CreateFromUsage);
|
||||
setSmallVariant(false);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
protected DefaultActionGroup createPopupActionGroup(JComponent button) {
|
||||
final DefaultActionGroup actionGroup = new DefaultActionGroup();
|
||||
for (QuickFixAction fix : fixes) {
|
||||
actionGroup.add(fix);
|
||||
}
|
||||
return actionGroup;
|
||||
}
|
||||
};
|
||||
fixPanel.add(fixComboBox.createCustomComponent(fixComboBox.getTemplatePresentation()));
|
||||
}
|
||||
else {
|
||||
for (QuickFixAction fix : fixes) {
|
||||
fixPanel.add(createQuickFixButton(fix));
|
||||
}
|
||||
}
|
||||
return fixPanel;
|
||||
}
|
||||
|
||||
private static void fill(int row,
|
||||
@NotNull Supplier<JComponent> componentSupplier,
|
||||
@NotNull List<JPanel> parent) {
|
||||
if (row == -1) {
|
||||
return;
|
||||
}
|
||||
final JPanel rowPanel = parent.get(row);
|
||||
rowPanel.add(componentSupplier.get());
|
||||
}
|
||||
|
||||
private static int getSuppressPlacement(boolean multipleDescriptors) {
|
||||
return multipleDescriptors ? 1 : 0;
|
||||
}
|
||||
|
||||
private static int getFixesPlacement(boolean hasQuickFixes, boolean multipleDescriptors) {
|
||||
return hasQuickFixes ? multipleDescriptors ? 1 : 0 : -1;
|
||||
}
|
||||
|
||||
private static int getDescriptionLabelPlacement(boolean multipleDescriptors) {
|
||||
return multipleDescriptors ? 0 : -1;
|
||||
}
|
||||
|
||||
private static int getBulbPlacement(boolean hasQuickFixes) {
|
||||
return hasQuickFixes ? 0 : -1;
|
||||
}
|
||||
|
||||
private static JComponent createQuickFixButton(@NotNull QuickFixAction fix) {
|
||||
final MyCustomComponentLocalQuickFixWrapper action = new MyCustomComponentLocalQuickFixWrapper(fix);
|
||||
return action.createCustomComponent(action.getTemplatePresentation());
|
||||
}
|
||||
|
||||
private static class MyCustomComponentLocalQuickFixWrapper extends AnAction implements CustomComponentAction {
|
||||
private QuickFixAction myUnderlying;
|
||||
|
||||
public MyCustomComponentLocalQuickFixWrapper(@NotNull QuickFixAction underlying) {
|
||||
myUnderlying = underlying;
|
||||
copyFrom(underlying);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public JComponent createCustomComponent(Presentation presentation) {
|
||||
final JButton button = new JButton(presentation.getText());
|
||||
button.setIcon(presentation.getIcon());
|
||||
new ClickListener() {
|
||||
@Override
|
||||
public boolean onClick(@NotNull MouseEvent event, int clickCount) {
|
||||
actionPerformed(AnActionEvent.createFromAnAction(MyCustomComponentLocalQuickFixWrapper.this,
|
||||
event,
|
||||
"LOCAL_QUICK_FIX_WRAPPER_PANEL",
|
||||
DataManager.getInstance().getDataContext(button)));
|
||||
return true;
|
||||
}
|
||||
}.installOn(button);
|
||||
return button;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void update(AnActionEvent e) {
|
||||
myUnderlying.update(e);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void actionPerformed(AnActionEvent e) {
|
||||
myUnderlying.actionPerformed(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -71,11 +71,6 @@ public class RefElementNode extends InspectionTreeNode {
|
||||
return myIcon.getIcon();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getProblemCount() {
|
||||
return Math.max(1, super.getProblemCount());
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
final RefEntity element = getElement();
|
||||
if (element == null || !element.isValid()) {
|
||||
|
||||
+21
-3
@@ -32,6 +32,7 @@ import com.intellij.codeInspection.ui.RefElementNode;
|
||||
import com.intellij.openapi.actionSystem.ActionGroup;
|
||||
import com.intellij.openapi.actionSystem.AnAction;
|
||||
import com.intellij.openapi.actionSystem.AnActionEvent;
|
||||
import com.intellij.openapi.actionSystem.Separator;
|
||||
import com.intellij.openapi.application.ApplicationManager;
|
||||
import com.intellij.openapi.command.CommandProcessor;
|
||||
import com.intellij.openapi.diagnostic.Logger;
|
||||
@@ -49,6 +50,8 @@ import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import javax.swing.tree.TreeNode;
|
||||
import javax.swing.tree.TreePath;
|
||||
import java.util.Arrays;
|
||||
import java.util.Comparator;
|
||||
import java.util.Set;
|
||||
|
||||
public class SuppressActionWrapper extends ActionGroup {
|
||||
@@ -60,7 +63,7 @@ public class SuppressActionWrapper extends ActionGroup {
|
||||
|
||||
public SuppressActionWrapper(@NotNull final Project project,
|
||||
@NotNull final InspectionToolWrapper toolWrapper,
|
||||
@NotNull final TreePath[] paths) {
|
||||
@NotNull final TreePath... paths) {
|
||||
super(InspectionsBundle.message("suppress.inspection.problem"), false);
|
||||
myProject = project;
|
||||
myManager = (InspectionManagerEx)InspectionManager.getInstance(myProject);
|
||||
@@ -83,14 +86,25 @@ public class SuppressActionWrapper extends ActionGroup {
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
public SuppressTreeAction[] getChildren(@Nullable final AnActionEvent e) {
|
||||
public AnAction[] getChildren(@Nullable final AnActionEvent e) {
|
||||
final SuppressIntentionAction[] suppressActions = InspectionManagerEx.getSuppressActions(myToolWrapper);
|
||||
if (suppressActions == null || suppressActions.length == 0) return new SuppressTreeAction[0];
|
||||
final SuppressTreeAction[] actions = new SuppressTreeAction[suppressActions.length];
|
||||
final AnAction[] actions = new AnAction[suppressActions.length + 1];
|
||||
for (int i = 0; i < suppressActions.length; i++) {
|
||||
final SuppressIntentionAction suppressAction = suppressActions[i];
|
||||
actions[i] = new SuppressTreeAction(suppressAction);
|
||||
}
|
||||
actions[suppressActions.length] = Separator.getInstance();
|
||||
Arrays.sort(actions, new Comparator<AnAction>() {
|
||||
@Override
|
||||
public int compare(AnAction a1, AnAction a2) {
|
||||
return getWeight(a1) - getWeight(a2);
|
||||
}
|
||||
|
||||
public int getWeight(AnAction a) {
|
||||
return a instanceof Separator ? 0 : ((SuppressTreeAction)a).isSuppressAll() ? 1 : -1;
|
||||
}
|
||||
});
|
||||
return actions;
|
||||
}
|
||||
|
||||
@@ -219,5 +233,9 @@ public class SuppressActionWrapper extends ActionGroup {
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public boolean isSuppressAll() {
|
||||
return mySuppressAction.isSuppressAll();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+128
@@ -0,0 +1,128 @@
|
||||
/*
|
||||
* Copyright 2000-2016 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.intellij.codeInspection.ui.actions.occurrences;
|
||||
|
||||
import com.intellij.codeInspection.CommonProblemDescriptor;
|
||||
import com.intellij.codeInspection.ProblemDescriptorBase;
|
||||
import com.intellij.icons.AllIcons;
|
||||
import com.intellij.openapi.actionSystem.ActionGroup;
|
||||
import com.intellij.openapi.actionSystem.AnAction;
|
||||
import com.intellij.openapi.actionSystem.AnActionEvent;
|
||||
import com.intellij.openapi.actionSystem.DefaultActionGroup;
|
||||
import com.intellij.openapi.application.ApplicationManager;
|
||||
import com.intellij.openapi.application.ModalityState;
|
||||
import com.intellij.openapi.editor.Editor;
|
||||
import com.intellij.openapi.editor.ScrollType;
|
||||
import com.intellij.psi.PsiDocumentManager;
|
||||
import com.intellij.psi.PsiElement;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
/**
|
||||
* @author Dmitry Batkovich
|
||||
*/
|
||||
public class GoToSubsequentOccurrenceAction extends AnAction {
|
||||
private final boolean myNext;
|
||||
private OccurrencesManager myManager;
|
||||
|
||||
private GoToSubsequentOccurrenceAction(boolean next, OccurrencesManager manager) {
|
||||
myNext = next;
|
||||
myManager = manager;
|
||||
getTemplatePresentation().setIcon(next ? AllIcons.Actions.NextOccurence : AllIcons.Actions.PreviousOccurence);
|
||||
getTemplatePresentation().setDescription("Navigate to the " + (next ? "Next" : "Previous") + " Occurrence");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void update(AnActionEvent e) {
|
||||
e.getPresentation().setEnabledAndVisible(myManager.hasValidSubsequent());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void actionPerformed(AnActionEvent e) {
|
||||
myManager.selectSubsequent(myNext);
|
||||
}
|
||||
|
||||
public static ActionGroup createNextPreviousActions(@NotNull Editor editor, @NotNull CommonProblemDescriptor[] descriptors) {
|
||||
OccurrencesManager manager = new OccurrencesManager(editor, descriptors);
|
||||
return new DefaultActionGroup(new GoToSubsequentOccurrenceAction(false, manager), new GoToSubsequentOccurrenceAction(true, manager));
|
||||
}
|
||||
|
||||
private static class OccurrencesManager {
|
||||
private final Editor myEditor;
|
||||
private final ProblemDescriptorBase[] myChildren;
|
||||
|
||||
private int mySelected = -1;
|
||||
|
||||
private OccurrencesManager(@NotNull Editor editor, @NotNull CommonProblemDescriptor[] descriptors) {
|
||||
myEditor = editor;
|
||||
myChildren = Arrays.stream(descriptors)
|
||||
.filter(d -> d instanceof ProblemDescriptorBase)
|
||||
.map(d -> (ProblemDescriptorBase) d)
|
||||
.filter(d -> {
|
||||
PsiElement element = d.getPsiElement();
|
||||
return element != null && element.isValid();
|
||||
})
|
||||
.sorted((o1, o2) -> o1.getPsiElement().getTextOffset() - o2.getPsiElement().getTextOffset())
|
||||
.toArray(ProblemDescriptorBase[]::new);
|
||||
selectSubsequent(true);
|
||||
}
|
||||
|
||||
public void selectSubsequent(boolean next) {
|
||||
int subsequentIdz = mySelected;
|
||||
while (true) {
|
||||
subsequentIdz += next ? 1 : -1;
|
||||
subsequentIdz += myChildren.length;
|
||||
subsequentIdz %= myChildren.length;
|
||||
if (mySelected == subsequentIdz) {
|
||||
throw new IllegalStateException("Selection is unavailable");
|
||||
}
|
||||
ProblemDescriptorBase descriptorBase = myChildren[subsequentIdz];
|
||||
if (descriptorBase.getPsiElement().isValid()) {
|
||||
mySelected = subsequentIdz;
|
||||
ApplicationManager.getApplication().invokeLater(() -> {
|
||||
if (myEditor == null || myEditor.isDisposed()) return;
|
||||
PsiElement toSelect = descriptorBase.getPsiElement();
|
||||
PsiDocumentManager.getInstance(myEditor.getProject()).commitAllDocuments();
|
||||
myEditor.getCaretModel().moveToOffset(toSelect.getTextOffset());
|
||||
myEditor.getScrollingModel().scrollToCaret(ScrollType.CENTER);
|
||||
myEditor.getSelectionModel().setSelection(toSelect.getTextRange().getStartOffset(), toSelect.getTextRange().getEndOffset());
|
||||
}, ModalityState.NON_MODAL);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public boolean hasValidSubsequent() {
|
||||
if (myEditor.isDisposed()) {
|
||||
return false;
|
||||
}
|
||||
int subsequentIdz = mySelected;
|
||||
while (true) {
|
||||
subsequentIdz += 1 + myChildren.length;
|
||||
subsequentIdz %= myChildren.length;
|
||||
if (mySelected == subsequentIdz) {
|
||||
return false;
|
||||
}
|
||||
ProblemDescriptorBase descriptorBase = myChildren[subsequentIdz];
|
||||
PsiElement element = descriptorBase.getPsiElement();
|
||||
if (element != null && element.isValid()) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -25,6 +25,7 @@ import com.intellij.openapi.editor.Editor;
|
||||
import com.intellij.openapi.fileEditor.FileEditorManager;
|
||||
import com.intellij.openapi.fileEditor.ex.FileEditorManagerEx;
|
||||
import com.intellij.openapi.keymap.KeymapUtil;
|
||||
import com.intellij.openapi.progress.ProcessCanceledException;
|
||||
import com.intellij.openapi.project.DumbAwareAction;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.util.Pair;
|
||||
@@ -67,6 +68,9 @@ public abstract class GotoActionBase extends AnAction {
|
||||
myHistoryIndex = strings == null || strings.size() <= 1 || !ourLastStrings.containsKey(myInAction) ? 0 : 1;
|
||||
gotoActionPerformed(e);
|
||||
}
|
||||
catch (ProcessCanceledException e1) {
|
||||
myInAction = null;
|
||||
}
|
||||
catch (Throwable t) {
|
||||
LOG.error(t);
|
||||
myInAction = null;
|
||||
|
||||
+5
-2
@@ -57,8 +57,7 @@ public class AbstractNewProjectStep extends DefaultActionGroup implements DumbAw
|
||||
|
||||
NullableConsumer<ProjectSettingsStepBase> callback = customization.createCallback();
|
||||
ProjectSpecificAction projectSpecificAction = customization.createProjectSpecificAction(callback);
|
||||
|
||||
addAll(projectSpecificAction.getChildren(null));
|
||||
addProjectSpecificAction(projectSpecificAction);
|
||||
|
||||
DirectoryProjectGenerator[] generators = customization.getProjectGenerators();
|
||||
customization.setUpBasicAction(projectSpecificAction, generators);
|
||||
@@ -67,6 +66,10 @@ public class AbstractNewProjectStep extends DefaultActionGroup implements DumbAw
|
||||
addAll(customization.getExtraActions(callback));
|
||||
}
|
||||
|
||||
protected void addProjectSpecificAction(@NotNull final ProjectSpecificAction projectSpecificAction) {
|
||||
addAll(projectSpecificAction.getChildren(null));
|
||||
}
|
||||
|
||||
protected static abstract class Customization {
|
||||
@NotNull
|
||||
protected ProjectSpecificAction createProjectSpecificAction(@NotNull final NullableConsumer<ProjectSettingsStepBase> callback) {
|
||||
|
||||
+11
-13
@@ -92,8 +92,6 @@ import java.io.StringReader;
|
||||
import java.util.*;
|
||||
import java.util.List;
|
||||
|
||||
import com.intellij.util.containers.Queue;
|
||||
|
||||
/**
|
||||
* User: anna
|
||||
* Date: 31-May-2006
|
||||
@@ -773,9 +771,9 @@ public class SingleInspectionProfilePanel extends JPanel {
|
||||
}
|
||||
|
||||
// TODO 134099: see IntentionDescriptionPanel#readHTML
|
||||
private boolean readHTML(String text) {
|
||||
public static boolean readHTML(JEditorPane browser, String text) {
|
||||
try {
|
||||
myBrowser.read(new StringReader(text), null);
|
||||
browser.read(new StringReader(text), null);
|
||||
return true;
|
||||
}
|
||||
catch (IOException ignored) {
|
||||
@@ -783,10 +781,10 @@ public class SingleInspectionProfilePanel extends JPanel {
|
||||
}
|
||||
}
|
||||
|
||||
// TODO 134099: see IntentionDescriptionPanel#toHTML
|
||||
private String toHTML(String text) {
|
||||
final HintHint hintHint = new HintHint(myBrowser, new Point(0, 0));
|
||||
hintHint.setFont(UIUtil.getLabelFont());
|
||||
// TODO 134099: see IntentionDescriptionPanel#setHTML
|
||||
public static String toHTML(JEditorPane browser, String text, boolean miniFontSize) {
|
||||
final HintHint hintHint = new HintHint(browser, new Point(0, 0));
|
||||
hintHint.setFont(miniFontSize ? UIUtil.getLabelFont(UIUtil.FontSize.SMALL) : UIUtil.getLabelFont());
|
||||
return HintUtil.prepareHintText(text, hintHint);
|
||||
}
|
||||
|
||||
@@ -806,8 +804,8 @@ public class SingleInspectionProfilePanel extends JPanel {
|
||||
final Descriptor defaultDescriptor = singleNode.getDefaultDescriptor();
|
||||
final String description = defaultDescriptor.loadDescription();
|
||||
try {
|
||||
if (!readHTML(SearchUtil.markup(toHTML(description), myProfileFilter.getFilter()))) {
|
||||
readHTML(toHTML("<b>" + UNDER_CONSTRUCTION + "</b>"));
|
||||
if (!readHTML(myBrowser, SearchUtil.markup(toHTML(myBrowser, description, false), myProfileFilter.getFilter()))) {
|
||||
readHTML(myBrowser, toHTML(myBrowser, "<b>" + UNDER_CONSTRUCTION + "</b>", false));
|
||||
}
|
||||
}
|
||||
catch (Throwable t) {
|
||||
@@ -819,11 +817,11 @@ public class SingleInspectionProfilePanel extends JPanel {
|
||||
|
||||
}
|
||||
else {
|
||||
readHTML(toHTML("Can't find inspection description."));
|
||||
readHTML(myBrowser, toHTML(myBrowser, "Can't find inspection description.", false));
|
||||
}
|
||||
}
|
||||
else {
|
||||
readHTML(toHTML("Multiple inspections are selected. You can edit them as a single inspection."));
|
||||
readHTML(myBrowser, toHTML(myBrowser, "Multiple inspections are selected. You can edit them as a single inspection.", false));
|
||||
}
|
||||
|
||||
myOptionsPanel.removeAll();
|
||||
@@ -1021,7 +1019,7 @@ public class SingleInspectionProfilePanel extends JPanel {
|
||||
|
||||
private void initOptionsAndDescriptionPanel() {
|
||||
myOptionsPanel.removeAll();
|
||||
readHTML(EMPTY_HTML);
|
||||
readHTML(myBrowser, EMPTY_HTML);
|
||||
myOptionsPanel.validate();
|
||||
myOptionsPanel.repaint();
|
||||
}
|
||||
|
||||
@@ -585,7 +585,9 @@ public abstract class BaseRefactoringProcessor implements Runnable {
|
||||
|
||||
@Override
|
||||
public String getMessage() {
|
||||
return StringUtil.join(messages, "\n");
|
||||
List<String> result = new ArrayList<>(messages);
|
||||
Collections.sort(result);
|
||||
return StringUtil.join(result, "\n");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -81,7 +81,7 @@ public abstract class ComboBoxAction extends AnAction implements CustomComponent
|
||||
DataContext context = e.getDataContext();
|
||||
Project project = e.getProject();
|
||||
if (project == null) return;
|
||||
DefaultActionGroup group = createPopupActionGroup(button);
|
||||
ActionGroup group = createPopupActionGroup(button);
|
||||
ListPopup popup = JBPopupFactory.getInstance().createActionGroupPopup(
|
||||
myPopupTitle, group, context, false, shouldShowDisabledActions(), false, null, getMaxRows(), getPreselectCondition());
|
||||
popup.setMinimumSize(new Dimension(getMinWidth(), getMinHeight()));
|
||||
@@ -124,7 +124,7 @@ public abstract class ComboBoxAction extends AnAction implements CustomComponent
|
||||
|
||||
|
||||
@NotNull
|
||||
protected abstract DefaultActionGroup createPopupActionGroup(JComponent button);
|
||||
protected abstract ActionGroup createPopupActionGroup(JComponent button);
|
||||
|
||||
protected int getMaxRows() {
|
||||
return 30;
|
||||
@@ -152,7 +152,9 @@ public abstract class ComboBoxAction extends AnAction implements CustomComponent
|
||||
setModel(new MyButtonModel());
|
||||
setHorizontalAlignment(LEFT);
|
||||
setFocusable(false);
|
||||
putClientProperty("styleCombo", Boolean.TRUE);
|
||||
if (isSmallVariant()) {
|
||||
putClientProperty("styleCombo", Boolean.TRUE);
|
||||
}
|
||||
Insets margins = getMargin();
|
||||
setMargin(JBUI.insets(margins.top, 2, margins.bottom, 2));
|
||||
if (isSmallVariant()) {
|
||||
@@ -277,7 +279,7 @@ public abstract class ComboBoxAction extends AnAction implements CustomComponent
|
||||
}
|
||||
|
||||
protected JBPopup createPopup(Runnable onDispose) {
|
||||
DefaultActionGroup group = createPopupActionGroup(this);
|
||||
ActionGroup group = createPopupActionGroup(this);
|
||||
|
||||
DataContext context = getDataContext();
|
||||
ListPopup popup = JBPopupFactory.getInstance().createActionGroupPopup(
|
||||
@@ -410,7 +412,6 @@ public abstract class ComboBoxAction extends AnAction implements CustomComponent
|
||||
final Dimension size = getSize();
|
||||
|
||||
if (SystemInfo.isMac && UIUtil.isUnderIntelliJLaF()) {
|
||||
putClientProperty("styleCombo", Boolean.TRUE);
|
||||
super.paint(g);
|
||||
} else {
|
||||
UISettings.setupAntialiasing(g);
|
||||
|
||||
@@ -570,7 +570,6 @@ public class JBScrollPane extends JScrollPane {
|
||||
// so that if we don't ask after resetting the bounds we may have gotten the wrong answer.
|
||||
if (viewport != null) {
|
||||
viewport.setBounds(bounds);
|
||||
pane.setComponentZOrder(viewport, pane.getComponentCount() - 1);
|
||||
if (scrollable != null && hsbOpaque && vsbOpaque) {
|
||||
viewTracksViewportWidth = scrollable.getScrollableTracksViewportWidth();
|
||||
viewTracksViewportHeight = scrollable.getScrollableTracksViewportHeight();
|
||||
@@ -655,7 +654,6 @@ public class JBScrollPane extends JScrollPane {
|
||||
int overlapY = !hsbOnTop ? 0 : overlapHeight;
|
||||
vsb.setBounds(vsbBounds.x, vsbBounds.y + overlapY, vsbBounds.width, vsbBounds.height - overlapHeight);
|
||||
vsb.putClientProperty(Alignment.class, vsbOnLeft ? Alignment.LEFT : Alignment.RIGHT);
|
||||
pane.setComponentZOrder(vsb, 0);
|
||||
}
|
||||
// Modify the bounds of the translucent scroll bar.
|
||||
if (!vsbOpaque) {
|
||||
@@ -714,6 +712,20 @@ public class JBScrollPane extends JScrollPane {
|
||||
vsbOnLeft ? rowHeadBounds.width : vsbBounds.width,
|
||||
hsbOnTop ? hsbBounds.height : colHeadBounds.height);
|
||||
}
|
||||
if (!vsbOpaque && vsbNeeded || !hsbOpaque && hsbNeeded) {
|
||||
fixComponentZOrder(vsb, 0);
|
||||
fixComponentZOrder(viewport, -1);
|
||||
}
|
||||
}
|
||||
|
||||
private static void fixComponentZOrder(Component component, int index) {
|
||||
if (component != null) {
|
||||
Container parent = component.getParent();
|
||||
synchronized (parent.getTreeLock()) {
|
||||
if (index < 0) index += parent.getComponentCount();
|
||||
parent.setComponentZOrder(component, index);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void adjustForVSB(Rectangle bounds, Insets insets, Rectangle vsbBounds, boolean vsbOpaque, boolean vsbOnLeft) {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2000-2015 JetBrains s.r.o.
|
||||
* Copyright 2000-2016 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -96,7 +96,7 @@ public class JobLauncherImpl extends JobLauncher {
|
||||
Boolean result = processImmediatelyIfTooFew(things, wrapper, runInReadAction, thingProcessor);
|
||||
if (result != null) return result.booleanValue();
|
||||
|
||||
ApplierCompleter<T> applier = new ApplierCompleter<T>(null, runInReadAction, wrapper, things, thingProcessor, 0, things.size(), null);
|
||||
ApplierCompleter<T> applier = new ApplierCompleter<>(null, runInReadAction, wrapper, things, thingProcessor, 0, things.size(), null);
|
||||
try {
|
||||
pool.invoke(applier);
|
||||
if (applier.throwable != null) throw applier.throwable;
|
||||
@@ -109,10 +109,7 @@ public class JobLauncherImpl extends JobLauncher {
|
||||
// then task2 calls checkCancel() and get here
|
||||
return false;
|
||||
}
|
||||
catch (RuntimeException e) {
|
||||
throw e;
|
||||
}
|
||||
catch (Error e) {
|
||||
catch (RuntimeException | Error e) {
|
||||
throw e;
|
||||
}
|
||||
catch (Throwable e) {
|
||||
@@ -125,7 +122,7 @@ public class JobLauncherImpl extends JobLauncher {
|
||||
// if {@code things} are too few to be processed in the real pool, returns TRUE if processed successfully, FALSE if not
|
||||
// returns null if things need to be processed in the real pool
|
||||
private static <T> Boolean processImmediatelyIfTooFew(@NotNull final List<T> things,
|
||||
final ProgressIndicator progress,
|
||||
@NotNull final ProgressIndicator progress,
|
||||
boolean runInReadAction,
|
||||
@NotNull final Processor<? super T> thingProcessor) {
|
||||
// commit can be invoked from within write action
|
||||
@@ -136,24 +133,16 @@ public class JobLauncherImpl extends JobLauncher {
|
||||
|
||||
if (things.size() <= 1 || JobSchedulerImpl.CORES_COUNT <= CORES_FORK_THRESHOLD) {
|
||||
final AtomicBoolean result = new AtomicBoolean(true);
|
||||
Runnable runnable = new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
ProgressManager.getInstance().executeProcessUnderProgress(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
//noinspection ForLoopReplaceableByForEach
|
||||
for (int i = 0; i < things.size(); i++) {
|
||||
T thing = things.get(i);
|
||||
if (!thingProcessor.process(thing)) {
|
||||
result.set(false);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}, progress);
|
||||
Runnable runnable = () -> ProgressManager.getInstance().executeProcessUnderProgress(() -> {
|
||||
//noinspection ForLoopReplaceableByForEach
|
||||
for (int i = 0; i < things.size(); i++) {
|
||||
T thing = things.get(i);
|
||||
if (!thingProcessor.process(thing)) {
|
||||
result.set(false);
|
||||
break;
|
||||
}
|
||||
}
|
||||
};
|
||||
}, progress);
|
||||
if (runInReadAction) {
|
||||
if (!ApplicationManagerEx.getApplicationEx().tryRunReadAction(runnable)) return false;
|
||||
}
|
||||
@@ -318,35 +307,32 @@ public class JobLauncherImpl extends JobLauncher {
|
||||
|
||||
@Override
|
||||
public Boolean call() throws Exception {
|
||||
ProgressManager.getInstance().executeProcessUnderProgress(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
try {
|
||||
while (true) {
|
||||
progress.checkCanceled();
|
||||
T element = failedToProcess.poll();
|
||||
if (element == null) element = things.take();
|
||||
ProgressManager.getInstance().executeProcessUnderProgress(() -> {
|
||||
try {
|
||||
while (true) {
|
||||
progress.checkCanceled();
|
||||
T element = failedToProcess.poll();
|
||||
if (element == null) element = things.take();
|
||||
|
||||
if (element == tombStone) {
|
||||
things.offer(element);
|
||||
result = true;
|
||||
if (element == tombStone) {
|
||||
things.offer(element);
|
||||
result = true;
|
||||
break;
|
||||
}
|
||||
try {
|
||||
if (!thingProcessor.process(element)) {
|
||||
result = false;
|
||||
break;
|
||||
}
|
||||
try {
|
||||
if (!thingProcessor.process(element)) {
|
||||
result = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
catch (RuntimeException e) {
|
||||
failedToProcess.add(element);
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
catch (RuntimeException e) {
|
||||
failedToProcess.add(element);
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
catch (InterruptedException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
catch (InterruptedException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}, progress);
|
||||
return result;
|
||||
@@ -372,7 +358,7 @@ public class JobLauncherImpl extends JobLauncher {
|
||||
}
|
||||
}
|
||||
|
||||
List<ForkJoinTask<Boolean>> tasks = new ArrayList<ForkJoinTask<Boolean>>();
|
||||
List<ForkJoinTask<Boolean>> tasks = new ArrayList<>();
|
||||
for (int i = 0; i < JobSchedulerImpl.CORES_COUNT; i++) {
|
||||
tasks.add(pool.submit(new MyTask(i)));
|
||||
}
|
||||
|
||||
@@ -218,6 +218,59 @@ public class Switcher extends AnAction implements DumbAware {
|
||||
final Alarm myAlarm;
|
||||
final SwitcherSpeedSearch mySpeedSearch;
|
||||
final String myTitle;
|
||||
|
||||
|
||||
private class MyFocusTraversalPolicy extends FocusTraversalPolicy {
|
||||
|
||||
@Override
|
||||
public Component getComponentAfter(Container aContainer, Component aComponent) {
|
||||
return aComponent == toolWindows ? files : toolWindows;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Component getComponentBefore(Container aContainer, Component aComponent) {
|
||||
return aComponent == toolWindows ? files : toolWindows;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Component getFirstComponent(Container aContainer) {
|
||||
return toolWindows;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Component getLastComponent(Container aContainer) {
|
||||
return files;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Component getDefaultComponent(Container aContainer) {
|
||||
return files;
|
||||
}
|
||||
}
|
||||
|
||||
private static void exchangeSelectionState (JBList toClear, JBList toSelect) {
|
||||
if (toSelect.getModel().getSize() > 0) {
|
||||
int index = Math.min(toClear.getSelectedIndex(), toSelect.getModel().getSize() - 1);
|
||||
toSelect.setSelectedIndex(index);
|
||||
toSelect.ensureIndexIsVisible(index);
|
||||
toClear.clearSelection();
|
||||
}
|
||||
}
|
||||
|
||||
private class MyToolWindowsListFocusListener extends FocusAdapter {
|
||||
@Override
|
||||
public void focusGained(FocusEvent e) {
|
||||
exchangeSelectionState(files, toolWindows);
|
||||
}
|
||||
}
|
||||
|
||||
private class MyFilesListFocusListener extends FocusAdapter {
|
||||
@Override
|
||||
public void focusGained(FocusEvent e) {
|
||||
exchangeSelectionState(toolWindows, files);
|
||||
}
|
||||
}
|
||||
|
||||
final ClickListener myClickListener = new ClickListener() {
|
||||
@Override
|
||||
public boolean onClick(@NotNull MouseEvent e, int clickCount) {
|
||||
@@ -287,6 +340,7 @@ public class Switcher extends AnAction implements DumbAware {
|
||||
}
|
||||
|
||||
toolWindows = new JBList(twModel);
|
||||
toolWindows.addFocusListener(new MyToolWindowsListFocusListener());
|
||||
if (pinned) {
|
||||
new NameFilteringListModel<ToolWindow>(toolWindows, new Function<ToolWindow, String>() {
|
||||
@NotNull
|
||||
@@ -526,6 +580,7 @@ public class Switcher extends AnAction implements DumbAware {
|
||||
ScrollingUtil.installActions(files);
|
||||
files.addMouseListener(this);
|
||||
files.addMouseMotionListener(this);
|
||||
files.addFocusListener(new MyFilesListFocusListener());
|
||||
myClickListener.installOn(files);
|
||||
ScrollingUtil.ensureSelectionExists(files);
|
||||
|
||||
@@ -569,12 +624,6 @@ public class Switcher extends AnAction implements DumbAware {
|
||||
}).createPopup();
|
||||
|
||||
if (isPinnedMode()) {
|
||||
new AnAction(null, null, null) {
|
||||
@Override
|
||||
public void actionPerformed(@NotNull AnActionEvent e) {
|
||||
changeSelection();
|
||||
}
|
||||
}.registerCustomShortcutSet(CustomShortcutSet.fromString("TAB"), this, myPopup);
|
||||
new AnAction(null, null, null) {
|
||||
@Override
|
||||
public void actionPerformed(@NotNull AnActionEvent e) {
|
||||
@@ -600,6 +649,22 @@ public class Switcher extends AnAction implements DumbAware {
|
||||
}
|
||||
myAlarm = new Alarm(Alarm.ThreadToUse.SWING_THREAD, myPopup);
|
||||
myPopup.showInCenterOf(window);
|
||||
|
||||
Container popupFocusAncestor = myPopup.getContent().getFocusCycleRootAncestor();
|
||||
|
||||
popupFocusAncestor.setFocusTraversalPolicy(new MyFocusTraversalPolicy());
|
||||
|
||||
addFocusTraversalKeys(popupFocusAncestor, KeyboardFocusManager.FORWARD_TRAVERSAL_KEYS, "RIGHT");
|
||||
addFocusTraversalKeys(popupFocusAncestor, KeyboardFocusManager.BACKWARD_TRAVERSAL_KEYS, "LEFT");
|
||||
|
||||
}
|
||||
|
||||
private static void addFocusTraversalKeys (Container focusCycleRoot, int focusTraversalType, String keyStroke) {
|
||||
Set<AWTKeyStroke> focusTraversalKeySet = focusCycleRoot.getFocusTraversalKeys(focusTraversalType);
|
||||
|
||||
Set<AWTKeyStroke> set = new HashSet<AWTKeyStroke>(focusTraversalKeySet);
|
||||
set.add(KeyStroke.getKeyStroke(keyStroke));
|
||||
focusCycleRoot.setFocusTraversalKeys(focusTraversalType, set);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@@ -653,12 +718,6 @@ public class Switcher extends AnAction implements DumbAware {
|
||||
if (ctrl && isAutoHide() || enter) {
|
||||
navigate(e);
|
||||
}
|
||||
else if (e.getKeyCode() == VK_LEFT) {
|
||||
goLeft();
|
||||
}
|
||||
else if (e.getKeyCode() == VK_RIGHT) {
|
||||
goRight();
|
||||
}
|
||||
}
|
||||
|
||||
KeyEvent lastEvent;
|
||||
@@ -673,18 +732,6 @@ public class Switcher extends AnAction implements DumbAware {
|
||||
closeTabOrToolWindow();
|
||||
break;
|
||||
}
|
||||
if (e.getKeyCode() == ALT_KEY) {
|
||||
changeSelection();
|
||||
}
|
||||
}
|
||||
|
||||
private void changeSelection() {
|
||||
if (isFilesSelected()) {
|
||||
goLeft();
|
||||
}
|
||||
else {
|
||||
goRight();
|
||||
}
|
||||
}
|
||||
|
||||
private void closeTabOrToolWindow() {
|
||||
@@ -721,7 +768,6 @@ public class Switcher extends AnAction implements DumbAware {
|
||||
}
|
||||
}, 300);
|
||||
if (jList.getModel().getSize() == 1) {
|
||||
goLeft();
|
||||
removeElementAt(jList, selectedIndex);
|
||||
this.remove(jList);
|
||||
this.remove(separator);
|
||||
@@ -793,38 +839,10 @@ public class Switcher extends AnAction implements DumbAware {
|
||||
return getSelectedList() == toolWindows;
|
||||
}
|
||||
|
||||
private void goRight() {
|
||||
if ((isFilesSelected() || !isFilesVisible()) && isAutoHide()) {
|
||||
cancel();
|
||||
}
|
||||
else {
|
||||
if (files.getModel().getSize() > 0) {
|
||||
final int index = Math.min(toolWindows.getSelectedIndex(), files.getModel().getSize() - 1);
|
||||
files.setSelectedIndex(index);
|
||||
files.ensureIndexIsVisible(index);
|
||||
toolWindows.getSelectionModel().clearSelection();
|
||||
IdeFocusManager.findInstanceByComponent(files).requestFocus(files, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void cancel() {
|
||||
myPopup.cancel();
|
||||
}
|
||||
|
||||
private void goLeft() {
|
||||
if (isToolWindowsSelected() && isAutoHide()) {
|
||||
cancel();
|
||||
}
|
||||
else {
|
||||
if (toolWindows.getModel().getSize() > 0) {
|
||||
toolWindows.setSelectedIndex(Math.min(files.getSelectedIndex(), toolWindows.getModel().getSize() - 1));
|
||||
files.getSelectionModel().clearSelection();
|
||||
IdeFocusManager.findInstanceByComponent(toolWindows).requestFocus(toolWindows, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void go(boolean forward) {
|
||||
JBList selected = getSelectedList();
|
||||
JList list = selected;
|
||||
|
||||
@@ -70,6 +70,7 @@
|
||||
<completion.contributor order="last, before JsonSchemaCompletionContributor" language="JSON" implementationClass="com.jetbrains.jsonSchema.ide.JsonSchemaCompletionContributor"/>
|
||||
<lang.documentationProvider language="JSON"
|
||||
implementationClass="com.jetbrains.jsonSchema.ide.JsonSchemaDocumentationProvider"/>
|
||||
<refactoring.elementListenerProvider implementation="com.jetbrains.jsonSchema.JsonSchemaRefactoringListenerProvider"/>
|
||||
</extensions>
|
||||
<extensions defaultExtensionNs="JavaScript">
|
||||
<JsonSchema.ProviderFactory implementation="com.jetbrains.jsonSchema.extension.JsonSchemaImportedProviderFactory"/>
|
||||
|
||||
@@ -262,6 +262,6 @@
|
||||
<extensionPoint name="remote.credentialsType" interface="com.intellij.remote.ext.CredentialsTypeEx"/>
|
||||
<extensionPoint name="remote.credentialsLanguageContribution"
|
||||
interface="com.intellij.remote.ext.CredentialsLanguageContribution"/>
|
||||
<extensionPoint name="stripTrailingSpacesLineFilter" interface="com.intellij.openapi.editor.StripTrailingSpacesLineFilter"/>
|
||||
<extensionPoint name="stripTrailingSpacesFilterFactory" interface="com.intellij.openapi.editor.StripTrailingSpacesFilterFactory"/>
|
||||
</extensionPoints>
|
||||
</idea-plugin>
|
||||
|
||||
@@ -27,4 +27,15 @@ SourceSafe
|
||||
TFS
|
||||
ro.redeul.google.go
|
||||
com.intellij.plugins.html.instantEditing
|
||||
com.jetbrains.intellij.api.watcher
|
||||
com.jetbrains.intellij.api.watcher
|
||||
com.jetbrains.php.framework
|
||||
com.intellij.phing
|
||||
com.intellij.apacheConfig
|
||||
com.jetbrains.plugins.ini4idea
|
||||
com.jetbrains.php.gae
|
||||
com.jetbrains.php.drupal
|
||||
com.jetbrains.php.wordPress
|
||||
org.jetbrains.plugins.phpstorm-remote-interpreter
|
||||
com.jetbrains.php.behat
|
||||
com.jetbrains.php.blade
|
||||
com.jetbrains.performancePlugin
|
||||
+16
-1
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2000-2015 JetBrains s.r.o.
|
||||
* Copyright 2000-2016 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -15,6 +15,8 @@
|
||||
*/
|
||||
package com.intellij.openapi.progress.impl;
|
||||
|
||||
import com.intellij.codeInsight.daemon.impl.DaemonProgressIndicator;
|
||||
import com.intellij.concurrency.SensitiveProgressWrapper;
|
||||
import com.intellij.ide.util.DelegatingProgressIndicator;
|
||||
import com.intellij.openapi.application.ApplicationManager;
|
||||
import com.intellij.openapi.application.ModalityState;
|
||||
@@ -377,6 +379,19 @@ public class ProgressIndicatorTest extends LightPlatformTestCase {
|
||||
}
|
||||
}
|
||||
|
||||
public void testSOEUnderExtremelyNestedWrappedIndicator() {
|
||||
ProgressIndicator indicator = new DaemonProgressIndicator();
|
||||
for (int i=0;i<10000;i++) {
|
||||
indicator = new SensitiveProgressWrapper(indicator);
|
||||
}
|
||||
ProgressManager.getInstance().executeProcessUnderProgress(() -> {
|
||||
ProgressIndicator progressIndicator = ProgressIndicatorProvider.getGlobalProgressIndicator();
|
||||
assertTrue(progressIndicator instanceof SensitiveProgressWrapper);
|
||||
progressIndicator.checkCanceled();
|
||||
progressIndicator.isCanceled();
|
||||
}, indicator);
|
||||
}
|
||||
|
||||
public void testBombedIndicator() {
|
||||
final int count = 10;
|
||||
new BombedProgressIndicator(count).runBombed(() -> {
|
||||
|
||||
@@ -19,5 +19,5 @@ package org.jetbrains.debugger
|
||||
* @author Konstantin.Ulitin
|
||||
*/
|
||||
interface WorkerManager {
|
||||
val activeWorkers: Set<String>
|
||||
val activeWorkers: Map<String, WebWorker>
|
||||
}
|
||||
@@ -21,5 +21,5 @@ import java.util.*
|
||||
* @author Konstantin.Ulitin
|
||||
*/
|
||||
abstract class WorkerManagerBase : WorkerManager {
|
||||
override val activeWorkers: Set<String> = Collections.emptySet()
|
||||
override val activeWorkers: Map<String, WebWorker> = Collections.emptyMap()
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
/*
|
||||
* Copyright 2000-2016 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.jetbrains.debugger
|
||||
|
||||
|
||||
/**
|
||||
* @author Konstantin.Ulitin
|
||||
*/
|
||||
interface WebWorker {
|
||||
val id: String
|
||||
val url: String
|
||||
}
|
||||
@@ -18,6 +18,7 @@ package com.intellij.usages.impl;
|
||||
|
||||
import com.intellij.lang.injection.InjectedLanguageManager;
|
||||
import com.intellij.openapi.application.ApplicationManager;
|
||||
import com.intellij.openapi.application.ModalityState;
|
||||
import com.intellij.openapi.diagnostic.Logger;
|
||||
import com.intellij.openapi.editor.*;
|
||||
import com.intellij.openapi.editor.colors.EditorColors;
|
||||
@@ -108,22 +109,30 @@ public class UsagePreviewPanel extends UsageContextPanelBase {
|
||||
revalidate();
|
||||
}
|
||||
|
||||
final Editor editor = myEditor;
|
||||
SwingUtilities.invokeLater(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
if (myProject.isDisposed()) return;
|
||||
highlight(infos, editor);
|
||||
}
|
||||
});
|
||||
highlight(infos, myEditor, myProject);
|
||||
}
|
||||
|
||||
private static final Key<Boolean> IN_PREVIEW_USAGE_FLAG = Key.create("IN_PREVIEW_USAGE_FLAG");
|
||||
private void highlight(@NotNull List<UsageInfo> infos, @NotNull Editor editor) {
|
||||
if (editor != myEditor) return; //already disposed
|
||||
PsiDocumentManager.getInstance(myProject).commitAllDocuments();
|
||||
|
||||
MarkupModel markupModel = myEditor.getMarkupModel();
|
||||
|
||||
public static void highlight(@NotNull final List<UsageInfo> infos, @NotNull final Editor editor, @NotNull final Project project) {
|
||||
@SuppressWarnings("UnnecessaryLocalVariable") final Editor editor1 = editor;
|
||||
ApplicationManager.getApplication().invokeLater(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
if (project.isDisposed()) return;
|
||||
//noinspection ConstantConditions
|
||||
if (editor1 == editor && !editor.isDisposed()) {
|
||||
doHighlight(infos, editor, project);
|
||||
}
|
||||
}
|
||||
}, ModalityState.NON_MODAL);
|
||||
}
|
||||
|
||||
private static void doHighlight(@NotNull List<UsageInfo> infos, @NotNull Editor editor, @NotNull Project project) {
|
||||
PsiDocumentManager.getInstance(project).commitAllDocuments();
|
||||
|
||||
MarkupModel markupModel = editor.getMarkupModel();
|
||||
for (RangeHighlighter highlighter : markupModel.getAllHighlighters()) {
|
||||
if (highlighter.getUserData(IN_PREVIEW_USAGE_FLAG) != null) {
|
||||
highlighter.dispose();
|
||||
@@ -154,15 +163,15 @@ public class UsagePreviewPanel extends UsageContextPanelBase {
|
||||
}
|
||||
}
|
||||
// highlight injected element in host document textrange
|
||||
textRange = InjectedLanguageManager.getInstance(myProject).injectedToHost(psiElement, textRange);
|
||||
textRange = InjectedLanguageManager.getInstance(project).injectedToHost(psiElement, textRange);
|
||||
|
||||
RangeHighlighter highlighter = markupModel.addRangeHighlighter(textRange.getStartOffset(), textRange.getEndOffset(),
|
||||
HighlighterLayer.ADDITIONAL_SYNTAX, attributes,
|
||||
HighlighterTargetArea.EXACT_RANGE);
|
||||
highlighter.putUserData(IN_PREVIEW_USAGE_FLAG, Boolean.TRUE);
|
||||
myEditor.getCaretModel().moveToOffset(textRange.getEndOffset());
|
||||
editor.getCaretModel().moveToOffset(textRange.getEndOffset());
|
||||
}
|
||||
myEditor.getScrollingModel().scrollToCaret(ScrollType.CENTER);
|
||||
editor.getScrollingModel().scrollToCaret(ScrollType.CENTER);
|
||||
}
|
||||
|
||||
private static final Key<UsagePreviewPanel> PREVIEW_EDITOR_FLAG = Key.create("PREVIEW_EDITOR_FLAG");
|
||||
|
||||
@@ -24,7 +24,6 @@ import com.intellij.openapi.util.Condition;
|
||||
import com.intellij.openapi.util.Disposer;
|
||||
import com.intellij.openapi.util.Ref;
|
||||
import com.intellij.openapi.util.ThrowableComputable;
|
||||
import com.intellij.openapi.util.io.FileUtil;
|
||||
import com.intellij.openapi.util.text.StringUtil;
|
||||
import com.intellij.openapi.vfs.VirtualFile;
|
||||
import com.intellij.util.CommonProcessors;
|
||||
@@ -34,7 +33,10 @@ import com.intellij.util.io.IOUtil;
|
||||
import com.intellij.util.io.KeyDescriptor;
|
||||
import com.intellij.util.io.Page;
|
||||
import com.intellij.util.io.PersistentEnumerator;
|
||||
import com.intellij.vcs.log.*;
|
||||
import com.intellij.vcs.log.CommitId;
|
||||
import com.intellij.vcs.log.Hash;
|
||||
import com.intellij.vcs.log.VcsLogHashMap;
|
||||
import com.intellij.vcs.log.VcsLogProvider;
|
||||
import com.intellij.vcs.log.impl.HashImpl;
|
||||
import com.intellij.vcs.log.impl.VcsRootsRegistry;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
@@ -80,20 +82,19 @@ public class VcsLogHashMapImpl implements Disposable, VcsLogHashMap {
|
||||
private final PersistentEnumerator<CommitId> myPersistentEnumerator;
|
||||
|
||||
public VcsLogHashMapImpl(@NotNull final Project project, @NotNull Map<VirtualFile, VcsLogProvider> logProviders) throws IOException {
|
||||
cleanupOldNaming(project, logProviders);
|
||||
String logId = calcLogId(project, logProviders);
|
||||
final File mapFile = new File(LOG_CACHE_APP_DIR, logId + "." + VERSION);
|
||||
if (!mapFile.exists()) {
|
||||
IOUtil.deleteAllFilesStartingWith(new File(LOG_CACHE_APP_DIR, logId));
|
||||
}
|
||||
|
||||
Disposer.register(project, this);
|
||||
myPersistentEnumerator = IOUtil.openCleanOrResetBroken(new ThrowableComputable<PersistentEnumerator<CommitId>, IOException>() {
|
||||
@Override
|
||||
public PersistentEnumerator<CommitId> compute() throws IOException {
|
||||
return new PersistentEnumerator<CommitId>(mapFile, new MyCommitIdKeyDescriptor(project), Page.PAGE_SIZE);
|
||||
}
|
||||
}, mapFile);
|
||||
Disposer.register(project, this);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@@ -102,13 +103,6 @@ public class VcsLogHashMapImpl implements Disposable, VcsLogHashMap {
|
||||
return project.getLocationHash() + "." + Integer.toHexString(hashcode);
|
||||
}
|
||||
|
||||
// TODO remove in IDEA 15
|
||||
private static void cleanupOldNaming(@NotNull Project project, @NotNull Map<VirtualFile, VcsLogProvider> providers) {
|
||||
int hashcode = calcLogProvidersHash(providers);
|
||||
String oldLogId = project.getName() + "." + hashcode;
|
||||
FileUtil.delete(new File(LOG_CACHE, oldLogId));
|
||||
}
|
||||
|
||||
private static int calcLogProvidersHash(@NotNull final Map<VirtualFile, VcsLogProvider> logProviders) {
|
||||
List<VirtualFile> sortedRoots = ContainerUtil.sorted(logProviders.keySet(), new Comparator<VirtualFile>() {
|
||||
@Override
|
||||
@@ -196,7 +190,7 @@ public class VcsLogHashMapImpl implements Disposable, VcsLogHashMap {
|
||||
}
|
||||
|
||||
private static class MyCommitIdKeyDescriptor implements KeyDescriptor<CommitId> {
|
||||
private final VcsRootsRegistry myRootsRegistry;
|
||||
@NotNull private final VcsRootsRegistry myRootsRegistry;
|
||||
|
||||
public MyCommitIdKeyDescriptor(@NotNull Project project) {
|
||||
myRootsRegistry = ServiceManager.getService(project, VcsRootsRegistry.class);
|
||||
|
||||
@@ -35,20 +35,20 @@ public class BranchesPanel extends JPanel {
|
||||
private static final int TOP = 2;
|
||||
private static final int BOTTOM = 3;
|
||||
@NotNull private final VcsLogDataHolder myDataHolder;
|
||||
@NotNull private final VcsLogUiImpl myUI;
|
||||
@NotNull private final VcsLogUiImpl myUi;
|
||||
@NotNull private final VcsRefPainter myReferencePainter;
|
||||
|
||||
@NotNull private LinkedHashMap<VirtualFile, List<RefGroup>> myRefGroups;
|
||||
@Nullable private Collection<VirtualFile> myRoots = null;
|
||||
|
||||
public BranchesPanel(@NotNull VcsLogDataHolder dataHolder, @NotNull VcsLogUiImpl UI, @NotNull RefsModel initialRefsModel) {
|
||||
public BranchesPanel(@NotNull VcsLogDataHolder dataHolder, @NotNull VcsLogUiImpl ui, @NotNull RefsModel initialRefsModel) {
|
||||
super(new FlowLayout(FlowLayout.LEADING, BIG_ROOTS_GAP - 2 * SMALL_ROOTS_GAP, 0));
|
||||
setBorder(new EmptyBorder(TOP, SMALL_ROOTS_GAP, BOTTOM, SMALL_ROOTS_GAP));
|
||||
|
||||
myDataHolder = dataHolder;
|
||||
myUI = UI;
|
||||
myUi = ui;
|
||||
myRefGroups = getRefsToDisplayOnPanel(initialRefsModel);
|
||||
myReferencePainter = new VcsRefPainter(myUI.getColorManager(), true);
|
||||
myReferencePainter = new VcsRefPainter(myUi.getColorManager(), true);
|
||||
|
||||
recreateComponents();
|
||||
}
|
||||
@@ -129,7 +129,7 @@ public class BranchesPanel extends JPanel {
|
||||
myGroups = groups;
|
||||
|
||||
for (RefGroup group : myGroups) {
|
||||
add(new ReferenceGroupComponent(group, myReferencePainter, myUI, root));
|
||||
add(new ReferenceGroupComponent(group, myReferencePainter, myUi, root));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -83,7 +83,7 @@ public class VcsLogGraphTable extends JBTable implements DataProvider, CopyProvi
|
||||
private static final int MAX_ROWS_TO_CALC_WIDTH = 1000;
|
||||
private static final int MAX_ROWS_TO_CALC_OFFSET = 100;
|
||||
|
||||
@NotNull private final VcsLogUiImpl myUI;
|
||||
@NotNull private final VcsLogUiImpl myUi;
|
||||
private final VcsLogDataHolder myLogDataHolder;
|
||||
private final MyDummyTableCellEditor myDummyEditor = new MyDummyTableCellEditor();
|
||||
@NotNull private final TableCellRenderer myDummyRenderer = new DefaultTableCellRenderer();
|
||||
@@ -104,13 +104,13 @@ public class VcsLogGraphTable extends JBTable implements DataProvider, CopyProvi
|
||||
}
|
||||
};
|
||||
|
||||
public VcsLogGraphTable(@NotNull VcsLogUiImpl UI, @NotNull final VcsLogDataHolder logDataHolder, @NotNull VisiblePack initialDataPack) {
|
||||
public VcsLogGraphTable(@NotNull VcsLogUiImpl ui, @NotNull final VcsLogDataHolder logDataHolder, @NotNull VisiblePack initialDataPack) {
|
||||
super();
|
||||
myUI = UI;
|
||||
myUi = ui;
|
||||
myLogDataHolder = logDataHolder;
|
||||
myGraphCommitCellRenderer = new GraphCommitCellRender(logDataHolder, myGraphCellPainter, this);
|
||||
|
||||
setDefaultRenderer(VirtualFile.class, new RootCellRenderer(myUI));
|
||||
setDefaultRenderer(VirtualFile.class, new RootCellRenderer(myUi));
|
||||
setDefaultRenderer(GraphCommitCell.class, myGraphCommitCellRenderer);
|
||||
setDefaultRenderer(String.class, new StringCellRenderer());
|
||||
|
||||
@@ -125,7 +125,7 @@ public class VcsLogGraphTable extends JBTable implements DataProvider, CopyProvi
|
||||
PopupHandler.installPopupHandler(this, VcsLogActionPlaces.POPUP_ACTION_GROUP, VcsLogActionPlaces.VCS_LOG_TABLE_PLACE);
|
||||
ScrollingUtil.installActions(this, false);
|
||||
|
||||
GraphTableModel model = new GraphTableModel(initialDataPack, myLogDataHolder, myUI);
|
||||
GraphTableModel model = new GraphTableModel(initialDataPack, myLogDataHolder, myUi);
|
||||
setModel(model);
|
||||
initColumnSize();
|
||||
}
|
||||
@@ -193,10 +193,10 @@ public class VcsLogGraphTable extends JBTable implements DataProvider, CopyProvi
|
||||
|
||||
private void setRootColumnSize(TableColumn column) {
|
||||
int rootWidth;
|
||||
if (!myUI.isMultipleRoots()) {
|
||||
if (!myUi.isMultipleRoots()) {
|
||||
rootWidth = 0;
|
||||
}
|
||||
else if (!myUI.isShowRootNames()) {
|
||||
else if (!myUi.isShowRootNames()) {
|
||||
rootWidth = ROOT_INDICATOR_WIDTH;
|
||||
}
|
||||
else {
|
||||
@@ -231,7 +231,7 @@ public class VcsLogGraphTable extends JBTable implements DataProvider, CopyProvi
|
||||
return "<html><b>" +
|
||||
((VirtualFile)at).getPresentableUrl() +
|
||||
"</b><br/>Click to " +
|
||||
(myUI.isShowRootNames() ? "collapse" : "expand") +
|
||||
(myUi.isShowRootNames() ? "collapse" : "expand") +
|
||||
"</html>";
|
||||
}
|
||||
}
|
||||
@@ -363,7 +363,7 @@ public class VcsLogGraphTable extends JBTable implements DataProvider, CopyProvi
|
||||
private boolean expandOrCollapseRoots(@NotNull MouseEvent e) {
|
||||
TableColumn column = getRootColumnOrNull(e);
|
||||
if (column != null) {
|
||||
myUI.setShowRootNames(!myUI.isShowRootNames());
|
||||
myUi.setShowRootNames(!myUi.isShowRootNames());
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
@@ -400,7 +400,7 @@ public class VcsLogGraphTable extends JBTable implements DataProvider, CopyProvi
|
||||
}
|
||||
}
|
||||
|
||||
myUI.repaintUI(); // in case of repaintUI doing something more than just repainting this table in some distant future
|
||||
myUi.repaintUI(); // in case of repaintUI doing something more than just repainting this table in some distant future
|
||||
|
||||
if (answer == null) {
|
||||
return;
|
||||
|
||||
@@ -45,9 +45,9 @@ public class GraphTableModel extends AbstractTableModel {
|
||||
|
||||
private boolean myMoreRequested;
|
||||
|
||||
public GraphTableModel(@NotNull VisiblePack dataPack, @NotNull VcsLogDataHolder dataHolder, @NotNull VcsLogUiImpl UI) {
|
||||
public GraphTableModel(@NotNull VisiblePack dataPack, @NotNull VcsLogDataHolder dataHolder, @NotNull VcsLogUiImpl ui) {
|
||||
myLogDataHolder = dataHolder;
|
||||
myUi = UI;
|
||||
myUi = ui;
|
||||
myDataPack = dataPack;
|
||||
myDataHolder = dataHolder;
|
||||
}
|
||||
|
||||
+2
-2
@@ -23,6 +23,7 @@ import com.intellij.psi.PsiModifierList;
|
||||
import com.intellij.psi.PsiModifierListOwner;
|
||||
import com.intellij.psi.util.PsiTreeUtil;
|
||||
import com.intellij.util.IncorrectOperationException;
|
||||
import com.intellij.util.VisibilityUtil;
|
||||
import com.siyeh.InspectionGadgetsBundle;
|
||||
import com.siyeh.ig.InspectionGadgetsFix;
|
||||
import org.jetbrains.annotations.NonNls;
|
||||
@@ -40,8 +41,7 @@ public class ChangeModifierFix extends InspectionGadgetsFix {
|
||||
@Override
|
||||
@NotNull
|
||||
public String getName() {
|
||||
return InspectionGadgetsBundle.message("change.modifier.quickfix",
|
||||
modifierText);
|
||||
return InspectionGadgetsBundle.message("change.modifier.quickfix", VisibilityUtil.toPresentableText(modifierText));
|
||||
}
|
||||
|
||||
@NotNull
|
||||
|
||||
+26
-4
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2000-2015 JetBrains s.r.o.
|
||||
* Copyright 2000-2016 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -15,13 +15,21 @@
|
||||
*/
|
||||
package com.siyeh.ig.j2me;
|
||||
|
||||
import com.intellij.codeInspection.ui.SingleCheckboxOptionsPanel;
|
||||
import com.intellij.psi.*;
|
||||
import com.siyeh.InspectionGadgetsBundle;
|
||||
import com.siyeh.ig.BaseInspection;
|
||||
import com.siyeh.ig.BaseInspectionVisitor;
|
||||
import com.siyeh.ig.psiutils.MethodCallUtils;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import javax.swing.*;
|
||||
|
||||
public class MethodCallInLoopConditionInspectionBase extends BaseInspection {
|
||||
|
||||
public boolean ignoreIterationMethods = true;
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
public String getDisplayName() {
|
||||
@@ -39,12 +47,18 @@ public class MethodCallInLoopConditionInspectionBase extends BaseInspection {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public JComponent createOptionsPanel() {
|
||||
return new SingleCheckboxOptionsPanel("Ignore iteration method calls", this, "ignoreIterationMethods");
|
||||
}
|
||||
|
||||
@Override
|
||||
public BaseInspectionVisitor buildVisitor() {
|
||||
return new MethodCallInLoopConditionVisitor();
|
||||
}
|
||||
|
||||
private static class MethodCallInLoopConditionVisitor extends BaseInspectionVisitor {
|
||||
private class MethodCallInLoopConditionVisitor extends BaseInspectionVisitor {
|
||||
|
||||
@Override
|
||||
public void visitForStatement(@NotNull PsiForStatement statement) {
|
||||
@@ -80,9 +94,17 @@ public class MethodCallInLoopConditionInspectionBase extends BaseInspection {
|
||||
final PsiElementVisitor visitor = new JavaRecursiveElementWalkingVisitor() {
|
||||
|
||||
@Override
|
||||
public void visitMethodCallExpression(
|
||||
@NotNull PsiMethodCallExpression expression) {
|
||||
public void visitMethodCallExpression(@NotNull PsiMethodCallExpression expression) {
|
||||
super.visitMethodCallExpression(expression);
|
||||
if (ignoreIterationMethods) {
|
||||
final PsiMethod method = expression.resolveMethod();
|
||||
if (MethodCallUtils.isCallToMethod(expression, CommonClassNames.JAVA_UTIL_ITERATOR, PsiType.BOOLEAN, "hasNext") ||
|
||||
MethodCallUtils.isCallToMethod(expression, "java.util.ListIterator", PsiType.BOOLEAN, "hasPrevious") ||
|
||||
MethodCallUtils.isCallToMethod(expression, "java.sql.ResultSet", PsiType.BOOLEAN, "next") ||
|
||||
MethodCallUtils.isCallToMethod(expression, "java.util.Enumeration", PsiType.BOOLEAN, "hasMoreElements")) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
registerMethodCallError(expression);
|
||||
}
|
||||
};
|
||||
|
||||
-22
@@ -1,22 +0,0 @@
|
||||
package com.siyeh.igtest.j2me;
|
||||
|
||||
public class MethodCallInLoopConditionInspection {
|
||||
public void foo() {
|
||||
for (int i = 0; i < bar(); i++) {
|
||||
|
||||
}
|
||||
while (bar() != 4) {
|
||||
foo();
|
||||
}
|
||||
|
||||
do {
|
||||
foo();
|
||||
}
|
||||
while (bar() != 4);
|
||||
|
||||
}
|
||||
|
||||
private int bar() {
|
||||
return 3;
|
||||
}
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user