Add possibility to edit target platform for non-HMPP projects in order to keep ability to edit target platform for IDEA-based projects

This commit is contained in:
Andrey Uskov
2019-06-28 23:35:50 +03:00
parent efb0e692ae
commit e079615cdf
3 changed files with 120 additions and 24 deletions
@@ -39,5 +39,11 @@ object CommonPlatforms {
// TODO(dsavvinov): extensions points? // TODO(dsavvinov): extensions points?
}.toList() }.toList()
val allDefaultTargetPlatforms: List<TargetPlatform>
get() = sequence {
yieldAll(allSimplePlatforms)
yieldAll(listOf(defaultCommonPlatform))
}.toList()
} }
@@ -93,5 +93,9 @@
description="Use new Java to Kotlin Converter (experimental)" description="Use new Java to Kotlin Converter (experimental)"
defaultValue="false" defaultValue="false"
restartRequired="false"/> restartRequired="false"/>
<registryKey key="kotlin.mpp.editTargetPlatformEnabled"
description="Enable manual editing of MPP target platforms"
defaultValue="false"
restartRequired="false"/>
</extensions> </extensions>
</idea-plugin> </idea-plugin>
@@ -21,7 +21,6 @@ import com.intellij.ide.actions.ShowSettingsUtilImpl
import com.intellij.openapi.project.Project import com.intellij.openapi.project.Project
import com.intellij.openapi.ui.ComboBox import com.intellij.openapi.ui.ComboBox
import com.intellij.ui.HoverHyperlinkLabel import com.intellij.ui.HoverHyperlinkLabel
import com.intellij.util.ui.CheckBox
import com.intellij.util.ui.FormBuilder import com.intellij.util.ui.FormBuilder
import com.intellij.util.ui.ThreeStateCheckBox import com.intellij.util.ui.ThreeStateCheckBox
import org.jetbrains.kotlin.cli.common.arguments.* import org.jetbrains.kotlin.cli.common.arguments.*
@@ -37,12 +36,37 @@ import java.awt.BorderLayout
import javax.swing.* import javax.swing.*
import javax.swing.border.EmptyBorder import javax.swing.border.EmptyBorder
import kotlin.reflect.full.findAnnotation import kotlin.reflect.full.findAnnotation
import com.intellij.openapi.util.registry.Registry
import org.jetbrains.kotlin.platform.jvm.JvmPlatforms
import java.awt.Component
import java.awt.GridLayout
class KotlinFacetEditorGeneralTab( class KotlinFacetEditorGeneralTab(
private val configuration: KotlinFacetConfiguration, private val configuration: KotlinFacetConfiguration,
private val editorContext: FacetEditorContext, private val editorContext: FacetEditorContext,
private val validatorsManager: FacetValidatorsManager private val validatorsManager: FacetValidatorsManager
) : FacetEditorTab() { ) : FacetEditorTab() {
//TODO(auskov): remove this hack as far as inconsistent equals in JdkPlatform is removed
// what it actually does: if version of JVM target platform changed the TargetPlatform will
// return true because equals in JvmPlatform is declared in the following way:
// override fun equals(other: Any?): Boolean = other is JdkPlatform
class TargetPlatformWrapper(val targetPlatform: TargetPlatform) {
override fun equals(other: Any?): Boolean {
if (other is TargetPlatformWrapper) {
if (this.targetPlatform == other.targetPlatform) {
return if (this.targetPlatform.size == 1) {
this.targetPlatform.componentPlatforms.singleOrNull() === other.targetPlatform.componentPlatforms.singleOrNull()
} else {
true
}
}
}
return false
}
}
class EditorComponent( class EditorComponent(
private val project: Project, private val project: Project,
private val configuration: KotlinFacetConfiguration? private val configuration: KotlinFacetConfiguration?
@@ -60,11 +84,34 @@ class KotlinFacetEditorGeneralTab(
lateinit var useProjectSettingsCheckBox: ThreeStateCheckBox lateinit var useProjectSettingsCheckBox: ThreeStateCheckBox
lateinit var platformToCheckbox: Map<SimplePlatform, ThreeStateCheckBox> // UI components related to MPP target platforms
lateinit var hmppCheckbox: ThreeStateCheckBox lateinit var targetPlatformSelectSingleCombobox: ComboBox<TargetPlatformWrapper>
lateinit var targetPlatformWrappers: List<TargetPlatformWrapper>
lateinit var targetPlatformSelectMultipleCheckboxes: Map<SimplePlatform, ThreeStateCheckBox>
private fun isTargetPlatformForceEditable() = Registry.`is`("kotlin.mpp.editTargetPlatformEnabled")
private lateinit var projectSettingsLink: HoverHyperlinkLabel private lateinit var projectSettingsLink: HoverHyperlinkLabel
private fun FormBuilder.addTargetPlatformComponents(): FormBuilder {
return if (configuration?.settings?.isHmppEnabled == true) {
val targetPlatformsPanel = JPanel()
targetPlatformsPanel.layout = GridLayout(0, 1)
targetPlatformSelectMultipleCheckboxes.values.forEach {
targetPlatformsPanel.add(it)
it.isEnabled = isTargetPlatformForceEditable()
if (!isTargetPlatformForceEditable()) {
it.toolTipText = "The project is imported from external build system and could not be edited"
}
}
this.addComponent(JLabel("Selected target platforms:"))
this.addLabeledComponent("", targetPlatformsPanel)
} else {
this.addLabeledComponent("&Target platform: ", targetPlatformSelectSingleCombobox)
}
}
fun initialize() { fun initialize() {
if (isMultiEditor) { if (isMultiEditor) {
editableCommonArguments = object : CommonCompilerArguments() {} editableCommonArguments = object : CommonCompilerArguments() {}
@@ -92,12 +139,30 @@ class KotlinFacetEditorGeneralTab(
) )
useProjectSettingsCheckBox = ThreeStateCheckBox("Use project settings").apply { isThirdStateEnabled = isMultiEditor } useProjectSettingsCheckBox = ThreeStateCheckBox("Use project settings").apply { isThirdStateEnabled = isMultiEditor }
platformToCheckbox = CommonPlatforms targetPlatformSelectMultipleCheckboxes = CommonPlatforms
.allSimplePlatforms .allSimplePlatforms
.flatMap { it.componentPlatforms } .flatMap { it.componentPlatforms }
.distinct() .sortedBy(SimplePlatform::platformName)
.sortedBy { it.platformName } .associateWith { ThreeStateCheckBox(it.platformName).apply { isThirdStateEnabled = isMultiEditor } }
.associate { Pair(it, ThreeStateCheckBox(it.platformName).apply { isThirdStateEnabled = isMultiEditor }) } targetPlatformWrappers = CommonPlatforms.allDefaultTargetPlatforms.sortedBy { it.oldFashionedDescription }.map { TargetPlatformWrapper(it) }
targetPlatformSelectSingleCombobox =
ComboBox(targetPlatformWrappers.toTypedArray()).apply {
setRenderer(object : DefaultListCellRenderer() {
override fun getListCellRendererComponent(
list: JList<*>?,
value: Any?,
index: Int,
isSelected: Boolean,
cellHasFocus: Boolean
): Component {
return super.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus).apply {
text =
(value as? TargetPlatformWrapper)?.targetPlatform?.componentPlatforms?.singleOrNull()?.oldFashionedDescription
?: "Multiplatform"
}
}
})
}
projectSettingsLink = HoverHyperlinkLabel("Edit project settings").apply { projectSettingsLink = HoverHyperlinkLabel("Edit project settings").apply {
addHyperlinkListener { addHyperlinkListener {
ShowSettingsUtilImpl.showSettingsDialog(project, compilerConfigurable.id, "") ShowSettingsUtilImpl.showSettingsDialog(project, compilerConfigurable.id, "")
@@ -107,21 +172,12 @@ class KotlinFacetEditorGeneralTab(
} }
} }
val targetPlatformsPanel = JPanel()
platformToCheckbox.values.forEach {
targetPlatformsPanel.add(it)
it.isEnabled = true //TODO(auskov): think about enabling/disabling editing facet settings
}
hmppCheckbox = ThreeStateCheckBox().apply {
this.isEnabled = false
}
val contentPanel = FormBuilder val contentPanel = FormBuilder
.createFormBuilder() .createFormBuilder()
.addComponent(JPanel(BorderLayout()).apply { .addComponent(JPanel(BorderLayout()).apply {
add(useProjectSettingsCheckBox, BorderLayout.WEST) add(useProjectSettingsCheckBox, BorderLayout.WEST)
add(projectSettingsLink, BorderLayout.EAST) add(projectSettingsLink, BorderLayout.EAST)
}).addLabeledComponent("Selected target platforms:", targetPlatformsPanel) }).addTargetPlatformComponents()
.addLabeledComponent("HMPP enabled:", hmppCheckbox)
.addComponent(compilerConfigurable.createComponent()!!.apply { .addComponent(compilerConfigurable.createComponent()!!.apply {
border = null border = null
}) })
@@ -135,11 +191,14 @@ class KotlinFacetEditorGeneralTab(
updateCompilerConfigurable() updateCompilerConfigurable()
} }
platformToCheckbox.values.forEach { targetPlatformSelectMultipleCheckboxes.values.forEach {
it.addActionListener { it.addActionListener {
updateCompilerConfigurable() updateCompilerConfigurable()
} }
} }
targetPlatformSelectSingleCombobox.addActionListener {
updateCompilerConfigurable()
}
} }
internal fun updateCompilerConfigurable() { internal fun updateCompilerConfigurable() {
@@ -164,8 +223,12 @@ class KotlinFacetEditorGeneralTab(
} }
fun getChosenPlatform(): TargetPlatform? { fun getChosenPlatform(): TargetPlatform? {
val simplePlatforms = platformToCheckbox.filter { it.value.isSelected }.map { it.key }.toSet() return if (configuration?.settings?.isHmppEnabled == true) {
return if (simplePlatforms.isEmpty()) null else TargetPlatform(simplePlatforms) val simplePlatforms = targetPlatformSelectMultipleCheckboxes.filter { it.value.isSelected }.map { it.key }.toSet()
if (simplePlatforms.isEmpty()) null else TargetPlatform(simplePlatforms)
} else {
targetPlatformSelectSingleCombobox.selectedItemTyped?.targetPlatform
}
} }
} }
@@ -286,9 +349,10 @@ class KotlinFacetEditorGeneralTab(
apiVersionComboBox.validateOnChange() apiVersionComboBox.validateOnChange()
coroutineSupportComboBox.validateOnChange() coroutineSupportComboBox.validateOnChange()
} }
editor.platformToCheckbox.values.forEach { editor.targetPlatformSelectMultipleCheckboxes.values.forEach {
it.validateOnChange() it.validateOnChange()
} }
editor.targetPlatformSelectSingleCombobox.validateOnChange()
editor.updateCompilerConfigurable() editor.updateCompilerConfigurable()
isInitialized = true isInitialized = true
@@ -303,7 +367,21 @@ class KotlinFacetEditorGeneralTab(
override fun isModified(): Boolean { override fun isModified(): Boolean {
if (!isInitialized) return false if (!isInitialized) return false
if (editor.useProjectSettingsCheckBox.isSelected != configuration.settings.useProjectSettings) return true if (editor.useProjectSettingsCheckBox.isSelected != configuration.settings.useProjectSettings) return true
if (editor.getChosenPlatform() != configuration.settings.targetPlatform) return true val chosenPlatform = editor.getChosenPlatform()
if (chosenPlatform != configuration.settings.targetPlatform) return true
// work-around for hacked equals in JvmPlatform
if (!configuration?.settings?.isHmppEnabled) {
if (configuration.settings.targetPlatform?.let { TargetPlatformWrapper(it) } != editor.targetPlatformSelectSingleCombobox.selectedItemTyped) {
return true
}
}
val chosenSingle = chosenPlatform?.componentPlatforms?.singleOrNull()
if (chosenSingle != null && chosenSingle == JvmPlatforms.defaultJvmPlatform) {
if (chosenSingle !== configuration.settings.targetPlatform) {
return true
}
}
return !editor.useProjectSettingsCheckBox.isSelected && editor.compilerConfigurable.isModified return !editor.useProjectSettingsCheckBox.isSelected && editor.compilerConfigurable.isModified
} }
@@ -311,10 +389,17 @@ class KotlinFacetEditorGeneralTab(
if (!isInitialized) return if (!isInitialized) return
validateOnce { validateOnce {
editor.useProjectSettingsCheckBox.isSelected = configuration.settings.useProjectSettings editor.useProjectSettingsCheckBox.isSelected = configuration.settings.useProjectSettings
editor.platformToCheckbox.forEach { editor.targetPlatformSelectMultipleCheckboxes.forEach {
it.value.isSelected = configuration.settings.targetPlatform?.contains(it.key) ?: false it.value.isSelected = configuration.settings.targetPlatform?.contains(it.key) ?: false
} }
editor.hmppCheckbox.isSelected = configuration.settings.isHmppEnabled editor.targetPlatformSelectSingleCombobox.selectedItem = configuration.settings.targetPlatform?.let {
val index = editor.targetPlatformWrappers.indexOf(TargetPlatformWrapper(it))
if (index >= 0) {
editor.targetPlatformWrappers.get(index)
} else {
null
}
}
editor.compilerConfigurable.reset() editor.compilerConfigurable.reset()
editor.updateCompilerConfigurable() editor.updateCompilerConfigurable()
} }
@@ -341,6 +426,7 @@ class KotlinFacetEditorGeneralTab(
} }
} }
} }
configuration.settings.targetPlatform = editor.getChosenPlatform()
updateMergedArguments() updateMergedArguments()
} }
} }