feat: improved keyPair comboBox (#92)

This commit is contained in:
hstyi
2025-01-16 18:18:58 +08:00
committed by GitHub
parent 992015c8e5
commit 63b27a2f83
4 changed files with 84 additions and 30 deletions

View File

@@ -1,8 +1,5 @@
package app.termora
import app.termora.keymgr.KeyManager
import app.termora.keymgr.OhKeyPair
class EditHostOptionsPane(private val host: Host) : HostOptionsPane() {
init {
generalOption.portTextField.value = host.port
@@ -10,15 +7,12 @@ class EditHostOptionsPane(private val host: Host) : HostOptionsPane() {
generalOption.protocolTypeComboBox.selectedItem = host.protocol
generalOption.usernameTextField.text = host.username
generalOption.hostTextField.text = host.host
generalOption.passwordTextField.text = host.authentication.password
generalOption.remarkTextArea.text = host.remark
generalOption.authenticationTypeComboBox.selectedItem = host.authentication.type
if (host.authentication.type == AuthenticationType.PublicKey) {
val ohKeyPair = KeyManager.getInstance().getOhKeyPair(host.authentication.password)
if (ohKeyPair != null) {
generalOption.publicKeyTextField.text = ohKeyPair.name
generalOption.publicKeyTextField.putClientProperty(OhKeyPair::class, ohKeyPair)
}
if (host.authentication.type == AuthenticationType.Password) {
generalOption.passwordTextField.text = host.authentication.password
} else if (host.authentication.type == AuthenticationType.PublicKey) {
generalOption.publicKeyComboBox.selectedItem = host.authentication.password
}
proxyOption.proxyTypeComboBox.selectedItem = host.proxy.type

View File

@@ -1,7 +1,7 @@
package app.termora
import app.termora.keymgr.KeyManager
import app.termora.keymgr.KeyManagerDialog
import app.termora.keymgr.OhKeyPair
import com.formdev.flatlaf.FlatClientProperties
import com.formdev.flatlaf.extras.components.FlatComboBox
import com.formdev.flatlaf.ui.FlatTextBorder
@@ -49,10 +49,9 @@ open class HostOptionsPane : OptionsPane() {
password = String(generalOption.passwordTextField.password)
)
} else if (generalOption.authenticationTypeComboBox.selectedItem == AuthenticationType.PublicKey) {
val keyPair = generalOption.publicKeyTextField.getClientProperty(OhKeyPair::class) as OhKeyPair?
authentication = authentication.copy(
type = AuthenticationType.PublicKey,
password = keyPair?.id ?: StringUtils.EMPTY
password = generalOption.publicKeyComboBox.selectedItem?.toString() ?: StringUtils.EMPTY
)
}
@@ -111,7 +110,7 @@ open class HostOptionsPane : OptionsPane() {
return false
}
} else if (host.authentication.type == AuthenticationType.PublicKey) {
if (validateField(generalOption.publicKeyTextField)) {
if (validateField(generalOption.publicKeyComboBox)) {
return false
}
}
@@ -149,6 +148,19 @@ open class HostOptionsPane : OptionsPane() {
return false
}
/**
* 返回 true 表示有错误
*/
private fun validateField(comboBox: JComboBox<*>): Boolean {
if (comboBox.isEnabled && comboBox.selectedItem == null) {
selectOptionJComponent(comboBox)
comboBox.putClientProperty(FlatClientProperties.OUTLINE, FlatClientProperties.OUTLINE_ERROR)
comboBox.requestFocusInWindow()
return true
}
return false
}
protected inner class GeneralOption : JPanel(BorderLayout()), Option {
val portTextField = PortSpinner()
val nameTextField = OutlineTextField(128)
@@ -158,7 +170,7 @@ open class HostOptionsPane : OptionsPane() {
private val passwordPanel = JPanel(BorderLayout())
private val chooseKeyBtn = JButton(Icons.greyKey)
val passwordTextField = OutlinePasswordField(255)
val publicKeyTextField = OutlineTextField()
val publicKeyComboBox = OutlineComboBox<String>()
val remarkTextArea = FixedLengthTextArea(512)
val authenticationTypeComboBox = FlatComboBox<AuthenticationType>()
@@ -170,7 +182,7 @@ open class HostOptionsPane : OptionsPane() {
private fun initView() {
add(getCenterComponent(), BorderLayout.CENTER)
publicKeyTextField.isEditable = false
publicKeyComboBox.isEditable = false
chooseKeyBtn.isFocusable = false
protocolTypeComboBox.renderer = object : DefaultListCellRenderer() {
@@ -191,6 +203,28 @@ open class HostOptionsPane : OptionsPane() {
}
}
publicKeyComboBox.renderer = object : DefaultListCellRenderer() {
override fun getListCellRendererComponent(
list: JList<*>?,
value: Any?,
index: Int,
isSelected: Boolean,
cellHasFocus: Boolean
): Component {
var text = StringUtils.EMPTY
if (value is String) {
text = KeyManager.getInstance().getOhKeyPair(value)?.name ?: text
}
return super.getListCellRendererComponent(
list,
text,
index,
isSelected,
cellHasFocus
)
}
}
authenticationTypeComboBox.renderer = object : DefaultListCellRenderer() {
override fun getListCellRendererComponent(
list: JList<*>?,
@@ -269,14 +303,20 @@ open class HostOptionsPane : OptionsPane() {
dialog.pack()
dialog.setLocationRelativeTo(null)
dialog.isVisible = true
if (dialog.ok) {
val lastKeyPair = dialog.getLasOhKeyPair()
if (lastKeyPair != null) {
publicKeyTextField.putClientProperty(OhKeyPair::class, lastKeyPair)
publicKeyTextField.text = lastKeyPair.name
publicKeyTextField.outline = null
}
val selectedItem = publicKeyComboBox.selectedItem
publicKeyComboBox.removeAllItems()
for (keyPair in KeyManager.getInstance().getOhKeyPairs()) {
publicKeyComboBox.addItem(keyPair.id)
}
publicKeyComboBox.selectedItem = selectedItem
if (!dialog.ok) {
return
}
publicKeyComboBox.selectedItem = dialog.getLasOhKeyPair()?.id ?: return
}
private fun refreshStates() {
@@ -284,6 +324,7 @@ open class HostOptionsPane : OptionsPane() {
portTextField.isEnabled = true
usernameTextField.isEnabled = true
authenticationTypeComboBox.isEnabled = true
publicKeyComboBox.isEnabled = true
passwordTextField.isEnabled = true
chooseKeyBtn.isEnabled = true
@@ -293,6 +334,7 @@ open class HostOptionsPane : OptionsPane() {
usernameTextField.isEnabled = false
authenticationTypeComboBox.isEnabled = false
passwordTextField.isEnabled = false
publicKeyComboBox.isEnabled = false
chooseKeyBtn.isEnabled = false
}
@@ -369,10 +411,16 @@ open class HostOptionsPane : OptionsPane() {
passwordPanel.removeAll()
if (authenticationTypeComboBox.selectedItem == AuthenticationType.PublicKey) {
val selectedItem = publicKeyComboBox.selectedItem
publicKeyComboBox.removeAllItems()
for (pair in KeyManager.getInstance().getOhKeyPairs()) {
publicKeyComboBox.addItem(pair.id)
}
publicKeyComboBox.selectedItem = selectedItem
passwordPanel.add(
FormBuilder.create()
.layout(FormLayout("default:grow, 4dlu, left:pref", "pref"))
.add(publicKeyTextField).xy(1, 1)
.add(publicKeyComboBox).xy(1, 1)
.add(chooseKeyBtn).xy(3, 1)
.build(), BorderLayout.CENTER
)

View File

@@ -522,13 +522,18 @@ class HostTree : JTree(), Disposable {
while (parents.isNotEmpty()) {
val p = parents.removeFirst()
for (i in 0 until model.getChildCount(p)) {
val child = model.getChild(p, i) as Host
for (i in 0 until getModel().getChildCount(p)) {
val child = getModel().getChild(p, i) as Host
nodes.add(child)
parents.add(child)
}
}
// 确保是最新的
for (i in 0 until nodes.size) {
nodes[i] = model.getHost(nodes[i].id) ?: continue
}
return nodes
}

View File

@@ -1,13 +1,11 @@
package app.termora
import com.formdev.flatlaf.FlatClientProperties
import com.formdev.flatlaf.extras.components.*
import com.formdev.flatlaf.ui.FlatTextBorder
import org.apache.commons.lang3.StringUtils
import java.awt.Component
import java.awt.event.FocusAdapter
import java.awt.event.FocusEvent
import java.awt.event.KeyAdapter
import java.awt.event.KeyEvent
import java.awt.event.*
import java.text.ParseException
import javax.swing.DefaultListCellRenderer
import javax.swing.JComboBox
@@ -53,6 +51,15 @@ class OutlineTextArea : FlatTextArea() {
}
}
class OutlineComboBox<T> : JComboBox<T>() {
init {
addItemListener {
if (it.stateChange == ItemEvent.SELECTED) {
putClientProperty(FlatClientProperties.OUTLINE, null)
}
}
}
}
class FixedLengthTextArea(var maxLength: Int = Int.MAX_VALUE) : FlatTextArea() {
init {