mirror of
				https://github.com/packwiz/packwiz-installer.git
				synced 2025-11-04 12:34:31 +01:00 
			
		
		
		
	Separate IUserInterface logic out into GUIHandler
This commit is contained in:
		@@ -4,7 +4,7 @@ package link.infra.packwiz.installer
 | 
			
		||||
 | 
			
		||||
import link.infra.packwiz.installer.metadata.SpaceSafeURI
 | 
			
		||||
import link.infra.packwiz.installer.ui.cli.CLIHandler
 | 
			
		||||
import link.infra.packwiz.installer.ui.gui.InstallWindow
 | 
			
		||||
import link.infra.packwiz.installer.ui.gui.GUIHandler
 | 
			
		||||
import org.apache.commons.cli.DefaultParser
 | 
			
		||||
import org.apache.commons.cli.Options
 | 
			
		||||
import org.apache.commons.cli.ParseException
 | 
			
		||||
@@ -47,7 +47,7 @@ class Main(args: Array<String>) {
 | 
			
		||||
			guiEnabled = false
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		val ui = if (guiEnabled) InstallWindow() else CLIHandler()
 | 
			
		||||
		val ui = if (guiEnabled) GUIHandler() else CLIHandler()
 | 
			
		||||
 | 
			
		||||
		val unparsedArgs = cmd.args
 | 
			
		||||
		if (unparsedArgs.size > 1) {
 | 
			
		||||
 
 | 
			
		||||
@@ -0,0 +1,134 @@
 | 
			
		||||
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.EventQueue
 | 
			
		||||
import java.util.concurrent.CompletableFuture
 | 
			
		||||
import java.util.concurrent.Future
 | 
			
		||||
import javax.swing.JDialog
 | 
			
		||||
import javax.swing.JOptionPane
 | 
			
		||||
import javax.swing.UIManager
 | 
			
		||||
import kotlin.system.exitProcess
 | 
			
		||||
 | 
			
		||||
class GUIHandler : IUserInterface {
 | 
			
		||||
	private lateinit var frmPackwizlauncher: InstallWindow
 | 
			
		||||
 | 
			
		||||
	@Volatile
 | 
			
		||||
	override var optionsButtonPressed = false
 | 
			
		||||
	@Volatile
 | 
			
		||||
	override var cancelButtonPressed = false
 | 
			
		||||
 | 
			
		||||
	private var title = "Updating modpack..."
 | 
			
		||||
 | 
			
		||||
	init {
 | 
			
		||||
		EventQueue.invokeAndWait {
 | 
			
		||||
			try {
 | 
			
		||||
				UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName())
 | 
			
		||||
			} catch (e: Exception) {
 | 
			
		||||
				println("Failed to set look and feel:")
 | 
			
		||||
				e.printStackTrace()
 | 
			
		||||
			}
 | 
			
		||||
			frmPackwizlauncher = InstallWindow(this).apply {
 | 
			
		||||
				title = this@GUIHandler.title
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	override fun show() = EventQueue.invokeLater {
 | 
			
		||||
		frmPackwizlauncher.isVisible = true
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	override fun dispose() = EventQueue.invokeAndWait {
 | 
			
		||||
		frmPackwizlauncher.dispose()
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	override fun handleException(e: Exception) {
 | 
			
		||||
		e.printStackTrace()
 | 
			
		||||
		EventQueue.invokeAndWait {
 | 
			
		||||
			JOptionPane.showMessageDialog(null,
 | 
			
		||||
					"An error occurred: \n" + e.javaClass.canonicalName + ": " + e.message,
 | 
			
		||||
					title, JOptionPane.ERROR_MESSAGE)
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	override fun handleExceptionAndExit(e: Exception) {
 | 
			
		||||
		e.printStackTrace()
 | 
			
		||||
		EventQueue.invokeAndWait {
 | 
			
		||||
			JOptionPane.showMessageDialog(null,
 | 
			
		||||
					"A fatal error occurred: \n" + e.javaClass.canonicalName + ": " + e.message,
 | 
			
		||||
					title, JOptionPane.ERROR_MESSAGE)
 | 
			
		||||
			exitProcess(1)
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	override fun setTitle(title: String) {
 | 
			
		||||
		this.title = title
 | 
			
		||||
		EventQueue.invokeLater { frmPackwizlauncher.title = title }
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	override fun submitProgress(progress: InstallProgress) {
 | 
			
		||||
		val sb = StringBuilder()
 | 
			
		||||
		if (progress.hasProgress) {
 | 
			
		||||
			sb.append('(')
 | 
			
		||||
			sb.append(progress.progress)
 | 
			
		||||
			sb.append('/')
 | 
			
		||||
			sb.append(progress.progressTotal)
 | 
			
		||||
			sb.append(") ")
 | 
			
		||||
		}
 | 
			
		||||
		sb.append(progress.message)
 | 
			
		||||
		// TODO: better logging library?
 | 
			
		||||
		println(sb.toString())
 | 
			
		||||
		EventQueue.invokeLater {
 | 
			
		||||
			frmPackwizlauncher.displayProgress(progress)
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	override fun showOptions(options: List<IOptionDetails>): Future<Boolean> {
 | 
			
		||||
		val future = CompletableFuture<Boolean>()
 | 
			
		||||
		EventQueue.invokeLater {
 | 
			
		||||
			if (options.isEmpty()) {
 | 
			
		||||
				JOptionPane.showMessageDialog(null,
 | 
			
		||||
					"This modpack has no optional mods!",
 | 
			
		||||
					"Optional mods", JOptionPane.INFORMATION_MESSAGE)
 | 
			
		||||
				future.complete(false)
 | 
			
		||||
			} else {
 | 
			
		||||
				OptionsSelectWindow(options, future, frmPackwizlauncher).apply {
 | 
			
		||||
					defaultCloseOperation = JDialog.DISPOSE_ON_CLOSE
 | 
			
		||||
					isVisible = true
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
		return future
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	override fun showExceptions(exceptions: List<ExceptionDetails>, numTotal: Int, allowsIgnore: Boolean): Future<ExceptionListResult> {
 | 
			
		||||
		val future = CompletableFuture<ExceptionListResult>()
 | 
			
		||||
		EventQueue.invokeLater {
 | 
			
		||||
			ExceptionListWindow(exceptions, future, numTotal, allowsIgnore, frmPackwizlauncher).apply {
 | 
			
		||||
				defaultCloseOperation = JDialog.DISPOSE_ON_CLOSE
 | 
			
		||||
				isVisible = true
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
		return future
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	override fun disableOptionsButton() = EventQueue.invokeLater {
 | 
			
		||||
		frmPackwizlauncher.disableOptionsButton()
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	override fun showCancellationDialog(): Future<IUserInterface.CancellationResult> {
 | 
			
		||||
		val future = CompletableFuture<IUserInterface.CancellationResult>()
 | 
			
		||||
		EventQueue.invokeLater {
 | 
			
		||||
			val buttons = arrayOf("Quit", "Ignore")
 | 
			
		||||
			val result = JOptionPane.showOptionDialog(frmPackwizlauncher,
 | 
			
		||||
					"The installation was cancelled. Would you like to quit the game, or ignore the update and start the game?",
 | 
			
		||||
					"Cancelled installation",
 | 
			
		||||
					JOptionPane.YES_NO_OPTION, JOptionPane.QUESTION_MESSAGE, null, buttons, buttons[0])
 | 
			
		||||
			future.complete(if (result == 0) IUserInterface.CancellationResult.QUIT else IUserInterface.CancellationResult.CONTINUE)
 | 
			
		||||
		}
 | 
			
		||||
		return future
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
@@ -1,202 +1,84 @@
 | 
			
		||||
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.awt.BorderLayout
 | 
			
		||||
import java.awt.Component
 | 
			
		||||
import java.awt.GridBagConstraints
 | 
			
		||||
import java.awt.GridBagLayout
 | 
			
		||||
import javax.swing.*
 | 
			
		||||
import javax.swing.border.EmptyBorder
 | 
			
		||||
import kotlin.system.exitProcess
 | 
			
		||||
 | 
			
		||||
class InstallWindow : IUserInterface {
 | 
			
		||||
	private lateinit var frmPackwizlauncher: JFrame
 | 
			
		||||
	private lateinit var lblProgresslabel: JLabel
 | 
			
		||||
	private lateinit var progressBar: JProgressBar
 | 
			
		||||
	private lateinit var btnOptions: JButton
 | 
			
		||||
 | 
			
		||||
	@Volatile
 | 
			
		||||
	override var optionsButtonPressed = false
 | 
			
		||||
	@Volatile
 | 
			
		||||
	override var cancelButtonPressed = false
 | 
			
		||||
 | 
			
		||||
	private var title = "Updating modpack..."
 | 
			
		||||
 | 
			
		||||
	// TODO: separate JFrame junk from IUserInterface junk?
 | 
			
		||||
class InstallWindow(private val handler: GUIHandler) : JFrame() {
 | 
			
		||||
	private var lblProgresslabel: JLabel
 | 
			
		||||
	private var progressBar: JProgressBar
 | 
			
		||||
	private var btnOptions: JButton
 | 
			
		||||
 | 
			
		||||
	init {
 | 
			
		||||
		EventQueue.invokeAndWait {
 | 
			
		||||
			frmPackwizlauncher = JFrame().apply {
 | 
			
		||||
				title = this@InstallWindow.title
 | 
			
		||||
				setBounds(100, 100, 493, 95)
 | 
			
		||||
				defaultCloseOperation = JFrame.EXIT_ON_CLOSE
 | 
			
		||||
				setLocationRelativeTo(null)
 | 
			
		||||
		setBounds(100, 100, 493, 95)
 | 
			
		||||
		defaultCloseOperation = EXIT_ON_CLOSE
 | 
			
		||||
		setLocationRelativeTo(null)
 | 
			
		||||
 | 
			
		||||
				// Progress bar and loading text
 | 
			
		||||
				add(JPanel().apply {
 | 
			
		||||
					border = EmptyBorder(10, 10, 10, 10)
 | 
			
		||||
					layout = BorderLayout(0, 0)
 | 
			
		||||
		// Progress bar and loading text
 | 
			
		||||
		add(JPanel().apply {
 | 
			
		||||
			border = EmptyBorder(10, 10, 10, 10)
 | 
			
		||||
			layout = BorderLayout(0, 0)
 | 
			
		||||
 | 
			
		||||
					progressBar = JProgressBar().apply {
 | 
			
		||||
						isIndeterminate = true
 | 
			
		||||
					}
 | 
			
		||||
					add(progressBar, BorderLayout.CENTER)
 | 
			
		||||
 | 
			
		||||
					lblProgresslabel = JLabel("Loading...")
 | 
			
		||||
					add(lblProgresslabel, BorderLayout.SOUTH)
 | 
			
		||||
				}, BorderLayout.CENTER)
 | 
			
		||||
 | 
			
		||||
				// Buttons
 | 
			
		||||
				add(JPanel().apply {
 | 
			
		||||
					border = EmptyBorder(0, 5, 0, 5)
 | 
			
		||||
					layout = GridBagLayout()
 | 
			
		||||
 | 
			
		||||
					btnOptions = JButton("Optional mods...").apply {
 | 
			
		||||
						alignmentX = Component.CENTER_ALIGNMENT
 | 
			
		||||
 | 
			
		||||
						addActionListener {
 | 
			
		||||
							text = "Loading..."
 | 
			
		||||
							isEnabled = false
 | 
			
		||||
							optionsButtonPressed = true
 | 
			
		||||
						}
 | 
			
		||||
					}
 | 
			
		||||
					add(btnOptions, GridBagConstraints().apply {
 | 
			
		||||
						gridx = 0
 | 
			
		||||
						gridy = 0
 | 
			
		||||
					})
 | 
			
		||||
 | 
			
		||||
					add(JButton("Cancel").apply {
 | 
			
		||||
						addActionListener {
 | 
			
		||||
							isEnabled = false
 | 
			
		||||
							cancelButtonPressed = true
 | 
			
		||||
						}
 | 
			
		||||
					}, GridBagConstraints().apply {
 | 
			
		||||
						gridx = 0
 | 
			
		||||
						gridy = 1
 | 
			
		||||
					})
 | 
			
		||||
				}, BorderLayout.EAST)
 | 
			
		||||
			progressBar = JProgressBar().apply {
 | 
			
		||||
				isIndeterminate = true
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
			add(progressBar, BorderLayout.CENTER)
 | 
			
		||||
 | 
			
		||||
	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) {
 | 
			
		||||
				e.printStackTrace()
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
			lblProgresslabel = JLabel("Loading...")
 | 
			
		||||
			add(lblProgresslabel, BorderLayout.SOUTH)
 | 
			
		||||
		}, BorderLayout.CENTER)
 | 
			
		||||
 | 
			
		||||
	override fun dispose() {
 | 
			
		||||
		EventQueue.invokeAndWait {
 | 
			
		||||
			frmPackwizlauncher.dispose()
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
		// Buttons
 | 
			
		||||
		add(JPanel().apply {
 | 
			
		||||
			border = EmptyBorder(0, 5, 0, 5)
 | 
			
		||||
			layout = GridBagLayout()
 | 
			
		||||
 | 
			
		||||
	override fun handleException(e: Exception) {
 | 
			
		||||
		e.printStackTrace()
 | 
			
		||||
		EventQueue.invokeAndWait {
 | 
			
		||||
			JOptionPane.showMessageDialog(null,
 | 
			
		||||
					"An error occurred: \n" + e.javaClass.canonicalName + ": " + e.message,
 | 
			
		||||
					title, JOptionPane.ERROR_MESSAGE)
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
			btnOptions = JButton("Optional mods...").apply {
 | 
			
		||||
				alignmentX = Component.CENTER_ALIGNMENT
 | 
			
		||||
 | 
			
		||||
	override fun handleExceptionAndExit(e: Exception) {
 | 
			
		||||
		e.printStackTrace()
 | 
			
		||||
		EventQueue.invokeAndWait {
 | 
			
		||||
			JOptionPane.showMessageDialog(null,
 | 
			
		||||
					"A fatal error occurred: \n" + e.javaClass.canonicalName + ": " + e.message,
 | 
			
		||||
					title, JOptionPane.ERROR_MESSAGE)
 | 
			
		||||
			exitProcess(1)
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	override fun setTitle(title: String) {
 | 
			
		||||
		this.title = title
 | 
			
		||||
		EventQueue.invokeLater { frmPackwizlauncher.title = title }
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	override fun submitProgress(progress: InstallProgress) {
 | 
			
		||||
		val sb = StringBuilder()
 | 
			
		||||
		if (progress.hasProgress) {
 | 
			
		||||
			sb.append('(')
 | 
			
		||||
			sb.append(progress.progress)
 | 
			
		||||
			sb.append('/')
 | 
			
		||||
			sb.append(progress.progressTotal)
 | 
			
		||||
			sb.append(") ")
 | 
			
		||||
		}
 | 
			
		||||
		sb.append(progress.message)
 | 
			
		||||
		// TODO: better logging library?
 | 
			
		||||
		println(sb.toString())
 | 
			
		||||
		EventQueue.invokeLater {
 | 
			
		||||
			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
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	override fun showOptions(options: List<IOptionDetails>): Future<Boolean> {
 | 
			
		||||
		val future = CompletableFuture<Boolean>()
 | 
			
		||||
		EventQueue.invokeLater {
 | 
			
		||||
			if (options.isEmpty()) {
 | 
			
		||||
				JOptionPane.showMessageDialog(null,
 | 
			
		||||
					"This modpack has no optional mods!",
 | 
			
		||||
					"Optional mods", JOptionPane.INFORMATION_MESSAGE)
 | 
			
		||||
				future.complete(false)
 | 
			
		||||
			} else {
 | 
			
		||||
				OptionsSelectWindow(options, future, frmPackwizlauncher).apply {
 | 
			
		||||
					defaultCloseOperation = JDialog.DISPOSE_ON_CLOSE
 | 
			
		||||
					isVisible = true
 | 
			
		||||
				addActionListener {
 | 
			
		||||
					text = "Loading..."
 | 
			
		||||
					isEnabled = false
 | 
			
		||||
					handler.optionsButtonPressed = true
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
		return future
 | 
			
		||||
			add(btnOptions, GridBagConstraints().apply {
 | 
			
		||||
				gridx = 0
 | 
			
		||||
				gridy = 0
 | 
			
		||||
			})
 | 
			
		||||
 | 
			
		||||
			add(JButton("Cancel").apply {
 | 
			
		||||
				addActionListener {
 | 
			
		||||
					isEnabled = false
 | 
			
		||||
					handler.cancelButtonPressed = true
 | 
			
		||||
				}
 | 
			
		||||
			}, GridBagConstraints().apply {
 | 
			
		||||
				gridx = 0
 | 
			
		||||
				gridy = 1
 | 
			
		||||
			})
 | 
			
		||||
		}, BorderLayout.EAST)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	override fun showExceptions(exceptions: List<ExceptionDetails>, numTotal: Int, allowsIgnore: Boolean): Future<ExceptionListResult> {
 | 
			
		||||
		val future = CompletableFuture<ExceptionListResult>()
 | 
			
		||||
		EventQueue.invokeLater {
 | 
			
		||||
			ExceptionListWindow(exceptions, future, numTotal, allowsIgnore, frmPackwizlauncher).apply {
 | 
			
		||||
				defaultCloseOperation = JDialog.DISPOSE_ON_CLOSE
 | 
			
		||||
				isVisible = true
 | 
			
		||||
			}
 | 
			
		||||
	fun displayProgress(progress: InstallProgress) {
 | 
			
		||||
		if (progress.hasProgress) {
 | 
			
		||||
			progressBar.isIndeterminate = false
 | 
			
		||||
			progressBar.value = progress.progress
 | 
			
		||||
			progressBar.maximum = progress.progressTotal
 | 
			
		||||
		} else {
 | 
			
		||||
			progressBar.isIndeterminate = true
 | 
			
		||||
			progressBar.value = 0
 | 
			
		||||
		}
 | 
			
		||||
		return future
 | 
			
		||||
		lblProgresslabel.text = progress.message
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	override fun disableOptionsButton() {
 | 
			
		||||
		EventQueue.invokeLater {
 | 
			
		||||
			btnOptions.apply {
 | 
			
		||||
				text = "No optional mods"
 | 
			
		||||
				isEnabled = false
 | 
			
		||||
			}
 | 
			
		||||
	fun disableOptionsButton() {
 | 
			
		||||
		btnOptions.apply {
 | 
			
		||||
			text = "No optional mods"
 | 
			
		||||
			isEnabled = false
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	override fun showCancellationDialog(): Future<IUserInterface.CancellationResult> {
 | 
			
		||||
		val future = CompletableFuture<IUserInterface.CancellationResult>()
 | 
			
		||||
		EventQueue.invokeLater {
 | 
			
		||||
			val buttons = arrayOf("Quit", "Ignore")
 | 
			
		||||
			val result = JOptionPane.showOptionDialog(frmPackwizlauncher,
 | 
			
		||||
					"The installation was cancelled. Would you like to quit the game, or ignore the update and start the game?",
 | 
			
		||||
					"Cancelled installation",
 | 
			
		||||
					JOptionPane.YES_NO_OPTION, JOptionPane.QUESTION_MESSAGE, null, buttons, buttons[0])
 | 
			
		||||
			future.complete(if (result == 0) IUserInterface.CancellationResult.QUIT else IUserInterface.CancellationResult.CONTINUE)
 | 
			
		||||
		}
 | 
			
		||||
		return future
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
		Reference in New Issue
	
	Block a user