Fix tooltip labels

This commit is contained in:
downthecrop 2025-11-17 11:28:23 -08:00
parent 5bb81c7bd3
commit 5240963743
7 changed files with 135 additions and 156 deletions

View file

@ -4,44 +4,31 @@ import KondoKit.pluginmanager.GitLabPlugin
import KondoKit.pluginmanager.PluginProperties import KondoKit.pluginmanager.PluginProperties
import KondoKit.util.HttpFetcher import KondoKit.util.HttpFetcher
import KondoKit.pluginmanager.GitLabConfig import KondoKit.pluginmanager.GitLabConfig
import KondoKit.util.HttpStatusException
import KondoKit.util.JsonParser import KondoKit.util.JsonParser
import com.google.gson.JsonObject import com.google.gson.JsonObject
import java.io.BufferedReader
import java.io.InputStreamReader
import java.net.HttpURLConnection
import java.util.concurrent.* import java.util.concurrent.*
import javax.swing.SwingUtilities import javax.swing.SwingUtilities
object GitLabPluginFetcher { object GitLabPluginFetcher {
private const val TAG = "GitLabPluginFetcher"
// Thread pool for concurrent plugin property fetching // Thread pool for concurrent plugin property fetching
private val executorService = Executors.newFixedThreadPool(5) private val executorService = Executors.newFixedThreadPool(5)
// Debug logging function // Debug logging function
private fun debugLog(message: String) { private fun debugLog(message: String) = PluginLogger.debug(TAG, message)
if (GitLabConfig.DEBUG) {
println("[GitLabPluginFetcher] $message")
}
}
// Function to fetch plugins from GitLab // Function to fetch plugins from GitLab
fun fetchGitLabPlugins(onComplete: (List<GitLabPlugin>) -> Unit) { fun fetchGitLabPlugins(onComplete: (List<GitLabPlugin>) -> Unit) {
Thread { Thread {
val plugins = mutableListOf<GitLabPlugin>()
try { try {
debugLog("Starting to fetch GitLab plugins...") debugLog("Starting to fetch GitLab plugins...")
val plugins = mutableListOf<GitLabPlugin>()
val apiUrl = GitLabConfig.getRepositoryTreeUrl() val apiUrl = GitLabConfig.getRepositoryTreeUrl()
debugLog("API URL: $apiUrl") debugLog("API URL: $apiUrl")
val connection = HttpFetcher.openGetConnection(apiUrl) val response = HttpFetcher.fetchString(apiUrl)
// Read response
val responseCode = connection.responseCode
debugLog("Response code: $responseCode")
if (responseCode == HttpURLConnection.HTTP_OK) {
val reader = BufferedReader(InputStreamReader(connection.inputStream))
val response = reader.use { it.readText() }
debugLog("Response length: ${response.length} characters") debugLog("Response length: ${response.length} characters")
debugLog("Response preview: ${response.take(200)}...") debugLog("Response preview: ${response.take(200)}...")
@ -85,11 +72,11 @@ object GitLabPluginFetcher {
debugLog("Error getting plugin result: ${e.message}") debugLog("Error getting plugin result: ${e.message}")
} }
} }
} else { } catch (e: HttpStatusException) {
debugLog("HTTP error: $responseCode") debugLog("HTTP error ${e.statusCode} fetching plugin tree: ${e.body.take(200)}")
val errorReader = BufferedReader(InputStreamReader(connection.errorStream)) } catch (e: Exception) {
val errorResponse = errorReader.use { it.readText() } debugLog("Exception occurred: ${e.message}")
debugLog("Error response: $errorResponse") e.printStackTrace()
} }
debugLog("Completed fetching plugins. Total plugins: ${plugins.size}") debugLog("Completed fetching plugins. Total plugins: ${plugins.size}")
@ -97,13 +84,6 @@ object GitLabPluginFetcher {
SwingUtilities.invokeLater { SwingUtilities.invokeLater {
onComplete(plugins) onComplete(plugins)
} }
} catch (e: Exception) {
debugLog("Exception occurred: ${e.message}")
e.printStackTrace()
SwingUtilities.invokeLater {
onComplete(emptyList())
}
}
}.start() }.start()
} }
@ -113,25 +93,16 @@ object GitLabPluginFetcher {
val pluginUrl = GitLabConfig.getRawFileUrl(pluginFilePath) val pluginUrl = GitLabConfig.getRawFileUrl(pluginFilePath)
debugLog("Fetching plugin.properties from: $pluginUrl") debugLog("Fetching plugin.properties from: $pluginUrl")
val connection = HttpFetcher.openGetConnection(pluginUrl) try {
val rawContent = HttpFetcher.fetchString(pluginUrl)
// Read response
val responseCode = connection.responseCode
debugLog("plugin.properties response code: $responseCode")
if (responseCode == HttpURLConnection.HTTP_OK) {
val reader = BufferedReader(InputStreamReader(connection.inputStream))
val rawContent = reader.use { it.readText() }
debugLog("plugin.properties content length: ${rawContent.length} characters") debugLog("plugin.properties content length: ${rawContent.length} characters")
debugLog("plugin.properties content preview: ${rawContent.take(200)}...") debugLog("plugin.properties content preview: ${rawContent.take(200)}...")
return parseProperties(rawContent) return parseProperties(rawContent)
} else { } catch (e: HttpStatusException) {
debugLog("Failed to fetch plugin.properties. Response code: $responseCode") debugLog("Failed to fetch plugin.properties. Response code: ${e.statusCode}")
val errorReader = BufferedReader(InputStreamReader(connection.errorStream)) debugLog("Error response for plugin.properties: ${e.body.take(200)}")
val errorResponse = errorReader.use { it.readText() } throw Exception("Plugin file not found for folder: $folderPath", e)
debugLog("Error response for plugin.properties: $errorResponse")
throw Exception("Plugin file not found for folder: $folderPath")
} }
} }

