diff --git a/build.gradle.kts b/build.gradle.kts
index f036437..340de4b 100644
--- a/build.gradle.kts
+++ b/build.gradle.kts
@@ -6,7 +6,7 @@ plugins {
}
group = "com.prepeep"
-version = "1.0.0-SNAPSHOT"
+version = "1.0.0"
repositories {
mavenCentral()
diff --git a/src/main/kotlin/com/harmness/toolwindow/HarmnessBrowserConfigurablePanel.kt b/src/main/kotlin/com/harmness/toolwindow/HarmnessBrowserConfigurablePanel.kt
deleted file mode 100644
index dffd0e0..0000000
--- a/src/main/kotlin/com/harmness/toolwindow/HarmnessBrowserConfigurablePanel.kt
+++ /dev/null
@@ -1,45 +0,0 @@
-package com.harmness.toolwindow
-
-import com.intellij.openapi.diagnostic.Logger
-import com.intellij.ui.components.JBLabel
-import com.intellij.ui.components.JBTextField
-import com.intellij.util.ui.FormBuilder
-import com.intellij.util.ui.UIUtil
-import javax.swing.JComponent
-import javax.swing.JPanel
-
-/**
- * 设置面板 UI:编辑「起始地址」并即时生效。
- */
-class HarmnessBrowserConfigurablePanel {
-
- private val urlField = JBTextField()
-
- val panel: JPanel = FormBuilder.createFormBuilder()
- .addLabeledComponent("Start URL", urlField, 1, false)
- .addComponentFillVertically(JBLabel(
- "Embedded browser will open this URL when the tool window is shown.
" +
- "The target site must allow embedding (no strict X-Frame-Options / CSP frame-ancestors).
" +
- "e.g. http://127.0.0.1:8888", UIUtil.ComponentStyle.SMALL, UIUtil.FontColor.NORMAL), 1)
- .panel
-
- init {
- urlField.columns = 40
- urlField.emptyText.text = "http://127.0.0.1:8888"
- }
-
- fun isModified(settings: SettingsState): Boolean =
- urlField.text != settings.startUrl
-
- fun apply(settings: SettingsState) {
- settings.startUrl = urlField.text.trim()
- }
-
- fun reset(settings: SettingsState) {
- urlField.text = settings.startUrl
- }
-
- companion object {
- private val LOG = Logger.getInstance(HarmnessBrowserConfigurablePanel::class.java)
- }
-}
\ No newline at end of file
diff --git a/src/main/kotlin/com/harmness/toolwindow/HarmnessBrowserPanel.kt b/src/main/kotlin/com/harmness/toolwindow/HarmnessBrowserPanel.kt
index 1737f19..c41f7f2 100644
--- a/src/main/kotlin/com/harmness/toolwindow/HarmnessBrowserPanel.kt
+++ b/src/main/kotlin/com/harmness/toolwindow/HarmnessBrowserPanel.kt
@@ -18,24 +18,19 @@ import java.awt.Desktop
import java.awt.FlowLayout
import java.awt.event.ActionEvent
import javax.swing.AbstractAction
+import javax.swing.BorderFactory
import javax.swing.JButton
import javax.swing.JComponent
import javax.swing.JPanel
import javax.swing.JTextField
+import javax.swing.SwingUtilities
/**
* 嵌入浏览器面板。
*
- * 职责:
- * - 使用 JBCefBrowser 渲染用户配置的起始地址(例如本地 Harness 地址)
- * - 工具栏:地址栏、前进/后退、刷新、设置入口(快捷跳转到 IDE Settings 的插件配置页)
- * - 通过 [JBCefJSQuery] 提供 JS ↔ 插件代码双向桥
- * - 拦截并处理 _blank 弹窗(默认吞掉,可选交给系统浏览器)
- *
- * 由于 IntelliJ Platform 官方插件模型目前不允许在 JCEF 浏览器内部直接调用
- * "打开当前项目文件" 之类的 API(无 DOM 访问权限),插件通过注入到页面中的
- * 桥接函数 [JS_BRIDGE_NAME] 让网页(如 Harness 前端)发起请求,
- * 再由本类把结果返回给页面。
+ * 两种视图模式,通过右上角「⚙」图标切换:
+ * - [Mode.BROWSER]:显示配置好的网页(JCEF)
+ * - [Mode.SETTINGS]:表单,可修改「起始地址」,点保存后自动切回浏览器并加载新地址
*/
class HarmnessBrowserPanel(
private val project: com.intellij.openapi.project.Project,
@@ -49,6 +44,10 @@ class HarmnessBrowserPanel(
private lateinit var query: JBCefJSQuery
private val loadEnded = java.util.concurrent.atomic.AtomicBoolean(false)
+ private var mode = Mode.BROWSER
+
+ private enum class Mode { BROWSER, SETTINGS }
+
init {
Disposer.register(parentDisposable, this)
@@ -59,21 +58,39 @@ class HarmnessBrowserPanel(
BorderLayout.CENTER)
} else {
browser = JBCefBrowser()
-
- // 布局:顶部工具栏 + 浏览器
- add(createToolbar(), BorderLayout.NORTH)
- add(browser.component, BorderLayout.CENTER)
-
- // 设置弹窗处理
setupPopupHandling()
- // 设置 JS 桥
setupBridge()
- // 初始加载
- loadCurrentUrl()
+ // 顶部工具栏(右上角 ⚙)
+ add(createToolbar(), BorderLayout.NORTH)
+ // 初始为浏览器视图
+ showBrowserMode()
}
}
+ // ------------------------------------------------------------------
+ // 视图切换
+ // ------------------------------------------------------------------
+
+ private fun showBrowserMode() {
+ mode = Mode.BROWSER
+ removeAll()
+ add(createToolbar(), BorderLayout.NORTH)
+ add(browser.component, BorderLayout.CENTER)
+ revalidate()
+ repaint()
+ loadCurrentUrl()
+ }
+
+ private fun showSettingsMode() {
+ mode = Mode.SETTINGS
+ removeAll()
+ add(createToolbar(), BorderLayout.NORTH)
+ add(createSettingsForm(), BorderLayout.CENTER)
+ revalidate()
+ repaint()
+ }
+
// ------------------------------------------------------------------
// 工具栏
// ------------------------------------------------------------------
@@ -94,12 +111,13 @@ class HarmnessBrowserPanel(
val reload = JButton(object : AbstractAction("⟳") {
override fun actionPerformed(e: ActionEvent) { cefBrowser.reload() }
})
+
+ // 右上角:设置图标(⚙),点击在两种模式间切换
val settingsBtn = JButton(object : AbstractAction("⚙") {
- override fun actionPerformed(e: ActionEvent) { openSettings() }
- })
- val externalBtn = JButton(object : AbstractAction("⧉") {
- override fun actionPerformed(e: ActionEvent) { openInExternalBrowser() }
+ override fun actionPerformed(e: ActionEvent) { toggleSettings() }
})
+ settingsBtn.toolTipText = if (mode == Mode.BROWSER) "设置" else "返回主界面"
+ settingsBtn.border = BorderFactory.createEmptyBorder(2, 6, 2, 6)
addressField = JTextField(settings.startUrl)
addressField.toolTipText = "当前页面地址(可手动输入后回车跳转)"
@@ -111,35 +129,81 @@ class HarmnessBrowserPanel(
toolbar.add(reload)
toolbar.add(addressField)
toolbar.add(settingsBtn)
- toolbar.add(externalBtn)
return toolbar
}
+ private fun toggleSettings() {
+ if (mode == Mode.BROWSER) {
+ showSettingsMode()
+ } else {
+ // 从设置页切回主界面时重新加载
+ showBrowserMode()
+ }
+ }
+
private fun navigate(url: String) {
val fixedUrl = if (url.startsWith("http://") || url.startsWith("https://")) url else "http://$url"
browser.loadURL(fixedUrl)
+ loadEnded.set(false)
}
- private fun openSettings() {
- val app = com.intellij.openapi.application.ApplicationManager.getApplication()
- val show = Runnable {
- com.intellij.openapi.options.ShowSettingsUtil.getInstance()
- .showSettingsDialog(project, "Harmness Browser")
- }
- if (app.isDispatchThread) show.run() else app.invokeLater(show)
- }
+ // ------------------------------------------------------------------
+ // 设置表单
+ // ------------------------------------------------------------------
- private fun openInExternalBrowser() {
- val url = addressField.text.ifBlank { settings.startUrl }
- if (Desktop.isDesktopSupported()) {
- try {
- Desktop.getDesktop().browse(java.net.URI(url))
- } catch (e: Exception) {
- BrowserUtil.browse(url)
+ private fun createSettingsForm(): JComponent {
+ val panel = JBPanel>()
+ panel.layout = java.awt.GridBagLayout()
+ val gbc = java.awt.GridBagConstraints()
+ gbc.insets = java.awt.Insets(6, 8, 6, 8)
+ gbc.fill = java.awt.GridBagConstraints.HORIZONTAL
+ gbc.anchor = java.awt.GridBagConstraints.NORTH
+
+ val title = JBLabel("Settings
")
+ gbc.gridx = 0; gbc.gridy = 0; gbc.gridwidth = 2
+ panel.add(title, gbc)
+ gbc.gridwidth = 1
+
+ val label = JBLabel("起始地址 (Start URL):")
+ gbc.gridx = 0; gbc.gridy = 1
+ panel.add(label, gbc)
+
+ val urlField = JTextField(settings.startUrl, 30)
+ gbc.gridx = 1; gbc.gridy = 1
+ panel.add(urlField, gbc)
+
+ val hint = JBLabel("例如:http://127.0.0.1:8899 (本地 Harness 服务地址)")
+ gbc.gridx = 0; gbc.gridy = 2; gbc.gridwidth = 2
+ panel.add(hint, gbc)
+ gbc.gridwidth = 1
+
+ val saveBtn = JButton("保存")
+ saveBtn.addActionListener {
+ settings.startUrl = urlField.text.trim()
+ saveBtn.text = "已保存 ✓"
+ SwingUtilities.invokeLater {
+ Thread.sleep(400)
+ saveBtn.text = "保存"
}
- } else {
- BrowserUtil.browse(url)
+ showBrowserMode()
}
+
+ val cancelBtn = JButton("取消")
+ cancelBtn.addActionListener {
+ showBrowserMode()
+ }
+
+ val btnPanel = JPanel(FlowLayout(FlowLayout.LEFT, 8, 0))
+ btnPanel.add(saveBtn)
+ btnPanel.add(cancelBtn)
+ gbc.gridx = 0; gbc.gridy = 3; gbc.gridwidth = 2
+ panel.add(btnPanel, gbc)
+
+ gbc.gridy = 4
+ gbc.weighty = 1.0
+ panel.add(JBPanel>(), gbc)
+
+ return panel
}
// ------------------------------------------------------------------
@@ -224,10 +288,6 @@ class HarmnessBrowserPanel(
loadEnded.set(false)
}
- fun reloadFromSettings() {
- loadCurrentUrl()
- }
-
override fun dispose() {
loadEnded.set(false)
if (::query.isInitialized) {
diff --git a/src/main/kotlin/com/harmness/toolwindow/HarmnessSettingsConfigurable.kt b/src/main/kotlin/com/harmness/toolwindow/HarmnessSettingsConfigurable.kt
deleted file mode 100644
index b3fa402..0000000
--- a/src/main/kotlin/com/harmness/toolwindow/HarmnessSettingsConfigurable.kt
+++ /dev/null
@@ -1,36 +0,0 @@
-package com.harmness.toolwindow
-
-import com.intellij.openapi.options.Configurable
-import javax.swing.JComponent
-
-/**
- * Settings configurable registered in plugin.xml.
- * Shows the HarmnessBrowserConfigurablePanel under Tools → Harmness Browser.
- */
-class HarmnessSettingsConfigurable : Configurable {
-
- private var panel: HarmnessBrowserConfigurablePanel? = null
-
- override fun getDisplayName(): String = "Harmness Browser"
-
- override fun getHelpTopic(): String? = null
-
- override fun createComponent(): JComponent {
- panel = HarmnessBrowserConfigurablePanel()
- return panel!!.panel
- }
-
- override fun isModified(): Boolean = panel?.isModified(SettingsState.getInstance()) ?: false
-
- override fun apply() {
- panel?.apply(SettingsState.getInstance())
- }
-
- override fun reset() {
- panel?.reset(SettingsState.getInstance())
- }
-
- override fun disposeUIResources() {
- panel = null
- }
-}
\ No newline at end of file
diff --git a/src/main/kotlin/com/harmness/toolwindow/SettingsState.kt b/src/main/kotlin/com/harmness/toolwindow/SettingsState.kt
index e898cb6..a2a15ec 100644
--- a/src/main/kotlin/com/harmness/toolwindow/SettingsState.kt
+++ b/src/main/kotlin/com/harmness/toolwindow/SettingsState.kt
@@ -8,18 +8,14 @@ import com.intellij.openapi.components.Storage
import com.intellij.openapi.diagnostic.Logger
/**
- * 插件设置:目前仅保存一个「浏览器起始地址」。
- *
- * 该地址必须是一个允许被嵌入的 Web 应用地址(例如本地 Harness 服务地址),
- * 并且需要在页面上开启允许被 iframe/嵌入浏览(X-Frame-Options / CSP frame-ancestors)
- * 或者由 Harness 提供专门的无 frame 限制入口。
+ * 插件设置:仅保存「浏览器起始地址」。
*/
@State(name = "HarmnessToolwindowSettings", storages = [Storage("harmness-toolwindow.xml")])
@Service(Service.Level.APP)
class SettingsState : PersistentStateComponent {
data class State(
- var startUrl: String = "http://127.0.0.1:8888",
+ var startUrl: String = DEFAULT_URL,
)
private var myState = State()
@@ -39,7 +35,8 @@ class SettingsState : PersistentStateComponent {
}
companion object {
- const val DEFAULT_URL = "http://127.0.0.1:8888"
+ // 与 DSH Web GUI 默认端口一致
+ const val DEFAULT_URL = "http://127.0.0.1:8899"
fun getInstance(): SettingsState =
ServiceManager.getService(SettingsState::class.java)
diff --git a/src/main/resources/META-INF/plugin.xml b/src/main/resources/META-INF/plugin.xml
index 914f2ab..e41bb7d 100644
--- a/src/main/resources/META-INF/plugin.xml
+++ b/src/main/resources/META-INF/plugin.xml
@@ -9,7 +9,7 @@
IDEA without switching to a separate browser window.
]]>
-
+
com.intellij.modules.platform
@@ -21,12 +21,6 @@
anchor="right"
/>
-
-