diff --git a/platform/lang-impl/src/com/intellij/ide/navigationToolbar/rider/RiderMainToolbarRootPaneExtension.kt b/platform/lang-impl/src/com/intellij/ide/navigationToolbar/rider/RiderMainToolbarRootPaneExtension.kt index c2579f35889d..6436368bbfd6 100644 --- a/platform/lang-impl/src/com/intellij/ide/navigationToolbar/rider/RiderMainToolbarRootPaneExtension.kt +++ b/platform/lang-impl/src/com/intellij/ide/navigationToolbar/rider/RiderMainToolbarRootPaneExtension.kt @@ -30,7 +30,7 @@ import com.intellij.openapi.project.Project import com.intellij.openapi.util.Disposer import com.intellij.openapi.util.SimpleModificationTracker import com.intellij.openapi.wm.IdeRootPaneNorthExtension -import com.intellij.openapi.wm.ex.ProjectFrameActionExclusionService +import com.intellij.openapi.wm.ex.ProjectFrameTypeService import com.intellij.util.cancelOnDispose import com.intellij.util.concurrency.AppExecutorUtil import com.intellij.util.concurrency.annotations.RequiresBackgroundThread @@ -116,7 +116,7 @@ open class RiderMainToolbarRootPaneManager(private val project: Project) : Simpl @RequiresBackgroundThread private fun correctedToolbarActions(panel: JPanel): Map { val toolbarGroup = getToolbarGroup() ?: return emptyMap() - val excludedActionIds = service().getExcludedActionIds(panel.projectFrameTypeId(), ActionPlaces.MAIN_TOOLBAR) + val excludedActionIds = service().getExcludedActionIds(panel.projectFrameTypeId(), ActionPlaces.MAIN_TOOLBAR) val leftGroup = sideGroup(toolbarGroup, excludedActionIds, ::isLeftSideAction) val rightGroup = sideGroup(toolbarGroup, excludedActionIds, ::isRightSideAction) diff --git a/platform/lang-impl/testSources/com/intellij/openapi/wm/ex/ProjectFrameCapabilitiesServiceTest.kt b/platform/lang-impl/testSources/com/intellij/openapi/wm/ex/ProjectFrameCapabilitiesServiceTest.kt index f20659a000ba..e9ee93f77f01 100644 --- a/platform/lang-impl/testSources/com/intellij/openapi/wm/ex/ProjectFrameCapabilitiesServiceTest.kt +++ b/platform/lang-impl/testSources/com/intellij/openapi/wm/ex/ProjectFrameCapabilitiesServiceTest.kt @@ -26,7 +26,7 @@ class ProjectFrameCapabilitiesServiceTest { val uiPolicyRef = AtomicReference( ProjectFrameUiPolicy( projectPaneToActivateId = "pane-1", - toolWindowLayoutProfileId = "layout-profile-1", + startupToolWindowIdToActivate = "toolwindow-1", ) ) val capabilitiesComputationCount = AtomicInteger() @@ -59,16 +59,16 @@ class ProjectFrameCapabilitiesServiceTest { val service = ProjectFrameCapabilitiesService() assertThat(service.getUiPolicy(project)?.projectPaneToActivateId).isEqualTo("pane-1") - assertThat(service.getUiPolicy(project)?.toolWindowLayoutProfileId).isEqualTo("layout-profile-1") + assertThat(service.getUiPolicy(project)?.startupToolWindowIdToActivate).isEqualTo("toolwindow-1") uiPolicyRef.set( ProjectFrameUiPolicy( projectPaneToActivateId = "pane-2", - toolWindowLayoutProfileId = "layout-profile-2", + startupToolWindowIdToActivate = "toolwindow-2", ) ) assertThat(service.getUiPolicy(project)?.projectPaneToActivateId).isEqualTo("pane-2") - assertThat(service.getUiPolicy(project)?.toolWindowLayoutProfileId).isEqualTo("layout-profile-2") + assertThat(service.getUiPolicy(project)?.startupToolWindowIdToActivate).isEqualTo("toolwindow-2") assertThat(service.getAll(project)).isEqualTo(setOf(ProjectFrameCapability.WELCOME_EXPERIENCE)) assertThat(service.has(project, ProjectFrameCapability.WELCOME_EXPERIENCE)).isTrue() diff --git a/platform/platform-impl/src/com/intellij/openapi/wm/impl/ToolWindowLayoutProfileMigrationHelper.kt b/platform/platform-impl/src/com/intellij/openapi/wm/impl/ToolWindowLayoutProfileMigrationHelper.kt index b86aafb366a8..fee487cd5e12 100644 --- a/platform/platform-impl/src/com/intellij/openapi/wm/impl/ToolWindowLayoutProfileMigrationHelper.kt +++ b/platform/platform-impl/src/com/intellij/openapi/wm/impl/ToolWindowLayoutProfileMigrationHelper.kt @@ -4,7 +4,7 @@ package com.intellij.openapi.wm.impl import com.intellij.ide.util.PropertiesComponent import com.intellij.openapi.components.service import com.intellij.openapi.project.Project -import com.intellij.openapi.wm.ex.ProjectFrameCapabilitiesService +import com.intellij.openapi.wm.ex.ProjectFrameTypeService import com.intellij.toolWindow.ToolWindowLayoutApplyMode import com.intellij.toolWindow.ToolWindowLayoutProfile import com.intellij.toolWindow.ToolWindowLayoutProfileService @@ -17,11 +17,11 @@ internal data class ProjectFrameToolWindowLayoutProfile( ) internal fun resolveProjectFrameToolWindowLayoutProfile( + projectFrameTypeId: String?, project: Project, isNewUi: Boolean, ): ProjectFrameToolWindowLayoutProfile? { - val uiPolicy = service().getUiPolicy(project) ?: return null - val profileId = uiPolicy.toolWindowLayoutProfileId ?: return null + val profileId = service().getToolWindowLayoutProfileId(projectFrameTypeId) ?: return null val profile = service().getProfile(project = project, profileId = profileId, isNewUi = isNewUi) ?: return null return ProjectFrameToolWindowLayoutProfile(profileId = profileId, profile = profile) diff --git a/platform/platform-impl/src/com/intellij/openapi/wm/impl/ToolWindowManagerImpl.kt b/platform/platform-impl/src/com/intellij/openapi/wm/impl/ToolWindowManagerImpl.kt index 21ab47161523..d3db3cda4025 100644 --- a/platform/platform-impl/src/com/intellij/openapi/wm/impl/ToolWindowManagerImpl.kt +++ b/platform/platform-impl/src/com/intellij/openapi/wm/impl/ToolWindowManagerImpl.kt @@ -55,7 +55,7 @@ import com.intellij.openapi.wm.ToolWindowType import com.intellij.openapi.wm.WINDOW_INFO_DEFAULT_TOOL_WINDOW_PANE_ID import com.intellij.openapi.wm.WindowInfo import com.intellij.openapi.wm.WindowManager -import com.intellij.openapi.wm.ex.ProjectFrameCapabilitiesService +import com.intellij.openapi.wm.ex.ProjectFrameTypeService import com.intellij.openapi.wm.ex.ToolWindowEx import com.intellij.openapi.wm.ex.ToolWindowManagerEx import com.intellij.openapi.wm.ex.ToolWindowManagerListener @@ -198,18 +198,12 @@ open class ToolWindowManagerImpl @NonInjectable @TestOnly internal constructor( delay = SystemProperties.getIntProperty("actionSystem.keyGestureDblClickTime", 300), coroutineScope = coroutineScope, ) - val projectFrameLayoutProfile = resolveProjectFrameToolWindowLayoutProfile(project = project, isNewUi = isNewUi) - if (state.noStateLoaded) { - loadDefault(projectFrameLayoutProfile) - } @Suppress("LeakingThis") state.scheduledLayout.afterChange(this) { dl -> dl?.let { toolWindowSetInitializer.scheduleSetLayout(it) } } state.scheduledLayout.get()?.let { toolWindowSetInitializer.scheduleSetLayout(it) } - applyProjectFrameLayoutPolicy(projectFrameLayoutProfile) { layout -> - toolWindowSetInitializer.scheduleSetLayout(layout) - } + // the frame-type layout profile is resolved in `doInit`, once `projectFrameTypeId` is known } } @@ -426,6 +420,22 @@ open class ToolWindowManagerImpl @NonInjectable @TestOnly internal constructor( projectFrameTypeId: String? = this.projectFrameTypeId, ) { this.projectFrameTypeId = projectFrameTypeId + + // Resolved here rather than in the constructor: the layout profile is keyed by frame type, and + // `projectFrameTypeId` is only known now. `initUi` below consumes whatever layout we schedule. + val projectFrameLayoutProfile = resolveProjectFrameToolWindowLayoutProfile( + projectFrameTypeId = projectFrameTypeId, + project = project, + isNewUi = isNewUi, + ) + if (state.noStateLoaded) { + // `noStateLoaded` is set exactly when no layout was scheduled, so this cannot overwrite a restored one. + loadDefault(projectFrameLayoutProfile) + } + applyProjectFrameLayoutPolicy(projectFrameLayoutProfile) { layout -> + toolWindowSetInitializer.scheduleSetLayout(layout) + } + withContext(ModalityState.any().asContextElement()) { val defaultPaneInitialization = launch(Dispatchers.EDT) { this@ToolWindowManagerImpl.projectFrame = pane.frame @@ -526,7 +536,7 @@ open class ToolWindowManagerImpl @NonInjectable @TestOnly internal constructor( } private fun getProjectFrameToolWindowLayoutProfileId(): String? { - return service().getUiPolicy(project)?.toolWindowLayoutProfileId + return service().getToolWindowLayoutProfileId(projectFrameTypeId) } private fun getDefaultToolWindowPaneIfInitialized(): ToolWindowPane { @@ -557,12 +567,7 @@ open class ToolWindowManagerImpl @NonInjectable @TestOnly internal constructor( } } - private fun loadDefault( - projectFrameLayoutProfile: ProjectFrameToolWindowLayoutProfile? = resolveProjectFrameToolWindowLayoutProfile( - project = project, - isNewUi = isNewUi, - ), - ) { + private fun loadDefault(projectFrameLayoutProfile: ProjectFrameToolWindowLayoutProfile?) { val layout = projectFrameLayoutProfile?.profile?.layout ?: ToolWindowDefaultLayoutManager.getInstance().getLayoutCopy() toolWindowSetInitializer.scheduleSetLayout(layout) } diff --git a/platform/platform-impl/src/com/intellij/openapi/wm/impl/headertoolbar/MainToolbar.kt b/platform/platform-impl/src/com/intellij/openapi/wm/impl/headertoolbar/MainToolbar.kt index a9a92a01c460..4a2e28f63504 100644 --- a/platform/platform-impl/src/com/intellij/openapi/wm/impl/headertoolbar/MainToolbar.kt +++ b/platform/platform-impl/src/com/intellij/openapi/wm/impl/headertoolbar/MainToolbar.kt @@ -50,7 +50,7 @@ import com.intellij.openapi.keymap.impl.ui.ActionsTreeUtil import com.intellij.openapi.project.DumbAwareAction import com.intellij.openapi.util.IconLoader import com.intellij.openapi.util.SystemInfoRt -import com.intellij.openapi.wm.ex.ProjectFrameActionExclusionService +import com.intellij.openapi.wm.ex.ProjectFrameTypeService import com.intellij.openapi.wm.impl.IdeBackgroundUtil import com.intellij.openapi.wm.impl.ToolbarComboButton import com.intellij.openapi.wm.impl.customFrameDecorations.header.CustomWindowHeaderUtil @@ -563,7 +563,7 @@ private suspend fun computeMainActionGroups( customActionSchema: CustomActionsSchema, projectFrameTypeId: String? = null, ): List> { - val excludedActionIds = serviceAsync().getExcludedActionIds(projectFrameTypeId, ActionPlaces.MAIN_TOOLBAR) + val excludedActionIds = serviceAsync().getExcludedActionIds(projectFrameTypeId, ActionPlaces.MAIN_TOOLBAR) val result = ArrayList>(3) for (info in getMainToolbarGroups()) { customActionSchema.getCorrectedActionAsync(info.id, info.name)?.let { actionGroup -> @@ -581,7 +581,7 @@ internal fun blockingComputeMainActionGroups( customActionSchema: CustomActionsSchema, projectFrameTypeId: String? = null, ): List> { - val excludedActionIds = service().getExcludedActionIds(projectFrameTypeId, ActionPlaces.MAIN_TOOLBAR) + val excludedActionIds = service().getExcludedActionIds(projectFrameTypeId, ActionPlaces.MAIN_TOOLBAR) return getMainToolbarGroups() .mapNotNull { info -> customActionSchema.getCorrectedAction(info.id, info.name)?.let { actionGroup -> diff --git a/platform/platform-impl/src/com/intellij/toolWindow/ToolWindowSetInitializer.kt b/platform/platform-impl/src/com/intellij/toolWindow/ToolWindowSetInitializer.kt index e2866164ac02..636377c64d97 100644 --- a/platform/platform-impl/src/com/intellij/toolWindow/ToolWindowSetInitializer.kt +++ b/platform/platform-impl/src/com/intellij/toolWindow/ToolWindowSetInitializer.kt @@ -12,7 +12,6 @@ import com.intellij.openapi.application.EDT import com.intellij.openapi.application.ModalityState import com.intellij.openapi.application.UI import com.intellij.openapi.application.asContextElement -import com.intellij.openapi.components.service import com.intellij.openapi.components.serviceAsync import com.intellij.openapi.diagnostic.Logger import com.intellij.openapi.extensions.ExtensionPointListener @@ -26,7 +25,7 @@ import com.intellij.openapi.wm.ToolWindowAnchor import com.intellij.openapi.wm.ToolWindowEP import com.intellij.openapi.wm.ToolWindowFactory import com.intellij.openapi.wm.WINDOW_INFO_DEFAULT_TOOL_WINDOW_PANE_ID -import com.intellij.openapi.wm.ex.ProjectFrameCapabilitiesService +import com.intellij.openapi.wm.ex.ProjectFrameTypeService import com.intellij.openapi.wm.ex.ToolWindowManagerListener import com.intellij.openapi.wm.impl.DesktopLayout import com.intellij.openapi.wm.impl.ToolWindowManagerAppLevelHelper @@ -378,8 +377,8 @@ private fun beanToTask( @OptIn(ExperimentalCoroutinesApi::class) internal suspend fun computeToolWindowBeans(project: Project, projectFrameTypeId: String? = null): List { - val projectFrameToolWindowLayoutProfileId = service().getUiPolicy(project)?.toolWindowLayoutProfileId - val suppressedToolWindowIds = service().getSuppressedToolWindowIds( + val projectFrameToolWindowLayoutProfileId = serviceAsync().getToolWindowLayoutProfileId(projectFrameTypeId) + val suppressedToolWindowIds = serviceAsync().getSuppressedToolWindowIds( frameType = projectFrameTypeId, profileId = projectFrameToolWindowLayoutProfileId, ) diff --git a/platform/platform-impl/testSrc/com/intellij/toolWindow/ProjectFrameToolWindowLayoutServiceTest.kt b/platform/platform-impl/testSrc/com/intellij/toolWindow/ProjectFrameToolWindowLayoutServiceTest.kt index f8c60fd29003..a3d7f41d065d 100644 --- a/platform/platform-impl/testSrc/com/intellij/toolWindow/ProjectFrameToolWindowLayoutServiceTest.kt +++ b/platform/platform-impl/testSrc/com/intellij/toolWindow/ProjectFrameToolWindowLayoutServiceTest.kt @@ -11,10 +11,8 @@ import com.intellij.openapi.wm.ToolWindowAnchor import com.intellij.openapi.wm.ToolWindowEP import com.intellij.openapi.wm.ToolWindowFactory import com.intellij.openapi.wm.ToolWindowId -import com.intellij.openapi.wm.ex.ProjectFrameCapabilitiesProvider -import com.intellij.openapi.wm.ex.ProjectFrameCapabilitiesService -import com.intellij.openapi.wm.ex.ProjectFrameCapability -import com.intellij.openapi.wm.ex.ProjectFrameUiPolicy +import com.intellij.openapi.wm.ex.ProjectFrameTypeBean +import com.intellij.openapi.wm.ex.ProjectFrameTypeService import com.intellij.testFramework.ExtensionTestUtil import com.intellij.testFramework.junit5.TestApplication import com.intellij.testFramework.junit5.TestDisposable @@ -199,18 +197,27 @@ class ProjectFrameToolWindowLayoutServiceTest { } @Test - fun uiPolicyLayoutProfileSuppressesToolWindowEpWhenFrameTypeIsMissing() { - registerSuppressedToolWindowLayout() + fun frameTypeProfileSuppressesToolWindowEpWhenLayoutFrameTypeDoesNotMatch() { + registerLayoutBean( + ProjectFrameToolWindowLayoutBean().apply { + id = "dedicated" + frameType = "OTHER" + toolWindows = listOf(suppressedToolWindow("Suppressed")) + } + ) CountingToolWindowFactory.createdCount = 0 ExtensionTestUtil.maskExtensions(ToolWindowEP.EP_NAME, listOf(suppressedToolWindowEp()), disposable, fireEvents = false) ExtensionTestUtil.maskExtensions( - ProjectFrameCapabilitiesService.EP_NAME, - listOf(testUiPolicyProvider { "dedicated" }), + ProjectFrameTypeService.EP_NAME, + listOf(ProjectFrameTypeBean().apply { + id = "DEDICATED" + toolWindowLayoutProfile = "dedicated" + }), disposable, fireEvents = false, ) - val tasks = runBlocking { computeToolWindowBeans(project, projectFrameTypeId = null) } + val tasks = runBlocking { computeToolWindowBeans(project, projectFrameTypeId = "DEDICATED") } assertThat(tasks).isEmpty() assertThat(CountingToolWindowFactory.createdCount).isEqualTo(0) @@ -259,18 +266,6 @@ private fun suppressedToolWindowEp(): ToolWindowEP { } } -private fun testUiPolicyProvider(profileIdProvider: () -> String?): ProjectFrameCapabilitiesProvider { - return object : ProjectFrameCapabilitiesProvider { - override fun getCapabilities(project: Project): Set { - return emptySet() - } - - override fun getUiPolicy(project: Project, capabilities: Set): ProjectFrameUiPolicy? { - return profileIdProvider()?.let { ProjectFrameUiPolicy(toolWindowLayoutProfileId = it) } - } - } -} - private const val AGENT_SESSIONS_TOOL_WINDOW_ID = "agent.workbench.sessions" class CountingToolWindowFactory : ToolWindowFactory {