ton of profile stuff, fixes

This commit is contained in:
Bixilon 2021-12-06 21:09:02 +01:00
parent ec965fbd0b
commit f155985ab1
No known key found for this signature in database
GPG Key ID: 5CAD791931B09AC4
27 changed files with 498 additions and 58 deletions

View File

@ -26,7 +26,7 @@ import de.bixilon.minosoft.data.registries.ResourceLocation
class ConnectionProfiles(
overrides: Map<ResourceLocation, String> = mapOf(),
val eros: ErosProfile = overrides[ErosProfileManager.namespace]?.let { return@let ErosProfileManager.profiles[it] } ?: ErosProfileManager.selected,
val eros: ErosProfile = ErosProfileManager.selected,
val particle: ParticleProfile = overrides[ParticleProfileManager.namespace]?.let { return@let ParticleProfileManager.profiles[it] } ?: ParticleProfileManager.selected,
val audio: AudioProfile = overrides[AudioProfileManager.namespace]?.let { return@let AudioProfileManager.profiles[it] } ?: AudioProfileManager.selected,
val entity: EntityProfile = overrides[EntityProfileManager.namespace]?.let { return@let EntityProfileManager.profiles[it] } ?: EntityProfileManager.selected,

View File

@ -29,29 +29,35 @@ import de.bixilon.minosoft.util.task.time.TimeWorkerTask
import java.io.File
object GlobalProfileManager {
val DEFAULT_MANAGERS: List<ProfileManager<out Profile>> = listOf(
ErosProfileManager,
ParticleProfileManager,
AudioProfileManager,
EntityProfileManager,
ResourcesProfileManager,
AccountProfileManager,
RenderingProfileManager,
BlockProfileManager,
ConnectionProfileManager,
HUDProfileManager,
ControlsProfileManager,
OtherProfileManager,
)
val DEFAULT_MANAGERS: Map<ResourceLocation, ProfileManager<out Profile>>
private val SELECTED_PROFILES_TYPE: MapType = Jackson.MAPPER.typeFactory.constructMapType(HashMap::class.java, ResourceLocation::class.java, String::class.java)
val CLASS_MAPPING: Map<Class<out Profile>, ProfileManager<*>>
init {
val map: MutableMap<ResourceLocation, ProfileManager<out Profile>> = mutableMapOf()
val classMapping: MutableMap<Class<out Profile>, ProfileManager<*>> = mutableMapOf()
for (manager in DEFAULT_MANAGERS) {
val list = listOf(
ErosProfileManager,
ParticleProfileManager,
AudioProfileManager,
EntityProfileManager,
ResourcesProfileManager,
AccountProfileManager,
RenderingProfileManager,
BlockProfileManager,
ConnectionProfileManager,
HUDProfileManager,
ControlsProfileManager,
OtherProfileManager,
)
for (manager in list) {
map.put(manager.namespace, manager)?.let { throw IllegalStateException("Duplicate profile namespace: ${manager.namespace}") }
classMapping[manager.profileClass] = manager
}
CLASS_MAPPING = classMapping.toMap()
this.DEFAULT_MANAGERS = map.toMap()
this.CLASS_MAPPING = classMapping.toMap()
}
private var initialized = false
@ -100,15 +106,15 @@ object GlobalProfileManager {
throw IllegalStateException("Already initialized!")
}
loadSelectedProfiles()
for (manager in DEFAULT_MANAGERS) {
manager.load(selectedProfiles[manager.namespace])
for ((namespace, manager) in DEFAULT_MANAGERS) {
manager.load(selectedProfiles[namespace])
}
loading = false
if (selectedProfilesChanges) {
saveSelectedProfiles()
}
TimeWorker += TimeWorkerTask(1000) {
for (manager in DEFAULT_MANAGERS) {
for (manager in DEFAULT_MANAGERS.values) {
for (profile in manager.profiles.values) {
if (profile.saved) {
continue
@ -136,4 +142,6 @@ object GlobalProfileManager {
saveSelectedProfiles()
}
}
operator fun get(resourceLocation: ResourceLocation): ProfileManager<out Profile>? = DEFAULT_MANAGERS[resourceLocation]
}

View File

@ -36,6 +36,8 @@ interface ProfileManager<T : Profile> {
val latestVersion: Int
val saveLock: ReentrantLock
val profileClass: Class<T>
val profileSelectable: Boolean
get() = true
val profiles: HashBiMap<String, T>
var selected: T
@ -99,10 +101,19 @@ interface ProfileManager<T : Profile> {
fun createDefaultProfile(name: String = DEFAULT_PROFILE_NAME): T
fun initDefaultProfile() {
fun initDefaultProfile(): T {
profiles[DEFAULT_PROFILE_NAME]?.let { return it }
val profile = createDefaultProfile()
add(profile)
this.selected = profile
saveAsync(profile)
return profile
}
fun add(profile: T) {
save(profile)
if (RunConfiguration.PROFILES_HOT_RELOADING) {
watchProfile(DEFAULT_PROFILE_NAME, File(DEFAULT_PROFILE_NAME))
}
}
@ -150,12 +161,13 @@ interface ProfileManager<T : Profile> {
throw IOException("${baseDirectory.path} is not an directory!")
}
val profileNames = baseDirectory.list { current, name -> File(current, name).isDirectory }?.toMutableSet() ?: throw IOException("Can not create a list of profiles in ${baseDirectory.path}")
if (selected == null || profileNames.isEmpty()) {
profileNames += DEFAULT_PROFILE_NAME
}
for (profileName in profileNames) {
val path = getPath(profileName, baseDirectory)
val (saveFile, json) = readAndMigrate(path)
if (json == null) {
continue
}
val profile: T
try {
profile = load(profileName, json)
@ -171,7 +183,7 @@ interface ProfileManager<T : Profile> {
}
}
profiles[selected]?.let { this.selected = it } ?: selectDefault()
profiles[selected]?.let { this.selected = it } ?: initDefaultProfile()
Log.log(LogMessageType.PROFILES, LogLevels.VERBOSE) { "Loaded ${profiles.size} $namespace profiles!" }
}

View File

@ -33,7 +33,9 @@ open class ListDelegateProfile<V>(
if (StaticConfiguration.LOG_DELEGATE) {
Log.log(LogMessageType.PROFILES, LogLevels.VERBOSE) { "Changed list entry $it in profile $profileName" }
}
profileManager.profiles[profileName]?.saved = false
if (!profile.reloading) {
profileManager.profiles[profileName]?.saved = false
}
ProfilesDelegateManager.onChange(profile, property.javaField ?: return@ListChangeListener, null, it)
})
@ -44,5 +46,8 @@ open class ListDelegateProfile<V>(
override fun set(value: MutableList<V>) {
this.value = FXCollections.synchronizedObservableList(FXCollections.observableList(value))
initListener()
if (!profile.reloading) {
profileManager.profiles[profileName]?.saved = false
}
}
}

View File

@ -37,7 +37,9 @@ open class MapDelegateProfile<K, V>(
if (StaticConfiguration.LOG_DELEGATE) {
Log.log(LogMessageType.PROFILES, LogLevels.VERBOSE) { "Changed map entry $it in profile $profileName" }
}
profileManager.profiles[profileName]?.saved = false
if (!profile.reloading) {
profileManager.profiles[profileName]?.saved = false
}
ProfilesDelegateManager.onChange(profile, property.javaField ?: return@MapChangeListener, null, it)
})
@ -54,6 +56,7 @@ open class MapDelegateProfile<K, V>(
if (!profileInitialized || profile.initializing || !profile.reloading) {
this.value = FXCollections.synchronizedObservableMap(FXCollections.observableMap(value))
initListener()
profileManager.profiles[profileName]?.saved = false
return
}

View File

@ -34,7 +34,9 @@ open class SetDelegateProfile<V>(
if (StaticConfiguration.LOG_DELEGATE) {
Log.log(LogMessageType.PROFILES, LogLevels.VERBOSE) { "Changed set entry $it in profile $profileName" }
}
profileManager.profiles[profileName]?.saved = false
if (!profile.reloading) {
profileManager.profiles[profileName]?.saved = false
}
ProfilesDelegateManager.onChange(profile, property.javaField ?: return@SetChangeListener, null, it)
})
@ -45,5 +47,8 @@ open class SetDelegateProfile<V>(
override fun set(value: MutableSet<V>) {
this.value = FXCollections.synchronizedObservableSet(FXCollections.observableSet(value))
initListener()
if (!profile.reloading) {
profileManager.profiles[profileName]?.saved = false
}
}
}

View File

@ -22,6 +22,8 @@ object ErosProfileManager : ProfileManager<ErosProfile> {
override val latestVersion = 1
override val saveLock = ReentrantLock()
override val profileClass = ErosProfile::class.java
override val profileSelectable: Boolean
get() = false
override var currentLoadingPath: String? = null

View File

@ -28,6 +28,7 @@ class Server(
address: String,
name: ChatComponent = ChatComponent.of(address),
forcedVersion: Version? = null,
profiles: MutableMap<ResourceLocation, String> = mutableMapOf(),
) {
/**
* Server-address as string. May contain the port
@ -44,7 +45,7 @@ class Server(
* Changing profiles requires reconnect
* If profile is unset, defaults to eros global profiles
*/
var profiles: MutableMap<ResourceLocation, String> by mapDelegate()
var profiles: MutableMap<ResourceLocation, String> by mapDelegate(profiles)
@get:JsonProperty("forced_version")
@get:JsonInclude(JsonInclude.Include.NON_NULL)

View File

@ -27,7 +27,13 @@ class Language(
}
override fun translate(key: ResourceLocation?, parent: TextComponent?, vararg data: Any?): ChatComponent {
val placeholder = this.data[key] ?: return ChatComponent.of(key.toString() + "->" + data.toString(), null, parent)
val placeholder = this.data[key]
if (placeholder == null) {
if (data.isEmpty()) {
return ChatComponent.of(key.toString(), null, parent)
}
return ChatComponent.of(key.toString() + "->" + data.contentToString(), null, parent)
}
val ret = BaseComponent()

View File

@ -46,7 +46,11 @@ class LanguageManager(
}
return language.translate(key, parent, *data)
}
return ChatComponent.of("$key: ${data.contentToString()}")
if (data.isEmpty()) {
return ChatComponent.of(key.toString(), null, parent)
}
return ChatComponent.of(key.toString() + "->" + data.contentToString(), null, parent)
}
companion object {

View File

@ -0,0 +1,228 @@
/*
* Minosoft
* Copyright (C) 2021 Moritz Zwerger
*
* This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along with this program. If not, see <https://www.gnu.org/licenses/>.
*
* This software is not affiliated with Mojang AB, the original developer of Minecraft.
*/
package de.bixilon.minosoft.gui.eros.dialog
import de.bixilon.minosoft.Minosoft
import de.bixilon.minosoft.config.profile.GlobalProfileManager
import de.bixilon.minosoft.data.registries.ResourceLocation
import de.bixilon.minosoft.gui.eros.controller.DialogController
import de.bixilon.minosoft.gui.eros.util.JavaFXUtil
import de.bixilon.minosoft.gui.eros.util.JavaFXUtil.text
import de.bixilon.minosoft.util.KUtil.toResourceLocation
import javafx.fxml.FXML
import javafx.scene.control.*
import javafx.scene.input.KeyCode
import javafx.scene.input.KeyEvent
import javafx.scene.text.TextFlow
import javafx.stage.Modality
class ProfileSelectDialog(
profiles: MutableMap<ResourceLocation, String>,
private val onConfirm: (Map<ResourceLocation, String>) -> Unit,
private val onCancel: () -> Unit,
) : DialogController() {
private val profiles = profiles.toMutableMap()
@FXML private lateinit var headerFX: TextFlow
@FXML private lateinit var profilesFX: TableView<ProfileEntry>
@FXML private lateinit var typeColumnFX: TableColumn<ProfileEntry, ResourceLocation>
@FXML private lateinit var valueColumnFX: TableColumn<ProfileEntry, String>
@FXML private lateinit var createProfileButtonFX: Button
@FXML private lateinit var cancelButtonFX: Button
@FXML private lateinit var confirmButtonFX: Button
fun show() {
JavaFXUtil.runLater {
JavaFXUtil.openModal(TITLE, LAYOUT, this, Modality.APPLICATION_MODAL)
stage.show()
}
}
override fun init() {
headerFX.text = Minosoft.LANGUAGE_MANAGER.translate(HEADER)
typeColumnFX.setCellFactory { ResourceLocationCell() }
valueColumnFX.setCellFactory { ProfileCell() }
for ((type, profile) in profiles) {
profilesFX.items += ProfileEntry(type, profile)
}
profilesFX.items += ProfileEntry(null, "")
}
override fun postInit() {
super.postInit()
stage.setOnCloseRequest { cancel() }
stage.scene.root.addEventFilter(KeyEvent.KEY_PRESSED) {
if (it.code == KeyCode.ENTER) {
cancel()
}
}
}
@FXML
fun newProfile() {
}
@FXML
fun confirm() {
stage.close()
val profiles: MutableMap<ResourceLocation, String> = mutableMapOf()
for ((resourceLocation, profile) in this.profilesFX.items) {
if (profile.isBlank()) {
continue
}
profiles[resourceLocation ?: continue] = profile
}
onConfirm(profiles)
}
@FXML
fun cancel() {
onCancel()
stage.close()
}
companion object {
private val LAYOUT = "minosoft:eros/dialog/profile_select.fxml".toResourceLocation()
private val TITLE = "minosoft:general.dialog.profile_select.title".toResourceLocation()
private val HEADER = "minosoft:general.dialog.profile_select.header".toResourceLocation()
}
private data class ProfileEntry(
var resourceLocation: ResourceLocation?,
var profile: String = "",
)
private abstract inner class EditTableCell<T> : TableCell<ProfileEntry, T>() {
protected val label = Label()
protected val comboBox = ComboBox<T>()
init {
graphic = label
selectedProperty().addListener { _, _, _ -> cancelEdit() }
comboBox.selectionModel.selectedItemProperty().addListener { _, _, selected ->
commitEdit(selected)
}
}
override fun updateItem(item: T, empty: Boolean) {
super.updateItem(item, empty)
graphic = label
isVisible = !empty
if (empty) {
return
}
update(tableRow.item)
}
abstract fun update(entry: ProfileEntry)
abstract fun updateItem(item: T)
override fun startEdit() {
super.startEdit()
graphic = comboBox
comboBox.show()
}
override fun cancelEdit() {
super.cancelEdit()
graphic = label
}
override fun commitEdit(newValue: T?) {
super.commitEdit(newValue)
updateItem(newValue ?: return)
graphic = label
}
}
private inner class ResourceLocationCell : EditTableCell<ResourceLocation?>() {
init {
comboBox.selectionModel.selectedItemProperty().addListener { _, previous, selected ->
if (previous == null && selected != null) {
tableView.items += ProfileEntry(null, "")
tableView.refresh()
}
}
}
override fun startEdit() {
val thisNamespace = tableRow.item.resourceLocation
if (comboBox.items.isEmpty()) {
val alreadyDisplayed: MutableSet<ResourceLocation?> = mutableSetOf()
for (entry in tableView.items) {
alreadyDisplayed += entry.resourceLocation ?: continue
}
for ((namespace, profileManager) in GlobalProfileManager.DEFAULT_MANAGERS) {
if (!profileManager.profileSelectable || (thisNamespace != namespace && namespace in alreadyDisplayed)) {
continue
}
comboBox.items += namespace
}
}
comboBox.selectionModel.select(thisNamespace)
super.startEdit()
}
override fun update(entry: ProfileEntry) = updateItem(entry.resourceLocation)
override fun updateItem(item: ResourceLocation?) {
label.text = item?.toString() ?: "Double click to select"
tableRow.item.resourceLocation = item
}
}
private inner class ProfileCell : EditTableCell<String>() {
override fun startEdit() {
comboBox.items.clear()
comboBox.setCellFactory {
object : ListCell<String>() {
override fun updateItem(item: String?, empty: Boolean) {
super.updateItem(item, empty)
text = if (item?.isBlank() == true && !empty) {
"<None>"
} else {
item.toString()
}
}
}
}
comboBox.items += ""
GlobalProfileManager[tableRow.item.resourceLocation ?: return]?.let {
comboBox.items += it.profiles.keys
}
comboBox.selectionModel.select(this.tableRow.item.profile)
super.startEdit()
}
override fun update(entry: ProfileEntry) = updateItem(entry.profile)
override fun updateItem(item: String) {
if (item.isBlank()) {
label.text = "<None>"
} else {
label.text = item
}
tableRow.item.profile = item
}
}
}

View File

@ -15,6 +15,7 @@ package de.bixilon.minosoft.gui.eros.dialog
import de.bixilon.minosoft.Minosoft
import de.bixilon.minosoft.data.text.ChatComponent
import de.bixilon.minosoft.data.text.TranslatableComponents
import de.bixilon.minosoft.gui.eros.controller.DialogController
import de.bixilon.minosoft.gui.eros.util.JavaFXUtil
import de.bixilon.minosoft.gui.eros.util.JavaFXUtil.text
@ -31,8 +32,8 @@ class SimpleErosConfirmationDialog(
val title: Any = DEFAULT_TITLE_TEXT,
val header: Any = DEFAULT_TITLE_TEXT,
val description: Any? = null,
val cancelButtonText: Any = DEFAULT_CANCEL_TEXT,
val confirmButtonText: Any = DEFAULT_CONFIRM_TEXT,
val cancelButtonText: Any = TranslatableComponents.GENERAL_CANCEL,
val confirmButtonText: Any = TranslatableComponents.GENERAL_CONFIRM,
val onCancel: () -> Unit = {},
val onConfirm: () -> Unit,
val modality: Modality = Modality.WINDOW_MODAL,
@ -86,7 +87,5 @@ class SimpleErosConfirmationDialog(
companion object {
private val LAYOUT = "minosoft:eros/dialog/simple_confirmation.fxml".toResourceLocation()
private val DEFAULT_TITLE_TEXT = "minosoft:general.dialog.are_you_sure".toResourceLocation()
private val DEFAULT_CANCEL_TEXT = "minosoft:general.cancel".toResourceLocation()
private val DEFAULT_CONFIRM_TEXT = "minosoft:general.confirm".toResourceLocation()
}
}

View File

@ -15,8 +15,10 @@ package de.bixilon.minosoft.gui.eros.dialog
import de.bixilon.minosoft.Minosoft
import de.bixilon.minosoft.config.profile.delegate.watcher.SimpleProfileDelegateLWatcher.Companion.profileWatchFX
import de.bixilon.minosoft.config.profile.profiles.audio.AudioProfileManager
import de.bixilon.minosoft.config.profile.profiles.eros.ErosProfileManager
import de.bixilon.minosoft.config.profile.profiles.eros.server.entries.Server
import de.bixilon.minosoft.data.registries.ResourceLocation
import de.bixilon.minosoft.data.registries.versions.Version
import de.bixilon.minosoft.data.registries.versions.VersionTypes
import de.bixilon.minosoft.data.registries.versions.Versions
@ -41,7 +43,7 @@ import javafx.scene.text.TextFlow
*/
class UpdateServerDialog(
private val server: Server? = null,
val onUpdate: (name: String, address: String, forcedVersion: Version?) -> Unit,
val onUpdate: (name: String, address: String, forcedVersion: Version?, profiles: Map<ResourceLocation, String>) -> Unit,
) : DialogController() {
@FXML private lateinit var descriptionFX: TextFlow
@FXML private lateinit var serverNameLabelFX: TextFlow
@ -54,10 +56,18 @@ class UpdateServerDialog(
@FXML private lateinit var showReleasesFX: CheckBox
@FXML private lateinit var showSnapshotsFX: CheckBox
@FXML private lateinit var profilesLabelFX: TextFlow
@FXML private lateinit var openProfileSelectDialogButtonFX: Button
@FXML private lateinit var updateServerButtonFX: Button
@FXML private lateinit var cancelButtonFX: Button
private var profileSelectDialog: ProfileSelectDialog? = null
private var profiles = server?.profiles ?: mutableMapOf(AudioProfileManager.namespace to "Default") // ToDo
fun show() {
JavaFXUtil.runLater {
JavaFXUtil.openModal((server == null).decide(ADD_TITLE, EDIT_TITLE), LAYOUT, this)
@ -95,6 +105,8 @@ class UpdateServerDialog(
serverAddressLabelFX.text = SERVER_ADDRESS_LABEL
serverAddressFX.placeholder = SERVER_ADDRESS_PLACEHOLDER
forcedVersionLabelFX.text = FORCED_VERSION_LABEL
profilesLabelFX.text = PROFILES_LABEL
openProfileSelectDialogButtonFX.ctext = PROFILES_OPEN_PROFILE_SELECT
cancelButtonFX.ctext = TranslatableComponents.GENERAL_CANCEL
@ -176,7 +188,7 @@ class UpdateServerDialog(
return
}
val forcedVersion = (forcedVersionFX.selectionModel.selectedItem == Versions.AUTOMATIC_VERSION).decide(null) { forcedVersionFX.selectionModel.selectedItem }
DefaultThreadPool += { onUpdate(serverNameFX.text.isBlank().decide({ serverAddressFX.text.toString() }, { serverNameFX.text.trim() }), serverAddressFX.text, forcedVersion) }
DefaultThreadPool += { onUpdate(serverNameFX.text.isBlank().decide({ serverAddressFX.text.toString() }, { serverNameFX.text.trim() }), serverAddressFX.text, forcedVersion, profiles) }
stage.close()
}
@ -185,6 +197,23 @@ class UpdateServerDialog(
stage.close()
}
@FXML
fun openProfileSelectDialog() {
profileSelectDialog?.let { it.show(); return }
val dialog = ProfileSelectDialog(
profiles = profiles,
onConfirm = {
this.profiles = it.toMutableMap()
this.profileSelectDialog = null
},
onCancel = {
this.profileSelectDialog = null
},
)
this.profileSelectDialog = dialog
dialog.show()
}
companion object {
private val LAYOUT = "minosoft:eros/dialog/update_server.fxml".toResourceLocation()
@ -197,6 +226,8 @@ class UpdateServerDialog(
private val VERSION_AUTOMATIC = "minosoft:update_server.forced_version.automatic".toResourceLocation()
private val SHOW_RELEASES = "minosoft:update_server.forced_version.releases".toResourceLocation()
private val SHOW_SNAPSHOTS = "minosoft:update_server.forced_version.snapshots".toResourceLocation()
private val PROFILES_LABEL = "minosoft:update_server.profiles.label".toResourceLocation()
private val PROFILES_OPEN_PROFILE_SELECT = "minosoft:update_server.profiles.open_select_dialog".toResourceLocation()
private val ADD_TITLE = "minosoft:update_server.add.title".toResourceLocation()
private val ADD_DESCRIPTION = "minosoft:update_server.add.description".toResourceLocation()

View File

@ -263,9 +263,10 @@ class ServerListController : EmbeddedJavaFXController<Pane>(), Refreshable {
it.add(Button("Edit").apply {
setOnAction {
val server = serverCard.server
UpdateServerDialog(server = server, onUpdate = { name, address, forcedVersion ->
UpdateServerDialog(server = server, onUpdate = { name, address, forcedVersion, profiles ->
server.name = ChatComponent.of(name)
server.forcedVersion = forcedVersion
server.profiles = profiles.toMutableMap()
if (server.address != address) {
serverCard.rawFavicon = null
@ -344,8 +345,8 @@ class ServerListController : EmbeddedJavaFXController<Pane>(), Refreshable {
@FXML
fun addServer() {
UpdateServerDialog(onUpdate = { name, address, forcedVersion ->
serverType!!.servers += Server(name = ChatComponent.of(name), address = address, forcedVersion = forcedVersion)
UpdateServerDialog(onUpdate = { name, address, forcedVersion, profiles ->
serverType!!.servers += Server(name = ChatComponent.of(name), address = address, forcedVersion = forcedVersion, profiles = profiles.toMutableMap())
}).show()
}

View File

@ -384,8 +384,8 @@ object KUtil {
fun Any?.toLong(): Long {
return when (this) {
is Long -> this
is Number -> this.toLong()
is Int -> this.toLong()
is Number -> this.toLong()
else -> TODO()
}
}

View File

@ -24,7 +24,6 @@ import java.net.http.HttpResponse
object HTTP2 {
fun Map<String, Any>.headers(): Array<String> {
val headers: MutableList<String> = mutableListOf()

View File

@ -56,7 +56,7 @@
<padding>
<Insets top="5.0"/>
</padding>
<Button maxWidth="Infinity" onAction="#exit" text="Exit" GridPane.columnIndex="2"/>
<Button maxWidth="Infinity" onAction="#exit" defaultButton="true" text="Exit" GridPane.columnIndex="2"/>
<Button maxWidth="Infinity" onAction="#hardCrash" text="Hard crash"/>
</GridPane>
</GridPane>

View File

@ -44,7 +44,7 @@
<Insets bottom="5.0" left="5.0" right="5.0" top="10.0"/>
</GridPane.margin>
</Button>
<Button fx:id="closeButtonFX" text="Close" GridPane.columnIndex="1">
<Button fx:id="closeButtonFX" text="Close" defaultButton="true" GridPane.columnIndex="1">
<GridPane.margin>
<Insets bottom="5.0" left="5.0" right="5.0" top="10.0"/>
</GridPane.margin>

View File

@ -49,7 +49,7 @@
<padding>
<Insets top="5.0"/>
</padding>
<Button fx:id="ignoreFX" maxWidth="Infinity" onAction="#ignore" text="Ignore" GridPane.columnIndex="2"/>
<Button fx:id="ignoreFX" maxWidth="Infinity" defaultButton="true" onAction="#ignore" text="Ignore" GridPane.columnIndex="2"/>
<Button fx:id="fatalCrashFX" maxWidth="Infinity" onAction="#fatalCrash" text="Fatal crash"/>
</GridPane>
</GridPane>

View File

@ -0,0 +1,66 @@
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.geometry.*?>
<?import javafx.scene.control.*?>
<?import javafx.scene.layout.*?>
<?import javafx.scene.text.Text?>
<?import javafx.scene.text.TextFlow?>
<VBox xmlns:fx="http://javafx.com/fxml/1" fx:id="root" prefHeight="300.0" prefWidth="600.0" xmlns="http://javafx.com/javafx/17">
<GridPane VBox.vgrow="ALWAYS">
<columnConstraints>
<ColumnConstraints hgrow="ALWAYS"/>
</columnConstraints>
<rowConstraints>
<RowConstraints valignment="CENTER" vgrow="NEVER"/>
<RowConstraints vgrow="ALWAYS"/>
<RowConstraints vgrow="NEVER"/>
</rowConstraints>
<VBox.margin>
<Insets bottom="5.0" left="5.0" right="5.0" top="5.0"/>
</VBox.margin>
<TextFlow fx:id="headerFX" textAlignment="CENTER">
<Text text="Select your profiles"/>
</TextFlow>
<TableView fx:id="profilesFX" editable="true" GridPane.hgrow="ALWAYS" GridPane.rowIndex="1">
<columns>
<TableColumn fx:id="typeColumnFX" minWidth="220.0" prefWidth="220.0" reorderable="false" text="Type"/>
<TableColumn fx:id="valueColumnFX" maxWidth="1.7976931348623157E308" minWidth="-1.0" prefWidth="-1.0" reorderable="false" text="Profile"/>
</columns>
<GridPane.margin>
<Insets bottom="5.0" left="5.0" right="5.0" top="5.0"/>
</GridPane.margin>
<columnResizePolicy>
<TableView fx:constant="CONSTRAINED_RESIZE_POLICY"/>
</columnResizePolicy>
</TableView>
<GridPane GridPane.rowIndex="2">
<columnConstraints>
<ColumnConstraints hgrow="ALWAYS"/>
<ColumnConstraints hgrow="NEVER"/>
<ColumnConstraints hgrow="NEVER"/>
<ColumnConstraints hgrow="NEVER"/>
</columnConstraints>
<rowConstraints>
<RowConstraints vgrow="NEVER"/>
</rowConstraints>
<Button fx:id="newProfileButtonFX" disable="true" onAction="#newProfile" text="Create new profile" GridPane.columnIndex="1">
<GridPane.margin>
<Insets left="5.0" right="5.0"/>
</GridPane.margin>
</Button>
<Button fx:id="cancelButtonFX" cancelButton="true" onAction="#cancel" text="Cancel" GridPane.columnIndex="2">
<GridPane.margin>
<Insets left="5.0" right="5.0"/>
</GridPane.margin>
</Button>
<Button fx:id="confirmButtonFX" defaultButton="true" onAction="#confirm" text="Confirm" GridPane.columnIndex="3">
<GridPane.margin>
<Insets left="5.0" right="5.0"/>
</GridPane.margin>
</Button>
</GridPane>
</GridPane>
</VBox>

View File

@ -65,12 +65,12 @@
<rowConstraints>
<RowConstraints vgrow="NEVER"/>
</rowConstraints>
<Button fx:id="confirmButtonFX" mnemonicParsing="false" onAction="#confirm" text="Confirm" GridPane.columnIndex="2">
<Button fx:id="confirmButtonFX" onAction="#confirm" text="Confirm" GridPane.columnIndex="2">
<GridPane.margin>
<Insets left="5.0" right="5.0"/>
</GridPane.margin>
</Button>
<Button fx:id="cancelButtonFX" mnemonicParsing="false" onAction="#cancel" text="Cancel" GridPane.columnIndex="1">
<Button fx:id="cancelButtonFX" onAction="#cancel" text="Cancel" GridPane.columnIndex="1">
<GridPane.margin>
<Insets left="5.0" right="5.0"/>
</GridPane.margin>

View File

@ -64,7 +64,7 @@
<rowConstraints>
<RowConstraints vgrow="NEVER"/>
</rowConstraints>
<Button fx:id="ignoreButtonFX" mnemonicParsing="false" onAction="#ignore" text="Ignore" GridPane.columnIndex="1">
<Button fx:id="ignoreButtonFX" defaultButton="true" onAction="#ignore" text="Ignore" GridPane.columnIndex="1">
<GridPane.margin>
<Insets left="5.0" right="5.0"/>
</GridPane.margin>

View File

@ -4,7 +4,7 @@
<?import javafx.scene.control.*?>
<?import javafx.scene.layout.*?>
<?import javafx.scene.text.*?>
<HBox xmlns:fx="http://javafx.com/fxml/1" prefHeight="250.0" prefWidth="600.0" xmlns="http://javafx.com/javafx/16"> <!--fx:controller="de.bixilon.minosoft.gui.eros.dialog.UpdateServerDialog" -->
<HBox xmlns:fx="http://javafx.com/fxml/1" prefHeight="250.0" prefWidth="600.0" xmlns="http://javafx.com/javafx/17"> <!--fx:controller="de.bixilon.minosoft.gui.eros.dialog.UpdateServerDialog" -->
<GridPane HBox.hgrow="ALWAYS">
<columnConstraints>
<ColumnConstraints hgrow="ALWAYS"/>
@ -29,8 +29,10 @@
<RowConstraints valignment="CENTER" vgrow="NEVER"/>
<RowConstraints valignment="CENTER" vgrow="NEVER"/>
<RowConstraints valignment="CENTER" vgrow="NEVER"/>
<RowConstraints minHeight="10.0" prefHeight="30.0" valignment="CENTER" vgrow="NEVER"/>
<RowConstraints valignment="CENTER" vgrow="NEVER"/>
<RowConstraints minHeight="10.0" prefHeight="30.0" valignment="CENTER" vgrow="ALWAYS"/>
</rowConstraints>
<TextFlow fx:id="serverNameLabelFX">
<GridPane.margin>
<Insets left="5.0" right="30.0" top="15.0"/>
@ -42,6 +44,7 @@
<Insets left="5.0" right="5.0"/>
</GridPane.margin>
</TextField>
<TextFlow fx:id="serverAddressLabelFX" GridPane.rowIndex="1">
<GridPane.margin>
<Insets left="5.0" right="30.0" top="15.0"/>
@ -53,6 +56,7 @@
<Insets left="5.0" right="5.0"/>
</GridPane.margin>
</TextField>
<TextFlow fx:id="forcedVersionLabelFX" GridPane.rowIndex="2">
<GridPane.margin>
<Insets left="5.0" right="30.0" top="15.0"/>
@ -92,6 +96,18 @@
</CheckBox>
</GridPane>
</GridPane>
<TextFlow fx:id="profilesLabelFX" GridPane.rowIndex="3">
<GridPane.margin>
<Insets left="5.0" right="30.0" top="15.0"/>
</GridPane.margin>
<Text text="Profiles"/>
</TextFlow>
<Button fx:id="openProfileSelectDialogButtonFX" onAction="#openProfileSelectDialog" maxWidth="Infinity" text="Open profile select dialog" textAlignment="CENTER" GridPane.columnIndex="1" GridPane.rowIndex="3">
<GridPane.margin>
<Insets bottom="5.0" left="5.0" right="5.0" top="5.0"/>
</GridPane.margin>
</Button>
</GridPane>
<GridPane GridPane.rowIndex="2">
<columnConstraints>
@ -103,7 +119,7 @@
<RowConstraints/>
<RowConstraints vgrow="NEVER"/>
</rowConstraints>
<Button fx:id="updateServerButtonFX" disable="true" onAction="#update" text="Update server" GridPane.columnIndex="2" GridPane.rowIndex="1">
<Button fx:id="updateServerButtonFX" defaultButton="true" disable="true" onAction="#update" text="Update server" GridPane.columnIndex="2" GridPane.rowIndex="1">
<GridPane.margin>
<Insets bottom="10.0" left="5.0" right="10.0" top="5.0"/>
</GridPane.margin>

View File

@ -41,7 +41,7 @@
<rowConstraints>
<RowConstraints vgrow="NEVER"/>
</rowConstraints>
<Button fx:id="addButtonFX" mnemonicParsing="false" text="Add" GridPane.columnIndex="1">
<Button fx:id="addButtonFX" text="Add" GridPane.columnIndex="1">
<GridPane.margin>
<Insets bottom="5.0" left="5.0" right="5.0" top="5.0"/>
</GridPane.margin>

View File

@ -23,22 +23,22 @@
<rowConstraints>
<RowConstraints vgrow="NEVER"/>
</rowConstraints>
<CheckBox fx:id="hideOfflineFX" onAction="#refreshList" mnemonicParsing="false" text="Hide offline">
<CheckBox fx:id="hideOfflineFX" onAction="#refreshList" text="Hide offline">
<GridPane.margin>
<Insets left="5.0" right="5.0"/>
</GridPane.margin>
</CheckBox>
<CheckBox fx:id="hideFullFX" onAction="#refreshList" mnemonicParsing="false" text="Hide full" GridPane.columnIndex="1">
<CheckBox fx:id="hideFullFX" onAction="#refreshList" text="Hide full" GridPane.columnIndex="1">
<GridPane.margin>
<Insets left="5.0" right="5.0"/>
</GridPane.margin>
</CheckBox>
<CheckBox fx:id="hideEmptyFX" onAction="#refreshList" mnemonicParsing="false" text="Hide empty" GridPane.columnIndex="2">
<CheckBox fx:id="hideEmptyFX" onAction="#refreshList" text="Hide empty" GridPane.columnIndex="2">
<GridPane.margin>
<Insets left="5.0" right="5.0"/>
</GridPane.margin>
</CheckBox>
<Button fx:id="addServerButtonFX" onAction="#addServer" mnemonicParsing="false" text="Add Server" GridPane.columnIndex="4"/>
<Button fx:id="addServerButtonFX" onAction="#addServer" text="Add Server" GridPane.columnIndex="4"/>
<GridPane.margin>
<Insets top="5.0"/>
</GridPane.margin>

View File

@ -40,11 +40,25 @@
-fx-border-color: -primary-light-color;
}
.button:armed, .button:focused {
.button:armed {
-fx-border-color: -primary-color;
-fx-background-color: -primary-color;
}
.button:default {
-fx-border-color: -primary-color;
}
.button:default:hover {
-fx-border-color: -primary-color;
-fx-background-color: -primary-color;
}
.button:default:armed {
-fx-border-color: -primary-dark-color;
-fx-background-color: -primary-dark-color;
}
/* Check box */
@ -267,3 +281,41 @@
.obfuscated {
-fx-font-family: 'monospaced';
}
/* Table view */
.table-view {
-fx-background-color: -secondary-color;
}
.table-view .table-column {
-fx-background-color: -secondary-light-color;
}
.table-view .placeholder {
-fx-background-color: -secondary-color;
-fx-border-width: 1px;
-fx-border-color: -secondary-light-color;
}
.table-row-cell {
-fx-background-color: -secondary-color;
-fx-text-background-color: -secondary-text-color;
}
.table-row-cell:hover {
-fx-background-color: -secondary-light-color;
}
.table-row-cell:selected {
-fx-background-color: -primary-color;
}
.table-row-cell:selected:hover {
-fx-background-color: -primary-dark-color;
}
.table-row-cell:empty {
-fx-background-color: -secondary-color;
}

View File

@ -44,6 +44,8 @@ minosoft:update_server.forced_version.label=Forced version
minosoft:update_server.forced_version.automatic=Auto detect
minosoft:update_server.forced_version.releases=Releases
minosoft:update_server.forced_version.snapshots=Snapshots
minosoft:update_server.profiles.label=Profiles
minosoft:update_server.profiles.open_select_dialog=Open profile selector
minosoft:update_server.add.title=Add server - Minosoft
minosoft:update_server.add.description=Please enter the server name, their hostname or IP address and select the version in order to add the server