From 0205cd51d0601666e23acc3833ace828d5f744a7 Mon Sep 17 00:00:00 2001 From: Daniil Ovchinnikov Date: Wed, 10 May 2017 18:23:37 +0300 Subject: [PATCH] [groovy] console: show module popup under the action button - extract GroovySelectModuleStep - add ability to create a popup but not show it - refactor ModuleChooserUtil and GroovyConsoleUtil - move strings to bundle --- .../plugins/groovy/GroovyBundle.properties | 3 + .../groovy/console/GroovyConsoleUtil.java | 29 ++-- .../groovy/console/GroovyConsoleUtil.kt | 31 ++++ .../console/actions/GrNewConsoleAction.java | 22 +-- .../console/actions/GrSelectModuleAction.kt | 31 ++-- .../groovy/shell/GroovyShellActionBase.java | 17 +-- .../groovy/util/GroovySelectModuleStep.kt | 42 ++++++ .../groovy/util/ModuleChooserUtil.java | 133 ------------------ .../jetbrains/plugins/groovy/util/logic.kt | 30 ++++ .../plugins/groovy/util/moduleChooserUtil.kt | 99 +++++++++++++ 10 files changed, 243 insertions(+), 194 deletions(-) create mode 100644 plugins/groovy/src/org/jetbrains/plugins/groovy/console/GroovyConsoleUtil.kt create mode 100644 plugins/groovy/src/org/jetbrains/plugins/groovy/util/GroovySelectModuleStep.kt delete mode 100644 plugins/groovy/src/org/jetbrains/plugins/groovy/util/ModuleChooserUtil.java create mode 100644 plugins/groovy/src/org/jetbrains/plugins/groovy/util/logic.kt create mode 100644 plugins/groovy/src/org/jetbrains/plugins/groovy/util/moduleChooserUtil.kt diff --git a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/GroovyBundle.properties b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/GroovyBundle.properties index 343e3f285fd6..dc18da88ba36 100644 --- a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/GroovyBundle.properties +++ b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/GroovyBundle.properties @@ -385,3 +385,6 @@ trait.method.cannot.be.protected=Trait methods are not allowed to be protected traits.are.not.supported.in.groovy.0=Traits are not supported in Groovy {0} non.static.classes.not.allowed=Non-static inner classes are not allowed in traits selfType.class.does.not.inherit=@SelfType: Class ''{0}'' does not inherit ''{1}'' + +select.module.description=Which module to use classpath of? +select.module.title=Select module... diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/console/GroovyConsoleUtil.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/console/GroovyConsoleUtil.java index 6e9bfdbdcf83..e1cf67005376 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/console/GroovyConsoleUtil.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/console/GroovyConsoleUtil.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2015 JetBrains s.r.o. + * Copyright 2000-2017 JetBrains s.r.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -15,30 +15,24 @@ */ package org.jetbrains.plugins.groovy.console; -import com.intellij.openapi.actionSystem.DataContext; import com.intellij.openapi.module.Module; -import com.intellij.openapi.module.ModuleManager; import com.intellij.openapi.project.Project; -import com.intellij.openapi.util.Condition; import com.intellij.psi.JavaPsiFacade; import com.intellij.psi.search.GlobalSearchScope; import com.intellij.util.Consumer; import com.intellij.util.Function; -import org.jetbrains.annotations.Contract; import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; import org.jetbrains.plugins.groovy.config.AbstractConfigUtils; import org.jetbrains.plugins.groovy.config.GroovyConfigUtils; import org.jetbrains.plugins.groovy.config.GroovyFacetUtil; import org.jetbrains.plugins.groovy.util.LibrariesUtil; import org.jetbrains.plugins.groovy.util.ModuleChooserUtil; -import java.util.Arrays; +import static org.jetbrains.plugins.groovy.console.GroovyConsoleUtilKt.getApplicableModules; +import static org.jetbrains.plugins.groovy.util.ModuleChooserUtil.formatModuleVersion; public class GroovyConsoleUtil { - public static final Condition APPLICABLE_MODULE = module -> GroovyFacetUtil.isSuitableModule(module); - private static final Function MODULE_VERSION = module -> { final String moduleGroovyHomePath = LibrariesUtil.getGroovyHomePath(module); boolean bundled = moduleGroovyHomePath == null || !hasGroovyAll(module); @@ -61,19 +55,12 @@ public class GroovyConsoleUtil { public static void selectModuleAndRun(Project project, Consumer consumer) { ModuleChooserUtil.selectModule(project, - ModuleChooserUtil.filterGroovyCompatibleModules( - Arrays.asList(ModuleManager.getInstance(project).getModules()), APPLICABLE_MODULE), - MODULE_VERSION, consumer); + getApplicableModules(project), + GroovyConsoleUtil::getTitle, consumer); } - public static void selectModuleAndRun(Project project, Consumer consumer, DataContext context) { - ModuleChooserUtil.selectModule(project, ModuleChooserUtil.filterGroovyCompatibleModules( - Arrays.asList(ModuleManager.getInstance(project).getModules()), APPLICABLE_MODULE), - MODULE_VERSION, consumer, context); - } - - @Contract("null -> null; !null -> !null") - public static String getTitle(@Nullable Module module) { - return module == null ? null : String.format("%s (%s)", module.getName(), MODULE_VERSION.fun(module)); + @NotNull + public static String getTitle(@NotNull Module module) { + return formatModuleVersion(module, MODULE_VERSION.fun(module)); } } diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/console/GroovyConsoleUtil.kt b/plugins/groovy/src/org/jetbrains/plugins/groovy/console/GroovyConsoleUtil.kt new file mode 100644 index 000000000000..f373f7d83d4c --- /dev/null +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/console/GroovyConsoleUtil.kt @@ -0,0 +1,31 @@ +/* + * Copyright 2000-2017 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 org.jetbrains.plugins.groovy.console + +import com.intellij.openapi.module.Module +import com.intellij.openapi.module.ModuleManager +import com.intellij.openapi.project.Project +import org.jetbrains.plugins.groovy.config.GroovyFacetUtil.isSuitableModule +import org.jetbrains.plugins.groovy.util.filterGroovyCompatibleModules + +fun getApplicableModules(project: Project): List { + val modules = ModuleManager.getInstance(project).modules.toList() + return filterGroovyCompatibleModules(modules, ::isSuitableModule) +} + +fun getAnyApplicableModule(project: Project): Module? { + return getApplicableModules(project).firstOrNull() +} diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/console/actions/GrNewConsoleAction.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/console/actions/GrNewConsoleAction.java index 65257a4afa8d..c1d5d591fce1 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/console/actions/GrNewConsoleAction.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/console/actions/GrNewConsoleAction.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2015 JetBrains s.r.o. + * Copyright 2000-2017 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. @@ -19,22 +19,15 @@ import com.intellij.execution.console.ConsoleHistoryController; import com.intellij.ide.scratch.ScratchFileService; import com.intellij.openapi.actionSystem.AnAction; import com.intellij.openapi.actionSystem.AnActionEvent; -import com.intellij.openapi.actionSystem.CommonDataKeys; import com.intellij.openapi.fileEditor.FileEditorManager; import com.intellij.openapi.module.Module; -import com.intellij.openapi.module.ModuleManager; -import com.intellij.openapi.module.ModuleUtilCore; import com.intellij.openapi.project.Project; import com.intellij.openapi.vfs.VirtualFile; import org.jetbrains.annotations.Nullable; import org.jetbrains.plugins.groovy.console.GroovyConsole; import org.jetbrains.plugins.groovy.console.GroovyConsoleRootType; -import org.jetbrains.plugins.groovy.util.ModuleChooserUtil; -import java.util.Arrays; -import java.util.List; - -import static org.jetbrains.plugins.groovy.console.GroovyConsoleUtil.APPLICABLE_MODULE; +import static org.jetbrains.plugins.groovy.console.GroovyConsoleUtilKt.getAnyApplicableModule; public class GrNewConsoleAction extends AnAction { @@ -63,15 +56,6 @@ public class GrNewConsoleAction extends AnAction { protected Module getModule(AnActionEvent e) { final Project project = e.getProject(); if (project == null) return null; - final VirtualFile file = CommonDataKeys.VIRTUAL_FILE.getData(e.getDataContext()); - - if (file != null) { - final Module moduleForFile = ModuleUtilCore.findModuleForFile(file, project); - if (moduleForFile != null) return moduleForFile; - } - - final List modules = ModuleChooserUtil.filterGroovyCompatibleModules( - Arrays.asList(ModuleManager.getInstance(project).getModules()), APPLICABLE_MODULE); - return modules.isEmpty() ? null : modules.get(0); + return getAnyApplicableModule(project); } } diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/console/actions/GrSelectModuleAction.kt b/plugins/groovy/src/org/jetbrains/plugins/groovy/console/actions/GrSelectModuleAction.kt index e4db97eaa2a8..42c9f8f4770f 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/console/actions/GrSelectModuleAction.kt +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/console/actions/GrSelectModuleAction.kt @@ -22,16 +22,18 @@ import com.intellij.openapi.actionSystem.AnActionEvent import com.intellij.openapi.module.Module import com.intellij.openapi.project.Project import com.intellij.openapi.vfs.VirtualFile -import com.intellij.util.Consumer +import org.jetbrains.plugins.groovy.GroovyBundle.message import org.jetbrains.plugins.groovy.console.GroovyConsole import org.jetbrains.plugins.groovy.console.GroovyConsoleStateService -import org.jetbrains.plugins.groovy.console.GroovyConsoleUtil +import org.jetbrains.plugins.groovy.console.GroovyConsoleUtil.getTitle +import org.jetbrains.plugins.groovy.console.getApplicableModules +import org.jetbrains.plugins.groovy.util.createSelectModulePopup import org.jetbrains.plugins.groovy.util.removeUserData class GrSelectModuleAction( private val project: Project, private val file: VirtualFile -) : AnAction(null, "Which module to use classpath of?", AllIcons.Nodes.Module) { +) : AnAction(message("select.module.title"), message("select.module.description"), AllIcons.Nodes.Module) { private val consoleService by lazy { GroovyConsoleStateService.getInstance(project) @@ -39,19 +41,22 @@ class GrSelectModuleAction( override fun update(e: AnActionEvent) { val module = consoleService.getSelectedModule(file) - e.presentation.text = if (module == null || module.isDisposed) "Select module..." else GroovyConsoleUtil.getTitle(module) + if (module == null || module.isDisposed) return + e.presentation.text = getTitle(module) } - override fun displayTextInToolbar(): Boolean { - return true - } + override fun displayTextInToolbar(): Boolean = true override fun actionPerformed(e: AnActionEvent) { - GroovyConsoleUtil.selectModuleAndRun(project, Consumer { module: Module -> - if (consoleService.getSelectedModule(file) == module) return@Consumer - file.removeUserData(GroovyConsole.GROOVY_CONSOLE)?.stop() - consoleService.setFileModule(file, module) - ProjectView.getInstance(project).refresh() - }, e.dataContext) + val component = e.inputEvent?.component ?: return + val popup = createSelectModulePopup(project, getApplicableModules(project), ::getTitle, { moduleSelected(it) }) + popup.showUnderneathOf(component) + } + + private fun moduleSelected(module: Module) { + if (consoleService.getSelectedModule(file) == module) return + file.removeUserData(GroovyConsole.GROOVY_CONSOLE)?.stop() + consoleService.setFileModule(file, module) + ProjectView.getInstance(project).refresh() } } diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/shell/GroovyShellActionBase.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/shell/GroovyShellActionBase.java index ca1665a2df41..270c259c5549 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/shell/GroovyShellActionBase.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/shell/GroovyShellActionBase.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2015 JetBrains s.r.o. + * Copyright 2000-2017 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. @@ -28,10 +28,12 @@ import com.intellij.psi.util.CachedValueProvider; import com.intellij.psi.util.CachedValuesManager; import com.intellij.util.Consumer; import com.intellij.util.Function; -import org.jetbrains.annotations.Nullable; import org.jetbrains.plugins.groovy.util.ModuleChooserUtil; import java.util.Collection; +import java.util.List; + +import static org.jetbrains.plugins.groovy.util.ModuleChooserUtil.formatModuleVersion; public abstract class GroovyShellActionBase extends AnAction { @@ -47,10 +49,10 @@ public abstract class GroovyShellActionBase extends AnAction { // non-static to distinguish different module acceptability conditions private final Key> APPLICABLE_MODULE_CACHE = Key.create("APPLICABLE_MODULE_CACHE"); - private final Function VERSION_PROVIDER = new Function() { + private final Function TITLE_PROVIDER = new Function() { @Override public String fun(Module module) { - return myConfig.getVersion(module); + return formatModuleVersion(module, myConfig.getVersion(module)); } }; @@ -86,9 +88,8 @@ public abstract class GroovyShellActionBase extends AnAction { public void actionPerformed(AnActionEvent e) { final Project project = e.getData(CommonDataKeys.PROJECT); assert project != null; - Collection suitableModules = ModuleChooserUtil.filterGroovyCompatibleModules(myConfig.getPossiblySuitableModules(project), - APPLICABLE_MODULE); - ModuleChooserUtil.selectModule(project, suitableModules, VERSION_PROVIDER, RUNNER); + List suitableModules = ModuleChooserUtil.filterGroovyCompatibleModules(myConfig.getPossiblySuitableModules(project), + APPLICABLE_MODULE); + ModuleChooserUtil.selectModule(project, suitableModules, TITLE_PROVIDER, RUNNER); } - } diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/util/GroovySelectModuleStep.kt b/plugins/groovy/src/org/jetbrains/plugins/groovy/util/GroovySelectModuleStep.kt new file mode 100644 index 000000000000..94a0eeefa203 --- /dev/null +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/util/GroovySelectModuleStep.kt @@ -0,0 +1,42 @@ +/* + * Copyright 2000-2017 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 org.jetbrains.plugins.groovy.util + +import com.intellij.openapi.module.Module +import com.intellij.openapi.ui.popup.PopupStep +import com.intellij.openapi.ui.popup.util.BaseListPopupStep +import com.intellij.util.PlatformIcons +import org.jetbrains.plugins.groovy.GroovyBundle.message + +class GroovySelectModuleStep( + modules: List, + titleProvider: (Module) -> String, + private val consumer: (Module) -> Unit +) : BaseListPopupStep(message("select.module.description"), modules, PlatformIcons.CONTENT_ROOT_ICON_CLOSED) { + + private val myTitles = modules.associate { it to titleProvider(it) } + + override fun getTextFor(value: Module): String = myTitles[value] ?: value.name + + override fun getIndexedString(value: Module): String = value.name + + override fun isSpeedSearchEnabled(): Boolean = true + + override fun onChosen(selectedValue: Module, finalChoice: Boolean): PopupStep<*>? { + consumer(selectedValue) + return null + } +} diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/util/ModuleChooserUtil.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/util/ModuleChooserUtil.java deleted file mode 100644 index 6e4af6917951..000000000000 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/util/ModuleChooserUtil.java +++ /dev/null @@ -1,133 +0,0 @@ -/* - * Copyright 2000-2015 JetBrains s.r.o. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.jetbrains.plugins.groovy.util; - -import com.intellij.ide.util.PropertiesComponent; -import com.intellij.openapi.actionSystem.DataContext; -import com.intellij.openapi.module.Module; -import com.intellij.openapi.project.Project; -import com.intellij.openapi.projectRoots.JavaSdkType; -import com.intellij.openapi.projectRoots.Sdk; -import com.intellij.openapi.roots.ModuleRootManager; -import com.intellij.openapi.roots.ui.configuration.ModulesAlphaComparator; -import com.intellij.openapi.ui.popup.JBPopupFactory; -import com.intellij.openapi.ui.popup.ListPopup; -import com.intellij.openapi.ui.popup.PopupStep; -import com.intellij.openapi.ui.popup.util.BaseListPopupStep; -import com.intellij.openapi.util.Condition; -import com.intellij.util.Consumer; -import com.intellij.util.Function; -import com.intellij.util.PlatformIcons; -import com.intellij.util.containers.ContainerUtil; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -import java.util.*; - -public class ModuleChooserUtil { - - private static final String GROOVY_LAST_MODULE = "Groovy.Last.Module.Chosen"; - - public static void selectModule(@NotNull Project project, - final Collection suitableModules, - final Function versionProvider, - final Consumer callback) { - selectModule(project, suitableModules, versionProvider, callback, null); - } - - public static void selectModule(@NotNull Project project, - final Collection suitableModules, - final Function versionProvider, - final Consumer callback, - @Nullable DataContext context) { - final List modules = new ArrayList<>(); - final Map versions = new HashMap<>(); - - for (Module module : suitableModules) { - modules.add(module); - versions.put(module, versionProvider.fun(module)); - } - - if (modules.size() == 1) { - callback.consume(modules.get(0)); - return; - } - - Collections.sort(modules, ModulesAlphaComparator.INSTANCE); - - BaseListPopupStep step = - new BaseListPopupStep("Which module to use classpath of?", modules, PlatformIcons.CONTENT_ROOT_ICON_CLOSED) { - @NotNull - @Override - public String getTextFor(Module value) { - return String.format("%s (%s)", value.getName(), versions.get(value)); - } - - @Override - public String getIndexedString(Module value) { - return value.getName(); - } - - @Override - public boolean isSpeedSearchEnabled() { - return true; - } - - @Override - public PopupStep onChosen(Module selectedValue, boolean finalChoice) { - PropertiesComponent.getInstance(selectedValue.getProject()).setValue(GROOVY_LAST_MODULE, selectedValue.getName()); - callback.consume(selectedValue); - return null; - } - }; - - final String lastModuleName = PropertiesComponent.getInstance(project).getValue(GROOVY_LAST_MODULE); - if (lastModuleName != null) { - int defaultOption = ContainerUtil.indexOf(modules, (Condition)module -> module.getName().equals(lastModuleName)); - if (defaultOption >= 0) { - step.setDefaultOptionIndex(defaultOption); - } - } - final ListPopup listPopup = JBPopupFactory.getInstance().createListPopup(step); - if (context == null) { - listPopup.showCenteredInCurrentWindow(project); - } - else { - listPopup.showInBestPositionFor(context); - } - } - - @NotNull - private static Condition isGroovyCompatibleModule(final Condition condition) { - return module -> { - if (condition.value(module)) { - final Sdk sdk = ModuleRootManager.getInstance(module).getSdk(); - if (sdk != null && sdk.getSdkType() instanceof JavaSdkType) { - return true; - } - } - return false; - }; - } - - public static List filterGroovyCompatibleModules(Collection modules, final Condition condition) { - return ContainerUtil.filter(modules, isGroovyCompatibleModule(condition)); - } - - public static boolean hasGroovyCompatibleModules(Collection modules, final Condition condition) { - return ContainerUtil.or(modules, isGroovyCompatibleModule(condition)); - } -} diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/util/logic.kt b/plugins/groovy/src/org/jetbrains/plugins/groovy/util/logic.kt new file mode 100644 index 000000000000..099457ac3418 --- /dev/null +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/util/logic.kt @@ -0,0 +1,30 @@ +/* + * Copyright 2000-2017 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 org.jetbrains.plugins.groovy.util + +import com.intellij.openapi.util.Condition + +inline infix fun ((T) -> Boolean).and(crossinline another: (T) -> Boolean): (T) -> Boolean { + return { + this(it) && another(it) + } +} + +fun Condition.toPredicate(): (T) -> Boolean { + return { + value(it) + } +} diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/util/moduleChooserUtil.kt b/plugins/groovy/src/org/jetbrains/plugins/groovy/util/moduleChooserUtil.kt new file mode 100644 index 000000000000..402df7d7b4fc --- /dev/null +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/util/moduleChooserUtil.kt @@ -0,0 +1,99 @@ +/* + * Copyright 2000-2017 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. + */ +@file:JvmName("ModuleChooserUtil") + +package org.jetbrains.plugins.groovy.util + +import com.intellij.ide.util.PropertiesComponent +import com.intellij.openapi.module.Module +import com.intellij.openapi.project.Project +import com.intellij.openapi.projectRoots.JavaSdkType +import com.intellij.openapi.roots.ModuleRootManager +import com.intellij.openapi.roots.ui.configuration.ModulesAlphaComparator +import com.intellij.openapi.ui.popup.JBPopupFactory +import com.intellij.openapi.ui.popup.ListPopup +import com.intellij.openapi.ui.popup.ListPopupStep +import com.intellij.openapi.util.Condition +import com.intellij.util.Consumer +import com.intellij.util.Function +import java.util.* + +private val GROOVY_LAST_MODULE = "Groovy.Last.Module.Chosen" + +fun selectModule(project: Project, + modules: List, + titleProvider: Function, + consumer: Consumer) { + modules.singleOrNull()?.let { + consumer.consume(it) + return + } + Collections.sort(modules, ModulesAlphaComparator.INSTANCE) + createSelectModulePopup(project, modules, { titleProvider.`fun`(it) }, { consumer.consume(it) }).showCenteredInCurrentWindow(project) +} + +fun createSelectModulePopup(project: Project, + modules: List, + titleProvider: (Module) -> String, + consumer: (Module) -> Unit): ListPopup { + val step = createSelectModulePopupStep(project, modules, titleProvider, consumer) + return JBPopupFactory.getInstance().createListPopup(step) +} + + +fun createSelectModulePopupStep(project: Project, + modules: List, + titleProvider: (Module) -> String, + consumer: (Module) -> Unit): ListPopupStep { + val propertiesComponent = PropertiesComponent.getInstance(project) + + val step = GroovySelectModuleStep(modules, titleProvider) { + propertiesComponent.setValue(GROOVY_LAST_MODULE, it.name) + consumer(it) + } + + propertiesComponent.getValue(GROOVY_LAST_MODULE)?.let { lastModuleName -> + step.defaultOptionIndex = modules.indexOfFirst { it.name == lastModuleName } + } + + return step +} + +fun formatModuleVersion(module: Module, version: String): String = "${module.name} (${version})" + +fun filterGroovyCompatibleModules(modules: Collection, condition: Condition): List { + return filterGroovyCompatibleModules(modules, condition.toPredicate()) +} + +fun filterGroovyCompatibleModules(modules: Collection, condition: (Module) -> Boolean): List { + return modules.filter(isGroovyCompatibleModule(condition)) +} + +fun hasGroovyCompatibleModules(modules: Collection, condition: Condition): Boolean { + return hasGroovyCompatibleModules(modules, condition.toPredicate()) +} + +fun hasGroovyCompatibleModules(modules: Collection, condition: (Module) -> Boolean): Boolean { + return modules.any(isGroovyCompatibleModule(condition)) +} + +private inline fun isGroovyCompatibleModule(crossinline condition: (Module) -> Boolean): (Module) -> Boolean { + val sdkTypeCheck = { it: Module -> + val sdk = ModuleRootManager.getInstance(it).sdk + sdk != null && sdk.sdkType is JavaSdkType + } + return sdkTypeCheck and condition +}