mirror of
https://github.com/TermoraDev/termora.git
synced 2026-01-16 02:12:58 +08:00
feat: support fixed SFTP tab (#286)
This commit is contained in:
@@ -599,6 +599,12 @@ class Database private constructor(private val env: Environment) : Disposable {
|
|||||||
*/
|
*/
|
||||||
var sftpCommand by StringPropertyDelegate(StringUtils.EMPTY)
|
var sftpCommand by StringPropertyDelegate(StringUtils.EMPTY)
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 是否固定在标签栏
|
||||||
|
*/
|
||||||
|
var pinTab by BooleanPropertyDelegate(false)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -12,10 +12,11 @@ import javax.swing.SwingUtilities
|
|||||||
|
|
||||||
class SFTPTerminalTab : Disposable, TerminalTab, DataProvider {
|
class SFTPTerminalTab : Disposable, TerminalTab, DataProvider {
|
||||||
|
|
||||||
private val transportPanel by lazy {
|
private val sftp get() = Database.getDatabase().sftp
|
||||||
TransportPanel().apply {
|
private val transportPanel = TransportPanel()
|
||||||
Disposer.register(this@SFTPTerminalTab, this)
|
|
||||||
}
|
init {
|
||||||
|
Disposer.register(this, transportPanel)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun getTitle(): String {
|
override fun getTitle(): String {
|
||||||
@@ -43,6 +44,11 @@ class SFTPTerminalTab : Disposable, TerminalTab, DataProvider {
|
|||||||
|
|
||||||
override fun canClose(): Boolean {
|
override fun canClose(): Boolean {
|
||||||
assertEventDispatchThread()
|
assertEventDispatchThread()
|
||||||
|
|
||||||
|
if (sftp.pinTab) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
val transportManager = transportPanel.getData(TransportDataProviders.TransportManager) ?: return true
|
val transportManager = transportPanel.getData(TransportDataProviders.TransportManager) ?: return true
|
||||||
if (transportManager.getTransports().isEmpty()) {
|
if (transportManager.getTransports().isEmpty()) {
|
||||||
return true
|
return true
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ import app.termora.AES.encodeBase64String
|
|||||||
import app.termora.Application.ohMyJson
|
import app.termora.Application.ohMyJson
|
||||||
import app.termora.actions.AnAction
|
import app.termora.actions.AnAction
|
||||||
import app.termora.actions.AnActionEvent
|
import app.termora.actions.AnActionEvent
|
||||||
|
import app.termora.actions.DataProviders
|
||||||
import app.termora.highlight.KeywordHighlight
|
import app.termora.highlight.KeywordHighlight
|
||||||
import app.termora.highlight.KeywordHighlightManager
|
import app.termora.highlight.KeywordHighlightManager
|
||||||
import app.termora.keymap.Keymap
|
import app.termora.keymap.Keymap
|
||||||
@@ -22,6 +23,7 @@ import app.termora.terminal.CursorStyle
|
|||||||
import app.termora.terminal.DataKey
|
import app.termora.terminal.DataKey
|
||||||
import app.termora.terminal.panel.FloatingToolbarPanel
|
import app.termora.terminal.panel.FloatingToolbarPanel
|
||||||
import app.termora.terminal.panel.TerminalPanel
|
import app.termora.terminal.panel.TerminalPanel
|
||||||
|
import app.termora.transport.SFTPAction
|
||||||
import cash.z.ecc.android.bip39.Mnemonics
|
import cash.z.ecc.android.bip39.Mnemonics
|
||||||
import com.formdev.flatlaf.FlatClientProperties
|
import com.formdev.flatlaf.FlatClientProperties
|
||||||
import com.formdev.flatlaf.extras.FlatSVGIcon
|
import com.formdev.flatlaf.extras.FlatSVGIcon
|
||||||
@@ -43,6 +45,7 @@ import org.apache.commons.lang3.SystemUtils
|
|||||||
import org.apache.commons.lang3.exception.ExceptionUtils
|
import org.apache.commons.lang3.exception.ExceptionUtils
|
||||||
import org.apache.commons.lang3.time.DateFormatUtils
|
import org.apache.commons.lang3.time.DateFormatUtils
|
||||||
import org.jdesktop.swingx.JXEditorPane
|
import org.jdesktop.swingx.JXEditorPane
|
||||||
|
import org.jdesktop.swingx.action.ActionManager
|
||||||
import org.slf4j.LoggerFactory
|
import org.slf4j.LoggerFactory
|
||||||
import java.awt.BorderLayout
|
import java.awt.BorderLayout
|
||||||
import java.awt.Component
|
import java.awt.Component
|
||||||
@@ -67,6 +70,7 @@ class SettingsOptionsPane : OptionsPane() {
|
|||||||
private val hostManager get() = HostManager.getInstance()
|
private val hostManager get() = HostManager.getInstance()
|
||||||
private val keymapManager get() = KeymapManager.getInstance()
|
private val keymapManager get() = KeymapManager.getInstance()
|
||||||
private val macroManager get() = MacroManager.getInstance()
|
private val macroManager get() = MacroManager.getInstance()
|
||||||
|
private val actionManager get() = ActionManager.getInstance()
|
||||||
private val keywordHighlightManager get() = KeywordHighlightManager.getInstance()
|
private val keywordHighlightManager get() = KeywordHighlightManager.getInstance()
|
||||||
private val keyManager get() = KeyManager.getInstance()
|
private val keyManager get() = KeyManager.getInstance()
|
||||||
|
|
||||||
@@ -1306,9 +1310,11 @@ class SettingsOptionsPane : OptionsPane() {
|
|||||||
|
|
||||||
private inner class SFTPOption : JPanel(BorderLayout()), Option {
|
private inner class SFTPOption : JPanel(BorderLayout()), Option {
|
||||||
|
|
||||||
val editCommandField = OutlineTextField(255)
|
private val editCommandField = OutlineTextField(255)
|
||||||
val sftpCommandField = OutlineTextField(255)
|
private val sftpCommandField = OutlineTextField(255)
|
||||||
|
private val pinTabComboBox = YesOrNoComboBox()
|
||||||
private val sftp get() = database.sftp
|
private val sftp get() = database.sftp
|
||||||
|
private val sftpAction get() = actionManager.getAction(Actions.SFTP) as SFTPAction
|
||||||
|
|
||||||
init {
|
init {
|
||||||
initView()
|
initView()
|
||||||
@@ -1329,6 +1335,26 @@ class SettingsOptionsPane : OptionsPane() {
|
|||||||
sftp.sftpCommand = sftpCommandField.text
|
sftp.sftpCommand = sftpCommandField.text
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
pinTabComboBox.addItemListener {
|
||||||
|
if (it.stateChange == ItemEvent.SELECTED) {
|
||||||
|
sftp.pinTab = pinTabComboBox.selectedItem as Boolean
|
||||||
|
for (window in TermoraFrameManager.getInstance().getWindows()) {
|
||||||
|
val evt = AnActionEvent(window, StringUtils.EMPTY, EventObject(window))
|
||||||
|
if (pinTabComboBox.selectedItem == true) {
|
||||||
|
sftpAction.openOrCreateSFTPTerminalTab(evt)
|
||||||
|
}
|
||||||
|
val tabbed = evt.getData(DataProviders.TabbedPane) ?: continue
|
||||||
|
val manager = evt.getData(DataProviders.TerminalTabbedManager) ?: continue
|
||||||
|
for ((index, tab) in manager.getTerminalTabs().withIndex()) {
|
||||||
|
if (tab is SFTPTerminalTab) {
|
||||||
|
tabbed.setTabClosable(index, pinTabComboBox.selectedItem != true)
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -1347,6 +1373,7 @@ class SettingsOptionsPane : OptionsPane() {
|
|||||||
|
|
||||||
editCommandField.text = sftp.editCommand
|
editCommandField.text = sftp.editCommand
|
||||||
sftpCommandField.text = sftp.sftpCommand
|
sftpCommandField.text = sftp.sftpCommand
|
||||||
|
pinTabComboBox.selectedItem = sftp.pinTab
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun getIcon(isSelected: Boolean): Icon {
|
override fun getIcon(isSelected: Boolean): Icon {
|
||||||
@@ -1368,10 +1395,12 @@ class SettingsOptionsPane : OptionsPane() {
|
|||||||
)
|
)
|
||||||
|
|
||||||
val builder = FormBuilder.create().layout(layout).debug(false)
|
val builder = FormBuilder.create().layout(layout).debug(false)
|
||||||
builder.add("${I18n.getString("termora.settings.sftp.edit-command")}:").xy(1, 1)
|
builder.add("${I18n.getString("termora.settings.sftp.fixed-tab")}:").xy(1, 1)
|
||||||
builder.add(editCommandField).xy(3, 1)
|
builder.add(pinTabComboBox).xy(3, 1)
|
||||||
builder.add("${I18n.getString("termora.tabbed.contextmenu.sftp-command")}:").xy(1, 3)
|
builder.add("${I18n.getString("termora.settings.sftp.edit-command")}:").xy(1, 3)
|
||||||
builder.add(sftpCommandField).xy(3, 3)
|
builder.add(editCommandField).xy(3, 3)
|
||||||
|
builder.add("${I18n.getString("termora.tabbed.contextmenu.sftp-command")}:").xy(1, 5)
|
||||||
|
builder.add(sftpCommandField).xy(3, 5)
|
||||||
|
|
||||||
return builder.build()
|
return builder.build()
|
||||||
|
|
||||||
|
|||||||
@@ -280,7 +280,7 @@ class TerminalTabbed(
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
close.isEnabled = c !is WelcomePanel
|
close.isEnabled = tab.canClose()
|
||||||
rename.isEnabled = close.isEnabled
|
rename.isEnabled = close.isEnabled
|
||||||
clone.isEnabled = close.isEnabled
|
clone.isEnabled = close.isEnabled
|
||||||
openInNewWindow.isEnabled = close.isEnabled
|
openInNewWindow.isEnabled = close.isEnabled
|
||||||
@@ -306,7 +306,7 @@ class TerminalTabbed(
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private fun addTab(index: Int, tab: TerminalTab) {
|
private fun addTab(index: Int, tab: TerminalTab, selected: Boolean) {
|
||||||
val c = tab.getJComponent()
|
val c = tab.getJComponent()
|
||||||
val title = (c.getClientProperty(titleProperty) ?: tab.getTitle()).toString()
|
val title = (c.getClientProperty(titleProperty) ?: tab.getTitle()).toString()
|
||||||
|
|
||||||
@@ -317,13 +317,20 @@ class TerminalTabbed(
|
|||||||
StringUtils.EMPTY,
|
StringUtils.EMPTY,
|
||||||
index
|
index
|
||||||
)
|
)
|
||||||
c.putClientProperty(titleProperty, title)
|
|
||||||
|
|
||||||
|
// 设置标题
|
||||||
|
c.putClientProperty(titleProperty, title)
|
||||||
// 监听 icons 变化
|
// 监听 icons 变化
|
||||||
tab.addPropertyChangeListener(iconListener)
|
tab.addPropertyChangeListener(iconListener)
|
||||||
|
|
||||||
tabs.add(index, tab)
|
tabs.add(index, tab)
|
||||||
|
|
||||||
|
if (selected) {
|
||||||
tabbedPane.selectedIndex = index
|
tabbedPane.selectedIndex = index
|
||||||
|
}
|
||||||
|
|
||||||
|
tabbedPane.setTabClosable(index, tab.canClose())
|
||||||
|
|
||||||
Disposer.register(this, tab)
|
Disposer.register(this, tab)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -445,12 +452,12 @@ class TerminalTabbed(
|
|||||||
override fun dispose() {
|
override fun dispose() {
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun addTerminalTab(tab: TerminalTab) {
|
override fun addTerminalTab(tab: TerminalTab, selected: Boolean) {
|
||||||
addTab(tabs.size, tab)
|
addTab(tabs.size, tab, selected)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun addTerminalTab(index: Int, tab: TerminalTab) {
|
override fun addTerminalTab(index: Int, tab: TerminalTab, selected: Boolean) {
|
||||||
addTab(index, tab)
|
addTab(index, tab, selected)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun getSelectedTerminalTab(): TerminalTab? {
|
override fun getSelectedTerminalTab(): TerminalTab? {
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
package app.termora
|
package app.termora
|
||||||
|
|
||||||
interface TerminalTabbedManager {
|
interface TerminalTabbedManager {
|
||||||
fun addTerminalTab(tab: TerminalTab)
|
fun addTerminalTab(tab: TerminalTab, selected: Boolean = true)
|
||||||
fun addTerminalTab(index: Int, tab: TerminalTab)
|
fun addTerminalTab(index: Int, tab: TerminalTab, selected: Boolean = true)
|
||||||
fun getSelectedTerminalTab(): TerminalTab?
|
fun getSelectedTerminalTab(): TerminalTab?
|
||||||
fun getTerminalTabs(): List<TerminalTab>
|
fun getTerminalTabs(): List<TerminalTab>
|
||||||
fun setSelectedTerminalTab(tab: TerminalTab)
|
fun setSelectedTerminalTab(tab: TerminalTab)
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
package app.termora
|
package app.termora
|
||||||
|
|
||||||
|
|
||||||
import app.termora.actions.ActionManager
|
|
||||||
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
|
||||||
@@ -12,7 +11,6 @@ import com.formdev.flatlaf.util.SystemInfo
|
|||||||
import com.jetbrains.JBR
|
import com.jetbrains.JBR
|
||||||
import java.awt.Dimension
|
import java.awt.Dimension
|
||||||
import java.awt.Insets
|
import java.awt.Insets
|
||||||
import java.awt.KeyboardFocusManager
|
|
||||||
import java.awt.event.MouseAdapter
|
import java.awt.event.MouseAdapter
|
||||||
import java.awt.event.MouseEvent
|
import java.awt.event.MouseEvent
|
||||||
import java.util.*
|
import java.util.*
|
||||||
@@ -32,7 +30,6 @@ fun assertEventDispatchThread() {
|
|||||||
class TermoraFrame : JFrame(), DataProvider {
|
class TermoraFrame : JFrame(), DataProvider {
|
||||||
|
|
||||||
|
|
||||||
private val actionManager get() = ActionManager.getInstance()
|
|
||||||
private val id = UUID.randomUUID().toString()
|
private val id = UUID.randomUUID().toString()
|
||||||
private val windowScope = ApplicationScope.forWindowScope(this)
|
private val windowScope = ApplicationScope.forWindowScope(this)
|
||||||
private val titleBar = LogicCustomTitleBar.createCustomTitleBar(this)
|
private val titleBar = LogicCustomTitleBar.createCustomTitleBar(this)
|
||||||
@@ -42,7 +39,7 @@ class TermoraFrame : JFrame(), DataProvider {
|
|||||||
private val isWindowDecorationsSupported by lazy { JBR.isWindowDecorationsSupported() }
|
private val isWindowDecorationsSupported by lazy { JBR.isWindowDecorationsSupported() }
|
||||||
private val dataProviderSupport = DataProviderSupport()
|
private val dataProviderSupport = DataProviderSupport()
|
||||||
private val welcomePanel = WelcomePanel(windowScope)
|
private val welcomePanel = WelcomePanel(windowScope)
|
||||||
private val keyboardFocusManager by lazy { KeyboardFocusManager.getCurrentKeyboardFocusManager() }
|
private val sftp get() = Database.getDatabase().sftp
|
||||||
|
|
||||||
|
|
||||||
init {
|
init {
|
||||||
@@ -103,6 +100,13 @@ class TermoraFrame : JFrame(), DataProvider {
|
|||||||
minimumSize = Dimension(640, 400)
|
minimumSize = Dimension(640, 400)
|
||||||
terminalTabbed.addTerminalTab(welcomePanel)
|
terminalTabbed.addTerminalTab(welcomePanel)
|
||||||
|
|
||||||
|
// 下一次事件循环检测是否固定 SFTP
|
||||||
|
SwingUtilities.invokeLater {
|
||||||
|
if (sftp.pinTab) {
|
||||||
|
terminalTabbed.addTerminalTab(SFTPTerminalTab(), false)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// macOS 要避开左边的控制栏
|
// macOS 要避开左边的控制栏
|
||||||
if (SystemInfo.isMacOS) {
|
if (SystemInfo.isMacOS) {
|
||||||
val left = max(titleBar.leftInset.toInt(), 76)
|
val left = max(titleBar.leftInset.toInt(), 76)
|
||||||
|
|||||||
@@ -23,20 +23,22 @@ class SFTPAction : AnAction("SFTP", Icons.folder) {
|
|||||||
*
|
*
|
||||||
* @return null 表示当前条件下无法创建
|
* @return null 表示当前条件下无法创建
|
||||||
*/
|
*/
|
||||||
fun openOrCreateSFTPTerminalTab(evt: AnActionEvent): SFTPTerminalTab? {
|
fun openOrCreateSFTPTerminalTab(evt: AnActionEvent, selected: Boolean = true): SFTPTerminalTab? {
|
||||||
val terminalTabbedManager = evt.getData(DataProviders.TerminalTabbedManager) ?: return null
|
val terminalTabbedManager = evt.getData(DataProviders.TerminalTabbedManager) ?: return null
|
||||||
|
|
||||||
val tabs = terminalTabbedManager.getTerminalTabs()
|
val tabs = terminalTabbedManager.getTerminalTabs()
|
||||||
for (tab in tabs) {
|
for (tab in tabs) {
|
||||||
if (tab is SFTPTerminalTab) {
|
if (tab is SFTPTerminalTab) {
|
||||||
|
if (selected) {
|
||||||
terminalTabbedManager.setSelectedTerminalTab(tab)
|
terminalTabbedManager.setSelectedTerminalTab(tab)
|
||||||
|
}
|
||||||
return tab
|
return tab
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 创建一个新的
|
// 创建一个新的
|
||||||
val tab = SFTPTerminalTab()
|
val tab = SFTPTerminalTab()
|
||||||
terminalTabbedManager.addTerminalTab(tab)
|
terminalTabbedManager.addTerminalTab(tab, selected)
|
||||||
|
|
||||||
return tab
|
return tab
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -110,6 +110,7 @@ termora.settings.keymap.already-exists=The shortcut [{0}] is already in use by [
|
|||||||
|
|
||||||
|
|
||||||
termora.settings.sftp.edit-command=Edit Command
|
termora.settings.sftp.edit-command=Edit Command
|
||||||
|
termora.settings.sftp.fixed-tab=Fixed tab
|
||||||
|
|
||||||
|
|
||||||
termora.settings.restart.title=Restart
|
termora.settings.restart.title=Restart
|
||||||
|
|||||||
@@ -113,6 +113,7 @@ termora.settings.keymap.already-exists=快捷键 [{0}] 已经被 [{1}] 占用
|
|||||||
|
|
||||||
|
|
||||||
termora.settings.sftp.edit-command=编辑命令
|
termora.settings.sftp.edit-command=编辑命令
|
||||||
|
termora.settings.sftp.fixed-tab=固定标签
|
||||||
|
|
||||||
|
|
||||||
# Welcome
|
# Welcome
|
||||||
|
|||||||
@@ -63,6 +63,7 @@ termora.settings.keymap.action=操作
|
|||||||
termora.settings.keymap.already-exists=快捷鍵 [{0}] 已經被 [{1}] 占用
|
termora.settings.keymap.already-exists=快捷鍵 [{0}] 已經被 [{1}] 占用
|
||||||
|
|
||||||
termora.settings.sftp.edit-command=編輯命令
|
termora.settings.sftp.edit-command=編輯命令
|
||||||
|
termora.settings.sftp.fixed-tab=固定標籤
|
||||||
|
|
||||||
|
|
||||||
# Find everywhere
|
# Find everywhere
|
||||||
|
|||||||
Reference in New Issue
Block a user