From 9301f7d994fe016302bde062a8e41ae002012a8b Mon Sep 17 00:00:00 2001 From: UnicornFreedom Date: Sat, 14 Oct 2023 20:44:59 +0200 Subject: [PATCH] Add an option to extract OpenComputers config copy --- .gitignore | 2 + .../widget/settings/SystemSettingsTab.scala | 107 ++++++++++++++---- .../scala/ocelot/desktop/util/FileUtils.scala | 16 ++- 3 files changed, 104 insertions(+), 21 deletions(-) diff --git a/.gitignore b/.gitignore index 6801145..e9014be 100644 --- a/.gitignore +++ b/.gitignore @@ -51,6 +51,8 @@ cacerts # Ocelot configuration file /ocelot.conf +/brain.conf +/opencomputers.conf # Design sketches /refs/ diff --git a/src/main/scala/ocelot/desktop/ui/widget/settings/SystemSettingsTab.scala b/src/main/scala/ocelot/desktop/ui/widget/settings/SystemSettingsTab.scala index 5d44ec7..b5e2285 100644 --- a/src/main/scala/ocelot/desktop/ui/widget/settings/SystemSettingsTab.scala +++ b/src/main/scala/ocelot/desktop/ui/widget/settings/SystemSettingsTab.scala @@ -5,27 +5,33 @@ import ocelot.desktop.{ColorScheme, OcelotDesktop, Settings} import ocelot.desktop.geometry.Padding2D import ocelot.desktop.graphics.{Graphics, IconSource} import ocelot.desktop.ui.layout.LinearLayout -import ocelot.desktop.ui.widget.{IconButton, Label, PaddingBox, TextInput, Widget} -import ocelot.desktop.util.Orientation +import ocelot.desktop.ui.widget.modal.notification.{NotificationDialog, NotificationType} +import ocelot.desktop.ui.widget.{Button, IconButton, Label, PaddingBox, TextInput, Widget} +import ocelot.desktop.util.{FileUtils, Logging, Orientation} +import java.io.File import javax.swing.JFileChooser -import scala.util.Success +import scala.util.{Failure, Success, Try} + +class SystemSettingsTab extends SettingsTab with Logging { + private val OpenComputersConfigName = "opencomputers.conf" + private val OpenComputersConfigResource = "/application.conf" -class SystemSettingsTab extends SettingsTab { override val icon: IconSource = IconSource.SettingsSystem override val label: String = "System" - children :+= new PaddingBox(new Label("OpenComputers configuration file path"), Padding2D(bottom = 8)) + children :+= new PaddingBox(new Label("OpenComputers configuration file path:"), Padding2D(bottom = 8)) + + private val textInput: TextInput = new TextInput(Settings.get.brainConfigPath.getOrElse("")) { + override def onInput(text: String): Unit = { + Settings.get.brainConfigPath = Some(text) + restartWarning.isVisible = true + } + } children :+= new PaddingBox(new Widget { override val layout = new LinearLayout(this, orientation = Orientation.Horizontal) - val textInput: TextInput = new TextInput(Settings.get.brainConfigPath.getOrElse("")) { - override def onInput(text: String): Unit = { - Settings.get.brainConfigPath = Some(text) - restartWarning.isVisible = true - } - } children :+= new PaddingBox(textInput, Padding2D(right = 8)) children :+= new IconButton( @@ -40,10 +46,7 @@ class SystemSettingsTab extends SettingsTab { override def onPressed(): Unit = { OcelotDesktop.showFileChooserDialog(JFileChooser.OPEN_DIALOG, JFileChooser.FILES_ONLY) { case Some(dir) => - val path = dir.getCanonicalPath - Settings.get.brainConfigPath = Some(path) - textInput.setInput(path) - restartWarning.isVisible = true + setConfigPath(dir.getCanonicalPath) Success(()) case None => Success(()) } @@ -51,13 +54,77 @@ class SystemSettingsTab extends SettingsTab { } }, Padding2D(bottom = 4)) - private val restartWarning: InvisibleLabel = new InvisibleLabel { - override def isSmall: Boolean = true - override def color: Color = ColorScheme("ErrorMessage") - override def text = "Restart Ocelot to apply new configuration" + children :+= new PaddingBox(new Label("Generate new OpenComputers configuration file in:"), Padding2D(top = 8, bottom = 8)) + + children :+= new Widget { + children :+= new Button { + override def text: String = "Current Directory" + override def onClick(): Unit = { + unpackConfig(new File(OpenComputersConfigName)) + } + } + children :+= new PaddingBox(new Button { + override def text: String = "Config Directory" + override def onClick(): Unit = { + val path = new File(FileUtils.getOcelotConfigDirectory.toFile, OpenComputersConfigName) + println(path) + unpackConfig(path) + } + }, Padding2D(left = 8)) + children :+= new PaddingBox(new Button { + override def text: String = "Custom Path" + override def onClick(): Unit = { + OcelotDesktop.showFileChooserDialog(JFileChooser.SAVE_DIALOG, JFileChooser.FILES_ONLY) { + case Some(file) => + unpackConfig(file) + Success(()) + case None => Success(()) + } + } + }, Padding2D(left = 8)) } - children :+= new PaddingBox(restartWarning, Padding2D(bottom = 8)) + private def unpackConfig(file: File): Unit = { + if (file.exists()) { + new NotificationDialog(s"You are overriding an existing file!", NotificationType.Warning) { + addButton("Proceed") { + unpackAndOverrideConfig(file) + close() + } + }.addCloseButton("Cancel").show() + } else { + unpackAndOverrideConfig(file) + } + } + + private def unpackAndOverrideConfig(file: File): Unit = { + val path = FileUtils.unpackResource(OpenComputersConfigResource, file) + path match { + case Success(dir) => + logger.info(s"Saved OpenComputers configuration to: ${dir.getCanonicalPath}") + setConfigPath(dir.getCanonicalPath) + case Failure(exception) => + new NotificationDialog( + s"Something went wrong!\n($exception)\nCheck the log file for a full stacktrace.", + NotificationType.Error + ).addCloseButton().show() + } + } + + private def setConfigPath(path: String): Unit = { + Settings.get.brainConfigPath = Some(path) + textInput.setInput(path) + restartWarning.isVisible = true + } + + private val restartWarning: InvisibleLabel = new InvisibleLabel { + override def isSmall: Boolean = true + + override def color: Color = ColorScheme("ErrorMessage") + + override def text = "Restart Ocelot to apply new configuration" + } + children :+= new PaddingBox(restartWarning, Padding2D(top = 4, bottom = 8)) private class InvisibleLabel extends Label { var isVisible = false diff --git a/src/main/scala/ocelot/desktop/util/FileUtils.scala b/src/main/scala/ocelot/desktop/util/FileUtils.scala index 0a465cb..d94e767 100644 --- a/src/main/scala/ocelot/desktop/util/FileUtils.scala +++ b/src/main/scala/ocelot/desktop/util/FileUtils.scala @@ -1,10 +1,13 @@ package ocelot.desktop.util +import ocelot.desktop.Settings import org.apache.commons.lang3.SystemUtils -import java.io.{IOException, RandomAccessFile} +import java.io.{File, FileOutputStream, IOException, RandomAccessFile} import java.nio.ByteBuffer +import java.nio.channels.Channels import java.nio.file.{Path, Paths} +import scala.util.{Try, Using} object FileUtils extends Logging { def load(filename: String): ByteBuffer = { @@ -27,6 +30,17 @@ object FileUtils extends Logging { } } + def unpackResource(resource: String, target: File): Try[File] = Try { + val configResource = classOf[Settings].getResource(resource) + Using.resources(Channels.newChannel(configResource.openStream()), new FileOutputStream(target).getChannel) { (in, out) => + out.transferFrom(in, 0, Long.MaxValue) + target.setReadable(true, false) + target.setWritable(true, false) + target.setExecutable(false, false) + target + } + } + def getOcelotConfigDirectory: Path = { if (SystemUtils.IS_OS_WINDOWS) Paths.get(System.getenv("APPDATA"), "Ocelot") else Paths.get(System.getProperty("user.home"), ".config", "ocelot")