fix: SFTP path not jumping on Windows (#483)

This commit is contained in:
hstyi
2025-04-10 11:08:51 +08:00
committed by GitHub
parent 5ffdd219d9
commit ed65853ebe
5 changed files with 50 additions and 13 deletions

View File

@@ -0,0 +1,9 @@
package app.termora.sftp
import org.apache.commons.vfs2.FileSystem
interface FileSystemProvider {
fun getFileSystem(): FileSystem
fun setFileSystem(fileSystem: FileSystem)
}

View File

@@ -27,7 +27,7 @@ import javax.swing.filechooser.FileSystemView
import kotlin.io.path.absolutePathString import kotlin.io.path.absolutePathString
class FileSystemViewNav( class FileSystemViewNav(
private val fileSystem: org.apache.commons.vfs2.FileSystem, private val fileSystemProvider: FileSystemProvider,
private val homeDirectory: FileObject private val homeDirectory: FileObject
) : JPanel(BorderLayout()) { ) : JPanel(BorderLayout()) {
@@ -103,7 +103,7 @@ class FileSystemViewNav(
add(layeredPane, BorderLayout.CENTER) add(layeredPane, BorderLayout.CENTER)
if (SystemInfo.isWindows && fileSystem is LocalFileSystem) { if (SystemInfo.isWindows && fileSystemProvider.getFileSystem() is LocalFileSystem) {
try { try {
for (root in fileSystemView.roots) { for (root in fileSystemView.roots) {
history.add(root.absolutePath) history.add(root.absolutePath)
@@ -174,9 +174,14 @@ class FileSystemViewNav(
override fun actionPerformed(e: ActionEvent) { override fun actionPerformed(e: ActionEvent) {
val name = textField.text.trim() val name = textField.text.trim()
if (name.isBlank()) return if (name.isBlank()) return
val fileSystem = fileSystemProvider.getFileSystem()
try { try {
if (fileSystem is LocalFileSystem && SystemUtils.IS_OS_WINDOWS) { if (fileSystem is LocalFileSystem && SystemUtils.IS_OS_WINDOWS) {
changeSelectedPath(fileSystem.resolveFile("file://${name}")) val file = VFS.getManager().resolveFile("file://${name}")
if (!StringUtils.equals(file.fileSystem.rootURI, fileSystemProvider.getFileSystem().rootURI)) {
fileSystemProvider.setFileSystem(file.fileSystem)
}
changeSelectedPath(file)
} else { } else {
changeSelectedPath(fileSystem.resolveFile(name)) changeSelectedPath(fileSystem.resolveFile(name))
} }
@@ -192,6 +197,7 @@ class FileSystemViewNav(
private fun showComboBoxPopup() { private fun showComboBoxPopup() {
comboBox.removeAllItems() comboBox.removeAllItems()
val fileSystem = fileSystemProvider.getFileSystem()
for (text in history) { for (text in history) {
val path = if (SystemInfo.isWindows && fileSystem is LocalFileSystem) { val path = if (SystemInfo.isWindows && fileSystem is LocalFileSystem) {

View File

@@ -10,9 +10,13 @@ import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
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.SystemUtils import org.apache.commons.lang3.SystemUtils
import org.apache.commons.lang3.exception.ExceptionUtils import org.apache.commons.lang3.exception.ExceptionUtils
import org.apache.commons.vfs2.FileObject import org.apache.commons.vfs2.FileObject
import org.apache.commons.vfs2.FileSystem
import org.apache.commons.vfs2.VFS
import org.apache.commons.vfs2.provider.local.LocalFileSystem
import org.jdesktop.swingx.JXBusyLabel import org.jdesktop.swingx.JXBusyLabel
import java.awt.BorderLayout import java.awt.BorderLayout
import java.awt.event.* import java.awt.event.*
@@ -22,14 +26,14 @@ import javax.swing.*
class FileSystemViewPanel( class FileSystemViewPanel(
val host: Host, val host: Host,
val fileSystem: org.apache.commons.vfs2.FileSystem, private var fileSystem: FileSystem,
private val transportManager: TransportManager, private val transportManager: TransportManager,
private val coroutineScope: CoroutineScope, private val coroutineScope: CoroutineScope,
) : JPanel(BorderLayout()), Disposable, DataProvider { ) : JPanel(BorderLayout()), Disposable, DataProvider, FileSystemProvider {
private val properties get() = Database.getDatabase().properties private val properties get() = Database.getDatabase().properties
private val sftp get() = Database.getDatabase().sftp private val sftp get() = Database.getDatabase().sftp
private val table = FileSystemViewTable(fileSystem, transportManager, coroutineScope) private val table = FileSystemViewTable(this, transportManager, coroutineScope)
private val disposed = AtomicBoolean(false) private val disposed = AtomicBoolean(false)
private var nextReloadTicks = emptyArray<Consumer<Unit>>() private var nextReloadTicks = emptyArray<Consumer<Unit>>()
private val isLoading = AtomicBoolean(false) private val isLoading = AtomicBoolean(false)
@@ -37,7 +41,7 @@ class FileSystemViewPanel(
private val loadingPanel = LoadingPanel() private val loadingPanel = LoadingPanel()
private val layeredPane = LayeredPane() private val layeredPane = LayeredPane()
private val homeDirectory = getHomeDirectory() private val homeDirectory = getHomeDirectory()
private val nav = FileSystemViewNav(fileSystem, homeDirectory) private val nav = FileSystemViewNav(this, homeDirectory)
private var workdir = homeDirectory private var workdir = homeDirectory
private val model get() = table.model as FileSystemViewTableModel private val model get() = table.model as FileSystemViewTableModel
private val showHiddenFilesKey = "termora.transport.host.${host.id}.show-hidden-files" private val showHiddenFilesKey = "termora.transport.host.${host.id}.show-hidden-files"
@@ -173,7 +177,15 @@ class FileSystemViewPanel(
} }
bookmarkBtn.isBookmark = !bookmarkBtn.isBookmark bookmarkBtn.isBookmark = !bookmarkBtn.isBookmark
} else { } else {
changeWorkdir(fileSystem.resolveFile(e.actionCommand)) if (fileSystem is LocalFileSystem && SystemUtils.IS_OS_WINDOWS) {
val file = VFS.getManager().resolveFile("file://${e.actionCommand}")
if (!StringUtils.equals(file.fileSystem.rootURI, fileSystem.rootURI)) {
fileSystem = file.fileSystem
}
changeWorkdir(file)
} else {
changeWorkdir(fileSystem.resolveFile(e.actionCommand))
}
} }
} }
@@ -372,6 +384,7 @@ class FileSystemViewPanel(
} }
private fun getHomeDirectory(): FileObject { private fun getHomeDirectory(): FileObject {
val fileSystem = this.fileSystem
if (fileSystem is MySftpFileSystem) { if (fileSystem is MySftpFileSystem) {
val host = fileSystem.getClientSession().getAttribute(SshClients.HOST_KEY) val host = fileSystem.getClientSession().getAttribute(SshClients.HOST_KEY)
?: return fileSystem.resolveFile(fileSystem.getDefaultDir()) ?: return fileSystem.resolveFile(fileSystem.getDefaultDir())
@@ -429,6 +442,14 @@ class FileSystemViewPanel(
return if (dataKey == SFTPDataProviders.FileSystemViewTable) table as T else null return if (dataKey == SFTPDataProviders.FileSystemViewTable) table as T else null
} }
override fun getFileSystem(): FileSystem {
return fileSystem
}
override fun setFileSystem(fileSystem: FileSystem) {
this.fileSystem = fileSystem
}
private class LoadingPanel : JPanel() { private class LoadingPanel : JPanel() {
private val busyLabel = JXBusyLabel() private val busyLabel = JXBusyLabel()

View File

@@ -52,7 +52,7 @@ import kotlin.time.Duration.Companion.milliseconds
@Suppress("DuplicatedCode", "CascadeIf") @Suppress("DuplicatedCode", "CascadeIf")
class FileSystemViewTable( class FileSystemViewTable(
private val fileSystem: org.apache.commons.vfs2.FileSystem, private val fileSystemProvider: FileSystemProvider,
private val transportManager: TransportManager, private val transportManager: TransportManager,
private val coroutineScope: CoroutineScope private val coroutineScope: CoroutineScope
) : JTable(), Disposable { ) : JTable(), Disposable {
@@ -184,7 +184,7 @@ class FileSystemViewTable(
val data = support.transferable.getTransferData(FileSystemTableRowTransferable.dataFlavor) val data = support.transferable.getTransferData(FileSystemTableRowTransferable.dataFlavor)
return data is FileSystemTableRowTransferable && data.source != table return data is FileSystemTableRowTransferable && data.source != table
} else if (support.isDataFlavorSupported(DataFlavor.javaFileListFlavor)) { } else if (support.isDataFlavorSupported(DataFlavor.javaFileListFlavor)) {
return fileSystem !is LocalFileSystem return fileSystemProvider.getFileSystem() !is LocalFileSystem
} }
return false return false
@@ -261,6 +261,7 @@ class FileSystemViewTable(
private fun showContextMenu(rows: IntArray, e: MouseEvent) { private fun showContextMenu(rows: IntArray, e: MouseEvent) {
val files = rows.map { model.getFileObject(it) } val files = rows.map { model.getFileObject(it) }
val hasParent = rows.contains(0) val hasParent = rows.contains(0)
val fileSystem = fileSystemProvider.getFileSystem()
val popupMenu = FlatPopupMenu() val popupMenu = FlatPopupMenu()
val newMenu = JMenu(I18n.getString("termora.transport.table.contextmenu.new")) val newMenu = JMenu(I18n.getString("termora.transport.table.contextmenu.new"))
@@ -571,7 +572,7 @@ class FileSystemViewTable(
coroutineScope.launch(Dispatchers.IO) { coroutineScope.launch(Dispatchers.IO) {
runCatching { runCatching {
if (fileSystem is MySftpFileSystem) { if (fileSystemProvider.getFileSystem() is MySftpFileSystem) {
deleteSftpPaths(paths, rm) deleteSftpPaths(paths, rm)
} else { } else {
deleteRecursively(paths) deleteRecursively(paths)
@@ -594,7 +595,7 @@ class FileSystemViewTable(
private fun deleteSftpPaths(files: List<FileObject>, rm: Boolean = false) { private fun deleteSftpPaths(files: List<FileObject>, rm: Boolean = false) {
if (rm) { if (rm) {
val session = (this.fileSystem as MySftpFileSystem).getClientSession() val session = (this.fileSystemProvider.getFileSystem() as MySftpFileSystem).getClientSession()
for (path in files) { for (path in files) {
session.executeRemoteCommand( session.executeRemoteCommand(
"rm -rf '${path.absolutePathString()}'", "rm -rf '${path.absolutePathString()}'",

View File

@@ -127,7 +127,7 @@ class SFTPPanel : JPanel(BorderLayout()), DataProvider, Disposable {
return return
} }
val fs = c.fileSystem val fs = c.getFileSystem()
val root = transportManager.root val root = transportManager.root
transportManager.lock.withLock { transportManager.lock.withLock {