From f8a49a6127b033af87b6f3f3285df9403718bc6f Mon Sep 17 00:00:00 2001 From: Dmitry Batkovich Date: Fri, 18 Mar 2016 11:20:26 +0300 Subject: [PATCH 01/81] inspection tool window: repaint navigation panel to avoid glitches --- .../ui/InspectionViewNavigationPanel.java | 30 +++++++++++-------- 1 file changed, 18 insertions(+), 12 deletions(-) diff --git a/platform/lang-impl/src/com/intellij/codeInspection/ui/InspectionViewNavigationPanel.java b/platform/lang-impl/src/com/intellij/codeInspection/ui/InspectionViewNavigationPanel.java index da25b546f6e4..110222cdaaab 100644 --- a/platform/lang-impl/src/com/intellij/codeInspection/ui/InspectionViewNavigationPanel.java +++ b/platform/lang-impl/src/com/intellij/codeInspection/ui/InspectionViewNavigationPanel.java @@ -50,6 +50,21 @@ public class InspectionViewNavigationPanel extends JPanel implements InspectionT resetChildrenNavigation(); } + @Override + public void updateLoadingProgress() { + resetChildrenAndRepaint(); + } + + @Override + public void treeLoaded() { + resetChildrenAndRepaint(); + } + + @NotNull + public static String getTitleText(boolean addGroupWord, boolean addColon) { + return "Select inspection" + (addGroupWord ? " group " : " ") + "to see problems" + (addColon ? ":" : "."); + } + private void resetChildrenNavigation() { final int currentChildrenCount = myNode.getChildCount(); if (myShownChildrenCount != currentChildrenCount) { @@ -70,18 +85,9 @@ public class InspectionViewNavigationPanel extends JPanel implements InspectionT } } - @NotNull - public static String getTitleText(boolean addGroupWord, boolean addColon) { - return "Select inspection" + (addGroupWord ? " group " : " ") + "to see problems" + (addColon ? ":" : "."); - } - - @Override - public void updateLoadingProgress() { - resetChildrenNavigation(); - } - - @Override - public void treeLoaded() { + private void resetChildrenAndRepaint() { resetChildrenNavigation(); + revalidate(); + repaint(); } } From 1a2e84ddfa113dc2516ee1daae6a5511e70ff35f Mon Sep 17 00:00:00 2001 From: Boris Puzikov Date: Sat, 19 Mar 2016 16:56:38 +0300 Subject: [PATCH 02/81] spell checker: levenshtein->damerau-levenstein --- .../util/testSrc/com/intellij/util/text/EditDistanceTest.java | 2 ++ .../src/com/intellij/spellchecker/engine/BaseSpellChecker.java | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/platform/util/testSrc/com/intellij/util/text/EditDistanceTest.java b/platform/util/testSrc/com/intellij/util/text/EditDistanceTest.java index 084d1791b007..57b9d4671125 100644 --- a/platform/util/testSrc/com/intellij/util/text/EditDistanceTest.java +++ b/platform/util/testSrc/com/intellij/util/text/EditDistanceTest.java @@ -40,6 +40,7 @@ public class EditDistanceTest { @Test public void optimalAlignment() { + assertEquals(0, EditDistance.optimalAlignment("", "", true)); assertEquals(1, EditDistance.optimalAlignment("ab", "ba", true)); assertEquals(2, EditDistance.optimalAlignment("AB", "ba", true)); assertEquals(3, EditDistance.optimalAlignment("ca", "abc", true)); @@ -48,6 +49,7 @@ public class EditDistanceTest { @Test public void optimalAlignmentCaseInsensitive() { + assertEquals(0, EditDistance.optimalAlignment("", "", false)); assertEquals(1, EditDistance.optimalAlignment("ab", "ba", false)); assertEquals(1, EditDistance.optimalAlignment("AB", "ba", false)); assertEquals(3, EditDistance.optimalAlignment("ca", "abc", false)); diff --git a/spellchecker/src/com/intellij/spellchecker/engine/BaseSpellChecker.java b/spellchecker/src/com/intellij/spellchecker/engine/BaseSpellChecker.java index a62777dc4070..408df45b8142 100644 --- a/spellchecker/src/com/intellij/spellchecker/engine/BaseSpellChecker.java +++ b/spellchecker/src/com/intellij/spellchecker/engine/BaseSpellChecker.java @@ -223,7 +223,7 @@ public class BaseSpellChecker implements SpellCheckerEngine { List suggestions = new ArrayList(rawSuggestions.size()); for (String rawSuggestion : rawSuggestions) { - int distance = EditDistance.levenshtein(transformed, rawSuggestion, true); + int distance = EditDistance.optimalAlignment(transformed, rawSuggestion, true); suggestions.add(new Suggestion(rawSuggestion, distance)); } From 26aae67407c2f0c63d740831d73747111a3e5d2a Mon Sep 17 00:00:00 2001 From: Eugene Zhuravlev Date: Sat, 19 Mar 2016 15:56:27 +0100 Subject: [PATCH 03/81] cross-compilation: fork javac process decision is based on required target platform version (language level) --- .../jps/incremental/java/JavaBuilder.java | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/jps/jps-builders/src/org/jetbrains/jps/incremental/java/JavaBuilder.java b/jps/jps-builders/src/org/jetbrains/jps/incremental/java/JavaBuilder.java index 93e5c9f2f5ea..fe74298cb857 100644 --- a/jps/jps-builders/src/org/jetbrains/jps/incremental/java/JavaBuilder.java +++ b/jps/jps-builders/src/org/jetbrains/jps/incremental/java/JavaBuilder.java @@ -384,13 +384,15 @@ public class JavaBuilder extends ModuleLevelBuilder { } final boolean rc; - if (!shouldForkCompilerProcess(context, chunkSdkVersion)) { + if (!shouldForkCompilerProcess(context, chunkSdkVersion, convertToNumber(getLanguageLevel(chunk.getModules().iterator().next())))) { rc = JavacMain.compile( options, files, classpath, _platformCp, sourcePath, outs, diagnosticSink, classesConsumer, context.getCancelStatus(), compilingTool ); } else { - // fork external javac + // fork external javac, compilers from SDK 1.6+ are supported + // todo: If chunkSDK is older than 1.6, we have to ask the user to specify a path to javac6+ to be used for compilation. + // todo: Add setting in compiler configuration for this. final String sdkHome = getChunkSdkHome(chunk); if (sdkHome == null) { diagnosticSink.report(new PlainMessageDiagnostic(Diagnostic.Kind.ERROR, "Cannot start javac process for " + chunk.getName() + ": unknown JDK home path.\nPlease check project configuration.")); @@ -449,7 +451,7 @@ public class JavaBuilder extends ModuleLevelBuilder { return null; } - private static boolean shouldForkCompilerProcess(CompileContext context, final int chunkSdkVersion) { + private static boolean shouldForkCompilerProcess(CompileContext context, final int chunkSdkVersion, int chunkLanguageLevel) { final int compilerSdkVersion = getCompilerSdkVersion(context); if (compilerSdkVersion < 9 || chunkSdkVersion < 0) { // javac up to version 9 supports all previous releases @@ -461,10 +463,13 @@ public class JavaBuilder extends ModuleLevelBuilder { // there is no way to specify full platform classpath for cross-compilation purposes. // We have for fork compiler process with corresponding SDK runtime to ensure that compiler resolves platform classes // against the SDK version specified for the given chunk. + // todo: if chunkSdkVersion complies to "one plus three back" rule, and "-release" option is supported, return false return true; } - // according to JEP 182: Retiring javac "one plus three back" policy - return Math.abs(compilerSdkVersion - chunkSdkVersion) > 3; + + // compilerSdkVersion is 9+ here, so applying JEP 182 "Retiring javac 'one plus three back'" policy + final int requestedTargetPlatformVersion = chunkLanguageLevel > 0 ? chunkLanguageLevel : Math.min(chunkLanguageLevel, chunkSdkVersion); + return Math.abs(compilerSdkVersion - requestedTargetPlatformVersion) > 3; } // If platformCp of the build process is the same as the target plafform, do not specify platformCp explicitly From e133141c951579c1d1a6714b550b0d8c9abe4076 Mon Sep 17 00:00:00 2001 From: "Anna.Kozlova" Date: Sat, 19 Mar 2016 18:29:17 +0100 Subject: [PATCH 04/81] class type: don't provide invalid types with inconsistent number of parameters if type corresponds to the raw substitution --- .../com/intellij/psi/impl/source/PsiImmediateClassType.java | 3 +++ 1 file changed, 3 insertions(+) diff --git a/java/java-psi-impl/src/com/intellij/psi/impl/source/PsiImmediateClassType.java b/java/java-psi-impl/src/com/intellij/psi/impl/source/PsiImmediateClassType.java index 4c2957e7b6c1..15823d067a90 100644 --- a/java/java-psi-impl/src/com/intellij/psi/impl/source/PsiImmediateClassType.java +++ b/java/java-psi-impl/src/com/intellij/psi/impl/source/PsiImmediateClassType.java @@ -130,6 +130,9 @@ public class PsiImmediateClassType extends PsiClassType.Stub { if (substituted != null) { lst.add(substituted); } + else { + return PsiType.EMPTY_ARRAY; + } } return lst.toArray(createArray(lst.size())); } From fecb1dd5450fe72fd0fbeb65711e341dc1e4353c Mon Sep 17 00:00:00 2001 From: Alexandru-Constantin Bledea Date: Sat, 19 Mar 2016 20:44:29 +0200 Subject: [PATCH 05/81] fix constructor arguments for extended inner classes --- .../decompiler/exps/InvocationExprent.java | 2 +- .../java/decompiler/SingleClassesTest.java | 3 +- .../pkg/TestExtendingSubclass$Subclass1.class | Bin 0 -> 555 bytes .../pkg/TestExtendingSubclass$Subclass2.class | Bin 0 -> 594 bytes .../classes/pkg/TestExtendingSubclass.class | Bin 0 -> 441 bytes .../results/TestExtendingSubclass.dec | 35 ++++++++++++++++++ .../src/pkg/TestExtendingSubclass.java | 18 +++++++++ 7 files changed, 56 insertions(+), 2 deletions(-) create mode 100644 plugins/java-decompiler/engine/testData/classes/pkg/TestExtendingSubclass$Subclass1.class create mode 100644 plugins/java-decompiler/engine/testData/classes/pkg/TestExtendingSubclass$Subclass2.class create mode 100644 plugins/java-decompiler/engine/testData/classes/pkg/TestExtendingSubclass.class create mode 100644 plugins/java-decompiler/engine/testData/results/TestExtendingSubclass.dec create mode 100644 plugins/java-decompiler/engine/testData/src/pkg/TestExtendingSubclass.java diff --git a/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/modules/decompiler/exps/InvocationExprent.java b/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/modules/decompiler/exps/InvocationExprent.java index 3ceb99cafc60..758b93f3adaa 100644 --- a/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/modules/decompiler/exps/InvocationExprent.java +++ b/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/modules/decompiler/exps/InvocationExprent.java @@ -334,7 +334,7 @@ public class InvocationExprent extends Exprent { boolean firstParameter = true; int start = isEnum ? 2 : 0; for (int i = start; i < lstParameters.size(); i++) { - if (sigFields == null) { + if (sigFields == null || null == sigFields.get(i)) { if (!firstParameter) { buf.append(", "); } diff --git a/plugins/java-decompiler/engine/test/org/jetbrains/java/decompiler/SingleClassesTest.java b/plugins/java-decompiler/engine/test/org/jetbrains/java/decompiler/SingleClassesTest.java index e905fb373014..260445ddd283 100644 --- a/plugins/java-decompiler/engine/test/org/jetbrains/java/decompiler/SingleClassesTest.java +++ b/plugins/java-decompiler/engine/test/org/jetbrains/java/decompiler/SingleClassesTest.java @@ -84,6 +84,7 @@ public class SingleClassesTest { @Test public void testMethodReferenceLetterClass() { doTest("pkg/TestMethodReferenceLetterClass"); } @Test public void testMemberAnnotations() { doTest("pkg/TestMemberAnnotations"); } @Test public void testStaticNameClash() { doTest("pkg/TestStaticNameClash"); } + @Test public void testExtendingSubclass() { doTest("pkg/TestExtendingSubclass"); } protected void doTest(String testFile, String... companionFiles) { ConsoleDecompiler decompiler = fixture.getDecompiler(); @@ -130,4 +131,4 @@ public class SingleClassesTest { return files; } -} \ No newline at end of file +} diff --git a/plugins/java-decompiler/engine/testData/classes/pkg/TestExtendingSubclass$Subclass1.class b/plugins/java-decompiler/engine/testData/classes/pkg/TestExtendingSubclass$Subclass1.class new file mode 100644 index 0000000000000000000000000000000000000000..fbf2ce2b4220de642b95b58ed3cbb2148db60da8 GIT binary patch literal 555 zcmaJ;O-sW-5Ph4*#>8l2{cL*?tWYbM3f?MSih>aI(9-)RU21B&l_VAamIo0$_yhb= z;!II{(8{vR%-c8f-tNACyuJZAMa@P5n+{BDS=h0#D^SdDM~{@)jw~2%xx}~P;_CTVxcOqzwnLb$^zb8@FpCoC>JO+_$4X}+p$MKW6~!H&tpl> zXj@pOXj2xzAO_$xkDei#FEE~{GT<;q5yZ4 Mo1tV7+gJrY0UM2l+yDRo literal 0 HcmV?d00001 diff --git a/plugins/java-decompiler/engine/testData/classes/pkg/TestExtendingSubclass$Subclass2.class b/plugins/java-decompiler/engine/testData/classes/pkg/TestExtendingSubclass$Subclass2.class new file mode 100644 index 0000000000000000000000000000000000000000..d30cc61f527200abd5220e809d3632d540ce773b GIT binary patch literal 594 zcma)3T}uK%6g{(UZrb{heX1`(2Bnb}y&1hoL9q0Y;`^wBZLMSMuF>D>A%Y(I0sW}x zjPwO%#4>x&oqNx@XJ%erpPm66qMSkk%W2qHaj@oKT_71>`cb7JQ1))FhxLw%;*+~r z>4C3@?Mbg6$S7*E?a0@Dd@Rt|{-e*klDD!RNIk5#OhCZ3TC literal 0 HcmV?d00001 diff --git a/plugins/java-decompiler/engine/testData/classes/pkg/TestExtendingSubclass.class b/plugins/java-decompiler/engine/testData/classes/pkg/TestExtendingSubclass.class new file mode 100644 index 0000000000000000000000000000000000000000..eb4f049285b0ef4ac6e9ef8c9d06eb0b0bc291bd GIT binary patch literal 441 zcma)2O-sW-5Pj38T^pmV@eB1NdQcCBiZ{heQ4oS2T6*84OWYbal1;?F@d@A@+b){$1=a;N1U3nsVHw4#wDyeP-5R6vLB*66*!orN z6WW*B=;DgdJUSi|oIy5Ggl?#fx+|X|m5*eUvf_tXEYq>fb;W0*Q#@!(*bAQ@lVGH5 zas65-GtnlQ|9?Snhgq4&>PA;>cK>vpPUVaA(1A (Lpkg/TestExtendingSubclass;Ljava/lang/String;)V' { + 8 5 + b 6 + } +} + +class 'pkg/TestExtendingSubclass$Subclass1' { + method ' (Lpkg/TestExtendingSubclass;Ljava/lang/String;)V' { + 9 11 + } +} + +Lines mapping: +9 <-> 12 +14 <-> 6 +15 <-> 7 +Not mapped: +8 +13 diff --git a/plugins/java-decompiler/engine/testData/src/pkg/TestExtendingSubclass.java b/plugins/java-decompiler/engine/testData/src/pkg/TestExtendingSubclass.java new file mode 100644 index 000000000000..f63baedce1f5 --- /dev/null +++ b/plugins/java-decompiler/engine/testData/src/pkg/TestExtendingSubclass.java @@ -0,0 +1,18 @@ +package pkg; + +import java.math.BigDecimal; + +public class TestExtendingSubclass { + + class Subclass1 { + Subclass1(String name) { + } + } + + class Subclass2 extends Subclass1 { + Subclass2(String name) { + super(name); + } + } + +} From eb4b800f64fbc346fb7e999a996e99d605cde109 Mon Sep 17 00:00:00 2001 From: Sergey Malenkov Date: Fri, 18 Mar 2016 16:49:45 +0300 Subject: [PATCH 06/81] Add internal test for ColorBlindness --- .../intellij/ide/ui/DaltonizationFilter.java | 10 +- .../com/intellij/ide/ui/SimulationFilter.java | 20 +-- .../src/com/intellij/ide/ui/WeightFilter.java | 16 +- .../ide/ui/ColorBlindnessInternalAction.java | 147 ++++++++++++++++++ 4 files changed, 175 insertions(+), 18 deletions(-) create mode 100644 platform/platform-impl/src/com/intellij/ide/ui/ColorBlindnessInternalAction.java diff --git a/platform/editor-ui-api/src/com/intellij/ide/ui/DaltonizationFilter.java b/platform/editor-ui-api/src/com/intellij/ide/ui/DaltonizationFilter.java index ced72d726d5c..ecd40a1ca7b9 100644 --- a/platform/editor-ui-api/src/com/intellij/ide/ui/DaltonizationFilter.java +++ b/platform/editor-ui-api/src/com/intellij/ide/ui/DaltonizationFilter.java @@ -8,21 +8,21 @@ final class DaltonizationFilter extends WeightFilter { public static final ImageFilter tritanopia = forTritanopia(null); public static ImageFilter forProtanopia(Double weight) { - return new DaltonizationFilter(weight, 0, 2.02344, -2.52581, 0, 1, 0, 0, 0, 1); + return new DaltonizationFilter("Protanopia", weight, 0, 2.02344, -2.52581, 0, 1, 0, 0, 0, 1); } public static ImageFilter forDeuteranopia(Double weight) { - return new DaltonizationFilter(weight, 1, 0, 0, 0.494207, 0, 1.24827, 0, 0, 1); + return new DaltonizationFilter("Deuteranopia", weight, 1, 0, 0, 0.494207, 0, 1.24827, 0, 0, 1); } public static ImageFilter forTritanopia(Double weight) { - return new DaltonizationFilter(weight, 1, 0, 0, 0, 1, 0, -0.395913, 0.801109, 0); + return new DaltonizationFilter("Tritanopia", weight, 1, 0, 0, 0, 1, 0, -0.395913, 0.801109, 0); } private final double[] myMatrix; - private DaltonizationFilter(Double weight, double... matrix) { - super(weight); + private DaltonizationFilter(String name, Double weight, double... matrix) { + super(name + " (daltonization)", weight); myMatrix = matrix; } diff --git a/platform/editor-ui-api/src/com/intellij/ide/ui/SimulationFilter.java b/platform/editor-ui-api/src/com/intellij/ide/ui/SimulationFilter.java index 86137be69739..f2b3d6942480 100644 --- a/platform/editor-ui-api/src/com/intellij/ide/ui/SimulationFilter.java +++ b/platform/editor-ui-api/src/com/intellij/ide/ui/SimulationFilter.java @@ -9,19 +9,19 @@ final class SimulationFilter extends WeightFilter { public static final ImageFilter achromatopsia = forAchromatopsia(null); public static ImageFilter forProtanopia(Double weight) { - return new SimulationFilter(weight, 0.7465, 0.2535, 1.273463, -0.073894); + return new SimulationFilter("Protanopia", weight, 0.7465, 0.2535, 1.273463, -0.073894); } - + public static ImageFilter forDeuteranopia(Double weight) { - return new SimulationFilter(weight, 1.4, -0.4, 0.968437, 0.003331); + return new SimulationFilter("Deuteranopia", weight, 1.4, -0.4, 0.968437, 0.003331); } public static ImageFilter forTritanopia(Double weight) { - return new SimulationFilter(weight, 0.1748, 0, 0.062921, 0.292119); + return new SimulationFilter("Tritanopia", weight, 0.1748, 0, 0.062921, 0.292119); } public static ImageFilter forAchromatopsia(Double weight) { - return new WeightFilter(weight) { + return new WeightFilter("Achromatopsia (simulation)", weight) { @Override int toRGB(int srcR, int srcG, int srcB) { double gray = 0.212656 * srcR + 0.715158 * srcG + 0.072186 * srcB; @@ -35,8 +35,8 @@ final class SimulationFilter extends WeightFilter { private final double myConfuseM; private final double myConfuseYint; - private SimulationFilter(Double weight, double x, double y, double m, double yint) { - super(weight); + private SimulationFilter(String name, Double weight, double x, double y, double m, double yint) { + super(name + " (simulation)", weight); myConfuseX = x; myConfuseY = y; myConfuseM = m; @@ -85,9 +85,9 @@ final class SimulationFilter extends WeightFilter { double fitG = ((dstG < 0 ? 0 : 1) - dstG) / diffG; double fitB = ((dstB < 0 ? 0 : 1) - dstB) / diffB; double adjust = Math.max(Math.max( // highest value - (fitR < 0 || 1 < fitR) ? 0 : fitR, - (fitG < 0 || 1 < fitG) ? 0 : fitG), - (fitB < 0 || 1 < fitB) ? 0 : fitB); + (fitR < 0 || 1 < fitR) ? 0 : fitR, + (fitG < 0 || 1 < fitG) ? 0 : fitG), + (fitB < 0 || 1 < fitB) ? 0 : fitB); // Shift proportional to the greatest shift dstR += adjust * diffR; dstG += adjust * diffG; diff --git a/platform/editor-ui-api/src/com/intellij/ide/ui/WeightFilter.java b/platform/editor-ui-api/src/com/intellij/ide/ui/WeightFilter.java index 8e00effef346..f926d59ed16e 100644 --- a/platform/editor-ui-api/src/com/intellij/ide/ui/WeightFilter.java +++ b/platform/editor-ui-api/src/com/intellij/ide/ui/WeightFilter.java @@ -3,16 +3,26 @@ package com.intellij.ide.ui; import java.awt.image.RGBImageFilter; abstract class WeightFilter extends RGBImageFilter { + private final String myName; private final Double myWeight; - WeightFilter(Double weight) { - if (weight != null && (weight < 0 || 1 < weight)) { - throw new IllegalArgumentException("weight " + weight + " out of [0..1]"); + WeightFilter(String name, Double weight) { + if (weight != null) { + if (weight < 0 || 1 < weight) { + throw new IllegalArgumentException("weight " + weight + " out of [0..1]"); + } + name = name + " weight: " + weight; } + myName = name; myWeight = weight; canFilterIndexColorModel = true; } + @Override + public String toString() { + return myName; + } + @Override public final int filterRGB(int x, int y, int rgb) { return (0xFF000000 & rgb) | toRGB(0xFF & (rgb >> 16), 0xFF & (rgb >> 8), 0xFF & rgb); diff --git a/platform/platform-impl/src/com/intellij/ide/ui/ColorBlindnessInternalAction.java b/platform/platform-impl/src/com/intellij/ide/ui/ColorBlindnessInternalAction.java new file mode 100644 index 000000000000..5163f40dadbd --- /dev/null +++ b/platform/platform-impl/src/com/intellij/ide/ui/ColorBlindnessInternalAction.java @@ -0,0 +1,147 @@ +/* + * 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.ide.ui; + +import com.intellij.openapi.actionSystem.AnActionEvent; +import com.intellij.openapi.project.DumbAwareAction; +import com.intellij.openapi.ui.ComboBox; +import com.intellij.openapi.ui.DialogWrapper; +import com.intellij.util.ui.ImageUtil; +import com.intellij.util.ui.JBDimension; +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.ItemEvent; +import java.awt.event.ItemListener; +import java.awt.image.BufferedImage; +import java.awt.image.ImageFilter; + +/** + * @author Sergey.Malenkov + */ +public class ColorBlindnessInternalAction extends DumbAwareAction { + @Override + public void actionPerformed(AnActionEvent event) { + new ColorDialog(event).show(); + } + + private static final class ColorDialog extends DialogWrapper { + private final ColorView myView = new ColorView(); + + private ColorDialog(AnActionEvent event) { + super(event.getProject()); + init(); + setTitle("ColorBlindness"); + } + + @Override + protected JComponent createCenterPanel() { + myView.setMinimumSize(new JBDimension(360, 200)); + myView.setPreferredSize(new JBDimension(720, 400)); + + JComboBox combo = new ComboBox<>(FilterItem.ALL); + combo.addItemListener(myView); + + JPanel panel = new JPanel(new BorderLayout(10, 10)); + panel.add(BorderLayout.CENTER, myView); + panel.add(BorderLayout.SOUTH, combo); + return panel; + } + + @NotNull + @Override + protected Action[] createActions() { + return new Action[]{getCancelAction()}; + } + } + + private static final class FilterItem { + private final ImageFilter myFilter; + + public FilterItem(ImageFilter filter) { + myFilter = filter; + } + + @Override + public String toString() { + return myFilter == null ? "No filtering" : myFilter.toString(); + } + + private static final FilterItem[] ALL = new FilterItem[]{ + new FilterItem(null), + new FilterItem(DaltonizationFilter.protanopia), + new FilterItem(DaltonizationFilter.forProtanopia(.5)), + new FilterItem(DaltonizationFilter.deuteranopia), + new FilterItem(DaltonizationFilter.forDeuteranopia(.5)), + new FilterItem(DaltonizationFilter.tritanopia), + new FilterItem(DaltonizationFilter.forTritanopia(.5)), + new FilterItem(SimulationFilter.protanopia), + new FilterItem(SimulationFilter.forProtanopia(.5)), + new FilterItem(SimulationFilter.deuteranopia), + new FilterItem(SimulationFilter.forDeuteranopia(.5)), + new FilterItem(SimulationFilter.tritanopia), + new FilterItem(SimulationFilter.forTritanopia(.5)), + new FilterItem(SimulationFilter.achromatopsia), + new FilterItem(SimulationFilter.forAchromatopsia(.5)), + }; + } + + private static final class ColorView extends JComponent implements ItemListener { + private ImageFilter myFilter; + private Image myImage; + + @Override + protected void paintComponent(Graphics g) { + Rectangle bounds = new Rectangle(getWidth(), getHeight()); + JBInsets.removeFrom(bounds, getInsets()); + if (bounds.isEmpty()) return; + + if (myImage == null || bounds.width != myImage.getWidth(this) || bounds.height != myImage.getHeight(this)) { + int[] array = new int[bounds.width * bounds.height]; + float width = (float)(bounds.width - 1); + float height = (float)(bounds.height - 1); + for (int i = 0, h = 0; h < bounds.height; h++) { + for (int w = 0; w < bounds.width; w++, i++) { + float level = 2 * h / height; + float saturation = (level > 1f) ? 1 : level; + float brightness = (level > 1f) ? 2 - level : 1; + array[i] = Color.HSBtoRGB(w / width, saturation, brightness); + } + } + BufferedImage image = UIUtil.createImage(bounds.width, bounds.height, BufferedImage.TYPE_INT_RGB); + image.setRGB(0, 0, bounds.width, bounds.height, array, 0, bounds.width); + myImage = ImageUtil.filter(image, myFilter); + } + g.drawImage(myImage, bounds.x, bounds.y, bounds.width, bounds.height, this); + } + + @Override + public void itemStateChanged(ItemEvent event) { + if (ItemEvent.SELECTED == event.getStateChange()) { + Object object = event.getItem(); + if (object instanceof FilterItem) { + FilterItem item = (FilterItem)object; + myFilter = item.myFilter; + myImage = null; + repaint(); + } + } + } + } +} From 9d6a4f1c73d5ab20f758ad8f23d84608acbe9a3b Mon Sep 17 00:00:00 2001 From: Sergey Malenkov Date: Sat, 19 Mar 2016 21:50:50 +0300 Subject: [PATCH 07/81] Fix results of the daltonization alghoritm --- .../src/com/intellij/ide/ui/DaltonizationFilter.java | 11 ++++------- .../src/com/intellij/ide/ui/WeightFilter.java | 4 ++++ 2 files changed, 8 insertions(+), 7 deletions(-) diff --git a/platform/editor-ui-api/src/com/intellij/ide/ui/DaltonizationFilter.java b/platform/editor-ui-api/src/com/intellij/ide/ui/DaltonizationFilter.java index ecd40a1ca7b9..d05917088c67 100644 --- a/platform/editor-ui-api/src/com/intellij/ide/ui/DaltonizationFilter.java +++ b/platform/editor-ui-api/src/com/intellij/ide/ui/DaltonizationFilter.java @@ -46,12 +46,9 @@ final class DaltonizationFilter extends WeightFilter { B = srcB - B; // Shift colors towards visible spectrum (apply error modifications) // and add compensation to original values - double dstR = srcR + (0.0 * R) + (0.0 * G) + (0.0 * B); - double dstG = srcG + (0.7 * R) + (1.0 * G) + (0.0 * B); - double dstB = srcB + (0.7 * R) + (0.0 * G) + (1.0 * B); - return toRGB(srcR, srcG, srcB, - dstR < 0 ? 0 : dstR > 255 ? 255 : dstR, - dstR < 0 ? 0 : dstR > 255 ? 255 : dstG, - dstR < 0 ? 0 : dstR > 255 ? 255 : dstB); + double dstR = fix(srcR + (0.0 * R) + (0.0 * G) + (0.0 * B)); + double dstG = fix(srcG + (0.7 * R) + (1.0 * G) + (0.0 * B)); + double dstB = fix(srcB + (0.7 * R) + (0.0 * G) + (1.0 * B)); + return toRGB(srcR, srcG, srcB, dstR, dstG, dstB); } } diff --git a/platform/editor-ui-api/src/com/intellij/ide/ui/WeightFilter.java b/platform/editor-ui-api/src/com/intellij/ide/ui/WeightFilter.java index f926d59ed16e..14a369e6e1c7 100644 --- a/platform/editor-ui-api/src/com/intellij/ide/ui/WeightFilter.java +++ b/platform/editor-ui-api/src/com/intellij/ide/ui/WeightFilter.java @@ -44,4 +44,8 @@ abstract class WeightFilter extends RGBImageFilter { srcB = (int)dstB; return (srcR << 16) | (srcG << 8) | srcB; } + + static double fix(double value) { + return Double.isNaN(value) || value < 0 ? 0 : value > 255 ? 255 : value; + } } From dec380a6e40640c8d4b6a519142660704d73a316 Mon Sep 17 00:00:00 2001 From: Sergey Malenkov Date: Sat, 19 Mar 2016 22:48:00 +0300 Subject: [PATCH 08/81] Add internal action for ColorBlindness test --- platform/platform-resources/src/idea/PlatformActions.xml | 1 + 1 file changed, 1 insertion(+) diff --git a/platform/platform-resources/src/idea/PlatformActions.xml b/platform/platform-resources/src/idea/PlatformActions.xml index cc74cfad64b0..90b4aecc8310 100644 --- a/platform/platform-resources/src/idea/PlatformActions.xml +++ b/platform/platform-resources/src/idea/PlatformActions.xml @@ -702,6 +702,7 @@ + From 2636722c3a275063dc044409bc2da37335816e0e Mon Sep 17 00:00:00 2001 From: Julia Beliaeva Date: Sun, 13 Mar 2016 03:30:02 +0300 Subject: [PATCH 09/81] [text-completion] extract interface for TextCompletionProvider, simplify contributor --- .../CompletionContributorForTextField.java | 48 --------------- .../util/TextCompletionContributor.java | 46 ++++++++++++++ .../intellij/util/TextCompletionProvider.java | 50 ++++++++++++++++ .../util/TextFieldCompletionProvider.java | 60 +++++++++++++++---- .../src/META-INF/LangExtensions.xml | 2 +- 5 files changed, 145 insertions(+), 61 deletions(-) delete mode 100644 platform/lang-impl/src/com/intellij/util/CompletionContributorForTextField.java create mode 100644 platform/lang-impl/src/com/intellij/util/TextCompletionContributor.java create mode 100644 platform/lang-impl/src/com/intellij/util/TextCompletionProvider.java diff --git a/platform/lang-impl/src/com/intellij/util/CompletionContributorForTextField.java b/platform/lang-impl/src/com/intellij/util/CompletionContributorForTextField.java deleted file mode 100644 index 427805facc71..000000000000 --- a/platform/lang-impl/src/com/intellij/util/CompletionContributorForTextField.java +++ /dev/null @@ -1,48 +0,0 @@ -package com.intellij.util; - -import com.intellij.codeInsight.completion.CompletionContributor; -import com.intellij.codeInsight.completion.CompletionParameters; -import com.intellij.codeInsight.completion.CompletionResultSet; -import com.intellij.openapi.project.DumbAware; -import com.intellij.openapi.project.DumbService; -import com.intellij.psi.PsiFile; -import com.intellij.psi.PsiPlainTextFile; -import org.jetbrains.annotations.NotNull; - -/** - * @author sergey.evdokimov - */ -public class CompletionContributorForTextField extends CompletionContributor implements DumbAware { - - @Override - public void fillCompletionVariants(@NotNull CompletionParameters parameters, @NotNull CompletionResultSet result) { - PsiFile file = parameters.getOriginalFile(); - if (!(file instanceof PsiPlainTextFile)) return; - - TextFieldCompletionProvider field = file.getUserData(TextFieldCompletionProvider.COMPLETING_TEXT_FIELD_KEY); - if (field == null) return; - - if (!(field instanceof DumbAware) && DumbService.isDumb(file.getProject())) return; - - String text = file.getText(); - int offset = Math.min(text.length(), parameters.getOffset()); - - String prefix = field.getPrefix(text.substring(0, offset)); - - CompletionResultSet activeResult; - - if (!result.getPrefixMatcher().getPrefix().equals(prefix)) { - activeResult = result.withPrefixMatcher(prefix); - } - else { - activeResult = result; - } - - if (field.isCaseInsensitivity()) { - activeResult = activeResult.caseInsensitive(); - } - - field.addCompletionVariants(text, offset, prefix, activeResult); - activeResult.stopHere(); - } -} diff --git a/platform/lang-impl/src/com/intellij/util/TextCompletionContributor.java b/platform/lang-impl/src/com/intellij/util/TextCompletionContributor.java new file mode 100644 index 000000000000..a1339d29f6c5 --- /dev/null +++ b/platform/lang-impl/src/com/intellij/util/TextCompletionContributor.java @@ -0,0 +1,46 @@ +/* + * 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.util; + +import com.intellij.codeInsight.completion.CompletionContributor; +import com.intellij.codeInsight.completion.CompletionParameters; +import com.intellij.codeInsight.completion.CompletionResultSet; +import com.intellij.openapi.project.DumbAware; +import com.intellij.psi.PsiFile; +import org.jetbrains.annotations.NotNull; + +/** + * @author sergey.evdokimov + */ +public class TextCompletionContributor extends CompletionContributor implements DumbAware { + + @Override + public void fillCompletionVariants(@NotNull CompletionParameters parameters, @NotNull CompletionResultSet result) { + PsiFile file = parameters.getOriginalFile(); + + TextCompletionProvider provider = TextCompletionProvider.getProvider(file); + if (provider == null) return; + + String text = file.getText(); + int offset = Math.min(text.length(), parameters.getOffset()); + String prefix = provider.getPrefix(text, offset); + if (prefix == null) return; + + CompletionResultSet activeResult = provider.applyPrefixMatcher(result, prefix); + + provider.fillCompletionVariants(parameters, prefix, activeResult); + } +} diff --git a/platform/lang-impl/src/com/intellij/util/TextCompletionProvider.java b/platform/lang-impl/src/com/intellij/util/TextCompletionProvider.java new file mode 100644 index 000000000000..087cbec47979 --- /dev/null +++ b/platform/lang-impl/src/com/intellij/util/TextCompletionProvider.java @@ -0,0 +1,50 @@ +/* + * 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.util; + +import com.intellij.codeInsight.completion.CompletionParameters; +import com.intellij.codeInsight.completion.CompletionResultSet; +import com.intellij.codeInsight.lookup.CharFilter; +import com.intellij.openapi.project.DumbService; +import com.intellij.openapi.util.Key; +import com.intellij.psi.PsiFile; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +public interface TextCompletionProvider { + Key COMPLETING_TEXT_FIELD_KEY = Key.create("COMPLETING_TEXT_FIELD_KEY"); + + @Nullable + String getPrefix(@NotNull String text, int offset); + + @NotNull + CompletionResultSet applyPrefixMatcher(@NotNull CompletionResultSet result, @NotNull String prefix); + + @Nullable + CharFilter.Result acceptChar(char c); + + void fillCompletionVariants(@NotNull CompletionParameters parameters, @NotNull String prefix, @NotNull CompletionResultSet result); + + @Nullable + static TextCompletionProvider getProvider(@NotNull PsiFile file) { + TextCompletionProvider provider = file.getUserData(COMPLETING_TEXT_FIELD_KEY); + + if (provider == null || (DumbService.isDumb(file.getProject()) && !DumbService.isDumbAware(provider))) { + return null; + } + return provider; + } +} diff --git a/platform/lang-impl/src/com/intellij/util/TextFieldCompletionProvider.java b/platform/lang-impl/src/com/intellij/util/TextFieldCompletionProvider.java index 09c1a7e83e06..9f27ba1a3738 100644 --- a/platform/lang-impl/src/com/intellij/util/TextFieldCompletionProvider.java +++ b/platform/lang-impl/src/com/intellij/util/TextFieldCompletionProvider.java @@ -1,13 +1,14 @@ package com.intellij.util; +import com.intellij.codeInsight.completion.CompletionParameters; import com.intellij.codeInsight.completion.CompletionResultSet; +import com.intellij.codeInsight.lookup.CharFilter; import com.intellij.openapi.editor.Document; import com.intellij.openapi.editor.Editor; import com.intellij.openapi.editor.ex.EditorEx; import com.intellij.openapi.fileTypes.FileType; import com.intellij.openapi.fileTypes.PlainTextLanguage; import com.intellij.openapi.project.Project; -import com.intellij.openapi.util.Key; import com.intellij.psi.PsiDocumentManager; import com.intellij.psi.PsiFile; import com.intellij.psi.PsiFileFactory; @@ -18,10 +19,7 @@ import org.jetbrains.annotations.Nullable; /** * @author sergey.evdokimov */ -public abstract class TextFieldCompletionProvider { - - static final Key COMPLETING_TEXT_FIELD_KEY = Key.create("COMPLETING_TEXT_FIELD_KEY"); - +public abstract class TextFieldCompletionProvider implements TextCompletionProvider { protected boolean myCaseInsensitivity; protected TextFieldCompletionProvider() { @@ -32,13 +30,49 @@ public abstract class TextFieldCompletionProvider { myCaseInsensitivity = caseInsensitivity; } + @Nullable + @Override + public String getPrefix(@NotNull String text, int offset) { + return getPrefix(text.substring(0, offset)); + } + + @NotNull + @Override + public CompletionResultSet applyPrefixMatcher(@NotNull CompletionResultSet result, @NotNull String prefix) { + CompletionResultSet activeResult = result; + + if (!activeResult.getPrefixMatcher().getPrefix().equals(prefix)) { + activeResult = activeResult.withPrefixMatcher(prefix); + } + + if (isCaseInsensitivity()) { + activeResult = activeResult.caseInsensitive(); + } + + return activeResult; + } + + @Nullable + @Override + public CharFilter.Result acceptChar(char c) { + return null; + } + + @Override + public void fillCompletionVariants(@NotNull CompletionParameters parameters, + @NotNull String prefix, + @NotNull CompletionResultSet result) { + addCompletionVariants(parameters.getOriginalFile().getText(), parameters.getOffset(), prefix, result); + result.stopHere(); + } + public void apply(@NotNull EditorTextField field, @NotNull String text) { Project project = field.getProject(); if (project != null) { field.setDocument(createDocument(project, text)); } } - + public void apply(@NotNull EditorTextField field) { apply(field, ""); } @@ -51,7 +85,7 @@ public abstract class TextFieldCompletionProvider { final PsiFile psiFile = PsiFileFactory.getInstance(project) .createFileFromText("Dummy." + fileType.getDefaultExtension(), fileType, text, stamp, true, false); - psiFile.putUserData(COMPLETING_TEXT_FIELD_KEY, this); + psiFile.putUserData(TextCompletionProvider.COMPLETING_TEXT_FIELD_KEY, this); final Document document = PsiDocumentManager.getInstance(project).getDocument(psiFile); assert document != null; @@ -67,23 +101,25 @@ public abstract class TextFieldCompletionProvider { return currentTextPrefix; } - protected abstract void addCompletionVariants(@NotNull String text, int offset, @NotNull String prefix, @NotNull CompletionResultSet result); + protected abstract void addCompletionVariants(@NotNull String text, + int offset, + @NotNull String prefix, + @NotNull CompletionResultSet result); @NotNull public EditorTextField createEditor(Project project) { return createEditor(project, true); } - + @NotNull public EditorTextField createEditor(Project project, final boolean shouldHaveBorder) { return createEditor(project, shouldHaveBorder, null); } - + @NotNull public EditorTextField createEditor(Project project, final boolean shouldHaveBorder, - @Nullable final Consumer editorConstructionCallback) - { + @Nullable final Consumer editorConstructionCallback) { return new EditorTextField(createDocument(project, ""), project, PlainTextLanguage.INSTANCE.getAssociatedFileType()) { @Override protected boolean shouldHaveBorder() { diff --git a/platform/platform-resources/src/META-INF/LangExtensions.xml b/platform/platform-resources/src/META-INF/LangExtensions.xml index ca09d5f97caf..61670bd35895 100644 --- a/platform/platform-resources/src/META-INF/LangExtensions.xml +++ b/platform/platform-resources/src/META-INF/LangExtensions.xml @@ -880,7 +880,7 @@ - From 2d12223d42f13f7b31fb5f0c8ade0910ef57796b Mon Sep 17 00:00:00 2001 From: Julia Beliaeva Date: Mon, 14 Mar 2016 01:02:23 +0300 Subject: [PATCH 10/81] [text-completion] create TextFieldWithCompletion --- .../util/TextCompletionContributor.java | 2 +- .../intellij/util/TextCompletionProvider.java | 14 ----- .../com/intellij/util/TextCompletionUtil.java | 54 +++++++++++++++++++ .../util/TextFieldCompletionProvider.java | 2 +- .../util/TextFieldWithCompletion.java | 47 ++++++++++++++++ 5 files changed, 103 insertions(+), 16 deletions(-) create mode 100644 platform/lang-impl/src/com/intellij/util/TextCompletionUtil.java create mode 100644 platform/lang-impl/src/com/intellij/util/TextFieldWithCompletion.java diff --git a/platform/lang-impl/src/com/intellij/util/TextCompletionContributor.java b/platform/lang-impl/src/com/intellij/util/TextCompletionContributor.java index a1339d29f6c5..56afdc8f7bb8 100644 --- a/platform/lang-impl/src/com/intellij/util/TextCompletionContributor.java +++ b/platform/lang-impl/src/com/intellij/util/TextCompletionContributor.java @@ -31,7 +31,7 @@ public class TextCompletionContributor extends CompletionContributor implements public void fillCompletionVariants(@NotNull CompletionParameters parameters, @NotNull CompletionResultSet result) { PsiFile file = parameters.getOriginalFile(); - TextCompletionProvider provider = TextCompletionProvider.getProvider(file); + TextCompletionProvider provider = TextCompletionUtil.getProvider(file); if (provider == null) return; String text = file.getText(); diff --git a/platform/lang-impl/src/com/intellij/util/TextCompletionProvider.java b/platform/lang-impl/src/com/intellij/util/TextCompletionProvider.java index 087cbec47979..f2a7ff3f1198 100644 --- a/platform/lang-impl/src/com/intellij/util/TextCompletionProvider.java +++ b/platform/lang-impl/src/com/intellij/util/TextCompletionProvider.java @@ -18,15 +18,11 @@ package com.intellij.util; import com.intellij.codeInsight.completion.CompletionParameters; import com.intellij.codeInsight.completion.CompletionResultSet; import com.intellij.codeInsight.lookup.CharFilter; -import com.intellij.openapi.project.DumbService; import com.intellij.openapi.util.Key; -import com.intellij.psi.PsiFile; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; public interface TextCompletionProvider { - Key COMPLETING_TEXT_FIELD_KEY = Key.create("COMPLETING_TEXT_FIELD_KEY"); - @Nullable String getPrefix(@NotNull String text, int offset); @@ -37,14 +33,4 @@ public interface TextCompletionProvider { CharFilter.Result acceptChar(char c); void fillCompletionVariants(@NotNull CompletionParameters parameters, @NotNull String prefix, @NotNull CompletionResultSet result); - - @Nullable - static TextCompletionProvider getProvider(@NotNull PsiFile file) { - TextCompletionProvider provider = file.getUserData(COMPLETING_TEXT_FIELD_KEY); - - if (provider == null || (DumbService.isDumb(file.getProject()) && !DumbService.isDumbAware(provider))) { - return null; - } - return provider; - } } diff --git a/platform/lang-impl/src/com/intellij/util/TextCompletionUtil.java b/platform/lang-impl/src/com/intellij/util/TextCompletionUtil.java new file mode 100644 index 000000000000..d0e878919010 --- /dev/null +++ b/platform/lang-impl/src/com/intellij/util/TextCompletionUtil.java @@ -0,0 +1,54 @@ +/* + * 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.util; + +import com.intellij.openapi.project.DumbService; +import com.intellij.openapi.util.Key; +import com.intellij.psi.PsiFile; +import com.intellij.ui.LanguageTextField; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +public class TextCompletionUtil { + public static final Key COMPLETING_TEXT_FIELD_KEY = Key.create("COMPLETING_TEXT_FIELD_KEY"); + + public static void installProvider(@NotNull PsiFile psiFile, @NotNull TextCompletionProvider provider) { + psiFile.putUserData(COMPLETING_TEXT_FIELD_KEY, provider); + } + + @Nullable + public static TextCompletionProvider getProvider(@NotNull PsiFile file) { + TextCompletionProvider provider = file.getUserData(COMPLETING_TEXT_FIELD_KEY); + + if (provider == null || (DumbService.isDumb(file.getProject()) && !DumbService.isDumbAware(provider))) { + return null; + } + return provider; + } + + public static class DocumentWithCompletionCreator extends LanguageTextField.SimpleDocumentCreator { + @NotNull private final TextCompletionProvider myProvider; + + public DocumentWithCompletionCreator(@NotNull TextCompletionProvider provider) { + myProvider = provider; + } + + @Override + public void customizePsiFile(@NotNull PsiFile file) { + installProvider(file, myProvider); + } + } +} diff --git a/platform/lang-impl/src/com/intellij/util/TextFieldCompletionProvider.java b/platform/lang-impl/src/com/intellij/util/TextFieldCompletionProvider.java index 9f27ba1a3738..1e75cafa7463 100644 --- a/platform/lang-impl/src/com/intellij/util/TextFieldCompletionProvider.java +++ b/platform/lang-impl/src/com/intellij/util/TextFieldCompletionProvider.java @@ -85,7 +85,7 @@ public abstract class TextFieldCompletionProvider implements TextCompletionProvi final PsiFile psiFile = PsiFileFactory.getInstance(project) .createFileFromText("Dummy." + fileType.getDefaultExtension(), fileType, text, stamp, true, false); - psiFile.putUserData(TextCompletionProvider.COMPLETING_TEXT_FIELD_KEY, this); + TextCompletionUtil.installProvider(psiFile, this); final Document document = PsiDocumentManager.getInstance(project).getDocument(psiFile); assert document != null; diff --git a/platform/lang-impl/src/com/intellij/util/TextFieldWithCompletion.java b/platform/lang-impl/src/com/intellij/util/TextFieldWithCompletion.java new file mode 100644 index 000000000000..b60ead97c0aa --- /dev/null +++ b/platform/lang-impl/src/com/intellij/util/TextFieldWithCompletion.java @@ -0,0 +1,47 @@ +/* + * 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.util; + +import com.intellij.codeInsight.AutoPopupController; +import com.intellij.openapi.editor.SpellCheckingEditorCustomizationProvider; +import com.intellij.openapi.editor.ex.EditorEx; +import com.intellij.openapi.fileTypes.PlainTextLanguage; +import com.intellij.openapi.project.Project; +import com.intellij.ui.EditorCustomization; +import com.intellij.ui.LanguageTextField; +import org.jetbrains.annotations.NotNull; + +public class TextFieldWithCompletion extends LanguageTextField { + private final boolean myAutoPopup; + + public TextFieldWithCompletion(@NotNull Project project, + @NotNull TextCompletionProvider provider, + @NotNull String value, + boolean oneLineMode, + boolean autoPopup) { + super(PlainTextLanguage.INSTANCE, project, value, new TextCompletionUtil.DocumentWithCompletionCreator(provider), oneLineMode); + myAutoPopup = autoPopup; + } + + @Override + protected EditorEx createEditor() { + EditorEx editor = super.createEditor(); + EditorCustomization disableSpellChecking = SpellCheckingEditorCustomizationProvider.getInstance().getDisabledCustomization(); + if (disableSpellChecking != null) disableSpellChecking.customize(editor); + editor.putUserData(AutoPopupController.ALWAYS_AUTO_POPUP, myAutoPopup); + return editor; + } +} From 6ed00e22f0201a00eb95ef596358f7d1e3e91fa7 Mon Sep 17 00:00:00 2001 From: Julia Beliaeva Date: Mon, 14 Mar 2016 02:31:10 +0300 Subject: [PATCH 11/81] [text-completion] move text completion classes to textCompletion package --- .../src/com/intellij/util/TextFieldCompletionProvider.java | 2 ++ .../util/{ => textCompletion}/TextCompletionContributor.java | 2 +- .../util/{ => textCompletion}/TextCompletionProvider.java | 2 +- .../intellij/util/{ => textCompletion}/TextCompletionUtil.java | 2 +- .../util/{ => textCompletion}/TextFieldWithCompletion.java | 2 +- platform/platform-resources/src/META-INF/LangExtensions.xml | 2 +- 6 files changed, 7 insertions(+), 5 deletions(-) rename platform/lang-impl/src/com/intellij/util/{ => textCompletion}/TextCompletionContributor.java (97%) rename platform/lang-impl/src/com/intellij/util/{ => textCompletion}/TextCompletionProvider.java (96%) rename platform/lang-impl/src/com/intellij/util/{ => textCompletion}/TextCompletionUtil.java (97%) rename platform/lang-impl/src/com/intellij/util/{ => textCompletion}/TextFieldWithCompletion.java (97%) diff --git a/platform/lang-impl/src/com/intellij/util/TextFieldCompletionProvider.java b/platform/lang-impl/src/com/intellij/util/TextFieldCompletionProvider.java index 1e75cafa7463..8d7bde9b3a70 100644 --- a/platform/lang-impl/src/com/intellij/util/TextFieldCompletionProvider.java +++ b/platform/lang-impl/src/com/intellij/util/TextFieldCompletionProvider.java @@ -13,6 +13,8 @@ import com.intellij.psi.PsiDocumentManager; import com.intellij.psi.PsiFile; import com.intellij.psi.PsiFileFactory; import com.intellij.ui.EditorTextField; +import com.intellij.util.textCompletion.TextCompletionProvider; +import com.intellij.util.textCompletion.TextCompletionUtil; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; diff --git a/platform/lang-impl/src/com/intellij/util/TextCompletionContributor.java b/platform/lang-impl/src/com/intellij/util/textCompletion/TextCompletionContributor.java similarity index 97% rename from platform/lang-impl/src/com/intellij/util/TextCompletionContributor.java rename to platform/lang-impl/src/com/intellij/util/textCompletion/TextCompletionContributor.java index 56afdc8f7bb8..9893e6383c83 100644 --- a/platform/lang-impl/src/com/intellij/util/TextCompletionContributor.java +++ b/platform/lang-impl/src/com/intellij/util/textCompletion/TextCompletionContributor.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package com.intellij.util; +package com.intellij.util.textCompletion; import com.intellij.codeInsight.completion.CompletionContributor; import com.intellij.codeInsight.completion.CompletionParameters; diff --git a/platform/lang-impl/src/com/intellij/util/TextCompletionProvider.java b/platform/lang-impl/src/com/intellij/util/textCompletion/TextCompletionProvider.java similarity index 96% rename from platform/lang-impl/src/com/intellij/util/TextCompletionProvider.java rename to platform/lang-impl/src/com/intellij/util/textCompletion/TextCompletionProvider.java index f2a7ff3f1198..03dfa793831c 100644 --- a/platform/lang-impl/src/com/intellij/util/TextCompletionProvider.java +++ b/platform/lang-impl/src/com/intellij/util/textCompletion/TextCompletionProvider.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package com.intellij.util; +package com.intellij.util.textCompletion; import com.intellij.codeInsight.completion.CompletionParameters; import com.intellij.codeInsight.completion.CompletionResultSet; diff --git a/platform/lang-impl/src/com/intellij/util/TextCompletionUtil.java b/platform/lang-impl/src/com/intellij/util/textCompletion/TextCompletionUtil.java similarity index 97% rename from platform/lang-impl/src/com/intellij/util/TextCompletionUtil.java rename to platform/lang-impl/src/com/intellij/util/textCompletion/TextCompletionUtil.java index d0e878919010..294b18c37294 100644 --- a/platform/lang-impl/src/com/intellij/util/TextCompletionUtil.java +++ b/platform/lang-impl/src/com/intellij/util/textCompletion/TextCompletionUtil.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package com.intellij.util; +package com.intellij.util.textCompletion; import com.intellij.openapi.project.DumbService; import com.intellij.openapi.util.Key; diff --git a/platform/lang-impl/src/com/intellij/util/TextFieldWithCompletion.java b/platform/lang-impl/src/com/intellij/util/textCompletion/TextFieldWithCompletion.java similarity index 97% rename from platform/lang-impl/src/com/intellij/util/TextFieldWithCompletion.java rename to platform/lang-impl/src/com/intellij/util/textCompletion/TextFieldWithCompletion.java index b60ead97c0aa..477f5fdf0316 100644 --- a/platform/lang-impl/src/com/intellij/util/TextFieldWithCompletion.java +++ b/platform/lang-impl/src/com/intellij/util/textCompletion/TextFieldWithCompletion.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package com.intellij.util; +package com.intellij.util.textCompletion; import com.intellij.codeInsight.AutoPopupController; import com.intellij.openapi.editor.SpellCheckingEditorCustomizationProvider; diff --git a/platform/platform-resources/src/META-INF/LangExtensions.xml b/platform/platform-resources/src/META-INF/LangExtensions.xml index 61670bd35895..787069f7d429 100644 --- a/platform/platform-resources/src/META-INF/LangExtensions.xml +++ b/platform/platform-resources/src/META-INF/LangExtensions.xml @@ -880,7 +880,7 @@ - From 4730d2ab34a933e16ee4bae74215ad56d1ed4e89 Mon Sep 17 00:00:00 2001 From: Julia Beliaeva Date: Fri, 11 Mar 2016 00:57:05 +0300 Subject: [PATCH 12/81] [text-completion] add char filter so that text completion provider could define which chars to accept IDEA-152511 --- .../TextCompletionCharFilter.java | 35 +++++++++++++++++++ .../src/META-INF/LangExtensions.xml | 1 + 2 files changed, 36 insertions(+) create mode 100644 platform/lang-impl/src/com/intellij/util/textCompletion/TextCompletionCharFilter.java diff --git a/platform/lang-impl/src/com/intellij/util/textCompletion/TextCompletionCharFilter.java b/platform/lang-impl/src/com/intellij/util/textCompletion/TextCompletionCharFilter.java new file mode 100644 index 000000000000..d55768ba9ac2 --- /dev/null +++ b/platform/lang-impl/src/com/intellij/util/textCompletion/TextCompletionCharFilter.java @@ -0,0 +1,35 @@ +/* + * 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.util.textCompletion; + +import com.intellij.codeInsight.lookup.CharFilter; +import com.intellij.codeInsight.lookup.Lookup; +import com.intellij.psi.PsiFile; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +public class TextCompletionCharFilter extends CharFilter { + @Nullable + @Override + public Result acceptChar(char c, int prefixLength, @NotNull Lookup lookup) { + if (!lookup.isCompletion()) return null; + PsiFile file = lookup.getPsiFile(); + if (file == null) return null; + TextCompletionProvider provider = TextCompletionUtil.getProvider(file); + if (provider != null) return provider.acceptChar(c); + return null; + } +} diff --git a/platform/platform-resources/src/META-INF/LangExtensions.xml b/platform/platform-resources/src/META-INF/LangExtensions.xml index 787069f7d429..c30e72c34d46 100644 --- a/platform/platform-resources/src/META-INF/LangExtensions.xml +++ b/platform/platform-resources/src/META-INF/LangExtensions.xml @@ -882,6 +882,7 @@ + From f0e80a92fce64fc96f58d5c5cff303f5a797938b Mon Sep 17 00:00:00 2001 From: Julia Beliaeva Date: Mon, 14 Mar 2016 03:06:29 +0300 Subject: [PATCH 13/81] [text-completion] completion provider for collection of values --- .../DefaultTextCompletionValueDescriptor.java | 86 ++++++++++++++++++ .../TextCompletionValueDescriptor.java | 26 ++++++ .../ValuesCompletionProvider.java | 91 +++++++++++++++++++ 3 files changed, 203 insertions(+) create mode 100644 platform/lang-impl/src/com/intellij/util/textCompletion/DefaultTextCompletionValueDescriptor.java create mode 100644 platform/lang-impl/src/com/intellij/util/textCompletion/TextCompletionValueDescriptor.java create mode 100644 platform/lang-impl/src/com/intellij/util/textCompletion/ValuesCompletionProvider.java diff --git a/platform/lang-impl/src/com/intellij/util/textCompletion/DefaultTextCompletionValueDescriptor.java b/platform/lang-impl/src/com/intellij/util/textCompletion/DefaultTextCompletionValueDescriptor.java new file mode 100644 index 000000000000..2b11cea9c464 --- /dev/null +++ b/platform/lang-impl/src/com/intellij/util/textCompletion/DefaultTextCompletionValueDescriptor.java @@ -0,0 +1,86 @@ +/* + * 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.util.textCompletion; + +import com.intellij.codeInsight.completion.InsertHandler; +import com.intellij.codeInsight.lookup.LookupElement; +import com.intellij.codeInsight.lookup.LookupElementBuilder; +import com.intellij.openapi.util.text.StringUtil; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import javax.swing.*; + +public abstract class DefaultTextCompletionValueDescriptor implements TextCompletionValueDescriptor { + @NotNull + protected abstract String getLookupString(@NotNull T item); + + @Nullable + protected Icon getIcon(@NotNull T item) { + return null; + } + + @Nullable + protected String getTailText(@NotNull T item) { + return null; + } + + @Nullable + protected String getTypeText(@NotNull T item) { + return null; + } + + @Nullable + protected InsertHandler createInsertHandler(@NotNull final T item) { + return null; + } + + @Override + public int compare(T item1, T item2) { + return StringUtil.compare(getLookupString(item1), getLookupString(item2), false); + } + + @NotNull + @Override + public LookupElementBuilder createLookupBuilder(@NotNull T item) { + LookupElementBuilder builder = LookupElementBuilder.create(item, getLookupString(item)) + .withIcon(getIcon(item)); + + InsertHandler handler = createInsertHandler(item); + if (handler != null) { + builder = builder.withInsertHandler(handler); + } + + String tailText = getTailText(item); + if (tailText != null) { + builder = builder.withTailText(tailText, true); + } + + String typeText = getTypeText(item); + if (typeText != null) { + builder = builder.withTypeText(typeText); + } + return builder; + } + + public static class StringValueDescriptor extends DefaultTextCompletionValueDescriptor { + @NotNull + @Override + public String getLookupString(@NotNull String item) { + return item; + } + } +} diff --git a/platform/lang-impl/src/com/intellij/util/textCompletion/TextCompletionValueDescriptor.java b/platform/lang-impl/src/com/intellij/util/textCompletion/TextCompletionValueDescriptor.java new file mode 100644 index 000000000000..e3e0c27fb7fe --- /dev/null +++ b/platform/lang-impl/src/com/intellij/util/textCompletion/TextCompletionValueDescriptor.java @@ -0,0 +1,26 @@ +/* + * 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.util.textCompletion; + +import com.intellij.codeInsight.lookup.LookupElementBuilder; +import org.jetbrains.annotations.NotNull; + +import java.util.Comparator; + +public interface TextCompletionValueDescriptor extends Comparator { + @NotNull + LookupElementBuilder createLookupBuilder(@NotNull T item); +} diff --git a/platform/lang-impl/src/com/intellij/util/textCompletion/ValuesCompletionProvider.java b/platform/lang-impl/src/com/intellij/util/textCompletion/ValuesCompletionProvider.java new file mode 100644 index 000000000000..da8c3d2a0a14 --- /dev/null +++ b/platform/lang-impl/src/com/intellij/util/textCompletion/ValuesCompletionProvider.java @@ -0,0 +1,91 @@ +/* + * 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.util.textCompletion; + +import com.intellij.codeInsight.completion.CompletionParameters; +import com.intellij.codeInsight.completion.CompletionResultSet; +import com.intellij.codeInsight.completion.PlainPrefixMatcher; +import com.intellij.codeInsight.lookup.CharFilter; +import com.intellij.util.containers.ContainerUtil; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.Collection; +import java.util.List; + +public class ValuesCompletionProvider implements TextCompletionProvider { + @NotNull private final TextCompletionValueDescriptor myDescriptor; + @NotNull private final List mySeparators; + @NotNull private final Collection myValues; + private final boolean myCaseSensitive; + + public ValuesCompletionProvider(@NotNull TextCompletionValueDescriptor descriptor, + @NotNull List separators, + @NotNull Collection values, boolean caseSensitive) { + myDescriptor = descriptor; + mySeparators = separators; + myValues = values; + myCaseSensitive = caseSensitive; + } + + @Nullable + @Override + public String getPrefix(@NotNull String text, int offset) { + return getPrefix(text, offset, mySeparators); + } + + @NotNull + protected static String getPrefix(@NotNull String text, int offset, @NotNull Collection separators) { + int index = -1; + for (char c : separators) { + index = Math.max(text.lastIndexOf(c, offset - 1), index); + } + return text.substring(index + 1, offset); + } + + @NotNull + @Override + public CompletionResultSet applyPrefixMatcher(@NotNull CompletionResultSet result, @NotNull String prefix) { + CompletionResultSet resultWithMatcher = result.withPrefixMatcher(new PlainPrefixMatcher(prefix)); + if (!myCaseSensitive) resultWithMatcher = resultWithMatcher.caseInsensitive(); + return resultWithMatcher; + } + + @Override + @Nullable + public CharFilter.Result acceptChar(char c) { + if (!mySeparators.contains(c)) return CharFilter.Result.ADD_TO_PREFIX; + return CharFilter.Result.HIDE_LOOKUP; + } + + @Override + public void fillCompletionVariants(@NotNull CompletionParameters parameters, + @NotNull String prefix, + @NotNull CompletionResultSet result) { + Collection values = getValues(prefix, result); + values = ContainerUtil.sorted(values, myDescriptor); + + for (T completionVariant : values) { + result.addElement(myDescriptor.createLookupBuilder(completionVariant)); + } + result.stopHere(); + } + + @NotNull + protected Collection getValues(@NotNull String prefix, @NotNull CompletionResultSet result) { + return myValues; + } +} From afff0c8b300e9b1294bce8e2cebf59b73758a161 Mon Sep 17 00:00:00 2001 From: Julia Beliaeva Date: Mon, 14 Mar 2016 03:29:52 +0300 Subject: [PATCH 14/81] [vcs-log] use new TextFieldWithCompletion in log filters --- .../log/ui/filter/MultilinePopupBuilder.java | 78 ++++++------------- 1 file changed, 22 insertions(+), 56 deletions(-) diff --git a/platform/vcs-log/impl/src/com/intellij/vcs/log/ui/filter/MultilinePopupBuilder.java b/platform/vcs-log/impl/src/com/intellij/vcs/log/ui/filter/MultilinePopupBuilder.java index 728bd2fc9045..250cee7bddf5 100644 --- a/platform/vcs-log/impl/src/com/intellij/vcs/log/ui/filter/MultilinePopupBuilder.java +++ b/platform/vcs-log/impl/src/com/intellij/vcs/log/ui/filter/MultilinePopupBuilder.java @@ -15,15 +15,13 @@ */ package com.intellij.vcs.log.ui.filter; -import com.intellij.codeInsight.AutoPopupController; +import com.google.common.primitives.Chars; +import com.intellij.codeInsight.completion.CompletionParameters; import com.intellij.codeInsight.completion.CompletionResultSet; -import com.intellij.codeInsight.lookup.LookupElementBuilder; import com.intellij.openapi.actionSystem.AnAction; import com.intellij.openapi.actionSystem.AnActionEvent; import com.intellij.openapi.actionSystem.CommonShortcuts; -import com.intellij.openapi.editor.SpellCheckingEditorCustomizationProvider; import com.intellij.openapi.editor.ex.EditorEx; -import com.intellij.openapi.fileTypes.FileTypes; import com.intellij.openapi.keymap.KeymapUtil; import com.intellij.openapi.project.DumbAwareAction; import com.intellij.openapi.project.Project; @@ -31,13 +29,13 @@ import com.intellij.openapi.ui.popup.ComponentPopupBuilder; import com.intellij.openapi.ui.popup.JBPopup; import com.intellij.openapi.ui.popup.JBPopupFactory; import com.intellij.openapi.util.text.StringUtil; -import com.intellij.ui.EditorCustomization; import com.intellij.ui.EditorTextField; -import com.intellij.ui.LanguageTextField; import com.intellij.ui.SoftWrapsEditorCustomization; import com.intellij.util.Function; -import com.intellij.util.TextFieldCompletionProviderDumbAware; import com.intellij.util.containers.ContainerUtil; +import com.intellij.util.textCompletion.DefaultTextCompletionValueDescriptor; +import com.intellij.util.textCompletion.TextFieldWithCompletion; +import com.intellij.util.textCompletion.ValuesCompletionProvider; import org.jetbrains.annotations.NotNull; import javax.swing.*; @@ -46,7 +44,6 @@ import java.awt.*; import java.util.Collection; class MultilinePopupBuilder { - private static final char[] SEPARATORS = {',', '|', '\n'}; @NotNull private final EditorTextField myTextField; @@ -63,20 +60,16 @@ class MultilinePopupBuilder { Collection values, boolean supportsNegativeValues, @NotNull String initialValue) { - EditorTextField textField = new LanguageTextField(FileTypes.PLAIN_TEXT.getLanguage(), project, "") { - @Override - protected EditorEx createEditor() { - EditorEx editor = super.createEditor(); - SoftWrapsEditorCustomization.ENABLED.customize(editor); - EditorCustomization disableSpellChecking = SpellCheckingEditorCustomizationProvider.getInstance().getDisabledCustomization(); - if (disableSpellChecking != null) disableSpellChecking.customize(editor); - editor.putUserData(AutoPopupController.ALWAYS_AUTO_POPUP, true); - return editor; - } - }; - new MyCompletionProvider(values, supportsNegativeValues).apply(textField, initialValue); + TextFieldWithCompletion textField = + new TextFieldWithCompletion(project, new MyCompletionProvider(values, supportsNegativeValues), initialValue, false, true) { + @Override + protected EditorEx createEditor() { + EditorEx editor = super.createEditor(); + SoftWrapsEditorCustomization.ENABLED.customize(editor); + return editor; + } + }; textField.setBorder(new CompoundBorder(BorderFactory.createEmptyBorder(2, 2, 2, 2), textField.getBorder())); - textField.setOneLineMode(false); return textField; } @@ -115,45 +108,18 @@ class MultilinePopupBuilder { }); } - private static class MyCompletionProvider extends TextFieldCompletionProviderDumbAware { - - @NotNull private final Collection myValues; - private final boolean mySupportsNegativeValues; - + private static class MyCompletionProvider extends ValuesCompletionProvider { MyCompletionProvider(@NotNull Collection values, boolean supportsNegativeValues) { - super(true); - myValues = values; - mySupportsNegativeValues = supportsNegativeValues; + super(new DefaultTextCompletionValueDescriptor.StringValueDescriptor(), + supportsNegativeValues ? ContainerUtil.append(Chars.asList(SEPARATORS), '-') : Chars.asList(SEPARATORS), values, false); } - @NotNull @Override - protected String getPrefix(@NotNull String currentTextPrefix) { - final int separatorPosition = lastSeparatorPosition(currentTextPrefix); - String prefix = separatorPosition == -1 ? currentTextPrefix : currentTextPrefix.substring(separatorPosition + 1).trim(); - return mySupportsNegativeValues && prefix.startsWith("-") ? prefix.substring(1) : prefix; - } - - private static int lastSeparatorPosition(@NotNull String text) { - int lastPosition = -1; - for (char separator : SEPARATORS) { - int lio = text.lastIndexOf(separator); - if (lio > lastPosition) { - lastPosition = lio; - } - } - return lastPosition; - } - - @SuppressWarnings("StringToUpperCaseOrToLowerCaseWithoutLocale") - @Override - protected void addCompletionVariants(@NotNull String text, int offset, @NotNull String prefix, - @NotNull CompletionResultSet result) { - result.addLookupAdvertisement("Select one or more users separated with comma, | or new lines"); - for (String completionVariant : myValues) { - final LookupElementBuilder element = LookupElementBuilder.create(completionVariant); - result.addElement(element.withLookupString(completionVariant.toLowerCase())); - } + public void fillCompletionVariants(@NotNull CompletionParameters parameters, + @NotNull String prefix, + @NotNull CompletionResultSet result) { + result.addLookupAdvertisement("Select one or more users separated with | or new lines"); + super.fillCompletionVariants(parameters, prefix, result); } } } From 608256eeb7b9e700895d5ef60dd6d59c43a3783e Mon Sep 17 00:00:00 2001 From: Julia Beliaeva Date: Mon, 14 Mar 2016 03:50:58 +0300 Subject: [PATCH 15/81] [vcs-log] use new TextFieldWithCompletion in go to hash IDEA-152511 --- .../ValuesCompletionProvider.java | 5 +- .../log/ui/actions/GoToHashOrRefPopup.java | 84 +++++++++---------- .../log/ui/actions/TextFieldWithProgress.java | 27 ++---- 3 files changed, 49 insertions(+), 67 deletions(-) diff --git a/platform/lang-impl/src/com/intellij/util/textCompletion/ValuesCompletionProvider.java b/platform/lang-impl/src/com/intellij/util/textCompletion/ValuesCompletionProvider.java index da8c3d2a0a14..cdd01efa8395 100644 --- a/platform/lang-impl/src/com/intellij/util/textCompletion/ValuesCompletionProvider.java +++ b/platform/lang-impl/src/com/intellij/util/textCompletion/ValuesCompletionProvider.java @@ -19,6 +19,7 @@ import com.intellij.codeInsight.completion.CompletionParameters; import com.intellij.codeInsight.completion.CompletionResultSet; import com.intellij.codeInsight.completion.PlainPrefixMatcher; import com.intellij.codeInsight.lookup.CharFilter; +import com.intellij.codeInsight.lookup.LookupElementBuilder; import com.intellij.util.containers.ContainerUtil; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -27,9 +28,9 @@ import java.util.Collection; import java.util.List; public class ValuesCompletionProvider implements TextCompletionProvider { - @NotNull private final TextCompletionValueDescriptor myDescriptor; + @NotNull protected final TextCompletionValueDescriptor myDescriptor; @NotNull private final List mySeparators; - @NotNull private final Collection myValues; + @NotNull protected final Collection myValues; private final boolean myCaseSensitive; public ValuesCompletionProvider(@NotNull TextCompletionValueDescriptor descriptor, diff --git a/platform/vcs-log/impl/src/com/intellij/vcs/log/ui/actions/GoToHashOrRefPopup.java b/platform/vcs-log/impl/src/com/intellij/vcs/log/ui/actions/GoToHashOrRefPopup.java index b085efb224c5..cf9ef8842774 100644 --- a/platform/vcs-log/impl/src/com/intellij/vcs/log/ui/actions/GoToHashOrRefPopup.java +++ b/platform/vcs-log/impl/src/com/intellij/vcs/log/ui/actions/GoToHashOrRefPopup.java @@ -15,10 +15,9 @@ */ package com.intellij.vcs.log.ui.actions; -import com.intellij.codeInsight.completion.CompletionParameters; +import com.intellij.codeInsight.completion.CompletionResultSet; import com.intellij.codeInsight.completion.InsertHandler; import com.intellij.codeInsight.completion.InsertionContext; -import com.intellij.codeInsight.completion.PlainPrefixMatcher; import com.intellij.codeInsight.lookup.LookupElement; import com.intellij.codeInsight.lookup.LookupElementBuilder; import com.intellij.openapi.application.ApplicationManager; @@ -30,10 +29,11 @@ import com.intellij.openapi.ui.popup.JBPopupListener; import com.intellij.openapi.ui.popup.LightweightWindowEvent; import com.intellij.openapi.util.Condition; import com.intellij.openapi.vfs.VirtualFile; -import com.intellij.ui.TextFieldWithAutoCompletionListProvider; import com.intellij.ui.components.JBLabel; import com.intellij.util.Function; import com.intellij.util.containers.ContainerUtil; +import com.intellij.util.textCompletion.DefaultTextCompletionValueDescriptor; +import com.intellij.util.textCompletion.ValuesCompletionProvider; import com.intellij.util.ui.ColorIcon; import com.intellij.util.ui.UIUtil; import com.intellij.vcs.log.VcsRef; @@ -46,8 +46,10 @@ import org.jetbrains.annotations.Nullable; import javax.swing.*; import javax.swing.border.EmptyBorder; import java.awt.*; -import java.util.*; -import java.util.List; +import java.util.Collection; +import java.util.Collections; +import java.util.Comparator; +import java.util.Map; import java.util.concurrent.CancellationException; import java.util.concurrent.ExecutionException; import java.util.concurrent.Future; @@ -72,7 +74,7 @@ public class GoToHashOrRefPopup { myOnSelectedHash = onSelectedHash; myOnSelectedRef = onSelectedRef; myTextField = - new TextFieldWithProgress(project, new VcsRefCompletionProvider(project, variants, roots, colorManager, comparator)) { + new TextFieldWithProgress(project, new VcsRefCompletionProvider(project, variants, roots, colorManager, comparator)) { @Override public void onOk() { if (myFuture == null) { @@ -154,47 +156,64 @@ public class GoToHashOrRefPopup { myPopup.showInCenterOf(anchor); } - private class VcsRefCompletionProvider extends TextFieldWithAutoCompletionListProvider { - @NotNull private final Project myProject; - @NotNull private final VcsLogColorManager myColorManager; - @NotNull private final Comparator myReferenceComparator; - @NotNull private final Map myCachedRootNames = ContainerUtil.newHashMap(); + private class VcsRefCompletionProvider extends ValuesCompletionProvider { public VcsRefCompletionProvider(@NotNull Project project, @NotNull Collection variants, @NotNull Collection roots, @NotNull VcsLogColorManager colorManager, @NotNull Comparator comparator) { - super(variants); + super(new VcsRefDescriptor(project, colorManager, comparator, roots), Collections.emptyList(), variants, false); + } + + @NotNull + @Override + protected Collection getValues(@NotNull String prefix, @NotNull CompletionResultSet result) { + return ContainerUtil.filter(myValues, new Condition() { + @Override + public boolean value(VcsRef vcsRef) { + return result.getPrefixMatcher().prefixMatches(vcsRef.getName()); + } + }); + } + } + + private class VcsRefDescriptor extends DefaultTextCompletionValueDescriptor { + @NotNull private final Project myProject; + @NotNull private final VcsLogColorManager myColorManager; + @NotNull private final Comparator myReferenceComparator; + @NotNull private final Map myCachedRootNames = ContainerUtil.newHashMap(); + + private VcsRefDescriptor(@NotNull Project project, + @NotNull VcsLogColorManager manager, + @NotNull Comparator comparator, + @NotNull Collection roots) { myProject = project; - myColorManager = colorManager; + myColorManager = manager; myReferenceComparator = comparator; + for (VirtualFile root : roots) { String text = VcsImplUtil.getShortVcsRootName(myProject, root); myCachedRootNames.put(root, text); } } + @NotNull @Override public LookupElementBuilder createLookupBuilder(@NotNull VcsRef item) { LookupElementBuilder lookupBuilder = super.createLookupBuilder(item); if (myColorManager.isMultipleRoots()) { lookupBuilder = lookupBuilder - .withTypeText(getTypeText(item), new ColorIcon(15, VcsLogGraphTable.getRootBackgroundColor(item.getRoot(), myColorManager)), + .withTypeText(getTypeText(item), + new ColorIcon(15, VcsLogGraphTable.getRootBackgroundColor(item.getRoot(), myColorManager)), true); } return lookupBuilder; } - @Nullable - @Override - protected Icon getIcon(@NotNull VcsRef item) { - return null; - } - @NotNull @Override - protected String getLookupString(@NotNull VcsRef item) { + public String getLookupString(@NotNull VcsRef item) { return item.getName(); } @@ -244,28 +263,5 @@ public class GoToHashOrRefPopup { } }; } - - @NotNull - @Override - public Collection getItems(String prefix, boolean cached, CompletionParameters parameters) { - if (prefix == null) { - return Collections.emptyList(); - } - - List items = new ArrayList(getMatched(myVariants, prefix)); - Collections.sort(items, this); - - return items; - } - - private List getMatched(@NotNull Collection refs, @NotNull String prefix) { - final PlainPrefixMatcher prefixMatcher = new PlainPrefixMatcher(prefix); - return ContainerUtil.filter(refs, new Condition() { - @Override - public boolean value(VcsRef vcsRef) { - return prefixMatcher.prefixMatches(vcsRef.getName()); - } - }); - } } } diff --git a/platform/vcs-log/impl/src/com/intellij/vcs/log/ui/actions/TextFieldWithProgress.java b/platform/vcs-log/impl/src/com/intellij/vcs/log/ui/actions/TextFieldWithProgress.java index ae7a3e9c6c4d..d536fb1ae340 100644 --- a/platform/vcs-log/impl/src/com/intellij/vcs/log/ui/actions/TextFieldWithProgress.java +++ b/platform/vcs-log/impl/src/com/intellij/vcs/log/ui/actions/TextFieldWithProgress.java @@ -15,14 +15,10 @@ */ package com.intellij.vcs.log.ui.actions; -import com.intellij.codeInsight.AutoPopupController; -import com.intellij.openapi.editor.SpellCheckingEditorCustomizationProvider; -import com.intellij.openapi.editor.ex.EditorEx; import com.intellij.openapi.project.Project; -import com.intellij.ui.EditorCustomization; import com.intellij.ui.IdeBorderFactory; -import com.intellij.ui.TextFieldWithAutoCompletion; -import com.intellij.ui.TextFieldWithAutoCompletionListProvider; +import com.intellij.util.textCompletion.TextCompletionProvider; +import com.intellij.util.textCompletion.TextFieldWithCompletion; import com.intellij.util.ui.AsyncProcessIcon; import org.jetbrains.annotations.NotNull; @@ -30,34 +26,23 @@ import javax.swing.*; import java.awt.*; import java.awt.event.KeyEvent; -public abstract class TextFieldWithProgress extends JPanel { - @NotNull private final TextFieldWithAutoCompletion myTextField; +public abstract class TextFieldWithProgress extends JPanel { + @NotNull private final TextFieldWithCompletion myTextField; @NotNull private final AsyncProcessIcon myProgressIcon; public TextFieldWithProgress(@NotNull Project project, - @NotNull TextFieldWithAutoCompletionListProvider completionProvider) { + @NotNull TextCompletionProvider completionProvider) { super(new BorderLayout()); setBorder(IdeBorderFactory.createEmptyBorder(3)); myProgressIcon = new AsyncProcessIcon("Loading commits"); - myTextField = new TextFieldWithAutoCompletion(project, completionProvider, false, null) { + myTextField = new TextFieldWithCompletion(project, completionProvider, "", true, true) { @Override public void setBackground(Color bg) { super.setBackground(bg); myProgressIcon.setBackground(bg); } - @Override - protected EditorEx createEditor() { - EditorEx editor = super.createEditor(); - editor.putUserData(AutoPopupController.ALWAYS_AUTO_POPUP, true); - EditorCustomization customization = SpellCheckingEditorCustomizationProvider.getInstance().getDisabledCustomization(); - if (customization != null) { - customization.customize(editor); - } - return editor; - } - @Override protected boolean processKeyBinding(KeyStroke ks, final KeyEvent e, int condition, boolean pressed) { if (e.getKeyCode() == KeyEvent.VK_ENTER) { From e910496c51a33531044512e827dd696ce0a4e10e Mon Sep 17 00:00:00 2001 From: Julia Beliaeva Date: Mon, 14 Mar 2016 04:42:21 +0300 Subject: [PATCH 16/81] [text-completion] TextFieldWithCompletion can show hint, extract installCompletionHint and move it to TextCompletionUtil --- .../ui/TextFieldWithAutoCompletion.java | 48 ++----------------- .../textCompletion/TextCompletionUtil.java | 46 ++++++++++++++++++ .../TextFieldWithCompletion.java | 10 +++- .../log/ui/actions/TextFieldWithProgress.java | 2 +- .../log/ui/filter/MultilinePopupBuilder.java | 2 +- 5 files changed, 61 insertions(+), 47 deletions(-) diff --git a/platform/lang-impl/src/com/intellij/ui/TextFieldWithAutoCompletion.java b/platform/lang-impl/src/com/intellij/ui/TextFieldWithAutoCompletion.java index d0cca1a34c09..1b09bd823045 100644 --- a/platform/lang-impl/src/com/intellij/ui/TextFieldWithAutoCompletion.java +++ b/platform/lang-impl/src/com/intellij/ui/TextFieldWithAutoCompletion.java @@ -16,20 +16,12 @@ package com.intellij.ui; -import com.intellij.codeInsight.hint.HintManager; -import com.intellij.openapi.actionSystem.*; -import com.intellij.openapi.application.ApplicationManager; -import com.intellij.openapi.editor.Editor; -import com.intellij.openapi.editor.event.DocumentAdapter; -import com.intellij.openapi.editor.event.DocumentEvent; import com.intellij.openapi.editor.ex.EditorEx; -import com.intellij.openapi.editor.ex.FocusChangeListener; import com.intellij.openapi.fileTypes.PlainTextLanguage; -import com.intellij.openapi.keymap.KeymapUtil; import com.intellij.openapi.project.DumbAware; import com.intellij.openapi.project.Project; -import com.intellij.openapi.util.Ref; import com.intellij.openapi.util.text.StringUtil; +import com.intellij.util.textCompletion.TextCompletionUtil; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -94,44 +86,12 @@ public class TextFieldWithAutoCompletion extends LanguageTextField { @Override protected EditorEx createEditor() { - final EditorEx editor = super.createEditor(); + EditorEx editor = super.createEditor(); - if (!myShowAutocompletionIsAvailableHint) { - return editor; + if (myShowAutocompletionIsAvailableHint) { + TextCompletionUtil.installCompletionHint(editor); } - final String completionShortcutText = - KeymapUtil.getFirstKeyboardShortcutText(ActionManager.getInstance().getAction(IdeActions.ACTION_CODE_COMPLETION)); - if (StringUtil.isEmpty(completionShortcutText)) { - return editor; - } - - final Ref toShowHintRef = new Ref(true); - editor.getDocument().addDocumentListener(new DocumentAdapter() { - @Override - public void documentChanged(DocumentEvent e) { - toShowHintRef.set(false); - } - }); - - editor.addFocusListener(new FocusChangeListener() { - @Override - public void focusGained(final Editor editor) { - if (toShowHintRef.get() && getText().length() == 0) { - ApplicationManager.getApplication().invokeLater(new Runnable() { - @Override - public void run() { - HintManager.getInstance().showInformationHint(editor, "Code completion available ( " + completionShortcutText + " )"); - } - }); - } - } - - @Override - public void focusLost(Editor editor) { - // Do nothing - } - }); return editor; } diff --git a/platform/lang-impl/src/com/intellij/util/textCompletion/TextCompletionUtil.java b/platform/lang-impl/src/com/intellij/util/textCompletion/TextCompletionUtil.java index 294b18c37294..fa73d8724dfa 100644 --- a/platform/lang-impl/src/com/intellij/util/textCompletion/TextCompletionUtil.java +++ b/platform/lang-impl/src/com/intellij/util/textCompletion/TextCompletionUtil.java @@ -15,8 +15,20 @@ */ package com.intellij.util.textCompletion; +import com.intellij.codeInsight.hint.HintManager; +import com.intellij.openapi.actionSystem.ActionManager; +import com.intellij.openapi.actionSystem.IdeActions; +import com.intellij.openapi.application.ApplicationManager; +import com.intellij.openapi.editor.Editor; +import com.intellij.openapi.editor.event.DocumentAdapter; +import com.intellij.openapi.editor.event.DocumentEvent; +import com.intellij.openapi.editor.ex.EditorEx; +import com.intellij.openapi.editor.ex.FocusChangeListener; +import com.intellij.openapi.keymap.KeymapUtil; import com.intellij.openapi.project.DumbService; import com.intellij.openapi.util.Key; +import com.intellij.openapi.util.Ref; +import com.intellij.openapi.util.text.StringUtil; import com.intellij.psi.PsiFile; import com.intellij.ui.LanguageTextField; import org.jetbrains.annotations.NotNull; @@ -39,6 +51,40 @@ public class TextCompletionUtil { return provider; } + public static void installCompletionHint(@NotNull EditorEx editor) { + String completionShortcutText = + KeymapUtil.getFirstKeyboardShortcutText(ActionManager.getInstance().getAction(IdeActions.ACTION_CODE_COMPLETION)); + if (!StringUtil.isEmpty(completionShortcutText)) { + + final Ref toShowHintRef = new Ref(true); + editor.getDocument().addDocumentListener(new DocumentAdapter() { + @Override + public void documentChanged(DocumentEvent e) { + toShowHintRef.set(false); + } + }); + + editor.addFocusListener(new FocusChangeListener() { + @Override + public void focusGained(final Editor editor) { + if (toShowHintRef.get() && editor.getDocument().getText().isEmpty()) { + ApplicationManager.getApplication().invokeLater(new Runnable() { + @Override + public void run() { + HintManager.getInstance().showInformationHint(editor, "Code completion available ( " + completionShortcutText + " )"); + } + }); + } + } + + @Override + public void focusLost(Editor editor) { + // Do nothing + } + }); + } + } + public static class DocumentWithCompletionCreator extends LanguageTextField.SimpleDocumentCreator { @NotNull private final TextCompletionProvider myProvider; diff --git a/platform/lang-impl/src/com/intellij/util/textCompletion/TextFieldWithCompletion.java b/platform/lang-impl/src/com/intellij/util/textCompletion/TextFieldWithCompletion.java index 477f5fdf0316..3032916edfcf 100644 --- a/platform/lang-impl/src/com/intellij/util/textCompletion/TextFieldWithCompletion.java +++ b/platform/lang-impl/src/com/intellij/util/textCompletion/TextFieldWithCompletion.java @@ -26,14 +26,17 @@ import org.jetbrains.annotations.NotNull; public class TextFieldWithCompletion extends LanguageTextField { private final boolean myAutoPopup; + private final boolean myShowHint; public TextFieldWithCompletion(@NotNull Project project, @NotNull TextCompletionProvider provider, @NotNull String value, boolean oneLineMode, - boolean autoPopup) { + boolean autoPopup, + boolean showHint) { super(PlainTextLanguage.INSTANCE, project, value, new TextCompletionUtil.DocumentWithCompletionCreator(provider), oneLineMode); myAutoPopup = autoPopup; + myShowHint = showHint; } @Override @@ -42,6 +45,11 @@ public class TextFieldWithCompletion extends LanguageTextField { EditorCustomization disableSpellChecking = SpellCheckingEditorCustomizationProvider.getInstance().getDisabledCustomization(); if (disableSpellChecking != null) disableSpellChecking.customize(editor); editor.putUserData(AutoPopupController.ALWAYS_AUTO_POPUP, myAutoPopup); + + if (myShowHint) { + TextCompletionUtil.installCompletionHint(editor); + } + return editor; } } diff --git a/platform/vcs-log/impl/src/com/intellij/vcs/log/ui/actions/TextFieldWithProgress.java b/platform/vcs-log/impl/src/com/intellij/vcs/log/ui/actions/TextFieldWithProgress.java index d536fb1ae340..0f861b13809f 100644 --- a/platform/vcs-log/impl/src/com/intellij/vcs/log/ui/actions/TextFieldWithProgress.java +++ b/platform/vcs-log/impl/src/com/intellij/vcs/log/ui/actions/TextFieldWithProgress.java @@ -36,7 +36,7 @@ public abstract class TextFieldWithProgress extends JPanel { setBorder(IdeBorderFactory.createEmptyBorder(3)); myProgressIcon = new AsyncProcessIcon("Loading commits"); - myTextField = new TextFieldWithCompletion(project, completionProvider, "", true, true) { + myTextField = new TextFieldWithCompletion(project, completionProvider, "", true, true, false) { @Override public void setBackground(Color bg) { super.setBackground(bg); diff --git a/platform/vcs-log/impl/src/com/intellij/vcs/log/ui/filter/MultilinePopupBuilder.java b/platform/vcs-log/impl/src/com/intellij/vcs/log/ui/filter/MultilinePopupBuilder.java index 250cee7bddf5..9ccba1d22a58 100644 --- a/platform/vcs-log/impl/src/com/intellij/vcs/log/ui/filter/MultilinePopupBuilder.java +++ b/platform/vcs-log/impl/src/com/intellij/vcs/log/ui/filter/MultilinePopupBuilder.java @@ -61,7 +61,7 @@ class MultilinePopupBuilder { boolean supportsNegativeValues, @NotNull String initialValue) { TextFieldWithCompletion textField = - new TextFieldWithCompletion(project, new MyCompletionProvider(values, supportsNegativeValues), initialValue, false, true) { + new TextFieldWithCompletion(project, new MyCompletionProvider(values, supportsNegativeValues), initialValue, false, true, false) { @Override protected EditorEx createEditor() { EditorEx editor = super.createEditor(); From 9ef586877cfa742b54c80890e1e78eae75d625ef Mon Sep 17 00:00:00 2001 From: Julia Beliaeva Date: Mon, 14 Mar 2016 04:44:41 +0300 Subject: [PATCH 17/81] [git] use TextFieldWithCompletion in git commit dialog --- .../ValuesCompletionProvider.java | 10 +++- .../log/ui/actions/GoToHashOrRefPopup.java | 2 +- .../checkin/GitCheckinEnvironment.java | 48 ++++++++----------- 3 files changed, 30 insertions(+), 30 deletions(-) diff --git a/platform/lang-impl/src/com/intellij/util/textCompletion/ValuesCompletionProvider.java b/platform/lang-impl/src/com/intellij/util/textCompletion/ValuesCompletionProvider.java index cdd01efa8395..3e4cbcb19ae2 100644 --- a/platform/lang-impl/src/com/intellij/util/textCompletion/ValuesCompletionProvider.java +++ b/platform/lang-impl/src/com/intellij/util/textCompletion/ValuesCompletionProvider.java @@ -19,12 +19,12 @@ import com.intellij.codeInsight.completion.CompletionParameters; import com.intellij.codeInsight.completion.CompletionResultSet; import com.intellij.codeInsight.completion.PlainPrefixMatcher; import com.intellij.codeInsight.lookup.CharFilter; -import com.intellij.codeInsight.lookup.LookupElementBuilder; import com.intellij.util.containers.ContainerUtil; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import java.util.Collection; +import java.util.Collections; import java.util.List; public class ValuesCompletionProvider implements TextCompletionProvider { @@ -42,6 +42,14 @@ public class ValuesCompletionProvider implements TextCompletionProvider { myCaseSensitive = caseSensitive; } + /* + Single-line single-value case-insensitive completion. + */ + public ValuesCompletionProvider(@NotNull TextCompletionValueDescriptor presentation, + @NotNull Collection values) { + this(presentation, Collections.emptyList(), values, false); + } + @Nullable @Override public String getPrefix(@NotNull String text, int offset) { diff --git a/platform/vcs-log/impl/src/com/intellij/vcs/log/ui/actions/GoToHashOrRefPopup.java b/platform/vcs-log/impl/src/com/intellij/vcs/log/ui/actions/GoToHashOrRefPopup.java index cf9ef8842774..e89226b4974f 100644 --- a/platform/vcs-log/impl/src/com/intellij/vcs/log/ui/actions/GoToHashOrRefPopup.java +++ b/platform/vcs-log/impl/src/com/intellij/vcs/log/ui/actions/GoToHashOrRefPopup.java @@ -163,7 +163,7 @@ public class GoToHashOrRefPopup { @NotNull Collection roots, @NotNull VcsLogColorManager colorManager, @NotNull Comparator comparator) { - super(new VcsRefDescriptor(project, colorManager, comparator, roots), Collections.emptyList(), variants, false); + super(new VcsRefDescriptor(project, colorManager, comparator, roots), variants); } @NotNull diff --git a/plugins/git4idea/src/git4idea/checkin/GitCheckinEnvironment.java b/plugins/git4idea/src/git4idea/checkin/GitCheckinEnvironment.java index a8b998665084..2386cbc89644 100644 --- a/plugins/git4idea/src/git4idea/checkin/GitCheckinEnvironment.java +++ b/plugins/git4idea/src/git4idea/checkin/GitCheckinEnvironment.java @@ -16,14 +16,11 @@ package git4idea.checkin; import com.intellij.CommonBundle; -import com.intellij.codeInsight.AutoPopupController; import com.intellij.dvcs.DvcsCommitAdditionalComponent; import com.intellij.dvcs.DvcsUtil; import com.intellij.dvcs.push.ui.VcsPushDialog; import com.intellij.openapi.components.ServiceManager; import com.intellij.openapi.diagnostic.Logger; -import com.intellij.openapi.editor.SpellCheckingEditorCustomizationProvider; -import com.intellij.openapi.editor.ex.EditorEx; import com.intellij.openapi.project.Project; import com.intellij.openapi.util.Ref; import com.intellij.openapi.util.io.FileUtil; @@ -37,12 +34,17 @@ import com.intellij.openapi.vcs.checkin.CheckinChangeListSpecificComponent; import com.intellij.openapi.vcs.checkin.CheckinEnvironment; import com.intellij.openapi.vcs.ui.RefreshableOnComponent; import com.intellij.openapi.vfs.VirtualFile; -import com.intellij.ui.*; +import com.intellij.ui.EditorTextField; +import com.intellij.ui.GuiUtils; import com.intellij.util.Function; import com.intellij.util.FunctionUtil; import com.intellij.util.NullableFunction; import com.intellij.util.PairConsumer; import com.intellij.util.containers.ContainerUtil; +import com.intellij.util.textCompletion.DefaultTextCompletionValueDescriptor; +import com.intellij.util.textCompletion.TextCompletionProvider; +import com.intellij.util.textCompletion.TextFieldWithCompletion; +import com.intellij.util.textCompletion.ValuesCompletionProvider; import com.intellij.util.ui.UIUtil; import com.intellij.vcs.log.VcsFullCommitDetails; import com.intellij.vcs.log.VcsUser; @@ -89,7 +91,9 @@ public class GitCheckinEnvironment implements CheckinEnvironment { private Boolean myNextCommitIsPushed = null; // The push option of the next commit private Date myNextCommitAuthorDate; - public GitCheckinEnvironment(@NotNull Project project, @NotNull final VcsDirtyScopeManager dirtyScopeManager, final GitVcsSettings settings) { + public GitCheckinEnvironment(@NotNull Project project, + @NotNull final VcsDirtyScopeManager dirtyScopeManager, + final GitVcsSettings settings) { myProject = project; myDirtyScopeManager = dirtyScopeManager; mySettings = settings; @@ -249,14 +253,13 @@ public class GitCheckinEnvironment implements CheckinEnvironment { /** * Preform a merge commit * - * - * @param project a project - * @param root a vcs root - * @param added added files - * @param removed removed files - * @param messageFile a message file for commit - * @param author an author - * @param exceptions the list of exceptions to report + * @param project a project + * @param root a vcs root + * @param added added files + * @param removed removed files + * @param messageFile a message file for commit + * @param author an author + * @param exceptions the list of exceptions to report * @param partialOperation * @return true if merge commit was successful */ @@ -284,7 +287,7 @@ public class GitCheckinEnvironment implements CheckinEnvironment { return false; } String rootPath = root.getPath(); - for (StringTokenizer lines = new StringTokenizer(output, "\n", false); lines.hasMoreTokens();) { + for (StringTokenizer lines = new StringTokenizer(output, "\n", false); lines.hasMoreTokens(); ) { String line = lines.nextToken().trim(); if (line.length() == 0) { continue; @@ -365,7 +368,6 @@ public class GitCheckinEnvironment implements CheckinEnvironment { /** * Check if commit has failed due to unfinished merge or cherry-pick. * - * * @param ex an exception to examine * @return true if exception means that there is a partial commit during merge */ @@ -619,19 +621,9 @@ public class GitCheckinEnvironment implements CheckinEnvironment { @NotNull private EditorTextField createTextField(@NotNull Project project, @NotNull List list) { - TextFieldWithAutoCompletionListProvider completionProvider = new TextFieldWithAutoCompletion.StringsCompletionProvider(list, null); - return new TextFieldWithAutoCompletion(project, completionProvider, true, null) { - @Override - protected EditorEx createEditor() { - EditorEx editor = super.createEditor(); - editor.putUserData(AutoPopupController.ALWAYS_AUTO_POPUP, true); - EditorCustomization customization = SpellCheckingEditorCustomizationProvider.getInstance().getDisabledCustomization(); - if (customization != null) { - customization.customize(editor); - } - return editor; - } - }; + TextCompletionProvider completionProvider = + new ValuesCompletionProvider<>(new DefaultTextCompletionValueDescriptor.StringValueDescriptor(), list); + return new TextFieldWithCompletion(project, completionProvider, "", true, true, true); } @Override From 499fcdfb59c3a006cbdf1af627ff2dc78643d588 Mon Sep 17 00:00:00 2001 From: Julia Beliaeva Date: Mon, 14 Mar 2016 06:15:09 +0300 Subject: [PATCH 18/81] [hg] use TextFieldWithCompletion in hg push --- .../dvcs/push/ui/PushTargetTextField.java | 33 ++++++------------- .../zmlx/hg4idea/push/HgPushTargetPanel.java | 3 +- 2 files changed, 12 insertions(+), 24 deletions(-) diff --git a/platform/dvcs-impl/src/com/intellij/dvcs/push/ui/PushTargetTextField.java b/platform/dvcs-impl/src/com/intellij/dvcs/push/ui/PushTargetTextField.java index 5571c7e5df51..affbc2e59e0c 100644 --- a/platform/dvcs-impl/src/com/intellij/dvcs/push/ui/PushTargetTextField.java +++ b/platform/dvcs-impl/src/com/intellij/dvcs/push/ui/PushTargetTextField.java @@ -15,24 +15,22 @@ */ package com.intellij.dvcs.push.ui; -import com.intellij.openapi.editor.SpellCheckingEditorCustomizationProvider; import com.intellij.openapi.editor.ex.EditorEx; import com.intellij.openapi.project.Project; -import com.intellij.ui.EditorCustomization; -import com.intellij.ui.TextFieldWithAutoCompletion; -import com.intellij.ui.TextFieldWithAutoCompletionListProvider; import com.intellij.util.containers.ContainerUtil; +import com.intellij.util.textCompletion.DefaultTextCompletionValueDescriptor; +import com.intellij.util.textCompletion.TextCompletionProvider; +import com.intellij.util.textCompletion.TextFieldWithCompletion; +import com.intellij.util.textCompletion.ValuesCompletionProvider; import org.jetbrains.annotations.NotNull; import java.awt.event.FocusAdapter; import java.awt.event.FocusEvent; import java.util.List; -public class PushTargetTextField extends TextFieldWithAutoCompletion { - - public PushTargetTextField(@NotNull Project project, @NotNull final List targetVariants, @NotNull String defaultTargetName) { - super(project, getCompletionProvider(targetVariants), true, defaultTargetName); - setOneLineMode(true); +public class PushTargetTextField extends TextFieldWithCompletion { + public PushTargetTextField(@NotNull Project project, @NotNull List targetVariants, @NotNull String defaultTargetName) { + super(project, getCompletionProvider(targetVariants), defaultTargetName, true, true, true); addFocusListener(new FocusAdapter() { @Override public void focusGained(FocusEvent e) { @@ -46,28 +44,17 @@ public class PushTargetTextField extends TextFieldWithAutoCompletion { }); } - @Override - protected EditorEx createEditor() { - // editor created lazy, so we need to update editor customization after initialization - EditorEx editorEx = super.createEditor(); - EditorCustomization customization = SpellCheckingEditorCustomizationProvider.getInstance().getDisabledCustomization(); - if (customization != null) { - customization.customize(editorEx); - } - return editorEx; - } - @Override protected void updateBorder(@NotNull final EditorEx editor) { } @NotNull - private static TextFieldWithAutoCompletionListProvider getCompletionProvider(@NotNull final List targetVariants) { - return new StringsCompletionProvider(targetVariants, null) { + private static TextCompletionProvider getCompletionProvider(@NotNull final List targetVariants) { + return new ValuesCompletionProvider<>(new DefaultTextCompletionValueDescriptor.StringValueDescriptor() { @Override public int compare(String item1, String item2) { return Integer.valueOf(ContainerUtil.indexOf(targetVariants, item1)).compareTo(ContainerUtil.indexOf(targetVariants, item2)); } - }; + }, targetVariants); } } diff --git a/plugins/hg4idea/src/org/zmlx/hg4idea/push/HgPushTargetPanel.java b/plugins/hg4idea/src/org/zmlx/hg4idea/push/HgPushTargetPanel.java index 4b5644758f63..c6740a13bb91 100644 --- a/plugins/hg4idea/src/org/zmlx/hg4idea/push/HgPushTargetPanel.java +++ b/plugins/hg4idea/src/org/zmlx/hg4idea/push/HgPushTargetPanel.java @@ -28,6 +28,7 @@ import com.intellij.openapi.util.text.StringUtil; import com.intellij.ui.ColoredTreeCellRenderer; import com.intellij.ui.SimpleTextAttributes; import com.intellij.ui.TextFieldWithAutoCompletion; +import com.intellij.util.textCompletion.TextFieldWithCompletion; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.zmlx.hg4idea.repo.HgRepository; @@ -41,7 +42,7 @@ public class HgPushTargetPanel extends PushTargetPanel { private final static String ENTER_REMOTE = "Enter Remote"; private final HgRepository myRepository; private final String myBranchName; - private final TextFieldWithAutoCompletion myDestTargetPanel; + private final TextFieldWithCompletion myDestTargetPanel; private final VcsEditableTextComponent myTargetRenderedComponent; public HgPushTargetPanel(@NotNull HgRepository repository, @Nullable HgTarget defaultTarget) { From 0d723c20e9f84fc567a11c089ca884d2609fd025 Mon Sep 17 00:00:00 2001 From: Julia Beliaeva Date: Thu, 10 Mar 2016 21:26:44 +0300 Subject: [PATCH 19/81] [text-completion] text autocompletion auto-popups on symbols that are added to prefix by provider IDEA-152845 --- .../TextCompletionContributor.java | 17 +++++++++++++++++ .../util/textCompletion/TextCompletionUtil.java | 6 +++++- .../textCompletion/TextFieldWithCompletion.java | 2 +- 3 files changed, 23 insertions(+), 2 deletions(-) diff --git a/platform/lang-impl/src/com/intellij/util/textCompletion/TextCompletionContributor.java b/platform/lang-impl/src/com/intellij/util/textCompletion/TextCompletionContributor.java index 9893e6383c83..6ca84858653f 100644 --- a/platform/lang-impl/src/com/intellij/util/textCompletion/TextCompletionContributor.java +++ b/platform/lang-impl/src/com/intellij/util/textCompletion/TextCompletionContributor.java @@ -18,10 +18,16 @@ package com.intellij.util.textCompletion; import com.intellij.codeInsight.completion.CompletionContributor; import com.intellij.codeInsight.completion.CompletionParameters; import com.intellij.codeInsight.completion.CompletionResultSet; +import com.intellij.codeInsight.lookup.CharFilter; import com.intellij.openapi.project.DumbAware; +import com.intellij.psi.PsiElement; import com.intellij.psi.PsiFile; import org.jetbrains.annotations.NotNull; +import java.util.Objects; + +import static com.intellij.codeInsight.AutoPopupController.ALWAYS_AUTO_POPUP; + /** * @author sergey.evdokimov */ @@ -43,4 +49,15 @@ public class TextCompletionContributor extends CompletionContributor implements provider.fillCompletionVariants(parameters, prefix, activeResult); } + + @Override + public boolean invokeAutoPopup(@NotNull PsiElement position, char typeChar) { + TextCompletionProvider provider = TextCompletionUtil.getProvider(position.getContainingFile()); + if (provider != null) { + if (Boolean.TRUE.equals(position.getContainingFile().getUserData(ALWAYS_AUTO_POPUP))) { + return Objects.equals(CharFilter.Result.ADD_TO_PREFIX, provider.acceptChar(typeChar)); + } + } + return super.invokeAutoPopup(position, typeChar); + } } diff --git a/platform/lang-impl/src/com/intellij/util/textCompletion/TextCompletionUtil.java b/platform/lang-impl/src/com/intellij/util/textCompletion/TextCompletionUtil.java index fa73d8724dfa..3c2c4026f7fd 100644 --- a/platform/lang-impl/src/com/intellij/util/textCompletion/TextCompletionUtil.java +++ b/platform/lang-impl/src/com/intellij/util/textCompletion/TextCompletionUtil.java @@ -15,6 +15,7 @@ */ package com.intellij.util.textCompletion; +import com.intellij.codeInsight.AutoPopupController; import com.intellij.codeInsight.hint.HintManager; import com.intellij.openapi.actionSystem.ActionManager; import com.intellij.openapi.actionSystem.IdeActions; @@ -87,14 +88,17 @@ public class TextCompletionUtil { public static class DocumentWithCompletionCreator extends LanguageTextField.SimpleDocumentCreator { @NotNull private final TextCompletionProvider myProvider; + private final boolean myAutoPopup; - public DocumentWithCompletionCreator(@NotNull TextCompletionProvider provider) { + public DocumentWithCompletionCreator(@NotNull TextCompletionProvider provider, boolean autoPopup) { myProvider = provider; + myAutoPopup = autoPopup; } @Override public void customizePsiFile(@NotNull PsiFile file) { installProvider(file, myProvider); + file.putUserData(AutoPopupController.ALWAYS_AUTO_POPUP, myAutoPopup); } } } diff --git a/platform/lang-impl/src/com/intellij/util/textCompletion/TextFieldWithCompletion.java b/platform/lang-impl/src/com/intellij/util/textCompletion/TextFieldWithCompletion.java index 3032916edfcf..99be2ca434ff 100644 --- a/platform/lang-impl/src/com/intellij/util/textCompletion/TextFieldWithCompletion.java +++ b/platform/lang-impl/src/com/intellij/util/textCompletion/TextFieldWithCompletion.java @@ -34,7 +34,7 @@ public class TextFieldWithCompletion extends LanguageTextField { boolean oneLineMode, boolean autoPopup, boolean showHint) { - super(PlainTextLanguage.INSTANCE, project, value, new TextCompletionUtil.DocumentWithCompletionCreator(provider), oneLineMode); + super(PlainTextLanguage.INSTANCE, project, value, new TextCompletionUtil.DocumentWithCompletionCreator(provider, autoPopup), oneLineMode); myAutoPopup = autoPopup; myShowHint = showHint; } From b8776a058b4be0227d1ea8422549a9822189aff1 Mon Sep 17 00:00:00 2001 From: Julia Beliaeva Date: Mon, 14 Mar 2016 08:16:19 +0300 Subject: [PATCH 20/81] [text-completion] TextFieldWithAutoCompletionListProvider extends DefaultTextCompletionValueDescriptor --- ...xtFieldWithAutoCompletionListProvider.java | 53 +++---------------- 1 file changed, 6 insertions(+), 47 deletions(-) diff --git a/platform/lang-impl/src/com/intellij/ui/TextFieldWithAutoCompletionListProvider.java b/platform/lang-impl/src/com/intellij/ui/TextFieldWithAutoCompletionListProvider.java index 8ef12dfb1878..7529bc1c42fe 100644 --- a/platform/lang-impl/src/com/intellij/ui/TextFieldWithAutoCompletionListProvider.java +++ b/platform/lang-impl/src/com/intellij/ui/TextFieldWithAutoCompletionListProvider.java @@ -16,40 +16,25 @@ package com.intellij.ui; import com.intellij.codeInsight.completion.CompletionParameters; -import com.intellij.codeInsight.completion.InsertHandler; import com.intellij.codeInsight.completion.PlainPrefixMatcher; import com.intellij.codeInsight.completion.PrefixMatcher; -import com.intellij.codeInsight.lookup.LookupElement; -import com.intellij.codeInsight.lookup.LookupElementBuilder; +import com.intellij.util.textCompletion.DefaultTextCompletionValueDescriptor; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -import javax.swing.*; -import java.util.*; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.List; /** * @author Roman.Chernyatchik */ -public abstract class TextFieldWithAutoCompletionListProvider implements Comparator { +public abstract class TextFieldWithAutoCompletionListProvider extends DefaultTextCompletionValueDescriptor { @NotNull protected Collection myVariants; @Nullable private String myCompletionAdvertisement; - @Nullable - protected abstract Icon getIcon(@NotNull final T item); - - @NotNull - protected abstract String getLookupString(@NotNull final T item); - - @Nullable - protected abstract String getTailText(@NotNull final T item); - - @Nullable - protected abstract String getTypeText(@NotNull final T item); - - @Override - public abstract int compare(T item1, T item2); - protected TextFieldWithAutoCompletionListProvider(@Nullable final Collection variants) { setItems(variants); myCompletionAdvertisement = null; @@ -106,27 +91,6 @@ public abstract class TextFieldWithAutoCompletionListProvider implements Comp return new PlainPrefixMatcher(prefix); } - public LookupElementBuilder createLookupBuilder(@NotNull final T item) { - LookupElementBuilder builder = LookupElementBuilder.create(item, getLookupString(item)) - .withIcon(getIcon(item)); - - final InsertHandler handler = createInsertHandler(item); - if (handler != null) { - builder = builder.withInsertHandler(handler); - } - - final String tailText = getTailText(item); - if (tailText != null) { - builder = builder.withTailText(tailText, true); - } - - final String typeText = getTypeText(item); - if (typeText != null) { - builder = builder.withTypeText(typeText); - } - return builder; - } - @Nullable public String getPrefix(@NotNull final CompletionParameters parameters) { return getCompletionPrefix(parameters); @@ -144,9 +108,4 @@ public abstract class TextFieldWithAutoCompletionListProvider implements Comp protected String getQuickDocHotKeyAdvertisementTail(@NotNull final String shortcut) { return null; } - - @Nullable - protected InsertHandler createInsertHandler(@NotNull final T item) { - return null; - } } From 61fea9848aa0e1a5ee242272bdc2071b8968e9cf Mon Sep 17 00:00:00 2001 From: Julia Beliaeva Date: Mon, 14 Mar 2016 08:33:06 +0300 Subject: [PATCH 21/81] [text-completion] completion provider can show ads --- .../intellij/util/TextFieldCompletionProvider.java | 6 ++++++ .../textCompletion/TextCompletionContributor.java | 5 +++++ .../util/textCompletion/TextCompletionProvider.java | 3 +++ .../util/textCompletion/ValuesCompletionProvider.java | 6 ++++++ .../vcs/log/ui/filter/MultilinePopupBuilder.java | 11 ++++------- 5 files changed, 24 insertions(+), 7 deletions(-) diff --git a/platform/lang-impl/src/com/intellij/util/TextFieldCompletionProvider.java b/platform/lang-impl/src/com/intellij/util/TextFieldCompletionProvider.java index 8d7bde9b3a70..6986319ca2a2 100644 --- a/platform/lang-impl/src/com/intellij/util/TextFieldCompletionProvider.java +++ b/platform/lang-impl/src/com/intellij/util/TextFieldCompletionProvider.java @@ -103,6 +103,12 @@ public abstract class TextFieldCompletionProvider implements TextCompletionProvi return currentTextPrefix; } + @Nullable + @Override + public String getAdvertisement() { + return null; + } + protected abstract void addCompletionVariants(@NotNull String text, int offset, @NotNull String prefix, diff --git a/platform/lang-impl/src/com/intellij/util/textCompletion/TextCompletionContributor.java b/platform/lang-impl/src/com/intellij/util/textCompletion/TextCompletionContributor.java index 6ca84858653f..858dc66e3def 100644 --- a/platform/lang-impl/src/com/intellij/util/textCompletion/TextCompletionContributor.java +++ b/platform/lang-impl/src/com/intellij/util/textCompletion/TextCompletionContributor.java @@ -40,6 +40,11 @@ public class TextCompletionContributor extends CompletionContributor implements TextCompletionProvider provider = TextCompletionUtil.getProvider(file); if (provider == null) return; + String advertisement = provider.getAdvertisement(); + if (advertisement != null) { + result.addLookupAdvertisement(advertisement); + } + String text = file.getText(); int offset = Math.min(text.length(), parameters.getOffset()); String prefix = provider.getPrefix(text, offset); diff --git a/platform/lang-impl/src/com/intellij/util/textCompletion/TextCompletionProvider.java b/platform/lang-impl/src/com/intellij/util/textCompletion/TextCompletionProvider.java index 03dfa793831c..f87da73ca238 100644 --- a/platform/lang-impl/src/com/intellij/util/textCompletion/TextCompletionProvider.java +++ b/platform/lang-impl/src/com/intellij/util/textCompletion/TextCompletionProvider.java @@ -23,6 +23,9 @@ import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; public interface TextCompletionProvider { + @Nullable + String getAdvertisement(); + @Nullable String getPrefix(@NotNull String text, int offset); diff --git a/platform/lang-impl/src/com/intellij/util/textCompletion/ValuesCompletionProvider.java b/platform/lang-impl/src/com/intellij/util/textCompletion/ValuesCompletionProvider.java index 3e4cbcb19ae2..80c80dd3edcd 100644 --- a/platform/lang-impl/src/com/intellij/util/textCompletion/ValuesCompletionProvider.java +++ b/platform/lang-impl/src/com/intellij/util/textCompletion/ValuesCompletionProvider.java @@ -50,6 +50,12 @@ public class ValuesCompletionProvider implements TextCompletionProvider { this(presentation, Collections.emptyList(), values, false); } + @Nullable + @Override + public String getAdvertisement() { + return ""; + } + @Nullable @Override public String getPrefix(@NotNull String text, int offset) { diff --git a/platform/vcs-log/impl/src/com/intellij/vcs/log/ui/filter/MultilinePopupBuilder.java b/platform/vcs-log/impl/src/com/intellij/vcs/log/ui/filter/MultilinePopupBuilder.java index 9ccba1d22a58..4baeb6f8ea5c 100644 --- a/platform/vcs-log/impl/src/com/intellij/vcs/log/ui/filter/MultilinePopupBuilder.java +++ b/platform/vcs-log/impl/src/com/intellij/vcs/log/ui/filter/MultilinePopupBuilder.java @@ -16,8 +16,6 @@ package com.intellij.vcs.log.ui.filter; import com.google.common.primitives.Chars; -import com.intellij.codeInsight.completion.CompletionParameters; -import com.intellij.codeInsight.completion.CompletionResultSet; import com.intellij.openapi.actionSystem.AnAction; import com.intellij.openapi.actionSystem.AnActionEvent; import com.intellij.openapi.actionSystem.CommonShortcuts; @@ -37,6 +35,7 @@ import com.intellij.util.textCompletion.DefaultTextCompletionValueDescriptor; import com.intellij.util.textCompletion.TextFieldWithCompletion; import com.intellij.util.textCompletion.ValuesCompletionProvider; import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; import javax.swing.*; import javax.swing.border.CompoundBorder; @@ -114,12 +113,10 @@ class MultilinePopupBuilder { supportsNegativeValues ? ContainerUtil.append(Chars.asList(SEPARATORS), '-') : Chars.asList(SEPARATORS), values, false); } + @Nullable @Override - public void fillCompletionVariants(@NotNull CompletionParameters parameters, - @NotNull String prefix, - @NotNull CompletionResultSet result) { - result.addLookupAdvertisement("Select one or more users separated with | or new lines"); - super.fillCompletionVariants(parameters, prefix, result); + public String getAdvertisement() { + return "Select one or more values separated with | or new lines"; } } } From de18fab9fe229d5478e11dcc5fa38417e915b3fe Mon Sep 17 00:00:00 2001 From: Julia Beliaeva Date: Mon, 14 Mar 2016 09:42:10 +0300 Subject: [PATCH 22/81] [text-completion] remove TextFieldWithAutoCompletionContributor, make TextFieldWithAutoCompletionListProvider implement TextCompletionProvider --- .../ui/TextFieldWithAutoCompletion.java | 17 +- ...extFieldWithAutoCompletionContributor.java | 154 ----------------- ...xtFieldWithAutoCompletionListProvider.java | 159 ++++++++++++++---- .../util/TextFieldCompletionProvider.java | 2 +- .../textCompletion/TextCompletionUtil.java | 6 +- .../src/META-INF/LangExtensions.xml | 3 - .../generic/GenericRepositoryEditor.java | 23 ++- .../tasks/impl/TaskChangelistSupport.java | 4 +- .../intellij/tasks/TaskCompletionTest.java | 12 +- 9 files changed, 166 insertions(+), 214 deletions(-) delete mode 100644 platform/lang-impl/src/com/intellij/ui/TextFieldWithAutoCompletionContributor.java diff --git a/platform/lang-impl/src/com/intellij/ui/TextFieldWithAutoCompletion.java b/platform/lang-impl/src/com/intellij/ui/TextFieldWithAutoCompletion.java index 1b09bd823045..88a5a8fa3b86 100644 --- a/platform/lang-impl/src/com/intellij/ui/TextFieldWithAutoCompletion.java +++ b/platform/lang-impl/src/com/intellij/ui/TextFieldWithAutoCompletion.java @@ -16,11 +16,14 @@ package com.intellij.ui; +import com.intellij.openapi.editor.Document; import com.intellij.openapi.editor.ex.EditorEx; import com.intellij.openapi.fileTypes.PlainTextLanguage; import com.intellij.openapi.project.DumbAware; import com.intellij.openapi.project.Project; import com.intellij.openapi.util.text.StringUtil; +import com.intellij.psi.PsiDocumentManager; +import com.intellij.psi.PsiFile; import com.intellij.util.textCompletion.TextCompletionUtil; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -57,7 +60,7 @@ public class TextFieldWithAutoCompletion extends LanguageTextField { myShowAutocompletionIsAvailableHint = showAutocompletionIsAvailableHint; myProvider = provider; - TextFieldWithAutoCompletionContributor.installCompletion(getDocument(), project, provider, true); + installCompletion(getDocument(), project, provider, true); } public static TextFieldWithAutoCompletion create(final Project project, @@ -81,7 +84,17 @@ public class TextFieldWithAutoCompletion extends LanguageTextField { } public void installProvider(@NotNull TextFieldWithAutoCompletionListProvider provider) { - TextFieldWithAutoCompletionContributor.installCompletion(getDocument(), getProject(), provider, true); + installCompletion(getDocument(), getProject(), provider, true); + } + + public static void installCompletion(@NotNull Document document, + @NotNull Project project, + @NotNull TextFieldWithAutoCompletionListProvider provider, + boolean autoPopup) { + PsiFile psiFile = PsiDocumentManager.getInstance(project).getPsiFile(document); + if (psiFile != null) { + TextCompletionUtil.installProvider(psiFile, provider, autoPopup); + } } @Override diff --git a/platform/lang-impl/src/com/intellij/ui/TextFieldWithAutoCompletionContributor.java b/platform/lang-impl/src/com/intellij/ui/TextFieldWithAutoCompletionContributor.java deleted file mode 100644 index 9ef69189f3f9..000000000000 --- a/platform/lang-impl/src/com/intellij/ui/TextFieldWithAutoCompletionContributor.java +++ /dev/null @@ -1,154 +0,0 @@ -/* - * Copyright 2000-2012 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.ui; - -import com.intellij.codeInsight.completion.*; -import com.intellij.codeInsight.lookup.AutoCompletionPolicy; -import com.intellij.codeInsight.lookup.LookupElementBuilder; -import com.intellij.concurrency.SensitiveProgressWrapper; -import com.intellij.openapi.actionSystem.IdeActions; -import com.intellij.openapi.application.ApplicationManager; -import com.intellij.openapi.diagnostic.Logger; -import com.intellij.openapi.editor.Document; -import com.intellij.openapi.progress.EmptyProgressIndicator; -import com.intellij.openapi.progress.ProcessCanceledException; -import com.intellij.openapi.progress.ProgressIndicator; -import com.intellij.openapi.progress.ProgressManager; -import com.intellij.openapi.project.DumbAware; -import com.intellij.openapi.project.DumbService; -import com.intellij.openapi.project.Project; -import com.intellij.openapi.util.Computable; -import com.intellij.openapi.util.Key; -import com.intellij.psi.PsiDocumentManager; -import com.intellij.psi.PsiFile; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -import java.util.Collection; -import java.util.concurrent.Callable; -import java.util.concurrent.Future; -import java.util.concurrent.TimeUnit; - -/** - * @author Roman.Chernyatchik - */ -public class TextFieldWithAutoCompletionContributor extends CompletionContributor implements DumbAware { - private static final Logger LOG = Logger.getInstance("#com.intellij.ui.TextFieldWithAutoCompletionContributor"); - private static final Key KEY = Key.create("text field simple completion available"); - private static final Key AUTO_POPUP_KEY = Key.create("text Field simple completion auto-popup"); - - public static void installCompletion(Document document, - Project project, - @Nullable TextFieldWithAutoCompletionListProvider provider, - boolean autoPopup) { - PsiFile psiFile = PsiDocumentManager.getInstance(project).getPsiFile(document); - if (psiFile != null) { - //noinspection unchecked - psiFile.putUserData(KEY, provider == null ? TextFieldWithAutoCompletion.EMPTY_COMPLETION : provider); - psiFile.putUserData(AUTO_POPUP_KEY, autoPopup); - } - } - - - @Override - public void fillCompletionVariants(@NotNull final CompletionParameters parameters, @NotNull CompletionResultSet result) { - PsiFile file = parameters.getOriginalFile(); - final TextFieldWithAutoCompletionListProvider provider = file.getUserData(KEY); - - if (provider == null || (DumbService.isDumb(file.getProject()) && !DumbService.isDumbAware(provider))) { - return; - } - String adv = provider.getAdvertisement(); - if (adv == null) { - final String shortcut = getActionShortcut(IdeActions.ACTION_QUICK_JAVADOC); - if (shortcut != null) { - adv = provider.getQuickDocHotKeyAdvertisement(shortcut); - } - } - if (adv != null) { - result.addLookupAdvertisement(adv); - } - - final String prefix = provider.getPrefix(parameters); - if (prefix == null) { - return; - } - if (parameters.getInvocationCount() == 0 && !file.getUserData(AUTO_POPUP_KEY)) { // is autopopup - return; - } - final PrefixMatcher prefixMatcher = provider.createPrefixMatcher(prefix); - if (prefixMatcher != null) { - result = result.withPrefixMatcher(prefixMatcher); - } - - Collection items = provider.getItems(prefix, true, parameters); - addCompletionElements(result, provider, items, -10000); - - final ProgressManager progressManager = ProgressManager.getInstance(); - ProgressIndicator mainIndicator = progressManager.getProgressIndicator(); - final ProgressIndicator indicator = mainIndicator != null ? new SensitiveProgressWrapper(mainIndicator) : new EmptyProgressIndicator(); - Future> - future = - ApplicationManager.getApplication().executeOnPooledThread(new Callable>() { - @Override - public Collection call() { - return progressManager.runProcess(new Computable>() { - @Override - public Collection compute() { - return provider.getItems(prefix, false, parameters); - } - }, indicator); - } - }); - - while (true) { - try { - Collection tasks = future.get(100, TimeUnit.MILLISECONDS); - if (tasks != null) { - addCompletionElements(result, provider, tasks, 0); - return; - } - } - catch (ProcessCanceledException e) { - throw e; - } - catch (Exception ignore) { - - } - ProgressManager.checkCanceled(); - } - } - - private static void addCompletionElements(final CompletionResultSet result, - final TextFieldWithAutoCompletionListProvider listProvider, - final Collection items, - final int index) { - final AutoCompletionPolicy completionPolicy = ApplicationManager.getApplication().isUnitTestMode() - ? AutoCompletionPolicy.ALWAYS_AUTOCOMPLETE - : AutoCompletionPolicy.NEVER_AUTOCOMPLETE; - int grouping = index; - for (final T item : items) { - if (item == null) { - LOG.error("Null item from " + listProvider); - continue; - } - - LookupElementBuilder builder = listProvider.createLookupBuilder(item); - - result.addElement(PrioritizedLookupElement.withGrouping(builder.withAutoCompletionPolicy(completionPolicy), grouping--)); - } - } -} diff --git a/platform/lang-impl/src/com/intellij/ui/TextFieldWithAutoCompletionListProvider.java b/platform/lang-impl/src/com/intellij/ui/TextFieldWithAutoCompletionListProvider.java index 7529bc1c42fe..815e6b3b18a6 100644 --- a/platform/lang-impl/src/com/intellij/ui/TextFieldWithAutoCompletionListProvider.java +++ b/platform/lang-impl/src/com/intellij/ui/TextFieldWithAutoCompletionListProvider.java @@ -15,10 +15,24 @@ */ package com.intellij.ui; -import com.intellij.codeInsight.completion.CompletionParameters; -import com.intellij.codeInsight.completion.PlainPrefixMatcher; -import com.intellij.codeInsight.completion.PrefixMatcher; +import com.intellij.codeInsight.completion.*; +import com.intellij.codeInsight.lookup.AutoCompletionPolicy; +import com.intellij.codeInsight.lookup.CharFilter; +import com.intellij.codeInsight.lookup.LookupElementBuilder; +import com.intellij.concurrency.SensitiveProgressWrapper; +import com.intellij.openapi.actionSystem.IdeActions; +import com.intellij.openapi.application.ApplicationManager; +import com.intellij.openapi.diagnostic.Logger; +import com.intellij.openapi.keymap.KeymapUtil; +import com.intellij.openapi.progress.EmptyProgressIndicator; +import com.intellij.openapi.progress.ProcessCanceledException; +import com.intellij.openapi.progress.ProgressIndicator; +import com.intellij.openapi.progress.ProgressManager; +import com.intellij.openapi.util.Computable; import com.intellij.util.textCompletion.DefaultTextCompletionValueDescriptor; +import com.intellij.util.textCompletion.TextCompletionProvider; +import com.intellij.util.textCompletion.TextCompletionUtil; +import com.intellij.util.textCompletion.TextCompletionValueDescriptor; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -26,11 +40,16 @@ import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.List; +import java.util.concurrent.Callable; +import java.util.concurrent.Future; +import java.util.concurrent.TimeUnit; /** * @author Roman.Chernyatchik */ -public abstract class TextFieldWithAutoCompletionListProvider extends DefaultTextCompletionValueDescriptor { +public abstract class TextFieldWithAutoCompletionListProvider extends DefaultTextCompletionValueDescriptor implements + TextCompletionProvider { + private static final Logger LOG = Logger.getInstance(TextFieldWithAutoCompletionListProvider.class); @NotNull protected Collection myVariants; @Nullable private String myCompletionAdvertisement; @@ -40,6 +59,92 @@ public abstract class TextFieldWithAutoCompletionListProvider extends Default myCompletionAdvertisement = null; } + @Nullable + @Override + public String getPrefix(@NotNull String text, int offset) { + return getCompletionPrefix(text, offset); + } + + @NotNull + @Override + public CompletionResultSet applyPrefixMatcher(@NotNull CompletionResultSet result, @NotNull String prefix) { + PrefixMatcher prefixMatcher = createPrefixMatcher(prefix); + if (prefixMatcher != null) { + return result.withPrefixMatcher(prefixMatcher); + } + return result; + } + + @Nullable + @Override + public CharFilter.Result acceptChar(char c) { + return null; + } + + @Override + public void fillCompletionVariants(@NotNull CompletionParameters parameters, + @NotNull String prefix, + @NotNull CompletionResultSet result) { + if (parameters.getInvocationCount() == 0 && !parameters.getOriginalFile().getUserData(TextCompletionUtil.AUTO_POPUP_KEY)) { // is autopopup + return; + } + Collection items = getItems(prefix, true, parameters); + addCompletionElements(result, this, items, -10000); + + final ProgressManager progressManager = ProgressManager.getInstance(); + ProgressIndicator mainIndicator = progressManager.getProgressIndicator(); + final ProgressIndicator indicator = mainIndicator != null ? new SensitiveProgressWrapper(mainIndicator) : new EmptyProgressIndicator(); + Future> + future = + ApplicationManager.getApplication().executeOnPooledThread(new Callable>() { + @Override + public Collection call() { + return progressManager.runProcess(new Computable>() { + @Override + public Collection compute() { + return getItems(prefix, false, parameters); + } + }, indicator); + } + }); + + while (true) { + try { + Collection tasks = future.get(100, TimeUnit.MILLISECONDS); + if (tasks != null) { + addCompletionElements(result, this, tasks, 0); + return; + } + } + catch (ProcessCanceledException e) { + throw e; + } + catch (Exception ignore) { + + } + ProgressManager.checkCanceled(); + } + } + + private static void addCompletionElements(final CompletionResultSet result, + final TextCompletionValueDescriptor descriptor, + final Collection items, + final int index) { + final AutoCompletionPolicy completionPolicy = ApplicationManager.getApplication().isUnitTestMode() + ? AutoCompletionPolicy.ALWAYS_AUTOCOMPLETE + : AutoCompletionPolicy.NEVER_AUTOCOMPLETE; + int grouping = index; + for (final T item : items) { + if (item == null) { + LOG.error("Null item from " + descriptor); + continue; + } + + LookupElementBuilder builder = descriptor.createLookupBuilder(item); + result.addElement(PrioritizedLookupElement.withGrouping(builder.withAutoCompletionPolicy(completionPolicy), grouping--)); + } + } + public void setItems(@Nullable final Collection variants) { myVariants = (variants != null) ? variants : Collections.emptyList(); } @@ -56,21 +161,6 @@ public abstract class TextFieldWithAutoCompletionListProvider extends Default return items; } - /** - * Completion list advertisement for documentation popup - * - * @param shortcut - * @return text - */ - @Nullable - public String getQuickDocHotKeyAdvertisement(@NotNull final String shortcut) { - final String advertisementTail = getQuickDocHotKeyAdvertisementTail(shortcut); - if (advertisementTail == null) { - return null; - } - return "Pressing " + shortcut + " would show " + advertisementTail; - } - /** * Completion list advertisement text, if null advertisement for documentation * popup will be shown @@ -79,10 +169,21 @@ public abstract class TextFieldWithAutoCompletionListProvider extends Default */ @Nullable public String getAdvertisement() { - return myCompletionAdvertisement; + if (myCompletionAdvertisement != null) return myCompletionAdvertisement; + String shortcut = KeymapUtil.getFirstKeyboardShortcutText((IdeActions.ACTION_QUICK_JAVADOC)); + String advertisementTail = getQuickDocHotKeyAdvertisementTail(shortcut); + if (advertisementTail == null) { + return null; + } + return "Pressing " + shortcut + " would show " + advertisementTail; } - public void setAdvertisement(@Nullable final String completionAdvertisement) { + @Nullable + protected String getQuickDocHotKeyAdvertisementTail(@NotNull final String shortcut) { + return null; + } + + public void setAdvertisement(@Nullable String completionAdvertisement) { myCompletionAdvertisement = completionAdvertisement; } @@ -91,21 +192,17 @@ public abstract class TextFieldWithAutoCompletionListProvider extends Default return new PlainPrefixMatcher(prefix); } - @Nullable - public String getPrefix(@NotNull final CompletionParameters parameters) { - return getCompletionPrefix(parameters); - } - + @NotNull public static String getCompletionPrefix(CompletionParameters parameters) { String text = parameters.getOriginalFile().getText(); int offset = parameters.getOffset(); + return getCompletionPrefix(text, offset); + } + + @NotNull + private static String getCompletionPrefix(String text, int offset) { int i = text.lastIndexOf(' ', offset - 1) + 1; int j = text.lastIndexOf('\n', offset - 1) + 1; return text.substring(Math.max(i, j), offset); } - - @Nullable - protected String getQuickDocHotKeyAdvertisementTail(@NotNull final String shortcut) { - return null; - } } diff --git a/platform/lang-impl/src/com/intellij/util/TextFieldCompletionProvider.java b/platform/lang-impl/src/com/intellij/util/TextFieldCompletionProvider.java index 6986319ca2a2..b00c08a58ab3 100644 --- a/platform/lang-impl/src/com/intellij/util/TextFieldCompletionProvider.java +++ b/platform/lang-impl/src/com/intellij/util/TextFieldCompletionProvider.java @@ -87,7 +87,7 @@ public abstract class TextFieldCompletionProvider implements TextCompletionProvi final PsiFile psiFile = PsiFileFactory.getInstance(project) .createFileFromText("Dummy." + fileType.getDefaultExtension(), fileType, text, stamp, true, false); - TextCompletionUtil.installProvider(psiFile, this); + TextCompletionUtil.installProvider(psiFile, this, true); final Document document = PsiDocumentManager.getInstance(project).getDocument(psiFile); assert document != null; diff --git a/platform/lang-impl/src/com/intellij/util/textCompletion/TextCompletionUtil.java b/platform/lang-impl/src/com/intellij/util/textCompletion/TextCompletionUtil.java index 3c2c4026f7fd..bb1c42b899d6 100644 --- a/platform/lang-impl/src/com/intellij/util/textCompletion/TextCompletionUtil.java +++ b/platform/lang-impl/src/com/intellij/util/textCompletion/TextCompletionUtil.java @@ -37,9 +37,11 @@ import org.jetbrains.annotations.Nullable; public class TextCompletionUtil { public static final Key COMPLETING_TEXT_FIELD_KEY = Key.create("COMPLETING_TEXT_FIELD_KEY"); + public static final Key AUTO_POPUP_KEY = Key.create("AUTOPOPUP_TEXT_FIELD_KEY"); - public static void installProvider(@NotNull PsiFile psiFile, @NotNull TextCompletionProvider provider) { + public static void installProvider(@NotNull PsiFile psiFile, @NotNull TextCompletionProvider provider, boolean autoPopup) { psiFile.putUserData(COMPLETING_TEXT_FIELD_KEY, provider); + psiFile.putUserData(AUTO_POPUP_KEY, autoPopup); } @Nullable @@ -97,7 +99,7 @@ public class TextCompletionUtil { @Override public void customizePsiFile(@NotNull PsiFile file) { - installProvider(file, myProvider); + installProvider(file, myProvider, myAutoPopup); file.putUserData(AutoPopupController.ALWAYS_AUTO_POPUP, myAutoPopup); } } diff --git a/platform/platform-resources/src/META-INF/LangExtensions.xml b/platform/platform-resources/src/META-INF/LangExtensions.xml index c30e72c34d46..02489b6d7dd9 100644 --- a/platform/platform-resources/src/META-INF/LangExtensions.xml +++ b/platform/platform-resources/src/META-INF/LangExtensions.xml @@ -877,9 +877,6 @@ - - diff --git a/plugins/tasks/tasks-core/src/com/intellij/tasks/generic/GenericRepositoryEditor.java b/plugins/tasks/tasks-core/src/com/intellij/tasks/generic/GenericRepositoryEditor.java index 0d1c68c49ac1..96b95e07771a 100644 --- a/plugins/tasks/tasks-core/src/com/intellij/tasks/generic/GenericRepositoryEditor.java +++ b/plugins/tasks/tasks-core/src/com/intellij/tasks/generic/GenericRepositoryEditor.java @@ -26,9 +26,7 @@ import java.util.IdentityHashMap; import java.util.List; import java.util.Map; -import static com.intellij.tasks.generic.GenericRepositoryUtil.concat; -import static com.intellij.tasks.generic.GenericRepositoryUtil.createPlaceholdersList; -import static com.intellij.tasks.generic.GenericRepositoryUtil.prettifyVariableName; +import static com.intellij.tasks.generic.GenericRepositoryUtil.*; import static com.intellij.ui.TextFieldWithAutoCompletion.StringsCompletionProvider; /** @@ -258,17 +256,16 @@ public class GenericRepositoryEditor extends BaseRe private TextFieldWithAutoCompletion createTextFieldWithCompletion(String text, final List variants) { final StringsCompletionProvider provider = new StringsCompletionProvider(variants, null) { - @Nullable - @Override - public String getPrefix(@NotNull CompletionParameters parameters) { - final String text = parameters.getOriginalFile().getText(); - final int i = text.lastIndexOf('{', parameters.getOffset() - 1); - if (i < 0) { - return ""; - } - return text.substring(i, parameters.getOffset()); + @Nullable + @Override + public String getPrefix(@NotNull String text, int offset) { + final int i = text.lastIndexOf('{', offset - 1); + if (i < 0) { + return ""; } - }; + return text.substring(i, offset); + } + }; return new TextFieldWithAutoCompletion(myProject, provider, true, text); } diff --git a/plugins/tasks/tasks-core/src/com/intellij/tasks/impl/TaskChangelistSupport.java b/plugins/tasks/tasks-core/src/com/intellij/tasks/impl/TaskChangelistSupport.java index 980afc7a90d9..7b857e5bb085 100644 --- a/plugins/tasks/tasks-core/src/com/intellij/tasks/impl/TaskChangelistSupport.java +++ b/plugins/tasks/tasks-core/src/com/intellij/tasks/impl/TaskChangelistSupport.java @@ -24,7 +24,7 @@ import com.intellij.tasks.ChangeListInfo; import com.intellij.tasks.LocalTask; import com.intellij.tasks.actions.TaskAutoCompletionListProvider; import com.intellij.ui.EditorTextField; -import com.intellij.ui.TextFieldWithAutoCompletionContributor; +import com.intellij.ui.TextFieldWithAutoCompletion; import com.intellij.util.Consumer; import javax.swing.*; @@ -47,7 +47,7 @@ public class TaskChangelistSupport implements EditChangelistSupport { final TaskAutoCompletionListProvider completionProvider = new TaskAutoCompletionListProvider(myProject); - TextFieldWithAutoCompletionContributor.installCompletion(document, myProject, completionProvider, false); + TextFieldWithAutoCompletion.installCompletion(document, myProject, completionProvider, false); } public Consumer addControls(JPanel bottomPanel, final LocalChangeList initial) { diff --git a/plugins/tasks/tasks-tests/test/com/intellij/tasks/TaskCompletionTest.java b/plugins/tasks/tasks-tests/test/com/intellij/tasks/TaskCompletionTest.java index 0f86009cc66c..63b94db2ca92 100644 --- a/plugins/tasks/tasks-tests/test/com/intellij/tasks/TaskCompletionTest.java +++ b/plugins/tasks/tasks-tests/test/com/intellij/tasks/TaskCompletionTest.java @@ -11,7 +11,7 @@ import com.intellij.tasks.impl.LocalTaskImpl; import com.intellij.tasks.impl.TaskManagerImpl; import com.intellij.testFramework.MapDataContext; import com.intellij.testFramework.fixtures.LightCodeInsightFixtureTestCase; -import com.intellij.ui.TextFieldWithAutoCompletionContributor; +import com.intellij.ui.TextFieldWithAutoCompletion; import java.util.Arrays; import java.util.List; @@ -22,7 +22,7 @@ import java.util.List; public class TaskCompletionTest extends LightCodeInsightFixtureTestCase { public TaskCompletionTest() { -// super(UsefulTestCase.IDEA_MARKER_CLASS, "PlatformLangXml"); + // super(UsefulTestCase.IDEA_MARKER_CLASS, "PlatformLangXml"); } public void testTaskCompletion() throws Exception { @@ -55,7 +55,7 @@ public class TaskCompletionTest extends LightCodeInsightFixtureTestCase { getManager().updateIssues(null); List issues = getManager().getCachedIssues(); -// assertEquals("TEST-002", issues.get(0).getSummary()); + // assertEquals("TEST-002", issues.get(0).getSummary()); myFixture.complete(CompletionType.BASIC); assertEquals(Arrays.asList("TEST-002", "TEST-003", "TEST-001", "TEST-004"), myFixture.getLookupElementStrings()); @@ -87,9 +87,9 @@ public class TaskCompletionTest extends LightCodeInsightFixtureTestCase { PsiFile psiFile = myFixture.configureByText("test.txt", text); Document document = myFixture.getDocument(psiFile); final Project project = getProject(); - TextFieldWithAutoCompletionContributor.installCompletion(document, project, - new TaskAutoCompletionListProvider(project), - false); + TextFieldWithAutoCompletion.installCompletion(document, project, + new TaskAutoCompletionListProvider(project), + false); document.putUserData(CommitMessage.DATA_CONTEXT_KEY, new MapDataContext()); } From ed4bc0a2e53277f67f002f68c5b4afa64489652c Mon Sep 17 00:00:00 2001 From: Julia Beliaeva Date: Mon, 14 Mar 2016 09:55:52 +0300 Subject: [PATCH 23/81] [text-completion] add auto-popup functionality to TextCompletionContributor, force auto-popup and auto-popup are not the same things --- .../dvcs/push/ui/PushTargetTextField.java | 2 +- .../TextFieldWithAutoCompletionListProvider.java | 3 --- .../TextCompletionContributor.java | 7 ++++++- .../util/textCompletion/TextCompletionUtil.java | 2 -- .../textCompletion/TextFieldWithCompletion.java | 16 +++++++++++++--- 5 files changed, 20 insertions(+), 10 deletions(-) diff --git a/platform/dvcs-impl/src/com/intellij/dvcs/push/ui/PushTargetTextField.java b/platform/dvcs-impl/src/com/intellij/dvcs/push/ui/PushTargetTextField.java index affbc2e59e0c..ea01f8e6d614 100644 --- a/platform/dvcs-impl/src/com/intellij/dvcs/push/ui/PushTargetTextField.java +++ b/platform/dvcs-impl/src/com/intellij/dvcs/push/ui/PushTargetTextField.java @@ -30,7 +30,7 @@ import java.util.List; public class PushTargetTextField extends TextFieldWithCompletion { public PushTargetTextField(@NotNull Project project, @NotNull List targetVariants, @NotNull String defaultTargetName) { - super(project, getCompletionProvider(targetVariants), defaultTargetName, true, true, true); + super(project, getCompletionProvider(targetVariants), defaultTargetName, true, false, true); addFocusListener(new FocusAdapter() { @Override public void focusGained(FocusEvent e) { diff --git a/platform/lang-impl/src/com/intellij/ui/TextFieldWithAutoCompletionListProvider.java b/platform/lang-impl/src/com/intellij/ui/TextFieldWithAutoCompletionListProvider.java index 815e6b3b18a6..860fc6ea8a69 100644 --- a/platform/lang-impl/src/com/intellij/ui/TextFieldWithAutoCompletionListProvider.java +++ b/platform/lang-impl/src/com/intellij/ui/TextFieldWithAutoCompletionListProvider.java @@ -85,9 +85,6 @@ public abstract class TextFieldWithAutoCompletionListProvider extends Default public void fillCompletionVariants(@NotNull CompletionParameters parameters, @NotNull String prefix, @NotNull CompletionResultSet result) { - if (parameters.getInvocationCount() == 0 && !parameters.getOriginalFile().getUserData(TextCompletionUtil.AUTO_POPUP_KEY)) { // is autopopup - return; - } Collection items = getItems(prefix, true, parameters); addCompletionElements(result, this, items, -10000); diff --git a/platform/lang-impl/src/com/intellij/util/textCompletion/TextCompletionContributor.java b/platform/lang-impl/src/com/intellij/util/textCompletion/TextCompletionContributor.java index 858dc66e3def..84a7a6e5a4a5 100644 --- a/platform/lang-impl/src/com/intellij/util/textCompletion/TextCompletionContributor.java +++ b/platform/lang-impl/src/com/intellij/util/textCompletion/TextCompletionContributor.java @@ -40,6 +40,11 @@ public class TextCompletionContributor extends CompletionContributor implements TextCompletionProvider provider = TextCompletionUtil.getProvider(file); if (provider == null) return; + if (parameters.getInvocationCount() == 0 && + !Boolean.FALSE.equals(file.getUserData(TextCompletionUtil.AUTO_POPUP_KEY))) { + return; + } + String advertisement = provider.getAdvertisement(); if (advertisement != null) { result.addLookupAdvertisement(advertisement); @@ -59,7 +64,7 @@ public class TextCompletionContributor extends CompletionContributor implements public boolean invokeAutoPopup(@NotNull PsiElement position, char typeChar) { TextCompletionProvider provider = TextCompletionUtil.getProvider(position.getContainingFile()); if (provider != null) { - if (Boolean.TRUE.equals(position.getContainingFile().getUserData(ALWAYS_AUTO_POPUP))) { + if (Boolean.TRUE.equals(position.getContainingFile().getUserData(TextCompletionUtil.AUTO_POPUP_KEY))) { return Objects.equals(CharFilter.Result.ADD_TO_PREFIX, provider.acceptChar(typeChar)); } } diff --git a/platform/lang-impl/src/com/intellij/util/textCompletion/TextCompletionUtil.java b/platform/lang-impl/src/com/intellij/util/textCompletion/TextCompletionUtil.java index bb1c42b899d6..e6255e310f9e 100644 --- a/platform/lang-impl/src/com/intellij/util/textCompletion/TextCompletionUtil.java +++ b/platform/lang-impl/src/com/intellij/util/textCompletion/TextCompletionUtil.java @@ -15,7 +15,6 @@ */ package com.intellij.util.textCompletion; -import com.intellij.codeInsight.AutoPopupController; import com.intellij.codeInsight.hint.HintManager; import com.intellij.openapi.actionSystem.ActionManager; import com.intellij.openapi.actionSystem.IdeActions; @@ -100,7 +99,6 @@ public class TextCompletionUtil { @Override public void customizePsiFile(@NotNull PsiFile file) { installProvider(file, myProvider, myAutoPopup); - file.putUserData(AutoPopupController.ALWAYS_AUTO_POPUP, myAutoPopup); } } } diff --git a/platform/lang-impl/src/com/intellij/util/textCompletion/TextFieldWithCompletion.java b/platform/lang-impl/src/com/intellij/util/textCompletion/TextFieldWithCompletion.java index 99be2ca434ff..cb489f795213 100644 --- a/platform/lang-impl/src/com/intellij/util/textCompletion/TextFieldWithCompletion.java +++ b/platform/lang-impl/src/com/intellij/util/textCompletion/TextFieldWithCompletion.java @@ -25,17 +25,27 @@ import com.intellij.ui.LanguageTextField; import org.jetbrains.annotations.NotNull; public class TextFieldWithCompletion extends LanguageTextField { - private final boolean myAutoPopup; + private final boolean myForceAutoPopup; private final boolean myShowHint; + public TextFieldWithCompletion(@NotNull Project project, + @NotNull TextCompletionProvider provider, + @NotNull String value, + boolean oneLineMode, + boolean forceAutoPopup, + boolean showHint) { + this(project, provider, value, oneLineMode, true, forceAutoPopup, showHint); + } + public TextFieldWithCompletion(@NotNull Project project, @NotNull TextCompletionProvider provider, @NotNull String value, boolean oneLineMode, boolean autoPopup, + boolean forceAutoPopup, boolean showHint) { super(PlainTextLanguage.INSTANCE, project, value, new TextCompletionUtil.DocumentWithCompletionCreator(provider, autoPopup), oneLineMode); - myAutoPopup = autoPopup; + myForceAutoPopup = forceAutoPopup; myShowHint = showHint; } @@ -44,7 +54,7 @@ public class TextFieldWithCompletion extends LanguageTextField { EditorEx editor = super.createEditor(); EditorCustomization disableSpellChecking = SpellCheckingEditorCustomizationProvider.getInstance().getDisabledCustomization(); if (disableSpellChecking != null) disableSpellChecking.customize(editor); - editor.putUserData(AutoPopupController.ALWAYS_AUTO_POPUP, myAutoPopup); + editor.putUserData(AutoPopupController.ALWAYS_AUTO_POPUP, myForceAutoPopup); if (myShowHint) { TextCompletionUtil.installCompletionHint(editor); From f68a7fb1c21e1eb691ef88a77169c3e7a80c8285 Mon Sep 17 00:00:00 2001 From: Julia Beliaeva Date: Mon, 14 Mar 2016 09:58:09 +0300 Subject: [PATCH 24/81] [text-completion] remove empty implementations --- .../com/intellij/ui/TextFieldWithAutoCompletion.java | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/platform/lang-impl/src/com/intellij/ui/TextFieldWithAutoCompletion.java b/platform/lang-impl/src/com/intellij/ui/TextFieldWithAutoCompletion.java index 88a5a8fa3b86..e908e49eda9b 100644 --- a/platform/lang-impl/src/com/intellij/ui/TextFieldWithAutoCompletion.java +++ b/platform/lang-impl/src/com/intellij/ui/TextFieldWithAutoCompletion.java @@ -132,15 +132,5 @@ public class TextFieldWithAutoCompletion extends LanguageTextField { protected String getLookupString(@NotNull final String item) { return item; } - - @Override - protected String getTailText(@NotNull final String item) { - return null; - } - - @Override - protected String getTypeText(@NotNull final String item) { - return null; - } } } From c0acd6ff8aeca0a60267b9588033bd47f10803a6 Mon Sep 17 00:00:00 2001 From: Julia Beliaeva Date: Mon, 14 Mar 2016 10:10:15 +0300 Subject: [PATCH 25/81] [text-completion] restore providers dumb-awareness --- .../dvcs/push/ui/PushTargetTextField.java | 5 +++-- .../textCompletion/ValuesCompletionProvider.java | 15 +++++++++++++++ .../vcs/log/ui/filter/MultilinePopupBuilder.java | 3 ++- .../git4idea/checkin/GitCheckinEnvironment.java | 3 ++- 4 files changed, 22 insertions(+), 4 deletions(-) diff --git a/platform/dvcs-impl/src/com/intellij/dvcs/push/ui/PushTargetTextField.java b/platform/dvcs-impl/src/com/intellij/dvcs/push/ui/PushTargetTextField.java index ea01f8e6d614..25686eb20781 100644 --- a/platform/dvcs-impl/src/com/intellij/dvcs/push/ui/PushTargetTextField.java +++ b/platform/dvcs-impl/src/com/intellij/dvcs/push/ui/PushTargetTextField.java @@ -22,6 +22,7 @@ import com.intellij.util.textCompletion.DefaultTextCompletionValueDescriptor; import com.intellij.util.textCompletion.TextCompletionProvider; import com.intellij.util.textCompletion.TextFieldWithCompletion; import com.intellij.util.textCompletion.ValuesCompletionProvider; +import com.intellij.util.textCompletion.ValuesCompletionProvider.ValuesCompletionProviderDumbAware; import org.jetbrains.annotations.NotNull; import java.awt.event.FocusAdapter; @@ -30,7 +31,7 @@ import java.util.List; public class PushTargetTextField extends TextFieldWithCompletion { public PushTargetTextField(@NotNull Project project, @NotNull List targetVariants, @NotNull String defaultTargetName) { - super(project, getCompletionProvider(targetVariants), defaultTargetName, true, false, true); + super(project, getCompletionProvider(targetVariants), defaultTargetName, true, true, true); addFocusListener(new FocusAdapter() { @Override public void focusGained(FocusEvent e) { @@ -50,7 +51,7 @@ public class PushTargetTextField extends TextFieldWithCompletion { @NotNull private static TextCompletionProvider getCompletionProvider(@NotNull final List targetVariants) { - return new ValuesCompletionProvider<>(new DefaultTextCompletionValueDescriptor.StringValueDescriptor() { + return new ValuesCompletionProviderDumbAware<>(new DefaultTextCompletionValueDescriptor.StringValueDescriptor() { @Override public int compare(String item1, String item2) { return Integer.valueOf(ContainerUtil.indexOf(targetVariants, item1)).compareTo(ContainerUtil.indexOf(targetVariants, item2)); diff --git a/platform/lang-impl/src/com/intellij/util/textCompletion/ValuesCompletionProvider.java b/platform/lang-impl/src/com/intellij/util/textCompletion/ValuesCompletionProvider.java index 80c80dd3edcd..9f872c6d5daa 100644 --- a/platform/lang-impl/src/com/intellij/util/textCompletion/ValuesCompletionProvider.java +++ b/platform/lang-impl/src/com/intellij/util/textCompletion/ValuesCompletionProvider.java @@ -19,6 +19,7 @@ import com.intellij.codeInsight.completion.CompletionParameters; import com.intellij.codeInsight.completion.CompletionResultSet; import com.intellij.codeInsight.completion.PlainPrefixMatcher; import com.intellij.codeInsight.lookup.CharFilter; +import com.intellij.openapi.project.DumbAware; import com.intellij.util.containers.ContainerUtil; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -103,4 +104,18 @@ public class ValuesCompletionProvider implements TextCompletionProvider { protected Collection getValues(@NotNull String prefix, @NotNull CompletionResultSet result) { return myValues; } + + public static class ValuesCompletionProviderDumbAware extends ValuesCompletionProvider implements DumbAware { + public ValuesCompletionProviderDumbAware(@NotNull TextCompletionValueDescriptor descriptor, + @NotNull List separators, + @NotNull Collection values, + boolean caseSensitive) { + super(descriptor, separators, values, caseSensitive); + } + + public ValuesCompletionProviderDumbAware(@NotNull TextCompletionValueDescriptor presentation, + @NotNull Collection values) { + super(presentation, values); + } + } } diff --git a/platform/vcs-log/impl/src/com/intellij/vcs/log/ui/filter/MultilinePopupBuilder.java b/platform/vcs-log/impl/src/com/intellij/vcs/log/ui/filter/MultilinePopupBuilder.java index 4baeb6f8ea5c..62c2ef8d8af0 100644 --- a/platform/vcs-log/impl/src/com/intellij/vcs/log/ui/filter/MultilinePopupBuilder.java +++ b/platform/vcs-log/impl/src/com/intellij/vcs/log/ui/filter/MultilinePopupBuilder.java @@ -34,6 +34,7 @@ import com.intellij.util.containers.ContainerUtil; import com.intellij.util.textCompletion.DefaultTextCompletionValueDescriptor; import com.intellij.util.textCompletion.TextFieldWithCompletion; import com.intellij.util.textCompletion.ValuesCompletionProvider; +import com.intellij.util.textCompletion.ValuesCompletionProvider.ValuesCompletionProviderDumbAware; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -107,7 +108,7 @@ class MultilinePopupBuilder { }); } - private static class MyCompletionProvider extends ValuesCompletionProvider { + private static class MyCompletionProvider extends ValuesCompletionProviderDumbAware { MyCompletionProvider(@NotNull Collection values, boolean supportsNegativeValues) { super(new DefaultTextCompletionValueDescriptor.StringValueDescriptor(), supportsNegativeValues ? ContainerUtil.append(Chars.asList(SEPARATORS), '-') : Chars.asList(SEPARATORS), values, false); diff --git a/plugins/git4idea/src/git4idea/checkin/GitCheckinEnvironment.java b/plugins/git4idea/src/git4idea/checkin/GitCheckinEnvironment.java index 2386cbc89644..a654a1745692 100644 --- a/plugins/git4idea/src/git4idea/checkin/GitCheckinEnvironment.java +++ b/plugins/git4idea/src/git4idea/checkin/GitCheckinEnvironment.java @@ -45,6 +45,7 @@ import com.intellij.util.textCompletion.DefaultTextCompletionValueDescriptor; import com.intellij.util.textCompletion.TextCompletionProvider; import com.intellij.util.textCompletion.TextFieldWithCompletion; import com.intellij.util.textCompletion.ValuesCompletionProvider; +import com.intellij.util.textCompletion.ValuesCompletionProvider.ValuesCompletionProviderDumbAware; import com.intellij.util.ui.UIUtil; import com.intellij.vcs.log.VcsFullCommitDetails; import com.intellij.vcs.log.VcsUser; @@ -622,7 +623,7 @@ public class GitCheckinEnvironment implements CheckinEnvironment { @NotNull private EditorTextField createTextField(@NotNull Project project, @NotNull List list) { TextCompletionProvider completionProvider = - new ValuesCompletionProvider<>(new DefaultTextCompletionValueDescriptor.StringValueDescriptor(), list); + new ValuesCompletionProviderDumbAware<>(new DefaultTextCompletionValueDescriptor.StringValueDescriptor(), list); return new TextFieldWithCompletion(project, completionProvider, "", true, true, true); } From 791ab530319877a3b08e6ae48427bbb40a4155a3 Mon Sep 17 00:00:00 2001 From: Julia Beliaeva Date: Mon, 14 Mar 2016 11:23:40 +0300 Subject: [PATCH 26/81] [text-completion] minor: remove unused constructor, annotations, renames --- .../ui/TextFieldWithAutoCompletion.java | 60 +++++++++---------- 1 file changed, 28 insertions(+), 32 deletions(-) diff --git a/platform/lang-impl/src/com/intellij/ui/TextFieldWithAutoCompletion.java b/platform/lang-impl/src/com/intellij/ui/TextFieldWithAutoCompletion.java index e908e49eda9b..bb8cd11cfe09 100644 --- a/platform/lang-impl/src/com/intellij/ui/TextFieldWithAutoCompletion.java +++ b/platform/lang-impl/src/com/intellij/ui/TextFieldWithAutoCompletion.java @@ -41,42 +41,39 @@ import java.util.Collection; * @author Roman Chernyatchik */ public class TextFieldWithAutoCompletion extends LanguageTextField { - public static final TextFieldWithAutoCompletionListProvider EMPTY_COMPLETION = new StringsCompletionProvider(null, null); - private final boolean myShowAutocompletionIsAvailableHint; - private final TextFieldWithAutoCompletionListProvider myProvider; + @NotNull private final TextFieldWithAutoCompletionListProvider myProvider; + private final boolean myShowCompletionHint; - @SuppressWarnings("unchecked") - public TextFieldWithAutoCompletion() { - this(null, EMPTY_COMPLETION, false, null); - } - - - public TextFieldWithAutoCompletion(final Project project, - @NotNull final TextFieldWithAutoCompletionListProvider provider, - final boolean showAutocompletionIsAvailableHint, @Nullable final String text) { + public TextFieldWithAutoCompletion(@Nullable Project project, + @NotNull TextFieldWithAutoCompletionListProvider provider, + boolean showCompletionHint, + @Nullable String text) { super(project == null ? null : PlainTextLanguage.INSTANCE, project, text == null ? "" : text); - myShowAutocompletionIsAvailableHint = showAutocompletionIsAvailableHint; + myShowCompletionHint = showCompletionHint; myProvider = provider; - installCompletion(getDocument(), project, provider, true); + if (project != null) { + installCompletion(getDocument(), project, provider, true); + } } - public static TextFieldWithAutoCompletion create(final Project project, - @NotNull final Collection items, - final boolean showAutocompletionIsAvailableHint, - @Nullable final String text) { - return create(project, items, null, showAutocompletionIsAvailableHint, text); + @NotNull + public static TextFieldWithAutoCompletion create(@Nullable Project project, + @NotNull Collection items, + boolean showCompletionHint, + @Nullable String text) { + return create(project, items, null, showCompletionHint, text); } - public static TextFieldWithAutoCompletion create(final Project project, - @NotNull final Collection items, - @Nullable final Icon icon, - final boolean showAutocompletionIsAvailableHint, - @Nullable final String text) { - return new TextFieldWithAutoCompletion(project, new StringsCompletionProvider(items, icon), showAutocompletionIsAvailableHint, - text); + @NotNull + public static TextFieldWithAutoCompletion create(@Nullable Project project, + @NotNull Collection items, + @Nullable Icon icon, + boolean showCompletionHint, + @Nullable String text) { + return new TextFieldWithAutoCompletion(project, new StringsCompletionProvider(items, icon), showCompletionHint, text); } public void setVariants(@NotNull Collection variants) { @@ -101,7 +98,7 @@ public class TextFieldWithAutoCompletion extends LanguageTextField { protected EditorEx createEditor() { EditorEx editor = super.createEditor(); - if (myShowAutocompletionIsAvailableHint) { + if (myShowCompletionHint) { TextCompletionUtil.installCompletionHint(editor); } @@ -111,25 +108,24 @@ public class TextFieldWithAutoCompletion extends LanguageTextField { public static class StringsCompletionProvider extends TextFieldWithAutoCompletionListProvider implements DumbAware { @Nullable private final Icon myIcon; - public StringsCompletionProvider(@Nullable final Collection variants, - @Nullable final Icon icon) { + public StringsCompletionProvider(@Nullable Collection variants, @Nullable Icon icon) { super(variants); myIcon = icon; } @Override - public int compare(final String item1, final String item2) { + public int compare(String item1, String item2) { return StringUtil.compare(item1, item2, false); } @Override - protected Icon getIcon(@NotNull final String item) { + protected Icon getIcon(@NotNull String item) { return myIcon; } @NotNull @Override - protected String getLookupString(@NotNull final String item) { + protected String getLookupString(@NotNull String item) { return item; } } From ef0c0fd1952030c734904bc109284f46a08b62fb Mon Sep 17 00:00:00 2001 From: Julia Beliaeva Date: Mon, 14 Mar 2016 12:07:22 +0300 Subject: [PATCH 27/81] [text-completion] remove unused method --- .../src/com/intellij/util/TextFieldCompletionProvider.java | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/platform/lang-impl/src/com/intellij/util/TextFieldCompletionProvider.java b/platform/lang-impl/src/com/intellij/util/TextFieldCompletionProvider.java index b00c08a58ab3..47611ca6dad3 100644 --- a/platform/lang-impl/src/com/intellij/util/TextFieldCompletionProvider.java +++ b/platform/lang-impl/src/com/intellij/util/TextFieldCompletionProvider.java @@ -116,12 +116,7 @@ public abstract class TextFieldCompletionProvider implements TextCompletionProvi @NotNull public EditorTextField createEditor(Project project) { - return createEditor(project, true); - } - - @NotNull - public EditorTextField createEditor(Project project, final boolean shouldHaveBorder) { - return createEditor(project, shouldHaveBorder, null); + return createEditor(project, true, null); } @NotNull From d78d9203d40d56ff50bf49a96cca4ad79c61b26e Mon Sep 17 00:00:00 2001 From: Julia Beliaeva Date: Mon, 14 Mar 2016 12:29:04 +0300 Subject: [PATCH 28/81] [text-completion] reuse code from LanguageTextField --- .../src/com/intellij/ui/LanguageTextField.java | 4 ++-- .../util/TextFieldCompletionProvider.java | 17 ++++------------- 2 files changed, 6 insertions(+), 15 deletions(-) diff --git a/platform/lang-impl/src/com/intellij/ui/LanguageTextField.java b/platform/lang-impl/src/com/intellij/ui/LanguageTextField.java index 9074e7478d36..d0b51e3f7814 100644 --- a/platform/lang-impl/src/com/intellij/ui/LanguageTextField.java +++ b/platform/lang-impl/src/com/intellij/ui/LanguageTextField.java @@ -83,8 +83,8 @@ public class LanguageTextField extends EditorTextField { } } - private static Document createDocument(String value, @Nullable Language language, Project project, - @NotNull SimpleDocumentCreator documentCreator) { + public static Document createDocument(String value, @Nullable Language language, Project project, + @NotNull SimpleDocumentCreator documentCreator) { if (language != null) { final PsiFileFactory factory = PsiFileFactory.getInstance(project); final FileType fileType = language.getAssociatedFileType(); diff --git a/platform/lang-impl/src/com/intellij/util/TextFieldCompletionProvider.java b/platform/lang-impl/src/com/intellij/util/TextFieldCompletionProvider.java index 47611ca6dad3..3d9e4c92353e 100644 --- a/platform/lang-impl/src/com/intellij/util/TextFieldCompletionProvider.java +++ b/platform/lang-impl/src/com/intellij/util/TextFieldCompletionProvider.java @@ -13,8 +13,10 @@ import com.intellij.psi.PsiDocumentManager; import com.intellij.psi.PsiFile; import com.intellij.psi.PsiFileFactory; import com.intellij.ui.EditorTextField; +import com.intellij.ui.LanguageTextField; import com.intellij.util.textCompletion.TextCompletionProvider; import com.intellij.util.textCompletion.TextCompletionUtil; +import com.intellij.util.textCompletion.TextFieldWithCompletion; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -79,19 +81,8 @@ public abstract class TextFieldCompletionProvider implements TextCompletionProvi apply(field, ""); } - private Document createDocument(final Project project, @NotNull String text) { - final FileType fileType = PlainTextLanguage.INSTANCE.getAssociatedFileType(); - assert fileType != null; - - final long stamp = LocalTimeCounter.currentTime(); - final PsiFile psiFile = PsiFileFactory.getInstance(project) - .createFileFromText("Dummy." + fileType.getDefaultExtension(), fileType, text, stamp, true, false); - - TextCompletionUtil.installProvider(psiFile, this, true); - - final Document document = PsiDocumentManager.getInstance(project).getDocument(psiFile); - assert document != null; - return document; + private Document createDocument(Project project, @NotNull String text) { + return LanguageTextField.createDocument(text, PlainTextLanguage.INSTANCE, project, new TextCompletionUtil.DocumentWithCompletionCreator(this, true)); } public boolean isCaseInsensitivity() { From d57bf87cbb2b9737071a7eab7a00919881cad2fa Mon Sep 17 00:00:00 2001 From: Kirill Likhodedov Date: Sun, 20 Mar 2016 18:58:40 +0300 Subject: [PATCH 29/81] MultiRootMessageTest: fix separator assertion for windows --- .../testSrc/com.intellij.dvcs/MultiRootMessageTest.kt | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/platform/dvcs-impl/testSrc/com.intellij.dvcs/MultiRootMessageTest.kt b/platform/dvcs-impl/testSrc/com.intellij.dvcs/MultiRootMessageTest.kt index 8aa186959111..d7fe47ba40e7 100644 --- a/platform/dvcs-impl/testSrc/com.intellij.dvcs/MultiRootMessageTest.kt +++ b/platform/dvcs-impl/testSrc/com.intellij.dvcs/MultiRootMessageTest.kt @@ -24,6 +24,7 @@ import org.junit.Before import org.junit.Test import org.mockito.Mockito import org.mockito.Mockito.mock +import java.io.File class MultiRootMessageTest { @@ -101,7 +102,7 @@ class MultiRootMessageTest { assertEquals( """ Pruned obsolete remote references: origin/fix1, origin/fix2 in idea - Pruned obsolete remote references: origin/fix3 in community, contrib and community/android + Pruned obsolete remote references: origin/fix3 in community, contrib and community${File.separator}android """.trimIndent(), multiRootMessage.asString()) } From 948210c6983f15b2ea9796d2b72711106c823b5f Mon Sep 17 00:00:00 2001 From: Julia Beliaeva Date: Sun, 20 Mar 2016 21:16:13 +0300 Subject: [PATCH 30/81] [text-completion] fix completion autopopup --- .../intellij/util/textCompletion/TextCompletionContributor.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/platform/lang-impl/src/com/intellij/util/textCompletion/TextCompletionContributor.java b/platform/lang-impl/src/com/intellij/util/textCompletion/TextCompletionContributor.java index 84a7a6e5a4a5..27818913d6be 100644 --- a/platform/lang-impl/src/com/intellij/util/textCompletion/TextCompletionContributor.java +++ b/platform/lang-impl/src/com/intellij/util/textCompletion/TextCompletionContributor.java @@ -41,7 +41,7 @@ public class TextCompletionContributor extends CompletionContributor implements if (provider == null) return; if (parameters.getInvocationCount() == 0 && - !Boolean.FALSE.equals(file.getUserData(TextCompletionUtil.AUTO_POPUP_KEY))) { + !Boolean.TRUE.equals(file.getUserData(TextCompletionUtil.AUTO_POPUP_KEY))) { return; } From c9a4b73a52f0bf1dd35bd804a9957a60f2dafc0e Mon Sep 17 00:00:00 2001 From: Dmitry Trofimov Date: Sun, 20 Mar 2016 23:13:34 +0100 Subject: [PATCH 31/81] Fix test --- .../execution/process/ProcessInfo.java | 4 +- .../process/impl/ProcessListUtil.java | 2 +- .../process/impl/ProcessListTest.java | 56 +++++++++---------- 3 files changed, 32 insertions(+), 30 deletions(-) diff --git a/platform/platform-impl/src/com/intellij/execution/process/ProcessInfo.java b/platform/platform-impl/src/com/intellij/execution/process/ProcessInfo.java index 700432978815..cf1525fa90a1 100644 --- a/platform/platform-impl/src/com/intellij/execution/process/ProcessInfo.java +++ b/platform/platform-impl/src/com/intellij/execution/process/ProcessInfo.java @@ -94,7 +94,8 @@ public class ProcessInfo { @Override public String toString() { - return myPid + " '" + myCommandLine + "' '" + myExecutableName + "' '" + myArgs + "'"; + return myPid + " '" + myCommandLine + "' '" + myExecutableName + "' '" + myArgs + "'" + + (myExecutablePath.isPresent() ? " " + myExecutablePath.get() : ""); } @Override @@ -108,6 +109,7 @@ public class ProcessInfo { if (!myExecutableName.equals(info.myExecutableName)) return false; if (!myArgs.equals(info.myArgs)) return false; if (!myCommandLine.equals(info.myCommandLine)) return false; + if (!myExecutablePath.equals(info.myExecutablePath)) return false; return true; } diff --git a/platform/platform-impl/src/com/intellij/execution/process/impl/ProcessListUtil.java b/platform/platform-impl/src/com/intellij/execution/process/impl/ProcessListUtil.java index fa42c2837020..fc52580be38e 100644 --- a/platform/platform-impl/src/com/intellij/execution/process/impl/ProcessListUtil.java +++ b/platform/platform-impl/src/com/intellij/execution/process/impl/ProcessListUtil.java @@ -305,7 +305,7 @@ public class ProcessListUtil { String name = line.substring(0, commandLineStart).trim(); if (name.isEmpty()) continue; - String commandLine = line.substring(commandLineStart, pidStart).trim(); + String commandLine = line.substring(commandLineStart, executablePathStart).trim(); String args = ""; if (commandLine.isEmpty()) { diff --git a/platform/platform-tests/testSrc/com/intellij/execution/process/impl/ProcessListTest.java b/platform/platform-tests/testSrc/com/intellij/execution/process/impl/ProcessListTest.java index dc63a5c33291..4a5bcd83f444 100644 --- a/platform/platform-tests/testSrc/com/intellij/execution/process/impl/ProcessListTest.java +++ b/platform/platform-tests/testSrc/com/intellij/execution/process/impl/ProcessListTest.java @@ -45,9 +45,9 @@ public class ProcessListTest extends UsefulTestCase { " 3 S user ./dir/dir/file param param" ); assertOrderedEquals(infos, - new ProcessInfo(1, "/dir/file", "file", ""), - new ProcessInfo(2, "./dir/dir/file", "file", ""), - new ProcessInfo(3, "./dir/dir/file param param", "file", "param param")); + new ProcessInfo(1, "/dir/file", "file", "", "/dir/file"), + new ProcessInfo(2, "./dir/dir/file", "file", "", "./dir/dir/file"), + new ProcessInfo(3, "./dir/dir/file param param", "file", "param param", "./dir/dir/file")); } public void testMac_DoNotIncludeProcessedMissingOnTheSecondPSRun() throws Exception { @@ -59,7 +59,7 @@ public class ProcessListTest extends UsefulTestCase { " 1 S user /dir/file\n" + " 5 S user /dir/file\n" ); - assertOrderedEquals(infos, new ProcessInfo(1, "/dir/file", "file", "")); + assertOrderedEquals(infos, new ProcessInfo(1, "/dir/file", "file", "", "/dir/file")); } public void testMac_DoNotIncludeProcessedChangedOnTheSecondPSRun() throws Exception { @@ -75,7 +75,7 @@ public class ProcessListTest extends UsefulTestCase { " 3 S user /dir/file1\n" + " 4 S user /dir/file/1\n" ); - assertOrderedEquals(infos, new ProcessInfo(1, "/dir/file param", "file", "param")); + assertOrderedEquals(infos, new ProcessInfo(1, "/dir/file param", "file", "param", "/dir/file")); } public void testMac_DoNotIncludeZombies() throws Exception { @@ -89,7 +89,7 @@ public class ProcessListTest extends UsefulTestCase { " 2 Z user /dir/file\n" + " 3 SZ user /dir/file\n" ); - assertOrderedEquals(infos, new ProcessInfo(1, "/dir/file", "file", "")); + assertOrderedEquals(infos, new ProcessInfo(1, "/dir/file", "file", "", "/dir/file")); } public void testMac_VariousFormsPidStatUser() throws Exception { @@ -102,8 +102,8 @@ public class ProcessListTest extends UsefulTestCase { " 101 Ss user_name /dir/file\n" ); assertOrderedEquals(infos, - new ProcessInfo(1, "/dir/file", "file", ""), - new ProcessInfo(101, "/dir/file", "file", "")); + new ProcessInfo(1, "/dir/file", "file", "", "/dir/file"), + new ProcessInfo(101, "/dir/file", "file", "", "/dir/file")); } public void testMac_WrongFormat() throws Exception { @@ -146,28 +146,28 @@ public class ProcessListTest extends UsefulTestCase { public void testWindows_WMIC() throws Exception { List infos = ProcessListUtil.parseWMICOutput( - "Caption CommandLine ProcessId \n" + - "smss.exe 304 \n" + - "sihost.exe sihost.exe 3052 \n" + - "taskhostw.exe taskhostw.exe {222A245B-E637-4AE9-A93F-A59CA119A75E} 3068 \n" + - "explorer.exe C:\\WINDOWS\\Explorer.EXE 3164 \n" + - "TPAutoConnect.exe TPAutoConnect.exe -q -i vmware -a COM1 -F 30 3336 \n" + - "conhost.exe \\??\\C:\\WINDOWS\\system32\\conhost.exe 0x4 3348 \n"); + "Caption CommandLine ExecutablePath ProcessId \n" + + "smss.exe 304 \n" + + "sihost.exe sihost.exe 3052 \n" + + "taskhostw.exe taskhostw.exe {222A245B-E637-4AE9-A93F-A59CA119A75E} 3068 \n" + + "explorer.exe C:\\WINDOWS\\Explorer.EXE C:\\WINDOWS\\Explorer.EXE 3164 \n" + + "TPAutoConnect.exe TPAutoConnect.exe -q -i vmware -a COM1 -F 30 3336 \n" + + "conhost.exe \\??\\C:\\WINDOWS\\system32\\conhost.exe 0x4 \\??\\C:\\WINDOWS\\system32\\conhost.exe 3348 \n"); assertOrderedEquals(infos, new ProcessInfo(304, "smss.exe", "smss.exe", ""), new ProcessInfo(3052, "sihost.exe", "sihost.exe", ""), new ProcessInfo(3068, "taskhostw.exe {222A245B-E637-4AE9-A93F-A59CA119A75E}", "taskhostw.exe", "{222A245B-E637-4AE9-A93F-A59CA119A75E}"), - new ProcessInfo(3164, "C:\\WINDOWS\\Explorer.EXE", "explorer.exe", ""), + new ProcessInfo(3164, "C:\\WINDOWS\\Explorer.EXE", "explorer.exe", "", "C:\\WINDOWS\\Explorer.EXE"), new ProcessInfo(3336, "TPAutoConnect.exe -q -i vmware -a COM1 -F 30", "TPAutoConnect.exe", "-q -i vmware -a COM1 -F 30"), - new ProcessInfo(3348, "\\??\\C:\\WINDOWS\\system32\\conhost.exe 0x4", "conhost.exe", "0x4")); + new ProcessInfo(3348, "\\??\\C:\\WINDOWS\\system32\\conhost.exe 0x4", "conhost.exe", "0x4", "\\??\\C:\\WINDOWS\\system32\\conhost.exe")); } public void testOnWindows_WMIC_DoNotIncludeSystemIdleProcess() throws Exception { List infos = ProcessListUtil.parseWMICOutput( - "Caption CommandLine ProcessId \n" + - "System Idle Process 0 \n" + - "System 4 \n" + - "smss.exe 304 \n"); + "Caption CommandLine ExecutablePath ProcessId \n" + + "System Idle Process 0 \n" + + "System 4 \n" + + "smss.exe 304 \n"); assertOrderedEquals(infos, new ProcessInfo(4, "System", "System", ""), new ProcessInfo(304, "smss.exe", "smss.exe", "")); @@ -179,19 +179,19 @@ public class ProcessListTest extends UsefulTestCase { assertNull(ProcessListUtil.parseWMICOutput( "wrong format")); assertEmpty(ProcessListUtil.parseWMICOutput( - "Caption CommandLine ProcessId \n")); + "Caption CommandLine ExecutablePath ProcessId \n")); assertNull(ProcessListUtil.parseWMICOutput( "smss.exe 304 \n")); assertNull(ProcessListUtil.parseWMICOutput( - "Caption XXX ProcessId \n" + - "smss.exe 304 \n")); + "Caption XXX ExecutablePath ProcessId \n" + + "smss.exe 304 \n")); assertNull(ProcessListUtil.parseWMICOutput( - "Caption CommandLine XXX \n" + - "smss.exe 304 \n")); + "Caption CommandLine ExecutablePath XXX \n" + + "smss.exe 304 \n")); assertEmpty(ProcessListUtil.parseWMICOutput( - "Caption CommandLine ProcessId \n" + - " \n")); + "Caption CommandLine ExecutablePath ProcessId \n" + + " \n")); } public void testWindows_TaskList() throws Exception { From 1eb60bf11fcb837b3ff5cbcfb6ffa990fb40018d Mon Sep 17 00:00:00 2001 From: Dmitry Trofimov Date: Mon, 21 Mar 2016 03:08:10 +0100 Subject: [PATCH 32/81] Don't run console with Pty on Windows (PY-18231) --- .../python/console/PydevConsoleRunner.java | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/python/src/com/jetbrains/python/console/PydevConsoleRunner.java b/python/src/com/jetbrains/python/console/PydevConsoleRunner.java index 875480d5b0e8..707bfa6e6130 100644 --- a/python/src/com/jetbrains/python/console/PydevConsoleRunner.java +++ b/python/src/com/jetbrains/python/console/PydevConsoleRunner.java @@ -64,6 +64,7 @@ import com.intellij.openapi.ui.Messages; import com.intellij.openapi.util.Couple; import com.intellij.openapi.util.Key; import com.intellij.openapi.util.Pair; +import com.intellij.openapi.util.SystemInfo; import com.intellij.openapi.util.io.StreamUtil; import com.intellij.openapi.util.text.StringUtil; import com.intellij.openapi.vfs.CharsetToolkit; @@ -407,7 +408,7 @@ public class PydevConsoleRunner extends AbstractConsoleRunnerWithHistory Date: Mon, 21 Mar 2016 09:58:45 +0300 Subject: [PATCH 33/81] inspection toolwindow: title of toolwindow is changes in case of "run inspection by name" IDEA-153292 --- .../codeInspection/ex/GlobalInspectionContextImpl.java | 5 ++++- .../src/messages/InspectionsBundle.properties | 1 + 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/platform/lang-impl/src/com/intellij/codeInspection/ex/GlobalInspectionContextImpl.java b/platform/lang-impl/src/com/intellij/codeInspection/ex/GlobalInspectionContextImpl.java index 9163102f2fa8..6f48462e275a 100644 --- a/platform/lang-impl/src/com/intellij/codeInspection/ex/GlobalInspectionContextImpl.java +++ b/platform/lang-impl/src/com/intellij/codeInspection/ex/GlobalInspectionContextImpl.java @@ -141,7 +141,10 @@ public class GlobalInspectionContextImpl extends GlobalInspectionContextBase imp public void addView(@NotNull InspectionResultsView view) { addView(view, view.getCurrentProfileName() == null ? InspectionsBundle.message("inspection.results.title") - : InspectionsBundle.message("inspection.results.for.profile.toolwindow.title", view.getCurrentProfileName())); + : InspectionsBundle.message(mySingleInspectionRun ? + "inspection.results.for.inspection.toolwindow.title" : + "inspection.results.for.profile.toolwindow.title", + view.getCurrentProfileName())); } diff --git a/platform/platform-resources-en/src/messages/InspectionsBundle.properties b/platform/platform-resources-en/src/messages/InspectionsBundle.properties index ce1fec43b296..c620f262226f 100644 --- a/platform/platform-resources-en/src/messages/InspectionsBundle.properties +++ b/platform/platform-resources-en/src/messages/InspectionsBundle.properties @@ -316,6 +316,7 @@ inspection.unused.symbol.check.classes=Check &Classes inspection.unused.symbol.check.parameters=Check &Parameters inspection.results.for.profile.toolwindow.title=Results for Inspection Profile ''{0}'' +inspection.results.for.inspection.toolwindow.title=Results for Inspection ''{0}'' inspection.export.results.invalidated.item=invalidated item inspection.export.results.at.line=at line From f76abe1d76a07b468d6a5c2c740111728f9c7455 Mon Sep 17 00:00:00 2001 From: Dmitry Batkovich Date: Mon, 21 Mar 2016 10:12:09 +0300 Subject: [PATCH 34/81] inspection toolwindow: use action toolbar for fix buttons --- .../codeInspection/ex/QuickFixAction.java | 39 +++++- .../codeInspection/ui/InspectionNodeInfo.java | 4 +- .../codeInspection/ui/QuickFixToolbar.java | 113 +++++------------- 3 files changed, 65 insertions(+), 91 deletions(-) diff --git a/platform/lang-impl/src/com/intellij/codeInspection/ex/QuickFixAction.java b/platform/lang-impl/src/com/intellij/codeInspection/ex/QuickFixAction.java index 0fdb32ffe2d8..4f1849247987 100644 --- a/platform/lang-impl/src/com/intellij/codeInspection/ex/QuickFixAction.java +++ b/platform/lang-impl/src/com/intellij/codeInspection/ex/QuickFixAction.java @@ -25,15 +25,17 @@ import com.intellij.codeInspection.reference.RefEntity; import com.intellij.codeInspection.reference.RefManagerImpl; import com.intellij.codeInspection.ui.InspectionResultsView; import com.intellij.codeInspection.ui.InspectionTree; +import com.intellij.codeInspection.ui.QuickFixToolbar; import com.intellij.icons.AllIcons; -import com.intellij.openapi.actionSystem.AnAction; -import com.intellij.openapi.actionSystem.AnActionEvent; -import com.intellij.openapi.actionSystem.CustomShortcutSet; +import com.intellij.ide.DataManager; +import com.intellij.openapi.actionSystem.*; +import com.intellij.openapi.actionSystem.ex.CustomComponentAction; import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.command.CommandProcessor; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.progress.ProgressManager; import com.intellij.openapi.project.Project; +import com.intellij.openapi.util.IconLoader; import com.intellij.openapi.vfs.ReadonlyStatusHandler; import com.intellij.openapi.vfs.VfsUtilCore; import com.intellij.openapi.vfs.VirtualFile; @@ -41,6 +43,8 @@ import com.intellij.psi.PsiDocumentManager; import com.intellij.psi.PsiElement; import com.intellij.psi.PsiFile; import com.intellij.psi.util.PsiUtilCore; +import com.intellij.ui.ClickListener; +import com.intellij.ui.IdeBorderFactory; import com.intellij.util.SequentialModalProgressTask; import gnu.trove.THashSet; import org.jetbrains.annotations.NotNull; @@ -49,12 +53,13 @@ import javax.swing.*; import javax.swing.tree.DefaultTreeModel; import javax.swing.tree.TreeNode; import javax.swing.tree.TreePath; +import java.awt.event.MouseEvent; import java.util.*; /** * @author max */ -public class QuickFixAction extends AnAction { +public class QuickFixAction extends AnAction implements CustomComponentAction { private static final Logger LOG = Logger.getInstance("#" + QuickFixAction.class.getName()); public static final QuickFixAction[] EMPTY = new QuickFixAction[0]; @@ -307,6 +312,32 @@ public class QuickFixAction extends AnAction { return true; } + @Override + public JComponent createCustomComponent(Presentation presentation) { + final JButton button = new JButton(presentation.getText()); + Icon icon = presentation.getIcon(); + if (icon == null) { + icon = AllIcons.Actions.CreateFromUsage; + } + button.setEnabled(presentation.isEnabled()); + button.setIcon(IconLoader.getTransparentIcon(icon, 0.75f)); + new ClickListener() { + @Override + public boolean onClick(@NotNull MouseEvent event, int clickCount) { + actionPerformed(AnActionEvent.createFromAnAction(QuickFixAction.this, + event, + ActionPlaces.UNKNOWN, + DataManager.getInstance().getDataContext(button))); + return true; + } + }.installOn(button); + JPanel panel = new JPanel(); + panel.setLayout(new BoxLayout(panel, BoxLayout.LINE_AXIS)); + panel.setBorder(IdeBorderFactory.createEmptyBorder(7, 0, 8, 0)); + panel.add(button); + return panel; + } + private class PerformFixesTask extends PerformFixesModalTask { @NotNull private final GlobalInspectionContextImpl myContext; @NotNull diff --git a/platform/lang-impl/src/com/intellij/codeInspection/ui/InspectionNodeInfo.java b/platform/lang-impl/src/com/intellij/codeInspection/ui/InspectionNodeInfo.java index d39b8b27c179..b4b119bac81f 100644 --- a/platform/lang-impl/src/com/intellij/codeInspection/ui/InspectionNodeInfo.java +++ b/platform/lang-impl/src/com/intellij/codeInspection/ui/InspectionNodeInfo.java @@ -19,14 +19,12 @@ 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.JBLabel; import com.intellij.ui.components.JBLabelDecorator; -import com.intellij.ui.components.JBScrollPane; import com.intellij.util.ui.JBInsets; import com.intellij.util.ui.JBUI; import com.intellij.util.ui.UIUtil; @@ -79,7 +77,7 @@ public class InspectionNodeInfo extends JPanel { add(pane, new GridBagConstraints(0, 1, 1, 1, 1.0, 1.0, GridBagConstraints.NORTHWEST, GridBagConstraints.BOTH, - new JBInsets(0, 12, 0, 0), 0, 0)); + new JBInsets(0, 10, 0, 0), 0, 0)); add(myButton, new GridBagConstraints(0, 2, 1, 1, 1.0, 0.0, GridBagConstraints.NORTHWEST, GridBagConstraints.NONE, new JBInsets(15, 9, 9, 0), 0, 0)); diff --git a/platform/lang-impl/src/com/intellij/codeInspection/ui/QuickFixToolbar.java b/platform/lang-impl/src/com/intellij/codeInspection/ui/QuickFixToolbar.java index 181b7fecf479..a78fad833042 100644 --- a/platform/lang-impl/src/com/intellij/codeInspection/ui/QuickFixToolbar.java +++ b/platform/lang-impl/src/com/intellij/codeInspection/ui/QuickFixToolbar.java @@ -20,28 +20,24 @@ import com.intellij.codeInspection.ex.InspectionToolWrapper; import com.intellij.codeInspection.ex.QuickFixAction; import com.intellij.codeInspection.ui.actions.SuppressActionWrapper; 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.diagnostic.Logger; import com.intellij.openapi.editor.ex.EditorEx; import com.intellij.openapi.project.Project; import com.intellij.openapi.util.Disposer; -import com.intellij.openapi.util.IconLoader; -import com.intellij.ui.ClickListener; import com.intellij.ui.IdeBorderFactory; import com.intellij.ui.SimpleColoredComponent; +import com.intellij.util.containers.ContainerUtil; import com.intellij.util.ui.AsyncProcessIcon; -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.function.Supplier; +import java.util.Collections; +import java.util.List; /** * @author Dmitry Batkovich @@ -114,9 +110,20 @@ public class QuickFixToolbar extends JPanel implements InspectionTreeLoadingProg boolean hasFixes = fixes != null && fixes.length != 0; int problemCount = descriptors.length; boolean multipleDescriptors = problemCount > 1; - fill(multipleDescriptors, () -> getLabel(fixes, problemCount), this); - fill(hasFixes, () -> createFixPanel(fixes, multipleDescriptors), this); - fill(true, () -> createSuppressionCombo(myWrapper, tree.getSelectionPaths(), project, multipleDescriptors), this); + setLayout(new BoxLayout(this, BoxLayout.LINE_AXIS)); + if (multipleDescriptors) { + add(getLabel(fixes, problemCount)); + } + + final DefaultActionGroup actions = new DefaultActionGroup(); + if (hasFixes) { + actions.addAll(createFixActions(fixes, multipleDescriptors)); + } + actions.add(createSuppressionCombo(myWrapper, tree.getSelectionPaths(), project, multipleDescriptors)); + final ActionToolbar toolbar = ActionManager.getInstance().createActionToolbar(ActionPlaces.UNKNOWN, actions, true); + final JComponent component = toolbar.getComponent(); + toolbar.setTargetComponent(this); + add(component); } @Nullable @@ -159,7 +166,7 @@ public class QuickFixToolbar extends JPanel implements InspectionTreeLoadingProg } } - private static JComponent createSuppressionCombo(@NotNull final InspectionToolWrapper toolWrapper, + private static AnAction createSuppressionCombo(@NotNull final InspectionToolWrapper toolWrapper, @NotNull final TreePath[] paths, @NotNull final Project project, boolean multipleDescriptors) { @@ -179,26 +186,11 @@ public class QuickFixToolbar extends JPanel implements InspectionTreeLoadingProg } }; action.setSmallVariant(false); - return fixComboBoxActionComponent(action.createCustomComponent(action.getTemplatePresentation())); - } - - private static JComponent fixComboBoxActionComponent(JComponent component) { - JPanel containingPanel = new JPanel(new FlowLayout(FlowLayout.LEFT, 0, 0)); - containingPanel.add(component); - containingPanel.setBorder(IdeBorderFactory.createEmptyBorder(7, 0, 8, 0)); - return containingPanel; - } - - private static void fill(boolean add, - @NotNull Supplier componentSupplier, - @NotNull JPanel parent) { - if (add) { - parent.add(componentSupplier.get()); - } + return action; } @NotNull - private static JComponent createFixPanel(QuickFixAction[] fixes, boolean multipleDescriptors) { + private static List createFixActions(QuickFixAction[] fixes, boolean multipleDescriptors) { if (fixes.length > MAX_FIX_COUNT) { final ComboBoxAction fixComboBox = new ComboBoxAction() { { @@ -217,71 +209,24 @@ public class QuickFixToolbar extends JPanel implements InspectionTreeLoadingProg return actionGroup; } }; - return fixComboBoxActionComponent(fixComboBox.createCustomComponent(fixComboBox.getTemplatePresentation())); + return Collections.singletonList(fixComboBox); } else { - JPanel fixPanel = new JPanel(); - fixPanel.setLayout(new BoxLayout(fixPanel, BoxLayout.LINE_AXIS)); - fixPanel.setBorder(IdeBorderFactory.createEmptyBorder(7, 0, 8, 0)); + final DefaultActionGroup group = new DefaultActionGroup(); final boolean multipleFixes = fixes.length > 1; for (QuickFixAction fix : fixes) { - fixPanel.add(createQuickFixButton(fix, multipleDescriptors && !multipleFixes)); - if (fix != fixes[fixes.length - 1]) { - fixPanel.add(Box.createHorizontalStrut(3)); - } + final AnAction quickFixButtonCustonPresentation = createQuickFixButton(fix, multipleDescriptors && !multipleFixes); + //group.addAll(fixes); + group.add(quickFixButtonCustonPresentation); } - return fixPanel; + return ContainerUtil.list(fixes); } } - private static JComponent createQuickFixButton(@NotNull QuickFixAction fix, boolean multipleFixes) { - final MyCustomComponentLocalQuickFixWrapper action = new MyCustomComponentLocalQuickFixWrapper(fix); + private static AnAction createQuickFixButton(@NotNull QuickFixAction fix, boolean multipleFixes) { if (multipleFixes) { - action.getTemplatePresentation().setText("Fix all '" + fix.getText() + "'"); - } - 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()); - Icon icon = presentation.getIcon(); - if (icon == null) { - icon = AllIcons.Actions.CreateFromUsage; - } - button.setEnabled(presentation.isEnabled()); - button.setIcon(IconLoader.getTransparentIcon(icon, 0.75f)); - 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); + fix.getTemplatePresentation().setText("Fix all '" + fix.getText() + "'"); } + return fix; } } From 61ead5131db764000ec2ff43e3d91f64f8cfc0ef Mon Sep 17 00:00:00 2001 From: Max Medvedev Date: Mon, 21 Mar 2016 11:03:07 +0300 Subject: [PATCH 35/81] make project compilable on Mac with old buggy jdks --- .../intellij/facet/frameworks/SettingsConnectionService.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/platform/lang-api/src/com/intellij/facet/frameworks/SettingsConnectionService.java b/platform/lang-api/src/com/intellij/facet/frameworks/SettingsConnectionService.java index b2a79a00d6ea..efcd33fd0135 100644 --- a/platform/lang-api/src/com/intellij/facet/frameworks/SettingsConnectionService.java +++ b/platform/lang-api/src/com/intellij/facet/frameworks/SettingsConnectionService.java @@ -79,7 +79,7 @@ public abstract class SettingsConnectionService { LOG.error(e); } return settings; - }, Collections.emptyMap(), LOG); + }, Collections.emptyMap(), LOG); } @Nullable From a9629a157512b06751aa203b41dd0638d3be43a8 Mon Sep 17 00:00:00 2001 From: Sergey Simonchik Date: Mon, 21 Mar 2016 12:30:59 +0300 Subject: [PATCH 36/81] WEB-20882 Preserve setting `toggle auto-test` between IDEA restarts --- .../autotest/AutoTestManager.java | 109 +++++++++++++----- 1 file changed, 77 insertions(+), 32 deletions(-) diff --git a/platform/testRunner/src/com/intellij/execution/testframework/autotest/AutoTestManager.java b/platform/testRunner/src/com/intellij/execution/testframework/autotest/AutoTestManager.java index 7a9b06229082..f817967cf63f 100644 --- a/platform/testRunner/src/com/intellij/execution/testframework/autotest/AutoTestManager.java +++ b/platform/testRunner/src/com/intellij/execution/testframework/autotest/AutoTestManager.java @@ -15,8 +15,10 @@ */ package com.intellij.execution.testframework.autotest; -import com.intellij.execution.DelayedDocumentWatcher; -import com.intellij.execution.ExecutionManager; +import com.intellij.execution.*; +import com.intellij.execution.configurations.RunConfiguration; +import com.intellij.execution.configurations.RunProfile; +import com.intellij.execution.impl.RunManagerImpl; import com.intellij.execution.process.ProcessAdapter; import com.intellij.execution.process.ProcessEvent; import com.intellij.execution.process.ProcessHandler; @@ -31,7 +33,7 @@ import com.intellij.ide.util.PropertiesComponent; import com.intellij.openapi.actionSystem.LangDataKeys; import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.application.ModalityState; -import com.intellij.openapi.components.ServiceManager; +import com.intellij.openapi.components.*; import com.intellij.openapi.fileEditor.FileEditorManager; import com.intellij.openapi.project.Project; import com.intellij.openapi.util.Condition; @@ -39,24 +41,35 @@ import com.intellij.openapi.util.Key; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.ui.content.Content; import com.intellij.util.Consumer; +import com.intellij.util.ObjectUtils; +import com.intellij.util.containers.ContainerUtil; +import com.intellij.util.xmlb.annotations.AbstractCollection; +import com.intellij.util.xmlb.annotations.Attribute; +import com.intellij.util.xmlb.annotations.Tag; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import javax.swing.*; +import java.util.List; +import java.util.Set; /** * @author yole */ -public class AutoTestManager { +@State( + name = "AutoTestManager", + storages = {@Storage(StoragePathMacros.WORKSPACE_FILE)} +) +public class AutoTestManager implements PersistentStateComponent { private static final String AUTO_TEST_MANAGER_DELAY = "auto.test.manager.delay"; private static final int AUTO_TEST_MANAGER_DELAY_DEFAULT = 3000; private static final Key ON_TERMINATION_RESTARTER_KEY = Key.create("auto.test.manager.on.termination.restarter"); - private static final Key EXECUTION_ENVIRONMENT_KEY = Key.create("auto.test.manager.execution.environment"); private final Project myProject; private int myDelayMillis; private DelayedDocumentWatcher myDocumentWatcher; + private final Set myEnabledRunProfiles = ContainerUtil.newHashSet(); @NotNull public static AutoTestManager getInstance(Project project) { @@ -92,11 +105,11 @@ public class AutoTestManager { Content content = descriptor.getAttachedContent(); if (content != null) { if (enabled) { - EXECUTION_ENVIRONMENT_KEY.set(content, environment); + myEnabledRunProfiles.add(environment.getRunProfile()); myDocumentWatcher.activate(); } else { - EXECUTION_ENVIRONMENT_KEY.set(content, null); + myEnabledRunProfiles.remove(environment.getRunProfile()); if (!hasEnabledAutoTests()) { myDocumentWatcher.deactivate(); } @@ -122,19 +135,11 @@ public class AutoTestManager { return isAutoTestEnabledForDescriptor(descriptor); } - private static boolean isAutoTestEnabledForDescriptor(@NotNull RunContentDescriptor descriptor) { + private boolean isAutoTestEnabledForDescriptor(@NotNull RunContentDescriptor descriptor) { Content content = descriptor.getAttachedContent(); if (content != null) { - ExecutionEnvironment watched = EXECUTION_ENVIRONMENT_KEY.get(content); - if (watched != null) { - ExecutionEnvironment current = getCurrentEnvironment(content); - boolean result = current != null && equals(current, watched); - if (!result) { - // let GC do its work - EXECUTION_ENVIRONMENT_KEY.set(content, null); - } - return result; - } + ExecutionEnvironment environment = getCurrentEnvironment(content); + return environment != null && myEnabledRunProfiles.contains(environment.getRunProfile()); } return false; } @@ -148,13 +153,6 @@ public class AutoTestManager { return LangDataKeys.EXECUTION_ENVIRONMENT.getData(DataManager.getInstance().getDataContext(component)); } - private static boolean equals(@NotNull ExecutionEnvironment env1, @NotNull ExecutionEnvironment env2) { - return env1.getRunProfile() == env2.getRunProfile() && - env1.getRunner() == env2.getRunner() && - env1.getExecutor() == env2.getExecutor() && - env1.getExecutionTarget() == env2.getExecutionTarget(); - } - private static void clearRestarterListener(@NotNull ProcessHandler processHandler) { ProcessListener restarterListener = ON_TERMINATION_RESTARTER_KEY.get(processHandler, null); if (restarterListener != null) { @@ -177,9 +175,9 @@ public class AutoTestManager { } } - private static void restartAutoTest(@NotNull RunContentDescriptor descriptor, - int modificationStamp, - @NotNull DelayedDocumentWatcher documentWatcher) { + private void restartAutoTest(@NotNull RunContentDescriptor descriptor, + int modificationStamp, + @NotNull DelayedDocumentWatcher documentWatcher) { ProcessHandler processHandler = descriptor.getProcessHandler(); if (processHandler != null && !processHandler.isProcessTerminated()) { scheduleRestartOnTermination(descriptor, processHandler, modificationStamp, documentWatcher); @@ -189,10 +187,10 @@ public class AutoTestManager { } } - private static void scheduleRestartOnTermination(@NotNull final RunContentDescriptor descriptor, - @NotNull final ProcessHandler processHandler, - final int modificationStamp, - @NotNull final DelayedDocumentWatcher documentWatcher) { + private void scheduleRestartOnTermination(@NotNull final RunContentDescriptor descriptor, + @NotNull final ProcessHandler processHandler, + final int modificationStamp, + @NotNull final DelayedDocumentWatcher documentWatcher) { ProcessListener restarterListener = ON_TERMINATION_RESTARTER_KEY.get(processHandler); if (restarterListener != null) { clearRestarterListener(processHandler); @@ -234,4 +232,51 @@ public class AutoTestManager { } PropertiesComponent.getInstance(myProject).setValue(AUTO_TEST_MANAGER_DELAY, myDelayMillis, AUTO_TEST_MANAGER_DELAY_DEFAULT); } + + @Nullable + @Override + public State getState() { + State state = new State(); + for (RunProfile profile : myEnabledRunProfiles) { + RunConfiguration runConfiguration = ObjectUtils.tryCast(profile, RunConfiguration.class); + if (runConfiguration != null) { + RunConfigurationDescriptor descriptor = new RunConfigurationDescriptor(); + descriptor.myType = runConfiguration.getType().getId(); + descriptor.myName = runConfiguration.getName(); + state.myEnabledRunConfigurations.add(descriptor); + } + } + return state; + } + + @Override + public void loadState(State state) { + List configurations = ContainerUtil.newArrayList(); + RunManagerImpl runManager = RunManagerImpl.getInstanceImpl(myProject); + for (RunConfigurationDescriptor descriptor : state.myEnabledRunConfigurations) { + RunnerAndConfigurationSettings settings = runManager.findConfigurationByTypeAndName(descriptor.myType, + descriptor.myName); + RunConfiguration configuration = settings != null ? settings.getConfiguration() : null; + if (configuration != null) { + configurations.add(configuration); + } + } + myEnabledRunProfiles.clear(); + myEnabledRunProfiles.addAll(configurations); + } + + static class State { + @Tag("enabled-run-configurations") + @AbstractCollection(surroundWithTag = false) + List myEnabledRunConfigurations = ContainerUtil.newArrayList(); + } + + @Tag("run-configuration") + static class RunConfigurationDescriptor { + @Attribute("type") + String myType; + + @Attribute("name") + String myName; + } } From 6d8e50b42d8866dddba0a0b99c787e7daf40bc7b Mon Sep 17 00:00:00 2001 From: Dmitry Batrak Date: Mon, 21 Mar 2016 12:34:54 +0300 Subject: [PATCH 37/81] IDEA-124976 Make Shift+Backspace operate like Backspace in Swing text editing components --- .../com/intellij/openapi/editor/actions/BackspaceAction.java | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/platform/platform-impl/src/com/intellij/openapi/editor/actions/BackspaceAction.java b/platform/platform-impl/src/com/intellij/openapi/editor/actions/BackspaceAction.java index 88e5db1b7ab4..7cd8e62c5531 100644 --- a/platform/platform-impl/src/com/intellij/openapi/editor/actions/BackspaceAction.java +++ b/platform/platform-impl/src/com/intellij/openapi/editor/actions/BackspaceAction.java @@ -28,12 +28,11 @@ import com.intellij.injected.editor.EditorWindow; import com.intellij.openapi.actionSystem.DataContext; import com.intellij.openapi.command.CommandProcessor; import com.intellij.openapi.editor.*; -import com.intellij.openapi.editor.actionSystem.EditorAction; import com.intellij.openapi.editor.actionSystem.EditorWriteActionHandler; import com.intellij.util.ui.MacUIUtil; import org.jetbrains.annotations.NotNull; -public class BackspaceAction extends EditorAction { +public class BackspaceAction extends TextComponentEditorAction { public BackspaceAction() { super(new Handler()); } From c32932b4c1d0fd04c75ac491c2faf960fab65cff Mon Sep 17 00:00:00 2001 From: Dmitry Batkovich Date: Mon, 21 Mar 2016 12:50:44 +0300 Subject: [PATCH 38/81] inspection toolwindow: splitter doesn't honor minimal size --- .../com/intellij/codeInspection/ui/InspectionResultsView.java | 1 + 1 file changed, 1 insertion(+) diff --git a/platform/lang-impl/src/com/intellij/codeInspection/ui/InspectionResultsView.java b/platform/lang-impl/src/com/intellij/codeInspection/ui/InspectionResultsView.java index 7dce42438570..11267ba53642 100644 --- a/platform/lang-impl/src/com/intellij/codeInspection/ui/InspectionResultsView.java +++ b/platform/lang-impl/src/com/intellij/codeInspection/ui/InspectionResultsView.java @@ -138,6 +138,7 @@ public class InspectionResultsView extends JPanel implements Disposable, Occuren mySplitter = new OnePixelSplitter(false, AnalysisUIOptions.getInstance(myProject).SPLITTER_PROPORTION); mySplitter.setFirstComponent(ScrollPaneFactory.createScrollPane(myTree, SideBorder.LEFT)); + mySplitter.setHonorComponentsMinimumSize(false); mySplitter.addPropertyChangeListener(evt -> { if (Splitter.PROP_PROPORTION.equals(evt.getPropertyName())) { From 23382c7d268de2fc2b499fc9cdb391fc3bbfdaf1 Mon Sep 17 00:00:00 2001 From: Bas Leijdekkers Date: Mon, 21 Mar 2016 10:45:07 +0100 Subject: [PATCH 39/81] fix incorrect boolean check for hierarchy scope --- .../intellij/psi/search/PredefinedSearchScopeProviderImpl.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/platform/lang-impl/src/com/intellij/psi/search/PredefinedSearchScopeProviderImpl.java b/platform/lang-impl/src/com/intellij/psi/search/PredefinedSearchScopeProviderImpl.java index 9f32bbc32655..33df34bfeb80 100644 --- a/platform/lang-impl/src/com/intellij/psi/search/PredefinedSearchScopeProviderImpl.java +++ b/platform/lang-impl/src/com/intellij/psi/search/PredefinedSearchScopeProviderImpl.java @@ -146,7 +146,7 @@ public class PredefinedSearchScopeProviderImpl extends PredefinedSearchScopeProv } if (usageView) { - if (prevSearchFiles) { + if (!prevSearchFiles) { addHierarchyScope(project, result); } UsageView selectedUsageView = UsageViewManager.getInstance(project).getSelectedUsageView(); From 5a536597788379a579c3be2f275cf37217814dd5 Mon Sep 17 00:00:00 2001 From: "Egor.Ushakov" Date: Mon, 21 Mar 2016 13:20:05 +0300 Subject: [PATCH 40/81] IDEA-121775 XDebugger: merge Watches and Variables in one view - enable by default --- platform/util/resources/misc/registry.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/platform/util/resources/misc/registry.properties b/platform/util/resources/misc/registry.properties index 71ab7efa478b..cc338814ad06 100644 --- a/platform/util/resources/misc/registry.properties +++ b/platform/util/resources/misc/registry.properties @@ -195,7 +195,7 @@ debugger.breakpoint.message.full.trace.description='Log message to console' brea for the thread that hit the breakpoint. debugger.batch.evaluation=false debugger.compiling.evaluator=true -debugger.watches.in.variables=false +debugger.watches.in.variables=true debugger.auto.fetch.icons=true debugger.close.dialog.on.navigate=true debugger.close.dialog.on.navigate.description=Close evaluate dialog on Jump to (type) source action From f5f162ada4452dc984891205bf87fa12b6ae9323 Mon Sep 17 00:00:00 2001 From: Andrey Starovoyt Date: Mon, 21 Mar 2016 13:20:33 +0300 Subject: [PATCH 41/81] postfix templates: improve error message --- .../templates/LanguagePostfixTemplate.java | 24 +++++++++++++++---- 1 file changed, 20 insertions(+), 4 deletions(-) diff --git a/platform/lang-impl/src/com/intellij/codeInsight/template/postfix/templates/LanguagePostfixTemplate.java b/platform/lang-impl/src/com/intellij/codeInsight/template/postfix/templates/LanguagePostfixTemplate.java index 99c21b9dbff6..07ad9f698dcf 100644 --- a/platform/lang-impl/src/com/intellij/codeInsight/template/postfix/templates/LanguagePostfixTemplate.java +++ b/platform/lang-impl/src/com/intellij/codeInsight/template/postfix/templates/LanguagePostfixTemplate.java @@ -15,6 +15,7 @@ */ package com.intellij.codeInsight.template.postfix.templates; +import com.intellij.ide.plugins.cl.PluginClassLoader; import com.intellij.lang.Language; import com.intellij.lang.LanguageExtension; import com.intellij.openapi.diagnostic.Logger; @@ -22,7 +23,7 @@ import com.intellij.util.containers.ContainerUtil; import org.jetbrains.annotations.NotNull; import java.util.List; -import java.util.Set; +import java.util.Map; public class LanguagePostfixTemplate extends LanguageExtension { private static final Logger LOG = Logger.getInstance(LanguagePostfixTemplate.class); @@ -44,13 +45,28 @@ public class LanguagePostfixTemplate extends LanguageExtension providers) { - Set templateKeys = ContainerUtil.newHashSet(); + Map templateKeys = ContainerUtil.newHashMap(); for (PostfixTemplateProvider provider : providers) { for (PostfixTemplate template : provider.getTemplates()) { - if (!templateKeys.add(template.getKey())) { - LOG.error("Duplicated key " + template.getKey() + " for language " + key.getID() + " provider " + provider.getClass()); + PostfixTemplateProvider oldProvider = templateKeys.put(template.getKey(), provider); + if (oldProvider != null) { + String oldPlugin = getPluginId(oldProvider); + String newPlugin = getPluginId(provider); + LOG.error("Duplicated postfix completion key '" + template.getKey() + "' for language " + key.getID() + + ". Possible you need to disable one of the plugins: " + oldPlugin + ", " + newPlugin); } } } } + + @NotNull + private static String getPluginId(@NotNull PostfixTemplateProvider provider) { + ClassLoader loader = provider.getClass().getClassLoader(); + if (loader instanceof PluginClassLoader) { + return ((PluginClassLoader)loader).getPluginId().getIdString(); + } + + return ""; + } + } From 0b01e21ba405f3cd8fb6f0ff49df4cac9d85dd15 Mon Sep 17 00:00:00 2001 From: "Egor.Ushakov" Date: Mon, 21 Mar 2016 13:34:11 +0300 Subject: [PATCH 42/81] fixed debugger tests --- .../intellij/xdebugger/impl/ui/tree/nodes/WatchNodeImpl.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/ui/tree/nodes/WatchNodeImpl.java b/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/ui/tree/nodes/WatchNodeImpl.java index 362bac2ac83b..dd59735b763c 100644 --- a/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/ui/tree/nodes/WatchNodeImpl.java +++ b/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/ui/tree/nodes/WatchNodeImpl.java @@ -16,6 +16,7 @@ package com.intellij.xdebugger.impl.ui.tree.nodes; import com.intellij.icons.AllIcons; +import com.intellij.openapi.application.ApplicationManager; import com.intellij.util.ThreeState; import com.intellij.xdebugger.Obsolescent; import com.intellij.xdebugger.XExpression; @@ -42,7 +43,8 @@ public class WatchNodeImpl extends XValueNodeImpl implements WatchNode { @NotNull WatchesRootNode parent, @NotNull XExpression expression, @Nullable XStackFrame stackFrame) { - super(tree, parent, expression.getExpression(), new XWatchValue(expression, tree.isShowing() ? stackFrame : null)); + super(tree, parent, expression.getExpression(), + new XWatchValue(expression, tree.isShowing() || ApplicationManager.getApplication().isUnitTestMode() ? stackFrame : null)); myExpression = expression; } From f81a2f9e3f1123ec474bce3278107a94c70e0dc3 Mon Sep 17 00:00:00 2001 From: Elizaveta Shashkova Date: Mon, 21 Mar 2016 14:22:05 +0300 Subject: [PATCH 43/81] Fix deadlock in remote debugger (PY-18546) --- .../helpers/pydev/_pydev_bundle/_pydev_filesystem_encoding.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/python/helpers/pydev/_pydev_bundle/_pydev_filesystem_encoding.py b/python/helpers/pydev/_pydev_bundle/_pydev_filesystem_encoding.py index 1cb3aa462cd5..6264e3dbd354 100644 --- a/python/helpers/pydev/_pydev_bundle/_pydev_filesystem_encoding.py +++ b/python/helpers/pydev/_pydev_bundle/_pydev_filesystem_encoding.py @@ -1,8 +1,10 @@ +import sys + + def __getfilesystemencoding(): ''' Note: there's a copy of this method in interpreterInfo.py ''' - import sys try: ret = sys.getfilesystemencoding() if not ret: From 6ea71d6961e5ea7390afadfc4a79ef07da5885c5 Mon Sep 17 00:00:00 2001 From: Roman Shevchenko Date: Mon, 21 Mar 2016 12:26:50 +0100 Subject: [PATCH 44/81] Cleanup (formatting; typos) --- .../decompiler/exps/InvocationExprent.java | 70 ++++++++----------- .../java/decompiler/SingleClassesTest.java | 2 +- 2 files changed, 32 insertions(+), 40 deletions(-) diff --git a/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/modules/decompiler/exps/InvocationExprent.java b/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/modules/decompiler/exps/InvocationExprent.java index 758b93f3adaa..1b8188a3f0c5 100644 --- a/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/modules/decompiler/exps/InvocationExprent.java +++ b/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/modules/decompiler/exps/InvocationExprent.java @@ -224,20 +224,20 @@ public class InvocationExprent extends Exprent { else { if (instance != null && instance.type == Exprent.EXPRENT_VAR) { - VarExprent instvar = (VarExprent)instance; - VarVersionPair varpaar = new VarVersionPair(instvar); + VarExprent instVar = (VarExprent)instance; + VarVersionPair varPair = new VarVersionPair(instVar); - VarProcessor vproc = instvar.getProcessor(); - if (vproc == null) { - MethodWrapper current_meth = (MethodWrapper)DecompilerContext.getProperty(DecompilerContext.CURRENT_METHOD_WRAPPER); - if (current_meth != null) { - vproc = current_meth.varproc; + VarProcessor varProc = instVar.getProcessor(); + if (varProc == null) { + MethodWrapper currentMethod = (MethodWrapper)DecompilerContext.getProperty(DecompilerContext.CURRENT_METHOD_WRAPPER); + if (currentMethod != null) { + varProc = currentMethod.varproc; } } String this_classname = null; - if (vproc != null) { - this_classname = vproc.getThisVars().get(varpaar); + if (varProc != null) { + this_classname = varProc.getThisVars().get(varPair); } if (this_classname != null) { @@ -334,7 +334,7 @@ public class InvocationExprent extends Exprent { boolean firstParameter = true; int start = isEnum ? 2 : 0; for (int i = start; i < lstParameters.size(); i++) { - if (sigFields == null || null == sigFields.get(i)) { + if (sigFields == null || sigFields.get(i) == null) { if (!firstParameter) { buf.append(", "); } @@ -512,43 +512,35 @@ public class InvocationExprent extends Exprent { // ***************************************************************************** // IMatchable implementation // ***************************************************************************** - - public boolean match(MatchNode matchNode, MatchEngine engine) { - if(!super.match(matchNode, engine)) { + @Override + public boolean match(MatchNode matchNode, MatchEngine engine) { + if (!super.match(matchNode, engine)) { return false; } - - for(Entry rule : matchNode.getRules().entrySet()) { + + for (Entry rule : matchNode.getRules().entrySet()) { RuleValue value = rule.getValue(); - - switch(rule.getKey()) { - case EXPRENT_INVOCATION_PARAMETER: - if(value.isVariable()) { - if(value.parameter < lstParameters.size()) { - if(!engine.checkAndSetVariableValue(value.value.toString(), lstParameters.get(value.parameter))) { - return false; - } - } else { - return false; - } + + MatchProperties key = rule.getKey(); + if (key == MatchProperties.EXPRENT_INVOCATION_PARAMETER) { + if (value.isVariable() && (value.parameter >= lstParameters.size() || + !engine.checkAndSetVariableValue(value.value.toString(), lstParameters.get(value.parameter)))) { + return false; } - break; - case EXPRENT_INVOCATION_CLASS: - if(!value.value.equals(this.classname)) { + } + else if (key == MatchProperties.EXPRENT_INVOCATION_CLASS) { + if (!value.value.equals(this.classname)) { + return false; + } + } + else if (key == MatchProperties.EXPRENT_INVOCATION_SIGNATURE) { + if (!value.value.equals(this.name + this.stringDescriptor)) { return false; } - break; - case EXPRENT_INVOCATION_SIGNATURE: - if(!value.value.equals(this.name + this.stringDescriptor)) { - return false; - } - break; } - } - + return true; } - -} +} \ No newline at end of file diff --git a/plugins/java-decompiler/engine/test/org/jetbrains/java/decompiler/SingleClassesTest.java b/plugins/java-decompiler/engine/test/org/jetbrains/java/decompiler/SingleClassesTest.java index 260445ddd283..100deeba6282 100644 --- a/plugins/java-decompiler/engine/test/org/jetbrains/java/decompiler/SingleClassesTest.java +++ b/plugins/java-decompiler/engine/test/org/jetbrains/java/decompiler/SingleClassesTest.java @@ -131,4 +131,4 @@ public class SingleClassesTest { return files; } -} +} \ No newline at end of file From 89ef47289dd21c7c316e69a2aed11574d3834941 Mon Sep 17 00:00:00 2001 From: "Vladimir.Orlov" Date: Mon, 21 Mar 2016 14:50:04 +0300 Subject: [PATCH 45/81] updated unpackJdks.gant to use custom jdk. --- build/scripts/unpackJdks.gant | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/build/scripts/unpackJdks.gant b/build/scripts/unpackJdks.gant index 209c57cd131a..1be2a69c7c4e 100644 --- a/build/scripts/unpackJdks.gant +++ b/build/scripts/unpackJdks.gant @@ -4,7 +4,7 @@ import com.intellij.openapi.util.io.FileUtil import static org.jetbrains.jps.idea.IdeaProjectLoader.guessHome /* - * 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. @@ -26,7 +26,7 @@ target(default: "Unpack JDKs") { } def unpackJdks() { - def osDirName = SystemInfo.isWindows ? "win" : SystemInfo.isMac ? "mac" : "linux" + def osDirName = SystemInfo.isWindows ? "win" : SystemInfo.isMac ? "mac/custom" : "linux/custom" String basePath if (new File(home).getName().equals("community")) { basePath = new File(home).getParent() @@ -65,7 +65,7 @@ private void unpackJdk(File osDir, File jdkDir, String majorVersion) { if (jdkFile.name.endsWith(".zip")) { ant.unzip(src: jdkFile, dest: destDir) } - else if (jdkFile.name.endsWith(".tar")) { + else if (jdkFile.name.startsWith("openjdk") && jdkFile.name.endsWith(".tar")) { projectBuilder.info("Extracting $jdkFile to $destDir") ant.mkdir(dir: destDir) //'tar' and 'mv' commands are used instead of Ant tasks to ensure that executable flag and symlink will be preserved From 2c69e1fb4219f07fcf3d5c11cba53e94ae8ba017 Mon Sep 17 00:00:00 2001 From: Aleksey Pivovarov Date: Mon, 21 Mar 2016 15:02:40 +0300 Subject: [PATCH 46/81] disable RefreshFileChooserAction outside of FileChooser dialog fix ActionsWithoutUpdateMethodTest --- .../actions/RefreshFileChooserAction.java | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/platform/platform-impl/src/com/intellij/openapi/fileChooser/actions/RefreshFileChooserAction.java b/platform/platform-impl/src/com/intellij/openapi/fileChooser/actions/RefreshFileChooserAction.java index d57c2f55a579..1117602ec1e9 100644 --- a/platform/platform-impl/src/com/intellij/openapi/fileChooser/actions/RefreshFileChooserAction.java +++ b/platform/platform-impl/src/com/intellij/openapi/fileChooser/actions/RefreshFileChooserAction.java @@ -15,18 +15,21 @@ */ package com.intellij.openapi.fileChooser.actions; -import com.intellij.openapi.actionSystem.AnAction; import com.intellij.openapi.actionSystem.AnActionEvent; import com.intellij.openapi.application.ModalityState; -import com.intellij.openapi.project.DumbAware; +import com.intellij.openapi.fileChooser.FileSystemTree; import com.intellij.openapi.vfs.newvfs.ManagingFS; import com.intellij.openapi.vfs.newvfs.RefreshQueue; /** * @author yole -*/ -public class RefreshFileChooserAction extends AnAction implements DumbAware { - public void actionPerformed(final AnActionEvent e) { + */ +public class RefreshFileChooserAction extends FileChooserAction { + protected void update(FileSystemTree fileChooser, AnActionEvent e) { + } + + @Override + protected void actionPerformed(FileSystemTree fileChooser, AnActionEvent e) { RefreshQueue.getInstance().refresh(true, true, null, ModalityState.current(), ManagingFS.getInstance().getLocalRoots()); } } \ No newline at end of file From 30976405383b411324f9518ee918a713d2807102 Mon Sep 17 00:00:00 2001 From: "Vladimir.Orlov" Date: Mon, 21 Mar 2016 16:01:29 +0300 Subject: [PATCH 47/81] jdk1.8.0_73.tar for OS X revert - updated unpackJdks.gant to use custom jdk. --- build/scripts/unpackJdks.gant | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/build/scripts/unpackJdks.gant b/build/scripts/unpackJdks.gant index 1be2a69c7c4e..3b71c7e0acda 100644 --- a/build/scripts/unpackJdks.gant +++ b/build/scripts/unpackJdks.gant @@ -26,7 +26,7 @@ target(default: "Unpack JDKs") { } def unpackJdks() { - def osDirName = SystemInfo.isWindows ? "win" : SystemInfo.isMac ? "mac/custom" : "linux/custom" + def osDirName = SystemInfo.isWindows ? "win" : SystemInfo.isMac ? "mac" : "linux" String basePath if (new File(home).getName().equals("community")) { basePath = new File(home).getParent() @@ -65,7 +65,7 @@ private void unpackJdk(File osDir, File jdkDir, String majorVersion) { if (jdkFile.name.endsWith(".zip")) { ant.unzip(src: jdkFile, dest: destDir) } - else if (jdkFile.name.startsWith("openjdk") && jdkFile.name.endsWith(".tar")) { + else if (jdkFile.name.endsWith(".tar")) { projectBuilder.info("Extracting $jdkFile to $destDir") ant.mkdir(dir: destDir) //'tar' and 'mv' commands are used instead of Ant tasks to ensure that executable flag and symlink will be preserved From b0a05f7c1bc9c0ed0ed85153107fef3ce0d0675f Mon Sep 17 00:00:00 2001 From: peter Date: Mon, 21 Mar 2016 12:16:45 +0100 Subject: [PATCH 48/81] IDEA-149939 CCE in com.intellij.execution.stacktrace.StackTraceLine.getMethodLocation causes frozen UI --- .../com/intellij/execution/stacktrace/StackTraceLine.java | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/java/execution/impl/src/com/intellij/execution/stacktrace/StackTraceLine.java b/java/execution/impl/src/com/intellij/execution/stacktrace/StackTraceLine.java index c85686c80b5c..7079d61bd650 100644 --- a/java/execution/impl/src/com/intellij/execution/stacktrace/StackTraceLine.java +++ b/java/execution/impl/src/com/intellij/execution/stacktrace/StackTraceLine.java @@ -118,9 +118,10 @@ public class StackTraceLine { if (project == null) return null; final PsiManager psiManager = PsiManager.getInstance(project); PsiClass psiClass = JavaPsiFacade.getInstance(psiManager.getProject()).findClass(className, GlobalSearchScope.allScope(project)); - if (psiClass == null || (psiClass.getNavigationElement() instanceof PsiCompiledElement)) return null; - psiClass = (PsiClass)psiClass.getNavigationElement(); - final PsiFile psiFile = psiClass.getContainingFile(); + PsiElement navElement = psiClass == null ? null : psiClass.getNavigationElement(); + if (psiClass == null || navElement instanceof PsiCompiledElement) return null; + + final PsiFile psiFile = navElement.getContainingFile(); return PsiTreeUtil.getParentOfType(psiFile.findElementAt(offsetOfLine(psiFile, lineNumber)), PsiClass.class, false); } From 3a700a9bc90ec22517e481e57b92a4c48dc41ab4 Mon Sep 17 00:00:00 2001 From: "Anna.Kozlova" Date: Mon, 21 Mar 2016 11:11:42 +0100 Subject: [PATCH 49/81] process override equivalent methods when check for functional interface target (IDEA-153324) --- .../impl/analysis/GenericsHighlightUtil.java | 35 +---------- .../src/com/intellij/psi/LambdaUtil.java | 12 ++++ .../intellij/psi/util/PsiSuperMethodUtil.java | 61 +++++++++++++++++++ .../psi/impl/PsiSuperMethodImplUtil.java | 25 +------- ...alentMethodsAreFoundInSuperInterfaces.java | 12 ++++ .../Interface8MethodsHighlightingTest.java | 1 + 6 files changed, 90 insertions(+), 56 deletions(-) create mode 100644 java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/interfaceMethods/CheckForFunctionalInterfaceCandidatesWhenOverrideEquivalentMethodsAreFoundInSuperInterfaces.java diff --git a/java/java-analysis-impl/src/com/intellij/codeInsight/daemon/impl/analysis/GenericsHighlightUtil.java b/java/java-analysis-impl/src/com/intellij/codeInsight/daemon/impl/analysis/GenericsHighlightUtil.java index 0729b89613ce..0a4661824460 100644 --- a/java/java-analysis-impl/src/com/intellij/codeInsight/daemon/impl/analysis/GenericsHighlightUtil.java +++ b/java/java-analysis-impl/src/com/intellij/codeInsight/daemon/impl/analysis/GenericsHighlightUtil.java @@ -35,7 +35,6 @@ import com.intellij.openapi.vfs.VirtualFile; import com.intellij.pom.java.LanguageLevel; import com.intellij.psi.*; import com.intellij.psi.impl.PsiClassImplUtil; -import com.intellij.psi.impl.PsiSuperMethodImplUtil; import com.intellij.psi.search.GlobalSearchScope; import com.intellij.psi.search.PsiShortNamesCache; import com.intellij.psi.search.searches.ReferencesSearch; @@ -442,36 +441,7 @@ public class GenericsHighlightUtil { static HighlightInfo checkUnrelatedDefaultMethods(@NotNull PsiClass aClass, @NotNull PsiIdentifier classIdentifier) { - final Map> overrideEquivalent = - new THashMap>(MethodSignatureUtil.METHOD_PARAMETERS_ERASURE_EQUALITY); - PsiClass[] supers = aClass.getSupers(); - for (int i = 0; i < supers.length; i++) { - PsiClass superClass = supers[i]; - boolean subType = false; - for (int j = 0; j < supers.length; j++) { - if (j == i) continue; - subType |= supers[j].isInheritor(supers[i], true); - } - if (subType) continue; - final PsiSubstitutor superClassSubstitutor = TypeConversionUtil.getSuperClassSubstitutor(superClass, aClass, PsiSubstitutor.EMPTY); - for (HierarchicalMethodSignature hms : superClass.getVisibleSignatures()) { - final PsiMethod method = hms.getMethod(); - if (MethodSignatureUtil.findMethodBySignature(aClass, method.getSignature(superClassSubstitutor), false) != null) continue; - final PsiClass containingClass = method.getContainingClass(); - if (containingClass == null) continue; - final PsiSubstitutor containingClassSubstitutor = TypeConversionUtil.getClassSubstitutor(containingClass, aClass, PsiSubstitutor.EMPTY); - if (containingClassSubstitutor == null) continue; - final PsiSubstitutor finalSubstitutor = - PsiSuperMethodImplUtil.obtainFinalSubstitutor(containingClass, containingClassSubstitutor, hms.getSubstitutor(), false); - final MethodSignatureBackedByPsiMethod signature = MethodSignatureBackedByPsiMethod.create(method, finalSubstitutor, false); - Set methods = overrideEquivalent.get(signature); - if (methods == null) { - methods = new LinkedHashSet(); - overrideEquivalent.put(signature, methods); - } - methods.add(method); - } - } + final Map> overrideEquivalent = PsiSuperMethodUtil.collectOverrideEquivalents(aClass); final boolean isInterface = aClass.isInterface(); for (Set overrideEquivalentMethods : overrideEquivalent.values()) { @@ -550,7 +520,8 @@ public class GenericsHighlightUtil { final PsiClass containingClass = method.getContainingClass(); if (containingClass == null) continue; final PsiSubstitutor containingClassSubstitutor = TypeConversionUtil.getSuperClassSubstitutor(containingClass, psiClass, PsiSubstitutor.EMPTY); - final PsiSubstitutor finalSubstitutor = PsiSuperMethodImplUtil.obtainFinalSubstitutor(containingClass, containingClassSubstitutor, hms.getSubstitutor(), false); + final PsiSubstitutor finalSubstitutor = PsiSuperMethodUtil + .obtainFinalSubstitutor(containingClass, containingClassSubstitutor, hms.getSubstitutor(), false); final MethodSignatureBackedByPsiMethod signature = MethodSignatureBackedByPsiMethod.create(method, finalSubstitutor, false); final PsiMethod foundMethod = overrideEquivalent.get(signature); PsiClass foundMethodContainingClass; diff --git a/java/java-psi-api/src/com/intellij/psi/LambdaUtil.java b/java/java-psi-api/src/com/intellij/psi/LambdaUtil.java index 3aa98a200e69..503e95c702ea 100644 --- a/java/java-psi-api/src/com/intellij/psi/LambdaUtil.java +++ b/java/java-psi-api/src/com/intellij/psi/LambdaUtil.java @@ -216,11 +216,23 @@ public class LambdaUtil { public static List findFunctionCandidates(PsiClass psiClass) { if (psiClass != null && psiClass.isInterface() && !psiClass.isAnnotationType()) { final List methods = new ArrayList(); + final Map> overrideEquivalents = PsiSuperMethodUtil.collectOverrideEquivalents(psiClass); final Collection visibleSignatures = psiClass.getVisibleSignatures(); for (HierarchicalMethodSignature signature : visibleSignatures) { final PsiMethod psiMethod = signature.getMethod(); if (!psiMethod.hasModifierProperty(PsiModifier.ABSTRACT)) continue; if (psiMethod.hasModifierProperty(PsiModifier.STATIC)) continue; + final Set equivalentMethods = overrideEquivalents.get(signature); + if (equivalentMethods != null && equivalentMethods.size() > 1) { + boolean hasNonAbstractOverrideEquivalent = false; + for (PsiMethod method : equivalentMethods) { + if (!method.hasModifierProperty(PsiModifier.ABSTRACT) && !MethodSignatureUtil.isSuperMethod(method, psiMethod)) { + hasNonAbstractOverrideEquivalent = true; + break; + } + } + if (hasNonAbstractOverrideEquivalent) continue; + } if (!overridesPublicObjectMethod(signature)) { methods.add(signature); } diff --git a/java/java-psi-api/src/com/intellij/psi/util/PsiSuperMethodUtil.java b/java/java-psi-api/src/com/intellij/psi/util/PsiSuperMethodUtil.java index bdc77c57a86b..2148bd45b3cb 100644 --- a/java/java-psi-api/src/com/intellij/psi/util/PsiSuperMethodUtil.java +++ b/java/java-psi-api/src/com/intellij/psi/util/PsiSuperMethodUtil.java @@ -17,10 +17,13 @@ package com.intellij.psi.util; import com.intellij.psi.*; import com.intellij.util.containers.HashSet; +import gnu.trove.THashMap; import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.NotNull; +import java.util.LinkedHashSet; import java.util.List; +import java.util.Map; import java.util.Set; public class PsiSuperMethodUtil { @@ -80,4 +83,62 @@ public class PsiSuperMethodUtil { return false; } + + @NotNull + public static PsiSubstitutor obtainFinalSubstitutor(@NotNull PsiClass superClass, + @NotNull PsiSubstitutor superSubstitutor, + @NotNull PsiSubstitutor derivedSubstitutor, + boolean inRawContext) { + if (inRawContext) { + Set typeParams = superSubstitutor.getSubstitutionMap().keySet(); + PsiElementFactory factory = JavaPsiFacade.getElementFactory(superClass.getProject()); + superSubstitutor = factory.createRawSubstitutor(derivedSubstitutor, typeParams.toArray(new PsiTypeParameter[typeParams.size()])); + } + Map map = null; + for (PsiTypeParameter typeParameter : PsiUtil.typeParametersIterable(superClass)) { + PsiType type = superSubstitutor.substitute(typeParameter); + final PsiType t = derivedSubstitutor.substitute(type); + if (map == null) { + map = new THashMap(); + } + map.put(typeParameter, t); + } + + return map == null ? PsiSubstitutor.EMPTY : JavaPsiFacade.getInstance(superClass.getProject()).getElementFactory().createSubstitutor(map); + } + + @NotNull + public static Map> collectOverrideEquivalents(@NotNull PsiClass aClass) { + final Map> overrideEquivalent = + new THashMap>(MethodSignatureUtil.METHOD_PARAMETERS_ERASURE_EQUALITY); + PsiClass[] supers = aClass.getSupers(); + for (int i = 0; i < supers.length; i++) { + PsiClass superClass = supers[i]; + boolean subType = false; + for (int j = 0; j < supers.length; j++) { + if (j == i) continue; + subType |= supers[j].isInheritor(supers[i], true); + } + if (subType) continue; + final PsiSubstitutor superClassSubstitutor = TypeConversionUtil.getSuperClassSubstitutor(superClass, aClass, PsiSubstitutor.EMPTY); + for (HierarchicalMethodSignature hms : superClass.getVisibleSignatures()) { + final PsiMethod method = hms.getMethod(); + if (MethodSignatureUtil.findMethodBySignature(aClass, method.getSignature(superClassSubstitutor), false) != null) continue; + final PsiClass containingClass = method.getContainingClass(); + if (containingClass == null) continue; + final PsiSubstitutor containingClassSubstitutor = TypeConversionUtil.getClassSubstitutor(containingClass, aClass, PsiSubstitutor.EMPTY); + if (containingClassSubstitutor == null) continue; + final PsiSubstitutor finalSubstitutor = + obtainFinalSubstitutor(containingClass, containingClassSubstitutor, hms.getSubstitutor(), false); + final MethodSignatureBackedByPsiMethod signature = MethodSignatureBackedByPsiMethod.create(method, finalSubstitutor, false); + Set methods = overrideEquivalent.get(signature); + if (methods == null) { + methods = new LinkedHashSet(); + overrideEquivalent.put(signature, methods); + } + methods.add(method); + } + } + return overrideEquivalent; + } } diff --git a/java/java-psi-impl/src/com/intellij/psi/impl/PsiSuperMethodImplUtil.java b/java/java-psi-impl/src/com/intellij/psi/impl/PsiSuperMethodImplUtil.java index 66421a109e0a..0c8f93252fd8 100644 --- a/java/java-psi-impl/src/com/intellij/psi/impl/PsiSuperMethodImplUtil.java +++ b/java/java-psi-impl/src/com/intellij/psi/impl/PsiSuperMethodImplUtil.java @@ -229,7 +229,7 @@ public class PsiSuperMethodImplUtil { if (superClass == null) continue; if (!visited.add(superClass)) continue; // cyclic inheritance final PsiSubstitutor superSubstitutor = superTypeResolveResult.getSubstitutor(); - PsiSubstitutor finalSubstitutor = obtainFinalSubstitutor(superClass, superSubstitutor, substitutor, isInRawContext); + PsiSubstitutor finalSubstitutor = PsiSuperMethodUtil.obtainFinalSubstitutor(superClass, superSubstitutor, substitutor, isInRawContext); final boolean isInRawContextSuper = (isInRawContext || PsiUtil.isRawSubstitutor(superClass, superSubstitutor)) && superClass.getTypeParameters().length != 0; Map superResult = buildMethodHierarchy(superClass, nameHint, finalSubstitutor, false, visited, isInRawContextSuper, resolveScope); @@ -373,29 +373,6 @@ public class PsiSuperMethodImplUtil { return hierarchicalMethodSignature; } - @NotNull - public static PsiSubstitutor obtainFinalSubstitutor(@NotNull PsiClass superClass, - @NotNull PsiSubstitutor superSubstitutor, - @NotNull PsiSubstitutor derivedSubstitutor, - boolean inRawContext) { - if (inRawContext) { - Set typeParams = superSubstitutor.getSubstitutionMap().keySet(); - PsiElementFactory factory = JavaPsiFacade.getElementFactory(superClass.getProject()); - superSubstitutor = factory.createRawSubstitutor(derivedSubstitutor, typeParams.toArray(new PsiTypeParameter[typeParams.size()])); - } - Map map = null; - for (PsiTypeParameter typeParameter : PsiUtil.typeParametersIterable(superClass)) { - PsiType type = superSubstitutor.substitute(typeParameter); - final PsiType t = derivedSubstitutor.substitute(type); - if (map == null) { - map = new THashMap(); - } - map.put(typeParameter, t); - } - - return map == null ? PsiSubstitutor.EMPTY : JavaPsiFacade.getInstance(superClass.getProject()).getElementFactory().createSubstitutor(map); - } - @NotNull public static Collection getVisibleSignatures(@NotNull PsiClass aClass) { Map map = getSignaturesMap(aClass); diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/interfaceMethods/CheckForFunctionalInterfaceCandidatesWhenOverrideEquivalentMethodsAreFoundInSuperInterfaces.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/interfaceMethods/CheckForFunctionalInterfaceCandidatesWhenOverrideEquivalentMethodsAreFoundInSuperInterfaces.java new file mode 100644 index 000000000000..44ac61ff8a91 --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/interfaceMethods/CheckForFunctionalInterfaceCandidatesWhenOverrideEquivalentMethodsAreFoundInSuperInterfaces.java @@ -0,0 +1,12 @@ +import java.util.*; + +@FunctionalInterface +interface InfiniteIntIterator extends InfiniteIterator, PrimitiveIterator.OfInt {} + +@FunctionalInterface +interface InfiniteIterator extends Iterator { + @Override + default boolean hasNext() { + return true; + } +} \ No newline at end of file diff --git a/java/java-tests/testSrc/com/intellij/codeInsight/daemon/lambda/Interface8MethodsHighlightingTest.java b/java/java-tests/testSrc/com/intellij/codeInsight/daemon/lambda/Interface8MethodsHighlightingTest.java index 74c56a435b23..365fdbf30fc9 100644 --- a/java/java-tests/testSrc/com/intellij/codeInsight/daemon/lambda/Interface8MethodsHighlightingTest.java +++ b/java/java-tests/testSrc/com/intellij/codeInsight/daemon/lambda/Interface8MethodsHighlightingTest.java @@ -30,6 +30,7 @@ public class Interface8MethodsHighlightingTest extends LightCodeInsightFixtureTe public void testInheritUnrelatedDefaults() { doTest(true, false); } public void testExtensionMethods() { doTest(false, false); } public void testInheritDefaultMethodInInterface() { doTest(false, false); } + public void testCheckForFunctionalInterfaceCandidatesWhenOverrideEquivalentMethodsAreFoundInSuperInterfaces() { doTest(false, false);} public void testStaticMethodsInFunctionalInterface() { doTest(false, false); } public void testCyclicSubstitutor() { doTest(false, false); } public void testThisAccessibility() { doTest(false, false); } From ab7f16e4b9e9767e7808ff31d15954737f15fb0a Mon Sep 17 00:00:00 2001 From: "Anna.Kozlova" Date: Mon, 21 Mar 2016 12:07:25 +0100 Subject: [PATCH 50/81] testdata for IDEA-153284 --- .../lambda/newLambda/IDEA153284.java | 19 +++++++++++++++++++ .../lambda/NewLambdaHighlightingTest.java | 4 ++++ 2 files changed, 23 insertions(+) create mode 100644 java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/newLambda/IDEA153284.java diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/newLambda/IDEA153284.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/newLambda/IDEA153284.java new file mode 100644 index 000000000000..2efeebfe6745 --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/newLambda/IDEA153284.java @@ -0,0 +1,19 @@ +import java.util.Iterator; +import java.util.List; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +class Test { + public void validRedSquiggles(Stream> stream) { + final Iterator x = concat(stream + .map(cs -> cs.iterator()) + .collect(Collectors.toList()).iterator()); + final Iterator x1 = concat(stream + .map(List::iterator) + .collect(Collectors.toList()).iterator()); + } + + public static Iterator concat(final Iterator> inputs) { + return null; + } +} \ No newline at end of file diff --git a/java/java-tests/testSrc/com/intellij/codeInsight/daemon/lambda/NewLambdaHighlightingTest.java b/java/java-tests/testSrc/com/intellij/codeInsight/daemon/lambda/NewLambdaHighlightingTest.java index fce1622b589c..f68c93acfc70 100644 --- a/java/java-tests/testSrc/com/intellij/codeInsight/daemon/lambda/NewLambdaHighlightingTest.java +++ b/java/java-tests/testSrc/com/intellij/codeInsight/daemon/lambda/NewLambdaHighlightingTest.java @@ -284,6 +284,10 @@ public class NewLambdaHighlightingTest extends LightDaemonAnalyzerTestCase { doTest(); } + public void testIDEA153284() throws Exception { + doTest(); + } + private void doTest() { doTest(false); } From f14159a85270a0ab3ea58dd9b807524806cdad75 Mon Sep 17 00:00:00 2001 From: "Anna.Kozlova" Date: Mon, 21 Mar 2016 12:38:29 +0100 Subject: [PATCH 51/81] disable replace with collect for raw collection substitutors (IDEA-153325) --- .../StreamApiMigrationInspection.java | 19 +++++++++--------- .../beforeRawCollectionSubstitution.java | 20 +++++++++++++++++++ 2 files changed, 30 insertions(+), 9 deletions(-) create mode 100644 java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/streamApiMigration/beforeRawCollectionSubstitution.java diff --git a/java/java-analysis-impl/src/com/intellij/codeInspection/StreamApiMigrationInspection.java b/java/java-analysis-impl/src/com/intellij/codeInspection/StreamApiMigrationInspection.java index 4fec55781590..ddbc38ac6337 100644 --- a/java/java-analysis-impl/src/com/intellij/codeInspection/StreamApiMigrationInspection.java +++ b/java/java-analysis-impl/src/com/intellij/codeInspection/StreamApiMigrationInspection.java @@ -32,10 +32,7 @@ import com.intellij.psi.controlFlow.*; import com.intellij.psi.search.GlobalSearchScope; import com.intellij.psi.search.LocalSearchScope; import com.intellij.psi.search.searches.ReferencesSearch; -import com.intellij.psi.util.InheritanceUtil; -import com.intellij.psi.util.PsiTreeUtil; -import com.intellij.psi.util.PsiUtil; -import com.intellij.psi.util.RedundantCastUtil; +import com.intellij.psi.util.*; import com.intellij.util.containers.ContainerUtil; import com.intellij.util.containers.IntArrayList; import org.jetbrains.annotations.Nls; @@ -103,9 +100,9 @@ public class StreamApiMigrationInspection extends BaseJavaBatchLocalInspectionTo final PsiStatement body = statement.getBody(); if (iteratedValue != null && body != null) { final PsiType iteratedValueType = iteratedValue.getType(); - if (InheritanceUtil.isInheritor(iteratedValueType, CommonClassNames.JAVA_UTIL_COLLECTION)) { - final PsiClass iteratorClass = PsiUtil.resolveClassInType(iteratedValueType); - LOG.assertTrue(iteratorClass != null); + final PsiClass iteratorClass = PsiUtil.resolveClassInType(iteratedValueType); + final PsiClass collectionClass = JavaPsiFacade.getInstance(body.getProject()).findClass(CommonClassNames.JAVA_UTIL_COLLECTION, statement.getResolveScope()); + if (collectionClass != null && InheritanceUtil.isInheritorOrSelf(iteratorClass, collectionClass, true)) { try { final ControlFlow controlFlow = ControlFlowFactory.getInstance(holder.getProject()) .getControlFlow(body, LocalsOrMyInstanceFieldsControlFlowPolicy.getInstance()); @@ -124,8 +121,7 @@ public class StreamApiMigrationInspection extends BaseJavaBatchLocalInspectionTo } if (ExceptionUtil.getThrownCheckedExceptions(new PsiElement[] {body}).isEmpty()) { - if (!(iteratedValueType instanceof PsiClassType && ((PsiClassType)iteratedValueType).isRaw()) && - isCollectCall(body, statement.getIterationParameter())) { + if (!isRawSubstitution(iteratedValueType, collectionClass) && isCollectCall(body, statement.getIterationParameter())) { boolean addAll = isAddAllCall(statement, body); holder.registerProblem(iteratedValue, "Can be replaced with " + (addAll ? "addAll call" : "collect call"), ProblemHighlightType.GENERIC_ERROR_OR_WARNING, @@ -151,6 +147,11 @@ public class StreamApiMigrationInspection extends BaseJavaBatchLocalInspectionTo } } } + + private boolean isRawSubstitution(PsiType iteratedValueType, PsiClass collectionClass) { + return iteratedValueType instanceof PsiClassType && PsiUtil + .isRawSubstitutor(collectionClass, TypeConversionUtil.getSuperClassSubstitutor(collectionClass, (PsiClassType)iteratedValueType)); + } }; } diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/streamApiMigration/beforeRawCollectionSubstitution.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/streamApiMigration/beforeRawCollectionSubstitution.java new file mode 100644 index 000000000000..fdb4d9617ef5 --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/streamApiMigration/beforeRawCollectionSubstitution.java @@ -0,0 +1,20 @@ +// "Replace with collect" "false" + +import java.util.ArrayList; +import java.util.List; + +class Main2 { + public static void main(String[] args) { + MyList list = new MyList(); + List integerList = new ArrayList<>(); + for (Object element : list) { + if (element instanceof Integer) { + integerList.add((Integer) element); + } + } + } + + public static class MyList extends ArrayList { + + } +} From 348b89190c7e4ef3d772bcfb5343f7efadf91e0c Mon Sep 17 00:00:00 2001 From: "Anna.Kozlova" Date: Mon, 21 Mar 2016 12:49:44 +0100 Subject: [PATCH 52/81] suspicious method calls: don't ignore array types, captures, etc (IDEA-153097) --- .../SuspiciousMethodCallUtil.java | 2 +- .../suspiciousCalls/NonClassArgTypes.java | 31 +++++++++++++++++++ .../SuspiciousCollectionMethodCallsTest.java | 4 +++ 3 files changed, 36 insertions(+), 1 deletion(-) create mode 100644 java/java-tests/testData/inspection/suspiciousCalls/NonClassArgTypes.java diff --git a/java/java-analysis-impl/src/com/intellij/codeInspection/miscGenerics/SuspiciousMethodCallUtil.java b/java/java-analysis-impl/src/com/intellij/codeInspection/miscGenerics/SuspiciousMethodCallUtil.java index d725158a5201..9197cf6145e6 100644 --- a/java/java-analysis-impl/src/com/intellij/codeInspection/miscGenerics/SuspiciousMethodCallUtil.java +++ b/java/java-analysis-impl/src/com/intellij/codeInspection/miscGenerics/SuspiciousMethodCallUtil.java @@ -115,7 +115,7 @@ public class SuspiciousMethodCallUtil { argType = ((PsiPrimitiveType)argType).getBoxedType(methodCall); } - if (!(argType instanceof PsiClassType)) return null; + if (argType == null) return null; final JavaResolveResult resolveResult = methodExpression.advancedResolve(false); PsiMethod calleeMethod = (PsiMethod)resolveResult.getElement(); diff --git a/java/java-tests/testData/inspection/suspiciousCalls/NonClassArgTypes.java b/java/java-tests/testData/inspection/suspiciousCalls/NonClassArgTypes.java new file mode 100644 index 000000000000..f3270c74262f --- /dev/null +++ b/java/java-tests/testData/inspection/suspiciousCalls/NonClassArgTypes.java @@ -0,0 +1,31 @@ +import java.util.ArrayList; +import java.util.List; + +class Main { + void suspicious(Object[][] data) { + List stringList = new ArrayList<>(); + + stringList.remove(data); + stringList.remove(data[0]); + stringList.remove(data[0][0]); + + stringList.contains(data); + stringList.contains(data[0]); + stringList.contains(data[0][0]); + + M m = new M<>(); + stringList.contains(m.get()); + + M m1 = new M<>(); + stringList.contains(m1.get()); + + M m2 = new M<>(); + stringList.contains(m2.get()); + } + + class M { + public T get() { + return null; + } + } +} diff --git a/java/java-tests/testSrc/com/intellij/codeInspection/SuspiciousCollectionMethodCallsTest.java b/java/java-tests/testSrc/com/intellij/codeInspection/SuspiciousCollectionMethodCallsTest.java index 4d3ef19d9828..58c96b5562a1 100644 --- a/java/java-tests/testSrc/com/intellij/codeInspection/SuspiciousCollectionMethodCallsTest.java +++ b/java/java-tests/testSrc/com/intellij/codeInspection/SuspiciousCollectionMethodCallsTest.java @@ -29,6 +29,10 @@ public class SuspiciousCollectionMethodCallsTest extends LightCodeInsightFixture doTest(); } + public void testNonClassArgTypes() throws Exception { + doTest(); + } + @NotNull @Override protected LightProjectDescriptor getProjectDescriptor() { From 279c4bab3174aa1373d7a3e255beeed327988a81 Mon Sep 17 00:00:00 2001 From: Dmitry Batrak Date: Mon, 21 Mar 2016 16:18:56 +0300 Subject: [PATCH 53/81] ScrollingModelImpl refactoring --- .../openapi/editor/impl/ScrollingModelImpl.java | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/platform/platform-impl/src/com/intellij/openapi/editor/impl/ScrollingModelImpl.java b/platform/platform-impl/src/com/intellij/openapi/editor/impl/ScrollingModelImpl.java index e0de68cfdb2c..e487c7c303c1 100644 --- a/platform/platform-impl/src/com/intellij/openapi/editor/impl/ScrollingModelImpl.java +++ b/platform/platform-impl/src/com/intellij/openapi/editor/impl/ScrollingModelImpl.java @@ -148,9 +148,13 @@ public class ScrollingModelImpl implements ScrollingModelEx { } private void scrollTo(@NotNull VisualPosition pos, @NotNull ScrollType scrollType) { + Point targetLocation = myEditor.visualPositionToXY(pos); + scrollTo(targetLocation, scrollType); + } + + private void scrollTo(@NotNull Point targetLocation, @NotNull ScrollType scrollType) { AnimatedScrollingRunnable canceledThread = cancelAnimatedScrolling(false); Rectangle viewRect = canceledThread != null ? canceledThread.getTargetVisibleArea() : getVisibleArea(); - Point targetLocation = myEditor.visualPositionToXY(pos); Point p = calcOffsetsToScroll(targetLocation, scrollType, viewRect); scrollToOffsets(p.x, p.y); } @@ -159,11 +163,8 @@ public class ScrollingModelImpl implements ScrollingModelEx { public void scrollTo(@NotNull LogicalPosition pos, @NotNull ScrollType scrollType) { assertIsDispatchThread(); - AnimatedScrollingRunnable canceledThread = cancelAnimatedScrolling(false); - Rectangle viewRect = canceledThread != null ? canceledThread.getTargetVisibleArea() : getVisibleArea(); Point targetLocation = myEditor.logicalPositionToXY(pos); - Point p = calcOffsetsToScroll(targetLocation, scrollType, viewRect); - scrollToOffsets(p.x, p.y); + scrollTo(targetLocation, scrollType); } private static void assertIsDispatchThread() { From 230aeaf3699d9fdf2fb7a23a829251f6a56949bd Mon Sep 17 00:00:00 2001 From: Aleksey Pivovarov Date: Fri, 18 Mar 2016 20:02:58 +0300 Subject: [PATCH 54/81] vcs: remove some unused obsolete classes The only external usages are from Scala and Crucible4Idea plugins. --- .../ui/views/DirectoryHistoryDialog.java | 1 - .../changes/BinaryDiffRequestFromChange.java | 49 --- .../actions/DiffRequestFromChange.java | 35 -- .../vcs/changes/actions/ShowDiffAction.java | 338 ------------------ .../changes/actions/ShowDiffUIContext.java | 58 --- .../changes/actions/diff/ShowDiffAction.java | 14 - 6 files changed, 495 deletions(-) delete mode 100644 platform/vcs-impl/src/com/intellij/openapi/vcs/changes/BinaryDiffRequestFromChange.java delete mode 100644 platform/vcs-impl/src/com/intellij/openapi/vcs/changes/actions/DiffRequestFromChange.java delete mode 100644 platform/vcs-impl/src/com/intellij/openapi/vcs/changes/actions/ShowDiffAction.java delete mode 100644 platform/vcs-impl/src/com/intellij/openapi/vcs/changes/actions/ShowDiffUIContext.java diff --git a/platform/lvcs-impl/src/com/intellij/history/integration/ui/views/DirectoryHistoryDialog.java b/platform/lvcs-impl/src/com/intellij/history/integration/ui/views/DirectoryHistoryDialog.java index 6fe0f50465b1..af52ad97f4d9 100644 --- a/platform/lvcs-impl/src/com/intellij/history/integration/ui/views/DirectoryHistoryDialog.java +++ b/platform/lvcs-impl/src/com/intellij/history/integration/ui/views/DirectoryHistoryDialog.java @@ -27,7 +27,6 @@ import com.intellij.openapi.util.IconLoader; import com.intellij.openapi.util.Pair; import com.intellij.diff.DiffDialogHints; import com.intellij.openapi.vcs.changes.Change; -import com.intellij.openapi.vcs.changes.actions.ShowDiffUIContext; import com.intellij.openapi.vcs.changes.actions.diff.ShowDiffAction; import com.intellij.openapi.vcs.changes.actions.diff.ShowDiffContext; import com.intellij.openapi.vcs.changes.ui.ChangeNodeDecorator; diff --git a/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/BinaryDiffRequestFromChange.java b/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/BinaryDiffRequestFromChange.java deleted file mode 100644 index db57d5319961..000000000000 --- a/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/BinaryDiffRequestFromChange.java +++ /dev/null @@ -1,49 +0,0 @@ -/* - * Copyright 2000-2011 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.vcs.changes; - -import com.intellij.openapi.diff.DiffContent; -import com.intellij.openapi.project.Project; -import com.intellij.openapi.vcs.VcsException; -import com.intellij.openapi.vcs.changes.actions.DiffRequestFromChange; -import com.intellij.openapi.vcs.changes.actions.ShowDiffAction; -import com.intellij.util.BeforeAfter; - -import java.util.Collections; -import java.util.List; - -/** - * @author irengrig - * Date: 6/15/11 - * Time: 5:48 PM - */ -public class BinaryDiffRequestFromChange implements DiffRequestFromChange { - private final Project myProject; - - public BinaryDiffRequestFromChange(Project project) { - myProject = project; - } - - @Override - public boolean canCreateRequest(Change change) { - return ShowDiffAction.isBinaryChangeAndCanShow(myProject, change); - } - - @Override - public List> createRequestForChange(Change change, int extraLines) throws VcsException { - return Collections.singletonList(ShowDiffAction.createBinaryDiffContents(myProject, change)); - } -} diff --git a/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/actions/DiffRequestFromChange.java b/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/actions/DiffRequestFromChange.java deleted file mode 100644 index 70257d4f2d06..000000000000 --- a/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/actions/DiffRequestFromChange.java +++ /dev/null @@ -1,35 +0,0 @@ -/* - * Copyright 2000-2011 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.vcs.changes.actions; - -import com.intellij.openapi.diff.DiffContent; -import com.intellij.openapi.vcs.VcsException; -import com.intellij.openapi.vcs.changes.Change; -import com.intellij.util.BeforeAfter; -import org.jetbrains.annotations.Nullable; - -import java.util.List; - -/** - * @author irengrig - * Date: 6/10/11 - * Time: 6:39 PM - */ -public interface DiffRequestFromChange { - boolean canCreateRequest(final Change change); - @Nullable - List> createRequestForChange(final Change change, int extraLines) throws VcsException; -} diff --git a/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/actions/ShowDiffAction.java b/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/actions/ShowDiffAction.java deleted file mode 100644 index 597780a6b3de..000000000000 --- a/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/actions/ShowDiffAction.java +++ /dev/null @@ -1,338 +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.openapi.vcs.changes.actions; - -import com.intellij.icons.AllIcons; -import com.intellij.idea.ActionsBundle; -import com.intellij.openapi.actionSystem.AnAction; -import com.intellij.openapi.actionSystem.AnActionEvent; -import com.intellij.openapi.actionSystem.CommonDataKeys; -import com.intellij.openapi.application.ModalityState; -import com.intellij.openapi.diagnostic.Logger; -import com.intellij.openapi.diff.*; -import com.intellij.openapi.diff.impl.external.BinaryDiffTool; -import com.intellij.openapi.project.DumbAware; -import com.intellij.openapi.project.Project; -import com.intellij.openapi.ui.Messages; -import com.intellij.openapi.util.Condition; -import com.intellij.openapi.vcs.FilePath; -import com.intellij.openapi.vcs.VcsBundle; -import com.intellij.openapi.vcs.VcsDataKeys; -import com.intellij.openapi.vcs.VcsException; -import com.intellij.openapi.vcs.changes.*; -import com.intellij.util.ArrayUtil; -import com.intellij.util.BeforeAfter; -import com.intellij.util.containers.ContainerUtil; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -import java.io.IOException; -import java.util.*; - -/** - * @author max - */ -public class ShowDiffAction extends AnAction implements DumbAware { - private static final Logger LOG = Logger.getInstance(ShowDiffAction.class); - - private static final String ourText = ActionsBundle.actionText("ChangesView.Diff"); - - public ShowDiffAction() { - super(ourText, - ActionsBundle.actionDescription("ChangesView.Diff"), - AllIcons.Actions.Diff); - } - - public void update(AnActionEvent e) { - Change[] changes = e.getData(VcsDataKeys.CHANGES); - Project project = e.getData(CommonDataKeys.PROJECT); - e.getPresentation().setEnabled(project != null && canShowDiff(changes)); - } - - protected static boolean canShowDiff(Change[] changes) { - if (changes == null || changes.length == 0) return false; - for (Change change : changes) { - if (!ChangesUtil.getFilePath(change).isDirectory() || change.hasOtherLayers()) return true; - } - return false; - } - - public void actionPerformed(final AnActionEvent e) { - final Project project = e.getData(CommonDataKeys.PROJECT); - if (project == null) return; - if (ChangeListManager.getInstance(project).isFreezedWithNotification(null)) return; - final Change[] changes = e.getData(VcsDataKeys.CHANGES); - if (changes == null) return; - - final boolean needsConvertion = checkIfThereAreFakeRevisions(project, changes); - final List changesInList = e.getData(VcsDataKeys.CHANGES_IN_LIST_KEY); - - // this trick is essential since we are under some conditions to refresh changes; - // but we can only rely on callback after refresh - final Runnable performer = new Runnable() { - public void run() { - Change[] convertedChanges; - if (needsConvertion) { - convertedChanges = loadFakeRevisions(project, changes); - } else { - convertedChanges = changes; - } - - if (convertedChanges == null || convertedChanges.length == 0) { - return; - } - - List changesInListCopy = changesInList; - - int index = 0; - if (convertedChanges.length == 1) { - final Change selectedChange = convertedChanges[0]; - ChangeList changeList = ((ChangeListManagerImpl) ChangeListManager.getInstance(project)).getIdentityChangeList(selectedChange); - if (changeList != null) { - if (changesInListCopy == null) { - changesInListCopy = new ArrayList(changeList.getChanges()); - Collections.sort(changesInListCopy, new Comparator() { - public int compare(final Change o1, final Change o2) { - return ChangesUtil.getFilePath(o1).getName().compareToIgnoreCase(ChangesUtil.getFilePath(o2).getName()); - } - }); - } - convertedChanges = changesInListCopy.toArray(new Change[changesInListCopy.size()]); - index = Math.max(0, ContainerUtil.indexOfIdentity(changesInListCopy, selectedChange)); - } - } - - showDiffForChange(convertedChanges, index, project); - } - }; - - if (needsConvertion) { - ChangeListManager.getInstance(project).invokeAfterUpdate(performer, InvokeAfterUpdateMode.BACKGROUND_CANCELLABLE, ourText, ModalityState.current()); - } else { - performer.run(); - } - } - - public static void showDiffForChange(final Change[] changes, final int index, final Project project) { - showDiffForChange(changes, index, project, new ShowDiffUIContext(true)); - } - - private static boolean checkIfThereAreFakeRevisions(final Project project, final Change[] changes) { - boolean needsConversion = false; - for(Change change: changes) { - final ContentRevision beforeRevision = change.getBeforeRevision(); - final ContentRevision afterRevision = change.getAfterRevision(); - if (beforeRevision instanceof FakeRevision) { - VcsDirtyScopeManager.getInstance(project).fileDirty(beforeRevision.getFile()); - needsConversion = true; - } - if (afterRevision instanceof FakeRevision) { - VcsDirtyScopeManager.getInstance(project).fileDirty(afterRevision.getFile()); - needsConversion = true; - } - } - return needsConversion; - } - - @Nullable - private static Change[] loadFakeRevisions(final Project project, final Change[] changes) { - List matchingChanges = new ArrayList(); - for(Change change: changes) { - matchingChanges.addAll(ChangeListManager.getInstance(project).getChangesIn(ChangesUtil.getFilePath(change))); - } - return matchingChanges.toArray(new Change[matchingChanges.size()]); - } - - public static void showDiffForChange(final Iterable changes, final Condition selectionChecker, - final Project project, @NotNull ShowDiffUIContext context) { - int newIndex = -1; - ChangeForDiffConvertor convertor = new ChangeForDiffConvertor(project, true); - final List changeList = ContainerUtil.newArrayList(); - for (Change change : changes) { - if (! directoryOrBinary(change)) { //todo - DiffRequestPresentable presentable = convertor.convert(change); - if (presentable != null) { - if ((newIndex == -1) && selectionChecker.value(change)) { - newIndex = changeList.size(); - } - changeList.add(presentable); - } - } - } - if (changeList.isEmpty()) { - return; - } - if (newIndex < 0) { - newIndex = 0; - } - - showDiffImpl(project, changeList, newIndex, context); - } - - public static void showDiffForChange(final Change[] changes, int index, final Project project, @NotNull ShowDiffUIContext context) { - final Change selected = index >= 0 ? changes[index] : null; - /*if (isBinaryDiff(project, changes, index)) { - showBinaryDiff(project, changes[index]); - return; - }*/ - showDiffForChange(Arrays.asList(changes), new Condition() { - @Override - public boolean value(final Change change) { - return selected != null && selected.equals(change); - } - }, project, context); - } - - private static FileContent createBinaryFileContent(final Project project, final ContentRevision contentRevision, final String fileName) - throws VcsException, IOException { - final FileContent fileContent; - if (contentRevision == null) { - fileContent = FileContent.createFromTempFile(project, - fileName, - fileName, - ArrayUtil.EMPTY_BYTE_ARRAY); - } else { - byte[] content = ((BinaryContentRevision)contentRevision).getBinaryContent(); - fileContent = FileContent.createFromTempFile(project, - contentRevision.getFile().getName(), - contentRevision.getFile().getName(), - content == null ? ArrayUtil.EMPTY_BYTE_ARRAY : content); - } - return fileContent; - } - - private static SimpleDiffRequest createBinaryDiffRequest(final Project project, final Change change) throws VcsException { - final FilePath filePath = ChangesUtil.getFilePath(change); - final SimpleDiffRequest request = new SimpleDiffRequest(project, filePath.getPath()); - try { - request.setContents(createBinaryFileContent(project, change.getBeforeRevision(), filePath.getName()), - createBinaryFileContent(project, change.getAfterRevision(), filePath.getName())); - return request; - } - catch (IOException e) { - throw new VcsException(e); - } - } - - public static BeforeAfter createBinaryDiffContents(final Project project, final Change change) throws VcsException { - final FilePath filePath = ChangesUtil.getFilePath(change); - try { - return new BeforeAfter(createBinaryFileContent(project, change.getBeforeRevision(), filePath.getName()), - createBinaryFileContent(project, change.getAfterRevision(), filePath.getName())); - } - catch (IOException e) { - throw new VcsException(e); - } - } - - private static void showBinaryDiff(Project project, Change change) { - try { - final SimpleDiffRequest request = createBinaryDiffRequest(project, change); - if (DiffManager.getInstance().getDiffTool().canShow(request)) { - DiffManager.getInstance().getDiffTool().show(request); - } - } - catch (VcsException e) { - Messages.showWarningDialog(e.getMessage(), "Show Diff"); - LOG.info(e); - } - } - - private static boolean isBinaryDiff(Project project, Change[] changes, int index) { - if (index >= 0 && index < changes.length) { - final Change change = changes[index]; - return isBinaryChangeAndCanShow(project, change); - } - return false; - } - - public static boolean isBinaryChange(Change change) { - if (change.hasOtherLayers()) return false; // +- - final ContentRevision bRev = change.getBeforeRevision(); - final ContentRevision aRev = change.getAfterRevision(); - - return (aRev == null || aRev instanceof BinaryContentRevision) - && (bRev == null || bRev instanceof BinaryContentRevision); - } - - public static boolean isBinaryChangeAndCanShow(Project project, Change change) { - // todo bug here would appear when there would be another diff providers for bimary revisions - return isBinaryChange(change) && (change.getAfterRevision() == null || BinaryDiffTool.canShow(project, change.getVirtualFile())); - } - - public static void showDiffImpl(final Project project, @NotNull List changeList, int index, - @NotNull final ShowDiffUIContext context) { - final ChangeDiffRequest request = new ChangeDiffRequest(project, changeList, context.getActionsFactory(), context.isShowFrame()); - final DiffTool tool = DiffManager.getInstance().getDiffTool(); - final DiffRequest simpleRequest; - try { - request.quickCheckHaveStuff(); - simpleRequest = request.init(index); - } - catch (VcsException e) { - Messages.showWarningDialog(e.getMessage(), "Show Diff"); - LOG.info(e); - return; - } - - if (simpleRequest != null) { - final DiffNavigationContext navigationContext = context.getDiffNavigationContext(); - if (navigationContext != null) { - simpleRequest.passForDataContext(DiffTool.SCROLL_TO_LINE, navigationContext); - } - tool.show(simpleRequest); - } - } - - private static boolean directoryOrBinary(final Change change) { - // todo instead for repository tab, filter directories (? ask remotely ? non leaf nodes) - /*if ((change.getBeforeRevision() instanceof BinaryContentRevision) || (change.getAfterRevision() instanceof BinaryContentRevision)) { - changesList.remove(i); - continue; - }*/ - final FilePath path = ChangesUtil.getFilePath(change); - if (path.isDirectory()) { - return ! change.hasOtherLayers(); - } - /*final FileType type = path.getFileType(); - if ((! FileTypes.UNKNOWN.equals(type)) && (type.isBinary())) { - return true; - }*/ - return false; - } - - private static boolean checkNotifyBinaryDiff(final Change selectedChange) { - final ContentRevision beforeRevision = selectedChange.getBeforeRevision(); - final ContentRevision afterRevision = selectedChange.getAfterRevision(); - if (beforeRevision instanceof BinaryContentRevision && - afterRevision instanceof BinaryContentRevision) { - try { - byte[] beforeContent = ((BinaryContentRevision)beforeRevision).getBinaryContent(); - byte[] afterContent = ((BinaryContentRevision)afterRevision).getBinaryContent(); - if (Arrays.equals(beforeContent, afterContent)) { - Messages.showInfoMessage(VcsBundle.message("message.text.binary.versions.are.identical"), VcsBundle.message("message.title.diff")); - } else { - Messages.showInfoMessage(VcsBundle.message("message.text.binary.versions.are.different"), VcsBundle.message("message.title.diff")); - } - } - catch (VcsException e) { - Messages.showInfoMessage(e.getMessage(), VcsBundle.message("message.title.diff")); - } - return true; - } - return false; - } -} diff --git a/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/actions/ShowDiffUIContext.java b/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/actions/ShowDiffUIContext.java deleted file mode 100644 index 937b81ead9e5..000000000000 --- a/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/actions/ShowDiffUIContext.java +++ /dev/null @@ -1,58 +0,0 @@ -/* - * Copyright 2000-2010 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.vcs.changes.actions; - -import com.intellij.openapi.diff.DiffNavigationContext; -import org.jetbrains.annotations.NotNull; - -public class ShowDiffUIContext { - private DiffExtendUIFactory myActionsFactory; - private boolean myShowFrame; - private DiffNavigationContext myDiffNavigationContext; - - public ShowDiffUIContext() { - myActionsFactory = DiffExtendUIFactory.NONE; - } - - public ShowDiffUIContext(boolean showFrame) { - myShowFrame = showFrame; - myActionsFactory = DiffExtendUIFactory.NONE; - } - - public DiffExtendUIFactory getActionsFactory() { - return myActionsFactory; - } - - public void setActionsFactory(@NotNull DiffExtendUIFactory actionsFactory) { - this.myActionsFactory = actionsFactory; - } - - public DiffNavigationContext getDiffNavigationContext() { - return myDiffNavigationContext; - } - - public void setDiffNavigationContext(DiffNavigationContext diffNavigationContext) { - myDiffNavigationContext = diffNavigationContext; - } - - public boolean isShowFrame() { - return myShowFrame; - } - - public void setShowFrame(boolean showFrame) { - this.myShowFrame = showFrame; - } -} diff --git a/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/actions/diff/ShowDiffAction.java b/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/actions/diff/ShowDiffAction.java index 55bec3ec9451..379007ffbac6 100644 --- a/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/actions/diff/ShowDiffAction.java +++ b/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/actions/diff/ShowDiffAction.java @@ -15,7 +15,6 @@ */ package com.intellij.openapi.vcs.changes.actions.diff; -import com.intellij.diff.DiffDialogHints; import com.intellij.diff.DiffManager; import com.intellij.diff.chains.DiffRequestChain; import com.intellij.diff.util.DiffUserDataKeys; @@ -33,7 +32,6 @@ import com.intellij.openapi.util.Condition; import com.intellij.openapi.util.Key; import com.intellij.openapi.vcs.VcsDataKeys; import com.intellij.openapi.vcs.changes.*; -import com.intellij.openapi.vcs.changes.actions.ShowDiffUIContext; import com.intellij.util.containers.ContainerUtil; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -219,16 +217,4 @@ public class ShowDiffAction extends AnAction implements DumbAware { DiffManager.getInstance().showDiff(project, chain, context.getDialogHints()); } - - // - // Compatibility - // - - @NotNull - public static ShowDiffContext convertContext(@NotNull ShowDiffUIContext uiContext) { - if (uiContext.getActionsFactory() != null) LOG.warn("DiffExtendUIFactory ignored"); - if (uiContext.getDiffNavigationContext() != null) LOG.warn("DiffNavigationContext ignored"); - - return new ShowDiffContext(uiContext.isShowFrame() ? DiffDialogHints.FRAME : DiffDialogHints.MODAL); - } } From 43fbd999dc541c9279b2d073699a0960fcdae494 Mon Sep 17 00:00:00 2001 From: Kirill Likhodedov Date: Mon, 21 Mar 2016 16:24:54 +0300 Subject: [PATCH 55/81] vcs: fix scope for a library used only for tests --- platform/dvcs-impl/dvcs-impl.iml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/platform/dvcs-impl/dvcs-impl.iml b/platform/dvcs-impl/dvcs-impl.iml index aebe42866489..3b75b42d7d51 100644 --- a/platform/dvcs-impl/dvcs-impl.iml +++ b/platform/dvcs-impl/dvcs-impl.iml @@ -20,6 +20,6 @@ - + \ No newline at end of file From efe720add3b2b9f71dfba51472800982c00a6ebf Mon Sep 17 00:00:00 2001 From: Kirill Likhodedov Date: Mon, 21 Mar 2016 16:37:06 +0300 Subject: [PATCH 56/81] fix line breaks in html notification Let MultiRootMessage support
line breaks. Actually use "
\n" as html separator to make message look nicer even when not rendered (e.g. in tests). --- .../src/com/intellij/dvcs/MultiRootMessage.kt | 5 +++-- .../com.intellij.dvcs/MultiRootMessageTest.kt | 18 ++++++++++-------- .../src/git4idea/update/GitFetcher.java | 2 +- 3 files changed, 14 insertions(+), 11 deletions(-) diff --git a/platform/dvcs-impl/src/com/intellij/dvcs/MultiRootMessage.kt b/platform/dvcs-impl/src/com/intellij/dvcs/MultiRootMessage.kt index 424e19654706..996b12d46dd4 100644 --- a/platform/dvcs-impl/src/com/intellij/dvcs/MultiRootMessage.kt +++ b/platform/dvcs-impl/src/com/intellij/dvcs/MultiRootMessage.kt @@ -22,9 +22,10 @@ import com.intellij.openapi.vfs.VirtualFile import com.intellij.util.containers.ContainerUtil import com.intellij.vcsUtil.VcsImplUtil.getShortVcsRootName -class MultiRootMessage(private val myProject: Project, private val myAllRoots: Collection) { +class MultiRootMessage(private val myProject: Project, private val myAllRoots: Collection, html: Boolean) { private val LOG = Logger.getInstance(MultiRootMessage::class.java) private val myMessages = ContainerUtil.newLinkedHashMap() + private val myLineSeparator = if (html) "
\n" else "\n" fun append(root: VirtualFile, message: String): MultiRootMessage { if (!myAllRoots.contains(root)) { @@ -47,7 +48,7 @@ class MultiRootMessage(private val myProject: Project, private val myAllRoots: C } val grouped = myMessages.keys.groupBy { myMessages[it]!!.trim() } if (grouped.size == 1 && myAllRoots.size == myMessages.size) return myMessages.values.first() - return grouped.keys.joinToString("\n") { + return grouped.keys.joinToString(myLineSeparator) { val shortRootNames = grouped[it]!!.map { getShortVcsRootName(myProject, it) } "$it in ${joinWithAnd(shortRootNames, 5)}" } } diff --git a/platform/dvcs-impl/testSrc/com.intellij.dvcs/MultiRootMessageTest.kt b/platform/dvcs-impl/testSrc/com.intellij.dvcs/MultiRootMessageTest.kt index d7fe47ba40e7..9bbf05193d84 100644 --- a/platform/dvcs-impl/testSrc/com.intellij.dvcs/MultiRootMessageTest.kt +++ b/platform/dvcs-impl/testSrc/com.intellij.dvcs/MultiRootMessageTest.kt @@ -39,14 +39,14 @@ class MultiRootMessageTest { @Test fun `test empty message`() { val root = myProject.baseDir - val multiRootMessage = MultiRootMessage(myProject, setOf(root)) + val multiRootMessage = multiRootMessage(root) assertTrue(multiRootMessage.asString().isEmpty()) } @Test fun `test single repository`() { val root = myProject.baseDir - val multiRootMessage = MultiRootMessage(myProject, setOf(root)) + val multiRootMessage = multiRootMessage(root) multiRootMessage.append(root, "Pruned obsolete remote references: origin/fix1, origin/fix2") assertEquals("Pruned obsolete remote references: origin/fix1, origin/fix2", multiRootMessage.asString()) } @@ -56,7 +56,7 @@ class MultiRootMessageTest { val idea = myProject.baseDir val community = createSubDir(idea, "community") - val multiRootMessage = MultiRootMessage(myProject, setOf(idea, community)) + val multiRootMessage = multiRootMessage(idea, community) multiRootMessage.append(idea, "Pruned obsolete remote references: origin/fix1, origin/fix2") assertEquals("Pruned obsolete remote references: origin/fix1, origin/fix2 in idea", multiRootMessage.asString()) } @@ -66,7 +66,7 @@ class MultiRootMessageTest { val idea = myProject.baseDir val community = createSubDir(idea, "community") - val multiRootMessage = MultiRootMessage(myProject, setOf(idea, community)) + val multiRootMessage = multiRootMessage(idea, community) multiRootMessage.append(idea, "Pruned obsolete remote references: origin/fix1, origin/fix2") multiRootMessage.append(community, "Pruned obsolete remote references: origin/fix1, origin/fix2") assertEquals("Pruned obsolete remote references: origin/fix1, origin/fix2", multiRootMessage.asString()) @@ -77,7 +77,7 @@ class MultiRootMessageTest { val idea = myProject.baseDir val community = createSubDir(idea, "community") - val multiRootMessage = MultiRootMessage(myProject, setOf(idea, community)) + val multiRootMessage = multiRootMessage(idea, community) multiRootMessage.append(idea, "Pruned obsolete remote references: origin/fix1, origin/fix2") multiRootMessage.append(community, "Pruned obsolete remote references: origin/fix3") assertEquals( @@ -88,24 +88,26 @@ class MultiRootMessageTest { } @Test - fun `test three roots with same message, and one root with another`() { + fun `test html message for three roots with same message, and one root with another`() { val idea = myProject.baseDir val community = createSubDir(idea, "community") val contrib = createSubDir(idea, "contrib") val android = createSubDir(community, "android") - val multiRootMessage = MultiRootMessage(myProject, setOf(idea, community, contrib, android)) + val multiRootMessage = MultiRootMessage(myProject, setOf(idea, community, contrib, android), true) multiRootMessage.append(idea, "Pruned obsolete remote references: origin/fix1, origin/fix2") multiRootMessage.append(community, "Pruned obsolete remote references: origin/fix3") multiRootMessage.append(contrib, "Pruned obsolete remote references: origin/fix3") multiRootMessage.append(android, "Pruned obsolete remote references: origin/fix3") assertEquals( """ - Pruned obsolete remote references: origin/fix1, origin/fix2 in idea + Pruned obsolete remote references: origin/fix1, origin/fix2 in idea
Pruned obsolete remote references: origin/fix3 in community, contrib and community${File.separator}android """.trimIndent(), multiRootMessage.asString()) } + private fun multiRootMessage(vararg roots : VirtualFile) = MultiRootMessage(myProject, roots.asList(), false) + private fun createSubDir(parent: VirtualFile, name: String): VirtualFile { val vf = MockVirtualFile(true, name) vf.parent = parent diff --git a/plugins/git4idea/src/git4idea/update/GitFetcher.java b/plugins/git4idea/src/git4idea/update/GitFetcher.java index cc5fb3dd4b9c..531cd9a1c84a 100644 --- a/plugins/git4idea/src/git4idea/update/GitFetcher.java +++ b/plugins/git4idea/src/git4idea/update/GitFetcher.java @@ -256,7 +256,7 @@ public class GitFetcher { */ public boolean fetchRootsAndNotify(@NotNull Collection roots, @Nullable String errorNotificationTitle, boolean notifySuccess) { - MultiRootMessage additionalInfo = new MultiRootMessage(myProject, GitUtil.getRootsFromRepositories(roots)); + MultiRootMessage additionalInfo = new MultiRootMessage(myProject, GitUtil.getRootsFromRepositories(roots), true); for (GitRepository repository : roots) { LOG.info("fetching " + repository); GitFetchResult result = fetch(repository); From 214dfa45e426a480559d8d9099cfa22228bd57fe Mon Sep 17 00:00:00 2001 From: Philipp Smorygo Date: Mon, 21 Mar 2016 16:39:05 +0300 Subject: [PATCH 57/81] OC-11919 Navigation from Objective-C code directly to Swift declaration and implementation does not work, instead you jump to the auto-generated ObjC bridging header make this work faster --- .../util/src/com/intellij/util/containers/ContainerUtil.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/platform/util/src/com/intellij/util/containers/ContainerUtil.java b/platform/util/src/com/intellij/util/containers/ContainerUtil.java index f954137a570f..2b19021c1685 100644 --- a/platform/util/src/com/intellij/util/containers/ContainerUtil.java +++ b/platform/util/src/com/intellij/util/containers/ContainerUtil.java @@ -2407,7 +2407,7 @@ public class ContainerUtil extends ContainerUtilRt { return true; } - @Nullable + @Contract("null -> null; !null -> !null") public static List trimToSize(@Nullable List list) { if (list == null) return null; if (list.isEmpty()) return emptyList(); From 9f25ff87a3b2e42de24ca00b057dd77fc1b9e2ca Mon Sep 17 00:00:00 2001 From: "Egor.Ushakov" Date: Mon, 21 Mar 2016 17:15:09 +0300 Subject: [PATCH 58/81] edit watch use shortcut of set value --- platform/platform-resources/src/idea/Keymap_Default.xml | 3 --- platform/platform-resources/src/idea/LangActions.xml | 2 +- 2 files changed, 1 insertion(+), 4 deletions(-) diff --git a/platform/platform-resources/src/idea/Keymap_Default.xml b/platform/platform-resources/src/idea/Keymap_Default.xml index 66d81bbbd679..be6172a40e67 100644 --- a/platform/platform-resources/src/idea/Keymap_Default.xml +++ b/platform/platform-resources/src/idea/Keymap_Default.xml @@ -692,9 +692,6 @@ - - - diff --git a/platform/platform-resources/src/idea/LangActions.xml b/platform/platform-resources/src/idea/LangActions.xml index 1b76370488e4..f7dc145b8ea3 100644 --- a/platform/platform-resources/src/idea/LangActions.xml +++ b/platform/platform-resources/src/idea/LangActions.xml @@ -725,7 +725,7 @@ - + Date: Mon, 21 Mar 2016 17:16:29 +0300 Subject: [PATCH 59/81] cleanup: remove "my" prefixes from kotlin class --- .../src/com/intellij/dvcs/MultiRootMessage.kt | 34 +++++++++---------- .../com.intellij.dvcs/MultiRootMessageTest.kt | 22 ++++++------ 2 files changed, 28 insertions(+), 28 deletions(-) diff --git a/platform/dvcs-impl/src/com/intellij/dvcs/MultiRootMessage.kt b/platform/dvcs-impl/src/com/intellij/dvcs/MultiRootMessage.kt index 996b12d46dd4..b8034d1764b0 100644 --- a/platform/dvcs-impl/src/com/intellij/dvcs/MultiRootMessage.kt +++ b/platform/dvcs-impl/src/com/intellij/dvcs/MultiRootMessage.kt @@ -22,38 +22,38 @@ import com.intellij.openapi.vfs.VirtualFile import com.intellij.util.containers.ContainerUtil import com.intellij.vcsUtil.VcsImplUtil.getShortVcsRootName -class MultiRootMessage(private val myProject: Project, private val myAllRoots: Collection, html: Boolean) { +class MultiRootMessage(private val project: Project, private val allRoots: Collection, html: Boolean) { private val LOG = Logger.getInstance(MultiRootMessage::class.java) - private val myMessages = ContainerUtil.newLinkedHashMap() - private val myLineSeparator = if (html) "
\n" else "\n" + private val messages = ContainerUtil.newLinkedHashMap() + private val lineSeparator = if (html) "
\n" else "\n" fun append(root: VirtualFile, message: String): MultiRootMessage { - if (!myAllRoots.contains(root)) { - LOG.error("The root ${root.path} is unexpected: $myAllRoots") + if (!allRoots.contains(root)) { + LOG.error("The root ${root.path} is unexpected: $allRoots") return this } - if (myMessages.containsKey(root)) { + if (messages.containsKey(root)) { LOG.error("Duplicate root ${root.path} reporting message [$message]") } - myMessages.put(root, message) + messages.put(root, message) return this } fun asString(): String { - if (myMessages.isEmpty()) return ""; - if (myAllRoots.size == 1) return myMessages.values.first() - if (myMessages.size == 1) { - val (root, message) = myMessages.entries.first() - return "$message in ${getShortVcsRootName(myProject, root)}" + if (messages.isEmpty()) return ""; + if (allRoots.size == 1) return messages.values.first() + if (messages.size == 1) { + val (root, message) = messages.entries.first() + return "$message in ${getShortVcsRootName(project, root)}" } - val grouped = myMessages.keys.groupBy { myMessages[it]!!.trim() } - if (grouped.size == 1 && myAllRoots.size == myMessages.size) return myMessages.values.first() - return grouped.keys.joinToString(myLineSeparator) { - val shortRootNames = grouped[it]!!.map { getShortVcsRootName(myProject, it) } + val grouped = messages.keys.groupBy { messages[it]!!.trim() } + if (grouped.size == 1 && allRoots.size == messages.size) return messages.values.first() + return grouped.keys.joinToString(lineSeparator) { + val shortRootNames = grouped[it]!!.map { getShortVcsRootName(project, it) } "$it in ${joinWithAnd(shortRootNames, 5)}" } } override fun toString(): String { - return myMessages.toString() + return messages.toString() } } diff --git a/platform/dvcs-impl/testSrc/com.intellij.dvcs/MultiRootMessageTest.kt b/platform/dvcs-impl/testSrc/com.intellij.dvcs/MultiRootMessageTest.kt index 9bbf05193d84..4dc1da754747 100644 --- a/platform/dvcs-impl/testSrc/com.intellij.dvcs/MultiRootMessageTest.kt +++ b/platform/dvcs-impl/testSrc/com.intellij.dvcs/MultiRootMessageTest.kt @@ -28,24 +28,24 @@ import java.io.File class MultiRootMessageTest { - private lateinit var myProject : Project + private lateinit var project: Project @Before fun setUp() { - myProject = mock(Project::class.java) - Mockito.`when`(myProject.baseDir).thenReturn(MockVirtualFile(true, "idea")) + project = mock(Project::class.java) + Mockito.`when`(project.baseDir).thenReturn(MockVirtualFile(true, "idea")) } @Test fun `test empty message`() { - val root = myProject.baseDir + val root = project.baseDir val multiRootMessage = multiRootMessage(root) assertTrue(multiRootMessage.asString().isEmpty()) } @Test fun `test single repository`() { - val root = myProject.baseDir + val root = project.baseDir val multiRootMessage = multiRootMessage(root) multiRootMessage.append(root, "Pruned obsolete remote references: origin/fix1, origin/fix2") assertEquals("Pruned obsolete remote references: origin/fix1, origin/fix2", multiRootMessage.asString()) @@ -53,7 +53,7 @@ class MultiRootMessageTest { @Test fun `test single root message in multi-root project`() { - val idea = myProject.baseDir + val idea = project.baseDir val community = createSubDir(idea, "community") val multiRootMessage = multiRootMessage(idea, community) @@ -63,7 +63,7 @@ class MultiRootMessageTest { @Test fun `test two roots with same messages`() { - val idea = myProject.baseDir + val idea = project.baseDir val community = createSubDir(idea, "community") val multiRootMessage = multiRootMessage(idea, community) @@ -74,7 +74,7 @@ class MultiRootMessageTest { @Test fun `test two roots with different messages`() { - val idea = myProject.baseDir + val idea = project.baseDir val community = createSubDir(idea, "community") val multiRootMessage = multiRootMessage(idea, community) @@ -89,12 +89,12 @@ class MultiRootMessageTest { @Test fun `test html message for three roots with same message, and one root with another`() { - val idea = myProject.baseDir + val idea = project.baseDir val community = createSubDir(idea, "community") val contrib = createSubDir(idea, "contrib") val android = createSubDir(community, "android") - val multiRootMessage = MultiRootMessage(myProject, setOf(idea, community, contrib, android), true) + val multiRootMessage = MultiRootMessage(project, setOf(idea, community, contrib, android), true) multiRootMessage.append(idea, "Pruned obsolete remote references: origin/fix1, origin/fix2") multiRootMessage.append(community, "Pruned obsolete remote references: origin/fix3") multiRootMessage.append(contrib, "Pruned obsolete remote references: origin/fix3") @@ -106,7 +106,7 @@ class MultiRootMessageTest { """.trimIndent(), multiRootMessage.asString()) } - private fun multiRootMessage(vararg roots : VirtualFile) = MultiRootMessage(myProject, roots.asList(), false) + private fun multiRootMessage(vararg roots : VirtualFile) = MultiRootMessage(project, roots.asList(), false) private fun createSubDir(parent: VirtualFile, name: String): VirtualFile { val vf = MockVirtualFile(true, name) From 34bd807cd111a5308efc3e4f05c759755db6085d Mon Sep 17 00:00:00 2001 From: peter Date: Mon, 21 Mar 2016 15:20:15 +0100 Subject: [PATCH 60/81] another case of IDEA-149939 CCE in com.intellij.execution.stacktrace.StackTraceLine.getMethodLocation causes frozen UI --- .../execution/stacktrace/StackTraceLine.java | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/java/execution/impl/src/com/intellij/execution/stacktrace/StackTraceLine.java b/java/execution/impl/src/com/intellij/execution/stacktrace/StackTraceLine.java index 7079d61bd650..5d956fabdfb3 100644 --- a/java/execution/impl/src/com/intellij/execution/stacktrace/StackTraceLine.java +++ b/java/execution/impl/src/com/intellij/execution/stacktrace/StackTraceLine.java @@ -103,15 +103,16 @@ public class StackTraceLine { final int dollarIndex = className.indexOf('$'); if (dollarIndex != -1) className = className.substring(0, dollarIndex); PsiClass psiClass = findClass(project, className, lineNumber); - if (psiClass == null || (psiClass.getNavigationElement() instanceof PsiCompiledElement)) return null; - psiClass = (PsiClass)psiClass.getNavigationElement(); - final PsiMethod psiMethod = getMethodAtLine(psiClass, methodName, lineNumber); - if (psiMethod != null) { - return new MethodLineLocation(project, psiMethod, PsiLocation.fromPsiElement(psiClass), lineNumber); - } - else { - return null; + PsiElement navElement = psiClass == null ? null : psiClass.getNavigationElement(); + if (psiClass == null || navElement instanceof PsiCompiledElement) return null; + + if (navElement instanceof PsiClass) { + final PsiMethod psiMethod = getMethodAtLine((PsiClass)navElement, methodName, lineNumber); + if (psiMethod != null) { + return new MethodLineLocation(project, psiMethod, PsiLocation.fromPsiElement((PsiClass)navElement), lineNumber); + } } + return null; } private static PsiClass findClass(final Project project, final String className, final int lineNumber) { From a682213311c8c3a637f984e868bbe31dea790a7a Mon Sep 17 00:00:00 2001 From: Roman Shevchenko Date: Mon, 21 Mar 2016 14:13:28 +0100 Subject: [PATCH 61/81] [platform] completely skips paid upgrade check (IDEA-153200) --- .../impl/AbstractUpdateDialog.java | 58 +++++-------------- .../updateSettings/impl/NewChannelDialog.java | 36 ++++-------- .../updateSettings/impl/UpdateInfoDialog.java | 4 +- .../src/com/intellij/ui/LicensingFacade.java | 14 ++--- .../src/messages/IdeBundle.properties | 3 - 5 files changed, 33 insertions(+), 82 deletions(-) diff --git a/platform/platform-impl/src/com/intellij/openapi/updateSettings/impl/AbstractUpdateDialog.java b/platform/platform-impl/src/com/intellij/openapi/updateSettings/impl/AbstractUpdateDialog.java index 0f40317966d1..71f4a2cbc933 100644 --- a/platform/platform-impl/src/com/intellij/openapi/updateSettings/impl/AbstractUpdateDialog.java +++ b/platform/platform-impl/src/com/intellij/openapi/updateSettings/impl/AbstractUpdateDialog.java @@ -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,8 +40,6 @@ public abstract class AbstractUpdateDialog extends DialogWrapper { private final boolean myEnableLink; protected String myLicenseInfo = null; - protected boolean myPaidUpgrade; - protected boolean mySubscriptionLicense = false; protected AbstractUpdateDialog(boolean enableLink) { super(true); @@ -71,56 +69,34 @@ public abstract class AbstractUpdateDialog extends DialogWrapper { } protected void restart() { - final ApplicationEx app = ApplicationManagerEx.getApplicationEx(); // do not stack several modal dialogs (native & swing) - app.invokeLater(new Runnable() { - @Override - public void run() { - app.restart(true); - } - }); + ApplicationEx app = ApplicationManagerEx.getApplicationEx(); + app.invokeLater(() -> app.restart(true)); } - protected void initLicensingInfo(@NotNull UpdateChannel channel, @NotNull BuildInfo build) { + protected void initLicensingInfo(@NotNull UpdateChannel channel, @SuppressWarnings("UnusedParameters") @NotNull BuildInfo build) { LicensingFacade facade = LicensingFacade.getInstance(); if (facade != null) { - mySubscriptionLicense = facade.isSubscriptionLicense(); - if (!channel.getLicensing().equals(UpdateChannel.LICENSING_EAP)) { - int majorVersion = build.getMajorVersion(); - if (majorVersion < 0) { - majorVersion = channel.getMajorVersion(); // fallback - } - final Boolean paidUpgrade = facade.isPaidUpgrade(majorVersion, build.getReleaseDate()); - if (paidUpgrade == Boolean.TRUE) { - myPaidUpgrade = true; - myLicenseInfo = IdeBundle.message("updates.channel.key.needed", channel.getEvalDays()); - } - else if (paidUpgrade == Boolean.FALSE) { - myLicenseInfo = IdeBundle.message("updates.channel.existing.key"); - } - } - else { + if (channel.getLicensing().equals(UpdateChannel.LICENSING_EAP)) { myLicenseInfo = IdeBundle.message("updates.channel.bundled.key"); } } } - protected void configureMessageArea(@NotNull JEditorPane area) { String messageBody = myEnableLink ? IdeBundle.message("updates.configure.label", ShowSettingsUtil.getSettingsMenuName()) : ""; configureMessageArea(area, messageBody, null, null); } - protected void configureMessageArea(final @NotNull JEditorPane area, + protected void configureMessageArea(@NotNull JEditorPane area, @NotNull String messageBody, @Nullable Color fontColor, @Nullable HyperlinkListener listener) { - String text = "" + - UIUtil.getCssFontDeclaration(UIUtil.getLabelFont(), fontColor, null, null) + - "" + - "" + - messageBody + - ""; + String text = + "" + + UIUtil.getCssFontDeclaration(UIUtil.getLabelFont(), fontColor, null, null) + + "" + + "" + messageBody + ""; area.setBackground(UIUtil.getPanelBackground()); area.setBorder(IdeBorderFactory.createEmptyBorder()); @@ -128,13 +104,9 @@ public abstract class AbstractUpdateDialog extends DialogWrapper { area.setEditable(false); if (listener == null && myEnableLink) { - listener = new HyperlinkListener() { - @Override - public void hyperlinkUpdate(final HyperlinkEvent e) { - if (e.getEventType() == HyperlinkEvent.EventType.ACTIVATED) { - UpdateSettingsConfigurable settings = new UpdateSettingsConfigurable(false); - ShowSettingsUtil.getInstance().editConfigurable(area, settings); - } + listener = (e) -> { + if (e.getEventType() == HyperlinkEvent.EventType.ACTIVATED) { + ShowSettingsUtil.getInstance().editConfigurable(area, new UpdateSettingsConfigurable(false)); } }; } @@ -142,4 +114,4 @@ public abstract class AbstractUpdateDialog extends DialogWrapper { area.addHyperlinkListener(listener); } } -} +} \ No newline at end of file diff --git a/platform/platform-impl/src/com/intellij/openapi/updateSettings/impl/NewChannelDialog.java b/platform/platform-impl/src/com/intellij/openapi/updateSettings/impl/NewChannelDialog.java index ff093e28e489..d97a02f78c88 100644 --- a/platform/platform-impl/src/com/intellij/openapi/updateSettings/impl/NewChannelDialog.java +++ b/platform/platform-impl/src/com/intellij/openapi/updateSettings/impl/NewChannelDialog.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2014 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. @@ -18,13 +18,11 @@ package com.intellij.openapi.updateSettings.impl; import com.intellij.ide.BrowserUtil; import com.intellij.ide.IdeBundle; import com.intellij.ui.BrowserHyperlinkListener; -import com.intellij.ui.LicensingFacade; -import com.intellij.util.containers.ContainerUtil; import org.jetbrains.annotations.NotNull; import javax.swing.*; import java.awt.event.ActionEvent; -import java.util.List; +import java.util.Objects; /** * @author yole @@ -52,31 +50,19 @@ class NewChannelDialog extends AbstractUpdateDialog { @NotNull @Override protected Action[] createActions() { - List actions = ContainerUtil.newArrayList(getOKAction()); + return new Action[]{ + getOKAction(), - if (myPaidUpgrade) { - actions.add(new AbstractAction(IdeBundle.message("updates.buy.online.button")) { + new AbstractAction(IdeBundle.message("updates.remind.later.button")) { @Override public void actionPerformed(ActionEvent e) { - LicensingFacade facade = LicensingFacade.getInstance(); - assert facade != null; - BrowserUtil.browse(facade.getUpgradeUrl()); + UpdateSettings.getInstance().forgetChannelId(myChannel.getId()); doCancelAction(); } - }); - } + }, - actions.add(new AbstractAction(IdeBundle.message("updates.remind.later.button")) { - @Override - public void actionPerformed(ActionEvent e) { - UpdateSettings.getInstance().forgetChannelId(myChannel.getId()); - doCancelAction(); - } - }); - - actions.add(getCancelAction()); - - return actions.toArray(new Action[actions.size()]); + getCancelAction() + }; } @Override @@ -91,7 +77,7 @@ class NewChannelDialog extends AbstractUpdateDialog { @Override protected void doOKAction() { - BrowserUtil.browse(myChannel.getHomePageUrl()); + BrowserUtil.browse(Objects.requireNonNull(myChannel.getHomePageUrl(), "missing URL for channel " + myChannel.getId())); super.doOKAction(); } @@ -112,4 +98,4 @@ class NewChannelDialog extends AbstractUpdateDialog { } } } -} +} \ No newline at end of file diff --git a/platform/platform-impl/src/com/intellij/openapi/updateSettings/impl/UpdateInfoDialog.java b/platform/platform-impl/src/com/intellij/openapi/updateSettings/impl/UpdateInfoDialog.java index 6c7a1ced59fe..9fd19b71de69 100644 --- a/platform/platform-impl/src/com/intellij/openapi/updateSettings/impl/UpdateInfoDialog.java +++ b/platform/platform-impl/src/com/intellij/openapi/updateSettings/impl/UpdateInfoDialog.java @@ -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. @@ -236,7 +236,7 @@ class UpdateInfoDialog extends AbstractUpdateDialog { } if (myLicenseInfo != null) { - configureMessageArea(myLicenseArea, myLicenseInfo, myPaidUpgrade ? JBColor.RED : null, null); + configureMessageArea(myLicenseArea, myLicenseInfo, null, null); } } } diff --git a/platform/platform-impl/src/com/intellij/ui/LicensingFacade.java b/platform/platform-impl/src/com/intellij/ui/LicensingFacade.java index 9df936acdfbf..1518cfeafa51 100644 --- a/platform/platform-impl/src/com/intellij/ui/LicensingFacade.java +++ b/platform/platform-impl/src/com/intellij/ui/LicensingFacade.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2011 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. @@ -17,7 +17,6 @@ package com.intellij.ui; import org.jetbrains.annotations.Nullable; -import java.util.Date; import java.util.List; /** @@ -32,11 +31,8 @@ public abstract class LicensingFacade { } public abstract String getLicensedToMessage(); - public abstract List getLicenseRestrictionsMessages(); - public abstract boolean isEvaluationLicense(); - public abstract boolean isSubscriptionLicense(); - @Nullable - public abstract Boolean isPaidUpgrade(int majorVersion, Date releaseDate); - public abstract String getUpgradeUrl(); -} + public abstract List getLicenseRestrictionsMessages(); + + public abstract boolean isEvaluationLicense(); +} \ No newline at end of file diff --git a/platform/platform-resources-en/src/messages/IdeBundle.properties b/platform/platform-resources-en/src/messages/IdeBundle.properties index f153c9455837..c414af819eb5 100644 --- a/platform/platform-resources-en/src/messages/IdeBundle.properties +++ b/platform/platform-resources-en/src/messages/IdeBundle.properties @@ -907,8 +907,6 @@ updates.error.plugin.description.failed=Failed to load plugin descriptions from: update.notifications.title=Platform and Plugin Updates update.notifications.group=Platform and Plugin Updates updates.channel.name.message={0}: {1} -updates.channel.key.needed=You can evaluate the new version for {0} days or buy a license key or an upgrade online. -updates.channel.existing.key=The new version can be used with your existing license key. updates.channel.bundled.key=The new version has an expiration date and does not require a license key. updates.ready.message={0} is ready to update. updates.plugins.ready.message=The following plugin{0,choice,1# is|2#s are} ready to update: {1} @@ -923,7 +921,6 @@ updates.more.info.button=&More Info... updates.download.page.button=Open &Download Page updates.ignore.update.button=&Ignore This Update updates.remind.later.button=&Remind Me Later -updates.buy.online.button=&Buy Upgrade Online updates.new.version.available=A new version of {0} is available! updates.current.version=Current version: updates.available.version=New version: From 8b16bc30376ff1bed25876b673b3c5b4321aef99 Mon Sep 17 00:00:00 2001 From: Konstantin Bulenkov Date: Mon, 21 Mar 2016 15:10:17 +0100 Subject: [PATCH 62/81] initial --- .../options/EditorFontsConstants.java | 54 +++++++++++++++++++ 1 file changed, 54 insertions(+) create mode 100644 platform/editor-ui-ex/src/com/intellij/application/options/EditorFontsConstants.java diff --git a/platform/editor-ui-ex/src/com/intellij/application/options/EditorFontsConstants.java b/platform/editor-ui-ex/src/com/intellij/application/options/EditorFontsConstants.java new file mode 100644 index 000000000000..2b5087caf046 --- /dev/null +++ b/platform/editor-ui-ex/src/com/intellij/application/options/EditorFontsConstants.java @@ -0,0 +1,54 @@ +/* + * 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.application.options; + +import com.intellij.util.ui.JBUI; + +/** + * @author Konstantin Bulenkov + */ +public class EditorFontsConstants { + public static int getMinEditorFontSize() {return JBUI.scale(4);} + + public static int getMaxEditorFontSize() {return JBUI.scale(40);} + + public static int getDefaultEditorFontSize() {return JBUI.scale(12);} + + public static float getMinEditorLineSpacing() {return JBUI.scale(.6F);} + + public static float getMaxEditorLineSpacing() {return JBUI.scale(3f);} + + public static float getDefaultEditorLineSpacing() {return JBUI.scale(1f);} + + public static int checkAndFixEditorFontSize(int size) { + return round(getMinEditorFontSize(), getMaxEditorFontSize(), size); + } + + public static int checkAndFixEditorLineSpacing(int size) { + return round(getMinEditorFontSize(), getMaxEditorFontSize(), size); + } + + private static int round(int min, int max, int val) { + return val < min ? min : val > max ? max : val; + } + + private static float round(float min, float max, float val) { + return val < min ? min : val > max ? max : val; + } + + private EditorFontsConstants() { + } +} From 3b2377eb51c67c725835cb40343863d3efc2babb Mon Sep 17 00:00:00 2001 From: Konstantin Bulenkov Date: Mon, 21 Mar 2016 15:11:27 +0100 Subject: [PATCH 63/81] deprecate OptionsConstants class --- .../application/options/OptionsConstants.java | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/platform/platform-impl/src/com/intellij/application/options/OptionsConstants.java b/platform/platform-impl/src/com/intellij/application/options/OptionsConstants.java index b020da27f557..be5beec6eceb 100644 --- a/platform/platform-impl/src/com/intellij/application/options/OptionsConstants.java +++ b/platform/platform-impl/src/com/intellij/application/options/OptionsConstants.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2011 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. @@ -18,14 +18,21 @@ package com.intellij.application.options; /** * @author Denis Zhdanov * @since 4/25/11 4:23 PM + * @deprecated + * @use com.intellij.application.options.EditorFontsConstants */ public class OptionsConstants { - + @Deprecated public static final int MIN_EDITOR_FONT_SIZE = 4; + @Deprecated public static final int MAX_EDITOR_FONT_SIZE = 40; + @Deprecated public static final int DEFAULT_EDITOR_FONT_SIZE = 12; + @Deprecated public static final float MIN_EDITOR_LINE_SPACING = .6F; + @Deprecated public static final float MAX_EDITOR_LINE_SPACING = 3; + @Deprecated public static final float DEFAULT_EDITOR_LINE_SPACING = 1; private OptionsConstants() { From d3ec5c3e51a5ba7d67dc68a8e2d18397307932f8 Mon Sep 17 00:00:00 2001 From: Konstantin Bulenkov Date: Mon, 21 Mar 2016 15:13:19 +0100 Subject: [PATCH 64/81] use DPI aware editor font constants --- .../application/options/colors/FontOptions.java | 16 ++++++++-------- .../actions/ChangeEditorFontSizeAction.java | 6 +++--- .../intellij/openapi/editor/impl/EditorImpl.java | 9 +++++---- 3 files changed, 16 insertions(+), 15 deletions(-) diff --git a/platform/lang-impl/src/com/intellij/application/options/colors/FontOptions.java b/platform/lang-impl/src/com/intellij/application/options/colors/FontOptions.java index f3cad4d24ba1..7170c9e7fe0a 100644 --- a/platform/lang-impl/src/com/intellij/application/options/colors/FontOptions.java +++ b/platform/lang-impl/src/com/intellij/application/options/colors/FontOptions.java @@ -16,7 +16,7 @@ package com.intellij.application.options.colors; -import com.intellij.application.options.OptionsConstants; +import com.intellij.application.options.EditorFontsConstants; import com.intellij.ide.BrowserUtil; import com.intellij.ide.ui.AntialiasingType; import com.intellij.ide.ui.UISettings; @@ -161,7 +161,7 @@ public class FontOptions extends JPanel implements OptionsPanel{ try { int value = Integer.parseInt(myEditorFontSizeField.getText()); value += (up ? 1 : -1); - value = Math.min(OptionsConstants.MAX_EDITOR_FONT_SIZE, Math.max(OptionsConstants.MIN_EDITOR_FONT_SIZE, value)); + value = Math.min(EditorFontsConstants.getMaxEditorFontSize(), Math.max(EditorFontsConstants.getMinEditorFontSize(), value)); myEditorFontSizeField.setText(String.valueOf(value)); } catch (NumberFormatException ignored) { @@ -188,7 +188,7 @@ public class FontOptions extends JPanel implements OptionsPanel{ try { float value = Float.parseFloat(myLineSpacingField.getText()); value += (up ? 1 : -1) * .1F; - value = Math.min(OptionsConstants.MAX_EDITOR_LINE_SPACING, Math.max(OptionsConstants.MIN_EDITOR_LINE_SPACING, value)); + value = Math.min(EditorFontsConstants.getMaxEditorLineSpacing(), Math.max(EditorFontsConstants.getMinEditorLineSpacing(), value)); myLineSpacingField.setText(String.format(Locale.ENGLISH, "%.1f", value)); } catch (NumberFormatException ignored) { @@ -200,19 +200,19 @@ public class FontOptions extends JPanel implements OptionsPanel{ private int getFontSizeFromField() { try { - return Math.min(OptionsConstants.MAX_EDITOR_FONT_SIZE, - Math.max(OptionsConstants.MIN_EDITOR_FONT_SIZE, Integer.parseInt(myEditorFontSizeField.getText()))); + return Math.min(EditorFontsConstants.getMaxEditorFontSize(), + Math.max(EditorFontsConstants.getMinEditorFontSize(), Integer.parseInt(myEditorFontSizeField.getText()))); } catch (NumberFormatException e) { - return OptionsConstants.DEFAULT_EDITOR_FONT_SIZE; + return EditorFontsConstants.getDefaultEditorFontSize(); } } private float getLineSpacingFromField() { try { - return Math.min(OptionsConstants.MAX_EDITOR_LINE_SPACING, Math.max(OptionsConstants.MIN_EDITOR_LINE_SPACING, Float.parseFloat(myLineSpacingField.getText()))); + return Math.min(EditorFontsConstants.getMaxEditorLineSpacing(), Math.max(EditorFontsConstants.getMinEditorLineSpacing(), Float.parseFloat(myLineSpacingField.getText()))); } catch (NumberFormatException e){ - return OptionsConstants.DEFAULT_EDITOR_LINE_SPACING; + return EditorFontsConstants.getDefaultEditorLineSpacing(); } } diff --git a/platform/platform-impl/src/com/intellij/openapi/editor/actions/ChangeEditorFontSizeAction.java b/platform/platform-impl/src/com/intellij/openapi/editor/actions/ChangeEditorFontSizeAction.java index 9213f1a63a44..a76fa22c6cf7 100644 --- a/platform/platform-impl/src/com/intellij/openapi/editor/actions/ChangeEditorFontSizeAction.java +++ b/platform/platform-impl/src/com/intellij/openapi/editor/actions/ChangeEditorFontSizeAction.java @@ -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,7 +15,7 @@ */ package com.intellij.openapi.editor.actions; -import com.intellij.application.options.OptionsConstants; +import com.intellij.application.options.EditorFontsConstants; import com.intellij.openapi.actionSystem.AnAction; import com.intellij.openapi.actionSystem.AnActionEvent; import com.intellij.openapi.actionSystem.CommonDataKeys; @@ -41,7 +41,7 @@ public abstract class ChangeEditorFontSizeAction extends AnAction implements Dum final EditorImpl editor = getEditor(e); if (editor != null) { final int size = editor.getFontSize() + myStep; - if (size >= 8 && size <= OptionsConstants.MAX_EDITOR_FONT_SIZE) { + if (size >= 8 && size <= EditorFontsConstants.getMaxEditorFontSize()) { editor.setFontSize(size); } } diff --git a/platform/platform-impl/src/com/intellij/openapi/editor/impl/EditorImpl.java b/platform/platform-impl/src/com/intellij/openapi/editor/impl/EditorImpl.java index f9698c4342d1..a8652b4ea975 100644 --- a/platform/platform-impl/src/com/intellij/openapi/editor/impl/EditorImpl.java +++ b/platform/platform-impl/src/com/intellij/openapi/editor/impl/EditorImpl.java @@ -15,7 +15,7 @@ */ package com.intellij.openapi.editor.impl; -import com.intellij.application.options.OptionsConstants; +import com.intellij.application.options.EditorFontsConstants; import com.intellij.codeInsight.hint.DocumentFragmentTooltipRenderer; import com.intellij.codeInsight.hint.EditorFragmentComponent; import com.intellij.codeInsight.hint.TooltipController; @@ -30,7 +30,8 @@ import com.intellij.openapi.Disposable; import com.intellij.openapi.actionSystem.*; import com.intellij.openapi.actionSystem.ex.ActionManagerEx; import com.intellij.openapi.actionSystem.impl.MouseGestureManager; -import com.intellij.openapi.application.*; +import com.intellij.openapi.application.ApplicationManager; +import com.intellij.openapi.application.ModalityState; import com.intellij.openapi.command.CommandProcessor; import com.intellij.openapi.command.UndoConfirmationPolicy; import com.intellij.openapi.diagnostic.Logger; @@ -6338,7 +6339,7 @@ public final class EditorImpl extends UserDataHolderBase implements EditorEx, Hi private final Map myOwnColors = ContainerUtilRt.newHashMap(); private final EditorColorsScheme myCustomGlobalScheme; private Map myFontsMap; - private int myMaxFontSize = OptionsConstants.MAX_EDITOR_FONT_SIZE; + private int myMaxFontSize = EditorFontsConstants.getMaxEditorFontSize(); private int myFontSize = -1; private int myConsoleFontSize = -1; private String myFaceName; @@ -6510,7 +6511,7 @@ public final class EditorImpl extends UserDataHolderBase implements EditorEx, Hi public void setDelegate(@NotNull EditorColorsScheme delegate) { super.setDelegate(delegate); int globalFontSize = getDelegate().getEditorFontSize(); - myMaxFontSize = Math.max(OptionsConstants.MAX_EDITOR_FONT_SIZE, globalFontSize); + myMaxFontSize = Math.max(EditorFontsConstants.getMaxEditorFontSize(), globalFontSize); reinitFonts(); clearSettingsCache(); } From 3b1c00101ea5bd3d9a1c278168ea5db2f182bb20 Mon Sep 17 00:00:00 2001 From: Konstantin Bulenkov Date: Mon, 21 Mar 2016 15:15:45 +0100 Subject: [PATCH 65/81] fix OOM while loading incorrectly high font size --- .../openapi/editor/colors/impl/AbstractColorsScheme.java | 3 +++ 1 file changed, 3 insertions(+) diff --git a/platform/editor-ui-ex/src/com/intellij/openapi/editor/colors/impl/AbstractColorsScheme.java b/platform/editor-ui-ex/src/com/intellij/openapi/editor/colors/impl/AbstractColorsScheme.java index 18e4c995590a..6fd9f3bfc839 100644 --- a/platform/editor-ui-ex/src/com/intellij/openapi/editor/colors/impl/AbstractColorsScheme.java +++ b/platform/editor-ui-ex/src/com/intellij/openapi/editor/colors/impl/AbstractColorsScheme.java @@ -19,6 +19,7 @@ */ package com.intellij.openapi.editor.colors.impl; +import com.intellij.application.options.EditorFontsConstants; import com.intellij.ide.ui.ColorBlindness; import com.intellij.ide.ui.UISettings; import com.intellij.openapi.editor.HighlighterColors; @@ -173,6 +174,7 @@ public abstract class AbstractColorsScheme implements EditorColorsScheme { @Override public void setEditorFontSize(int fontSize) { + fontSize = EditorFontsConstants.checkAndFixEditorFontSize(fontSize); myFontPreferences.register(getEditorFontName(), fontSize); initFonts(); } @@ -707,6 +709,7 @@ public abstract class AbstractColorsScheme implements EditorColorsScheme { @Override public void setConsoleFontSize(int fontSize) { + fontSize = EditorFontsConstants.checkAndFixEditorFontSize(fontSize); myConsoleFontPreferences.register(getConsoleFontName(), fontSize); initFonts(); } From d18ea6bdd72656fe0892b98533f0190ffe46259d Mon Sep 17 00:00:00 2001 From: Dmitry Batkovich Date: Mon, 21 Mar 2016 17:51:18 +0300 Subject: [PATCH 66/81] inspection toolwindow: cosmetics from youtrack commentaries --- .../codeInspection/ui/InspectionNodeInfo.java | 4 +- .../ui/InspectionResultsView.java | 15 ++-- .../codeInspection/ui/QuickFixToolbar.java | 69 ++++--------------- 3 files changed, 26 insertions(+), 62 deletions(-) diff --git a/platform/lang-impl/src/com/intellij/codeInspection/ui/InspectionNodeInfo.java b/platform/lang-impl/src/com/intellij/codeInspection/ui/InspectionNodeInfo.java index b4b119bac81f..86932581b6c7 100644 --- a/platform/lang-impl/src/com/intellij/codeInspection/ui/InspectionNodeInfo.java +++ b/platform/lang-impl/src/com/intellij/codeInspection/ui/InspectionNodeInfo.java @@ -76,8 +76,8 @@ public class InspectionNodeInfo extends JPanel { JScrollPane pane = ScrollPaneFactory.createScrollPane(description, true); add(pane, - new GridBagConstraints(0, 1, 1, 1, 1.0, 1.0, GridBagConstraints.NORTHWEST, GridBagConstraints.BOTH, - new JBInsets(0, 10, 0, 0), 0, 0)); + new GridBagConstraints(0, 1, 1, 1, 1.0, 1.0, GridBagConstraints.NORTHWEST, GridBagConstraints.VERTICAL, + new JBInsets(0, 10, 0, 0), getFontMetrics(UIUtil.getLabelFont()).charWidth('f') * 110 - pane.getMinimumSize().width, 0)); add(myButton, new GridBagConstraints(0, 2, 1, 1, 1.0, 0.0, GridBagConstraints.NORTHWEST, GridBagConstraints.NONE, new JBInsets(15, 9, 9, 0), 0, 0)); diff --git a/platform/lang-impl/src/com/intellij/codeInspection/ui/InspectionResultsView.java b/platform/lang-impl/src/com/intellij/codeInspection/ui/InspectionResultsView.java index 11267ba53642..ccced5ca3302 100644 --- a/platform/lang-impl/src/com/intellij/codeInspection/ui/InspectionResultsView.java +++ b/platform/lang-impl/src/com/intellij/codeInspection/ui/InspectionResultsView.java @@ -40,6 +40,7 @@ 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; import com.intellij.openapi.editor.ex.EditorEx; import com.intellij.openapi.fileEditor.OpenFileDescriptor; import com.intellij.openapi.project.DumbAware; @@ -397,7 +398,7 @@ public class InspectionResultsView extends JPanel implements Disposable, Occuren mySplitter.setSecondComponent(getNothingToShowTextLabel()); } else { - showInRightPanel(myTree.getCommonSelectedElement()); + showInRightPanel(myTree.getCommonSelectedElement(), oldEditor == null); } } else { @@ -406,12 +407,12 @@ public class InspectionResultsView extends JPanel implements Disposable, Occuren final InspectionTreeNode node = (InspectionTreeNode)pathSelected.getLastPathComponent(); if (node instanceof ProblemDescriptionNode) { final ProblemDescriptionNode problemNode = (ProblemDescriptionNode)node; - showInRightPanel(problemNode.getElement()); + showInRightPanel(problemNode.getElement(), oldEditor == null); } else if (node instanceof InspectionPackageNode || node instanceof InspectionModuleNode || node instanceof RefElementNode) { - showInRightPanel(node.getContainingFileLocalEntity()); + showInRightPanel(node.getContainingFileLocalEntity(), oldEditor == null); } else if (node instanceof InspectionNode) { final String shortName = ((InspectionNode)node).getToolWrapper().getShortName(); @@ -419,7 +420,7 @@ public class InspectionResultsView extends JPanel implements Disposable, Occuren mySplitter.setSecondComponent(getNothingToShowTextLabel()); } else { - showInRightPanel(null); + showInRightPanel(null, oldEditor == null); } } else if (node instanceof InspectionRootNode || node instanceof InspectionGroupNode || node instanceof InspectionSeverityGroupNode) { @@ -453,7 +454,7 @@ public class InspectionResultsView extends JPanel implements Disposable, Occuren return multipleSelectionLabel; } - private void showInRightPanel(@Nullable final RefEntity refEntity) { + private void showInRightPanel(@Nullable final RefEntity refEntity, boolean hasNoEditorToReuse) { Cursor currentCursor = getCursor(); try { setCursor(new Cursor(Cursor.WAIT_CURSOR)); @@ -471,7 +472,7 @@ public class InspectionResultsView extends JPanel implements Disposable, Occuren } editorPanel.add(previewPanel, BorderLayout.CENTER); if (problemCount > 0) { - final QuickFixToolbar fixToolbar = new QuickFixToolbar(myPreviewEditor == null || myPreviewEditor.getUserData(PREVIEW_EDITOR_IS_REUSED_KEY) == null + final QuickFixToolbar fixToolbar = new QuickFixToolbar(myPreviewEditor == null || (!hasNoEditorToReuse && myPreviewEditor.getUserData(PREVIEW_EDITOR_IS_REUSED_KEY) == null) ? null : myPreviewEditor, this); myLoadingProgressPreview = fixToolbar; @@ -522,9 +523,11 @@ public class InspectionResultsView extends JPanel implements Disposable, Occuren settings.setLeadingWhitespaceShown(true); settings.setRightMarginShown(true); settings.setRightMargin(60); + myPreviewEditor.getColorsScheme().setColor(EditorColors.GUTTER_BACKGROUND, myPreviewEditor.getColorsScheme().getDefaultBackground()); myPreviewEditor.getScrollPane().setBorder(IdeBorderFactory.createBorder(SideBorder.TOP)); UsagePreviewPanel.highlight(Collections.emptyList(), myPreviewEditor, myProject); } + myPreviewEditor.getSettings().setFoldingOutlineShown(problemCount != 1); if (problemCount == 1) { final PsiElement finalSelectedElement = selectedElement; diff --git a/platform/lang-impl/src/com/intellij/codeInspection/ui/QuickFixToolbar.java b/platform/lang-impl/src/com/intellij/codeInspection/ui/QuickFixToolbar.java index a78fad833042..c05757c1cf4e 100644 --- a/platform/lang-impl/src/com/intellij/codeInspection/ui/QuickFixToolbar.java +++ b/platform/lang-impl/src/com/intellij/codeInspection/ui/QuickFixToolbar.java @@ -28,7 +28,6 @@ import com.intellij.openapi.project.Project; import com.intellij.openapi.util.Disposer; import com.intellij.ui.IdeBorderFactory; import com.intellij.ui.SimpleColoredComponent; -import com.intellij.util.containers.ContainerUtil; import com.intellij.util.ui.AsyncProcessIcon; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -36,8 +35,6 @@ import org.jetbrains.annotations.Nullable; import javax.swing.*; import javax.swing.tree.TreePath; import java.awt.*; -import java.util.Collections; -import java.util.List; /** * @author Dmitry Batkovich @@ -45,7 +42,6 @@ import java.util.List; public class QuickFixToolbar extends JPanel implements InspectionTreeLoadingProgressAware { private static final Logger LOG = Logger.getInstance(QuickFixToolbar.class); private static final int MAX_FIX_COUNT = 3; - @Nullable private final String myTargetName; @NotNull private final InspectionResultsView myView; private final InspectionToolWrapper myWrapper; private final ProblemPreviewEditorFoldings myFoldings; @@ -62,13 +58,12 @@ public class QuickFixToolbar extends JPanel implements InspectionTreeLoadingProg int problemCount = descriptors.length; setLayout(new FlowLayout(FlowLayout.LEFT, 0, 0)); - myTargetName = getTargetName(); if (view.isUpdating() && !areDescriptorNodesSelected()) { setBorder(IdeBorderFactory.createEmptyBorder(16, 9, 13, 0)); AsyncProcessIcon waitingIcon = new AsyncProcessIcon("Inspection preview panel updating..."); Disposer.register(this, waitingIcon); - myWaitingLabel = getLabel(null, problemCount); + myWaitingLabel = getLabel(problemCount); add(myWaitingLabel); add(waitingIcon); } @@ -98,7 +93,7 @@ public class QuickFixToolbar extends JPanel implements InspectionTreeLoadingProg if (myWaitingLabel != null) { myWaitingLabel.clear(); final InspectionTree tree = myView.getTree(); - appendTextToLabel(myWaitingLabel, tree.getSelectedProblemCount(), null); + appendTextToLabel(myWaitingLabel, tree.getSelectedProblemCount()); } } @@ -112,29 +107,20 @@ public class QuickFixToolbar extends JPanel implements InspectionTreeLoadingProg boolean multipleDescriptors = problemCount > 1; setLayout(new BoxLayout(this, BoxLayout.LINE_AXIS)); if (multipleDescriptors) { - add(getLabel(fixes, problemCount)); + add(getLabel(problemCount)); } final DefaultActionGroup actions = new DefaultActionGroup(); if (hasFixes) { actions.addAll(createFixActions(fixes, multipleDescriptors)); } - actions.add(createSuppressionCombo(myWrapper, tree.getSelectionPaths(), project, multipleDescriptors)); + actions.add(createSuppressionCombo(myWrapper, tree.getSelectionPaths(), project)); final ActionToolbar toolbar = ActionManager.getInstance().createActionToolbar(ActionPlaces.UNKNOWN, actions, true); final JComponent component = toolbar.getComponent(); toolbar.setTargetComponent(this); add(component); } - @Nullable - private String getTargetName() { - if (myView.getTree().getSelectionCount() == 1) { - final Object node = myView.getTree().getSelectionPath().getLastPathComponent(); - return node instanceof RefElementNode ? ((RefElementNode)node).getElement().getName() : null; - } - return null; - } - private boolean areDescriptorNodesSelected() { final TreePath[] paths = myView.getTree().getSelectionPaths(); for (TreePath path : paths) { @@ -146,34 +132,25 @@ public class QuickFixToolbar extends JPanel implements InspectionTreeLoadingProg } @NotNull - private SimpleColoredComponent getLabel(QuickFixAction[] fixes, int problemsCount) { + private static SimpleColoredComponent getLabel(int problemsCount) { SimpleColoredComponent label = new SimpleColoredComponent(); - appendTextToLabel(label, problemsCount, fixes); + appendTextToLabel(label, problemsCount); label.setBorder(IdeBorderFactory.createEmptyBorder(0, 0, 0, 2)); return label; } - private void appendTextToLabel(SimpleColoredComponent label, - int problemsCount, - QuickFixAction[] fixes) { - boolean hasFixesNonIntersectedFixes = fixes != null && fixes.length == 0; - label.append(problemsCount + " problems" + - (myTargetName == null ? "" : (" in " + myTargetName)) + - (problemsCount > 1 && (fixes != null && fixes.length >= MAX_FIX_COUNT) ? " Fix all:" : "") + - (!hasFixesNonIntersectedFixes ? ":" : "")); - if (hasFixesNonIntersectedFixes) { - label.append(" select a single problem to see its quick fixes"); - } + private static void appendTextToLabel(SimpleColoredComponent label, + int problemsCount) { + label.append(problemsCount + " problems:"); } private static AnAction createSuppressionCombo(@NotNull final InspectionToolWrapper toolWrapper, - @NotNull final TreePath[] paths, - @NotNull final Project project, - boolean multipleDescriptors) { + @NotNull final TreePath[] paths, + @NotNull final Project project) { final AnAction[] suppressors = new SuppressActionWrapper(project, toolWrapper, paths).getChildren(null); final ComboBoxAction action = new ComboBoxAction() { { - getTemplatePresentation().setText(multipleDescriptors ? "Suppress All" : "Suppress"); + getTemplatePresentation().setText("Suppress"); getTemplatePresentation().setEnabledAndVisible(suppressors.length != 0); } @@ -190,7 +167,7 @@ public class QuickFixToolbar extends JPanel implements InspectionTreeLoadingProg } @NotNull - private static List createFixActions(QuickFixAction[] fixes, boolean multipleDescriptors) { + private static AnAction[] createFixActions(QuickFixAction[] fixes, boolean multipleDescriptors) { if (fixes.length > MAX_FIX_COUNT) { final ComboBoxAction fixComboBox = new ComboBoxAction() { { @@ -209,24 +186,8 @@ public class QuickFixToolbar extends JPanel implements InspectionTreeLoadingProg return actionGroup; } }; - return Collections.singletonList(fixComboBox); + return new AnAction[] {fixComboBox}; } - else { - final DefaultActionGroup group = new DefaultActionGroup(); - final boolean multipleFixes = fixes.length > 1; - for (QuickFixAction fix : fixes) { - final AnAction quickFixButtonCustonPresentation = createQuickFixButton(fix, multipleDescriptors && !multipleFixes); - //group.addAll(fixes); - group.add(quickFixButtonCustonPresentation); - } - return ContainerUtil.list(fixes); - } - } - - private static AnAction createQuickFixButton(@NotNull QuickFixAction fix, boolean multipleFixes) { - if (multipleFixes) { - fix.getTemplatePresentation().setText("Fix all '" + fix.getText() + "'"); - } - return fix; + return fixes; } } From ba5149249c85989fb90ebe85a4b45c4578005214 Mon Sep 17 00:00:00 2001 From: Konstantin Bulenkov Date: Mon, 21 Mar 2016 15:55:27 +0100 Subject: [PATCH 67/81] fix typos --- .../intellij/application/options/EditorFontsConstants.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/platform/editor-ui-ex/src/com/intellij/application/options/EditorFontsConstants.java b/platform/editor-ui-ex/src/com/intellij/application/options/EditorFontsConstants.java index 2b5087caf046..c1dda7b50924 100644 --- a/platform/editor-ui-ex/src/com/intellij/application/options/EditorFontsConstants.java +++ b/platform/editor-ui-ex/src/com/intellij/application/options/EditorFontsConstants.java @@ -37,8 +37,8 @@ public class EditorFontsConstants { return round(getMinEditorFontSize(), getMaxEditorFontSize(), size); } - public static int checkAndFixEditorLineSpacing(int size) { - return round(getMinEditorFontSize(), getMaxEditorFontSize(), size); + public static float checkAndFixEditorLineSpacing(int size) { + return round(getMinEditorLineSpacing(), getMaxEditorLineSpacing(), size); } private static int round(int min, int max, int val) { From c932c993e5cd945986e84a3be3a1d38f4271dbe2 Mon Sep 17 00:00:00 2001 From: "Gregory.Shrago" Date: Mon, 21 Mar 2016 17:55:09 +0300 Subject: [PATCH 68/81] IDEA-126952 Scratches should have an extension --- .../intellij/ide/scratch/LRUPopupBuilder.java | 75 +++++++++++++++++-- .../ide/scratch/ScratchFileActions.java | 6 +- .../com/intellij/ide/scratch/ScratchUtil.java | 41 ++++++++++ 3 files changed, 113 insertions(+), 9 deletions(-) diff --git a/platform/lang-impl/src/com/intellij/ide/scratch/LRUPopupBuilder.java b/platform/lang-impl/src/com/intellij/ide/scratch/LRUPopupBuilder.java index 77601cc4b877..6a15f3c5b5b8 100644 --- a/platform/lang-impl/src/com/intellij/ide/scratch/LRUPopupBuilder.java +++ b/platform/lang-impl/src/com/intellij/ide/scratch/LRUPopupBuilder.java @@ -19,12 +19,19 @@ import com.intellij.ide.util.PropertiesComponent; import com.intellij.lang.Language; import com.intellij.lang.LanguageUtil; import com.intellij.lang.PerFileMappings; +import com.intellij.openapi.application.Result; +import com.intellij.openapi.command.WriteCommandAction; +import com.intellij.openapi.command.undo.BasicUndoableAction; +import com.intellij.openapi.command.undo.UndoManager; +import com.intellij.openapi.command.undo.UnexpectedUndoException; import com.intellij.openapi.fileTypes.LanguageFileType; import com.intellij.openapi.project.Project; import com.intellij.openapi.ui.popup.*; import com.intellij.openapi.ui.popup.util.BaseListPopupStep; import com.intellij.openapi.util.Pair; import com.intellij.openapi.util.text.StringUtil; +import com.intellij.openapi.vfs.ReadonlyStatusHandler; +import com.intellij.openapi.vfs.VfsUtilCore; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.util.ArrayUtil; import com.intellij.util.Consumer; @@ -38,10 +45,9 @@ import org.jetbrains.annotations.Nullable; import javax.swing.*; import java.awt.*; -import java.util.Collections; -import java.util.Comparator; +import java.io.IOException; +import java.util.*; import java.util.List; -import java.util.Map; /** * @author gregsh @@ -62,13 +68,23 @@ public abstract class LRUPopupBuilder { private JBIterable myExtraItems = JBIterable.empty(); @NotNull - public static ListPopup forFileLanguages(@NotNull Project project, @NotNull final Iterable files, @NotNull final PerFileMappings mappings) { + public static ListPopup forFileLanguages(@NotNull Project project, @NotNull Iterable files, @NotNull final PerFileMappings mappings) { + final VirtualFile[] filesCopy = VfsUtilCore.toVirtualFileArray(JBIterable.from(files).toList()); + Arrays.sort(filesCopy, new Comparator() { + @Override + public int compare(VirtualFile o1, VirtualFile o2) { + return StringUtil.compare(o1.getName(), o2.getName(), !o1.getFileSystem().isCaseSensitive()); + } + }); return forFileLanguages(project, null, new Consumer() { @Override - public void consume(Language t) { - for (VirtualFile file : files) { - mappings.setMapping(file, t); - } + public void consume(final Language t) { + new WriteCommandAction(project, "Change Language") { + @Override + protected void run(@NotNull Result result) throws Throwable { + changeLanguageWithUndo(project, t, filesCopy, mappings); + } + }.execute(); } }); } @@ -260,4 +276,47 @@ public abstract class LRUPopupBuilder { return getClass().getName() + "/" + myTitle; } + + private static void changeLanguageWithUndo(@NotNull Project project, + @NotNull final Language t, + @NotNull final VirtualFile[] sortedFiles, + @NotNull final PerFileMappings mappings) throws UnexpectedUndoException { + ReadonlyStatusHandler.OperationStatus status = ReadonlyStatusHandler.getInstance(project).ensureFilesWritable(sortedFiles); + if (status.hasReadonlyFiles()) return; + + final Set matchedExtensions = ContainerUtil.newLinkedHashSet(); + final Map oldMapping = ContainerUtil.newHashMap(); + for (VirtualFile file : sortedFiles) { + oldMapping.put(file, mappings.getMapping(file)); + if (ScratchUtil.hasMatchingExtension(project, file)) { + matchedExtensions.add(file); + } + } + + BasicUndoableAction action = new BasicUndoableAction(sortedFiles) { + @Override + public void undo() throws UnexpectedUndoException { + for (VirtualFile file : sortedFiles) { + mappings.setMapping(file, oldMapping.get(file)); + } + } + + @Override + public void redo() throws UnexpectedUndoException { + for (VirtualFile file : sortedFiles) { + mappings.setMapping(file, t); + } + } + }; + action.redo(); + UndoManager.getInstance(project).undoableActionPerformed(action); + + for (VirtualFile file : matchedExtensions) { + try { + ScratchUtil.updateFileExtension(project, file); + } + catch (IOException ignored) { + } + } + } } diff --git a/platform/lang-impl/src/com/intellij/ide/scratch/ScratchFileActions.java b/platform/lang-impl/src/com/intellij/ide/scratch/ScratchFileActions.java index 80aa2bb61178..3e5edb681115 100644 --- a/platform/lang-impl/src/com/intellij/ide/scratch/ScratchFileActions.java +++ b/platform/lang-impl/src/com/intellij/ide/scratch/ScratchFileActions.java @@ -26,6 +26,7 @@ import com.intellij.openapi.actionSystem.CommonDataKeys; import com.intellij.openapi.editor.Caret; import com.intellij.openapi.editor.Editor; import com.intellij.openapi.fileEditor.FileEditorManager; +import com.intellij.openapi.fileTypes.LanguageFileType; import com.intellij.openapi.project.DumbAwareAction; import com.intellij.openapi.project.Project; import com.intellij.openapi.util.Condition; @@ -37,6 +38,7 @@ import com.intellij.psi.PsiFile; import com.intellij.util.Consumer; import com.intellij.util.Function; import com.intellij.util.ObjectUtils; +import com.intellij.util.PathUtil; import com.intellij.util.containers.ContainerUtil; import com.intellij.util.containers.JBIterable; import org.jetbrains.annotations.NotNull; @@ -111,9 +113,11 @@ public class ScratchFileActions { static void doCreateNewScratch(@NotNull Project project, boolean buffer, @NotNull Language language, @NotNull String text) { FeatureUsageTracker.getInstance().triggerFeatureUsed("scratch"); + LanguageFileType fileType = language.getAssociatedFileType(); + String ext = buffer || fileType == null? "" : fileType.getDefaultExtension(); String fileName = buffer ? "buffer" + nextBufferIndex() : "scratch"; ScratchFileService.Option option = buffer ? ScratchFileService.Option.create_if_missing : ScratchFileService.Option.create_new_always; - VirtualFile f = ScratchRootType.getInstance().createScratchFile(project, fileName, language, text, option); + VirtualFile f = ScratchRootType.getInstance().createScratchFile(project, PathUtil.makeFileName(fileName, ext), language, text, option); if (f != null) { FileEditorManager.getInstance(project).openFile(f, true); } diff --git a/platform/lang-impl/src/com/intellij/ide/scratch/ScratchUtil.java b/platform/lang-impl/src/com/intellij/ide/scratch/ScratchUtil.java index 124e220ecb9c..5e60577fb799 100644 --- a/platform/lang-impl/src/com/intellij/ide/scratch/ScratchUtil.java +++ b/platform/lang-impl/src/com/intellij/ide/scratch/ScratchUtil.java @@ -15,9 +15,21 @@ */ package com.intellij.ide.scratch; +import com.intellij.lang.Language; +import com.intellij.lang.LanguageUtil; +import com.intellij.openapi.application.ApplicationManager; +import com.intellij.openapi.command.CommandProcessor; +import com.intellij.openapi.fileTypes.FileType; +import com.intellij.openapi.fileTypes.FileTypeManager; +import com.intellij.openapi.project.Project; +import com.intellij.openapi.util.text.StringUtil; import com.intellij.openapi.vfs.VirtualFile; +import com.intellij.util.PathUtil; +import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; +import java.io.IOException; + /** * @author gregsh */ @@ -33,4 +45,33 @@ public class ScratchUtil { public static boolean isScratch(@Nullable VirtualFile file) { return file != null && file.getFileType() == ScratchFileType.INSTANCE; } + + public static void updateFileExtension(@NotNull Project project, @Nullable VirtualFile file) throws IOException { + ApplicationManager.getApplication().assertWriteAccessAllowed(); + if (CommandProcessor.getInstance().getCurrentCommand() == null) { + throw new AssertionError("command required"); + } + + if (file == null) return; + Language language = LanguageUtil.getLanguageForPsi(project, file); + String extension = file.getExtension(); + FileType expected = extension == null ? null : FileTypeManager.getInstance().getFileTypeByExtension(extension); + FileType actual = language == null ? null : language.getAssociatedFileType(); + if (expected == actual || actual == null) return; + String ext = actual.getDefaultExtension(); + if (StringUtil.isEmpty(ext)) return; + + String newName = PathUtil.makeFileName(file.getNameWithoutExtension(), ext); + VirtualFile parent = file.getParent(); + newName = parent != null && parent.findChild(newName) != null ? PathUtil.makeFileName(file.getName(), ext) : newName; + file.rename(ScratchUtil.class, newName); + } + + public static boolean hasMatchingExtension(@NotNull Project project, @NotNull VirtualFile file) { + String extension = file.getExtension(); + Language language = LanguageUtil.getLanguageForPsi(project, file); + FileType expected = extension == null ? null : FileTypeManager.getInstance().getFileTypeByExtension(extension); + FileType actual = language == null ? null : language.getAssociatedFileType(); + return expected == actual && actual != null; + } } From 116bb6e247b9d163f59537727bfd058fa314feea Mon Sep 17 00:00:00 2001 From: Aleksey Pivovarov Date: Mon, 21 Mar 2016 17:39:36 +0300 Subject: [PATCH 69/81] IDEA-153246 diff: clarify notification message in case of equal contents --- .../tools/fragmented/UnifiedDiffViewer.java | 6 +++- .../diff/tools/simple/SimpleDiffViewer.java | 8 ++++- .../diff/tools/util/DiffNotifications.java | 14 ++++++++ .../tools/util/base/TextDiffViewerUtil.java | 21 +++++++++++ .../src/com/intellij/diff/util/DiffUtil.java | 36 +++---------------- .../src/messages/DiffBundle.properties | 2 ++ 6 files changed, 54 insertions(+), 33 deletions(-) diff --git a/platform/diff-impl/src/com/intellij/diff/tools/fragmented/UnifiedDiffViewer.java b/platform/diff-impl/src/com/intellij/diff/tools/fragmented/UnifiedDiffViewer.java index fccd126640ad..bc69178dc9ab 100644 --- a/platform/diff-impl/src/com/intellij/diff/tools/fragmented/UnifiedDiffViewer.java +++ b/platform/diff-impl/src/com/intellij/diff/tools/fragmented/UnifiedDiffViewer.java @@ -385,7 +385,11 @@ public class UnifiedDiffViewer extends ListenerDiffViewerBase { myFoldingModel.updateContext(myRequest, getFoldingModelSettings()); clearDiffPresentation(); - if (isContentsEqual) myPanel.addNotification(DiffNotifications.createEqualContents()); + if (isContentsEqual) { + boolean equalCharsets = TextDiffViewerUtil.areEqualCharsets(getContents()); + boolean equalSeparators = TextDiffViewerUtil.areEqualLineSeparators(getContents()); + myPanel.addNotification(DiffNotifications.createEqualContents(equalCharsets, equalSeparators)); + } TIntFunction separatorLines = myFoldingModel.getLineNumberConvertor(); myEditor.getGutterComponentEx().setLineNumberConvertor(mergeConverters(data.getLineConvertor1(), separatorLines), diff --git a/platform/diff-impl/src/com/intellij/diff/tools/simple/SimpleDiffViewer.java b/platform/diff-impl/src/com/intellij/diff/tools/simple/SimpleDiffViewer.java index f3fcf63c4237..f1ffaaafb92c 100644 --- a/platform/diff-impl/src/com/intellij/diff/tools/simple/SimpleDiffViewer.java +++ b/platform/diff-impl/src/com/intellij/diff/tools/simple/SimpleDiffViewer.java @@ -19,6 +19,7 @@ import com.intellij.diff.DiffContext; import com.intellij.diff.actions.BufferedLineIterator; import com.intellij.diff.actions.NavigationContextChecker; import com.intellij.diff.comparison.DiffTooBigException; +import com.intellij.diff.contents.DocumentContent; import com.intellij.diff.fragments.LineFragment; import com.intellij.diff.requests.ContentDiffRequest; import com.intellij.diff.requests.DiffRequest; @@ -52,6 +53,7 @@ import org.jetbrains.annotations.*; import javax.swing.*; import java.awt.*; +import java.nio.charset.Charset; import java.util.ArrayList; import java.util.BitSet; import java.util.Iterator; @@ -237,7 +239,11 @@ public class SimpleDiffViewer extends TwosideTextDiffViewer { clearDiffPresentation(); myIsContentsEqual = data.isContentsEqual(); - if (data.isContentsEqual()) myPanel.addNotification(DiffNotifications.createEqualContents()); + if (data.isContentsEqual()) { + boolean equalCharsets = TextDiffViewerUtil.areEqualCharsets(getContents()); + boolean equalSeparators = TextDiffViewerUtil.areEqualLineSeparators(getContents()); + myPanel.addNotification(DiffNotifications.createEqualContents(equalCharsets, equalSeparators)); + } if (data.getFragments() != null) { for (LineFragment fragment : data.getFragments()) { diff --git a/platform/diff-impl/src/com/intellij/diff/tools/util/DiffNotifications.java b/platform/diff-impl/src/com/intellij/diff/tools/util/DiffNotifications.java index 7681a2c5bae9..6c0fa383b977 100644 --- a/platform/diff-impl/src/com/intellij/diff/tools/util/DiffNotifications.java +++ b/platform/diff-impl/src/com/intellij/diff/tools/util/DiffNotifications.java @@ -45,6 +45,20 @@ public class DiffNotifications { @NotNull public static JPanel createEqualContents() { + return createEqualContents(true, true); + } + + @NotNull + public static JPanel createEqualContents(boolean equalCharsets, boolean equalSeparators) { + if (!equalCharsets && !equalSeparators) { + return createNotification(DiffBundle.message("diff.contents.have.differences.only.in.charset.and.line.separators.message.text")); + } + if (!equalSeparators) { + return createNotification(DiffBundle.message("diff.contents.have.differences.only.in.line.separators.message.text")); + } + if (!equalCharsets) { + return createNotification(DiffBundle.message("diff.contents.have.differences.only.in.charset.message.text")); + } return createNotification(DiffBundle.message("diff.contents.are.identical.message.text")); } diff --git a/platform/diff-impl/src/com/intellij/diff/tools/util/base/TextDiffViewerUtil.java b/platform/diff-impl/src/com/intellij/diff/tools/util/base/TextDiffViewerUtil.java index f0be1ed3a70a..acb6f14a902e 100644 --- a/platform/diff-impl/src/com/intellij/diff/tools/util/base/TextDiffViewerUtil.java +++ b/platform/diff-impl/src/com/intellij/diff/tools/util/base/TextDiffViewerUtil.java @@ -18,6 +18,7 @@ package com.intellij.diff.tools.util.base; import com.intellij.diff.DiffContext; import com.intellij.diff.contents.DiffContent; import com.intellij.diff.contents.DocumentContent; +import com.intellij.diff.contents.EmptyContent; import com.intellij.diff.requests.ContentDiffRequest; import com.intellij.diff.tools.util.FoldingModelSupport; import com.intellij.diff.tools.util.base.TextDiffSettingsHolder.TextDiffSettings; @@ -38,6 +39,7 @@ import com.intellij.openapi.util.Condition; import com.intellij.openapi.util.Key; import com.intellij.ui.ToggleActionButton; import com.intellij.util.EditorPopupHandler; +import com.intellij.util.Function; import com.intellij.util.containers.ContainerUtil; import org.jetbrains.annotations.NotNull; @@ -127,6 +129,25 @@ public class TextDiffViewerUtil { } } + public static boolean areEqualLineSeparators(@NotNull List contents) { + return areEqualDocumentContentProperties(contents, DocumentContent::getLineSeparator); + } + + public static boolean areEqualCharsets(@NotNull List contents) { + return areEqualDocumentContentProperties(contents, DocumentContent::getCharset); + } + + private static boolean areEqualDocumentContentProperties(@NotNull List contents, + @NotNull Function propertyGetter) { + List properties = ContainerUtil.mapNotNull(contents, (content) -> { + if (content instanceof EmptyContent) return null; + return propertyGetter.fun((DocumentContent)content); + }); + + if (properties.size() < 2) return true; + return ContainerUtil.newHashSet(properties).size() == 1; + } + // // Actions // diff --git a/platform/diff-impl/src/com/intellij/diff/util/DiffUtil.java b/platform/diff-impl/src/com/intellij/diff/util/DiffUtil.java index fbd81919c2e6..d93881d78e88 100644 --- a/platform/diff-impl/src/com/intellij/diff/util/DiffUtil.java +++ b/platform/diff-impl/src/com/intellij/diff/util/DiffUtil.java @@ -36,6 +36,7 @@ import com.intellij.diff.requests.ContentDiffRequest; import com.intellij.diff.requests.DiffRequest; import com.intellij.diff.tools.util.base.HighlightPolicy; import com.intellij.diff.tools.util.base.IgnorePolicy; +import com.intellij.diff.tools.util.base.TextDiffViewerUtil; import com.intellij.icons.AllIcons; import com.intellij.lang.Language; import com.intellij.openapi.actionSystem.AnAction; @@ -98,6 +99,8 @@ import java.util.BitSet; import java.util.Collections; import java.util.List; +import static com.intellij.diff.tools.util.base.TextDiffViewerUtil.areEqualLineSeparators; + public class DiffUtil { private static final Logger LOG = Logger.getInstance(DiffUtil.class); @@ -376,23 +379,8 @@ public class DiffUtil { List contents = request.getContents(); List titles = request.getContentTitles(); - List charsets = ContainerUtil.map(contents, new Function() { - @Override - public Charset fun(DiffContent content) { - if (content instanceof EmptyContent) return null; - return ((DocumentContent)content).getCharset(); - } - }); - List separators = ContainerUtil.map(contents, new Function() { - @Override - public LineSeparator fun(DiffContent content) { - if (content instanceof EmptyContent) return null; - return ((DocumentContent)content).getLineSeparator(); - } - }); - - boolean equalCharsets = isEqualElements(charsets); - boolean equalSeparators = isEqualElements(separators); + boolean equalCharsets = TextDiffViewerUtil.areEqualCharsets(contents); + boolean equalSeparators = TextDiffViewerUtil.areEqualLineSeparators(contents); List result = new ArrayList(contents.size()); @@ -421,20 +409,6 @@ public class DiffUtil { return createStackedComponents(components, TITLE_GAP); } - private static boolean isEqualElements(@NotNull List elements) { - for (int i = 0; i < elements.size(); i++) { - for (int j = i + 1; j < elements.size(); j++) { - if (!isEqualElements(elements.get(i), elements.get(j))) return false; - } - } - return true; - } - - private static boolean isEqualElements(@Nullable Object element1, @Nullable Object element2) { - if (element1 == null || element2 == null) return true; - return element1.equals(element2); - } - @Nullable private static JComponent createTitle(@NotNull String title, @NotNull DiffContent content, diff --git a/platform/platform-resources-en/src/messages/DiffBundle.properties b/platform/platform-resources-en/src/messages/DiffBundle.properties index 21c7b42012cd..6a872087a243 100644 --- a/platform/platform-resources-en/src/messages/DiffBundle.properties +++ b/platform/platform-resources-en/src/messages/DiffBundle.properties @@ -57,6 +57,8 @@ select.external.diff.program.dialog.title=Select External Diff Program select.external.merge.program.dialog.title=Select External Merge Program diff.contents.are.identical.message.text=Contents are identical diff.contents.have.differences.only.in.line.separators.message.text=Contents have differences only in line separators +diff.contents.have.differences.only.in.charset.message.text=Contents have differences only in encoding +diff.contents.have.differences.only.in.charset.and.line.separators.message.text=Contents have differences only in line separators and encoding diff.contents.have.differences.only.in.line.separators.or.whitespaces=Contents have differences only in line separators or whitespaces show.diff.anyway.dialog.message=Show diff anyway? no.differences.dialog.title=No Differences From f8899bc0949e11c776aa6e21411f8fa50782b89d Mon Sep 17 00:00:00 2001 From: Aleksey Pivovarov Date: Mon, 21 Mar 2016 17:42:54 +0300 Subject: [PATCH 70/81] diff: remove deprecated code --- .../com/intellij/diff/tools/util/DiffNotifications.java | 7 ------- 1 file changed, 7 deletions(-) diff --git a/platform/diff-impl/src/com/intellij/diff/tools/util/DiffNotifications.java b/platform/diff-impl/src/com/intellij/diff/tools/util/DiffNotifications.java index 6c0fa383b977..8421fdce6a9d 100644 --- a/platform/diff-impl/src/com/intellij/diff/tools/util/DiffNotifications.java +++ b/platform/diff-impl/src/com/intellij/diff/tools/util/DiffNotifications.java @@ -26,13 +26,6 @@ import javax.swing.*; import java.awt.*; public class DiffNotifications { - @Deprecated @NotNull public static final JPanel INSERTED_CONTENT = createInsertedContent(); - @Deprecated @NotNull public static final JPanel REMOVED_CONTENT = createRemovedContent(); - @Deprecated @NotNull public static final JPanel EQUAL_CONTENTS = createEqualContents(); - @Deprecated @NotNull public static final JPanel ERROR = createError(); - @Deprecated @NotNull public static final JPanel OPERATION_CANCELED = createOperationCanceled(); - @Deprecated @NotNull public static final JPanel DIFF_TOO_BIG = createDiffTooBig(); - @NotNull public static JPanel createInsertedContent() { return createNotification("Content added", TextDiffType.INSERTED.getColor(null)); From 09ec6ac1535c2599c95507e5881a909a063a92f2 Mon Sep 17 00:00:00 2001 From: Dennis Ushakov Date: Mon, 21 Mar 2016 18:09:51 +0300 Subject: [PATCH 71/81] more url fixes --- build/scripts/libLicenses.gant | 56 +++++++++++++++++----------------- 1 file changed, 28 insertions(+), 28 deletions(-) diff --git a/build/scripts/libLicenses.gant b/build/scripts/libLicenses.gant index 051209e96c8d..7bda2f3f0d1b 100644 --- a/build/scripts/libLicenses.gant +++ b/build/scripts/libLicenses.gant @@ -149,8 +149,8 @@ binding.setVariable("generateLicensesTable", {String filePath, Set usedM notifyArtifactBuilt(filePath) }) -libraryLicense(name: "aether-api-0.9.0.M2.jar", version: "0.9.0.M2", libraryNames: ["aether-api-0.9.0.M2.jar"], license: "Eclipse Public License v1.0", url: "http://nexus.sonatype.org/", licenseUrl: "http://www.eclipse.org/org/documents/epl-v10.html") -libraryLicense(name: "aether-api", version: "1.13.1", libraryNames: ["aether-api-1.13.1.jar"], license: "Apache 2.0", url: "http://maven.apache.org/", licenseUrl: "http://maven.apache.org/license.html") +libraryLicense(name: "aether-api-0.9.0.M2.jar", version: "0.9.0.M2", libraryNames: ["aether-api-0.9.0.M2.jar"], license: "Eclipse Public License v1.0", url: "http://www.eclipse.org/aether/", licenseUrl: "http://www.eclipse.org/org/documents/epl-v10.html") +libraryLicense(name: "aether-api", version: "1.13.1", libraryNames: ["aether-api-1.13.1.jar"], license: "Apache 2.0", url: "http://maven.apache.org/", licenseUrl: "http://www.apache.org/licenses/LICENSE-2.0") libraryLicense(name: "Alloy L&F", libraryName: "alloy.jar", version: "1.4.4", license: "link (company license)", url: "http://lookandfeel.incors.com/", licenseUrl: "http://lookandfeel.incors.com/display_licence.php?back=purchase.php&selMenu=Purchase") libraryLicense(name: "Android Builder Model", libraryName: "builder-model", license: "Apache 2.0", url: "http://source.android.com/") libraryLicense(name: "Android Builder", libraryName: "android-builder", license: "Apache 2.0", url: "http://source.android.com/") @@ -161,9 +161,9 @@ libraryLicense(name: "Ant", version: "1.9", license: "Apache 2.0", url: "http:// libraryLicense(name: "ANTLR 4 Runtime", libraryName: "antlr-runtime-4.1.jar", version: "4.1", license: "BSD", url: "http://www.antlr.org", licenseUrl: "http://www.antlr.org/license.html") libraryLicense(name: "Antlr", libraryName: "antlr.jar", version: "3.4", license: "BSD", url: "http://www.antlr.org", licenseUrl: "http://www.antlr.org/license.html") libraryLicense(name: "Apache Commons BeanUtils", libraryName: "commons-beanutils.jar", version: "1.6", license: "Apache 2.0", url: "http://commons.apache.org/beanutils/") -libraryLicense(name: "Apache Commons Codec", libraryName: "commons-codec", version: "1.8", license: "Apache 2.0", url: "http://commons.apache.org/codec/", licenseUrl: "http://commons.apache.org/license.html") +libraryLicense(name: "Apache Commons Codec", libraryName: "commons-codec", version: "1.8", license: "Apache 2.0", url: "http://commons.apache.org/codec/", licenseUrl: "http://www.apache.org/licenses/") libraryLicense(name: "Apache Commons Compress", libraryName: "commons-compress-android", version: "1.0", license: "Apache 2.0", url: "http://commons.apache.org/proper/commons-compress/", licenseUrl: "http://www.apache.org/licenses/LICENSE-2.0") -libraryLicense(name: "Apache Commons Discovery", libraryName: "commons-discovery-0.4.jar", version: "0.4", license: "Apache 2.0", url: "http://jakarta.apache.org/commons/discovery/", licenseUrl: "http://commons.apache.org/license.html") +libraryLicense(name: "Apache Commons Discovery", libraryName: "commons-discovery-0.4.jar", version: "0.4", license: "Apache 2.0", url: "http://jakarta.apache.org/commons/discovery/", licenseUrl: "http://www.apache.org/licenses/") libraryLicense(name: "Apache Commons HTTPClient", libraryName: "http-client-3.1", version: "3.1  (with patch by JetBrains)", license: "Apache 2.0", url: "http://hc.apache.org/httpclient-3.x") libraryLicense(name: "Apache Commons IO", libraryName: "commons-io-1.4.jar", version: "1.4", license: "Apache 2.0", url: "http://commons.apache.org/io/", licenseUrl: "http://www.apache.org/licenses/LICENSE-2.0.txt") libraryLicense(name: "Apache Commons Logging", libraryName: "commons-logging", version: "1.1.1", license: "Apache 2.0", url: "http://commons.apache.org/logging/") @@ -178,15 +178,15 @@ libraryLicense(name: "ASM Bytecode Manipulation Framework", libraryName: "asm4", libraryLicense(name: "ASM Bytecode Manipulation Framework", libraryName: "asm5", version: "5.0.3 (with patches by JetBrains)", license: "BSD", url: "http://asm.objectweb.org/", licenseUrl: "http://asm.objectweb.org/license.html") libraryLicense(name: "assertJ", version: "3", license: "Apache 2.0", url: "https://github.com/joel-costigliola/assertj-core") libraryLicense(name: "Automaton", libraryName: "automaton.jar", version: "1.11", license: "BSD", url: "http://www.brics.dk/automaton/", licenseUrl: "http://www.opensource.org/licenses/bsd-license.php") -libraryLicense(name: "Axis", libraryName: "axis-1.4", version: "1.4", license: "Apache 2.0", url: "http://ws.apache.org/axis/", licenseUrl: "http://svn.jetbrains.org/idea/Trunk/bundled/WebServices/resources/lib/axis-1.4.0/axis.LICENSE") +libraryLicense(name: "Axis", libraryName: "axis-1.4", version: "1.4", license: "Apache 2.0", url: "http://ws.apache.org/axis/", licenseUrl: "http://www.apache.org/licenses/LICENSE-2.0.html") libraryLicense(name: "bouncy-castle", version: "1.48", license: "MIT License", url: "http://bouncycastle.org", licenseUrl: "http://bouncycastle.org/licence.html") libraryLicense(name: "CGLib", libraryName: "CGLIB", version: "2.2.2", license: "Apache", url: "http://cglib.sourceforge.net/", licenseUrl: "http://www.apache.org/foundation/licence-FAQ.html") -libraryLicense(name: "classworlds", libraryName: "classworlds-1.1.jar", version: "1.1", license: "codehaus", url: "http://classworlds.codehaus.org/", licenseUrl: "http://classworlds.codehaus.org/license.html") +libraryLicense(name: "classworlds", libraryName: "classworlds-1.1.jar", version: "1.1", license: "codehaus", url: "https://github.com/codehaus/classworlds", licenseUrl: "https://github.com/codehaus/classworlds/blob/master/classworlds/LICENSE.txt") libraryLicense(name: "coverage.py", attachedTo: "python-helpers", version: "3.7.1", license: "Apache 2.0", url: "http://coverage.readthedocs.org/") libraryLicense(name: "Cucumber-Core", libraryName: "cucumber-core", version: "1.2.4", license: "MIT License", url: "https://github.com/cucumber/cucumber-jvm/", licenseUrl: "http://www.opensource.org/licenses/mit-license.html") libraryLicense(name: "Cucumber-Groovy", libraryName: "cucumber-groovy", version: "1.2.4", license: "MIT License", url: "https://github.com/cucumber/cucumber-jvm/", licenseUrl: "http://www.opensource.org/licenses/mit-license.html") libraryLicense(name: "Cucumber-Java", libraryName: "cucumber-java", version: "1.2.4", license: "MIT License", url: "https://github.com/cucumber/cucumber-jvm/", licenseUrl: "http://www.opensource.org/licenses/mit-license.html") -libraryLicense(name: "Diffutils", libraryName: "Diffutils", version: "1.2.1", license: "The Apache Software License, Version 2.0", url: "http://www.apache.org/licenses/LICENSE-2.0", licenseUrl: "http://xstream.codehaus.org/license.html") +libraryLicense(name: "Diffutils", libraryName: "Diffutils", version: "1.2.1", license: "The Apache Software License, Version 2.0", url: "https://code.google.com/archive/p/java-diff-utils/", licenseUrl: "http://www.apache.org/licenses/LICENSE-2.0") libraryLicense(name: "docutils", attachedTo: "python-helpers", version: "0.8", license: "BSD", url: "http://docutils.sourceforge.net/") libraryLicense(name: "DTDParser", version: "1.13", license: "LGPL", url: "http://sourceforge.net/projects/dtdparser/", licenseUrl: "http://www.opensource.org/licenses/lgpl-2.1") libraryLicense(name: "Eclipse JDT Core", libraryName: "Eclipse", version: "4.2.1", license: "CPL 1.0", url: "http://www.eclipse.org/jdt/core/index.php") @@ -196,7 +196,7 @@ libraryLicense(name: "Fest", libraryName: "fest", version: "", license: "Apache libraryLicense(name: "FreeMarker", attachedTo: "coverage", version: "2.3.15", license: "BSD", url: "http://freemarker.sourceforge.net/") libraryLicense(name: "FreeMarker", libraryName: "freemarker-2.3.20", version: "2.3.20", license: "BSD", url: "http://freemarker.sourceforge.net/") libraryLicense(name: "fxg-utils", libraryName: "fxg-utils", version: "4.9.1", license: "Apache 2.0", url: "http://flex.apache.org", licenseUrl: "http://www.apache.org/licenses/LICENSE-2.0") -libraryLicense(name: "Gant", version: "1.9.8", libraryName: "gant-1.9.11_groovy-2.3.0.jar", license: "Apache 2.0", url: "http://gant.codehaus.org/", licenseUrl: "http://gant.codehaus.org/Licence") +libraryLicense(name: "Gant", version: "1.9.8", libraryName: "gant-1.9.11_groovy-2.3.0.jar", license: "Apache 2.0", url: "https://github.com/codehaus/gant", licenseUrl: "https://github.com/codehaus/gant/blob/master/LICENCE.txt") libraryLicense(name: "Gherkin", libraryName: "Gherkin", version: "2.12.2", license: "MIT", licenseUrl: "http://www.apache.org/licenses/LICENSE-2.0.txt", url: "https://github.com/cucumber/gherkin") libraryLicense(name: "Google Feedback", libraryName: "GoogleFeedback.jar", version: "", license: "TBD") libraryLicense(name: "gradle-tooling-api-2.9.jar", version: "2.9", license: "Apache 2.0", url: "http://gradle.org/", licenseUrl: "http://gradle.org/license") @@ -210,7 +210,7 @@ libraryLicense(name: "Guava", version: "17.0", license: "Apache 2.0", url: "http libraryLicense(name: "hamcrest", version: "1.3", license: "BSD", url: "http://hamcrest.org/", licenseUrl: "http://opensource.org/licenses/BSD-3-Clause") libraryLicense(name: "HttpComponents HttpClient", libraryName: "http-client", version: "4.3.2", license: "Apache 2.0", url: "http://hc.apache.org/httpcomponents-client-ga/index.html") libraryLicense(name: "imgscalr", libraryName: "imgscalr", version: "4.2", license: "Apache 2.0", licenseUrl: "http://www.apache.org/licenses/LICENSE-2.0.txt", url: "https://github.com/thebuzzmedia/imgscalr") -libraryLicense(name: "batik", libraryName: "batik", version: "1.7.1", license: "Apache 2.0", licenseUrl: "http://www.apache.org/licenses/LICENSE-2.0.txt", url: "https://svn.apache.org/repos/asf/xmlgraphics/batik") +libraryLicense(name: "batik", libraryName: "batik", version: "1.7.1", license: "Apache 2.0", licenseUrl: "http://www.apache.org/licenses/LICENSE-2.0.txt", url: "https://xmlgraphics.apache.org/batik/") libraryLicense(name: "xmlgraphics-commons", libraryName: "xmlgraphics-commons", version: "1.5", license: "Apache 2.0", licenseUrl: "http://www.apache.org/licenses/LICENSE-2.0.txt", url: "https://xmlgraphics.apache.org/commons/") libraryLicense(name: "xml-apis-ext", libraryName: "xml-apis-ext", version: "1.3", license: "Apache 2.0", licenseUrl: "http://www.apache.org/licenses/LICENSE-2.0.txt", url: "http://xerces.apache.org/xml-commons/components/external") libraryLicense(name: "ImageIO", libraryName: "com.twelvemonkeys.imageio:imageio-tiff:3.2.1", version: "3.2.1", license: "BSD", url: "https://github.com/haraldk/TwelveMonkeys", licenseUrl: "https://github.com/haraldk/TwelveMonkeys#license") @@ -218,7 +218,7 @@ libraryLicense(name: "ini4j", libraryName: "ini4j-0.5.2-patched", version: "0.5. libraryLicense(name: "ISO RELAX", libraryName: "isorelax.jar", license: "MIT License", url: "http://sourceforge.net/projects/iso-relax/", licenseUrl: "http://www.opensource.org/licenses/mit-license.html") libraryLicense(name: "Jakarta ORO", libraryName: "OroMatcher", version: "2.0.8", license: "Apache", url: "http://jakarta.apache.org/oro/", licenseUrl: "http://svn.apache.org/repos/asf/jakarta/oro/trunk/LICENSE") libraryLicense(name: "Java-WebSocket", libraryName: "java_websocket.jar", version: "1.4.0 Trunk", license: "MIT", url: "https://github.com/TooTallNate/Java-WebSocket", licenseUrl:"https://github.com/TooTallNate/Java-WebSocket/blob/master/LICENSE") -libraryLicense(name: "JavaCVS", attachedTo: "javacvs-src", version: "no version number available (with patches by JetBrains)", license: "Sun Public License", url: "https://versioncontrol.netbeans.org/javacvs/library/", licenseUrl: "http://www.netbeans.org/about/legal/spl.html") +libraryLicense(name: "JavaCVS", attachedTo: "javacvs-src", version: "no version number available (with patches by JetBrains)", license: "Sun Public License", url: "https://versioncontrol.netbeans.org/javacvs/library/", licenseUrl: "https://netbeans.org/about/legal/license.html") libraryLicense(name: "JavaHelp", version: "2.0_02", license: "included as license/javahelp_license.html in IntelliJ IDEA distribution", url: "http://java.sun.com/products/javahelp/") libraryLicense(name: "javawriter", libraryName: "javawriter", license: "Apache 2.0", url: "https://github.com/square/javawriter") libraryLicense(name: "JAXB", libraryName: "JAXB", version: "2.2.4-1", license: "CDDL 1.1", url: "http://jaxb.java.net/", licenseUrl: "http://glassfish.java.net/public/CDDL+GPL_1_1.html") @@ -230,9 +230,9 @@ libraryLicense(name: "JediTerm", libraryName: "jediterm-pty", version: "0.2", li libraryLicense(name: "JEuclid", libraryName: "jeuclid-core-3.1.9.jar", version: "3.1.9", license: "Apache 2.0", url: "http://jeuclid.sourceforge.net", licenseUrl:"http://sourceforge.net/p/jeuclid/code/ci/default/tree/LICENSE.txt") libraryLicense(name: "JGit", libraryName: "jackson", version: "2.5.1", license: "Apache 2.0", licenseUrl: "http://www.eclipse.org/org/documents/edl-v10.php", url: "https://github.com/FasterXML/jackson") libraryLicense(name: "JGit", libraryName: "jgit", version: "4.0", license: "Eclipse Distribution License 1.0", licenseUrl: "http://www.eclipse.org/org/documents/edl-v10.php", url: "https://eclipse.org/jgit/") -libraryLicense(name: "JGoodies Common", libraryName: "jgoodies-common", version: "1.2.1", license: "BSD ", url: "http://www.jgoodies.com/freeware/libraries/looks/", licenseUrl: "http://www.jgoodies.com/downloads/libraries.html") -libraryLicense(name: "JGoodies Forms", libraryName: "jgoodies-forms", version: "1.1-preview 2006-05-04 11:55:37", license: "BSD ", url: "http://www.jgoodies.com/freeware/libraries/forms/", licenseUrl: "http://www.jgoodies.com/downloads/libraries.html") -libraryLicense(name: "JGoodies Looks", libraryName: "jgoodies-looks", version: "2.4.2", license: "BSD ", url: "http://www.jgoodies.com/freeware/libraries/looks/", licenseUrl: "http://www.jgoodies.com/downloads/libraries.html") +libraryLicense(name: "JGoodies Common", libraryName: "jgoodies-common", version: "1.2.1", license: "BSD ", url: "http://www.jgoodies.com/freeware/libraries/looks/", licenseUrl: "https://opensource.org/licenses/bsd-license.html") +libraryLicense(name: "JGoodies Forms", libraryName: "jgoodies-forms", version: "1.1-preview 2006-05-04 11:55:37", license: "BSD ", url: "http://www.jgoodies.com/freeware/libraries/forms/", licenseUrl: "https://opensource.org/licenses/bsd-license.html") +libraryLicense(name: "JGoodies Looks", libraryName: "jgoodies-looks", version: "2.4.2", license: "BSD ", url: "http://www.jgoodies.com/freeware/libraries/looks/", licenseUrl: "https://opensource.org/licenses/bsd-license.html") libraryLicense(name: "JNA", libraryName: "jna", version: "4.1.0", license: "LGPL 2.1", url: "https://github.com/java-native-access/jna", licenseUrl: "http://www.opensource.org/licenses/lgpl-2.1.php") libraryLicense(name: "jsch-agent-proxy for svnkit trilead", libraryName: "jsch.agentproxy.svnkit-trilead-ssh2.jar", version: "0.0.7", license: "BSD", url: "https://github.com/ymnk/jsch-agent-proxy", licenseUrl: "https://github.com/ymnk/jsch-agent-proxy/blob/master/LICENSE.txt") libraryLicense(name: "jsch-agent-proxy", libraryName: "jsch-agent-proxy", version: "0.0.7", license: "BSD", url: "https://github.com/ymnk/jsch-agent-proxy", licenseUrl: "https://github.com/ymnk/jsch-agent-proxy/blob/master/LICENSE.txt") @@ -248,16 +248,16 @@ libraryLicense(name: "jzlib", libraryName: "jzlib", version: "1.1.1", license: " libraryLicense(name: "Kryo", libraryName: "Kryo", version: "2.22", license: "New BSD License", url: "https://github.com/EsotericSoftware/kryo", licenseUrl: "https://github.com/EsotericSoftware/kryo/blob/master/license.txt") libraryLicense(name: "kXML2", libraryName: "kxml2", version: "2.3.0", license: "BSD", url: "http://sourceforge.net/projects/kxml/") libraryLicense(name: "Lobo evolution", libraryName: "Loboevolution.jar", version: "0.98.6 (with patches by JetBrains)", license: "MIT", url: "http://sourceforge.net/projects/loboevolution/", licenseUrl: "http://opensource.org/licenses/mit-license.php") -libraryLicense(name: "Log4j", libraryName: "Log4J", version: "1.2.17", license: "Apache 2.0", url: "http://logging.apache.org/log4j/1.2/index.html", licenseUrl: "http://logging.apache.org/license.html") +libraryLicense(name: "Log4j", libraryName: "Log4J", version: "1.2.17", license: "Apache 2.0", url: "http://logging.apache.org/log4j/1.2/index.html", licenseUrl: "http://www.apache.org/licenses/LICENSE-2.0") libraryLicense(name: "Lombok AST", libraryName: "lombok-ast", version: "0.2.1", license: "MIT", url: "http://projectlombok.org/", licenseUrl: "http://opensource.org/licenses/mit-license.php") libraryLicense(name: "markdown4j", libraryName: "markdown4j-2.2", version: "2.2", license: "New BSD", url: "https://code.google.com/p/markdown4j/", licenseUrl: "http://opensource.org/licenses/BSD-3-Clause") -libraryLicense(name: "markdownj", attachedTo: "tasks-core", version: "", license: "BSD", url: "http://markdownj.org/", licenseUrl: "http://www.opensource.org/licenses/bsd-license.php") -libraryLicense(name: "markdownj", libraryName: "markdownj", version: "0.4.2", license: "New BSD", url: "https://code.google.com/p/markdownj/", licenseUrl: "http://opensource.org/licenses/BSD-3-Clause") -libraryLicense(name: "maven-2.2.1-uber", version: "2.2.1", libraryNames: ["maven-2.2.1-uber.jar"], license: "Apache 2.0", url: "http://maven.apache.org/", licenseUrl: "http://maven.apache.org/license.html") -libraryLicense(name: "maven-artifact", version: "3.0.5", libraryNames: ["maven-artifact-3.0.5.jar"], license: "Apache 2.0", url: "http://maven.apache.org/", licenseUrl: "http://maven.apache.org/license.html") -libraryLicense(name: "maven-core", version: "3.0.5", libraryNames: ["maven-core-3.0.5.jar"], license: "Apache 2.0", url: "http://maven.apache.org/", licenseUrl: "http://maven.apache.org/license.html") -libraryLicense(name: "Maven", version: "2.2.1", license: "Apache 2.0", url: "http://maven.apache.org/", licenseUrl: "http://maven.apache.org/license.html") -libraryLicense(name: "Maven3", libraryNames: ["Maven3", "maven-dependency-tree-1.2.jar", "archetype-catalog-2.2.jar", "archetype-common-2.2.jar"], version: "3.0.5", license: "Apache 2.0", url: "http://maven.apache.org/", licenseUrl: "http://maven.apache.org/license.html") +libraryLicense(name: "markdownj", attachedTo: "tasks-core", version: "", license: "BSD", url: "https://github.com/myabc/markdownj", licenseUrl: "http://www.opensource.org/licenses/bsd-license.php") +libraryLicense(name: "markdownj", libraryName: "markdownj", version: "0.4.2", license: "New BSD", url: "https://github.com/myabc/markdownj", licenseUrl: "http://opensource.org/licenses/BSD-3-Clause") +libraryLicense(name: "maven-2.2.1-uber", version: "2.2.1", libraryNames: ["maven-2.2.1-uber.jar"], license: "Apache 2.0", url: "http://maven.apache.org/", licenseUrl: "http://www.apache.org/licenses/LICENSE-2.0") +libraryLicense(name: "maven-artifact", version: "3.0.5", libraryNames: ["maven-artifact-3.0.5.jar"], license: "Apache 2.0", url: "http://maven.apache.org/", licenseUrl: "http://www.apache.org/licenses/LICENSE-2.0") +libraryLicense(name: "maven-core", version: "3.0.5", libraryNames: ["maven-core-3.0.5.jar"], license: "Apache 2.0", url: "http://maven.apache.org/", licenseUrl: "http://www.apache.org/licenses/LICENSE-2.0") +libraryLicense(name: "Maven", version: "2.2.1", license: "Apache 2.0", url: "http://maven.apache.org/", licenseUrl: "http://www.apache.org/licenses/LICENSE-2.0") +libraryLicense(name: "Maven3", libraryNames: ["Maven3", "maven-dependency-tree-1.2.jar", "archetype-catalog-2.2.jar", "archetype-common-2.2.jar"], version: "3.0.5", license: "Apache 2.0", url: "http://maven.apache.org/", licenseUrl: "http://www.apache.org/licenses/LICENSE-2.0") libraryLicense(name: "mercurial_prompthooks", attachedTo: "hg4idea", version: "", license: "GPLv2 (used as hg extension called from hg executable)", url: "https://github.com/willemv/mercurial_prompthooks", licenseUrl: "https://github.com/willemv/mercurial_prompthooks/blob/master/LICENSE.txt") libraryLicense(name: "Microba", libraryName: "microba", version: "0.4.2", license: "BSD", url: "http://microba.sourceforge.net/", licenseUrl: "http://microba.sourceforge.net/license.txt") libraryLicense(name: "MigLayout", libraryName: "miglayout-swing", version: "3.7.1", license: "BSD", url: "http://www.miglayout.com/", licenseUrl: "http://www.miglayout.com/mavensite/license.html") @@ -268,14 +268,14 @@ libraryLicense(name: "Netty", libraryName: "Netty", version: "4.1.0.Beta3", lice libraryLicense(name: "Objenesis", libraryName: "objenesis-1.2.jar", version: "1.2", license: "Apache 2.0", url: "http://objenesis.org/", licenseUrl: "http://apache.org/licenses/LICENSE-2.0") libraryLicense(name: "opentest4j", libraryName: "opentest4j", version: "1.0.0", license: "Apache 2.0", url: "https://github.com/ota4j-team/opentest4j", licenseUrl: "http://apache.org/licenses/LICENSE-2.0") libraryLicense(name: "pep8.py", attachedTo: "python-helpers", version: "1.6.2", license: "MIT", url: "http://pep8.readthedocs.org/") -libraryLicense(name: "PicoContainer", libraryName: "picocontainer", version: "1.2", license: "BSD", url: "http://www.picocontainer.org/", licenseUrl: "http://docs.codehaus.org/display/PICO/License") +libraryLicense(name: "PicoContainer", libraryName: "picocontainer", version: "1.2", license: "BSD", url: "https://github.com/codehaus/picocontainer", licenseUrl: "https://opensource.org/licenses/bsd-license.php") libraryLicense(name: "plexus-archiver", libraryName: "plexus-archiver-2.4.4.jar", version: "2.4.4", license: "Apache 2.0", url: "https://github.com/codehaus-plexus/plexus-archiver", licenseUrl: "http://apache.org/licenses/LICENSE-2.0") libraryLicense(name: "plexus-classworlds", libraryName: "plexus-classworlds-2.4.jar", version: "2.4", license: "Apache 2.0", url: "https://github.com/codehaus-plexus/plexus-classworlds", licenseUrl: "http://apache.org/licenses/LICENSE-2.0") -libraryLicense(name: "plexus-component-annotations", version: "1.5.5", libraryNames: ["plexus-component-annotations-1.5.5.jar"], license: "Apache 2.0", url: "http://maven.apache.org/", licenseUrl: "http://maven.apache.org/license.html") +libraryLicense(name: "plexus-component-annotations", version: "1.5.5", libraryNames: ["plexus-component-annotations-1.5.5.jar"], license: "Apache 2.0", url: "http://maven.apache.org/", licenseUrl: "http://www.apache.org/licenses/LICENSE-2.0") libraryLicense(name: "plexus-util", version: "2.0.6", license: "Apache 2.0", url: "http://maven.apache.org/", libraryNames:['plexus-utils-2.0.6.jar'], licenseUrl: "http://apache.org/licenses/LICENSE-2.0") libraryLicense(name: "Plexus Utils", libraryName: "plexus-utils-1.5.5.jar", version: "1.5.5", license: "Apache 2.0", url: "http://plexus.codehaus.org/plexus-utils") libraryLicense(name: "pockets", attachedTo: "python-helpers", version: "0.2.4", license: "BSD", url: "http://pockets.readthedocs.org/") -libraryLicense(name: "protobuf", version: "2.5.0", license: "New BSD", url: "http://code.google.com/p/protobuf/", licenseUrl: "http://code.google.com/p/protobuf/source/browse/trunk/COPYING.txt?r=367") +libraryLicense(name: "protobuf", version: "2.5.0", license: "New BSD", url: "http://code.google.com/p/protobuf/", licenseUrl: "https://github.com/google/protobuf/blob/master/LICENSE") libraryLicense(name: "proxy-vole", libraryName: "proxy-vole", version: "20131209", license: "New BSD License", url: "http://code.google.com/p/proxy-vole/", licenseUrl: "http://opensource.org/licenses/BSD-3-Clause") libraryLicense(name: "pty4j", libraryName: "pty4j", version: "0.6", license: "Eclipse Public License v1.0", url: "https://github.com/traff/pty4j") libraryLicense(name: "PureJavaComm", libraryName: "purejavacomm", version: "0.0.16", license: "BSD", url: "http://www.sparetimelabs.com/purejavacomm") @@ -300,19 +300,19 @@ libraryLicense(name: "sqljet", version: "bundled with SVNKit", libraryName: "sql libraryLicense(name: "svnkit-javahl", version: "bundled with SVNKit", libraryName: "svnkit-javahl.jar", license: "link (commercial license)", url: "http://www.svnkit.com/", licenseUrl: "http://svnkit.com/license.html") libraryLicense(name: "SVNKit", libraryName: "svnkit.jar", version: "1.8.7", license: "link (commercial license)", url: "http://www.svnkit.com/", licenseUrl: "http://svnkit.com/license.html") libraryLicense(name: "swingx", libraryName: "swingx", version: "1.6.2", license: "LGPL 2.1", url: "http://java.net/downloads/swingx/", licenseUrl: "http://www.opensource.org/licenses/lgpl-2.1.php") -libraryLicense(name: "TestNG", version: "6.9 snapshot", license: "Apache 2.0", url: "http://testng.org/doc/", licenseUrl: "http://code.google.com/p/testng/") +libraryLicense(name: "TestNG", version: "6.9 snapshot", license: "Apache 2.0", url: "http://testng.org/doc/", licenseUrl: "https://github.com/cbeust/testng/blob/master/LICENSE.txt") libraryLicense(name: "Trilead SSH", libraryName: "trilead-ssh2", version: "build 213 and 217", license: "BSD style (see LICENSE.txt in trilead.jar)", url: "http://www.trilead.com/SSH_Library/") libraryLicense(name: "Twitter4J", libraryName: "twitter4j-core-4.0.4.jar", version: "4.0.4", license: "Apache 2.0", url: "http://twitter4j.org/", licenseUrl: "http://twitter4j.org/en/index.html#license") libraryLicense(name: "Trove4j", version: "1.1 (with patches by JetBrains)", license: "LGPL", url: "http://trove4j.sourceforge.net/", licenseUrl: "http://trove4j.sourceforge.net/html/license.html") -libraryLicense(name: "Velocity", version: "1.7", license: "Apache 2.0", url: "http://velocity.apache.org/", licenseUrl: "http://velocity.apache.org/index.html") +libraryLicense(name: "Velocity", version: "1.7", license: "Apache 2.0", url: "http://velocity.apache.org/", licenseUrl: "http://www.apache.org/licenses/LICENSE-2.0.txt") libraryLicense(name: "winp", version: "1.23", license: "MIT", url: "http://java.net/projects/winp", licenseUrl: "http://opensource.org/licenses/mit-license.php") libraryLicense(name: "Xalan", libraryName:"Xalan-2.7.1", version: "2.7.1", license: "Apache 2.0", url: "http://xml.apache.org/xalan-j/", licenseUrl: "http://xml.apache.org/xalan-j/") libraryLicense(name: "Xerces", version: "2.11", license: "Apache 2.0", url: "http://xerces.apache.org/xerces2-j/", licenseUrl: "http://xerces.apache.org/xerces2-j/") libraryLicense(name: "XML-RPC", libraryName: "XmlRPC", version: "2.0", license: "Apache 2.0", url: "http://ws.apache.org/xmlrpc/xmlrpc2/", licenseUrl: "http://ws.apache.org/xmlrpc/xmlrpc2/license.html") libraryLicense(name: "XML Commons (xml-apis.jar, resolver.jar)", version: "", license: "Apache 2.0, W3C Software License , public domain", url: "http://xml.apache.org/commons/", licenseUrl: "http://xml.apache.org/commons/licenses.html") libraryLicense(name: "XMLBeans", libraryName: "XmlBeans", version: "2.3.0", license: "Apache 2.0", url: "http://xmlbeans.apache.org/", licenseUrl: "http://svn.jetbrains.org/idea/Trunk/bundled/WebServices/resources/lib/xmlbeans-2.3.0/xmlbeans.LICENSE") -libraryLicense(name: "XStream", libraryName: "XStream", version: "1.4.2", license: "BSD License", url: "https://github.com/codehaus/xstream", licenseUrl: "http://xstream.codehaus.org/license.html") -libraryLicense(name: "XStream", version: "1.4.3", license: "BSD", url: "https://github.com/codehaus/xstream", licenseUrl: "http://xstream.codehaus.org/license.html") +libraryLicense(name: "XStream", libraryName: "XStream", version: "1.4.2", license: "BSD License", url: "https://github.com/codehaus/xstream", licenseUrl: "https://github.com/codehaus/xstream/blob/master/LICENSE.txt") +libraryLicense(name: "XStream", version: "1.4.3", license: "BSD", url: "https://github.com/codehaus/xstream", licenseUrl: "https://github.com/codehaus/xstream/blob/master/LICENSE.txt") libraryLicense(name: "YourKit Java Profiler", libraryName: "yjp-controller-api-redist.jar", version: "8.0.x", license: "link (commercial license)", url: "http://yourkit.com/", licenseUrl: "http://www.yourkit.com/purchase/license.html") jetbrainsLibrary("Coverage") From 99bffc3d18e1be1749dc091a4be403e014cdd8a1 Mon Sep 17 00:00:00 2001 From: Roman Shevchenko Date: Mon, 21 Mar 2016 16:32:35 +0100 Subject: [PATCH 72/81] [platform] subscription info in the update dialog (IDEA-153200) --- .../updateSettings/impl/AbstractUpdateDialog.java | 12 ++++++++++++ .../src/com/intellij/ui/LicensingFacade.java | 7 +++++++ .../src/messages/IdeBundle.properties | 2 ++ 3 files changed, 21 insertions(+) diff --git a/platform/platform-impl/src/com/intellij/openapi/updateSettings/impl/AbstractUpdateDialog.java b/platform/platform-impl/src/com/intellij/openapi/updateSettings/impl/AbstractUpdateDialog.java index 71f4a2cbc933..fe27df9d859c 100644 --- a/platform/platform-impl/src/com/intellij/openapi/updateSettings/impl/AbstractUpdateDialog.java +++ b/platform/platform-impl/src/com/intellij/openapi/updateSettings/impl/AbstractUpdateDialog.java @@ -24,6 +24,7 @@ import com.intellij.openapi.ui.DialogWrapper; import com.intellij.ui.ColorUtil; import com.intellij.ui.IdeBorderFactory; import com.intellij.ui.LicensingFacade; +import com.intellij.util.text.DateFormatUtil; import com.intellij.util.ui.UIUtil; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -32,6 +33,7 @@ import javax.swing.*; import javax.swing.event.HyperlinkEvent; import javax.swing.event.HyperlinkListener; import java.awt.*; +import java.util.Date; /** * @author anna @@ -80,6 +82,16 @@ public abstract class AbstractUpdateDialog extends DialogWrapper { if (channel.getLicensing().equals(UpdateChannel.LICENSING_EAP)) { myLicenseInfo = IdeBundle.message("updates.channel.bundled.key"); } + else { + Date buildDate = build.getReleaseDate(); + Date expiration = facade.getLicenseExpirationDate(); + if (buildDate != null && facade.isPerpetualForProduct(buildDate)) { + myLicenseInfo = IdeBundle.message("updates.fallback.build"); + } + else if (expiration != null && expiration.after(new Date())) { + myLicenseInfo = IdeBundle.message("updates.subscription.active.till", DateFormatUtil.formatAboutDialogDate(expiration)); + } + } } } diff --git a/platform/platform-impl/src/com/intellij/ui/LicensingFacade.java b/platform/platform-impl/src/com/intellij/ui/LicensingFacade.java index 1518cfeafa51..4cc49749ac9b 100644 --- a/platform/platform-impl/src/com/intellij/ui/LicensingFacade.java +++ b/platform/platform-impl/src/com/intellij/ui/LicensingFacade.java @@ -15,8 +15,10 @@ */ package com.intellij.ui; +import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; +import java.util.Date; import java.util.List; /** @@ -35,4 +37,9 @@ public abstract class LicensingFacade { public abstract List getLicenseRestrictionsMessages(); public abstract boolean isEvaluationLicense(); + + public abstract boolean isPerpetualForProduct(@NotNull Date productBuildDate); + + @Nullable + public abstract Date getLicenseExpirationDate(); } \ No newline at end of file diff --git a/platform/platform-resources-en/src/messages/IdeBundle.properties b/platform/platform-resources-en/src/messages/IdeBundle.properties index c414af819eb5..e9e4f52f914d 100644 --- a/platform/platform-resources-en/src/messages/IdeBundle.properties +++ b/platform/platform-resources-en/src/messages/IdeBundle.properties @@ -908,6 +908,8 @@ update.notifications.title=Platform and Plugin Updates update.notifications.group=Platform and Plugin Updates updates.channel.name.message={0}: {1} updates.channel.bundled.key=The new version has an expiration date and does not require a license key. +updates.fallback.build=You have perpetual fallback license for the new version. +updates.subscription.active.till=Your subscription is active until {0}. updates.ready.message={0} is ready to update. updates.plugins.ready.message=The following plugin{0,choice,1# is|2#s are} ready to update: {1} updates.no.updates.message=You already have the latest version of {0} installed. From 49a3d65608f677b47abbcfa57717aa61bf8b6218 Mon Sep 17 00:00:00 2001 From: "Egor.Ushakov" Date: Mon, 21 Mar 2016 18:41:02 +0300 Subject: [PATCH 73/81] EA-80772 - VMDE: MethodReturnValueWatcher.createExitRequest --- .../engine/requests/MethodReturnValueWatcher.java | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/java/debugger/impl/src/com/intellij/debugger/engine/requests/MethodReturnValueWatcher.java b/java/debugger/impl/src/com/intellij/debugger/engine/requests/MethodReturnValueWatcher.java index 213dae83cf4a..5f7915741d8d 100644 --- a/java/debugger/impl/src/com/intellij/debugger/engine/requests/MethodReturnValueWatcher.java +++ b/java/debugger/impl/src/com/intellij/debugger/engine/requests/MethodReturnValueWatcher.java @@ -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. @@ -21,10 +21,7 @@ import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.util.Comparing; import com.intellij.openapi.util.registry.Registry; import com.intellij.util.ArrayUtil; -import com.sun.jdi.Method; -import com.sun.jdi.ObjectCollectedException; -import com.sun.jdi.ThreadReference; -import com.sun.jdi.Value; +import com.sun.jdi.*; import com.sun.jdi.event.Event; import com.sun.jdi.event.MethodEntryEvent; import com.sun.jdi.event.MethodExitEvent; @@ -118,6 +115,9 @@ public class MethodReturnValueWatcher { enableEntryWatching(false); } } + catch (VMDisconnectedException e) { + throw e; + } catch (Exception e) { LOG.error(e); } From c46099ac2b94a8e2b04855d98261f5bc574576c0 Mon Sep 17 00:00:00 2001 From: peter Date: Mon, 21 Mar 2016 16:56:03 +0100 Subject: [PATCH 74/81] allow user-activity-driven write actions without transactions --- .../openapi/application/TransactionGuard.java | 14 ++++++- .../application/TransactionGuardImpl.java | 40 ++++++++++++++++++- .../ide/actions/GotoActionAction.java | 12 +++--- .../src/com/intellij/ide/IdeEventQueue.java | 6 +-- .../actionSystem/impl/ActionManagerImpl.java | 14 +++---- .../application/impl/ApplicationImpl.java | 6 +-- .../keymap/impl/IdeKeyEventDispatcher.java | 8 ++-- .../com/intellij/ui/popup/AbstractPopup.java | 3 +- 8 files changed, 74 insertions(+), 29 deletions(-) diff --git a/platform/core-api/src/com/intellij/openapi/application/TransactionGuard.java b/platform/core-api/src/com/intellij/openapi/application/TransactionGuard.java index 2b304ae3f440..3153ee035154 100644 --- a/platform/core-api/src/com/intellij/openapi/application/TransactionGuard.java +++ b/platform/core-api/src/com/intellij/openapi/application/TransactionGuard.java @@ -19,6 +19,7 @@ import com.intellij.openapi.components.ServiceManager; import com.intellij.openapi.progress.ProcessCanceledException; import com.intellij.openapi.util.Computable; import com.intellij.openapi.util.Ref; +import com.intellij.util.ThrowableRunnable; import org.jetbrains.annotations.NotNull; /** @@ -30,7 +31,9 @@ import org.jetbrains.annotations.NotNull; * and process UI events in other ways: it's guaranteed that no one will be able to sneak in with an unexpected model change using * {@link javax.swing.SwingUtilities#invokeLater(Runnable)} or analogs.

* - * Transactions are run on UI thread. They have read access by default. All write actions should be performed inside a transaction.

+ * Transactions are run on UI thread. They have read access by default. All write actions that don't happen as the result of direct user input + * should be performed inside a transaction. No write action should be performed from within an {@code invokeLater}-like call + * unless wrapped into a transaction.

* * The recommended way to perform a transaction is to invoke {@link #submitTransaction(Runnable)}. It either runs the transaction immediately * (if on UI thread and there's no other transaction running) or queues it to invoke at some later moment, when it becomes possible.

@@ -192,4 +195,13 @@ public abstract class TransactionGuard { * @param errorMessage the message that will be logged if current transaction status differs from the expected one */ public abstract void assertInsideTransaction(boolean transactionRequired, @NotNull String errorMessage); + + /** + * Executes the given code and marks it as a user activity, to allow write actions to be run without requiring transactions. + * Please note that only direct keyboard/mouse event processing can be wrapped in such calls. If you wish to invoke some actionPerformed, + * please consider using {@code ActionManager.tryToExecute()} instead, or ensure in some other way that the action is enabled + * and can be invoked in the current modality state. + */ + public abstract void performUserActivity(ThrowableRunnable activity) throws T; + } diff --git a/platform/core-impl/src/com/intellij/openapi/application/TransactionGuardImpl.java b/platform/core-impl/src/com/intellij/openapi/application/TransactionGuardImpl.java index 620fc91fca6e..53e26bf6c5a1 100644 --- a/platform/core-impl/src/com/intellij/openapi/application/TransactionGuardImpl.java +++ b/platform/core-impl/src/com/intellij/openapi/application/TransactionGuardImpl.java @@ -18,7 +18,9 @@ package com.intellij.openapi.application; import com.intellij.openapi.diagnostic.Attachment; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.progress.ProcessCanceledException; +import com.intellij.openapi.util.registry.Registry; import com.intellij.psi.impl.DebugUtil; +import com.intellij.util.ThrowableRunnable; import com.intellij.util.concurrency.Semaphore; import com.intellij.util.containers.ContainerUtil; import org.jetbrains.annotations.NotNull; @@ -37,13 +39,14 @@ public class TransactionGuardImpl extends TransactionGuard { private final Set myMergeableKinds = ContainerUtil.newHashSet(); private String myTransactionStartTrace; private ModalityState myTransactionModality; + private boolean myUserActivity; @Override @NotNull public AccessToken startSynchronousTransaction(@NotNull TransactionKind kind) throws IllegalStateException { ModalityState modality = ModalityState.current(); if (isInsideTransaction()) { - if (modality.equals(myTransactionModality)) { + if (modality.equals(myTransactionModality) || myUserActivity) { return AccessToken.EMPTY_ACCESS_TOKEN; } @@ -200,4 +203,39 @@ public class TransactionGuardImpl extends TransactionGuard { throw new RuntimeException(exception[0]); } } + + @Override + public void performUserActivity(ThrowableRunnable activity) throws T { + ApplicationManager.getApplication().assertIsDispatchThread(); + AccessToken token = startActivity(true); + try { + activity.run(); + } + finally { + token.finish(); + } + } + + /** + * An absolutely guru method, only intended to be used from Swing event processing. Please consult Peter if you think you need to invoke this. + */ + @NotNull + public AccessToken startActivity(boolean userActivity) { + if (myUserActivity == userActivity) { + return AccessToken.EMPTY_ACCESS_TOKEN; + } + + final boolean prev = myUserActivity; + myUserActivity = userActivity; + return new AccessToken() { + @Override + public void finish() { + myUserActivity = prev; + } + }; + } + + public boolean isWriteActionAllowed() { + return !Registry.is("ide.require.transaction.for.model.changes", false) || isInsideTransaction() || myUserActivity; + } } diff --git a/platform/lang-impl/src/com/intellij/ide/actions/GotoActionAction.java b/platform/lang-impl/src/com/intellij/ide/actions/GotoActionAction.java index 502ff5851c92..bbc74f4bb4e5 100644 --- a/platform/lang-impl/src/com/intellij/ide/actions/GotoActionAction.java +++ b/platform/lang-impl/src/com/intellij/ide/actions/GotoActionAction.java @@ -29,6 +29,7 @@ import com.intellij.openapi.actionSystem.ex.ActionUtil; import com.intellij.openapi.actionSystem.ex.QuickList; import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.application.ModalityState; +import com.intellij.openapi.application.TransactionGuard; import com.intellij.openapi.editor.Editor; import com.intellij.openapi.keymap.Keymap; import com.intellij.openapi.keymap.KeymapManager; @@ -250,10 +251,9 @@ public class GotoActionAction extends GotoActionBase implements DumbAware { public static void performAction(Object element, @Nullable final Component component, @Nullable final AnActionEvent e) { // element could be AnAction (SearchEverywhere) final AnAction action = element instanceof AnAction ? (AnAction)element : ((GotoActionModel.ActionWrapper)element).getAction(); - ApplicationManager.getApplication().invokeLater(new Runnable() { - @Override - public void run() { - if (component == null) return; + ApplicationManager.getApplication().invokeLater(() -> { + if (component == null) return; + TransactionGuard.getInstance().performUserActivity(() -> { DataManager instance = DataManager.getInstance(); DataContext context = instance != null ? instance.getDataContext(component) : DataContext.EMPTY_CONTEXT; InputEvent inputEvent = e == null ? null : e.getInputEvent(); @@ -270,12 +270,12 @@ public class GotoActionAction extends GotoActionBase implements DumbAware { else { popup.showInFocusCenter(); } - } + } else { ActionUtil.performActionDumbAware(action, event); } } - } + }); }, ModalityState.NON_MODAL); } diff --git a/platform/platform-impl/src/com/intellij/ide/IdeEventQueue.java b/platform/platform-impl/src/com/intellij/ide/IdeEventQueue.java index 3ceb6f620964..cdf1d46b57d6 100644 --- a/platform/platform-impl/src/com/intellij/ide/IdeEventQueue.java +++ b/platform/platform-impl/src/com/intellij/ide/IdeEventQueue.java @@ -21,9 +21,7 @@ import com.intellij.ide.plugins.PluginManager; import com.intellij.ide.ui.UISettings; import com.intellij.idea.IdeaApplication; import com.intellij.openapi.Disposable; -import com.intellij.openapi.application.Application; -import com.intellij.openapi.application.ApplicationManager; -import com.intellij.openapi.application.ModalityState; +import com.intellij.openapi.application.*; import com.intellij.openapi.application.ex.ApplicationEx; import com.intellij.openapi.application.impl.LaterInvocator; import com.intellij.openapi.diagnostic.FrequentEventDetector; @@ -385,6 +383,7 @@ public class IdeEventQueue extends EventQueue { } AWTEvent oldEvent = myCurrentEvent; myCurrentEvent = e; + AccessToken token = ((TransactionGuardImpl)TransactionGuard.getInstance()).startActivity(myIsInInputEvent); try { _dispatchEvent(e, false); @@ -393,6 +392,7 @@ public class IdeEventQueue extends EventQueue { processException(t); } finally { + token.finish(); myIsInInputEvent = wasInputEvent; myCurrentEvent = oldEvent; diff --git a/platform/platform-impl/src/com/intellij/openapi/actionSystem/impl/ActionManagerImpl.java b/platform/platform-impl/src/com/intellij/openapi/actionSystem/impl/ActionManagerImpl.java index c6fe3dfc6c8e..375f764abfc1 100644 --- a/platform/platform-impl/src/com/intellij/openapi/actionSystem/impl/ActionManagerImpl.java +++ b/platform/platform-impl/src/com/intellij/openapi/actionSystem/impl/ActionManagerImpl.java @@ -29,10 +29,7 @@ import com.intellij.openapi.actionSystem.*; import com.intellij.openapi.actionSystem.ex.ActionManagerEx; import com.intellij.openapi.actionSystem.ex.ActionUtil; import com.intellij.openapi.actionSystem.ex.AnActionListener; -import com.intellij.openapi.application.Application; -import com.intellij.openapi.application.ApplicationActivationListener; -import com.intellij.openapi.application.ApplicationManager; -import com.intellij.openapi.application.ModalityState; +import com.intellij.openapi.application.*; import com.intellij.openapi.application.ex.ApplicationManagerEx; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.extensions.PluginId; @@ -1298,15 +1295,14 @@ public final class ActionManagerImpl extends ActionManagerEx implements Disposab private void tryToExecuteNow(final AnAction action, final InputEvent inputEvent, final Component contextComponent, final String place, final ActionCallback result) { final Presentation presentation = action.getTemplatePresentation().clone(); - IdeFocusManager.findInstanceByContext(getContextBy(contextComponent)).doWhenFocusSettlesDown(new Runnable() { - @Override - public void run() { + IdeFocusManager.findInstanceByContext(getContextBy(contextComponent)).doWhenFocusSettlesDown( + () -> TransactionGuard.getInstance().performUserActivity(() -> { final DataContext context = getContextBy(contextComponent); AnActionEvent event = new AnActionEvent( inputEvent, context, place != null ? place : ActionPlaces.UNKNOWN, - presentation, ActionManagerImpl.this, + presentation, this, inputEvent.getModifiersEx() ); @@ -1346,7 +1342,7 @@ public final class ActionManagerImpl extends ActionManagerEx implements Disposab result.setDone(); queueActionPerformedEvent(action, context, event); } - }); + )); } private class MyTimer extends Timer implements ActionListener { diff --git a/platform/platform-impl/src/com/intellij/openapi/application/impl/ApplicationImpl.java b/platform/platform-impl/src/com/intellij/openapi/application/impl/ApplicationImpl.java index beee7d02aef0..48e6b1d9e314 100644 --- a/platform/platform-impl/src/com/intellij/openapi/application/impl/ApplicationImpl.java +++ b/platform/platform-impl/src/com/intellij/openapi/application/impl/ApplicationImpl.java @@ -1229,9 +1229,9 @@ public class ApplicationImpl extends PlatformComponentManagerImpl implements App private void startWrite(/*@NotNull*/ Class clazz) { assertIsDispatchThread(getStatus(), "Write access is allowed from event dispatch thread only"); HeavyProcessLatch.INSTANCE.stopThreadPrioritizing(); // let non-cancellable read actions complete faster, if present - if (Registry.is("ide.require.transaction.for.model.changes", false)) { - TransactionGuard.getInstance().assertInsideTransaction( - true, "Write access is allowed from model transactions only, see TransactionGuard documentation for details"); + if (!((TransactionGuardImpl)TransactionGuard.getInstance()).isWriteActionAllowed()) { + // please assign exceptions here to Peter + LOG.error("Write access is allowed from model transactions only, see TransactionGuard documentation for details"); } boolean writeActionPending = myWriteActionPending; if (gatherWriteActionStatistics && myWriteActionsStack.isEmpty() && !writeActionPending) { diff --git a/platform/platform-impl/src/com/intellij/openapi/keymap/impl/IdeKeyEventDispatcher.java b/platform/platform-impl/src/com/intellij/openapi/keymap/impl/IdeKeyEventDispatcher.java index 1cfb301ef9d7..992c83d5a577 100644 --- a/platform/platform-impl/src/com/intellij/openapi/keymap/impl/IdeKeyEventDispatcher.java +++ b/platform/platform-impl/src/com/intellij/openapi/keymap/impl/IdeKeyEventDispatcher.java @@ -868,17 +868,15 @@ public final class IdeKeyEventDispatcher implements Disposable { } private static void invokeAction(@NotNull final AnAction action, final DataContext ctx) { - ApplicationManager.getApplication().invokeLater(new Runnable() { - @Override - public void run() { + ApplicationManager.getApplication().invokeLater( + () -> TransactionGuard.getInstance().performUserActivity(() -> { final AnActionEvent event = new AnActionEvent(null, ctx, ActionPlaces.UNKNOWN, action.getTemplatePresentation().clone(), ActionManager.getInstance(), 0); if (ActionUtil.lastUpdateAndCheckDumb(action, event, true)) { ActionUtil.performActionDumbAware(action, event); } - } - }); + })); } @Override diff --git a/platform/platform-impl/src/com/intellij/ui/popup/AbstractPopup.java b/platform/platform-impl/src/com/intellij/ui/popup/AbstractPopup.java index 76959083f905..312a605add38 100644 --- a/platform/platform-impl/src/com/intellij/ui/popup/AbstractPopup.java +++ b/platform/platform-impl/src/com/intellij/ui/popup/AbstractPopup.java @@ -28,6 +28,7 @@ import com.intellij.openapi.actionSystem.DataProvider; import com.intellij.openapi.actionSystem.PlatformDataKeys; import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.application.ModalityState; +import com.intellij.openapi.application.TransactionGuard; import com.intellij.openapi.application.ex.ApplicationManagerEx; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.editor.Editor; @@ -1392,7 +1393,7 @@ public class AbstractPopup implements JBPopup { //noinspection SSBasedInspection SwingUtilities.invokeLater(() -> { if (ModalityState.current().equals(modalityState)) { - finalRunnable.run(); + TransactionGuard.getInstance().performUserActivity(finalRunnable::run); } // Otherwise the UI has changed unexpectedly and the action is likely not applicable. // And we don't want finalRunnable to perform potentially destructive actions From ce3bfb7a2cd40a305b98a8d7b818057732738c01 Mon Sep 17 00:00:00 2001 From: Roman Shevchenko Date: Mon, 21 Mar 2016 17:02:55 +0100 Subject: [PATCH 75/81] Cleanup (warnings; formatting; dead code) --- .../util/text/LevenshteinDistance.java | 26 ----- .../spellchecker/engine/BaseSpellChecker.java | 100 +++++++----------- .../spellchecker/engine/Suggestion.java | 21 ++-- 3 files changed, 47 insertions(+), 100 deletions(-) delete mode 100644 platform/util/src/com/intellij/openapi/util/text/LevenshteinDistance.java diff --git a/platform/util/src/com/intellij/openapi/util/text/LevenshteinDistance.java b/platform/util/src/com/intellij/openapi/util/text/LevenshteinDistance.java deleted file mode 100644 index b66d61ad0568..000000000000 --- a/platform/util/src/com/intellij/openapi/util/text/LevenshteinDistance.java +++ /dev/null @@ -1,26 +0,0 @@ -/* - * Copyright 2000-2015 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.util.text; - -import com.intellij.util.text.EditDistance; - -/** @deprecated use {@link EditDistance} (to be removed in IDEA 17) */ -@SuppressWarnings("unused") -public class LevenshteinDistance { - public int calculateMetrics(CharSequence str1, CharSequence str2) { - return EditDistance.levenshtein(str1, str2, true); - } -} diff --git a/spellchecker/src/com/intellij/spellchecker/engine/BaseSpellChecker.java b/spellchecker/src/com/intellij/spellchecker/engine/BaseSpellChecker.java index 408df45b8142..fe5e25098f17 100644 --- a/spellchecker/src/com/intellij/spellchecker/engine/BaseSpellChecker.java +++ b/spellchecker/src/com/intellij/spellchecker/engine/BaseSpellChecker.java @@ -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. @@ -16,6 +16,7 @@ package com.intellij.spellchecker.engine; import com.intellij.codeInsight.daemon.DaemonCodeAnalyzer; +import com.intellij.openapi.application.Application; import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.project.Project; @@ -49,7 +50,7 @@ public class BaseSpellChecker implements SpellCheckerEngine { private final List>> myDictionariesToLoad = ContainerUtil.createLockFreeCopyOnWriteList(); private final Project myProject; - public BaseSpellChecker(final Project project) { + public BaseSpellChecker(@NotNull Project project) { myProject = project; } @@ -72,70 +73,55 @@ public class BaseSpellChecker implements SpellCheckerEngine { addCompressedFixedDictionary(dictionary); } else { - loadDictionaryAsync(loader, new Consumer() { - @Override - public void consume(final Dictionary dictionary) { - addCompressedFixedDictionary(dictionary); - } - }); + loadDictionaryAsync(loader, this::addCompressedFixedDictionary); } } private void loadDictionaryAsync(@NotNull final Loader loader, @NotNull final Consumer consumer) { if (myLoadingDictionaries.compareAndSet(false, true)) { LOG.debug("Loading " + loader.getName()); - _doLoadDictionaryAsync(loader, consumer); + doLoadDictionaryAsync(loader, consumer); } else { queueDictionaryLoad(loader, consumer); } } - private void _doLoadDictionaryAsync(final Loader loader, final Consumer consumer) { - final Runnable runnable = new Runnable() { - @Override - public void run() { - LOG.debug("Loading " + loader.getName()); - ApplicationManager.getApplication().executeOnPooledThread(new Runnable() { - @Override - public void run() { - if (ApplicationManager.getApplication().isDisposed()) return; - - final CompressedDictionary dictionary = CompressedDictionary.create(loader, transform); - LOG.debug(loader.getName() + " loaded!"); - consumer.consume(dictionary); + private void doLoadDictionaryAsync(Loader loader, Consumer consumer) { + StartupManager.getInstance(myProject).runWhenProjectIsInitialized(() -> { + LOG.debug("Loading " + loader.getName()); + Application app = ApplicationManager.getApplication(); + app.executeOnPooledThread(() -> { + if (app.isDisposed()) return; - while (!myDictionariesToLoad.isEmpty()) { - if (ApplicationManager.getApplication().isDisposed()) return; - - final Pair> nextDictionary = myDictionariesToLoad.remove(0); - Loader nextDictionaryLoader = nextDictionary.getFirst(); - CompressedDictionary dictionary1 = CompressedDictionary.create(nextDictionaryLoader, transform); - LOG.debug(nextDictionaryLoader.getName() + " loaded!"); - nextDictionary.getSecond().consume(dictionary1); + CompressedDictionary dictionary = CompressedDictionary.create(loader, transform); + LOG.debug(loader.getName() + " loaded!"); + consumer.consume(dictionary); + + while (!myDictionariesToLoad.isEmpty()) { + if (app.isDisposed()) return; + + Pair> nextDictionary = myDictionariesToLoad.remove(0); + Loader nextDictionaryLoader = nextDictionary.getFirst(); + dictionary = CompressedDictionary.create(nextDictionaryLoader, transform); + LOG.debug(nextDictionaryLoader.getName() + " loaded!"); + nextDictionary.getSecond().consume(dictionary); + } + + LOG.debug("Loading finished, restarting daemon..."); + myLoadingDictionaries.set(false); + UIUtil.invokeLaterIfNeeded(() -> { + if (app.isDisposed()) return; + + for (final Project project : ProjectManager.getInstance().getOpenProjects()) { + if (project.isInitialized() && project.isOpen() && !project.isDefault()) { + DaemonCodeAnalyzer instance = DaemonCodeAnalyzer.getInstance(project); + if (instance != null) instance.restart(); } - - LOG.debug("Loading finished, restarting daemon..."); - myLoadingDictionaries.set(false); - UIUtil.invokeLaterIfNeeded(new Runnable() { - @Override - public void run() { - if (ApplicationManager.getApplication().isDisposed()) return; - - for (final Project project : ProjectManager.getInstance().getOpenProjects()) { - if (project.isInitialized() && project.isOpen() && !project.isDefault()) { - final DaemonCodeAnalyzer instance = DaemonCodeAnalyzer.getInstance(project); - if (instance != null) instance.restart(); - } - } - } - }); } }); - } - }; - - StartupManager.getInstance(myProject).runWhenProjectIsInitialized(runnable); + }); + }); } private void queueDictionaryLoad(final Loader loader, final Consumer consumer) { @@ -167,12 +153,9 @@ public class BaseSpellChecker implements SpellCheckerEngine { ((CompressedDictionary)dictionary).getWords(first, i, j, result); } else { - dictionary.traverse(new Consumer() { - @Override - public void consume(String s) { - if (!StringUtil.isEmpty(s) && s.charAt(0) == first && s.length() >= i && s.length() <= j) { - result.add(s); - } + dictionary.traverse(s -> { + if (!StringUtil.isEmpty(s) && s.charAt(0) == first && s.length() >= i && s.length() <= j) { + result.add(s); } }); } @@ -268,9 +251,6 @@ public class BaseSpellChecker implements SpellCheckerEngine { @Nullable public Dictionary getBundledDictionaryByName(@NotNull String name) { - if (bundledDictionaries == null) { - return null; - } for (Dictionary dictionary : bundledDictionaries) { if (name.equals(dictionary.getName())) { return dictionary; @@ -278,4 +258,4 @@ public class BaseSpellChecker implements SpellCheckerEngine { } return null; } -} +} \ No newline at end of file diff --git a/spellchecker/src/com/intellij/spellchecker/engine/Suggestion.java b/spellchecker/src/com/intellij/spellchecker/engine/Suggestion.java index c88507c05990..71d4d9a3876b 100644 --- a/spellchecker/src/com/intellij/spellchecker/engine/Suggestion.java +++ b/spellchecker/src/com/intellij/spellchecker/engine/Suggestion.java @@ -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. @@ -16,8 +16,9 @@ package com.intellij.spellchecker.engine; import com.intellij.openapi.util.text.StringUtil; +import org.jetbrains.annotations.NotNull; -public class Suggestion implements Comparable{ +public class Suggestion implements Comparable { private final String word; private final int metrics; @@ -30,7 +31,6 @@ public class Suggestion implements Comparable{ return word; } - public int getMetrics() { return metrics; } @@ -55,21 +55,14 @@ public class Suggestion implements Comparable{ return result; } - @Override - public int compareTo(Object o) { - if (!(o instanceof Suggestion)) throw new IllegalArgumentException(); - Suggestion r = (Suggestion)o; - int c = new Integer(getMetrics()).compareTo(r.getMetrics()); - if (c !=0) return c; - return StringUtil.compare(word, r.word, true); + public int compareTo(@NotNull Suggestion o) { + int c = new Integer(getMetrics()).compareTo(o.getMetrics()); + return c != 0 ? c : StringUtil.compare(word, o.word, true); } @Override public String toString() { return word + " : " + metrics; } -} - - - +} \ No newline at end of file From 088851c3f300251b14b57f5a24070206d1cc0d71 Mon Sep 17 00:00:00 2001 From: Dmitry Trofimov Date: Mon, 21 Mar 2016 16:47:17 +0100 Subject: [PATCH 76/81] Don't send ESC when ALT pressed for non cursor keys (IDEA-152291) --- plugins/terminal/lib/jediterm-pty-2.1.jar | Bin 251117 -> 251189 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/plugins/terminal/lib/jediterm-pty-2.1.jar b/plugins/terminal/lib/jediterm-pty-2.1.jar index 6460d2ac6cda7604c50ae4bee059e98c2f9bf5d0..a7423f50a1422b1b072d399542a798a4cc62e633 100644 GIT binary patch delta 41384 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

JwWvI_0^hum?j=U_4OpNi{DQFvzEywZNxorL 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 Date: Mon, 21 Mar 2016 17:00:36 +0100 Subject: [PATCH 77/81] Don't show horizontal scrollbar in python console editor until it is scrolling is implemented properly (PY-18440) --- .../python/console/PythonConsoleView.java | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/python/src/com/jetbrains/python/console/PythonConsoleView.java b/python/src/com/jetbrains/python/console/PythonConsoleView.java index a8a18a59ec76..486354e26c83 100644 --- a/python/src/com/jetbrains/python/console/PythonConsoleView.java +++ b/python/src/com/jetbrains/python/console/PythonConsoleView.java @@ -25,6 +25,7 @@ import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.editor.Editor; import com.intellij.openapi.editor.colors.EditorColorsScheme; +import com.intellij.openapi.editor.ex.EditorEx; import com.intellij.openapi.progress.ProgressIndicator; import com.intellij.openapi.progress.ProgressManager; import com.intellij.openapi.progress.Task; @@ -36,6 +37,7 @@ import com.intellij.openapi.util.text.StringUtil; import com.intellij.openapi.vfs.LocalFileSystem; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.openapi.wm.IdeFocusManager; +import com.intellij.testFramework.LightVirtualFile; import com.intellij.ui.JBSplitter; import com.intellij.util.TimeoutUtil; import com.intellij.util.ui.UIUtil; @@ -73,7 +75,7 @@ public class PythonConsoleView extends LanguageConsoleImpl implements Observable private XStandaloneVariablesView mySplitView; public PythonConsoleView(final Project project, final String title, final Sdk sdk) { - super(project, title, PythonLanguage.getInstance()); + super(new MyHelper(project, title, PythonLanguage.getInstance())); getVirtualFile().putUserData(LanguageLevel.KEY, PythonSdkType.getLanguageLevelForSdk(sdk)); // Mark editor as console one, to prevent autopopup completion @@ -309,4 +311,16 @@ public class PythonConsoleView extends LanguageConsoleImpl implements Observable validate(); repaint(); } + + private static class MyHelper extends Helper { + public MyHelper(@NotNull Project project, String title, PythonLanguage language) { + super(project, new LightVirtualFile(title, language, "")); + } + + @Override + public void setupEditor(@NotNull EditorEx editor) { + super.setupEditor(editor); + editor.setHorizontalScrollbarVisible(false); + } + } } From 755871e3f3f3bd0dc922d97645822dab71810003 Mon Sep 17 00:00:00 2001 From: Elizaveta Shashkova Date: Mon, 21 Mar 2016 19:21:56 +0300 Subject: [PATCH 78/81] The correct way to ignore libraries, even if virtual env is situated inside project directory (PY-16899) --- .../pydev/_pydevd_bundle/pydevd_utils.py | 19 +++++++++++++++ .../python/debugger/PyDebugRunner.java | 23 ++++++++++++++++--- 2 files changed, 39 insertions(+), 3 deletions(-) diff --git a/python/helpers/pydev/_pydevd_bundle/pydevd_utils.py b/python/helpers/pydev/_pydevd_bundle/pydevd_utils.py index 4fe32e1cb496..ef5c96f312a7 100644 --- a/python/helpers/pydev/_pydevd_bundle/pydevd_utils.py +++ b/python/helpers/pydev/_pydevd_bundle/pydevd_utils.py @@ -132,6 +132,18 @@ def _get_project_roots(project_roots_cache=[]): return project_roots_cache[-1] # returns the project roots with case normalized +def _get_library_roots(library_roots_cache=[]): + # Note: the project_roots_cache is the same instance among the many calls to the method + if not library_roots_cache: + roots = os.getenv('LIBRARY_ROOTS', '').split(os.pathsep) + pydev_log.debug("LIBRARY_ROOTS %s\n" % roots) + new_roots = [] + for root in roots: + new_roots.append(os.path.normcase(root)) + library_roots_cache.append(new_roots) + return library_roots_cache[-1] # returns the project roots with case normalized + + def not_in_project_roots(filename, filename_to_not_in_scope_cache={}): # Note: the filename_to_not_in_scope_cache is the same instance among the many calls to the method try: @@ -146,6 +158,13 @@ def not_in_project_roots(filename, filename_to_not_in_scope_cache={}): else: # for else (only called if the break wasn't reached). filename_to_not_in_scope_cache[filename] = True + if not filename_to_not_in_scope_cache[filename]: + # additional check if interpreter is situated in a project directory + library_roots = _get_library_roots() + for root in library_roots: + if filename.startswith(root): + filename_to_not_in_scope_cache[filename] = True + # at this point it must be loaded. return filename_to_not_in_scope_cache[filename] diff --git a/python/src/com/jetbrains/python/debugger/PyDebugRunner.java b/python/src/com/jetbrains/python/debugger/PyDebugRunner.java index fb2270d17bd2..a25b47238dc7 100644 --- a/python/src/com/jetbrains/python/debugger/PyDebugRunner.java +++ b/python/src/com/jetbrains/python/debugger/PyDebugRunner.java @@ -16,9 +16,7 @@ package com.jetbrains.python.debugger; import com.google.common.collect.Lists; -import com.intellij.execution.ExecutionException; -import com.intellij.execution.ExecutionResult; -import com.intellij.execution.Executor; +import com.intellij.execution.*; import com.intellij.execution.configurations.*; import com.intellij.execution.console.LanguageConsoleBuilder; import com.intellij.execution.executors.DefaultDebugExecutor; @@ -30,6 +28,7 @@ import com.intellij.execution.ui.RunContentDescriptor; import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.fileEditor.FileDocumentManager; import com.intellij.openapi.project.Project; +import com.intellij.openapi.roots.OrderRootType; import com.intellij.openapi.roots.ProjectRootManager; import com.intellij.openapi.util.text.StringUtil; import com.intellij.openapi.vfs.VirtualFile; @@ -68,6 +67,7 @@ public class PyDebugRunner extends GenericProgramRunner { public static final String FILE_PARAM = "--file"; public static final String MODULE_PARAM = "--module"; public static final String IDE_PROJECT_ROOTS = "IDE_PROJECT_ROOTS"; + public static final String LIBRARY_ROOTS = "LIBRARY_ROOTS"; public static final String PYTHON_ASYNCIO_DEBUG = "PYTHONASYNCIODEBUG"; @SuppressWarnings("SpellCheckingInspection") public static final String GEVENT_SUPPORT = "GEVENT_SUPPORT"; @@ -301,6 +301,7 @@ public class PyDebugRunner extends GenericProgramRunner { } addProjectRootsToEnv(project, cmd); + addSdkRootsToEnv(project, cmd); final String[] debuggerArgs = new String[]{ CLIENT_PARAM, "127.0.0.1", @@ -347,4 +348,20 @@ public class PyDebugRunner extends GenericProgramRunner { commandLine.getEnvironment().put(IDE_PROJECT_ROOTS, StringUtil.join(roots, File.pathSeparator)); } + + private static void addSdkRootsToEnv(@NotNull Project project, @NotNull GeneralCommandLine commandLine) { + final RunManager runManager = RunManager.getInstance(project); + final RunnerAndConfigurationSettings selectedConfiguration = runManager.getSelectedConfiguration(); + if (selectedConfiguration != null) { + final RunConfiguration configuration = selectedConfiguration.getConfiguration(); + if (configuration instanceof AbstractPythonRunConfiguration) { + AbstractPythonRunConfiguration runConfiguration = (AbstractPythonRunConfiguration)configuration; + List roots = Lists.newArrayList(); + for (VirtualFile contentRoot : runConfiguration.getSdk().getSdkModificator().getRoots(OrderRootType.CLASSES)) { + roots.add(contentRoot.getPath()); + } + commandLine.getEnvironment().put(LIBRARY_ROOTS, StringUtil.join(roots, File.pathSeparator)); + } + } + } } From cc438adc3ba5b2200d7e1e484b7c62ddd96fc5da Mon Sep 17 00:00:00 2001 From: Dmitry Batrak Date: Mon, 21 Mar 2016 19:25:21 +0300 Subject: [PATCH 79/81] IDEA-65904 make editor actions not reveal information about password field contents --- .../actions/SelectWordAtCaretAction.java | 13 +++++++-- .../editor/actions/NextPrevWordHandler.java | 28 ++++++++++++------- .../openapi/editor/ex/util/EditorUtil.java | 4 +++ 3 files changed, 32 insertions(+), 13 deletions(-) diff --git a/platform/lang-impl/src/com/intellij/openapi/editor/actions/SelectWordAtCaretAction.java b/platform/lang-impl/src/com/intellij/openapi/editor/actions/SelectWordAtCaretAction.java index 2d84961be490..020b3a2ba9aa 100644 --- a/platform/lang-impl/src/com/intellij/openapi/editor/actions/SelectWordAtCaretAction.java +++ b/platform/lang-impl/src/com/intellij/openapi/editor/actions/SelectWordAtCaretAction.java @@ -30,6 +30,7 @@ import com.intellij.openapi.actionSystem.DataContext; import com.intellij.openapi.editor.*; import com.intellij.openapi.editor.actionSystem.EditorActionHandler; import com.intellij.openapi.editor.ex.EditorEx; +import com.intellij.openapi.editor.ex.util.EditorUtil; import com.intellij.openapi.editor.highlighter.HighlighterIterator; import com.intellij.openapi.project.DumbAware; import com.intellij.openapi.util.TextRange; @@ -53,9 +54,16 @@ public class SelectWordAtCaretAction extends TextComponentEditorAction implement @Override public void doExecute(Editor editor, @Nullable Caret caret, DataContext dataContext) { + SelectionModel selectionModel = editor.getSelectionModel(); + Document document = editor.getDocument(); + + if (EditorUtil.isPasswordEditor(editor)) { + selectionModel.setSelection(0, document.getTextLength()); + return; + } + int lineNumber = editor.getCaretModel().getLogicalPosition().line; int caretOffset = editor.getCaretModel().getOffset(); - Document document = editor.getDocument(); if (lineNumber >= document.getLineCount()) { return; } @@ -72,10 +80,9 @@ public class SelectWordAtCaretAction extends TextComponentEditorAction implement if (ranges.isEmpty()) return; - SelectionModel selectionModel = editor.getSelectionModel(); final TextRange selectionRange = new TextRange(selectionModel.getSelectionStart(), selectionModel.getSelectionEnd()); - TextRange minimumRange = new TextRange(0, editor.getDocument().getTextLength()); + TextRange minimumRange = new TextRange(0, document.getTextLength()); for (TextRange range : ranges) { if (range.contains(selectionRange) && !range.equals(selectionRange)) { if (minimumRange.contains(range)) { diff --git a/platform/platform-impl/src/com/intellij/openapi/editor/actions/NextPrevWordHandler.java b/platform/platform-impl/src/com/intellij/openapi/editor/actions/NextPrevWordHandler.java index c4fb7417d770..84d669bd8303 100644 --- a/platform/platform-impl/src/com/intellij/openapi/editor/actions/NextPrevWordHandler.java +++ b/platform/platform-impl/src/com/intellij/openapi/editor/actions/NextPrevWordHandler.java @@ -20,6 +20,7 @@ import com.intellij.openapi.editor.Caret; import com.intellij.openapi.editor.Editor; import com.intellij.openapi.editor.VisualPosition; import com.intellij.openapi.editor.actionSystem.EditorActionHandler; +import com.intellij.openapi.editor.ex.util.EditorUtil; import org.jetbrains.annotations.Nullable; class NextPrevWordHandler extends EditorActionHandler { @@ -37,21 +38,28 @@ class NextPrevWordHandler extends EditorActionHandler { @Override protected void doExecute(Editor editor, @Nullable Caret caret, DataContext dataContext) { assert caret != null; - VisualPosition currentPosition = caret.getVisualPosition(); - if (caret.isAtBidiRunBoundary() && (myNext ^ currentPosition.leansRight)) { + if (EditorUtil.isPasswordEditor(editor)) { int selectionStartOffset = caret.getLeadSelectionOffset(); - VisualPosition selectionStartPosition = caret.getLeadSelectionPosition(); - caret.moveToVisualPosition(currentPosition.leanRight(!currentPosition.leansRight)); - if (myWithSelection) { - caret.setSelection(selectionStartPosition, selectionStartOffset, caret.getVisualPosition(), caret.getOffset()); - } + caret.moveToOffset(myNext ? editor.getDocument().getTextLength() : 0); + if (myWithSelection) caret.setSelection(selectionStartOffset, caret.getOffset()); } else { - if (myNext ^ caret.isAtRtlLocation()) { - EditorActionUtil.moveCaretToNextWord(editor, myWithSelection, myInDifferentHumpsMode ^ editor.getSettings().isCamelWords()); + VisualPosition currentPosition = caret.getVisualPosition(); + if (caret.isAtBidiRunBoundary() && (myNext ^ currentPosition.leansRight)) { + int selectionStartOffset = caret.getLeadSelectionOffset(); + VisualPosition selectionStartPosition = caret.getLeadSelectionPosition(); + caret.moveToVisualPosition(currentPosition.leanRight(!currentPosition.leansRight)); + if (myWithSelection) { + caret.setSelection(selectionStartPosition, selectionStartOffset, caret.getVisualPosition(), caret.getOffset()); + } } else { - EditorActionUtil.moveCaretToPreviousWord(editor, myWithSelection, myInDifferentHumpsMode ^ editor.getSettings().isCamelWords()); + if (myNext ^ caret.isAtRtlLocation()) { + EditorActionUtil.moveCaretToNextWord(editor, myWithSelection, myInDifferentHumpsMode ^ editor.getSettings().isCamelWords()); + } + else { + EditorActionUtil.moveCaretToPreviousWord(editor, myWithSelection, myInDifferentHumpsMode ^ editor.getSettings().isCamelWords()); + } } } } diff --git a/platform/platform-impl/src/com/intellij/openapi/editor/ex/util/EditorUtil.java b/platform/platform-impl/src/com/intellij/openapi/editor/ex/util/EditorUtil.java index 7ca257da3030..4fc821552145 100644 --- a/platform/platform-impl/src/com/intellij/openapi/editor/ex/util/EditorUtil.java +++ b/platform/platform-impl/src/com/intellij/openapi/editor/ex/util/EditorUtil.java @@ -65,6 +65,10 @@ public final class EditorUtil { return editor != null && TextEditorProvider.getInstance().getTextEditor(editor) instanceof TextEditorImpl; } + public static boolean isPasswordEditor(@Nullable Editor editor) { + return editor != null && editor.getContentComponent() instanceof JPasswordField; + } + public static int getLastVisualLineColumnNumber(@NotNull Editor editor, final int line) { if (editor instanceof EditorImpl && ((EditorImpl)editor).myUseNewRendering) { LogicalPosition lineEndPosition = editor.visualToLogicalPosition(new VisualPosition(line, Integer.MAX_VALUE)); From a12d8c39d247e68c67a7ec99e736bd8b8956f4ea Mon Sep 17 00:00:00 2001 From: Dmitry Trofimov Date: Mon, 21 Mar 2016 17:47:44 +0100 Subject: [PATCH 80/81] Always send ESC for backspace https://github.com/JetBrains/jediterm/commit/030bf2b97dafac76ea6106ec27ce3f8601779546 --- plugins/terminal/lib/jediterm-pty-2.1.jar | Bin 251189 -> 251240 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/plugins/terminal/lib/jediterm-pty-2.1.jar b/plugins/terminal/lib/jediterm-pty-2.1.jar index a7423f50a1422b1b072d399542a798a4cc62e633..ed7656f50d297dc2b0db990158f7bb865ccdccc0 100644 GIT binary patch delta 10352 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 delta 10580 zcmZWu2Rv5a8-MS;_KY;FkPs4DL`s7usbrMUq$%x%hN9BY8>f_&k&GzxibP8aQBkR= zXc3kE8XEdP=bTr5Z`FtA-0$;!#(B=T=N@lU6?0P+<(#H+Vlq6Q6pxn}94=?bCIp9D zd|?xV`KF8sJn%i4Ay|a71JUy+PJ&;|$l&L4#u^K0c03l2>{v>&#Fl03a4cAEG#2AH z3lP~`Ia3zPbn!efESJdm5?Q5C#e!}2DJ3g0EbDu{#?SnczTfa;vFaOf{CGy|7k*69 zcEQ^7x~>d?6+TAat*sEE!zXEf0CFityL&ZHi@ z%5E8=&l1+prG_&Y2_A2e96x+BAt`209j+vSNuJgPBpr3zR3dLq2qh6`*e@aS;>2Op zNo`B+wBDbLX?Oi zRfuCzLBXU2h10&r6?~0Z`~Kpyk#DSBzncF3bxmP=;7_-b^{PW>3_KR$ue-0ul6U?+ z)&?!eGu)#!VPyIK7m86>>_IGYQ zF;CCp!K7C;M_vW@a&$~IXfYf5#VX(FLVLrc@LGP4N!fEg9r4VKemnWl5c74ntzLfG zUovmJY1RDbLWh>P@7rgrv-MP369007;?RIc>(}1Tip+GexP7ZVC8%-Ol4Ev--cQ0l zwrnxlFq=8B)B8&D_*Yf6mv&A0W>7xfu1?L+y~8kIp7WGazrA^j>Qo}!7iH|;9m0hS zI~2FqKGW=!&YOq{KA)1t*%vJejnWFpO*IfxbRT(TXVSJn!?e?u6|X9)ce+&1(!CKj ze|18I%gVYbP0RC_CS4CS-y0t!X~ei*3~)Cd%ztKnX>X(Xx_Ik7iGB4y28IP>l&qd3 z=hqk({POoy8`X82w0`zpnB{cjT<>dEqxZ#!Nt$2UwNWo;i?-vj#DlVHZNH;_YNjJNb$&N*LV`VahJ=Tm#(!- zQx#*RwUmBn-rVG1d}-CYs(oUQbzW@s5dUcP&@ZSu{ZRbm)d$}xY^}Sc)#Ovj|MIoR z`b6WKo-)68oB2qUpE2#>{5!Pjr);&&L^pYxkaUSy-BS_*r_5D4x1TY?`$-4%j8-hM zNEY;%)tEMaYtppJkcRvB|F^zPQKKUu^JkQ<>84i?H8YlHf)LxlqewudRlSAg3IQ!ZcH#XFUYkj?KD&65a z;zNCd@8gz$1B%C%40|r6kg&UarQY%{s z-;$a$+30&_`H9wVBLjCPwuhnjUU!XusR!(kaul=jAF`VHwL{%<_vo13YmXi1Imut| z#mm9(+OE&H88*EB)#Cclo=*3Swbs9^^XxdL`=R}|>3auT*|~izuc^rOD0TNJ(f0Cr zlWH43d;6E5K2`0bZSVi!1vz}+h83Dt>9B>iao5DYE9|)ZPPW}y{B5$Vvw>;R=jrow zJ71j8HR^1Nt+xMJC$RF&S~%dI-A>h;y*&B{)Tc3NuEjB(j#*8=ij%)`C+ZbfZ1Kwa z(6go2&ghq$BD_y;D;}+E%JpfH7t`tYxT5)?l<^bG_6H->Jp1>%UXl84U{F!+% zD>wRC&h^;1V1)PY$)UCGLrjZ1Ms9m%(=eBnZJYbpra@1Q`_?lm`Fm%WRg>zCPkk=^ zjOgPVD5s}%Xwy55A@=2j4cEaOuFY zMtT396aDvJNxXIC$+0UTj#=yR`>2da*;l~b5~`FXQ+<@b?KLXI!?(z=nksWY?VW}Eux4S`dioF1N}mXocwO)l@3_TD}h z_uuip5IkFP`ij|&cdbt3N!nRVw9_49r<ZnBno>^Q-0=Wlx$JLEiVzW>pY*c6KF^L9VCCv1Q<#+YC8O zeDHW*wHM6PIsV;whR7+Llgu{r;1lwVc}YaB@Jgm+$4z=`!hozv$k~(UM-%pJWEGOi;+I)MGv^JljHH)BTQ2EwYV; z!P5Tumhfacr(s^M8{>ne;0nvUprfWQ&dX^7#|JswXDdOo7{e0EdkMylG=@tvudx$> zrYvJc5O;aTmNZT%GUG_&nUWCEQDIW>SyND^#)K%~hO;5l7k6H;Y7ldtc4l**MwxjK zb3E>hK0k<+K#D^dS>%<($qM|;86Ohv(GcbVX=Dv!ibxcH3x*}G)>|=FM0L)ZQ6)(E zXl4~2A;GALOdBDaPGJyHl{zpp38LY|^dY$ocVQHXxxFj%+ZbC-+{HMOY*9GlgTDnX zoMepf8CftWjuDW?t3*a08zK2*rk#w*5FO>^42+rwjd##j-1Feqdiuy5JRObb4}3p%bbN`xy{%DDEz$l^Lio1_?0&u9?q zr02{C(x_`-+(^UX74wU5M!aFxlCGvTGcu$hXl2X@r|AQ8jUZ?LCq$lqW(E*MqJx=4 zf;#~NuvTM@NyArz-A>{*Yq1Q8+p5c25S6|@D?#co*qB{Ioqki?^u!H5 zV>;#d^S^4K!y2rz;OQWCg9KSGwHh5~jwthZKZo*_{D@Xba9}8VN*QNnZqL?;!`GNV zY8q>TKhFdfj_e~2H%BI4Y{qX1V<7ZxI4sU6l_;UQfP-2>_I)QaJmAoK-PiyI=h3NPYjfH zu_y4Srr>M{`&k8dJLx1lomBHn3@eX!8G(2TYeLAw&amNR>fTIcn@IsD=fzcK!wU4` z@CTlWpe2pHP76P>uu`WD3ez99%ag1DdS1**3R*H)y6`?`v2J7#r{u6>NMpZ%eM}~y z&qa1MiCz9g+}s=tK>hM$($}kkuzXSJ$$1 z+1!4D2Nn^}7}i^7C?wYL9*1(5jw zaXK!mAF@iQzMNAPBz+Qgv*%~wvN`dUwIk*YKiK#9NH&Fl3--ohUL$ z<-tHRG^Tf~N z4pM(H2RT>ry7+Ucg4jdcbZwDi8B8oAmmj~OYA7^5U0V$&BD+6=))nd zrxrHtW4%x*6b4)a_6p-JJCKPx{E*IJ&I()3I}Db#uGmr!#U18)lAzPSZ4Sm~K~=oV zh*&nc6Doh+97**1Feit7$cKZE+_}^T8~~}0eI_dzFYrZy2OS0F0slWrwC1R=e?BQ%pY)(KR1$SXm$T*Vg zO9~d!LOsVL@N)aO5LZUc;05=+6XP|}eE+O|XsFP(_8E~mfse%fH ziZZMSzucveL%mN@cSa{cvHdDle7xEV1)ij?!mwgaIZ>dplbjkUia}V5!L9xFuFhA$ceT$Z!Z5N_6I430o+jtkdJRCTEObExWS zsOl&Y``%wE6$TiebkL3%uy^X9V2u!bhe7@i3XX~8R7f8ZKEEqz2d9Vsaa#6^Q29=s zQs~S%T8E-o@S(~>ZKt`u@C~Mq)Z?haFb)(u*)Byt6c8uOy8H8q$Fmm6da+nH{WZ{W z=0C8XOo?vA^!TnFW5ST9hak}}u!cqbe39y==K&r2sfY(Z^)lUx1vy+#Dg0WHIZ~X9 z6cV`JteSkcI#!;MMBi@H&cvPqV-Lk{?f*_uuTlx1h*RoTcqCATKUOsK>{4i=>j`v5 zJ;I7GwQfZZbw*ObX)432aQN>p`0@eSCIYFKVHZgW9WZ2ipxX(;d9!}2;)^-3Ps+;v zJ?^H1L~LZxmqe})?!ICYcx*Hy+Q^}d8vbx3icMH?d`OqV1U*TjeQv@E|6yGU71T0} zkwasWsn#JGv_mYqwHX$S%-`L}#H0~cT_i=6ZpEm>=Q?$vc^b59tg*HqdS=Ziqvb-) zW~@0d`j18i6`dCDi@LsT+mc|wkHfw%`U?7GkNM;kWS#={A1C8yW3(lOj>sVl?scHx zBO%y|!Mf=bbai5SqiJVoc5}{v=F4oVS?$8~BpW9=N2Gl?yCN435EVY~{t=nLlIX=5 zdT!HB1#_ug*t{R|Nae^zx)p|$CnECXIdRU3*jnm{?W)FpH#Xie_)M%9U7Yj#~qtY&VaZ#FWp{P0~?G441wr* zaZ){{7SuD+e^2_NOz^ejIVKE2idmd8>CfrQvEJe^Z?A$c3z1Y~kZl%ck1HFR1(x4l zQp-nKblSFJ@at;|+ME;aeG_l^4G{>JfvCF`&6L{O4Eq<}rAb$^t2fv_fv#vk_>m&v zH?>l}BuZc7+Eaf z${I`(`-k+9MdmpWxde85+`T6`5X4KIg3rX+f41H+xj=X;NeKsYg<14FdVa)PSQ=4k zJl-&o`Yk}kx!ictf59H7(`is7GnkU5BBYbOkoiSeZVnfO zkIh9FAgQ0KR3j;%UC|H#XsAKKMM7{h2Gihr4ToEQNf^%SnU~Tt$n57o@AR{}lBSw{XSZV%r4Ro)_{v(*=s1a zG(^`g3SWj8{A7oVt&TkG**^4iif@}Hd==As3@ID^vtVvbMRyB1GZdT;GZwyHPvnD> zZw?e}%7@|r*onb=GblK%fP(W20G#DaLAbfae+yre* zIy1`fk~ffk|3flyr~YuUapZlMAjtE%6!h|dQG9j@iU*ojteNgfHFrEgL(UhVaVi8& zvp3bm6bci|xGlNXA7XBX^)yZ-F?Uo|$ju6M5xyGsC{bKGl00l9BKnY|T3wQ4+*MuAEN!@kQPa&0DNJ(_^l$`#Lk@t1D z!=`JJy7zQqA{NR_X7T%X3Uvmxc*OXy6T+_^2BIuFare@C~{< z9LM0fEDF8=kZe)uM~j$t7-Kz{2%=k*Y!0Q4E)i~d&QD*A#mDPXpo>zcq17eypp{hu zK?Yu=mfyeoHh!6N84xp%iA=pj&i%v$_SEvNEdKaZ4Dw z`yTc0qm1qyN`;$M+M(_{)qkiplsfV@O~Uaugpz(p!3ZIkib3;Q3bp}As+7118Pvi^ zl)w@fJ#X%RLa7dALaI&v61@&szx{jsP0gyK)H6WEMYvoBp+3K);L2C5I?^tuMHpNT zn(`*9f$LfYG%Hki`tH8bU8}=(nuLSIWOw!Rg@4pMnXS@B@PbQU5!_)SiS~DsF%{K2RvpH#FY@ zy{O{UBTG4XwCxUE*2nIEkDHc6fvQfjQmFP0r%E=|?n~ysPknkwsS<7pVP|ou1oOVu z|1pQVWeu!J$8w>Ks74yq+i;TTS0#N9$W{SI*H)ARr4a5zzF0ln?mud{mF`P&i*x<- zMhu3x4}1{li4?T}J+I=1kzKNBUxua(kVe8B5Uo7xfa34MCz01(u0QcNuFZAcY#5{o zaBi{_@wXJk-Q}Fg$lQ7+-w^>yC8(^W2ua5U`x}5P?{WR{$avg?%;j7u805;qpPBB{ zE|+4>3^%Hgxz7zG=LUlh&WU{?{HcGAB?V~4eKa;k9sw#V@Ad(q#XqDJc2okume^IrQOP5D}`7fP?Db3Y%eBi8>>i=!{q o^pqiA1Dcsz{%FL|~{Z>Oo^P--6UDf}NclgE39|8CCvKh!JqkN^Mx From bbc9b62df087f383c884da99c742100f9841968e Mon Sep 17 00:00:00 2001 From: Pavel Dolgov Date: Mon, 21 Mar 2016 20:50:14 +0300 Subject: [PATCH 81/81] Javafx: Simplify tests on event handler methods' signature. Implement quick fix that corrects the event handler method's signature. Move reused code to utility class. Add tests for the quick fix. (IDEA-151694) --- .../JavaFxEventHandlerInspectionTest.java | 36 +++- .../src/META-INF/common-javaFX-plugin.xml | 2 +- .../plugins/javaFX/fxml/JavaFxPsiUtil.java | 63 ++++-- .../JavaFxEventHandlerInspection.java | 200 +++++++----------- .../refs/JavaFxEventHandlerReference.java | 44 ++-- ...ontroller.java => HighlightAmbiguous.java} | 2 +- ...actController.java => HighlightExact.java} | 2 +- ...cController.java => HighlightGeneric.java} | 2 +- .../eventHandler/HighlightHalfRaw.java | 15 ++ .../HighlightMixedGenericController.java | 37 ---- ...dController.java => HighlightNonVoid.java} | 2 +- .../eventHandler/HighlightRaw.java | 13 ++ .../eventHandler/HighlightSpecific.java | 15 ++ ...Controller.java => HighlightWildcard.java} | 2 +- .../eventHandler/QuickfixHalfRaw.java | 7 + .../eventHandler/QuickfixHalfRaw_after.java | 12 ++ .../inspections/eventHandler/QuickfixRaw.java | 6 + .../eventHandler/QuickfixRaw_after.java | 11 + .../eventHandler/QuickfixSpecific.java | 8 + .../eventHandler/QuickfixSpecific_after.java | 13 ++ .../eventHandler/highlightAmbiguous.fxml | 2 +- .../eventHandler/highlightExact.fxml | 4 +- ...mpleGeneric.fxml => highlightGeneric.fxml} | 2 +- .../eventHandler/highlightHalfRaw.fxml | 10 + .../eventHandler/highlightMixedGeneric.fxml | 71 ------- .../eventHandler/highlightNonVoid.fxml | 2 +- .../eventHandler/highlightRaw.fxml | 11 + .../eventHandler/highlightSpecific.fxml | 10 + .../eventHandler/highlightWildcard.fxml | 6 +- .../eventHandler/quickfixHalfRaw.fxml | 5 + .../inspections/eventHandler/quickfixRaw.fxml | 5 + .../eventHandler/quickfixSpecific.fxml | 5 + 32 files changed, 327 insertions(+), 298 deletions(-) rename plugins/javaFX/testData/inspections/eventHandler/{HighlightAmbiguousController.java => HighlightAmbiguous.java} (88%) rename plugins/javaFX/testData/inspections/eventHandler/{HighlightExactController.java => HighlightExact.java} (91%) rename plugins/javaFX/testData/inspections/eventHandler/{HighlightSimpleGenericController.java => HighlightGeneric.java} (84%) create mode 100644 plugins/javaFX/testData/inspections/eventHandler/HighlightHalfRaw.java delete mode 100644 plugins/javaFX/testData/inspections/eventHandler/HighlightMixedGenericController.java rename plugins/javaFX/testData/inspections/eventHandler/{HighlightNonVoidController.java => HighlightNonVoid.java} (84%) create mode 100644 plugins/javaFX/testData/inspections/eventHandler/HighlightRaw.java create mode 100644 plugins/javaFX/testData/inspections/eventHandler/HighlightSpecific.java rename plugins/javaFX/testData/inspections/eventHandler/{HighlightWildcardController.java => HighlightWildcard.java} (90%) create mode 100644 plugins/javaFX/testData/inspections/eventHandler/QuickfixHalfRaw.java create mode 100644 plugins/javaFX/testData/inspections/eventHandler/QuickfixHalfRaw_after.java create mode 100644 plugins/javaFX/testData/inspections/eventHandler/QuickfixRaw.java create mode 100644 plugins/javaFX/testData/inspections/eventHandler/QuickfixRaw_after.java create mode 100644 plugins/javaFX/testData/inspections/eventHandler/QuickfixSpecific.java create mode 100644 plugins/javaFX/testData/inspections/eventHandler/QuickfixSpecific_after.java rename plugins/javaFX/testData/inspections/eventHandler/{highlightSimpleGeneric.fxml => highlightGeneric.fxml} (90%) create mode 100644 plugins/javaFX/testData/inspections/eventHandler/highlightHalfRaw.fxml delete mode 100644 plugins/javaFX/testData/inspections/eventHandler/highlightMixedGeneric.fxml create mode 100644 plugins/javaFX/testData/inspections/eventHandler/highlightRaw.fxml create mode 100644 plugins/javaFX/testData/inspections/eventHandler/highlightSpecific.fxml create mode 100644 plugins/javaFX/testData/inspections/eventHandler/quickfixHalfRaw.fxml create mode 100644 plugins/javaFX/testData/inspections/eventHandler/quickfixRaw.fxml create mode 100644 plugins/javaFX/testData/inspections/eventHandler/quickfixSpecific.fxml diff --git a/plugins/javaFX/javaFX-CE/testSrc/org/jetbrains/plugins/javaFX/fxml/JavaFxEventHandlerInspectionTest.java b/plugins/javaFX/javaFX-CE/testSrc/org/jetbrains/plugins/javaFX/fxml/JavaFxEventHandlerInspectionTest.java index d7548ba56ba9..b16ff99fff5b 100644 --- a/plugins/javaFX/javaFX-CE/testSrc/org/jetbrains/plugins/javaFX/fxml/JavaFxEventHandlerInspectionTest.java +++ b/plugins/javaFX/javaFX-CE/testSrc/org/jetbrains/plugins/javaFX/fxml/JavaFxEventHandlerInspectionTest.java @@ -1,6 +1,8 @@ package org.jetbrains.plugins.javaFX.fxml; +import com.intellij.codeInsight.intention.IntentionAction; import com.intellij.openapi.application.PluginPathManager; +import com.intellij.testFramework.PlatformTestUtil; import org.jetbrains.annotations.NotNull; import org.jetbrains.plugins.javaFX.fxml.codeInsight.inspections.JavaFxEventHandlerInspection; @@ -30,11 +32,19 @@ public class JavaFxEventHandlerInspectionTest extends AbstractJavaFXTestCase { doHighlightingTest(); } - public void testHighlightSimpleGeneric() throws Exception { + public void testHighlightGeneric() throws Exception { doHighlightingTest(); } - public void testHighlightMixedGeneric() throws Exception { + public void testHighlightRaw() throws Exception { + doHighlightingTest(); + } + + public void testHighlightHalfRaw() throws Exception { + doHighlightingTest(); + } + + public void testHighlightSpecific() throws Exception { doHighlightingTest(); } @@ -42,11 +52,31 @@ public class JavaFxEventHandlerInspectionTest extends AbstractJavaFXTestCase { doHighlightingTest(); } + public void testQuickfixRaw() throws Exception { + doQuickfixTest("Create method 'void onSort(SortEvent)'"); + } + + public void testQuickfixHalfRaw() throws Exception { + doQuickfixTest("Create method 'void onSort(SortEvent)'"); + } + + public void testQuickfixSpecific() throws Exception { + doQuickfixTest("Create method 'void onSort(SortEvent)'"); + } + private void doHighlightingTest() throws Exception { - myFixture.configureByFiles(getTestName(true) + ".fxml", getTestName(false) + "Controller.java"); + myFixture.configureByFiles(getTestName(true) + ".fxml", getTestName(false) + ".java"); myFixture.checkHighlighting(); } + private void doQuickfixTest(final String actionName) throws Exception { + String path = getTestName(true) + ".fxml"; + final IntentionAction intention = myFixture.getAvailableIntention(actionName, path, getTestName(false) + ".java"); + assertNotNull(intention); + myFixture.launchAction(intention); + myFixture.checkResultByFile(getTestName(false) + ".java", getTestName(false) + "_after.java", true); + } + @NotNull @Override protected String getTestDataPath() { diff --git a/plugins/javaFX/src/META-INF/common-javaFX-plugin.xml b/plugins/javaFX/src/META-INF/common-javaFX-plugin.xml index 4254ed7768e6..ab49b0351667 100644 --- a/plugins/javaFX/src/META-INF/common-javaFX-plugin.xml +++ b/plugins/javaFX/src/META-INF/common-javaFX-plugin.xml @@ -26,7 +26,7 @@ enabledByDefault="true" level="WARNING" displayName="JavaFX redundant property values" groupName="JavaFX"/> - diff --git a/plugins/javaFX/src/org/jetbrains/plugins/javaFX/fxml/JavaFxPsiUtil.java b/plugins/javaFX/src/org/jetbrains/plugins/javaFX/fxml/JavaFxPsiUtil.java index 74ace5e83b0d..59516d09cc67 100644 --- a/plugins/javaFX/src/org/jetbrains/plugins/javaFX/fxml/JavaFxPsiUtil.java +++ b/plugins/javaFX/src/org/jetbrains/plugins/javaFX/fxml/JavaFxPsiUtil.java @@ -112,7 +112,8 @@ public class JavaFxPsiUtil { for (String anImport : imports) { if (StringUtil.getShortName(anImport).equals(name)) { psiClass = psiFacade.findClass(anImport, file.getResolveScope()); - } else if (StringUtil.endsWith(anImport, ".*")) { + } + else if (StringUtil.endsWith(anImport, ".*")) { psiClass = psiFacade.findClass(StringUtil.trimEnd(anImport, "*") + name, file.getResolveScope()); } if (psiClass != null) { @@ -133,7 +134,8 @@ public class JavaFxPsiUtil { final XmlProlog prolog = document.getProlog(); if (prolog != null) { prolog.add(processingInstruction); - } else { + } + else { document.addBefore(processingInstruction, document.getRootTag()); } PostprocessReformattingAspect.getInstance(xmlFile.getProject()).doPostponedFormatting(xmlFile.getViewProvider()); @@ -223,6 +225,7 @@ public class JavaFxPsiUtil { private static final Key> INJECTED_CONTROLLER = Key.create("javafx.injected.controller"); private static final RecursionGuard ourGuard = RecursionManager.createGuard("javafx.controller"); + public static PsiClass getControllerClass(final PsiFile containingFile) { if (containingFile instanceof XmlFile) { final XmlTag rootTag = ((XmlFile)containingFile).getRootTag(); @@ -262,7 +265,7 @@ public class JavaFxPsiUtil { final String attributeValue = attribute.getValue(); if (!StringUtil.isEmptyOrSpaces(attributeValue)) { final GlobalSearchScope customScope = GlobalSearchScope.projectScope(project).intersectWith(containingFile.getResolveScope()); - return JavaPsiFacade.getInstance(project).findClass(attributeValue, customScope); + return JavaPsiFacade.getInstance(project).findClass(attributeValue, customScope); } return null; } @@ -373,7 +376,8 @@ public class JavaFxPsiUtil { } public static PsiType getDefaultPropertyExpectedType(PsiClass aClass) { - final PsiAnnotation annotation = AnnotationUtil.findAnnotationInHierarchy(aClass, Collections.singleton(JavaFxCommonNames.JAVAFX_BEANS_DEFAULT_PROPERTY)); + final PsiAnnotation annotation = + AnnotationUtil.findAnnotationInHierarchy(aClass, Collections.singleton(JavaFxCommonNames.JAVAFX_BEANS_DEFAULT_PROPERTY)); if (annotation != null) { final PsiAnnotationMemberValue memberValue = annotation.findAttributeValue(null); if (memberValue != null) { @@ -392,7 +396,8 @@ public class JavaFxPsiUtil { return null; } final PsiAnnotation annotation = AnnotationUtil.findAnnotationInHierarchy(aClass, - Collections.singleton(JavaFxCommonNames.JAVAFX_BEANS_DEFAULT_PROPERTY)); + Collections.singleton( + JavaFxCommonNames.JAVAFX_BEANS_DEFAULT_PROPERTY)); if (annotation != null) { final PsiAnnotationMemberValue memberValue = annotation.findAttributeValue(null); if (memberValue != null) { @@ -403,7 +408,7 @@ public class JavaFxPsiUtil { } public static String isAbleToInstantiate(final PsiClass psiClass) { - if(psiClass.getConstructors().length > 0) { + if (psiClass.getConstructors().length > 0) { for (PsiMethod constr : psiClass.getConstructors()) { final PsiParameter[] parameters = constr.getParameterList().getParameters(); if (parameters.length == 0) return null; @@ -496,7 +501,7 @@ public class JavaFxPsiUtil { final String qualifiedName = baseClass.getQualifiedName(); if (qualifiedName != null && !Comparing.strEqual(qualifiedName, CommonClassNames.JAVA_LANG_STRING)) { if (!InheritanceUtil.isInheritor(aClass, qualifiedName)) { - return unableToCoerceMessage(aClass, qualifiedName); + return unableToCoerceMessage(aClass, qualifiedName); } } } @@ -505,7 +510,7 @@ public class JavaFxPsiUtil { } private static String unableToCoerceMessage(PsiClass aClass, String qualifiedName) { - return "Unable to coerce " + HighlightUtil.formatClass(aClass)+ " to " + qualifiedName; + return "Unable to coerce " + HighlightUtil.formatClass(aClass) + " to " + qualifiedName; } public static boolean isOutOfHierarchy(final XmlAttributeValue element) { @@ -835,10 +840,10 @@ public class JavaFxPsiUtil { } @Nullable - public static PsiSubstitutor getTagClassSubstitutor(@NotNull XmlTag xmlTag, - @Nullable PsiClass fieldClass, - @Nullable PsiClass controllerClass) { - if (fieldClass != null && controllerClass != null) { + public static PsiSubstitutor getTagClassSubstitutor(@NotNull XmlAttribute xmlAttribute, @NotNull PsiClass controllerClass) { + final XmlTag xmlTag = xmlAttribute.getParent(); + final PsiClass tagClass = getTagClass(xmlTag); + if (tagClass != null) { final String tagFieldName = xmlTag.getAttributeValue(FxmlConstants.FX_ID); if (tagFieldName != null) { final PsiField tagField = controllerClass.findFieldByName(tagFieldName, true); @@ -846,7 +851,7 @@ public class JavaFxPsiUtil { final PsiClassType.ClassResolveResult resolveResult = PsiUtil.resolveGenericsClassInType(tagField.getType()); final PsiClass resolvedClass = resolveResult.getElement(); if (resolvedClass != null) { - return TypeConversionUtil.getClassSubstitutor(fieldClass, resolvedClass, resolveResult.getSubstitutor()); + return TypeConversionUtil.getClassSubstitutor(tagClass, resolvedClass, resolveResult.getSubstitutor()); } } } @@ -854,6 +859,38 @@ public class JavaFxPsiUtil { return null; } + @Nullable + public static PsiType getEventHandlerPropertyType(@NotNull PsiClass tagClass, @NotNull String eventName) { + final PsiMethod[] handlerSetterCandidates = tagClass.findMethodsByName(PropertyUtil.suggestSetterName(eventName), true); + for (PsiMethod handlerSetter : handlerSetterCandidates) { + if (!handlerSetter.hasModifierProperty(PsiModifier.STATIC) && + handlerSetter.hasModifierProperty(PsiModifier.PUBLIC)) { + final PsiType propertyType = PropertyUtil.getPropertyType(handlerSetter); + if (InheritanceUtil.isInheritor(propertyType, JavaFxCommonNames.JAVAFX_EVENT_EVENT_HANDLER)) { + return propertyType; + } + } + } + final PsiField handlerField = tagClass.findFieldByName(eventName, true); + final PsiClassType propertyType = getPropertyClassType(handlerField); + if (InheritanceUtil.isInheritor(propertyType, JavaFxCommonNames.JAVAFX_EVENT_EVENT_HANDLER)) { + return propertyType; + } + return null; + } + + @Nullable + public static PsiType substituteEventType(@NotNull PsiClassType eventHandlerClass, @NotNull Project project) { + final PsiClass eventHandlerInterface = + JavaPsiFacade.getInstance(project).findClass(JavaFxCommonNames.JAVAFX_EVENT_EVENT_HANDLER, GlobalSearchScope.allScope(project)); + if (eventHandlerInterface == null) return null; + final PsiTypeParameter[] typeParameters = eventHandlerInterface.getTypeParameters(); + if (typeParameters.length != 1) return null; + final PsiTypeParameter typeParameter = typeParameters[0]; + final PsiSubstitutor substitutor = TypeConversionUtil.getSuperClassSubstitutor(eventHandlerInterface, eventHandlerClass); + return substitutor.substitute(typeParameter); + } + private static class JavaFxControllerCachedValueProvider implements CachedValueProvider { private final Project myProject; private final PsiFile myContainingFile; diff --git a/plugins/javaFX/src/org/jetbrains/plugins/javaFX/fxml/codeInsight/inspections/JavaFxEventHandlerInspection.java b/plugins/javaFX/src/org/jetbrains/plugins/javaFX/fxml/codeInsight/inspections/JavaFxEventHandlerInspection.java index 6fce1ce6d307..962abbd1eb7d 100644 --- a/plugins/javaFX/src/org/jetbrains/plugins/javaFX/fxml/codeInsight/inspections/JavaFxEventHandlerInspection.java +++ b/plugins/javaFX/src/org/jetbrains/plugins/javaFX/fxml/codeInsight/inspections/JavaFxEventHandlerInspection.java @@ -1,18 +1,17 @@ package org.jetbrains.plugins.javaFX.fxml.codeInsight.inspections; +import com.intellij.codeInsight.intention.IntentionAction; +import com.intellij.codeInsight.intention.QuickFixFactory; +import com.intellij.codeInspection.IntentionWrapper; +import com.intellij.codeInspection.LocalQuickFix; import com.intellij.codeInspection.ProblemsHolder; import com.intellij.codeInspection.XmlSuppressableInspectionTool; import com.intellij.codeInspection.ui.SingleCheckboxOptionsPanel; -import com.intellij.openapi.project.Project; import com.intellij.psi.*; -import com.intellij.psi.search.GlobalSearchScope; import com.intellij.psi.util.InheritanceUtil; -import com.intellij.psi.util.PropertyUtil; import com.intellij.psi.xml.XmlAttribute; import com.intellij.psi.xml.XmlAttributeValue; import com.intellij.psi.xml.XmlFile; -import com.intellij.psi.xml.XmlTag; -import com.intellij.xml.XmlElementDescriptor; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.jetbrains.plugins.javaFX.fxml.JavaFxCommonNames; @@ -20,11 +19,12 @@ import org.jetbrains.plugins.javaFX.fxml.JavaFxFileTypeFactory; import org.jetbrains.plugins.javaFX.fxml.JavaFxPsiUtil; import javax.swing.*; +import java.util.ArrayList; import java.util.Arrays; import java.util.List; import java.util.stream.Collectors; -import static org.jetbrains.plugins.javaFX.fxml.JavaFxPsiUtil.isNotFullyResolvedGeneric; +import static org.jetbrains.plugins.javaFX.fxml.JavaFxPsiUtil.getTagClass; /** * @author Pavel.Dolgov @@ -43,11 +43,12 @@ public class JavaFxEventHandlerInspection extends XmlSuppressableInspectionTool } @Override - public void visitXmlAttribute(XmlAttribute attribute) { - super.visitXmlAttribute(attribute); - - final PsiFile containingFile = attribute.getContainingFile(); - final PsiClass controllerClass = JavaFxPsiUtil.getControllerClass(containingFile); + public void visitXmlAttributeValue(XmlAttributeValue xmlAttributeValue) { + super.visitXmlAttributeValue(xmlAttributeValue); + final PsiElement valueParent = xmlAttributeValue.getParent(); + if (!(valueParent instanceof XmlAttribute)) return; + final XmlAttribute attribute = (XmlAttribute)valueParent; + final PsiClass controllerClass = JavaFxPsiUtil.getControllerClass(attribute.getContainingFile()); if (controllerClass == null) return; final String valueText = attribute.getValue(); @@ -61,7 +62,7 @@ public class JavaFxEventHandlerInspection extends XmlSuppressableInspectionTool .collect(Collectors.toList()); if (eventHandlerMethods.size() == 0) return; if (eventHandlerMethods.size() != 1) { - holder.registerProblem(getHighlightedElement(attribute), "Ambiguous event handler name: more than one matching method found"); + holder.registerProblem(xmlAttributeValue, "Ambiguous event handler name: more than one matching method found"); } if (myDetectNonVoidReturnType) { @@ -69,136 +70,77 @@ public class JavaFxEventHandlerInspection extends XmlSuppressableInspectionTool .map(PsiMethod::getReturnType) .filter(returnType -> !PsiType.VOID.equals(returnType)) .findAny() - .ifPresent(ignored -> holder.registerProblem(getHighlightedElement(attribute), "Return type of event handler should be void")); + .ifPresent(ignored -> holder.registerProblem(xmlAttributeValue, "Return type of event handler should be void")); } - final PsiClassType eventClassType = getHandlerArgumentClassType(attribute, controllerClass); - if (eventClassType == null) return; - final boolean eventClassTypeNotFullyResolved = isNotFullyResolvedGeneric(eventClassType); + final PsiSubstitutor tagClassSubstitutor = JavaFxPsiUtil.getTagClassSubstitutor(attribute, controllerClass); + final PsiClassType declaredType = getDeclaredEventType(attribute, tagClassSubstitutor); + if (declaredType == null) return; - eventHandlerMethods.stream() - .map(method -> method.getParameterList().getParameters()) - .filter(parameters -> parameters.length == 1) - .map(parameters -> parameters[0].getType()) - .forEach(argType -> { - if (argType instanceof PsiClassType) { - final boolean assignable; - if (eventClassTypeNotFullyResolved || isNotFullyResolvedGeneric((PsiClassType)argType)) { - assignable = isAssignableFromIgnoringUnresolved((PsiClassType)argType, eventClassType); - } - else { - assignable = argType.isAssignableFrom(eventClassType); - } - if (!assignable) { - holder.registerProblem(getHighlightedElement(attribute), - "Incompatible event handler argument: " + argType.getPresentableText() + - " is not assignable from " + eventClassType.getPresentableText()); + for (PsiMethod method : eventHandlerMethods) { + final PsiParameter[] parameters = method.getParameterList().getParameters(); + if (parameters.length == 1) { + final PsiType actualType = parameters[0].getType(); + if (actualType instanceof PsiClassType) { + if (!actualType.isAssignableFrom(declaredType)) { + final LocalQuickFix quickFix = createChangeArgumentTypeQuickFix(controllerClass, declaredType, method, tagClassSubstitutor); + + final PsiClassType actualRawType = ((PsiClassType)actualType).rawType(); + final PsiClassType expectedRawType = declaredType.rawType(); + if (actualRawType.isAssignableFrom(expectedRawType)) { + holder.registerProblem(xmlAttributeValue, + "Incompatible generic parameter of event handler argument: " + actualType.getCanonicalText() + + " is not assignable from " + declaredType.getCanonicalText(), + quickFix); + } + else { + holder.registerProblem(xmlAttributeValue, + "Incompatible event handler argument: " + actualRawType.getCanonicalText() + + " is not assignable from " + expectedRawType.getCanonicalText(), + quickFix); + } } } - else { - holder.registerProblem(getHighlightedElement(attribute), - "Unresolved event handler argument type " + argType.getCanonicalText()); - } - }); + } + } } }; } - private static boolean isAssignableFromIgnoringUnresolved(@Nullable PsiClassType left, @Nullable PsiClassType right) { - if (left == null || right == null) return true; - final PsiClassType.ClassResolveResult leftResolveResult = left.resolveGenerics(); - final PsiClassType.ClassResolveResult rightResolveResult = right.resolveGenerics(); - - final PsiClass leftClass = leftResolveResult.getElement(); - final PsiClass rightClass = rightResolveResult.getElement(); - - if (leftClass == null || rightClass == null || leftClass instanceof PsiTypeParameter || rightClass instanceof PsiTypeParameter) { - return true; - } - if (leftClass.getManager().areElementsEquivalent(leftClass, rightClass)) { - // generic args are assignable or unresolved - if (!leftClass.hasTypeParameters()) return true; - final PsiSubstitutor leftSubstitutor = leftResolveResult.getSubstitutor(); - final PsiSubstitutor rightSubstitutor = rightResolveResult.getSubstitutor(); - final PsiTypeParameter[] typeParameters = leftClass.getTypeParameters(); - for (PsiTypeParameter typeParameter : typeParameters) { - final PsiType leftParameter = leftSubstitutor.substitute(typeParameter); - if (leftParameter == null || leftParameter instanceof PsiTypeParameter) continue; - final PsiType rightParameter = rightSubstitutor.substitute(typeParameter); - if (rightParameter == null || rightParameter instanceof PsiTypeParameter) continue; - final PsiClassType leftParameterClass = getBoundClassType(leftParameter, true); - final PsiClassType rightParameterClass = getBoundClassType(rightParameter, false); - if (!isAssignableFromIgnoringUnresolved(leftParameterClass, rightParameterClass)) { - return false; - } - } - return true; - } - else if (leftClass.isInheritor(rightClass, true)) { - // generic args are equal - final PsiType rightSubstitute = leftResolveResult.getSubstitutor().substitute(right); - return rightSubstitute.isAssignableFrom(left); - } - return false; + @NotNull + private static LocalQuickFix createChangeArgumentTypeQuickFix(@NotNull PsiClass controllerClass, + @NotNull PsiClassType declaredType, + @NotNull PsiMethod method, + @Nullable PsiSubstitutor tagClassSubstitutor) { + final PsiElementFactory psiElementFactory = JavaPsiFacade.getElementFactory(controllerClass.getProject()); + final PsiExpression expression = psiElementFactory.createExpressionFromText("new " + declaredType.getCanonicalText() + "(){}", method); + final IntentionAction intentionAction = QuickFixFactory.getInstance() + .createChangeMethodSignatureFromUsageFix(method, new PsiExpression[]{expression}, + tagClassSubstitutor != null ? tagClassSubstitutor : PsiSubstitutor.EMPTY, + controllerClass, false, 2); + return new IntentionWrapper(intentionAction, method.getContainingFile()); } @Nullable - private static PsiClassType getBoundClassType(PsiType psiType, boolean isSuper) { - if (psiType instanceof PsiClassType) { - return (PsiClassType)psiType; - } - if (psiType instanceof PsiWildcardType) { - PsiWildcardType wildcardType = (PsiWildcardType)psiType; - if (isSuper && wildcardType.isSuper() || !isSuper && wildcardType.isExtends()) { - final PsiType bound = wildcardType.getBound(); - if (bound instanceof PsiClassType) return (PsiClassType)bound; + private static PsiClassType getDeclaredEventType(@NotNull XmlAttribute attribute, @Nullable PsiSubstitutor tagClassSubstitutor) { + final PsiClass tagClass = getTagClass(attribute.getParent()); + if (tagClass == null) return null; + + final PsiType eventHandlerPropertyType = JavaFxPsiUtil.getEventHandlerPropertyType(tagClass, attribute.getName()); + if (eventHandlerPropertyType == null) return null; + + final PsiType handlerType = + tagClassSubstitutor != null ? tagClassSubstitutor.substitute(eventHandlerPropertyType) : eventHandlerPropertyType; + if (handlerType instanceof PsiClassType) { + final PsiType eventType = JavaFxPsiUtil.substituteEventType((PsiClassType)handlerType, tagClass.getProject()); + if (eventType instanceof PsiClassType) { + return (PsiClassType)eventType; } - } - return null; - } - - private static PsiElement getHighlightedElement(XmlAttribute attribute) { - final XmlAttributeValue valueElement = attribute.getValueElement(); - return valueElement != null ? valueElement : attribute; - } - - @Nullable - private static PsiClassType getHandlerArgumentClassType(@NotNull XmlAttribute attribute, PsiClass controllerClass) { - final XmlTag xmlTag = attribute.getParent(); - final XmlElementDescriptor descriptor = xmlTag.getDescriptor(); - if (descriptor == null) return null; - final PsiElement declaration = descriptor.getDeclaration(); - if (!(declaration instanceof PsiClass)) return null; - final PsiClass tagClass = (PsiClass)declaration; - - final String handlerSetterName = PropertyUtil.suggestSetterName(attribute.getName()); - final PsiMethod[] handlerSetterCandidates = tagClass.findMethodsByName(handlerSetterName, true); - if (handlerSetterCandidates.length == 0) return null; - - final Project project = attribute.getProject(); - final PsiClass javaFxEventHandlerClass = JavaPsiFacade.getInstance(project).findClass(JavaFxCommonNames.JAVAFX_EVENT_EVENT_HANDLER, - GlobalSearchScope.allScope(project)); - if (javaFxEventHandlerClass != null) { - final PsiTypeParameter[] typeParameters = javaFxEventHandlerClass.getTypeParameters(); - if (typeParameters.length == 1) { - final PsiTypeParameter javaFxEventHandlerTypeParameter = typeParameters[0]; - final PsiSubstitutor tagClassSubstitutor = JavaFxPsiUtil.getTagClassSubstitutor(xmlTag, tagClass, controllerClass); - for (PsiMethod handlerSetter : handlerSetterCandidates) { - if (handlerSetter.hasModifierProperty(PsiModifier.STATIC) || !handlerSetter.hasModifierProperty(PsiModifier.PUBLIC)) continue; - final PsiParameter[] parameters = handlerSetter.getParameterList().getParameters(); - if (parameters.length == 1) { - PsiType handlerParameterType = parameters[0].getType(); - if (tagClassSubstitutor != null) { - handlerParameterType = tagClassSubstitutor.substitute(handlerParameterType); - } - if (handlerParameterType instanceof PsiClassType && - InheritanceUtil.isInheritorOrSelf(((PsiClassType)handlerParameterType).resolve(), javaFxEventHandlerClass, true)) { - final PsiClassType.ClassResolveResult resolveResult = ((PsiClassType)handlerParameterType).resolveGenerics(); - final PsiType eventType = resolveResult.getSubstitutor().substitute(javaFxEventHandlerTypeParameter); - PsiClassType eventClassType = getBoundClassType(eventType, true); - if (eventClassType != null) return eventClassType; - } - } + if (eventType instanceof PsiWildcardType) { + PsiWildcardType wildcardType = (PsiWildcardType)eventType; + if (wildcardType.isSuper()) { + final PsiType bound = wildcardType.getBound(); + if (bound instanceof PsiClassType) return (PsiClassType)bound; } } } diff --git a/plugins/javaFX/src/org/jetbrains/plugins/javaFX/fxml/refs/JavaFxEventHandlerReference.java b/plugins/javaFX/src/org/jetbrains/plugins/javaFX/fxml/refs/JavaFxEventHandlerReference.java index 387dde67d20a..28b92236fd79 100644 --- a/plugins/javaFX/src/org/jetbrains/plugins/javaFX/fxml/refs/JavaFxEventHandlerReference.java +++ b/plugins/javaFX/src/org/jetbrains/plugins/javaFX/fxml/refs/JavaFxEventHandlerReference.java @@ -18,15 +18,11 @@ package org.jetbrains.plugins.javaFX.fxml.refs; import com.intellij.codeInsight.daemon.QuickFixActionRegistrar; import com.intellij.codeInsight.daemon.impl.quickfix.CreateMethodQuickFix; import com.intellij.codeInsight.quickfix.UnresolvedReferenceQuickFixProvider; -import com.intellij.openapi.project.Project; import com.intellij.openapi.util.TextRange; import com.intellij.psi.*; -import com.intellij.psi.search.GlobalSearchScope; import com.intellij.psi.util.InheritanceUtil; -import com.intellij.psi.util.TypeConversionUtil; import com.intellij.psi.xml.XmlAttribute; import com.intellij.psi.xml.XmlAttributeValue; -import com.intellij.psi.xml.XmlTag; import com.intellij.util.ArrayUtil; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -108,35 +104,21 @@ public class JavaFxEventHandlerReference extends PsiReferenceBase list; public void onEditStart(ListView.EditEvent e) {} diff --git a/plugins/javaFX/testData/inspections/eventHandler/HighlightHalfRaw.java b/plugins/javaFX/testData/inspections/eventHandler/HighlightHalfRaw.java new file mode 100644 index 000000000000..a66d653be29a --- /dev/null +++ b/plugins/javaFX/testData/inspections/eventHandler/HighlightHalfRaw.java @@ -0,0 +1,15 @@ +import javafx.fxml.FXML; +import javafx.scene.control.*; +import javafx.util.Pair; + +import java.util.Map; + +public class HighlightHalfRaw { + @FXML TableView positive; + @FXML TableView negative; + public void sortPositive(SortEvent> e) {} + public void scrollPositive(ScrollToEvent> e) {} + + public void sortNegative(SortEvent e) {} + public void scrollNegative(ScrollToEvent> e) {} +} diff --git a/plugins/javaFX/testData/inspections/eventHandler/HighlightMixedGenericController.java b/plugins/javaFX/testData/inspections/eventHandler/HighlightMixedGenericController.java deleted file mode 100644 index 32c5e07d3f3c..000000000000 --- a/plugins/javaFX/testData/inspections/eventHandler/HighlightMixedGenericController.java +++ /dev/null @@ -1,37 +0,0 @@ -import javafx.fxml.FXML; -import javafx.scene.control.*; -import javafx.util.Pair; -import java.util.Map; - -public class HighlightMixedGenericController { - @FXML TableView> specificTable; - @FXML TableView> specificTableHalfRawArg; - @FXML TableView> specificTableIncompatibleArg; - @FXML TableView> specificTableIncompatibleHalfRawArg; - - @FXML TableView halfRawTable; - @FXML TableView halfRawTableHalfRawArg; - @FXML TableView halfRawTableIncompatibleArg; - @FXML TableView halfRawTableIncompatibleHalfRawArg; - - @FXML TableView rawTable; - @FXML TableView rawTableHalfRawArg; - @FXML TableView rawTableIncompatibleArg; - @FXML TableView rawTableIncompatibleHalfRawArg; - - public void onSort(SortEvent>> e) {} - public void onScrollTo(ScrollToEvent e) {} - public void onScrollToColumn(ScrollToEvent, ?>> e) {} - - public void onSortHalfRawArg(SortEvent e) {} - public void onScrollToHalfRawArg(ScrollToEvent e) {} - public void onScrollToColumnHalfRawArg(ScrollToEvent e) {} - - public void onSortIncompatibleArg(SortEvent>> e) {} - public void onScrollToIncompatibleArg(ScrollToEvent e) {} - public void onScrollToColumnIncompatibleArg(ScrollToEvent, ?>> e) {} - - public void onSortIncompatibleHalfRawArg(SortEvent> e) {} - public void onScrollToIncompatibleHalfRawArg(ScrollToEvent e) {} - public void onScrollToColumnIncompatibleHalfRawArg(ScrollToEvent> e) {} -} diff --git a/plugins/javaFX/testData/inspections/eventHandler/HighlightNonVoidController.java b/plugins/javaFX/testData/inspections/eventHandler/HighlightNonVoid.java similarity index 84% rename from plugins/javaFX/testData/inspections/eventHandler/HighlightNonVoidController.java rename to plugins/javaFX/testData/inspections/eventHandler/HighlightNonVoid.java index d14be2642bd5..fb246bca9199 100644 --- a/plugins/javaFX/testData/inspections/eventHandler/HighlightNonVoidController.java +++ b/plugins/javaFX/testData/inspections/eventHandler/HighlightNonVoid.java @@ -1,7 +1,7 @@ import javafx.event.ActionEvent; import javafx.event.Event; -public class HighlightNonVoidController { +public class HighlightNonVoid { public String onSameArgNotVoid(ActionEvent e) {return "";} public Boolean onSuperArgNotVoid(Event e) {return false;} public int onNoArgNotVoid() {return 1;} diff --git a/plugins/javaFX/testData/inspections/eventHandler/HighlightRaw.java b/plugins/javaFX/testData/inspections/eventHandler/HighlightRaw.java new file mode 100644 index 000000000000..fee21b0a7793 --- /dev/null +++ b/plugins/javaFX/testData/inspections/eventHandler/HighlightRaw.java @@ -0,0 +1,13 @@ +import javafx.fxml.FXML; +import javafx.scene.control.*; + +public class HighlightRaw { + @FXML TableView positive; + @FXML TableView negative; + + public void sortPositive(SortEvent e) {} + public void scrollPositive(ScrollToEvent e) {} + + public void sortNegative(ScrollToEvent e) {} + public void scrollNegative(ScrollToEvent e) {} +} diff --git a/plugins/javaFX/testData/inspections/eventHandler/HighlightSpecific.java b/plugins/javaFX/testData/inspections/eventHandler/HighlightSpecific.java new file mode 100644 index 000000000000..461aecc03310 --- /dev/null +++ b/plugins/javaFX/testData/inspections/eventHandler/HighlightSpecific.java @@ -0,0 +1,15 @@ +import javafx.fxml.FXML; +import javafx.scene.control.*; +import javafx.util.Pair; + +import java.util.Map; + +public class HighlightSpecific { + @FXML TableView> positive; + @FXML TableView> negative; + public void sortPositive(SortEvent>> e) {} + public void scrollPositive(ScrollToEvent, ?>> e) {} + + public void sortNegative(SortEvent e) {} + public void scrollNegative(ScrollToEvent, ?>> e) {} +} diff --git a/plugins/javaFX/testData/inspections/eventHandler/HighlightWildcardController.java b/plugins/javaFX/testData/inspections/eventHandler/HighlightWildcard.java similarity index 90% rename from plugins/javaFX/testData/inspections/eventHandler/HighlightWildcardController.java rename to plugins/javaFX/testData/inspections/eventHandler/HighlightWildcard.java index 4bb1b0f45474..40c969b14e88 100644 --- a/plugins/javaFX/testData/inspections/eventHandler/HighlightWildcardController.java +++ b/plugins/javaFX/testData/inspections/eventHandler/HighlightWildcard.java @@ -4,7 +4,7 @@ import javafx.scene.control.SortEvent; import javafx.scene.input.MouseDragEvent; import javafx.scene.input.MouseEvent; -public class HighlightWildcardController { +public class HighlightWildcard { @FXML private void onSameArg(MouseEvent e) {} @FXML private void onSuperArg(Event e) {} @FXML private void onNoArg() {} diff --git a/plugins/javaFX/testData/inspections/eventHandler/QuickfixHalfRaw.java b/plugins/javaFX/testData/inspections/eventHandler/QuickfixHalfRaw.java new file mode 100644 index 000000000000..3db6b6a54a77 --- /dev/null +++ b/plugins/javaFX/testData/inspections/eventHandler/QuickfixHalfRaw.java @@ -0,0 +1,7 @@ +import javafx.fxml.FXML; +import javafx.scene.control.TableView; +import javafx.util.Pair; + +public class QuickfixHalfRaw { + @FXML TableView table; +} diff --git a/plugins/javaFX/testData/inspections/eventHandler/QuickfixHalfRaw_after.java b/plugins/javaFX/testData/inspections/eventHandler/QuickfixHalfRaw_after.java new file mode 100644 index 000000000000..c6dd5f73ae91 --- /dev/null +++ b/plugins/javaFX/testData/inspections/eventHandler/QuickfixHalfRaw_after.java @@ -0,0 +1,12 @@ +import javafx.fxml.FXML; +import javafx.scene.control.SortEvent; +import javafx.scene.control.TableView; +import javafx.util.Pair; + +public class QuickfixHalfRaw { + @FXML TableView table; + + public void onSort(SortEvent sortEvent) { + + } +} diff --git a/plugins/javaFX/testData/inspections/eventHandler/QuickfixRaw.java b/plugins/javaFX/testData/inspections/eventHandler/QuickfixRaw.java new file mode 100644 index 000000000000..d11b3be7b70b --- /dev/null +++ b/plugins/javaFX/testData/inspections/eventHandler/QuickfixRaw.java @@ -0,0 +1,6 @@ +import javafx.fxml.FXML; +import javafx.scene.control.TableView; + +public class QuickfixRaw { + @FXML TableView table; +} diff --git a/plugins/javaFX/testData/inspections/eventHandler/QuickfixRaw_after.java b/plugins/javaFX/testData/inspections/eventHandler/QuickfixRaw_after.java new file mode 100644 index 000000000000..5a0886c9dfca --- /dev/null +++ b/plugins/javaFX/testData/inspections/eventHandler/QuickfixRaw_after.java @@ -0,0 +1,11 @@ +import javafx.fxml.FXML; +import javafx.scene.control.SortEvent; +import javafx.scene.control.TableView; + +public class QuickfixRaw { + @FXML TableView table; + + public void onSort(SortEvent sortEvent) { + + } +} diff --git a/plugins/javaFX/testData/inspections/eventHandler/QuickfixSpecific.java b/plugins/javaFX/testData/inspections/eventHandler/QuickfixSpecific.java new file mode 100644 index 000000000000..9d7b7e9ec760 --- /dev/null +++ b/plugins/javaFX/testData/inspections/eventHandler/QuickfixSpecific.java @@ -0,0 +1,8 @@ +import javafx.fxml.FXML; +import javafx.scene.control.TableView; +import javafx.util.Pair; + +public class QuickfixSpecific { + @FXML + TableView> table; +} \ No newline at end of file diff --git a/plugins/javaFX/testData/inspections/eventHandler/QuickfixSpecific_after.java b/plugins/javaFX/testData/inspections/eventHandler/QuickfixSpecific_after.java new file mode 100644 index 000000000000..9ad1f4c4332f --- /dev/null +++ b/plugins/javaFX/testData/inspections/eventHandler/QuickfixSpecific_after.java @@ -0,0 +1,13 @@ +import javafx.fxml.FXML; +import javafx.scene.control.SortEvent; +import javafx.scene.control.TableView; +import javafx.util.Pair; + +public class QuickfixSpecific { + @FXML + TableView> table; + + public void onSort(SortEvent>> tableViewSortEvent) { + + } +} \ No newline at end of file diff --git a/plugins/javaFX/testData/inspections/eventHandler/highlightAmbiguous.fxml b/plugins/javaFX/testData/inspections/eventHandler/highlightAmbiguous.fxml index 56b8dab341dc..84274cc22494 100644 --- a/plugins/javaFX/testData/inspections/eventHandler/highlightAmbiguous.fxml +++ b/plugins/javaFX/testData/inspections/eventHandler/highlightAmbiguous.fxml @@ -1,6 +1,6 @@ - +