mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
vcs: Allow excluding changed blocks from non-modal commit (IDEA-215860)
GitOrigin-RevId: 7a12b6dbe3823693cc14092c3dedc23ca716a5f3
This commit is contained in:
committed by
intellij-monorepo-bot
parent
3fdee6712b
commit
66db99aecd
+3
-2
@@ -51,6 +51,7 @@ import java.util.Optional;
|
||||
|
||||
import static com.intellij.openapi.util.text.StringUtil.shortenTextWithEllipsis;
|
||||
import static com.intellij.openapi.vcs.changes.ui.ChangesListView.UNVERSIONED_FILES_DATA_KEY;
|
||||
import static com.intellij.util.containers.ContainerUtil.immutableSingletonList;
|
||||
import static com.intellij.util.ui.update.MergingUpdateQueue.ANY_COMPONENT;
|
||||
|
||||
class MultipleLocalChangeListsBrowser extends CommitDialogChangesBrowser implements Disposable {
|
||||
@@ -95,7 +96,7 @@ class MultipleLocalChangeListsBrowser extends CommitDialogChangesBrowser impleme
|
||||
}
|
||||
}
|
||||
|
||||
myInclusionModel = new PartialCommitInclusionModel(myProject, myChangeList);
|
||||
myInclusionModel = new PartialCommitInclusionModel(myProject);
|
||||
Disposer.register(this, myInclusionModel);
|
||||
getViewer().setInclusionModel(myInclusionModel);
|
||||
Disposer.register(myInclusionModel, () -> getViewer().setInclusionModel(null));
|
||||
@@ -225,7 +226,7 @@ class MultipleLocalChangeListsBrowser extends CommitDialogChangesBrowser impleme
|
||||
updateDisplayedChanges();
|
||||
if (isListChanged && mySelectedListChangeListener != null) mySelectedListChangeListener.run();
|
||||
|
||||
myInclusionModel.setChangeList(myChangeList);
|
||||
myInclusionModel.setChangeLists(immutableSingletonList(myChangeList));
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
+31
-20
@@ -7,18 +7,30 @@ import com.intellij.openapi.vcs.ex.ExclusionState
|
||||
import com.intellij.openapi.vcs.ex.LineStatusTracker
|
||||
import com.intellij.openapi.vcs.ex.PartialLocalLineStatusTracker
|
||||
import com.intellij.openapi.vcs.impl.LineStatusTrackerManager
|
||||
import com.intellij.util.containers.ContainerUtil.canonicalStrategy
|
||||
import com.intellij.util.ui.update.MergingUpdateQueue
|
||||
import com.intellij.util.ui.update.Update
|
||||
import gnu.trove.THashMap
|
||||
import gnu.trove.THashSet
|
||||
import gnu.trove.TObjectHashingStrategy
|
||||
import org.jetbrains.annotations.CalledInAwt
|
||||
import java.util.*
|
||||
|
||||
abstract class PartiallyExcludedFilesStateHolder<T>(project: Project, private var myChangelistId: String) : Disposable {
|
||||
abstract class PartiallyExcludedFilesStateHolder<T>(
|
||||
project: Project,
|
||||
private val hashingStrategy: TObjectHashingStrategy<T> = canonicalStrategy()
|
||||
) : Disposable {
|
||||
|
||||
private fun PartialLocalLineStatusTracker.setExcludedFromCommit(element: T, isExcluded: Boolean) =
|
||||
getChangeListId(element)?.let { setExcludedFromCommit(it, isExcluded) }
|
||||
|
||||
private fun PartialLocalLineStatusTracker.getExcludedFromCommitState(element: T): ExclusionState =
|
||||
getChangeListId(element)?.let { getExcludedFromCommitState(it) } ?: ExclusionState.NO_CHANGES
|
||||
|
||||
protected val myUpdateQueue =
|
||||
MergingUpdateQueue(PartiallyExcludedFilesStateHolder::class.java.name, 300, true, MergingUpdateQueue.ANY_COMPONENT, this)
|
||||
|
||||
private val myIncludedElements = THashSet<T>()
|
||||
private val myTrackerExclusionStates = HashMap<T, ExclusionState>()
|
||||
private val myIncludedElements = THashSet<T>(hashingStrategy)
|
||||
private val myTrackerExclusionStates = THashMap<T, ExclusionState>(hashingStrategy)
|
||||
|
||||
init {
|
||||
MyTrackerManagerListener().install(project)
|
||||
@@ -27,23 +39,19 @@ abstract class PartiallyExcludedFilesStateHolder<T>(project: Project, private va
|
||||
override fun dispose() = Unit
|
||||
|
||||
protected abstract val trackableElements: Sequence<T>
|
||||
protected abstract fun findElementFor(tracker: PartialLocalLineStatusTracker): T?
|
||||
protected abstract fun getChangeListId(element: T): String?
|
||||
protected abstract fun findElementFor(tracker: PartialLocalLineStatusTracker, changeListId: String): T?
|
||||
protected abstract fun findTrackerFor(element: T): PartialLocalLineStatusTracker?
|
||||
|
||||
private val trackers
|
||||
get() = trackableElements.mapNotNull { element -> findTrackerFor(element)?.let { tracker -> element to tracker } }
|
||||
|
||||
fun setChangelistId(changelistId: String) {
|
||||
myChangelistId = changelistId
|
||||
updateExclusionStates()
|
||||
}
|
||||
|
||||
@CalledInAwt
|
||||
open fun updateExclusionStates() {
|
||||
myTrackerExclusionStates.clear()
|
||||
|
||||
trackers.forEach { (element, tracker) ->
|
||||
val state = tracker.getExcludedFromCommitState(myChangelistId)
|
||||
val state = tracker.getExcludedFromCommitState(element)
|
||||
if (state != ExclusionState.NO_CHANGES) myTrackerExclusionStates[element] = state
|
||||
}
|
||||
}
|
||||
@@ -75,17 +83,20 @@ abstract class PartiallyExcludedFilesStateHolder<T>(project: Project, private va
|
||||
override fun onTrackerAdded(tracker: LineStatusTracker<*>) {
|
||||
if (tracker !is PartialLocalLineStatusTracker) return
|
||||
|
||||
findElementFor(tracker)?.let { element -> tracker.setExcludedFromCommit(element !in myIncludedElements) }
|
||||
tracker.getAffectedChangeListsIds().forEach { changeListId ->
|
||||
findElementFor(tracker, changeListId)?.let { element -> tracker.setExcludedFromCommit(element, element !in myIncludedElements) }
|
||||
}
|
||||
tracker.addListener(trackerListener, disposable)
|
||||
}
|
||||
|
||||
override fun onTrackerRemoved(tracker: LineStatusTracker<*>) {
|
||||
if (tracker !is PartialLocalLineStatusTracker) return
|
||||
|
||||
findElementFor(tracker)?.let { element ->
|
||||
myTrackerExclusionStates -= element
|
||||
tracker.getAffectedChangeListsIds().forEach { changeListId ->
|
||||
val element = findElementFor(tracker, changeListId) ?: return@forEach
|
||||
|
||||
val exclusionState = tracker.getExcludedFromCommitState(myChangelistId)
|
||||
myTrackerExclusionStates -= element
|
||||
val exclusionState = tracker.getExcludedFromCommitState(element)
|
||||
if (exclusionState != ExclusionState.NO_CHANGES) {
|
||||
if (exclusionState != ExclusionState.ALL_EXCLUDED) myIncludedElements += element else myIncludedElements -= element
|
||||
}
|
||||
@@ -96,7 +107,7 @@ abstract class PartiallyExcludedFilesStateHolder<T>(project: Project, private va
|
||||
}
|
||||
|
||||
fun getIncludedSet(): Set<T> {
|
||||
val set = HashSet(myIncludedElements)
|
||||
val set = THashSet(myIncludedElements, hashingStrategy)
|
||||
myTrackerExclusionStates.forEach { (element, state) ->
|
||||
if (state == ExclusionState.ALL_EXCLUDED) set -= element else set += element
|
||||
}
|
||||
@@ -104,9 +115,9 @@ abstract class PartiallyExcludedFilesStateHolder<T>(project: Project, private va
|
||||
}
|
||||
|
||||
fun setIncludedElements(elements: Collection<T>) {
|
||||
val set = HashSet(elements)
|
||||
val set = THashSet(elements, hashingStrategy)
|
||||
trackers.forEach { (element, tracker) ->
|
||||
tracker.setExcludedFromCommit(element !in set)
|
||||
tracker.setExcludedFromCommit(element, element !in set)
|
||||
}
|
||||
|
||||
myIncludedElements.clear()
|
||||
@@ -116,14 +127,14 @@ abstract class PartiallyExcludedFilesStateHolder<T>(project: Project, private va
|
||||
}
|
||||
|
||||
fun includeElements(elements: Collection<T>) {
|
||||
elements.forEach { findTrackerFor(it)?.setExcludedFromCommit(false) }
|
||||
elements.forEach { findTrackerFor(it)?.setExcludedFromCommit(it, false) }
|
||||
myIncludedElements += elements
|
||||
|
||||
updateExclusionStates()
|
||||
}
|
||||
|
||||
fun excludeElements(elements: Collection<T>) {
|
||||
elements.forEach { findTrackerFor(it)?.setExcludedFromCommit(true) }
|
||||
elements.forEach { findTrackerFor(it)?.setExcludedFromCommit(it, true) }
|
||||
myIncludedElements -= elements
|
||||
|
||||
updateExclusionStates()
|
||||
|
||||
@@ -14,9 +14,9 @@ import com.intellij.openapi.ui.popup.LightweightWindowEvent
|
||||
import com.intellij.openapi.util.Disposer
|
||||
import com.intellij.openapi.vcs.VcsBundle.message
|
||||
import com.intellij.openapi.vcs.changes.Change
|
||||
import com.intellij.openapi.vcs.changes.ChangeListChange
|
||||
import com.intellij.openapi.vcs.changes.ChangesViewManager
|
||||
import com.intellij.openapi.vcs.changes.InclusionListener
|
||||
import com.intellij.openapi.vcs.changes.InclusionModel
|
||||
import com.intellij.openapi.vcs.changes.ui.*
|
||||
import com.intellij.openapi.vcs.changes.ui.ChangesBrowserNode.UNVERSIONED_FILES_TAG
|
||||
import com.intellij.openapi.vcs.changes.ui.VcsTreeModelData.*
|
||||
@@ -112,7 +112,6 @@ class ChangesViewCommitPanel(private val changesView: ChangesListView, private v
|
||||
buildLayout()
|
||||
|
||||
with(changesView) {
|
||||
setInclusionModel(DefaultInclusionModel(ChangeListChange.HASHING_STRATEGY))
|
||||
setInclusionListener { inclusionEventDispatcher.multicaster.inclusionChanged() }
|
||||
isShowCheckboxes = true
|
||||
}
|
||||
@@ -224,6 +223,12 @@ class ChangesViewCommitPanel(private val changesView: ChangesListView, private v
|
||||
override fun getIncludedUnversionedFiles(): List<VirtualFile> =
|
||||
includedUnderTag(changesView, UNVERSIONED_FILES_TAG).userObjects(VirtualFile::class.java)
|
||||
|
||||
override var inclusionModel: InclusionModel?
|
||||
get() = changesView.inclusionModel
|
||||
set(value) {
|
||||
changesView.setInclusionModel(value)
|
||||
}
|
||||
|
||||
override fun isInclusionEmpty(): Boolean = changesView.isInclusionEmpty
|
||||
override fun getInclusion(): Set<Any> = changesView.includedSet
|
||||
override fun clearInclusion() = changesView.clearInclusion()
|
||||
@@ -247,8 +252,6 @@ class ChangesViewCommitPanel(private val changesView: ChangesListView, private v
|
||||
with(changesView) {
|
||||
isShowCheckboxes = false
|
||||
setInclusionListener(null)
|
||||
clearInclusion()
|
||||
setInclusionModel(null)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -31,8 +31,11 @@ class ChangesViewCommitWorkflowHandler(
|
||||
private val changeListManager = ChangeListManager.getInstance(project)
|
||||
private var knownActiveChanges: Collection<Change> = emptyList()
|
||||
|
||||
private val inclusionModel = PartialCommitInclusionModel(project)
|
||||
|
||||
init {
|
||||
Disposer.register(this, Disposable { workflow.disposeCommitOptions() })
|
||||
Disposer.register(this, inclusionModel)
|
||||
Disposer.register(ui, this)
|
||||
|
||||
workflow.addListener(this, this)
|
||||
@@ -40,6 +43,8 @@ class ChangesViewCommitWorkflowHandler(
|
||||
ui.addExecutorListener(this, this)
|
||||
ui.addDataProvider(createDataProvider())
|
||||
ui.addInclusionListener(this, this)
|
||||
ui.inclusionModel = inclusionModel
|
||||
Disposer.register(inclusionModel, Disposable { ui.inclusionModel = null })
|
||||
|
||||
vcsesChanged() // as currently vcses are set before handler subscribes to corresponding event
|
||||
}
|
||||
@@ -89,6 +94,8 @@ class ChangesViewCommitWorkflowHandler(
|
||||
val activeChanges = changeListManager.defaultChangeList.changes
|
||||
knownActiveChanges = knownActiveChanges.intersect(activeChanges)
|
||||
}
|
||||
|
||||
inclusionModel.changeLists = changeLists
|
||||
}
|
||||
|
||||
fun setCommitState(items: Collection<Any>, force: Boolean) {
|
||||
|
||||
@@ -3,11 +3,13 @@ package com.intellij.vcs.commit
|
||||
|
||||
import com.intellij.openapi.actionSystem.AnAction
|
||||
import com.intellij.openapi.actionSystem.DataContext
|
||||
import com.intellij.openapi.vcs.changes.InclusionModel
|
||||
|
||||
interface ChangesViewCommitWorkflowUi : CommitWorkflowUi {
|
||||
var isDefaultCommitActionEnabled: Boolean
|
||||
fun setCustomCommitActions(actions: List<AnAction>)
|
||||
|
||||
var inclusionModel: InclusionModel?
|
||||
// TODO Looks better to create "interface ItemInclusionModel" to which ChangesTree will delegate
|
||||
// And just pass such model to CommitWorkflowUi instead of adding include-related methods to CommitWorkflowUi directly
|
||||
fun isInclusionEmpty(): Boolean
|
||||
|
||||
@@ -5,6 +5,7 @@ import com.intellij.openapi.Disposable
|
||||
import com.intellij.openapi.project.Project
|
||||
import com.intellij.openapi.util.Disposer
|
||||
import com.intellij.openapi.vcs.changes.Change
|
||||
import com.intellij.openapi.vcs.changes.ChangeListChange
|
||||
import com.intellij.openapi.vcs.changes.LocalChangeList
|
||||
import com.intellij.openapi.vcs.changes.ui.BaseInclusionModel
|
||||
import com.intellij.openapi.vcs.changes.ui.PartiallyExcludedFilesStateHolder
|
||||
@@ -14,15 +15,12 @@ import com.intellij.openapi.vcs.impl.PartialChangesUtil.convertExclusionState
|
||||
import com.intellij.openapi.vcs.impl.PartialChangesUtil.getPartialTracker
|
||||
import com.intellij.util.ui.ThreeStateCheckBox
|
||||
|
||||
class PartialCommitInclusionModel(
|
||||
private val project: Project,
|
||||
changeList: LocalChangeList
|
||||
) : BaseInclusionModel(), Disposable {
|
||||
class PartialCommitInclusionModel(private val project: Project) : BaseInclusionModel(), Disposable {
|
||||
|
||||
var changeList: LocalChangeList = changeList
|
||||
var changeLists: Collection<LocalChangeList> = emptyList()
|
||||
set(value) {
|
||||
field = value
|
||||
stateHolder.setChangelistId(value.id)
|
||||
stateHolder.updateExclusionStates()
|
||||
}
|
||||
|
||||
private val stateHolder = StateHolder()
|
||||
@@ -49,11 +47,13 @@ class PartialCommitInclusionModel(
|
||||
|
||||
override fun dispose() = Unit
|
||||
|
||||
private inner class StateHolder : PartiallyExcludedFilesStateHolder<Any>(project, changeList.id) {
|
||||
override val trackableElements: Sequence<Any> get() = changeList.changes.asSequence()
|
||||
private inner class StateHolder : PartiallyExcludedFilesStateHolder<Any>(project, ChangeListChange.HASHING_STRATEGY) {
|
||||
override val trackableElements: Sequence<Any> get() = changeLists.asSequence().flatMap { it.changes.asSequence() }
|
||||
|
||||
override fun findElementFor(tracker: PartialLocalLineStatusTracker): Any? =
|
||||
changeList.changes.find { tracker.virtualFile == PartialChangesUtil.getVirtualFile(it) }
|
||||
override fun getChangeListId(element: Any) = (element as? ChangeListChange)?.changeListId
|
||||
|
||||
override fun findElementFor(tracker: PartialLocalLineStatusTracker, changeListId: String): Any? =
|
||||
changeLists.find { it.id == changeListId }?.changes?.find { tracker.virtualFile == PartialChangesUtil.getVirtualFile(it) }
|
||||
|
||||
override fun findTrackerFor(element: Any): PartialLocalLineStatusTracker? =
|
||||
(element as? Change)?.let { getPartialTracker(project, it) }
|
||||
|
||||
+4
-2
@@ -16,7 +16,7 @@ abstract class BasePartiallyExcludedChangesTest : BaseLineStatusTrackerManagerTe
|
||||
stateHolder.updateExclusionStates()
|
||||
}
|
||||
|
||||
protected inner class MyStateHolder : PartiallyExcludedFilesStateHolder<FilePath>(getProject(), DEFAULT.asListNameToId()) {
|
||||
protected inner class MyStateHolder : PartiallyExcludedFilesStateHolder<FilePath>(getProject()) {
|
||||
val paths = HashSet<FilePath>()
|
||||
|
||||
init {
|
||||
@@ -26,7 +26,9 @@ abstract class BasePartiallyExcludedChangesTest : BaseLineStatusTrackerManagerTe
|
||||
|
||||
override val trackableElements: Sequence<FilePath> get() = paths.asSequence()
|
||||
|
||||
override fun findElementFor(tracker: PartialLocalLineStatusTracker): FilePath? {
|
||||
override fun getChangeListId(element: FilePath): String = DEFAULT.asListNameToId()
|
||||
|
||||
override fun findElementFor(tracker: PartialLocalLineStatusTracker, changeListId: String): FilePath? {
|
||||
return paths.find { it.virtualFile == tracker.virtualFile }
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user