From 32a76c8067966ae49fa357060cd210060e9e4f8d Mon Sep 17 00:00:00 2001 From: Dmitry Batrak Date: Fri, 9 Jan 2026 16:52:17 +0200 Subject: [PATCH] IJPL-188924 Rewrite Build for Remote Development introduce FrontendBuildView GitOrigin-RevId: 6160ceab9240b0c87252da2936ef8dc78b676afd --- .../buildView/frontend/src/BuildTreeView.kt | 75 ++++++++--- .../frontend/src/FrontendBuildView.kt | 119 ++++++++++++++++++ .../src/FrontendMultipleBuildsView.kt | 36 +++--- .../build/BackendMultipleBuildsView.kt | 7 +- .../intellij/build/BuildTreeConsoleView.java | 19 ++- .../src/com/intellij/build/BuildView.java | 13 ++ .../src/com/intellij/build/BuildViewApiDto.kt | 3 + .../com/intellij/build/BuildViewViewModel.kt | 6 +- .../com/intellij/build/buildTreeFilters.kt | 29 +++-- 9 files changed, 258 insertions(+), 49 deletions(-) create mode 100644 platform/buildView/frontend/src/FrontendBuildView.kt diff --git a/platform/buildView/frontend/src/BuildTreeView.kt b/platform/buildView/frontend/src/BuildTreeView.kt index e8858cac167c..2ffde1de8a6f 100644 --- a/platform/buildView/frontend/src/BuildTreeView.kt +++ b/platform/buildView/frontend/src/BuildTreeView.kt @@ -3,6 +3,7 @@ package com.intellij.platform.buildView.frontend import com.intellij.build.* import com.intellij.ide.IdeBundle +import com.intellij.ide.OccurenceNavigator import com.intellij.ide.OccurenceNavigatorSupport import com.intellij.ide.actions.OccurenceNavigatorActionBase import com.intellij.ide.nls.NlsMessages @@ -56,8 +57,12 @@ import javax.swing.tree.* private val LOG = fileLogger() -internal class BuildTreeView(private val project: Project, parentScope: CoroutineScope, private val buildViewId: BuildViewId) - : JPanel(), UiDataProvider, ComponentContainer { +internal class BuildTreeView( + private val project: Project, + parentScope: CoroutineScope, + private val buildViewId: BuildViewId, + private val backendNavigationAndFiltering: Boolean = true, +) : JPanel(), UiDataProvider, ComponentContainer { private val uiScope = parentScope.childScope("BuildTreeView", Dispatchers.UI + ModalityState.any().asContextElement()) private val model = BuildTreeViewModelProxy.getInstance(buildViewId) @@ -80,6 +85,18 @@ internal class BuildTreeView(private val project: Project, parentScope: Coroutin private val occurenceNavigatorSupport = MyOccurenceNavigatorSupport(tree) + internal var showingSuccessful: Boolean + get() = filteringState.showSuccessful + set(value) { + handleFilteringStateChange(filteringState.copy(showSuccessful = value)) + } + + internal var showingWarnings: Boolean + get() = filteringState.showWarnings + set(value) { + handleFilteringStateChange(filteringState.copy(showWarnings = value)) + } + // A factor which can correct for the difference between frontend's and backend's clocks, // in case we need to display a duration of a process, for which we know the start timestamp on the backend. // It doesn't include the connection latency, but that seems acceptable in our case. @@ -98,15 +115,17 @@ internal class BuildTreeView(private val project: Project, parentScope: Coroutin handleTreeEvent(event, nodeMap) } } - uiScope.launch(Dispatchers.EDT /* Navigatable-s might expect WIL to be taken */) { - model.getNavigationFlow().collect { - handleNavigation(it.forward) + if (backendNavigationAndFiltering) { + uiScope.launch(Dispatchers.EDT /* Navigatable-s might expect WIL to be taken */) { + model.getNavigationFlow().collect { + handleNavigation(it.forward) + } } - } - uiScope.launch { - navigationContext.collect { - LOG.debug { "Navigation context: $it" } - model.onNavigationContextChange(it) + uiScope.launch { + navigationContext.collect { + LOG.debug { "Navigation context: $it" } + model.onNavigationContextChange(it) + } } } } @@ -219,7 +238,7 @@ internal class BuildTreeView(private val project: Project, parentScope: Coroutin val nodeId = event.nodeId if (nodeId == null) { LOG.debug { "Clearing selection" } - tree.clearSelection() + clearTreeSelection() } else { val node = nodeMap[nodeId] @@ -239,7 +258,9 @@ internal class BuildTreeView(private val project: Project, parentScope: Coroutin } } is BuildTreeFilteringState -> { - handleFilteringStateChange(event) + if (backendNavigationAndFiltering) { + handleFilteringStateChange(event) + } } } } @@ -292,10 +313,12 @@ internal class BuildTreeView(private val project: Project, parentScope: Coroutin } private fun updateNavigationContext() { - val hasPrevNode = occurenceNavigatorSupport.hasPreviousOccurence() - val hasNextNode = occurenceNavigatorSupport.hasNextOccurence() - val hasAnyNode = hasNextNode || hasPrevNode || (tree.selectionPath?.lastPathComponent as? MyNode)?.occurrenceNavigatable != null - navigationContext.value = BuildTreeNavigationContext(hasPrevNode, hasNextNode, hasAnyNode) + if (backendNavigationAndFiltering) { + val hasPrevNode = occurenceNavigatorSupport.hasPreviousOccurence() + val hasNextNode = occurenceNavigatorSupport.hasNextOccurence() + val hasAnyNode = hasNextNode || hasPrevNode || (tree.selectionPath?.lastPathComponent as? MyNode)?.occurrenceNavigatable != null + navigationContext.value = BuildTreeNavigationContext(hasPrevNode, hasNextNode, hasAnyNode) + } } fun maybeExpand(path: TreePath?): Boolean { @@ -337,6 +360,26 @@ internal class BuildTreeView(private val project: Project, parentScope: Coroutin return if (navigatables.isEmpty()) null else navigatables.toTypedArray() } + internal fun clearTreeSelection() { + tree.clearSelection() + } + + internal fun hasNextOccurence(): Boolean { + return occurenceNavigatorSupport.hasNextOccurence() + } + + internal fun hasPreviousOccurence(): Boolean { + return occurenceNavigatorSupport.hasPreviousOccurence() + } + + internal fun goNextOccurence(): OccurenceNavigator.OccurenceInfo? { + return occurenceNavigatorSupport.goNextOccurence() + } + + internal fun goPreviousOccurence(): OccurenceNavigator.OccurenceInfo? { + return occurenceNavigatorSupport.goPreviousOccurence() + } + private class MyOccurenceNavigatorSupport(tree: JTree) : OccurenceNavigatorSupport(tree) { override fun createDescriptorForNode(node: DefaultMutableTreeNode): Navigatable? { return (node as? MyNode)?.occurrenceNavigatable?.navigatable() diff --git a/platform/buildView/frontend/src/FrontendBuildView.kt b/platform/buildView/frontend/src/FrontendBuildView.kt new file mode 100644 index 000000000000..671c827eb10a --- /dev/null +++ b/platform/buildView/frontend/src/FrontendBuildView.kt @@ -0,0 +1,119 @@ +// 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.platform.buildView.frontend + +import com.intellij.build.BuildTreeConsoleView +import com.intellij.build.BuildViewId +import com.intellij.build.SuccessfulStepsToggleAction +import com.intellij.build.WarningsToggleAction +import com.intellij.icons.AllIcons +import com.intellij.ide.OccurenceNavigator +import com.intellij.ide.rpc.ComponentDirectTransferId +import com.intellij.ide.rpc.getComponent +import com.intellij.ide.util.PropertiesComponent +import com.intellij.lang.LangBundle +import com.intellij.openapi.Disposable +import com.intellij.openapi.actionSystem.* +import com.intellij.openapi.project.DumbAware +import com.intellij.openapi.project.Project +import com.intellij.openapi.util.NlsContexts +import com.intellij.platform.util.coroutines.childScope +import com.intellij.ui.OnePixelSplitter +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.cancel +import java.awt.BorderLayout +import java.lang.ref.Reference +import java.lang.ref.WeakReference +import javax.swing.JPanel +import kotlin.reflect.KMutableProperty1 + +internal class FrontendBuildView( + project: Project, + parentScope: CoroutineScope, + treeViewId: BuildViewId?, + consoleComponent: ComponentDirectTransferId, +) : JPanel(BorderLayout()), Disposable { + private val scope = parentScope.childScope("FrontendBuildView") + internal val treeView: BuildTreeView? + + init { + val console = consoleComponent.getComponent() + if (treeViewId != null) { + treeView = BuildTreeView(project, scope, treeViewId, false) + restoreSavedFiltering(treeView) + val splitter = OnePixelSplitter(BuildTreeConsoleView.SPLITTER_PROPERTY, BuildTreeConsoleView.SPLITTER_DEFAULT_PROPORTION).apply { + firstComponent = treeView + secondComponent = console + } + add(splitter) + } + else { + treeView = null + add(console) + } + } + + override fun dispose() { + scope.cancel() + } + + fun hasNextOccurence(): Boolean { + return treeView?.hasNextOccurence() ?: false + } + + fun hasPreviousOccurence(): Boolean { + return treeView?.hasPreviousOccurence() ?: false + } + + fun goNextOccurence(): OccurenceNavigator.OccurenceInfo? { + return treeView?.goNextOccurence() + } + + fun goPreviousOccurence(): OccurenceNavigator.OccurenceInfo? { + return treeView?.goPreviousOccurence() + } + + fun createFilteringActionGroup(): ActionGroup { + val actionGroup = DefaultActionGroup(LangBundle.message("action.filters.text"), true) + actionGroup.templatePresentation.icon = AllIcons.Actions.Show + val treeViewRef = WeakReference(treeView) + actionGroup.add(FilteringToggleAction(LangBundle.message("build.tree.filters.show.warnings"), WarningsToggleAction.STATE_KEY, + BuildTreeView::showingWarnings, WarningsToggleAction.DEFAULT_STATE, treeViewRef)) + actionGroup.add(FilteringToggleAction(LangBundle.message("build.tree.filters.show.successful"), SuccessfulStepsToggleAction.STATE_KEY, + BuildTreeView::showingSuccessful, SuccessfulStepsToggleAction.DEFAULT_STATE, treeViewRef)) + return actionGroup + } +} + +private fun restoreSavedFiltering(treeView: BuildTreeView) { + treeView.showingWarnings = PropertiesComponent.getInstance().getBoolean(WarningsToggleAction.STATE_KEY, + WarningsToggleAction.DEFAULT_STATE) + treeView.showingSuccessful = PropertiesComponent.getInstance().getBoolean(SuccessfulStepsToggleAction.STATE_KEY, + SuccessfulStepsToggleAction.DEFAULT_STATE) +} + +private class FilteringToggleAction( + @NlsContexts.Command text: String, + private val stateKey: String, + private val property: KMutableProperty1, + private val defaultState: Boolean, + private val treeViewRef: Reference, +) : ToggleAction(text), DumbAware { + override fun getActionUpdateThread() = ActionUpdateThread.EDT + + override fun isSelected(e: AnActionEvent): Boolean { + val presentation = e.presentation + val treeView = treeViewRef.get() + if (treeView == null) { + presentation.isEnabledAndVisible = false + return false + } + presentation.isEnabledAndVisible = true + return property.get(treeView) + } + + override fun setSelected(e: AnActionEvent, state: Boolean) { + val treeView = treeViewRef.get() ?: return + property.set(treeView, state) + PropertiesComponent.getInstance().setValue(stateKey, state, defaultState) + } +} diff --git a/platform/buildView/frontend/src/FrontendMultipleBuildsView.kt b/platform/buildView/frontend/src/FrontendMultipleBuildsView.kt index 012840e9d712..d871305f5414 100644 --- a/platform/buildView/frontend/src/FrontendMultipleBuildsView.kt +++ b/platform/buildView/frontend/src/FrontendMultipleBuildsView.kt @@ -18,7 +18,6 @@ import com.intellij.openapi.diagnostic.fileLogger import com.intellij.openapi.project.DumbAwareAction import com.intellij.openapi.project.Project import com.intellij.openapi.ui.OnePixelDivider -import com.intellij.openapi.util.Computable import com.intellij.openapi.util.Disposer import com.intellij.openapi.util.NlsContexts import com.intellij.openapi.wm.ToolWindow @@ -57,14 +56,14 @@ internal class FrontendMultipleBuildsView( private val id = buildContent.id private val name = buildContent.name private val buildMap = mutableMapOf() - private val viewMap = mutableMapOf() + private val viewMap = mutableMapOf() private val toolbarActions = DefaultActionGroup() private val threeComponentsSplitter = createSplitter() private val buildListModel = DefaultListModel() private val buildList = createList() private val content: Content = createContent(id, buildContent.isPinned) private val focusWatcher = FocusWatcher() - private var activeView: BuildView? = null + private var activeView: FrontendBuildView? = null private var locked = false init { @@ -165,7 +164,7 @@ internal class FrontendMultipleBuildsView( buildList.setFixedCellHeight(JBUI.scale(UIUtil.LIST_FIXED_CELL_HEIGHT * 2)) } - private fun setActiveView(view: BuildView?) { + private fun setActiveView(view: FrontendBuildView?) { if (activeView === view) { return } @@ -176,20 +175,20 @@ internal class FrontendMultipleBuildsView( content.preferredFocusableComponent = null } else { - threeComponentsSplitter.secondComponent = view.component - content.setPreferredFocusedComponent(Computable { view.preferredFocusableComponent }) + threeComponentsSplitter.secondComponent = view + content.preferredFocusableComponent = view if (focusWatcher.focused) { - view.preferredFocusableComponent?.requestFocusInWindow() // todo check IJPL-172285 + view.requestFocusInWindow() // todo check IJPL-172285 } } } - private fun configureToolbar(view: BuildView?) { + private fun configureToolbar(view: FrontendBuildView?) { toolbarActions.removeAll() if (view != null) { - toolbarActions.addAll(*view.createConsoleActions()) + // todo view-dependent actions toolbarActions.add(PinBuildViewAction()) - toolbarActions.add(createFilteringActionsGroup(WeakFilterableSupplier(view))) + toolbarActions.add(view.createFilteringActionGroup()) } } @@ -199,7 +198,7 @@ internal class FrontendMultipleBuildsView( val info = FrontendBuildInfo(event) buildMap[event.buildId] = info buildListModel.addElement(info) - val buildView = BuildView(project, info, "build.toolwindow.${name}.selection.state", MyViewManager) + val buildView = FrontendBuildView(project, scope, event.treeViewId, event.consoleComponent) viewMap[info] = buildView Disposer.register(this, buildView) if (activeView == null) { @@ -243,10 +242,14 @@ internal class FrontendMultipleBuildsView( is BuildViewEvent.BuildRemoved -> { val info = buildMap.remove(event.buildId) ?: return buildListModel.removeElement(info) - Disposer.dispose(viewMap.remove(info)!!) + val buildView = viewMap.remove(info)!! + Disposer.dispose(buildView) if (buildListModel.size == 1) { setBuildListVisible(false) } + if (buildView === activeView) { + setActiveView(null) + } } } } @@ -304,10 +307,10 @@ internal class FrontendMultipleBuildsView( val range = if (next) index.. val buildInfo = buildListModel.getElementAt(i) - val buildView: BuildView? = viewMap[buildInfo] + val buildView: FrontendBuildView? = viewMap[buildInfo] if (buildView == null) return@firstNotNullOfOrNull null if (i != index) { - val eventView = buildView.eventView + val eventView = buildView.treeView if (eventView == null) return@firstNotNullOfOrNull null eventView.clearTreeSelection() } @@ -429,9 +432,4 @@ internal class FrontendMultipleBuildsView( override fun toString() = "Build[$id/$title]" } - - private object MyViewManager : ViewManager { - override fun isConsoleEnabledByDefault() = false - override fun isBuildContentView() = true - } } \ No newline at end of file diff --git a/platform/lang-impl/src/com/intellij/build/BackendMultipleBuildsView.kt b/platform/lang-impl/src/com/intellij/build/BackendMultipleBuildsView.kt index 64f16ef0e45e..f1547ac4cd12 100644 --- a/platform/lang-impl/src/com/intellij/build/BackendMultipleBuildsView.kt +++ b/platform/lang-impl/src/com/intellij/build/BackendMultipleBuildsView.kt @@ -2,6 +2,7 @@ package com.intellij.build import com.intellij.build.events.* +import com.intellij.ide.rpc.setupTransfer import com.intellij.openapi.diagnostic.debug import com.intellij.openapi.diagnostic.fileLogger import com.intellij.openapi.diagnostic.trace @@ -121,9 +122,13 @@ class BackendMultipleBuildsView( buildView.onEvent(buildId, event) + val treeViewId = buildView.eventView?.buildViewId + val consoleComponent = buildView.consoleComponent.setupTransfer(buildView) + viewManager.onBuildStart(buildInfo) viewModel.onBuildStarted(this, id, buildInfo.title, buildInfo.startTime, event.message, - buildInfo.isAutoFocusContent, buildInfo.isActivateToolWindowWhenAdded) + buildInfo.isAutoFocusContent, buildInfo.isActivateToolWindowWhenAdded, + treeViewId, consoleComponent) } else { if (!isFirstErrorShown && diff --git a/platform/lang-impl/src/com/intellij/build/BuildTreeConsoleView.java b/platform/lang-impl/src/com/intellij/build/BuildTreeConsoleView.java index 7e53e5785e3d..3a2f7d1a7bf4 100644 --- a/platform/lang-impl/src/com/intellij/build/BuildTreeConsoleView.java +++ b/platform/lang-impl/src/com/intellij/build/BuildTreeConsoleView.java @@ -101,7 +101,10 @@ public final class BuildTreeConsoleView implements ConsoleView, UiDataProvider, public static final DataKey COMPONENT_KEY = DataKey.create("BuildTreeConsoleView"); private static final @NonNls String TREE = "tree"; - private static final @NonNls String SPLITTER_PROPERTY = "BuildView.Splitter.Proportion"; + @ApiStatus.Internal + public static final @NonNls String SPLITTER_PROPERTY = "BuildView.Splitter.Proportion"; + @ApiStatus.Internal + public static final float SPLITTER_DEFAULT_PROPORTION = 0.33f; @Service(Service.Level.PROJECT) private static final class ScopeHolder { @@ -140,7 +143,8 @@ public final class BuildTreeConsoleView implements ConsoleView, UiDataProvider, private final OccurenceNavigator myOccurrenceNavigatorSupport; private final Set myDeferredEvents = ConcurrentCollectionFactory.createConcurrentSet(); - private final boolean mySplitImplementation = Registry.is("build.toolwindow.split.tree", false); + private final boolean mySplitImplementation = Registry.is("build.toolwindow.split.tree", false) || + Registry.is("build.toolwindow.split", false); public BuildTreeConsoleView(@NotNull Project project, @NotNull BuildDescriptor buildDescriptor, @@ -204,7 +208,7 @@ public final class BuildTreeConsoleView implements ConsoleView, UiDataProvider, } myPanel.setLayout(new BorderLayout()); - OnePixelSplitter myThreeComponentsSplitter = new OnePixelSplitter(SPLITTER_PROPERTY, 0.33f); + OnePixelSplitter myThreeComponentsSplitter = new OnePixelSplitter(SPLITTER_PROPERTY, SPLITTER_DEFAULT_PROPORTION); myThreeComponentsSplitter.setFirstComponent(treeComponent); List filters = myBuildDescriptor.getExecutionFilters(); myConsoleViewHandler = new ConsoleViewHandler(myProject, myTree, myBuildProgressRootNode, this, @@ -1119,6 +1123,15 @@ public final class BuildTreeConsoleView implements ConsoleView, UiDataProvider, myConsoleViewHandler.setNodeIfChanged(node); } + BuildViewId getBuildViewId() { + return mySplitImplementation ? myTreeVm.getId() : null; + } + + @NotNull + JComponent getConsoleComponent() { + return myConsoleViewHandler.getComponent(); + } + private static final class ConsoleViewHandler implements Disposable { private static final String EMPTY_CONSOLE_NAME = "empty"; private final Project myProject; diff --git a/platform/lang-impl/src/com/intellij/build/BuildView.java b/platform/lang-impl/src/com/intellij/build/BuildView.java index b95882482ba3..065043fb2665 100644 --- a/platform/lang-impl/src/com/intellij/build/BuildView.java +++ b/platform/lang-impl/src/com/intellij/build/BuildView.java @@ -245,6 +245,19 @@ public class BuildView extends CompositeView return getView(BuildTreeConsoleView.class.getName(), BuildTreeConsoleView.class); } + // returns a non-null value after the view is initialized (after build start event is processed) + JComponent getConsoleComponent() { + BuildTreeConsoleView eventView = getEventView(); + if (eventView != null) { + return eventView.getConsoleComponent(); + } + ExecutionConsole console = getView(CONSOLE_VIEW_NAME); + if (console != null) { + return console.getComponent(); + } + return null; + } + @Override public void addChangeListener(@NotNull ChangeListener listener, @NotNull Disposable parent) { ExecutionConsole console = getConsoleView(); diff --git a/platform/lang-impl/src/com/intellij/build/BuildViewApiDto.kt b/platform/lang-impl/src/com/intellij/build/BuildViewApiDto.kt index 1b320ecd20ec..63947cabadff 100644 --- a/platform/lang-impl/src/com/intellij/build/BuildViewApiDto.kt +++ b/platform/lang-impl/src/com/intellij/build/BuildViewApiDto.kt @@ -2,6 +2,7 @@ package com.intellij.build import com.intellij.build.events.BuildEventsNls +import com.intellij.ide.rpc.ComponentDirectTransferId import com.intellij.ide.ui.icons.IconId import com.intellij.openapi.util.NlsContexts import com.intellij.platform.rpc.Id @@ -23,6 +24,8 @@ sealed interface BuildViewEvent { val message: @BuildEventsNls.Message String, val requestFocus: Boolean, val activateToolWindow: Boolean, + val treeViewId: BuildViewId?, + val consoleComponent: ComponentDirectTransferId, ) : BuildViewEvent @Serializable diff --git a/platform/lang-impl/src/com/intellij/build/BuildViewViewModel.kt b/platform/lang-impl/src/com/intellij/build/BuildViewViewModel.kt index 9d5ce576bad4..54d0bcb8e266 100644 --- a/platform/lang-impl/src/com/intellij/build/BuildViewViewModel.kt +++ b/platform/lang-impl/src/com/intellij/build/BuildViewViewModel.kt @@ -2,6 +2,7 @@ package com.intellij.build import com.intellij.build.events.BuildEventsNls +import com.intellij.ide.rpc.ComponentDirectTransferId import com.intellij.ide.ui.icons.rpcId import com.intellij.openapi.components.Service import com.intellij.openapi.components.service @@ -27,10 +28,13 @@ class BuildViewViewModel(scope: CoroutineScope) : FlowWithHistory) { WarningsToggleAction.install(filterable) } -internal open class FilterToggleAction( +@ApiStatus.Internal +open class FilterToggleAction( @NlsContexts.Command text: String, private val stateKey: String?, private val filterableRef: Supplier?>, @@ -100,26 +101,36 @@ private fun install( } } -internal class SuccessfulStepsToggleAction(filterable: Supplier?>) : - FilterToggleAction(LangBundle.message("build.tree.filters.show.successful"), STATE_KEY, filterable, SUCCESSFUL_STEPS_FILTER, false), DumbAware { +@ApiStatus.Internal +class SuccessfulStepsToggleAction(filterable: Supplier?>) : + FilterToggleAction(LangBundle.message("build.tree.filters.show.successful"), + STATE_KEY, filterable, SUCCESSFUL_STEPS_FILTER, DEFAULT_STATE), DumbAware { companion object { - private const val STATE_KEY = "build.toolwindow.show.successful.steps.selection.state" + @ApiStatus.Internal + const val STATE_KEY: String = "build.toolwindow.show.successful.steps.selection.state" + @ApiStatus.Internal + const val DEFAULT_STATE: Boolean = false fun install(filterable: Filterable) { - install(filterable, SUCCESSFUL_STEPS_FILTER, STATE_KEY, false) + install(filterable, SUCCESSFUL_STEPS_FILTER, STATE_KEY, DEFAULT_STATE) } } } -internal class WarningsToggleAction(filterable: Supplier?>) : - FilterToggleAction(LangBundle.message("build.tree.filters.show.warnings"), STATE_KEY, filterable, WARNINGS_FILTER, true), DumbAware { +@ApiStatus.Internal +class WarningsToggleAction(filterable: Supplier?>) : + FilterToggleAction(LangBundle.message("build.tree.filters.show.warnings"), + STATE_KEY, filterable, WARNINGS_FILTER, DEFAULT_STATE), DumbAware { companion object { - private const val STATE_KEY = "build.toolwindow.show.warnings.selection.state" + @ApiStatus.Internal + const val STATE_KEY: String = "build.toolwindow.show.warnings.selection.state" + @ApiStatus.Internal + const val DEFAULT_STATE: Boolean = true fun install(filterable: Filterable) { - install(filterable, WARNINGS_FILTER, STATE_KEY, true) + install(filterable, WARNINGS_FILTER, STATE_KEY, DEFAULT_STATE) } } }