Skip to content

Commit

Permalink
feat: finish config dialog
Browse files Browse the repository at this point in the history
  • Loading branch information
MC-XiaoHei committed Jun 8, 2024
1 parent 512b247 commit fbe74b0
Show file tree
Hide file tree
Showing 4 changed files with 195 additions and 12 deletions.
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
package cn.xor7.xiaohei.leavesknife.activities

import cn.xor7.xiaohei.leavesknife.services.LEAVESKNIFE_CONFIG_FILE
import cn.xor7.xiaohei.leavesknife.services.leavesknifeStoreService
import com.intellij.openapi.project.Project
import com.intellij.openapi.project.guessProjectDir
Expand All @@ -9,26 +8,26 @@ import org.gradle.tooling.GradleConnector
import org.gradle.tooling.model.idea.IdeaProject
import java.io.File
import java.nio.file.Files
import java.nio.file.Paths


class ProjectStartupActivity : ProjectActivity {
override suspend fun execute(project: Project) {
val store = project.leavesknifeStoreService
project.guessProjectDir()?.let { projectDir ->
if (Files.exists(Paths.get(projectDir.path, LEAVESKNIFE_CONFIG_FILE))) {
// TODO 检查配置文件合法性 合法则设置 enablePlugin 为 true 否则设置 needConfigure 为 true
store.enablePlugin = true
if (Files.exists(store.configPath)) {

Check warning on line 17 in src/main/kotlin/cn/xor7/xiaohei/leavesknife/activities/ProjectStartupActivity.kt

View workflow job for this annotation

GitHub Actions / Qodana Community for JVM

Control flow with empty body

'if' has empty body
// TODO 检查配置文件合法性 合法则设置 enablePlugin 为 true
}
GradleConnector.newConnector()
.forProjectDirectory(File(projectDir.path))
.connect().use { connection ->
val ideaProject: IdeaProject = connection.getModel(IdeaProject::class.java)
store.modulePaths = ideaProject.modules.associateTo(mutableMapOf()) {
store.modulePaths = ideaProject.modules.filter {
it.gradleProject.path != ":"
}.associateTo(mutableMapOf()) {
it.name to it.contentRoots.first().rootDirectory.absolutePath
}
if (!store.modulePaths.containsKey("paper-api-generator") && !store.enablePlugin) return@let
store.enablePlugin = true
if (!store.enablePlugin) store.needConfigure = true
}
}
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,162 @@
package cn.xor7.xiaohei.leavesknife.dialogs

class PluginConfigurationDialog {
import cn.xor7.xiaohei.leavesknife.CommonBundle
import cn.xor7.xiaohei.leavesknife.services.PatchType
import cn.xor7.xiaohei.leavesknife.services.PatchesInfo
import cn.xor7.xiaohei.leavesknife.services.leavesknifeStoreService
import com.intellij.openapi.fileChooser.FileChooserDescriptorFactory
import com.intellij.openapi.project.Project
import com.intellij.openapi.project.guessProjectDir
import com.intellij.openapi.ui.ComboBox
import com.intellij.openapi.ui.DialogWrapper
import com.intellij.openapi.ui.TextFieldWithBrowseButton
import com.intellij.openapi.ui.ValidationInfo
import com.intellij.ui.dsl.builder.*
import org.jetbrains.annotations.Nullable
import java.io.FileInputStream
import java.util.*
import javax.swing.DefaultComboBoxModel
import javax.swing.JComponent


class PluginConfigurationDialog(private val project: Project) : DialogWrapper(true) {
private val store = project.leavesknifeStoreService
private val baseTextFields = mutableMapOf<PatchType, Cell<TextFieldWithBrowseButton>>()
private val moduleComboBoxes = mutableMapOf<PatchType, Cell<ComboBox<String>>>()

init {
title = CommonBundle.message("dialog.configure.title")
init()
startTrackingValidation()
}

@Nullable
override fun createCenterPanel(): JComponent = panel {
createPatchGroup(PatchType.SERVER, "Server")
createPatchGroup(PatchType.API, "API")
createPatchGroup(PatchType.GENERATED_API, "Generated API")
}

@Suppress("DialogTitleCapitalization")
private fun Panel.createPatchGroup(patchType: PatchType, name: String) {
group("$name Patches") {
row(CommonBundle.message("dialog.configure.common.module")) {
val comboBoxModel = DefaultComboBoxModel(store.modulePaths.keys.toTypedArray())
moduleComboBoxes[patchType] = comboBox(comboBoxModel).bindItem(
getter = {
if (!store.patchesInfo.containsKey(patchType)) {
store.patchesInfo[patchType] = PatchesInfo(getFallbackOption(patchType), "")
}
store.patchesInfo[patchType]?.moduleName ?: getFallbackOption(patchType)
},
setter = {
store.patchesInfo[patchType]?.moduleName = it ?: getFallbackOption(patchType)
}
).validationOnInput { component ->
validateModule(patchType, component)
}.validationOnApply { component ->
validateModule(patchType, component)
}
}
row(CommonBundle.message("dialog.configure.common.base")) {
baseTextFields[patchType] = textFieldWithBrowseButton(
browseDialogTitle = CommonBundle.message(
"dialog.configure.${patchType.name.lowercase(Locale.getDefault())}.browse.title"
),
project = project,
fileChooserDescriptor = FileChooserDescriptorFactory.createSingleFolderDescriptor(),
fileChosen = { chosenFile -> chosenFile.path }
).bindText(
getter = {
store.patchesInfo[patchType]?.base ?: ""
},
setter = {
store.patchesInfo[patchType]?.base = it
}
).validationOnInput { component ->
if (component.text.isEmpty()) error(CommonBundle.message("dialog.configure.common.base.error.empty"))
else when (patchType) {
PatchType.SERVER -> null
PatchType.API ->
if (component.text == baseTextFields[PatchType.SERVER]?.component?.text) {
error(CommonBundle.message("dialog.configure.common.base.error.same"))
} else null

PatchType.GENERATED_API ->
if (component.text == baseTextFields[PatchType.SERVER]?.component?.text ||
component.text == baseTextFields[PatchType.API]?.component?.text
) {
error(CommonBundle.message("dialog.configure.common.base.error.same"))
} else null
}
}.validationOnApply {
if (it.text.isEmpty()) error(CommonBundle.message("dialog.configure.common.base.error.empty"))
else null
}
}
}
}

override fun doOKAction() {
super.doOKAction()
with(store) {
enablePlugin = true
needConfigure = false
val configFile = configPath.toFile()
if (!configFile.exists()) configFile.createNewFile()
FileInputStream(configFile).use { fileInputStream ->
with(properties) {
load(fileInputStream)
val serverPatchesInfo = patchesInfo[PatchType.SERVER]!!
setProperty("patches.server.module", serverPatchesInfo.moduleName)
setProperty("patches.server.base", serverPatchesInfo.base)
setProperty("patches.server.path", modulePaths[serverPatchesInfo.moduleName])
val apiPatchesInfo = patchesInfo[PatchType.API]!!
setProperty("patches.api.module", apiPatchesInfo.moduleName)
setProperty("patches.api.base", apiPatchesInfo.base)
setProperty("patches.api.path", modulePaths[apiPatchesInfo.moduleName])
val generatedApiPatchesInfo = patchesInfo[PatchType.GENERATED_API]!!
setProperty("patches.generated-api.module", generatedApiPatchesInfo.moduleName)
setProperty("patches.generated-api.base", generatedApiPatchesInfo.base)
setProperty("patches.generated-api.path", modulePaths[generatedApiPatchesInfo.moduleName])
}
configFile.outputStream().use { fileOutputStream ->
properties.store(fileOutputStream, null)
}
project.guessProjectDir()?.refresh(true, false)
}
}
}

@Suppress("DialogTitleCapitalization")
private fun validateModule(patchType: PatchType, component: ComboBox<String>): ValidationInfo? {
return when (patchType) {
PatchType.SERVER -> null
PatchType.API ->
if (component.selectedItem as String ==
moduleComboBoxes[PatchType.SERVER]?.component?.selectedItem as String
) {
ValidationInfo(CommonBundle.message("dialog.configure.common.module.error.same"))
} else null

PatchType.GENERATED_API ->
if (component.selectedItem as String ==
moduleComboBoxes[PatchType.SERVER]?.component?.selectedItem as String ||
component.selectedItem as String ==
moduleComboBoxes[PatchType.API]?.component?.selectedItem as String
) {
ValidationInfo(CommonBundle.message("dialog.configure.common.module.error.same"))
} else null
}
}


private fun getFallbackOption(patchType: PatchType): String {
return if (patchType == PatchType.GENERATED_API)
store.modulePaths.keys.find { it.contains("generator", ignoreCase = true) }
?: store.modulePaths.keys.first()
else
store.modulePaths.keys.find { it.contains(patchType.name, ignoreCase = true) }
?: store.modulePaths.keys.first()
}
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package cn.xor7.xiaohei.leavesknife.services

import cn.xor7.xiaohei.leavesknife.CommonBundle
import cn.xor7.xiaohei.leavesknife.dialogs.PluginConfigurationDialog
import com.intellij.notification.Notification
import com.intellij.notification.NotificationAction
import com.intellij.notification.NotificationGroupManager
Expand All @@ -9,7 +10,11 @@ import com.intellij.openapi.actionSystem.AnActionEvent
import com.intellij.openapi.application.runInEdt
import com.intellij.openapi.components.Service
import com.intellij.openapi.project.Project
import com.intellij.openapi.project.guessProjectDir
import com.intellij.openapi.wm.ToolWindowManager
import java.nio.file.Path
import java.nio.file.Paths
import java.util.*

const val LEAVESKNIFE_CONFIG_FILE = "leavesknife.properties"

Expand Down Expand Up @@ -40,15 +45,24 @@ class ProjectStoreService(private val project: Project) {
)
.addAction(object : NotificationAction(CommonBundle.message("notification.configure.action")) {
override fun actionPerformed(e: AnActionEvent, notification: Notification) {
// TODO 打开配置窗口
notification.hideBalloon()
PluginConfigurationDialog(project).show()
}
})
.notify(project)
}
}
var modulePaths: MutableMap<String, String> = mutableMapOf()
val patchesInfo: MutableMap<PatchType, PatchesInfo> = mutableMapOf()
val properties = Properties()
val configPath: Path = Paths.get(project.guessProjectDir()?.path ?: ".", LEAVESKNIFE_CONFIG_FILE)
}

val Project.leavesknifeStoreService: ProjectStoreService
get() = this.getService(ProjectStoreService::class.java)
get() = this.getService(ProjectStoreService::class.java)

data class PatchesInfo(var moduleName: String, var base: String)

enum class PatchType {
SERVER, API, GENERATED_API
}
16 changes: 14 additions & 2 deletions src/main/resources/messages/CommonBundle.properties
Original file line number Diff line number Diff line change
@@ -1,2 +1,14 @@
notification.configure.title=?????? LeavesKnife
notification.configure.action=??
notification.configure.title=\u7F3A\u5931 LeavesKnife \u914D\u7F6E
notification.configure.action=\u914D\u7F6E
dialog.configure.title=LeavesKnife \u914D\u7F6E
# suppress inspection "UnusedProperty"
dialog.configure.server.browse.title=\u9009\u62E9 Server Patches \u57FA\u76EE\u5F55
# suppress inspection "UnusedProperty"
dialog.configure.api.browse.title=\u9009\u62E9 API Patches \u57FA\u76EE\u5F55
# suppress inspection "UnusedProperty"
dialog.configure.generated_api.browse.title=\u9009\u62E9 Generated API \u57FA\u76EE\u5F55
dialog.configure.common.module=\u6A21\u5757
dialog.configure.common.base=\u57FA\u76EE\u5F55
dialog.configure.common.base.error.empty=\u57FA\u76EE\u5F55\u4E0D\u80FD\u4E3A\u7A7A
dialog.configure.common.base.error.same=\u4E0D\u5141\u8BB8\u51FA\u73B0\u540C\u6837\u7684\u57FA\u76EE\u5F55
dialog.configure.common.module.error.same=\u4E0D\u5141\u8BB8\u51FA\u73B0\u540C\u6837\u7684\u6A21\u5757

0 comments on commit fbe74b0

Please sign in to comment.