feat: keyword highlight set

This commit is contained in:
hstyi
2025-07-18 21:47:57 +08:00
committed by GitHub
parent f99e3e9147
commit ae7730fb35
20 changed files with 545 additions and 259 deletions

View File

@@ -4,7 +4,7 @@ plugins {
project.version = "0.0.3" project.version = "0.0.4"
dependencies { dependencies {

View File

@@ -1,6 +1,8 @@
package app.termora.plugins.serial package app.termora.plugins.serial
import app.termora.* import app.termora.*
import app.termora.account.AccountOwner
import app.termora.highlight.KeywordHighlight
import app.termora.plugin.internal.AltKeyModifier import app.termora.plugin.internal.AltKeyModifier
import app.termora.plugin.internal.BasicGeneralOption import app.termora.plugin.internal.BasicGeneralOption
import app.termora.plugin.internal.BasicTerminalOption import app.termora.plugin.internal.BasicTerminalOption
@@ -19,11 +21,12 @@ import java.awt.event.ComponentAdapter
import java.awt.event.ComponentEvent import java.awt.event.ComponentEvent
import javax.swing.* import javax.swing.*
class SerialHostOptionsPane : OptionsPane() { class SerialHostOptionsPane(private val accountOwner: AccountOwner) : OptionsPane() {
private val generalOption = BasicGeneralOption() private val generalOption = BasicGeneralOption()
private val terminalOption = BasicTerminalOption().apply { private val terminalOption = BasicTerminalOption().apply {
showCharsetComboBox = true showCharsetComboBox = true
showStartupCommandTextField = true showStartupCommandTextField = true
accountOwner = this@SerialHostOptionsPane.accountOwner
init() init()
} }
private val serialCommOption = SerialCommOption() private val serialCommOption = SerialCommOption()
@@ -56,6 +59,8 @@ class SerialHostOptionsPane : OptionsPane() {
extras = mutableMapOf( extras = mutableMapOf(
"altModifier" to (terminalOption.altModifierComboBox.selectedItem?.toString() "altModifier" to (terminalOption.altModifierComboBox.selectedItem?.toString()
?: AltKeyModifier.EightBit.name), ?: AltKeyModifier.EightBit.name),
"keywordHighlightSetId" to ((terminalOption.highlightSetComboBox.selectedItem as? KeywordHighlight)?.id
?: "-1"),
) )
) )
@@ -88,6 +93,17 @@ class SerialHostOptionsPane : OptionsPane() {
val altModifier = host.options.extras["altModifier"] ?: AltKeyModifier.EightBit.name val altModifier = host.options.extras["altModifier"] ?: AltKeyModifier.EightBit.name
terminalOption.altModifierComboBox.selectedItem = runCatching { AltKeyModifier.valueOf(altModifier) } terminalOption.altModifierComboBox.selectedItem = runCatching { AltKeyModifier.valueOf(altModifier) }
.getOrNull() ?: AltKeyModifier.EightBit .getOrNull() ?: AltKeyModifier.EightBit
val keywordHighlightSetId = host.options.extras["keywordHighlightSetId"]
for (i in 0 until terminalOption.highlightSetComboBox.itemCount) {
val item = terminalOption.highlightSetComboBox.getItemAt(i)
if (item.id == keywordHighlightSetId) {
terminalOption.highlightSetComboBox.selectedItem = item
break
}
}
} }
fun validateFields(): Boolean { fun validateFields(): Boolean {

View File

@@ -2,11 +2,12 @@ package app.termora.plugins.serial
import app.termora.Disposer import app.termora.Disposer
import app.termora.Host import app.termora.Host
import app.termora.account.AccountOwner
import app.termora.protocol.ProtocolHostPanel import app.termora.protocol.ProtocolHostPanel
import java.awt.BorderLayout import java.awt.BorderLayout
class SerialProtocolHostPanel : ProtocolHostPanel() { class SerialProtocolHostPanel(accountOwner: AccountOwner) : ProtocolHostPanel() {
private val pane = SerialHostOptionsPane() private val pane = SerialHostOptionsPane(accountOwner)
init { init {
initView() initView()

View File

@@ -16,7 +16,7 @@ internal class SerialProtocolHostPanelExtension private constructor() : Protocol
} }
override fun createProtocolHostPanel(accountOwner: AccountOwner): ProtocolHostPanel { override fun createProtocolHostPanel(accountOwner: AccountOwner): ProtocolHostPanel {
return SerialProtocolHostPanel() return SerialProtocolHostPanel(accountOwner)
} }
override fun ordered(): Long { override fun ordered(): Long {

View File

@@ -8,6 +8,16 @@ import org.apache.commons.lang3.StringUtils
data class KeywordHighlight( data class KeywordHighlight(
val id: String = randomUUID(), val id: String = randomUUID(),
/**
* Set id默认 0
*/
val parentId: String = "0",
/**
* [KeywordHighlightType]
*/
val type: KeywordHighlightType = KeywordHighlightType.Highlight,
/** /**
* 关键词 * 关键词
*/ */

View File

@@ -1,12 +1,9 @@
package app.termora.highlight package app.termora.highlight
import app.termora.ApplicationScope import app.termora.*
import app.termora.Disposable
import app.termora.Disposer
import app.termora.account.Account import app.termora.account.Account
import app.termora.account.AccountExtension import app.termora.account.AccountExtension
import app.termora.account.AccountManager import app.termora.account.AccountManager
import app.termora.assertEventDispatchThread
import app.termora.database.DataType import app.termora.database.DataType
import app.termora.database.DatabaseChangedExtension import app.termora.database.DatabaseChangedExtension
import app.termora.plugin.internal.extension.DynamicExtensionHandler import app.termora.plugin.internal.extension.DynamicExtensionHandler
@@ -20,7 +17,7 @@ import java.util.concurrent.atomic.AtomicBoolean
import kotlin.math.min import kotlin.math.min
import kotlin.random.Random import kotlin.random.Random
class KeywordHighlightPaintListener private constructor() : TerminalPaintListener, Disposable { internal class KeywordHighlightPaintListener private constructor() : TerminalPaintListener, Disposable {
companion object { companion object {
fun getInstance(): KeywordHighlightPaintListener { fun getInstance(): KeywordHighlightPaintListener {
@@ -93,11 +90,22 @@ class KeywordHighlightPaintListener private constructor() : TerminalPaintListene
} }
} }
for (highlight in keywordHighlights) { // 默认情况是:默认集
if (highlight.enabled.not()) { var keywordHighlightSetId = "0"
continue val terminalModel = terminal.getTerminalModel()
if (terminalModel.hasData(HostTerminalTab.Host)) {
val host = terminalModel.getData(HostTerminalTab.Host)
keywordHighlightSetId = host.options.extras["keywordHighlightSetId"] ?: keywordHighlightSetId
} }
// -1 表示不使用高亮集
if (keywordHighlightSetId == "-1") return
for (highlight in keywordHighlights) {
if (highlight.enabled.not()) continue
if (highlight.type != KeywordHighlightType.Highlight) continue
if (keywordHighlightSetId != highlight.parentId) continue
val document = terminal.getDocument() val document = terminal.getDocument()
val kinds = mutableListOf<FindKind>() val kinds = mutableListOf<FindKind>()
val iterator = object : Iterator<TerminalLine> { val iterator = object : Iterator<TerminalLine> {

View File

@@ -4,6 +4,8 @@ import app.termora.*
import app.termora.Application.ohMyJson import app.termora.Application.ohMyJson
import app.termora.account.AccountOwner import app.termora.account.AccountOwner
import app.termora.terminal.TerminalColor import app.termora.terminal.TerminalColor
import com.formdev.flatlaf.extras.components.FlatPopupMenu
import com.formdev.flatlaf.extras.components.FlatTabbedPane
import com.formdev.flatlaf.extras.components.FlatTable import com.formdev.flatlaf.extras.components.FlatTable
import com.jgoodies.forms.builder.FormBuilder import com.jgoodies.forms.builder.FormBuilder
import com.jgoodies.forms.layout.FormLayout import com.jgoodies.forms.layout.FormLayout
@@ -12,12 +14,13 @@ import org.apache.commons.lang3.exception.ExceptionUtils
import java.awt.BorderLayout import java.awt.BorderLayout
import java.awt.Color import java.awt.Color
import java.awt.Component import java.awt.Component
import java.awt.event.ActionEvent
import java.awt.event.MouseAdapter import java.awt.event.MouseAdapter
import java.awt.event.MouseEvent import java.awt.event.MouseEvent
import java.io.File import java.io.File
import java.nio.charset.StandardCharsets import java.nio.charset.StandardCharsets
import javax.swing.* import javax.swing.*
import javax.swing.border.EmptyBorder import javax.swing.JTabbedPane.SCROLL_TAB_LAYOUT
import javax.swing.table.DefaultTableCellRenderer import javax.swing.table.DefaultTableCellRenderer
import javax.swing.table.TableCellRenderer import javax.swing.table.TableCellRenderer
@@ -25,17 +28,146 @@ import javax.swing.table.TableCellRenderer
class KeywordHighlightPanel(private val accountOwner: AccountOwner) : JPanel(BorderLayout()), Disposable { class KeywordHighlightPanel(private val accountOwner: AccountOwner) : JPanel(BorderLayout()), Disposable {
private val owner get() = SwingUtilities.getWindowAncestor(this) private val owner get() = SwingUtilities.getWindowAncestor(this)
private val model = KeywordHighlightTableModel(accountOwner)
private val table = FlatTable()
private val keywordHighlightManager get() = KeywordHighlightManager.getInstance() private val keywordHighlightManager get() = KeywordHighlightManager.getInstance()
private val terminal = TerminalFactory.getInstance().createTerminal() private val terminal = TerminalFactory.getInstance().createTerminal()
private val colorPalette get() = terminal.getTerminalModel().getColorPalette() private val colorPalette get() = terminal.getTerminalModel().getColorPalette()
private val tabbed = FlatTabbedPane()
init {
initView()
initEvents()
}
private fun initView() {
tabbed.styleMap = mapOf(
"focusColor" to DynamicColor("TabbedPane.background"),
"hoverColor" to DynamicColor("TabbedPane.background"),
"inactiveUnderlineColor" to DynamicColor("TabbedPane.underlineColor"),
)
tabbed.isHasFullBorder = false
tabbed.tabPlacement = JTabbedPane.LEFT
tabbed.tabType = FlatTabbedPane.TabType.underlined
tabbed.isTabsClosable = false
tabbed.tabLayoutPolicy = SCROLL_TAB_LAYOUT
tabbed.tabWidthMode = FlatTabbedPane.TabWidthMode.preferred
tabbed.isFocusable = false
tabbed.tabHeight = UIManager.getInt("TabbedPane.tabHeight") - 8
val sets = keywordHighlightManager.getKeywordHighlights(accountOwner.id)
.filter { it.type == KeywordHighlightType.Set }
.sortedBy { it.sort }
tabbed.addTab(I18n.getString("termora.highlight.default-set"), KeywordHighlightMiniPanel("0"))
for (highlight in sets) {
tabbed.addTab(highlight.keyword, KeywordHighlightMiniPanel(highlight.id))
}
add(tabbed, BorderLayout.CENTER)
}
private fun initEvents() {
tabbed.addMouseListener(object : MouseAdapter() {
override fun mouseClicked(e: MouseEvent) {
if (SwingUtilities.isRightMouseButton(e).not()) {
return
}
val index = tabbed.indexAtLocation(e.x, e.y)
if (index < 0) return
tabbed.selectedIndex = index
showContextmenu(index, e)
}
})
Disposer.register(this, object : Disposable {
override fun dispose() {
terminal.close()
}
})
}
private fun showContextmenu(index: Int, e: MouseEvent) {
var offset = 0
for (i in 0..index) offset += tabbed.ui.getTabBounds(tabbed, i).height
val popupMenu = FlatPopupMenu()
popupMenu.add(I18n.getString("termora.new-host.tunneling.add")).addActionListener(object : AbstractAction() {
override fun actionPerformed(e: ActionEvent) {
val text = OptionPane.showInputDialog(owner) ?: return
if (text.isBlank()) return
val highlight = KeywordHighlight(
keyword = text,
type = KeywordHighlightType.Set
)
keywordHighlightManager.addKeywordHighlight(highlight, accountOwner)
tabbed.addTab(text, KeywordHighlightMiniPanel(highlight.id))
tabbed.selectedIndex = tabbed.tabCount - 1
}
})
if (index > 0) {
popupMenu.add(I18n.getString("termora.tabbed.contextmenu.rename"))
.addActionListener(object : AbstractAction() {
override fun actionPerformed(e: ActionEvent) {
val tab = tabbed.getComponentAt(index) as? KeywordHighlightMiniPanel ?: return
val title = tabbed.getTitleAt(index) ?: return
val text = OptionPane.showInputDialog(owner, value = title) ?: return
if (text.isBlank() || title == text) return
val highlight = keywordHighlightManager.getKeywordHighlights(accountOwner.id)
.filter { it.type == KeywordHighlightType.Set }
.firstOrNull { it.id == tab.setId } ?: return
keywordHighlightManager.addKeywordHighlight(
highlight.copy(
updateDate = System.currentTimeMillis(),
keyword = text
), accountOwner
)
tabbed.setTitleAt(index, text)
}
})
popupMenu.add(I18n.getString("termora.remove")).addActionListener(object : AbstractAction() {
override fun actionPerformed(e: ActionEvent) {
val tab = tabbed.getComponentAt(index) as? KeywordHighlightMiniPanel ?: return
if (OptionPane.showConfirmDialog(
owner,
I18n.getString("termora.keymgr.delete-warning"),
I18n.getString("termora.remove"),
JOptionPane.YES_NO_OPTION,
JOptionPane.QUESTION_MESSAGE
) != JOptionPane.YES_OPTION
) return
tabbed.removeTabAt(index)
for (highlight in keywordHighlightManager.getKeywordHighlights(accountOwner.id)) {
if (highlight.parentId == tab.setId || highlight.id == tab.setId) {
keywordHighlightManager.removeKeywordHighlight(highlight.id)
}
}
}
})
}
popupMenu.show(e.component, e.x, e.y)
}
private inner class KeywordHighlightMiniPanel(val setId: String) : JPanel(BorderLayout()) {
private val addBtn = JButton(I18n.getString("termora.new-host.tunneling.add")) private val addBtn = JButton(I18n.getString("termora.new-host.tunneling.add"))
private val editBtn = JButton(I18n.getString("termora.keymgr.edit")) private val editBtn = JButton(I18n.getString("termora.keymgr.edit"))
private val deleteBtn = JButton(I18n.getString("termora.remove")) private val deleteBtn = JButton(I18n.getString("termora.remove"))
private val importBtn = JButton(I18n.getString("termora.keymgr.import")) private val importBtn = JButton(I18n.getString("termora.keymgr.import"))
private val exportBtn = JButton(I18n.getString("termora.keymgr.export")) private val exportBtn = JButton(I18n.getString("termora.keymgr.export"))
private val model = KeywordHighlightTableModel(accountOwner, setId)
private val table = FlatTable()
init { init {
initView() initView()
@@ -110,7 +242,6 @@ class KeywordHighlightPanel(private val accountOwner: AccountOwner) : JPanel(Bor
}) })
add(createCenterPanel(), BorderLayout.CENTER) add(createCenterPanel(), BorderLayout.CENTER)
} }
private fun initEvents() { private fun initEvents() {
@@ -123,10 +254,12 @@ class KeywordHighlightPanel(private val accountOwner: AccountOwner) : JPanel(Bor
if (row >= 0 && column == 0) { if (row >= 0 && column == 0) {
val keywordHighlight = model.getKeywordHighlight(row) val keywordHighlight = model.getKeywordHighlight(row)
keywordHighlightManager.addKeywordHighlight( keywordHighlightManager.addKeywordHighlight(
keywordHighlight.copy(enabled = !keywordHighlight.enabled), keywordHighlight.copy(enabled = keywordHighlight.enabled.not()),
accountOwner accountOwner
) )
model.fireTableCellUpdated(row, column) model.fireTableCellUpdated(row, column)
} else if (row < 0) {
table.clearSelection()
} }
} }
} }
@@ -138,7 +271,7 @@ class KeywordHighlightPanel(private val accountOwner: AccountOwner) : JPanel(Bor
dialog.isVisible = true dialog.isVisible = true
val keywordHighlight = dialog.keywordHighlight val keywordHighlight = dialog.keywordHighlight
if (keywordHighlight != null) { if (keywordHighlight != null) {
keywordHighlightManager.addKeywordHighlight(keywordHighlight, accountOwner) keywordHighlightManager.addKeywordHighlight(keywordHighlight.copy(parentId = setId), accountOwner)
model.fireTableRowsInserted(model.rowCount - 1, model.rowCount) model.fireTableRowsInserted(model.rowCount - 1, model.rowCount)
} }
} }
@@ -188,7 +321,10 @@ class KeywordHighlightPanel(private val accountOwner: AccountOwner) : JPanel(Bor
val value = dialog.keywordHighlight val value = dialog.keywordHighlight
if (value != null) { if (value != null) {
keywordHighlight = value.copy(id = keywordHighlight.id, sort = keywordHighlight.sort) keywordHighlight = value.copy(
id = keywordHighlight.id, parentId = setId,
sort = keywordHighlight.sort
)
keywordHighlightManager.addKeywordHighlight(keywordHighlight, accountOwner) keywordHighlightManager.addKeywordHighlight(keywordHighlight, accountOwner)
model.fireTableRowsUpdated(row, row) model.fireTableRowsUpdated(row, row)
} }
@@ -226,6 +362,7 @@ class KeywordHighlightPanel(private val accountOwner: AccountOwner) : JPanel(Bor
fileChooser.showSaveDialog(owner, "highlights.json").thenAccept { file -> fileChooser.showSaveDialog(owner, "highlights.json").thenAccept { file ->
file?.outputStream()?.use { file?.outputStream()?.use {
val highlights = keywordHighlightManager.getKeywordHighlights(accountOwner.id) val highlights = keywordHighlightManager.getKeywordHighlights(accountOwner.id)
.filter { e -> e.parentId == setId }
.map { e -> e.copy(id = randomUUID()) } .map { e -> e.copy(id = randomUUID()) }
IOUtils.write(ohMyJson.encodeToString(highlights), it, StandardCharsets.UTF_8) IOUtils.write(ohMyJson.encodeToString(highlights), it, StandardCharsets.UTF_8)
} }
@@ -242,17 +379,12 @@ class KeywordHighlightPanel(private val accountOwner: AccountOwner) : JPanel(Bor
.thenAccept { if (it.isNotEmpty()) SwingUtilities.invokeLater { importKeywordHighlights(it.first()) } } .thenAccept { if (it.isNotEmpty()) SwingUtilities.invokeLater { importKeywordHighlights(it.first()) } }
} }
Disposer.register(this, object : Disposable {
override fun dispose() {
terminal.close()
}
})
} }
private fun importKeywordHighlights(file: File) { private fun importKeywordHighlights(file: File) {
try { try {
val highlights = ohMyJson.decodeFromString<List<KeywordHighlight>>(file.readText()) val highlights = ohMyJson.decodeFromString<List<KeywordHighlight>>(file.readText())
.map { it.copy(id = randomUUID()) } .map { it.copy(id = randomUUID(), parentId = setId) }
for (highlight in highlights) { for (highlight in highlights) {
keywordHighlightManager.addKeywordHighlight(highlight, accountOwner) keywordHighlightManager.addKeywordHighlight(highlight, accountOwner)
model.fireTableRowsInserted(model.rowCount - 1, model.rowCount) model.fireTableRowsInserted(model.rowCount - 1, model.rowCount)
@@ -266,11 +398,15 @@ class KeywordHighlightPanel(private val accountOwner: AccountOwner) : JPanel(Bor
} }
} }
private fun createCenterPanel(): JComponent { private fun createCenterPanel(): JComponent {
val panel = JPanel(BorderLayout()) val panel = JPanel(BorderLayout())
panel.add(JScrollPane(table).apply { panel.add(JScrollPane(table).apply {
border = BorderFactory.createMatteBorder(1, 1, 1, 1, DynamicColor.BorderColor) border = BorderFactory.createCompoundBorder(
BorderFactory.createEmptyBorder(8, 8, 8, 0),
BorderFactory.createMatteBorder(1, 1, 1, 1, DynamicColor.BorderColor)
)
}, BorderLayout.CENTER) }, BorderLayout.CENTER)
var rows = 1 var rows = 1
@@ -281,7 +417,8 @@ class KeywordHighlightPanel(private val accountOwner: AccountOwner) : JPanel(Bor
"pref, $formMargin, pref, $formMargin, pref, $formMargin, pref, $formMargin, pref" "pref, $formMargin, pref, $formMargin, pref, $formMargin, pref, $formMargin, pref"
) )
panel.add( panel.add(
FormBuilder.create().layout(layout).padding(EmptyBorder(0, 12, 0, 0)) FormBuilder.create().layout(layout)
.border(BorderFactory.createEmptyBorder(8, 8, 8, 8))
.add(addBtn).xy(1, rows).apply { rows += step } .add(addBtn).xy(1, rows).apply { rows += step }
.add(editBtn).xy(1, rows).apply { rows += step } .add(editBtn).xy(1, rows).apply { rows += step }
.add(deleteBtn).xy(1, rows).apply { rows += step } .add(deleteBtn).xy(1, rows).apply { rows += step }
@@ -290,13 +427,7 @@ class KeywordHighlightPanel(private val accountOwner: AccountOwner) : JPanel(Bor
.build(), .build(),
BorderLayout.EAST) BorderLayout.EAST)
panel.border = BorderFactory.createEmptyBorder(
12,
12, 12, 12
)
return panel return panel
} }
}
} }

View File

@@ -3,8 +3,14 @@ package app.termora.highlight
import app.termora.account.AccountOwner import app.termora.account.AccountOwner
import javax.swing.table.DefaultTableModel import javax.swing.table.DefaultTableModel
class KeywordHighlightTableModel(private val accountOwner: AccountOwner) : DefaultTableModel() { class KeywordHighlightTableModel(
private val rows get() = KeywordHighlightManager.getInstance().getKeywordHighlights(accountOwner.id) private val accountOwner: AccountOwner,
private val setId: String
) : DefaultTableModel() {
private val rows
get() = KeywordHighlightManager.getInstance()
.getKeywordHighlights(accountOwner.id).filter { it.parentId == setId }
.filter { it.type == KeywordHighlightType.Highlight }
override fun isCellEditable(row: Int, column: Int): Boolean { override fun isCellEditable(row: Int, column: Int): Boolean {
return false return false

View File

@@ -0,0 +1,6 @@
package app.termora.highlight
enum class KeywordHighlightType {
Set,
Highlight,
}

View File

@@ -3,6 +3,10 @@ package app.termora.plugin.internal
import app.termora.* import app.termora.*
import app.termora.OptionsPane.Companion.FORM_MARGIN import app.termora.OptionsPane.Companion.FORM_MARGIN
import app.termora.OptionsPane.Option import app.termora.OptionsPane.Option
import app.termora.account.AccountOwner
import app.termora.highlight.KeywordHighlight
import app.termora.highlight.KeywordHighlightManager
import app.termora.highlight.KeywordHighlightType
import app.termora.plugin.internal.telnet.TelnetHostOptionsPane.Backspace import app.termora.plugin.internal.telnet.TelnetHostOptionsPane.Backspace
import com.formdev.flatlaf.extras.components.FlatTabbedPane import com.formdev.flatlaf.extras.components.FlatTabbedPane
import com.formdev.flatlaf.ui.FlatTextBorder import com.formdev.flatlaf.ui.FlatTextBorder
@@ -24,6 +28,8 @@ class BasicTerminalOption() : JPanel(BorderLayout()), Option {
var showBackspaceComboBox: Boolean = false var showBackspaceComboBox: Boolean = false
var showCharacterAtATimeTextField: Boolean = false var showCharacterAtATimeTextField: Boolean = false
var showAltModifierComboBox: Boolean = true var showAltModifierComboBox: Boolean = true
var showHighlightSet: Boolean = true
var accountOwner: AccountOwner? = null
val charsetComboBox = JComboBox<String>() val charsetComboBox = JComboBox<String>()
val startupCommandTextField = OutlineTextField() val startupCommandTextField = OutlineTextField()
@@ -32,6 +38,7 @@ class BasicTerminalOption() : JPanel(BorderLayout()), Option {
val loginScripts = mutableListOf<LoginScript>() val loginScripts = mutableListOf<LoginScript>()
val backspaceComboBox = JComboBox<Backspace>() val backspaceComboBox = JComboBox<Backspace>()
val altModifierComboBox = JComboBox<AltKeyModifier>() val altModifierComboBox = JComboBox<AltKeyModifier>()
val highlightSetComboBox = JComboBox<KeywordHighlight>()
val characterAtATimeTextField = YesOrNoComboBox() val characterAtATimeTextField = YesOrNoComboBox()
@@ -82,6 +89,36 @@ class BasicTerminalOption() : JPanel(BorderLayout()), Option {
} }
} }
val accountOwner = this.accountOwner
if (showHighlightSet && accountOwner != null) {
val highlights = KeywordHighlightManager.getInstance()
.getKeywordHighlights(accountOwner.id)
.filter { it.type == KeywordHighlightType.Set }
highlightSetComboBox.addItem(KeywordHighlight(id = "-1", keyword = "None"))
val defaultHighlight = KeywordHighlight(id = "0", keyword = I18n.getString("termora.highlight.default-set"))
highlightSetComboBox.addItem(defaultHighlight)
for (highlight in highlights) {
highlightSetComboBox.addItem(highlight)
}
highlightSetComboBox.selectedItem = defaultHighlight
highlightSetComboBox.renderer = object : DefaultListCellRenderer() {
override fun getListCellRendererComponent(
list: JList<*>?,
value: Any?,
index: Int,
isSelected: Boolean,
cellHasFocus: Boolean
): Component? {
var text = value?.toString() ?: value
if (value is KeywordHighlight) {
text = value.keyword
}
return super.getListCellRendererComponent(list, text, index, isSelected, cellHasFocus)
}
}
}
if (showBackspaceComboBox) { if (showBackspaceComboBox) {
backspaceComboBox.addItem(Backspace.Delete) backspaceComboBox.addItem(Backspace.Delete)
@@ -136,9 +173,10 @@ class BasicTerminalOption() : JPanel(BorderLayout()), Option {
private fun getCenterComponent(): JComponent { private fun getCenterComponent(): JComponent {
val layout = FormLayout( val layout = FormLayout(
"left:pref, $FORM_MARGIN, default:grow", "left:pref, $FORM_MARGIN, default:grow",
"pref, $FORM_MARGIN, pref, $FORM_MARGIN, pref, $FORM_MARGIN, pref, $FORM_MARGIN, pref, $FORM_MARGIN, pref, $FORM_MARGIN, pref, $FORM_MARGIN, pref" "pref, $FORM_MARGIN, pref, $FORM_MARGIN, pref, $FORM_MARGIN, pref, $FORM_MARGIN, pref, $FORM_MARGIN, pref, $FORM_MARGIN, pref, $FORM_MARGIN, pref, $FORM_MARGIN, pref"
) )
val accountOwner = this.accountOwner
var rows = 1 var rows = 1
val step = 2 val step = 2
val builder = FormBuilder.create().layout(layout) val builder = FormBuilder.create().layout(layout)
@@ -151,6 +189,11 @@ class BasicTerminalOption() : JPanel(BorderLayout()), Option {
.add(charsetComboBox).xy(3, rows).apply { rows += step } .add(charsetComboBox).xy(3, rows).apply { rows += step }
} }
if (showHighlightSet && accountOwner != null) {
builder.add("${I18n.getString("termora.highlight")}:").xy(1, rows)
.add(highlightSetComboBox).xy(3, rows).apply { rows += step }
}
if (showAltModifierComboBox) { if (showAltModifierComboBox) {
builder.add("${I18n.getString("termora.new-host.terminal.alt-modifier")}:").xy(1, rows) builder.add("${I18n.getString("termora.new-host.terminal.alt-modifier")}:").xy(1, rows)
.add(altModifierComboBox).xy(3, rows).apply { rows += step } .add(altModifierComboBox).xy(3, rows).apply { rows += step }

View File

@@ -4,6 +4,8 @@ import app.termora.Host
import app.termora.Options import app.termora.Options
import app.termora.OptionsPane import app.termora.OptionsPane
import app.termora.SerialComm import app.termora.SerialComm
import app.termora.account.AccountOwner
import app.termora.highlight.KeywordHighlight
import app.termora.plugin.internal.AltKeyModifier import app.termora.plugin.internal.AltKeyModifier
import app.termora.plugin.internal.BasicGeneralOption import app.termora.plugin.internal.BasicGeneralOption
import app.termora.plugin.internal.BasicTerminalOption import app.termora.plugin.internal.BasicTerminalOption
@@ -12,12 +14,14 @@ import java.awt.Window
import javax.swing.JTextField import javax.swing.JTextField
import javax.swing.SwingUtilities import javax.swing.SwingUtilities
internal open class LocalHostOptionsPane : OptionsPane() { internal open class LocalHostOptionsPane(private val accountOwner: AccountOwner) : OptionsPane() {
protected val generalOption = BasicGeneralOption() protected val generalOption = BasicGeneralOption()
private val terminalOption = BasicTerminalOption().apply { private val terminalOption = BasicTerminalOption().apply {
showCharsetComboBox = true showCharsetComboBox = true
showEnvironmentTextArea = true showEnvironmentTextArea = true
showStartupCommandTextField = true showStartupCommandTextField = true
showHighlightSet = true
accountOwner = this@LocalHostOptionsPane.accountOwner
init() init()
} }
protected val owner: Window get() = SwingUtilities.getWindowAncestor(this) protected val owner: Window get() = SwingUtilities.getWindowAncestor(this)
@@ -43,6 +47,8 @@ internal open class LocalHostOptionsPane : OptionsPane() {
extras = mutableMapOf( extras = mutableMapOf(
"altModifier" to (terminalOption.altModifierComboBox.selectedItem?.toString() "altModifier" to (terminalOption.altModifierComboBox.selectedItem?.toString()
?: AltKeyModifier.EightBit.name), ?: AltKeyModifier.EightBit.name),
"keywordHighlightSetId" to ((terminalOption.highlightSetComboBox.selectedItem as? KeywordHighlight)?.id
?: "-1"),
) )
) )
@@ -66,6 +72,15 @@ internal open class LocalHostOptionsPane : OptionsPane() {
val altModifier = host.options.extras["altModifier"] ?: AltKeyModifier.EightBit.name val altModifier = host.options.extras["altModifier"] ?: AltKeyModifier.EightBit.name
terminalOption.altModifierComboBox.selectedItem = runCatching { AltKeyModifier.valueOf(altModifier) } terminalOption.altModifierComboBox.selectedItem = runCatching { AltKeyModifier.valueOf(altModifier) }
.getOrNull() ?: AltKeyModifier.EightBit .getOrNull() ?: AltKeyModifier.EightBit
val keywordHighlightSetId = host.options.extras["keywordHighlightSetId"]
for (i in 0 until terminalOption.highlightSetComboBox.itemCount) {
val item = terminalOption.highlightSetComboBox.getItemAt(i)
if (item.id == keywordHighlightSetId) {
terminalOption.highlightSetComboBox.selectedItem = item
break
}
}
} }
fun validateFields(): Boolean { fun validateFields(): Boolean {

View File

@@ -2,12 +2,13 @@ package app.termora.plugin.internal.local
import app.termora.Disposer import app.termora.Disposer
import app.termora.Host import app.termora.Host
import app.termora.account.AccountOwner
import app.termora.protocol.ProtocolHostPanel import app.termora.protocol.ProtocolHostPanel
import java.awt.BorderLayout import java.awt.BorderLayout
internal class LocalProtocolHostPanel : ProtocolHostPanel() { internal class LocalProtocolHostPanel(accountOwner: AccountOwner) : ProtocolHostPanel() {
private val pane = LocalHostOptionsPane() private val pane = LocalHostOptionsPane(accountOwner)
init { init {
initView() initView()

View File

@@ -16,7 +16,7 @@ internal class LocalProtocolHostPanelExtension private constructor() : ProtocolH
} }
override fun createProtocolHostPanel(accountOwner: AccountOwner): ProtocolHostPanel { override fun createProtocolHostPanel(accountOwner: AccountOwner): ProtocolHostPanel {
return LocalProtocolHostPanel() return LocalProtocolHostPanel(accountOwner)
} }
override fun ordered(): Long { override fun ordered(): Long {

View File

@@ -2,6 +2,7 @@ package app.termora.plugin.internal.ssh
import app.termora.* import app.termora.*
import app.termora.account.AccountOwner import app.termora.account.AccountOwner
import app.termora.highlight.KeywordHighlight
import app.termora.keymgr.KeyManager import app.termora.keymgr.KeyManager
import app.termora.keymgr.KeyManagerDialog import app.termora.keymgr.KeyManagerDialog
import app.termora.plugin.internal.AltKeyModifier import app.termora.plugin.internal.AltKeyModifier
@@ -37,6 +38,8 @@ internal class SSHHostOptionsPane(private val accountOwner: AccountOwner) : Opti
showEnvironmentTextArea = true showEnvironmentTextArea = true
showStartupCommandTextField = true showStartupCommandTextField = true
showHeartbeatIntervalTextField = true showHeartbeatIntervalTextField = true
showHighlightSet = true
accountOwner = this@SSHHostOptionsPane.accountOwner
init() init()
} }
private val jumpHostsOption = JumpHostsOption() private val jumpHostsOption = JumpHostsOption()
@@ -108,6 +111,8 @@ internal class SSHHostOptionsPane(private val accountOwner: AccountOwner) : Opti
extras = mutableMapOf( extras = mutableMapOf(
"altModifier" to (terminalOption.altModifierComboBox.selectedItem?.toString() "altModifier" to (terminalOption.altModifierComboBox.selectedItem?.toString()
?: AltKeyModifier.EightBit.name), ?: AltKeyModifier.EightBit.name),
"keywordHighlightSetId" to ((terminalOption.highlightSetComboBox.selectedItem as? KeywordHighlight)?.id
?: "-1"),
) )
) )
@@ -157,6 +162,17 @@ internal class SSHHostOptionsPane(private val accountOwner: AccountOwner) : Opti
terminalOption.altModifierComboBox.selectedItem = runCatching { AltKeyModifier.valueOf(altModifier) } terminalOption.altModifierComboBox.selectedItem = runCatching { AltKeyModifier.valueOf(altModifier) }
.getOrNull() ?: AltKeyModifier.EightBit .getOrNull() ?: AltKeyModifier.EightBit
val keywordHighlightSetId = host.options.extras["keywordHighlightSetId"]
for (i in 0 until terminalOption.highlightSetComboBox.itemCount) {
val item = terminalOption.highlightSetComboBox.getItemAt(i)
if (item.id == keywordHighlightSetId) {
terminalOption.highlightSetComboBox.selectedItem = item
break
}
}
tunnelingOption.tunnelings.addAll(host.tunnelings) tunnelingOption.tunnelings.addAll(host.tunnelings)
tunnelingOption.x11ForwardingCheckBox.isSelected = host.options.enableX11Forwarding tunnelingOption.x11ForwardingCheckBox.isSelected = host.options.enableX11Forwarding
tunnelingOption.x11ServerTextField.text = StringUtils.defaultIfBlank(host.options.x11Forwarding, "localhost:0") tunnelingOption.x11ServerTextField.text = StringUtils.defaultIfBlank(host.options.x11Forwarding, "localhost:0")

View File

@@ -2,6 +2,7 @@ package app.termora.plugin.internal.telnet
import app.termora.* import app.termora.*
import app.termora.account.AccountOwner import app.termora.account.AccountOwner
import app.termora.highlight.KeywordHighlight
import app.termora.plugin.internal.AltKeyModifier import app.termora.plugin.internal.AltKeyModifier
import app.termora.plugin.internal.BasicProxyOption import app.termora.plugin.internal.BasicProxyOption
import app.termora.plugin.internal.BasicTerminalOption import app.termora.plugin.internal.BasicTerminalOption
@@ -16,7 +17,7 @@ import java.awt.event.ComponentEvent
import javax.swing.* import javax.swing.*
class TelnetHostOptionsPane(private val accountOwner: AccountOwner) : OptionsPane() { class TelnetHostOptionsPane(private val accountOwner: AccountOwner) : OptionsPane() {
protected val generalOption = GeneralOption() private val generalOption = GeneralOption()
// telnet 不支持代理密码 // telnet 不支持代理密码
private val proxyOption = BasicProxyOption(authenticationTypes = listOf()) private val proxyOption = BasicProxyOption(authenticationTypes = listOf())
@@ -27,6 +28,7 @@ class TelnetHostOptionsPane(private val accountOwner: AccountOwner) : OptionsPan
showCharacterAtATimeTextField = true showCharacterAtATimeTextField = true
showEnvironmentTextArea = true showEnvironmentTextArea = true
showLoginScripts = true showLoginScripts = true
accountOwner = this@TelnetHostOptionsPane.accountOwner
init() init()
} }
@@ -70,6 +72,8 @@ class TelnetHostOptionsPane(private val accountOwner: AccountOwner) : OptionsPan
"character-at-a-time" to (terminalOption.characterAtATimeTextField.selectedItem?.toString() ?: "false"), "character-at-a-time" to (terminalOption.characterAtATimeTextField.selectedItem?.toString() ?: "false"),
"altModifier" to (terminalOption.altModifierComboBox.selectedItem?.toString() "altModifier" to (terminalOption.altModifierComboBox.selectedItem?.toString()
?: AltKeyModifier.EightBit.name), ?: AltKeyModifier.EightBit.name),
"keywordHighlightSetId" to ((terminalOption.highlightSetComboBox.selectedItem as? KeywordHighlight)?.id
?: "-1"),
) )
) )
@@ -109,6 +113,16 @@ class TelnetHostOptionsPane(private val accountOwner: AccountOwner) : OptionsPan
terminalOption.altModifierComboBox.selectedItem = runCatching { AltKeyModifier.valueOf(altModifier) } terminalOption.altModifierComboBox.selectedItem = runCatching { AltKeyModifier.valueOf(altModifier) }
.getOrNull() ?: AltKeyModifier.EightBit .getOrNull() ?: AltKeyModifier.EightBit
val keywordHighlightSetId = host.options.extras["keywordHighlightSetId"]
for (i in 0 until terminalOption.highlightSetComboBox.itemCount) {
val item = terminalOption.highlightSetComboBox.getItemAt(i)
if (item.id == keywordHighlightSetId) {
terminalOption.highlightSetComboBox.selectedItem = item
break
}
}
terminalOption.loginScripts.clear() terminalOption.loginScripts.clear()
terminalOption.loginScripts.addAll(host.options.loginScripts) terminalOption.loginScripts.addAll(host.options.loginScripts)
} }

View File

@@ -1,6 +1,7 @@
package app.termora.plugin.internal.wsl package app.termora.plugin.internal.wsl
import app.termora.* import app.termora.*
import app.termora.highlight.KeywordHighlight
import app.termora.plugin.internal.AltKeyModifier import app.termora.plugin.internal.AltKeyModifier
import app.termora.plugin.internal.BasicTerminalOption import app.termora.plugin.internal.BasicTerminalOption
import com.formdev.flatlaf.FlatClientProperties import com.formdev.flatlaf.FlatClientProperties
@@ -47,6 +48,8 @@ internal open class WSLHostOptionsPane : OptionsPane() {
"wsl-guid" to wsl.guid, "wsl-flavor" to wsl.flavor, "wsl-guid" to wsl.guid, "wsl-flavor" to wsl.flavor,
"altModifier" to (terminalOption.altModifierComboBox.selectedItem?.toString() "altModifier" to (terminalOption.altModifierComboBox.selectedItem?.toString()
?: AltKeyModifier.EightBit.name), ?: AltKeyModifier.EightBit.name),
"keywordHighlightSetId" to ((terminalOption.highlightSetComboBox.selectedItem as? KeywordHighlight)?.id
?: "-1"),
) )
) )
@@ -76,6 +79,18 @@ internal open class WSLHostOptionsPane : OptionsPane() {
} }
} }
val altModifier = host.options.extras["altModifier"] ?: AltKeyModifier.EightBit.name
terminalOption.altModifierComboBox.selectedItem = runCatching { AltKeyModifier.valueOf(altModifier) }
.getOrNull() ?: AltKeyModifier.EightBit
val keywordHighlightSetId = host.options.extras["keywordHighlightSetId"]
for (i in 0 until terminalOption.highlightSetComboBox.itemCount) {
val item = terminalOption.highlightSetComboBox.getItemAt(i)
if (item.id == keywordHighlightSetId) {
terminalOption.highlightSetComboBox.selectedItem = item
break
}
}
} }
fun validateFields(): Boolean { fun validateFields(): Boolean {

View File

@@ -266,6 +266,7 @@ termora.terminal-logger.open-in-folder=Open in {0}
# Highlight # Highlight
termora.highlight=Highlight Sets termora.highlight=Highlight Sets
termora.highlight.default-set=Default Set
termora.highlight.text-color=Text Color termora.highlight.text-color=Text Color
termora.highlight.background-color=Background Color termora.highlight.background-color=Background Color
termora.highlight.keyword=Keyword termora.highlight.keyword=Keyword

View File

@@ -230,6 +230,7 @@ termora.terminal-logger.open-in-folder=Открыть в {0}
# Highlight # Highlight
termora.highlight=Персонализация termora.highlight=Персонализация
termora.highlight.default-set=Набор по умолчанию
termora.highlight.text-color=Цвет Текста termora.highlight.text-color=Цвет Текста
termora.highlight.background-color=Фоновый Цвет termora.highlight.background-color=Фоновый Цвет
termora.highlight.keyword=Слово termora.highlight.keyword=Слово

View File

@@ -263,6 +263,7 @@ termora.terminal-logger.open-in-folder=在 {0} 中打开
# Highlight # Highlight
termora.highlight=关键词高亮 termora.highlight=关键词高亮
termora.highlight.default-set=默认集
termora.highlight.text-color=文本颜色 termora.highlight.text-color=文本颜色
termora.highlight.background-color=背景颜色 termora.highlight.background-color=背景颜色
termora.highlight.keyword=关键词 termora.highlight.keyword=关键词

View File

@@ -259,6 +259,7 @@ termora.terminal-logger.open-in-folder=在 {0} 中打開
# Highlight # Highlight
termora.highlight=關鍵字高亮 termora.highlight=關鍵字高亮
termora.highlight.default-set=預設集
termora.highlight.text-color=文字顏色 termora.highlight.text-color=文字顏色
termora.highlight.background-color=背景顏色 termora.highlight.background-color=背景顏色
termora.highlight.keyword=關鍵字 termora.highlight.keyword=關鍵字