From f90ba61bcfc47eb2b71a87c4b81e3daf4d6941d3 Mon Sep 17 00:00:00 2001 From: Anna Kozlova Date: Wed, 14 Jan 2015 11:30:02 +0100 Subject: [PATCH 01/15] code cleanup also for code generation on completion --- ...JavaGenerateMemberCompletionContributor.java | 17 +++++++++++++---- .../completion/NormalCompletionTest.groovy | 17 +++++++++++++++++ .../ex/GlobalInspectionContextBase.java | 2 +- 3 files changed, 31 insertions(+), 5 deletions(-) diff --git a/java/java-impl/src/com/intellij/codeInsight/completion/JavaGenerateMemberCompletionContributor.java b/java/java-impl/src/com/intellij/codeInsight/completion/JavaGenerateMemberCompletionContributor.java index 8ae9622f3440..e636ab4fc9b4 100644 --- a/java/java-impl/src/com/intellij/codeInsight/completion/JavaGenerateMemberCompletionContributor.java +++ b/java/java-impl/src/com/intellij/codeInsight/completion/JavaGenerateMemberCompletionContributor.java @@ -18,6 +18,7 @@ package com.intellij.codeInsight.completion; import com.intellij.codeInsight.generation.*; import com.intellij.codeInsight.lookup.LookupElement; import com.intellij.codeInsight.lookup.LookupElementBuilder; +import com.intellij.codeInspection.ex.GlobalInspectionContextBase; import com.intellij.icons.AllIcons; import com.intellij.openapi.util.Iconable; import com.intellij.openapi.util.Key; @@ -30,10 +31,7 @@ import com.intellij.util.VisibilityUtil; import com.intellij.util.containers.ContainerUtil; import javax.swing.*; -import java.util.Arrays; -import java.util.Collections; -import java.util.List; -import java.util.Set; +import java.util.*; import static com.intellij.patterns.PlatformPatterns.psiElement; @@ -137,6 +135,17 @@ public class JavaGenerateMemberCompletionContributor { List> newInfos = GenerateMembersUtil .insertMembersAtOffset(context.getFile(), context.getStartOffset(), infos); if (!newInfos.isEmpty()) { + final List elements = new ArrayList(); + for (GenerationInfo member : newInfos) { + if (!(member instanceof TemplateGenerationInfo)) { + final PsiMember psiMember = member.getPsiMember(); + if (psiMember != null) { + elements.add(psiMember); + } + } + } + + GlobalInspectionContextBase.cleanupElements(context.getProject(), null, elements.toArray(new PsiElement[elements.size()])); newInfos.get(0).positionCaret(context.getEditor(), true); } } diff --git a/java/java-tests/testSrc/com/intellij/codeInsight/completion/NormalCompletionTest.groovy b/java/java-tests/testSrc/com/intellij/codeInsight/completion/NormalCompletionTest.groovy index 3bf3f6fbe428..dafb0ea9445b 100644 --- a/java/java-tests/testSrc/com/intellij/codeInsight/completion/NormalCompletionTest.groovy +++ b/java/java-tests/testSrc/com/intellij/codeInsight/completion/NormalCompletionTest.groovy @@ -27,6 +27,7 @@ import com.intellij.psi.PsiDocumentManager import com.intellij.psi.PsiMethod import com.intellij.psi.codeStyle.CodeStyleSettingsManager import com.intellij.psi.codeStyle.CommonCodeStyleSettings +import com.siyeh.ig.style.UnqualifiedFieldAccessInspection public class NormalCompletionTest extends LightFixtureCompletionTestCase { @Override @@ -1484,5 +1485,21 @@ class Bar { myFixture.assertPreferredCompletionItems(0, "xcreateZoo", "xcreateElephant"); } + public void "test code cleanup during completion generation"() { + myFixture.configureByText "a.java", "class Foo {int i; ge}" + def inspection = new UnqualifiedFieldAccessInspection() + try { + myFixture.enableInspections(inspection) + myFixture.complete(CompletionType.BASIC) + myFixture.checkResult '''class Foo {int i; + public int getI() { + return this.i; + } +}''' + } + finally { + myFixture.disableInspections(inspection) + } + } } diff --git a/platform/analysis-impl/src/com/intellij/codeInspection/ex/GlobalInspectionContextBase.java b/platform/analysis-impl/src/com/intellij/codeInspection/ex/GlobalInspectionContextBase.java index 4372a5944a2f..b284780ae278 100644 --- a/platform/analysis-impl/src/com/intellij/codeInspection/ex/GlobalInspectionContextBase.java +++ b/platform/analysis-impl/src/com/intellij/codeInspection/ex/GlobalInspectionContextBase.java @@ -438,7 +438,7 @@ public class GlobalInspectionContextBase extends UserDataHolderBase implements G }; Application application = ApplicationManager.getApplication(); - if (application.isWriteAccessAllowed()) { + if (application.isWriteAccessAllowed() && !application.isUnitTestMode()) { application.invokeLater(cleanupRunnable); } else { From 73239255ecc2c55da04b0c5d1d220a3d514991f0 Mon Sep 17 00:00:00 2001 From: Anna Kozlova Date: Wed, 14 Jan 2015 12:35:44 +0100 Subject: [PATCH 02/15] disable add exception to catch/generalize catch inside functional interface inside try statement (IDEA-135171) --- .../impl/quickfix/AddExceptionToCatchFix.java | 4 +-- .../impl/quickfix/GeneralizeCatchFix.java | 2 +- .../afterInsideLambdaTryInside.java | 25 +++++++++++++++++++ .../addCatchBlock/beforeInsideLambda.java | 16 ++++++++++++ .../beforeInsideLambdaTryInside.java | 23 +++++++++++++++++ .../addCatchBlock/beforeInsideMethodRef.java | 16 ++++++++++++ .../generalizeCatch/beforeInsideLambda.java | 16 ++++++++++++ .../beforeInsideMethodRef.java | 16 ++++++++++++ .../quickFix/AddExceptionToCatchTest.java | 8 ++++++ .../daemon/quickFix/GeneralizeCatchTest.java | 8 ++++++ 10 files changed, 131 insertions(+), 3 deletions(-) create mode 100644 java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/addCatchBlock/afterInsideLambdaTryInside.java create mode 100644 java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/addCatchBlock/beforeInsideLambda.java create mode 100644 java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/addCatchBlock/beforeInsideLambdaTryInside.java create mode 100644 java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/addCatchBlock/beforeInsideMethodRef.java create mode 100644 java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/generalizeCatch/beforeInsideLambda.java create mode 100644 java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/generalizeCatch/beforeInsideMethodRef.java diff --git a/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/AddExceptionToCatchFix.java b/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/AddExceptionToCatchFix.java index 5d51949c1d6b..cc43f962fc19 100644 --- a/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/AddExceptionToCatchFix.java +++ b/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/AddExceptionToCatchFix.java @@ -171,8 +171,8 @@ public class AddExceptionToCatchFix extends BaseIntentionAction { if (element == null) return null; @SuppressWarnings({"unchecked"}) - final PsiElement parent = PsiTreeUtil.getParentOfType(element, PsiTryStatement.class, PsiMethod.class); - if (parent == null || parent instanceof PsiMethod) return null; + final PsiElement parent = PsiTreeUtil.getParentOfType(element, PsiTryStatement.class, PsiMethod.class, PsiFunctionalExpression.class); + if (parent == null || parent instanceof PsiMethod || parent instanceof PsiFunctionalExpression) return null; final PsiTryStatement statement = (PsiTryStatement) parent; final PsiCodeBlock tryBlock = statement.getTryBlock(); diff --git a/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/GeneralizeCatchFix.java b/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/GeneralizeCatchFix.java index 64ad43808b86..2f7c34e47886 100644 --- a/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/GeneralizeCatchFix.java +++ b/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/GeneralizeCatchFix.java @@ -63,7 +63,7 @@ public class GeneralizeCatchFix implements IntentionAction { myTryStatement = (PsiTryStatement)element.getParent(); break; } - if (element instanceof PsiMethod || (element instanceof PsiClass && !(element instanceof PsiAnonymousClass))) break; + if (element instanceof PsiMethod || element instanceof PsiFunctionalExpression || (element instanceof PsiClass && !(element instanceof PsiAnonymousClass))) break; element = element.getParent(); } if (myTryStatement == null) return false; diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/addCatchBlock/afterInsideLambdaTryInside.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/addCatchBlock/afterInsideLambdaTryInside.java new file mode 100644 index 000000000000..0bad23e6f11a --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/addCatchBlock/afterInsideLambdaTryInside.java @@ -0,0 +1,25 @@ +// "Add 'catch' clause(s)" "true" +import java.io.IOException; +import java.util.function.Supplier; + +class C { + static Object get() throws Exception { + return null; + } + + void method() { + try { + Supplier lambda1 = () -> { + try { + return C.get(); + } catch (IOException e) { + throw new RuntimeException(); + } catch (Exception e) { + e.printStackTrace(); + } + }; + } catch( Exception e) { + throw new RuntimeException(e); + } + } +} \ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/addCatchBlock/beforeInsideLambda.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/addCatchBlock/beforeInsideLambda.java new file mode 100644 index 000000000000..08b71cbd8571 --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/addCatchBlock/beforeInsideLambda.java @@ -0,0 +1,16 @@ +// "Add 'catch' clause(s)" "false" +import java.util.function.Supplier; + +class C { + static Object get() throws Exception { + return null; + } + + void method() { + try { + Supplier lambda1 = () -> C.get(); + } catch( Exception e) { + throw new RuntimeException(e); + } + } +} \ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/addCatchBlock/beforeInsideLambdaTryInside.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/addCatchBlock/beforeInsideLambdaTryInside.java new file mode 100644 index 000000000000..857e16005aa8 --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/addCatchBlock/beforeInsideLambdaTryInside.java @@ -0,0 +1,23 @@ +// "Add 'catch' clause(s)" "true" +import java.io.IOException; +import java.util.function.Supplier; + +class C { + static Object get() throws Exception { + return null; + } + + void method() { + try { + Supplier lambda1 = () -> { + try { + return C.get(); + } catch (IOException e) { + throw new RuntimeException(); + } + }; + } catch( Exception e) { + throw new RuntimeException(e); + } + } +} \ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/addCatchBlock/beforeInsideMethodRef.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/addCatchBlock/beforeInsideMethodRef.java new file mode 100644 index 000000000000..300d6bdc806c --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/addCatchBlock/beforeInsideMethodRef.java @@ -0,0 +1,16 @@ +// "Add 'catch' clause(s)" "false" +import java.util.function.Supplier; + +class C { + static Object get() throws Exception { + return null; + } + + void method() { + try { + Supplier lambda1 = C::get; + } catch( Exception e) { + throw new RuntimeException(e); + } + } +} \ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/generalizeCatch/beforeInsideLambda.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/generalizeCatch/beforeInsideLambda.java new file mode 100644 index 000000000000..97db7ea2a88f --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/generalizeCatch/beforeInsideLambda.java @@ -0,0 +1,16 @@ +// "Generalize catch for 'java.lang.Exception' to 'java.lang.Exception'" "false" +import java.util.function.Supplier; + +class C { + static Object get() throws Exception { + return null; + } + + void method() { + try { + Supplier lambda1 = () -> C.get(); + } catch( Exception e) { + throw new RuntimeException(e); + } + } +} \ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/generalizeCatch/beforeInsideMethodRef.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/generalizeCatch/beforeInsideMethodRef.java new file mode 100644 index 000000000000..1bc024dd7453 --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/generalizeCatch/beforeInsideMethodRef.java @@ -0,0 +1,16 @@ +// "Generalize catch for 'java.lang.Exception' to 'java.lang.Exception'" "false" +import java.util.function.Supplier; + +class C { + static Object get() throws Exception { + return null; + } + + void method() { + try { + Supplier lambda1 = C::get; + } catch( Exception e) { + throw new RuntimeException(e); + } + } +} \ No newline at end of file diff --git a/java/java-tests/testSrc/com/intellij/codeInsight/daemon/quickFix/AddExceptionToCatchTest.java b/java/java-tests/testSrc/com/intellij/codeInsight/daemon/quickFix/AddExceptionToCatchTest.java index 4ef4c493e09d..e55cced09985 100644 --- a/java/java-tests/testSrc/com/intellij/codeInsight/daemon/quickFix/AddExceptionToCatchTest.java +++ b/java/java-tests/testSrc/com/intellij/codeInsight/daemon/quickFix/AddExceptionToCatchTest.java @@ -1,5 +1,8 @@ package com.intellij.codeInsight.daemon.quickFix; +import com.intellij.openapi.projectRoots.Sdk; +import com.intellij.testFramework.IdeaTestUtil; + public class AddExceptionToCatchTest extends LightQuickFixParameterizedTestCase { public void test() throws Exception { doAllTests(); @@ -9,4 +12,9 @@ public class AddExceptionToCatchTest extends LightQuickFixParameterizedTestCase protected String getBasePath() { return "/codeInsight/daemonCodeAnalyzer/quickFix/addCatchBlock"; } + + @Override + protected Sdk getProjectJDK() { + return IdeaTestUtil.getMockJdk18(); + } } diff --git a/java/java-tests/testSrc/com/intellij/codeInsight/daemon/quickFix/GeneralizeCatchTest.java b/java/java-tests/testSrc/com/intellij/codeInsight/daemon/quickFix/GeneralizeCatchTest.java index ac0c5b4ae09e..90299b35923c 100644 --- a/java/java-tests/testSrc/com/intellij/codeInsight/daemon/quickFix/GeneralizeCatchTest.java +++ b/java/java-tests/testSrc/com/intellij/codeInsight/daemon/quickFix/GeneralizeCatchTest.java @@ -1,5 +1,8 @@ package com.intellij.codeInsight.daemon.quickFix; +import com.intellij.openapi.projectRoots.Sdk; +import com.intellij.testFramework.IdeaTestUtil; + public class GeneralizeCatchTest extends LightQuickFixParameterizedTestCase { public void test() throws Exception { doAllTests(); @@ -9,4 +12,9 @@ public class GeneralizeCatchTest extends LightQuickFixParameterizedTestCase { protected String getBasePath() { return "/codeInsight/daemonCodeAnalyzer/quickFix/generalizeCatch"; } + + @Override + protected Sdk getProjectJDK() { + return IdeaTestUtil.getMockJdk18(); + } } From a1b44a53ac7ca01f9a642e0c9ba2ce24415ed685 Mon Sep 17 00:00:00 2001 From: Anna Kozlova Date: Wed, 14 Jan 2015 13:20:34 +0100 Subject: [PATCH 03/15] redundant throws: find throws clauses inside functional expressions (IDEA-135181) --- .../reference/RefJavaUtilImpl.java | 27 +++++++++++++++++++ .../expected.xml | 9 +++++++ .../src/Foo.java | 23 ++++++++++++++++ .../codeInspection/RedundantThrowTest.java | 15 +++++++++++ 4 files changed, 74 insertions(+) create mode 100644 java/java-tests/testData/inspection/redundantThrow/ThrownClausesInFunctionalExpressions/expected.xml create mode 100644 java/java-tests/testData/inspection/redundantThrow/ThrownClausesInFunctionalExpressions/src/Foo.java diff --git a/java/java-analysis-impl/src/com/intellij/codeInspection/reference/RefJavaUtilImpl.java b/java/java-analysis-impl/src/com/intellij/codeInspection/reference/RefJavaUtilImpl.java index e35aa3aa80a5..22d347ee1ecb 100644 --- a/java/java-analysis-impl/src/com/intellij/codeInspection/reference/RefJavaUtilImpl.java +++ b/java/java-analysis-impl/src/com/intellij/codeInspection/reference/RefJavaUtilImpl.java @@ -20,6 +20,7 @@ */ package com.intellij.codeInspection.reference; +import com.intellij.codeInsight.ExceptionUtil; import com.intellij.codeInspection.InspectionsBundle; import com.intellij.psi.*; import com.intellij.psi.search.GlobalSearchScope; @@ -30,6 +31,9 @@ import com.intellij.util.VisibilityUtil; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; +import java.util.Collection; +import java.util.Collections; + public class RefJavaUtilImpl extends RefJavaUtil{ @Override @@ -114,6 +118,29 @@ public class RefJavaUtilImpl extends RefJavaUtil{ final PsiMethod interfaceMethod = LambdaUtil.getFunctionalInterfaceMethod(aClass); if (interfaceMethod != null) { refFrom.addReference(refFrom.getRefManager().getReference(interfaceMethod), interfaceMethod, psiFrom, false, true, null); + + PsiElement body = null; + PsiElement topElement = null; + if (expression instanceof PsiLambdaExpression) { + body = ((PsiLambdaExpression)expression).getBody(); + topElement = expression; + } + else { + final PsiElement resolve = ((PsiMethodReferenceExpression)expression).resolve(); + if (resolve instanceof PsiMethod) { + body = ((PsiMethod)resolve).getBody(); + topElement = resolve; + } + } + + final Collection exceptionTypes = body != null ? ExceptionUtil.collectUnhandledExceptions(body, topElement, false) + : Collections.emptyList(); + RefElement refResolved = refFrom.getRefManager().getReference(interfaceMethod); + if (refResolved instanceof RefMethodImpl) { + for (final PsiClassType exceptionType : exceptionTypes) { + ((RefMethodImpl)refResolved).updateThrowsList(exceptionType); + } + } } } } diff --git a/java/java-tests/testData/inspection/redundantThrow/ThrownClausesInFunctionalExpressions/expected.xml b/java/java-tests/testData/inspection/redundantThrow/ThrownClausesInFunctionalExpressions/expected.xml new file mode 100644 index 000000000000..d7687ccb6f07 --- /dev/null +++ b/java/java-tests/testData/inspection/redundantThrow/ThrownClausesInFunctionalExpressions/expected.xml @@ -0,0 +1,9 @@ + + + + Foo.java + 21 + ObjectStreamException + + + diff --git a/java/java-tests/testData/inspection/redundantThrow/ThrownClausesInFunctionalExpressions/src/Foo.java b/java/java-tests/testData/inspection/redundantThrow/ThrownClausesInFunctionalExpressions/src/Foo.java new file mode 100644 index 000000000000..78316c54cfb5 --- /dev/null +++ b/java/java-tests/testData/inspection/redundantThrow/ThrownClausesInFunctionalExpressions/src/Foo.java @@ -0,0 +1,23 @@ +import java.io.*; + +class ExceptionTest { + + MyFunction method() { + return () -> { + throw new EOFException(); + }; + } + + MyFunction method1() { + return this::e; + } + + private void e() throws FileNotFoundException { + throw new FileNotFoundException(); + } + + @FunctionalInterface + private interface MyFunction { + void call() throws FileNotFoundException, EOFException, ObjectStreamException; + } +} \ No newline at end of file diff --git a/java/java-tests/testSrc/com/intellij/codeInspection/RedundantThrowTest.java b/java/java-tests/testSrc/com/intellij/codeInspection/RedundantThrowTest.java index c1017d242538..61dc1d9a5600 100644 --- a/java/java-tests/testSrc/com/intellij/codeInspection/RedundantThrowTest.java +++ b/java/java-tests/testSrc/com/intellij/codeInspection/RedundantThrowTest.java @@ -17,6 +17,10 @@ package com.intellij.codeInspection; import com.intellij.JavaTestUtil; import com.intellij.codeInspection.unneededThrows.RedundantThrows; +import com.intellij.openapi.projectRoots.Sdk; +import com.intellij.openapi.roots.LanguageLevelProjectExtension; +import com.intellij.pom.java.LanguageLevel; +import com.intellij.testFramework.IdeaTestUtil; import com.intellij.testFramework.InspectionTestCase; public class RedundantThrowTest extends InspectionTestCase { @@ -60,4 +64,15 @@ public class RedundantThrowTest extends InspectionTestCase { public void testSelfCall() throws Exception { doTest(); } + + public void testThrownClausesInFunctionalExpressions() throws Exception { + doTest(); + } + + @Override + protected Sdk getTestProjectSdk() { + Sdk sdk = IdeaTestUtil.getMockJdk17(); + LanguageLevelProjectExtension.getInstance(getProject()).setLanguageLevel(LanguageLevel.JDK_1_8); + return sdk; + } } From a4575a6bddfec50eb127c154184d4c6a52732588 Mon Sep 17 00:00:00 2001 From: Konstantin Bulenkov Date: Wed, 14 Jan 2015 13:41:31 +0100 Subject: [PATCH 04/15] common Y offset for IntelliJ and Darcula radio buttons --- .../intellij/ide/ui/laf/darcula/ui/DarculaRadioButtonUI.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/platform/platform-impl/src/com/intellij/ide/ui/laf/darcula/ui/DarculaRadioButtonUI.java b/platform/platform-impl/src/com/intellij/ide/ui/laf/darcula/ui/DarculaRadioButtonUI.java index 4b1d9dfafaf9..e3fe9f582393 100644 --- a/platform/platform-impl/src/com/intellij/ide/ui/laf/darcula/ui/DarculaRadioButtonUI.java +++ b/platform/platform-impl/src/com/intellij/ide/ui/laf/darcula/ui/DarculaRadioButtonUI.java @@ -117,7 +117,7 @@ public class DarculaRadioButtonUI extends MetalRadioButtonUI { if (b.isSelected()) { final boolean enabled = b.isEnabled(); g.setColor(UIManager.getColor(enabled ? "RadioButton.darcula.selectionEnabledShadowColor" : "RadioButton.darcula.selectionDisabledShadowColor"));// ? Gray._30 : Gray._60); - final int yOff = UIUtil.isUnderDarcula() ? 2 : JBUI.scale(1); + final int yOff = 2; g.fillOval(w/2 - rad/2, h/2 - rad/2 + yOff , rad, rad); g.setColor(UIManager.getColor(enabled ? "RadioButton.darcula.selectionEnabledColor" : "RadioButton.darcula.selectionDisabledColor")); //Gray._170 : Gray._120); g.fillOval(w/2 - rad/2, h/2 - rad/2 -1 + yOff, rad, rad); From 8a290943610f2a4d8412a843499757c80539f2c6 Mon Sep 17 00:00:00 2001 From: Dmitry Batrak Date: Wed, 14 Jan 2015 16:02:26 +0300 Subject: [PATCH 05/15] IDEA-134811 After ctrl-w selects line, shift-down should contain current line in selection --- .../openapi/actionSystem/IdeActions.java | 2 ++ .../openapi/editor/impl/CaretImpl.java | 3 ++- .../editor/actions/EditorActionTest.java | 20 +++++++++++++++++++ 3 files changed, 24 insertions(+), 1 deletion(-) diff --git a/platform/platform-api/src/com/intellij/openapi/actionSystem/IdeActions.java b/platform/platform-api/src/com/intellij/openapi/actionSystem/IdeActions.java index f81859417580..22f5eddf54c8 100644 --- a/platform/platform-api/src/com/intellij/openapi/actionSystem/IdeActions.java +++ b/platform/platform-api/src/com/intellij/openapi/actionSystem/IdeActions.java @@ -40,6 +40,8 @@ public interface IdeActions { @NonNls String ACTION_EDITOR_BACKSPACE = "EditorBackSpace"; @NonNls String ACTION_EDITOR_MOVE_CARET_LEFT_WITH_SELECTION = "EditorLeftWithSelection"; @NonNls String ACTION_EDITOR_MOVE_CARET_RIGHT_WITH_SELECTION = "EditorRightWithSelection"; + @NonNls String ACTION_EDITOR_MOVE_CARET_UP_WITH_SELECTION = "EditorUpWithSelection"; + @NonNls String ACTION_EDITOR_MOVE_CARET_DOWN_WITH_SELECTION = "EditorDownWithSelection"; @NonNls String ACTION_EDITOR_MOVE_CARET_UP = "EditorUp"; @NonNls String ACTION_EDITOR_MOVE_CARET_LEFT = "EditorLeft"; @NonNls String ACTION_EDITOR_MOVE_CARET_DOWN = "EditorDown"; diff --git a/platform/platform-impl/src/com/intellij/openapi/editor/impl/CaretImpl.java b/platform/platform-impl/src/com/intellij/openapi/editor/impl/CaretImpl.java index fd49b3b5574d..233f0cc45621 100644 --- a/platform/platform-impl/src/com/intellij/openapi/editor/impl/CaretImpl.java +++ b/platform/platform-impl/src/com/intellij/openapi/editor/impl/CaretImpl.java @@ -248,6 +248,7 @@ public class CaretImpl extends UserDataHolderBase implements Caret { myEditor.getCaretModel().doWithCaretMerging(new Runnable() { @Override public void run() { + int oldOffset = myOffset; final int leadSelectionOffset = getLeadSelectionOffset(); final VisualPosition leadSelectionPosition = getLeadSelectionPosition(); EditorSettings editorSettings = myEditor.getSettings(); @@ -370,7 +371,7 @@ public class CaretImpl extends UserDataHolderBase implements Caret { else { int selectionStartToUse = leadSelectionOffset; VisualPosition selectionStartPositionToUse = leadSelectionPosition; - if (isUnknownDirection()) { + if (isUnknownDirection() || oldOffset > getSelectionStart() && oldOffset < getSelectionEnd()) { if (getOffset() > leadSelectionOffset ^ getSelectionStart() < getSelectionEnd()) { selectionStartToUse = getSelectionEnd(); selectionStartPositionToUse = getSelectionEndPosition(); diff --git a/platform/platform-tests/testSrc/com/intellij/openapi/editor/actions/EditorActionTest.java b/platform/platform-tests/testSrc/com/intellij/openapi/editor/actions/EditorActionTest.java index a653da599d80..2545df56d20c 100644 --- a/platform/platform-tests/testSrc/com/intellij/openapi/editor/actions/EditorActionTest.java +++ b/platform/platform-tests/testSrc/com/intellij/openapi/editor/actions/EditorActionTest.java @@ -167,4 +167,24 @@ public class EditorActionTest extends AbstractEditorTest { executeAction(IdeActions.ACTION_EDITOR_DELETE_TO_WORD_END); checkResultByText("class Foo { String s = \"a\\b\"; }"); } + + public void testUpWithSelectionOnCaretInsideSelection() throws Exception { + initText("blah blah\n" + + "blah blah\n" + + "blah blah"); + executeAction(IdeActions.ACTION_EDITOR_MOVE_CARET_UP_WITH_SELECTION); + checkResultByText("blah blah\n" + + "blah blah\n" + + "blah blah"); + } + + public void testDownWithSelectionOnCaretInsideSelection() throws Exception { + initText("blah blah\n" + + "blah blah\n" + + "blah blah"); + executeAction(IdeActions.ACTION_EDITOR_MOVE_CARET_DOWN_WITH_SELECTION); + checkResultByText("blah blah\n" + + "blah blah\n" + + "blah blah"); + } } \ No newline at end of file From 2394bc283028017efd43f503c88db75d7bf4ad1f Mon Sep 17 00:00:00 2001 From: Julia Beliaeva Date: Wed, 14 Jan 2015 16:08:45 +0300 Subject: [PATCH 06/15] [vcs-log] show progress in find by hash popup while loading log IDEA-134749 --- .../api/src/com/intellij/vcs/log/VcsLog.java | 4 +- .../com/intellij/vcs/log/impl/VcsLogImpl.java | 7 +- .../vcs/log/ui/FindPopupWithProgress.java | 125 ++++++++++++++++++ .../intellij/vcs/log/ui/GoToRefAction.java | 20 +-- .../PopupWithTextFieldWithAutoCompletion.java | 85 ------------ .../vcs/log/ui/TextFieldWithProgress.java | 104 +++++++++++++++ .../com/intellij/vcs/log/ui/VcsLogUiImpl.java | 26 ++-- .../SelectRevisionInGitLogAction.java | 36 ++++- 8 files changed, 293 insertions(+), 114 deletions(-) create mode 100644 platform/vcs-log/impl/src/com/intellij/vcs/log/ui/FindPopupWithProgress.java delete mode 100644 platform/vcs-log/impl/src/com/intellij/vcs/log/ui/PopupWithTextFieldWithAutoCompletion.java create mode 100644 platform/vcs-log/impl/src/com/intellij/vcs/log/ui/TextFieldWithProgress.java diff --git a/platform/vcs-log/api/src/com/intellij/vcs/log/VcsLog.java b/platform/vcs-log/api/src/com/intellij/vcs/log/VcsLog.java index 29f63e6cdeb3..9636218cd449 100644 --- a/platform/vcs-log/api/src/com/intellij/vcs/log/VcsLog.java +++ b/platform/vcs-log/api/src/com/intellij/vcs/log/VcsLog.java @@ -21,6 +21,7 @@ import org.jetbrains.annotations.Nullable; import java.awt.*; import java.util.Collection; import java.util.List; +import java.util.concurrent.Future; /** * Use this interface to access information available in the VCS Log. @@ -55,7 +56,7 @@ public interface VcsLog { /** * Selects the commit node defined by the given reference (commit hash, branch or tag). */ - void jumpToReference(String reference); + Future jumpToReference(String reference); /** * Returns the VCS log toolbar component. @@ -68,5 +69,4 @@ public interface VcsLog { */ @NotNull Collection getLogProviders(); - } diff --git a/platform/vcs-log/impl/src/com/intellij/vcs/log/impl/VcsLogImpl.java b/platform/vcs-log/impl/src/com/intellij/vcs/log/impl/VcsLogImpl.java index e80032bbd9ba..a36e871489bd 100644 --- a/platform/vcs-log/impl/src/com/intellij/vcs/log/impl/VcsLogImpl.java +++ b/platform/vcs-log/impl/src/com/intellij/vcs/log/impl/VcsLogImpl.java @@ -28,6 +28,7 @@ import org.jetbrains.annotations.Nullable; import java.awt.*; import java.util.Collection; import java.util.List; +import java.util.concurrent.Future; /** * @@ -85,7 +86,7 @@ public class VcsLogImpl implements VcsLog { } @Override - public void jumpToReference(final String reference) { + public Future jumpToReference(final String reference) { Collection references = getAllReferences(); VcsRef ref = ContainerUtil.find(references, new Condition() { @Override @@ -94,10 +95,10 @@ public class VcsLogImpl implements VcsLog { } }); if (ref != null) { - myUi.jumpToCommit(ref.getCommitHash()); + return myUi.jumpToCommit(ref.getCommitHash()); } else { - myUi.jumpToCommitByPartOfHash(reference); + return myUi.jumpToCommitByPartOfHash(reference); } } diff --git a/platform/vcs-log/impl/src/com/intellij/vcs/log/ui/FindPopupWithProgress.java b/platform/vcs-log/impl/src/com/intellij/vcs/log/ui/FindPopupWithProgress.java new file mode 100644 index 000000000000..0b46160165ad --- /dev/null +++ b/platform/vcs-log/impl/src/com/intellij/vcs/log/ui/FindPopupWithProgress.java @@ -0,0 +1,125 @@ +/* + * 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.vcs.log.ui; + +import com.intellij.openapi.application.ApplicationManager; +import com.intellij.openapi.diagnostic.Logger; +import com.intellij.openapi.project.Project; +import com.intellij.openapi.ui.popup.JBPopup; +import com.intellij.openapi.ui.popup.JBPopupFactory; +import com.intellij.openapi.ui.popup.JBPopupListener; +import com.intellij.openapi.ui.popup.LightweightWindowEvent; +import com.intellij.ui.components.JBTextField; +import com.intellij.util.Function; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.awt.*; +import java.util.Collection; +import java.util.concurrent.CancellationException; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.Future; + +public class FindPopupWithProgress { + private static final Logger LOG = Logger.getInstance(FindPopupWithProgress.class); + + @NotNull private final TextFieldWithProgress myTextField; + @NotNull private final Function myFunction; + @NotNull private final JBPopup myPopup; + @Nullable private Future myFuture; + + public FindPopupWithProgress(@NotNull final Project project, + @NotNull Collection variants, + @NotNull Function function) { + myFunction = function; + myTextField = new TextFieldWithProgress(project, variants) { + @Override + public void onOk() { + if (myFuture == null) { + final Future future = myFunction.fun(getText().trim()); + myFuture = future; + showProgress(); + ApplicationManager.getApplication().executeOnPooledThread(new Runnable() { + @Override + public void run() { + try { + future.get(); + ok(); + } + catch (CancellationException ex) { + cancel(); + } + catch (InterruptedException ex) { + cancel(); + } + catch (ExecutionException ex) { + LOG.error(ex); + cancel(); + } + } + }); + } + } + }; + + myPopup = JBPopupFactory.getInstance().createComponentPopupBuilder(myTextField, myTextField.getPreferableFocusComponent()) + .setCancelOnClickOutside(true).setCancelOnWindowDeactivation(true).setCancelKeyEnabled(true).setRequestFocus(true).createPopup(); + myPopup.addListener(new JBPopupListener.Adapter() { + @Override + public void onClosed(LightweightWindowEvent event) { + if (!event.isOk()) { + if (myFuture != null) { + myFuture.cancel(false); + myFuture = null; + } + } + } + }); + + final JBTextField field = new JBTextField(20); + final Dimension size = field.getPreferredSize(); + final Insets insets = myTextField.getBorder().getBorderInsets(myTextField); + size.height += 6 + insets.top + insets.bottom; + size.width += 4 + insets.left + insets.right; + myPopup.setSize(size); + } + + private void cancel() { + ApplicationManager.getApplication().invokeLater(new Runnable() { + @Override + public void run() { + if (myFuture != null) myFuture = null; + myTextField.hideProgress(); + myPopup.cancel(); + } + }); + } + + private void ok() { + ApplicationManager.getApplication().invokeLater(new Runnable() { + @Override + public void run() { + if (myFuture != null) myFuture = null; + myTextField.hideProgress(); + myPopup.closeOk(null); + } + }); + } + + public void showUnderneathOf(@NotNull Component anchor) { + myPopup.showUnderneathOf(anchor); + } +} diff --git a/platform/vcs-log/impl/src/com/intellij/vcs/log/ui/GoToRefAction.java b/platform/vcs-log/impl/src/com/intellij/vcs/log/ui/GoToRefAction.java index 8b117c72da26..12f6b65a0551 100644 --- a/platform/vcs-log/impl/src/com/intellij/vcs/log/ui/GoToRefAction.java +++ b/platform/vcs-log/impl/src/com/intellij/vcs/log/ui/GoToRefAction.java @@ -18,9 +18,6 @@ package com.intellij.vcs.log.ui; import com.intellij.openapi.actionSystem.AnActionEvent; import com.intellij.openapi.project.DumbAwareAction; import com.intellij.openapi.project.Project; -import com.intellij.openapi.ui.popup.JBPopup; -import com.intellij.openapi.ui.popup.JBPopupListener; -import com.intellij.openapi.ui.popup.LightweightWindowEvent; import com.intellij.util.Function; import com.intellij.util.containers.ContainerUtil; import com.intellij.vcs.log.VcsLog; @@ -28,6 +25,7 @@ import com.intellij.vcs.log.VcsLogDataKeys; import com.intellij.vcs.log.VcsRef; import java.util.Collection; +import java.util.concurrent.Future; public class GoToRefAction extends DumbAwareAction { @@ -45,16 +43,12 @@ public class GoToRefAction extends DumbAwareAction { return ref.getName(); } }); - final PopupWithTextFieldWithAutoCompletion textField = new PopupWithTextFieldWithAutoCompletion(project, refs); - JBPopup popup = textField.createPopup(); - popup.addListener(new JBPopupListener.Adapter() { - @Override - public void onClosed(LightweightWindowEvent event) { - if (event.isOk()) { - log.jumpToReference(textField.getText().trim()); - } - } - }); + FindPopupWithProgress popup = new FindPopupWithProgress(project, refs, new Function() { + @Override + public Future fun(String text) { + return log.jumpToReference(text); + } + }); popup.showUnderneathOf(log.getToolbar()); } diff --git a/platform/vcs-log/impl/src/com/intellij/vcs/log/ui/PopupWithTextFieldWithAutoCompletion.java b/platform/vcs-log/impl/src/com/intellij/vcs/log/ui/PopupWithTextFieldWithAutoCompletion.java deleted file mode 100644 index fbfb71de3c04..000000000000 --- a/platform/vcs-log/impl/src/com/intellij/vcs/log/ui/PopupWithTextFieldWithAutoCompletion.java +++ /dev/null @@ -1,85 +0,0 @@ -/* - * Copyright 2000-2013 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.vcs.log.ui; - -import com.intellij.openapi.editor.ex.EditorEx; -import com.intellij.openapi.project.Project; -import com.intellij.openapi.ui.popup.JBPopup; -import com.intellij.openapi.ui.popup.JBPopupFactory; -import com.intellij.spellchecker.ui.SpellCheckingEditorCustomization; -import com.intellij.ui.TextFieldWithAutoCompletion; -import com.intellij.ui.components.JBTextField; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -import javax.swing.*; -import javax.swing.border.EmptyBorder; -import java.awt.*; -import java.awt.event.KeyEvent; -import java.util.Collection; - -public class PopupWithTextFieldWithAutoCompletion extends TextFieldWithAutoCompletion { - - @Nullable private JBPopup myPopup; - - public PopupWithTextFieldWithAutoCompletion(@NotNull Project project, @NotNull Collection variants) { - super(project, new StringsCompletionProvider(variants, null), false, null); - setBorder(new EmptyBorder(3, 3, 3, 3)); - } - - public JBPopup createPopup() { - myPopup = JBPopupFactory.getInstance().createComponentPopupBuilder(this, this) - .setCancelOnClickOutside(true) - .setCancelOnWindowDeactivation(true) - .setCancelKeyEnabled(true) - .setRequestFocus(true) - .createPopup(); - - final JBTextField field = new JBTextField(20); - final Dimension size = field.getPreferredSize(); - final Insets insets = getBorder().getBorderInsets(this); - size.height+=6 + insets.top + insets.bottom; - size.width +=4 + insets.left + insets.right; - myPopup.setSize(size); - - return myPopup; - } - - @Override - protected boolean processKeyBinding(KeyStroke ks, KeyEvent e, int condition, boolean pressed) { - if (e.getKeyCode() == KeyEvent.VK_ENTER) { - if (myPopup != null) { - myPopup.closeOk(e); - } - return true; - } - else if (e.getKeyCode() == KeyEvent.VK_ESCAPE) { - if (myPopup != null) { - myPopup.cancel(e); - } - return true; - } - return false; - } - - @Override - protected EditorEx createEditor() { - // spell check is not needed - EditorEx editor = super.createEditor(); - SpellCheckingEditorCustomization.getInstance(false).customize(editor); - return editor; - } -} diff --git a/platform/vcs-log/impl/src/com/intellij/vcs/log/ui/TextFieldWithProgress.java b/platform/vcs-log/impl/src/com/intellij/vcs/log/ui/TextFieldWithProgress.java new file mode 100644 index 000000000000..70901fe4caaa --- /dev/null +++ b/platform/vcs-log/impl/src/com/intellij/vcs/log/ui/TextFieldWithProgress.java @@ -0,0 +1,104 @@ +/* + * 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.vcs.log.ui; + +import com.intellij.openapi.editor.ex.EditorEx; +import com.intellij.openapi.progress.PerformInBackgroundOption; +import com.intellij.openapi.progress.ProgressIndicator; +import com.intellij.openapi.progress.ProgressManager; +import com.intellij.openapi.progress.Task; +import com.intellij.openapi.project.Project; +import com.intellij.spellchecker.ui.SpellCheckingEditorCustomization; +import com.intellij.ui.IdeBorderFactory; +import com.intellij.ui.TextFieldWithAutoCompletion; +import com.intellij.util.ui.AsyncProcessIcon; +import org.jetbrains.annotations.NotNull; + +import javax.swing.*; +import javax.swing.border.EmptyBorder; +import java.awt.*; +import java.awt.event.KeyEvent; +import java.util.Collection; +import java.util.concurrent.CancellationException; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.Future; + +public abstract class TextFieldWithProgress extends JPanel { + @NotNull private final TextFieldWithAutoCompletion myTextField; + @NotNull private final AsyncProcessIcon myProgressIcon; + + public TextFieldWithProgress(@NotNull Project project, @NotNull Collection variants) { + super(new BorderLayout()); + setBorder(IdeBorderFactory.createEmptyBorder(3)); + + myProgressIcon = new AsyncProcessIcon("Loading commits"); + myTextField = + new TextFieldWithAutoCompletion(project, new TextFieldWithAutoCompletion.StringsCompletionProvider(variants, null), false, + null) { + @Override + public void setBackground(Color bg) { + super.setBackground(bg); + myProgressIcon.setBackground(bg); + } + + @Override + protected EditorEx createEditor() { + // spell check is not needed + EditorEx editor = super.createEditor(); + SpellCheckingEditorCustomization.getInstance(false).customize(editor); + return editor; + } + + @Override + protected boolean processKeyBinding(KeyStroke ks, final KeyEvent e, int condition, boolean pressed) { + if (e.getKeyCode() == KeyEvent.VK_ENTER) { + onOk(); + return true; + } + return false; + } + }; + myTextField.setBorder(IdeBorderFactory.createEmptyBorder()); + + myProgressIcon.setOpaque(true); + myProgressIcon.setBackground(myTextField.getBackground()); + + add(myTextField, BorderLayout.CENTER); + add(myProgressIcon, BorderLayout.EAST); + + hideProgress(); + } + + public JComponent getPreferableFocusComponent() { + return myTextField; + } + + public void showProgress() { + myTextField.setEnabled(false); + myProgressIcon.setVisible(true); + } + + public void hideProgress() { + myTextField.setEnabled(true); + myProgressIcon.setVisible(false); + } + + public String getText() { + return myTextField.getText(); + } + + public abstract void onOk(); +} diff --git a/platform/vcs-log/impl/src/com/intellij/vcs/log/ui/VcsLogUiImpl.java b/platform/vcs-log/impl/src/com/intellij/vcs/log/ui/VcsLogUiImpl.java index 78ce9caeb2a1..7e098af05ee9 100644 --- a/platform/vcs-log/impl/src/com/intellij/vcs/log/ui/VcsLogUiImpl.java +++ b/platform/vcs-log/impl/src/com/intellij/vcs/log/ui/VcsLogUiImpl.java @@ -1,5 +1,6 @@ package com.intellij.vcs.log.ui; +import com.google.common.util.concurrent.SettableFuture; import com.intellij.openapi.Disposable; import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.diagnostic.Logger; @@ -32,6 +33,7 @@ import javax.swing.table.TableModel; import java.awt.*; import java.util.ArrayList; import java.util.Collection; +import java.util.concurrent.Future; public class VcsLogUiImpl implements VcsLogUi, Disposable { @@ -192,22 +194,26 @@ public class VcsLogUiImpl implements VcsLogUi, Disposable { return myUiProperties.isShowRootNames(); } - public void jumpToCommit(@NotNull Hash commitHash) { + public Future jumpToCommit(@NotNull Hash commitHash) { + SettableFuture future = SettableFuture.create(); jumpTo(commitHash, new PairFunction() { @Override public Integer fun(GraphTableModel model, Hash hash) { return model.getRowOfCommit(hash); } - }); + }, future); + return future; } - public void jumpToCommitByPartOfHash(@NotNull String commitHash) { + public Future jumpToCommitByPartOfHash(@NotNull String commitHash) { + SettableFuture future = SettableFuture.create(); jumpTo(commitHash, new PairFunction() { @Override public Integer fun(GraphTableModel model, String hash) { return model.getRowOfCommitByPartOfHash(hash); } - }); + }, future); + return future; } public void handleAnswer(@Nullable GraphAnswer answer, boolean dataCouldChange) { @@ -235,13 +241,15 @@ public class VcsLogUiImpl implements VcsLogUi, Disposable { } } - private void jumpTo(@NotNull final T commitId, @NotNull final PairFunction rowGetter) { + private void jumpTo(@NotNull final T commitId, @NotNull final PairFunction rowGetter, @NotNull final SettableFuture future) { + if (future.isCancelled()) return; + GraphTableModel model = getModel(); if (model == null) { invokeOnChange(new Runnable() { @Override public void run() { - jumpTo(commitId, rowGetter); + jumpTo(commitId, rowGetter, future); } }); return; @@ -250,12 +258,13 @@ public class VcsLogUiImpl implements VcsLogUi, Disposable { int row = rowGetter.fun(model, commitId); if (row >= 0) { myMainFrame.getGraphTable().jumpToRow(row); + future.set(true); } else if (model.canRequestMore()) { model.requestToLoadMore(new Runnable() { @Override public void run() { - jumpTo(commitId, rowGetter); + jumpTo(commitId, rowGetter, future); } }); } @@ -263,12 +272,13 @@ public class VcsLogUiImpl implements VcsLogUi, Disposable { invokeOnChange(new Runnable() { @Override public void run() { - jumpTo(commitId, rowGetter); + jumpTo(commitId, rowGetter, future); } }); } else { commitNotFound(commitId.toString()); + future.set(false); } } diff --git a/plugins/git4idea/src/git4idea/history/wholeTree/SelectRevisionInGitLogAction.java b/plugins/git4idea/src/git4idea/history/wholeTree/SelectRevisionInGitLogAction.java index 1d7db804019b..0d4c66a44f8e 100644 --- a/plugins/git4idea/src/git4idea/history/wholeTree/SelectRevisionInGitLogAction.java +++ b/plugins/git4idea/src/git4idea/history/wholeTree/SelectRevisionInGitLogAction.java @@ -2,6 +2,11 @@ package git4idea.history.wholeTree; import com.intellij.openapi.actionSystem.AnActionEvent; import com.intellij.openapi.actionSystem.CommonDataKeys; +import com.intellij.openapi.diagnostic.Logger; +import com.intellij.openapi.progress.PerformInBackgroundOption; +import com.intellij.openapi.progress.ProgressIndicator; +import com.intellij.openapi.progress.ProgressManager; +import com.intellij.openapi.progress.Task; import com.intellij.openapi.project.DumbAwareAction; import com.intellij.openapi.project.Project; import com.intellij.openapi.ui.MessageType; @@ -22,7 +27,12 @@ import git4idea.i18n.GitBundle; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; +import java.util.concurrent.CancellationException; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.Future; + public class SelectRevisionInGitLogAction extends DumbAwareAction { + private static final Logger LOG = Logger.getInstance(SelectRevisionInGitLogAction.class); public SelectRevisionInGitLogAction() { super(GitBundle.getString("vcs.history.action.gitlog"), GitBundle.getString("vcs.history.action.gitlog"), null); @@ -30,7 +40,7 @@ public class SelectRevisionInGitLogAction extends DumbAwareAction { @Override public void actionPerformed(@NotNull AnActionEvent event) { - Project project = event.getRequiredData(CommonDataKeys.PROJECT); + final Project project = event.getRequiredData(CommonDataKeys.PROJECT); final VcsRevisionNumber revision = getRevisionNumber(event); if (revision == null) { return; @@ -60,7 +70,7 @@ public class SelectRevisionInGitLogAction extends DumbAwareAction { Runnable selectCommit = new Runnable() { @Override public void run() { - log.jumpToReference(revision.asString()); + jumpToRevisionUnderProgress(project, log, revision); } }; @@ -128,5 +138,25 @@ public class SelectRevisionInGitLogAction extends DumbAwareAction { return null; } - + private static void jumpToRevisionUnderProgress(@NotNull Project project, @NotNull VcsLog log, @NotNull VcsRevisionNumber revision) { + final Future future = log.jumpToReference(revision.asString()); + if (!future.isDone()) { + ProgressManager.getInstance().run(new Task.Backgroundable(project, "Searching for revision " + revision.asString(), false/*can not cancel*/, + PerformInBackgroundOption.ALWAYS_BACKGROUND) { + @Override + public void run(@NotNull ProgressIndicator indicator) { + try { + future.get(); + } + catch (CancellationException ignored) { + } + catch (InterruptedException ignored) { + } + catch (ExecutionException e) { + LOG.error(e); + } + } + }); + } + } } From f0ee490791db7d125016b123dae86ae60e49614e Mon Sep 17 00:00:00 2001 From: Julia Beliaeva Date: Wed, 14 Jan 2015 16:13:47 +0300 Subject: [PATCH 07/15] [vcs-log] add NotNull annotations --- platform/vcs-log/api/src/com/intellij/vcs/log/VcsLog.java | 1 + .../vcs-log/impl/src/com/intellij/vcs/log/impl/VcsLogImpl.java | 1 + .../vcs-log/impl/src/com/intellij/vcs/log/ui/VcsLogUiImpl.java | 2 ++ 3 files changed, 4 insertions(+) diff --git a/platform/vcs-log/api/src/com/intellij/vcs/log/VcsLog.java b/platform/vcs-log/api/src/com/intellij/vcs/log/VcsLog.java index 9636218cd449..73b0c3bfdb54 100644 --- a/platform/vcs-log/api/src/com/intellij/vcs/log/VcsLog.java +++ b/platform/vcs-log/api/src/com/intellij/vcs/log/VcsLog.java @@ -56,6 +56,7 @@ public interface VcsLog { /** * Selects the commit node defined by the given reference (commit hash, branch or tag). */ + @NotNull Future jumpToReference(String reference); /** diff --git a/platform/vcs-log/impl/src/com/intellij/vcs/log/impl/VcsLogImpl.java b/platform/vcs-log/impl/src/com/intellij/vcs/log/impl/VcsLogImpl.java index a36e871489bd..0b685dffc3f1 100644 --- a/platform/vcs-log/impl/src/com/intellij/vcs/log/impl/VcsLogImpl.java +++ b/platform/vcs-log/impl/src/com/intellij/vcs/log/impl/VcsLogImpl.java @@ -85,6 +85,7 @@ public class VcsLogImpl implements VcsLog { return myUi.getDataPack().getRefsModel().getAllRefs(); } + @NotNull @Override public Future jumpToReference(final String reference) { Collection references = getAllReferences(); diff --git a/platform/vcs-log/impl/src/com/intellij/vcs/log/ui/VcsLogUiImpl.java b/platform/vcs-log/impl/src/com/intellij/vcs/log/ui/VcsLogUiImpl.java index 7e098af05ee9..440b3efd1a9a 100644 --- a/platform/vcs-log/impl/src/com/intellij/vcs/log/ui/VcsLogUiImpl.java +++ b/platform/vcs-log/impl/src/com/intellij/vcs/log/ui/VcsLogUiImpl.java @@ -194,6 +194,7 @@ public class VcsLogUiImpl implements VcsLogUi, Disposable { return myUiProperties.isShowRootNames(); } + @NotNull public Future jumpToCommit(@NotNull Hash commitHash) { SettableFuture future = SettableFuture.create(); jumpTo(commitHash, new PairFunction() { @@ -205,6 +206,7 @@ public class VcsLogUiImpl implements VcsLogUi, Disposable { return future; } + @NotNull public Future jumpToCommitByPartOfHash(@NotNull String commitHash) { SettableFuture future = SettableFuture.create(); jumpTo(commitHash, new PairFunction() { From ba2dc0e0db889f2451af3e723900376491759a00 Mon Sep 17 00:00:00 2001 From: Dmitry Avdeev Date: Wed, 14 Jan 2015 16:08:44 +0300 Subject: [PATCH 08/15] IDEA-17307 Enum must not be local in JSP declaration block --- .../codeInsight/daemon/impl/analysis/GenericsHighlightUtil.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 76da573725a8..e1fdc3840f2a 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 @@ -1173,7 +1173,7 @@ public class GenericsHighlightUtil { public static HighlightInfo checkEnumMustNotBeLocal(final PsiClass aClass) { if (!aClass.isEnum()) return null; PsiElement parent = aClass.getParent(); - if (!(parent instanceof PsiClass || parent instanceof PsiFile)) { + if (!(parent instanceof PsiClass || parent instanceof PsiFile || parent instanceof PsiClassLevelDeclarationStatement)) { String description = JavaErrorMessages.message("local.enum"); TextRange textRange = HighlightNamesUtil.getClassDeclarationTextRange(aClass); return HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR).range(textRange).descriptionAndTooltip(description).create(); From 2806b9890bd3078b2a27d4d6ce2e9d1f0d1eb8ac Mon Sep 17 00:00:00 2001 From: "Vassiliy.Kudryashov" Date: Wed, 14 Jan 2015 16:29:01 +0300 Subject: [PATCH 09/15] IDEA-135089 Search and replace multiline text allows to input only three lines --- .../intellij/find/EditorSearchComponent.java | 17 ++++++++++++++--- .../util/src/com/intellij/util/ui/UIUtil.java | 4 ++++ 2 files changed, 18 insertions(+), 3 deletions(-) diff --git a/platform/lang-impl/src/com/intellij/find/EditorSearchComponent.java b/platform/lang-impl/src/com/intellij/find/EditorSearchComponent.java index 747cea82df93..f30da0b39b4b 100644 --- a/platform/lang-impl/src/com/intellij/find/EditorSearchComponent.java +++ b/platform/lang-impl/src/com/intellij/find/EditorSearchComponent.java @@ -450,6 +450,9 @@ public class EditorSearchComponent extends EditorHeaderComponent implements Data else { nothingToSearchFor(); } + if (mySearchField instanceof JTextArea) { + UIUtil.adjustRows((JTextArea)mySearchField, 2, 6); + } } public boolean isRegexp() { @@ -637,6 +640,9 @@ public class EditorSearchComponent extends EditorHeaderComponent implements Data private void replaceFieldDocumentChanged() { setMatchesLimit(LivePreviewController.MATCHES_LIMIT); myFindModel.setStringToReplace(myReplaceField.getText()); + if (myReplaceField instanceof JTextArea) { + UIUtil.adjustRows((JTextArea)myReplaceField, 2, 6); + } } private boolean canReplaceCurrent() { @@ -697,12 +703,17 @@ public class EditorSearchComponent extends EditorHeaderComponent implements Data super.paintBorder(g); paintBorderOfTextField(g); } + + @Override + public Dimension getPreferredSize() { + return super.getPreferredSize(); + } }; ((JTextArea)editorTextField).setColumns(25); - ((JTextArea)editorTextField).setRows(3); + ((JTextArea)editorTextField).setRows(2); final JScrollPane scrollPane = new JBScrollPane(editorTextField, - ScrollPaneConstants.VERTICAL_SCROLLBAR_NEVER, - ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER); + ScrollPaneConstants.VERTICAL_SCROLLBAR_AS_NEEDED, + ScrollPaneConstants.HORIZONTAL_SCROLLBAR_AS_NEEDED); myLeftComponent.add(scrollPane, constraint); componentRef.set(scrollPane); } diff --git a/platform/util/src/com/intellij/util/ui/UIUtil.java b/platform/util/src/com/intellij/util/ui/UIUtil.java index 02bed0eedf02..6af544af7755 100644 --- a/platform/util/src/com/intellij/util/ui/UIUtil.java +++ b/platform/util/src/com/intellij/util/ui/UIUtil.java @@ -3215,6 +3215,10 @@ public class UIUtil { textComponent.getActionMap().put("redoKeystroke", REDO_ACTION); } + public static void adjustRows(JTextArea area, int minRows, int maxRows) { + area.setRows(Math.max(minRows, Math.min(maxRows, area.getText().split("\n").length))); + } + public static void playSoundFromResource(final String resourceName) { final Class callerClass = ReflectionUtil.getGrandCallerClass(); if (callerClass == null) return; From 2300591f46220e96d094598e969b21bfb0cdc88d Mon Sep 17 00:00:00 2001 From: "Maxim.Mossienko" Date: Wed, 14 Jan 2015 14:48:41 +0100 Subject: [PATCH 10/15] show usage in preview editor --- .../com/intellij/find/impl/FindDialog.java | 85 +++++++++++++------ 1 file changed, 60 insertions(+), 25 deletions(-) diff --git a/platform/lang-impl/src/com/intellij/find/impl/FindDialog.java b/platform/lang-impl/src/com/intellij/find/impl/FindDialog.java index d44e4a25cb17..6db6bfe0e4db 100644 --- a/platform/lang-impl/src/com/intellij/find/impl/FindDialog.java +++ b/platform/lang-impl/src/com/intellij/find/impl/FindDialog.java @@ -60,6 +60,7 @@ import com.intellij.ui.components.JBScrollPane; import com.intellij.ui.table.JBTable; import com.intellij.usageView.UsageInfo; import com.intellij.usages.*; +import com.intellij.usages.impl.UsagePreviewPanel; import com.intellij.util.ArrayUtil; import com.intellij.util.Consumer; import com.intellij.util.Processor; @@ -70,14 +71,14 @@ import org.jetbrains.annotations.Nullable; import javax.swing.*; import javax.swing.event.ChangeEvent; import javax.swing.event.ChangeListener; +import javax.swing.event.ListSelectionEvent; +import javax.swing.event.ListSelectionListener; import javax.swing.table.DefaultTableModel; import javax.swing.table.TableCellRenderer; import java.awt.*; import java.awt.event.*; -import java.util.Arrays; -import java.util.HashMap; +import java.util.*; import java.util.List; -import java.util.Map; import java.util.concurrent.atomic.AtomicInteger; import java.util.regex.Pattern; import java.util.regex.PatternSyntaxException; @@ -123,7 +124,9 @@ public class FindDialog extends DialogWrapper { private static boolean myPreviewResultsTabWasSelected; private static final int RESULTS_PREVIEW_TAB_INDEX = 1; + private Splitter myPreviewSplitter; private JBTable myResultsPreviewTable; + private UsagePreviewPanel myUsagePreviewPanel; private TabbedPane myContent; private volatile ProgressIndicatorBase myResultsPreviewSearchProgress; @@ -173,6 +176,7 @@ public class FindDialog extends DialogWrapper { @Override protected void dispose() { finishPreviousPreviewSearch(); + if (myUsagePreviewPanel != null) Disposer.dispose(myUsagePreviewPanel); for(Map.Entry e: myComboBoxListeners.entrySet()) { e.getKey().removeDocumentListener(e.getValue()); } @@ -489,8 +493,29 @@ public class FindDialog extends DialogWrapper { } }; table.setShowColumns(false); + table.setShowGrid(false); new NavigateToSourceListener().installOn(table); + + Splitter previewSplitter = new Splitter(true, 0.5f, 0.1f, 0.9f); + myUsagePreviewPanel = new UsagePreviewPanel(myProject, new UsageViewPresentation()); myResultsPreviewTable = table; + myResultsPreviewTable.getSelectionModel().addListSelectionListener(new ListSelectionListener() { + @Override + public void valueChanged(ListSelectionEvent e) { + if (e.getValueIsAdjusting()) return; + int index = myResultsPreviewTable.getSelectionModel().getLeadSelectionIndex(); + if (index != -1) { + UsageInfo usageInfo = ((UsageInfo2UsageAdapter)myResultsPreviewTable.getModel().getValueAt(index, 0)).getUsageInfo(); + myUsagePreviewPanel.updateLayout(Collections.singletonList(usageInfo)); + } + else { + myUsagePreviewPanel.updateLayout(null); + } + } + }); + previewSplitter.setFirstComponent(new JBScrollPane(myResultsPreviewTable)); + previewSplitter.setSecondComponent(myUsagePreviewPanel.createComponent()); + myPreviewSplitter = previewSplitter; } } else { @@ -513,10 +538,10 @@ public class FindDialog extends DialogWrapper { resultsOptionPanel.add(myCbToOpenInNewTab); } - if (myResultsPreviewTable != null) { + if (myPreviewSplitter != null) { TabbedPane pane = new TabbedPaneImpl(SwingConstants.TOP); pane.insertTab("Options", null, optionsPanel, null, 0); - pane.insertTab("Preview", null, new JBScrollPane(myResultsPreviewTable), null, RESULTS_PREVIEW_TAB_INDEX); + pane.insertTab("Preview", null, myPreviewSplitter, null, RESULTS_PREVIEW_TAB_INDEX); myContent = pane; if (myPreviewResultsTabWasSelected) myContent.setSelectedIndex(RESULTS_PREVIEW_TAB_INDEX); @@ -1389,36 +1414,46 @@ public class FindDialog extends DialogWrapper { } private static class UsageTableCellRenderer extends JPanel implements TableCellRenderer { - private SimpleColoredComponent myUsageRenderer = new SimpleColoredComponent(); - private SimpleColoredComponent myFileAndLineNumber = new SimpleColoredComponent(); + private ColoredTableCellRenderer myUsageRenderer = new ColoredTableCellRenderer() { + @Override + protected void customizeCellRenderer(JTable table, Object value, boolean selected, boolean hasFocus, int row, int column) { + if (value instanceof UsageInfo2UsageAdapter) { + TextChunk[] text = ((UsageInfo2UsageAdapter)value).getPresentation().getText(); + + // skip line number / file info + for (int i = 1; i < text.length; ++i) { + TextChunk textChunk = text[i]; + myUsageRenderer.append(textChunk.getText(), textChunk.getSimpleAttributesIgnoreBackground()); + } + } + setBorder(null); + } + }; + private ColoredTableCellRenderer myFileAndLineNumber = new ColoredTableCellRenderer() { + @Override + protected void customizeCellRenderer(JTable table, Object value, boolean selected, boolean hasFocus, int row, int column) { + if (value instanceof UsageInfo2UsageAdapter) { + TextChunk[] text = ((UsageInfo2UsageAdapter)value).getPresentation().getText(); + // line number / file info + append(((UsageInfo2UsageAdapter)value).getFile().getName() + " " + text[0].getText(), SimpleTextAttributes.GRAYED_ITALIC_ATTRIBUTES); + } + setBorder(null); + } + }; UsageTableCellRenderer() { setLayout(new BorderLayout()); + add(myUsageRenderer, BorderLayout.WEST); add(myFileAndLineNumber, BorderLayout.EAST); } @Override public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) { - myUsageRenderer.clear(); - myFileAndLineNumber.clear(); - setBackground(isSelected && hasFocus ? UIUtil.getTableSelectionBackground() : UIUtil.getTableBackground()); + setBackground(UIUtil.getTableBackground(isSelected)); + myUsageRenderer.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column); + myFileAndLineNumber.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column); - if (value instanceof UsageInfo2UsageAdapter) { - UsageInfo2UsageAdapter usageAdapter = (UsageInfo2UsageAdapter)value; - UsagePresentation presentation = usageAdapter.getPresentation(); - TextChunk[] text = presentation.getText(); - - // put line number / file info at the right - for (int i = 1; i < text.length; ++i) { - TextChunk textChunk = text[i]; - SimpleTextAttributes simples = textChunk.getSimpleAttributesIgnoreBackground(); - myUsageRenderer.append(textChunk.getText(), simples); - } - - myFileAndLineNumber.append(usageAdapter.getFile().getName() + " " + text[0].getText(), - SimpleTextAttributes.GRAYED_ITALIC_ATTRIBUTES); - } return this; } } From 5b2519635a36baaa0290fac6f0205a39249abfaf Mon Sep 17 00:00:00 2001 From: Anton Makeev Date: Wed, 14 Jan 2015 14:49:44 +0100 Subject: [PATCH 11/15] Platform: ListTable/ListTableModel fixes: 1) first cell was always selected when TAB was pressed during editing. Fix: event.consume() 2) editing, adding and removing elements should scroll to the effected element 3) pressing 'add' when last element is empty should focus it and edit, otherwise isn't not clear, why 'add' doesn't work. 4) a bit more compact view (interlaced spacing removed, stripes added) 5) ListTableModel should send notifications, when value in a cell has been changed --- .../execution/util/ListTableWithButtons.java | 23 +++++++++++++++---- .../com/intellij/util/ui/ListTableModel.java | 1 + 2 files changed, 20 insertions(+), 4 deletions(-) diff --git a/platform/lang-api/src/com/intellij/execution/util/ListTableWithButtons.java b/platform/lang-api/src/com/intellij/execution/util/ListTableWithButtons.java index 78f833591ebc..22cbf612d5fd 100644 --- a/platform/lang-api/src/com/intellij/execution/util/ListTableWithButtons.java +++ b/platform/lang-api/src/com/intellij/execution/util/ListTableWithButtons.java @@ -27,6 +27,7 @@ import org.jetbrains.annotations.Nullable; import javax.swing.*; import javax.swing.table.DefaultTableCellRenderer; import javax.swing.table.TableCellRenderer; +import java.awt.*; import java.awt.event.KeyAdapter; import java.awt.event.KeyEvent; import java.util.Collections; @@ -40,6 +41,7 @@ public abstract class ListTableWithButtons extends Observable { private final List myElements = ContainerUtil.newArrayList(); private final JPanel myPanel; private final TableView myTableView; + private final CommonActionsPanel myActionsPanel; private boolean myIsEnabled = true; protected ListTableWithButtons() { @@ -55,6 +57,7 @@ public abstract class ListTableWithButtons extends Observable { final int column = myTableView.getEditingColumn(); final int row = myTableView.getEditingRow(); if (e.getModifiers() == 0 && (e.getKeyCode() == KeyEvent.VK_ENTER || e.getKeyCode() == KeyEvent.VK_TAB)) { + e.consume(); SwingUtilities.invokeLater(new Runnable() { @Override public void run() { @@ -69,6 +72,7 @@ public abstract class ListTableWithButtons extends Observable { nextRow = 0; } } + myTableView.scrollRectToVisible(myTableView.getCellRect(nextRow, nextColumn, true)); myTableView.editCellAt(nextRow, nextColumn); } }); @@ -79,19 +83,24 @@ public abstract class ListTableWithButtons extends Observable { } }; myTableView.setRowHeight(new JTextField().getPreferredSize().height); + myTableView.setIntercellSpacing(new Dimension(0, 0)); + myTableView.setStriped(true); + myTableView.getTableViewModel().setSortable(false); - myPanel = ToolbarDecorator.createDecorator(myTableView) + ToolbarDecorator decorator = ToolbarDecorator.createDecorator(myTableView); + myPanel = decorator .setAddAction(new AnActionButtonRunnable() { @Override public void run(AnActionButton button) { - if (!myElements.isEmpty() && isEmpty(myElements.get(myElements.size() - 1))) return; myTableView.stopEditing(); setModified(); SwingUtilities.invokeLater(new Runnable() { @Override public void run() { - myElements.add(createElement()); - myTableView.getTableViewModel().setItems(myElements); + if (myElements.isEmpty() || !isEmpty(myElements.get(myElements.size() - 1))) { + myElements.add(createElement()); + myTableView.getTableViewModel().setItems(myElements); + } myTableView.scrollRectToVisible(myTableView.getCellRect(myElements.size() - 1, 0, true)); myTableView.getComponent().editCellAt(myElements.size() - 1, 0); } @@ -105,6 +114,7 @@ public abstract class ListTableWithButtons extends Observable { T selected = getSelection(); if (selected != null) { int selectedIndex = myElements.indexOf(selected); + myTableView.scrollRectToVisible(myTableView.getCellRect(selectedIndex, 0, true)); myElements.remove(selected); myTableView.getTableViewModel().setItems(myElements); @@ -133,6 +143,7 @@ public abstract class ListTableWithButtons extends Observable { } }); + myActionsPanel = decorator.getActionsPanel(); myTableView.getComponent().setSelectionMode(ListSelectionModel.SINGLE_SELECTION); } @@ -157,6 +168,10 @@ public abstract class ListTableWithButtons extends Observable { return myPanel; } + public CommonActionsPanel getActionsPanel() { + return myActionsPanel; + } + public void setEnabled() { myTableView.getComponent().setEnabled(true); myIsEnabled = true; diff --git a/platform/util/src/com/intellij/util/ui/ListTableModel.java b/platform/util/src/com/intellij/util/ui/ListTableModel.java index 8e01d89374cc..bdd04ec399ac 100644 --- a/platform/util/src/com/intellij/util/ui/ListTableModel.java +++ b/platform/util/src/com/intellij/util/ui/ListTableModel.java @@ -116,6 +116,7 @@ public class ListTableModel extends TableViewModel implements Editab if (rowIndex < myItems.size()) { myColumnInfos[columnIndex].setValue(getItem(rowIndex), aValue); } + fireTableCellUpdated(rowIndex, columnIndex); } /** From f1c1790bdda323e3ce38003d2d48f48eb833f8cb Mon Sep 17 00:00:00 2001 From: Kirill Likhodedov Date: Wed, 14 Jan 2015 16:57:32 +0300 Subject: [PATCH 12/15] [vcs] EA-62261 don't modify the externally received collection --- .../vcs/changes/patch/ApplyPatchDifferentiatedDialog.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/patch/ApplyPatchDifferentiatedDialog.java b/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/patch/ApplyPatchDifferentiatedDialog.java index 80f78e885500..e32434c67177 100644 --- a/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/patch/ApplyPatchDifferentiatedDialog.java +++ b/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/patch/ApplyPatchDifferentiatedDialog.java @@ -947,12 +947,12 @@ public class ApplyPatchDifferentiatedDialog extends DialogWrapper { if (myPatches.isEmpty() || (! myContainBasedChanges)) return; final List changes = getAllChanges(); Collections.sort(changes, myMyChangeComparator); - final List selectedChanges = myChangesTreeList.getSelectedChanges(); + List selectedChanges = myChangesTreeList.getSelectedChanges(); int selectedIdx = 0; final ArrayList diffRequestPresentables = new ArrayList(changes.size()); if (selectedChanges.isEmpty()) { - selectedChanges.addAll(changes); + selectedChanges = changes; } if (! selectedChanges.isEmpty()) { final FilePatchInProgress.PatchChange c = selectedChanges.get(0); From 5a24769ec5d6339e875028d0f86b9b3933b78d72 Mon Sep 17 00:00:00 2001 From: "Egor.Ushakov" Date: Wed, 14 Jan 2015 17:43:19 +0300 Subject: [PATCH 13/15] do not normalize "at breakpoint" thread state --- .../src/com/intellij/unscramble/UnscrambleDialog.java | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/java/java-impl/src/com/intellij/unscramble/UnscrambleDialog.java b/java/java-impl/src/com/intellij/unscramble/UnscrambleDialog.java index 4c60a453eafa..1245f04103cd 100644 --- a/java/java-impl/src/com/intellij/unscramble/UnscrambleDialog.java +++ b/java/java-impl/src/com/intellij/unscramble/UnscrambleDialog.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2012 JetBrains s.r.o. + * 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. @@ -314,6 +314,10 @@ public class UnscrambleDialog extends DialogWrapper { builder.append(trimSuffix(line)).append("\n"); continue; } + if (line.startsWith("at breakpoint")) { // possible thread status mixed with "at ..." + builder.append(" ").append(trimSuffix(line)); + continue; + } if (!first && mustHaveNewLineBefore(line)) { builder.append("\n"); if (line.startsWith("\"")) builder.append("\n"); // Additional line break for thread names From 82f9db055916819edc3df85cf27e9c1880c72d00 Mon Sep 17 00:00:00 2001 From: Konstantin Bulenkov Date: Wed, 14 Jan 2015 15:42:44 +0100 Subject: [PATCH 14/15] refactor to extract renderer from GotoActionModel --- .../ide/util/gotoByName/GotoActionModel.java | 248 ++++++++++-------- 1 file changed, 133 insertions(+), 115 deletions(-) diff --git a/platform/lang-impl/src/com/intellij/ide/util/gotoByName/GotoActionModel.java b/platform/lang-impl/src/com/intellij/ide/util/gotoByName/GotoActionModel.java index 3a9001e005ac..84fb10920923 100644 --- a/platform/lang-impl/src/com/intellij/ide/util/gotoByName/GotoActionModel.java +++ b/platform/lang-impl/src/com/intellij/ide/util/gotoByName/GotoActionModel.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2014 JetBrains s.r.o. + * 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. @@ -41,6 +41,7 @@ import com.intellij.ui.components.JBLabel; import com.intellij.ui.components.OnOffButton; import com.intellij.ui.speedSearch.SpeedSearchUtil; import com.intellij.util.ArrayUtil; +import com.intellij.util.Function; import com.intellij.util.containers.ContainerUtil; import com.intellij.util.containers.ContainerUtilRt; import com.intellij.util.ui.EmptyIcon; @@ -144,7 +145,7 @@ public class GotoActionModel implements ChooseByNameModel, CustomMatcherModel, C @NotNull public final Comparable value; @NotNull final String pattern; - MatchedValue(@NotNull Comparable value, @NotNull String pattern) { + public MatchedValue(@NotNull Comparable value, @NotNull String pattern) { this.value = value; this.pattern = pattern; } @@ -208,121 +209,12 @@ public class GotoActionModel implements ChooseByNameModel, CustomMatcherModel, C @Override public ListCellRenderer getListCellRenderer() { - return new DefaultListCellRenderer() { + return new GotoActionListCellRenderer(new Function() { @Override - public Component getListCellRendererComponent(@NotNull final JList list, - final Object matchedValue, - final int index, final boolean isSelected, final boolean cellHasFocus) { - final JPanel panel = new JPanel(new BorderLayout()); - panel.setBorder(IdeBorderFactory.createEmptyBorder(2)); - panel.setOpaque(true); - Color bg = UIUtil.getListBackground(isSelected); - panel.setBackground(bg); - - if (matchedValue instanceof String) { //... - final JBLabel label = new JBLabel((String)matchedValue); - label.setIcon(EMPTY_ICON); - panel.add(label, BorderLayout.WEST); - return panel; - } - - Color groupFg = isSelected ? UIUtil.getListSelectionForeground() : UIUtil.getLabelDisabledForeground(); - - final Object value = ((MatchedValue) matchedValue).value; - String pattern = ((MatchedValue)matchedValue).pattern; - - SimpleColoredComponent nameComponent = new SimpleColoredComponent(); - nameComponent.setBackground(bg); - panel.add(nameComponent, BorderLayout.CENTER); - - if (value instanceof ActionWrapper) { - final ActionWrapper actionWithParentGroup = (ActionWrapper)value; - final AnAction anAction = actionWithParentGroup.getAction(); - final Presentation presentation = anAction.getTemplatePresentation(); - boolean toggle = anAction instanceof ToggleAction; - String groupName = actionWithParentGroup.getAction() instanceof ApplyIntentionAction ? null : actionWithParentGroup.getGroupName(); - final Color fg = defaultActionForeground(isSelected, actionWithParentGroup.getPresentation()); - panel.add(createIconLabel(presentation.getIcon()), BorderLayout.WEST); - appendWithColoredMatches(nameComponent, getName(presentation.getText(), groupName, toggle), pattern, fg, isSelected); - - final Shortcut shortcut = preferKeyboardShortcut(KeymapManager.getInstance().getActiveKeymap().getShortcuts(getActionId(anAction))); - if (shortcut != null) { - nameComponent.append(" (" + KeymapUtil.getShortcutText(shortcut) + ")", new SimpleTextAttributes(STYLE_PLAIN, groupFg)); - } - - if (toggle) { - final OnOffButton button = new OnOffButton(); - AnActionEvent event = new AnActionEvent(null, ((ActionWrapper)value).myDataContext, - ActionPlaces.UNKNOWN, new Presentation(), ActionManager.getInstance(), - 0); - button.setSelected(((ToggleAction)anAction).isSelected(event)); - panel.add(button, BorderLayout.EAST); - panel.setBorder(IdeBorderFactory.createEmptyBorder()); - } - else { - if (groupName != null) { - final JLabel groupLabel = new JLabel(groupName); - groupLabel.setBackground(bg); - groupLabel.setForeground(groupFg); - panel.add(groupLabel, BorderLayout.EAST); - } - } - } - else if (value instanceof OptionDescription) { - if (!isSelected && !(value instanceof BooleanOptionDescription)) { - Color descriptorBg = UIUtil.isUnderDarcula() ? ColorUtil.brighter(UIUtil.getListBackground(), 1) : LightColors.SLIGHTLY_GRAY; - panel.setBackground(descriptorBg); - nameComponent.setBackground(descriptorBg); - } - String hit = ((OptionDescription)value).getHit(); - if (hit == null) { - hit = ((OptionDescription)value).getOption(); - } - hit = StringUtil.unescapeXml(hit); - hit = hit.replace(" ", " "); // avoid extra spaces from mnemonics and xml conversion - String fullHit = hit; - hit = StringUtil.first(hit, 45, true); - - final Color fg = UIUtil.getListForeground(isSelected); - - appendWithColoredMatches(nameComponent, hit.trim(), pattern, fg, isSelected); - - panel.add(new JLabel(EMPTY_ICON), BorderLayout.WEST); - panel.setToolTipText(fullHit); - - if (value instanceof BooleanOptionDescription) { - final OnOffButton button = new OnOffButton(); - button.setSelected(((BooleanOptionDescription)value).isOptionEnabled()); - panel.add(button, BorderLayout.EAST); - panel.setBorder(IdeBorderFactory.createEmptyBorder()); - } - else { - final JLabel settingsLabel = new JLabel(getGroupName((OptionDescription)value)); - settingsLabel.setForeground(groupFg); - settingsLabel.setBackground(bg); - panel.add(settingsLabel, BorderLayout.EAST); - } - } - return panel; + public String fun(OptionDescription description) { + return getGroupName(description); } - - public String getName(String text, String groupName, boolean toggle) { - return toggle && StringUtil.isNotEmpty(groupName)? groupName + ": "+ text : text; - } - - private void appendWithColoredMatches(SimpleColoredComponent nameComponent, String name, String pattern, Color fg, boolean selected) { - final SimpleTextAttributes plain = new SimpleTextAttributes(STYLE_PLAIN, fg); - final SimpleTextAttributes highlighted = new SimpleTextAttributes(null, fg, null, STYLE_SEARCH_MATCH); - List fragments = ContainerUtil.newArrayList(); - if (selected) { - int matchStart = StringUtil.indexOfIgnoreCase(name, pattern, 0); - if (matchStart >= 0) { - fragments.add(TextRange.from(matchStart, pattern.length())); - } - } - SpeedSearchUtil.appendColoredFragments(nameComponent, name, fragments, plain, highlighted); - } - }; + }); } protected String getActionId(@NotNull final AnAction anAction) { @@ -721,4 +613,130 @@ public class GotoActionModel implements ChooseByNameModel, CustomMatcherModel, C return myAction.getTemplatePresentation().getText().hashCode(); } } + + public static class GotoActionListCellRenderer extends DefaultListCellRenderer { + private final Function myGroupNamer; + + public GotoActionListCellRenderer(Function groupNamer) { + myGroupNamer = groupNamer; + } + + @Override + public Component getListCellRendererComponent(@NotNull final JList list, + final Object matchedValue, + final int index, final boolean isSelected, final boolean cellHasFocus) { + final JPanel panel = new JPanel(new BorderLayout()); + panel.setBorder(IdeBorderFactory.createEmptyBorder(2)); + panel.setOpaque(true); + Color bg = UIUtil.getListBackground(isSelected); + panel.setBackground(bg); + + if (matchedValue instanceof String) { //... + final JBLabel label = new JBLabel((String)matchedValue); + label.setIcon(EMPTY_ICON); + panel.add(label, BorderLayout.WEST); + return panel; + } + + Color groupFg = isSelected ? UIUtil.getListSelectionForeground() : UIUtil.getLabelDisabledForeground(); + + final Object value = ((MatchedValue) matchedValue).value; + String pattern = ((MatchedValue)matchedValue).pattern; + + SimpleColoredComponent nameComponent = new SimpleColoredComponent(); + nameComponent.setBackground(bg); + panel.add(nameComponent, BorderLayout.CENTER); + + if (value instanceof ActionWrapper) { + final ActionWrapper actionWithParentGroup = (ActionWrapper)value; + final AnAction anAction = actionWithParentGroup.getAction(); + final Presentation presentation = anAction.getTemplatePresentation(); + boolean toggle = anAction instanceof ToggleAction; + String groupName = actionWithParentGroup.getAction() instanceof ApplyIntentionAction ? null : actionWithParentGroup.getGroupName(); + final Color fg = defaultActionForeground(isSelected, actionWithParentGroup.getPresentation()); + panel.add(createIconLabel(presentation.getIcon()), BorderLayout.WEST); + appendWithColoredMatches(nameComponent, getName(presentation.getText(), groupName, toggle), pattern, fg, isSelected); + + final Shortcut shortcut = preferKeyboardShortcut(KeymapManager.getInstance().getActiveKeymap().getShortcuts(ActionManager.getInstance().getId(anAction))); + if (shortcut != null) { + nameComponent.append(" (" + KeymapUtil.getShortcutText(shortcut) + ")", new SimpleTextAttributes(STYLE_PLAIN, groupFg)); + } + + if (toggle) { + final OnOffButton button = new OnOffButton(); + AnActionEvent event = new AnActionEvent(null, ((ActionWrapper)value).myDataContext, + ActionPlaces.UNKNOWN, new Presentation(), ActionManager.getInstance(), + 0); + button.setSelected(((ToggleAction)anAction).isSelected(event)); + panel.add(button, BorderLayout.EAST); + panel.setBorder(IdeBorderFactory.createEmptyBorder()); + } + else { + if (groupName != null) { + final JLabel groupLabel = new JLabel(groupName); + groupLabel.setBackground(bg); + groupLabel.setForeground(groupFg); + panel.add(groupLabel, BorderLayout.EAST); + } + } + } + else if (value instanceof OptionDescription) { + if (!isSelected && !(value instanceof BooleanOptionDescription)) { + Color descriptorBg = UIUtil.isUnderDarcula() ? ColorUtil.brighter(UIUtil.getListBackground(), 1) : LightColors.SLIGHTLY_GRAY; + panel.setBackground(descriptorBg); + nameComponent.setBackground(descriptorBg); + } + String hit = ((OptionDescription)value).getHit(); + if (hit == null) { + hit = ((OptionDescription)value).getOption(); + } + hit = StringUtil.unescapeXml(hit); + hit = hit.replace(" ", " "); // avoid extra spaces from mnemonics and xml conversion + String fullHit = hit; + hit = StringUtil.first(hit, 45, true); + + final Color fg = UIUtil.getListForeground(isSelected); + + appendWithColoredMatches(nameComponent, hit.trim(), pattern, fg, isSelected); + + panel.add(new JLabel(EMPTY_ICON), BorderLayout.WEST); + panel.setToolTipText(fullHit); + + if (value instanceof BooleanOptionDescription) { + final OnOffButton button = new OnOffButton(); + button.setSelected(((BooleanOptionDescription)value).isOptionEnabled()); + panel.add(button, BorderLayout.EAST); + panel.setBorder(IdeBorderFactory.createEmptyBorder()); + } + else { + final JLabel settingsLabel = new JLabel(myGroupNamer.fun((OptionDescription)value)); + settingsLabel.setForeground(groupFg); + settingsLabel.setBackground(bg); + panel.add(settingsLabel, BorderLayout.EAST); + } + } + return panel; + } + + public String getName(String text, String groupName, boolean toggle) { + return toggle && StringUtil.isNotEmpty(groupName)? groupName + ": "+ text : text; + } + + private static void appendWithColoredMatches(SimpleColoredComponent nameComponent, + String name, + String pattern, + Color fg, + boolean selected) { + final SimpleTextAttributes plain = new SimpleTextAttributes(STYLE_PLAIN, fg); + final SimpleTextAttributes highlighted = new SimpleTextAttributes(null, fg, null, STYLE_SEARCH_MATCH); + List fragments = ContainerUtil.newArrayList(); + if (selected) { + int matchStart = StringUtil.indexOfIgnoreCase(name, pattern, 0); + if (matchStart >= 0) { + fragments.add(TextRange.from(matchStart, pattern.length())); + } + } + SpeedSearchUtil.appendColoredFragments(nameComponent, name, fragments, plain, highlighted); + } + } } From e3b6f8adb31b67c2bb58def0a4e4ae47860fc231 Mon Sep 17 00:00:00 2001 From: Konstantin Bulenkov Date: Wed, 14 Jan 2015 15:43:37 +0100 Subject: [PATCH 15/15] renderer with shortcuts for actions and cache for action updates --- .../ide/actions/SearchEverywhereAction.java | 47 ++++++++++++++----- 1 file changed, 34 insertions(+), 13 deletions(-) diff --git a/platform/lang-impl/src/com/intellij/ide/actions/SearchEverywhereAction.java b/platform/lang-impl/src/com/intellij/ide/actions/SearchEverywhereAction.java index ee1e5dcf2695..60dcc2ea2d06 100644 --- a/platform/lang-impl/src/com/intellij/ide/actions/SearchEverywhereAction.java +++ b/platform/lang-impl/src/com/intellij/ide/actions/SearchEverywhereAction.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2014 JetBrains s.r.o. + * 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. @@ -158,6 +158,7 @@ public class SearchEverywhereAction extends AnAction implements CustomComponentA private JBList myList; private JCheckBox myNonProjectCheckBox; private AnActionEvent myActionEvent; + private Set myDisabledActions = new HashSet(); private Component myContextComponent; private CalcThread myCalcThread; private static AtomicBoolean ourShiftIsPressed = new AtomicBoolean(false); @@ -1040,6 +1041,7 @@ public class SearchEverywhereAction extends AnAction implements CustomComponentA } }; SearchEverywherePsiRenderer myFileRenderer = new SearchEverywherePsiRenderer(myList); + ListCellRenderer myActionsRenderer = new GotoActionModel.GotoActionListCellRenderer(Function.TO_STRING); private String myLocationString; private DefaultPsiElementCellRenderer myPsiRenderer = new DefaultPsiElementCellRenderer() { @@ -1080,6 +1082,8 @@ public class SearchEverywhereAction extends AnAction implements CustomComponentA } else if (value instanceof PsiElement) { myFileRenderer.setPatternMatcher(matcher); cmp = myFileRenderer.getListCellRendererComponent(list, value, index, isSelected, isSelected); + } else if (value instanceof GotoActionModel.ActionWrapper) { + cmp = myActionsRenderer.getListCellRendererComponent(list, new GotoActionModel.MatchedValue(((GotoActionModel.ActionWrapper)value), pattern), index, isSelected, isSelected); } else { cmp = super.getListCellRendererComponent(list, value, index, isSelected, isSelected); final JPanel p = new JPanel(new BorderLayout()); @@ -1464,7 +1468,10 @@ public class SearchEverywhereAction extends AnAction implements CustomComponentA result.add(object); } } else if (actions && !isToolWindowAction(object) && isActionValue(object)) { - result.add(object); + AnAction action = object instanceof AnAction ? ((AnAction)object) : ((GotoActionModel.ActionWrapper)object).getAction(); + if (isEnabled(action)) { + result.add(object); + } } return result.size() <= max; } @@ -1905,19 +1912,9 @@ public class SearchEverywhereAction extends AnAction implements CustomComponentA public void run() { if (isCanceled()) return; - for (Object element : new ArrayList(elements)) { if (element instanceof AnAction) { - final AnAction action = (AnAction)element; - final AnActionEvent e = new AnActionEvent(myActionEvent.getInputEvent(), - myActionEvent.getDataContext(), - myActionEvent.getPlace(), - action.getTemplatePresentation(), - myActionEvent.getActionManager(), - myActionEvent.getModifiers()); - ActionUtil.performDumbAwareUpdate(action, e, false); - final Presentation presentation = e.getPresentation(); - if (!presentation.isEnabled() || !presentation.isVisible() || StringUtil.isEmpty(presentation.getText())) { + if (!isEnabled((AnAction)element)) { elements.remove(element); } if (isCanceled()) return; @@ -1933,6 +1930,29 @@ public class SearchEverywhereAction extends AnAction implements CustomComponentA } } + protected boolean isEnabled(final AnAction action) { + if (myDisabledActions.contains(action)) return false; + final AnActionEvent e = new AnActionEvent(myActionEvent.getInputEvent(), + myActionEvent.getDataContext(), + myActionEvent.getPlace(), + action.getTemplatePresentation(), + myActionEvent.getActionManager(), + myActionEvent.getModifiers()); + + UIUtil.invokeAndWaitIfNeeded(new Runnable() { + @Override + public void run() { + ActionUtil.performDumbAwareUpdate(action, e, false); + } + }); + final Presentation presentation = e.getPresentation(); + final boolean enabled = presentation.isEnabled() && presentation.isVisible() && !StringUtil.isEmpty(presentation.getText()); + if (!enabled) { + myDisabledActions.add(action); + } + return enabled; + } + private synchronized void checkModelsUpToDate() { if (myClassModel == null) { myClassModel = new GotoClassModel2(project); @@ -2165,6 +2185,7 @@ public class SearchEverywhereAction extends AnAction implements CustomComponentA myEditor = null; myFileEditor = null; myStructureModel = null; + myDisabledActions.clear(); } } }