mirror of
https://github.com/packwiz/packwiz-installer.git
synced 2025-11-07 13:04:32 +01:00
Refactor GUI code, remove bad SwingWorker junk
This commit is contained in:
@@ -1,30 +1,29 @@
|
||||
package link.infra.packwiz.installer.ui
|
||||
|
||||
import link.infra.packwiz.installer.ui.data.ExceptionDetails
|
||||
import link.infra.packwiz.installer.ui.data.IOptionDetails
|
||||
import link.infra.packwiz.installer.ui.data.InstallProgress
|
||||
import java.util.concurrent.CompletableFuture
|
||||
import java.util.concurrent.Future
|
||||
import kotlin.system.exitProcess
|
||||
|
||||
interface IUserInterface {
|
||||
fun show(handler: InputStateHandler)
|
||||
fun show()
|
||||
fun dispose()
|
||||
fun handleException(e: Exception)
|
||||
@JvmDefault
|
||||
fun handleExceptionAndExit(e: Exception) {
|
||||
handleException(e)
|
||||
exitProcess(1)
|
||||
}
|
||||
|
||||
@JvmDefault
|
||||
fun setTitle(title: String) {}
|
||||
fun submitProgress(progress: InstallProgress)
|
||||
fun executeManager(task: () -> Unit)
|
||||
// Return true if the installation was cancelled!
|
||||
fun showOptions(options: List<IOptionDetails>): Future<Boolean>
|
||||
|
||||
fun showExceptions(exceptions: List<ExceptionDetails>, numTotal: Int, allowsIgnore: Boolean): Future<ExceptionListResult>
|
||||
@JvmDefault
|
||||
fun disableOptionsButton() {}
|
||||
|
||||
@JvmDefault
|
||||
fun showCancellationDialog(): Future<CancellationResult> {
|
||||
return CompletableFuture<CancellationResult>().apply {
|
||||
complete(CancellationResult.QUIT)
|
||||
@@ -38,4 +37,7 @@ interface IUserInterface {
|
||||
enum class CancellationResult {
|
||||
QUIT, CONTINUE
|
||||
}
|
||||
|
||||
var optionsButtonPressed: Boolean
|
||||
var cancelButtonPressed: Boolean
|
||||
}
|
||||
@@ -1,21 +0,0 @@
|
||||
package link.infra.packwiz.installer.ui
|
||||
|
||||
class InputStateHandler {
|
||||
// TODO: convert to coroutines/locks?
|
||||
@get:Synchronized
|
||||
var optionsButton = false
|
||||
private set
|
||||
@get:Synchronized
|
||||
var cancelButton = false
|
||||
private set
|
||||
|
||||
@Synchronized
|
||||
fun pressCancelButton() {
|
||||
cancelButton = true
|
||||
}
|
||||
|
||||
@Synchronized
|
||||
fun pressOptionsButton() {
|
||||
optionsButton = true
|
||||
}
|
||||
}
|
||||
@@ -1,13 +0,0 @@
|
||||
package link.infra.packwiz.installer.ui
|
||||
|
||||
import javax.swing.SwingWorker
|
||||
|
||||
// Q: AAA WHAT HAVE YOU DONE THIS IS DISGUSTING
|
||||
// A: it just makes things easier, so i can easily have one interface for CLI/GUI
|
||||
// if someone has a better way to do this please PR it
|
||||
abstract class SwingWorkerButWithPublicPublish<T, V> : SwingWorker<T, V>() {
|
||||
@SafeVarargs
|
||||
fun publishPublic(vararg chunks: V) {
|
||||
publish(*chunks)
|
||||
}
|
||||
}
|
||||
@@ -1,16 +1,26 @@
|
||||
package link.infra.packwiz.installer.ui
|
||||
package link.infra.packwiz.installer.ui.cli
|
||||
|
||||
import link.infra.packwiz.installer.ui.IUserInterface
|
||||
import link.infra.packwiz.installer.ui.IUserInterface.ExceptionListResult
|
||||
import link.infra.packwiz.installer.ui.data.ExceptionDetails
|
||||
import link.infra.packwiz.installer.ui.data.IOptionDetails
|
||||
import link.infra.packwiz.installer.ui.data.InstallProgress
|
||||
import java.util.concurrent.CompletableFuture
|
||||
import java.util.concurrent.Future
|
||||
import kotlin.system.exitProcess
|
||||
|
||||
class CLIHandler : IUserInterface {
|
||||
@Volatile
|
||||
override var optionsButtonPressed = false
|
||||
@Volatile
|
||||
override var cancelButtonPressed = false
|
||||
|
||||
override fun handleException(e: Exception) {
|
||||
e.printStackTrace()
|
||||
}
|
||||
|
||||
override fun show(handler: InputStateHandler) {}
|
||||
override fun show() {}
|
||||
override fun dispose() {}
|
||||
override fun submitProgress(progress: InstallProgress) {
|
||||
val sb = StringBuilder()
|
||||
if (progress.hasProgress) {
|
||||
@@ -24,11 +34,6 @@ class CLIHandler : IUserInterface {
|
||||
println(sb.toString())
|
||||
}
|
||||
|
||||
override fun executeManager(task: () -> Unit) {
|
||||
task()
|
||||
println("Finished successfully!")
|
||||
}
|
||||
|
||||
override fun showOptions(options: List<IOptionDetails>): Future<Boolean> {
|
||||
for (opt in options) {
|
||||
opt.optionValue = true
|
||||
@@ -1,4 +1,4 @@
|
||||
package link.infra.packwiz.installer.ui
|
||||
package link.infra.packwiz.installer.ui.data
|
||||
|
||||
data class ExceptionDetails(
|
||||
val name: String,
|
||||
@@ -1,4 +1,4 @@
|
||||
package link.infra.packwiz.installer.ui
|
||||
package link.infra.packwiz.installer.ui.data
|
||||
|
||||
interface IOptionDetails {
|
||||
val name: String
|
||||
@@ -1,4 +1,4 @@
|
||||
package link.infra.packwiz.installer.ui
|
||||
package link.infra.packwiz.installer.ui.data
|
||||
|
||||
data class InstallProgress(
|
||||
val message: String,
|
||||
@@ -1,5 +1,7 @@
|
||||
package link.infra.packwiz.installer.ui
|
||||
package link.infra.packwiz.installer.ui.gui
|
||||
|
||||
import link.infra.packwiz.installer.ui.IUserInterface
|
||||
import link.infra.packwiz.installer.ui.data.ExceptionDetails
|
||||
import java.awt.BorderLayout
|
||||
import java.awt.Desktop
|
||||
import java.awt.event.WindowAdapter
|
||||
@@ -16,7 +18,7 @@ import javax.swing.border.EmptyBorder
|
||||
class ExceptionListWindow(eList: List<ExceptionDetails>, future: CompletableFuture<IUserInterface.ExceptionListResult>, numTotal: Int, allowsIgnore: Boolean, parentWindow: JFrame?) : JDialog(parentWindow, "Failed file downloads", true) {
|
||||
private val lblExceptionStacktrace: JTextArea
|
||||
|
||||
private class ExceptionListModel internal constructor(private val details: List<ExceptionDetails>) : AbstractListModel<String>() {
|
||||
private class ExceptionListModel(private val details: List<ExceptionDetails>) : AbstractListModel<String>() {
|
||||
override fun getSize() = details.size
|
||||
override fun getElementAt(index: Int) = details[index].name
|
||||
fun getExceptionAt(index: Int) = details[index].exception
|
||||
@@ -1,10 +1,13 @@
|
||||
package link.infra.packwiz.installer.ui
|
||||
package link.infra.packwiz.installer.ui.gui
|
||||
|
||||
import link.infra.packwiz.installer.ui.IUserInterface
|
||||
import link.infra.packwiz.installer.ui.IUserInterface.ExceptionListResult
|
||||
import link.infra.packwiz.installer.ui.data.ExceptionDetails
|
||||
import link.infra.packwiz.installer.ui.data.IOptionDetails
|
||||
import link.infra.packwiz.installer.ui.data.InstallProgress
|
||||
import java.awt.*
|
||||
import java.util.concurrent.CompletableFuture
|
||||
import java.util.concurrent.Future
|
||||
import java.util.concurrent.atomic.AtomicBoolean
|
||||
import javax.swing.*
|
||||
import javax.swing.border.EmptyBorder
|
||||
import kotlin.system.exitProcess
|
||||
@@ -15,10 +18,12 @@ class InstallWindow : IUserInterface {
|
||||
private lateinit var progressBar: JProgressBar
|
||||
private lateinit var btnOptions: JButton
|
||||
|
||||
private var inputStateHandler: InputStateHandler? = null
|
||||
@Volatile
|
||||
override var optionsButtonPressed = false
|
||||
@Volatile
|
||||
override var cancelButtonPressed = false
|
||||
|
||||
private var title = "Updating modpack..."
|
||||
private var worker: SwingWorkerButWithPublicPublish<Unit, InstallProgress>? = null
|
||||
private val aboutToCrash = AtomicBoolean()
|
||||
|
||||
// TODO: separate JFrame junk from IUserInterface junk?
|
||||
|
||||
@@ -55,7 +60,7 @@ class InstallWindow : IUserInterface {
|
||||
addActionListener {
|
||||
text = "Loading..."
|
||||
isEnabled = false
|
||||
inputStateHandler?.pressOptionsButton()
|
||||
optionsButtonPressed = true
|
||||
}
|
||||
}
|
||||
add(btnOptions, GridBagConstraints().apply {
|
||||
@@ -66,7 +71,7 @@ class InstallWindow : IUserInterface {
|
||||
add(JButton("Cancel").apply {
|
||||
addActionListener {
|
||||
isEnabled = false
|
||||
inputStateHandler?.pressCancelButton()
|
||||
cancelButtonPressed = true
|
||||
}
|
||||
}, GridBagConstraints().apply {
|
||||
gridx = 0
|
||||
@@ -77,10 +82,10 @@ class InstallWindow : IUserInterface {
|
||||
}
|
||||
}
|
||||
|
||||
override fun show(handler: InputStateHandler) {
|
||||
inputStateHandler = handler
|
||||
override fun show() {
|
||||
EventQueue.invokeLater {
|
||||
try {
|
||||
// TODO: shouldn't we do this before everything else?
|
||||
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName())
|
||||
frmPackwizlauncher.isVisible = true
|
||||
} catch (e: Exception) {
|
||||
@@ -89,9 +94,15 @@ class InstallWindow : IUserInterface {
|
||||
}
|
||||
}
|
||||
|
||||
override fun dispose() {
|
||||
EventQueue.invokeAndWait {
|
||||
frmPackwizlauncher.dispose()
|
||||
}
|
||||
}
|
||||
|
||||
override fun handleException(e: Exception) {
|
||||
e.printStackTrace()
|
||||
EventQueue.invokeLater {
|
||||
EventQueue.invokeAndWait {
|
||||
JOptionPane.showMessageDialog(null,
|
||||
"An error occurred: \n" + e.javaClass.canonicalName + ": " + e.message,
|
||||
title, JOptionPane.ERROR_MESSAGE)
|
||||
@@ -100,27 +111,17 @@ class InstallWindow : IUserInterface {
|
||||
|
||||
override fun handleExceptionAndExit(e: Exception) {
|
||||
e.printStackTrace()
|
||||
// TODO: Fix this mess
|
||||
// Used to prevent the done() handler of SwingWorker executing if the invokeLater hasn't happened yet
|
||||
aboutToCrash.set(true)
|
||||
EventQueue.invokeLater {
|
||||
EventQueue.invokeAndWait {
|
||||
JOptionPane.showMessageDialog(null,
|
||||
"A fatal error occurred: \n" + e.javaClass.canonicalName + ": " + e.message,
|
||||
title, JOptionPane.ERROR_MESSAGE)
|
||||
exitProcess(1)
|
||||
}
|
||||
// Pause forever, so it blocks while we wait for System.exit to take effect
|
||||
try {
|
||||
Thread.currentThread().join()
|
||||
} catch (ex: InterruptedException) { // no u
|
||||
}
|
||||
}
|
||||
|
||||
override fun setTitle(title: String) {
|
||||
this.title = title
|
||||
frmPackwizlauncher.let { frame ->
|
||||
EventQueue.invokeLater { frame.title = title }
|
||||
}
|
||||
EventQueue.invokeLater { frmPackwizlauncher.title = title }
|
||||
}
|
||||
|
||||
override fun submitProgress(progress: InstallProgress) {
|
||||
@@ -135,45 +136,16 @@ class InstallWindow : IUserInterface {
|
||||
sb.append(progress.message)
|
||||
// TODO: better logging library?
|
||||
println(sb.toString())
|
||||
worker?.publishPublic(progress)
|
||||
}
|
||||
|
||||
override fun executeManager(task: Function0<Unit>) {
|
||||
EventQueue.invokeLater {
|
||||
// TODO: rewrite this stupidity to use channels??!!!
|
||||
worker = object : SwingWorkerButWithPublicPublish<Unit, InstallProgress>() {
|
||||
override fun doInBackground() {
|
||||
task.invoke()
|
||||
}
|
||||
|
||||
override fun process(chunks: List<InstallProgress>) {
|
||||
// Only process last chunk
|
||||
if (chunks.isNotEmpty()) {
|
||||
val (message, hasProgress, progress, progressTotal) = chunks[chunks.size - 1]
|
||||
if (hasProgress) {
|
||||
progressBar.isIndeterminate = false
|
||||
progressBar.value = progress
|
||||
progressBar.maximum = progressTotal
|
||||
} else {
|
||||
progressBar.isIndeterminate = true
|
||||
progressBar.value = 0
|
||||
}
|
||||
lblProgresslabel.text = message
|
||||
}
|
||||
}
|
||||
|
||||
override fun done() {
|
||||
if (aboutToCrash.get()) {
|
||||
return
|
||||
}
|
||||
// TODO: a better way to do this?
|
||||
frmPackwizlauncher.dispose()
|
||||
println("Finished successfully!")
|
||||
exitProcess(0)
|
||||
}
|
||||
}.also {
|
||||
it.execute()
|
||||
if (progress.hasProgress) {
|
||||
progressBar.isIndeterminate = false
|
||||
progressBar.value = progress.progress
|
||||
progressBar.maximum = progress.progressTotal
|
||||
} else {
|
||||
progressBar.isIndeterminate = true
|
||||
progressBar.value = 0
|
||||
}
|
||||
lblProgresslabel.text = progress.message
|
||||
}
|
||||
}
|
||||
|
||||
@@ -207,9 +179,11 @@ class InstallWindow : IUserInterface {
|
||||
}
|
||||
|
||||
override fun disableOptionsButton() {
|
||||
btnOptions.apply {
|
||||
text = "No optional mods"
|
||||
isEnabled = false
|
||||
EventQueue.invokeLater {
|
||||
btnOptions.apply {
|
||||
text = "No optional mods"
|
||||
isEnabled = false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
package link.infra.packwiz.installer.ui
|
||||
package link.infra.packwiz.installer.ui.gui
|
||||
|
||||
import link.infra.packwiz.installer.ui.data.IOptionDetails
|
||||
|
||||
// Serves as a proxy for IOptionDetails, so that setOptionValue isn't called until OK is clicked
|
||||
internal class OptionTempHandler(private val opt: IOptionDetails) : IOptionDetails {
|
||||
@@ -1,5 +1,6 @@
|
||||
package link.infra.packwiz.installer.ui
|
||||
package link.infra.packwiz.installer.ui.gui
|
||||
|
||||
import link.infra.packwiz.installer.ui.data.IOptionDetails
|
||||
import java.awt.BorderLayout
|
||||
import java.awt.FlowLayout
|
||||
import java.awt.event.ActionEvent
|
||||
@@ -18,7 +19,7 @@ class OptionsSelectWindow internal constructor(optList: List<IOptionDetails>, fu
|
||||
private val tableModel: OptionTableModel
|
||||
private val future: CompletableFuture<Boolean>
|
||||
|
||||
private class OptionTableModel internal constructor(givenOpts: List<IOptionDetails>) : TableModel {
|
||||
private class OptionTableModel(givenOpts: List<IOptionDetails>) : TableModel {
|
||||
private val opts: List<OptionTempHandler>
|
||||
|
||||
init {
|
||||
Reference in New Issue
Block a user