diff --git a/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/ChangeListWorker.java b/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/ChangeListWorker.java index c87579a17ccc..d75f29339eae 100644 --- a/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/ChangeListWorker.java +++ b/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/ChangeListWorker.java @@ -15,6 +15,7 @@ */ package com.intellij.openapi.vcs.changes; +import com.intellij.openapi.application.ReadAction; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.project.Project; import com.intellij.openapi.util.Comparing; @@ -25,11 +26,13 @@ import com.intellij.openapi.util.io.FileUtil; import com.intellij.openapi.util.text.StringUtil; import com.intellij.openapi.vcs.*; import com.intellij.openapi.vcs.changes.ui.PlusMinusModify; +import com.intellij.openapi.vcs.history.VcsRevisionNumber; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.util.IncorrectOperationException; import com.intellij.util.ThreeState; import com.intellij.util.containers.ContainerUtil; import com.intellij.util.containers.MultiMap; +import com.intellij.util.containers.OpenTHashSet; import com.intellij.vcsUtil.VcsUtil; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -213,7 +216,7 @@ public class ChangeListWorker implements ChangeListsWriteOperations { myMap.put(name, newList); if (inUpdate) { // scope is not important: nothing had been added jet, nothing to move to "old state" members - newList.startProcessingChanges(myProject, null); // this is executed only when use through GATE + startProcessingChanges(newList, null); // this is executed only when use through GATE } return newList.copy(); } @@ -234,7 +237,7 @@ public class ChangeListWorker implements ChangeListsWriteOperations { LOG.debug("[addChangeToCorrespondingList] for change " + path + " type: " + change.getType() + " have before revision: " + (change.getBeforeRevision() != null)); assert myDefault != null; for (LocalChangeListImpl list : myMap.values()) { - if (list.hadChangeBeforeUpdate(change)) { + if (list.getChangesBeforeUpdate().contains(change)) { LOG.debug("[addChangeToCorrespondingList] matched: " + list.getName()); list.addChange(change); myIdx.changeAdded(change, vcsKey); @@ -330,7 +333,7 @@ public class ChangeListWorker implements ChangeListsWriteOperations { public void notifyStartProcessingChanges(final VcsModifiableDirtyScope scope) { final Collection oldChanges = new ArrayList<>(); for (LocalChangeListImpl list : myMap.values()) { - final Collection affectedChanges = list.startProcessingChanges(myProject, scope); + final Collection affectedChanges = startProcessingChanges(list, scope); if (!affectedChanges.isEmpty()) { oldChanges.addAll(affectedChanges); } @@ -363,7 +366,7 @@ public class ChangeListWorker implements ChangeListsWriteOperations { final List removed = new ArrayList<>(); final List added = new ArrayList<>(); - if (list.doneProcessingChanges(removed, added)) { + if (doneProcessingChanges(list, removed, added)) { changedLists.add(list); } if (!removed.isEmpty()) { @@ -392,6 +395,85 @@ public class ChangeListWorker implements ChangeListsWriteOperations { myListsToDisappear.clear(); } + private Collection startProcessingChanges(@NotNull LocalChangeListImpl list, @Nullable final VcsDirtyScope scope) { + OpenTHashSet changesBeforeUpdate = new OpenTHashSet<>(list.getChanges()); + list.setChangesBeforeUpdate(changesBeforeUpdate); + + final Collection result = new ArrayList<>(); + for (Change oldBoy : changesBeforeUpdate) { + final ContentRevision before = oldBoy.getBeforeRevision(); + final ContentRevision after = oldBoy.getAfterRevision(); + if (scope == null || before != null && scope.belongsTo(before.getFile()) || after != null && scope.belongsTo(after.getFile()) + || isIgnoredChange(oldBoy, myProject)) { + result.add(oldBoy); + list.removeChange(oldBoy); + } + } + return result; + } + + private static boolean isIgnoredChange(@NotNull Change change, @NotNull Project project) { + boolean beforeRevIgnored = change.getBeforeRevision() == null || isIgnoredRevision(change.getBeforeRevision(), project); + boolean afterRevIgnored = change.getAfterRevision() == null || isIgnoredRevision(change.getAfterRevision(), project); + return beforeRevIgnored && afterRevIgnored; + } + + private static boolean isIgnoredRevision(final @NotNull ContentRevision revision, final @NotNull Project project) { + return ReadAction.compute(() -> { + if (project.isDisposed()) { + return false; + } + VirtualFile vFile = revision.getFile().getVirtualFile(); + return vFile != null && ProjectLevelVcsManager.getInstance(project).isIgnored(vFile); + }); + } + + private boolean doneProcessingChanges(@NotNull LocalChangeListImpl list, List removedChanges, List addedChanges) { + OpenTHashSet changesBeforeUpdate = list.getChangesBeforeUpdate(); + Set changes = list.getChanges(); + boolean changesDetected = (changes.size() != changesBeforeUpdate.size()); + + for (Change newChange : changes) { + Change oldChange = findOldChange(changesBeforeUpdate, newChange); + if (oldChange == null) { + addedChanges.add(newChange); + } + } + changesDetected |= (!addedChanges.isEmpty()); + final List removed = new ArrayList<>(changesBeforeUpdate); + // since there are SAME objects... + removed.removeAll(changes); + removedChanges.addAll(removed); + changesDetected = changesDetected || (!removedChanges.isEmpty()); + + list.setChangesBeforeUpdate(null); + + return changesDetected; + } + + @Nullable + private static Change findOldChange(OpenTHashSet changesBeforeUpdate, Change newChange) { + Change oldChange = changesBeforeUpdate.get(newChange); + if (oldChange != null && sameBeforeRevision(oldChange, newChange) && + newChange.getFileStatus().equals(oldChange.getFileStatus())) { + return oldChange; + } + return null; + } + + private static boolean sameBeforeRevision(final Change change1, final Change change2) { + final ContentRevision b1 = change1.getBeforeRevision(); + final ContentRevision b2 = change2.getBeforeRevision(); + if (b1 != null && b2 != null) { + final VcsRevisionNumber rn1 = b1.getRevisionNumber(); + final VcsRevisionNumber rn2 = b2.getRevisionNumber(); + final boolean isBinary1 = (b1 instanceof BinaryContentRevision); + final boolean isBinary2 = (b2 instanceof BinaryContentRevision); + return rn1 != VcsRevisionNumber.NULL && rn2 != VcsRevisionNumber.NULL && rn1.compareTo(rn2) == 0 && isBinary1 == isBinary2; + } + return b1 == null && b2 == null; + } + @NotNull public List getListsCopy() { final List result = new ArrayList<>(); diff --git a/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/LocalChangeListImpl.java b/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/LocalChangeListImpl.java index 24c6a08cf684..57ba67abf879 100644 --- a/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/LocalChangeListImpl.java +++ b/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/LocalChangeListImpl.java @@ -1,19 +1,18 @@ package com.intellij.openapi.vcs.changes; -import com.intellij.openapi.application.ReadAction; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.project.Project; import com.intellij.openapi.util.registry.Registry; import com.intellij.openapi.util.text.StringUtil; -import com.intellij.openapi.vcs.ProjectLevelVcsManager; -import com.intellij.openapi.vcs.history.VcsRevisionNumber; -import com.intellij.openapi.vfs.VirtualFile; import com.intellij.util.containers.ContainerUtil; import com.intellij.util.containers.OpenTHashSet; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -import java.util.*; +import java.util.Collection; +import java.util.Collections; +import java.util.Set; +import java.util.UUID; /** * @author yole @@ -157,83 +156,12 @@ public class LocalChangeListImpl extends LocalChangeList { return null; } - Collection startProcessingChanges(final Project project, @Nullable final VcsDirtyScope scope) { - final Collection result = new ArrayList<>(); - myChangesBeforeUpdate = new OpenTHashSet<>(myChanges); - for (Change oldBoy : myChangesBeforeUpdate) { - final ContentRevision before = oldBoy.getBeforeRevision(); - final ContentRevision after = oldBoy.getAfterRevision(); - if (scope == null || before != null && scope.belongsTo(before.getFile()) || after != null && scope.belongsTo(after.getFile()) - || isIgnoredChange(oldBoy, project)) { - result.add(oldBoy); - removeChange(oldBoy); - } - } - return result; + void setChangesBeforeUpdate(OpenTHashSet changesBeforeUpdate) { + myChangesBeforeUpdate = changesBeforeUpdate; } - private static boolean isIgnoredChange(@NotNull Change change, @NotNull Project project) { - boolean beforeRevIgnored = change.getBeforeRevision() == null || isIgnoredRevision(change.getBeforeRevision(), project); - boolean afterRevIgnored = change.getAfterRevision() == null || isIgnoredRevision(change.getAfterRevision(), project); - return beforeRevIgnored && afterRevIgnored; - } - - private static boolean isIgnoredRevision(final @NotNull ContentRevision revision, final @NotNull Project project) { - return ReadAction.compute(() -> { - if (project.isDisposed()) { - return false; - } - VirtualFile vFile = revision.getFile().getVirtualFile(); - return vFile != null && ProjectLevelVcsManager.getInstance(project).isIgnored(vFile); - }); - } - - boolean hadChangeBeforeUpdate(@NotNull Change change) { - return myChangesBeforeUpdate.contains(change); - } - - boolean doneProcessingChanges(final List removedChanges, final List addedChanges) { - boolean changesDetected = (myChanges.size() != myChangesBeforeUpdate.size()); - - for (Change newChange : myChanges) { - Change oldChange = findOldChange(newChange); - if (oldChange == null) { - addedChanges.add(newChange); - } - } - changesDetected |= (!addedChanges.isEmpty()); - final List removed = new ArrayList<>(myChangesBeforeUpdate); - // since there are SAME objects... - removed.removeAll(myChanges); - removedChanges.addAll(removed); - changesDetected = changesDetected || (!removedChanges.isEmpty()); - - myChangesBeforeUpdate = null; - - return changesDetected; - } - - @Nullable - private Change findOldChange(final Change newChange) { - Change oldChange = myChangesBeforeUpdate.get(newChange); - if (oldChange != null && sameBeforeRevision(oldChange, newChange) && - newChange.getFileStatus().equals(oldChange.getFileStatus())) { - return oldChange; - } - return null; - } - - private static boolean sameBeforeRevision(final Change change1, final Change change2) { - final ContentRevision b1 = change1.getBeforeRevision(); - final ContentRevision b2 = change2.getBeforeRevision(); - if (b1 != null && b2 != null) { - final VcsRevisionNumber rn1 = b1.getRevisionNumber(); - final VcsRevisionNumber rn2 = b2.getRevisionNumber(); - final boolean isBinary1 = (b1 instanceof BinaryContentRevision); - final boolean isBinary2 = (b2 instanceof BinaryContentRevision); - return rn1 != VcsRevisionNumber.NULL && rn2 != VcsRevisionNumber.NULL && rn1.compareTo(rn2) == 0 && isBinary1 == isBinary2; - } - return b1 == null && b2 == null; + OpenTHashSet getChangesBeforeUpdate() { + return myChangesBeforeUpdate; } public boolean equals(final Object o) {