mirror of
https://github.com/TermoraDev/termora.git
synced 2026-01-16 02:12:58 +08:00
feat: supports custom editing of SFTP command (#210)
This commit is contained in:
@@ -14,6 +14,7 @@ import kotlinx.coroutines.GlobalScope
|
|||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
import kotlinx.serialization.encodeToString
|
import kotlinx.serialization.encodeToString
|
||||||
import org.apache.commons.io.IOUtils
|
import org.apache.commons.io.IOUtils
|
||||||
|
import org.apache.commons.lang3.StringUtils
|
||||||
import org.slf4j.LoggerFactory
|
import org.slf4j.LoggerFactory
|
||||||
import java.io.File
|
import java.io.File
|
||||||
import java.util.*
|
import java.util.*
|
||||||
@@ -55,6 +56,7 @@ class Database private constructor(private val env: Environment) : Disposable {
|
|||||||
val safetyProperties by lazy { SafetyProperties("Setting.SafetyProperties") }
|
val safetyProperties by lazy { SafetyProperties("Setting.SafetyProperties") }
|
||||||
val terminal by lazy { Terminal() }
|
val terminal by lazy { Terminal() }
|
||||||
val appearance by lazy { Appearance() }
|
val appearance by lazy { Appearance() }
|
||||||
|
val sftp by lazy { SFTP() }
|
||||||
val sync by lazy { Sync() }
|
val sync by lazy { Sync() }
|
||||||
|
|
||||||
private val doorman get() = Doorman.getInstance()
|
private val doorman get() = Doorman.getInstance()
|
||||||
@@ -573,6 +575,19 @@ class Database private constructor(private val env: Environment) : Disposable {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* SFTP
|
||||||
|
*/
|
||||||
|
inner class SFTP : Property("Setting.SFTP") {
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 编辑命令
|
||||||
|
*/
|
||||||
|
var editCommand by StringPropertyDelegate(StringUtils.EMPTY)
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 同步配置
|
* 同步配置
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -109,6 +109,7 @@ class SettingsOptionsPane : OptionsPane() {
|
|||||||
addOption(AppearanceOption())
|
addOption(AppearanceOption())
|
||||||
addOption(TerminalOption())
|
addOption(TerminalOption())
|
||||||
addOption(KeyShortcutsOption())
|
addOption(KeyShortcutsOption())
|
||||||
|
addOption(SFTPOption())
|
||||||
addOption(CloudSyncOption())
|
addOption(CloudSyncOption())
|
||||||
addOption(DoormanOption())
|
addOption(DoormanOption())
|
||||||
addOption(AboutOption())
|
addOption(AboutOption())
|
||||||
@@ -1172,6 +1173,63 @@ class SettingsOptionsPane : OptionsPane() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private inner class SFTPOption : JPanel(BorderLayout()), Option {
|
||||||
|
|
||||||
|
val editCommandField = OutlineTextField(255)
|
||||||
|
private val sftp get() = database.sftp
|
||||||
|
|
||||||
|
init {
|
||||||
|
initView()
|
||||||
|
initEvents()
|
||||||
|
add(getCenterComponent(), BorderLayout.CENTER)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun initEvents() {
|
||||||
|
editCommandField.document.addDocumentListener(object : DocumentAdaptor() {
|
||||||
|
override fun changedUpdate(e: DocumentEvent) {
|
||||||
|
sftp.editCommand = editCommandField.text
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private fun initView() {
|
||||||
|
if (SystemInfo.isWindows || SystemInfo.isLinux) {
|
||||||
|
editCommandField.placeholderText = "notepad {0}"
|
||||||
|
} else if (SystemInfo.isMacOS) {
|
||||||
|
editCommandField.placeholderText = "open -a TextEdit {0}"
|
||||||
|
}
|
||||||
|
|
||||||
|
editCommandField.text = sftp.editCommand
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getIcon(isSelected: Boolean): Icon {
|
||||||
|
return Icons.folder
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getTitle(): String {
|
||||||
|
return "SFTP"
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getJComponent(): JComponent {
|
||||||
|
return this
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun getCenterComponent(): JComponent {
|
||||||
|
val layout = FormLayout(
|
||||||
|
"left:pref, $formMargin, default:grow, 30dlu",
|
||||||
|
"pref, $formMargin, pref, $formMargin, pref, $formMargin, pref, $formMargin, pref, $formMargin, pref"
|
||||||
|
)
|
||||||
|
|
||||||
|
val builder = FormBuilder.create().layout(layout).debug(false)
|
||||||
|
builder.add("${I18n.getString("termora.settings.sftp.edit-command")}:").xy(1, 1)
|
||||||
|
builder.add(editCommandField).xy(3, 1)
|
||||||
|
|
||||||
|
return builder.build()
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private inner class AboutOption : JPanel(BorderLayout()), Option {
|
private inner class AboutOption : JPanel(BorderLayout()), Option {
|
||||||
|
|
||||||
init {
|
init {
|
||||||
|
|||||||
@@ -33,7 +33,9 @@ import java.awt.event.MouseAdapter
|
|||||||
import java.awt.event.MouseEvent
|
import java.awt.event.MouseEvent
|
||||||
import java.io.File
|
import java.io.File
|
||||||
import java.nio.file.*
|
import java.nio.file.*
|
||||||
|
import java.text.MessageFormat
|
||||||
import java.util.*
|
import java.util.*
|
||||||
|
import java.util.regex.Pattern
|
||||||
import javax.swing.*
|
import javax.swing.*
|
||||||
import javax.swing.table.DefaultTableCellRenderer
|
import javax.swing.table.DefaultTableCellRenderer
|
||||||
import kotlin.io.path.absolutePathString
|
import kotlin.io.path.absolutePathString
|
||||||
@@ -489,8 +491,8 @@ class FileSystemPanel(
|
|||||||
|
|
||||||
// 编辑
|
// 编辑
|
||||||
val edit = popupMenu.add(I18n.getString("termora.transport.table.contextmenu.edit"))
|
val edit = popupMenu.add(I18n.getString("termora.transport.table.contextmenu.edit"))
|
||||||
// 不是 Linux & 不是本地文件系统 & 包含文件
|
// 不是本地文件系统 & 包含文件
|
||||||
edit.isEnabled = !SystemInfo.isLinux && !tableModel.isLocalFileSystem && paths.any { !it.isDirectory }
|
edit.isEnabled = !tableModel.isLocalFileSystem && paths.any { !it.isDirectory }
|
||||||
edit.addActionListener {
|
edit.addActionListener {
|
||||||
val files = paths.filter { !it.isDirectory }
|
val files = paths.filter { !it.isDirectory }
|
||||||
if (files.isNotEmpty()) {
|
if (files.isNotEmpty()) {
|
||||||
@@ -615,20 +617,38 @@ class FileSystemPanel(
|
|||||||
|
|
||||||
private fun editFileTransportListener(source: Path, localPath: Path): TransportListener {
|
private fun editFileTransportListener(source: Path, localPath: Path): TransportListener {
|
||||||
return object : TransportListener {
|
return object : TransportListener {
|
||||||
|
private val sftp get() = Database.getDatabase().sftp
|
||||||
override fun onTransportChanged(transport: Transport) {
|
override fun onTransportChanged(transport: Transport) {
|
||||||
// 传输成功
|
// 传输成功
|
||||||
if (transport.state == TransportState.Done) {
|
if (transport.state == TransportState.Done) {
|
||||||
val transportManager = evt.getData(TransportDataProviders.TransportManager) ?: return
|
val transportManager = evt.getData(TransportDataProviders.TransportManager) ?: return
|
||||||
var lastModifiedTime = localPath.getLastModifiedTime().toMillis()
|
var lastModifiedTime = localPath.getLastModifiedTime().toMillis()
|
||||||
|
|
||||||
if (SystemInfo.isMacOS) {
|
try {
|
||||||
ProcessBuilder("open", "-a", "TextEdit", localPath.absolutePathString()).start()
|
if (sftp.editCommand.isNotBlank()) {
|
||||||
} else if (SystemInfo.isWindows) {
|
ProcessBuilder(
|
||||||
ProcessBuilder("notepad", localPath.absolutePathString()).start()
|
parseCommand(
|
||||||
} else {
|
MessageFormat.format(
|
||||||
|
sftp.editCommand,
|
||||||
|
localPath.absolutePathString()
|
||||||
|
)
|
||||||
|
)
|
||||||
|
).start()
|
||||||
|
} else if (SystemInfo.isMacOS) {
|
||||||
|
ProcessBuilder("open", "-a", "TextEdit", localPath.absolutePathString()).start()
|
||||||
|
} else if (SystemInfo.isWindows) {
|
||||||
|
ProcessBuilder("notepad", localPath.absolutePathString()).start()
|
||||||
|
} else {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
} catch (e: Exception) {
|
||||||
|
if (log.isErrorEnabled) {
|
||||||
|
log.error(e.message, e)
|
||||||
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
coroutineScope.launch(Dispatchers.IO) {
|
coroutineScope.launch(Dispatchers.IO) {
|
||||||
while (coroutineScope.isActive) {
|
while (coroutineScope.isActive) {
|
||||||
try {
|
try {
|
||||||
@@ -657,6 +677,20 @@ class FileSystemPanel(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun parseCommand(command: String): List<String> {
|
||||||
|
val result = mutableListOf<String>()
|
||||||
|
val matcher = Pattern.compile("\"([^\"]*)\"|(\\S+)").matcher(command)
|
||||||
|
|
||||||
|
while (matcher.find()) {
|
||||||
|
if (matcher.group(1) != null) {
|
||||||
|
result.add(matcher.group(1)) // 处理双引号部分
|
||||||
|
} else {
|
||||||
|
result.add(matcher.group(2).replace("\\\\ ", " "))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -106,6 +106,9 @@ termora.settings.keymap.action=Action
|
|||||||
termora.settings.keymap.already-exists=The shortcut [{0}] is already in use by [{1}]
|
termora.settings.keymap.already-exists=The shortcut [{0}] is already in use by [{1}]
|
||||||
|
|
||||||
|
|
||||||
|
termora.settings.sftp.edit-command=Edit Command
|
||||||
|
|
||||||
|
|
||||||
termora.settings.restart.title=Restart
|
termora.settings.restart.title=Restart
|
||||||
termora.settings.restart.message=Changes will take effect after restarting the application
|
termora.settings.restart.message=Changes will take effect after restarting the application
|
||||||
|
|
||||||
|
|||||||
@@ -110,6 +110,10 @@ termora.settings.keymap.shortcut=快捷键
|
|||||||
termora.settings.keymap.action=操作
|
termora.settings.keymap.action=操作
|
||||||
termora.settings.keymap.already-exists=快捷键 [{0}] 已经被 [{1}] 占用
|
termora.settings.keymap.already-exists=快捷键 [{0}] 已经被 [{1}] 占用
|
||||||
|
|
||||||
|
|
||||||
|
termora.settings.sftp.edit-command=编辑命令
|
||||||
|
|
||||||
|
|
||||||
# Welcome
|
# Welcome
|
||||||
termora.welcome.my-hosts=我的主机
|
termora.welcome.my-hosts=我的主机
|
||||||
termora.welcome.contextmenu.open=打开
|
termora.welcome.contextmenu.open=打开
|
||||||
|
|||||||
@@ -62,6 +62,8 @@ termora.settings.keymap.shortcut=快捷鍵
|
|||||||
termora.settings.keymap.action=操作
|
termora.settings.keymap.action=操作
|
||||||
termora.settings.keymap.already-exists=快捷鍵 [{0}] 已經被 [{1}] 占用
|
termora.settings.keymap.already-exists=快捷鍵 [{0}] 已經被 [{1}] 占用
|
||||||
|
|
||||||
|
termora.settings.sftp.edit-command=編輯命令
|
||||||
|
|
||||||
|
|
||||||
# Find everywhere
|
# Find everywhere
|
||||||
termora.find-everywhere=尋找
|
termora.find-everywhere=尋找
|
||||||
|
|||||||
Reference in New Issue
Block a user