diff --git a/platform/ide-core/src/com/intellij/notification/DoNotAskManager.kt b/platform/ide-core/src/com/intellij/notification/DoNotAskManager.kt new file mode 100644 index 000000000000..23b3402cf268 --- /dev/null +++ b/platform/ide-core/src/com/intellij/notification/DoNotAskManager.kt @@ -0,0 +1,34 @@ +// Copyright 2000-2026 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license. +package com.intellij.notification + +import com.intellij.openapi.application.ApplicationManager +import com.intellij.openapi.project.Project +import org.jetbrains.annotations.ApiStatus +import org.jetbrains.annotations.Nls + +@ApiStatus.Internal +interface DoNotAskManager { + fun isDoNotAsk(notificationId: String): Boolean + + fun markDoNotAsk(notificationId: String, @Nls displayName: String?) + + fun clearDoNotAsk(notificationId: String) + + fun getDoNotAskNotifications(): Map +} + +@ApiStatus.Internal +interface DoNotAskAppManager : DoNotAskManager { + companion object { + @JvmStatic + fun getInstance(): DoNotAskAppManager = ApplicationManager.getApplication().getService(DoNotAskAppManager::class.java) + } +} + +@ApiStatus.Internal +interface DoNotAskProjectManager : DoNotAskManager { + companion object { + @JvmStatic + fun getInstance(project: Project): DoNotAskProjectManager = project.getService(DoNotAskProjectManager::class.java) + } +} diff --git a/platform/ide-core/src/com/intellij/notification/Notification.java b/platform/ide-core/src/com/intellij/notification/Notification.java index bdf47a2e3545..a92d7c8bff26 100644 --- a/platform/ide-core/src/com/intellij/notification/Notification.java +++ b/platform/ide-core/src/com/intellij/notification/Notification.java @@ -3,7 +3,6 @@ package com.intellij.notification; import com.intellij.ide.IdeCoreBundle; import com.intellij.ide.ui.IdeUiService; -import com.intellij.ide.util.PropertiesComponent; import com.intellij.openapi.actionSystem.ActionPlaces; import com.intellij.openapi.actionSystem.ActionUiKind; import com.intellij.openapi.actionSystem.AnAction; @@ -204,13 +203,11 @@ public class Notification { myDoNotAskDisplayName = title; myDoNotAskId = myGroupId; } - var id = "Notification.DoNotAsk-" + myDoNotAskId; - var doNotAsk = PropertiesComponent.getInstance().getBoolean(id, false); - if (doNotAsk) { + if (DoNotAskAppManager.getInstance().isDoNotAsk(myDoNotAskId)) { return false; } if (project != null) { - return !PropertiesComponent.getInstance(project).getBoolean(id, false); + return !DoNotAskProjectManager.getInstance(project).isDoNotAsk(myDoNotAskId); } return true; } @@ -443,22 +440,22 @@ public class Notification { ); } - private static final String DO_NOT_ASK_PREFIX = "Notification.DoNotAsk-"; - private static final String DO_NOT_ASK_DISPLAY_PREFIX = "Notification.DisplayName-DoNotAsk-"; - @ApiStatus.Experimental @Contract("_ -> this") public Notification setDoNotAskFor(@Nullable Project project) { - var manager = project == null ? PropertiesComponent.getInstance() : PropertiesComponent.getInstance(project); - manager.setValue(DO_NOT_ASK_PREFIX + myDoNotAskId, true); - manager.setValue(DO_NOT_ASK_DISPLAY_PREFIX + myDoNotAskId, myDoNotAskDisplayName); + if (project == null) { + DoNotAskAppManager.getInstance().markDoNotAsk(myDoNotAskId, myDoNotAskDisplayName); + } + else { + DoNotAskProjectManager.getInstance(project).markDoNotAsk(myDoNotAskId, myDoNotAskDisplayName); + } return this; } @ApiStatus.Experimental public static boolean isDoNotAskFor(@Nullable Project project, @NotNull String doNotAskId) { - return project != null && PropertiesComponent.getInstance(project).getBoolean(DO_NOT_ASK_PREFIX + doNotAskId) || - PropertiesComponent.getInstance().getBoolean(DO_NOT_ASK_PREFIX + doNotAskId); + return project != null && DoNotAskProjectManager.getInstance(project).isDoNotAsk(doNotAskId) || + DoNotAskAppManager.getInstance().isDoNotAsk(doNotAskId); } @ApiStatus.Internal diff --git a/platform/platform-impl/src/com/intellij/notification/impl/DoNotAskManagerImpl.kt b/platform/platform-impl/src/com/intellij/notification/impl/DoNotAskManagerImpl.kt new file mode 100644 index 000000000000..3eb070b5d762 --- /dev/null +++ b/platform/platform-impl/src/com/intellij/notification/impl/DoNotAskManagerImpl.kt @@ -0,0 +1,42 @@ +// Copyright 2000-2026 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license. +package com.intellij.notification.impl + +import com.intellij.configurationStore.saveSettingsForRemoteDevelopment +import com.intellij.ide.util.PropertiesComponent +import com.intellij.notification.DoNotAskAppManager +import com.intellij.notification.DoNotAskProjectManager +import com.intellij.openapi.components.State +import com.intellij.openapi.components.Storage +import com.intellij.openapi.project.Project +import com.intellij.util.application +import kotlinx.coroutines.CoroutineScope + +@State(name = "DoNotAskAppManager", storages = [Storage(value = "doNotAskNotifications.xml")]) +internal class DoNotAskAppManagerImpl(private val cs: CoroutineScope) : + DoNotAskSettings(), DoNotAskAppManager { + + override fun saveSettingsForRemDev() { + saveSettingsForRemoteDevelopment(cs, application) + } + + override fun getPropertiesComponent() : PropertiesComponent { + return PropertiesComponent.getInstance() + } + +} + +@State(name = "DoNotAskProjectManager", storages = [Storage(value = "doNotAskNotifications.xml")], useLoadedStateAsExisting = false) +internal class DoNotAskProjectManagerImpl(private val project: Project, private val cs: CoroutineScope) : + DoNotAskSettings(), DoNotAskProjectManager { + + override fun saveSettingsForRemDev() { + saveSettingsForRemoteDevelopment(cs, project) + } + + override fun getPropertiesComponent() : PropertiesComponent { + return PropertiesComponent.getInstance(project) + } + +} + + diff --git a/platform/platform-impl/src/com/intellij/notification/impl/DoNotAskSettings.kt b/platform/platform-impl/src/com/intellij/notification/impl/DoNotAskSettings.kt new file mode 100644 index 000000000000..9c420cb976e2 --- /dev/null +++ b/platform/platform-impl/src/com/intellij/notification/impl/DoNotAskSettings.kt @@ -0,0 +1,71 @@ +// Copyright 2000-2026 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license. +package com.intellij.notification.impl + +import com.intellij.ide.util.BasePropertyService +import com.intellij.ide.util.PropertiesComponent +import com.intellij.openapi.components.BaseState +import com.intellij.openapi.components.SimplePersistentStateComponent +import org.jetbrains.annotations.Nls + +private const val DO_NOT_ASK_KEY_PREFIX = "Notification.DoNotAsk-" +private const val DO_NOT_ASK_DISPLAY_KEY_PREFIX = "Notification.DisplayName-DoNotAsk-" + +internal class DoNotAskState : BaseState() { + var idToDisplayName: MutableMap by map() +} + +internal abstract class DoNotAskSettings : SimplePersistentStateComponent(DoNotAskState()) { + + @Synchronized + fun isDoNotAsk(notificationId: String): Boolean = notificationId in state.idToDisplayName + + @Synchronized + fun markDoNotAsk(notificationId: String, @Nls displayName: String?) { + state.idToDisplayName[notificationId] = displayName ?: notificationId + + saveSettingsForRemDev() + } + + @Synchronized + fun getDoNotAskNotifications(): Map = LinkedHashMap(state.idToDisplayName) + + @Synchronized + open fun clearDoNotAsk(notificationId: String) { + state.idToDisplayName.remove(notificationId) + + saveSettingsForRemDev() + } + + @Synchronized + override fun noStateLoaded() { + state.idToDisplayName.clear() + + migrateFromPropertiesComponent(getPropertiesComponent()) + } + + abstract fun saveSettingsForRemDev() + + abstract fun getPropertiesComponent() : PropertiesComponent + + fun migrateFromPropertiesComponent(manager: PropertiesComponent) { + if (manager !is BasePropertyService) return + + val idsToMigrate = ArrayList() + + manager.forEachPrimitiveValue { key, _ -> + if (key.startsWith(DO_NOT_ASK_KEY_PREFIX)) { + val notificationId = key.substring(DO_NOT_ASK_KEY_PREFIX.length) + idsToMigrate.add(notificationId) + } + } + + for (id in idsToMigrate) { + val displayName = manager.getValue(DO_NOT_ASK_DISPLAY_KEY_PREFIX + id, id) + + state.idToDisplayName[id] = displayName + + manager.unsetValue(DO_NOT_ASK_KEY_PREFIX + id) + manager.unsetValue(DO_NOT_ASK_DISPLAY_KEY_PREFIX + id) + } + } +} diff --git a/platform/platform-impl/src/com/intellij/notification/impl/ui/DoNotAskConfigurableUi.kt b/platform/platform-impl/src/com/intellij/notification/impl/ui/DoNotAskConfigurableUi.kt index f416af3a7a5d..d8a640e0f7de 100644 --- a/platform/platform-impl/src/com/intellij/notification/impl/ui/DoNotAskConfigurableUi.kt +++ b/platform/platform-impl/src/com/intellij/notification/impl/ui/DoNotAskConfigurableUi.kt @@ -3,8 +3,8 @@ package com.intellij.notification.impl.ui import com.intellij.ide.DataManager import com.intellij.ide.IdeBundle -import com.intellij.ide.util.BasePropertyService -import com.intellij.ide.util.PropertiesComponent +import com.intellij.notification.DoNotAskAppManager +import com.intellij.notification.DoNotAskProjectManager import com.intellij.openapi.actionSystem.CommonDataKeys import com.intellij.openapi.project.Project import com.intellij.openapi.wm.WindowManager @@ -16,8 +16,6 @@ import javax.swing.DefaultListModel import javax.swing.JComponent import kotlin.math.min -private const val DO_NOT_ASK_KEY_PREFIX = "Notification.DoNotAsk-" - internal class DoNotAskConfigurableUi { private var myCreated = false private lateinit var myList: JBList @@ -33,33 +31,32 @@ internal class DoNotAskConfigurableUi { } private fun getDoNotAskValues(): List { - val list = ArrayList() + return buildList { + addAll( + convertToDoNotAskValues( + DoNotAskAppManager.getInstance().getDoNotAskNotifications(), + forProject = false + ) + ) - getValues(PropertiesComponent.getInstance(), list, false) - - val project = getProject() - if (project != null) { - getValues(PropertiesComponent.getInstance(project), list, true) - } - - list.sortWith(Comparator { o1, o2 -> o1.id.compareTo(o2.id) }) - - return list + getProject()?.let { project -> + addAll( + convertToDoNotAskValues( + DoNotAskProjectManager.getInstance(project).getDoNotAskNotifications(), + forProject = true + ) + ) + } + }.sortedBy(DoNotAskInfo::id) } private fun getProject(): Project? { return CommonDataKeys.PROJECT.getData(DataManager.getInstance().getDataContext(WindowManager.getInstance().mostRecentFocusedWindow)) } - private fun getValues(manager: PropertiesComponent, list: ArrayList, forProject: Boolean) { - if (manager is BasePropertyService) { - manager.forEachPrimitiveValue { key, _ -> - if (key.startsWith(DO_NOT_ASK_KEY_PREFIX)) { - val id = key.substring(DO_NOT_ASK_KEY_PREFIX.length) - val name = manager.getValue("Notification.DisplayName-DoNotAsk-$id", id) - list.add(DoNotAskInfo(id, name, forProject)) - } - } + private fun convertToDoNotAskValues(entries: Map, forProject: Boolean): List { + return entries.map { (id, name) -> + DoNotAskInfo(id, name, forProject) } } @@ -101,28 +98,18 @@ internal class DoNotAskConfigurableUi { } fun apply() { - val manager = PropertiesComponent.getInstance() - val project = getProject() - val projectManager = if (project == null) null else PropertiesComponent.getInstance(project) for (info in myRemoveList) { if (info.forProject) { - if (projectManager != null) { - removeKey(projectManager, info.id) - } + project?.let { DoNotAskProjectManager.getInstance(it).clearDoNotAsk(info.id) } } else { - removeKey(manager, info.id) + DoNotAskAppManager.getInstance().clearDoNotAsk(info.id) } } } - - private fun removeKey(manager: PropertiesComponent, id: String) { - manager.unsetValue("Notification.DoNotAsk-$id") - manager.unsetValue("Notification.DisplayName-DoNotAsk-$id") - } } @ApiStatus.Internal -data class DoNotAskInfo(val id: String, val name: String, val forProject: Boolean) \ No newline at end of file +data class DoNotAskInfo(val id: String, val name: String, val forProject: Boolean) diff --git a/platform/platform-resources/src/META-INF/PlatformExtensions.xml b/platform/platform-resources/src/META-INF/PlatformExtensions.xml index 798357cea951..c750b37ca00c 100644 --- a/platform/platform-resources/src/META-INF/PlatformExtensions.xml +++ b/platform/platform-resources/src/META-INF/PlatformExtensions.xml @@ -904,6 +904,14 @@ The refresh itself is toggled by (Preferences | Appearance & Behavior | Syst serviceImplementation="com.intellij.notification.impl.NotificationsManagerImpl"/> + + + + + +