mirror of
https://github.com/TermoraDev/termora.git
synced 2026-01-16 10:22:58 +08:00
feat: ftp plugin
This commit is contained in:
@@ -153,7 +153,8 @@ class TermoraFencePanel(
|
||||
|
||||
|
||||
override fun dispose() {
|
||||
enableManager.setFlag("Termora.Fence.dividerLocation", max(splitPane.dividerLocation, 10))
|
||||
if (leftTreePanel.isVisible)
|
||||
enableManager.setFlag("Termora.Fence.dividerLocation", max(splitPane.dividerLocation, 10))
|
||||
}
|
||||
|
||||
fun getHostTree(): NewHostTree {
|
||||
|
||||
@@ -78,8 +78,6 @@ class BasicProxyOption(
|
||||
proxyAuthenticationTypeComboBox.addItem(type)
|
||||
}
|
||||
|
||||
proxyUsernameTextField.text = "root"
|
||||
|
||||
refreshStates()
|
||||
}
|
||||
|
||||
|
||||
@@ -8,6 +8,7 @@ import com.formdev.flatlaf.FlatLaf
|
||||
import com.formdev.flatlaf.util.UIScale
|
||||
import com.github.weisj.jsvg.SVGDocument
|
||||
import com.github.weisj.jsvg.parser.SVGLoader
|
||||
import com.github.weisj.jsvg.parser.impl.MutableLoaderContext
|
||||
import java.awt.Component
|
||||
import java.awt.Graphics
|
||||
import java.awt.Graphics2D
|
||||
@@ -21,8 +22,8 @@ class PluginSVGIcon(input: InputStream, dark: InputStream? = null) : Icon {
|
||||
|
||||
}
|
||||
|
||||
private val document = svgLoader.load(input)
|
||||
private val darkDocument = dark?.let { svgLoader.load(it) }
|
||||
private val document = svgLoader.load(input, null, MutableLoaderContext.createDefault())
|
||||
private val darkDocument = dark?.let { svgLoader.load(it, null, MutableLoaderContext.createDefault()) }
|
||||
|
||||
override fun getIconHeight(): Int {
|
||||
return 32
|
||||
|
||||
@@ -8,6 +8,7 @@ import kotlinx.coroutines.*
|
||||
import kotlinx.coroutines.swing.Swing
|
||||
import okio.withLock
|
||||
import org.apache.commons.io.IOUtils
|
||||
import org.apache.commons.lang3.StringUtils
|
||||
import org.jdesktop.swingx.treetable.DefaultMutableTreeTableNode
|
||||
import org.jdesktop.swingx.treetable.DefaultTreeTableModel
|
||||
import org.slf4j.LoggerFactory
|
||||
@@ -500,6 +501,10 @@ class TransferTableModel(private val coroutineScope: CoroutineScope) :
|
||||
|
||||
}
|
||||
|
||||
override fun dispose() {
|
||||
removeTransfer(StringUtils.EMPTY)
|
||||
}
|
||||
|
||||
private class UserCanceledException : RuntimeException()
|
||||
|
||||
|
||||
|
||||
@@ -9,6 +9,7 @@ import app.termora.plugin.ExtensionManager
|
||||
import app.termora.plugin.internal.wsl.WSLHostTerminalTab
|
||||
import app.termora.terminal.DataKey
|
||||
import app.termora.transfer.TransportTableModel.Attributes
|
||||
import app.termora.transfer.s3.S3FileAttributes
|
||||
import com.formdev.flatlaf.FlatClientProperties
|
||||
import com.formdev.flatlaf.extras.components.FlatToolBar
|
||||
import com.formdev.flatlaf.icons.FlatTreeClosedIcon
|
||||
@@ -48,6 +49,7 @@ import java.util.*
|
||||
import java.util.concurrent.CompletableFuture
|
||||
import java.util.concurrent.Future
|
||||
import java.util.concurrent.atomic.AtomicBoolean
|
||||
import java.util.concurrent.atomic.AtomicLong
|
||||
import java.util.stream.Stream
|
||||
import javax.swing.*
|
||||
import javax.swing.TransferHandler
|
||||
@@ -83,6 +85,7 @@ internal class TransportPanel(
|
||||
|
||||
}
|
||||
|
||||
private val mod = AtomicLong(0)
|
||||
private val owner get() = SwingUtilities.getWindowAncestor(this)
|
||||
private val lru = object : LinkedHashMap<String, Icon?>() {
|
||||
override fun removeEldestEntry(eldest: Map.Entry<String?, Icon?>?): Boolean {
|
||||
@@ -113,7 +116,7 @@ internal class TransportPanel(
|
||||
get() = enableManager.getFlag(showHiddenFilesKey, true)
|
||||
set(value) = enableManager.setFlag(showHiddenFilesKey, value)
|
||||
private val navigator get() = this
|
||||
private val nextReloadCallbacks = mutableListOf<() -> Unit>()
|
||||
private val nextReloadCallbacks = Collections.synchronizedMap(mutableMapOf<Long, MutableList<() -> Unit>>())
|
||||
private val history = linkedSetOf<Path>()
|
||||
private val undoManager = MyUndoManager()
|
||||
private val editTransferListener = EditTransferListener()
|
||||
@@ -301,7 +304,7 @@ internal class TransportPanel(
|
||||
}
|
||||
if (target.pathString == workdir?.pathString || target.parent.pathString == workdir?.pathString) {
|
||||
if (loading) {
|
||||
nextReloadCallbacks.add { reload(requestFocus = false) }
|
||||
registerNextReloadCallback { reload(requestFocus = false) }
|
||||
} else {
|
||||
reload(requestFocus = false)
|
||||
}
|
||||
@@ -620,7 +623,7 @@ internal class TransportPanel(
|
||||
}
|
||||
|
||||
fun registerSelectRow(name: String) {
|
||||
nextReloadCallbacks.add {
|
||||
registerNextReloadCallback {
|
||||
for (i in 0 until model.rowCount) {
|
||||
if (model.getAttributes(i).name == name) {
|
||||
val c = sorter.convertRowIndexToView(i)
|
||||
@@ -633,6 +636,11 @@ internal class TransportPanel(
|
||||
}
|
||||
}
|
||||
|
||||
private fun registerNextReloadCallback(block: () -> Unit) {
|
||||
nextReloadCallbacks.computeIfAbsent(mod.get()) { mutableListOf() }
|
||||
.add(block)
|
||||
}
|
||||
|
||||
fun reload(
|
||||
oldPath: String? = workdir?.absolutePathString(),
|
||||
newPath: String? = workdir?.absolutePathString(),
|
||||
@@ -643,6 +651,8 @@ internal class TransportPanel(
|
||||
if (loading) return false
|
||||
loading = true
|
||||
|
||||
val mod = mod.getAndAdd(1)
|
||||
|
||||
coroutineScope.launch {
|
||||
try {
|
||||
|
||||
@@ -650,7 +660,7 @@ internal class TransportPanel(
|
||||
|
||||
withContext(Dispatchers.Swing) {
|
||||
setNewWorkdir(workdir)
|
||||
nextReloadCallbacks.forEach { runCatching { it.invoke() } }
|
||||
nextReloadCallbacks[mod]?.forEach { runCatching { it.invoke() } }
|
||||
}
|
||||
|
||||
} catch (e: Exception) {
|
||||
@@ -665,7 +675,7 @@ internal class TransportPanel(
|
||||
} finally {
|
||||
withContext(Dispatchers.Swing) {
|
||||
loading = false
|
||||
nextReloadCallbacks.clear()
|
||||
nextReloadCallbacks.entries.removeIf { it.key <= mod }
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -730,6 +740,13 @@ internal class TransportPanel(
|
||||
if (files.isNotEmpty())
|
||||
consume.invoke()
|
||||
|
||||
if (first.compareAndSet(false, true)) {
|
||||
withContext(Dispatchers.Swing) {
|
||||
model.clear()
|
||||
table.scrollRectToVisible(Rectangle())
|
||||
}
|
||||
}
|
||||
|
||||
if (requestFocus)
|
||||
coroutineScope.launch(Dispatchers.Swing) { table.requestFocusInWindow() }
|
||||
|
||||
@@ -776,7 +793,9 @@ internal class TransportPanel(
|
||||
.getOrNull()
|
||||
|
||||
val fileSize = basicAttributes?.size() ?: 0
|
||||
val permissions = posixFileAttribute?.permissions() ?: emptySet()
|
||||
val permissions = posixFileAttribute?.permissions()
|
||||
?: if (basicAttributes is S3FileAttributes) basicAttributes.permissions
|
||||
else emptySet()
|
||||
val owner = fileOwnerAttribute?.name ?: StringUtils.EMPTY
|
||||
val lastModifiedTime = basicAttributes?.lastModifiedTime()?.toMillis() ?: 0
|
||||
val isDirectory = basicAttributes?.isDirectory ?: false
|
||||
|
||||
@@ -68,6 +68,7 @@ internal class TransportViewer : JPanel(BorderLayout()), DataProvider, Disposabl
|
||||
}
|
||||
|
||||
private fun initEvents() {
|
||||
|
||||
splitPane.addComponentListener(object : ComponentAdapter() {
|
||||
override fun componentResized(e: ComponentEvent) {
|
||||
removeComponentListener(this)
|
||||
@@ -91,6 +92,8 @@ internal class TransportViewer : JPanel(BorderLayout()), DataProvider, Disposabl
|
||||
}
|
||||
}
|
||||
|
||||
Disposer.register(this, transferManager)
|
||||
Disposer.register(this, transferTable)
|
||||
Disposer.register(this, leftTabbed)
|
||||
Disposer.register(this, rightTabbed)
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@ package app.termora.transfer.s3
|
||||
|
||||
import java.nio.file.attribute.BasicFileAttributes
|
||||
import java.nio.file.attribute.FileTime
|
||||
import java.nio.file.attribute.PosixFilePermission
|
||||
|
||||
data class S3FileAttributes(
|
||||
private val lastModifiedTime: Long = 0,
|
||||
@@ -13,7 +14,12 @@ data class S3FileAttributes(
|
||||
private val symbolicLink: Boolean = false,
|
||||
private val other: Boolean = false,
|
||||
private val size: Long = 0,
|
||||
) : BasicFileAttributes {
|
||||
|
||||
) : BasicFileAttributes {
|
||||
|
||||
var permissions: Set<PosixFilePermission> = emptySet()
|
||||
|
||||
|
||||
override fun lastModifiedTime(): FileTime {
|
||||
return FileTime.fromMillis(lastModifiedTime)
|
||||
}
|
||||
@@ -49,4 +55,6 @@ data class S3FileAttributes(
|
||||
override fun fileKey(): Any? {
|
||||
return null
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user