View file

@ -18,6 +18,7 @@ import javax.swing.SwingUtilities
* Manages downloading and installing plugins from GitLab with concurrent support * Manages downloading and installing plugins from GitLab with concurrent support
*/ */
object PluginDownloadManager { object PluginDownloadManager {
private const val TAG = "PluginDownloadManager"
private const val MAX_CONCURRENT_DOWNLOADS = 3 private const val MAX_CONCURRENT_DOWNLOADS = 3
// Thread pool for concurrent downloads // Thread pool for concurrent downloads
@ -30,11 +31,7 @@ object PluginDownloadManager {
} }
// Debug logging function // Debug logging function
private fun debugLog(message: String) { private fun debugLog(message: String) = PluginLogger.debug(TAG, message)
if (GitLabConfig.DEBUG) {
println("[PluginDownloadManager] $message")
}
}
// Get download URL for debugging/logging purposes // Get download URL for debugging/logging purposes
fun getDownloadUrlForLogging(plugin: GitLabPlugin): String { fun getDownloadUrlForLogging(plugin: GitLabPlugin): String {

View file

@ -0,0 +1,13 @@
package KondoKit.pluginmanager
/**
* Shared lightweight logger so pluginmanager classes don't each redefine
* their own debug helper tied to GitLabConfig.DEBUG.
*/
object PluginLogger {
fun debug(tag: String, message: String) {
if (GitLabConfig.DEBUG) {
println("[$tag] $message")
}
}
}

View file

@ -435,50 +435,50 @@ class SettingsPanel(private val plugin: Plugin) : JPanel() {
companion object { companion object {
var customToolTipWindow: JWindow? = null var customToolTipWindow: JWindow? = null
private var customToolTipLabel: JLabel? = null
fun showCustomToolTip(text: String, component: JComponent) { fun showCustomToolTip(text: String, component: JComponent) {
val tooltipFont = ViewConstants.FONT_RUNESCAPE_SMALL_PLAIN_16 val tooltipFont = ViewConstants.FONT_RUNESCAPE_SMALL_PLAIN_16
val maxWidth = 150 val maxWidth = 150
// Create a dummy JLabel to get FontMetrics for the font used in the tooltip
val dummyLabel = JLabel()
dummyLabel.font = tooltipFont
val fontMetrics = dummyLabel.getFontMetrics(tooltipFont)
val lineHeight = fontMetrics.height
// Calculate the approximate width of the text
val textWidth = fontMetrics.stringWidth(text)
// Calculate the number of lines required based on the text width and max tooltip width
val numberOfLines = Math.ceil(textWidth.toDouble() / maxWidth).toInt()
// Calculate the required height of the tooltip
val requiredHeight = numberOfLines * lineHeight + 6 // Adding some padding
if (customToolTipWindow == null) {
customToolTipWindow = JWindow().apply {
val bgColor = Helpers.colorToHex(KondoKit.plugin.Companion.TOOLTIP_BACKGROUND) val bgColor = Helpers.colorToHex(KondoKit.plugin.Companion.TOOLTIP_BACKGROUND)
val textColor = Helpers.colorToHex(KondoKit.plugin.Companion.secondaryColor) val textColor = Helpers.colorToHex(KondoKit.plugin.Companion.secondaryColor)
contentPane = JLabel("<html><div style='color: $textColor; background-color: $bgColor; padding: 3px; word-break: break-all;'>$text</div></html>").apply { // Constrain width via HTML so Swing's renderer wraps the text naturally.
val safeText = text
.replace("&", "&amp;")
.replace("<", "&lt;")
.replace(">", "&gt;")
val html = """
<html>
<body style="margin:0; padding:6px; width:${maxWidth}px; color:$textColor; background-color:$bgColor; word-wrap:break-word;">
$safeText
</body>
</html>
""".trimIndent()
val (window, label) = if (customToolTipWindow == null || customToolTipLabel == null) {
val lbl = JLabel().apply {
border = BorderFactory.createLineBorder(Color.BLACK) border = BorderFactory.createLineBorder(Color.BLACK)
isOpaque = true isOpaque = true
background = KondoKit.plugin.Companion.TOOLTIP_BACKGROUND background = KondoKit.plugin.Companion.TOOLTIP_BACKGROUND
foreground = Color.WHITE foreground = Color.WHITE
font = tooltipFont font = tooltipFont
maximumSize = Dimension(maxWidth, Int.MAX_VALUE) horizontalAlignment = SwingConstants.LEFT
preferredSize = Dimension(maxWidth, requiredHeight) verticalAlignment = SwingConstants.TOP
}
pack()
} }
val win = JWindow().apply { contentPane.add(lbl) }
customToolTipWindow = win
customToolTipLabel = lbl
win to lbl
} else { } else {
// Update the tooltip text customToolTipWindow!! to customToolTipLabel!!
val label = customToolTipWindow!!.contentPane as JLabel
val bgColor = Helpers.colorToHex(KondoKit.plugin.Companion.TOOLTIP_BACKGROUND)
val textColor = Helpers.colorToHex(KondoKit.plugin.Companion.secondaryColor)
label.text = "<html><div style='color: $textColor; background-color: $bgColor; padding: 3px; word-break: break-all;'>$text</div></html>"
label.preferredSize = Dimension(maxWidth, requiredHeight)
customToolTipWindow!!.pack()
} }
label.text = html
label.font = tooltipFont
label.preferredSize = null // let HTML + pack decide size from width constraint
window.pack()
// Position the tooltip near the component // Position the tooltip near the component
val locationOnScreen = component.locationOnScreen val locationOnScreen = component.locationOnScreen
customToolTipWindow!!.setLocation(locationOnScreen.x, locationOnScreen.y + 15) customToolTipWindow!!.setLocation(locationOnScreen.x, locationOnScreen.y + 15)

View file

@ -18,15 +18,23 @@ object GEPriceService {
val grand_exchange_price: String? val grand_exchange_price: String?
) )
private fun <T> mapToPriceMap(
items: Array<T>,
idSelector: (T) -> String?,
priceSelector: (T) -> String?
): Map<String, String> {
return items.mapNotNull { item ->
val id = idSelector(item)
val price = priceSelector(item)
if (id != null && price != null) id to price else null
}.toMap()
}
fun loadRemotePrices(): Map<String, String> { fun loadRemotePrices(): Map<String, String> {
return try { return try {
val payload = HttpFetcher.fetchString(REMOTE_GE_URL) val payload = HttpFetcher.fetchString(REMOTE_GE_URL)
val items = JsonParser.fromJson<Array<RemoteGEItem>>(payload) val items = JsonParser.fromJson<Array<RemoteGEItem>>(payload)
items.mapNotNull { item -> mapToPriceMap(items, { it.item_id }, { it.value })
val id = item.item_id
val value = item.value
if (id != null && value != null) id to value else null
}.toMap()
} catch (e: Exception) { } catch (e: Exception) {
emptyMap() emptyMap()
} }
@ -36,11 +44,7 @@ object GEPriceService {
return try { return try {
val json = jsonProvider() ?: return emptyMap() val json = jsonProvider() ?: return emptyMap()
val items = JsonParser.fromJson<Array<LocalGEItem>>(json) val items = JsonParser.fromJson<Array<LocalGEItem>>(json)
items.mapNotNull { item -> mapToPriceMap(items, { it.id }, { it.grand_exchange_price })
val id = item.id
val price = item.grand_exchange_price
if (id != null && price != null) id to price else null
}.toMap()
} catch (e: Exception) { } catch (e: Exception) {
emptyMap() emptyMap()
} }

View file

@ -15,6 +15,7 @@ import KondoKit.util.setFixedSize
import KondoKit.views.XPTrackerView.wrappedWidget import KondoKit.views.XPTrackerView.wrappedWidget
import KondoKit.ui.components.PopupMenuComponent import KondoKit.ui.components.PopupMenuComponent
import KondoKit.ui.components.ProgressBar import KondoKit.ui.components.ProgressBar
import KondoKit.ui.components.LabelComponent
import KondoKit.ui.components.WidgetPanel import KondoKit.ui.components.WidgetPanel
import KondoKit.plugin.Companion.TITLE_BAR_COLOR import KondoKit.plugin.Companion.TITLE_BAR_COLOR
import KondoKit.plugin.Companion.TOOLTIP_BACKGROUND import KondoKit.plugin.Companion.TOOLTIP_BACKGROUND
@ -171,12 +172,8 @@ object LootTrackerView : View, OnPostClientTickCallback, OnKillingBlowNPCCallbac
} }
} }
private fun createLabel(text: String): JLabel { private fun createLabel(text: String): LabelComponent =
return JLabel(text).apply { LabelComponent(text, alignment = JLabel.LEFT)
font = ViewConstants.FONT_RUNESCAPE_SMALL_16
horizontalAlignment = JLabel.LEFT
}
}
private fun addItemToLootPanel(lootTrackerView: JPanel, drop: Item, npcName: String) { private fun addItemToLootPanel(lootTrackerView: JPanel, drop: Item, npcName: String) {
findLootItemsPanel(lootTrackerView, npcName)?.let { lootPanel -> findLootItemsPanel(lootTrackerView, npcName)?.let { lootPanel ->

View file

@ -16,6 +16,7 @@ import KondoKit.util.attachPopupMenu
import KondoKit.util.XPTable import KondoKit.util.XPTable
import KondoKit.ui.components.PopupMenuComponent import KondoKit.ui.components.PopupMenuComponent
import KondoKit.ui.components.ProgressBar import KondoKit.ui.components.ProgressBar
import KondoKit.ui.components.LabelComponent
import KondoKit.ui.components.WidgetPanel import KondoKit.ui.components.WidgetPanel
import KondoKit.ui.components.XPWidget import KondoKit.ui.components.XPWidget
import KondoKit.plugin.Companion.IMAGE_SIZE import KondoKit.plugin.Companion.IMAGE_SIZE
@ -91,15 +92,11 @@ object XPTrackerView : View, OnUpdateCallback, OnXPUpdateCallback {
} }
} }
private fun createMetricLabel(title: String, initialValue: String = "0", topPadding: Int = 0): JLabel { private fun createMetricLabel(title: String, initialValue: String = "0", topPadding: Int = 0): LabelComponent =
return JLabel(formatHtmlLabelText("$title ", primaryColor, initialValue, secondaryColor)).apply { LabelComponent(alignment = JLabel.LEFT).apply {
horizontalAlignment = JLabel.LEFT updateHtmlText("$title ", primaryColor, initialValue, secondaryColor)
font = widgetFont
if (topPadding > 0) { if (topPadding > 0) {
border = BorderFactory.createEmptyBorder(topPadding, 0, 0, 0) border = BorderFactory.createEmptyBorder(topPadding, 0, 0, 0)
} else {
border = BorderFactory.createEmptyBorder(0, 0, 0, 0)
}
} }
} }