diff --git a/platform/vcs-impl/frontend/src/com/intellij/platform/vcs/impl/frontend/changes/ChangesViewSplitComponentProvider.kt b/platform/vcs-impl/frontend/src/com/intellij/platform/vcs/impl/frontend/changes/ChangesViewSplitComponentProvider.kt index f54e95e36ae9..8872df310abe 100644 --- a/platform/vcs-impl/frontend/src/com/intellij/platform/vcs/impl/frontend/changes/ChangesViewSplitComponentProvider.kt +++ b/platform/vcs-impl/frontend/src/com/intellij/platform/vcs/impl/frontend/changes/ChangesViewSplitComponentProvider.kt @@ -4,8 +4,6 @@ package com.intellij.platform.vcs.impl.frontend.changes import com.intellij.openapi.project.Project import com.intellij.openapi.vcs.FilePath import com.intellij.openapi.vcs.changes.* -import com.intellij.openapi.vcs.changes.ui.ChangesGroupingPolicyFactory -import com.intellij.openapi.vcs.changes.ui.TreeModelBuilder import com.intellij.platform.vcs.impl.shared.changes.ChangeListsViewModel import com.intellij.ui.split.SplitComponentBinding import com.intellij.ui.split.SplitComponentProvider @@ -21,11 +19,11 @@ internal class ChangesViewSplitComponentProvider : SplitComponentProvider, unversionedFiles: List) { @@ -40,10 +38,4 @@ internal class ChangesViewSplitComponentProvider : SplitComponentProvider ChangeNodeDecorator + @ApiStatus.Internal object ChangesViewUtil { - private fun getChangeDecoratorProvider(project: Project, isAllowExcludeFromCommit: () -> Boolean): (ChangeNodeDecorator?) -> PartialCommitChangeNodeDecorator { - return { baseDecorator: ChangeNodeDecorator? -> PartialCommitChangeNodeDecorator(project, baseDecorator, isAllowExcludeFromCommit) } - } + private fun getChangeDecoratorProvider(project: Project, isAllowExcludeFromCommit: () -> Boolean): DecoratorProvider = + { baseDecorator -> PartialCommitChangeNodeDecorator(project, baseDecorator, isAllowExcludeFromCommit) } fun createTreeModel( project: Project, grouping: ChangesGroupingPolicyFactory, changeLists: List, unversionedFiles: List, - showIgnoredFiles: Boolean, + ignoredFiles: List, isAllowExcludeFromCommit: () -> Boolean ): DefaultTreeModel { - val changeListManager = ChangeListManagerImpl.getInstanceImpl(project) - - val shouldShowUntrackedLoading = unversionedFiles.isEmpty() && - !project.getService(InitialVfsRefreshService::class.java).isInitialVfsRefreshFinished() && - changeListManager.isUnversionedInUpdateMode - val skipSingleDefaultChangeList = !changeListManager.areChangeListsEnabled() - + val skipSingleDefaultChangeList = !ChangeListsViewModel.getInstance(project).areChangeListsEnabled.value val treeModelBuilder = TreeModelBuilder(project, grouping) .setChangeLists(changeLists, skipSingleDefaultChangeList, getChangeDecoratorProvider(project, isAllowExcludeFromCommit)) - .also { TreeModelBuilderEx.getInstanceOrNull(project)?.modifyTreeModelBuilder(it) } + .also { TreeModelBuilderEx.getInstanceOrNull(project)?.modifyTreeModelBuilder(it, unversionedFiles) } .setUnversioned(unversionedFiles) - if (showIgnoredFiles) { - val ignoredFilePaths: List = changeListManager.getIgnoredFilePaths() - treeModelBuilder.setIgnored(ignoredFilePaths) - } - if (shouldShowUntrackedLoading) { - treeModelBuilder.insertSubtreeRoot(ChangesBrowserUnversionedLoadingPendingNode()) - } + treeModelBuilder.setIgnored(ignoredFiles) for (extension in ChangesViewModifier.KEY.getExtensions(project)) { try { diff --git a/platform/vcs-impl/shared/src/com/intellij/openapi/vcs/changes/CommitChangesViewWithToolbarPanel.kt b/platform/vcs-impl/shared/src/com/intellij/openapi/vcs/changes/CommitChangesViewWithToolbarPanel.kt index a470eae3b73d..a244a8fe7bb2 100644 --- a/platform/vcs-impl/shared/src/com/intellij/openapi/vcs/changes/CommitChangesViewWithToolbarPanel.kt +++ b/platform/vcs-impl/shared/src/com/intellij/openapi/vcs/changes/CommitChangesViewWithToolbarPanel.kt @@ -11,7 +11,6 @@ import com.intellij.openapi.progress.checkCanceled import com.intellij.openapi.project.Project import com.intellij.openapi.vcs.FilePath import com.intellij.openapi.vcs.changes.ChangesViewModifier.ChangesViewModifierListener -import com.intellij.openapi.vcs.changes.ui.ChangesGroupingPolicyFactory import com.intellij.openapi.vcs.changes.ui.ChangesListView import com.intellij.openapi.vcs.changes.ui.ChangesTree import com.intellij.openapi.vcs.changes.ui.TreeModelBuilder @@ -34,7 +33,6 @@ import kotlinx.coroutines.flow.collectLatest import org.jetbrains.annotations.ApiStatus import org.jetbrains.annotations.CalledInAny import java.lang.Runnable -import javax.swing.tree.DefaultTreeModel import kotlin.time.Duration.Companion.milliseconds @ApiStatus.Internal @@ -141,16 +139,25 @@ class CommitChangesViewWithToolbarPanel( if (!cs.isActive || !project.isInitialized || application.isUnitTestMode) return val modelProvider = modelProvider ?: return - val model = TRACER.spanBuilder(ChangesView.ChangesViewRefreshBackground.name).use { - modelProvider.getModel(changesView.grouping) + val (modelData, model) = TRACER.spanBuilder(ChangesView.ChangesViewRefreshBackground.name).use { + val modelData = modelProvider.getModelData() + + modelData to ChangesViewUtil.createTreeModel( + project, + changesView.grouping, + modelData.changeLists, + modelData.unversionedFiles, + modelData.ignoredFiles, + modelData.isAllowExcludeFromCommit, + ) } checkCanceled() withContext(Dispatchers.EDT) { TRACER.spanBuilder(ChangesView.ChangesViewRefreshEdt.getName()).use { - changesView.updateTreeModel(model.treeModel, ChangesViewTreeStateStrategy()) + changesView.updateTreeModel(model, ChangesViewTreeStateStrategy()) checkCanceled() - modelProvider.synchronizeInclusion(model.changeLists, model.unversionedFiles) + modelProvider.synchronizeInclusion(modelData.changeLists, modelData.unversionedFiles) } } } @@ -191,11 +198,14 @@ class CommitChangesViewWithToolbarPanel( } interface ModelProvider { - fun getModel(grouping: ChangesGroupingPolicyFactory): ExtendedTreeModel + fun getModelData(): ModelData fun synchronizeInclusion(changeLists: List, unversionedFiles: List) - class ExtendedTreeModel(val changeLists: List, val unversionedFiles: List, val treeModel: DefaultTreeModel) + class ModelData(val changeLists: List, + val unversionedFiles: List, + val ignoredFiles: List, + val isAllowExcludeFromCommit: () -> Boolean) } interface Initializer { diff --git a/platform/vcs-impl/shared/src/com/intellij/platform/vcs/impl/shared/changes/ChangeListsViewModel.kt b/platform/vcs-impl/shared/src/com/intellij/platform/vcs/impl/shared/changes/ChangeListsViewModel.kt index 3b6d91481528..7b6f4206dc8c 100644 --- a/platform/vcs-impl/shared/src/com/intellij/platform/vcs/impl/shared/changes/ChangeListsViewModel.kt +++ b/platform/vcs-impl/shared/src/com/intellij/platform/vcs/impl/shared/changes/ChangeListsViewModel.kt @@ -22,7 +22,7 @@ class ChangeListsViewModel( ) { val areChangeListsEnabled: StateFlow = changeListsApiFlow(checkRegistry = false) { api, projectId -> emitAll(api.areChangeListsEnabled(projectId)) - }.stateIn(cs, SharingStarted.Eagerly, false) + }.stateIn(cs, SharingStarted.Eagerly, true) val changeListManagerState: StateFlow = changeListsApiFlow(checkRegistry = false) { api, projectId -> emitAll(api.getChangeListManagerState(projectId)) diff --git a/platform/vcs-impl/shared/src/com/intellij/platform/vcs/impl/shared/changes/TreeModelBuilderEx.kt b/platform/vcs-impl/shared/src/com/intellij/platform/vcs/impl/shared/changes/TreeModelBuilderEx.kt index 74fa2650592b..aae0eefaaaf5 100644 --- a/platform/vcs-impl/shared/src/com/intellij/platform/vcs/impl/shared/changes/TreeModelBuilderEx.kt +++ b/platform/vcs-impl/shared/src/com/intellij/platform/vcs/impl/shared/changes/TreeModelBuilderEx.kt @@ -3,6 +3,7 @@ package com.intellij.platform.vcs.impl.shared.changes import com.intellij.openapi.components.serviceOrNull import com.intellij.openapi.project.Project +import com.intellij.openapi.vcs.FilePath import com.intellij.openapi.vcs.changes.Change import com.intellij.openapi.vcs.changes.ui.ChangeListRemoteState import com.intellij.openapi.vcs.changes.ui.ChangeNodeDecorator @@ -19,7 +20,7 @@ interface TreeModelBuilderEx { */ fun getChangeNodeInChangelistBaseDecorator(listRemoteState: ChangeListRemoteState, change: Change, index: Int): ChangeNodeDecorator? - fun modifyTreeModelBuilder(modelBuilder: TreeModelBuilder) + fun modifyTreeModelBuilder(modelBuilder: TreeModelBuilder, unversionedFiles: List) companion object { @JvmStatic diff --git a/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/ui/BackendChangesViewModelBuilderService.kt b/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/ui/BackendChangesViewModelBuilderService.kt index 8118685a9390..f75613d9c6f9 100644 --- a/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/ui/BackendChangesViewModelBuilderService.kt +++ b/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/ui/BackendChangesViewModelBuilderService.kt @@ -1,7 +1,9 @@ // Copyright 2000-2025 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license. package com.intellij.openapi.vcs.changes.ui +import com.intellij.openapi.project.InitialVfsRefreshService import com.intellij.openapi.project.Project +import com.intellij.openapi.vcs.FilePath import com.intellij.openapi.vcs.FileStatus import com.intellij.openapi.vcs.changes.* import com.intellij.openapi.vfs.VirtualFile @@ -22,9 +24,16 @@ internal class BackendChangesViewModelBuilderService(private val project: Projec ): ChangeNodeDecorator = RemoteStatusChangeNodeDecorator(revisionsCache, listRemoteState, index) - override fun modifyTreeModelBuilder(modelBuilder: TreeModelBuilder) { + override fun modifyTreeModelBuilder(modelBuilder: TreeModelBuilder, unversionedFiles: List) { val changeListManager = ChangeListManagerImpl.getInstanceImpl(project) + val shouldShowUntrackedLoading = unversionedFiles.isEmpty() && + !project.getService(InitialVfsRefreshService::class.java).isInitialVfsRefreshFinished() && + changeListManager.isUnversionedInUpdateMode + if (shouldShowUntrackedLoading) { + modelBuilder.insertSubtreeRoot(ChangesBrowserUnversionedLoadingPendingNode()) + } + modelBuilder.setLocallyDeletedPaths(changeListManager.deletedFiles) .setModifiedWithoutEditing(changeListManager.modifiedWithoutEditing) .setSwitchedFiles(changeListManager.switchedFilesMap) diff --git a/platform/vcs-impl/src/com/intellij/vcs/changes/viewModel/BackendLocalCommitChangesViewModel.kt b/platform/vcs-impl/src/com/intellij/vcs/changes/viewModel/BackendLocalCommitChangesViewModel.kt index c46e1fa53bc4..05927bdee37f 100644 --- a/platform/vcs-impl/src/com/intellij/vcs/changes/viewModel/BackendLocalCommitChangesViewModel.kt +++ b/platform/vcs-impl/src/com/intellij/vcs/changes/viewModel/BackendLocalCommitChangesViewModel.kt @@ -4,9 +4,7 @@ package com.intellij.openapi.vcs.changes import com.intellij.openapi.actionSystem.ActionManager import com.intellij.openapi.actionSystem.AnAction import com.intellij.openapi.vcs.FilePath -import com.intellij.openapi.vcs.changes.CommitChangesViewWithToolbarPanel.ModelProvider.ExtendedTreeModel import com.intellij.openapi.vcs.changes.ui.ChangesBrowserNode.UNVERSIONED_FILES_TAG -import com.intellij.openapi.vcs.changes.ui.ChangesGroupingPolicyFactory import com.intellij.openapi.vcs.changes.ui.ChangesListView import com.intellij.openapi.vcs.changes.ui.VcsTreeModelData.* import com.intellij.openapi.vfs.VirtualFile @@ -107,20 +105,18 @@ internal class BackendLocalCommitChangesViewModel(private val panel: CommitChang override fun getPreferredFocusableComponent(): JComponent = panel.changesView.preferredFocusedComponent private inner class ModelProvider : CommitChangesViewWithToolbarPanel.ModelProvider { - override fun getModel(grouping: ChangesGroupingPolicyFactory): ExtendedTreeModel { + override fun getModelData(): CommitChangesViewWithToolbarPanel.ModelProvider.ModelData { val project = panel.project val changeListManager = ChangeListManagerImpl.getInstanceImpl(project) val changeLists = changeListManager.changeLists val unversionedFiles = changeListManager.unversionedFilesPaths - val treeModel = ChangesViewUtil.createTreeModel( - project, - grouping, + val ignoredFiles = if (ChangesViewSettings.getInstance(project).showIgnored) changeListManager.ignoredFilePaths else emptyList() + return CommitChangesViewWithToolbarPanel.ModelProvider.ModelData( changeLists, unversionedFiles, - ChangesViewSettings.getInstance(project).showIgnored + ignoredFiles, ) { commitWorkflowHandler?.isActive == true } - return ExtendedTreeModel(changeLists, unversionedFiles, treeModel) } override fun synchronizeInclusion(changeLists: List, unversionedFiles: List) {