Refactor GUI code, remove bad SwingWorker junk

This commit is contained in:
comp500 2020-12-13 16:12:44 +00:00
parent f52cd19ad4
commit f5b22f37a4
16 changed files with 94 additions and 149 deletions

View File

@ -6,8 +6,8 @@ import link.infra.packwiz.installer.metadata.SpaceSafeURI
import link.infra.packwiz.installer.metadata.hash.Hash import link.infra.packwiz.installer.metadata.hash.Hash
import link.infra.packwiz.installer.metadata.hash.HashUtils.getHash import link.infra.packwiz.installer.metadata.hash.HashUtils.getHash
import link.infra.packwiz.installer.metadata.hash.HashUtils.getHasher import link.infra.packwiz.installer.metadata.hash.HashUtils.getHasher
import link.infra.packwiz.installer.ui.ExceptionDetails import link.infra.packwiz.installer.ui.data.ExceptionDetails
import link.infra.packwiz.installer.ui.IOptionDetails import link.infra.packwiz.installer.ui.data.IOptionDetails
import okio.Buffer import okio.Buffer
import okio.HashingSink import okio.HashingSink
import okio.buffer import okio.buffer

View File

@ -3,9 +3,8 @@
package link.infra.packwiz.installer package link.infra.packwiz.installer
import link.infra.packwiz.installer.metadata.SpaceSafeURI import link.infra.packwiz.installer.metadata.SpaceSafeURI
import link.infra.packwiz.installer.ui.CLIHandler import link.infra.packwiz.installer.ui.cli.CLIHandler
import link.infra.packwiz.installer.ui.InputStateHandler import link.infra.packwiz.installer.ui.gui.InstallWindow
import link.infra.packwiz.installer.ui.InstallWindow
import org.apache.commons.cli.DefaultParser import org.apache.commons.cli.DefaultParser
import org.apache.commons.cli.Options import org.apache.commons.cli.Options
import org.apache.commons.cli.ParseException import org.apache.commons.cli.ParseException
@ -19,7 +18,7 @@ import kotlin.system.exitProcess
@Suppress("unused") @Suppress("unused")
class Main(args: Array<String>) { class Main(args: Array<String>) {
// Don't attempt to start a GUI if we are headless // Don't attempt to start a GUI if we are headless
var guiEnabled = !GraphicsEnvironment.isHeadless() private var guiEnabled = !GraphicsEnvironment.isHeadless()
private fun startup(args: Array<String>) { private fun startup(args: Array<String>) {
val options = Options() val options = Options()
@ -59,8 +58,7 @@ class Main(args: Array<String>) {
cmd.getOptionValue("title")?.also(ui::setTitle) cmd.getOptionValue("title")?.also(ui::setTitle)
val inputStateHandler = InputStateHandler() ui.show()
ui.show(inputStateHandler)
val uOptions = UpdateManager.Options().apply { val uOptions = UpdateManager.Options().apply {
side = cmd.getOptionValue("side")?.let((UpdateManager.Options.Side)::from) ?: side side = cmd.getOptionValue("side")?.let((UpdateManager.Options.Side)::from) ?: side
@ -76,18 +74,13 @@ class Main(args: Array<String>) {
} }
// Start update process! // Start update process!
// TODO: start in SwingWorker?
try { try {
ui.executeManager { UpdateManager(uOptions, ui)
try {
UpdateManager(uOptions, ui, inputStateHandler)
} catch (e: Exception) { // TODO: better error message?
ui.handleExceptionAndExit(e)
}
}
} catch (e: Exception) { // TODO: better error message? } catch (e: Exception) { // TODO: better error message?
ui.handleExceptionAndExit(e) ui.handleExceptionAndExit(e)
} }
println("Finished successfully!")
ui.dispose()
} }
companion object { companion object {

View File

@ -18,8 +18,7 @@ import link.infra.packwiz.installer.request.HandlerManager.getNewLoc
import link.infra.packwiz.installer.ui.IUserInterface import link.infra.packwiz.installer.ui.IUserInterface
import link.infra.packwiz.installer.ui.IUserInterface.CancellationResult import link.infra.packwiz.installer.ui.IUserInterface.CancellationResult
import link.infra.packwiz.installer.ui.IUserInterface.ExceptionListResult import link.infra.packwiz.installer.ui.IUserInterface.ExceptionListResult
import link.infra.packwiz.installer.ui.InputStateHandler import link.infra.packwiz.installer.ui.data.InstallProgress
import link.infra.packwiz.installer.ui.InstallProgress
import okio.buffer import okio.buffer
import java.io.FileNotFoundException import java.io.FileNotFoundException
import java.io.FileReader import java.io.FileReader
@ -34,7 +33,7 @@ import java.util.concurrent.ExecutorCompletionService
import java.util.concurrent.Executors import java.util.concurrent.Executors
import kotlin.system.exitProcess import kotlin.system.exitProcess
class UpdateManager internal constructor(private val opts: Options, val ui: IUserInterface, private val stateHandler: InputStateHandler) { class UpdateManager internal constructor(private val opts: Options, val ui: IUserInterface) {
private var cancelled = false private var cancelled = false
private var cancelledStartGame = false private var cancelledStartGame = false
private var errorsOccurred = false private var errorsOccurred = false
@ -119,7 +118,7 @@ class UpdateManager internal constructor(private val opts: Options, val ui: IUse
return return
} }
if (stateHandler.cancelButton) { if (ui.cancelButtonPressed) {
showCancellationDialog() showCancellationDialog()
handleCancellation() handleCancellation()
} }
@ -142,7 +141,7 @@ class UpdateManager internal constructor(private val opts: Options, val ui: IUse
} }
} }
if (stateHandler.cancelButton) { if (ui.cancelButtonPressed) {
showCancellationDialog() showCancellationDialog()
handleCancellation() handleCancellation()
} }
@ -178,14 +177,14 @@ class UpdateManager internal constructor(private val opts: Options, val ui: IUse
if (manifest.packFileHash?.let { packFileSource.hashIsEqual(it) } == true && invalidatedUris.isEmpty()) { if (manifest.packFileHash?.let { packFileSource.hashIsEqual(it) } == true && invalidatedUris.isEmpty()) {
println("Modpack is already up to date!") println("Modpack is already up to date!")
// todo: --force? // todo: --force?
if (!stateHandler.optionsButton) { if (!ui.optionsButtonPressed) {
return return
} }
} }
println("Modpack name: " + pf.name) println("Modpack name: " + pf.name)
if (stateHandler.cancelButton) { if (ui.cancelButtonPressed) {
showCancellationDialog() showCancellationDialog()
handleCancellation() handleCancellation()
} }
@ -234,7 +233,7 @@ class UpdateManager internal constructor(private val opts: Options, val ui: IUse
private fun processIndex(indexUri: SpaceSafeURI, indexHash: Hash, hashFormat: String, manifest: ManifestFile, invalidatedUris: List<SpaceSafeURI>) { private fun processIndex(indexUri: SpaceSafeURI, indexHash: Hash, hashFormat: String, manifest: ManifestFile, invalidatedUris: List<SpaceSafeURI>) {
if (manifest.indexFileHash == indexHash && invalidatedUris.isEmpty()) { if (manifest.indexFileHash == indexHash && invalidatedUris.isEmpty()) {
println("Modpack files are already up to date!") println("Modpack files are already up to date!")
if (!stateHandler.optionsButton) { if (!ui.optionsButtonPressed) {
return return
} }
} }
@ -258,7 +257,7 @@ class UpdateManager internal constructor(private val opts: Options, val ui: IUse
ui.handleExceptionAndExit(RuntimeException("Your index hash is invalid! Please run packwiz refresh on the pack again")) ui.handleExceptionAndExit(RuntimeException("Your index hash is invalid! Please run packwiz refresh on the pack again"))
return return
} }
if (stateHandler.cancelButton) { if (ui.cancelButtonPressed) {
showCancellationDialog() showCancellationDialog()
return return
} }
@ -295,7 +294,7 @@ class UpdateManager internal constructor(private val opts: Options, val ui: IUse
} }
} }
if (stateHandler.cancelButton) { if (ui.cancelButtonPressed) {
showCancellationDialog() showCancellationDialog()
return return
} }
@ -326,7 +325,7 @@ class UpdateManager internal constructor(private val opts: Options, val ui: IUse
f.updateFromCache(file) f.updateFromCache(file)
} }
if (stateHandler.cancelButton) { if (ui.cancelButtonPressed) {
showCancellationDialog() showCancellationDialog()
return return
} }
@ -360,7 +359,7 @@ class UpdateManager internal constructor(private val opts: Options, val ui: IUse
} }
} }
if (stateHandler.cancelButton) { if (ui.cancelButtonPressed) {
showCancellationDialog() showCancellationDialog()
return return
} }
@ -369,7 +368,7 @@ class UpdateManager internal constructor(private val opts: Options, val ui: IUse
val nonFailedFirstTasks = tasks.filter { t -> !t.failed() }.toList() val nonFailedFirstTasks = tasks.filter { t -> !t.failed() }.toList()
val optionTasks = nonFailedFirstTasks.filter(DownloadTask::correctSide).filter(DownloadTask::isOptional).toList() val optionTasks = nonFailedFirstTasks.filter(DownloadTask::correctSide).filter(DownloadTask::isOptional).toList()
// If options changed, present all options again // If options changed, present all options again
if (stateHandler.optionsButton || optionTasks.any(DownloadTask::isNewOptional)) { if (ui.optionsButtonPressed || optionTasks.any(DownloadTask::isNewOptional)) {
// new ArrayList is required so it's an IOptionDetails rather than a DownloadTask list // new ArrayList is required so it's an IOptionDetails rather than a DownloadTask list
val cancelledResult = ui.showOptions(ArrayList(optionTasks)) val cancelledResult = ui.showOptions(ArrayList(optionTasks))
try { try {
@ -433,7 +432,7 @@ class UpdateManager internal constructor(private val opts: Options, val ui: IUse
} }
ui.submitProgress(InstallProgress(progress, i + 1, tasks.size)) ui.submitProgress(InstallProgress(progress, i + 1, tasks.size))
if (stateHandler.cancelButton) { // Stop all tasks, don't launch the game (it's in an invalid state!) if (ui.cancelButtonPressed) { // Stop all tasks, don't launch the game (it's in an invalid state!)
threadPool.shutdown() threadPool.shutdown()
cancelled = true cancelled = true
return return
@ -483,6 +482,7 @@ class UpdateManager internal constructor(private val opts: Options, val ui: IUse
} }
} }
// TODO: move to UI?
private fun handleCancellation() { private fun handleCancellation() {
if (cancelled) { if (cancelled) {
println("Update cancelled by user!") println("Update cancelled by user!")

View File

@ -5,7 +5,7 @@ import okio.Source
class HashingSourceHasher internal constructor(private val type: String) : IHasher { class HashingSourceHasher internal constructor(private val type: String) : IHasher {
// i love naming things // i love naming things
private inner class HashingSourceGeneralHashingSource internal constructor(val delegateHashing: HashingSource) : GeneralHashingSource(delegateHashing) { private inner class HashingSourceGeneralHashingSource(val delegateHashing: HashingSource) : GeneralHashingSource(delegateHashing) {
override val hash: Hash by lazy(LazyThreadSafetyMode.NONE) { override val hash: Hash by lazy(LazyThreadSafetyMode.NONE) {
HashingSourceHash(delegateHashing.hash.hex()) HashingSourceHash(delegateHashing.hash.hex())
} }

View File

@ -25,7 +25,7 @@ abstract class RequestHandlerZip(private val modeHasFolder: Boolean) : RequestHa
} }
} }
private inner class ZipReader internal constructor(zip: Source) { private inner class ZipReader(zip: Source) {
private val zis = ZipInputStream(zip.buffer().inputStream()) private val zis = ZipInputStream(zip.buffer().inputStream())
private val readFiles: MutableMap<SpaceSafeURI, Buffer> = HashMap() private val readFiles: MutableMap<SpaceSafeURI, Buffer> = HashMap()
// Write lock implies access to ZipInputStream - only 1 thread must read at a time! // Write lock implies access to ZipInputStream - only 1 thread must read at a time!

View File

@ -1,30 +1,29 @@
package link.infra.packwiz.installer.ui 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.CompletableFuture
import java.util.concurrent.Future import java.util.concurrent.Future
import kotlin.system.exitProcess import kotlin.system.exitProcess
interface IUserInterface { interface IUserInterface {
fun show(handler: InputStateHandler) fun show()
fun dispose()
fun handleException(e: Exception) fun handleException(e: Exception)
@JvmDefault
fun handleExceptionAndExit(e: Exception) { fun handleExceptionAndExit(e: Exception) {
handleException(e) handleException(e)
exitProcess(1) exitProcess(1)
} }
@JvmDefault
fun setTitle(title: String) {} fun setTitle(title: String) {}
fun submitProgress(progress: InstallProgress) fun submitProgress(progress: InstallProgress)
fun executeManager(task: () -> Unit)
// Return true if the installation was cancelled! // Return true if the installation was cancelled!
fun showOptions(options: List<IOptionDetails>): Future<Boolean> fun showOptions(options: List<IOptionDetails>): Future<Boolean>
fun showExceptions(exceptions: List<ExceptionDetails>, numTotal: Int, allowsIgnore: Boolean): Future<ExceptionListResult> fun showExceptions(exceptions: List<ExceptionDetails>, numTotal: Int, allowsIgnore: Boolean): Future<ExceptionListResult>
@JvmDefault
fun disableOptionsButton() {} fun disableOptionsButton() {}
@JvmDefault
fun showCancellationDialog(): Future<CancellationResult> { fun showCancellationDialog(): Future<CancellationResult> {
return CompletableFuture<CancellationResult>().apply { return CompletableFuture<CancellationResult>().apply {
complete(CancellationResult.QUIT) complete(CancellationResult.QUIT)
@ -38,4 +37,7 @@ interface IUserInterface {
enum class CancellationResult { enum class CancellationResult {
QUIT, CONTINUE QUIT, CONTINUE
} }
var optionsButtonPressed: Boolean
var cancelButtonPressed: Boolean
} }

View File

@ -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
}
}

View File

@ -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)
}
}

View File

@ -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.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.CompletableFuture
import java.util.concurrent.Future import java.util.concurrent.Future
import kotlin.system.exitProcess import kotlin.system.exitProcess
class CLIHandler : IUserInterface { class CLIHandler : IUserInterface {
@Volatile
override var optionsButtonPressed = false
@Volatile
override var cancelButtonPressed = false
override fun handleException(e: Exception) { override fun handleException(e: Exception) {
e.printStackTrace() e.printStackTrace()
} }
override fun show(handler: InputStateHandler) {} override fun show() {}
override fun dispose() {}
override fun submitProgress(progress: InstallProgress) { override fun submitProgress(progress: InstallProgress) {
val sb = StringBuilder() val sb = StringBuilder()
if (progress.hasProgress) { if (progress.hasProgress) {
@ -24,11 +34,6 @@ class CLIHandler : IUserInterface {
println(sb.toString()) println(sb.toString())
} }
override fun executeManager(task: () -> Unit) {
task()
println("Finished successfully!")
}
override fun showOptions(options: List<IOptionDetails>): Future<Boolean> { override fun showOptions(options: List<IOptionDetails>): Future<Boolean> {
for (opt in options) { for (opt in options) {
opt.optionValue = true opt.optionValue = true

View File

@ -1,4 +1,4 @@
package link.infra.packwiz.installer.ui package link.infra.packwiz.installer.ui.data
data class ExceptionDetails( data class ExceptionDetails(
val name: String, val name: String,

View File

@ -1,4 +1,4 @@
package link.infra.packwiz.installer.ui package link.infra.packwiz.installer.ui.data
interface IOptionDetails { interface IOptionDetails {
val name: String val name: String

View File

@ -1,4 +1,4 @@
package link.infra.packwiz.installer.ui package link.infra.packwiz.installer.ui.data
data class InstallProgress( data class InstallProgress(
val message: String, val message: String,

View File

@ -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.BorderLayout
import java.awt.Desktop import java.awt.Desktop
import java.awt.event.WindowAdapter 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) { 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 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 getSize() = details.size
override fun getElementAt(index: Int) = details[index].name override fun getElementAt(index: Int) = details[index].name
fun getExceptionAt(index: Int) = details[index].exception fun getExceptionAt(index: Int) = details[index].exception

View File

@ -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.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.awt.*
import java.util.concurrent.CompletableFuture import java.util.concurrent.CompletableFuture
import java.util.concurrent.Future import java.util.concurrent.Future
import java.util.concurrent.atomic.AtomicBoolean
import javax.swing.* import javax.swing.*
import javax.swing.border.EmptyBorder import javax.swing.border.EmptyBorder
import kotlin.system.exitProcess import kotlin.system.exitProcess
@ -15,10 +18,12 @@ class InstallWindow : IUserInterface {
private lateinit var progressBar: JProgressBar private lateinit var progressBar: JProgressBar
private lateinit var btnOptions: JButton 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 title = "Updating modpack..."
private var worker: SwingWorkerButWithPublicPublish<Unit, InstallProgress>? = null
private val aboutToCrash = AtomicBoolean()
// TODO: separate JFrame junk from IUserInterface junk? // TODO: separate JFrame junk from IUserInterface junk?
@ -55,7 +60,7 @@ class InstallWindow : IUserInterface {
addActionListener { addActionListener {
text = "Loading..." text = "Loading..."
isEnabled = false isEnabled = false
inputStateHandler?.pressOptionsButton() optionsButtonPressed = true
} }
} }
add(btnOptions, GridBagConstraints().apply { add(btnOptions, GridBagConstraints().apply {
@ -66,7 +71,7 @@ class InstallWindow : IUserInterface {
add(JButton("Cancel").apply { add(JButton("Cancel").apply {
addActionListener { addActionListener {
isEnabled = false isEnabled = false
inputStateHandler?.pressCancelButton() cancelButtonPressed = true
} }
}, GridBagConstraints().apply { }, GridBagConstraints().apply {
gridx = 0 gridx = 0
@ -77,10 +82,10 @@ class InstallWindow : IUserInterface {
} }
} }
override fun show(handler: InputStateHandler) { override fun show() {
inputStateHandler = handler
EventQueue.invokeLater { EventQueue.invokeLater {
try { try {
// TODO: shouldn't we do this before everything else?
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName()) UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName())
frmPackwizlauncher.isVisible = true frmPackwizlauncher.isVisible = true
} catch (e: Exception) { } catch (e: Exception) {
@ -89,9 +94,15 @@ class InstallWindow : IUserInterface {
} }
} }
override fun dispose() {
EventQueue.invokeAndWait {
frmPackwizlauncher.dispose()
}
}
override fun handleException(e: Exception) { override fun handleException(e: Exception) {
e.printStackTrace() e.printStackTrace()
EventQueue.invokeLater { EventQueue.invokeAndWait {
JOptionPane.showMessageDialog(null, JOptionPane.showMessageDialog(null,
"An error occurred: \n" + e.javaClass.canonicalName + ": " + e.message, "An error occurred: \n" + e.javaClass.canonicalName + ": " + e.message,
title, JOptionPane.ERROR_MESSAGE) title, JOptionPane.ERROR_MESSAGE)
@ -100,27 +111,17 @@ class InstallWindow : IUserInterface {
override fun handleExceptionAndExit(e: Exception) { override fun handleExceptionAndExit(e: Exception) {
e.printStackTrace() e.printStackTrace()
// TODO: Fix this mess EventQueue.invokeAndWait {
// Used to prevent the done() handler of SwingWorker executing if the invokeLater hasn't happened yet
aboutToCrash.set(true)
EventQueue.invokeLater {
JOptionPane.showMessageDialog(null, JOptionPane.showMessageDialog(null,
"A fatal error occurred: \n" + e.javaClass.canonicalName + ": " + e.message, "A fatal error occurred: \n" + e.javaClass.canonicalName + ": " + e.message,
title, JOptionPane.ERROR_MESSAGE) title, JOptionPane.ERROR_MESSAGE)
exitProcess(1) 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) { override fun setTitle(title: String) {
this.title = title this.title = title
frmPackwizlauncher.let { frame -> EventQueue.invokeLater { frmPackwizlauncher.title = title }
EventQueue.invokeLater { frame.title = title }
}
} }
override fun submitProgress(progress: InstallProgress) { override fun submitProgress(progress: InstallProgress) {
@ -135,45 +136,16 @@ class InstallWindow : IUserInterface {
sb.append(progress.message) sb.append(progress.message)
// TODO: better logging library? // TODO: better logging library?
println(sb.toString()) println(sb.toString())
worker?.publishPublic(progress)
}
override fun executeManager(task: Function0<Unit>) {
EventQueue.invokeLater { EventQueue.invokeLater {
// TODO: rewrite this stupidity to use channels??!!! if (progress.hasProgress) {
worker = object : SwingWorkerButWithPublicPublish<Unit, InstallProgress>() { progressBar.isIndeterminate = false
override fun doInBackground() { progressBar.value = progress.progress
task.invoke() progressBar.maximum = progress.progressTotal
} } else {
progressBar.isIndeterminate = true
override fun process(chunks: List<InstallProgress>) { progressBar.value = 0
// 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()
} }
lblProgresslabel.text = progress.message
} }
} }
@ -207,9 +179,11 @@ class InstallWindow : IUserInterface {
} }
override fun disableOptionsButton() { override fun disableOptionsButton() {
btnOptions.apply { EventQueue.invokeLater {
text = "No optional mods" btnOptions.apply {
isEnabled = false text = "No optional mods"
isEnabled = false
}
} }
} }

View File

@ -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 // Serves as a proxy for IOptionDetails, so that setOptionValue isn't called until OK is clicked
internal class OptionTempHandler(private val opt: IOptionDetails) : IOptionDetails { internal class OptionTempHandler(private val opt: IOptionDetails) : IOptionDetails {

View File

@ -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.BorderLayout
import java.awt.FlowLayout import java.awt.FlowLayout
import java.awt.event.ActionEvent import java.awt.event.ActionEvent
@ -18,7 +19,7 @@ class OptionsSelectWindow internal constructor(optList: List<IOptionDetails>, fu
private val tableModel: OptionTableModel private val tableModel: OptionTableModel
private val future: CompletableFuture<Boolean> 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> private val opts: List<OptionTempHandler>
init { init {