@@ -4,6 +4,7 @@ import com.intellij.openapi.Disposable
4
4
import com.intellij.packageDependencies.ui.TreeModel
5
5
import com.intellij.ui.*
6
6
import com.intellij.ui.CheckboxTree.CheckboxTreeCellRenderer
7
+ import com.intellij.util.ui.JBUI
7
8
import org.tabooproject.development.step.ConfigurationPropertiesStep
8
9
import org.tabooproject.development.step.Module
9
10
import javax.swing.JScrollPane
@@ -38,35 +39,63 @@ class CheckModuleList : JScrollPane(), Disposable {
38
39
if (value.userObject is Module ) {
39
40
val module = value.userObject as Module
40
41
42
+ // 模块名称 - 使用更突出的颜色和字体
41
43
textRenderer.append(
42
44
ColoredText .singleFragment(
43
45
module.name, SimpleTextAttributes (
44
46
SimpleTextAttributes .STYLE_BOLD ,
45
- JBColor .BLACK
47
+ if (selected) JBColor .WHITE else JBColor ( 0x2D5AA0 , 0x4A9EFF ) // 蓝色主题
46
48
)
47
49
)
48
50
)
49
51
50
- textRenderer.append(" " )
52
+ // 添加合适的间距
53
+ textRenderer.append(" " )
51
54
55
+ // 模块描述 - 使用更柔和的灰色
56
+ val description = module.desc?.let {
57
+ if (it.length > 50 ) " ${it.take(50 )} ..." else it
58
+ } ? : " No description"
59
+
52
60
textRenderer.append(
53
61
ColoredText .singleFragment(
54
- module.desc ? : module.name , SimpleTextAttributes (
55
- SimpleTextAttributes .STYLE_PLAIN ,
56
- JBColor .GRAY
62
+ description , SimpleTextAttributes (
63
+ SimpleTextAttributes .STYLE_ITALIC ,
64
+ if (selected) JBColor . LIGHT_GRAY else JBColor .GRAY
57
65
)
58
66
)
59
67
)
60
68
}
61
69
} else if (value is DefaultMutableTreeNode ) {
62
- textRenderer.append(value.userObject.toString())
70
+ // 分类标题 - 使用更突出的样式
71
+ textRenderer.append(
72
+ ColoredText .singleFragment(
73
+ value.userObject.toString(), SimpleTextAttributes (
74
+ SimpleTextAttributes .STYLE_BOLD ,
75
+ if (selected) JBColor .WHITE else JBColor (0x1A472A , 0x5FB865 ) // 绿色分类标题
76
+ )
77
+ )
78
+ )
63
79
}
64
80
}
65
81
}, root)
66
82
67
83
init {
68
84
checkBoxList.model = treeNode
69
85
checkBoxList.isFocusable = false
86
+
87
+ // 设置树的行高和样式
88
+ checkBoxList.rowHeight = 24 // 增加行高让内容更易读
89
+ checkBoxList.isRootVisible = false // 隐藏根节点
90
+ checkBoxList.showsRootHandles = true // 显示展开/折叠句柄
91
+
92
+ // 默认展开所有分类节点
93
+ javax.swing.SwingUtilities .invokeLater {
94
+ for (i in 0 until checkBoxList.rowCount) {
95
+ checkBoxList.expandRow(i)
96
+ }
97
+ }
98
+
70
99
checkBoxList.addCheckboxTreeListener(object : CheckboxTreeListener {
71
100
override fun nodeStateChanged (node : CheckedTreeNode ) {
72
101
if (node.userObject !is Module ) return
@@ -79,9 +108,35 @@ class CheckModuleList : JScrollPane(), Disposable {
79
108
onModuleSelectionChanged?.invoke(export())
80
109
}
81
110
})
111
+
112
+ // 添加双击监听器用于展开/收起分类节点
113
+ checkBoxList.addMouseListener(object : java.awt.event.MouseAdapter () {
114
+ override fun mouseClicked (e : java.awt.event.MouseEvent ? ) {
115
+ if (e?.clickCount == 2 ) {
116
+ val path = checkBoxList.getPathForLocation(e.x, e.y)
117
+ if (path != null ) {
118
+ val node = path.lastPathComponent
119
+ if (node is DefaultMutableTreeNode && node.userObject !is Module ) {
120
+ // 这是一个分类节点,切换展开/收起状态
121
+ if (checkBoxList.isExpanded(path)) {
122
+ checkBoxList.collapsePath(path)
123
+ } else {
124
+ checkBoxList.expandPath(path)
125
+ }
126
+ }
127
+ }
128
+ }
129
+ }
130
+ })
131
+
82
132
setFocusable(false )
83
133
autoscrolls = true
84
134
setViewportView(checkBoxList)
135
+
136
+ // 设置滚动条样式
137
+ verticalScrollBarPolicy = VERTICAL_SCROLLBAR_AS_NEEDED
138
+ horizontalScrollBarPolicy = HORIZONTAL_SCROLLBAR_AS_NEEDED
139
+ border = JBUI .Borders .empty()
85
140
86
141
updateUI()
87
142
}
@@ -90,36 +145,69 @@ class CheckModuleList : JScrollPane(), Disposable {
90
145
* 设置模块数据
91
146
*/
92
147
fun setModules (modules : Map <String , List <Module >>) {
148
+ println (" CheckModuleList.setModules 被调用,收到 ${modules.size} 个分类" )
149
+ modules.forEach { (category, moduleList) ->
150
+ println (" 分类 '$category ': ${moduleList.size} 个模块" )
151
+ }
152
+
93
153
root.removeAllChildren()
94
- modules.map {
95
- DefaultMutableTreeNode (it.key).apply {
96
- it.value.forEach {
97
- add(CheckedTreeNode (it).apply {
98
- isChecked = false
99
- isFocusable = false
100
- })
101
- }
154
+
155
+ // 按分类名称排序,确保一致的显示顺序
156
+ val sortedModules = modules.toSortedMap()
157
+
158
+ sortedModules.forEach { (categoryName, moduleList) ->
159
+ val categoryNode = DefaultMutableTreeNode (categoryName).apply {
102
160
isFocusable = false
103
161
}
104
- }.forEach {
105
- root.add(it)
162
+
163
+ // 按模块名称排序
164
+ moduleList.sortedBy { it.name }.forEach { module ->
165
+ val moduleNode = CheckedTreeNode (module).apply {
166
+ isChecked = false
167
+ isFocusable = false
168
+ }
169
+ categoryNode.add(moduleNode)
170
+ }
171
+
172
+ root.add(categoryNode)
106
173
}
107
174
175
+ // 强制重新构建树模型
176
+ treeNode?.reload()
108
177
updateUI()
178
+
179
+ // 在EDT中展开所有分类节点以提供更好的用户体验
180
+ javax.swing.SwingUtilities .invokeLater {
181
+ for (i in 0 until checkBoxList.rowCount) {
182
+ checkBoxList.expandRow(i)
183
+ }
184
+ println (" CheckModuleList 展开了 ${checkBoxList.rowCount} 行" )
185
+ }
109
186
}
110
187
111
188
/* *
112
189
* 批量设置模块选中状态
113
190
*/
114
191
fun setSelectedModules (moduleIds : List <String >) {
115
- // 先清除所有选择
192
+ println (" CheckModuleList.setSelectedModules: 设置选中模块 ${moduleIds} " )
193
+
194
+ // 先清空ConfigurationPropertiesStep中的模块列表
195
+ ConfigurationPropertiesStep .property.modules.clear()
196
+
197
+ // 清除所有选择
116
198
clearAllSelections(root)
117
199
118
200
// 然后设置指定的模块为选中
119
201
moduleIds.forEach { moduleId ->
120
202
findAndSetModuleSelection(root, moduleId, true )
121
203
}
204
+
205
+ // 强制刷新UI
122
206
treeNode?.reload()
207
+ checkBoxList.repaint()
208
+ checkBoxList.updateUI()
209
+
210
+ println (" CheckModuleList.setSelectedModules: 完成后实际选中模块数量 ${export().size} " )
123
211
124
212
// 通知选择变更
125
213
onModuleSelectionChanged?.invoke(export())
@@ -157,12 +245,40 @@ class CheckModuleList : JScrollPane(), Disposable {
157
245
*/
158
246
private fun clearAllSelections (node : CheckedTreeNode ) {
159
247
node.isChecked = false
248
+ // 递归处理所有子节点
160
249
for (i in 0 until node.childCount) {
161
- val child = node.getChildAt(i) as ? CheckedTreeNode ? : continue
162
- clearAllSelections(child)
250
+ val child = node.getChildAt(i) as ? DefaultMutableTreeNode ? : continue
251
+ // 如果是分类节点,继续递归处理其模块节点
252
+ for (j in 0 until child.childCount) {
253
+ val moduleNode = child.getChildAt(j) as ? CheckedTreeNode ? : continue
254
+ moduleNode.isChecked = false
255
+ // 从配置中移除该模块
256
+ if (moduleNode.userObject is Module ) {
257
+ ConfigurationPropertiesStep .property.modules.remove(moduleNode.userObject as Module )
258
+ }
259
+ }
163
260
}
164
261
}
165
262
263
+ /* *
264
+ * 取消选中单个模块
265
+ */
266
+ fun unselectModule (moduleId : String ) {
267
+ println (" CheckModuleList.unselectModule: 取消选中模块 ${moduleId} " )
268
+
269
+ // 查找并取消选中指定模块
270
+ findAndSetModuleSelection(root, moduleId, false )
271
+
272
+ // 刷新UI
273
+ treeNode?.reload()
274
+ checkBoxList.repaint()
275
+
276
+ println (" CheckModuleList.unselectModule: 完成后实际选中模块数量 ${export().size} " )
277
+
278
+ // 通知选择变更
279
+ onModuleSelectionChanged?.invoke(export())
280
+ }
281
+
166
282
/* *
167
283
* 导出当前选中的模块
168
284
*/
0 commit comments