From ed65853ebea4cb680e1d3a66519b8967f8d58ad7 Mon Sep 17 00:00:00 2001 From: hstyi Date: Thu, 10 Apr 2025 11:08:51 +0800 Subject: [PATCH] fix: SFTP path not jumping on Windows (#483) --- .../app/termora/sftp/FileSystemProvider.kt | 9 ++++++ .../app/termora/sftp/FileSystemViewNav.kt | 12 +++++-- .../app/termora/sftp/FileSystemViewPanel.kt | 31 ++++++++++++++++--- .../app/termora/sftp/FileSystemViewTable.kt | 9 +++--- src/main/kotlin/app/termora/sftp/SFTPPanel.kt | 2 +- 5 files changed, 50 insertions(+), 13 deletions(-) create mode 100644 src/main/kotlin/app/termora/sftp/FileSystemProvider.kt diff --git a/src/main/kotlin/app/termora/sftp/FileSystemProvider.kt b/src/main/kotlin/app/termora/sftp/FileSystemProvider.kt new file mode 100644 index 0000000..04a776e --- /dev/null +++ b/src/main/kotlin/app/termora/sftp/FileSystemProvider.kt @@ -0,0 +1,9 @@ +package app.termora.sftp + +import org.apache.commons.vfs2.FileSystem + + +interface FileSystemProvider { + fun getFileSystem(): FileSystem + fun setFileSystem(fileSystem: FileSystem) +} \ No newline at end of file diff --git a/src/main/kotlin/app/termora/sftp/FileSystemViewNav.kt b/src/main/kotlin/app/termora/sftp/FileSystemViewNav.kt index e39c25c..92d4227 100644 --- a/src/main/kotlin/app/termora/sftp/FileSystemViewNav.kt +++ b/src/main/kotlin/app/termora/sftp/FileSystemViewNav.kt @@ -27,7 +27,7 @@ import javax.swing.filechooser.FileSystemView import kotlin.io.path.absolutePathString class FileSystemViewNav( - private val fileSystem: org.apache.commons.vfs2.FileSystem, + private val fileSystemProvider: FileSystemProvider, private val homeDirectory: FileObject ) : JPanel(BorderLayout()) { @@ -103,7 +103,7 @@ class FileSystemViewNav( add(layeredPane, BorderLayout.CENTER) - if (SystemInfo.isWindows && fileSystem is LocalFileSystem) { + if (SystemInfo.isWindows && fileSystemProvider.getFileSystem() is LocalFileSystem) { try { for (root in fileSystemView.roots) { history.add(root.absolutePath) @@ -174,9 +174,14 @@ class FileSystemViewNav( override fun actionPerformed(e: ActionEvent) { val name = textField.text.trim() if (name.isBlank()) return + val fileSystem = fileSystemProvider.getFileSystem() try { 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 { changeSelectedPath(fileSystem.resolveFile(name)) } @@ -192,6 +197,7 @@ class FileSystemViewNav( private fun showComboBoxPopup() { comboBox.removeAllItems() + val fileSystem = fileSystemProvider.getFileSystem() for (text in history) { val path = if (SystemInfo.isWindows && fileSystem is LocalFileSystem) { diff --git a/src/main/kotlin/app/termora/sftp/FileSystemViewPanel.kt b/src/main/kotlin/app/termora/sftp/FileSystemViewPanel.kt index 9dea672..4c0f4d5 100644 --- a/src/main/kotlin/app/termora/sftp/FileSystemViewPanel.kt +++ b/src/main/kotlin/app/termora/sftp/FileSystemViewPanel.kt @@ -10,9 +10,13 @@ import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.launch import kotlinx.coroutines.swing.Swing import kotlinx.coroutines.withContext +import org.apache.commons.lang3.StringUtils import org.apache.commons.lang3.SystemUtils import org.apache.commons.lang3.exception.ExceptionUtils 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 java.awt.BorderLayout import java.awt.event.* @@ -22,14 +26,14 @@ import javax.swing.* class FileSystemViewPanel( val host: Host, - val fileSystem: org.apache.commons.vfs2.FileSystem, + private var fileSystem: FileSystem, private val transportManager: TransportManager, private val coroutineScope: CoroutineScope, -) : JPanel(BorderLayout()), Disposable, DataProvider { +) : JPanel(BorderLayout()), Disposable, DataProvider, FileSystemProvider { private val properties get() = Database.getDatabase().properties 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 var nextReloadTicks = emptyArray>() private val isLoading = AtomicBoolean(false) @@ -37,7 +41,7 @@ class FileSystemViewPanel( private val loadingPanel = LoadingPanel() private val layeredPane = LayeredPane() private val homeDirectory = getHomeDirectory() - private val nav = FileSystemViewNav(fileSystem, homeDirectory) + private val nav = FileSystemViewNav(this, homeDirectory) private var workdir = homeDirectory private val model get() = table.model as FileSystemViewTableModel private val showHiddenFilesKey = "termora.transport.host.${host.id}.show-hidden-files" @@ -173,7 +177,15 @@ class FileSystemViewPanel( } bookmarkBtn.isBookmark = !bookmarkBtn.isBookmark } 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 { + val fileSystem = this.fileSystem if (fileSystem is MySftpFileSystem) { val host = fileSystem.getClientSession().getAttribute(SshClients.HOST_KEY) ?: return fileSystem.resolveFile(fileSystem.getDefaultDir()) @@ -429,6 +442,14 @@ class FileSystemViewPanel( 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 val busyLabel = JXBusyLabel() diff --git a/src/main/kotlin/app/termora/sftp/FileSystemViewTable.kt b/src/main/kotlin/app/termora/sftp/FileSystemViewTable.kt index 4233aa9..0d6397c 100644 --- a/src/main/kotlin/app/termora/sftp/FileSystemViewTable.kt +++ b/src/main/kotlin/app/termora/sftp/FileSystemViewTable.kt @@ -52,7 +52,7 @@ import kotlin.time.Duration.Companion.milliseconds @Suppress("DuplicatedCode", "CascadeIf") class FileSystemViewTable( - private val fileSystem: org.apache.commons.vfs2.FileSystem, + private val fileSystemProvider: FileSystemProvider, private val transportManager: TransportManager, private val coroutineScope: CoroutineScope ) : JTable(), Disposable { @@ -184,7 +184,7 @@ class FileSystemViewTable( val data = support.transferable.getTransferData(FileSystemTableRowTransferable.dataFlavor) return data is FileSystemTableRowTransferable && data.source != table } else if (support.isDataFlavorSupported(DataFlavor.javaFileListFlavor)) { - return fileSystem !is LocalFileSystem + return fileSystemProvider.getFileSystem() !is LocalFileSystem } return false @@ -261,6 +261,7 @@ class FileSystemViewTable( private fun showContextMenu(rows: IntArray, e: MouseEvent) { val files = rows.map { model.getFileObject(it) } val hasParent = rows.contains(0) + val fileSystem = fileSystemProvider.getFileSystem() val popupMenu = FlatPopupMenu() val newMenu = JMenu(I18n.getString("termora.transport.table.contextmenu.new")) @@ -571,7 +572,7 @@ class FileSystemViewTable( coroutineScope.launch(Dispatchers.IO) { runCatching { - if (fileSystem is MySftpFileSystem) { + if (fileSystemProvider.getFileSystem() is MySftpFileSystem) { deleteSftpPaths(paths, rm) } else { deleteRecursively(paths) @@ -594,7 +595,7 @@ class FileSystemViewTable( private fun deleteSftpPaths(files: List, rm: Boolean = false) { if (rm) { - val session = (this.fileSystem as MySftpFileSystem).getClientSession() + val session = (this.fileSystemProvider.getFileSystem() as MySftpFileSystem).getClientSession() for (path in files) { session.executeRemoteCommand( "rm -rf '${path.absolutePathString()}'", diff --git a/src/main/kotlin/app/termora/sftp/SFTPPanel.kt b/src/main/kotlin/app/termora/sftp/SFTPPanel.kt index 5b5a5a7..77f972a 100644 --- a/src/main/kotlin/app/termora/sftp/SFTPPanel.kt +++ b/src/main/kotlin/app/termora/sftp/SFTPPanel.kt @@ -127,7 +127,7 @@ class SFTPPanel : JPanel(BorderLayout()), DataProvider, Disposable { return } - val fs = c.fileSystem + val fs = c.getFileSystem() val root = transportManager.root transportManager.lock.withLock {