mirror of
https://github.com/TermoraDev/termora.git
synced 2026-01-16 02:12:58 +08:00
feat: use extension for floating toolbar
This commit is contained in:
@@ -37,7 +37,7 @@ record ExtensionProxy(Plugin plugin, Extension extension) implements InvocationH
|
|||||||
}
|
}
|
||||||
throw new IllegalCallerException(target.getMessage(), target);
|
throw new IllegalCallerException(target.getMessage(), target);
|
||||||
}
|
}
|
||||||
throw e;
|
throw target;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -23,7 +23,10 @@ abstract class PtyHostTerminalTab(
|
|||||||
|
|
||||||
private var readerJob: Job? = null
|
private var readerJob: Job? = null
|
||||||
private val ptyConnectorDelegate = PtyConnectorDelegate()
|
private val ptyConnectorDelegate = PtyConnectorDelegate()
|
||||||
protected val terminalPanel = TerminalPanelFactory.getInstance().createTerminalPanel(terminal, ptyConnectorDelegate)
|
protected val terminalPanel = TerminalPanelFactory.getInstance().createTerminalPanel(
|
||||||
|
this,
|
||||||
|
terminal, ptyConnectorDelegate
|
||||||
|
)
|
||||||
protected val ptyConnectorFactory get() = PtyConnectorFactory.getInstance()
|
protected val ptyConnectorFactory get() = PtyConnectorFactory.getInstance()
|
||||||
|
|
||||||
override fun start() {
|
override fun start() {
|
||||||
|
|||||||
@@ -38,9 +38,9 @@ class TerminalPanelFactory : Disposable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
fun createTerminalPanel(terminal: Terminal, ptyConnector: PtyConnector): TerminalPanel {
|
fun createTerminalPanel(tab: TerminalTab?, terminal: Terminal, ptyConnector: PtyConnector): TerminalPanel {
|
||||||
val writer = MyTerminalWriter(ptyConnector)
|
val writer = MyTerminalWriter(ptyConnector)
|
||||||
val terminalPanel = TerminalPanel(terminal, writer)
|
val terminalPanel = TerminalPanel(tab, terminal, writer)
|
||||||
|
|
||||||
// processDeviceStatusReport
|
// processDeviceStatusReport
|
||||||
terminal.getTerminalModel().setData(DataKey.TerminalWriter, writer)
|
terminal.getTerminalModel().setData(DataKey.TerminalWriter, writer)
|
||||||
|
|||||||
@@ -82,8 +82,8 @@ class TermoraFrame : JFrame(), DataProvider {
|
|||||||
if (scope != windowScope) return emptyList()
|
if (scope != windowScope) return emptyList()
|
||||||
|
|
||||||
var filter = hostTreeModel.root.getAllChildren()
|
var filter = hostTreeModel.root.getAllChildren()
|
||||||
.map { it.host }
|
|
||||||
.filter { it.isFolder.not() }
|
.filter { it.isFolder.not() }
|
||||||
|
.map { it.host }
|
||||||
|
|
||||||
if (pattern.isNotBlank()) {
|
if (pattern.isNotBlank()) {
|
||||||
filter = filter.filter {
|
filter = filter.filter {
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
package app.termora.actions
|
package app.termora.actions
|
||||||
|
|
||||||
|
import org.apache.commons.lang3.StringUtils
|
||||||
import org.jdesktop.swingx.action.BoundAction
|
import org.jdesktop.swingx.action.BoundAction
|
||||||
import java.awt.event.ActionEvent
|
import java.awt.event.ActionEvent
|
||||||
import javax.swing.Icon
|
import javax.swing.Icon
|
||||||
@@ -20,7 +21,7 @@ abstract class AnAction : BoundAction {
|
|||||||
if (evt is AnActionEvent) {
|
if (evt is AnActionEvent) {
|
||||||
actionPerformed(evt)
|
actionPerformed(evt)
|
||||||
} else {
|
} else {
|
||||||
actionPerformed(AnActionEvent(evt.source, evt.actionCommand, evt))
|
actionPerformed(AnActionEvent(evt.source, StringUtils.defaultString(evt.actionCommand), evt))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -40,7 +40,7 @@ class SSHCopyIdDialog(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
private val terminalPanel by lazy {
|
private val terminalPanel by lazy {
|
||||||
terminalPanelFactory.createTerminalPanel(terminal, PtyConnectorDelegate())
|
terminalPanelFactory.createTerminalPanel(null, terminal, PtyConnectorDelegate())
|
||||||
.apply { enableFloatingToolbar = false }
|
.apply { enableFloatingToolbar = false }
|
||||||
}
|
}
|
||||||
private val coroutineScope = CoroutineScope(SupervisorJob() + Dispatchers.IO)
|
private val coroutineScope = CoroutineScope(SupervisorJob() + Dispatchers.IO)
|
||||||
|
|||||||
@@ -13,6 +13,7 @@ import app.termora.plugin.internal.sftppty.SFTPPtyInternalPlugin
|
|||||||
import app.termora.plugin.internal.ssh.SSHInternalPlugin
|
import app.termora.plugin.internal.ssh.SSHInternalPlugin
|
||||||
import app.termora.plugin.internal.wsl.WSLInternalPlugin
|
import app.termora.plugin.internal.wsl.WSLInternalPlugin
|
||||||
import app.termora.swingCoroutineScope
|
import app.termora.swingCoroutineScope
|
||||||
|
import app.termora.terminal.panel.vw.FloatingToolbarPlugin
|
||||||
import app.termora.transfer.internal.local.LocalPlugin
|
import app.termora.transfer.internal.local.LocalPlugin
|
||||||
import app.termora.transfer.internal.sftp.SFTPPlugin
|
import app.termora.transfer.internal.sftp.SFTPPlugin
|
||||||
import com.formdev.flatlaf.util.SystemInfo
|
import com.formdev.flatlaf.util.SystemInfo
|
||||||
@@ -127,6 +128,9 @@ internal class PluginManager private constructor() {
|
|||||||
plugins.add(PluginDescriptor(LocalPlugin(), origin = PluginOrigin.Internal, version = version))
|
plugins.add(PluginDescriptor(LocalPlugin(), origin = PluginOrigin.Internal, version = version))
|
||||||
// sftp transfer plugin
|
// sftp transfer plugin
|
||||||
plugins.add(PluginDescriptor(SFTPPlugin(), origin = PluginOrigin.Internal, version = version))
|
plugins.add(PluginDescriptor(SFTPPlugin(), origin = PluginOrigin.Internal, version = version))
|
||||||
|
|
||||||
|
// floating
|
||||||
|
plugins.add(PluginDescriptor(FloatingToolbarPlugin(), origin = PluginOrigin.Internal, version = version))
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun loadSystemPlugins() {
|
private fun loadSystemPlugins() {
|
||||||
|
|||||||
@@ -0,0 +1,20 @@
|
|||||||
|
package app.termora.terminal.panel
|
||||||
|
|
||||||
|
import app.termora.TerminalTab
|
||||||
|
import app.termora.actions.AnAction
|
||||||
|
import app.termora.plugin.Extension
|
||||||
|
import app.termora.terminal.panel.vw.VisualWindow
|
||||||
|
import app.termora.terminal.panel.vw.VisualWindowManager
|
||||||
|
|
||||||
|
interface FloatingToolbarActionExtension : Extension {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 抛出 [UnsupportedOperationException] 表示不支持
|
||||||
|
*/
|
||||||
|
fun createActionButton(visualWindowManager: VisualWindowManager, tab: TerminalTab): AnAction
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取要返回的虚拟窗口
|
||||||
|
*/
|
||||||
|
fun getVisualWindowClass(tab: TerminalTab): Class<out VisualWindow>
|
||||||
|
}
|
||||||
@@ -6,13 +6,10 @@ import app.termora.actions.AnActionEvent
|
|||||||
import app.termora.actions.DataProvider
|
import app.termora.actions.DataProvider
|
||||||
import app.termora.actions.DataProviders
|
import app.termora.actions.DataProviders
|
||||||
import app.termora.database.DatabaseManager
|
import app.termora.database.DatabaseManager
|
||||||
|
import app.termora.plugin.ExtensionManager
|
||||||
import app.termora.plugin.internal.ssh.SSHTerminalTab
|
import app.termora.plugin.internal.ssh.SSHTerminalTab
|
||||||
import app.termora.snippet.SnippetAction
|
|
||||||
import app.termora.snippet.SnippetTreeDialog
|
|
||||||
import app.termora.terminal.DataKey
|
import app.termora.terminal.DataKey
|
||||||
import app.termora.terminal.panel.vw.NvidiaSMIVisualWindow
|
import app.termora.terminal.panel.vw.VisualWindowManager
|
||||||
import app.termora.terminal.panel.vw.SystemInformationVisualWindow
|
|
||||||
import app.termora.terminal.panel.vw.TransferVisualWindow
|
|
||||||
import com.formdev.flatlaf.extras.components.FlatToolBar
|
import com.formdev.flatlaf.extras.components.FlatToolBar
|
||||||
import com.formdev.flatlaf.ui.FlatRoundBorder
|
import com.formdev.flatlaf.ui.FlatRoundBorder
|
||||||
import org.apache.commons.lang3.StringUtils
|
import org.apache.commons.lang3.StringUtils
|
||||||
@@ -26,7 +23,7 @@ import javax.swing.SwingUtilities
|
|||||||
class FloatingToolbarPanel : FlatToolBar(), Disposable {
|
class FloatingToolbarPanel : FlatToolBar(), Disposable {
|
||||||
private val floatingToolbarEnable get() = DatabaseManager.getInstance().terminal.floatingToolbar
|
private val floatingToolbarEnable get() = DatabaseManager.getInstance().terminal.floatingToolbar
|
||||||
private var closed = false
|
private var closed = false
|
||||||
private val anEvent get() = AnActionEvent(this, StringUtils.EMPTY, EventObject(this))
|
private val event get() = AnActionEvent(this, StringUtils.EMPTY, EventObject(this))
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
|
|
||||||
@@ -79,7 +76,6 @@ class FloatingToolbarPanel : FlatToolBar(), Disposable {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
initActions()
|
|
||||||
initEvents()
|
initEvents()
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -116,26 +112,36 @@ class FloatingToolbarPanel : FlatToolBar(), Disposable {
|
|||||||
// Pin
|
// Pin
|
||||||
add(initPinActionButton())
|
add(initPinActionButton())
|
||||||
|
|
||||||
// 服务器信息
|
val tab = event.getData(DataProviders.TerminalTab)
|
||||||
add(initServerInfoActionButton())
|
val terminalPanel = (tab as DataProvider?)?.getData(DataProviders.TerminalPanel)
|
||||||
|
if (terminalPanel != null) {
|
||||||
|
val extensions = ExtensionManager.getInstance()
|
||||||
|
.getExtensions(FloatingToolbarActionExtension::class.java)
|
||||||
|
for (extension in extensions) {
|
||||||
|
try {
|
||||||
|
add(createButton(extension.createActionButton(terminalPanel, tab), terminalPanel, tab, extension))
|
||||||
|
} catch (_: UnsupportedOperationException) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Transfer
|
initReconnectActionButton(tab)
|
||||||
add(initTransferActionButton())
|
}
|
||||||
|
|
||||||
// Snippet
|
|
||||||
add(initSnippetActionButton())
|
|
||||||
|
|
||||||
// Nvidia 显卡信息
|
|
||||||
add(initNvidiaSMIActionButton())
|
|
||||||
|
|
||||||
// 重连
|
|
||||||
add(initReconnectActionButton())
|
|
||||||
|
|
||||||
// 关闭
|
// 关闭
|
||||||
add(initCloseActionButton())
|
add(initCloseActionButton())
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun initEvents() {
|
private fun initEvents() {
|
||||||
|
// 初始化 Action
|
||||||
|
addPropertyChangeListener("ancestor", object : PropertyChangeListener {
|
||||||
|
override fun propertyChange(evt: PropertyChangeEvent) {
|
||||||
|
removePropertyChangeListener("ancestor", this)
|
||||||
|
initActions()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
// 被添加到组件后
|
// 被添加到组件后
|
||||||
addPropertyChangeListener("ancestor", object : PropertyChangeListener {
|
addPropertyChangeListener("ancestor", object : PropertyChangeListener {
|
||||||
override fun propertyChange(evt: PropertyChangeEvent) {
|
override fun propertyChange(evt: PropertyChangeEvent) {
|
||||||
@@ -143,11 +149,12 @@ class FloatingToolbarPanel : FlatToolBar(), Disposable {
|
|||||||
SwingUtilities.invokeLater { resumeVisualWindows() }
|
SwingUtilities.invokeLater { resumeVisualWindows() }
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Suppress("UNCHECKED_CAST")
|
@Suppress("UNCHECKED_CAST")
|
||||||
private fun resumeVisualWindows() {
|
private fun resumeVisualWindows() {
|
||||||
val tab = anEvent.getData(DataProviders.TerminalTab) ?: return
|
val tab = event.getData(DataProviders.TerminalTab) ?: return
|
||||||
if (tab !is SSHTerminalTab) return
|
if (tab !is SSHTerminalTab) return
|
||||||
val terminalPanel = tab.getData(DataProviders.TerminalPanel) ?: return
|
val terminalPanel = tab.getData(DataProviders.TerminalPanel) ?: return
|
||||||
terminalPanel.resumeVisualWindows(tab.host.id, object : DataProvider {
|
terminalPanel.resumeVisualWindows(tab.host.id, object : DataProvider {
|
||||||
@@ -160,106 +167,30 @@ class FloatingToolbarPanel : FlatToolBar(), Disposable {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun createButton(
|
||||||
private fun initServerInfoActionButton(): JButton {
|
action: AnAction,
|
||||||
val btn = JButton(Icons.infoOutline)
|
visualWindowManager: VisualWindowManager,
|
||||||
btn.toolTipText = I18n.getString("termora.visual-window.system-information")
|
tab: TerminalTab,
|
||||||
btn.addActionListener(object : AnAction() {
|
extension: FloatingToolbarActionExtension
|
||||||
|
): JButton {
|
||||||
|
val btn = JButton(object : AnAction(action.smallIcon) {
|
||||||
override fun actionPerformed(evt: AnActionEvent) {
|
override fun actionPerformed(evt: AnActionEvent) {
|
||||||
val tab = anEvent.getData(DataProviders.TerminalTab) ?: return
|
try {
|
||||||
val terminalPanel = (tab as DataProvider?)?.getData(DataProviders.TerminalPanel) ?: return
|
val clazz = extension.getVisualWindowClass(tab)
|
||||||
|
for (window in visualWindowManager.getVisualWindows()) {
|
||||||
if (tab !is SSHTerminalTab) {
|
if (clazz.isInstance(window)) {
|
||||||
terminalPanel.toast(I18n.getString("termora.floating-toolbar.not-supported"))
|
visualWindowManager.moveToFront(window)
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
for (window in terminalPanel.getVisualWindows()) {
|
|
||||||
if (window is SystemInformationVisualWindow) {
|
|
||||||
terminalPanel.moveToFront(window)
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
action.actionPerformed(evt)
|
||||||
val visualWindowPanel = SystemInformationVisualWindow(tab, terminalPanel)
|
} catch (_: UnsupportedOperationException) {
|
||||||
terminalPanel.addVisualWindow(visualWindowPanel)
|
action.actionPerformed(evt)
|
||||||
|
}
|
||||||
}
|
|
||||||
})
|
|
||||||
return btn
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun initTransferActionButton(): JButton {
|
|
||||||
val btn = JButton(Icons.folder)
|
|
||||||
btn.toolTipText = I18n.getString("termora.transport.sftp")
|
|
||||||
btn.addActionListener(object : AnAction() {
|
|
||||||
override fun actionPerformed(evt: AnActionEvent) {
|
|
||||||
val tab = anEvent.getData(DataProviders.TerminalTab) ?: return
|
|
||||||
val terminalPanel = (tab as DataProvider?)?.getData(DataProviders.TerminalPanel) ?: return
|
|
||||||
|
|
||||||
if (tab !is SSHTerminalTab) {
|
|
||||||
terminalPanel.toast(I18n.getString("termora.floating-toolbar.not-supported"))
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
for (window in terminalPanel.getVisualWindows()) {
|
|
||||||
if (window is TransferVisualWindow) {
|
|
||||||
terminalPanel.moveToFront(window)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
val visualWindowPanel = TransferVisualWindow(tab, terminalPanel)
|
|
||||||
terminalPanel.addVisualWindow(visualWindowPanel)
|
|
||||||
|
|
||||||
}
|
|
||||||
})
|
|
||||||
return btn
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun initSnippetActionButton(): JButton {
|
|
||||||
val btn = JButton(Icons.codeSpan)
|
|
||||||
btn.toolTipText = I18n.getString("termora.snippet.title")
|
|
||||||
btn.addActionListener(object : AnAction() {
|
|
||||||
override fun actionPerformed(evt: AnActionEvent) {
|
|
||||||
val tab = anEvent.getData(DataProviders.TerminalTab) ?: return
|
|
||||||
val writer = tab.getData(DataProviders.TerminalWriter) ?: return
|
|
||||||
val dialog = SnippetTreeDialog(evt.window)
|
|
||||||
dialog.setLocationRelativeTo(btn)
|
|
||||||
dialog.setLocation(dialog.x, btn.locationOnScreen.y + height + 2)
|
|
||||||
dialog.isVisible = true
|
|
||||||
val node = dialog.getSelectedNode() ?: return
|
|
||||||
SnippetAction.getInstance().runSnippet(node.data, writer)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
return btn
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun initNvidiaSMIActionButton(): JButton {
|
|
||||||
val btn = JButton(Icons.nvidia)
|
|
||||||
btn.toolTipText = I18n.getString("termora.visual-window.nvidia-smi")
|
|
||||||
btn.addActionListener(object : AnAction() {
|
|
||||||
override fun actionPerformed(evt: AnActionEvent) {
|
|
||||||
val tab = anEvent.getData(DataProviders.TerminalTab) ?: return
|
|
||||||
val terminalPanel = (tab as DataProvider?)?.getData(DataProviders.TerminalPanel) ?: return
|
|
||||||
|
|
||||||
if (tab !is SSHTerminalTab) {
|
|
||||||
terminalPanel.toast(I18n.getString("termora.floating-toolbar.not-supported"))
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
for (window in terminalPanel.getVisualWindows()) {
|
|
||||||
if (window is NvidiaSMIVisualWindow) {
|
|
||||||
terminalPanel.moveToFront(window)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
val visualWindowPanel = NvidiaSMIVisualWindow(tab, terminalPanel)
|
|
||||||
terminalPanel.addVisualWindow(visualWindowPanel)
|
|
||||||
|
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
btn.text = StringUtils.EMPTY
|
||||||
|
btn.toolTipText = action.shortDescription
|
||||||
return btn
|
return btn
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -293,19 +224,16 @@ class FloatingToolbarPanel : FlatToolBar(), Disposable {
|
|||||||
return btn
|
return btn
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun initReconnectActionButton(): JButton {
|
private fun initReconnectActionButton(tab: TerminalTab) {
|
||||||
|
if (tab.canReconnect().not()) return
|
||||||
val btn = JButton(Icons.refresh)
|
val btn = JButton(Icons.refresh)
|
||||||
btn.toolTipText = I18n.getString("termora.tabbed.contextmenu.reconnect")
|
btn.toolTipText = I18n.getString("termora.tabbed.contextmenu.reconnect")
|
||||||
|
|
||||||
btn.addActionListener(object : AnAction() {
|
btn.addActionListener(object : AnAction() {
|
||||||
override fun actionPerformed(evt: AnActionEvent) {
|
override fun actionPerformed(evt: AnActionEvent) {
|
||||||
val tab = anEvent.getData(DataProviders.TerminalTab) ?: return
|
|
||||||
if (tab.canReconnect()) {
|
|
||||||
tab.reconnect()
|
tab.reconnect()
|
||||||
}
|
}
|
||||||
}
|
|
||||||
})
|
})
|
||||||
return btn
|
add(btn)
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -2,6 +2,7 @@ package app.termora.terminal.panel
|
|||||||
|
|
||||||
import app.termora.Disposable
|
import app.termora.Disposable
|
||||||
import app.termora.Disposer
|
import app.termora.Disposer
|
||||||
|
import app.termora.TerminalTab
|
||||||
import app.termora.actions.DataProvider
|
import app.termora.actions.DataProvider
|
||||||
import app.termora.actions.DataProviderSupport
|
import app.termora.actions.DataProviderSupport
|
||||||
import app.termora.actions.DataProviders
|
import app.termora.actions.DataProviders
|
||||||
@@ -35,7 +36,7 @@ import kotlin.time.Duration
|
|||||||
import kotlin.time.Duration.Companion.milliseconds
|
import kotlin.time.Duration.Companion.milliseconds
|
||||||
|
|
||||||
|
|
||||||
class TerminalPanel(val terminal: Terminal, private val writer: TerminalWriter) :
|
class TerminalPanel(val tab: TerminalTab?, val terminal: Terminal, private val writer: TerminalWriter) :
|
||||||
JPanel(BorderLayout()), DataProvider, Disposable, VisualWindowManager {
|
JPanel(BorderLayout()), DataProvider, Disposable, VisualWindowManager {
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
@@ -554,7 +555,13 @@ class TerminalPanel(val terminal: Terminal, private val writer: TerminalWriter)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Suppress("UNCHECKED_CAST")
|
||||||
override fun <T : Any> getData(dataKey: DataKey<T>): T? {
|
override fun <T : Any> getData(dataKey: DataKey<T>): T? {
|
||||||
|
if (dataKey == DataProviders.TerminalTab) {
|
||||||
|
if (tab != null) {
|
||||||
|
return tab as T
|
||||||
|
}
|
||||||
|
}
|
||||||
return dataProviderSupport.getData(dataKey)
|
return dataProviderSupport.getData(dataKey)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,27 @@
|
|||||||
|
package app.termora.terminal.panel.vw
|
||||||
|
|
||||||
|
import app.termora.plugin.Extension
|
||||||
|
import app.termora.plugin.InternalPlugin
|
||||||
|
import app.termora.terminal.panel.FloatingToolbarActionExtension
|
||||||
|
import app.termora.terminal.panel.vw.extensions.NvidiaVisualWindowActionExtension
|
||||||
|
import app.termora.terminal.panel.vw.extensions.ServerInfoVisualWindowActionExtension
|
||||||
|
import app.termora.terminal.panel.vw.extensions.SnippetVisualWindowActionExtension
|
||||||
|
import app.termora.terminal.panel.vw.extensions.TransferVisualWindowActionExtension
|
||||||
|
|
||||||
|
internal class FloatingToolbarPlugin : InternalPlugin() {
|
||||||
|
init {
|
||||||
|
support.addExtension(FloatingToolbarActionExtension::class.java) { TransferVisualWindowActionExtension.instance }
|
||||||
|
support.addExtension(FloatingToolbarActionExtension::class.java) { ServerInfoVisualWindowActionExtension.instance }
|
||||||
|
support.addExtension(FloatingToolbarActionExtension::class.java) { SnippetVisualWindowActionExtension.instance }
|
||||||
|
support.addExtension(FloatingToolbarActionExtension::class.java) { NvidiaVisualWindowActionExtension.instance }
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getName(): String {
|
||||||
|
return "FloatingToolbar"
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun <T : Extension> getExtensions(clazz: Class<T>): List<T> {
|
||||||
|
return support.getExtensions(clazz)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -10,6 +10,7 @@ import com.jgoodies.forms.builder.FormBuilder
|
|||||||
import com.jgoodies.forms.layout.FormLayout
|
import com.jgoodies.forms.layout.FormLayout
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
import kotlinx.coroutines.cancel
|
import kotlinx.coroutines.cancel
|
||||||
|
import kotlinx.coroutines.delay
|
||||||
import kotlinx.coroutines.swing.Swing
|
import kotlinx.coroutines.swing.Swing
|
||||||
import kotlinx.coroutines.withContext
|
import kotlinx.coroutines.withContext
|
||||||
import org.apache.commons.lang3.StringUtils
|
import org.apache.commons.lang3.StringUtils
|
||||||
@@ -25,6 +26,7 @@ import java.io.StringReader
|
|||||||
import javax.swing.*
|
import javax.swing.*
|
||||||
import javax.xml.parsers.DocumentBuilderFactory
|
import javax.xml.parsers.DocumentBuilderFactory
|
||||||
import javax.xml.xpath.XPathFactory
|
import javax.xml.xpath.XPathFactory
|
||||||
|
import kotlin.time.Duration.Companion.milliseconds
|
||||||
|
|
||||||
class NvidiaSMIVisualWindow(tab: SSHTerminalTab, visualWindowManager: VisualWindowManager) :
|
class NvidiaSMIVisualWindow(tab: SSHTerminalTab, visualWindowManager: VisualWindowManager) :
|
||||||
SSHVisualWindow(tab, "NVIDIA-SMI", visualWindowManager) {
|
SSHVisualWindow(tab, "NVIDIA-SMI", visualWindowManager) {
|
||||||
@@ -264,7 +266,14 @@ class NvidiaSMIVisualWindow(tab: SSHTerminalTab, visualWindowManager: VisualWind
|
|||||||
|
|
||||||
|
|
||||||
override suspend fun refresh(isFirst: Boolean) {
|
override suspend fun refresh(isFirst: Boolean) {
|
||||||
val session = tab.getData(SSHTerminalTab.SSHSession) ?: return
|
val session = suspend {
|
||||||
|
var c = tab.getData(SSHTerminalTab.SSHSession)
|
||||||
|
while (c == null) {
|
||||||
|
delay(250.milliseconds)
|
||||||
|
c = tab.getData(SSHTerminalTab.SSHSession)
|
||||||
|
}
|
||||||
|
c
|
||||||
|
}.invoke()
|
||||||
|
|
||||||
val doc = try {
|
val doc = try {
|
||||||
val (code, text) = SshClients.execChannel(session, "nvidia-smi -x -q")
|
val (code, text) = SshClients.execChannel(session, "nvidia-smi -x -q")
|
||||||
|
|||||||
@@ -0,0 +1,41 @@
|
|||||||
|
package app.termora.terminal.panel.vw.extensions
|
||||||
|
|
||||||
|
import app.termora.I18n
|
||||||
|
import app.termora.Icons
|
||||||
|
import app.termora.TerminalTab
|
||||||
|
import app.termora.actions.AnAction
|
||||||
|
import app.termora.actions.AnActionEvent
|
||||||
|
import app.termora.plugin.internal.ssh.SSHTerminalTab
|
||||||
|
import app.termora.terminal.panel.FloatingToolbarActionExtension
|
||||||
|
import app.termora.terminal.panel.vw.NvidiaSMIVisualWindow
|
||||||
|
import app.termora.terminal.panel.vw.VisualWindow
|
||||||
|
import app.termora.terminal.panel.vw.VisualWindowManager
|
||||||
|
|
||||||
|
class NvidiaVisualWindowActionExtension private constructor() : FloatingToolbarActionExtension {
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
val instance = NvidiaVisualWindowActionExtension()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun createActionButton(visualWindowManager: VisualWindowManager, tab: TerminalTab): AnAction {
|
||||||
|
if (tab !is SSHTerminalTab) throw UnsupportedOperationException()
|
||||||
|
return object : AnAction(Icons.nvidia) {
|
||||||
|
init {
|
||||||
|
putValue(SHORT_DESCRIPTION, I18n.getString("termora.visual-window.nvidia-smi"))
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun actionPerformed(evt: AnActionEvent) {
|
||||||
|
val visualWindowPanel = NvidiaSMIVisualWindow(tab, visualWindowManager)
|
||||||
|
visualWindowManager.addVisualWindow(visualWindowPanel)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getVisualWindowClass(tab: TerminalTab): Class<out VisualWindow> {
|
||||||
|
return NvidiaSMIVisualWindow::class.java
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun ordered(): Long {
|
||||||
|
return 3;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,42 @@
|
|||||||
|
package app.termora.terminal.panel.vw.extensions
|
||||||
|
|
||||||
|
import app.termora.I18n
|
||||||
|
import app.termora.Icons
|
||||||
|
import app.termora.TerminalTab
|
||||||
|
import app.termora.actions.AnAction
|
||||||
|
import app.termora.actions.AnActionEvent
|
||||||
|
import app.termora.plugin.internal.ssh.SSHTerminalTab
|
||||||
|
import app.termora.terminal.panel.FloatingToolbarActionExtension
|
||||||
|
import app.termora.terminal.panel.vw.SystemInformationVisualWindow
|
||||||
|
import app.termora.terminal.panel.vw.VisualWindow
|
||||||
|
import app.termora.terminal.panel.vw.VisualWindowManager
|
||||||
|
|
||||||
|
class ServerInfoVisualWindowActionExtension private constructor() : FloatingToolbarActionExtension {
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
val instance = ServerInfoVisualWindowActionExtension()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun createActionButton(visualWindowManager: VisualWindowManager, tab: TerminalTab): AnAction {
|
||||||
|
if (tab !is SSHTerminalTab) throw UnsupportedOperationException()
|
||||||
|
return object : AnAction(Icons.infoOutline) {
|
||||||
|
init {
|
||||||
|
putValue(SHORT_DESCRIPTION, I18n.getString("termora.visual-window.system-information"))
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun actionPerformed(evt: AnActionEvent) {
|
||||||
|
val visualWindowPanel = SystemInformationVisualWindow(tab, visualWindowManager)
|
||||||
|
visualWindowManager.addVisualWindow(visualWindowPanel)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getVisualWindowClass(tab: TerminalTab): Class<out VisualWindow> {
|
||||||
|
if (tab !is SSHTerminalTab) throw UnsupportedOperationException()
|
||||||
|
return SystemInformationVisualWindow::class.java
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun ordered(): Long {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,50 @@
|
|||||||
|
package app.termora.terminal.panel.vw.extensions
|
||||||
|
|
||||||
|
import app.termora.I18n
|
||||||
|
import app.termora.Icons
|
||||||
|
import app.termora.PtyHostTerminalTab
|
||||||
|
import app.termora.TerminalTab
|
||||||
|
import app.termora.actions.AnAction
|
||||||
|
import app.termora.actions.AnActionEvent
|
||||||
|
import app.termora.actions.DataProviders
|
||||||
|
import app.termora.snippet.SnippetAction
|
||||||
|
import app.termora.snippet.SnippetTreeDialog
|
||||||
|
import app.termora.terminal.panel.FloatingToolbarActionExtension
|
||||||
|
import app.termora.terminal.panel.vw.VisualWindow
|
||||||
|
import app.termora.terminal.panel.vw.VisualWindowManager
|
||||||
|
import javax.swing.JComponent
|
||||||
|
|
||||||
|
class SnippetVisualWindowActionExtension private constructor() : FloatingToolbarActionExtension {
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
val instance = SnippetVisualWindowActionExtension()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun createActionButton(visualWindowManager: VisualWindowManager, tab: TerminalTab): AnAction {
|
||||||
|
if (tab !is PtyHostTerminalTab) throw UnsupportedOperationException()
|
||||||
|
return object : AnAction(Icons.codeSpan) {
|
||||||
|
init {
|
||||||
|
putValue(SHORT_DESCRIPTION, I18n.getString("termora.snippet.title"))
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun actionPerformed(evt: AnActionEvent) {
|
||||||
|
val btn = evt.source as? JComponent ?: return
|
||||||
|
val writer = tab.getData(DataProviders.TerminalWriter) ?: return
|
||||||
|
val dialog = SnippetTreeDialog(evt.window)
|
||||||
|
dialog.setLocationRelativeTo(btn)
|
||||||
|
dialog.setLocation(dialog.x, btn.locationOnScreen.y + btn.height + 2)
|
||||||
|
dialog.isVisible = true
|
||||||
|
val node = dialog.getSelectedNode() ?: return
|
||||||
|
SnippetAction.getInstance().runSnippet(node.data, writer)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getVisualWindowClass(tab: TerminalTab): Class<out VisualWindow> {
|
||||||
|
throw UnsupportedOperationException()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun ordered(): Long {
|
||||||
|
return 2;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,37 @@
|
|||||||
|
package app.termora.terminal.panel.vw.extensions
|
||||||
|
|
||||||
|
import app.termora.Icons
|
||||||
|
import app.termora.TerminalTab
|
||||||
|
import app.termora.actions.AnAction
|
||||||
|
import app.termora.actions.AnActionEvent
|
||||||
|
import app.termora.plugin.internal.ssh.SSHTerminalTab
|
||||||
|
import app.termora.terminal.panel.FloatingToolbarActionExtension
|
||||||
|
import app.termora.terminal.panel.vw.TransferVisualWindow
|
||||||
|
import app.termora.terminal.panel.vw.VisualWindow
|
||||||
|
import app.termora.terminal.panel.vw.VisualWindowManager
|
||||||
|
|
||||||
|
class TransferVisualWindowActionExtension private constructor() : FloatingToolbarActionExtension {
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
val instance = TransferVisualWindowActionExtension()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun createActionButton(visualWindowManager: VisualWindowManager, tab: TerminalTab): AnAction {
|
||||||
|
if (tab !is SSHTerminalTab) throw UnsupportedOperationException()
|
||||||
|
return object : AnAction(Icons.folder) {
|
||||||
|
override fun actionPerformed(evt: AnActionEvent) {
|
||||||
|
val visualWindowPanel = TransferVisualWindow(tab, visualWindowManager)
|
||||||
|
visualWindowManager.addVisualWindow(visualWindowPanel)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getVisualWindowClass(tab: TerminalTab): Class<out VisualWindow> {
|
||||||
|
if (tab !is SSHTerminalTab) throw UnsupportedOperationException()
|
||||||
|
return TransferVisualWindow::class.java
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun ordered(): Long {
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user