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.fileEditor.FileDocumentManager
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.vfs.VfsUtil
import com.intellij.openapi.vfs.VirtualFile
@@ -31,40 +31,35 @@ import org.jetbrains.kotlin.idea.util.rootManager
import org.jetbrains.plugins.gradle.frameworkSupport.BuildScriptDataBuilder
import org.jetbrains.plugins.gradle.service.project.wizard.GradleModuleBuilder
import org.jetbrains.plugins.gradle.service.settings.GradleProjectSettingsControl
import javax.swing.Icon
class KotlinGradleMultiplatformModuleBuilder : GradleModuleBuilder() {
var commonModuleName: String? = null
var jvmModuleName: String? = null
var jsModuleName: String? = null
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 getDescription() =
"Multiplatform projects allow reusing the same code between multiple platforms supported by Kotlin. Such projects are built with Gradle."
"Multiplatform projects allow reusing the same code between multiple platforms supported by Kotlin. Such projects are built with Gradle."
override fun createWizardSteps(wizardContext: WizardContext, modulesProvider: ModulesProvider): Array<ModuleWizardStep> {
super.createWizardSteps(wizardContext, modulesProvider) // initializes GradleModuleBuilder.myWizardContext
return arrayOf(KotlinGradleMultiplatformWizardStep(this, wizardContext),
ExternalModuleSettingsStep(
wizardContext, this, GradleProjectSettingsControl(externalProjectSettings))
return arrayOf(
KotlinGradleMultiplatformWizardStep(this, wizardContext),
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) {
super.setupModule(module)
val contentRoot = module.rootManager.contentRoots.firstOrNull() ?: return
setupCommonModule(module, contentRoot)
setupPlatformModule(module, contentRoot, jvmModuleName, GradleKotlinMPPJavaFrameworkSupportProvider())
setupPlatformModule(module, contentRoot, jsModuleName, GradleKotlinMPPJSFrameworkSupportProvider())
@@ -72,24 +67,42 @@ class KotlinGradleMultiplatformModuleBuilder : GradleModuleBuilder() {
settingsGradle?.let {
module.project.executeCommand("Update settings.gradle") {
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)
}
}
}
private fun setupPlatformModule(module: Module,
contentRoot: VirtualFile,
platformModuleName: String?,
supportProvider: GradleKotlinFrameworkSupportProvider) {
if (platformModuleName.isNullOrEmpty()) return
val sdk = module.rootManager.sdk
val moduleDir = contentRoot.createChildDirectory(this, platformModuleName!!)
private fun setupChildModule(
rootModule: Module,
contentRoot: VirtualFile,
childModuleName: String?,
extendScript: (BuildScriptDataBuilder, Sdk?) -> Unit = { _, _ -> }
) {
if (childModuleName.isNullOrEmpty()) return
val moduleDir = contentRoot.createChildDirectory(this, childModuleName!!)
val buildGradle = moduleDir.createChildData(null, "build.gradle")
val buildScriptData = BuildScriptDataBuilder(buildGradle)
supportProvider.addSupport(buildScriptData, sdk)
buildScriptData.addDependencyNotation("expectedBy project(\":\")")
extendScript(buildScriptData, rootModule.rootManager.sdk)
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
) : ModuleWizardStep() {
private val mainModuleNameComponent: LabeledComponent<JTextField> =
LabeledComponent.create(JTextField(), "Main module name:", BorderLayout.WEST)
private val rootModuleNameComponent: LabeledComponent<JTextField> =
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> =
LabeledComponent.create(JTextField(), "JVM module name:", BorderLayout.WEST)
private val jsModuleNameComponent: LabeledComponent<JTextField> =
@@ -50,13 +52,14 @@ class KotlinGradleMultiplatformWizardStep(
init {
panel = object : JPanel(GridBagLayout()), PanelWithAnchor {
private var anchor: JComponent? = mainModuleNameComponent.anchor
private var anchor: JComponent? = rootModuleNameComponent.anchor
override fun getAnchor(): JComponent? = anchor
override fun setAnchor(anchor: JComponent?) {
this.anchor = anchor
mainModuleNameComponent.anchor = anchor
rootModuleNameComponent.anchor = anchor
commonModuleNameComponent.anchor = anchor
jvmModuleNameComponent.anchor = anchor
jsModuleNameComponent.anchor = anchor
}
@@ -64,12 +67,12 @@ class KotlinGradleMultiplatformWizardStep(
val baseDir = wizardContext.projectFileDirectory
val projectName = wizardContext.projectName
val initialProjectName = projectName ?: ProjectWizardUtil.findNonExistingFileName(baseDir, "untitled", "")
mainModuleNameComponent.component.text = initialProjectName
mainModuleNameComponent.component.select(0, initialProjectName.length)
rootModuleNameComponent.component.text = initialProjectName
rootModuleNameComponent.component.select(0, initialProjectName.length)
updateDerivedModuleNames()
mainModuleNameComponent.component.document.addDocumentListener(object : DocumentAdapter() {
rootModuleNameComponent.component.document.addDocumentListener(object : DocumentAdapter() {
override fun textChanged(e: DocumentEvent?) {
if (syncEditing) {
updateDerivedModuleNames()
@@ -84,18 +87,27 @@ class KotlinGradleMultiplatformWizardStep(
}
}
}
commonModuleNameComponent.component.document.addDocumentListener(stopSyncEditingListener)
jvmModuleNameComponent.component.document.addDocumentListener(stopSyncEditingListener)
jsModuleNameComponent.component.document.addDocumentListener(stopSyncEditingListener)
panel.border = BorderFactory.createEmptyBorder(10, 10, 10, 10)
panel.add(
mainModuleNameComponent,
rootModuleNameComponent,
GridBagConstraints(
0, GridBagConstraints.RELATIVE, 1, 1, 1.0, 0.0,
GridBagConstraints.NORTHWEST, GridBagConstraints.HORIZONTAL,
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(
jvmModuleNameComponent,
GridBagConstraints(
@@ -126,8 +138,9 @@ class KotlinGradleMultiplatformWizardStep(
private fun updateDerivedModuleNames() {
inSyncUpdate = true
try {
jvmModuleNameComponent.component.text = "$mainModuleName-jvm"
jsModuleNameComponent.component.text = "$mainModuleName-js"
commonModuleNameComponent.component.text = "$rootModuleName-common"
jvmModuleNameComponent.component.text = "$rootModuleName-jvm"
jsModuleNameComponent.component.text = "$rootModuleName-js"
} finally {
inSyncUpdate = false
@@ -136,30 +149,38 @@ class KotlinGradleMultiplatformWizardStep(
override fun updateDataModel() {
wizardContext.projectBuilder = builder
wizardContext.projectName = mainModuleName
wizardContext.projectName = rootModuleName
builder.projectId = ProjectId("", mainModuleName, "")
builder.projectId = ProjectId("", rootModuleName, "")
builder.commonModuleName = commonModuleName
builder.jvmModuleName = jvmModuleName
builder.jsModuleName = jsModuleName
}
override fun getComponent() = panel
private val mainModuleName: String
get() = mainModuleNameComponent.component.text
private val rootModuleName: String
get() = rootModuleNameComponent.component.text
private val commonModuleName: String
get() = commonModuleNameComponent.component.text
private val jvmModuleName: String
get() = jvmModuleNameComponent.component.text
private val jsModuleName: String
get() = jsModuleNameComponent.component.text
override fun validate(): Boolean {
if (mainModuleName.isEmpty()) {
throw ConfigurationException("Please specify the main module name")
if (rootModuleName.isEmpty()) {
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")
}
if (jsModuleName.isNotEmpty() && jsModuleName == mainModuleName) {
if (jsModuleName.isNotEmpty() && jsModuleName == rootModuleName) {
throw ConfigurationException("The IS module name should be distinct")
}
return true