diff --git a/java/java-impl/src/com/intellij/codeInsight/daemon/impl/MarkerType.java b/java/java-impl/src/com/intellij/codeInsight/daemon/impl/MarkerType.java index 7b4e4fd2777b..fce394b9462b 100644 --- a/java/java-impl/src/com/intellij/codeInsight/daemon/impl/MarkerType.java +++ b/java/java-impl/src/com/intellij/codeInsight/daemon/impl/MarkerType.java @@ -410,9 +410,10 @@ public class MarkerType { @Override public String getCaption(int size) { + String suffix = isFinished() ? "" : " so far"; return myClass.isInterface() - ? CodeInsightBundle.message("goto.implementation.chooserTitle", myClass.getName(), size) - : DaemonBundle.message("navigation.title.subclass", myClass.getName(), size); + ? CodeInsightBundle.message("goto.implementation.chooserTitle", myClass.getName(), size, suffix) + : DaemonBundle.message("navigation.title.subclass", myClass.getName(), size, suffix); } @Override diff --git a/java/java-tests/testSrc/com/intellij/navigation/GotoImplementationHandlerTest.java b/java/java-tests/testSrc/com/intellij/navigation/GotoImplementationHandlerTest.java index f90f143361c2..89cf3d7ef61f 100644 --- a/java/java-tests/testSrc/com/intellij/navigation/GotoImplementationHandlerTest.java +++ b/java/java-tests/testSrc/com/intellij/navigation/GotoImplementationHandlerTest.java @@ -15,15 +15,18 @@ */ package com.intellij.navigation; -import com.intellij.codeInsight.navigation.GotoImplementationHandler; import com.intellij.codeInsight.navigation.GotoTargetHandler; +import com.intellij.openapi.util.text.StringUtil; import com.intellij.psi.PsiClass; import com.intellij.psi.PsiElement; import com.intellij.psi.PsiFile; import com.intellij.psi.PsiMethod; import com.intellij.testFramework.PlatformTestUtil; +import com.intellij.testFramework.fixtures.CodeInsightTestUtil; import com.intellij.testFramework.fixtures.JavaCodeInsightFixtureTestCase; +import java.util.Arrays; + public class GotoImplementationHandlerTest extends JavaCodeInsightFixtureTestCase { public void testMultipleImplsFromAbstractCall() { PsiFile file = myFixture.addFileToProject("Foo.java", "public abstract class Hello {\n" + @@ -211,6 +214,12 @@ public class GotoImplementationHandlerTest extends JavaCodeInsightFixtureTestCas final PsiElement[] impls = getTargets(file); assertEquals(2, impls.length); + // target are non-deterministic now + Arrays.sort(impls, (o1, o2) -> { + String name1 = ((PsiMethod)o1).getContainingClass().getName(); + String name2 = ((PsiMethod)o2).getContainingClass().getName(); + return StringUtil.compare(name1, name2, false); + }); final PsiElement method = impls[0]; assertTrue(method instanceof PsiMethod); final PsiClass aClass = ((PsiMethod)method).getContainingClass(); @@ -219,7 +228,7 @@ public class GotoImplementationHandlerTest extends JavaCodeInsightFixtureTestCas } private PsiElement[] getTargets(PsiFile file) { - GotoTargetHandler.GotoData gotoData = new GotoImplementationHandler().getSourceAndTargetElements(myFixture.getEditor(), file); + GotoTargetHandler.GotoData gotoData = CodeInsightTestUtil.gotoImplementation(myFixture.getEditor(), file); assertNotNull(gotoData); return gotoData.targets; } diff --git a/platform/lang-impl/src/com/intellij/codeInsight/navigation/BackgroundUpdaterTask.java b/platform/lang-impl/src/com/intellij/codeInsight/navigation/BackgroundUpdaterTask.java index 539481824bfb..9070cd44d619 100644 --- a/platform/lang-impl/src/com/intellij/codeInsight/navigation/BackgroundUpdaterTask.java +++ b/platform/lang-impl/src/com/intellij/codeInsight/navigation/BackgroundUpdaterTask.java @@ -51,6 +51,7 @@ public abstract class BackgroundUpdaterTask extends Task.Backgroundable { private final Object lock = new Object(); private volatile boolean myCanceled; + private volatile boolean myFinished; public BackgroundUpdaterTask(Project project, String title, boolean canBeCancelled) { super(project, title, canBeCancelled); @@ -143,7 +144,17 @@ public abstract class BackgroundUpdaterTask extends Task.Backgroundable { @Override public void onSuccess() { + onFinished(); myPopup.setCaption(getCaption(getCurrentSize())); paintBusy(false); } + + @Override + protected void onFinished() { + myFinished = true; + } + + public boolean isFinished() { + return myFinished; + } } diff --git a/platform/lang-impl/src/com/intellij/codeInsight/navigation/GotoImplementationHandler.java b/platform/lang-impl/src/com/intellij/codeInsight/navigation/GotoImplementationHandler.java index 683c1be87aac..04c84f9dc208 100644 --- a/platform/lang-impl/src/com/intellij/codeInsight/navigation/GotoImplementationHandler.java +++ b/platform/lang-impl/src/com/intellij/codeInsight/navigation/GotoImplementationHandler.java @@ -19,7 +19,6 @@ package com.intellij.codeInsight.navigation; import com.intellij.codeInsight.CodeInsightBundle; import com.intellij.codeInsight.TargetElementUtil; import com.intellij.ide.util.PsiElementListCellRenderer; -import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.editor.Editor; import com.intellij.openapi.progress.ProgressIndicator; import com.intellij.openapi.project.Project; @@ -31,9 +30,7 @@ import com.intellij.util.containers.HashMap; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -import java.util.ArrayList; import java.util.Collections; -import java.util.List; import java.util.Map; public class GotoImplementationHandler extends GotoTargetHandler { @@ -48,45 +45,28 @@ public class GotoImplementationHandler extends GotoTargetHandler { int offset = editor.getCaretModel().getOffset(); PsiElement source = TargetElementUtil.getInstance().findTargetElement(editor, ImplementationSearcher.getFlags(), offset); if (source == null) return null; - final GotoData gotoData; final PsiReference reference = TargetElementUtil.findReference(editor, offset); final TargetElementUtil instance = TargetElementUtil.getInstance(); - if (!ApplicationManager.getApplication().isUnitTestMode()) { - gotoData = new GotoData(source, new ImplementationSearcher.FirstImplementationsSearcher(){ - @Override - protected boolean accept(PsiElement element) { - return instance.acceptImplementationForReference(reference, element); - } + PsiElement[] targets = new ImplementationSearcher.FirstImplementationsSearcher() { + @Override + protected boolean accept(PsiElement element) { + return instance.acceptImplementationForReference(reference, element); + } - @Override - protected boolean canShowPopupWithOneItem(PsiElement element) { - return false; - } - }.searchImplementations(editor, source, offset), Collections.emptyList()); - - gotoData.listUpdaterTask = new ImplementationsUpdaterTask(gotoData, editor, offset, reference); - } else { - gotoData = new GotoData(source, new ImplementationSearcher(){ - @Override - protected PsiElement[] filterElements(PsiElement element, PsiElement[] targetElements, int offset) { - final List result = new ArrayList(); - for (PsiElement targetElement : targetElements) { - if (instance.acceptImplementationForReference(reference, targetElement)) { - result.add(targetElement); - } - } - return result.toArray(new PsiElement[result.size()]); - } - }.searchImplementations(editor, source, offset), - Collections.emptyList()); - } + @Override + protected boolean canShowPopupWithOneItem(PsiElement element) { + return false; + } + }.searchImplementations(editor, source, offset); + GotoData gotoData = new GotoData(source, targets, Collections.emptyList()); + gotoData.listUpdaterTask = new ImplementationsUpdaterTask(gotoData, editor, offset, reference); return gotoData; } - @NotNull @Override - protected String getChooserTitle(PsiElement sourceElement, String name, int length) { - return CodeInsightBundle.message("goto.implementation.chooserTitle", name, length); + @NotNull + protected String getChooserTitle(PsiElement sourceElement, String name, int length, boolean finished) { + return CodeInsightBundle.message("goto.implementation.chooserTitle", name, length, finished ? "" : " so far"); } @NotNull @@ -108,7 +88,7 @@ public class GotoImplementationHandler extends GotoTargetHandler { private final Map renderers = new HashMap(); private final PsiReference myReference; - public ImplementationsUpdaterTask(@NotNull GotoData gotoData, @NotNull Editor editor, int offset, final PsiReference reference) { + ImplementationsUpdaterTask(@NotNull GotoData gotoData, @NotNull Editor editor, int offset, final PsiReference reference) { super(gotoData.source.getProject(), ImplementationSearcher.SEARCHING_FOR_IMPLEMENTATIONS); myEditor = editor; myOffset = offset; @@ -140,7 +120,7 @@ public class GotoImplementationHandler extends GotoTargetHandler { @Override public String getCaption(int size) { - return getChooserTitle(myGotoData.source, ((PsiNamedElement)myGotoData.source).getName(), size); + return getChooserTitle(myGotoData.source, ((PsiNamedElement)myGotoData.source).getName(), size, isFinished()); } } } diff --git a/platform/lang-impl/src/com/intellij/codeInsight/navigation/GotoTargetHandler.java b/platform/lang-impl/src/com/intellij/codeInsight/navigation/GotoTargetHandler.java index 159d5ebb8c96..5fa44d6a1f20 100644 --- a/platform/lang-impl/src/com/intellij/codeInsight/navigation/GotoTargetHandler.java +++ b/platform/lang-impl/src/com/intellij/codeInsight/navigation/GotoTargetHandler.java @@ -25,6 +25,7 @@ import com.intellij.ide.util.PsiElementListCellRenderer; import com.intellij.navigation.ItemPresentation; import com.intellij.navigation.NavigationItem; import com.intellij.openapi.application.ApplicationManager; +import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.editor.Editor; import com.intellij.openapi.editor.ex.util.EditorUtil; import com.intellij.openapi.extensions.Extensions; @@ -59,6 +60,7 @@ import java.util.*; import java.util.List; public abstract class GotoTargetHandler implements CodeInsightActionHandler { + private static final Logger LOG = Logger.getInstance("#" + GotoTargetHandler.class.getName()); private static final PsiElementListCellRenderer ourDefaultTargetElementRenderer = new DefaultPsiElementListCellRenderer(); private final DefaultListCellRenderer myActionElementRenderer = new ActionCellRenderer(); @@ -73,7 +75,7 @@ public abstract class GotoTargetHandler implements CodeInsightActionHandler { try { GotoData gotoData = getSourceAndTargetElements(editor, file); - if (gotoData != null && gotoData.source != null) { + if (gotoData != null) { show(project, editor, file, gotoData); } } @@ -113,7 +115,7 @@ public abstract class GotoTargetHandler implements CodeInsightActionHandler { } final String name = ((PsiNamedElement)gotoData.source).getName(); - final String title = getChooserTitle(gotoData.source, name, targets.length); + final String title = getChooserTitle(gotoData.source, name, targets.length, gotoData.listUpdaterTask.isFinished()); if (shouldSortTargets()) { Arrays.sort(targets, createComparator(gotoData.renderers, gotoData)); @@ -265,10 +267,20 @@ public abstract class GotoTargetHandler implements CodeInsightActionHandler { } @NotNull - protected abstract String getChooserTitle(PsiElement sourceElement, String name, int length); + @Deprecated // use getChooserTitle(PsiElement, String, int, boolean) instead + protected String getChooserTitle(PsiElement sourceElement, String name, int length) { + LOG.warn("Please override getChooserTitle(PsiElement, String, int, boolean) instead"); + return ""; + } + + @NotNull + protected String getChooserTitle(PsiElement sourceElement, String name, int length, boolean finished) { + return getChooserTitle(sourceElement, name, length); + } + @NotNull protected String getFindUsagesTitle(PsiElement sourceElement, String name, int length) { - return getChooserTitle(sourceElement, name, length); + return getChooserTitle(sourceElement, name, length, true); } @NotNull diff --git a/platform/lang-impl/src/com/intellij/testIntegration/GotoTestOrCodeHandler.java b/platform/lang-impl/src/com/intellij/testIntegration/GotoTestOrCodeHandler.java index b9428e00b9a0..bf0473009766 100644 --- a/platform/lang-impl/src/com/intellij/testIntegration/GotoTestOrCodeHandler.java +++ b/platform/lang-impl/src/com/intellij/testIntegration/GotoTestOrCodeHandler.java @@ -97,12 +97,13 @@ public class GotoTestOrCodeHandler extends GotoTargetHandler { @NotNull @Override - protected String getChooserTitle(PsiElement sourceElement, String name, int length) { + protected String getChooserTitle(PsiElement sourceElement, String name, int length, boolean finished) { + String suffix = finished ? "" : " so far"; if (TestFinderHelper.isTest(sourceElement)) { - return CodeInsightBundle.message("goto.test.chooserTitle.subject", name, length); + return CodeInsightBundle.message("goto.test.chooserTitle.subject", name, length, suffix); } else { - return CodeInsightBundle.message("goto.test.chooserTitle.test", name, length); + return CodeInsightBundle.message("goto.test.chooserTitle.test", name, length, suffix); } } diff --git a/platform/platform-resources-en/src/messages/CodeInsightBundle.properties b/platform/platform-resources-en/src/messages/CodeInsightBundle.properties index 1a7aae77370c..a9bbd0123a39 100644 --- a/platform/platform-resources-en/src/messages/CodeInsightBundle.properties +++ b/platform/platform-resources-en/src/messages/CodeInsightBundle.properties @@ -283,13 +283,13 @@ javadoc.method.specified.by=Specified by: javadoc.external.fetch.error.message=Cannot fetch remote documentation: internal error searching.for.implementations=Searching For Implementations... -goto.implementation.chooserTitle=Choose Implementation of {0} ({1} found) +goto.implementation.chooserTitle=Choose Implementation of {0} ({1} found{2}) goto.implementation.findUsages.title=Implementations of {0} goto.implementation.notFound=No implementations found -goto.test.chooserTitle.test=Choose Test for {0} ({1} found) +goto.test.chooserTitle.test=Choose Test for {0} ({1} found{2}) goto.test.findUsages.test.title=Tests for {0} -goto.test.chooserTitle.subject=Choose Test Subject for {0} ({1} found) +goto.test.chooserTitle.subject=Choose Test Subject for {0} ({1} found{2}) goto.test.findUsages.subject.title=Test Subjects for {0} goto.test.notFound=No test subjects found diff --git a/platform/platform-resources-en/src/messages/DaemonBundle.properties b/platform/platform-resources-en/src/messages/DaemonBundle.properties index 5e68cd355110..2b4b3458535e 100644 --- a/platform/platform-resources-en/src/messages/DaemonBundle.properties +++ b/platform/platform-resources-en/src/messages/DaemonBundle.properties @@ -40,7 +40,7 @@ navigation.title.super.method=Choose Super Method of {0} navigation.findUsages.title.super.method=Super Methods of {0} navigation.title.implementation.method=Choose Implementation of {0} ({1} methods found) navigation.title.overrider.method=Choose Overriding Method of {0} ({1} methods found) -navigation.title.subclass=Choose Subclass of {0} ({1} classes found) +navigation.title.subclass=Choose Subclass of {0} ({1} classes found{2}) performing.code.analysis=Performing code analysis inspection.extended.description=more... inspection.collapse.description=less... diff --git a/platform/testFramework/src/com/intellij/testFramework/fixtures/CodeInsightTestUtil.java b/platform/testFramework/src/com/intellij/testFramework/fixtures/CodeInsightTestUtil.java index f341e9aac372..febe381dbdff 100644 --- a/platform/testFramework/src/com/intellij/testFramework/fixtures/CodeInsightTestUtil.java +++ b/platform/testFramework/src/com/intellij/testFramework/fixtures/CodeInsightTestUtil.java @@ -23,6 +23,8 @@ import com.intellij.codeInsight.intention.IntentionAction; import com.intellij.codeInsight.lookup.Lookup; import com.intellij.codeInsight.lookup.LookupManager; import com.intellij.codeInsight.lookup.impl.LookupImpl; +import com.intellij.codeInsight.navigation.GotoImplementationHandler; +import com.intellij.codeInsight.navigation.GotoTargetHandler; import com.intellij.codeInsight.template.Template; import com.intellij.codeInsight.template.TemplateManager; import com.intellij.codeInsight.template.impl.TemplateManagerImpl; @@ -39,14 +41,23 @@ import com.intellij.openapi.application.Result; import com.intellij.openapi.command.WriteCommandAction; import com.intellij.openapi.editor.Editor; import com.intellij.openapi.project.Project; +import com.intellij.openapi.ui.popup.JBPopup; +import com.intellij.openapi.util.Condition; import com.intellij.openapi.util.Disposer; +import com.intellij.openapi.util.Ref; import com.intellij.openapi.util.TextRange; import com.intellij.openapi.util.io.FileUtil; import com.intellij.openapi.util.io.FileUtilRt; import com.intellij.psi.PsiElement; +import com.intellij.psi.PsiFile; import com.intellij.psi.codeStyle.CodeStyleManager; import com.intellij.refactoring.rename.inplace.VariableInplaceRenameHandler; import com.intellij.testFramework.TestDataFile; +import com.intellij.ui.components.JBList; +import com.intellij.ui.popup.AbstractPopup; +import com.intellij.ui.popup.ComponentPopupBuilderImpl; +import com.intellij.ui.speedSearch.NameFilteringListModel; +import com.intellij.util.Function; import com.intellij.util.ui.UIUtil; import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.NotNull; @@ -254,4 +265,28 @@ public class CodeInsightTestUtil { } }); } + + @NotNull + @TestOnly + public static GotoTargetHandler.GotoData gotoImplementation(Editor editor, PsiFile file) { + GotoTargetHandler.GotoData data = new GotoImplementationHandler().getSourceAndTargetElements(editor, file); + if (data.listUpdaterTask != null) { + JBList list = new JBList(); + list.setModel(new NameFilteringListModel(list, Function.ID, Condition.FALSE, String::new)); + JBPopup popup = new ComponentPopupBuilderImpl(list, null).createPopup(); + data.listUpdaterTask.init((AbstractPopup)popup, list, new Ref<>()); + + data.listUpdaterTask.queue(); + + try { + while (!data.listUpdaterTask.isFinished()) { + UIUtil.dispatchAllInvocationEvents(); + } + } + finally { + Disposer.dispose(popup); + } + } + return data; + } } diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/codeInsight/navigation/actions/GroovyGotoSuperHandler.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/codeInsight/navigation/actions/GroovyGotoSuperHandler.java index d2d4a1bc6161..7562cac483e8 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/codeInsight/navigation/actions/GroovyGotoSuperHandler.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/codeInsight/navigation/actions/GroovyGotoSuperHandler.java @@ -58,7 +58,7 @@ public class GroovyGotoSuperHandler extends GotoTargetHandler implements Languag @NotNull @Override - protected String getChooserTitle(PsiElement sourceElement, String name, int length) { + protected String getChooserTitle(PsiElement sourceElement, String name, int length, boolean finished) { return CodeInsightBundle.message("goto.super.method.chooser.title"); } diff --git a/plugins/groovy/test/org/jetbrains/plugins/groovy/GroovyGotoImplementationTest.java b/plugins/groovy/test/org/jetbrains/plugins/groovy/GroovyGotoImplementationTest.java index daa36e983307..344fe647061c 100644 --- a/plugins/groovy/test/org/jetbrains/plugins/groovy/GroovyGotoImplementationTest.java +++ b/plugins/groovy/test/org/jetbrains/plugins/groovy/GroovyGotoImplementationTest.java @@ -17,7 +17,6 @@ package org.jetbrains.plugins.groovy; -import com.intellij.codeInsight.navigation.GotoImplementationHandler; import com.intellij.openapi.application.Result; import com.intellij.openapi.command.WriteCommandAction; import com.intellij.openapi.vfs.VfsUtil; @@ -26,6 +25,7 @@ import com.intellij.psi.PsiDocumentManager; import com.intellij.psi.PsiElement; import com.intellij.psi.PsiFile; import com.intellij.testFramework.PsiTestUtil; +import com.intellij.testFramework.fixtures.CodeInsightTestUtil; import com.intellij.testFramework.fixtures.JavaCodeInsightFixtureTestCase; import com.intellij.testFramework.fixtures.TempDirTestFixture; import com.intellij.testFramework.fixtures.impl.TempDirTestFixtureImpl; @@ -55,7 +55,7 @@ public class GroovyGotoImplementationTest extends JavaCodeInsightFixtureTestCase PsiFile inProject = myFixture.addFileToProject("Foo.groovy", "class Foo {}\n class Bar extends Foo {}"); myFixture.configureFromExistingVirtualFile(inProject.getVirtualFile()); - final PsiElement[] impls = new GotoImplementationHandler().getSourceAndTargetElements(myFixture.getEditor(), inProject).targets; + final PsiElement[] impls = CodeInsightTestUtil.gotoImplementation(myFixture.getEditor(), inProject).targets; assertEquals(1, impls.length); } finally {