mirror of
https://github.com/TermoraDev/termora.git
synced 2026-01-16 02:12:58 +08:00
feat: SFTP file editing support (#209)
This commit is contained in:
@@ -73,6 +73,9 @@ class ApplicationRunner {
|
||||
// 解密数据
|
||||
val openDoor = measureTimeMillis { openDoor() }
|
||||
|
||||
// clear temporary
|
||||
clearTemporary()
|
||||
|
||||
// 启动主窗口
|
||||
val startMainFrame = measureTimeMillis { startMainFrame() }
|
||||
|
||||
@@ -94,6 +97,22 @@ class ApplicationRunner {
|
||||
}
|
||||
}
|
||||
|
||||
@Suppress("OPT_IN_USAGE")
|
||||
private fun clearTemporary() {
|
||||
GlobalScope.launch(Dispatchers.IO) {
|
||||
|
||||
// 启动时清除
|
||||
FileUtils.cleanDirectory(File(Application.getBaseDataDir(), "temporary"))
|
||||
|
||||
// 关闭时清除
|
||||
Disposer.register(ApplicationScope.forApplicationScope(), object : Disposable {
|
||||
override fun dispose() {
|
||||
FileUtils.cleanDirectory(File(Application.getBaseDataDir(), "temporary"))
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private fun openDoor() {
|
||||
if (Doorman.getInstance().isWorking()) {
|
||||
|
||||
@@ -12,6 +12,7 @@ import com.formdev.flatlaf.util.SystemInfo
|
||||
import kotlinx.coroutines.*
|
||||
import kotlinx.coroutines.swing.Swing
|
||||
import org.apache.commons.io.FileUtils
|
||||
import org.apache.commons.io.file.PathUtils
|
||||
import org.apache.commons.lang3.StringUtils
|
||||
import org.apache.commons.lang3.SystemUtils
|
||||
import org.apache.commons.lang3.exception.ExceptionUtils
|
||||
@@ -35,8 +36,11 @@ import java.nio.file.*
|
||||
import java.util.*
|
||||
import javax.swing.*
|
||||
import javax.swing.table.DefaultTableCellRenderer
|
||||
import kotlin.io.path.absolutePathString
|
||||
import kotlin.io.path.exists
|
||||
import kotlin.io.path.getLastModifiedTime
|
||||
import kotlin.io.path.isDirectory
|
||||
import kotlin.time.Duration.Companion.milliseconds
|
||||
|
||||
|
||||
/**
|
||||
@@ -44,9 +48,8 @@ import kotlin.io.path.isDirectory
|
||||
*/
|
||||
class FileSystemPanel(
|
||||
private val fileSystem: FileSystem,
|
||||
private val transportManager: TransportManager,
|
||||
private val host: Host
|
||||
) : JPanel(BorderLayout()), Disposable, FileSystemTransportListener.Provider {
|
||||
) : JPanel(BorderLayout()), Disposable {
|
||||
|
||||
companion object {
|
||||
private val log = LoggerFactory.getLogger(FileSystemPanel::class.java)
|
||||
@@ -64,6 +67,12 @@ class FileSystemPanel(
|
||||
private val showHiddenFilesBtn = JButton(Icons.eyeClose)
|
||||
private val properties get() = Database.getDatabase().properties
|
||||
private val showHiddenFilesKey by lazy { "termora.transport.host.${host.id}.show-hidden-files" }
|
||||
private val evt by lazy { AnActionEvent(this, StringUtils.EMPTY, EventObject(this)) }
|
||||
|
||||
/**
|
||||
* Edit
|
||||
*/
|
||||
private val coroutineScope by lazy { CoroutineScope(Dispatchers.IO + SupervisorJob()) }
|
||||
|
||||
val workdir get() = tableModel.workdir
|
||||
|
||||
@@ -342,6 +351,9 @@ class FileSystemPanel(
|
||||
|
||||
}
|
||||
|
||||
override fun dispose() {
|
||||
coroutineScope.cancel()
|
||||
}
|
||||
|
||||
private fun copyLocalFileToFileSystem(files: List<File>) {
|
||||
val event = AnActionEvent(this, StringUtils.EMPTY, EventObject(this))
|
||||
@@ -425,14 +437,6 @@ class FileSystemPanel(
|
||||
}
|
||||
|
||||
|
||||
override fun addFileSystemTransportListener(listener: FileSystemTransportListener) {
|
||||
listenerList.add(FileSystemTransportListener::class.java, listener)
|
||||
}
|
||||
|
||||
override fun removeFileSystemTransportListener(listener: FileSystemTransportListener) {
|
||||
listenerList.remove(FileSystemTransportListener::class.java, listener)
|
||||
}
|
||||
|
||||
private fun openFolder() {
|
||||
val row = table.selectedRow
|
||||
if (row < 0) return
|
||||
@@ -460,6 +464,7 @@ class FileSystemPanel(
|
||||
|
||||
|
||||
private fun showContextMenu(rows: IntArray, event: MouseEvent) {
|
||||
val paths = rows.filter { it != 0 }.map { tableModel.getCacheablePath(it) }
|
||||
val popupMenu = FlatPopupMenu()
|
||||
val newMenu = JMenu(I18n.getString("termora.transport.table.contextmenu.new"))
|
||||
|
||||
@@ -477,11 +482,22 @@ class FileSystemPanel(
|
||||
// 传输
|
||||
val transfer = popupMenu.add(I18n.getString("termora.transport.table.contextmenu.transfer"))
|
||||
transfer.addActionListener {
|
||||
val paths = rows.filter { it != 0 }.map { tableModel.getCacheablePath(it) }
|
||||
if (paths.isNotEmpty()) {
|
||||
transport(paths)
|
||||
}
|
||||
}
|
||||
|
||||
// 编辑
|
||||
val edit = popupMenu.add(I18n.getString("termora.transport.table.contextmenu.edit"))
|
||||
// 不是 Linux & 不是本地文件系统 & 包含文件
|
||||
edit.isEnabled = !SystemInfo.isLinux && !tableModel.isLocalFileSystem && paths.any { !it.isDirectory }
|
||||
edit.addActionListener {
|
||||
val files = paths.filter { !it.isDirectory }
|
||||
if (files.isNotEmpty()) {
|
||||
editFiles(files)
|
||||
}
|
||||
}
|
||||
|
||||
popupMenu.addSeparator()
|
||||
|
||||
// 复制路径
|
||||
@@ -574,6 +590,75 @@ class FileSystemPanel(
|
||||
popupMenu.show(table, event.x, event.y)
|
||||
}
|
||||
|
||||
private fun editFiles(files: List<FileSystemTableModel.CacheablePath>) {
|
||||
if (files.isEmpty()) return
|
||||
val transportManager = evt.getData(TransportDataProviders.TransportManager) ?: return
|
||||
|
||||
val temporary = Paths.get(Application.getBaseDataDir().absolutePath, "temporary")
|
||||
Files.createDirectories(temporary)
|
||||
|
||||
for (file in files) {
|
||||
val dir = Files.createTempDirectory(temporary, "termora-")
|
||||
val path = Paths.get(dir.absolutePathString(), file.fileName)
|
||||
transportManager.addTransport(
|
||||
transport = FileTransport(
|
||||
name = file.fileName,
|
||||
source = file.path,
|
||||
target = path,
|
||||
sourceHolder = this,
|
||||
targetHolder = this,
|
||||
listener = editFileTransportListener(file.path, path)
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private fun editFileTransportListener(source: Path, localPath: Path): TransportListener {
|
||||
return object : TransportListener {
|
||||
override fun onTransportChanged(transport: Transport) {
|
||||
// 传输成功
|
||||
if (transport.state == TransportState.Done) {
|
||||
val transportManager = evt.getData(TransportDataProviders.TransportManager) ?: return
|
||||
var lastModifiedTime = localPath.getLastModifiedTime().toMillis()
|
||||
|
||||
if (SystemInfo.isMacOS) {
|
||||
ProcessBuilder("open", "-a", "TextEdit", localPath.absolutePathString()).start()
|
||||
} else if (SystemInfo.isWindows) {
|
||||
ProcessBuilder("notepad", localPath.absolutePathString()).start()
|
||||
} else {
|
||||
return
|
||||
}
|
||||
|
||||
coroutineScope.launch(Dispatchers.IO) {
|
||||
while (coroutineScope.isActive) {
|
||||
try {
|
||||
val nowModifiedTime = localPath.getLastModifiedTime().toMillis()
|
||||
if (nowModifiedTime != lastModifiedTime) {
|
||||
lastModifiedTime = nowModifiedTime
|
||||
// upload
|
||||
transportManager.addTransport(
|
||||
transport = FileTransport(
|
||||
name = PathUtils.getFileNameString(localPath.fileName),
|
||||
source = localPath,
|
||||
target = source,
|
||||
sourceHolder = this@FileSystemPanel,
|
||||
targetHolder = this@FileSystemPanel,
|
||||
)
|
||||
)
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
if (log.isErrorEnabled) {
|
||||
log.error(e.message, e)
|
||||
}
|
||||
break
|
||||
}
|
||||
delay(250.milliseconds)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@OptIn(DelicateCoroutinesApi::class)
|
||||
private fun renamePath(path: Path) {
|
||||
@@ -789,17 +874,31 @@ class FileSystemPanel(
|
||||
|
||||
private suspend fun doTransport(paths: List<FileSystemTableModel.CacheablePath>) {
|
||||
if (paths.isEmpty()) return
|
||||
|
||||
val listeners = listenerList.getListeners(FileSystemTransportListener::class.java)
|
||||
if (listeners.isEmpty()) return
|
||||
|
||||
val transportPanel = evt.getData(TransportDataProviders.TransportPanel) ?: return
|
||||
val leftFileSystemPanel = evt.getData(TransportDataProviders.LeftFileSystemPanel) ?: return
|
||||
val rightFileSystemPanel = evt.getData(TransportDataProviders.RightFileSystemPanel) ?: return
|
||||
val sourceFileSystemPanel = this
|
||||
val targetFileSystemPanel = if (this == leftFileSystemPanel) rightFileSystemPanel else leftFileSystemPanel
|
||||
|
||||
// 收集数据
|
||||
for (e in paths) {
|
||||
|
||||
if (!e.isDirectory) {
|
||||
val job = TransportJob(
|
||||
fileSystemPanel = this,
|
||||
workdir = workdir,
|
||||
isDirectory = false,
|
||||
path = e.path,
|
||||
)
|
||||
withContext(Dispatchers.Swing) {
|
||||
listeners.forEach { it.transport(this@FileSystemPanel, workdir, false, e.path) }
|
||||
transportPanel.transport(
|
||||
sourceWorkdir = workdir,
|
||||
targetWorkdir = targetFileSystemPanel.workdir,
|
||||
isSourceDirectory = false,
|
||||
sourcePath = e.path,
|
||||
sourceHolder = sourceFileSystemPanel,
|
||||
targetHolder = targetFileSystemPanel
|
||||
)
|
||||
}
|
||||
continue
|
||||
}
|
||||
@@ -811,12 +910,26 @@ class FileSystemPanel(
|
||||
val isDirectory = if (path.attributes != null)
|
||||
path.attributes.isDirectory else path.isDirectory()
|
||||
withContext(Dispatchers.Swing) {
|
||||
listeners.forEach { it.transport(this@FileSystemPanel, workdir, isDirectory, path) }
|
||||
transportPanel.transport(
|
||||
sourceWorkdir = workdir,
|
||||
targetWorkdir = targetFileSystemPanel.workdir,
|
||||
isSourceDirectory = isDirectory,
|
||||
sourcePath = path,
|
||||
sourceHolder = sourceFileSystemPanel,
|
||||
targetHolder = targetFileSystemPanel
|
||||
)
|
||||
}
|
||||
} else {
|
||||
val isDirectory = path.isDirectory()
|
||||
withContext(Dispatchers.Swing) {
|
||||
listeners.forEach { it.transport(this@FileSystemPanel, workdir, isDirectory, path) }
|
||||
transportPanel.transport(
|
||||
sourceWorkdir = workdir,
|
||||
targetWorkdir = targetFileSystemPanel.workdir,
|
||||
isSourceDirectory = isDirectory,
|
||||
sourcePath = path,
|
||||
sourceHolder = sourceFileSystemPanel,
|
||||
targetHolder = targetFileSystemPanel
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,9 +3,9 @@ package app.termora.transport
|
||||
import app.termora.*
|
||||
import com.formdev.flatlaf.extras.components.FlatTabbedPane
|
||||
import org.apache.commons.lang3.StringUtils
|
||||
import java.awt.Component
|
||||
import java.awt.Point
|
||||
import java.nio.file.FileSystems
|
||||
import java.nio.file.Path
|
||||
import javax.swing.*
|
||||
import kotlin.math.max
|
||||
|
||||
@@ -13,9 +13,8 @@ import kotlin.math.max
|
||||
class FileSystemTabbed(
|
||||
private val transportManager: TransportManager,
|
||||
private val isLeft: Boolean = false
|
||||
) : FlatTabbedPane(), FileSystemTransportListener.Provider, Disposable {
|
||||
) : FlatTabbedPane(), Disposable {
|
||||
private val addBtn = JButton(Icons.add)
|
||||
private val listeners = mutableListOf<FileSystemTransportListener>()
|
||||
|
||||
init {
|
||||
initView()
|
||||
@@ -36,23 +35,20 @@ class FileSystemTabbed(
|
||||
trailingComponent = toolbar
|
||||
|
||||
if (isLeft) {
|
||||
addFileSystemTransportProvider(
|
||||
I18n.getString("termora.transport.local"),
|
||||
FileSystemPanel(
|
||||
addTab(
|
||||
I18n.getString("termora.transport.local"), FileSystemPanel(
|
||||
FileSystems.getDefault(),
|
||||
transportManager,
|
||||
host = Host(
|
||||
id = "local",
|
||||
name = I18n.getString("termora.transport.local"),
|
||||
protocol = Protocol.Local,
|
||||
)
|
||||
).apply { reload() }
|
||||
)
|
||||
).apply { reload() })
|
||||
setTabClosable(0, false)
|
||||
} else {
|
||||
addFileSystemTransportProvider(
|
||||
addTab(
|
||||
I18n.getString("termora.transport.sftp.select-host"),
|
||||
SftpFileSystemPanel(transportManager)
|
||||
SftpFileSystemPanel()
|
||||
)
|
||||
}
|
||||
|
||||
@@ -70,8 +66,8 @@ class FileSystemTabbed(
|
||||
dialog.isVisible = true
|
||||
|
||||
for (host in dialog.hosts) {
|
||||
val panel = SftpFileSystemPanel(transportManager, host)
|
||||
addFileSystemTransportProvider(host.name, panel)
|
||||
val panel = SftpFileSystemPanel(host)
|
||||
addTab(host.name, panel)
|
||||
panel.connect()
|
||||
}
|
||||
|
||||
@@ -120,9 +116,9 @@ class FileSystemTabbed(
|
||||
|
||||
if (tabCount == 0) {
|
||||
if (!isLeft) {
|
||||
addFileSystemTransportProvider(
|
||||
addTab(
|
||||
I18n.getString("termora.transport.sftp.select-host"),
|
||||
SftpFileSystemPanel(transportManager)
|
||||
SftpFileSystemPanel()
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -130,39 +126,31 @@ class FileSystemTabbed(
|
||||
|
||||
}
|
||||
|
||||
fun addFileSystemTransportProvider(title: String, provider: FileSystemTransportListener.Provider) {
|
||||
if (provider !is JComponent) {
|
||||
throw IllegalArgumentException("Provider is not an JComponent")
|
||||
}
|
||||
override fun addTab(title: String, component: Component) {
|
||||
super.addTab(title, component)
|
||||
|
||||
provider.addFileSystemTransportListener(object : FileSystemTransportListener {
|
||||
override fun transport(fileSystemPanel: FileSystemPanel, workdir: Path, isDirectory: Boolean, path: Path) {
|
||||
listeners.forEach { it.transport(fileSystemPanel, workdir, isDirectory, path) }
|
||||
}
|
||||
})
|
||||
selectedIndex = tabCount - 1
|
||||
|
||||
// 修改 Tab名称
|
||||
provider.addPropertyChangeListener("TabName") { e ->
|
||||
if (component is SftpFileSystemPanel) {
|
||||
component.addPropertyChangeListener("TabName") { e ->
|
||||
SwingUtilities.invokeLater {
|
||||
val name = StringUtils.defaultIfEmpty(
|
||||
e.newValue.toString(),
|
||||
I18n.getString("termora.transport.sftp.select-host")
|
||||
)
|
||||
for (i in 0 until tabCount) {
|
||||
if (getComponentAt(i) == provider) {
|
||||
if (getComponentAt(i) == component) {
|
||||
setTitleAt(i, name)
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
addTab(title, provider)
|
||||
|
||||
if (tabCount > 0)
|
||||
selectedIndex = tabCount - 1
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
fun getSelectedFileSystemPanel(): FileSystemPanel? {
|
||||
return getFileSystemPanel(selectedIndex)
|
||||
}
|
||||
@@ -184,14 +172,6 @@ class FileSystemTabbed(
|
||||
return null
|
||||
}
|
||||
|
||||
override fun addFileSystemTransportListener(listener: FileSystemTransportListener) {
|
||||
listeners.add(listener)
|
||||
}
|
||||
|
||||
override fun removeFileSystemTransportListener(listener: FileSystemTransportListener) {
|
||||
listeners.remove(listener)
|
||||
}
|
||||
|
||||
override fun dispose() {
|
||||
while (tabCount > 0) {
|
||||
val c = getComponentAt(0)
|
||||
|
||||
@@ -1,19 +0,0 @@
|
||||
package app.termora.transport
|
||||
|
||||
import java.nio.file.Path
|
||||
import java.util.*
|
||||
|
||||
interface FileSystemTransportListener : EventListener {
|
||||
/**
|
||||
* @param workdir 当前工作目录
|
||||
* @param isDirectory 要传输的是否是文件夹
|
||||
* @param path 要传输的文件/文件夹
|
||||
*/
|
||||
fun transport(fileSystemPanel: FileSystemPanel, workdir: Path, isDirectory: Boolean, path: Path)
|
||||
|
||||
|
||||
interface Provider {
|
||||
fun addFileSystemTransportListener(listener: FileSystemTransportListener)
|
||||
fun removeFileSystemTransportListener(listener: FileSystemTransportListener)
|
||||
}
|
||||
}
|
||||
@@ -21,15 +21,12 @@ import org.slf4j.LoggerFactory
|
||||
import java.awt.BorderLayout
|
||||
import java.awt.CardLayout
|
||||
import java.awt.event.ActionEvent
|
||||
import java.nio.file.Path
|
||||
import java.util.concurrent.atomic.AtomicBoolean
|
||||
import javax.swing.*
|
||||
|
||||
class SftpFileSystemPanel(
|
||||
private val transportManager: TransportManager,
|
||||
private var host: Host? = null
|
||||
) : JPanel(BorderLayout()), Disposable,
|
||||
FileSystemTransportListener.Provider {
|
||||
) : JPanel(BorderLayout()), Disposable {
|
||||
|
||||
companion object {
|
||||
private val log = LoggerFactory.getLogger(SftpFileSystemPanel::class.java)
|
||||
@@ -50,7 +47,6 @@ class SftpFileSystemPanel(
|
||||
private val connectingPanel = ConnectingPanel()
|
||||
private val selectHostPanel = SelectHostPanel()
|
||||
private val connectFailedPanel = ConnectFailedPanel()
|
||||
private val listeners = mutableListOf<FileSystemTransportListener>()
|
||||
private val isDisposed = AtomicBoolean(false)
|
||||
|
||||
private var client: SshClient? = null
|
||||
@@ -136,17 +132,7 @@ class SftpFileSystemPanel(
|
||||
withContext(Dispatchers.Swing) {
|
||||
state = State.Connected
|
||||
|
||||
val fileSystemPanel = FileSystemPanel(fileSystem, transportManager, host)
|
||||
fileSystemPanel.addFileSystemTransportListener(object : FileSystemTransportListener {
|
||||
override fun transport(
|
||||
fileSystemPanel: FileSystemPanel,
|
||||
workdir: Path,
|
||||
isDirectory: Boolean,
|
||||
path: Path
|
||||
) {
|
||||
listeners.forEach { it.transport(fileSystemPanel, workdir, isDirectory, path) }
|
||||
}
|
||||
})
|
||||
val fileSystemPanel = FileSystemPanel(fileSystem, host)
|
||||
|
||||
cardPanel.add(fileSystemPanel, State.Connected.name)
|
||||
cardLayout.show(cardPanel, State.Connected.name)
|
||||
@@ -312,11 +298,4 @@ class SftpFileSystemPanel(
|
||||
}
|
||||
|
||||
|
||||
override fun addFileSystemTransportListener(listener: FileSystemTransportListener) {
|
||||
listeners.add(listener)
|
||||
}
|
||||
|
||||
override fun removeFileSystemTransportListener(listener: FileSystemTransportListener) {
|
||||
listeners.remove(listener)
|
||||
}
|
||||
}
|
||||
@@ -31,10 +31,15 @@ abstract class Transport(
|
||||
val target: Path,
|
||||
val sourceHolder: Disposable,
|
||||
val targetHolder: Disposable,
|
||||
val listener: TransportListener = TransportListener.EMPTY
|
||||
) : Disposable, Runnable {
|
||||
|
||||
private val listeners = ArrayList<TransportListener>()
|
||||
|
||||
init {
|
||||
listeners.add(listener)
|
||||
}
|
||||
|
||||
@Volatile
|
||||
var state = TransportState.Waiting
|
||||
protected set(value) {
|
||||
@@ -142,9 +147,9 @@ private class SlidingWindowByteCounter {
|
||||
*/
|
||||
class FileTransport(
|
||||
name: String, source: Path, target: Path,
|
||||
sourceHolder: Disposable, targetHolder: Disposable,
|
||||
sourceHolder: Disposable, targetHolder: Disposable, listener: TransportListener = TransportListener.EMPTY
|
||||
) : Transport(
|
||||
name, source, target, sourceHolder, targetHolder,
|
||||
name, source, target, sourceHolder, targetHolder, listener
|
||||
), CopyStreamListener {
|
||||
|
||||
companion object {
|
||||
|
||||
27
src/main/kotlin/app/termora/transport/TransportJob.kt
Normal file
27
src/main/kotlin/app/termora/transport/TransportJob.kt
Normal file
@@ -0,0 +1,27 @@
|
||||
package app.termora.transport
|
||||
|
||||
import java.nio.file.Path
|
||||
|
||||
data class TransportJob(
|
||||
/**
|
||||
* 发起方
|
||||
*/
|
||||
val fileSystemPanel: FileSystemPanel,
|
||||
/**
|
||||
* 发起方工作目录
|
||||
*/
|
||||
val workdir: Path,
|
||||
/**
|
||||
* 要传输的文件是否是文件夹
|
||||
*/
|
||||
val isDirectory: Boolean,
|
||||
/**
|
||||
* 要传输的文件/文件夹
|
||||
*/
|
||||
val path: Path,
|
||||
|
||||
/**
|
||||
* 监听
|
||||
*/
|
||||
val listener: TransportListener? = null
|
||||
)
|
||||
@@ -3,18 +3,33 @@ package app.termora.transport
|
||||
import java.util.*
|
||||
|
||||
interface TransportListener : EventListener {
|
||||
|
||||
companion object {
|
||||
val EMPTY = object : TransportListener {
|
||||
override fun onTransportAdded(transport: Transport) {
|
||||
|
||||
}
|
||||
|
||||
override fun onTransportRemoved(transport: Transport) {
|
||||
}
|
||||
|
||||
override fun onTransportChanged(transport: Transport) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Added
|
||||
*/
|
||||
fun onTransportAdded(transport: Transport)
|
||||
fun onTransportAdded(transport: Transport){}
|
||||
|
||||
/**
|
||||
* Removed
|
||||
*/
|
||||
fun onTransportRemoved(transport: Transport)
|
||||
fun onTransportRemoved(transport: Transport){}
|
||||
|
||||
/**
|
||||
* 状态变化
|
||||
*/
|
||||
fun onTransportChanged(transport: Transport)
|
||||
fun onTransportChanged(transport: Transport){}
|
||||
}
|
||||
@@ -107,32 +107,6 @@ class TransportPanel : JPanel(BorderLayout()), Disposable, DataProvider {
|
||||
})
|
||||
|
||||
|
||||
leftFileSystemTabbed.addFileSystemTransportListener(object : FileSystemTransportListener {
|
||||
override fun transport(fileSystemPanel: FileSystemPanel, workdir: Path, isDirectory: Boolean, path: Path) {
|
||||
val target = rightFileSystemTabbed.getSelectedFileSystemPanel() ?: return
|
||||
transport(
|
||||
fileSystemPanel.workdir, target.workdir,
|
||||
isSourceDirectory = isDirectory,
|
||||
sourcePath = path,
|
||||
sourceHolder = fileSystemPanel,
|
||||
targetHolder = target,
|
||||
)
|
||||
}
|
||||
})
|
||||
|
||||
|
||||
rightFileSystemTabbed.addFileSystemTransportListener(object : FileSystemTransportListener {
|
||||
override fun transport(fileSystemPanel: FileSystemPanel, workdir: Path, isDirectory: Boolean, path: Path) {
|
||||
val target = leftFileSystemTabbed.getSelectedFileSystemPanel() ?: return
|
||||
transport(
|
||||
fileSystemPanel.workdir, target.workdir,
|
||||
isSourceDirectory = isDirectory,
|
||||
sourcePath = path,
|
||||
sourceHolder = fileSystemPanel,
|
||||
targetHolder = target,
|
||||
)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
fun transport(
|
||||
|
||||
@@ -259,6 +259,7 @@ termora.transport.table.owner=Owner
|
||||
|
||||
# contextmenu
|
||||
termora.transport.table.contextmenu.transfer=Transfer
|
||||
termora.transport.table.contextmenu.edit=${termora.keymgr.edit}
|
||||
termora.transport.table.contextmenu.copy-path=Copy Path
|
||||
termora.transport.table.contextmenu.open-in-folder=Open in {0}
|
||||
termora.transport.table.contextmenu.rename=${termora.welcome.contextmenu.rename}
|
||||
|
||||
Reference in New Issue
Block a user