Skip to content

Commit a4473b5

Browse files
authored
Refactor dynamic resources configurable so state is managed more safely (#2887)
1 parent 6ef0a59 commit a4473b5

File tree

1 file changed

+45
-69
lines changed

1 file changed

+45
-69
lines changed

jetbrains-core/src/software/aws/toolkits/jetbrains/settings/DynamicResourcesConfigurable.kt

Lines changed: 45 additions & 69 deletions
Original file line numberDiff line numberDiff line change
@@ -4,38 +4,35 @@
44
package software.aws.toolkits.jetbrains.settings
55

66
import com.intellij.openapi.application.ApplicationManager
7+
import com.intellij.openapi.application.ModalityState
8+
import com.intellij.openapi.application.runInEdt
79
import com.intellij.openapi.options.BoundConfigurable
810
import com.intellij.openapi.project.ProjectManager
911
import com.intellij.ui.CheckBoxList
1012
import com.intellij.ui.FilterComponent
1113
import com.intellij.ui.ListSpeedSearch
1214
import com.intellij.ui.layout.panel
15+
import software.aws.toolkits.core.utils.replace
1316
import software.aws.toolkits.jetbrains.core.explorer.ExplorerToolWindow
1417
import software.aws.toolkits.jetbrains.services.dynamic.DynamicResourceSupportedTypes
1518
import software.aws.toolkits.jetbrains.services.dynamic.explorer.OtherResourcesNode
1619
import software.aws.toolkits.resources.message
17-
import javax.swing.DefaultListModel
18-
import javax.swing.JCheckBox
1920
import javax.swing.ListSelectionModel
2021

2122
class DynamicResourcesConfigurable : BoundConfigurable(message("aws.settings.dynamic_resources_configurable.title")) {
2223

23-
private val checklistModel = DefaultListModel<JCheckBox>()
24-
private val checklist = CheckBoxList<String>(checklistModel)
25-
private val changeSet = mutableSetOf<Int>()
26-
private val checkboxListener = { idx: Int ->
27-
if (idx in changeSet) {
28-
changeSet.remove(idx)
29-
} else {
30-
changeSet.add(idx)
24+
private val checklist = CheckBoxList<String>()
25+
private val allResources = mutableSetOf<String>()
26+
private val selected = mutableSetOf<String>()
27+
private val filter = object : FilterComponent("filter", 5) {
28+
override fun filter() {
29+
updateCheckboxList()
3130
}
3231
}
3332

3433
init {
3534
checklist.selectionMode = ListSelectionModel.MULTIPLE_INTERVAL_SELECTION
36-
checklist.setCheckBoxListListener { idx, _ ->
37-
checkboxListener(idx)
38-
}
35+
checklist.setCheckBoxListListener(::checkboxStateHandler)
3936

4037
ListSpeedSearch(checklist) {
4138
it.text.substringAfter("::")
@@ -45,52 +42,27 @@ class DynamicResourcesConfigurable : BoundConfigurable(message("aws.settings.dyn
4542
override fun getPreferredFocusedComponent() = checklist
4643

4744
override fun createPanel() = panel {
48-
val allCheckboxes = mutableListOf<JCheckBox>()
49-
val selected = DynamicResourcesSettings.getInstance().selected
50-
45+
selected.replace(DynamicResourcesSettings.getInstance().selected)
5146
ApplicationManager.getApplication().executeOnPooledThread {
52-
DynamicResourceSupportedTypes.getInstance().getSupportedTypes().forEach {
53-
checklist.addItem(it, it, it in selected)
47+
allResources.addAll(DynamicResourceSupportedTypes.getInstance().getSupportedTypes())
48+
runInEdt(ModalityState.any()) {
49+
updateCheckboxList()
5450
}
55-
allCheckboxes.addAll(checklist.map { _, checkbox -> checkbox })
5651
}
5752

53+
row { filter(growX) }
5854
row {
59-
// filter
60-
val field = object : FilterComponent("filter", 5) {
61-
override fun filter() {
62-
checklistModel.clear()
63-
checklistModel.addAll(allCheckboxes.filter { it.text.contains(filter, ignoreCase = true) })
64-
}
65-
}
66-
field(growX)
67-
}
68-
69-
row {
70-
// scrollpane
7155
scrollPane(checklist)
7256
.constraints(growX, pushX)
73-
.onIsModified {
74-
// returns true if there is a change
75-
changeSet.size != 0
76-
}
57+
.onIsModified { selected != DynamicResourcesSettings.getInstance().selected }
7758
.onApply {
78-
changeSet.clear()
79-
80-
DynamicResourcesSettings.getInstance().selected = allCheckboxes.filter { it.isSelected }.map { it.text }.toSet()
81-
ProjectManager.getInstance().openProjects.forEach { project ->
82-
if (!project.isDisposed) {
83-
val toolWindow = ExplorerToolWindow.getInstance(project)
84-
toolWindow.findNode(OtherResourcesNode::class).then { node ->
85-
node?.let {
86-
toolWindow.invalidateTree(it)
87-
}
88-
}
89-
}
90-
}
59+
DynamicResourcesSettings.getInstance().selected = selected
60+
refreshAwsExplorer()
61+
}
62+
.onReset {
63+
selected.replace(DynamicResourcesSettings.getInstance().selected)
64+
updateCheckboxList()
9165
}
92-
93-
// select/clearall
9466
right {
9567
cell(isVerticalFlow = true) {
9668
val sizeGroup = "buttons"
@@ -107,33 +79,37 @@ class DynamicResourcesConfigurable : BoundConfigurable(message("aws.settings.dyn
10779
}
10880

10981
private fun CheckBoxList<*>.toggleAll(state: Boolean) {
110-
this.forEachIndexed { index, checkbox ->
111-
checkbox.isSelected = state
112-
checkboxListener(index)
82+
(0 until model.size).forEach { idx ->
83+
checkboxStateHandler(idx, state)
11384
}
114-
this.repaint()
85+
updateCheckboxList()
11586
}
11687

117-
private companion object {
118-
fun <T> CheckBoxList<*>.map(fn: (Int, JCheckBox) -> T): List<T> {
119-
val size = this.model.size - 1
88+
private fun updateCheckboxList() {
89+
checklist.clear()
90+
allResources.filter { it.contains(filter.filter, ignoreCase = true) }.sorted().forEach { checklist.addItem(it, it, it in selected) }
91+
}
12092

121-
return (0..size).map {
122-
fn(it, this.model.getElementAt(it))
93+
private fun checkboxStateHandler(idx: Int, state: Boolean) {
94+
checklist.getItemAt(idx)?.let { value ->
95+
if (state) {
96+
selected.add(value)
97+
} else {
98+
selected.remove(value)
12399
}
124100
}
101+
}
125102

126-
fun CheckBoxList<*>.filter(fn: (JCheckBox) -> Boolean): List<JCheckBox> =
127-
this.map { _, it ->
128-
if (fn(it)) {
129-
it
130-
} else {
131-
null
103+
private fun refreshAwsExplorer() {
104+
ProjectManager.getInstance().openProjects.forEach { project ->
105+
if (!project.isDisposed) {
106+
val toolWindow = ExplorerToolWindow.getInstance(project)
107+
toolWindow.findNode(OtherResourcesNode::class).then { node ->
108+
node.let {
109+
toolWindow.invalidateTree(it)
110+
}
132111
}
133-
}.filterNotNull()
134-
135-
fun CheckBoxList<*>.forEachIndexed(fn: (Int, JCheckBox) -> Unit) {
136-
this.map(fn)
112+
}
137113
}
138114
}
139115
}

0 commit comments

Comments
 (0)