mirror of
https://gitlab.com/2009scape/rt4-client.git
synced 2025-12-20 05:20:24 -07:00
More cleanup
This commit is contained in:
parent
47e545cbc7
commit
440b8d4de1
4 changed files with 571 additions and 482 deletions
|
|
@ -0,0 +1,473 @@
|
||||||
|
package KondoKit
|
||||||
|
|
||||||
|
import KondoKit.pluginmanager.*
|
||||||
|
import KondoKit.views.ReflectiveEditorView
|
||||||
|
import plugin.Plugin
|
||||||
|
import plugin.PluginInfo
|
||||||
|
import plugin.PluginRepository
|
||||||
|
import rt4.GlobalJsonConfig
|
||||||
|
import java.awt.Component
|
||||||
|
import java.io.File
|
||||||
|
import java.util.*
|
||||||
|
import javax.swing.*
|
||||||
|
|
||||||
|
class ReflectiveEditorPlugin : Plugin() {
|
||||||
|
|
||||||
|
// Fields that were previously in ReflectiveEditorView
|
||||||
|
private var gitLabPlugins: List<GitLabPlugin> = listOf()
|
||||||
|
private var pluginStatuses: List<PluginInfoWithStatus> = listOf()
|
||||||
|
private var reloadPlugins = false // Flag for scheduled plugin reload to avoid crashes
|
||||||
|
private val pluginsDirectory: File = File(GlobalJsonConfig.instance.pluginsFolder)
|
||||||
|
|
||||||
|
override fun Init() {
|
||||||
|
// Initialize the plugin, fetch remote plugins
|
||||||
|
GitLabPluginFetcher.fetchGitLabPlugins { plugins ->
|
||||||
|
gitLabPlugins = plugins
|
||||||
|
// Update plugin statuses with comparison between installed and remote plugins
|
||||||
|
updatePluginStatuses()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Plugin management functionality that was in ReflectiveEditorView
|
||||||
|
fun getGitLabPlugins(): List<GitLabPlugin> = gitLabPlugins
|
||||||
|
|
||||||
|
fun getPluginStatuses(): List<PluginInfoWithStatus> = pluginStatuses
|
||||||
|
|
||||||
|
fun updatePluginStatuses() {
|
||||||
|
val loadedPluginNames = getLoadedPluginNames()
|
||||||
|
val statuses = mutableListOf<PluginInfoWithStatus>()
|
||||||
|
|
||||||
|
// Get disabled plugin names and their versions
|
||||||
|
val disabledPluginInfo = getDisabledPluginInfo()
|
||||||
|
|
||||||
|
// Handle duplicate plugins (loaded and disabled) - delete the disabled version
|
||||||
|
handleDuplicatePlugins(loadedPluginNames, disabledPluginInfo)
|
||||||
|
|
||||||
|
// Process remote plugins
|
||||||
|
for (gitLabPlugin in gitLabPlugins) {
|
||||||
|
val pluginName = gitLabPlugin.path
|
||||||
|
// Skip KondoKit since it should always be loaded
|
||||||
|
if (isKondoKit(pluginName)) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
val remoteVersion = gitLabPlugin.pluginProperties?.version ?: "Unknown"
|
||||||
|
val description = gitLabPlugin.pluginProperties?.description ?: "No description available"
|
||||||
|
val author = gitLabPlugin.pluginProperties?.author ?: "Unknown"
|
||||||
|
|
||||||
|
val isLoaded = loadedPluginNames.contains(pluginName)
|
||||||
|
val isDisabled = disabledPluginInfo.containsKey(pluginName)
|
||||||
|
val disabledVersion = disabledPluginInfo[pluginName]
|
||||||
|
|
||||||
|
// Check if this plugin is currently being downloaded
|
||||||
|
val existingStatus = pluginStatuses.find { it.name == pluginName }
|
||||||
|
val isDownloading = existingStatus?.isDownloading ?: false
|
||||||
|
val downloadProgress = existingStatus?.downloadProgress ?: 0
|
||||||
|
|
||||||
|
if (isLoaded) {
|
||||||
|
// Plugin is currently loaded
|
||||||
|
statuses.add(PluginInfoWithStatus(
|
||||||
|
name = pluginName,
|
||||||
|
installedVersion = remoteVersion, // We don't have the actual installed version, but we know it's loaded
|
||||||
|
remoteVersion = remoteVersion,
|
||||||
|
description = description,
|
||||||
|
author = author,
|
||||||
|
gitLabPlugin = gitLabPlugin,
|
||||||
|
isInstalled = true,
|
||||||
|
needsUpdate = false, // We assume it's up-to-date since it's loaded
|
||||||
|
isDownloading = isDownloading,
|
||||||
|
downloadProgress = downloadProgress
|
||||||
|
))
|
||||||
|
} else if (isDisabled) {
|
||||||
|
// Plugin is disabled, check if versions match
|
||||||
|
val versionsMatch = disabledVersion != null && disabledVersion == remoteVersion
|
||||||
|
if (!versionsMatch) {
|
||||||
|
// Versions don't match, show update option
|
||||||
|
statuses.add(PluginInfoWithStatus(
|
||||||
|
name = pluginName,
|
||||||
|
installedVersion = disabledVersion,
|
||||||
|
remoteVersion = remoteVersion,
|
||||||
|
description = description,
|
||||||
|
author = author,
|
||||||
|
gitLabPlugin = gitLabPlugin,
|
||||||
|
isInstalled = true, // It's installed but disabled
|
||||||
|
needsUpdate = true, // Needs update since versions don't match
|
||||||
|
isDownloading = isDownloading,
|
||||||
|
downloadProgress = downloadProgress
|
||||||
|
))
|
||||||
|
}
|
||||||
|
// If versions match, we don't add it to the list since there's no point showing it
|
||||||
|
} else {
|
||||||
|
// Plugin is not installed at all
|
||||||
|
statuses.add(PluginInfoWithStatus(
|
||||||
|
name = pluginName,
|
||||||
|
installedVersion = null,
|
||||||
|
remoteVersion = remoteVersion,
|
||||||
|
description = description,
|
||||||
|
author = author,
|
||||||
|
gitLabPlugin = gitLabPlugin,
|
||||||
|
isInstalled = false,
|
||||||
|
needsUpdate = false,
|
||||||
|
isDownloading = isDownloading,
|
||||||
|
downloadProgress = downloadProgress
|
||||||
|
))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pluginStatuses = statuses
|
||||||
|
}
|
||||||
|
|
||||||
|
// Helper method to get currently loaded plugin names
|
||||||
|
private fun getLoadedPluginNames(): Set<String> {
|
||||||
|
val loadedPluginNames = mutableSetOf<String>()
|
||||||
|
|
||||||
|
try {
|
||||||
|
// Get loaded plugins
|
||||||
|
val loadedPluginsField = PluginRepository::class.java.getDeclaredField("loadedPlugins")
|
||||||
|
loadedPluginsField.isAccessible = true
|
||||||
|
val loadedPlugins = loadedPluginsField.get(null) as HashMap<*, *>
|
||||||
|
|
||||||
|
for ((_, plugin) in loadedPlugins) {
|
||||||
|
val pluginName = getPluginDirName(plugin as Plugin)
|
||||||
|
loadedPluginNames.add(pluginName)
|
||||||
|
}
|
||||||
|
} catch (e: Exception) {
|
||||||
|
e.printStackTrace()
|
||||||
|
}
|
||||||
|
|
||||||
|
return loadedPluginNames
|
||||||
|
}
|
||||||
|
|
||||||
|
// Helper method to parse plugin.properties content
|
||||||
|
private fun parsePluginProperties(content: String): PluginProperties {
|
||||||
|
var author = "Unknown"
|
||||||
|
var version = "Unknown"
|
||||||
|
var description = "No description available"
|
||||||
|
|
||||||
|
val lines = content.split("\n")
|
||||||
|
for (line in lines) {
|
||||||
|
val parts = line.split("=")
|
||||||
|
if (parts.size == 2) {
|
||||||
|
val key = parts[0].trim()
|
||||||
|
val value = parts[1].replace("\"", "").replace("'", "").trim()
|
||||||
|
|
||||||
|
when {
|
||||||
|
key.startsWith("AUTHOR", ignoreCase = true) -> {
|
||||||
|
author = value
|
||||||
|
}
|
||||||
|
key.startsWith("VERSION", ignoreCase = true) -> {
|
||||||
|
version = value
|
||||||
|
}
|
||||||
|
key.startsWith("DESCRIPTION", ignoreCase = true) -> {
|
||||||
|
description = value
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return PluginProperties(author, version, description)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Helper method to get disabled plugin names and their versions
|
||||||
|
private fun getDisabledPluginInfo(): Map<String, String> {
|
||||||
|
val disabledPluginInfo = mutableMapOf<String, String>()
|
||||||
|
val disabledDir = File(pluginsDirectory, "disabled")
|
||||||
|
|
||||||
|
if (disabledDir.exists() && disabledDir.isDirectory) {
|
||||||
|
val disabledPlugins = disabledDir.listFiles { file -> file.isDirectory } ?: arrayOf()
|
||||||
|
|
||||||
|
for (pluginDir in disabledPlugins) {
|
||||||
|
try {
|
||||||
|
val propertiesFile = File(pluginDir, "plugin.properties")
|
||||||
|
if (propertiesFile.exists()) {
|
||||||
|
val content = propertiesFile.readText()
|
||||||
|
val properties = parsePluginProperties(content)
|
||||||
|
disabledPluginInfo[pluginDir.name] = properties.version
|
||||||
|
}
|
||||||
|
} catch (e: Exception) {
|
||||||
|
e.printStackTrace()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return disabledPluginInfo
|
||||||
|
}
|
||||||
|
|
||||||
|
// Helper method to handle duplicate plugins (loaded and disabled)
|
||||||
|
private fun handleDuplicatePlugins(loadedPluginNames: Set<String>, disabledPluginInfo: Map<String, String>) {
|
||||||
|
var needsReload = false
|
||||||
|
for (pluginName in loadedPluginNames) {
|
||||||
|
if (disabledPluginInfo.containsKey(pluginName)) {
|
||||||
|
try {
|
||||||
|
val disabledDir = File(pluginsDirectory, "disabled")
|
||||||
|
val pluginDir = File(disabledDir, pluginName)
|
||||||
|
if (pluginDir.exists() && pluginDir.isDirectory) {
|
||||||
|
if (deleteRecursively(pluginDir)) {
|
||||||
|
needsReload = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (e: Exception) {
|
||||||
|
e.printStackTrace()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Reload plugins if we deleted any disabled duplicates
|
||||||
|
if (needsReload) {
|
||||||
|
PluginRepository.reloadPlugins()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Helper method to delete a plugin
|
||||||
|
fun deletePlugin(pluginName: String, isDisabled: Boolean, mainPanel: Component) {
|
||||||
|
try {
|
||||||
|
val pluginDir = if (isDisabled) {
|
||||||
|
File(File(pluginsDirectory, "disabled"), pluginName)
|
||||||
|
} else {
|
||||||
|
File(pluginsDirectory, pluginName)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pluginDir.exists() && pluginDir.isDirectory) {
|
||||||
|
// Recursively delete the directory
|
||||||
|
if (deleteRecursively(pluginDir)) {
|
||||||
|
Helpers.showToast(mainPanel, "Plugin deleted successfully", JOptionPane.INFORMATION_MESSAGE)
|
||||||
|
|
||||||
|
// If we deleted a loaded plugin, schedule plugin reload
|
||||||
|
if (!isDisabled) {
|
||||||
|
reloadPlugins = true
|
||||||
|
}
|
||||||
|
|
||||||
|
// Refresh the plugin list view
|
||||||
|
SwingUtilities.invokeLater {
|
||||||
|
ReflectiveEditorView.addPlugins(ReflectiveEditorView.panel)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
Helpers.showToast(mainPanel, "Failed to delete plugin", JOptionPane.ERROR_MESSAGE)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
Helpers.showToast(mainPanel, "Plugin directory not found", JOptionPane.ERROR_MESSAGE)
|
||||||
|
}
|
||||||
|
} catch (e: Exception) {
|
||||||
|
e.printStackTrace()
|
||||||
|
Helpers.showToast(mainPanel, "Error deleting plugin: ${e.message}", JOptionPane.ERROR_MESSAGE)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Helper method to recursively delete a directory
|
||||||
|
private fun deleteRecursively(file: File): Boolean {
|
||||||
|
if (file.isDirectory) {
|
||||||
|
file.listFiles()?.forEach { child ->
|
||||||
|
if (!deleteRecursively(child)) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return file.delete()
|
||||||
|
}
|
||||||
|
|
||||||
|
// Helper function to check if a plugin is the KondoKit plugin
|
||||||
|
private fun isKondoKit(pluginName: String): Boolean {
|
||||||
|
return pluginName == "KondoKit"
|
||||||
|
}
|
||||||
|
|
||||||
|
// Enable a plugin by moving it from disabled to main directory
|
||||||
|
fun enablePlugin(pluginName: String, mainPanel: Component) {
|
||||||
|
try {
|
||||||
|
// Source and destination directories
|
||||||
|
val disabledDir = File(pluginsDirectory, "disabled")
|
||||||
|
val sourceDir = File(disabledDir, pluginName)
|
||||||
|
val destDir = File(pluginsDirectory, pluginName)
|
||||||
|
|
||||||
|
// Check if source directory exists
|
||||||
|
if (!sourceDir.exists()) {
|
||||||
|
Helpers.showToast(mainPanel, "Plugin directory not found: ${sourceDir.absolutePath}", JOptionPane.ERROR_MESSAGE)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Move the directory
|
||||||
|
if (sourceDir.renameTo(destDir)) {
|
||||||
|
Helpers.showToast(mainPanel, "Plugin enabled")
|
||||||
|
|
||||||
|
// Schedule plugin reload to avoid crashes
|
||||||
|
reloadPlugins = true
|
||||||
|
|
||||||
|
// Refresh the plugin list view
|
||||||
|
SwingUtilities.invokeLater {
|
||||||
|
ReflectiveEditorView.addPlugins(ReflectiveEditorView.panel)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
Helpers.showToast(mainPanel, "Failed to enable plugin", JOptionPane.ERROR_MESSAGE)
|
||||||
|
}
|
||||||
|
} catch (e: Exception) {
|
||||||
|
e.printStackTrace()
|
||||||
|
Helpers.showToast(mainPanel, "Error enabling plugin: ${e.message}", JOptionPane.ERROR_MESSAGE)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Toggle a plugin's enable/disable state by moving it between directories
|
||||||
|
fun togglePlugin(plugin: Plugin, pluginInfo: PluginInfo, toggleSwitch: Component, activated: Boolean, mainPanel: Component) {
|
||||||
|
try {
|
||||||
|
// Get the plugin directory name from the plugin's class package
|
||||||
|
val pluginDirName = getPluginDirName(plugin)
|
||||||
|
|
||||||
|
// Source and destination directories
|
||||||
|
val sourceDir = if (activated) {
|
||||||
|
// Moving from disabled to enabled
|
||||||
|
File(File(pluginsDirectory, "disabled"), pluginDirName)
|
||||||
|
} else {
|
||||||
|
// Moving from enabled to disabled
|
||||||
|
File(pluginsDirectory, pluginDirName)
|
||||||
|
}
|
||||||
|
|
||||||
|
val destDir = if (activated) {
|
||||||
|
// Moving to main plugins directory
|
||||||
|
File(pluginsDirectory, pluginDirName)
|
||||||
|
} else {
|
||||||
|
// Moving to disabled directory
|
||||||
|
val disabledDir = File(pluginsDirectory, "disabled")
|
||||||
|
if (!disabledDir.exists()) {
|
||||||
|
disabledDir.mkdirs()
|
||||||
|
}
|
||||||
|
File(disabledDir, pluginDirName)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if source directory exists
|
||||||
|
if (!sourceDir.exists()) {
|
||||||
|
Helpers.showToast(mainPanel, "Plugin directory not found: ${sourceDir.absolutePath}", JOptionPane.ERROR_MESSAGE)
|
||||||
|
// Reset toggle switch to previous state
|
||||||
|
SwingUtilities.invokeLater {
|
||||||
|
if (toggleSwitch is JComponent) {
|
||||||
|
toggleSwitch.repaint()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Move the directory
|
||||||
|
if (sourceDir.renameTo(destDir)) {
|
||||||
|
Helpers.showToast(mainPanel, if (activated) "Plugin enabled" else "Plugin disabled")
|
||||||
|
|
||||||
|
// Schedule plugin reload to avoid crashes
|
||||||
|
reloadPlugins = true
|
||||||
|
|
||||||
|
// Refresh the plugin list view
|
||||||
|
SwingUtilities.invokeLater {
|
||||||
|
ReflectiveEditorView.addPlugins(ReflectiveEditorView.panel)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
Helpers.showToast(mainPanel, "Failed to ${if (activated) "enable" else "disable"} plugin", JOptionPane.ERROR_MESSAGE)
|
||||||
|
// Reset toggle switch to previous state
|
||||||
|
SwingUtilities.invokeLater {
|
||||||
|
if (toggleSwitch is JComponent) {
|
||||||
|
toggleSwitch.repaint()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (e: Exception) {
|
||||||
|
e.printStackTrace()
|
||||||
|
Helpers.showToast(mainPanel, "Error toggling plugin: ${e.message}", JOptionPane.ERROR_MESSAGE)
|
||||||
|
// Reset toggle switch to previous state
|
||||||
|
SwingUtilities.invokeLater {
|
||||||
|
if (toggleSwitch is JComponent) {
|
||||||
|
toggleSwitch.repaint()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Helper function to get plugin directory name from plugin instance
|
||||||
|
private fun getPluginDirName(plugin: Plugin): String {
|
||||||
|
// Extract the directory name from the plugin's package
|
||||||
|
// The package name is typically like "GroundItems.plugin" so we take the first part
|
||||||
|
val packageName = plugin.javaClass.`package`.name
|
||||||
|
return packageName.substringBefore(".")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if a plugin is currently enabled
|
||||||
|
fun isPluginEnabled(plugin: Plugin, pluginInfo: PluginInfo): Boolean {
|
||||||
|
// Get the plugin directory name from the plugin's class package
|
||||||
|
val pluginDirName = getPluginDirName(plugin)
|
||||||
|
val pluginDir = File(pluginsDirectory, pluginDirName)
|
||||||
|
return pluginDir.exists() && pluginDir.isDirectory
|
||||||
|
}
|
||||||
|
|
||||||
|
// Method to start downloading a plugin
|
||||||
|
fun startPluginDownload(pluginStatus: PluginInfoWithStatus, mainPanel: Component) {
|
||||||
|
val gitLabPlugin = pluginStatus.gitLabPlugin
|
||||||
|
if (gitLabPlugin == null) {
|
||||||
|
Helpers.showToast(mainPanel, "Plugin information not available", JOptionPane.ERROR_MESSAGE)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update plugin status to show downloading
|
||||||
|
val updatedStatuses = pluginStatuses.map {
|
||||||
|
if (it.name == pluginStatus.name) {
|
||||||
|
it.copy(isDownloading = true, downloadProgress = 0)
|
||||||
|
} else {
|
||||||
|
it
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pluginStatuses = updatedStatuses
|
||||||
|
|
||||||
|
// Refresh UI to show progress bar
|
||||||
|
SwingUtilities.invokeLater {
|
||||||
|
ReflectiveEditorView.addPlugins(ReflectiveEditorView.panel)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Start the download
|
||||||
|
PluginDownloadManager.downloadPlugin(gitLabPlugin, object : PluginDownloadManager.DownloadProgressCallback {
|
||||||
|
override fun onProgress(pluginName: String, progress: Int) {
|
||||||
|
// Update progress in plugin statuses
|
||||||
|
val updatedStatuses = pluginStatuses.map {
|
||||||
|
if (it.name == pluginName) {
|
||||||
|
it.copy(downloadProgress = progress)
|
||||||
|
} else {
|
||||||
|
it
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pluginStatuses = updatedStatuses
|
||||||
|
|
||||||
|
// Refresh UI to show progress
|
||||||
|
SwingUtilities.invokeLater {
|
||||||
|
ReflectiveEditorView.addPlugins(ReflectiveEditorView.panel)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onComplete(pluginName: String, success: Boolean, errorMessage: String?) {
|
||||||
|
// Update plugin status
|
||||||
|
val updatedStatuses = pluginStatuses.map {
|
||||||
|
if (it.name == pluginName) {
|
||||||
|
it.copy(isDownloading = false, downloadProgress = if (success) 100 else 0)
|
||||||
|
} else {
|
||||||
|
it
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pluginStatuses = updatedStatuses
|
||||||
|
|
||||||
|
// Show result to user
|
||||||
|
if (success) {
|
||||||
|
Helpers.showToast(mainPanel, "Plugin downloaded successfully!", JOptionPane.INFORMATION_MESSAGE)
|
||||||
|
// Reload plugins to make the newly downloaded plugin available
|
||||||
|
PluginRepository.reloadPlugins()
|
||||||
|
} else {
|
||||||
|
Helpers.showToast(mainPanel, "Failed to download plugin: ${errorMessage ?: "Unknown error"}", JOptionPane.ERROR_MESSAGE)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Refresh UI
|
||||||
|
SwingUtilities.invokeLater {
|
||||||
|
ReflectiveEditorView.addPlugins(ReflectiveEditorView.panel)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// Getter for plugin directory - needed for the view
|
||||||
|
fun getPluginsDirectory(): File = pluginsDirectory
|
||||||
|
|
||||||
|
// Getter for reload flag - needed for the view
|
||||||
|
fun shouldReloadPlugins(): Boolean = reloadPlugins
|
||||||
|
|
||||||
|
// Setter for reload flag - needed for the view
|
||||||
|
fun setReloadPlugins(reload: Boolean) {
|
||||||
|
reloadPlugins = reload
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -22,7 +22,7 @@ object ViewConstants {
|
||||||
val DIMENSION_SMALL_ICON = Dimension(12, 12)
|
val DIMENSION_SMALL_ICON = Dimension(12, 12)
|
||||||
val DIMENSION_LARGE_ICON = Dimension(30, 30)
|
val DIMENSION_LARGE_ICON = Dimension(30, 30)
|
||||||
val DEFAULT_WIDGET_SIZE = Dimension(234, 50)
|
val DEFAULT_WIDGET_SIZE = Dimension(234, 50)
|
||||||
val PLUGIN_LIST_ITEM_SIZE = Dimension(DEFAULT_WIDGET_SIZE.width, 30)
|
val PLUGIN_LIST_ITEM_SIZE = Dimension(DEFAULT_WIDGET_SIZE.width, 36)
|
||||||
val TOGGLE_PLACEHOLDER_SIZE = Dimension(60, 24)
|
val TOGGLE_PLACEHOLDER_SIZE = Dimension(60, 24)
|
||||||
val TOTAL_XP_WIDGET_SIZE = Dimension(DEFAULT_WIDGET_SIZE.width, 42)
|
val TOTAL_XP_WIDGET_SIZE = Dimension(DEFAULT_WIDGET_SIZE.width, 42)
|
||||||
val IMAGE_SIZE = Dimension(25, 23)
|
val IMAGE_SIZE = Dimension(25, 23)
|
||||||
|
|
|
||||||
|
|
@ -160,7 +160,7 @@ object PluginDownloadManager {
|
||||||
debugLog("Input stream available for plugin: ${plugin.path}")
|
debugLog("Input stream available for plugin: ${plugin.path}")
|
||||||
|
|
||||||
// Create output directory
|
// Create output directory
|
||||||
val pluginsDir = ReflectiveEditorView.pluginsDirectory
|
val pluginsDir = File(rt4.GlobalJsonConfig.instance.pluginsFolder)
|
||||||
debugLog("Plugins directory: ${pluginsDir.absolutePath}")
|
debugLog("Plugins directory: ${pluginsDir.absolutePath}")
|
||||||
|
|
||||||
// Validate plugins directory
|
// Validate plugins directory
|
||||||
|
|
|
||||||
|
|
@ -5,6 +5,7 @@ import KondoKit.components.*
|
||||||
import KondoKit.ViewConstants
|
import KondoKit.ViewConstants
|
||||||
import KondoKit.views.ViewLayoutHelpers.createSearchFieldSection
|
import KondoKit.views.ViewLayoutHelpers.createSearchFieldSection
|
||||||
import KondoKit.setFixedSize
|
import KondoKit.setFixedSize
|
||||||
|
import KondoKit.ReflectiveEditorPlugin
|
||||||
import KondoKit.pluginmanager.GitLabPlugin
|
import KondoKit.pluginmanager.GitLabPlugin
|
||||||
import KondoKit.pluginmanager.GitLabPluginFetcher
|
import KondoKit.pluginmanager.GitLabPluginFetcher
|
||||||
import KondoKit.pluginmanager.PluginDownloadManager
|
import KondoKit.pluginmanager.PluginDownloadManager
|
||||||
|
|
@ -41,17 +42,11 @@ object ReflectiveEditorView : View {
|
||||||
const val VIEW_NAME = "REFLECTIVE_EDITOR_VIEW"
|
const val VIEW_NAME = "REFLECTIVE_EDITOR_VIEW"
|
||||||
const val PLUGIN_LIST_VIEW = "PLUGIN_LIST"
|
const val PLUGIN_LIST_VIEW = "PLUGIN_LIST"
|
||||||
const val PLUGIN_DETAIL_VIEW = "PLUGIN_DETAIL"
|
const val PLUGIN_DETAIL_VIEW = "PLUGIN_DETAIL"
|
||||||
val pluginsDirectory: File = File(GlobalJsonConfig.instance.pluginsFolder)
|
|
||||||
|
|
||||||
private var gitLabPlugins: List<GitLabPlugin> = listOf()
|
private val reflectiveEditorPlugin = ReflectiveEditorPlugin()
|
||||||
|
|
||||||
private var pluginStatuses: List<PluginInfoWithStatus> = listOf()
|
|
||||||
|
|
||||||
private var searchField: SearchField? = null
|
private var searchField: SearchField? = null
|
||||||
|
|
||||||
// Flag for scheduled plugin reload to avoid crashes
|
|
||||||
private var reloadPlugins = false
|
|
||||||
|
|
||||||
// Helper function to check if a plugin is the KondoKit plugin
|
// Helper function to check if a plugin is the KondoKit plugin
|
||||||
private fun isKondoKit(pluginName: String): Boolean {
|
private fun isKondoKit(pluginName: String): Boolean {
|
||||||
return pluginName == "KondoKit"
|
return pluginName == "KondoKit"
|
||||||
|
|
@ -75,6 +70,8 @@ object ReflectiveEditorView : View {
|
||||||
get() = reflectiveEditorView ?: JPanel()
|
get() = reflectiveEditorView ?: JPanel()
|
||||||
|
|
||||||
override fun createView() {
|
override fun createView() {
|
||||||
|
// Initialize the plugin
|
||||||
|
reflectiveEditorPlugin.Init()
|
||||||
createReflectiveEditorView()
|
createReflectiveEditorView()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -102,12 +99,7 @@ object ReflectiveEditorView : View {
|
||||||
|
|
||||||
cardLayout.show(mainPanel, PLUGIN_LIST_VIEW)
|
cardLayout.show(mainPanel, PLUGIN_LIST_VIEW)
|
||||||
|
|
||||||
GitLabPluginFetcher.fetchGitLabPlugins { plugins ->
|
// Plugin initialization is handled by the plugin class, gitLabPlugins will be fetched automatically
|
||||||
gitLabPlugins = plugins
|
|
||||||
// Update plugin statuses with comparison between installed and remote plugins
|
|
||||||
updatePluginStatuses()
|
|
||||||
// We'll update the UI when needed
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun createPluginListView(): JPanel {
|
private fun createPluginListView(): JPanel {
|
||||||
|
|
@ -224,7 +216,7 @@ object ReflectiveEditorView : View {
|
||||||
e.printStackTrace()
|
e.printStackTrace()
|
||||||
}
|
}
|
||||||
|
|
||||||
val disabledDir = File(pluginsDirectory, "disabled")
|
val disabledDir = File(reflectiveEditorPlugin.getPluginsDirectory(), "disabled")
|
||||||
if (disabledDir.exists() && disabledDir.isDirectory) {
|
if (disabledDir.exists() && disabledDir.isDirectory) {
|
||||||
val disabledPlugins = disabledDir.listFiles { file -> file.isDirectory } ?: arrayOf()
|
val disabledPlugins = disabledDir.listFiles { file -> file.isDirectory } ?: arrayOf()
|
||||||
|
|
||||||
|
|
@ -241,7 +233,7 @@ object ReflectiveEditorView : View {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (pluginSearchText.isNotBlank()) {
|
if (pluginSearchText.isNotBlank()) {
|
||||||
val matchingPluginStatuses = pluginStatuses.filter { pluginStatus ->
|
val matchingPluginStatuses = reflectiveEditorPlugin.getPluginStatuses().filter { pluginStatus ->
|
||||||
!pluginStatus.isInstalled &&
|
!pluginStatus.isInstalled &&
|
||||||
!isKondoKit(pluginStatus.name) &&
|
!isKondoKit(pluginStatus.name) &&
|
||||||
(pluginStatus.name.contains(pluginSearchText, ignoreCase = true) ||
|
(pluginStatus.name.contains(pluginSearchText, ignoreCase = true) ||
|
||||||
|
|
@ -285,6 +277,10 @@ object ReflectiveEditorView : View {
|
||||||
val panel = WidgetPanel(
|
val panel = WidgetPanel(
|
||||||
widgetWidth = ViewConstants.PLUGIN_LIST_ITEM_SIZE.width,
|
widgetWidth = ViewConstants.PLUGIN_LIST_ITEM_SIZE.width,
|
||||||
widgetHeight = ViewConstants.PLUGIN_LIST_ITEM_SIZE.height,
|
widgetHeight = ViewConstants.PLUGIN_LIST_ITEM_SIZE.height,
|
||||||
|
paddingLeft = 10,
|
||||||
|
paddingRight = 10,
|
||||||
|
paddingTop = 10,
|
||||||
|
paddingBottom = 10,
|
||||||
addDefaultPadding = false
|
addDefaultPadding = false
|
||||||
).apply {
|
).apply {
|
||||||
layout = BorderLayout()
|
layout = BorderLayout()
|
||||||
|
|
@ -326,7 +322,7 @@ object ReflectiveEditorView : View {
|
||||||
infoPanel.background = WIDGET_COLOR
|
infoPanel.background = WIDGET_COLOR
|
||||||
infoPanel.add(nameLabel, BorderLayout.WEST)
|
infoPanel.add(nameLabel, BorderLayout.WEST)
|
||||||
|
|
||||||
val controlsPanel = JPanel(FlowLayout(FlowLayout.RIGHT, 5, 0))
|
val controlsPanel = JPanel(FlowLayout(FlowLayout.RIGHT, 5, -3))
|
||||||
controlsPanel.background = WIDGET_COLOR
|
controlsPanel.background = WIDGET_COLOR
|
||||||
|
|
||||||
editButton?.let { controlsPanel.add(it) }
|
editButton?.let { controlsPanel.add(it) }
|
||||||
|
|
@ -350,6 +346,10 @@ object ReflectiveEditorView : View {
|
||||||
val panel = WidgetPanel(
|
val panel = WidgetPanel(
|
||||||
widgetWidth = ViewConstants.PLUGIN_LIST_ITEM_SIZE.width,
|
widgetWidth = ViewConstants.PLUGIN_LIST_ITEM_SIZE.width,
|
||||||
widgetHeight = ViewConstants.PLUGIN_LIST_ITEM_SIZE.height,
|
widgetHeight = ViewConstants.PLUGIN_LIST_ITEM_SIZE.height,
|
||||||
|
paddingLeft = 10,
|
||||||
|
paddingRight = 10,
|
||||||
|
paddingTop = 10,
|
||||||
|
paddingBottom = 10,
|
||||||
addDefaultPadding = false
|
addDefaultPadding = false
|
||||||
).apply {
|
).apply {
|
||||||
layout = BorderLayout()
|
layout = BorderLayout()
|
||||||
|
|
@ -365,7 +365,7 @@ object ReflectiveEditorView : View {
|
||||||
toggleSwitch.setActivated(false)
|
toggleSwitch.setActivated(false)
|
||||||
toggleSwitch.onToggleListener = { activated ->
|
toggleSwitch.onToggleListener = { activated ->
|
||||||
if (activated) {
|
if (activated) {
|
||||||
enablePlugin(pluginName)
|
reflectiveEditorPlugin.enablePlugin(pluginName, mainPanel ?: JPanel())
|
||||||
}
|
}
|
||||||
// If trying to disable an already disabled plugin, reset the toggle
|
// If trying to disable an already disabled plugin, reset the toggle
|
||||||
else {
|
else {
|
||||||
|
|
@ -378,7 +378,7 @@ object ReflectiveEditorView : View {
|
||||||
infoPanel.background = WIDGET_COLOR
|
infoPanel.background = WIDGET_COLOR
|
||||||
infoPanel.add(nameLabel, BorderLayout.WEST)
|
infoPanel.add(nameLabel, BorderLayout.WEST)
|
||||||
|
|
||||||
val controlsPanel = JPanel(FlowLayout(FlowLayout.RIGHT, 5, 0))
|
val controlsPanel = JPanel(FlowLayout(FlowLayout.RIGHT, 0, 0))
|
||||||
controlsPanel.background = WIDGET_COLOR
|
controlsPanel.background = WIDGET_COLOR
|
||||||
controlsPanel.add(toggleSwitch)
|
controlsPanel.add(toggleSwitch)
|
||||||
|
|
||||||
|
|
@ -398,6 +398,10 @@ object ReflectiveEditorView : View {
|
||||||
val panel = WidgetPanel(
|
val panel = WidgetPanel(
|
||||||
widgetWidth = ViewConstants.PLUGIN_LIST_ITEM_SIZE.width,
|
widgetWidth = ViewConstants.PLUGIN_LIST_ITEM_SIZE.width,
|
||||||
widgetHeight = ViewConstants.PLUGIN_LIST_ITEM_SIZE.height,
|
widgetHeight = ViewConstants.PLUGIN_LIST_ITEM_SIZE.height,
|
||||||
|
paddingLeft = 10,
|
||||||
|
paddingRight = 10,
|
||||||
|
paddingTop = 10,
|
||||||
|
paddingBottom = 10,
|
||||||
addDefaultPadding = false
|
addDefaultPadding = false
|
||||||
).apply {
|
).apply {
|
||||||
layout = BorderLayout()
|
layout = BorderLayout()
|
||||||
|
|
@ -453,10 +457,71 @@ object ReflectiveEditorView : View {
|
||||||
|
|
||||||
if (pluginStatus.isInstalled && !pluginStatus.needsUpdate) {
|
if (pluginStatus.isInstalled && !pluginStatus.needsUpdate) {
|
||||||
toggleSwitch.onToggleListener = { activated ->
|
toggleSwitch.onToggleListener = { activated ->
|
||||||
// TODO: Implement enable/disable functionality
|
// Find the corresponding loaded plugin to use toggle functionality
|
||||||
showToast(mainPanel, "Enable/disable functionality not yet implemented", JOptionPane.INFORMATION_MESSAGE)
|
val loadedPluginsField = PluginRepository::class.java.getDeclaredField("loadedPlugins")
|
||||||
// Reset for now since functionality not implemented
|
loadedPluginsField.isAccessible = true
|
||||||
toggleSwitch.setActivated(true)
|
val loadedPlugins = loadedPluginsField.get(null) as HashMap<*, *>
|
||||||
|
|
||||||
|
var foundPlugin: Plugin? = null
|
||||||
|
var foundPluginInfo: PluginInfo? = null
|
||||||
|
|
||||||
|
for ((pluginInfo, plugin) in loadedPlugins) {
|
||||||
|
if (getPluginDirName(plugin as Plugin) == pluginStatus.name) {
|
||||||
|
foundPlugin = plugin
|
||||||
|
foundPluginInfo = pluginInfo as PluginInfo
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (foundPlugin != null && foundPluginInfo != null) {
|
||||||
|
reflectiveEditorPlugin.togglePlugin(foundPlugin, foundPluginInfo, toggleSwitch, activated, mainPanel ?: JPanel())
|
||||||
|
} else {
|
||||||
|
// Fallback for plugins that don't have loaded instances available
|
||||||
|
val pluginDirName = pluginStatus.name
|
||||||
|
val sourceDir = if (activated) {
|
||||||
|
// Moving from disabled to enabled
|
||||||
|
File(File(reflectiveEditorPlugin.getPluginsDirectory(), "disabled"), pluginDirName)
|
||||||
|
} else {
|
||||||
|
// Moving from enabled to disabled
|
||||||
|
File(reflectiveEditorPlugin.getPluginsDirectory(), pluginDirName)
|
||||||
|
}
|
||||||
|
|
||||||
|
val destDir = if (activated) {
|
||||||
|
// Moving to main plugins directory
|
||||||
|
File(reflectiveEditorPlugin.getPluginsDirectory(), pluginDirName)
|
||||||
|
} else {
|
||||||
|
// Moving to disabled directory
|
||||||
|
val disabledDir = File(reflectiveEditorPlugin.getPluginsDirectory(), "disabled")
|
||||||
|
if (!disabledDir.exists()) {
|
||||||
|
disabledDir.mkdirs()
|
||||||
|
}
|
||||||
|
File(disabledDir, pluginDirName)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if source directory exists
|
||||||
|
if (!sourceDir.exists()) {
|
||||||
|
showToast(mainPanel, "Plugin directory not found: ${sourceDir.absolutePath}", JOptionPane.ERROR_MESSAGE)
|
||||||
|
// Reset toggle switch to previous state
|
||||||
|
toggleSwitch.setActivated(!activated)
|
||||||
|
} else {
|
||||||
|
// Move the directory
|
||||||
|
if (sourceDir.renameTo(destDir)) {
|
||||||
|
showToast(mainPanel, if (activated) "Plugin enabled" else "Plugin disabled")
|
||||||
|
|
||||||
|
// Schedule plugin reload to avoid crashes
|
||||||
|
reflectiveEditorPlugin.setReloadPlugins(true)
|
||||||
|
|
||||||
|
// Refresh the plugin list view
|
||||||
|
SwingUtilities.invokeLater {
|
||||||
|
addPlugins(reflectiveEditorView!!)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
showToast(mainPanel, "Failed to ${if (activated) "enable" else "disable"} plugin", JOptionPane.ERROR_MESSAGE)
|
||||||
|
// Reset toggle switch to previous state
|
||||||
|
toggleSwitch.setActivated(!activated)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// Hide the toggle switch for non-installed plugins
|
// Hide the toggle switch for non-installed plugins
|
||||||
|
|
@ -468,7 +533,7 @@ object ReflectiveEditorView : View {
|
||||||
infoPanel.background = WIDGET_COLOR
|
infoPanel.background = WIDGET_COLOR
|
||||||
infoPanel.add(nameLabel, BorderLayout.WEST)
|
infoPanel.add(nameLabel, BorderLayout.WEST)
|
||||||
|
|
||||||
val controlsPanel = JPanel(FlowLayout(FlowLayout.RIGHT, 5, 0))
|
val controlsPanel = JPanel(FlowLayout(FlowLayout.RIGHT, 0, 0))
|
||||||
controlsPanel.background = WIDGET_COLOR
|
controlsPanel.background = WIDGET_COLOR
|
||||||
controlsPanel.add(actionButton)
|
controlsPanel.add(actionButton)
|
||||||
controlsPanel.add(progressBar)
|
controlsPanel.add(progressBar)
|
||||||
|
|
@ -524,60 +589,22 @@ object ReflectiveEditorView : View {
|
||||||
.replace(">", ">")
|
.replace(">", ">")
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun enablePlugin(pluginName: String) {
|
|
||||||
try {
|
|
||||||
// Source and destination directories
|
|
||||||
val disabledDir = File(pluginsDirectory, "disabled")
|
|
||||||
val sourceDir = File(disabledDir, pluginName)
|
|
||||||
val destDir = File(pluginsDirectory, pluginName)
|
|
||||||
|
|
||||||
// Check if source directory exists
|
|
||||||
if (!sourceDir.exists()) {
|
|
||||||
showToast(mainPanel, "Plugin directory not found: ${sourceDir.absolutePath}", JOptionPane.ERROR_MESSAGE)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// Move the directory
|
|
||||||
if (sourceDir.renameTo(destDir)) {
|
|
||||||
showToast(mainPanel, "Plugin enabled")
|
|
||||||
|
|
||||||
// Schedule plugin reload to avoid crashes
|
|
||||||
reloadPlugins = true
|
|
||||||
|
|
||||||
// Refresh the plugin list view
|
|
||||||
SwingUtilities.invokeLater {
|
|
||||||
addPlugins(reflectiveEditorView!!)
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
showToast(mainPanel, "Failed to enable plugin", JOptionPane.ERROR_MESSAGE)
|
|
||||||
}
|
|
||||||
} catch (e: Exception) {
|
|
||||||
e.printStackTrace()
|
|
||||||
showToast(mainPanel, "Error enabling plugin: ${e.message}", JOptionPane.ERROR_MESSAGE)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun createToggleSwitch(plugin: Plugin, pluginInfo: PluginInfo): ToggleSwitch {
|
private fun createToggleSwitch(plugin: Plugin, pluginInfo: PluginInfo): ToggleSwitch {
|
||||||
val toggleSwitch = ToggleSwitch()
|
val toggleSwitch = ToggleSwitch()
|
||||||
|
|
||||||
// Set initial state
|
// Set initial state
|
||||||
toggleSwitch.setActivated(isPluginEnabled(plugin, pluginInfo))
|
toggleSwitch.setActivated(reflectiveEditorPlugin.isPluginEnabled(plugin, pluginInfo))
|
||||||
|
|
||||||
// Add toggle listener
|
// Add toggle listener
|
||||||
toggleSwitch.onToggleListener = { activated ->
|
toggleSwitch.onToggleListener = { activated ->
|
||||||
togglePlugin(plugin, pluginInfo, toggleSwitch, activated)
|
reflectiveEditorPlugin.togglePlugin(plugin, pluginInfo, toggleSwitch, activated, mainPanel ?: JPanel())
|
||||||
}
|
}
|
||||||
|
|
||||||
return toggleSwitch
|
return toggleSwitch
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun isPluginEnabled(plugin: Plugin, pluginInfo: PluginInfo): Boolean {
|
|
||||||
// Get the plugin directory name from the plugin's class package
|
|
||||||
val pluginDirName = getPluginDirName(plugin)
|
|
||||||
val pluginDir = File(pluginsDirectory, pluginDirName)
|
|
||||||
return pluginDir.exists() && pluginDir.isDirectory
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun getPluginDirName(plugin: Plugin): String {
|
private fun getPluginDirName(plugin: Plugin): String {
|
||||||
// Extract the directory name from the plugin's package
|
// Extract the directory name from the plugin's package
|
||||||
// The package name is typically like "GroundItems.plugin" so we take the first part
|
// The package name is typically like "GroundItems.plugin" so we take the first part
|
||||||
|
|
@ -585,64 +612,6 @@ object ReflectiveEditorView : View {
|
||||||
return packageName.substringBefore(".")
|
return packageName.substringBefore(".")
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun togglePlugin(plugin: Plugin, pluginInfo: PluginInfo, toggleSwitch: ToggleSwitch, activated: Boolean) {
|
|
||||||
try {
|
|
||||||
// Get the plugin directory name from the plugin's class package
|
|
||||||
val pluginDirName = getPluginDirName(plugin)
|
|
||||||
|
|
||||||
// Source and destination directories
|
|
||||||
val sourceDir = if (activated) {
|
|
||||||
// Moving from disabled to enabled
|
|
||||||
File(File(pluginsDirectory, "disabled"), pluginDirName)
|
|
||||||
} else {
|
|
||||||
// Moving from enabled to disabled
|
|
||||||
File(pluginsDirectory, pluginDirName)
|
|
||||||
}
|
|
||||||
|
|
||||||
val destDir = if (activated) {
|
|
||||||
// Moving to main plugins directory
|
|
||||||
File(pluginsDirectory, pluginDirName)
|
|
||||||
} else {
|
|
||||||
// Moving to disabled directory
|
|
||||||
val disabledDir = File(pluginsDirectory, "disabled")
|
|
||||||
if (!disabledDir.exists()) {
|
|
||||||
disabledDir.mkdirs()
|
|
||||||
}
|
|
||||||
File(disabledDir, pluginDirName)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check if source directory exists
|
|
||||||
if (!sourceDir.exists()) {
|
|
||||||
showToast(mainPanel, "Plugin directory not found: ${sourceDir.absolutePath}", JOptionPane.ERROR_MESSAGE)
|
|
||||||
// Reset toggle switch to previous state
|
|
||||||
toggleSwitch.setActivated(!activated)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// Move the directory
|
|
||||||
if (sourceDir.renameTo(destDir)) {
|
|
||||||
showToast(mainPanel, if (activated) "Plugin enabled" else "Plugin disabled")
|
|
||||||
|
|
||||||
// Schedule plugin reload to avoid crashes
|
|
||||||
reloadPlugins = true
|
|
||||||
|
|
||||||
// Refresh the plugin list view
|
|
||||||
SwingUtilities.invokeLater {
|
|
||||||
addPlugins(reflectiveEditorView!!)
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
showToast(mainPanel, "Failed to ${if (activated) "enable" else "disable"} plugin", JOptionPane.ERROR_MESSAGE)
|
|
||||||
// Reset toggle switch to previous state
|
|
||||||
toggleSwitch.setActivated(!activated)
|
|
||||||
}
|
|
||||||
} catch (e: Exception) {
|
|
||||||
e.printStackTrace()
|
|
||||||
showToast(mainPanel, "Error toggling plugin: ${e.message}", JOptionPane.ERROR_MESSAGE)
|
|
||||||
// Reset toggle switch to previous state
|
|
||||||
toggleSwitch.setActivated(!activated)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun showPluginDetails(pluginInfo: PluginInfo, plugin: Plugin) {
|
private fun showPluginDetails(pluginInfo: PluginInfo, plugin: Plugin) {
|
||||||
currentPluginInfo = pluginInfo
|
currentPluginInfo = pluginInfo
|
||||||
currentPlugin = plugin
|
currentPlugin = plugin
|
||||||
|
|
@ -775,13 +744,13 @@ object ReflectiveEditorView : View {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check if we need to reload plugins
|
// Check if we need to reload plugins
|
||||||
if (reloadPlugins) {
|
if (reflectiveEditorPlugin.shouldReloadPlugins()) {
|
||||||
PluginRepository.reloadPlugins()
|
PluginRepository.reloadPlugins()
|
||||||
reloadPlugins = false
|
reflectiveEditorPlugin.setReloadPlugins(false)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Update plugin statuses to reflect current loaded plugins
|
// Update plugin statuses to reflect current loaded plugins
|
||||||
updatePluginStatuses()
|
reflectiveEditorPlugin.updatePluginStatuses()
|
||||||
|
|
||||||
val contentPanel = pluginListContentPanel
|
val contentPanel = pluginListContentPanel
|
||||||
if (contentPanel == null) {
|
if (contentPanel == null) {
|
||||||
|
|
@ -816,104 +785,6 @@ object ReflectiveEditorView : View {
|
||||||
mainPanel.repaint()
|
mainPanel.repaint()
|
||||||
}
|
}
|
||||||
|
|
||||||
var customToolTipWindow: JWindow? = null
|
|
||||||
|
|
||||||
fun showCustomToolTip(text: String, component: JComponent) {
|
|
||||||
val tooltipFont = ViewConstants.FONT_RUNESCAPE_SMALL_PLAIN_16
|
|
||||||
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 = 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(TOOLTIP_BACKGROUND)
|
|
||||||
val textColor = Helpers.colorToHex(secondaryColor)
|
|
||||||
contentPane = JLabel("<html><div style='color: $textColor; background-color: $bgColor; padding: 3px; word-break: break-all;'>$text</div></html>").apply {
|
|
||||||
border = BorderFactory.createLineBorder(Color.BLACK)
|
|
||||||
isOpaque = true
|
|
||||||
background = TOOLTIP_BACKGROUND
|
|
||||||
foreground = Color.WHITE
|
|
||||||
font = tooltipFont
|
|
||||||
maximumSize = Dimension(maxWidth, Int.MAX_VALUE)
|
|
||||||
preferredSize = Dimension(maxWidth, requiredHeight)
|
|
||||||
}
|
|
||||||
pack()
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// Update the tooltip text
|
|
||||||
val label = customToolTipWindow!!.contentPane as JLabel
|
|
||||||
val bgColor = Helpers.colorToHex(TOOLTIP_BACKGROUND)
|
|
||||||
val textColor = Helpers.colorToHex(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()
|
|
||||||
}
|
|
||||||
|
|
||||||
// Position the tooltip near the component
|
|
||||||
val locationOnScreen = component.locationOnScreen
|
|
||||||
customToolTipWindow!!.setLocation(locationOnScreen.x, locationOnScreen.y + 15)
|
|
||||||
customToolTipWindow!!.isVisible = true
|
|
||||||
}
|
|
||||||
|
|
||||||
// Add this helper function to read plugin properties from a disabled plugin directory
|
|
||||||
private fun readDisabledPluginProperties(pluginName: String): PluginProperties? {
|
|
||||||
try {
|
|
||||||
val disabledDir = File(pluginsDirectory, "disabled")
|
|
||||||
val pluginDir = File(disabledDir, pluginName)
|
|
||||||
val propertiesFile = File(pluginDir, "plugin.properties")
|
|
||||||
|
|
||||||
if (propertiesFile.exists()) {
|
|
||||||
val content = propertiesFile.readText()
|
|
||||||
return parsePluginProperties(content)
|
|
||||||
}
|
|
||||||
} catch (e: Exception) {
|
|
||||||
}
|
|
||||||
return null
|
|
||||||
}
|
|
||||||
|
|
||||||
// Helper function to parse plugin.properties content
|
|
||||||
private fun parsePluginProperties(content: String): PluginProperties {
|
|
||||||
var author = "Unknown"
|
|
||||||
var version = "Unknown"
|
|
||||||
var description = "No description available"
|
|
||||||
|
|
||||||
val lines = content.split("\n")
|
|
||||||
for (line in lines) {
|
|
||||||
val parts = line.split("=")
|
|
||||||
if (parts.size == 2) {
|
|
||||||
val key = parts[0].trim()
|
|
||||||
val value = parts[1].replace("\"", "").replace("'", "").trim()
|
|
||||||
|
|
||||||
when {
|
|
||||||
key.startsWith("AUTHOR", ignoreCase = true) -> {
|
|
||||||
author = value
|
|
||||||
}
|
|
||||||
key.startsWith("VERSION", ignoreCase = true) -> {
|
|
||||||
version = value
|
|
||||||
}
|
|
||||||
key.startsWith("DESCRIPTION", ignoreCase = true) -> {
|
|
||||||
description = value
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return PluginProperties(author, version, description)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Helper method to find and reset ScrollablePanel components within a container
|
// Helper method to find and reset ScrollablePanel components within a container
|
||||||
private fun findAndResetScrollablePanel(container: Component) {
|
private fun findAndResetScrollablePanel(container: Component) {
|
||||||
if (container is ScrollablePanel) {
|
if (container is ScrollablePanel) {
|
||||||
|
|
@ -925,234 +796,9 @@ object ReflectiveEditorView : View {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Helper method to get currently loaded plugin names
|
|
||||||
private fun getLoadedPluginNames(): Set<String> {
|
|
||||||
val loadedPluginNames = mutableSetOf<String>()
|
|
||||||
|
|
||||||
try {
|
|
||||||
// Get loaded plugins
|
|
||||||
val loadedPluginsField = PluginRepository::class.java.getDeclaredField("loadedPlugins")
|
|
||||||
loadedPluginsField.isAccessible = true
|
|
||||||
val loadedPlugins = loadedPluginsField.get(null) as HashMap<*, *>
|
|
||||||
|
|
||||||
|
|
||||||
for ((_, plugin) in loadedPlugins) {
|
|
||||||
val pluginName = getPluginDirName(plugin as Plugin)
|
|
||||||
loadedPluginNames.add(pluginName)
|
|
||||||
}
|
|
||||||
} catch (e: Exception) {
|
|
||||||
e.printStackTrace()
|
|
||||||
}
|
|
||||||
|
|
||||||
return loadedPluginNames
|
|
||||||
}
|
|
||||||
|
|
||||||
// Method to start downloading a plugin
|
// Method to start downloading a plugin
|
||||||
private fun startPluginDownload(pluginStatus: PluginInfoWithStatus) {
|
private fun startPluginDownload(pluginStatus: PluginInfoWithStatus) {
|
||||||
val gitLabPlugin = pluginStatus.gitLabPlugin
|
reflectiveEditorPlugin.startPluginDownload(pluginStatus, mainPanel ?: JPanel())
|
||||||
if (gitLabPlugin == null) {
|
|
||||||
showToast(mainPanel, "Plugin information not available", JOptionPane.ERROR_MESSAGE)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// Log the download URL for debugging
|
|
||||||
val downloadUrl = PluginDownloadManager.getDownloadUrlForLogging(gitLabPlugin)
|
|
||||||
|
|
||||||
// Update plugin status to show downloading
|
|
||||||
val updatedStatuses = pluginStatuses.map {
|
|
||||||
if (it.name == pluginStatus.name) {
|
|
||||||
it.copy(isDownloading = true, downloadProgress = 0)
|
|
||||||
} else {
|
|
||||||
it
|
|
||||||
}
|
|
||||||
}
|
|
||||||
pluginStatuses = updatedStatuses
|
|
||||||
|
|
||||||
// Refresh UI to show progress bar
|
|
||||||
SwingUtilities.invokeLater {
|
|
||||||
addPlugins(reflectiveEditorView!!)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Start the download
|
|
||||||
PluginDownloadManager.downloadPlugin(gitLabPlugin, object : PluginDownloadManager.DownloadProgressCallback {
|
|
||||||
override fun onProgress(pluginName: String, progress: Int) {
|
|
||||||
// Update progress in plugin statuses
|
|
||||||
val updatedStatuses = pluginStatuses.map {
|
|
||||||
if (it.name == pluginName) {
|
|
||||||
it.copy(downloadProgress = progress)
|
|
||||||
} else {
|
|
||||||
it
|
|
||||||
}
|
|
||||||
}
|
|
||||||
pluginStatuses = updatedStatuses
|
|
||||||
|
|
||||||
// Refresh UI to show progress
|
|
||||||
SwingUtilities.invokeLater {
|
|
||||||
addPlugins(reflectiveEditorView!!)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onComplete(pluginName: String, success: Boolean, errorMessage: String?) {
|
|
||||||
// Update plugin status
|
|
||||||
val updatedStatuses = pluginStatuses.map {
|
|
||||||
if (it.name == pluginName) {
|
|
||||||
it.copy(isDownloading = false, downloadProgress = if (success) 100 else 0)
|
|
||||||
} else {
|
|
||||||
it
|
|
||||||
}
|
|
||||||
}
|
|
||||||
pluginStatuses = updatedStatuses
|
|
||||||
|
|
||||||
// Show result to user
|
|
||||||
if (success) {
|
|
||||||
showToast(mainPanel, "Plugin downloaded successfully!", JOptionPane.INFORMATION_MESSAGE)
|
|
||||||
// Reload plugins to make the newly downloaded plugin available
|
|
||||||
PluginRepository.reloadPlugins()
|
|
||||||
} else {
|
|
||||||
showToast(mainPanel, "Failed to download plugin: ${errorMessage ?: "Unknown error"}", JOptionPane.ERROR_MESSAGE)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Refresh UI
|
|
||||||
SwingUtilities.invokeLater {
|
|
||||||
addPlugins(reflectiveEditorView!!)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
// Update plugin statuses by comparing installed and remote plugins
|
|
||||||
private fun updatePluginStatuses() {
|
|
||||||
val loadedPluginNames = getLoadedPluginNames()
|
|
||||||
val statuses = mutableListOf<PluginInfoWithStatus>()
|
|
||||||
|
|
||||||
|
|
||||||
// Get disabled plugin names and their versions
|
|
||||||
val disabledPluginInfo = getDisabledPluginInfo()
|
|
||||||
|
|
||||||
// Handle duplicate plugins (loaded and disabled) - delete the disabled version
|
|
||||||
handleDuplicatePlugins(loadedPluginNames, disabledPluginInfo)
|
|
||||||
|
|
||||||
// Process remote plugins
|
|
||||||
for (gitLabPlugin in gitLabPlugins) {
|
|
||||||
val pluginName = gitLabPlugin.path
|
|
||||||
// Skip KondoKit since it should always be loaded
|
|
||||||
if (isKondoKit(pluginName)) {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
val remoteVersion = gitLabPlugin.pluginProperties?.version ?: "Unknown"
|
|
||||||
val description = gitLabPlugin.pluginProperties?.description ?: "No description available"
|
|
||||||
val author = gitLabPlugin.pluginProperties?.author ?: "Unknown"
|
|
||||||
|
|
||||||
val isLoaded = loadedPluginNames.contains(pluginName)
|
|
||||||
val isDisabled = disabledPluginInfo.containsKey(pluginName)
|
|
||||||
val disabledVersion = disabledPluginInfo[pluginName]
|
|
||||||
|
|
||||||
|
|
||||||
// Check if this plugin is currently being downloaded
|
|
||||||
val existingStatus = pluginStatuses.find { it.name == pluginName }
|
|
||||||
val isDownloading = existingStatus?.isDownloading ?: false
|
|
||||||
val downloadProgress = existingStatus?.downloadProgress ?: 0
|
|
||||||
|
|
||||||
if (isLoaded) {
|
|
||||||
// Plugin is currently loaded
|
|
||||||
statuses.add(PluginInfoWithStatus(
|
|
||||||
name = pluginName,
|
|
||||||
installedVersion = remoteVersion, // We don't have the actual installed version, but we know it's loaded
|
|
||||||
remoteVersion = remoteVersion,
|
|
||||||
description = description,
|
|
||||||
author = author,
|
|
||||||
gitLabPlugin = gitLabPlugin,
|
|
||||||
isInstalled = true,
|
|
||||||
needsUpdate = false, // We assume it's up-to-date since it's loaded
|
|
||||||
isDownloading = isDownloading,
|
|
||||||
downloadProgress = downloadProgress
|
|
||||||
))
|
|
||||||
} else if (isDisabled) {
|
|
||||||
// Plugin is disabled, check if versions match
|
|
||||||
val versionsMatch = disabledVersion != null && disabledVersion == remoteVersion
|
|
||||||
if (!versionsMatch) {
|
|
||||||
// Versions don't match, show update option
|
|
||||||
statuses.add(PluginInfoWithStatus(
|
|
||||||
name = pluginName,
|
|
||||||
installedVersion = disabledVersion,
|
|
||||||
remoteVersion = remoteVersion,
|
|
||||||
description = description,
|
|
||||||
author = author,
|
|
||||||
gitLabPlugin = gitLabPlugin,
|
|
||||||
isInstalled = true, // It's installed but disabled
|
|
||||||
needsUpdate = true, // Needs update since versions don't match
|
|
||||||
isDownloading = isDownloading,
|
|
||||||
downloadProgress = downloadProgress
|
|
||||||
))
|
|
||||||
}
|
|
||||||
// If versions match, we don't add it to the list since there's no point showing it
|
|
||||||
} else {
|
|
||||||
// Plugin is not installed at all
|
|
||||||
statuses.add(PluginInfoWithStatus(
|
|
||||||
name = pluginName,
|
|
||||||
installedVersion = null,
|
|
||||||
remoteVersion = remoteVersion,
|
|
||||||
description = description,
|
|
||||||
author = author,
|
|
||||||
gitLabPlugin = gitLabPlugin,
|
|
||||||
isInstalled = false,
|
|
||||||
needsUpdate = false,
|
|
||||||
isDownloading = isDownloading,
|
|
||||||
downloadProgress = downloadProgress
|
|
||||||
))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pluginStatuses = statuses
|
|
||||||
}
|
|
||||||
|
|
||||||
// Helper method to handle duplicate plugins (loaded and disabled)
|
|
||||||
private fun handleDuplicatePlugins(loadedPluginNames: Set<String>, disabledPluginInfo: Map<String, String>) {
|
|
||||||
var needsReload = false
|
|
||||||
for (pluginName in loadedPluginNames) {
|
|
||||||
if (disabledPluginInfo.containsKey(pluginName)) {
|
|
||||||
try {
|
|
||||||
val disabledDir = File(pluginsDirectory, "disabled")
|
|
||||||
val pluginDir = File(disabledDir, pluginName)
|
|
||||||
if (pluginDir.exists() && pluginDir.isDirectory) {
|
|
||||||
if (deleteRecursively(pluginDir)) {
|
|
||||||
needsReload = true
|
|
||||||
} else {
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} catch (e: Exception) {
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Reload plugins if we deleted any disabled duplicates
|
|
||||||
if (needsReload) {
|
|
||||||
PluginRepository.reloadPlugins()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Helper method to get disabled plugin names and their versions
|
|
||||||
private fun getDisabledPluginInfo(): Map<String, String> {
|
|
||||||
val disabledPluginInfo = mutableMapOf<String, String>()
|
|
||||||
val disabledDir = File(pluginsDirectory, "disabled")
|
|
||||||
|
|
||||||
if (disabledDir.exists() && disabledDir.isDirectory) {
|
|
||||||
val disabledPlugins = disabledDir.listFiles { file -> file.isDirectory } ?: arrayOf()
|
|
||||||
|
|
||||||
for (pluginDir in disabledPlugins) {
|
|
||||||
try {
|
|
||||||
val propertiesFile = File(pluginDir, "plugin.properties")
|
|
||||||
if (propertiesFile.exists()) {
|
|
||||||
val content = propertiesFile.readText()
|
|
||||||
val properties = parsePluginProperties(content)
|
|
||||||
disabledPluginInfo[pluginDir.name] = properties.version
|
|
||||||
}
|
|
||||||
} catch (e: Exception) {
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return disabledPluginInfo
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Helper method to add context menu to a panel
|
// Helper method to add context menu to a panel
|
||||||
|
|
@ -1187,37 +833,7 @@ object ReflectiveEditorView : View {
|
||||||
|
|
||||||
// Helper method to delete a plugin
|
// Helper method to delete a plugin
|
||||||
private fun deletePlugin(pluginName: String, isDisabled: Boolean) {
|
private fun deletePlugin(pluginName: String, isDisabled: Boolean) {
|
||||||
try {
|
reflectiveEditorPlugin.deletePlugin(pluginName, isDisabled, mainPanel ?: JPanel())
|
||||||
val pluginDir = if (isDisabled) {
|
|
||||||
File(File(pluginsDirectory, "disabled"), pluginName)
|
|
||||||
} else {
|
|
||||||
File(pluginsDirectory, pluginName)
|
|
||||||
}
|
|
||||||
|
|
||||||
if (pluginDir.exists() && pluginDir.isDirectory) {
|
|
||||||
// Recursively delete the directory
|
|
||||||
if (deleteRecursively(pluginDir)) {
|
|
||||||
showToast(mainPanel, "Plugin deleted successfully", JOptionPane.INFORMATION_MESSAGE)
|
|
||||||
|
|
||||||
// If we deleted a loaded plugin, schedule plugin reload
|
|
||||||
if (!isDisabled) {
|
|
||||||
reloadPlugins = true
|
|
||||||
}
|
|
||||||
|
|
||||||
// Refresh the plugin list view
|
|
||||||
SwingUtilities.invokeLater {
|
|
||||||
addPlugins(reflectiveEditorView!!)
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
showToast(mainPanel, "Failed to delete plugin", JOptionPane.ERROR_MESSAGE)
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
showToast(mainPanel, "Plugin directory not found", JOptionPane.ERROR_MESSAGE)
|
|
||||||
}
|
|
||||||
} catch (e: Exception) {
|
|
||||||
e.printStackTrace()
|
|
||||||
showToast(mainPanel, "Error deleting plugin: ${e.message}", JOptionPane.ERROR_MESSAGE)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Helper method to recursively delete a directory
|
// Helper method to recursively delete a directory
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue