From 23cb40442046d15600df9797ca4b89d87ceede38 Mon Sep 17 00:00:00 2001 From: Vladimir Krivosheev Date: Fri, 1 Jul 2022 12:36:19 +0200 Subject: [PATCH] use kotlin coroutines instead of fork-join pool and completable future (part 8 - convert ImportModuleAction to kotlin) GitOrigin-RevId: 9d23b32c747b2f6fa9cb81ef93f68a91affad5bb --- .../ide/actions/ImportModuleAction.kt | 392 ++++++++---------- .../ide/actions/ImportProjectAction.java | 23 +- .../AbstractProjectWizard.java | 37 +- .../action/AttachExternalProjectAction.java | 14 +- .../ide/projectWizard/ImportActionTest.java | 7 +- 5 files changed, 202 insertions(+), 271 deletions(-) diff --git a/java/idea-ui/src/com/intellij/ide/actions/ImportModuleAction.kt b/java/idea-ui/src/com/intellij/ide/actions/ImportModuleAction.kt index a2fc8457636c..1ff48b79fe9b 100644 --- a/java/idea-ui/src/com/intellij/ide/actions/ImportModuleAction.kt +++ b/java/idea-ui/src/com/intellij/ide/actions/ImportModuleAction.kt @@ -1,244 +1,210 @@ // Copyright 2000-2022 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license. -package com.intellij.ide.actions; +package com.intellij.ide.actions -import com.intellij.ide.JavaUiBundle; -import com.intellij.ide.impl.NewProjectUtil; -import com.intellij.ide.impl.ProjectUtil; -import com.intellij.ide.impl.ProjectUtilCore; -import com.intellij.ide.util.PropertiesComponent; -import com.intellij.ide.util.newProjectWizard.AbstractProjectWizard; -import com.intellij.ide.util.newProjectWizard.AddModuleWizard; -import com.intellij.ide.util.projectWizard.ProjectBuilder; -import com.intellij.openapi.actionSystem.ActionUpdateThread; -import com.intellij.openapi.actionSystem.AnAction; -import com.intellij.openapi.actionSystem.AnActionEvent; -import com.intellij.openapi.actionSystem.Presentation; -import com.intellij.openapi.diagnostic.Logger; -import com.intellij.openapi.fileChooser.FileChooserDescriptor; -import com.intellij.openapi.fileChooser.FileChooserDescriptorFactory; -import com.intellij.openapi.fileChooser.FileChooserDialog; -import com.intellij.openapi.fileChooser.FileChooserFactory; -import com.intellij.openapi.module.Module; -import com.intellij.openapi.module.ModuleManager; -import com.intellij.openapi.project.Project; -import com.intellij.openapi.roots.ui.configuration.actions.NewModuleAction; -import com.intellij.openapi.ui.Messages; -import com.intellij.openapi.util.NlsContexts; -import com.intellij.openapi.util.text.HtmlBuilder; -import com.intellij.openapi.vfs.LocalFileSystem; -import com.intellij.openapi.vfs.VirtualFile; -import com.intellij.projectImport.DeprecatedProjectBuilderForImport; -import com.intellij.projectImport.ProjectImportProvider; -import com.intellij.util.containers.ContainerUtil; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; +import com.intellij.ide.JavaUiBundle +import com.intellij.ide.impl.NewProjectUtil +import com.intellij.ide.impl.ProjectUtil.findAndFocusExistingProjectForPath +import com.intellij.ide.impl.ProjectUtilCore +import com.intellij.ide.util.PropertiesComponent +import com.intellij.ide.util.newProjectWizard.AbstractProjectWizard +import com.intellij.ide.util.newProjectWizard.AddModuleWizard +import com.intellij.openapi.actionSystem.ActionUpdateThread +import com.intellij.openapi.actionSystem.AnAction +import com.intellij.openapi.actionSystem.AnActionEvent +import com.intellij.openapi.diagnostic.logger +import com.intellij.openapi.fileChooser.FileChooserDescriptor +import com.intellij.openapi.fileChooser.FileChooserDescriptorFactory +import com.intellij.openapi.fileChooser.FileChooserFactory +import com.intellij.openapi.module.Module +import com.intellij.openapi.module.ModuleManager +import com.intellij.openapi.project.Project +import com.intellij.openapi.roots.ui.configuration.actions.NewModuleAction +import com.intellij.openapi.ui.Messages +import com.intellij.openapi.util.NlsContexts +import com.intellij.openapi.util.text.HtmlBuilder +import com.intellij.openapi.vfs.LocalFileSystem +import com.intellij.openapi.vfs.VirtualFile +import com.intellij.projectImport.DeprecatedProjectBuilderForImport +import com.intellij.projectImport.ProjectImportProvider +import java.awt.Component +import java.nio.file.Path +import java.util.function.Predicate -import java.awt.*; -import java.nio.file.Paths; -import java.util.Arrays; -import java.util.Collections; -import java.util.List; -import java.util.function.Predicate; +private const val LAST_IMPORTED_LOCATION = "last.imported.location" +private val LOG = logger() -/** - * @author Dmitry Avdeev - */ -public class ImportModuleAction extends AnAction implements NewProjectOrModuleAction { - - private static final String LAST_IMPORTED_LOCATION = "last.imported.location"; - private static final Logger LOG = Logger.getInstance(ImportModuleAction.class); - - @Override - public void actionPerformed(@NotNull AnActionEvent e) { - doImport(getEventProject(e)); - } - - @Override - public void update(@NotNull AnActionEvent e) { - Presentation presentation = e.getPresentation(); - presentation.setEnabled(getEventProject(e) != null); - NewProjectAction.updateActionText(this, e); - } - - @Override - public @NotNull ActionUpdateThread getActionUpdateThread() { - return ActionUpdateThread.BGT; - } - - @NotNull - @Override - public String getActionText(boolean isInNewSubmenu, boolean isInJavaIde) { - return JavaUiBundle.message("import.module.action.text", isInNewSubmenu ? 1 : 0, isInJavaIde ? 1 : 0); - } - - @Override - public boolean isDumbAware() { - return true; - } - - public static List doImport(@Nullable Project project) { - AddModuleWizard wizard = selectFileAndCreateWizard(project, null); - - if (wizard == null || wizard.getStepCount() > 0 && !wizard.showAndGet()) { - return Collections.emptyList(); +open class ImportModuleAction : AnAction(), NewProjectOrModuleAction { + companion object { + fun doImport(project: Project?): List { + val wizard = selectFileAndCreateWizard(project = project, dialogParent = null) + return if (wizard == null || wizard.stepCount > 0 && !wizard.showAndGet()) emptyList() else createFromWizard(project, wizard) } - return createFromWizard(project, wizard); - } - public static List createFromWizard(@Nullable Project project, AbstractProjectWizard wizard) { - try { - return doCreateFromWizard(project, wizard); + @JvmStatic + fun createFromWizard(project: Project?, wizard: AbstractProjectWizard): List { + try { + return doCreateFromWizard(project, wizard) + } + finally { + wizard.disposeIfNeeded() + } } - finally { - wizard.disposeIfNeeded(); - } - } - private static List doCreateFromWizard(@Nullable Project project, AbstractProjectWizard wizard) { - final ProjectBuilder projectBuilder = wizard.getProjectBuilder(); - if (project == null) { - Project newProject; - if (projectBuilder instanceof DeprecatedProjectBuilderForImport) { - // The path to remove import action - newProject = openProject((DeprecatedProjectBuilderForImport)projectBuilder, wizard.getNewProjectFilePath()); + @JvmStatic + fun selectFileAndCreateWizard(project: Project?, dialogParent: Component?): AddModuleWizard? { + val descriptor = FileChooserDescriptorFactory.createSingleLocalFileDescriptor() + descriptor.isHideIgnored = false + descriptor.title = JavaUiBundle.message("chooser.title.select.file.or.directory.to.import") + val providers = getProviders(project) + val description = getFileChooserDescription(providers) + descriptor.description = description + return selectFileAndCreateWizard(project, dialogParent, descriptor, providers.toTypedArray()) + } + + @JvmStatic + fun selectFileAndCreateWizard( + project: Project?, + dialogParent: Component?, + descriptor: FileChooserDescriptor, + providers: Array + ): AddModuleWizard? { + return selectFileAndCreateWizard(project = project, + dialogParent = dialogParent, + descriptor = descriptor, + validateSelectedFile = Predicate { true }, + providers = providers) + } + + fun selectFileAndCreateWizard( + project: Project?, + dialogParent: Component?, + descriptor: FileChooserDescriptor, + validateSelectedFile: Predicate, + vararg providers: ProjectImportProvider + ): AddModuleWizard? { + val chooser = FileChooserFactory.getInstance().createFileChooser(descriptor, project, dialogParent) + var toSelect: VirtualFile? = null + val lastLocation = PropertiesComponent.getInstance().getValue(LAST_IMPORTED_LOCATION) + if (lastLocation != null) { + toSelect = LocalFileSystem.getInstance().refreshAndFindFileByPath(lastLocation) + } + + val files = chooser.choose(project, toSelect) + val file = files.firstOrNull() ?: return null + if (project == null) { + // wizard will create a new project + findAndFocusExistingProjectForPath(file.toNioPath()) + } + if (!validateSelectedFile.test(file)) { + return null + } + + PropertiesComponent.getInstance().setValue(LAST_IMPORTED_LOCATION, file.path) + return createImportWizard(project, dialogParent, file, *providers) + } + + @JvmStatic + fun getProviders(project: Project?): List { + val providers = ProjectImportProvider.PROJECT_IMPORT_PROVIDER.extensions + return providers.filter { if (project == null) it.canCreateNewProject() else it.canImportModule() } + } + + @JvmStatic + fun createImportWizard(project: Project?, + dialogParent: Component?, + file: VirtualFile, + vararg providers: ProjectImportProvider): AddModuleWizard? { + val available = providers.filter { it.canImport(file, project) } + if (available.isEmpty()) { + Messages.showInfoMessage(project, JavaUiBundle.message("message.cannot.import.anything.from.0", file.path), + JavaUiBundle.message("dialog.title.cannot.import")) + return null + } + + val path = if (available.size == 1) { + available[0].getPathToBeImported(file) } else { - newProject = NewProjectUtil.createFromWizard(wizard); + ProjectImportProvider.getDefaultPath(file) } - return newProject == null ? Collections.emptyList() : Arrays.asList(ModuleManager.getInstance(newProject).getModules()); - } - - try { - if (wizard.getStepCount() > 0) { - Module module = new NewModuleAction().createModuleFromWizard(project, null, wizard); - return Collections.singletonList(module); + val availableProviders = available.toTypedArray() + if (dialogParent == null) { + return AddModuleWizard(project, path, *availableProviders) } else { - if (!projectBuilder.validate(project, project)) { - return Collections.emptyList(); - } - return projectBuilder.commit(project); - } - } - finally { - if (projectBuilder != null) { - projectBuilder.cleanup(); + return AddModuleWizard(project, dialogParent, path, *availableProviders) } } } - @Nullable - private static Project openProject(@NotNull DeprecatedProjectBuilderForImport projectBuilder, @NotNull String projectPath) { - VirtualFile file = ProjectUtilCore.getFileAndRefresh(Paths.get(projectPath)); - if (file == null) { - LOG.warn(String.format("Cannot find project file in vfs `%s`", projectPath)); - return null; - } - return projectBuilder.getProjectOpenProcessor().doOpenProject(file, null, false); + override fun actionPerformed(e: AnActionEvent) { + doImport(getEventProject(e)) } - @Nullable - public static AddModuleWizard selectFileAndCreateWizard(@Nullable Project project, @Nullable Component dialogParent) { - FileChooserDescriptor descriptor = FileChooserDescriptorFactory.createSingleLocalFileDescriptor(); - descriptor.setHideIgnored(false); - descriptor.setTitle(JavaUiBundle.message("chooser.title.select.file.or.directory.to.import")); - List providers = getProviders(project); - String description = getFileChooserDescription(providers); - descriptor.setDescription(description); - return selectFileAndCreateWizard(project, dialogParent, descriptor, providers.toArray(new ProjectImportProvider[0])); + override fun update(e: AnActionEvent) { + val presentation = e.presentation + presentation.isEnabled = getEventProject(e) != null + NewProjectAction.updateActionText(this, e) } - @Nullable - public static AddModuleWizard selectFileAndCreateWizard( - @Nullable Project project, - @Nullable Component dialogParent, - @NotNull FileChooserDescriptor descriptor, - ProjectImportProvider[] providers - ) { - return selectFileAndCreateWizard(project, dialogParent, descriptor, __ -> true, providers); + override fun getActionUpdateThread() = ActionUpdateThread.BGT + + override fun getActionText(isInNewSubmenu: Boolean, isInJavaIde: Boolean): String { + return JavaUiBundle.message("import.module.action.text", if (isInNewSubmenu) 1 else 0, if (isInJavaIde) 1 else 0) } - @Nullable - public static AddModuleWizard selectFileAndCreateWizard( - @Nullable Project project, - @Nullable Component dialogParent, - @NotNull FileChooserDescriptor descriptor, - @NotNull Predicate validateSelectedFile, - ProjectImportProvider... providers - ) { - FileChooserDialog chooser = FileChooserFactory.getInstance().createFileChooser(descriptor, project, dialogParent); - VirtualFile toSelect = null; - String lastLocation = PropertiesComponent.getInstance().getValue(LAST_IMPORTED_LOCATION); - if (lastLocation != null) { - toSelect = LocalFileSystem.getInstance().refreshAndFindFileByPath(lastLocation); - } - VirtualFile[] files = chooser.choose(project, toSelect); - if (files.length == 0) { - return null; - } + override fun isDumbAware() = true +} - final VirtualFile file = files[0]; - if (project == null) { // wizard will create a new project - ProjectUtil.findAndFocusExistingProjectForPath(file.toNioPath()); - } - if (!validateSelectedFile.test(file)) { - return null; - } - PropertiesComponent.getInstance().setValue(LAST_IMPORTED_LOCATION, file.getPath()); - return createImportWizard(project, dialogParent, file, providers); - } - - private static @NlsContexts.Label String getFileChooserDescription(List providers) { - HtmlBuilder builder = new HtmlBuilder().append(JavaUiBundle.message("select")).append(" "); - boolean first = true; - if (providers.size() > 0) { - for (ProjectImportProvider provider : providers) { - String sample = provider.getFileSample(); - if (sample != null) { - if (!first) { - builder.append(", ").br(); - } - else { - first = false; - } - builder.appendRaw(sample); - } +private fun doCreateFromWizard(project: Project?, wizard: AbstractProjectWizard): List { + val projectBuilder = wizard.projectBuilder + if (project == null) { + val newProject = if (projectBuilder is DeprecatedProjectBuilderForImport) { + // the path to remove import action + val projectPath = Path.of(wizard.newProjectFilePath) + val file = ProjectUtilCore.getFileAndRefresh(projectPath) + if (file == null) { + LOG.warn(String.format("Cannot find project file in vfs `%s`", projectPath)) + null + } + else { + (projectBuilder as DeprecatedProjectBuilderForImport).getProjectOpenProcessor().doOpenProject(file, null, false) } - } - builder.append("."); - return builder.wrapWith("html").toString(); - } - - @NotNull - public static List getProviders(@Nullable final Project project) { - ProjectImportProvider[] providers = ProjectImportProvider.PROJECT_IMPORT_PROVIDER.getExtensions(); - return ContainerUtil.filter(providers, provider -> project == null ? provider.canCreateNewProject() : provider.canImportModule()); - } - - @Nullable - public static AddModuleWizard createImportWizard(@Nullable final Project project, - @Nullable Component dialogParent, - @NotNull final VirtualFile file, - ProjectImportProvider... providers) { - List available = ContainerUtil.filter(providers, provider -> provider.canImport(file, project)); - if (available.isEmpty()) { - Messages.showInfoMessage(project, JavaUiBundle.message("message.cannot.import.anything.from.0", file.getPath()), - JavaUiBundle.message("dialog.title.cannot.import")); - return null; - } - - String path; - if (available.size() == 1) { - path = available.get(0).getPathToBeImported(file); } else { - path = ProjectImportProvider.getDefaultPath(file); + NewProjectUtil.createFromWizard(wizard) } + return if (newProject == null) emptyList() else ModuleManager.getInstance(newProject).modules.asList() + } - ProjectImportProvider[] availableProviders = available.toArray(new ProjectImportProvider[0]); - - return dialogParent == null - ? new AddModuleWizard(project, path, availableProviders) - : new AddModuleWizard(project, dialogParent, path, availableProviders); + try { + if (wizard.stepCount > 0) { + return listOfNotNull(NewModuleAction().createModuleFromWizard(project, null, wizard)) + } + else { + return if (projectBuilder!!.validate(project, project)) projectBuilder.commit(project) else emptyList() + } + } + finally { + projectBuilder?.cleanup() } } + +private fun getFileChooserDescription(providers: List): @NlsContexts.Label String { + val builder = HtmlBuilder().append(JavaUiBundle.message("select")).append(" ") + var first = true + if (providers.isNotEmpty()) { + for (provider in providers) { + val sample = provider.fileSample ?: continue + if (!first) { + builder.append(", ").br() + } + else { + first = false + } + builder.appendRaw(sample) + } + } + builder.append(".") + return builder.wrapWith("html").toString() +} diff --git a/java/idea-ui/src/com/intellij/ide/actions/ImportProjectAction.java b/java/idea-ui/src/com/intellij/ide/actions/ImportProjectAction.java index 7fe8d6866543..14297c5f192e 100644 --- a/java/idea-ui/src/com/intellij/ide/actions/ImportProjectAction.java +++ b/java/idea-ui/src/com/intellij/ide/actions/ImportProjectAction.java @@ -1,18 +1,4 @@ -/* - * 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. - */ +// Copyright 2000-2022 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license. package com.intellij.ide.actions; import com.intellij.icons.AllIcons; @@ -21,13 +7,10 @@ import com.intellij.openapi.actionSystem.AnActionEvent; import com.intellij.openapi.wm.impl.welcomeScreen.NewWelcomeScreen; import org.jetbrains.annotations.NotNull; -/** - * @author Dmitry Avdeev - */ -public class ImportProjectAction extends ImportModuleAction { +public final class ImportProjectAction extends ImportModuleAction { @Override public void actionPerformed(@NotNull AnActionEvent e) { - doImport(null); + ImportModuleAction.Companion.doImport(null); } @Override diff --git a/java/idea-ui/src/com/intellij/ide/util/newProjectWizard/AbstractProjectWizard.java b/java/idea-ui/src/com/intellij/ide/util/newProjectWizard/AbstractProjectWizard.java index e886baae372d..ca6a19cba133 100644 --- a/java/idea-ui/src/com/intellij/ide/util/newProjectWizard/AbstractProjectWizard.java +++ b/java/idea-ui/src/com/intellij/ide/util/newProjectWizard/AbstractProjectWizard.java @@ -1,4 +1,4 @@ -// Copyright 2000-2020 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. +// Copyright 2000-2022 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license. package com.intellij.ide.util.newProjectWizard; import com.intellij.ide.highlighter.ModuleFileType; @@ -37,8 +37,7 @@ import java.nio.file.Paths; */ public abstract class AbstractProjectWizard extends AbstractWizard { protected final WizardContext myWizardContext; - @Nullable - private WizardDelegate myDelegate; + private @Nullable WizardDelegate myDelegate; public AbstractProjectWizard(@Nls String title, @Nullable Project project, String defaultPath) { super(title, project); @@ -74,8 +73,7 @@ public abstract class AbstractProjectWizard extends AbstractWizard { if (!isSelectedFile.test(virtualFile)) { String name = externalSystemId.getReadableName(); - String projectPath = getPresentablePath(virtualFile.getPath()); + String projectPath = UiUtils.getPresentablePath(virtualFile.getPath()); String message = virtualFile.isDirectory() ? JavaUiBundle.message("action.attach.external.project.warning.message.directory", projectPath, name) : JavaUiBundle.message("action.attach.external.project.warning.message.file", projectPath, name); diff --git a/java/idea-ui/testSrc/com/intellij/ide/projectWizard/ImportActionTest.java b/java/idea-ui/testSrc/com/intellij/ide/projectWizard/ImportActionTest.java index 02286e93b2aa..efc821f09213 100644 --- a/java/idea-ui/testSrc/com/intellij/ide/projectWizard/ImportActionTest.java +++ b/java/idea-ui/testSrc/com/intellij/ide/projectWizard/ImportActionTest.java @@ -1,4 +1,4 @@ -// Copyright 2000-2018 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. +// Copyright 2000-2022 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license. package com.intellij.ide.projectWizard; import com.intellij.ide.actions.ImportModuleAction; @@ -17,6 +17,7 @@ import com.intellij.openapi.roots.libraries.LibraryTablesRegistrar; import com.intellij.openapi.util.io.FileUtil; import com.intellij.openapi.vfs.LocalFileSystem; import com.intellij.openapi.vfs.VirtualFile; +import com.intellij.projectImport.ProjectImportProvider; import com.intellij.util.containers.ContainerUtil; import java.io.File; @@ -119,9 +120,9 @@ public class ImportActionTest extends ProjectWizardTestCase { } public void testProvidersCompatibility() { - Set> project = ContainerUtil.map2Set(ImportModuleAction.getProviders(null), p -> p.getClass()); + Set> project = ContainerUtil.map2Set(ImportModuleAction.getProviders(null), ProjectImportProvider::getClass); assertFalse(project.contains(ModuleImportProvider.class)); - Set> modular = ContainerUtil.map2Set(ImportModuleAction.getProviders(getProject()), p -> p.getClass()); + Set> modular = ContainerUtil.map2Set(ImportModuleAction.getProviders(getProject()), ProjectImportProvider::getClass); assertTrue(modular.contains(ModuleImportProvider.class)); } }