IJPL-158097 refactor Registry

GitOrigin-RevId: fc12759c96be04ffcca4e0df12f5d2502556d28d
This commit is contained in:
Vladimir Krivosheev
2024-07-10 14:47:25 +02:00
committed by intellij-monorepo-bot
parent f83776b01b
commit dc3c3f53ab
11 changed files with 483 additions and 504 deletions

View File

@@ -11805,10 +11805,9 @@ f:com.intellij.openapi.actionSystem.impl.ActionMenuItem
- f:updateFromPresentation(com.intellij.openapi.actionSystem.Presentation):V
- updateUI():V
c:com.intellij.openapi.actionSystem.impl.ActionToolbarImpl
- javax.swing.JPanel
- com.intellij.openapi.actionSystem.ActionToolbar
- com.intellij.ui.switcher.QuickActionProvider
- com.intellij.util.animation.AlphaAnimated
- javax.swing.JPanel
- sf:DO_NOT_ADD_CUSTOMIZATION_HANDLER:java.lang.String
- sf:IMPORTANT_TOOLBAR_KEY:java.lang.String
- sf:SUPPRESS_FAST_TRACK:java.lang.String
@@ -28697,28 +28696,6 @@ com.intellij.util.User32Ex
- a:SystemParametersInfo(com.sun.jna.platform.win32.WinDef$UINT,com.sun.jna.platform.win32.WinDef$UINT,com.sun.jna.platform.win32.WinDef$BOOLByReference,com.sun.jna.platform.win32.WinDef$UINT):Z
- a:SystemParametersInfo(com.sun.jna.platform.win32.WinDef$UINT,com.sun.jna.platform.win32.WinDef$UINT,com.sun.jna.platform.win32.WinDef$UINT,com.sun.jna.platform.win32.WinDef$UINT):Z
- a:SystemParametersInfo(com.sun.jna.platform.win32.WinDef$UINT,com.sun.jna.platform.win32.WinDef$UINT,com.sun.jna.platform.win32.WinDef$UINTByReference,com.sun.jna.platform.win32.WinDef$UINT):Z
*:com.intellij.util.animation.AlphaAnimated
- a:getAlphaContext():com.intellij.util.animation.AlphaAnimationContext
*f:com.intellij.util.animation.AlphaAnimationContext
- <init>(java.awt.AlphaComposite,java.util.function.Consumer):V
- <init>(java.awt.Component):V
- <init>(java.util.function.Consumer):V
- f:getAnimator():com.intellij.util.animation.ShowHideAnimator
- f:getComponent():java.awt.Component
- f:getComposite():java.awt.AlphaComposite
- f:getConsumer():java.util.function.Consumer
- f:getDisposable():com.intellij.openapi.Disposable
- f:isVisible():Z
- f:paint(java.awt.Graphics,java.lang.Runnable):V
- f:paintWithComposite(java.awt.Graphics2D,java.lang.Runnable):V
- f:setComponent(java.awt.Component):V
- f:setVisible(Z):V
*c:com.intellij.util.animation.ShowHideAnimator
- <init>(com.intellij.util.animation.Easing,java.util.function.DoubleConsumer):V
- <init>(java.util.function.DoubleConsumer):V
- f:getDisposable():com.intellij.openapi.Disposable
- f:setVisible(Z,kotlin.jvm.functions.Function0):V
- f:setVisibleImmediately(Z):V
a:com.intellij.util.concurrency.Invoker
- com.intellij.openapi.Disposable
- f:compute(java.util.function.Supplier):org.jetbrains.concurrency.CancellablePromise

View File

