mirror of
https://gitlab.bixilon.de/bixilon/minosoft.git
synced 2025-09-17 03:15:35 -04:00
ton of profile stuff, fixes
This commit is contained in:
parent
ec965fbd0b
commit
f155985ab1
@ -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,
|
||||
|
@ -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]
|
||||
}
|
||||
|
@ -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!" }
|
||||
}
|
||||
|
@ -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
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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)
|
||||
|
@ -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()
|
||||
|
||||
|
@ -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 {
|
||||
|
@ -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
|
||||
}
|
||||
}
|
||||
}
|
@ -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()
|
||||
}
|
||||
}
|
||||
|
@ -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()
|
||||
|
@ -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()
|
||||
}
|
||||
|
||||
|
@ -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()
|
||||
}
|
||||
}
|
||||
|
@ -24,7 +24,6 @@ import java.net.http.HttpResponse
|
||||
|
||||
object HTTP2 {
|
||||
|
||||
|
||||
fun Map<String, Any>.headers(): Array<String> {
|
||||
val headers: MutableList<String> = mutableListOf()
|
||||
|
||||
|
@ -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>
|
||||
|
@ -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>
|
||||
|
@ -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>
|
||||
|
@ -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>
|
@ -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>
|
||||
|
@ -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>
|
||||
|
@ -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>
|
||||
|
@ -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>
|
||||
|
@ -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>
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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
|
||||
|
Loading…
x
Reference in New Issue
Block a user