mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
IDEA-330211 lazy ui theme creation
GitOrigin-RevId: 53fe1cd13224c685a27e4416ae7cf2d5ed479c6d
This commit is contained in:
committed by
intellij-monorepo-bot
parent
53cbf9f015
commit
6a7ea7df0c
@@ -33,6 +33,7 @@ import java.lang.reflect.Constructor;
|
||||
import java.util.List;
|
||||
import java.util.*;
|
||||
import java.util.function.Function;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
/**
|
||||
* @author Konstantin Bulenkov
|
||||
@@ -85,21 +86,25 @@ public final class UITheme {
|
||||
}
|
||||
|
||||
public static @NotNull UITheme loadFromJson(@Nullable UITheme parentTheme,
|
||||
byte[] data,
|
||||
byte @NotNull [] data,
|
||||
@NotNull @NonNls String themeId,
|
||||
@Nullable ClassLoader provider,
|
||||
@NotNull Function<? super String, String> iconsMapper,
|
||||
@Nullable UITheme defaultDarkParent,
|
||||
@Nullable UITheme defaultLightParent) throws IOException {
|
||||
@Nullable Supplier<UITheme> defaultDarkParent,
|
||||
@Nullable Supplier<UITheme> defaultLightParent) throws IOException {
|
||||
UIThemeBean theme = UIThemeBean.Companion.readTheme(new JsonFactory().createParser(data));
|
||||
theme.id = themeId;
|
||||
if (theme.dark && parentTheme == null) {
|
||||
return postProcessTheme(theme, defaultDarkParent, provider, iconsMapper);
|
||||
if (parentTheme == null) {
|
||||
if (theme.dark) {
|
||||
return postProcessTheme(theme, defaultDarkParent == null ? null : defaultDarkParent.get(), provider, iconsMapper);
|
||||
}
|
||||
else {
|
||||
return postProcessTheme(theme, defaultLightParent == null ? null : defaultLightParent.get(), provider, iconsMapper);
|
||||
}
|
||||
}
|
||||
if (!theme.dark && parentTheme == null) {
|
||||
return postProcessTheme(theme, defaultLightParent, provider, iconsMapper);
|
||||
else {
|
||||
return postProcessTheme(theme, parentTheme, provider, iconsMapper);
|
||||
}
|
||||
return postProcessTheme(theme, parentTheme, provider, iconsMapper);
|
||||
}
|
||||
|
||||
private static @NotNull UITheme postProcessTheme(@NotNull UIThemeBean theme,
|
||||
@@ -451,15 +456,6 @@ public final class UITheme {
|
||||
}
|
||||
}
|
||||
|
||||
private static @NotNull String createUIKey(String key, String propertyName) {
|
||||
if ("UI".equals(propertyName)) {
|
||||
return key + propertyName;
|
||||
}
|
||||
else {
|
||||
return key + "." + propertyName;
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private static void addPattern(String key, Object value, UIDefaults defaults) {
|
||||
Object o = defaults.get("*");
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
package com.intellij.ide.ui
|
||||
|
||||
import com.intellij.diagnostic.PluginException
|
||||
import com.intellij.ide.ui.laf.UiThemeProviderListManager
|
||||
import com.intellij.openapi.diagnostic.thisLogger
|
||||
import com.intellij.openapi.extensions.ExtensionPointName
|
||||
import com.intellij.openapi.extensions.PluginAware
|
||||
@@ -12,6 +13,7 @@ import com.intellij.util.xmlb.annotations.Attribute
|
||||
import org.jetbrains.annotations.ApiStatus.Internal
|
||||
import java.io.IOException
|
||||
import java.util.function.Function
|
||||
import java.util.function.Supplier
|
||||
|
||||
/**
|
||||
* Extension point for adding UI themes.
|
||||
@@ -53,37 +55,48 @@ class UIThemeProvider : PluginAware {
|
||||
@Throws(IOException::class)
|
||||
@Internal
|
||||
fun getThemeJson(): ByteArray? {
|
||||
var path = path!!
|
||||
path = if (path[0] == '/') path.substring(1) else path
|
||||
return ResourceUtil.getResourceAsBytes(path, pluginDescriptor!!.getClassLoader())
|
||||
return ResourceUtil.getResourceAsBytes((path ?: return null).removePrefix("/"), pluginDescriptor!!.getClassLoader())
|
||||
}
|
||||
|
||||
fun createTheme(parentTheme: UITheme?, defaultDarkParent: UITheme?, defaultLightParent: UITheme?): UITheme? {
|
||||
if (defaultDarkParent != null && defaultDarkParent.id == id) {
|
||||
return defaultDarkParent
|
||||
internal fun createTheme(parentTheme: UITheme?,
|
||||
defaultDarkParent: Supplier<UITheme?>?,
|
||||
defaultLightParent: Supplier<UITheme?>?): UITheme? {
|
||||
if (defaultDarkParent != null && id == UiThemeProviderListManager.DEFAULT_DARK_PARENT_THEME) {
|
||||
val result = defaultDarkParent.get()
|
||||
if (result?.id == UiThemeProviderListManager.DEFAULT_DARK_PARENT_THEME) {
|
||||
return result
|
||||
}
|
||||
}
|
||||
if (defaultLightParent != null && defaultLightParent.id == id) {
|
||||
return defaultLightParent
|
||||
if (defaultLightParent != null && id == UiThemeProviderListManager.DEFAULT_LIGHT_PARENT_THEME) {
|
||||
val result = defaultLightParent.get()
|
||||
if (result?.id == UiThemeProviderListManager.DEFAULT_LIGHT_PARENT_THEME) {
|
||||
return result
|
||||
}
|
||||
}
|
||||
|
||||
val pluginDescriptor = pluginDescriptor!!
|
||||
try {
|
||||
val classLoader = pluginDescriptor!!.getPluginClassLoader()
|
||||
val stream = getThemeJson()
|
||||
if (stream == null) {
|
||||
val classLoader = pluginDescriptor.getPluginClassLoader()
|
||||
val data = getThemeJson()
|
||||
if (data == null) {
|
||||
thisLogger().warn(PluginException(
|
||||
"Cannot find theme resource: $path (classLoader=$classLoader, pluginDescriptor=$pluginDescriptor)",
|
||||
pluginDescriptor!!.getPluginId()
|
||||
))
|
||||
"Cannot find theme resource (path=$path, classLoader=$classLoader, pluginDescriptor=$pluginDescriptor)",
|
||||
pluginDescriptor.getPluginId()))
|
||||
return null
|
||||
}
|
||||
return UITheme.loadFromJson(parentTheme, stream, id!!, classLoader, Function.identity(), defaultDarkParent, defaultLightParent)
|
||||
|
||||
return UITheme.loadFromJson(parentTheme,
|
||||
data,
|
||||
id!!,
|
||||
classLoader,
|
||||
Function.identity(),
|
||||
defaultDarkParent,
|
||||
defaultLightParent)
|
||||
}
|
||||
catch (e: Throwable) {
|
||||
thisLogger().warn(PluginException(
|
||||
"error loading UITheme '$path', pluginDescriptor=$pluginDescriptor",
|
||||
e,
|
||||
pluginDescriptor!!.getPluginId()
|
||||
))
|
||||
thisLogger().warn(PluginException("Cannot load UI theme (path=$path, pluginDescriptor=$pluginDescriptor)",
|
||||
e,
|
||||
pluginDescriptor.getPluginId()))
|
||||
return null
|
||||
}
|
||||
}
|
||||
|
||||
@@ -109,13 +109,6 @@ private const val INTER_SIZE = 13
|
||||
reportStatistic = false)
|
||||
class LafManagerImpl(private val coroutineScope: CoroutineScope) : LafManager(), PersistentStateComponent<Element> {
|
||||
private val eventDispatcher = EventDispatcher.create(LafManagerListener::class.java)
|
||||
private val lafMap = SynchronizedClearableLazy {
|
||||
runActivity("compute LaF list") {
|
||||
UiThemeProviderListManager.getInstance().getLaFsWithUITypes()
|
||||
}
|
||||
}
|
||||
private val lafList: Set<UIThemeLookAndFeelInfo>
|
||||
get() = lafMap.value.keys
|
||||
|
||||
private val defaultDarkTheme = SynchronizedClearableLazy {
|
||||
val name = ApplicationInfoEx.getInstanceEx().defaultDarkLaf
|
||||
@@ -381,9 +374,9 @@ class LafManagerImpl(private val coroutineScope: CoroutineScope) : LafManager(),
|
||||
}
|
||||
}
|
||||
|
||||
private fun loadThemeState(element: Element, attrName: @NonNls String): UIThemeLookAndFeelInfo? {
|
||||
val lafElement = element.getChild(attrName) ?: return null
|
||||
return lafList.singleOrNull { it.theme.id == lafElement.getAttributeValue(ATTRIBUTE_THEME_NAME) }
|
||||
private fun loadThemeState(element: Element, attributeName: @NonNls String): UIThemeLookAndFeelInfo? {
|
||||
val id = element.getChild(attributeName)?.getAttributeValue(ATTRIBUTE_THEME_NAME) ?: return null
|
||||
return UiThemeProviderListManager.getInstance().findThemeById(id)
|
||||
}
|
||||
|
||||
override fun noStateLoaded() {
|
||||
@@ -395,19 +388,19 @@ class LafManagerImpl(private val coroutineScope: CoroutineScope) : LafManager(),
|
||||
autodetect = false
|
||||
}
|
||||
|
||||
override fun getState(): Element? {
|
||||
override fun getState(): Element {
|
||||
val element = Element("state")
|
||||
if (autodetect) {
|
||||
element.setAttribute(ATTRIBUTE_AUTODETECT, java.lang.Boolean.toString(autodetect))
|
||||
}
|
||||
if (currentTheme?.theme?.id != defaultThemeId) {
|
||||
getThemeState(element, ELEMENT_LAF, currentUIThemeLookAndFeel)
|
||||
writeThemeState(element, ELEMENT_LAF, currentUIThemeLookAndFeel)
|
||||
}
|
||||
if (preferredLightTheme != null && preferredLightTheme !== defaultLightLaf) {
|
||||
getThemeState(element, ELEMENT_PREFERRED_LIGHT_LAF, preferredLightTheme)
|
||||
writeThemeState(element, ELEMENT_PREFERRED_LIGHT_LAF, preferredLightTheme)
|
||||
}
|
||||
if (preferredDarkTheme != null && preferredDarkTheme !== defaultDarkLaf) {
|
||||
getThemeState(element, ELEMENT_PREFERRED_DARK_LAF, preferredDarkTheme)
|
||||
writeThemeState(element, ELEMENT_PREFERRED_DARK_LAF, preferredDarkTheme)
|
||||
}
|
||||
|
||||
if (lafToPreviousScheme.isNotEmpty()) {
|
||||
@@ -422,15 +415,19 @@ class LafManagerImpl(private val coroutineScope: CoroutineScope) : LafManager(),
|
||||
element.addContent(lafsToSchemes)
|
||||
}
|
||||
|
||||
return if (element.isEmpty) null else element
|
||||
return element
|
||||
}
|
||||
|
||||
override fun getInstalledLookAndFeels(): Array<UIThemeLookAndFeelInfo> = lafList.toTypedArray()
|
||||
override fun getInstalledLookAndFeels(): Array<UIThemeLookAndFeelInfo> {
|
||||
return UiThemeProviderListManager.getInstance().getLaFs().toList().toTypedArray()
|
||||
}
|
||||
|
||||
override fun getLafComboBoxModel(): CollectionComboBoxModel<LafReference> = lafComboBoxModel.value
|
||||
|
||||
fun getThemeListForTargetUI(targetUI: TargetUIType): List<UIThemeLookAndFeelInfo> {
|
||||
return lafMap.value.filterValues { it == targetUI }.keys.toList()
|
||||
fun getThemeListForTargetUI(targetUI: TargetUIType): Sequence<UIThemeLookAndFeelInfo> {
|
||||
return UiThemeProviderListManager.getInstance().getLaFsWithUITypes().asSequence()
|
||||
.filter { it.targetUiType == targetUI }
|
||||
.mapNotNull { it.theme.get() }
|
||||
}
|
||||
|
||||
private val allReferences: List<LafReference>
|
||||
@@ -458,7 +455,11 @@ class LafManagerImpl(private val coroutineScope: CoroutineScope) : LafManager(),
|
||||
}
|
||||
|
||||
override fun findLaf(reference: LafReference): UIThemeLookAndFeelInfo {
|
||||
return lafList.singleOrNull { it.theme.id == reference.themeId } ?: error("Theme not found for themeId: ${reference.themeId}")
|
||||
return UiThemeProviderListManager.getInstance().getLaFsWithUITypes()
|
||||
.singleOrNull { it.id == reference.themeId }
|
||||
?.theme
|
||||
?.get()
|
||||
?: error("Theme not found for themeId: ${reference.themeId}")
|
||||
}
|
||||
|
||||
@Suppress("removal")
|
||||
@@ -473,18 +474,18 @@ class LafManagerImpl(private val coroutineScope: CoroutineScope) : LafManager(),
|
||||
override fun getSettingsToolbar(): JComponent = settingsToolbar.value.component
|
||||
|
||||
private fun loadDefaultTheme(): UIThemeLookAndFeelInfo {
|
||||
// Use HighContrast theme for IDE in Windows if HighContrast desktop mode is set.
|
||||
// use HighContrast theme for IDE in Windows if HighContrast desktop mode is set
|
||||
if (SystemInfoRt.isWindows && Toolkit.getDefaultToolkit().getDesktopProperty("win.highContrast.on") == true) {
|
||||
for (laf in lafList) {
|
||||
if (HIGH_CONTRAST_THEME_ID == laf.theme.id) {
|
||||
return laf
|
||||
}
|
||||
UiThemeProviderListManager.getInstance().findThemeById(HIGH_CONTRAST_THEME_ID)?.let {
|
||||
return it
|
||||
}
|
||||
}
|
||||
return defaultDarkLaf
|
||||
}
|
||||
|
||||
private fun findLafByName(name: String): UIThemeLookAndFeelInfo? = installedLookAndFeels.firstOrNull { name == it.name }
|
||||
private fun findLafByName(name: String): UIThemeLookAndFeelInfo? {
|
||||
return UiThemeProviderListManager.getInstance().findThemeByName(name)
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets current LAF. The method doesn't update component hierarchy.
|
||||
@@ -829,22 +830,17 @@ class LafManagerImpl(private val coroutineScope: CoroutineScope) : LafManager(),
|
||||
|
||||
private inner class UiThemeEpListener : ExtensionPointListener<UIThemeProvider> {
|
||||
override fun extensionAdded(extension: UIThemeProvider, pluginDescriptor: PluginDescriptor) {
|
||||
val newLaF = UiThemeProviderListManager.getInstance().themeProviderAdded(extension) ?: return
|
||||
val oldLaFsMap = lafMap.value
|
||||
val newLaFsMap = mutableMapOf<UIThemeLookAndFeelInfo, TargetUIType>()
|
||||
newLaFsMap.putAll(oldLaFsMap)
|
||||
newLaFsMap.put(newLaF, extension.targetUI)
|
||||
lafMap.value = newLaFsMap
|
||||
val uiThemeProviderListManager = UiThemeProviderListManager.getInstance()
|
||||
val newLaF = uiThemeProviderListManager.themeProviderAdded(extension) ?: return
|
||||
updateLafComboboxModel()
|
||||
|
||||
// when updating a theme plugin that doesn't provide the current theme, don't select any of its themes as current
|
||||
val newTheme = newLaF.theme
|
||||
val pluginClassLoader = pluginDescriptor.pluginClassLoader
|
||||
if (pluginClassLoader != null) {
|
||||
newTheme.setProviderClassLoader(pluginClassLoader)
|
||||
pluginDescriptor.pluginClassLoader?.let {
|
||||
newTheme.setProviderClassLoader(it)
|
||||
}
|
||||
if (!autodetect && (!isUpdatingPlugin || newTheme.id == themeIdBeforePluginUpdate)) {
|
||||
setLookAndFeelImpl(newLaF, true, false)
|
||||
setLookAndFeelImpl(lookAndFeelInfo = newLaF, installEditorScheme = true, processChangeSynchronously = false)
|
||||
JBColor.setDark(newTheme.isDark)
|
||||
updateUI()
|
||||
}
|
||||
@@ -861,16 +857,9 @@ class LafManagerImpl(private val coroutineScope: CoroutineScope) : LafManager(),
|
||||
else {
|
||||
null
|
||||
}
|
||||
val newLaFs = mutableMapOf<UIThemeLookAndFeelInfo, TargetUIType>()
|
||||
for (laf in lafMap.value) {
|
||||
if (laf.key !== oldLaF) {
|
||||
newLaFs.put(laf.key, laf.value)
|
||||
}
|
||||
}
|
||||
lafMap.value = newLaFs
|
||||
updateLafComboboxModel()
|
||||
if (defaultLaF != null) {
|
||||
setLookAndFeelImpl(defaultLaF, true, true)
|
||||
setLookAndFeelImpl(lookAndFeelInfo = defaultLaF, installEditorScheme = true, processChangeSynchronously = true)
|
||||
if (ExperimentalUI.isNewUI()) {
|
||||
JBColor.setDark(defaultDarkTheme.isInitialized() && isDark)
|
||||
}
|
||||
@@ -1131,8 +1120,8 @@ private class OurPopupFactory(private val delegate: PopupFactory) : PopupFactory
|
||||
}
|
||||
}
|
||||
|
||||
private fun getThemeState(element: Element, attributeName: @NonNls String?, suggestedLaf: UIThemeLookAndFeelInfo?) {
|
||||
val laf = (if (suggestedLaf is TempUIThemeLookAndFeelInfo) suggestedLaf.previousLaf else null) ?: return
|
||||
private fun writeThemeState(element: Element, attributeName: @NonNls String?, suggestedLaf: UIThemeLookAndFeelInfo?) {
|
||||
val laf = (if (suggestedLaf is TempUIThemeLookAndFeelInfo) suggestedLaf.previousLaf else suggestedLaf) ?: return
|
||||
val child = Element(attributeName)
|
||||
child.setAttribute(ATTRIBUTE_THEME_NAME, laf.theme.id)
|
||||
element.addContent(child)
|
||||
|
||||
@@ -11,10 +11,10 @@ private class ThemeListProviderImpl : ThemeListProvider {
|
||||
val lafManager = LafManager.getInstance() as? LafManagerImpl ?: return emptyList()
|
||||
val result = mutableListOf<List<UIThemeLookAndFeelInfo>>()
|
||||
if (ExperimentalUI.isNewUI()) {
|
||||
result.add(lafManager.getThemeListForTargetUI(TargetUIType.NEW).sortedBy { it.name })
|
||||
result.add(lafManager.getThemeListForTargetUI(TargetUIType.NEW).sortedBy { it.name }.toList())
|
||||
}
|
||||
result.add((lafManager.getThemeListForTargetUI(TargetUIType.CLASSIC).filterNot { it.theme.id == "IntelliJ" }
|
||||
+ lafManager.getThemeListForTargetUI(TargetUIType.UNSPECIFIED)).sortedBy { it.name })
|
||||
+ lafManager.getThemeListForTargetUI(TargetUIType.UNSPECIFIED)).sortedBy { it.name }.toList())
|
||||
return result
|
||||
}
|
||||
}
|
||||
@@ -3,6 +3,7 @@
|
||||
|
||||
package com.intellij.ide.ui.laf
|
||||
|
||||
import com.intellij.diagnostic.runActivity
|
||||
import com.intellij.ide.ui.TargetUIType
|
||||
import com.intellij.ide.ui.UITheme
|
||||
import com.intellij.ide.ui.UIThemeProvider
|
||||
@@ -10,8 +11,8 @@ import com.intellij.openapi.components.Service
|
||||
import com.intellij.openapi.components.service
|
||||
import com.intellij.openapi.editor.colors.EditorColorsManager
|
||||
import com.intellij.openapi.editor.colors.impl.EditorColorsManagerImpl
|
||||
import com.intellij.util.graph.DFSTBuilder
|
||||
import com.intellij.util.graph.OutboundSemiGraph
|
||||
import com.intellij.util.concurrency.SynchronizedClearableLazy
|
||||
import java.util.function.Supplier
|
||||
|
||||
// separate service to avoid using LafManager in the EditorColorsManagerImpl initialization
|
||||
@Service(Service.Level.APP)
|
||||
@@ -24,16 +25,21 @@ internal class UiThemeProviderListManager {
|
||||
}
|
||||
|
||||
@Volatile
|
||||
private var lafMap: Map<UIThemeLookAndFeelInfo, TargetUIType> = computeMap()
|
||||
private var themeDescriptors: List<LafEntry> = computeMap()
|
||||
|
||||
private val lafList: Set<UIThemeLookAndFeelInfo>
|
||||
get() = lafMap.keys
|
||||
fun getLaFs(): Sequence<UIThemeLookAndFeelInfo> = themeDescriptors.asSequence().mapNotNull { it.theme.get() }
|
||||
|
||||
fun getLaFs(): List<UIThemeLookAndFeelInfo> = lafList.toList()
|
||||
fun findThemeByName(name: String): UIThemeLookAndFeelInfo? {
|
||||
return getLaFs().firstOrNull { it.theme.name == name }
|
||||
}
|
||||
|
||||
fun getLaFsWithUITypes(): Map<UIThemeLookAndFeelInfo, TargetUIType> = lafMap
|
||||
fun findThemeById(id: String): UIThemeLookAndFeelInfo? {
|
||||
return themeDescriptors.firstOrNull { it.id == id }?.theme?.get()
|
||||
}
|
||||
|
||||
fun findJetBrainsLightTheme(): UIThemeLookAndFeelInfo? = findLaFById(DEFAULT_LIGHT_THEME_ID)
|
||||
fun getLaFsWithUITypes(): List<LafEntry> = themeDescriptors
|
||||
|
||||
fun findJetBrainsLightTheme(): UIThemeLookAndFeelInfo? = findLaFById(DEFAULT_LIGHT_THEME_ID)?.theme?.get()
|
||||
|
||||
fun themeProviderAdded(provider: UIThemeProvider): UIThemeLookAndFeelInfo? {
|
||||
if (findLaFByProviderId(provider) != null) {
|
||||
@@ -41,63 +47,71 @@ internal class UiThemeProviderListManager {
|
||||
return null
|
||||
}
|
||||
|
||||
val parentTheme = findParentTheme(lafList, provider.parentTheme)
|
||||
val parentTheme = findParentTheme(themes = themeDescriptors, parentId = provider.parentTheme)
|
||||
val theme = provider.createTheme(
|
||||
parentTheme = parentTheme,
|
||||
defaultDarkParent = lafMap.keys.single { it.theme.id == DEFAULT_DARK_PARENT_THEME }.theme,
|
||||
defaultLightParent = lafMap.keys.single { it.theme.id == DEFAULT_LIGHT_PARENT_THEME }.theme,
|
||||
defaultDarkParent = SynchronizedClearableLazy { themeDescriptors.single { it.id == DEFAULT_DARK_PARENT_THEME }.theme.get()?.theme },
|
||||
defaultLightParent = SynchronizedClearableLazy { themeDescriptors.single { it.id == DEFAULT_LIGHT_PARENT_THEME }.theme.get()?.theme },
|
||||
) ?: return null
|
||||
editorColorManager.handleThemeAdded(theme)
|
||||
val newLaF = UIThemeLookAndFeelInfoImpl(theme)
|
||||
lafMap = lafMap + Pair(newLaF, provider.targetUI)
|
||||
themeDescriptors = themeDescriptors + LafEntry(Supplier { newLaF }, provider.targetUI, provider.id!!)
|
||||
return newLaF
|
||||
}
|
||||
|
||||
fun themeProviderRemoved(provider: UIThemeProvider): UIThemeLookAndFeelInfo? {
|
||||
val oldLaF = findLaFByProviderId(provider) ?: return null
|
||||
lafMap = lafMap - oldLaF
|
||||
editorColorManager.handleThemeRemoved(oldLaF.theme)
|
||||
return oldLaF
|
||||
themeDescriptors = themeDescriptors - oldLaF
|
||||
val theme = oldLaF.theme.get() ?: return null
|
||||
editorColorManager.handleThemeRemoved(theme.theme)
|
||||
return theme
|
||||
}
|
||||
|
||||
private fun findLaFById(id: String) = lafList.firstOrNull { it.theme.id == id }
|
||||
private fun findLaFById(id: String) = themeDescriptors.firstOrNull { it.id == id }
|
||||
|
||||
private fun findLaFByProviderId(provider: UIThemeProvider) = provider.id?.let { findLaFById(it) }
|
||||
}
|
||||
|
||||
private fun computeMap(): Map<UIThemeLookAndFeelInfo, TargetUIType> {
|
||||
val map = LinkedHashMap<UIThemeLookAndFeelInfo, TargetUIType>()
|
||||
val orderedProviders = sortTopologically(UIThemeProvider.EP_NAME.extensionList, { it.id }, { it.parentTheme })
|
||||
val darcula = orderedProviders.single { it.id == UiThemeProviderListManager.DEFAULT_DARK_PARENT_THEME }
|
||||
.createTheme(parentTheme = null, defaultDarkParent = null, defaultLightParent = null)
|
||||
val intelliJ = orderedProviders.single { it.id == UiThemeProviderListManager.DEFAULT_LIGHT_PARENT_THEME }
|
||||
.createTheme(parentTheme = darcula, defaultDarkParent = null, defaultLightParent = null)
|
||||
for (provider in orderedProviders) {
|
||||
val parentTheme = findParentTheme(map.keys, provider.parentTheme)
|
||||
val theme = UIThemeLookAndFeelInfoImpl(provider.createTheme(parentTheme = parentTheme,
|
||||
defaultDarkParent = darcula,
|
||||
defaultLightParent = intelliJ) ?: continue)
|
||||
map.put(theme, provider.targetUI)
|
||||
}
|
||||
return map
|
||||
}
|
||||
|
||||
private fun findParentTheme(themes: Collection<UIThemeLookAndFeelInfo>, parentId: String?): UITheme? {
|
||||
return if (parentId == null) null else themes.asSequence().map { it.theme }.firstOrNull { it.id == parentId }
|
||||
}
|
||||
|
||||
private fun <T, K> sortTopologically(list: List<T>, idFun: (T) -> K, parentIdFun: (T) -> K?): List<T> {
|
||||
val mapById = list.associateBy(idFun)
|
||||
val graph = object : OutboundSemiGraph<T> {
|
||||
override fun getNodes(): Collection<T> = list
|
||||
|
||||
override fun getOut(n: T): Iterator<T> {
|
||||
val parent = mapById.get(parentIdFun(n))
|
||||
return listOfNotNull(parent).iterator()
|
||||
private fun computeMap(): List<LafEntry> {
|
||||
val result = ArrayList<LafEntry>()
|
||||
runActivity("compute LaF list") {
|
||||
val darcula = SynchronizedClearableLazy {
|
||||
UIThemeProvider.EP_NAME.extensionList.single { it.id == DEFAULT_DARK_PARENT_THEME }
|
||||
.createTheme(parentTheme = null, defaultDarkParent = null, defaultLightParent = null)
|
||||
}
|
||||
val intelliJ = SynchronizedClearableLazy {
|
||||
UIThemeProvider.EP_NAME.extensionList.single { it.id == DEFAULT_LIGHT_PARENT_THEME }
|
||||
.createTheme(parentTheme = darcula.value, defaultDarkParent = null, defaultLightParent = null)
|
||||
}
|
||||
for (provider in UIThemeProvider.EP_NAME.extensionList) {
|
||||
result.add(LafEntry(
|
||||
theme = SynchronizedClearableLazy {
|
||||
val theme = when (provider.id) {
|
||||
DEFAULT_DARK_PARENT_THEME -> darcula.value
|
||||
DEFAULT_LIGHT_THEME_ID -> intelliJ.value
|
||||
else -> {
|
||||
val parentTheme = findParentTheme(themes = themeDescriptors, parentId = provider.parentTheme)
|
||||
provider.createTheme(parentTheme = parentTheme, defaultDarkParent = darcula, defaultLightParent = intelliJ)
|
||||
}
|
||||
}
|
||||
theme?.let { UIThemeLookAndFeelInfoImpl(it) }
|
||||
},
|
||||
targetUiType = provider.targetUI,
|
||||
id = provider.id!!,
|
||||
))
|
||||
}
|
||||
}
|
||||
return java.util.List.copyOf(result)
|
||||
}
|
||||
}
|
||||
|
||||
return DFSTBuilder(graph).sortedNodes.reversed()
|
||||
internal data class LafEntry(
|
||||
@JvmField val theme: Supplier<UIThemeLookAndFeelInfo?>,
|
||||
@JvmField val targetUiType: TargetUIType,
|
||||
@JvmField val id: String,
|
||||
)
|
||||
|
||||
private fun findParentTheme(themes: Collection<LafEntry>, parentId: String?): UITheme? {
|
||||
return if (parentId == null) null else themes.firstOrNull { it.id == parentId }?.theme?.get()?.theme
|
||||
}
|
||||
|
||||
private const val DEFAULT_LIGHT_THEME_ID = "JetBrainsLightTheme"
|
||||
|
||||
+12
-21
@@ -66,6 +66,7 @@ import com.intellij.util.messages.MessageBusConnection;
|
||||
import com.intellij.util.ui.StartupUiUtil;
|
||||
import com.intellij.util.xmlb.annotations.OptionTag;
|
||||
import kotlin.jvm.functions.Function1;
|
||||
import kotlin.sequences.SequencesKt;
|
||||
import org.jdom.Element;
|
||||
import org.jetbrains.annotations.*;
|
||||
|
||||
@@ -284,18 +285,15 @@ public final class EditorColorsManagerImpl extends EditorColorsManager implement
|
||||
@TestOnly
|
||||
public @Nullable EditorColorsScheme loadBundledScheme(@NotNull String themeName) {
|
||||
assert ApplicationManager.getApplication().isUnitTestMode() : "Test-only method";
|
||||
for (UIThemeLookAndFeelInfo laf : UiThemeProviderListManager.Companion.getInstance().getLaFs()) {
|
||||
UITheme theme = laf.getTheme();
|
||||
if (themeName.equals(theme.getName())) {
|
||||
String scheme = theme.getEditorScheme();
|
||||
if (scheme != null) {
|
||||
EditorColorsScheme bundledScheme = loadBundledScheme(scheme, theme, null);
|
||||
initEditableBundledSchemesCopies();
|
||||
return bundledScheme;
|
||||
}
|
||||
}
|
||||
UIThemeLookAndFeelInfo theme = UiThemeProviderListManager.Companion.getInstance().findThemeByName(themeName);
|
||||
String scheme = theme == null ? null : theme.getTheme().getEditorScheme();
|
||||
if (scheme == null) {
|
||||
return null;
|
||||
}
|
||||
return null;
|
||||
|
||||
EditorColorsScheme bundledScheme = loadBundledScheme(scheme, theme, null);
|
||||
initEditableBundledSchemesCopies();
|
||||
return bundledScheme;
|
||||
}
|
||||
|
||||
@TestOnly
|
||||
@@ -317,7 +315,7 @@ public final class EditorColorsManagerImpl extends EditorColorsManager implement
|
||||
return;
|
||||
}
|
||||
|
||||
for (UIThemeLookAndFeelInfo laf : UiThemeProviderListManager.Companion.getInstance().getLaFs()) {
|
||||
for (UIThemeLookAndFeelInfo laf : SequencesKt.asIterable(UiThemeProviderListManager.Companion.getInstance().getLaFs())) {
|
||||
UITheme theme = laf.getTheme();
|
||||
List<String> schemes = theme.getAdditionalEditorSchemes();
|
||||
PluginDescriptor pluginDescriptor = getPluginDescriptor(theme);
|
||||
@@ -764,25 +762,18 @@ public final class EditorColorsManagerImpl extends EditorColorsManager implement
|
||||
boolean isDark = ColorUtil.isDark(scheme.getDefaultBackground());
|
||||
String neededThemeName = isDark ? "Solarized Dark" : "Solarized Light";
|
||||
|
||||
UIThemeLookAndFeelInfo neededTheme = null;
|
||||
for (UIThemeLookAndFeelInfo theme : UiThemeProviderListManager.Companion.getInstance().getLaFs()) {
|
||||
if (theme.getName().equals(neededThemeName)) {
|
||||
neededTheme = theme;
|
||||
break;
|
||||
}
|
||||
}
|
||||
UIThemeLookAndFeelInfo neededTheme = UiThemeProviderListManager.Companion.getInstance().findThemeByName(neededThemeName);
|
||||
Notification notification = new Notification("ColorSchemeDeprecation",
|
||||
IdeBundle.message("notification.title.solarized.color.scheme.deprecation"),
|
||||
"",
|
||||
NotificationType.ERROR);
|
||||
if (neededTheme != null) {
|
||||
notification.setContent(IdeBundle.message("notification.content.solarized.color.scheme.deprecation.enable", name, neededThemeName));
|
||||
UIThemeLookAndFeelInfo finalNeededTheme = neededTheme;
|
||||
notification.addAction(new NotificationAction(IdeBundle.message("notification.title.enable.action.solarized.color.scheme.deprecation", neededThemeName)) {
|
||||
@Override
|
||||
public void actionPerformed(@NotNull AnActionEvent e, @NotNull Notification notification) {
|
||||
LafManager lafManager = LafManager.getInstance();
|
||||
lafManager.setCurrentLookAndFeel(finalNeededTheme, false);
|
||||
lafManager.setCurrentLookAndFeel(neededTheme, false);
|
||||
lafManager.updateUI();
|
||||
notification.expire();
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user