("com.demonwav.minecraft-dev.platformTypeWizard")
-
- fun create(parent: P) where P : NewProjectWizardStep, P : NewProjectWizardBaseData =
- PlatformTypeStep(parent)
- }
-
- override val self = this
- override val label
- get() = MCDevBundle("creator.ui.platform.type.label")
-
- interface Factory : NewProjectWizardMultiStepFactory
-}
Index: src/main/kotlin/creator/platformtype/PluginPlatformStep.kt
===================================================================
--- src/main/kotlin/creator/platformtype/PluginPlatformStep.kt (revision b568d06142977dcf39328de3dc6dbbd1cc5b0fd0)
+++ src/main/kotlin/creator/platformtype/PluginPlatformStep.kt (revision b568d06142977dcf39328de3dc6dbbd1cc5b0fd0)
@@ -1,53 +0,0 @@
-/*
- * Minecraft Development for IntelliJ
- *
- * https://mcdev.io/
- *
- * Copyright (C) 2025 minecraft-dev
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Lesser General Public License as published
- * by the Free Software Foundation, version 3.0 only.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program. If not, see .
- */
-
-package com.demonwav.mcdev.creator.platformtype
-
-import com.demonwav.mcdev.asset.MCDevBundle
-import com.demonwav.mcdev.creator.platformtype.PluginPlatformStep.Factory
-import com.intellij.ide.wizard.AbstractNewProjectWizardMultiStep
-import com.intellij.ide.wizard.NewProjectWizardMultiStepFactory
-import com.intellij.openapi.extensions.ExtensionPointName
-
-/**
- * The step to select a mod platform.
- *
- * To add custom mod platforms, register a [Factory] to the `com.demonwav.minecraft-dev.pluginPlatformWizard` extension
- * point.
- */
-class PluginPlatformStep(
- parent: PlatformTypeStep,
-) : AbstractNewProjectWizardMultiStep(parent, EP_NAME) {
- companion object {
- val EP_NAME = ExtensionPointName("com.demonwav.minecraft-dev.pluginPlatformWizard")
- }
-
- override val self = this
- override val label
- get() = MCDevBundle("creator.ui.platform.label")
-
- class TypeFactory : PlatformTypeStep.Factory {
- override val name
- get() = MCDevBundle("creator.ui.platform.plugin.name")
- override fun createStep(parent: PlatformTypeStep) = PluginPlatformStep(parent)
- }
-
- interface Factory : NewProjectWizardMultiStepFactory
-}
Index: src/main/kotlin/creator/step/AbstractCollapsibleStep.kt
===================================================================
--- src/main/kotlin/creator/step/AbstractCollapsibleStep.kt (revision b568d06142977dcf39328de3dc6dbbd1cc5b0fd0)
+++ src/main/kotlin/creator/step/AbstractCollapsibleStep.kt (revision b568d06142977dcf39328de3dc6dbbd1cc5b0fd0)
@@ -1,46 +0,0 @@
-/*
- * Minecraft Development for IntelliJ
- *
- * https://mcdev.io/
- *
- * Copyright (C) 2025 minecraft-dev
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Lesser General Public License as published
- * by the Free Software Foundation, version 3.0 only.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program. If not, see .
- */
-
-package com.demonwav.mcdev.creator.step
-
-import com.intellij.ide.wizard.AbstractNewProjectWizardStep
-import com.intellij.ide.wizard.NewProjectWizardStep
-import com.intellij.openapi.project.Project
-import com.intellij.ui.dsl.builder.Panel
-
-abstract class AbstractCollapsibleStep(parent: NewProjectWizardStep) : AbstractNewProjectWizardStep(parent) {
- private val child by lazy { createStep() }
-
- abstract val title: String
-
- protected abstract fun createStep(): NewProjectWizardStep
-
- override fun setupUI(builder: Panel) {
- with(builder) {
- collapsibleGroup(title) {
- child.setupUI(this)
- }
- }
- }
-
- override fun setupProject(project: Project) {
- child.setupProject(project)
- }
-}
Index: src/main/kotlin/creator/step/AbstractLatentStep.kt
===================================================================
--- src/main/kotlin/creator/step/AbstractLatentStep.kt (revision b568d06142977dcf39328de3dc6dbbd1cc5b0fd0)
+++ src/main/kotlin/creator/step/AbstractLatentStep.kt (revision b568d06142977dcf39328de3dc6dbbd1cc5b0fd0)
@@ -1,170 +0,0 @@
-/*
- * Minecraft Development for IntelliJ
- *
- * https://mcdev.io/
- *
- * Copyright (C) 2025 minecraft-dev
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Lesser General Public License as published
- * by the Free Software Foundation, version 3.0 only.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program. If not, see .
- */
-
-package com.demonwav.mcdev.creator.step
-
-import com.demonwav.mcdev.asset.MCDevBundle
-import com.demonwav.mcdev.util.asyncIO
-import com.demonwav.mcdev.util.capitalize
-import com.demonwav.mcdev.util.invokeLater
-import com.demonwav.mcdev.util.onHidden
-import com.demonwav.mcdev.util.onShown
-import com.intellij.ide.wizard.AbstractNewProjectWizardStep
-import com.intellij.ide.wizard.NewProjectWizardStep
-import com.intellij.openapi.Disposable
-import com.intellij.openapi.diagnostic.logger
-import com.intellij.openapi.project.Project
-import com.intellij.openapi.ui.ValidationInfo
-import com.intellij.openapi.ui.validation.DialogValidation
-import com.intellij.openapi.ui.validation.WHEN_GRAPH_PROPAGATION_FINISHED
-import com.intellij.openapi.util.Disposer
-import com.intellij.ui.JBColor
-import com.intellij.ui.dsl.builder.Panel
-import com.intellij.ui.dsl.builder.Placeholder
-import com.intellij.ui.dsl.builder.panel
-import com.intellij.util.ui.AsyncProcessIcon
-import kotlinx.coroutines.CoroutineScope
-import kotlinx.coroutines.Dispatchers
-import kotlinx.coroutines.launch
-import kotlinx.coroutines.swing.Swing
-
-/**
- * Used for when a long-running task is required to fully construct the wizard steps, for example when downloading
- * Minecraft versions.
- */
-abstract class AbstractLatentStep(parent: NewProjectWizardStep) : AbstractNewProjectWizardStep(parent) {
- companion object {
- private val LOGGER = logger>()
- }
-
- private var hasComputedData = false
- private var step: NewProjectWizardStep? = null
-
- /**
- * Description of this step displayed to the user.
- *
- * This should be in sentence case starting with a lower case letter, and starting with a verb in the present tense,
- * like a Git commit message.
- *
- * For example, "download Minecraft versions" would be an appropriate description.
- */
- protected abstract val description: String
-
- private fun doComputeData(placeholder: Placeholder, lifetime: Disposable) {
- if (hasComputedData) {
- return
- }
- hasComputedData = true
-
- var disposed = false
- Disposer.register(lifetime) {
- hasComputedData = false
- disposed = true
- }
-
- CoroutineScope(Dispatchers.Swing).launch {
- if (disposed) {
- return@launch
- }
-
- val (result: T?, errorMessage: String?) = asyncIO {
- try {
- computeData() to null
- } catch (e: Throwable) {
- LOGGER.warn("computeData failed", e)
- null to e.message
- }
- }.await()
-
- if (disposed) {
- return@launch
- }
-
- invokeLater {
- if (disposed) {
- return@invokeLater
- }
-
- if (result == null) {
- placeholder.component = panel {
- row {
- val labelValidationText =
- MCDevBundle("creator.ui.generic_validation_failure.message", description, errorMessage)
- val label = label(labelValidationText)
- .validationRequestor(WHEN_GRAPH_PROPAGATION_FINISHED(propertyGraph))
- .validation(DialogValidation { ValidationInfo(labelValidationText) })
- label.component.foreground = JBColor.RED
- }
- }
- } else {
- val s = createStep(result)
- step = s
- val panel = panel {
- s.setupUI(this)
- }
- placeholder.component = panel
- }
- }
- }
- }
-
- protected abstract suspend fun computeData(): T?
-
- protected abstract fun createStep(data: T): NewProjectWizardStep
-
- override fun setupUI(builder: Panel) {
- lateinit var placeholder: Placeholder
- with(builder) {
- row {
- placeholder = placeholder()
- }
- }
- placeholder.component = panel {
- row(description.capitalize()) {
- cell(
- AsyncProcessIcon("$javaClass.computeData").also { component ->
- var lifetime: Disposable? = null
- component.onShown {
- lifetime?.let(Disposer::dispose)
- lifetime = Disposer.newDisposable().also { lifetime ->
- Disposer.register(context.disposable, lifetime)
- doComputeData(placeholder, lifetime)
- }
- }
- component.onHidden {
- lifetime?.let(Disposer::dispose)
- lifetime = null
- }
- },
- )
- .validationRequestor(WHEN_GRAPH_PROPAGATION_FINISHED(propertyGraph))
- .validation(
- DialogValidation {
- ValidationInfo(MCDevBundle("creator.ui.generic_unfinished.message", description))
- }
- )
- }
- }
- }
-
- override fun setupProject(project: Project) {
- step?.setupProject(project)
- }
-}
Index: src/main/kotlin/creator/step/AbstractLongRunningAssetsStep.kt
===================================================================
--- src/main/kotlin/creator/step/AbstractLongRunningAssetsStep.kt (revision b568d06142977dcf39328de3dc6dbbd1cc5b0fd0)
+++ src/main/kotlin/creator/step/AbstractLongRunningAssetsStep.kt (revision b568d06142977dcf39328de3dc6dbbd1cc5b0fd0)
@@ -1,39 +0,0 @@
-/*
- * Minecraft Development for IntelliJ
- *
- * https://mcdev.io/
- *
- * Copyright (C) 2025 minecraft-dev
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Lesser General Public License as published
- * by the Free Software Foundation, version 3.0 only.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program. If not, see .
- */
-
-package com.demonwav.mcdev.creator.step
-
-import com.intellij.ide.wizard.NewProjectWizardStep
-import com.intellij.openapi.project.Project
-
-abstract class AbstractLongRunningAssetsStep(parent: NewProjectWizardStep) : AbstractLongRunningStep(parent) {
- protected val assets = object : FixedAssetsNewProjectWizardStep(parent) {
- override fun setupAssets(project: Project) {
- outputDirectory = context.projectFileDirectory
- this@AbstractLongRunningAssetsStep.setupAssets(project)
- }
- }
-
- abstract fun setupAssets(project: Project)
-
- override fun perform(project: Project) {
- assets.setupProject(project)
- }
-}
Index: src/main/kotlin/creator/step/AbstractLongRunningStep.kt
===================================================================
--- src/main/kotlin/creator/step/AbstractLongRunningStep.kt (revision b568d06142977dcf39328de3dc6dbbd1cc5b0fd0)
+++ src/main/kotlin/creator/step/AbstractLongRunningStep.kt (revision b568d06142977dcf39328de3dc6dbbd1cc5b0fd0)
@@ -1,99 +0,0 @@
-/*
- * Minecraft Development for IntelliJ
- *
- * https://mcdev.io/
- *
- * Copyright (C) 2025 minecraft-dev
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Lesser General Public License as published
- * by the Free Software Foundation, version 3.0 only.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program. If not, see .
- */
-
-package com.demonwav.mcdev.creator.step
-
-import com.demonwav.mcdev.asset.MCDevBundle
-import com.intellij.ide.wizard.AbstractNewProjectWizardStep
-import com.intellij.ide.wizard.NewProjectWizardStep
-import com.intellij.openapi.progress.ProgressIndicator
-import com.intellij.openapi.progress.ProgressManager
-import com.intellij.openapi.progress.Task
-import com.intellij.openapi.project.Project
-import com.intellij.openapi.util.Key
-import com.intellij.openapi.util.UserDataHolderEx
-import java.util.concurrent.ConcurrentLinkedQueue
-
-private typealias TaskQueue = ConcurrentLinkedQueue
-
-/**
- * Creator steps that either take a long time to complete, or need to be run after other steps that take a long time to
- * complete.
- *
- * These steps show an indeterminate progress bar to the user while they are running.
- */
-abstract class AbstractLongRunningStep(parent: NewProjectWizardStep) : AbstractNewProjectWizardStep(parent) {
-
- /**
- * The text to display on the progress bar
- */
- abstract val description: String
-
- abstract fun perform(project: Project)
-
- final override fun setupProject(project: Project) {
- val newQueue = TaskQueue()
- val queue = (data as UserDataHolderEx).putUserDataIfAbsent(TASK_QUEUE_KEY, newQueue)
- queue += this
- if (queue === newQueue) {
- startTaskQueue(project, queue)
- }
- }
-
- private fun startTaskQueue(project: Project, queue: TaskQueue) {
- val task = object : Task.Backgroundable(
- project,
- MCDevBundle("creator.step.generic.project_created.message")
- ) {
- override fun run(indicator: ProgressIndicator) {
- if (project.isDisposed) {
- return
- }
-
- indicator.text = MCDevBundle("creator.step.generic.project_created.message")
- var currentQueue = queue
- while (true) {
- while (true) {
- val task = currentQueue.poll() ?: break
- indicator.text2 = task.description
- if (project.isDisposed) {
- return
- }
- task.perform(project)
- if (project.isDisposed) {
- return
- }
- }
- if ((data as UserDataHolderEx).replace(TASK_QUEUE_KEY, currentQueue, null)) {
- break
- }
- currentQueue = data.getUserData(TASK_QUEUE_KEY) ?: break
- }
- indicator.text2 = null
- }
- }
-
- ProgressManager.getInstance().run(task)
- }
-
- companion object {
- private val TASK_QUEUE_KEY = Key.create("${AbstractLongRunningStep::class.java.name}.queue")
- }
-}
Index: src/main/kotlin/creator/step/AbstractReformatFilesStep.kt
===================================================================
--- src/main/kotlin/creator/step/AbstractReformatFilesStep.kt (revision b568d06142977dcf39328de3dc6dbbd1cc5b0fd0)
+++ src/main/kotlin/creator/step/AbstractReformatFilesStep.kt (revision b568d06142977dcf39328de3dc6dbbd1cc5b0fd0)
@@ -1,71 +0,0 @@
-/*
- * Minecraft Development for IntelliJ
- *
- * https://mcdev.io/
- *
- * Copyright (C) 2025 minecraft-dev
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Lesser General Public License as published
- * by the Free Software Foundation, version 3.0 only.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program. If not, see .
- */
-
-package com.demonwav.mcdev.creator.step
-
-import com.demonwav.mcdev.asset.MCDevBundle
-import com.demonwav.mcdev.creator.notifyCreatedProjectNotOpened
-import com.intellij.codeInsight.actions.ReformatCodeProcessor
-import com.intellij.ide.wizard.NewProjectWizardStep
-import com.intellij.openapi.application.ReadAction
-import com.intellij.openapi.command.WriteCommandAction
-import com.intellij.openapi.fileEditor.impl.NonProjectFileWritingAccessProvider
-import com.intellij.openapi.project.Project
-import com.intellij.openapi.vfs.VfsUtil
-import com.intellij.psi.PsiFile
-import com.intellij.psi.PsiManager
-import java.nio.file.Path
-
-abstract class AbstractReformatFilesStep(parent: NewProjectWizardStep) : AbstractLongRunningStep(parent) {
- override val description
- get() = MCDevBundle("creator.step.reformat.description")
-
- private val filesToReformat = mutableListOf()
-
- fun addFileToReformat(file: String) {
- filesToReformat += file
- }
-
- abstract fun addFilesToReformat()
-
- override fun perform(project: Project) {
- addFilesToReformat()
-
- val rootDir = VfsUtil.findFile(Path.of(context.projectFileDirectory), true) ?: return
- val psiManager = PsiManager.getInstance(project)
- val files = ReadAction.compute, Throwable> {
- filesToReformat.mapNotNull { path ->
- VfsUtil.findRelativeFile(rootDir, *path.split('/').toTypedArray())?.let(psiManager::findFile)
- }.toTypedArray()
- }
- files.ifEmpty { return }
-
- NonProjectFileWritingAccessProvider.disableChecksDuring {
- WriteCommandAction.writeCommandAction(project, *files).withGlobalUndo().run {
- if (project.isDisposed || !project.isInitialized) {
- notifyCreatedProjectNotOpened()
- return@run
- }
-
- ReformatCodeProcessor(project, files, null, false).run()
- }
- }
- }
-}
Index: src/main/kotlin/creator/step/AbstractSelectVersionStep.kt
===================================================================
--- src/main/kotlin/creator/step/AbstractSelectVersionStep.kt (revision b568d06142977dcf39328de3dc6dbbd1cc5b0fd0)
+++ src/main/kotlin/creator/step/AbstractSelectVersionStep.kt (revision b568d06142977dcf39328de3dc6dbbd1cc5b0fd0)
@@ -1,72 +0,0 @@
-/*
- * Minecraft Development for IntelliJ
- *
- * https://mcdev.io/
- *
- * Copyright (C) 2025 minecraft-dev
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Lesser General Public License as published
- * by the Free Software Foundation, version 3.0 only.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program. If not, see .
- */
-
-package com.demonwav.mcdev.creator.step
-
-import com.intellij.ide.util.PropertiesComponent
-import com.intellij.ide.wizard.AbstractNewProjectWizardStep
-import com.intellij.ide.wizard.NewProjectWizardStep
-import com.intellij.openapi.observable.util.bindStorage
-import com.intellij.openapi.ui.ComboBox
-import com.intellij.ui.dsl.builder.Panel
-import com.intellij.ui.dsl.builder.Row
-import com.intellij.ui.dsl.builder.bindItem
-
-abstract class AbstractSelectVersionStep>(
- parent: NewProjectWizardStep,
- val versions: List,
-) : AbstractNewProjectWizardStep(parent) {
- protected abstract val label: String
-
- val versionProperty = propertyGraph.property("")
- .bindStorage("${javaClass.name}.selectedVersion")
- var version by versionProperty
-
- protected lateinit var versionBox: ComboBox
-
- override fun setupUI(builder: Panel) {
- with(builder) {
- row(label) {
- setupRow(this)
- }
- }
- }
-
- open fun setupRow(builder: Row) {
- with(builder) {
- val box = comboBox(versions.sortedDescending().map(Any::toString)).bindItem(versionProperty)
- val selectedItem = box.component.selectedItem
- if (selectedItem is String) {
- version = selectedItem
- }
- versionBox = box.component
-
- // fix the selection to the latest version if it was previously at the latest version
- val props = PropertiesComponent.getInstance()
- val latestVersionProp = "${javaClass.name}.latestVersion"
- val prevLatestVersion = props.getValue(latestVersionProp)
- val latestVersion = versions.maxOrNull()?.toString()
- if (version == prevLatestVersion) {
- version = latestVersion ?: ""
- }
- props.setValue(latestVersionProp, latestVersion)
- }
- }
-}
Index: src/main/kotlin/creator/step/AbstractVersionChainStep.kt
===================================================================
--- src/main/kotlin/creator/step/AbstractVersionChainStep.kt (revision b568d06142977dcf39328de3dc6dbbd1cc5b0fd0)
+++ src/main/kotlin/creator/step/AbstractVersionChainStep.kt (revision b568d06142977dcf39328de3dc6dbbd1cc5b0fd0)
@@ -1,241 +0,0 @@
-/*
- * Minecraft Development for IntelliJ
- *
- * https://mcdev.io/
- *
- * Copyright (C) 2025 minecraft-dev
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Lesser General Public License as published
- * by the Free Software Foundation, version 3.0 only.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program. If not, see .
- */
-
-package com.demonwav.mcdev.creator.step
-
-import com.intellij.ide.wizard.AbstractNewProjectWizardMultiStepBase
-import com.intellij.ide.wizard.AbstractNewProjectWizardStep
-import com.intellij.ide.wizard.NewProjectWizardStep
-import com.intellij.openapi.components.PersistentStateComponent
-import com.intellij.openapi.components.RoamingType
-import com.intellij.openapi.components.Service
-import com.intellij.openapi.components.State
-import com.intellij.openapi.components.Storage
-import com.intellij.openapi.components.service
-import com.intellij.openapi.observable.properties.ObservableMutableProperty
-import com.intellij.openapi.ui.ComboBox
-import com.intellij.ui.CollectionComboBoxModel
-import com.intellij.ui.dsl.builder.Cell
-import com.intellij.ui.dsl.builder.Panel
-import com.intellij.ui.dsl.builder.Row
-import com.intellij.ui.dsl.builder.bindItem
-
-private class VersionProperties(
- val step: AbstractVersionChainStep,
- val versionProperties: Array>>,
- val preferredVersions: Array>, Comparable<*>>>,
-) {
- init {
- loadPreferredVersions()
-
- var propertyChangeCount = 0L
-
- for ((i, prop) in versionProperties.withIndex()) {
- prop.afterChange { value ->
- val prevPropertyChangeCount = ++propertyChangeCount
-
- val versionsAbove = versionProperties.take(i).map(ObservableMutableProperty>::get)
- val newestVersion = step.getAvailableVersions(versionsAbove).sortedDescending().first()
- if (value == newestVersion) {
- preferredVersions[i].remove(versionsAbove)
- } else {
- preferredVersions[i][versionsAbove] = value
- }
-
- for (j in (i + 1) until versionProperties.size) {
- val versionsAboveChild =
- versionProperties.take(j).map(ObservableMutableProperty>::get)
- val preferredVersion = preferredVersions[j][versionsAboveChild]
- step.comboBoxes?.let { comboBoxes ->
- step.setSelectableItems(j, step.getAvailableVersions(versionsAboveChild).sortedDescending())
- if (preferredVersion != null) {
- comboBoxes[j].selectedItem = preferredVersion
- } else {
- comboBoxes[j].selectedIndex = 0
- }
- } ?: run {
- versionProperties[j].set(
- preferredVersion ?: step.getAvailableVersions(versionsAboveChild).first(),
- )
- }
-
- // the above code could have triggered a recursive property change which would have dealt with the
- // rest of what we're going to do here
- if (propertyChangeCount != prevPropertyChangeCount) {
- return@afterChange
- }
- }
-
- savePreferredVersions()
- }
- }
- }
-
- private fun savePreferredVersions() {
- val stateComponent = PreferredVersionStateComponent.getInstance()
- val preferredVersions = this.preferredVersions.map { m ->
- m.map { (key, value) -> key.map(Comparable<*>::toString) to value.toString() }.toMap()
- }
- stateComponent.set("${step.javaClass.name}.preferredVersions", preferredVersions)
- }
-
- private fun loadPreferredVersions() {
- val stateComponent = PreferredVersionStateComponent.getInstance()
- val preferredVersions = stateComponent.get("${step.javaClass.name}.preferredVersions") ?: return
- for ((i, preferences) in preferredVersions.withIndex()) {
- if (i >= this.preferredVersions.size) {
- break
- }
-
- preferenceEntryLoop@
- for ((versionsAbove, version) in preferences) {
- if (versionsAbove.size != i) {
- continue@preferenceEntryLoop
- }
-
- val parsedVersionsAbove = mutableListOf>()
- for (versionAbove in versionsAbove) {
- parsedVersionsAbove += step.getAvailableVersions(parsedVersionsAbove)
- .firstOrNull { it.toString() == versionAbove }
- ?: continue@preferenceEntryLoop
- }
- val parsedVersion = step.getAvailableVersions(parsedVersionsAbove)
- .firstOrNull { it.toString() == version }
- ?: continue@preferenceEntryLoop
-
- this.preferredVersions[i][parsedVersionsAbove] = parsedVersion
- }
-
- val preferredVersion =
- this.preferredVersions[i][versionProperties.take(i).map(ObservableMutableProperty>::get)]
- if (preferredVersion != null) {
- versionProperties[i].set(preferredVersion)
- }
- }
- }
-}
-
-/**
- * This class replaces chains of [AbstractNewProjectWizardMultiStepBase]s. The problem with the latter approach is that
- * widgets become improperly aligned.
- */
-abstract class AbstractVersionChainStep(
- parent: NewProjectWizardStep,
- private vararg val labels: String,
-) : AbstractNewProjectWizardStep(parent) {
- private val versionProperties by lazy {
- val versionProperties = mutableListOf>>()
- for (i in labels.indices) {
- versionProperties += propertyGraph.property(
- getAvailableVersions(versionProperties.map(ObservableMutableProperty>::get)).first(),
- )
- }
- val preferredVersions = labels.indices.map { mutableMapOf>, Comparable<*>>() }
- VersionProperties(this, versionProperties.toTypedArray(), preferredVersions.toTypedArray())
- }
-
- internal var comboBoxes: Array? = null
-
- abstract fun getAvailableVersions(versionsAbove: List>): List>
-
- fun getVersionProperty(index: Int) = versionProperties.versionProperties[index]
-
- fun getVersion(index: Int) = versionProperties.versionProperties[index].get()
-
- fun getVersionBox(index: Int) = comboBoxes?.let { it[index] }
-
- open fun setSelectableItems(index: Int, items: List>) {
- getVersionBox(index)!!.setSelectableItems(items)
- }
-
- open fun createComboBox(row: Row, index: Int, items: List>): Cell {
- return row.cell(VersionChainComboBox(items))
- }
-
- override fun setupUI(builder: Panel) {
- val comboBoxes = mutableListOf()
- with(builder) {
- for ((i, label) in labels.withIndex()) {
- row(label) {
- val comboBox = createComboBox(
- this,
- i,
- getAvailableVersions(
- versionProperties.versionProperties
- .take(i).map(ObservableMutableProperty>::get),
- ).sortedDescending(),
- ).bindItem(versionProperties.versionProperties[i])
- comboBoxes += comboBox.component
- }
- }
- }
- this.comboBoxes = comboBoxes.toTypedArray()
- }
-}
-
-class VersionChainComboBox(items: List>) : ComboBox>() {
- init {
- setSelectableItems(items)
- }
-
- fun setSelectableItems(items: List>) {
- val currentItem = selectedItem
- model = CollectionComboBoxModel(items)
- if (selectedItem != currentItem) {
- // changing the model doesn't fire item change, which we want to receive
- selectedItemChanged()
- }
- }
-}
-
-private typealias PreferredVersionStateValue = List