feat: SFTP 支持不显示隐藏文件

This commit is contained in:
hstyi
2025-01-15 16:51:07 +08:00
committed by hstyi
parent 21cf22906b
commit 6aaed92f2c
10 changed files with 82 additions and 6 deletions

View File

@@ -8,6 +8,8 @@ object Icons {
val moveDown by lazy { DynamicIcon("icons/moveDown.svg", "icons/moveDown_dark.svg") } val moveDown by lazy { DynamicIcon("icons/moveDown.svg", "icons/moveDown_dark.svg") }
val close by lazy { DynamicIcon("icons/close.svg", "icons/close_dark.svg") } val close by lazy { DynamicIcon("icons/close.svg", "icons/close_dark.svg") }
val searchHistory by lazy { DynamicIcon("icons/searchHistory.svg", "icons/searchHistory_dark.svg") } val searchHistory by lazy { DynamicIcon("icons/searchHistory.svg", "icons/searchHistory_dark.svg") }
val eye by lazy { DynamicIcon("icons/eye.svg", "icons/eye_dark.svg") }
val eyeClose by lazy { DynamicIcon("icons/eyeClose.svg", "icons/eyeClose_dark.svg") }
val matchCase by lazy { DynamicIcon("icons/matchCase.svg", "icons/matchCase_dark.svg") } val matchCase by lazy { DynamicIcon("icons/matchCase.svg", "icons/matchCase_dark.svg") }
val regex by lazy { DynamicIcon("icons/regex.svg", "icons/regex_dark.svg") } val regex by lazy { DynamicIcon("icons/regex.svg", "icons/regex_dark.svg") }
val vcs by lazy { DynamicIcon("icons/vcs.svg", "icons/vcs_dark.svg") } val vcs by lazy { DynamicIcon("icons/vcs.svg", "icons/vcs_dark.svg") }

View File

@@ -6,6 +6,7 @@ import com.formdev.flatlaf.extras.components.FlatPopupMenu
import com.formdev.flatlaf.extras.components.FlatToolBar import com.formdev.flatlaf.extras.components.FlatToolBar
import com.formdev.flatlaf.icons.FlatFileViewDirectoryIcon import com.formdev.flatlaf.icons.FlatFileViewDirectoryIcon
import com.formdev.flatlaf.icons.FlatFileViewFileIcon import com.formdev.flatlaf.icons.FlatFileViewFileIcon
import com.formdev.flatlaf.ui.FlatTableUI
import com.formdev.flatlaf.util.SystemInfo import com.formdev.flatlaf.util.SystemInfo
import kotlinx.coroutines.* import kotlinx.coroutines.*
import kotlinx.coroutines.swing.Swing import kotlinx.coroutines.swing.Swing
@@ -42,8 +43,7 @@ class FileSystemPanel(
private val fileSystem: FileSystem, private val fileSystem: FileSystem,
private val transportManager: TransportManager, private val transportManager: TransportManager,
private val host: Host private val host: Host
) : JPanel(BorderLayout()), Disposable, ) : JPanel(BorderLayout()), Disposable, FileSystemTransportListener.Provider {
FileSystemTransportListener.Provider {
companion object { companion object {
private val log = LoggerFactory.getLogger(FileSystemPanel::class.java) private val log = LoggerFactory.getLogger(FileSystemPanel::class.java)
@@ -58,6 +58,10 @@ class FileSystemPanel(
private val loadingPanel = LoadingPanel() private val loadingPanel = LoadingPanel()
private val bookmarkBtn = BookmarkButton() private val bookmarkBtn = BookmarkButton()
private val homeBtn = JButton(Icons.homeFolder) private val homeBtn = JButton(Icons.homeFolder)
private val showHiddenFilesBtn = JButton(Icons.eyeClose)
private val properties get() = Database.getDatabase().properties
private var isShowHiddenFiles = false
private val showHiddenFilesKey by lazy { "termora.transport.host.${host.id}.show-hidden-files" }
val workdir get() = tableModel.workdir val workdir get() = tableModel.workdir
@@ -72,6 +76,8 @@ class FileSystemPanel(
bookmarkBtn.name = "Host.${host.id}.Bookmarks" bookmarkBtn.name = "Host.${host.id}.Bookmarks"
bookmarkBtn.isBookmark = bookmarkBtn.getBookmarks().contains(workdir.toString()) bookmarkBtn.isBookmark = bookmarkBtn.getBookmarks().contains(workdir.toString())
table.setUI(FlatTableUI())
table.rowHeight = UIManager.getInt("Table.rowHeight")
table.autoResizeMode = JTable.AUTO_RESIZE_OFF table.autoResizeMode = JTable.AUTO_RESIZE_OFF
table.fillsViewportHeight = true table.fillsViewportHeight = true
table.putClientProperty( table.putClientProperty(
@@ -121,6 +127,16 @@ class FileSystemPanel(
}) })
parentBtn.toolTipText = I18n.getString("termora.transport.parent-folder") parentBtn.toolTipText = I18n.getString("termora.transport.parent-folder")
showHiddenFilesBtn.toolTipText = I18n.getString("termora.transport.show-hidden-files")
if (properties.getString(showHiddenFilesKey, "true").toBoolean()) {
showHiddenFilesBtn.icon = Icons.eye
tableModel.isShowHiddenFiles = true
} else {
showHiddenFilesBtn.icon = Icons.eyeClose
properties.putString(showHiddenFilesKey, "true")
tableModel.isShowHiddenFiles = false
}
val toolbar = FlatToolBar() val toolbar = FlatToolBar()
@@ -128,6 +144,7 @@ class FileSystemPanel(
toolbar.add(Box.createHorizontalStrut(2)) toolbar.add(Box.createHorizontalStrut(2))
toolbar.add(workdirTextField) toolbar.add(workdirTextField)
toolbar.add(bookmarkBtn) toolbar.add(bookmarkBtn)
toolbar.add(showHiddenFilesBtn)
toolbar.add(parentBtn) toolbar.add(parentBtn)
toolbar.add(JButton(Icons.refresh).apply { toolbar.add(JButton(Icons.refresh).apply {
addActionListener { reload() } addActionListener { reload() }
@@ -290,6 +307,21 @@ class FileSystemPanel(
} }
} }
showHiddenFilesBtn.addActionListener {
val showHiddenFiles = tableModel.isShowHiddenFiles
tableModel.isShowHiddenFiles = !showHiddenFiles
if (tableModel.isShowHiddenFiles) {
showHiddenFilesBtn.icon = Icons.eye
} else {
showHiddenFilesBtn.icon = Icons.eyeClose
}
}
Disposer.register(this, object : Disposable {
override fun dispose() {
properties.putString(showHiddenFilesKey, "${tableModel.isShowHiddenFiles}")
}
})
} }

View File

@@ -45,13 +45,18 @@ class FileSystemTableModel(private val fileSystem: FileSystem) : DefaultTableMod
private val propertyChangeListeners = mutableListOf<PropertyChangeListener>() private val propertyChangeListeners = mutableListOf<PropertyChangeListener>()
val isLocalFileSystem by lazy { FileSystems.getDefault() == fileSystem } val isLocalFileSystem by lazy { FileSystems.getDefault() == fileSystem }
var isShowHiddenFiles = false
set(value) {
field = value
fireTableDataChanged()
}
override fun getRowCount(): Int { override fun getRowCount(): Int {
return files?.size ?: 0 return getShownFiles().size
} }
override fun getValueAt(row: Int, column: Int): Any { override fun getValueAt(row: Int, column: Int): Any {
val path = files?.get(row) ?: return StringUtils.EMPTY val path = getShownFiles()[row]
if (path.fileName == ".." && column != 0) { if (path.fileName == ".." && column != 0) {
return StringUtils.EMPTY return StringUtils.EMPTY
@@ -98,7 +103,7 @@ class FileSystemTableModel(private val fileSystem: FileSystem) : DefaultTableMod
} }
fun getCacheablePath(index: Int): CacheablePath { fun getCacheablePath(index: Int): CacheablePath {
return files?.get(index) ?: throw IndexOutOfBoundsException() return getShownFiles()[index]
} }
override fun isCellEditable(row: Int, column: Int): Boolean { override fun isCellEditable(row: Int, column: Int): Boolean {
@@ -106,7 +111,8 @@ class FileSystemTableModel(private val fileSystem: FileSystem) : DefaultTableMod
} }
override fun removeRow(row: Int) { override fun removeRow(row: Int) {
files?.removeAt(row) ?: return val e = getShownFiles()[row]
files?.removeIf { it == e }
fireTableRowsDeleted(row, row) fireTableRowsDeleted(row, row)
} }
@@ -155,11 +161,19 @@ class FileSystemTableModel(private val fileSystem: FileSystem) : DefaultTableMod
propertyChangeListeners.add(propertyChangeListener) propertyChangeListeners.add(propertyChangeListener)
} }
private fun getShownFiles(): List<CacheablePath> {
if (isShowHiddenFiles) {
return files ?: emptyList()
}
return files?.filter { !it.isHidden } ?: emptyList()
}
open class CacheablePath(val path: Path) { open class CacheablePath(val path: Path) {
val fileName by lazy { path.fileName.toString() } val fileName by lazy { path.fileName.toString() }
val extension by lazy { path.extension } val extension by lazy { path.extension }
open val isDirectory by lazy { path.isDirectory() } open val isDirectory by lazy { path.isDirectory() }
open val isHidden by lazy { fileName != ".." && path.isHidden() }
open val fileSize by lazy { path.fileSize() } open val fileSize by lazy { path.fileSize() }
open val lastModifiedTime by lazy { Files.getLastModifiedTime(path).toMillis() } open val lastModifiedTime by lazy { Files.getLastModifiedTime(path).toMillis() }
open val owner by lazy { path.getOwner().toString() } open val owner by lazy { path.getOwner().toString() }
@@ -216,6 +230,9 @@ class FileSystemTableModel(private val fileSystem: FileSystem) : DefaultTableMod
override val isDirectory: Boolean override val isDirectory: Boolean
get() = attributes.isDirectory get() = attributes.isDirectory
override val isHidden: Boolean
get() = fileName != ".." && fileName.startsWith(".")
override val fileSize: Long override val fileSize: Long
get() = attributes.size get() = attributes.size

View File

@@ -211,6 +211,7 @@ termora.tools.multiple=Send commands to multiple sessions
# Transport # Transport
termora.transport.local=Local termora.transport.local=Local
termora.transport.parent-folder=Parent Folder termora.transport.parent-folder=Parent Folder
termora.transport.show-hidden-files=Show hidden files
termora.transport.file-already-exists=The file {0} already exists termora.transport.file-already-exists=The file {0} already exists
termora.transport.bookmarks=Bookmarks Manager termora.transport.bookmarks=Bookmarks Manager

View File

@@ -207,6 +207,7 @@ termora.macro.run=运行
# Transport # Transport
termora.transport.local=本机 termora.transport.local=本机
termora.transport.parent-folder=父文件夹 termora.transport.parent-folder=父文件夹
termora.transport.show-hidden-files=显示隐藏文件
termora.transport.file-already-exists=文件 {0} 已存在 termora.transport.file-already-exists=文件 {0} 已存在
termora.transport.bookmarks=书签管理 termora.transport.bookmarks=书签管理

View File

@@ -201,6 +201,7 @@ termora.macro.run=運行
# Transport # Transport
termora.transport.local=本機 termora.transport.local=本機
termora.transport.parent-folder=父資料夾 termora.transport.parent-folder=父資料夾
termora.transport.show-hidden-files=顯示隱藏文件
termora.transport.file-already-exists=檔案 {0} 已存在 termora.transport.file-already-exists=檔案 {0} 已存在
termora.transport.bookmarks=書籤管理 termora.transport.bookmarks=書籤管理

View File

@@ -0,0 +1,7 @@
<svg t="1736928517310" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="877"
width="16" height="16">
<path d="M1001.472 482.64533333C893.61066667 255.43111111 730.56711111 141.08444445 512 141.08444445c-218.68088889 0-381.61066667 114.34666667-489.472 341.67466666-8.76088889 18.432-8.76088889 40.04977778 0 58.59555556C130.38933333 768.56888889 293.43288889 882.91555555 512 882.91555555c218.68088889 0 381.61066667-114.34666667 489.472-341.67466666 8.76088889-18.432 8.76088889-39.82222222 0-58.59555556zM512 800.99555555c-183.52355555 0-317.89511111-93.07022222-412.672-288.99555555C194.10488889 316.07466667 328.47644445 223.00444445 512 223.00444445c183.52355555 0 317.89511111 93.07022222 412.672 288.99555555C830.00888889 707.92533333 695.63733333 800.99555555 512 800.99555555z"
p-id="878" fill="#6C707E"></path>
<path d="M507.73333333 324.26666667c-103.68 0-187.73333333 84.05333333-187.73333333 187.73333333s84.05333333 187.73333333 187.73333333 187.73333333 187.73333333-84.05333333 187.73333334-187.73333333-84.05333333-187.73333333-187.73333334-187.73333333z m0 307.2c-66.02666667 0-119.46666667-53.44-119.46666666-119.46666667s53.44-119.46666667 119.46666666-119.46666667 119.46666667 53.44 119.46666667 119.46666667-53.44 119.46666667-119.46666667 119.46666667z"
p-id="879" fill="#6C707E"></path>
</svg>

After

Width:  |  Height:  |  Size: 1.4 KiB

View File

@@ -0,0 +1 @@
<svg t="1736928586708" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="907" width="16" height="16"><path d="M1001.58577778 482.87288889l-0.11377778-0.11377778-0.11377778-0.11377778c-41.41511111-87.26755555-91.02222222-157.80977778-148.70755555-211.62666666L794.96533333 328.81777778c49.72088889 45.73866667 92.72888889 106.60977778 129.82044445 183.06844444C830.00888889 707.92533333 695.63733333 800.99555555 512 800.99555555c-58.368 0-111.84355555-9.44355555-160.65422222-28.55822222l-62.23644445 62.23644445C355.66933333 866.75911111 429.85244445 882.91555555 512 882.91555555c218.68088889 0 381.61066667-114.34666667 489.472-341.67466666 8.76088889-18.432 8.76088889-39.82222222 0.11377778-58.368zM928.768 104.90311111l-48.24177778-48.24177778c-3.52711111-3.52711111-9.32977778-3.52711111-12.85688889 0L734.77688889 189.44C668.33066667 157.24088889 594.14755555 141.08444445 512 141.08444445c-218.68088889 0-381.61066667 114.34666667-489.472 341.67466666v0.11377778c-8.76088889 18.432-8.76088889 40.04977778 0 58.59555556 41.41511111 87.26755555 91.02222222 157.80977778 148.70755555 211.74044444L56.66133333 867.55555555c-3.52711111 3.52711111-3.52711111 9.32977778 0 12.8568889l48.24177778 48.24177777c3.52711111 3.52711111 9.32977778 3.52711111 12.85688889 0l811.008-811.008c3.52711111-3.41333333 3.52711111-9.216 0-12.74311111zM383.31733333 540.89955555c-2.16177778-9.32977778-3.29955555-19.00088889-3.29955555-28.89955555 0-70.42844445 57.00266667-127.43111111 127.43111111-127.43111111 9.89866667 0 19.68355555 1.13777778 28.89955556 3.29955556L383.31733333 540.89955555z m209.92-209.92C567.18222222 318.69155555 538.16888889 311.75111111 507.44888889 311.75111111c-110.592 0-200.24888889 89.65688889-200.24888889 200.24888889 0 30.72 6.94044445 59.73333333 19.22844445 85.78844445L229.03466667 695.18222222c-49.72088889-45.73866667-92.72888889-106.60977778-129.82044445-183.06844444C194.10488889 316.07466667 328.47644445 223.00444445 512 223.00444445c58.368 0 111.84355555 9.44355555 160.65422222 28.55822222l-79.41688889 79.41688888z" p-id="908" fill="#6C707E"></path><path d="M507.44888889 639.43111111c-7.28177778 0-14.44977778-0.56888889-21.39022222-1.82044444l-58.14044445 58.14044444c24.34844445 10.58133333 51.31377778 16.384 79.53066667 16.384 110.592 0 200.24888889-89.65688889 200.24888889-200.24888889 0-28.21688889-5.80266667-55.18222222-16.384-79.53066667l-58.14044445 58.14044445c1.13777778 6.94044445 1.82044445 14.10844445 1.82044445 21.39022222C634.88 582.42844445 577.87733333 639.43111111 507.44888889 639.43111111z" p-id="909" fill="#6C707E"></path></svg>

After

Width:  |  Height:  |  Size: 2.6 KiB

View File

@@ -0,0 +1,7 @@
<svg t="1736928517310" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="877"
width="16" height="16">
<path d="M1001.472 482.64533333C893.61066667 255.43111111 730.56711111 141.08444445 512 141.08444445c-218.68088889 0-381.61066667 114.34666667-489.472 341.67466666-8.76088889 18.432-8.76088889 40.04977778 0 58.59555556C130.38933333 768.56888889 293.43288889 882.91555555 512 882.91555555c218.68088889 0 381.61066667-114.34666667 489.472-341.67466666 8.76088889-18.432 8.76088889-39.82222222 0-58.59555556zM512 800.99555555c-183.52355555 0-317.89511111-93.07022222-412.672-288.99555555C194.10488889 316.07466667 328.47644445 223.00444445 512 223.00444445c183.52355555 0 317.89511111 93.07022222 412.672 288.99555555C830.00888889 707.92533333 695.63733333 800.99555555 512 800.99555555z"
p-id="878" fill="#CED0D6"></path>
<path d="M507.73333333 324.26666667c-103.68 0-187.73333333 84.05333333-187.73333333 187.73333333s84.05333333 187.73333333 187.73333333 187.73333333 187.73333333-84.05333333 187.73333334-187.73333333-84.05333333-187.73333333-187.73333334-187.73333333z m0 307.2c-66.02666667 0-119.46666667-53.44-119.46666666-119.46666667s53.44-119.46666667 119.46666666-119.46666667 119.46666667 53.44 119.46666667 119.46666667-53.44 119.46666667-119.46666667 119.46666667z"
p-id="879" fill="#CED0D6"></path>
</svg>

After

Width:  |  Height:  |  Size: 1.4 KiB

View File

@@ -0,0 +1,7 @@
<svg t="1736928517310" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="877"
width="16" height="16">
<path d="M1001.472 482.64533333C893.61066667 255.43111111 730.56711111 141.08444445 512 141.08444445c-218.68088889 0-381.61066667 114.34666667-489.472 341.67466666-8.76088889 18.432-8.76088889 40.04977778 0 58.59555556C130.38933333 768.56888889 293.43288889 882.91555555 512 882.91555555c218.68088889 0 381.61066667-114.34666667 489.472-341.67466666 8.76088889-18.432 8.76088889-39.82222222 0-58.59555556zM512 800.99555555c-183.52355555 0-317.89511111-93.07022222-412.672-288.99555555C194.10488889 316.07466667 328.47644445 223.00444445 512 223.00444445c183.52355555 0 317.89511111 93.07022222 412.672 288.99555555C830.00888889 707.92533333 695.63733333 800.99555555 512 800.99555555z"
p-id="878" fill="#CED0D6"></path>
<path d="M507.73333333 324.26666667c-103.68 0-187.73333333 84.05333333-187.73333333 187.73333333s84.05333333 187.73333333 187.73333333 187.73333333 187.73333333-84.05333333 187.73333334-187.73333333-84.05333333-187.73333333-187.73333334-187.73333333z m0 307.2c-66.02666667 0-119.46666667-53.44-119.46666666-119.46666667s53.44-119.46666667 119.46666666-119.46666667 119.46666667 53.44 119.46666667 119.46666667-53.44 119.46666667-119.46666667 119.46666667z"
p-id="879" fill="#CED0D6"></path>
</svg>

After

Width:  |  Height:  |  Size: 1.4 KiB