mirror of
https://gitlab.com/2009scape/rt4-client.git
synced 2025-12-17 03:50:24 -07:00
More helpers/DRY
This commit is contained in:
parent
573e579643
commit
47e545cbc7
17 changed files with 264 additions and 289 deletions
|
|
@ -3,6 +3,8 @@ package KondoKit.components
|
|||
import KondoKit.Helpers
|
||||
import KondoKit.Helpers.FieldNotifier
|
||||
import KondoKit.ViewConstants
|
||||
import KondoKit.components.UiStyler
|
||||
import KondoKit.setFixedSize
|
||||
import KondoKit.plugin.Companion.WIDGET_COLOR
|
||||
import KondoKit.plugin.Companion.primaryColor
|
||||
import KondoKit.plugin.Companion.secondaryColor
|
||||
|
|
@ -10,6 +12,7 @@ import plugin.Plugin
|
|||
import java.awt.*
|
||||
import java.awt.event.MouseAdapter
|
||||
import java.awt.event.MouseEvent
|
||||
import java.lang.reflect.Field
|
||||
import java.util.*
|
||||
import java.util.Timer
|
||||
import javax.swing.*
|
||||
|
|
@ -36,18 +39,7 @@ class SettingsPanel(private val plugin: Plugin) : JPanel() {
|
|||
field.isAccessible = true
|
||||
|
||||
// Get the "Exposed" annotation specifically and retrieve its description, if available
|
||||
val exposedAnnotation = field.annotations.firstOrNull { annotation ->
|
||||
annotation.annotationClass.simpleName == "Exposed"
|
||||
}
|
||||
|
||||
val description = exposedAnnotation?.let { annotation ->
|
||||
try {
|
||||
val descriptionField = annotation.annotationClass.java.getMethod("description")
|
||||
descriptionField.invoke(annotation) as String
|
||||
} catch (e: NoSuchMethodException) {
|
||||
"" // No description method, return empty string
|
||||
}
|
||||
} ?: ""
|
||||
val description = field.exposedDescription()
|
||||
|
||||
val fieldPanel = JPanel().apply {
|
||||
layout = GridBagLayout()
|
||||
|
|
@ -104,7 +96,7 @@ class SettingsPanel(private val plugin: Plugin) : JPanel() {
|
|||
}
|
||||
|
||||
// Check if the field is a HashMap
|
||||
field.type == HashMap::class.java || field.type.simpleName == "HashMap" -> {
|
||||
field.isHashMapType() -> {
|
||||
inputComponent = createHashMapEditor(field, plugin, fieldNotifier)
|
||||
isHashMapEditor = true
|
||||
}
|
||||
|
|
@ -141,42 +133,45 @@ class SettingsPanel(private val plugin: Plugin) : JPanel() {
|
|||
fieldPanel.add(inputComponent, gbc)
|
||||
|
||||
// Add apply button for non-HashMap editors
|
||||
val applyButton = JButton("\u2714").apply {
|
||||
maximumSize = Dimension(Int.MAX_VALUE, 8)
|
||||
val applyButton = UiStyler.button(
|
||||
text = "\u2714",
|
||||
onClick = {
|
||||
try {
|
||||
val newValue = when (inputComponent) {
|
||||
is JCheckBox -> inputComponent.isSelected
|
||||
is JComboBox<*> -> inputComponent.selectedItem
|
||||
is JSpinner -> inputComponent.value
|
||||
is JTextField -> Helpers.convertValue(field.type, field.genericType, inputComponent.text)
|
||||
else -> throw IllegalArgumentException("Unsupported input component type")
|
||||
}
|
||||
fieldNotifier.setFieldValue(field, newValue)
|
||||
Helpers.showToast(
|
||||
this@SettingsPanel,
|
||||
"${field.name} updated successfully!"
|
||||
)
|
||||
} catch (e: Exception) {
|
||||
Helpers.showToast(
|
||||
this@SettingsPanel,
|
||||
"Failed to update ${field.name}: ${e.message}",
|
||||
JOptionPane.ERROR_MESSAGE
|
||||
)
|
||||
}
|
||||
}
|
||||
).also {
|
||||
it.maximumSize = Dimension(Int.MAX_VALUE, 8)
|
||||
}
|
||||
|
||||
gbc.gridx = 2
|
||||
gbc.gridy = 0
|
||||
gbc.weightx = 0.0
|
||||
gbc.fill = GridBagConstraints.NONE
|
||||
applyButton.addActionListener {
|
||||
try {
|
||||
val newValue = when (inputComponent) {
|
||||
is JCheckBox -> inputComponent.isSelected
|
||||
is JComboBox<*> -> inputComponent.selectedItem
|
||||
is JSpinner -> inputComponent.value
|
||||
is JTextField -> Helpers.convertValue(field.type, field.genericType, inputComponent.text)
|
||||
else -> throw IllegalArgumentException("Unsupported input component type")
|
||||
}
|
||||
fieldNotifier.setFieldValue(field, newValue)
|
||||
Helpers.showToast(
|
||||
this@SettingsPanel,
|
||||
"${field.name} updated successfully!"
|
||||
)
|
||||
} catch (e: Exception) {
|
||||
Helpers.showToast(
|
||||
this@SettingsPanel,
|
||||
"Failed to update ${field.name}: ${e.message}",
|
||||
JOptionPane.ERROR_MESSAGE
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
fieldPanel.add(applyButton, gbc)
|
||||
add(fieldPanel)
|
||||
}
|
||||
|
||||
// Track field changes in real-time and update UI (skip HashMap fields)
|
||||
if (field.type != HashMap::class.java && field.type.simpleName != "HashMap") {
|
||||
if (!field.isHashMapType()) {
|
||||
var previousValue = field.get(plugin)?.toString()
|
||||
val timer = Timer()
|
||||
timer.schedule(object : TimerTask() {
|
||||
|
|
@ -205,7 +200,7 @@ class SettingsPanel(private val plugin: Plugin) : JPanel() {
|
|||
}
|
||||
}
|
||||
|
||||
private fun createHashMapEditor(field: java.lang.reflect.Field, plugin: Plugin, fieldNotifier: FieldNotifier): JComponent {
|
||||
private fun createHashMapEditor(field: Field, plugin: Plugin, fieldNotifier: FieldNotifier): JComponent {
|
||||
// Create a panel to hold the table and buttons
|
||||
val editorPanel = JPanel()
|
||||
editorPanel.layout = BoxLayout(editorPanel, BoxLayout.Y_AXIS)
|
||||
|
|
@ -213,19 +208,7 @@ class SettingsPanel(private val plugin: Plugin) : JPanel() {
|
|||
editorPanel.border = BorderFactory.createEmptyBorder(5, 0, 5, 0)
|
||||
editorPanel.maximumSize = Dimension(Int.MAX_VALUE, 250)
|
||||
|
||||
// Get the "Exposed" annotation specifically and retrieve its description, if available
|
||||
val exposedAnnotation = field.annotations.firstOrNull { annotation ->
|
||||
annotation.annotationClass.simpleName == "Exposed"
|
||||
}
|
||||
|
||||
val description = exposedAnnotation?.let { annotation ->
|
||||
try {
|
||||
val descriptionField = annotation.annotationClass.java.getMethod("description")
|
||||
descriptionField.invoke(annotation) as String
|
||||
} catch (e: NoSuchMethodException) {
|
||||
"" // No description method, return empty string
|
||||
}
|
||||
} ?: ""
|
||||
val description = field.exposedDescription()
|
||||
|
||||
// Create title label
|
||||
val titleLabel = JLabel("${field.name} (Key-Value Pairs)").apply {
|
||||
|
|
@ -288,9 +271,7 @@ class SettingsPanel(private val plugin: Plugin) : JPanel() {
|
|||
|
||||
// Create a scroll pane for the table with fixed size
|
||||
val scrollPane = JScrollPane(table).apply {
|
||||
preferredSize = Dimension(Int.MAX_VALUE, 150)
|
||||
maximumSize = preferredSize
|
||||
minimumSize = preferredSize
|
||||
setFixedSize(Dimension(Int.MAX_VALUE, 150))
|
||||
background = WIDGET_COLOR
|
||||
verticalScrollBarPolicy = JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED
|
||||
horizontalScrollBarPolicy = JScrollPane.HORIZONTAL_SCROLLBAR_NEVER
|
||||
|
|
@ -304,9 +285,9 @@ class SettingsPanel(private val plugin: Plugin) : JPanel() {
|
|||
}
|
||||
|
||||
// Add button
|
||||
val addButton = JButton("+").apply {
|
||||
maximumSize = Dimension(40, 30)
|
||||
addActionListener {
|
||||
val addButton = UiStyler.button(
|
||||
text = "+",
|
||||
onClick = {
|
||||
val vector = java.util.Vector<Any>()
|
||||
vector.add("")
|
||||
vector.add("")
|
||||
|
|
@ -317,12 +298,14 @@ class SettingsPanel(private val plugin: Plugin) : JPanel() {
|
|||
table.editCellAt(newRow, 0)
|
||||
table.editorComponent?.requestFocus()
|
||||
}
|
||||
).apply {
|
||||
setFixedSize(40, 30)
|
||||
}
|
||||
|
||||
|
||||
// Remove button
|
||||
val removeButton = JButton("-").apply {
|
||||
maximumSize = Dimension(40, 30)
|
||||
addActionListener {
|
||||
val removeButton = UiStyler.button(
|
||||
text = "-",
|
||||
onClick = {
|
||||
val selectedRow = table.selectedRow
|
||||
if (selectedRow >= 0) {
|
||||
tableModel.removeRow(selectedRow)
|
||||
|
|
@ -334,51 +317,53 @@ class SettingsPanel(private val plugin: Plugin) : JPanel() {
|
|||
)
|
||||
}
|
||||
}
|
||||
).apply {
|
||||
setFixedSize(40, 30)
|
||||
}
|
||||
|
||||
|
||||
// Apply button
|
||||
val applyButton = JButton("Apply Changes").apply {
|
||||
maximumSize = Dimension(120, 30)
|
||||
addActionListener {
|
||||
val applyButton = UiStyler.button(
|
||||
text = "Apply Changes",
|
||||
onClick = {
|
||||
try {
|
||||
// Commit any active cell editing before reading values
|
||||
if (table.isEditing) {
|
||||
table.cellEditor.stopCellEditing()
|
||||
}
|
||||
|
||||
|
||||
// Get the current HashMap from the field and modify it in place
|
||||
val currentHashMap = field.get(plugin) as? HashMap<Any, Any> ?: HashMap<Any, Any>()
|
||||
|
||||
|
||||
// Clear the current HashMap
|
||||
currentHashMap.clear()
|
||||
|
||||
|
||||
// Add the new entries from the table to the existing HashMap
|
||||
for (i in 0 until tableModel.rowCount) {
|
||||
val key = tableModel.getValueAt(i, 0).toString()
|
||||
val value = tableModel.getValueAt(i, 1).toString()
|
||||
// Only add non-empty keys
|
||||
if (key.isNotBlank()) {
|
||||
// Skip empty values
|
||||
if (value.isBlank()) {
|
||||
Helpers.showToast(
|
||||
this@SettingsPanel,
|
||||
"Skipping entry with empty value for key '$key'",
|
||||
JOptionPane.WARNING_MESSAGE
|
||||
)
|
||||
continue
|
||||
}
|
||||
|
||||
// Try to convert the value to the appropriate type based on the field's generic type
|
||||
val convertedValue = try {
|
||||
// For HashMap<String, Int> - treat all HashMap<String, Int> fields the same way regardless of plugin
|
||||
val fieldTypeName = field.genericType.toString()
|
||||
if (fieldTypeName.contains("java.util.HashMap<java.lang.String, java.lang.Integer>") ||
|
||||
fieldTypeName.contains("HashMap<String, Int>") ||
|
||||
fieldTypeName.contains("HashMap<String, Integer>")) {
|
||||
|
||||
if (key.isBlank()) {
|
||||
continue
|
||||
}
|
||||
|
||||
if (value.isBlank()) {
|
||||
Helpers.showToast(
|
||||
this@SettingsPanel,
|
||||
"Skipping entry with empty value for key '$key'",
|
||||
JOptionPane.WARNING_MESSAGE
|
||||
)
|
||||
continue
|
||||
}
|
||||
|
||||
val convertedValue = try {
|
||||
val fieldTypeName = field.genericType.toString()
|
||||
when {
|
||||
fieldTypeName.contains("java.util.HashMap<java.lang.String, java.lang.Integer>") ||
|
||||
fieldTypeName.contains("HashMap<String, Int>") ||
|
||||
fieldTypeName.contains("HashMap<String, Integer>") -> {
|
||||
try {
|
||||
val intValue = value.toInt()
|
||||
intValue
|
||||
} catch (e: NumberFormatException) {
|
||||
value.toInt()
|
||||
} catch (numberFormat: NumberFormatException) {
|
||||
Helpers.showToast(
|
||||
this@SettingsPanel,
|
||||
"Invalid number format for key '$key': '$value'. Using 0 as default.",
|
||||
|
|
@ -386,38 +371,20 @@ class SettingsPanel(private val plugin: Plugin) : JPanel() {
|
|||
)
|
||||
0
|
||||
}
|
||||
}
|
||||
// For other numeric types
|
||||
else if (fieldTypeName.contains("java.lang.Integer") ||
|
||||
fieldTypeName.contains("int")) {
|
||||
value.toInt()
|
||||
}
|
||||
else if (fieldTypeName.contains("java.lang.Double") ||
|
||||
fieldTypeName.contains("double")) {
|
||||
value.toDouble()
|
||||
}
|
||||
else if (fieldTypeName.contains("java.lang.Float") ||
|
||||
fieldTypeName.contains("float")) {
|
||||
value.toFloat()
|
||||
}
|
||||
else if (fieldTypeName.contains("java.lang.Boolean") ||
|
||||
fieldTypeName.contains("boolean")) {
|
||||
value.toBoolean()
|
||||
}
|
||||
// Default to string for other types
|
||||
else {
|
||||
value
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
// If conversion fails, keep as string
|
||||
value
|
||||
fieldTypeName.contains("java.lang.Integer") || fieldTypeName.contains("int") -> value.toInt()
|
||||
fieldTypeName.contains("java.lang.Double") || fieldTypeName.contains("double") -> value.toDouble()
|
||||
fieldTypeName.contains("java.lang.Float") || fieldTypeName.contains("float") -> value.toFloat()
|
||||
fieldTypeName.contains("java.lang.Boolean") || fieldTypeName.contains("boolean") -> value.toBoolean()
|
||||
else -> value
|
||||
}
|
||||
currentHashMap[key] = convertedValue
|
||||
} catch (e: Exception) {
|
||||
value
|
||||
}
|
||||
|
||||
currentHashMap[key] = convertedValue
|
||||
}
|
||||
|
||||
// Update the field to trigger notifications (even though the reference is the same)
|
||||
// This ensures OnKondoValueUpdated() gets called if it exists
|
||||
|
||||
fieldNotifier.setFieldValue(field, currentHashMap)
|
||||
Helpers.showToast(
|
||||
this@SettingsPanel,
|
||||
|
|
@ -431,6 +398,8 @@ class SettingsPanel(private val plugin: Plugin) : JPanel() {
|
|||
)
|
||||
}
|
||||
}
|
||||
).apply {
|
||||
setFixedSize(120, 30)
|
||||
}
|
||||
|
||||
buttonsPanel.add(addButton)
|
||||
|
|
@ -447,7 +416,24 @@ class SettingsPanel(private val plugin: Plugin) : JPanel() {
|
|||
|
||||
return editorPanel
|
||||
}
|
||||
|
||||
|
||||
private fun Field.exposedDescription(): String {
|
||||
val exposedAnnotation = annotations.firstOrNull {
|
||||
it.annotationClass.simpleName == "Exposed"
|
||||
} ?: return ""
|
||||
|
||||
return try {
|
||||
val descriptionMethod = exposedAnnotation.annotationClass.java.getMethod("description")
|
||||
descriptionMethod.invoke(exposedAnnotation) as? String ?: ""
|
||||
} catch (_: Exception) {
|
||||
""
|
||||
}
|
||||
}
|
||||
|
||||
private fun Field.isHashMapType(): Boolean {
|
||||
return type == HashMap::class.java || type.simpleName == "HashMap"
|
||||
}
|
||||
|
||||
companion object {
|
||||
var customToolTipWindow: JWindow? = null
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue