diff --git a/src/main/kotlin/app/termora/SSHTerminalTab.kt b/src/main/kotlin/app/termora/SSHTerminalTab.kt index cdbf249..f453f1e 100644 --- a/src/main/kotlin/app/termora/SSHTerminalTab.kt +++ b/src/main/kotlin/app/termora/SSHTerminalTab.kt @@ -52,6 +52,7 @@ class SSHTerminalTab(windowScope: WindowScope, host: Host) : init { terminalPanel.dropFiles = false + terminalPanel.dataProviderSupport.addData(DataProviders.TerminalTab, this) } override fun getJComponent(): JComponent { @@ -222,6 +223,11 @@ class SSHTerminalTab(windowScope: WindowScope, host: Host) : } } + override fun willBeClose(): Boolean { + // 保存窗口状态 + terminalPanel.storeVisualWindows(host.id) + return super.willBeClose() + } private inner class MySessionListener : SessionListener, Disposable { override fun sessionEvent(session: Session, event: Event) { diff --git a/src/main/kotlin/app/termora/terminal/panel/FloatingToolbarPanel.kt b/src/main/kotlin/app/termora/terminal/panel/FloatingToolbarPanel.kt index f6bb053..2507430 100644 --- a/src/main/kotlin/app/termora/terminal/panel/FloatingToolbarPanel.kt +++ b/src/main/kotlin/app/termora/terminal/panel/FloatingToolbarPanel.kt @@ -14,11 +14,16 @@ import com.formdev.flatlaf.extras.components.FlatToolBar import com.formdev.flatlaf.ui.FlatRoundBorder import org.apache.commons.lang3.StringUtils import java.awt.event.ActionListener +import java.beans.PropertyChangeEvent +import java.beans.PropertyChangeListener +import java.util.* import javax.swing.JButton +import javax.swing.SwingUtilities class FloatingToolbarPanel : FlatToolBar(), Disposable { private val floatingToolbarEnable get() = Database.getDatabase().terminal.floatingToolbar private var closed = false + private val anEvent get() = AnActionEvent(this, StringUtils.EMPTY, EventObject(this)) companion object { @@ -72,6 +77,7 @@ class FloatingToolbarPanel : FlatToolBar(), Disposable { } initActions() + initEvents() } override fun updateUI() { @@ -123,12 +129,38 @@ class FloatingToolbarPanel : FlatToolBar(), Disposable { add(initCloseActionButton()) } + private fun initEvents() { + // 被添加到组件后 + addPropertyChangeListener("ancestor", object : PropertyChangeListener { + override fun propertyChange(evt: PropertyChangeEvent) { + removePropertyChangeListener("ancestor", this) + SwingUtilities.invokeLater { resumeVisualWindows() } + } + }) + } + + @Suppress("UNCHECKED_CAST") + private fun resumeVisualWindows() { + val tab = anEvent.getData(DataProviders.TerminalTab) ?: return + if (tab !is SSHTerminalTab) return + val terminalPanel = tab.getData(DataProviders.TerminalPanel) ?: return + terminalPanel.resumeVisualWindows(tab.host.id, object : DataProvider { + override fun getData(dataKey: DataKey): T? { + if (dataKey == DataProviders.TerminalTab) { + return tab as T + } + return super.getData(dataKey) + } + }) + } + + private fun initServerInfoActionButton(): JButton { val btn = JButton(Icons.infoOutline) btn.toolTipText = I18n.getString("termora.visual-window.system-information") btn.addActionListener(object : AnAction() { override fun actionPerformed(evt: AnActionEvent) { - val tab = evt.getData(DataProviders.TerminalTab) ?: return + val tab = anEvent.getData(DataProviders.TerminalTab) ?: return val terminalPanel = (tab as DataProvider?)?.getData(DataProviders.TerminalPanel) ?: return if (tab !is SSHTerminalTab) { @@ -156,7 +188,7 @@ class FloatingToolbarPanel : FlatToolBar(), Disposable { btn.toolTipText = I18n.getString("termora.snippet.title") btn.addActionListener(object : AnAction() { override fun actionPerformed(evt: AnActionEvent) { - val tab = evt.getData(DataProviders.TerminalTab) ?: return + val tab = anEvent.getData(DataProviders.TerminalTab) ?: return val writer = tab.getData(DataProviders.TerminalWriter) ?: return val dialog = SnippetTreeDialog(evt.window) dialog.setLocationRelativeTo(btn) @@ -174,7 +206,7 @@ class FloatingToolbarPanel : FlatToolBar(), Disposable { btn.toolTipText = I18n.getString("termora.visual-window.nvidia-smi") btn.addActionListener(object : AnAction() { override fun actionPerformed(evt: AnActionEvent) { - val tab = evt.getData(DataProviders.TerminalTab) ?: return + val tab = anEvent.getData(DataProviders.TerminalTab) ?: return val terminalPanel = (tab as DataProvider?)?.getData(DataProviders.TerminalPanel) ?: return if (tab !is SSHTerminalTab) { @@ -233,7 +265,7 @@ class FloatingToolbarPanel : FlatToolBar(), Disposable { btn.addActionListener(object : AnAction() { override fun actionPerformed(evt: AnActionEvent) { - val tab = evt.getData(DataProviders.TerminalTab) ?: return + val tab = anEvent.getData(DataProviders.TerminalTab) ?: return if (tab.canReconnect()) { tab.reconnect() } @@ -242,8 +274,4 @@ class FloatingToolbarPanel : FlatToolBar(), Disposable { return btn } - override fun dispose() { - - } - } \ No newline at end of file diff --git a/src/main/kotlin/app/termora/terminal/panel/TerminalPanel.kt b/src/main/kotlin/app/termora/terminal/panel/TerminalPanel.kt index 62461d0..a969a18 100644 --- a/src/main/kotlin/app/termora/terminal/panel/TerminalPanel.kt +++ b/src/main/kotlin/app/termora/terminal/panel/TerminalPanel.kt @@ -1,13 +1,14 @@ package app.termora.terminal.panel +import app.termora.Database import app.termora.Disposable import app.termora.Disposer +import app.termora.SSHTerminalTab import app.termora.actions.DataProvider import app.termora.actions.DataProviderSupport import app.termora.actions.DataProviders import app.termora.terminal.* -import app.termora.terminal.panel.vw.VisualWindow -import app.termora.terminal.panel.vw.VisualWindowManager +import app.termora.terminal.panel.vw.* import com.formdev.flatlaf.util.SystemInfo import org.apache.commons.lang3.ArrayUtils import org.apache.commons.lang3.StringUtils @@ -44,15 +45,15 @@ class TerminalPanel(val terminal: Terminal, private val writer: TerminalWriter) val SelectCopy = DataKey(Boolean::class) } + private val properties get() = Database.getDatabase().properties private val terminalBlink = TerminalBlink(terminal) private val terminalFindPanel = TerminalFindPanel(this, terminal) private val floatingToolbar = FloatingToolbarPanel() private val terminalDisplay = TerminalDisplay(this, terminal, terminalBlink) - private val dataProviderSupport = DataProviderSupport() private val layeredPane = TerminalLayeredPane() private var visualWindows = emptyArray() - val scrollBar = TerminalScrollBar(this@TerminalPanel, terminalFindPanel, terminal) + val scrollBar = TerminalScrollBar(this, terminalFindPanel, terminal) var enableFloatingToolbar = true set(value) { field = value @@ -63,6 +64,8 @@ class TerminalPanel(val terminal: Terminal, private val writer: TerminalWriter) } } + val dataProviderSupport = DataProviderSupport() + /** * 键盘事件 @@ -585,6 +588,37 @@ class TerminalPanel(val terminal: Terminal, private val writer: TerminalWriter) requestFocusInWindow() } + override fun resumeVisualWindows(id: String, dataProvider: DataProvider) { + val windows = properties.getString("VisualWindow.${id}.store") ?: return + for (name in windows.split(",")) { + if (name == "NVIDIA-SMI") { + addVisualWindow( + NvidiaSMIVisualWindow( + dataProvider.getData(DataProviders.TerminalTab) as SSHTerminalTab, + this + ) + ) + } else if (name == "SystemInformation") { + addVisualWindow( + SystemInformationVisualWindow( + dataProvider.getData(DataProviders.TerminalTab) as SSHTerminalTab, + this + ) + ) + } + } + } + + override fun storeVisualWindows(id: String) { + val windows = mutableListOf() + for (window in getVisualWindows()) { + if (window is Resumeable) { + windows.add(window.getWindowName()) + } + } + properties.putString("VisualWindow.${id}.store", windows.joinToString(",")) + } + override fun getDimension(): Dimension { return Dimension( terminalDisplay.size.width + padding.left + padding.right, diff --git a/src/main/kotlin/app/termora/terminal/panel/vw/NvidiaSMIVisualWindow.kt b/src/main/kotlin/app/termora/terminal/panel/vw/NvidiaSMIVisualWindow.kt index 38b3f7b..b2ff173 100644 --- a/src/main/kotlin/app/termora/terminal/panel/vw/NvidiaSMIVisualWindow.kt +++ b/src/main/kotlin/app/termora/terminal/panel/vw/NvidiaSMIVisualWindow.kt @@ -47,6 +47,7 @@ class NvidiaSMIVisualWindow(tab: SSHTerminalTab, visualWindowManager: VisualWind private val percentageBtn by lazy { JButton(if (isPercentage) Icons.text else Icons.percentage) } init { + Disposer.register(tab, this) initViews() initEvents() initVisualWindowPanel() diff --git a/src/main/kotlin/app/termora/terminal/panel/vw/Resumeable.kt b/src/main/kotlin/app/termora/terminal/panel/vw/Resumeable.kt new file mode 100644 index 0000000..df4db26 --- /dev/null +++ b/src/main/kotlin/app/termora/terminal/panel/vw/Resumeable.kt @@ -0,0 +1,3 @@ +package app.termora.terminal.panel.vw + +interface Resumeable \ No newline at end of file diff --git a/src/main/kotlin/app/termora/terminal/panel/vw/SSHVisualWindow.kt b/src/main/kotlin/app/termora/terminal/panel/vw/SSHVisualWindow.kt index 2846965..2b63f8e 100644 --- a/src/main/kotlin/app/termora/terminal/panel/vw/SSHVisualWindow.kt +++ b/src/main/kotlin/app/termora/terminal/panel/vw/SSHVisualWindow.kt @@ -1,6 +1,5 @@ package app.termora.terminal.panel.vw -import app.termora.Disposer import app.termora.SSHTerminalTab import app.termora.actions.AnActionEvent import app.termora.actions.DataProviders @@ -11,11 +10,7 @@ abstract class SSHVisualWindow( protected val tab: SSHTerminalTab, id: String, visualWindowManager: VisualWindowManager -) : VisualWindowPanel(id, visualWindowManager) { - - init { - Disposer.register(tab, this) - } +) : VisualWindowPanel(id, visualWindowManager), Resumeable { override fun toggleWindow() { val evt = AnActionEvent(tab.getJComponent(), StringUtils.EMPTY, EventObject(this)) diff --git a/src/main/kotlin/app/termora/terminal/panel/vw/SystemInformationVisualWindow.kt b/src/main/kotlin/app/termora/terminal/panel/vw/SystemInformationVisualWindow.kt index cce4565..5a8910e 100644 --- a/src/main/kotlin/app/termora/terminal/panel/vw/SystemInformationVisualWindow.kt +++ b/src/main/kotlin/app/termora/terminal/panel/vw/SystemInformationVisualWindow.kt @@ -25,6 +25,7 @@ class SystemInformationVisualWindow(tab: SSHTerminalTab, visualWindowManager: Vi private val systemInformationPanel by lazy { SystemInformationPanel() } init { + Disposer.register(tab, this) initViews() initEvents() initVisualWindowPanel() @@ -137,7 +138,7 @@ class SystemInformationVisualWindow(tab: SSHTerminalTab, visualWindowManager: Vi private suspend fun refreshCPUAndMem(session: ClientSession) { // top - var pair = SshClients.execChannel(session, "top -bn1") + val pair = SshClients.execChannel(session, "top -bn1") if (pair.first != 0) { return } @@ -236,7 +237,7 @@ class SystemInformationVisualWindow(tab: SSHTerminalTab, visualWindowManager: Vi private suspend fun refreshDisk(session: ClientSession) { // df -h - var pair = SshClients.execChannel(session, "df -B1") + val pair = SshClients.execChannel(session, "df -B1") if (pair.first != 0) { return } diff --git a/src/main/kotlin/app/termora/terminal/panel/vw/VisualWindow.kt b/src/main/kotlin/app/termora/terminal/panel/vw/VisualWindow.kt index ddcd89b..4478795 100644 --- a/src/main/kotlin/app/termora/terminal/panel/vw/VisualWindow.kt +++ b/src/main/kotlin/app/termora/terminal/panel/vw/VisualWindow.kt @@ -28,4 +28,9 @@ interface VisualWindow : Disposable { * 切换独立模式 */ fun toggleWindow() + + /** + * 同一个类,返回的相同 + */ + fun getWindowName(): String } \ No newline at end of file diff --git a/src/main/kotlin/app/termora/terminal/panel/vw/VisualWindowManager.kt b/src/main/kotlin/app/termora/terminal/panel/vw/VisualWindowManager.kt index 73596ef..16075c7 100644 --- a/src/main/kotlin/app/termora/terminal/panel/vw/VisualWindowManager.kt +++ b/src/main/kotlin/app/termora/terminal/panel/vw/VisualWindowManager.kt @@ -1,5 +1,6 @@ package app.termora.terminal.panel.vw +import app.termora.actions.DataProvider import java.awt.Dimension interface VisualWindowManager { @@ -33,4 +34,14 @@ interface VisualWindowManager { * 获取管理器的宽高 */ fun getDimension(): Dimension + + /** + * 恢复所有窗口 + */ + fun resumeVisualWindows(id: String, dataProvider: DataProvider) + + /** + * 存储所有窗口 + */ + fun storeVisualWindows(id: String) } \ No newline at end of file diff --git a/src/main/kotlin/app/termora/terminal/panel/vw/VisualWindowPanel.kt b/src/main/kotlin/app/termora/terminal/panel/vw/VisualWindowPanel.kt index 2059c9c..aee484f 100644 --- a/src/main/kotlin/app/termora/terminal/panel/vw/VisualWindowPanel.kt +++ b/src/main/kotlin/app/termora/terminal/panel/vw/VisualWindowPanel.kt @@ -374,4 +374,8 @@ open class VisualWindowPanel(protected val id: String, protected val visualWindo return null } } + + override fun getWindowName(): String { + return id + } } \ No newline at end of file