@@ -1,4 +1,4 @@
// Copyright 2000-2023 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
// Copyright 2000-2024 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
package com.intellij.openapi.util.registry
import com.intellij.diagnostic.runActivity
@@ -73,7 +73,7 @@ internal class RegistryManagerImpl : PersistentStateComponent<Element>, Registry
Registry.setValueChangeListener(defaultValueChangeListener)
}
override fun getState(): Element = Registry.getInstance().state
override fun getState(): Element = Registry.getInstance().getState()
override fun noStateLoaded() {
Registry.loadState(/* state = */ null, /* earlyAccess = */ EarlyAccessRegistryManager.getOrLoadMap())

View File

@@ -1,4 +1,6 @@
// Copyright 2000-2024 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
@file:Suppress("ReplaceGetOrSet")
package com.intellij.openapi.util.registry
import com.intellij.ide.util.PropertiesComponent
@@ -19,7 +21,7 @@ internal suspend fun migrateRegistryToAdvSettings() {
return
}
val userProperties = Registry.getInstance().userProperties
val userProperties = Registry.getInstance().getUserProperties()
for (setting in AdvancedSettingBean.EP_NAME.extensionList) {
when (setting.id) {
"editor.tab.painting" -> migrateEditorTabPainting(userProperties, setting)
@@ -29,7 +31,7 @@ internal suspend fun migrateRegistryToAdvSettings() {
val userProperty = userProperties[setting.id] ?: continue
try {
AdvancedSettings.getInstance().setSetting(setting.id, setting.valueFromString(userProperty), setting.type())
userProperties -= setting.id
userProperties.remove(setting.id)
}
catch (_: IllegalArgumentException) { }
}
@@ -40,11 +42,11 @@ internal suspend fun migrateRegistryToAdvSettings() {
private fun migrateEditorTabPainting(userProperties: MutableMap<String, String>, setting: AdvancedSettingBean) {
val mode = if (userProperties["editor.old.tab.painting"] == "true") {
userProperties -= "editor.old.tab.painting"
userProperties.remove("editor.old.tab.painting")
TabCharacterPaintMode.LONG_ARROW
}
else if (userProperties["editor.arrow.tab.painting"] == "true") {
userProperties -= "editor.arrow.tab.painting"
userProperties.remove("editor.arrow.tab.painting")
TabCharacterPaintMode.ARROW
}
else {
@@ -55,13 +57,13 @@ private fun migrateEditorTabPainting(userProperties: MutableMap<String, String>,
private fun migrateVcsIgnoreProcessing(userProperties: MutableMap<String, String>, setting: AdvancedSettingBean) {
if (userProperties["git.process.ignored"] == "false") {
userProperties -= "git.process.ignored"
userProperties.remove("git.process.ignored")
}
else if (userProperties["hg4idea.process.ignored"] == "false") {
userProperties -= "hg4idea.process.ignored"
userProperties.remove("hg4idea.process.ignored")
}
else if (userProperties["p4.process.ignored"] == "false") {
userProperties -= "p4.process.ignored"
userProperties.remove("p4.process.ignored")
}
else {
return
@@ -71,11 +73,11 @@ private fun migrateVcsIgnoreProcessing(userProperties: MutableMap<String, String
private fun migrateNativeChooser(userProperties: MutableMap<String, String>, setting: AdvancedSettingBean) {
val enabled = when {
SystemInfo.isWindows -> userProperties["ide.win.file.chooser.native"] ?: System.getProperty("ide.win.file.chooser.native")
SystemInfo.isMac -> userProperties["ide.mac.file.chooser.native"] ?: System.getProperty("ide.mac.file.chooser.native") ?: "true"
SystemInfo.isWindows -> userProperties.get("ide.win.file.chooser.native") ?: System.getProperty("ide.win.file.chooser.native")
SystemInfo.isMac -> userProperties.get("ide.mac.file.chooser.native") ?: System.getProperty("ide.mac.file.chooser.native") ?: "true"
else -> null
} ?: return
userProperties -= "ide.win.file.chooser.native"
userProperties -= "ide.mac.file.chooser.native"
userProperties.remove("ide.win.file.chooser.native")
userProperties.remove("ide.mac.file.chooser.native")
AdvancedSettings.getInstance().setSetting(setting.id, enabled.toBoolean(), setting.type())
}

View File

@@ -1,9 +1,9 @@
// Copyright 2000-2021 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
// Copyright 2000-2024 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
package com.intellij.util.animation
import org.jetbrains.annotations.ApiStatus.Experimental
@Experimental
interface AlphaAnimated {
internal interface AlphaAnimated {
val alphaContext: AlphaAnimationContext
}

View File

@@ -1,4 +1,4 @@
// Copyright 2000-2021 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
// Copyright 2000-2024 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
package com.intellij.util.animation
import com.intellij.openapi.Disposable
@@ -8,7 +8,7 @@ import java.awt.Graphics
import java.awt.Graphics2D
import java.util.function.Consumer
class AlphaAnimationContext(private val base: AlphaComposite, val consumer: Consumer<AlphaComposite?>) {
internal class AlphaAnimationContext(private val base: AlphaComposite, private val consumer: Consumer<AlphaComposite?>) {
constructor(consumer: Consumer<AlphaComposite?>) : this(AlphaComposite.SrcOver, consumer)
constructor(component: Component) : this({ if (component.isShowing) component.repaint() }) {
this.component = component

View File

@@ -1,13 +1,13 @@
// Copyright 2000-2021 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
// Copyright 2000-2024 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
package com.intellij.util.animation
import com.intellij.openapi.Disposable
import com.intellij.openapi.util.registry.Registry.intValue
import com.intellij.openapi.util.registry.Registry
import java.util.concurrent.atomic.AtomicBoolean
import java.util.function.DoubleConsumer
import kotlin.math.roundToInt
open class ShowHideAnimator(easing: Easing, private val consumer: DoubleConsumer) {
internal open class ShowHideAnimator(easing: Easing, private val consumer: DoubleConsumer) {
private val animator = JBAnimator()
private val atomicVisible = AtomicBoolean()
private val statefulEasing = easing.stateful()
@@ -38,16 +38,16 @@ open class ShowHideAnimator(easing: Easing, private val consumer: DoubleConsumer
}
private val showingDelay
get() = intValue("ide.animation.showing.delay", 0)
get() = Registry.intValue("ide.animation.showing.delay", 0)
private val showingDuration
get() = intValue("ide.animation.showing.duration", 130)
get() = Registry.intValue("ide.animation.showing.duration", 130)
private val hidingDelay
get() = intValue("ide.animation.hiding.delay", 140)
get() = Registry.intValue("ide.animation.hiding.delay", 140)
private val hidingDuration
get() = intValue("ide.animation.hiding.duration", 150)
get() = Registry.intValue("ide.animation.hiding.duration", 150)
private fun createShowingAnimation(value: Double, updateVisibility: () -> Unit) = Animation(consumer).apply {
if (value > 0.0) {
@@ -60,7 +60,8 @@ open class ShowHideAnimator(easing: Easing, private val consumer: DoubleConsumer
easing = statefulEasing
}
}.runWhenScheduled {
if (atomicVisible.get()) { // Most likely not needed, just for consistency with hide. In the worst case we just avoid minor flickering here.
if (atomicVisible.get()) { // Most likely not needed, just for consistency with hide.
// In the worst case, we just avoid minor flickering here.
updateVisibility()
}
}
@@ -76,7 +77,7 @@ open class ShowHideAnimator(easing: Easing, private val consumer: DoubleConsumer
easing = statefulEasing.reverse()
}
}.runWhenExpiredOrCancelled {
if (!atomicVisible.get()) { // If the animation is cancelled and the component was already made visible, we do NOT want to hide it again!
if (!atomicVisible.get()) { // If the animation is canceled and the component was already made visible, we do NOT want to hide it again!
updateVisibility()
}
}

View File

@@ -1,4 +1,4 @@
// Copyright 2000-2023 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
// Copyright 2000-2024 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
package com.intellij.testFramework;
import com.intellij.concurrency.IdeaForkJoinWorkerThreadFactory;
@@ -139,7 +139,7 @@ public abstract class ParsingTestCase extends UsefulTestCase {
// That's for reparse routines
project.registerService(PomModel.class, new PomModelImpl(project));
Registry.markAsLoaded();
Registry.Companion.markAsLoaded();
LoadingState.setCurrentState(LoadingState.PROJECT_OPENED);
}

View File

@@ -1644,23 +1644,42 @@ f:com.intellij.openapi.util.io.WindowsRegistryUtil
- s:readRegistryDefault(java.lang.String):java.lang.String
- s:readRegistryValue(java.lang.String,java.lang.String):java.lang.String
f:com.intellij.openapi.util.registry.Registry
- sf:Companion:com.intellij.openapi.util.registry.Registry$Companion
- sf:REGISTRY_BUNDLE:java.lang.String
- <init>():V
- s:doubleValue(java.lang.String):D
- s:doubleValue(java.lang.String,D):D
- s:get(java.lang.String):com.intellij.openapi.util.registry.RegistryValue
- getBundleValueOrNull(java.lang.String):java.lang.String
- s:getColor(java.lang.String,java.awt.Color):java.awt.Color
- s:getInstance():com.intellij.openapi.util.registry.Registry
- getState():org.jdom.Element
- s:intValue(java.lang.String):I
- s:intValue(java.lang.String,I):I
- s:intValue(java.lang.String,I,I,I):I
- s:is(java.lang.String):Z
- s:is(java.lang.String,Z):Z
- isLoaded():Z
- isRestartNeeded():Z
- s:stringValue(java.lang.String):java.lang.String
- sf:doubleValue(java.lang.String):D
- sf:doubleValue(java.lang.String,D):D
- sf:get(java.lang.String):com.intellij.openapi.util.registry.RegistryValue
- f:getBundleValue(java.lang.String):java.lang.String
- f:getBundleValueOrNull(java.lang.String):java.lang.String
- sf:getColor(java.lang.String,java.awt.Color):java.awt.Color
- sf:getInstance():com.intellij.openapi.util.registry.Registry
- f:getState():org.jdom.Element
- f:getValueChangeListener():com.intellij.openapi.util.registry.RegistryValueListener
- sf:intValue(java.lang.String):I
- sf:intValue(java.lang.String,I):I
- sf:intValue(java.lang.String,I,I,I):I
- sf:is(java.lang.String):Z
- sf:is(java.lang.String,Z):Z
- f:isInDefaultState():Z
- f:isLoaded():Z
- f:isRestartNeeded():Z
- f:reset():V
- f:restoreDefaults():V
- sf:stringValue(java.lang.String):java.lang.String
f:com.intellij.openapi.util.registry.Registry$Companion
- f:awaitLoad():java.util.concurrent.CompletionStage
- f:doubleValue(java.lang.String):D
- f:doubleValue(java.lang.String,D):D
- f:get(java.lang.String):com.intellij.openapi.util.registry.RegistryValue
- f:getColor(java.lang.String,java.awt.Color):java.awt.Color
- f:getInstance():com.intellij.openapi.util.registry.Registry
- f:intValue(java.lang.String):I
- f:intValue(java.lang.String,I):I
- f:intValue(java.lang.String,I,I,I):I
- f:is(java.lang.String):Z
- f:is(java.lang.String,Z):Z
- f:stringValue(java.lang.String):java.lang.String
c:com.intellij.openapi.util.registry.RegistryValue
- addListener(com.intellij.openapi.util.registry.RegistryValueListener,com.intellij.openapi.Disposable):V
- addListener(com.intellij.openapi.util.registry.RegistryValueListener,kotlinx.coroutines.CoroutineScope):V

View File

@@ -1,402 +1,382 @@
// Copyright 2000-2023 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
package com.intellij.openapi.util.registry;
// Copyright 2000-2024 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
@file:Suppress("ReplaceGetOrSet", "ReplacePutWithAssignment")
import com.intellij.diagnostic.LoadingState;
import com.intellij.openapi.util.NlsSafe;
import com.intellij.util.MathUtil;
import org.jdom.Element;
import org.jetbrains.annotations.*;
package com.intellij.openapi.util.registry
import java.awt.*;
import java.io.IOException;
import java.io.InputStream;
import java.io.UncheckedIOException;
import java.lang.ref.Reference;
import java.lang.ref.SoftReference;
import java.util.List;
import java.util.*;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.CompletionStage;
import java.util.concurrent.ConcurrentHashMap;
import java.util.function.Function;
import com.intellij.diagnostic.LoadingState
import com.intellij.openapi.util.NlsSafe
import kotlinx.coroutines.CompletableDeferred
import org.jdom.Element
import org.jetbrains.annotations.ApiStatus.Internal
import org.jetbrains.annotations.NonNls
import org.jetbrains.annotations.TestOnly
import java.awt.Color
import java.io.IOException
import java.lang.ref.Reference
import java.lang.ref.SoftReference
import java.util.*
import java.util.concurrent.ConcurrentHashMap
import kotlin.concurrent.Volatile
/**
* Provides a UI to configure internal settings of the IDE.
* <p>
*
*
* Plugins can provide their own registry keys using the
* {@code com.intellij.registryKey} extension point (see {@link RegistryKeyBean} for more details).
* `com.intellij.registryKey` extension point (see [com.intellij.openapi.util.registry.RegistryKeyBean] for more details).
*/
public final class Registry {
private static Reference<Map<String, String>> bundledRegistry;
class Registry {
private val userProperties = LinkedHashMap<String, String>()
private val values = ConcurrentHashMap<String, RegistryValue>()
private var contributedKeys = emptyMap<String, RegistryKeyDescriptor>()
public static final @NonNls String REGISTRY_BUNDLE = "misc.registry";
@Volatile
var isLoaded: Boolean = false
private set
private static final RegistryValueListener EMPTY_VALUE_LISTENER = new RegistryValueListener() {
};
@Volatile
private var loadFuture = CompletableFuture<Void?>()
private final Map<String, String> myUserProperties = new LinkedHashMap<>();
private final Map<String, RegistryValue> myValues = new ConcurrentHashMap<>();
private Map<String, RegistryKeyDescriptor> myContributedKeys = Collections.emptyMap();
@Volatile
var valueChangeListener: RegistryValueListener = EMPTY_VALUE_LISTENER
private set
private static final Registry ourInstance = new Registry();
private volatile boolean isLoaded;
private volatile CompletableFuture<Void> myLoadFuture = new CompletableFuture<>();
companion object {
private var bundledRegistry: Reference<Map<String, String>>? = null
private volatile @NotNull RegistryValueListener valueChangeListener = EMPTY_VALUE_LISTENER;
const val REGISTRY_BUNDLE: @NonNls String = "misc.registry"
public static @NotNull RegistryValue get(@NonNls @NotNull String key) {
return getInstance().doGet(key);
}
@ApiStatus.Internal
public static @NotNull RegistryValue _getWithoutStateCheck(@NonNls @NotNull String key) {
return ourInstance.doGet(key);
}
private @NotNull RegistryValue doGet(@NonNls @NotNull String key) {
return myValues.computeIfAbsent(key, s -> new RegistryValue(this, s, myContributedKeys.get(s)));
}
public static boolean is(@NonNls @NotNull String key) throws MissingResourceException {
return get(key).asBoolean();
}
public static boolean is(@NonNls @NotNull String key, boolean defaultValue) {
if (!LoadingState.COMPONENTS_LOADED.isOccurred()) {
return defaultValue;
private val EMPTY_VALUE_LISTENER: RegistryValueListener = object : RegistryValueListener {
}
try {
return getInstance().doGet(key).asBoolean();
private val registry = Registry()
@JvmStatic
fun get(key: @NonNls String): RegistryValue = getInstance().doGet(key)
@Suppress("FunctionName")
@Internal
@JvmStatic
fun _getWithoutStateCheck(key: @NonNls String): RegistryValue = registry.doGet(key)
@Throws(MissingResourceException::class)
@JvmStatic
fun `is`(key: @NonNls String): Boolean = get(key).asBoolean()
@JvmStatic
fun `is`(key: @NonNls String, defaultValue: Boolean): Boolean {
if (!LoadingState.COMPONENTS_LOADED.isOccurred) {
return defaultValue
}
try {
return registry.doGet(key).asBoolean()
}
catch (ignore: MissingResourceException) {
return defaultValue
}
}
catch (MissingResourceException ignore) {
return defaultValue;
@Throws(MissingResourceException::class)
@JvmStatic
fun intValue(key: @NonNls String): Int = getInstance().doGet(key).asInteger()
@JvmStatic
fun intValue(key: @NonNls String, defaultValue: Int): Int {
if (!LoadingState.COMPONENTS_LOADED.isOccurred) {
LoadingState.COMPONENTS_REGISTERED.checkOccurred()
return defaultValue
}
try {
return registry.doGet(key).asInteger()
}
catch (ignore: MissingResourceException) {
return defaultValue
}
}
@JvmStatic
fun doubleValue(key: @NonNls String, defaultValue: Double): Double {
if (!LoadingState.COMPONENTS_LOADED.isOccurred) {
LoadingState.COMPONENTS_REGISTERED.checkOccurred()
return defaultValue
}
try {
return registry.doGet(key).asDouble()
}
catch (ignore: MissingResourceException) {
return defaultValue
}
}
@Throws(MissingResourceException::class)
@JvmStatic
fun doubleValue(key: @NonNls String): Double = get(key).asDouble()
@Throws(MissingResourceException::class)
@JvmStatic
fun stringValue(key: @NonNls String): String = get(key).asString()
@Throws(MissingResourceException::class)
@JvmStatic
fun getColor(key: @NonNls String, defaultValue: Color?): Color = get(key).asColor(defaultValue)
@Throws(IOException::class)
private fun loadFromBundledConfig(): Map<String, String>? {
bundledRegistry?.get()?.let {
return it
}
val map: MutableMap<String, String> = LinkedHashMap(1800)
val mainFound = loadFromResource("misc/registry.properties", map)
val overrideFound = loadFromResource("misc/registry.override.properties", map)
if (!mainFound && !overrideFound) {
return null
}
bundledRegistry = SoftReference(map)
return map
}
private fun loadFromResource(sourceResourceName: String, targetMap: MutableMap<String, String>): Boolean {
val stream = Registry::class.java.classLoader.getResourceAsStream(sourceResourceName) ?: return false
stream.use {
object : Properties() {
override fun put(key: Any, value: Any): Any? {
return targetMap.put(key as String, value as String)
}
}.load(stream)
}
return true
}
@JvmStatic
fun getInstance(): Registry {
LoadingState.COMPONENTS_LOADED.checkOccurred()
return registry
}
@JvmStatic
fun intValue(key: @NonNls String, defaultValue: Int, minValue: Int, maxValue: Int): Int {
require(!(defaultValue < minValue || defaultValue > maxValue)) {
"Wrong values for default:min:max ($defaultValue:$minValue:$maxValue)"
}
return intValue(key, defaultValue).coerceIn(minValue, maxValue)
}
private fun fromState(state: Element): Map<String, String> {
val map = LinkedHashMap<String, String>()
for (eachEntry in state.getChildren("entry")) {
val key = eachEntry.getAttributeValue("key") ?: continue
val value = eachEntry.getAttributeValue("value") ?: continue
map.put(key, value)
}
return map
}
private fun updateStateInternal(registry: Registry, state: Element?): Map<String, String> {
val userProperties = registry.userProperties
if (state == null) {
userProperties.clear()
return userProperties
}
val map = fromState(state)
val keysToProcess = HashSet(userProperties.keys)
for ((key, value) in map) {
val registryValue = registry.doGet(key)
val currentValue = registryValue.get(key, null, false)
// currentValue == null means value is not in the bundle. Ignore it
if (currentValue != null && currentValue != value) {
registryValue.setValue(value)
}
keysToProcess.remove(key)
}
// keys that are not in the state; we need to reset them to default value
for (key in keysToProcess) {
registry.doGet(key).resetToDefault()
}
return userProperties
}
@Internal
fun loadState(state: Element?, earlyAccess: Map<String, String>?): Map<String, String> {
val registry = registry
if (registry.isLoaded) {
return updateStateInternal(registry, state)
}
else {
return loadStateInternal(registry = registry, state = state, earlyAccess = earlyAccess)
}
}
@Internal
@JvmStatic
fun markAsLoaded() {
registry.isLoaded = true
registry.loadFuture.complete(null)
}
fun awaitLoad(): CompletionStage<Void?> = registry.loadFuture
@Internal
@JvmStatic
fun getAll(): List<RegistryValue> {
var bundle: Map<String, String>? = null
try {
bundle = loadFromBundledConfig()
}
catch (ignored: IOException) {
}
val keys = bundle?.keys ?: emptySet()
val result = ArrayList<RegistryValue>()
// don't use getInstance here - https://youtrack.jetbrains.com/issue/IDEA-271748
val instance = registry
val contributedKeys = instance.contributedKeys
for (key in keys) {
if (key.endsWith(".description") || key.endsWith(".restartRequired") || contributedKeys.containsKey(key)) {
continue
}
result.add(instance.doGet(key))
}
for (key in contributedKeys.keys) {
result.add(instance.doGet(key))
}
return result
}
private fun isRestartNeeded(map: Map<String, String>): Boolean {
val instance = getInstance()
for (s in map.keys) {
val eachValue = instance.doGet(s)
if (eachValue.isRestartRequired && eachValue.isChangedSinceAppStart) {
return true
}
}
return false
}
@Internal
@Synchronized
fun setKeys(descriptors: Map<String, RegistryKeyDescriptor>) {
// getInstance must be not used here - phase COMPONENT_REGISTERED is not yet completed
registry.contributedKeys = descriptors
}
@Internal
@Synchronized
fun mutateContributedKeys(mutator: (Map<String, RegistryKeyDescriptor>) -> Map<String, RegistryKeyDescriptor>) {
// getInstance must be not used here - phase COMPONENT_REGISTERED is not yet completed
registry.contributedKeys = mutator(registry.contributedKeys)
}
@Internal
fun setValueChangeListener(listener: RegistryValueListener?) {
registry.valueChangeListener = listener ?: EMPTY_VALUE_LISTENER
}
private fun loadStateInternal(
registry: Registry,
state: Element?,
earlyAccess: Map<String, String>?
): Map<String, String> {
val userProperties = registry.userProperties
userProperties.clear()
if (state != null) {
val map = fromState(state)
for ((key, value) in map) {
val registryValue = registry.doGet(key)
if (registryValue.isChangedFromDefault(value, registry)) {
userProperties[key] = value
registryValue.resetCache()
}
}
}
if (earlyAccess != null) {
// yes, earlyAccess overrides user properties
userProperties.putAll(earlyAccess)
}
registry.isLoaded = true
registry.loadFuture.complete(null)
return userProperties
}
}
public static int intValue(@NonNls @NotNull String key) throws MissingResourceException {
return getInstance().doGet(key).asInteger();
}
public static int intValue(@NonNls @NotNull String key, int defaultValue) {
if (!LoadingState.COMPONENTS_LOADED.isOccurred()) {
LoadingState.COMPONENTS_REGISTERED.checkOccurred();
return defaultValue;
}
try {
return getInstance().doGet(key).asInteger();
}
catch (MissingResourceException ignore) {
return defaultValue;
private fun doGet(key: @NonNls String): RegistryValue {
return values.computeIfAbsent(key) {
RegistryValue(this, it, contributedKeys.get(it))
}
}
@TestOnly
void reset() {
myUserProperties.clear();
myValues.clear();
isLoaded = false;
myLoadFuture.cancel(false);
myLoadFuture = new CompletableFuture<>();
fun reset() {
userProperties.clear()
values.clear()
isLoaded = false
loadFuture.cancel(false)
loadFuture = CompletableFuture()
}
public static double doubleValue(@NonNls @NotNull String key, double defaultValue) {
if (!LoadingState.COMPONENTS_LOADED.isOccurred()) {
LoadingState.COMPONENTS_REGISTERED.checkOccurred();
return defaultValue;
fun getBundleValueOrNull(key: @NonNls String): @NlsSafe String? {
contributedKeys.get(key)?.let {
return it.defaultValue
}
try {
return getInstance().doGet(key).asDouble();
}
catch (MissingResourceException ignore) {
return defaultValue;
}
return loadFromBundledConfig()?.get(key)
}
public static double doubleValue(@NonNls @NotNull String key) throws MissingResourceException {
return get(key).asDouble();
@Throws(MissingResourceException::class)
fun getBundleValue(key: @NonNls String): @NlsSafe String {
contributedKeys.get(key)?.let {
return it.defaultValue
}
return getBundleValueOrNull(key) ?: throw MissingResourceException("Registry key $key is not defined", REGISTRY_BUNDLE, key)
}
public static @NotNull String stringValue(@NonNls @NotNull String key) throws MissingResourceException {
return get(key).asString();
}
public static Color getColor(@NonNls @NotNull String key, Color defaultValue) throws MissingResourceException {
return get(key).asColor(defaultValue);
}
private static @Nullable Map<String, String> loadFromBundledConfig() throws IOException {
Reference<Map<String, String>> bundleRef = bundledRegistry;
Map<String, String> result = bundleRef == null ? null : bundleRef.get();
if (result != null) {
return result;
}
Map<String, String> map = new LinkedHashMap<>(1_800);
boolean mainFound = loadFromResource("misc/registry.properties", map);
boolean overrideFound = loadFromResource("misc/registry.override.properties", map);
if (!mainFound && !overrideFound) {
return null;
}
bundledRegistry = new SoftReference<>(map);
return map;
}
private static boolean loadFromResource(String sourceResourceName, Map<String, String> targetMap) throws IOException {
InputStream stream = Registry.class.getClassLoader().getResourceAsStream(sourceResourceName);
if (stream == null) {
return false;
}
try {
//noinspection NonSynchronizedMethodOverridesSynchronizedMethod
new Properties() {
@Override
public Object put(Object key, Object value) {
return targetMap.put((String)key, (String)value);
}
}.load(stream);
}
finally {
stream.close();
}
return true;
}
public @NlsSafe @Nullable String getBundleValueOrNull(@NonNls @NotNull String key) {
RegistryKeyDescriptor contributed = myContributedKeys.get(key);
if (contributed != null) {
return contributed.getDefaultValue();
}
try {
Map<String, String> bundle = loadFromBundledConfig();
return bundle == null ? null : bundle.get(key);
}
catch (IOException e) {
// critical start-up error (cannot parse properties file), don't bother clients
throw new UncheckedIOException(e);
}
}
@NlsSafe @NotNull String getBundleValue(@NonNls @NotNull String key) throws MissingResourceException {
RegistryKeyDescriptor contributed = myContributedKeys.get(key);
if (contributed != null) {
return contributed.getDefaultValue();
}
String result = getBundleValueOrNull(key);
if (result == null) {
throw new MissingResourceException("Registry key " + key + " is not defined", REGISTRY_BUNDLE, key);
}
return result;
}
public static @NotNull Registry getInstance() {
LoadingState.COMPONENTS_LOADED.checkOccurred();
return ourInstance;
}
public @NotNull Element getState() {
Element state = new Element("registry");
for (Map.Entry<String, String> entry : myUserProperties.entrySet()) {
RegistryValue registryValue = get(entry.getKey());
if (registryValue.isChangedFromDefault()) {
Element entryElement = new Element("entry");
entryElement.setAttribute("key", entry.getKey());
entryElement.setAttribute("value", entry.getValue());
state.addContent(entryElement);
fun getState(): Element {
val state = Element("registry")
for ((key, value) in userProperties) {
val registryValue = getInstance().doGet(key)
if (registryValue.isChangedFromDefault) {
val entryElement = Element("entry")
entryElement.setAttribute("key", key)
entryElement.setAttribute("value", value)
state.addContent(entryElement)
}
}
return state;
return state
}
public static int intValue(@NonNls @NotNull String key, int defaultValue, int minValue, int maxValue) {
if (defaultValue < minValue || defaultValue > maxValue) {
throw new IllegalArgumentException("Wrong values for default:min:max (" + defaultValue + ":" + minValue + ":" + maxValue + ")");
}
return MathUtil.clamp(intValue(key, defaultValue), minValue, maxValue);
}
@Internal
fun getUserProperties(): MutableMap<String, String> = userProperties
private static @NotNull Map<String, String> fromState(@NotNull Element state) {
Map<String, String> map = new LinkedHashMap<>();
for (Element eachEntry : state.getChildren("entry")) {
String key = eachEntry.getAttributeValue("key");
String value = eachEntry.getAttributeValue("value");
if (key != null && value != null) {
map.put(key, value);
}
}
return map;
}
private static @NotNull Map<String, String> updateStateInternal(@NotNull Registry registry, @Nullable Element state) {
Map<String, String> userProperties = registry.myUserProperties;
if (state == null) {
userProperties.clear();
return userProperties;
}
Map<String, String> map = fromState(state);
Set<String> keys2process = new HashSet<>(userProperties.keySet());
for (Map.Entry<String, String> entry : map.entrySet()) {
RegistryValue registryValue = registry.doGet(entry.getKey());
String currentValue = registryValue.get(entry.getKey(), null, false);
// currentValue == null means value is not in the bundle. Simply ignore it
if (currentValue != null && !currentValue.equals(entry.getValue())) {
registryValue.setValue(entry.getValue());
}
keys2process.remove(entry.getKey());
}
// keys that are not in the state, we need to reset them to default value
for (String key : keys2process) {
registry.doGet(key).resetToDefault();
}
return userProperties;
}
@ApiStatus.Internal
public static @NotNull Map<String, String> loadState(@Nullable Element state, @Nullable Map<String, String> earlyAccess) {
Registry registry = ourInstance;
if (registry.isLoaded) {
return updateStateInternal(registry, state);
}
else {
return loadStateInternal(registry, state, earlyAccess);
}
}
@ApiStatus.Internal
public static void markAsLoaded() {
ourInstance.isLoaded = true;
ourInstance.myLoadFuture.complete(null);
}
public boolean isLoaded() {
return isLoaded;
}
static CompletionStage<Void> awaitLoad() {
return ourInstance.myLoadFuture;
}
@NotNull Map<String, String> getUserProperties() {
return myUserProperties;
}
@ApiStatus.Internal
public static @NotNull List<RegistryValue> getAll() {
Map<String, String> bundle = null;
try {
bundle = loadFromBundledConfig();
}
catch (IOException ignored) {
}
Set<String> keys = bundle == null ? Collections.emptySet() : bundle.keySet();
List<RegistryValue> result = new ArrayList<>();
// don't use getInstance here - https://youtrack.jetbrains.com/issue/IDEA-271748
Registry instance = ourInstance;
Map<String, RegistryKeyDescriptor> contributedKeys = instance.myContributedKeys;
for (String key : keys) {
if (key.endsWith(".description") || key.endsWith(".restartRequired") || contributedKeys.containsKey(key)) {
continue;
}
result.add(instance.doGet(key));
}
for (String key : contributedKeys.keySet()) {
result.add(instance.doGet(key));
}
return result;
}
void restoreDefaults() {
Map<String, String> old = new LinkedHashMap<>(myUserProperties);
Registry instance = getInstance();
for (String key : old.keySet()) {
String v = instance.getBundleValueOrNull(key);
fun restoreDefaults() {
val old = LinkedHashMap(userProperties)
val registry = getInstance()
for (key in old.keys) {
val v = registry.getBundleValueOrNull(key)
if (v == null) {
// outdated property that is not declared in registry.properties anymore
myValues.remove(key);
values.remove(key)
}
else {
RegistryValue value = instance.myValues.get(key);
if (value != null) {
value.setValue(v);
}
registry.values.get(key)?.setValue(v)
}
}
}
boolean isInDefaultState() {
return myUserProperties.isEmpty();
}
val isInDefaultState: Boolean
get() = userProperties.isEmpty()
public boolean isRestartNeeded() {
return isRestartNeeded(myUserProperties);
}
private static boolean isRestartNeeded(@NotNull Map<String, String> map) {
Registry instance = getInstance();
for (String s : map.keySet()) {
RegistryValue eachValue = instance.doGet(s);
if (eachValue.isRestartRequired() && eachValue.isChangedSinceAppStart()) {
return true;
}
}
return false;
}
@ApiStatus.Internal
public static synchronized void setKeys(@NotNull Map<String, RegistryKeyDescriptor> descriptors) {
// getInstance must be not used here - phase COMPONENT_REGISTERED is not yet completed
ourInstance.myContributedKeys = descriptors;
}
@ApiStatus.Internal
public static synchronized void mutateContributedKeys(@NotNull Function<? super Map<String, RegistryKeyDescriptor>, ? extends Map<String, RegistryKeyDescriptor>> mutator) {
// getInstance must be not used here - phase COMPONENT_REGISTERED is not yet completed
ourInstance.myContributedKeys = mutator.apply(ourInstance.myContributedKeys);
}
@ApiStatus.Internal
public static void setValueChangeListener(@Nullable RegistryValueListener listener) {
ourInstance.valueChangeListener = listener == null ? EMPTY_VALUE_LISTENER : listener;
}
@NotNull RegistryValueListener getValueChangeListener() {
return valueChangeListener;
}
private static @NotNull Map<String, String> loadStateInternal(@NotNull Registry registry,
@Nullable Element state,
@Nullable Map<String, String> earlyAccess) {
Map<String, String> userProperties = registry.myUserProperties;
userProperties.clear();
if (state != null) {
Map<String, String> map = fromState(state);
for (Map.Entry<String, String> entry : map.entrySet()) {
RegistryValue registryValue = registry.doGet(entry.getKey());
if (registryValue.isChangedFromDefault(entry.getValue(), registry)) {
userProperties.put(entry.getKey(), entry.getValue());
registryValue.resetCache();
}
}
}
if (earlyAccess != null) {
// yes, earlyAccess overrides user properties
userProperties.putAll(earlyAccess);
}
registry.isLoaded = true;
registry.myLoadFuture.complete(null);
return userProperties;
}
val isRestartNeeded: Boolean
get() = isRestartNeeded(userProperties)
}

View File

@@ -1,4 +1,4 @@
// Copyright 2000-2023 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
// Copyright 2000-2024 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
package com.intellij.openapi.util.registry;
import com.intellij.openapi.Disposable;
@@ -28,59 +28,59 @@ import java.util.Objects;
public class RegistryValue {
private static final Logger LOG = Logger.getInstance(RegistryValue.class);
private final Registry myRegistry;
private final String myKey;
private final @Nullable RegistryKeyDescriptor myKeyDescriptor;
private final Registry registry;
private final String key;
private final @Nullable RegistryKeyDescriptor keyDescriptor;
private final List<RegistryValueListener> myListeners = ContainerUtil.createLockFreeCopyOnWriteList();
private final List<RegistryValueListener> listeners = ContainerUtil.createLockFreeCopyOnWriteList();
private boolean myChangedSinceStart;
private String myStringCachedValue;
private Integer myIntCachedValue;
private double myDoubleCachedValue = Double.NaN;
private Boolean myBooleanCachedValue;
private String stringCachedValue;
private Integer intCachedValue;
private double doubleCachedValue = Double.NaN;
private Boolean booleanCachedValue;
RegistryValue(@NotNull Registry registry, @NonNls @NotNull String key, @Nullable RegistryKeyDescriptor keyDescriptor) {
myRegistry = registry;
myKey = key;
myKeyDescriptor = keyDescriptor;
this.registry = registry;
this.key = key;
this.keyDescriptor = keyDescriptor;
}
public @NotNull @NlsSafe String getKey() {
return myKey;
return key;
}
public @NotNull @NlsSafe String asString() {
final String value = get(myKey, null, true);
assert value != null : myKey;
final String value = get(key, null, true);
assert value != null : key;
return value;
}
public boolean asBoolean() {
Boolean result = myBooleanCachedValue;
Boolean result = booleanCachedValue;
if (result == null) {
result = Boolean.valueOf(get(myKey, "false", true));
myBooleanCachedValue = result;
result = Boolean.valueOf(get(key, "false", true));
booleanCachedValue = result;
}
return result.booleanValue();
}
public int asInteger() {
Integer result = myIntCachedValue;
Integer result = intCachedValue;
if (result == null) {
result = calcInt();
myIntCachedValue = result;
intCachedValue = result;
}
return result.intValue();
}
private @NotNull Integer calcInt() {
try {
return Integer.valueOf(get(myKey, "0", true));
return Integer.valueOf(get(key, "0", true));
}
catch (NumberFormatException e) {
return Integer.valueOf(myRegistry.getBundleValue(myKey));
return Integer.valueOf(registry.getBundleValue(key));
}
}
@@ -89,7 +89,7 @@ public class RegistryValue {
}
public String[] getOptions() {
return getOptions(myRegistry.getBundleValue(myKey));
return getOptions(registry.getBundleValue(key));
}
private static String[] getOptions(String value) {
@@ -134,28 +134,28 @@ public class RegistryValue {
}
public double asDouble() {
double result = myDoubleCachedValue;
double result = doubleCachedValue;
if (Double.isNaN(result)) {
result = calcDouble();
myDoubleCachedValue = result;
doubleCachedValue = result;
}
return result;
}
private double calcDouble() {
try {
return Double.parseDouble(get(myKey, "0.0", true));
return Double.parseDouble(get(key, "0.0", true));
}
catch (NumberFormatException e) {
return Double.parseDouble(myRegistry.getBundleValue(myKey));
return Double.parseDouble(registry.getBundleValue(key));
}
}
Color asColor(Color defaultValue) {
final String s = get(myKey, null, true);
final String s = get(key, null, true);
if (s != null) {
Color color = ColorHexUtil.fromHex(s, null);
if (color != null && (myKey.endsWith(".color") || myKey.endsWith(".color.dark") || myKey.endsWith(".color.light"))) {
if (color != null && (key.endsWith(".color") || key.endsWith(".color.dark") || key.endsWith(".color.light"))) {
return color;
}
final String[] rgb = s.split(",");
@@ -171,43 +171,43 @@ public class RegistryValue {
}
public @NotNull @NlsSafe String getDescription() {
if (myKeyDescriptor != null) {
return myKeyDescriptor.getDescription();
if (keyDescriptor != null) {
return keyDescriptor.getDescription();
}
return get(myKey + ".description", "", false);
return get(key + ".description", "", false);
}
boolean isRestartRequired() {
if (myKeyDescriptor != null) {
return myKeyDescriptor.isRestartRequired();
if (keyDescriptor != null) {
return keyDescriptor.isRestartRequired();
}
return Boolean.parseBoolean(get(myKey + ".restartRequired", "false", false));
return Boolean.parseBoolean(get(key + ".restartRequired", "false", false));
}
public boolean isChangedFromDefault() {
return isChangedFromDefault(asString(), myRegistry);
return isChangedFromDefault(asString(), registry);
}
public @Nullable String getPluginId() {
return myKeyDescriptor != null ? myKeyDescriptor.getPluginId() : null;
return keyDescriptor != null ? keyDescriptor.getPluginId() : null;
}
final boolean isChangedFromDefault(@NotNull String newValue, @NotNull Registry registry) {
return !newValue.equals(registry.getBundleValueOrNull(myKey));
return !newValue.equals(registry.getBundleValueOrNull(key));
}
protected String get(@NonNls @NotNull String key, String defaultValue, boolean isValue) throws MissingResourceException {
if (isValue) {
if (myStringCachedValue == null) {
myStringCachedValue = _get(key, defaultValue, true);
if (stringCachedValue == null) {
stringCachedValue = _get(key, defaultValue, true);
}
return myStringCachedValue;
return stringCachedValue;
}
return _get(key, defaultValue, false);
}
private @Nullable String _get(@NonNls @NotNull String key, @Nullable String defaultValue, boolean mustExistInBundle) throws MissingResourceException {
String userValue = myRegistry.getUserProperties().get(key);
String userValue = registry.getUserProperties().get(key);
if (userValue != null) {
return userValue;
}
@@ -217,7 +217,7 @@ public class RegistryValue {
return systemProperty;
}
if (!myRegistry.isLoaded()) {
if (!registry.isLoaded()) {
String message = "Attempt to load key '" + key + "' for not yet loaded registry";
// use Disposer.isDebugMode as "we are in internal mode or inside test" flag
if (Disposer.isDebugMode()) {
@@ -229,10 +229,10 @@ public class RegistryValue {
}
if (mustExistInBundle) {
return myRegistry.getBundleValue(key);
return registry.getBundleValue(key);
}
else {
String bundleValue = myRegistry.getBundleValueOrNull(key);
String bundleValue = registry.getBundleValueOrNull(key);
return bundleValue == null ? defaultValue : bundleValue;
}
}
@@ -246,22 +246,22 @@ public class RegistryValue {
}
public void setValue(String value) {
RegistryValueListener globalValueChangeListener = myRegistry.getValueChangeListener();
RegistryValueListener globalValueChangeListener = registry.getValueChangeListener();
globalValueChangeListener.beforeValueChanged(this);
for (RegistryValueListener each : myListeners) {
for (RegistryValueListener each : listeners) {
each.beforeValueChanged(this);
}
resetCache();
myRegistry.getUserProperties().put(myKey, value);
LOG.info("Registry value '" + myKey + "' has changed to '" + value + '\'');
registry.getUserProperties().put(key, value);
LOG.info("Registry value '" + key + "' has changed to '" + value + '\'');
globalValueChangeListener.afterValueChanged(this);
for (RegistryValueListener each : myListeners) {
for (RegistryValueListener each : listeners) {
each.afterValueChanged(this);
}
if (!isChangedFromDefault() && !isRestartRequired()) {
myRegistry.getUserProperties().remove(myKey);
registry.getUserProperties().remove(key);
}
myChangedSinceStart = true;
@@ -290,37 +290,37 @@ public class RegistryValue {
}
public void resetToDefault() {
String value = myRegistry.getBundleValueOrNull(myKey);
String value = registry.getBundleValueOrNull(key);
if (value == null) {
myRegistry.getUserProperties().remove(myKey);
registry.getUserProperties().remove(key);
} else {
setValue(value);
}
}
public void addListener(@NotNull RegistryValueListener listener, @NotNull Disposable parent) {
myListeners.add(listener);
Disposer.register(parent, () -> myListeners.remove(listener));
listeners.add(listener);
Disposer.register(parent, () -> listeners.remove(listener));
}
public void addListener(@NotNull RegistryValueListener listener, @NotNull CoroutineScope coroutineScope) {
myListeners.add(listener);
listeners.add(listener);
Objects.requireNonNull(coroutineScope.getCoroutineContext().get(Job.Key)).invokeOnCompletion(__ -> {
myListeners.remove(listener);
listeners.remove(listener);
return Unit.INSTANCE;
});
}
@Override
public String toString() {
return myKey + "=" + asString();
return key + "=" + asString();
}
void resetCache() {
myStringCachedValue = null;
myIntCachedValue = null;
myDoubleCachedValue = Double.NaN;
myBooleanCachedValue = null;
stringCachedValue = null;
intCachedValue = null;
doubleCachedValue = Double.NaN;
booleanCachedValue = null;
}
public boolean isBoolean() {

View File

@@ -1,4 +1,4 @@
// Copyright 2000-2023 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
// Copyright 2000-2024 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
package com.intellij.openapi.util.registry;
import com.intellij.idea.TestFor;
@@ -21,7 +21,7 @@ public class RegistryTest {
@After
public void tearDown(){
Registry.setValueChangeListener(null);
Registry.Companion.setValueChangeListener(null);
}
@@ -39,7 +39,7 @@ public class RegistryTest {
String firstVal = "first.value1";
String secondValue = "second.value1";
final AtomicReference<Pair<String, String>> lastChangedPair = new AtomicReference<>();
Registry.setValueChangeListener(new RegistryValueListener() {
Registry.Companion.setValueChangeListener(new RegistryValueListener() {
@Override
public void afterValueChanged(@NotNull RegistryValue value) {
if (!value.getKey().equals(key))
@@ -50,13 +50,13 @@ public class RegistryTest {
Map<String, String> firstMap = new LinkedHashMap<>();
firstMap.put(key, firstVal);
Registry.loadState(registryElementFromMap(firstMap), null);
Registry.Companion.loadState(registryElementFromMap(firstMap), null);
assertEquals(firstVal, Registry.get(key).asString());
assertNull(lastChangedPair.get());
Map<String, String> secondMap = new LinkedHashMap<>();
secondMap.put(key, secondValue);
Registry.loadState(registryElementFromMap(secondMap), null);
Registry.Companion.loadState(registryElementFromMap(secondMap), null);
assertEquals(secondValue, Registry.get(key).asString());
assertEquals(Pair.create(key, secondValue), lastChangedPair.get());
}
@@ -71,7 +71,7 @@ public class RegistryTest {
String eaFirstVal = "ea.first.value";
String eaSecondValue = "ea.second.value";
final AtomicReference<Pair<String, String>> lastChangedPair = new AtomicReference<>();
Registry.setValueChangeListener(new RegistryValueListener() {
Registry.Companion.setValueChangeListener(new RegistryValueListener() {
@Override
public void afterValueChanged(@NotNull RegistryValue value) {
if (!(value.getKey().equals(key) || value.getKey().equals(eaKey)))
@@ -80,12 +80,12 @@ public class RegistryTest {
}
});
Registry.loadState(registryElementFromMap(Map.of(key, firstVal)), Map.of(eaKey, eaFirstVal));
Registry.Companion.loadState(registryElementFromMap(Map.of(key, firstVal)), Map.of(eaKey, eaFirstVal));
assertEquals(firstVal, Registry.get(key).asString());
assertEquals(eaFirstVal, Registry.get(eaKey).asString());
assertNull(lastChangedPair.get());
Registry.loadState(registryElementFromMap(Map.of(key, firstVal, eaKey, eaSecondValue)), null);
Registry.Companion.loadState(registryElementFromMap(Map.of(key, firstVal, eaKey, eaSecondValue)), null);
assertEquals(firstVal, Registry.get(key).asString());
assertEquals(eaSecondValue, Registry.get(eaKey).asString());
assertEquals(Pair.create(eaKey, eaSecondValue), lastChangedPair.get());
@@ -103,7 +103,7 @@ public class RegistryTest {
String newValue = "another.value";
final AtomicReference<Pair<String, String>> lastChangedPair = new AtomicReference<>();
final List<Pair<String, String>> changedPairs = new ArrayList<>();
Registry.setValueChangeListener(new RegistryValueListener() {
Registry.Companion.setValueChangeListener(new RegistryValueListener() {
@Override
public void afterValueChanged(@NotNull RegistryValue value) {
if (!(value.getKey().equals(key)))
@@ -116,14 +116,14 @@ public class RegistryTest {
Map<String, String> firstMap = new LinkedHashMap<>();
firstMap.put(key, firstVal);
Registry.loadState(registryElementFromMap(firstMap), null);
Registry.Companion.loadState(registryElementFromMap(firstMap), null);
assertEquals(firstVal, Registry.get(key).asString());
assertNull(lastChangedPair.get());
Map<String, String> secondMap = new LinkedHashMap<>();
secondMap.put(key, secondValue);
secondMap.put(newKey, newValue);
Registry.loadState(registryElementFromMap(secondMap), null);
Registry.Companion.loadState(registryElementFromMap(secondMap), null);
assertEquals(secondValue, Registry.get(key).asString());
RegistryValue newRegistryValue = Registry.get(newKey);
String loadedNewValue = newRegistryValue.get(newRegistryValue.getKey(), null, false);
@@ -143,7 +143,7 @@ public class RegistryTest {
String secondKeyChangedValue = "second.initValue";
// initialize registry
Registry.loadState(registryElementFromMap(new LinkedHashMap<>(){{
Registry.Companion.loadState(registryElementFromMap(new LinkedHashMap<>(){{
put(firstKey, firstKeyInitValue);
put(secondKey, secondKeyInitValue);
}}), null);
@@ -151,7 +151,7 @@ public class RegistryTest {
assertEquals(secondKeyInitValue, Registry.get(secondKey).asString());
// add custom values
Registry.loadState(registryElementFromMap(new LinkedHashMap<>(){{
Registry.Companion.loadState(registryElementFromMap(new LinkedHashMap<>(){{
put(firstKey, firstKeyChangedVal);
put(secondKey, secondKeyChangedValue);
}}), null);
@@ -159,7 +159,7 @@ public class RegistryTest {
assertEquals(secondKeyChangedValue, Registry.get(secondKey).asString());
// drop key - reset to original
Registry.loadState(registryElementFromMap(new LinkedHashMap<>(){{
Registry.Companion.loadState(registryElementFromMap(new LinkedHashMap<>(){{
put(firstKey, firstKeyChangedVal);
}}), null);
assertEquals(firstKeyChangedVal, Registry.get(firstKey).asString());
@@ -184,7 +184,7 @@ public class RegistryTest {
String registryValue = "testBoolean";
RegistryValue regValue = new RegistryValue(Registry.getInstance(), registryValue, null);
regValue.setValue(false);
Registry.setValueChangeListener(new RegistryValueListener() {
Registry.Companion.setValueChangeListener(new RegistryValueListener() {
@Override
public void beforeValueChanged(@NotNull RegistryValue value) {
regValue.asBoolean();
@@ -201,17 +201,17 @@ public class RegistryTest {
{
Map<String, String> map = populateMap(Comparator.naturalOrder(), "value");
Element state2load = registryElementFromMap(map);
Registry.loadState(state2load, null);
Registry.Companion.loadState(state2load, null);
assertEquals(JDOMUtil.writeElement(state2load), JDOMUtil.writeElement(Registry.getInstance().getState()));
}
// load state with elements reversed
Registry.loadState(registryElementFromMap(populateMap(Comparator.reverseOrder(), "AnotherValue1111")), null);
Registry.Companion.loadState(registryElementFromMap(populateMap(Comparator.reverseOrder(), "AnotherValue1111")), null);
assertEquals(JDOMUtil.writeElement(registryElementFromMap(populateMap(Comparator.naturalOrder(), "AnotherValue1111"))),
JDOMUtil.writeElement(Registry.getInstance().getState()));
}
private Map<String, String> populateMap(Comparator<String> comparator, String valueBase) {
private static Map<String, String> populateMap(Comparator<String> comparator, String valueBase) {
Map<String, String> map = new TreeMap<>(comparator);
map.put("first.key", "first." + valueBase);
for (int i = 0; i < 20; i++) {
@@ -225,7 +225,7 @@ public class RegistryTest {
}
private Element registryElementFromMap(Map<String, String> map){
private static Element registryElementFromMap(Map<String, String> map){
Element registryElement = new Element("registry");
for (Map.Entry<String, String> entry : map.entrySet()) {
Element entryElement = new Element("entry");