mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
IDEA-330211 convert UIThemeProvider from Java to Kotlin
GitOrigin-RevId: f45761263f910e7e1e9da9d31df840b58c0d44c7
This commit is contained in:
committed by
intellij-monorepo-bot
parent
0eff8628d1
commit
e1e77bdf4f
@@ -1,92 +1,94 @@
|
||||
// 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.ide.ui;
|
||||
package com.intellij.ide.ui
|
||||
|
||||
import com.intellij.diagnostic.PluginException;
|
||||
import com.intellij.openapi.diagnostic.Logger;
|
||||
import com.intellij.openapi.extensions.ExtensionPointName;
|
||||
import com.intellij.openapi.extensions.PluginAware;
|
||||
import com.intellij.openapi.extensions.PluginDescriptor;
|
||||
import com.intellij.openapi.extensions.RequiredElement;
|
||||
import com.intellij.util.ResourceUtil;
|
||||
import com.intellij.util.xmlb.annotations.Attribute;
|
||||
import org.jetbrains.annotations.ApiStatus;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.function.Function;
|
||||
import com.intellij.diagnostic.PluginException
|
||||
import com.intellij.openapi.diagnostic.thisLogger
|
||||
import com.intellij.openapi.extensions.ExtensionPointName
|
||||
import com.intellij.openapi.extensions.PluginAware
|
||||
import com.intellij.openapi.extensions.PluginDescriptor
|
||||
import com.intellij.openapi.extensions.RequiredElement
|
||||
import com.intellij.util.ResourceUtil
|
||||
import com.intellij.util.xmlb.annotations.Attribute
|
||||
import org.jetbrains.annotations.ApiStatus.Internal
|
||||
import java.io.IOException
|
||||
import java.util.function.Function
|
||||
|
||||
/**
|
||||
* Extension point for adding UI themes.
|
||||
* <br/>
|
||||
* Read more about <a href=https://plugins.jetbrains.com/docs/intellij/theme-structure.html>themes development</a>.
|
||||
* Read more about [themes development](https://plugins.jetbrains.com/docs/intellij/theme-structure.html).
|
||||
*
|
||||
* @author Konstantin Bulenkov
|
||||
*/
|
||||
public final class UIThemeProvider implements PluginAware {
|
||||
public static final ExtensionPointName<UIThemeProvider> EP_NAME = new ExtensionPointName<>("com.intellij.themeProvider");
|
||||
private PluginDescriptor pluginDescriptor;
|
||||
class UIThemeProvider : PluginAware {
|
||||
companion object {
|
||||
@JvmField
|
||||
val EP_NAME: ExtensionPointName<UIThemeProvider> = ExtensionPointName("com.intellij.themeProvider")
|
||||
}
|
||||
|
||||
private var pluginDescriptor: PluginDescriptor? = null
|
||||
|
||||
/**
|
||||
* Path to {@code *.theme.json} file
|
||||
* Path to `*.theme.json` file
|
||||
*/
|
||||
@Attribute("path")
|
||||
@RequiredElement
|
||||
public String path;
|
||||
@JvmField
|
||||
var path: String? = null
|
||||
|
||||
/**
|
||||
* Unique theme identifier. For example, MyTheme123
|
||||
*/
|
||||
@Attribute("id")
|
||||
@RequiredElement
|
||||
public String id;
|
||||
@JvmField
|
||||
var id: String? = null
|
||||
|
||||
@Attribute("parentTheme")
|
||||
public @Nullable String parentTheme;
|
||||
var parentTheme: String? = null
|
||||
|
||||
@Attribute("targetUi") public @NotNull TargetUIType targetUI = TargetUIType.UNSPECIFIED;
|
||||
@Attribute("targetUi")
|
||||
@JvmField
|
||||
var targetUI: TargetUIType = TargetUIType.UNSPECIFIED
|
||||
|
||||
@ApiStatus.Internal
|
||||
public byte[] getThemeJson() throws IOException {
|
||||
String path = this.path;
|
||||
path = path.charAt(0) == '/' ? path.substring(1) : path;
|
||||
return ResourceUtil.getResourceAsBytes(path, pluginDescriptor.getClassLoader());
|
||||
@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())
|
||||
}
|
||||
|
||||
public @Nullable UITheme createTheme(
|
||||
@Nullable UITheme parentTheme,
|
||||
@Nullable UITheme defaultDarkParent,
|
||||
@Nullable UITheme defaultLightParent) {
|
||||
if (defaultDarkParent != null && defaultDarkParent.getId().equals(id)) {
|
||||
return defaultDarkParent;
|
||||
fun createTheme(parentTheme: UITheme?, defaultDarkParent: UITheme?, defaultLightParent: UITheme?): UITheme? {
|
||||
if (defaultDarkParent != null && defaultDarkParent.id == id) {
|
||||
return defaultDarkParent
|
||||
}
|
||||
if (defaultLightParent != null && defaultLightParent.getId().equals(id)) {
|
||||
return defaultLightParent;
|
||||
if (defaultLightParent != null && defaultLightParent.id == id) {
|
||||
return defaultLightParent
|
||||
}
|
||||
|
||||
try {
|
||||
ClassLoader classLoader = pluginDescriptor.getPluginClassLoader();
|
||||
byte[] stream = getThemeJson();
|
||||
val classLoader = pluginDescriptor!!.getPluginClassLoader()
|
||||
val stream = getThemeJson()
|
||||
if (stream == null) {
|
||||
Logger.getInstance(getClass()).warn(new PluginException(
|
||||
"Cannot find theme resource: " + path + " (classLoader=" + classLoader + ", pluginDescriptor=" + pluginDescriptor + ")",
|
||||
pluginDescriptor.getPluginId()
|
||||
));
|
||||
return null;
|
||||
thisLogger().warn(PluginException(
|
||||
"Cannot find theme resource: $path (classLoader=$classLoader, pluginDescriptor=$pluginDescriptor)",
|
||||
pluginDescriptor!!.getPluginId()
|
||||
))
|
||||
return null
|
||||
}
|
||||
return UITheme.loadFromJson(parentTheme, stream, id, classLoader, Function.identity(), defaultDarkParent, defaultLightParent);
|
||||
return UITheme.loadFromJson(parentTheme, stream, id!!, classLoader, Function.identity(), defaultDarkParent, defaultLightParent)
|
||||
}
|
||||
catch (Throwable e) {
|
||||
Logger.getInstance(getClass()).warn(new PluginException(
|
||||
"error loading UITheme '" + path + "', pluginDescriptor=" + pluginDescriptor,
|
||||
catch (e: Throwable) {
|
||||
thisLogger().warn(PluginException(
|
||||
"error loading UITheme '$path', pluginDescriptor=$pluginDescriptor",
|
||||
e,
|
||||
pluginDescriptor.getPluginId()
|
||||
));
|
||||
return null;
|
||||
pluginDescriptor!!.getPluginId()
|
||||
))
|
||||
return null
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setPluginDescriptor(@NotNull PluginDescriptor pluginDescriptor) {
|
||||
this.pluginDescriptor = pluginDescriptor;
|
||||
override fun setPluginDescriptor(pluginDescriptor: PluginDescriptor) {
|
||||
this.pluginDescriptor = pluginDescriptor
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,6 +18,7 @@ import com.intellij.util.graph.OutboundSemiGraph
|
||||
internal class UiThemeProviderListManager {
|
||||
companion object {
|
||||
fun getInstance(): UiThemeProviderListManager = service()
|
||||
|
||||
internal const val DEFAULT_DARK_PARENT_THEME = "Darcula"
|
||||
internal const val DEFAULT_LIGHT_PARENT_THEME = "IntelliJ"
|
||||
}
|
||||
@@ -41,10 +42,12 @@ internal class UiThemeProviderListManager {
|
||||
}
|
||||
|
||||
val parentTheme = findParentTheme(lafList, provider.parentTheme)
|
||||
val theme = provider.createTheme(parentTheme,
|
||||
lafMap.keys.single { it.theme.id == DEFAULT_DARK_PARENT_THEME }.theme,
|
||||
lafMap.keys.single { it.theme.id == DEFAULT_LIGHT_PARENT_THEME }.theme) ?: return null
|
||||
editorColorManager().handleThemeAdded(theme)
|
||||
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,
|
||||
) ?: return null
|
||||
editorColorManager.handleThemeAdded(theme)
|
||||
val newLaF = UIThemeLookAndFeelInfoImpl(theme)
|
||||
lafMap = lafMap + Pair(newLaF, provider.targetUI)
|
||||
return newLaF
|
||||
@@ -53,35 +56,34 @@ internal class UiThemeProviderListManager {
|
||||
fun themeProviderRemoved(provider: UIThemeProvider): UIThemeLookAndFeelInfo? {
|
||||
val oldLaF = findLaFByProviderId(provider) ?: return null
|
||||
lafMap = lafMap - oldLaF
|
||||
editorColorManager().handleThemeRemoved(oldLaF.theme)
|
||||
editorColorManager.handleThemeRemoved(oldLaF.theme)
|
||||
return oldLaF
|
||||
}
|
||||
|
||||
private fun findLaFById(id: String) = lafList.find { it.theme.id == id }
|
||||
private fun findLaFById(id: String) = lafList.firstOrNull { it.theme.id == id }
|
||||
|
||||
private fun findLaFByProviderId(provider: UIThemeProvider) = findLaFById(provider.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(null, null, null)
|
||||
val intelliJ = orderedProviders.single{ it.id == UiThemeProviderListManager.DEFAULT_LIGHT_PARENT_THEME }
|
||||
.createTheme(darcula, null, null)
|
||||
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, darcula, intelliJ) ?: continue)
|
||||
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? {
|
||||
if (parentId == null) {
|
||||
return null
|
||||
}
|
||||
return themes.asSequence().map { it.theme }.find { it.id == parentId }
|
||||
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> {
|
||||
@@ -100,4 +102,5 @@ private fun <T, K> sortTopologically(list: List<T>, idFun: (T) -> K, parentIdFun
|
||||
|
||||
private const val DEFAULT_LIGHT_THEME_ID = "JetBrainsLightTheme"
|
||||
|
||||
private fun editorColorManager() = EditorColorsManager.getInstance() as EditorColorsManagerImpl
|
||||
private val editorColorManager: EditorColorsManagerImpl
|
||||
get() = EditorColorsManager.getInstance() as EditorColorsManagerImpl
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright 2000-2022 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
// Copyright 2000-2023 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
package org.jetbrains.idea.devkit.themes;
|
||||
|
||||
import com.intellij.ide.ui.UIThemeProvider;
|
||||
@@ -16,7 +16,7 @@ import org.jetbrains.idea.devkit.dom.ExtensionPoint;
|
||||
import org.jetbrains.idea.devkit.themes.metadata.UIThemeMetadataService;
|
||||
import org.jetbrains.idea.devkit.util.PsiUtil;
|
||||
|
||||
public class ThemeEPPathReferenceContributor extends PsiReferenceContributor {
|
||||
final class ThemeEPPathReferenceContributor extends PsiReferenceContributor {
|
||||
@Override
|
||||
public void registerReferenceProviders(@NotNull PsiReferenceRegistrar registrar) {
|
||||
registrar.registerReferenceProvider(XmlPatterns.xmlAttributeValue().withLocalName("path"), new PsiReferenceProvider() {
|
||||
|
||||
Reference in New Issue
Block a user