vcs: Refactor "MultipleLocalChangeListsBrowser" - provide custom "InclusionModel" instead of custom "ChangesTree"

GitOrigin-RevId: 9f367ca795be0759f7f0108b984f569e892bd8e1
This commit is contained in:
Konstantin Kolosovsky
2019-07-02 06:52:16 +03:00
committed by intellij-monorepo-bot
parent 8bce6cb5fe
commit 27548eefc9
5 changed files with 101 additions and 166 deletions
@@ -497,10 +497,8 @@ public abstract class ChangesTree extends Tree implements DataProvider {
myTreeInclusionListener = runnable;
}
protected void notifyInclusionListener() {
if (myTreeInclusionListener != null) {
myTreeInclusionListener.run();
}
private void notifyInclusionListener() {
if (myTreeInclusionListener != null) myTreeInclusionListener.run();
}
public void setIncludedChanges(@NotNull Collection<?> changes) {
@@ -533,8 +531,8 @@ public abstract class ChangesTree extends Tree implements DataProvider {
protected void toggleChanges(@NotNull Collection<?> changes) {
boolean hasExcluded = false;
for (Object value : changes) {
if (!isIncluded(value)) {
for (Object item : changes) {
if (getInclusionModel().getInclusionState(item) != State.SELECTED) {
hasExcluded = true;
break;
}
@@ -695,16 +693,22 @@ public abstract class ChangesTree extends Tree implements DataProvider {
}
}
protected State getNodeStatus(@NotNull ChangesBrowserNode<?> node) {
@NotNull
private State getNodeStatus(@NotNull ChangesBrowserNode<?> node) {
boolean hasIncluded = false;
boolean hasExcluded = false;
for (Object change : getUserObjectsUnder(node)) {
if (isIncluded(change)) {
for (Object item : getUserObjectsUnder(node)) {
State state = getInclusionModel().getInclusionState(item);
if (state == State.SELECTED) {
hasIncluded = true;
}
else if (state == State.NOT_SELECTED) {
hasExcluded = true;
}
else {
hasIncluded = true;
hasExcluded = true;
}
}
@@ -24,10 +24,7 @@ import com.intellij.openapi.vcs.changes.*;
import com.intellij.openapi.vcs.changes.actions.RollbackDialogAction;
import com.intellij.openapi.vcs.changes.actions.diff.UnversionedDiffRequestProducer;
import com.intellij.openapi.vcs.changes.actions.diff.lst.LocalChangeListDiffTool;
import com.intellij.openapi.vcs.ex.ExclusionState;
import com.intellij.openapi.vcs.ex.PartialLocalLineStatusTracker;
import com.intellij.openapi.vcs.impl.LineStatusTrackerManager;
import com.intellij.openapi.vcs.impl.PartialChangesUtil;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.ui.CollectionComboBoxModel;
import com.intellij.ui.ColoredListCellRenderer;
@@ -38,6 +35,7 @@ import com.intellij.util.ui.ThreeStateCheckBox.State;
import com.intellij.util.ui.update.MergingUpdateQueue;
import com.intellij.util.ui.update.Update;
import com.intellij.vcs.commit.PartialCommitChangeNodeDecorator;
import com.intellij.vcs.commit.PartialCommitInclusionModel;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@@ -46,9 +44,10 @@ import javax.swing.tree.DefaultTreeModel;
import java.awt.*;
import java.awt.event.ItemEvent;
import java.awt.event.ItemListener;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.*;
import java.util.stream.Stream;
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;
@@ -65,12 +64,12 @@ class MultipleLocalChangeListsBrowser extends CommitDialogChangesBrowser impleme
@NotNull private final ChangeListChooser myChangeListChooser;
@NotNull private final DeleteProvider myDeleteProvider = new VirtualFileDeleteProvider();
@NotNull private final PartialCommitInclusionModel myInclusionModel;
@NotNull private LocalChangeList myChangeList;
private final List<Change> myChanges = new ArrayList<>();
private final List<VirtualFile> myUnversioned = new ArrayList<>();
private boolean myHasHiddenUnversioned;
@NotNull private LocalChangeList myChangeList;
@Nullable private Runnable mySelectedListChangeListener;
private final RollbackDialogAction myRollbackDialogAction;
@@ -96,6 +95,11 @@ class MultipleLocalChangeListsBrowser extends CommitDialogChangesBrowser impleme
}
}
myInclusionModel = new PartialCommitInclusionModel(myProject, myChangeList);
Disposer.register(this, myInclusionModel);
getViewer().setInclusionModel(myInclusionModel);
Disposer.register(myInclusionModel, () -> getViewer().setInclusionModel(null));
ChangeListManager.getInstance(myProject).addChangeListListener(new MyChangeListListener(), this);
init();
@@ -103,13 +107,6 @@ class MultipleLocalChangeListsBrowser extends CommitDialogChangesBrowser impleme
updateSelectedChangeList(myChangeList);
}
@NotNull
@Override
protected ChangesBrowserTreeList createTreeList(@NotNull Project project, boolean showCheckboxes, boolean highlightProblems) {
String changelistId = ChangeListManager.getInstance(project).getDefaultChangeList().getId();
return new MyChangesBrowserTreeList(project, showCheckboxes, highlightProblems, changelistId, this);
}
@Nullable
@Override
protected JComponent createHeaderPanel() {
@@ -228,7 +225,7 @@ class MultipleLocalChangeListsBrowser extends CommitDialogChangesBrowser impleme
updateDisplayedChanges();
if (isListChanged && mySelectedListChangeListener != null) mySelectedListChangeListener.run();
((MyChangesBrowserTreeList)myViewer).setChangelistId(list.getId());
myInclusionModel.setChangeList(myChangeList);
}
@Override
@@ -450,7 +447,7 @@ class MultipleLocalChangeListsBrowser extends CommitDialogChangesBrowser impleme
public State isSelected(AnActionEvent e) {
Object object = getUserObject(e);
if (object == null) return State.NOT_SELECTED;
return ((MyChangesBrowserTreeList)myViewer).getUserObjectState(object);
return myInclusionModel.getInclusionState(object);
}
@Override
@@ -486,118 +483,4 @@ class MultipleLocalChangeListsBrowser extends CommitDialogChangesBrowser impleme
});
}
}
private class MyChangesBrowserTreeList extends ChangesBrowserTreeList {
private final MyStateHolder myStateHolder;
MyChangesBrowserTreeList(@NotNull Project project, boolean showCheckboxes, boolean highlightProblems,
@NotNull String changelistId, @NotNull Disposable disposable) {
super(MultipleLocalChangeListsBrowser.this, project, showCheckboxes, highlightProblems);
myStateHolder = new MyStateHolder(project, changelistId);
Disposer.register(disposable, myStateHolder);
}
@NotNull
private State getUserObjectState(@NotNull Object change) {
ExclusionState exclusionState = myStateHolder.getExclusionState(change);
return PartialChangesUtil.convertExclusionState(exclusionState);
}
@NotNull
@Override
protected State getNodeStatus(@NotNull ChangesBrowserNode<?> node) {
boolean hasIncluded = false;
boolean hasExcluded = false;
for (Object change : VcsTreeModelData.children(node).userObjects()) {
ExclusionState exclusionState = myStateHolder.getExclusionState(change);
if (exclusionState == ExclusionState.ALL_INCLUDED) {
hasIncluded = true;
}
else if (exclusionState == ExclusionState.ALL_EXCLUDED) {
hasExcluded = true;
}
else {
hasIncluded = true;
hasExcluded = true;
}
}
if (hasIncluded && hasExcluded) return State.DONT_CARE;
if (hasIncluded) return State.SELECTED;
return State.NOT_SELECTED;
}
@Override
public boolean isIncluded(@NotNull Object change) {
return myStateHolder.isIncluded(change);
}
@NotNull
@Override
public Set<Object> getIncludedSet() {
return myStateHolder.getIncludedSet();
}
@Override
public void setIncludedChanges(@NotNull Collection<?> changes) {
myStateHolder.setIncludedElements(changes);
}
@Override
public void includeChanges(@NotNull Collection<?> changes) {
myStateHolder.includeElements(changes);
}
@Override
public void excludeChanges(@NotNull Collection<?> changes) {
myStateHolder.excludeElements(changes);
}
@Override
protected void toggleChanges(@NotNull Collection<?> changes) {
myStateHolder.toggleElements(changes);
}
public void setChangelistId(@NotNull String changelistId) {
myStateHolder.setChangelistId(changelistId);
}
private class MyStateHolder extends PartiallyExcludedFilesStateHolder<Object> {
MyStateHolder(@NotNull Project project, @NotNull String changelistId) {
super(project, changelistId);
}
@NotNull
@Override
protected Stream<Change> getTrackableElementsStream() {
return VcsTreeModelData.all(MyChangesBrowserTreeList.this).userObjectsStream(Change.class);
}
@Nullable
@Override
protected Object findElementFor(@NotNull PartialLocalLineStatusTracker tracker) {
return getTrackableElementsStream().filter(change -> tracker.getVirtualFile().equals(PartialChangesUtil.getVirtualFile(change))).findFirst().orElse(null);
}
@Nullable
@Override
protected PartialLocalLineStatusTracker findTrackerFor(@NotNull Object element) {
if (element instanceof Change) {
return PartialChangesUtil.getPartialTracker(myProject, (Change)element);
}
return null;
}
@Override
public void updateExclusionStates() {
super.updateExclusionStates();
MyChangesBrowserTreeList.this.notifyInclusionListener();
MyChangesBrowserTreeList.this.repaint();
}
}
}
}
@@ -1,4 +1,4 @@
// Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
// Copyright 2000-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
package com.intellij.openapi.vcs.changes.ui;
import com.intellij.openapi.Disposable;
@@ -170,12 +170,6 @@ public abstract class PartiallyExcludedFilesStateHolder<T> implements Disposable
}
}
public boolean isIncluded(@NotNull T element) {
ExclusionState trackerState = getExclusionState(element);
return trackerState != ExclusionState.ALL_EXCLUDED;
}
@NotNull
public Set<T> getIncludedSet() {
HashSet<T> set = new HashSet<>(myIncludedElements);
@@ -234,22 +228,4 @@ public abstract class PartiallyExcludedFilesStateHolder<T> implements Disposable
updateExclusionStates();
}
public void toggleElements(@NotNull Collection<? extends T> elements) {
boolean hasExcluded = false;
for (T element : elements) {
ExclusionState exclusionState = getExclusionState(element);
if (exclusionState != ExclusionState.ALL_INCLUDED) {
hasExcluded = true;
break;
}
}
if (hasExcluded) {
includeElements(elements);
}
else {
excludeElements(elements);
}
}
}
@@ -0,0 +1,67 @@
// Copyright 2000-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
package com.intellij.vcs.commit
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.LocalChangeList
import com.intellij.openapi.vcs.changes.ui.BaseInclusionModel
import com.intellij.openapi.vcs.changes.ui.PartiallyExcludedFilesStateHolder
import com.intellij.openapi.vcs.ex.PartialLocalLineStatusTracker
import com.intellij.openapi.vcs.impl.PartialChangesUtil
import com.intellij.openapi.vcs.impl.PartialChangesUtil.convertExclusionState
import com.intellij.openapi.vcs.impl.PartialChangesUtil.getPartialTracker
import com.intellij.util.ui.ThreeStateCheckBox
import java.util.stream.Stream
class PartialCommitInclusionModel(
private val project: Project,
changeList: LocalChangeList
) : BaseInclusionModel(), Disposable {
var changeList: LocalChangeList = changeList
set(value) {
field = value
stateHolder.setChangelistId(value.id)
}
private val stateHolder = StateHolder()
init {
Disposer.register(this, stateHolder)
}
override fun getInclusion(): Set<Any> = stateHolder.includedSet
override fun getInclusionState(item: Any): ThreeStateCheckBox.State = convertExclusionState(stateHolder.getExclusionState(item))
override fun isInclusionEmpty(): Boolean = getInclusion().isEmpty()
override fun addInclusion(items: Collection<Any>) = stateHolder.includeElements(items)
override fun removeInclusion(items: Collection<Any>) = stateHolder.excludeElements(items)
override fun setInclusion(items: Collection<Any>) = stateHolder.setIncludedElements(items)
override fun retainInclusion(items: Collection<Any>) {
val toRemove = getInclusion() - items
if (toRemove.isNotEmpty()) removeInclusion(toRemove)
}
override fun clearInclusion() {
if (getInclusion().isNotEmpty()) setInclusion(emptySet())
}
override fun dispose() = Unit
private inner class StateHolder : PartiallyExcludedFilesStateHolder<Any>(project, changeList.id) {
override fun getTrackableElementsStream(): Stream<out Any> = changeList.changes.stream()
override fun findElementFor(tracker: PartialLocalLineStatusTracker): Any? =
changeList.changes.find { tracker.virtualFile == PartialChangesUtil.getVirtualFile(it) }
override fun findTrackerFor(element: Any): PartialLocalLineStatusTracker? =
(element as? Change)?.let { getPartialTracker(project, it) }
override fun updateExclusionStates() {
super.updateExclusionStates()
fireInclusionChanged()
}
}
}
@@ -1,4 +1,4 @@
// Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
// Copyright 2000-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
package com.intellij.openapi.vcs
import com.intellij.openapi.util.Disposer
@@ -36,6 +36,11 @@ abstract class BasePartiallyExcludedChangesTest : BaseLineStatusTrackerManagerTe
return PartialChangesUtil.getPartialTracker(getProject(), file)
}
fun toggleElements(elements: Collection<FilePath>) {
val hasExcluded = elements.any { getExclusionState(it) != ExclusionState.ALL_INCLUDED }
if (hasExcluded) includeElements(elements) else excludeElements(elements)
}
fun waitExclusionStateUpdate() {
myUpdateQueue.flush()
}