From 9ce4a880411fe2988d703942775df4b487b218dd Mon Sep 17 00:00:00 2001 From: hstyi Date: Thu, 3 Jul 2025 11:40:21 +0800 Subject: [PATCH] feat: use extension for floating toolbar --- .../app/termora/plugin/ExtensionProxy.java | 2 +- .../kotlin/app/termora/PtyHostTerminalTab.kt | 5 +- .../app/termora/TerminalPanelFactory.kt | 4 +- src/main/kotlin/app/termora/TermoraFrame.kt | 2 +- .../kotlin/app/termora/actions/AnAction.kt | 3 +- .../app/termora/keymgr/SSHCopyIdDialog.kt | 2 +- .../app/termora/plugin/PluginManager.kt | 4 + .../panel/FloatingToolbarActionExtension.kt | 20 ++ .../terminal/panel/FloatingToolbarPanel.kt | 172 +++++------------- .../termora/terminal/panel/TerminalPanel.kt | 9 +- .../panel/vw/FloatingToolbarPlugin.kt | 27 +++ .../panel/vw/NvidiaSMIVisualWindow.kt | 11 +- .../NvidiaVisualWindowActionExtension.kt | 41 +++++ .../ServerInfoVisualWindowActionExtension.kt | 42 +++++ .../SnippetVisualWindowActionExtension.kt | 50 +++++ .../TransferVisualWindowActionExtension.kt | 37 ++++ 16 files changed, 300 insertions(+), 131 deletions(-) create mode 100644 src/main/kotlin/app/termora/terminal/panel/FloatingToolbarActionExtension.kt create mode 100644 src/main/kotlin/app/termora/terminal/panel/vw/FloatingToolbarPlugin.kt create mode 100644 src/main/kotlin/app/termora/terminal/panel/vw/extensions/NvidiaVisualWindowActionExtension.kt create mode 100644 src/main/kotlin/app/termora/terminal/panel/vw/extensions/ServerInfoVisualWindowActionExtension.kt create mode 100644 src/main/kotlin/app/termora/terminal/panel/vw/extensions/SnippetVisualWindowActionExtension.kt create mode 100644 src/main/kotlin/app/termora/terminal/panel/vw/extensions/TransferVisualWindowActionExtension.kt diff --git a/src/main/java/app/termora/plugin/ExtensionProxy.java b/src/main/java/app/termora/plugin/ExtensionProxy.java index 1e25af2..f186e3f 100644 --- a/src/main/java/app/termora/plugin/ExtensionProxy.java +++ b/src/main/java/app/termora/plugin/ExtensionProxy.java @@ -37,7 +37,7 @@ record ExtensionProxy(Plugin plugin, Extension extension) implements InvocationH } throw new IllegalCallerException(target.getMessage(), target); } - throw e; + throw target; } } } diff --git a/src/main/kotlin/app/termora/PtyHostTerminalTab.kt b/src/main/kotlin/app/termora/PtyHostTerminalTab.kt index e3b8812..7f2a816 100644 --- a/src/main/kotlin/app/termora/PtyHostTerminalTab.kt +++ b/src/main/kotlin/app/termora/PtyHostTerminalTab.kt @@ -23,7 +23,10 @@ abstract class PtyHostTerminalTab( private var readerJob: Job? = null 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() override fun start() { diff --git a/src/main/kotlin/app/termora/TerminalPanelFactory.kt b/src/main/kotlin/app/termora/TerminalPanelFactory.kt index a7884c7..1b3a3d7 100644 --- a/src/main/kotlin/app/termora/TerminalPanelFactory.kt +++ b/src/main/kotlin/app/termora/TerminalPanelFactory.kt @@ -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 terminalPanel = TerminalPanel(terminal, writer) + val terminalPanel = TerminalPanel(tab, terminal, writer) // processDeviceStatusReport terminal.getTerminalModel().setData(DataKey.TerminalWriter, writer) diff --git a/src/main/kotlin/app/termora/TermoraFrame.kt b/src/main/kotlin/app/termora/TermoraFrame.kt index c91924a..dcd1d91 100644 --- a/src/main/kotlin/app/termora/TermoraFrame.kt +++ b/src/main/kotlin/app/termora/TermoraFrame.kt @@ -82,8 +82,8 @@ class TermoraFrame : JFrame(), DataProvider { if (scope != windowScope) return emptyList() var filter = hostTreeModel.root.getAllChildren() - .map { it.host } .filter { it.isFolder.not() } + .map { it.host } if (pattern.isNotBlank()) { filter = filter.filter { diff --git a/src/main/kotlin/app/termora/actions/AnAction.kt b/src/main/kotlin/app/termora/actions/AnAction.kt index 7c39d5a..759e587 100644 --- a/src/main/kotlin/app/termora/actions/AnAction.kt +++ b/src/main/kotlin/app/termora/actions/AnAction.kt @@ -1,5 +1,6 @@ package app.termora.actions +import org.apache.commons.lang3.StringUtils import org.jdesktop.swingx.action.BoundAction import java.awt.event.ActionEvent import javax.swing.Icon @@ -20,7 +21,7 @@ abstract class AnAction : BoundAction { if (evt is AnActionEvent) { actionPerformed(evt) } else { - actionPerformed(AnActionEvent(evt.source, evt.actionCommand, evt)) + actionPerformed(AnActionEvent(evt.source, StringUtils.defaultString(evt.actionCommand), evt)) } } diff --git a/src/main/kotlin/app/termora/keymgr/SSHCopyIdDialog.kt b/src/main/kotlin/app/termora/keymgr/SSHCopyIdDialog.kt index fc74eac..ff36c18 100644 --- a/src/main/kotlin/app/termora/keymgr/SSHCopyIdDialog.kt +++ b/src/main/kotlin/app/termora/keymgr/SSHCopyIdDialog.kt @@ -40,7 +40,7 @@ class SSHCopyIdDialog( } } private val terminalPanel by lazy { - terminalPanelFactory.createTerminalPanel(terminal, PtyConnectorDelegate()) + terminalPanelFactory.createTerminalPanel(null, terminal, PtyConnectorDelegate()) .apply { enableFloatingToolbar = false } } private val coroutineScope = CoroutineScope(SupervisorJob() + Dispatchers.IO) diff --git a/src/main/kotlin/app/termora/plugin/PluginManager.kt b/src/main/kotlin/app/termora/plugin/PluginManager.kt index c232eb4..5225ede 100644 --- a/src/main/kotlin/app/termora/plugin/PluginManager.kt +++ b/src/main/kotlin/app/termora/plugin/PluginManager.kt @@ -13,6 +13,7 @@ import app.termora.plugin.internal.sftppty.SFTPPtyInternalPlugin import app.termora.plugin.internal.ssh.SSHInternalPlugin import app.termora.plugin.internal.wsl.WSLInternalPlugin import app.termora.swingCoroutineScope +import app.termora.terminal.panel.vw.FloatingToolbarPlugin import app.termora.transfer.internal.local.LocalPlugin import app.termora.transfer.internal.sftp.SFTPPlugin import com.formdev.flatlaf.util.SystemInfo @@ -127,6 +128,9 @@ internal class PluginManager private constructor() { plugins.add(PluginDescriptor(LocalPlugin(), origin = PluginOrigin.Internal, version = version)) // sftp transfer plugin plugins.add(PluginDescriptor(SFTPPlugin(), origin = PluginOrigin.Internal, version = version)) + + // floating + plugins.add(PluginDescriptor(FloatingToolbarPlugin(), origin = PluginOrigin.Internal, version = version)) } private fun loadSystemPlugins() { diff --git a/src/main/kotlin/app/termora/terminal/panel/FloatingToolbarActionExtension.kt b/src/main/kotlin/app/termora/terminal/panel/FloatingToolbarActionExtension.kt new file mode 100644 index 0000000..4127b87 --- /dev/null +++ b/src/main/kotlin/app/termora/terminal/panel/FloatingToolbarActionExtension.kt @@ -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 +} \ No newline at end of file diff --git a/src/main/kotlin/app/termora/terminal/panel/FloatingToolbarPanel.kt b/src/main/kotlin/app/termora/terminal/panel/FloatingToolbarPanel.kt index 0fbcd8c..f5f82c3 100644 --- a/src/main/kotlin/app/termora/terminal/panel/FloatingToolbarPanel.kt +++ b/src/main/kotlin/app/termora/terminal/panel/FloatingToolbarPanel.kt @@ -6,13 +6,10 @@ import app.termora.actions.AnActionEvent import app.termora.actions.DataProvider import app.termora.actions.DataProviders import app.termora.database.DatabaseManager +import app.termora.plugin.ExtensionManager 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.panel.vw.NvidiaSMIVisualWindow -import app.termora.terminal.panel.vw.SystemInformationVisualWindow -import app.termora.terminal.panel.vw.TransferVisualWindow +import app.termora.terminal.panel.vw.VisualWindowManager import com.formdev.flatlaf.extras.components.FlatToolBar import com.formdev.flatlaf.ui.FlatRoundBorder import org.apache.commons.lang3.StringUtils @@ -26,7 +23,7 @@ import javax.swing.SwingUtilities class FloatingToolbarPanel : FlatToolBar(), Disposable { private val floatingToolbarEnable get() = DatabaseManager.getInstance().terminal.floatingToolbar 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 { @@ -79,7 +76,6 @@ class FloatingToolbarPanel : FlatToolBar(), Disposable { } } - initActions() initEvents() } @@ -116,26 +112,36 @@ class FloatingToolbarPanel : FlatToolBar(), Disposable { // Pin add(initPinActionButton()) - // 服务器信息 - add(initServerInfoActionButton()) + val tab = event.getData(DataProviders.TerminalTab) + 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 - add(initTransferActionButton()) + initReconnectActionButton(tab) + } - // Snippet - add(initSnippetActionButton()) - - // Nvidia 显卡信息 - add(initNvidiaSMIActionButton()) - - // 重连 - add(initReconnectActionButton()) // 关闭 add(initCloseActionButton()) } private fun initEvents() { + // 初始化 Action + addPropertyChangeListener("ancestor", object : PropertyChangeListener { + override fun propertyChange(evt: PropertyChangeEvent) { + removePropertyChangeListener("ancestor", this) + initActions() + } + }) + // 被添加到组件后 addPropertyChangeListener("ancestor", object : PropertyChangeListener { override fun propertyChange(evt: PropertyChangeEvent) { @@ -143,11 +149,12 @@ class FloatingToolbarPanel : FlatToolBar(), Disposable { SwingUtilities.invokeLater { resumeVisualWindows() } } }) + } @Suppress("UNCHECKED_CAST") private fun resumeVisualWindows() { - val tab = anEvent.getData(DataProviders.TerminalTab) ?: return + val tab = event.getData(DataProviders.TerminalTab) ?: return if (tab !is SSHTerminalTab) return val terminalPanel = tab.getData(DataProviders.TerminalPanel) ?: return terminalPanel.resumeVisualWindows(tab.host.id, object : DataProvider { @@ -160,106 +167,30 @@ class FloatingToolbarPanel : FlatToolBar(), Disposable { }) } - - private fun initServerInfoActionButton(): JButton { - val btn = JButton(Icons.infoOutline) - btn.toolTipText = I18n.getString("termora.visual-window.system-information") - btn.addActionListener(object : AnAction() { + private fun createButton( + action: AnAction, + visualWindowManager: VisualWindowManager, + tab: TerminalTab, + extension: FloatingToolbarActionExtension + ): JButton { + val btn = JButton(object : AnAction(action.smallIcon) { 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 SystemInformationVisualWindow) { - terminalPanel.moveToFront(window) - return + try { + val clazz = extension.getVisualWindowClass(tab) + for (window in visualWindowManager.getVisualWindows()) { + if (clazz.isInstance(window)) { + visualWindowManager.moveToFront(window) + return + } } + action.actionPerformed(evt) + } catch (_: UnsupportedOperationException) { + action.actionPerformed(evt) } - - val visualWindowPanel = SystemInformationVisualWindow(tab, terminalPanel) - terminalPanel.addVisualWindow(visualWindowPanel) - - } - }) - 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 } @@ -293,19 +224,16 @@ class FloatingToolbarPanel : FlatToolBar(), Disposable { return btn } - private fun initReconnectActionButton(): JButton { + private fun initReconnectActionButton(tab: TerminalTab) { + if (tab.canReconnect().not()) return val btn = JButton(Icons.refresh) btn.toolTipText = I18n.getString("termora.tabbed.contextmenu.reconnect") - btn.addActionListener(object : AnAction() { override fun actionPerformed(evt: AnActionEvent) { - val tab = anEvent.getData(DataProviders.TerminalTab) ?: return - if (tab.canReconnect()) { - tab.reconnect() - } + tab.reconnect() } }) - return btn + add(btn) } } \ 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 0697aa0..1e2d37d 100644 --- a/src/main/kotlin/app/termora/terminal/panel/TerminalPanel.kt +++ b/src/main/kotlin/app/termora/terminal/panel/TerminalPanel.kt @@ -2,6 +2,7 @@ package app.termora.terminal.panel import app.termora.Disposable import app.termora.Disposer +import app.termora.TerminalTab import app.termora.actions.DataProvider import app.termora.actions.DataProviderSupport import app.termora.actions.DataProviders @@ -35,7 +36,7 @@ import kotlin.time.Duration 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 { companion object { @@ -554,7 +555,13 @@ class TerminalPanel(val terminal: Terminal, private val writer: TerminalWriter) } } + @Suppress("UNCHECKED_CAST") override fun getData(dataKey: DataKey): T? { + if (dataKey == DataProviders.TerminalTab) { + if (tab != null) { + return tab as T + } + } return dataProviderSupport.getData(dataKey) } diff --git a/src/main/kotlin/app/termora/terminal/panel/vw/FloatingToolbarPlugin.kt b/src/main/kotlin/app/termora/terminal/panel/vw/FloatingToolbarPlugin.kt new file mode 100644 index 0000000..7f9207e --- /dev/null +++ b/src/main/kotlin/app/termora/terminal/panel/vw/FloatingToolbarPlugin.kt @@ -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 getExtensions(clazz: Class): List { + return support.getExtensions(clazz) + } + +} \ No newline at end of file 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 0f3946d..d64a50a 100644 --- a/src/main/kotlin/app/termora/terminal/panel/vw/NvidiaSMIVisualWindow.kt +++ b/src/main/kotlin/app/termora/terminal/panel/vw/NvidiaSMIVisualWindow.kt @@ -10,6 +10,7 @@ import com.jgoodies.forms.builder.FormBuilder import com.jgoodies.forms.layout.FormLayout import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.cancel +import kotlinx.coroutines.delay import kotlinx.coroutines.swing.Swing import kotlinx.coroutines.withContext import org.apache.commons.lang3.StringUtils @@ -25,6 +26,7 @@ import java.io.StringReader import javax.swing.* import javax.xml.parsers.DocumentBuilderFactory import javax.xml.xpath.XPathFactory +import kotlin.time.Duration.Companion.milliseconds class NvidiaSMIVisualWindow(tab: SSHTerminalTab, visualWindowManager: VisualWindowManager) : SSHVisualWindow(tab, "NVIDIA-SMI", visualWindowManager) { @@ -264,7 +266,14 @@ class NvidiaSMIVisualWindow(tab: SSHTerminalTab, visualWindowManager: VisualWind 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 (code, text) = SshClients.execChannel(session, "nvidia-smi -x -q") diff --git a/src/main/kotlin/app/termora/terminal/panel/vw/extensions/NvidiaVisualWindowActionExtension.kt b/src/main/kotlin/app/termora/terminal/panel/vw/extensions/NvidiaVisualWindowActionExtension.kt new file mode 100644 index 0000000..7ffccf1 --- /dev/null +++ b/src/main/kotlin/app/termora/terminal/panel/vw/extensions/NvidiaVisualWindowActionExtension.kt @@ -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 { + return NvidiaSMIVisualWindow::class.java + } + + override fun ordered(): Long { + return 3; + } +} \ No newline at end of file diff --git a/src/main/kotlin/app/termora/terminal/panel/vw/extensions/ServerInfoVisualWindowActionExtension.kt b/src/main/kotlin/app/termora/terminal/panel/vw/extensions/ServerInfoVisualWindowActionExtension.kt new file mode 100644 index 0000000..9e771b3 --- /dev/null +++ b/src/main/kotlin/app/termora/terminal/panel/vw/extensions/ServerInfoVisualWindowActionExtension.kt @@ -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 { + if (tab !is SSHTerminalTab) throw UnsupportedOperationException() + return SystemInformationVisualWindow::class.java + } + + override fun ordered(): Long { + return -1; + } +} \ No newline at end of file diff --git a/src/main/kotlin/app/termora/terminal/panel/vw/extensions/SnippetVisualWindowActionExtension.kt b/src/main/kotlin/app/termora/terminal/panel/vw/extensions/SnippetVisualWindowActionExtension.kt new file mode 100644 index 0000000..3fe10f4 --- /dev/null +++ b/src/main/kotlin/app/termora/terminal/panel/vw/extensions/SnippetVisualWindowActionExtension.kt @@ -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 { + throw UnsupportedOperationException() + } + + override fun ordered(): Long { + return 2; + } +} \ No newline at end of file diff --git a/src/main/kotlin/app/termora/terminal/panel/vw/extensions/TransferVisualWindowActionExtension.kt b/src/main/kotlin/app/termora/terminal/panel/vw/extensions/TransferVisualWindowActionExtension.kt new file mode 100644 index 0000000..d0d7854 --- /dev/null +++ b/src/main/kotlin/app/termora/terminal/panel/vw/extensions/TransferVisualWindowActionExtension.kt @@ -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 { + if (tab !is SSHTerminalTab) throw UnsupportedOperationException() + return TransferVisualWindow::class.java + } + + override fun ordered(): Long { + return 1 + } +} \ No newline at end of file