IDEA-335157 cleanup

GitOrigin-RevId: b6887791c62244681633a9ce3b0f0ef9b25c3c72
This commit is contained in:
Vladimir Krivosheev
2023-10-17 21:17:06 +02:00
committed by intellij-monorepo-bot
parent 5afd693a2e
commit e0580de9af
5 changed files with 73 additions and 74 deletions

View File

@@ -77,8 +77,8 @@ internal fun getCustomIcons(schema: CustomActionsSchema): List<ActionIconInfo> {
val action = actionManager.getAction(iconReference)
if (action == null) {
try {
val icon = CustomActionsSchema.loadCustomIcon(iconReference)
ActionIconInfo(icon, iconReference.substringAfterLast("/"), actionId, iconReference)
val icon = loadCustomIcon(iconReference)
ActionIconInfo(icon = icon, text = iconReference.substringAfterLast('/'), actionId = actionId, iconPath = iconReference)
}
catch (ex: IOException) {
null

View File

@@ -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 com.intellij.ide.ui.customization
import com.intellij.icons.AllIcons
@@ -47,7 +47,7 @@ internal class BrowseIconsComboBox(private val customActionsSchema: CustomAction
init {
iconsLoadedFuture = loadIconsAsync(withNoneItem)
isSwingPopup = false // in this case speed search will filter the list of items
isSwingPopup = false // in this case, speed search will filter the list of items
setEditable(true)
setEditor(createEditor())
setRenderer(createRenderer())
@@ -57,7 +57,7 @@ internal class BrowseIconsComboBox(private val customActionsSchema: CustomAction
private fun loadIconsAsync(withNoneItem: Boolean): CompletableFuture<Boolean> {
val future = CompletableFuture<Boolean>()
ReadAction.nonBlocking(Callable { createIconsList(withNoneItem) })
ReadAction.nonBlocking(Callable { createIconList(withNoneItem) })
.expireWith(parentDisposable)
.finishOnUiThread(ModalityState.any(), Consumer { icons ->
model = DefaultComboBoxModel(icons.toTypedArray())
@@ -67,7 +67,7 @@ internal class BrowseIconsComboBox(private val customActionsSchema: CustomAction
return future
}
private fun createIconsList(withNoneItem: Boolean): List<ActionIconInfo> {
private fun createIconList(withNoneItem: Boolean): List<ActionIconInfo> {
val defaultIcons = getDefaultIcons()
val customIcons = getCustomIcons(customActionsSchema)
.asSequence()
@@ -161,7 +161,7 @@ internal class BrowseIconsComboBox(private val customActionsSchema: CustomAction
ComponentValidator(parentDisposable).withValidator(Supplier {
val path = (selectedItem as? ActionIconInfo)?.iconPath ?: return@Supplier null
try {
CustomActionsSchema.loadCustomIcon(path)
loadCustomIcon(path)
null
}
catch (ex: FileNotFoundException) {
@@ -204,7 +204,7 @@ internal class BrowseIconsComboBox(private val customActionsSchema: CustomAction
val iconFile = FileChooser.chooseFile(descriptor, null, null)
if (iconFile != null) {
val icon = try {
CustomActionsSchema.loadCustomIcon(iconFile.path)
loadCustomIcon(iconFile.path)
}
catch (t: Throwable) {
thisLogger().warn("Failed to load icon from disk, path: ${iconFile.path}", t)

View File

@@ -4,7 +4,6 @@
package com.intellij.ide.ui.customization
import com.intellij.ide.IdeBundle
import com.intellij.ide.ui.customization.CustomActionsSchema.Companion.loadCustomIcon
import com.intellij.ide.ui.customization.CustomizableActionGroupProvider.CustomizableActionGroupRegistrar
import com.intellij.openapi.actionSystem.*
import com.intellij.openapi.actionSystem.impl.PresentationFactory
@@ -144,67 +143,6 @@ class CustomActionsSchema(private val coroutineScope: CoroutineScope?) : Persist
}
windowManager.getFrameHelper(null)?.updateView()
}
/**
* @param path absolute path to the icon file, url of the icon file or url of the icon file inside jar.
* Also, the path can contain '_dark', '@2x', '@2x_dark' suffixes, but the resulting icon will be taken
* according to current scale and UI theme.
*/
@ApiStatus.Internal
@Throws(Throwable::class)
fun loadCustomIcon(path: String): Icon {
val independentPath = FileUtil.toSystemIndependentName(path)
val urlString = if (independentPath.startsWith("file:") || independentPath.startsWith("jar:")) {
independentPath
}
else {
"file:$independentPath"
}
val lastDotIndex = urlString.lastIndexOf('.')
val (rawUrl, ext) = if (lastDotIndex == -1) {
urlString to "svg"
}
else {
urlString.substring(0, lastDotIndex) to urlString.substring(lastDotIndex + 1)
}
val possibleSuffixes = listOf("@2x_dark", "_dark@2x", "_dark", "@2x")
val adjustedUrl = possibleSuffixes.find { rawUrl.endsWith(it) }?.let { rawUrl.removeSuffix(it) } ?: rawUrl
val fullAdjustedUrl = "$adjustedUrl.$ext"
try {
return doLoadCustomIcon(fullAdjustedUrl)
}
catch (t: Throwable) {
// In Light theme we do not fall back on dark icon, so if the original provided path ends with '_dark'
// and there is no icon file without '_dark' suffix, we will fail.
// And in this case, we just need to load the file chosen by the user.
if (urlString == fullAdjustedUrl) {
throw t
}
else {
return doLoadCustomIcon(urlString)
}
}
}
private fun doLoadCustomIcon(urlString: String): Icon {
val url = URL(null, urlString)
val icon = IconLoader.findIcon(url) ?: throw FileNotFoundException("Failed to find icon by URL: $url")
val w = icon.iconWidth
val h = icon.iconHeight
if (w <= 1 || h <= 1) {
throw FileNotFoundException("Failed to find icon by URL: $url")
}
if (w > EmptyIcon.ICON_18.iconWidth || h > EmptyIcon.ICON_18.iconHeight) {
val scale = EmptyIcon.ICON_18.iconWidth / w.coerceAtLeast(h).toFloat()
// ScaledResultIcon will be returned here, so we will be unable to scale it again or get the dark version,
// but we have nothing to do because the icon is too large
return IconUtil.scale(icon, scale = scale, ancestor = null)
}
return icon
}
}
fun addAction(url: ActionUrl) {
@@ -563,6 +501,67 @@ private object ActionUrlComparator : Comparator<ActionUrl> {
}
}
/**
* @param path absolute path to the icon file, url of the icon file or url of the icon file inside jar.
* Also, the path can contain '_dark', '@2x', '@2x_dark' suffixes, but the resulting icon will be taken
* according to current scale and UI theme.
*/
@ApiStatus.Internal
@Throws(Throwable::class)
fun loadCustomIcon(path: String): Icon {
val independentPath = FileUtil.toSystemIndependentName(path)
val urlString = if (independentPath.startsWith("file:") || independentPath.startsWith("jar:")) {
independentPath
}
else {
"file:$independentPath"
}
val lastDotIndex = urlString.lastIndexOf('.')
val (rawUrl, ext) = if (lastDotIndex == -1) {
urlString to "svg"
}
else {
urlString.substring(0, lastDotIndex) to urlString.substring(lastDotIndex + 1)
}
val possibleSuffixes = listOf("@2x_dark", "_dark@2x", "_dark", "@2x")
val adjustedUrl = possibleSuffixes.find { rawUrl.endsWith(it) }?.let { rawUrl.removeSuffix(it) } ?: rawUrl
val fullAdjustedUrl = "$adjustedUrl.$ext"
try {
return doLoadCustomIcon(fullAdjustedUrl)
}
catch (t: Throwable) {
// In Light theme we do not fall back on dark icon, so if the original provided path ends with '_dark'
// and there is no icon file without '_dark' suffix, we will fail.
// And in this case, we just need to load the file chosen by the user.
if (urlString == fullAdjustedUrl) {
throw t
}
else {
return doLoadCustomIcon(urlString)
}
}
}
private fun doLoadCustomIcon(urlString: String): Icon {
val url = URL(null, urlString)
val icon = IconLoader.findIcon(url) ?: throw FileNotFoundException("Failed to find icon by URL: $url")
val w = icon.iconWidth
val h = icon.iconHeight
if (w <= 1 || h <= 1) {
throw FileNotFoundException("Failed to find icon by URL: $url")
}
if (w > EmptyIcon.ICON_18.iconWidth || h > EmptyIcon.ICON_18.iconHeight) {
val scale = EmptyIcon.ICON_18.iconWidth / w.coerceAtLeast(h).toFloat()
// ScaledResultIcon will be returned here, so we will be unable to scale it again or get the dark version,
// but we have nothing to do because the icon is too large
return IconUtil.scale(icon, scale = scale, ancestor = null)
}
return icon
}
internal fun getIconForPath(actionManager: ActionManager, iconPath: String): Icon? {
val reuseFrom = actionManager.getAction(iconPath)
if (reuseFrom != null) {

View File

@@ -400,7 +400,7 @@ public class CustomizableActionsPanel {
else {
Icon icon;
try {
icon = CustomActionsSchema.Companion.loadCustomIcon(path);
icon = CustomActionsSchemaKt.loadCustomIcon(path);
}
catch (Throwable t) {
Logger.getInstance(CustomizableActionsPanel.class)

View File

@@ -1,7 +1,7 @@
// 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 com.intellij.ui
import com.intellij.ide.ui.customization.CustomActionsSchema
import com.intellij.ide.ui.customization.loadCustomIcon
import com.intellij.openapi.util.IconLoader
import com.intellij.testFramework.PlatformTestUtil
import org.junit.Test
@@ -42,7 +42,7 @@ class CustomIconLoadingTest {
private fun doTest(path: String) {
IconLoader.activate()
try {
CustomActionsSchema.loadCustomIcon(path)
loadCustomIcon(path)
}
finally {
IconLoader.deactivate()