UI for standalone gradle scripts

^KT-39790 Fixed
This commit is contained in:
Natalia Selezneva
2020-08-05 15:21:19 +02:00
committed by Vladimir Dolzhenko
parent fc874e72b1
commit 54d96a2dd7
17 changed files with 412 additions and 86 deletions
@@ -56,6 +56,9 @@ action.text.install=Install
action.text.show.kotlin.gradle.dsl.logs.in=Show Kotlin Gradle DSL Logs in {0} action.text.show.kotlin.gradle.dsl.logs.in=Show Kotlin Gradle DSL Logs in {0}
build.0.project=Build {0} build.0.project=Build {0}
change.build.gradle.configuration=Change build.gradle configuration change.build.gradle.configuration=Change build.gradle configuration
standalone.scripts.settings.title=Manage Standalone Scripts
standalone.scripts.settings.column.name=Path
gradle.scripts.settings.title=Gradle Kotlin DSL Scripts
description.text.a.single.platform.kotlin.library.or.application.targeting.javascript=A single-platform Kotlin library or application targeting JavaScript description.text.a.single.platform.kotlin.library.or.application.targeting.javascript=A single-platform Kotlin library or application targeting JavaScript
description.text.a.single.platform.kotlin.library.or.application.targeting.js.for.browser=A single-platform Kotlin library or application targeting JavaScript for browser description.text.a.single.platform.kotlin.library.or.application.targeting.js.for.browser=A single-platform Kotlin library or application targeting JavaScript for browser
description.text.a.single.platform.kotlin.library.or.application.targeting.js.for.node.js=A single-platform Kotlin library or application targeting JavaScript for Node.js description.text.a.single.platform.kotlin.library.or.application.targeting.js.for.node.js=A single-platform Kotlin library or application targeting JavaScript for Node.js
@@ -6,11 +6,39 @@
package org.jetbrains.kotlin.idea.scripting.gradle.roots package org.jetbrains.kotlin.idea.scripting.gradle.roots
import com.intellij.openapi.diagnostic.logger import com.intellij.openapi.diagnostic.logger
import com.intellij.openapi.project.Project
import org.jetbrains.kotlin.idea.scripting.gradle.settings.StandaloneScriptsStorage
class GradleBuildRootIndex : StandaloneScriptsUpdater { class GradleBuildRootIndex(private val project: Project) : StandaloneScriptsUpdater {
private val log = logger<GradleBuildRootIndex>() private val log = logger<GradleBuildRootIndex>()
private val standaloneScriptRoots = mutableMapOf<String, GradleBuildRoot?>() private inner class StandaloneScriptRootsCache {
private val standaloneScripts: MutableSet<String>
get() = StandaloneScriptsStorage.getInstance(project)?.files ?: hashSetOf()
private val standaloneScriptRoots = mutableMapOf<String, GradleBuildRoot?>().apply {
standaloneScripts.forEach(::updateRootsCache)
}
fun all(): List<String> = standaloneScripts.toList()
fun get(path: String): GradleBuildRoot? = standaloneScriptRoots[path]
fun add(path: String) {
standaloneScripts.add(path)
updateRootsCache(path)
}
fun remove(path: String): GradleBuildRoot? {
standaloneScripts.remove(path)
return standaloneScriptRoots.remove(path)
}
fun updateRootsCache(path: String) {
standaloneScriptRoots[path] = findNearestRoot(path)
}
}
private val standaloneScriptRoots by lazy { StandaloneScriptRootsCache() }
private val byWorkingDir = HashMap<String, GradleBuildRoot>() private val byWorkingDir = HashMap<String, GradleBuildRoot>()
private val byProjectDir = HashMap<String, GradleBuildRoot>() private val byProjectDir = HashMap<String, GradleBuildRoot>()
@@ -27,7 +55,7 @@ class GradleBuildRootIndex : StandaloneScriptsUpdater {
} }
} }
standaloneScriptRoots.keys.forEach(::computeStandaloneScriptRoot) standaloneScriptRoots.all().forEach(standaloneScriptRoots::updateRootsCache)
} }
@Synchronized @Synchronized
@@ -48,10 +76,10 @@ class GradleBuildRootIndex : StandaloneScriptsUpdater {
fun getBuildByProjectDir(projectDir: String) = byProjectDir[projectDir] fun getBuildByProjectDir(projectDir: String) = byProjectDir[projectDir]
@Synchronized @Synchronized
fun isStandaloneScript(path: String) = path in standaloneScriptRoots fun isStandaloneScript(path: String) = path in standaloneScriptRoots.all()
@Synchronized @Synchronized
fun getStandaloneScriptRoot(path: String) = standaloneScriptRoots[path] fun getStandaloneScriptRoot(path: String) = standaloneScriptRoots.get(path)
@Synchronized @Synchronized
fun add(value: GradleBuildRoot): GradleBuildRoot? { fun add(value: GradleBuildRoot): GradleBuildRoot? {
@@ -70,21 +98,14 @@ class GradleBuildRootIndex : StandaloneScriptsUpdater {
@Synchronized @Synchronized
override fun addStandaloneScript(path: String) { override fun addStandaloneScript(path: String) {
computeStandaloneScriptRoot(path) standaloneScriptRoots.add(path)
} }
@Synchronized @Synchronized
override fun removeStandaloneScript(path: String) = override fun removeStandaloneScript(path: String): GradleBuildRoot? {
standaloneScriptRoots.remove(path) return standaloneScriptRoots.remove(path)
override var standaloneScripts: Collection<String>
@Synchronized get() = standaloneScriptRoots.keys
@Synchronized set(value) {
standaloneScriptRoots.clear()
value.forEach(::computeStandaloneScriptRoot)
}
private fun computeStandaloneScriptRoot(path: String) {
standaloneScriptRoots[path] = findNearestRoot(path)
} }
override val standaloneScripts: Collection<String>
@Synchronized get() = standaloneScriptRoots.all()
} }
@@ -5,6 +5,7 @@
package org.jetbrains.kotlin.idea.scripting.gradle.roots package org.jetbrains.kotlin.idea.scripting.gradle.roots
import com.intellij.openapi.project.Project
import com.intellij.openapi.vfs.VirtualFile import com.intellij.openapi.vfs.VirtualFile
/** /**
@@ -13,8 +14,8 @@ import com.intellij.openapi.vfs.VirtualFile
* *
* @see GradleBuildRootsManager for details. * @see GradleBuildRootsManager for details.
*/ */
abstract class GradleBuildRootsLocator { abstract class GradleBuildRootsLocator(project: Project) {
protected val roots = GradleBuildRootIndex() protected val roots = GradleBuildRootIndex(project)
abstract fun getScriptInfo(localPath: String): GradleScriptInfo? abstract fun getScriptInfo(localPath: String): GradleScriptInfo?
@@ -63,7 +63,7 @@ import java.util.concurrent.atomic.AtomicBoolean
* - [New] - not yet imported * - [New] - not yet imported
* - [Imported] - imported * - [Imported] - imported
*/ */
class GradleBuildRootsManager(val project: Project) : GradleBuildRootsLocator(), ScriptingSupport { class GradleBuildRootsManager(val project: Project) : GradleBuildRootsLocator(project), ScriptingSupport {
private val manager: CompositeScriptConfigurationManager private val manager: CompositeScriptConfigurationManager
get() = ScriptConfigurationManager.getInstance(project) as CompositeScriptConfigurationManager get() = ScriptConfigurationManager.getInstance(project) as CompositeScriptConfigurationManager
@@ -6,7 +6,7 @@
package org.jetbrains.kotlin.idea.scripting.gradle.roots package org.jetbrains.kotlin.idea.scripting.gradle.roots
interface StandaloneScriptsUpdater { interface StandaloneScriptsUpdater {
var standaloneScripts: Collection<String> val standaloneScripts: Collection<String>
fun addStandaloneScript(path: String) fun addStandaloneScript(path: String)
@@ -0,0 +1,142 @@
/*
* Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.idea.scripting.gradle.settings
import com.intellij.openapi.fileChooser.FileChooser
import com.intellij.openapi.fileChooser.FileChooserDescriptor
import com.intellij.openapi.options.UnnamedConfigurable
import com.intellij.openapi.project.Project
import com.intellij.openapi.vfs.VirtualFile
import com.intellij.openapi.wm.IdeFocusManager
import com.intellij.ui.ToolbarDecorator
import com.intellij.ui.table.JBTable
import com.intellij.ui.table.TableView
import com.intellij.util.ui.JBUI
import org.jetbrains.kotlin.idea.KotlinIdeaGradleBundle
import org.jetbrains.kotlin.idea.script.configuration.ScriptingSupportSpecificSettingsProvider
import org.jetbrains.kotlin.idea.scripting.gradle.roots.GradleBuildRootsLocator.NotificationKind
import org.jetbrains.kotlin.idea.scripting.gradle.roots.GradleBuildRootsManager
import org.jetbrains.kotlin.idea.scripting.gradle.settings.KotlinStandaloneScriptsModel.Companion.createModel
import java.awt.BorderLayout
import javax.swing.JComponent
import javax.swing.JPanel
import javax.swing.ListSelectionModel
import javax.swing.plaf.BorderUIResource.TitledBorderUIResource
class GradleSettingsProvider(private val project: Project) : ScriptingSupportSpecificSettingsProvider() {
override val title: String = KotlinIdeaGradleBundle.message("gradle.scripts.settings.title")
override fun createConfigurable(): UnnamedConfigurable {
return StandaloneScriptsUIComponent(project)
}
}
class StandaloneScriptsUIComponent(private val project: Project) : UnnamedConfigurable {
private val fileChooser: FileChooserDescriptor = object : FileChooserDescriptor(
true, false, false,
false, false, true
) {
override fun isFileSelectable(file: VirtualFile): Boolean {
val rootsManager = GradleBuildRootsManager.getInstance(project)
val scriptUnderRoot = rootsManager.findScriptBuildRoot(file)
val notificationKind = scriptUnderRoot?.notificationKind
return notificationKind == NotificationKind.legacyOutside || notificationKind == NotificationKind.notEvaluatedInLastImport
}
}
private var panel: JPanel? = null
private val scriptsFromStorage = StandaloneScriptsStorage.getInstance(project)?.files?.toList() ?: emptyList()
private val scriptsInTable = scriptsFromStorage.toMutableList()
private val table: JBTable
private val model: KotlinStandaloneScriptsModel
init {
model = createModel(scriptsInTable)
table = TableView(model)
table.preferredScrollableViewportSize = JBUI.size(300, -1)
table.selectionModel.selectionMode = ListSelectionModel.MULTIPLE_INTERVAL_SELECTION
model.addTableModelListener(table)
}
override fun reset() {
scriptsInTable.clear()
scriptsInTable.addAll(scriptsFromStorage)
model.items = scriptsInTable
}
override fun apply() {
GradleBuildRootsManager.getInstance(project).updateStandaloneScripts {
val previousScripts = scriptsFromStorage
scriptsInTable
.filterNot { previousScripts.contains(it) }
.forEach { addStandaloneScript(it) }
previousScripts
.filterNot { scriptsInTable.contains(it) }
.forEach { removeStandaloneScript(it) }
}
}
override fun createComponent(): JComponent? {
if (panel == null) {
val panel = JPanel(BorderLayout())
panel.border = TitledBorderUIResource(KotlinIdeaGradleBundle.message("standalone.scripts.settings.title"))
panel.add(
ToolbarDecorator.createDecorator(table)
.setAddAction { addScripts() }
.setRemoveAction { removeScripts() }
.setRemoveActionUpdater { table.selectedRow >= 0 }
.disableUpDownActions()
.createPanel()
)
this.panel = panel
}
return panel
}
override fun isModified(): Boolean {
return scriptsFromStorage != scriptsInTable
}
override fun disposeUIResources() {
panel = null
}
override fun cancel() {
reset()
}
private fun addScripts() {
val chosen = FileChooser.chooseFiles(fileChooser, project, null)
for (chosenFile in chosen) {
val path = chosenFile.path
if (scriptsInTable.contains(path)) continue
scriptsInTable.add(path)
model.addRow(path)
}
}
private fun removeScripts() {
val selected = table.selectedRows
if (selected == null || selected.isEmpty()) {
return
}
for ((removedCount, indexToRemove) in selected.withIndex()) {
val row = indexToRemove - removedCount
scriptsInTable.removeAt(row)
model.removeRow(row)
}
IdeFocusManager.getGlobalInstance()
.doWhenFocusSettlesDown { IdeFocusManager.getGlobalInstance().requestFocus(table, true) }
}
}
@@ -0,0 +1,28 @@
/*
* Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.idea.scripting.gradle.settings
import com.intellij.util.ui.ColumnInfo
import com.intellij.util.ui.ListTableModel
import org.jetbrains.kotlin.idea.KotlinIdeaGradleBundle
class KotlinStandaloneScriptsModel private constructor(scripts: MutableList<String>) :
ListTableModel<String>(
arrayOf(object : ColumnInfo<String, String>(KotlinIdeaGradleBundle.message("standalone.scripts.settings.column.name")) {
override fun valueOf(item: String?): String? = item
}),
scripts
) {
override fun setItems(items: List<String>) {
super.setItems(items.toMutableList())
}
companion object {
fun createModel(scripts: Collection<String>): KotlinStandaloneScriptsModel =
KotlinStandaloneScriptsModel(scripts.toMutableList())
}
}
@@ -0,0 +1,33 @@
/*
* Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.idea.scripting.gradle.settings
import com.intellij.openapi.components.*
import com.intellij.openapi.project.Project
import com.intellij.util.xmlb.XmlSerializerUtil
@State(
name = "StandaloneScriptsStorage",
storages = [Storage(StoragePathMacros.CACHE_FILE)]
)
class StandaloneScriptsStorage : PersistentStateComponent<StandaloneScriptsStorage> {
var files: MutableSet<String> = hashSetOf()
fun getScripts(): List<String> = files.toList()
override fun getState(): StandaloneScriptsStorage? {
return this
}
override fun loadState(state: StandaloneScriptsStorage) {
XmlSerializerUtil.copyBean(state, this)
}
companion object {
fun getInstance(project: Project): StandaloneScriptsStorage? =
ServiceManager.getService(project, StandaloneScriptsStorage::class.java)
}
}
@@ -5,18 +5,34 @@
package org.jetbrains.kotlin.idea.scripting.gradle.roots package org.jetbrains.kotlin.idea.scripting.gradle.roots
import com.intellij.mock.MockProjectEx
import com.intellij.openapi.Disposable
import junit.framework.TestCase
import org.jetbrains.kotlin.idea.scripting.gradle.GradleKotlinScriptConfigurationInputs import org.jetbrains.kotlin.idea.scripting.gradle.GradleKotlinScriptConfigurationInputs
import org.jetbrains.kotlin.idea.scripting.gradle.LastModifiedFiles import org.jetbrains.kotlin.idea.scripting.gradle.LastModifiedFiles
import org.jetbrains.kotlin.idea.scripting.gradle.importing.KotlinDslScriptModel import org.jetbrains.kotlin.idea.scripting.gradle.importing.KotlinDslScriptModel
import kotlin.test.assertEquals
open class AbstractGradleBuildRootsLocatorTest { open class AbstractGradleBuildRootsLocatorTest : TestCase() {
private val scripts = mutableMapOf<String, ScriptFixture>() private val scripts = mutableMapOf<String, ScriptFixture>()
private val locator = MyRootsLocator() private val locator = MyRootsLocator()
class ScriptFixture(val introductionTs: Long, val info: GradleScriptInfo) class ScriptFixture(val introductionTs: Long, val info: GradleScriptInfo)
private inner class MyRootsLocator : GradleBuildRootsLocator() { lateinit var disposable: Disposable
override fun setUp() {
super.setUp()
disposable = Disposable { }
}
override fun tearDown() {
disposable.dispose()
super.tearDown()
}
private inner class MyRootsLocator : GradleBuildRootsLocator(MockProjectEx(disposable)) {
override fun getScriptFirstSeenTs(path: String): Long = scripts[path]?.introductionTs ?: 0 override fun getScriptFirstSeenTs(path: String): Long = scripts[path]?.introductionTs ?: 0
override fun getScriptInfo(localPath: String): GradleScriptInfo? = scripts[localPath]?.info override fun getScriptInfo(localPath: String): GradleScriptInfo? = scripts[localPath]?.info
fun accessRoots() = roots fun accessRoots() = roots
@@ -2218,6 +2218,7 @@ action.usage.update.text=Usage update
progress.title.analyze.extraction.data=Analyze extraction data... progress.title.analyze.extraction.data=Analyze extraction data...
fix.move.file.to.package.dir.name.text=source root fix.move.file.to.package.dir.name.text=source root
move.refactoring.error.text.cannot.perform.refactoring.since.the.following.files.already.exist=Cannot perform refactoring since the following files already exist:\n\n move.refactoring.error.text.cannot.perform.refactoring.since.the.following.files.already.exist=Cannot perform refactoring since the following files already exist:\n\n
kotlin.script.definitions.title=Manage Script Definitions
kotlin.script.definitions.model.name.autoReloadScriptDependencies.description=Enable auto reload if you want to load script configurations automatically on file change kotlin.script.definitions.model.name.autoReloadScriptDependencies.description=Enable auto reload if you want to load script configurations automatically on file change
kotlin.script.definitions.model.name.autoReloadScriptDependencies=Auto Reload kotlin.script.definitions.model.name.autoReloadScriptDependencies=Auto Reload
kotlin.script.definitions.model.name.is.enabled=Is Enabled kotlin.script.definitions.model.name.is.enabled=Is Enabled
+3
View File
@@ -19,6 +19,8 @@
<loader order="first" implementation="org.jetbrains.kotlin.idea.scripting.gradle.legacy.GradleLegacyScriptConfigurationLoader"/> <loader order="first" implementation="org.jetbrains.kotlin.idea.scripting.gradle.legacy.GradleLegacyScriptConfigurationLoader"/>
<scriptingSupport implementation="org.jetbrains.kotlin.idea.scripting.gradle.roots.GradleBuildRootsManager"/> <scriptingSupport implementation="org.jetbrains.kotlin.idea.scripting.gradle.roots.GradleBuildRootsManager"/>
<settings.provider implementation="org.jetbrains.kotlin.idea.scripting.gradle.settings.GradleSettingsProvider"/>
</extensions> </extensions>
<extensions defaultExtensionNs="org.jetbrains.plugins.gradle"> <extensions defaultExtensionNs="org.jetbrains.plugins.gradle">
@@ -48,6 +50,7 @@
restartRequired="false"/> restartRequired="false"/>
<projectService serviceImplementation="org.jetbrains.kotlin.idea.scripting.gradle.legacy.GradleStandaloneScriptActionsManager"/> <projectService serviceImplementation="org.jetbrains.kotlin.idea.scripting.gradle.legacy.GradleStandaloneScriptActionsManager"/>
<projectService serviceImplementation="org.jetbrains.kotlin.idea.scripting.gradle.settings.StandaloneScriptsStorage"/>
</extensions> </extensions>
<actions> <actions>
+2
View File
@@ -19,6 +19,8 @@
<loader order="first" implementation="org.jetbrains.kotlin.idea.scripting.gradle.legacy.GradleLegacyScriptConfigurationLoader"/> <loader order="first" implementation="org.jetbrains.kotlin.idea.scripting.gradle.legacy.GradleLegacyScriptConfigurationLoader"/>
<scriptingSupport implementation="org.jetbrains.kotlin.idea.scripting.gradle.roots.GradleBuildRootsManager"/> <scriptingSupport implementation="org.jetbrains.kotlin.idea.scripting.gradle.roots.GradleBuildRootsManager"/>
<settings.provider implementation="org.jetbrains.kotlin.idea.scripting.gradle.settings.GradleSettingsProvider"/>
</extensions> </extensions>
<extensions defaultExtensionNs="org.jetbrains.plugins.gradle"> <extensions defaultExtensionNs="org.jetbrains.plugins.gradle">
@@ -3,6 +3,10 @@
<extensionPoint qualifiedName="org.jetbrains.kotlin.scripting.idea.scriptingSupport" <extensionPoint qualifiedName="org.jetbrains.kotlin.scripting.idea.scriptingSupport"
interface="org.jetbrains.kotlin.idea.core.script.configuration.ScriptingSupport" interface="org.jetbrains.kotlin.idea.core.script.configuration.ScriptingSupport"
area="IDEA_PROJECT"/> area="IDEA_PROJECT"/>
<extensionPoint qualifiedName="org.jetbrains.kotlin.scripting.idea.settings.provider"
interface="org.jetbrains.kotlin.idea.script.configuration.ScriptingSupportSpecificSettingsProvider"
area="IDEA_PROJECT"/>
</extensionPoints> </extensionPoints>
<extensions defaultExtensionNs="com.intellij"> <extensions defaultExtensionNs="com.intellij">
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<form xmlns="http://www.intellij.com/uidesigner/form/" version="1" bind-to-class="org.jetbrains.kotlin.idea.script.configuration.KotlinScriptingSettingsConfigurable"> <form xmlns="http://www.intellij.com/uidesigner/form/" version="1" bind-to-class="org.jetbrains.kotlin.idea.script.configuration.KotlinScriptingSettingsConfigurable">
<grid id="27dc6" binding="root" layout-manager="GridLayoutManager" row-count="1" column-count="1" same-size-horizontally="false" same-size-vertically="false" hgap="-1" vgap="-1"> <grid id="27dc6" binding="root" layout-manager="GridLayoutManager" row-count="2" column-count="1" same-size-horizontally="false" same-size-vertically="false" hgap="-1" vgap="-1">
<margin top="0" left="0" bottom="0" right="0"/> <margin top="0" left="0" bottom="0" right="0"/>
<constraints> <constraints>
<xy x="20" y="20" width="565" height="510"/> <xy x="20" y="20" width="565" height="510"/>
@@ -8,56 +8,23 @@
<properties/> <properties/>
<border type="none"/> <border type="none"/>
<children> <children>
<grid id="6126a" layout-manager="GridLayoutManager" row-count="2" column-count="1" same-size-horizontally="false" same-size-vertically="false" hgap="-1" vgap="-1"> <grid id="b43cd" binding="panelScriptDefinitionsChooser" layout-manager="GridLayoutManager" row-count="1" column-count="1" same-size-horizontally="false" same-size-vertically="false" hgap="-1" vgap="-1">
<margin top="0" left="0" bottom="0" right="0"/> <margin top="0" left="0" bottom="0" right="0"/>
<constraints> <constraints>
<grid row="0" column="0" row-span="1" col-span="1" vsize-policy="7" hsize-policy="3" anchor="0" fill="3" indent="0" use-parent-layout="false"/> <grid row="0" column="0" row-span="1" col-span="1" vsize-policy="3" hsize-policy="3" anchor="0" fill="3" indent="0" use-parent-layout="false"/>
</constraints> </constraints>
<properties/> <properties/>
<border type="none"/> <border type="none"/>
<children> <children/>
<vspacer id="7a19"> </grid>
<constraints> <grid id="2c58d" binding="additionalSettingsPanel" layout-manager="GridLayoutManager" row-count="1" column-count="1" same-size-horizontally="false" same-size-vertically="false" hgap="-1" vgap="-1">
<grid row="1" column="0" row-span="1" col-span="1" vsize-policy="6" hsize-policy="1" anchor="0" fill="2" indent="0" use-parent-layout="false"/> <margin top="0" left="0" bottom="0" right="0"/>
</constraints> <constraints>
</vspacer> <grid row="1" column="0" row-span="1" col-span="1" vsize-policy="3" hsize-policy="3" anchor="0" fill="3" indent="0" use-parent-layout="false"/>
<grid id="b9ce9" layout-manager="GridLayoutManager" row-count="2" column-count="1" same-size-horizontally="false" same-size-vertically="false" hgap="-1" vgap="-1"> </constraints>
<margin top="0" left="0" bottom="0" right="0"/> <properties/>
<constraints> <border type="none"/>
<grid row="0" column="0" row-span="1" col-span="1" vsize-policy="3" hsize-policy="3" anchor="0" fill="3" indent="0" use-parent-layout="false"/> <children/>
</constraints>
<properties/>
<clientProperties>
<BorderFactoryClass class="java.lang.String" value="com.intellij.ui.IdeBorderFactory$PlainSmallWithoutIndent"/>
</clientProperties>
<border type="etched" title="Manage script definitions" noi18n="true"/>
<children>
<grid id="5ec35" binding="panelScriptDefinitionsChooser" layout-manager="GridLayoutManager" row-count="1" column-count="1" same-size-horizontally="false" same-size-vertically="false" hgap="-1" vgap="-1">
<margin top="0" left="0" bottom="0" right="0"/>
<constraints>
<grid row="1" column="0" row-span="1" col-span="1" vsize-policy="3" hsize-policy="3" anchor="0" fill="3" indent="0" use-parent-layout="false"/>
</constraints>
<properties/>
<border type="none"/>
<children>
<vspacer id="a58a1">
<constraints>
<grid row="0" column="0" row-span="1" col-span="1" vsize-policy="6" hsize-policy="1" anchor="0" fill="2" indent="0" use-parent-layout="false"/>
</constraints>
</vspacer>
</children>
</grid>
<component id="54c9d" class="javax.swing.JLabel">
<constraints>
<grid row="0" column="0" row-span="1" col-span="1" vsize-policy="0" hsize-policy="0" anchor="8" fill="0" indent="0" use-parent-layout="false"/>
</constraints>
<properties>
<text resource-bundle="messages/KotlinBundle" key="kotlin.script.definitions.model.name.autoReloadScriptDependencies.description"/>
</properties>
</component>
</children>
</grid>
</children>
</grid> </grid>
</children> </children>
</grid> </grid>
@@ -4,11 +4,15 @@
*/ */
package org.jetbrains.kotlin.idea.script.configuration; package org.jetbrains.kotlin.idea.script.configuration;
import com.intellij.openapi.options.Configurable; import com.intellij.openapi.options.ConfigurationException;
import com.intellij.openapi.options.SearchableConfigurable; import com.intellij.openapi.options.SearchableConfigurable;
import com.intellij.openapi.options.UnnamedConfigurable;
import com.intellij.openapi.project.Project; import com.intellij.openapi.project.Project;
import com.intellij.ui.TitledSeparator;
import com.intellij.ui.ToolbarDecorator; import com.intellij.ui.ToolbarDecorator;
import com.intellij.ui.components.panels.VerticalLayout;
import com.intellij.ui.table.TableView; import com.intellij.ui.table.TableView;
import com.intellij.util.ui.UIUtil;
import org.jetbrains.annotations.Nls; import org.jetbrains.annotations.Nls;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
@@ -18,30 +22,42 @@ import org.jetbrains.kotlin.idea.core.script.settings.KotlinScriptingSettings;
import org.jetbrains.kotlin.scripting.definitions.ScriptDefinition; import org.jetbrains.kotlin.scripting.definitions.ScriptDefinition;
import javax.swing.*; import javax.swing.*;
import java.awt.*; import java.util.ArrayList;
import java.util.List;
public class KotlinScriptingSettingsConfigurable implements SearchableConfigurable, Configurable.NoScroll { public class KotlinScriptingSettingsConfigurable implements SearchableConfigurable {
public static final String ID = "preferences.language.Kotlin.scripting"; public static final String ID = "preferences.language.Kotlin.scripting";
private JPanel root; private JPanel root;
private JPanel panelScriptDefinitionsChooser; private JPanel panelScriptDefinitionsChooser;
private JPanel additionalSettingsPanel;
private KotlinScriptDefinitionsModel model; private final List<UnnamedConfigurable> scriptingSuppportSettingsConfigurables = new ArrayList<>();
private final KotlinScriptDefinitionsModel model;
private final Project project;
private final ScriptDefinitionsManager manager; private final ScriptDefinitionsManager manager;
private final KotlinScriptingSettings settings; private final KotlinScriptingSettings settings;
public KotlinScriptingSettingsConfigurable(Project project) { public KotlinScriptingSettingsConfigurable(Project project) {
this.project = project;
manager = ScriptDefinitionsManager.Companion.getInstance(project); manager = ScriptDefinitionsManager.Companion.getInstance(project);
settings = KotlinScriptingSettings.Companion.getInstance(project); settings = KotlinScriptingSettings.Companion.getInstance(project);
model = KotlinScriptDefinitionsModel.Companion.createModel(manager.getAllDefinitions(), settings);
} }
@Nullable @Nullable
@Override @Override
public JComponent createComponent() { public JComponent createComponent() {
model = KotlinScriptDefinitionsModel.Companion.createModel(manager.getAllDefinitions(), settings); panelScriptDefinitionsChooser.setLayout(new VerticalLayout(0));
panelScriptDefinitionsChooser.add(new TitledSeparator(KotlinBundle.message("kotlin.script.definitions.title")));
JLabel commentLabel = new JLabel(KotlinBundle.message("kotlin.script.definitions.model.name.autoReloadScriptDependencies.description"));
commentLabel.setForeground(UIUtil.getContextHelpForeground());
panelScriptDefinitionsChooser.add(commentLabel);
panelScriptDefinitionsChooser.setLayout(new BorderLayout());
TableView<ModelDescriptor> table = new TableView<>(model); TableView<ModelDescriptor> table = new TableView<>(model);
panelScriptDefinitionsChooser.add( panelScriptDefinitionsChooser.add(
ToolbarDecorator.createDecorator(table) ToolbarDecorator.createDecorator(table)
@@ -49,18 +65,36 @@ public class KotlinScriptingSettingsConfigurable implements SearchableConfigurab
.disableRemoveAction() .disableRemoveAction()
.createPanel() .createPanel()
); );
table.setVisibleRowCount(12);
table.setVisibleRowCount(15); additionalSettingsPanel.setLayout(new VerticalLayout(0));
List<ScriptingSupportSpecificSettingsProvider> providers =
ScriptingSupportSpecificSettingsProvider.SETTINGS_PROVIDERS.getExtensionList(project);
for (ScriptingSupportSpecificSettingsProvider provider : providers) {
additionalSettingsPanel.add(new TitledSeparator(provider.getTitle()));
UnnamedConfigurable configurable = provider.createConfigurable();
scriptingSuppportSettingsConfigurables.add(configurable);
additionalSettingsPanel.add(configurable.createComponent());
}
return root; return root;
} }
@Override @Override
public boolean isModified() { public boolean isModified() {
for (UnnamedConfigurable supportSpecificSetting : scriptingSuppportSettingsConfigurables) {
if (supportSpecificSetting.isModified()) {
return true;
}
}
return isScriptDefinitionsChanged(); return isScriptDefinitionsChanged();
} }
@Override @Override
public void apply() { public void apply() throws ConfigurationException {
if (isScriptDefinitionsChanged()) { if (isScriptDefinitionsChanged()) {
for (ModelDescriptor item : model.getItems()) { for (ModelDescriptor item : model.getItems()) {
ScriptDefinition definition = item.getDefinition(); ScriptDefinition definition = item.getDefinition();
@@ -72,11 +106,18 @@ public class KotlinScriptingSettingsConfigurable implements SearchableConfigurab
manager.reorderScriptDefinitions(); manager.reorderScriptDefinitions();
} }
for (UnnamedConfigurable supportSpecificSetting : scriptingSuppportSettingsConfigurables) {
supportSpecificSetting.apply();
}
} }
@Override @Override
public void reset() { public void reset() {
model.setDefinitions(manager.getAllDefinitions(), settings); model.setDefinitions(manager.getAllDefinitions(), settings);
for (UnnamedConfigurable supportSpecificSetting : scriptingSuppportSettingsConfigurables) {
supportSpecificSetting.reset();
}
} }
private boolean isScriptDefinitionsChanged() { private boolean isScriptDefinitionsChanged() {
@@ -4,11 +4,15 @@
*/ */
package org.jetbrains.kotlin.idea.script.configuration; package org.jetbrains.kotlin.idea.script.configuration;
import com.intellij.openapi.options.Configurable; import com.intellij.openapi.options.ConfigurationException;
import com.intellij.openapi.options.SearchableConfigurable; import com.intellij.openapi.options.SearchableConfigurable;
import com.intellij.openapi.options.UnnamedConfigurable;
import com.intellij.openapi.project.Project; import com.intellij.openapi.project.Project;
import com.intellij.ui.TitledSeparator;
import com.intellij.ui.ToolbarDecorator; import com.intellij.ui.ToolbarDecorator;
import com.intellij.ui.components.panels.VerticalLayout;
import com.intellij.ui.table.TableView; import com.intellij.ui.table.TableView;
import com.intellij.util.ui.UIUtil;
import org.jetbrains.annotations.Nls; import org.jetbrains.annotations.Nls;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
@@ -18,30 +22,42 @@ import org.jetbrains.kotlin.idea.core.script.settings.KotlinScriptingSettings;
import org.jetbrains.kotlin.scripting.definitions.ScriptDefinition; import org.jetbrains.kotlin.scripting.definitions.ScriptDefinition;
import javax.swing.*; import javax.swing.*;
import java.awt.*; import java.util.ArrayList;
import java.util.List;
public class KotlinScriptingSettingsConfigurable implements SearchableConfigurable, Configurable.NoScroll { public class KotlinScriptingSettingsConfigurable implements SearchableConfigurable {
public static final String ID = "preferences.language.Kotlin.scripting"; public static final String ID = "preferences.language.Kotlin.scripting";
private JPanel root; private JPanel root;
private JPanel panelScriptDefinitionsChooser; private JPanel panelScriptDefinitionsChooser;
private JPanel additionalSettingsPanel;
private KotlinScriptDefinitionsModel model; private final List<UnnamedConfigurable> scriptingSuppportSettingsConfigurables = new ArrayList<>();
private final KotlinScriptDefinitionsModel model;
private final Project project;
private final ScriptDefinitionsManager manager; private final ScriptDefinitionsManager manager;
private final KotlinScriptingSettings settings; private final KotlinScriptingSettings settings;
public KotlinScriptingSettingsConfigurable(Project project) { public KotlinScriptingSettingsConfigurable(Project project) {
this.project = project;
manager = ScriptDefinitionsManager.Companion.getInstance(project); manager = ScriptDefinitionsManager.Companion.getInstance(project);
settings = KotlinScriptingSettings.Companion.getInstance(project); settings = KotlinScriptingSettings.Companion.getInstance(project);
model = KotlinScriptDefinitionsModel.Companion.createModel(manager.getAllDefinitions(), settings);
} }
@Nullable @Nullable
@Override @Override
public JComponent createComponent() { public JComponent createComponent() {
model = KotlinScriptDefinitionsModel.Companion.createModel(manager.getAllDefinitions(), settings); panelScriptDefinitionsChooser.setLayout(new VerticalLayout(0));
panelScriptDefinitionsChooser.add(new TitledSeparator(KotlinBundle.message("kotlin.script.definitions.title")));
JLabel commentLabel = new JLabel(KotlinBundle.message("kotlin.script.definitions.model.name.autoReloadScriptDependencies.description"));
commentLabel.setForeground(UIUtil.getContextHelpForeground());
panelScriptDefinitionsChooser.add(commentLabel);
panelScriptDefinitionsChooser.setLayout(new BorderLayout());
TableView<ModelDescriptor> table = new TableView<>(model); TableView<ModelDescriptor> table = new TableView<>(model);
panelScriptDefinitionsChooser.add( panelScriptDefinitionsChooser.add(
ToolbarDecorator.createDecorator(table) ToolbarDecorator.createDecorator(table)
@@ -50,16 +66,34 @@ public class KotlinScriptingSettingsConfigurable implements SearchableConfigurab
.createPanel() .createPanel()
); );
additionalSettingsPanel.setLayout(new VerticalLayout(0));
List<ScriptingSupportSpecificSettingsProvider> providers =
ScriptingSupportSpecificSettingsProvider.SETTINGS_PROVIDERS.getExtensionList(project);
for (ScriptingSupportSpecificSettingsProvider provider : providers) {
additionalSettingsPanel.add(new TitledSeparator(provider.getTitle()));
UnnamedConfigurable configurable = provider.createConfigurable();
scriptingSuppportSettingsConfigurables.add(configurable);
additionalSettingsPanel.add(configurable.createComponent());
}
return root; return root;
} }
@Override @Override
public boolean isModified() { public boolean isModified() {
for (UnnamedConfigurable supportSpecificSetting : scriptingSuppportSettingsConfigurables) {
if (supportSpecificSetting.isModified()) {
return true;
}
}
return isScriptDefinitionsChanged(); return isScriptDefinitionsChanged();
} }
@Override @Override
public void apply() { public void apply() throws ConfigurationException {
if (isScriptDefinitionsChanged()) { if (isScriptDefinitionsChanged()) {
for (ModelDescriptor item : model.getItems()) { for (ModelDescriptor item : model.getItems()) {
ScriptDefinition definition = item.getDefinition(); ScriptDefinition definition = item.getDefinition();
@@ -71,11 +105,18 @@ public class KotlinScriptingSettingsConfigurable implements SearchableConfigurab
manager.reorderScriptDefinitions(); manager.reorderScriptDefinitions();
} }
for (UnnamedConfigurable supportSpecificSetting : scriptingSuppportSettingsConfigurables) {
supportSpecificSetting.apply();
}
} }
@Override @Override
public void reset() { public void reset() {
model.setDefinitions(manager.getAllDefinitions(), settings); model.setDefinitions(manager.getAllDefinitions(), settings);
for (UnnamedConfigurable supportSpecificSetting : scriptingSuppportSettingsConfigurables) {
supportSpecificSetting.reset();
}
} }
private boolean isScriptDefinitionsChanged() { private boolean isScriptDefinitionsChanged() {
@@ -0,0 +1,23 @@
/*
* Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.idea.script.configuration
import com.intellij.openapi.extensions.ExtensionPointName
import com.intellij.openapi.options.UnnamedConfigurable
abstract class ScriptingSupportSpecificSettingsProvider {
abstract val title: String
abstract fun createConfigurable(): UnnamedConfigurable
companion object {
@JvmField
val SETTINGS_PROVIDERS: ExtensionPointName<ScriptingSupportSpecificSettingsProvider> =
ExtensionPointName.create("org.jetbrains.kotlin.scripting.idea.settings.provider")
}
}