mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
Redesign test tasks choosing popup in accordance with doc in UX-487
This commit is contained in:
committed by
Sergei Vorobyov
parent
3aeb7ac39e
commit
61932662fe
@@ -424,3 +424,8 @@ run.dashboard.group.configurations.label=Group Name:
|
||||
run.dashboard.configurable.add.configuration.type=Add Configuration Type
|
||||
run.dashboard.configurable.types.panel.title=Configurations available in Run Dashboard
|
||||
application.configuration.include.provided.scope=Include dependencies with "Provided" scope
|
||||
|
||||
tests.tasks.choosing.popup.title.common=Run Tasks
|
||||
tests.tasks.choosing.popup.title=Run Tasks for {0}
|
||||
tests.tasks.choosing.popup.hint=Select several tasks to run them at once
|
||||
tests.tasks.choosing.warning.text=No test tasks available
|
||||
|
||||
+10
-6
@@ -6,6 +6,7 @@ import com.intellij.execution.actions.ConfigurationContext;
|
||||
import com.intellij.execution.actions.ConfigurationFromContext;
|
||||
import com.intellij.execution.configurations.ConfigurationFactory;
|
||||
import com.intellij.execution.junit.JavaRuntimeConfigurationProducerBase;
|
||||
import com.intellij.openapi.actionSystem.DataContext;
|
||||
import com.intellij.openapi.externalSystem.model.execution.ExternalSystemTaskExecutionSettings;
|
||||
import com.intellij.openapi.externalSystem.service.execution.ExternalSystemRunConfiguration;
|
||||
import com.intellij.openapi.externalSystem.util.ExternalSystemApiUtil;
|
||||
@@ -16,7 +17,6 @@ import com.intellij.openapi.vfs.VirtualFile;
|
||||
import com.intellij.psi.*;
|
||||
import com.intellij.psi.search.GlobalSearchScope;
|
||||
import com.intellij.util.ArrayUtil;
|
||||
import com.intellij.util.containers.ContainerUtil;
|
||||
import kotlin.jvm.functions.Function1;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
@@ -86,11 +86,13 @@ public final class AllInPackageGradleConfigurationProducer extends GradleTestRun
|
||||
performRunnable.run();
|
||||
return;
|
||||
}
|
||||
getTestTasksChooser().chooseTestTasks(context, ContainerUtil.newArrayList(configurationData.sourceElement), tasks -> {
|
||||
String locationName = String.format("'%s'", extractLocationName(configurationData.psiPackage, configurationData.module));
|
||||
DataContext dataContext = TestTasksChooser.contextWithLocationName(context.getDataContext(), locationName);
|
||||
PsiElement[] sourceElements = ArrayUtil.toObjectArray(PsiElement.class, configurationData.sourceElement);
|
||||
getTestTasksChooser().chooseTestTasks(context.getProject(), dataContext, sourceElements, tasks -> {
|
||||
ExternalSystemRunConfiguration configuration = (ExternalSystemRunConfiguration)fromContext.getConfiguration();
|
||||
ExternalSystemTaskExecutionSettings settings = configuration.getSettings();
|
||||
Function1<PsiElement, String> createFilter = (e) -> createTestFilterFrom(configurationData.psiPackage, /*hasSuffix=*/false);
|
||||
PsiElement[] sourceElements = ArrayUtil.toObjectArray(PsiElement.class, configurationData.sourceElement);
|
||||
if (!applyTestConfiguration(settings, context.getModule(), tasks, sourceElements, createFilter)) {
|
||||
LOG.warn("Cannot apply package test configuration, uses raw run configuration");
|
||||
performRunnable.run();
|
||||
@@ -140,10 +142,12 @@ public final class AllInPackageGradleConfigurationProducer extends GradleTestRun
|
||||
return sourceDirs[0];
|
||||
}
|
||||
|
||||
private static String extractLocationName(@NotNull PsiPackage aPackage, @NotNull Module module) {
|
||||
return aPackage.getQualifiedName().isEmpty() ? module.getName() : aPackage.getQualifiedName();
|
||||
}
|
||||
|
||||
private static String suggestName(@NotNull PsiPackage aPackage, @NotNull Module module) {
|
||||
return aPackage.getQualifiedName().isEmpty()
|
||||
? ExecutionBundle.message("test.in.scope.presentable.text", module.getName())
|
||||
: ExecutionBundle.message("test.in.scope.presentable.text", aPackage.getQualifiedName());
|
||||
return ExecutionBundle.message("test.in.scope.presentable.text", extractLocationName(aPackage, module));
|
||||
}
|
||||
|
||||
private static class ConfigurationData {
|
||||
|
||||
+1
-1
@@ -89,7 +89,7 @@ public final class PatternGradleConfigurationProducer extends GradleTestRunConfi
|
||||
Project project = context.getProject();
|
||||
List<String> tests = getTestPatterns(context);
|
||||
TestMappings testMappings = getTestMappings(project, tests);
|
||||
getTestTasksChooser().chooseTestTasks(context, testMappings.getClasses().values(), tasks -> {
|
||||
getTestTasksChooser().chooseTestTasks(project, context.getDataContext(), testMappings.getClasses().values(), tasks -> {
|
||||
ExternalSystemTaskExecutionSettings settings = configuration.getSettings();
|
||||
Function1<String, PsiClass> findPsiClass = test -> testMappings.getClasses().get(test);
|
||||
Function2<PsiClass, String, String> createFilter = (psiClass, test) ->
|
||||
|
||||
+4
-1
@@ -10,6 +10,7 @@ import com.intellij.execution.actions.ConfigurationFromContext;
|
||||
import com.intellij.execution.actions.RunConfigurationProducer;
|
||||
import com.intellij.execution.configurations.ConfigurationFactory;
|
||||
import com.intellij.execution.junit.InheritorChooser;
|
||||
import com.intellij.openapi.actionSystem.DataContext;
|
||||
import com.intellij.openapi.externalSystem.model.execution.ExternalSystemTaskExecutionSettings;
|
||||
import com.intellij.openapi.externalSystem.service.execution.ExternalSystemRunConfiguration;
|
||||
import com.intellij.openapi.externalSystem.util.ExternalSystemApiUtil;
|
||||
@@ -162,7 +163,9 @@ public class TestClassGradleConfigurationProducer extends GradleTestRunConfigura
|
||||
@NotNull ConfigurationContext context,
|
||||
@NotNull Runnable performRunnable,
|
||||
@NotNull PsiClass... classes) {
|
||||
getTestTasksChooser().chooseTestTasks(context, classes, tasks -> {
|
||||
String locationName = classes.length == 1 ? classes[0].getName() : null;
|
||||
DataContext dataContext = TestTasksChooser.contextWithLocationName(context.getDataContext(), locationName);
|
||||
getTestTasksChooser().chooseTestTasks(context.getProject(), dataContext, classes, tasks -> {
|
||||
ExternalSystemRunConfiguration configuration = (ExternalSystemRunConfiguration)fromContext.getConfiguration();
|
||||
ExternalSystemTaskExecutionSettings settings = configuration.getSettings();
|
||||
Function1<PsiClass, String> createFilter = (psiClass) -> createTestFilterFrom(psiClass, /*hasSuffix=*/true);
|
||||
|
||||
+5
-2
@@ -8,6 +8,7 @@ import com.intellij.execution.actions.ConfigurationFromContext;
|
||||
import com.intellij.execution.actions.RunConfigurationProducer;
|
||||
import com.intellij.execution.configurations.ConfigurationFactory;
|
||||
import com.intellij.execution.junit.InheritorChooser;
|
||||
import com.intellij.openapi.actionSystem.DataContext;
|
||||
import com.intellij.openapi.externalSystem.model.execution.ExternalSystemTaskExecutionSettings;
|
||||
import com.intellij.openapi.externalSystem.service.execution.ExternalSystemRunConfiguration;
|
||||
import com.intellij.openapi.externalSystem.util.ExternalSystemApiUtil;
|
||||
@@ -131,7 +132,9 @@ public class TestMethodGradleConfigurationProducer extends GradleTestRunConfigur
|
||||
@NotNull Runnable performRunnable,
|
||||
@NotNull PsiMethod psiMethod,
|
||||
@NotNull PsiClass... classes) {
|
||||
getTestTasksChooser().chooseTestTasks(context, classes, tasks -> {
|
||||
String locationName = (classes.length == 1 ? classes[0].getName() + "." : "") + psiMethod.getName();
|
||||
DataContext dataContext = TestTasksChooser.contextWithLocationName(context.getDataContext(), locationName);
|
||||
getTestTasksChooser().chooseTestTasks(context.getProject(), dataContext, classes, tasks -> {
|
||||
ExternalSystemRunConfiguration configuration = (ExternalSystemRunConfiguration)fromContext.getConfiguration();
|
||||
ExternalSystemTaskExecutionSettings settings = configuration.getSettings();
|
||||
Function1<PsiClass, String> createFilter = (psiClass) -> createTestFilter(context.getLocation(), psiClass, psiMethod);
|
||||
@@ -140,7 +143,7 @@ public class TestMethodGradleConfigurationProducer extends GradleTestRunConfigur
|
||||
performRunnable.run();
|
||||
return;
|
||||
}
|
||||
configuration.setName((classes.length == 1 ? classes[0].getName() + "." : "") + psiMethod.getName());
|
||||
configuration.setName(locationName);
|
||||
performRunnable.run();
|
||||
});
|
||||
}
|
||||
|
||||
@@ -1,18 +1,34 @@
|
||||
// Copyright 2000-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
|
||||
package org.jetbrains.plugins.gradle.execution.test.runner
|
||||
|
||||
import com.intellij.execution.actions.ConfigurationContext
|
||||
import com.intellij.execution.ExecutionBundle
|
||||
import com.intellij.notification.Notification
|
||||
import com.intellij.notification.NotificationType
|
||||
import com.intellij.notification.Notifications
|
||||
import com.intellij.openapi.actionSystem.DataContext
|
||||
import com.intellij.openapi.actionSystem.DataKey
|
||||
import com.intellij.openapi.actionSystem.PlatformDataKeys
|
||||
import com.intellij.openapi.application.ApplicationManager
|
||||
import com.intellij.openapi.diagnostic.Logger
|
||||
import com.intellij.openapi.editor.ex.EditorGutterComponentEx
|
||||
import com.intellij.openapi.project.Project
|
||||
import com.intellij.openapi.ui.popup.JBPopupFactory
|
||||
import com.intellij.openapi.vfs.VirtualFile
|
||||
import com.intellij.psi.PsiElement
|
||||
import com.intellij.psi.search.scope.TestsScope
|
||||
import com.intellij.ui.FileColorManager
|
||||
import com.intellij.ui.awt.RelativePoint
|
||||
import com.intellij.util.FunctionUtil
|
||||
import com.intellij.util.ui.JBUI
|
||||
import icons.ExternalSystemIcons
|
||||
import org.jetbrains.plugins.gradle.execution.test.runner.GradleTestRunConfigurationProducer.findAllTestsTaskToRun
|
||||
import org.jetbrains.plugins.gradle.util.TasksToRun
|
||||
import java.awt.Component
|
||||
import java.awt.MouseInfo
|
||||
import java.util.function.Consumer
|
||||
import javax.swing.DefaultListCellRenderer
|
||||
import javax.swing.JList
|
||||
import javax.swing.border.EmptyBorder
|
||||
|
||||
typealias SourcePath = String
|
||||
typealias TestName = String
|
||||
@@ -25,33 +41,35 @@ open class TestTasksChooser {
|
||||
private fun error(message: String): Nothing = LOG.error(message) as Nothing
|
||||
|
||||
fun chooseTestTasks(
|
||||
context: ConfigurationContext,
|
||||
project: Project,
|
||||
context: DataContext,
|
||||
elements: Iterable<PsiElement>,
|
||||
perform: Consumer<List<Map<SourcePath, TestTasks>>>
|
||||
) {
|
||||
val sources = elements.map { getSourceFile(it) ?: error("Can not find source file for $it") }
|
||||
chooseTestTasks(context.dataContext, sources, context.project, perform)
|
||||
chooseTestTasks(project, context, sources, perform)
|
||||
}
|
||||
|
||||
fun chooseTestTasks(
|
||||
context: ConfigurationContext,
|
||||
project: Project,
|
||||
context: DataContext,
|
||||
vararg elements: PsiElement,
|
||||
perform: Consumer<List<Map<SourcePath, TestTasks>>>
|
||||
) {
|
||||
chooseTestTasks(context, elements.asIterable(), perform)
|
||||
chooseTestTasks(project, context, elements.asIterable(), perform)
|
||||
}
|
||||
|
||||
private fun chooseTestTasks(
|
||||
project: Project,
|
||||
context: DataContext,
|
||||
sources: List<VirtualFile>,
|
||||
project: Project,
|
||||
perform: Consumer<List<Map<SourcePath, TestTasks>>>
|
||||
) {
|
||||
val testTasks = findAllTestsTaskToRun(sources, project)
|
||||
when {
|
||||
testTasks.isEmpty() -> showWarningTooltip(context)
|
||||
testTasks.isEmpty() -> showTestsNotFoundWarning(project, context)
|
||||
testTasks.size == 1 -> perform.accept(testTasks.values.toList())
|
||||
else -> chooseTestTasks(context, testTasks, perform)
|
||||
else -> chooseTestTasks(project, context, testTasks, perform)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -66,37 +84,101 @@ open class TestTasksChooser {
|
||||
}
|
||||
|
||||
protected open fun chooseTestTasks(
|
||||
project: Project,
|
||||
context: DataContext,
|
||||
testTasks: Map<TestName, Map<SourcePath, TasksToRun>>,
|
||||
perform: Consumer<List<Map<SourcePath, TestTasks>>>
|
||||
) {
|
||||
assert(!ApplicationManager.getApplication().isCommandLine)
|
||||
val sortedTestTasksNames = testTasks.keys.toList().sortedByDescending { it == TEST_TASK_NAME }
|
||||
val testTaskRenderer = TestTaskListCellRenderer(project)
|
||||
JBPopupFactory.getInstance()
|
||||
.createPopupChooserBuilder(testTasks.keys.toList())
|
||||
.setRenderer(DefaultListCellRenderer())
|
||||
.setTitle("Choose Tasks to Run")
|
||||
.setMovable(false)
|
||||
.createPopupChooserBuilder(sortedTestTasksNames)
|
||||
.setRenderer(testTaskRenderer)
|
||||
.setTitle(suggestPopupTitle(context))
|
||||
.setAutoselectOnMouseMove(false)
|
||||
.setNamerForFiltering(FunctionUtil.id())
|
||||
.setMovable(true)
|
||||
.setAdText(ExecutionBundle.message("tests.tasks.choosing.popup.hint"))
|
||||
.setResizable(false)
|
||||
.setRequestFocus(true)
|
||||
.setMinSize(JBUI.size(250, -1))
|
||||
.setItemsChosenCallback {
|
||||
val choosesTestTasks = it.mapNotNull(testTasks::get)
|
||||
when {
|
||||
choosesTestTasks.isEmpty() -> showWarningTooltip(context)
|
||||
choosesTestTasks.isEmpty() -> showTestsNotFoundWarning(project, context)
|
||||
else -> perform.accept(choosesTestTasks)
|
||||
}
|
||||
}
|
||||
.createPopup()
|
||||
.showInBestPositionFor(context)
|
||||
.show(getPreferredPopupPosition(context))
|
||||
}
|
||||
|
||||
protected open fun showWarningTooltip(context: DataContext) {
|
||||
protected open fun showTestsNotFoundWarning(project: Project, context: DataContext) {
|
||||
assert(!ApplicationManager.getApplication().isCommandLine)
|
||||
JBPopupFactory.getInstance()
|
||||
.createMessage("No tasks available")
|
||||
.showInBestPositionFor(context)
|
||||
val notification = Notification(
|
||||
"Test tasks chooser",
|
||||
ExecutionBundle.message("tests.tasks.choosing.warning.text"),
|
||||
"",
|
||||
NotificationType.WARNING)
|
||||
Notifications.Bus.notify(notification, project)
|
||||
}
|
||||
|
||||
private fun suggestPopupTitle(context: DataContext): String {
|
||||
val locationName = context.getData(LOCATION)
|
||||
return when (locationName) {
|
||||
null -> ExecutionBundle.message("tests.tasks.choosing.popup.title.common")
|
||||
else -> ExecutionBundle.message("tests.tasks.choosing.popup.title", locationName)
|
||||
}
|
||||
}
|
||||
|
||||
private fun getPreferredPopupPosition(context: DataContext): RelativePoint {
|
||||
return when (context.getData(PlatformDataKeys.CONTEXT_COMPONENT)) {
|
||||
is EditorGutterComponentEx -> RelativePoint(MouseInfo.getPointerInfo().location)
|
||||
else -> JBPopupFactory.getInstance().guessBestPopupLocation(context)
|
||||
}
|
||||
}
|
||||
|
||||
private class TestTaskListCellRenderer(project: Project) : DefaultListCellRenderer() {
|
||||
private val cellInsets = JBUI.insets(1, 5)
|
||||
private val colorManager = FileColorManager.getInstance(project)
|
||||
|
||||
override fun getListCellRendererComponent(
|
||||
list: JList<*>?,
|
||||
value: Any?,
|
||||
index: Int,
|
||||
isSelected: Boolean,
|
||||
cellHasFocus: Boolean
|
||||
): Component {
|
||||
super.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus)
|
||||
text = value.toString()
|
||||
icon = ExternalSystemIcons.Task
|
||||
iconTextGap = cellInsets.left
|
||||
border = EmptyBorder(cellInsets)
|
||||
if (!isSelected) {
|
||||
background = colorManager.getScopeColor(TestsScope.NAME)
|
||||
}
|
||||
return this
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
private const val TEST_TASK_NAME = "test"
|
||||
|
||||
@JvmField
|
||||
val LOCATION = DataKey.create<String?>("org.jetbrains.plugins.gradle.execution.test.runner.TestTasksChooser.LOCATION")
|
||||
|
||||
@JvmStatic
|
||||
fun contextWithLocationName(context: DataContext, locationName: String?): DataContext {
|
||||
if (locationName == null) return context
|
||||
return DataContext {
|
||||
when {
|
||||
LOCATION.`is`(it) -> locationName
|
||||
else -> context.getData(it)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun <K, V, R> Map<K, V>.mapNotNullValues(transform: (Map.Entry<K, V>) -> R?): Map<K, R> =
|
||||
mapNotNull { entry -> transform(entry)?.let { entry.key to it } }.toMap()
|
||||
}
|
||||
|
||||
+3
-1
@@ -10,6 +10,7 @@ import com.intellij.openapi.actionSystem.DataContext
|
||||
import com.intellij.openapi.actionSystem.LangDataKeys
|
||||
import com.intellij.openapi.externalSystem.service.execution.ExternalSystemRunConfiguration
|
||||
import com.intellij.openapi.module.ModuleUtilCore
|
||||
import com.intellij.openapi.project.Project
|
||||
import com.intellij.openapi.util.Ref
|
||||
import com.intellij.openapi.vfs.VirtualFile
|
||||
import com.intellij.psi.PsiClass
|
||||
@@ -70,7 +71,8 @@ abstract class GradleTestRunConfigurationProducerTestCase : GradleImportingTestC
|
||||
|
||||
protected fun GradleTestRunConfigurationProducer.setTestTasksChooser(testTasksFilter: (TestName) -> Boolean) {
|
||||
testTasksChooser = object : TestTasksChooser() {
|
||||
override fun chooseTestTasks(context: DataContext,
|
||||
override fun chooseTestTasks(project: Project,
|
||||
context: DataContext,
|
||||
testTasks: Map<TestName, Map<SourcePath, TasksToRun>>,
|
||||
perform: Consumer<List<Map<SourcePath, TestTasks>>>) {
|
||||
perform.accept(testTasks.filterKeys(testTasksFilter).values.toList())
|
||||
|
||||
Reference in New Issue
Block a user