IDEA-333099 Update generated project icon after renaming the project

GitOrigin-RevId: f2dbefc414c4907c6430193abcde240f6c91460a
This commit is contained in:
Aydar Mukhametzyanov
2023-09-26 13:37:22 +00:00
committed by intellij-monorepo-bot
parent 091b261d23
commit 11ddddb8fc
7 changed files with 57 additions and 26 deletions
@@ -14,6 +14,7 @@ import com.intellij.openapi.components.serviceAsync
import com.intellij.openapi.components.serviceIfCreated
import com.intellij.openapi.extensions.ExtensionNotApplicableException
import com.intellij.openapi.project.Project
import com.intellij.openapi.project.ProjectNameListener
import com.intellij.openapi.project.ex.ProjectManagerEx
import com.intellij.openapi.startup.ProjectActivity
import com.intellij.openapi.util.registry.Registry
@@ -47,11 +48,16 @@ private class ProjectWindowCustomizerIconCache(private val project: Project) {
busConnection.subscribe(LafManagerListener.TOPIC, LafManagerListener {
cachedIcon.drop()
})
busConnection.subscribe(ProjectNameListener.TOPIC, object: ProjectNameListener {
override fun nameChanged(newName: String) {
cachedIcon.drop()
}
})
}
private fun getIconRaw(): Icon {
val path = ProjectWindowCustomizerService.projectPath(project) ?: ""
return RecentProjectsManagerBase.getInstanceEx().getProjectIcon(path = path, isProjectValid = true, iconSize = 20)
return RecentProjectsManagerBase.getInstanceEx().getProjectIcon(path = path, isProjectValid = true, iconSize = 20, name = project.name)
}
}
@@ -83,8 +83,8 @@ internal class RecentProjectIconHelper {
}
@JvmStatic
fun generateProjectIcon(path: @SystemIndependent String, isProjectValid: Boolean, size: Int = unscaledProjectIconSize()): Icon {
val generatedProjectIcon = generateProjectIcon(path, isProjectValid, size, null)
fun generateProjectIcon(path: @SystemIndependent String, isProjectValid: Boolean, size: Int = unscaledProjectIconSize(), projectName: String? = null): Icon {
val generatedProjectIcon = generateProjectIcon(path, isProjectValid, size, null, projectName)
projectIconCache.put(Pair(path, size), ProjectIcon(icon = generatedProjectIcon,
isProjectValid = isProjectValid,
@@ -93,8 +93,8 @@ internal class RecentProjectIconHelper {
return generatedProjectIcon
}
fun generateProjectIcon(path: @SystemIndependent String, isProjectValid: Boolean, size: Int = unscaledProjectIconSize(), colorIndex: Int?): Icon {
val name = getProjectName(path, RecentProjectsManagerBase.getInstanceEx())
fun generateProjectIcon(path: @SystemIndependent String, isProjectValid: Boolean, size: Int = unscaledProjectIconSize(), colorIndex: Int?, projectName: String? = null): Icon {
val name = projectName ?: getProjectName(path, RecentProjectsManagerBase.getInstanceEx())
val palette = if (colorIndex != null) ChangeProjectIconPalette(colorIndex) else ProjectIconPalette
var generatedProjectIcon: Icon = AvatarIcon(targetSize = size,
@@ -122,13 +122,13 @@ internal class RecentProjectIconHelper {
}
}
fun getProjectIcon(path: @SystemIndependent String, isProjectValid: Boolean = true, iconSize: Int = unscaledProjectIconSize()): Icon {
fun getProjectIcon(path: @SystemIndependent String, isProjectValid: Boolean = true, iconSize: Int = unscaledProjectIconSize(), name: String? = null): Icon {
if (!RecentProjectsManagerBase.isFileSystemPath(path)) {
return EmptyIcon.create(iconSize)
}
return IconDeferrer.getInstance().defer(EmptyIcon.create(iconSize), Triple(path, isProjectValid, iconSize)) {
getCustomIcon(path = it.first, isProjectValid = it.second, iconSize) ?: getGeneratedProjectIcon(path = it.first, isProjectValid = it.second, iconSize)
getCustomIcon(path = it.first, isProjectValid = it.second, iconSize) ?: getGeneratedProjectIcon(path = it.first, isProjectValid = it.second, iconSize, name)
}
}
@@ -173,17 +173,21 @@ private fun getCustomIcon(path: @SystemIndependent String, isProjectValid: Boole
return iconWrapper.icon
}
private fun getGeneratedProjectIcon(path: @SystemIndependent String, isProjectValid: Boolean, size: Int = unscaledProjectIconSize()): Icon {
private fun getGeneratedProjectIcon(path: @SystemIndependent String, isProjectValid: Boolean, size: Int = unscaledProjectIconSize(), name: String? = null): Icon {
val projectIcon = projectIconCache.get(Pair(path, size))
if (projectIcon != null && isCachedIcon(projectIcon, isProjectValid)) {
if (projectIcon != null && isCachedIcon(projectIcon, isProjectValid, name = name)) {
return projectIcon.icon
}
return RecentProjectIconHelper.generateProjectIcon(path, isProjectValid, size)
return RecentProjectIconHelper.generateProjectIcon(path, isProjectValid, size, projectName = name)
}
private fun isCachedIcon(icon: ProjectIcon, isProjectValid: Boolean, timestamp: Long? = null): Boolean {
val isCached = icon.isProjectValid == isProjectValid && icon.lastUsedProjectIconSize == userScaledProjectIconSize()
return if (timestamp == null) isCached else isCached && icon.timestamp == timestamp
private fun isCachedIcon(icon: ProjectIcon, isProjectValid: Boolean, timestamp: Long? = null, name: String? = null): Boolean {
val isNameChanged = (icon.icon as? AvatarIcon)?.avatarName?.let { it != name } ?: false
val isTimestampChanged = timestamp?.let { icon.timestamp != it } ?: false
return icon.isProjectValid == isProjectValid
&& icon.lastUsedProjectIconSize == userScaledProjectIconSize()
&& !isNameChanged && !isTimestampChanged
}
private data class ProjectIcon(
@@ -221,8 +221,8 @@ open class RecentProjectsManagerBase(coroutineScope: CoroutineScope) :
return projectIconHelper.getProjectIcon(path, isProjectValid)
}
fun getProjectIcon(path: String, isProjectValid: Boolean, iconSize: Int): Icon {
return projectIconHelper.getProjectIcon(path, isProjectValid, iconSize)
fun getProjectIcon(path: String, isProjectValid: Boolean, iconSize: Int, name: String? = null): Icon {
return projectIconHelper.getProjectIcon(path, isProjectValid, iconSize, name)
}
@Suppress("OVERRIDE_DEPRECATION")
@@ -0,0 +1,17 @@
// 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.project
import com.intellij.util.messages.Topic
import java.util.*
/**
* Represents a listener for name changes of Project
*/
interface ProjectNameListener: EventListener {
fun nameChanged(newName: String)
companion object {
@Topic.ProjectLevel
val TOPIC = Topic(ProjectNameListener::class.java)
}
}
@@ -23,6 +23,7 @@ import com.intellij.openapi.diagnostic.debug
import com.intellij.openapi.diagnostic.logger
import com.intellij.openapi.project.Project
import com.intellij.openapi.project.ProjectManager
import com.intellij.openapi.project.ProjectNameListener
import com.intellij.openapi.project.ex.ProjectEx
import com.intellij.openapi.project.ex.ProjectManagerEx
import com.intellij.openapi.startup.StartupManager
@@ -175,7 +176,9 @@ open class ProjectImpl(parent: ComponentManagerImpl, filePath: Path, projectName
}
cachedName = value
if (!ApplicationManager.getApplication().isUnitTestMode) {
messageBus.syncPublisher(ProjectNameListener.TOPIC).nameChanged(value)
StartupManager.getInstance(this).runAfterOpened {
ApplicationManager.getApplication().invokeLater(Runnable {
val frame = WindowManager.getInstance().getFrame(this) ?: return@Runnable
@@ -18,16 +18,17 @@ import com.intellij.util.ui.JBPoint
class ChangeProjectColorActionGroup: DefaultActionGroup(), DumbAware {
override fun getChildren(e: AnActionEvent?): Array<AnAction> {
val projectPath = e?.project?.let { ProjectWindowCustomizerService.projectPath(it) } ?: return emptyArray()
val projectName = e.project?.name
return arrayOf(ChangeProjectColorAction(projectPath, IdeBundle.message("action.ChangeProjectColorAction.Amber.title"), 0),
ChangeProjectColorAction(projectPath, IdeBundle.message("action.ChangeProjectColorAction.Rust.title"), 1),
ChangeProjectColorAction(projectPath, IdeBundle.message("action.ChangeProjectColorAction.Olive.title"), 2),
ChangeProjectColorAction(projectPath, IdeBundle.message("action.ChangeProjectColorAction.Grass.title"), 8),
ChangeProjectColorAction(projectPath, IdeBundle.message("action.ChangeProjectColorAction.Ocean.title"), 7),
ChangeProjectColorAction(projectPath, IdeBundle.message("action.ChangeProjectColorAction.Sky.title"), 3),
ChangeProjectColorAction(projectPath, IdeBundle.message("action.ChangeProjectColorAction.Cobalt.title"), 4),
ChangeProjectColorAction(projectPath, IdeBundle.message("action.ChangeProjectColorAction.Violet.title"), 6),
ChangeProjectColorAction(projectPath, IdeBundle.message("action.ChangeProjectColorAction.Plum.title"), 5),
return arrayOf(ChangeProjectColorAction(projectPath, IdeBundle.message("action.ChangeProjectColorAction.Amber.title"), 0, projectName),
ChangeProjectColorAction(projectPath, IdeBundle.message("action.ChangeProjectColorAction.Rust.title"), 1, projectName),
ChangeProjectColorAction(projectPath, IdeBundle.message("action.ChangeProjectColorAction.Olive.title"), 2, projectName),
ChangeProjectColorAction(projectPath, IdeBundle.message("action.ChangeProjectColorAction.Grass.title"), 8, projectName),
ChangeProjectColorAction(projectPath, IdeBundle.message("action.ChangeProjectColorAction.Ocean.title"), 7, projectName),
ChangeProjectColorAction(projectPath, IdeBundle.message("action.ChangeProjectColorAction.Sky.title"), 3, projectName),
ChangeProjectColorAction(projectPath, IdeBundle.message("action.ChangeProjectColorAction.Cobalt.title"), 4, projectName),
ChangeProjectColorAction(projectPath, IdeBundle.message("action.ChangeProjectColorAction.Violet.title"), 6, projectName),
ChangeProjectColorAction(projectPath, IdeBundle.message("action.ChangeProjectColorAction.Plum.title"), 5, projectName),
Separator(),
ChooseCustomProjectColorAction()
)
@@ -40,7 +41,7 @@ class ChangeProjectColorActionGroup: DefaultActionGroup(), DumbAware {
}
}
class ChangeProjectColorAction(val projectPath: String, val name: @NlsSafe String, val index: Int):
class ChangeProjectColorAction(val projectPath: String, val name: @NlsSafe String, val index: Int, val projectName: String?):
AnAction(name, "", RecentProjectIconHelper.generateProjectIcon(projectPath, true, size = 16, colorIndex = index)), DumbAware
{
override fun getActionUpdateThread() = ActionUpdateThread.EDT
@@ -95,7 +95,7 @@ internal class ChangeProjectIconAction : RecentProjectsWelcomeScreenActionBase()
if (selectedItem is RecentProjectItem) {
return selectedItem.projectPath
}
return event.project?.basePath
return event.project?.let { ProjectWindowCustomizerService.projectPath(it) }
}
override fun update(event: AnActionEvent) {