From 034577d3fc8e111a9026ad56ebb47c8fdcd4e730 Mon Sep 17 00:00:00 2001 From: Roman Shevchenko Date: Wed, 14 Jun 2023 15:38:46 +0200 Subject: [PATCH] [platform] making `ApplicationInfoEx#getApplicationSvgIconUrl` and `#getSmallApplicationSvgIconUrl` non-null, per .xsd GitOrigin-RevId: dfe298178bd444b7f71653f3be6af3aa6cc5d63a --- .../application/ex/ApplicationInfoEx.java | 16 ++--- .../application/impl/ApplicationInfoImpl.java | 9 ++- .../ide/impl/ui/ProductIconsImpl.java | 24 +++---- .../WelcomeScreenComponentFactory.java | 30 ++++---- .../src/com/intellij/ui/AppUIUtil.kt | 69 +++++-------------- .../application/impl/ApplicationInfoTest.java | 11 +-- 6 files changed, 60 insertions(+), 99 deletions(-) diff --git a/platform/core-impl/src/com/intellij/openapi/application/ex/ApplicationInfoEx.java b/platform/core-impl/src/com/intellij/openapi/application/ex/ApplicationInfoEx.java index 19255fe64c2a..a2ffb557211c 100644 --- a/platform/core-impl/src/com/intellij/openapi/application/ex/ApplicationInfoEx.java +++ b/platform/core-impl/src/com/intellij/openapi/application/ex/ApplicationInfoEx.java @@ -22,23 +22,23 @@ public abstract class ApplicationInfoEx extends ApplicationInfo { public abstract String getAboutImageUrl(); - /** - * @deprecated use {@link #getSmallApplicationSvgIconUrl()} instead - */ + /** @deprecated please use {@link #getSmallApplicationSvgIconUrl()} instead */ @Deprecated @ApiStatus.ScheduledForRemoval public abstract @NotNull String getSmallIconUrl(); /** - * Return path to an SVG file containing icon of the current version of the product. The path is a relative path inside the product's JAR - * files. It may return a special icon for EAP builds. + * Returns a path to an SVG icon of the product. + * The path is a relative path inside the product's JAR files. + * Please note that release and EAP builds may have different icons. */ - public abstract @Nullable String getApplicationSvgIconUrl(); + public abstract @NotNull String getApplicationSvgIconUrl(); /** - * Return path to an SVG file containing a variant of {@link #getApplicationSvgIconUrl() the product icon} which is suitable for 16x16 images. + * Returns a path to an SVG file, + * containing a variant of {@link #getApplicationSvgIconUrl() the product icon} which is suitable for 16x16 images. */ - public abstract @Nullable String getSmallApplicationSvgIconUrl(); + public abstract @NotNull String getSmallApplicationSvgIconUrl(); public abstract String getToolWindowIconUrl(); diff --git a/platform/core-impl/src/com/intellij/openapi/application/impl/ApplicationInfoImpl.java b/platform/core-impl/src/com/intellij/openapi/application/impl/ApplicationInfoImpl.java index 4a811560577c..450fead0f005 100644 --- a/platform/core-impl/src/com/intellij/openapi/application/impl/ApplicationInfoImpl.java +++ b/platform/core-impl/src/com/intellij/openapi/application/impl/ApplicationInfoImpl.java @@ -343,6 +343,9 @@ public final class ApplicationInfoImpl extends ApplicationInfoEx { } } + requireNonNull(mySvgIconUrl, "Missing attribute: //icon@svg"); + requireNonNull(mySmallSvgIconUrl, "Missing attribute: //icon@svg-small"); + overrideFromProperties(); essentialPluginsIds.sort(null); @@ -515,16 +518,16 @@ public final class ApplicationInfoImpl extends ApplicationInfoEx { } @Override - public @Nullable String getApplicationSvgIconUrl() { + public @NotNull String getApplicationSvgIconUrl() { return isEAP() && mySvgEapIconUrl != null ? mySvgEapIconUrl : mySvgIconUrl; } @Override - public @Nullable String getSmallApplicationSvgIconUrl() { + public @NotNull String getSmallApplicationSvgIconUrl() { return getSmallApplicationSvgIconUrl(isEAP()); } - public @Nullable String getSmallApplicationSvgIconUrl(boolean isEap) { + public @NotNull String getSmallApplicationSvgIconUrl(boolean isEap) { return isEap && mySmallSvgEapIconUrl != null ? mySmallSvgEapIconUrl : mySmallSvgIconUrl; } diff --git a/platform/platform-impl/src/com/intellij/ide/impl/ui/ProductIconsImpl.java b/platform/platform-impl/src/com/intellij/ide/impl/ui/ProductIconsImpl.java index be006d883d7c..9b01d56e4aab 100644 --- a/platform/platform-impl/src/com/intellij/ide/impl/ui/ProductIconsImpl.java +++ b/platform/platform-impl/src/com/intellij/ide/impl/ui/ProductIconsImpl.java @@ -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.impl.ui; import com.intellij.icons.AllIcons; @@ -11,23 +11,17 @@ import org.jetbrains.annotations.NotNull; import javax.swing.*; -import static java.util.Objects.requireNonNullElse; +import static com.intellij.openapi.util.NotNullLazyValue.lazy; final class ProductIconsImpl implements ProductIcons { - private final NotNullLazyValue myProductIcon = NotNullLazyValue.createValue(() -> { - ApplicationInfoEx appInfo = ApplicationInfoEx.getInstanceEx(); - @SuppressWarnings("deprecation") String fallback = appInfo.getSmallIconUrl(); - return IconLoader.getIcon(requireNonNullElse(appInfo.getSmallApplicationSvgIconUrl(), fallback), ProductIconsImpl.class.getClassLoader()); - }); - private final NotNullLazyValue myProjectIcon = NotNullLazyValue.createValue( - () -> PlatformUtils.isJetBrainsProduct() - ? AllIcons.Actions.ProjectDirectory - : myProductIcon.getValue() + private final NotNullLazyValue myProductIcon = lazy( + () -> IconLoader.getIcon(ApplicationInfoEx.getInstanceEx().getSmallApplicationSvgIconUrl(), ProductIconsImpl.class.getClassLoader()) ); - private final NotNullLazyValue myProjectNodeIcon = NotNullLazyValue.createValue( - () -> PlatformUtils.isJetBrainsProduct() - ? AllIcons.Nodes.IdeaProject - : myProductIcon.getValue() + private final NotNullLazyValue myProjectIcon = lazy( + () -> PlatformUtils.isJetBrainsProduct() ? AllIcons.Actions.ProjectDirectory : myProductIcon.getValue() + ); + private final NotNullLazyValue myProjectNodeIcon = lazy( + () -> PlatformUtils.isJetBrainsProduct() ? AllIcons.Nodes.IdeaProject : myProductIcon.getValue() ); @Override diff --git a/platform/platform-impl/src/com/intellij/openapi/wm/impl/welcomeScreen/WelcomeScreenComponentFactory.java b/platform/platform-impl/src/com/intellij/openapi/wm/impl/welcomeScreen/WelcomeScreenComponentFactory.java index 4632ed602aab..8c934493c737 100644 --- a/platform/platform-impl/src/com/intellij/openapi/wm/impl/welcomeScreen/WelcomeScreenComponentFactory.java +++ b/platform/platform-impl/src/com/intellij/openapi/wm/impl/welcomeScreen/WelcomeScreenComponentFactory.java @@ -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.openapi.wm.impl.welcomeScreen; import com.intellij.application.Topics; @@ -59,21 +59,19 @@ public final class WelcomeScreenComponentFactory { NonOpaquePanel panel = new NonOpaquePanel(new BorderLayout()); String welcomeScreenLogoUrl = appInfo.getApplicationSvgIconUrl(); - if (welcomeScreenLogoUrl != null) { - Icon icon = IconLoader.getIcon(welcomeScreenLogoUrl, WelcomeScreenComponentFactory.class.getClassLoader()); - JLabel logo = new JLabel() { - @Override - public void updateUI() { - super.updateUI(); - float scale = JBUIScale.scale(28f) / icon.getIconWidth(); - Icon smallLogoIcon = IconUtil.scale(icon, null, scale); - setIcon(smallLogoIcon); - } - }; - logo.setBorder(JBUI.Borders.empty(29, 0, 27, 0)); - logo.setHorizontalAlignment(SwingConstants.CENTER); - panel.add(logo, BorderLayout.WEST); - } + Icon icon = IconLoader.getIcon(welcomeScreenLogoUrl, WelcomeScreenComponentFactory.class.getClassLoader()); + JLabel logo = new JLabel() { + @Override + public void updateUI() { + super.updateUI(); + float scale = JBUIScale.scale(28f) / icon.getIconWidth(); + Icon smallLogoIcon = IconUtil.scale(icon, null, scale); + setIcon(smallLogoIcon); + } + }; + logo.setBorder(JBUI.Borders.empty(29, 0, 27, 0)); + logo.setHorizontalAlignment(SwingConstants.CENTER); + panel.add(logo, BorderLayout.WEST); String applicationName = getAppName(); JLabel appName = new JLabel(applicationName); diff --git a/platform/platform-impl/src/com/intellij/ui/AppUIUtil.kt b/platform/platform-impl/src/com/intellij/ui/AppUIUtil.kt index 25d22c693741..72807e0d71a2 100644 --- a/platform/platform-impl/src/com/intellij/ui/AppUIUtil.kt +++ b/platform/platform-impl/src/com/intellij/ui/AppUIUtil.kt @@ -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. @file:Suppress("JAVA_MODULE_DOES_NOT_EXPORT_PACKAGE", "ReplaceGetOrSet") package com.intellij.ui @@ -18,8 +18,10 @@ import com.intellij.openapi.diagnostic.Logger import com.intellij.openapi.diagnostic.logger import com.intellij.openapi.project.Project import com.intellij.openapi.ui.DialogWrapper -import com.intellij.openapi.util.* +import com.intellij.openapi.util.Condition import com.intellij.openapi.util.IconLoader.setUseDarkIcons +import com.intellij.openapi.util.SystemInfo +import com.intellij.openapi.util.SystemInfoRt import com.intellij.openapi.wm.IdeFrame import com.intellij.ui.AppIcon.MacAppIcon import com.intellij.ui.icons.findSvgData @@ -28,8 +30,6 @@ import com.intellij.ui.scale.JBUIScale.scale import com.intellij.ui.scale.JBUIScale.sysScale import com.intellij.ui.scale.ScaleContext import com.intellij.ui.svg.loadWithSizes -import com.intellij.util.IconUtil -import com.intellij.util.ImageLoader.loadFromResource import com.intellij.util.JBHiDPIScaledImage import com.intellij.util.PlatformUtils import com.intellij.util.io.URLUtil @@ -68,20 +68,15 @@ fun updateAppWindowIcon(window: Window) { val smallSvgIconUrl = appInfo.smallApplicationSvgIconUrl val scaleContext = ScaleContext.create(window) if (SystemInfoRt.isUnix) { - loadApplicationIconImage(svgPath = svgIconUrl, scaleContext = scaleContext, size = 128)?.let { + loadAppIconImage(svgPath = svgIconUrl, scaleContext = scaleContext, size = 128)?.let { images.add(it) } } - val element = loadApplicationIconImage(svgPath = smallSvgIconUrl, scaleContext = scaleContext, size = 32) - if (element != null) { - images.add(element) + loadAppIconImage(svgPath = smallSvgIconUrl, scaleContext = scaleContext, size = 32)?.let { + images.add(it) } if (SystemInfoRt.isWindows) { - @Suppress("DEPRECATION") - loadApplicationIconImage(svgPath = smallSvgIconUrl, - scaleContext = scaleContext, - size = 16, - fallbackPath = appInfo.smallIconUrl)?.let { + loadAppIconImage(svgPath = smallSvgIconUrl, scaleContext = scaleContext, size = 16)?.let { images.add(it) } } @@ -106,14 +101,7 @@ fun updateAppWindowIcon(window: Window) { } } -/** - * Returns a hidpi-aware image. - */ -private fun loadApplicationIconImage(svgPath: String?, scaleContext: ScaleContext, size: Int, fallbackPath: String? = null): Image? { - val image = if (svgPath == null) null else loadAppIconImage(svgPath, scaleContext, size) - return image ?: loadFromResource(path = fallbackPath ?: return null, aClass = AppUIUtil::class.java) -} - +/** Returns a HiDPI-aware image. */ private fun loadAppIconImage(svgPath: String, scaleContext: ScaleContext, size: Int): Image? { val pixScale = scaleContext.getScale(DerivedScaleType.PIX_SCALE).toFloat() val svgData = findSvgData(path = svgPath, classLoader = AppUIUtil::class.java.classLoader, pixScale = pixScale) @@ -128,29 +116,12 @@ fun loadSmallApplicationIcon(scaleContext: ScaleContext, size: Int = 16, isReleaseIcon: Boolean = !ApplicationInfoImpl.getShadowInstance().isEAP): Icon { val appInfo = ApplicationInfoImpl.getShadowInstance() - var smallIconUrl = appInfo.smallApplicationSvgIconUrl - if (isReleaseIcon && appInfo.isEAP && appInfo is ApplicationInfoImpl) { + val smallIconUrl = if (isReleaseIcon && appInfo.isEAP && appInfo is ApplicationInfoImpl) { // This is the way to load the release icon in EAP. Needed for some actions. - smallIconUrl = appInfo.getSmallApplicationSvgIconUrl(false) - } - - var image = if (smallIconUrl == null) null else loadAppIconImage(smallIconUrl, scaleContext, size) - if (image != null) { - return JBImageIcon(image) - } - - @Suppress("DEPRECATION") - val fallbackSmallIconUrl = appInfo.smallIconUrl - image = loadFromResource(fallbackSmallIconUrl, AppUIUtil::class.java) ?: error("Can't load '$fallbackSmallIconUrl'") - - val icon = JBImageIcon(image) - val width = icon.iconWidth - if (width == size) { - return icon - } - - val scale = size / width.toFloat() - return IconUtil.scale(icon = icon, ancestor = null, scale = scale) + appInfo.getSmallApplicationSvgIconUrl(false) + } else appInfo.smallApplicationSvgIconUrl + val image = loadAppIconImage(smallIconUrl, scaleContext, size) ?: error("Can't load '${smallIconUrl}'") + return JBImageIcon(image) } fun findAppIcon(): String? { @@ -163,14 +134,8 @@ fun findAppIcon(): String? { } } } - val svgIconUrl = ApplicationInfoImpl.getShadowInstance().applicationSvgIconUrl - if (svgIconUrl != null) { - val url = ApplicationInfoEx::class.java.getResource(svgIconUrl) - if (url != null && URLUtil.FILE_PROTOCOL == url.protocol) { - return URLUtil.urlToFile(url).absolutePath - } - } - return null + val url = ApplicationInfoEx::class.java.getResource(ApplicationInfoImpl.getShadowInstance().applicationSvgIconUrl) + return if (url != null && URLUtil.FILE_PROTOCOL == url.protocol) URLUtil.urlToFile(url).absolutePath else null } object AppUIUtil { @@ -197,7 +162,7 @@ object AppUIUtil { @JvmStatic fun loadApplicationIcon(ctx: ScaleContext, size: Int): Icon? { val url = ApplicationInfoImpl.getShadowInstance().applicationSvgIconUrl - return if (url == null) null else loadAppIconImage(url, ctx, size)?.let { JBImageIcon(it) } + return loadAppIconImage(url, ctx, size)?.let { JBImageIcon(it) } } @JvmStatic diff --git a/platform/platform-tests/testSrc/com/intellij/openapi/application/impl/ApplicationInfoTest.java b/platform/platform-tests/testSrc/com/intellij/openapi/application/impl/ApplicationInfoTest.java index 2bce738bb357..f75b6ad66104 100644 --- a/platform/platform-tests/testSrc/com/intellij/openapi/application/impl/ApplicationInfoTest.java +++ b/platform/platform-tests/testSrc/com/intellij/openapi/application/impl/ApplicationInfoTest.java @@ -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 that can be found in the LICENSE file. +// 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.application.impl; import com.intellij.testFramework.PlatformTestUtil; @@ -14,7 +14,7 @@ import static org.assertj.core.api.Assertions.assertThat; public class ApplicationInfoTest { @Test - public void shortenCompanyName() throws Exception { + public void shortenCompanyName() { assertThat(createAppInfo(new XmlElement("company", Map.of("name", "Google Inc."), List.of(), null)).getShortCompanyName()).isEqualTo("Google"); assertThat(createAppInfo(new XmlElement("company", Map.of("name", "JetBrains s.r.o."), List.of(), null)).getShortCompanyName()).isEqualTo("JetBrains"); assertThat(createAppInfo(new XmlElement("company", Map.of("shortName", "Acme Inc."), List.of(), null)).getShortCompanyName()).isEqualTo("Acme Inc."); @@ -22,9 +22,9 @@ public class ApplicationInfoTest { @Test public void pluginsHostProperty() { - @SuppressWarnings("SpellCheckingInspection") String host = "IntellijIdeaRulezzz"; + var host = "IntellijIdeaRulezzz"; PlatformTestUtil.withSystemProperty(ApplicationInfoImpl.IDEA_PLUGINS_HOST_PROPERTY, host, () -> { - ApplicationInfoImpl info = createAppInfo(); + var info = createAppInfo(); assertThat(info.getPluginManagerUrl()).contains(host).doesNotContain(ApplicationInfoImpl.DEFAULT_PLUGINS_HOST); assertThat(info.getPluginsListUrl()).contains(host).doesNotContain(ApplicationInfoImpl.DEFAULT_PLUGINS_HOST); assertThat(info.getPluginsDownloadUrl()).contains(host).doesNotContain(ApplicationInfoImpl.DEFAULT_PLUGINS_HOST); @@ -33,7 +33,8 @@ public class ApplicationInfoTest { } public static @NotNull ApplicationInfoImpl createAppInfo(@NotNull XmlElement @NotNull ... content) { - List children = new ArrayList<>(List.of(content)); + var children = new ArrayList<>(List.of(content)); + children.add(new XmlElement("icon", Map.of("svg", "xxx.svg", "svg-small", "xxx.svg"), List.of(), null)); children.add(new XmlElement("plugins", Map.of(), List.of(), null)); return new ApplicationInfoImpl(new XmlElement("state", Map.of(), children, null)); }