MPP wizard: add common module at the same level with platform ones

Related to KT-23097
This commit is contained in:
Mikhail Glukhikh
2018-03-02 13:06:39 +03:00
parent 720c84d1d6
commit cc8a2b3123
2 changed files with 77 additions and 43 deletions
@@ -21,7 +21,7 @@ import com.intellij.ide.util.projectWizard.WizardContext
import com.intellij.openapi.externalSystem.service.project.wizard.ExternalModuleSettingsStep import com.intellij.openapi.externalSystem.service.project.wizard.ExternalModuleSettingsStep
import com.intellij.openapi.fileEditor.FileDocumentManager import com.intellij.openapi.fileEditor.FileDocumentManager
import com.intellij.openapi.module.Module import com.intellij.openapi.module.Module
import com.intellij.openapi.roots.ModifiableRootModel import com.intellij.openapi.projectRoots.Sdk
import com.intellij.openapi.roots.ui.configuration.ModulesProvider import com.intellij.openapi.roots.ui.configuration.ModulesProvider
import com.intellij.openapi.vfs.VfsUtil import com.intellij.openapi.vfs.VfsUtil
import com.intellij.openapi.vfs.VirtualFile import com.intellij.openapi.vfs.VirtualFile
@@ -31,14 +31,16 @@ import org.jetbrains.kotlin.idea.util.rootManager
import org.jetbrains.plugins.gradle.frameworkSupport.BuildScriptDataBuilder import org.jetbrains.plugins.gradle.frameworkSupport.BuildScriptDataBuilder
import org.jetbrains.plugins.gradle.service.project.wizard.GradleModuleBuilder import org.jetbrains.plugins.gradle.service.project.wizard.GradleModuleBuilder
import org.jetbrains.plugins.gradle.service.settings.GradleProjectSettingsControl import org.jetbrains.plugins.gradle.service.settings.GradleProjectSettingsControl
import javax.swing.Icon
class KotlinGradleMultiplatformModuleBuilder : GradleModuleBuilder() { class KotlinGradleMultiplatformModuleBuilder : GradleModuleBuilder() {
var commonModuleName: String? = null
var jvmModuleName: String? = null var jvmModuleName: String? = null
var jsModuleName: String? = null var jsModuleName: String? = null
override fun getBuilderId() = "kotlin.gradle.multiplatform" override fun getBuilderId() = "kotlin.gradle.multiplatform"
override fun getNodeIcon() = KotlinIcons.MPP override fun getNodeIcon(): Icon = KotlinIcons.MPP
override fun getPresentableName() = "Kotlin (Multiplatform - Experimental)" override fun getPresentableName() = "Kotlin (Multiplatform - Experimental)"
@@ -47,24 +49,17 @@ class KotlinGradleMultiplatformModuleBuilder : GradleModuleBuilder() {
override fun createWizardSteps(wizardContext: WizardContext, modulesProvider: ModulesProvider): Array<ModuleWizardStep> { override fun createWizardSteps(wizardContext: WizardContext, modulesProvider: ModulesProvider): Array<ModuleWizardStep> {
super.createWizardSteps(wizardContext, modulesProvider) // initializes GradleModuleBuilder.myWizardContext super.createWizardSteps(wizardContext, modulesProvider) // initializes GradleModuleBuilder.myWizardContext
return arrayOf(KotlinGradleMultiplatformWizardStep(this, wizardContext), return arrayOf(
ExternalModuleSettingsStep( KotlinGradleMultiplatformWizardStep(this, wizardContext),
wizardContext, this, GradleProjectSettingsControl(externalProjectSettings)) ExternalModuleSettingsStep(wizardContext, this, GradleProjectSettingsControl(externalProjectSettings))
) )
} }
override fun setupRootModel(modifiableRootModel: ModifiableRootModel) {
super.setupRootModel(modifiableRootModel)
val module = modifiableRootModel.module
val buildScriptData = getBuildScriptData(module) ?: return
val sdk = modifiableRootModel.sdk
GradleKotlinMPPCommonFrameworkSupportProvider().addSupport(buildScriptData, sdk)
}
override fun setupModule(module: Module) { override fun setupModule(module: Module) {
super.setupModule(module) super.setupModule(module)
val contentRoot = module.rootManager.contentRoots.firstOrNull() ?: return val contentRoot = module.rootManager.contentRoots.firstOrNull() ?: return
setupCommonModule(module, contentRoot)
setupPlatformModule(module, contentRoot, jvmModuleName, GradleKotlinMPPJavaFrameworkSupportProvider()) setupPlatformModule(module, contentRoot, jvmModuleName, GradleKotlinMPPJavaFrameworkSupportProvider())
setupPlatformModule(module, contentRoot, jsModuleName, GradleKotlinMPPJSFrameworkSupportProvider()) setupPlatformModule(module, contentRoot, jsModuleName, GradleKotlinMPPJSFrameworkSupportProvider())
@@ -72,24 +67,42 @@ class KotlinGradleMultiplatformModuleBuilder : GradleModuleBuilder() {
settingsGradle?.let { settingsGradle?.let {
module.project.executeCommand("Update settings.gradle") { module.project.executeCommand("Update settings.gradle") {
val doc = FileDocumentManager.getInstance().getDocument(it) ?: return@executeCommand val doc = FileDocumentManager.getInstance().getDocument(it) ?: return@executeCommand
doc.insertString(doc.textLength, "include '$jvmModuleName', '$jsModuleName'") val commonPrefix = commonModuleName?.let { "'$it', " } ?: ""
doc.insertString(doc.textLength, "include $commonPrefix'$jvmModuleName', '$jsModuleName'")
FileDocumentManager.getInstance().saveDocument(doc) FileDocumentManager.getInstance().saveDocument(doc)
} }
} }
} }
private fun setupPlatformModule(module: Module, private fun setupChildModule(
rootModule: Module,
contentRoot: VirtualFile, contentRoot: VirtualFile,
platformModuleName: String?, childModuleName: String?,
supportProvider: GradleKotlinFrameworkSupportProvider) { extendScript: (BuildScriptDataBuilder, Sdk?) -> Unit = { _, _ -> }
if (platformModuleName.isNullOrEmpty()) return ) {
if (childModuleName.isNullOrEmpty()) return
val sdk = module.rootManager.sdk val moduleDir = contentRoot.createChildDirectory(this, childModuleName!!)
val moduleDir = contentRoot.createChildDirectory(this, platformModuleName!!)
val buildGradle = moduleDir.createChildData(null, "build.gradle") val buildGradle = moduleDir.createChildData(null, "build.gradle")
val buildScriptData = BuildScriptDataBuilder(buildGradle) val buildScriptData = BuildScriptDataBuilder(buildGradle)
supportProvider.addSupport(buildScriptData, sdk) extendScript(buildScriptData, rootModule.rootManager.sdk)
buildScriptData.addDependencyNotation("expectedBy project(\":\")")
VfsUtil.saveText(buildGradle, buildScriptData.buildConfigurationPart() + buildScriptData.buildMainPart()) VfsUtil.saveText(buildGradle, buildScriptData.buildConfigurationPart() + buildScriptData.buildMainPart())
} }
private fun setupCommonModule(
rootModule: Module,
contentRoot: VirtualFile
) = setupChildModule(rootModule, contentRoot, commonModuleName) { builder, sdk ->
GradleKotlinMPPCommonFrameworkSupportProvider().addSupport(builder, sdk)
}
private fun setupPlatformModule(
rootModule: Module,
contentRoot: VirtualFile,
platformModuleName: String?,
supportProvider: GradleKotlinFrameworkSupportProvider
) = setupChildModule(rootModule, contentRoot, platformModuleName) { builder, sdk ->
supportProvider.addSupport(builder, sdk)
val dependency = commonModuleName ?: ""
builder.addDependencyNotation("expectedBy project(\":$dependency\")")
}
} }
@@ -37,8 +37,10 @@ class KotlinGradleMultiplatformWizardStep(
private val wizardContext: WizardContext private val wizardContext: WizardContext
) : ModuleWizardStep() { ) : ModuleWizardStep() {
private val mainModuleNameComponent: LabeledComponent<JTextField> = private val rootModuleNameComponent: LabeledComponent<JTextField> =
LabeledComponent.create(JTextField(), "Main module name:", BorderLayout.WEST) LabeledComponent.create(JTextField(), "Root module name:", BorderLayout.WEST)
private val commonModuleNameComponent: LabeledComponent<JTextField> =
LabeledComponent.create(JTextField(), "Common module name:", BorderLayout.WEST)
private val jvmModuleNameComponent: LabeledComponent<JTextField> = private val jvmModuleNameComponent: LabeledComponent<JTextField> =
LabeledComponent.create(JTextField(), "JVM module name:", BorderLayout.WEST) LabeledComponent.create(JTextField(), "JVM module name:", BorderLayout.WEST)
private val jsModuleNameComponent: LabeledComponent<JTextField> = private val jsModuleNameComponent: LabeledComponent<JTextField> =
@@ -50,13 +52,14 @@ class KotlinGradleMultiplatformWizardStep(
init { init {
panel = object : JPanel(GridBagLayout()), PanelWithAnchor { panel = object : JPanel(GridBagLayout()), PanelWithAnchor {
private var anchor: JComponent? = mainModuleNameComponent.anchor private var anchor: JComponent? = rootModuleNameComponent.anchor
override fun getAnchor(): JComponent? = anchor override fun getAnchor(): JComponent? = anchor
override fun setAnchor(anchor: JComponent?) { override fun setAnchor(anchor: JComponent?) {
this.anchor = anchor this.anchor = anchor
mainModuleNameComponent.anchor = anchor rootModuleNameComponent.anchor = anchor
commonModuleNameComponent.anchor = anchor
jvmModuleNameComponent.anchor = anchor jvmModuleNameComponent.anchor = anchor
jsModuleNameComponent.anchor = anchor jsModuleNameComponent.anchor = anchor
} }
@@ -64,12 +67,12 @@ class KotlinGradleMultiplatformWizardStep(
val baseDir = wizardContext.projectFileDirectory val baseDir = wizardContext.projectFileDirectory
val projectName = wizardContext.projectName val projectName = wizardContext.projectName
val initialProjectName = projectName ?: ProjectWizardUtil.findNonExistingFileName(baseDir, "untitled", "") val initialProjectName = projectName ?: ProjectWizardUtil.findNonExistingFileName(baseDir, "untitled", "")
mainModuleNameComponent.component.text = initialProjectName rootModuleNameComponent.component.text = initialProjectName
mainModuleNameComponent.component.select(0, initialProjectName.length) rootModuleNameComponent.component.select(0, initialProjectName.length)
updateDerivedModuleNames() updateDerivedModuleNames()
mainModuleNameComponent.component.document.addDocumentListener(object : DocumentAdapter() { rootModuleNameComponent.component.document.addDocumentListener(object : DocumentAdapter() {
override fun textChanged(e: DocumentEvent?) { override fun textChanged(e: DocumentEvent?) {
if (syncEditing) { if (syncEditing) {
updateDerivedModuleNames() updateDerivedModuleNames()
@@ -84,18 +87,27 @@ class KotlinGradleMultiplatformWizardStep(
} }
} }
} }
commonModuleNameComponent.component.document.addDocumentListener(stopSyncEditingListener)
jvmModuleNameComponent.component.document.addDocumentListener(stopSyncEditingListener) jvmModuleNameComponent.component.document.addDocumentListener(stopSyncEditingListener)
jsModuleNameComponent.component.document.addDocumentListener(stopSyncEditingListener) jsModuleNameComponent.component.document.addDocumentListener(stopSyncEditingListener)
panel.border = BorderFactory.createEmptyBorder(10, 10, 10, 10) panel.border = BorderFactory.createEmptyBorder(10, 10, 10, 10)
panel.add( panel.add(
mainModuleNameComponent, rootModuleNameComponent,
GridBagConstraints( GridBagConstraints(
0, GridBagConstraints.RELATIVE, 1, 1, 1.0, 0.0, 0, GridBagConstraints.RELATIVE, 1, 1, 1.0, 0.0,
GridBagConstraints.NORTHWEST, GridBagConstraints.HORIZONTAL, GridBagConstraints.NORTHWEST, GridBagConstraints.HORIZONTAL,
JBUI.insets(10, 0, 0, 0), 0, 0 JBUI.insets(10, 0, 0, 0), 0, 0
) )
) )
panel.add(
commonModuleNameComponent,
GridBagConstraints(
0, GridBagConstraints.RELATIVE, 1, 1, 1.0, 0.0,
GridBagConstraints.NORTHWEST, GridBagConstraints.HORIZONTAL,
JBUI.emptyInsets(), 0, 0
)
)
panel.add( panel.add(
jvmModuleNameComponent, jvmModuleNameComponent,
GridBagConstraints( GridBagConstraints(
@@ -126,8 +138,9 @@ class KotlinGradleMultiplatformWizardStep(
private fun updateDerivedModuleNames() { private fun updateDerivedModuleNames() {
inSyncUpdate = true inSyncUpdate = true
try { try {
jvmModuleNameComponent.component.text = "$mainModuleName-jvm" commonModuleNameComponent.component.text = "$rootModuleName-common"
jsModuleNameComponent.component.text = "$mainModuleName-js" jvmModuleNameComponent.component.text = "$rootModuleName-jvm"
jsModuleNameComponent.component.text = "$rootModuleName-js"
} finally { } finally {
inSyncUpdate = false inSyncUpdate = false
@@ -136,30 +149,38 @@ class KotlinGradleMultiplatformWizardStep(
override fun updateDataModel() { override fun updateDataModel() {
wizardContext.projectBuilder = builder wizardContext.projectBuilder = builder
wizardContext.projectName = mainModuleName wizardContext.projectName = rootModuleName
builder.projectId = ProjectId("", mainModuleName, "") builder.projectId = ProjectId("", rootModuleName, "")
builder.commonModuleName = commonModuleName
builder.jvmModuleName = jvmModuleName builder.jvmModuleName = jvmModuleName
builder.jsModuleName = jsModuleName builder.jsModuleName = jsModuleName
} }
override fun getComponent() = panel override fun getComponent() = panel
private val mainModuleName: String private val rootModuleName: String
get() = mainModuleNameComponent.component.text get() = rootModuleNameComponent.component.text
private val commonModuleName: String
get() = commonModuleNameComponent.component.text
private val jvmModuleName: String private val jvmModuleName: String
get() = jvmModuleNameComponent.component.text get() = jvmModuleNameComponent.component.text
private val jsModuleName: String private val jsModuleName: String
get() = jsModuleNameComponent.component.text get() = jsModuleNameComponent.component.text
override fun validate(): Boolean { override fun validate(): Boolean {
if (mainModuleName.isEmpty()) { if (rootModuleName.isEmpty()) {
throw ConfigurationException("Please specify the main module name") throw ConfigurationException("Please specify the root module name")
} }
if (jvmModuleName.isNotEmpty() && (jvmModuleName == mainModuleName || jvmModuleName == jsModuleName)) { if (commonModuleName.isNotEmpty()
&& (commonModuleName == rootModuleName || commonModuleName == jvmModuleName || commonModuleName == jsModuleName)
) {
throw ConfigurationException("The common module name should be distinct")
}
if (jvmModuleName.isNotEmpty() && (jvmModuleName == rootModuleName || jvmModuleName == jsModuleName)) {
throw ConfigurationException("The JVM module name should be distinct") throw ConfigurationException("The JVM module name should be distinct")
} }
if (jsModuleName.isNotEmpty() && jsModuleName == mainModuleName) { if (jsModuleName.isNotEmpty() && jsModuleName == rootModuleName) {
throw ConfigurationException("The IS module name should be distinct") throw ConfigurationException("The IS module name should be distinct")
} }
return true return true