mirror of
https://github.com/TermoraDev/termora.git
synced 2026-01-15 18:02:58 +08:00
feat: support for restoring virtual windows
This commit is contained in:
@@ -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) {
|
||||
|
||||
@@ -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 <T : Any> getData(dataKey: DataKey<T>): 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() {
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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<VisualWindow>()
|
||||
|
||||
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<String>()
|
||||
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,
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
package app.termora.terminal.panel.vw
|
||||
|
||||
interface Resumeable
|
||||
@@ -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))
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -28,4 +28,9 @@ interface VisualWindow : Disposable {
|
||||
* 切换独立模式
|
||||
*/
|
||||
fun toggleWindow()
|
||||
|
||||
/**
|
||||
* 同一个类,返回的相同
|
||||
*/
|
||||
fun getWindowName(): String
|
||||
}
|
||||
@@ -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)
|
||||
}
|
||||
@@ -374,4 +374,8 @@ open class VisualWindowPanel(protected val id: String, protected val visualWindo
|
||||
return null
|
||||
}
|
||||
}
|
||||
|
||||
override fun getWindowName(): String {
|
||||
return id
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user