diff options
Diffstat (limited to 'platform/vcs-api/vcs-api-core/src/com/intellij/openapi/vcs/changes/Change.java')
-rw-r--r-- | platform/vcs-api/vcs-api-core/src/com/intellij/openapi/vcs/changes/Change.java | 282 |
1 files changed, 282 insertions, 0 deletions
diff --git a/platform/vcs-api/vcs-api-core/src/com/intellij/openapi/vcs/changes/Change.java b/platform/vcs-api/vcs-api-core/src/com/intellij/openapi/vcs/changes/Change.java new file mode 100644 index 000000000000..b1d8978eea68 --- /dev/null +++ b/platform/vcs-api/vcs-api-core/src/com/intellij/openapi/vcs/changes/Change.java @@ -0,0 +1,282 @@ +/* + * Copyright 2000-2014 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.intellij.openapi.vcs.changes; + +import com.intellij.openapi.project.Project; +import com.intellij.openapi.util.Comparing; +import com.intellij.openapi.util.Getter; +import com.intellij.openapi.util.SystemInfo; +import com.intellij.openapi.vcs.FilePath; +import com.intellij.openapi.vcs.FileStatus; +import com.intellij.openapi.vcs.VcsBundle; +import com.intellij.openapi.vcs.impl.VcsPathPresenter; +import com.intellij.openapi.vfs.VirtualFile; +import com.intellij.vcsUtil.VcsFilePathUtil; +import org.jetbrains.annotations.NonNls; +import org.jetbrains.annotations.Nullable; + +import javax.swing.*; +import java.io.File; +import java.util.HashMap; +import java.util.Map; + +/** + * @author max + */ +public class Change { + private int myHash; + + public enum Type { + MODIFICATION, + NEW, + DELETED, + MOVED + } + + private final ContentRevision myBeforeRevision; + private final ContentRevision myAfterRevision; + private final FileStatus myFileStatus; + protected String myMoveRelativePath; + protected boolean myRenamed; + protected boolean myMoved; + protected boolean myRenameOrMoveCached = false; + private boolean myIsReplaced; + private Type myType; + private final Map<String, Change> myOtherLayers; + // if null, vcs's is used. intended: for property conflict case + private Getter<MergeTexts> myMergeProvider; + + public Change(@Nullable final ContentRevision beforeRevision, @Nullable final ContentRevision afterRevision) { + this(beforeRevision, afterRevision, convertStatus(beforeRevision, afterRevision)); + } + + public Change(@Nullable final ContentRevision beforeRevision, @Nullable final ContentRevision afterRevision, @Nullable FileStatus fileStatus) { + assert beforeRevision != null || afterRevision != null; + myBeforeRevision = beforeRevision; + myAfterRevision = afterRevision; + myFileStatus = fileStatus == null ? convertStatus(beforeRevision, afterRevision) : fileStatus; + myHash = -1; + myOtherLayers = new HashMap<String, Change>(0); + } + + private static FileStatus convertStatus(@Nullable ContentRevision beforeRevision, @Nullable ContentRevision afterRevision) { + if (beforeRevision == null) return FileStatus.ADDED; + if (afterRevision == null) return FileStatus.DELETED; + return FileStatus.MODIFIED; + } + + public Getter<MergeTexts> getMergeProvider() { + return myMergeProvider; + } + + public void setMergeProvider(Getter<MergeTexts> mergeProvider) { + myMergeProvider = mergeProvider; + } + + public void addAdditionalLayerElement(final String name, final Change change) { + myOtherLayers.put(name, change); + } + + public Map<String, Change> getOtherLayers() { + return myOtherLayers; + } + + public boolean isTreeConflict() { + return false; + } + + public boolean isPhantom() { + return false; + } + + public boolean hasOtherLayers() { + return ! myOtherLayers.isEmpty(); + } + + public Type getType() { + if (myType == null) { + if (myBeforeRevision == null) { + myType = Type.NEW; + return myType; + } + + if (myAfterRevision == null) { + myType = Type.DELETED; + return myType; + } + + if ((! Comparing.equal(myBeforeRevision.getFile(), myAfterRevision.getFile())) || + ((! SystemInfo.isFileSystemCaseSensitive) && VcsFilePathUtil + .caseDiffers(myBeforeRevision.getFile().getPath(), myAfterRevision.getFile().getPath()))) { + myType = Type.MOVED; + return myType; + } + + myType = Type.MODIFICATION; + } + return myType; + } + + @Nullable + public ContentRevision getBeforeRevision() { + return myBeforeRevision; + } + + @Nullable + public ContentRevision getAfterRevision() { + return myAfterRevision; + } + + public FileStatus getFileStatus() { + return myFileStatus; + } + + @Nullable + public VirtualFile getVirtualFile() { + return myAfterRevision == null ? null : myAfterRevision.getFile().getVirtualFile(); + } + + public boolean equals(final Object o) { + if (this == o) return true; + if (o == null || (! (o instanceof Change))) return false; + final Change otherChange = ((Change)o); + + final ContentRevision br1 = getBeforeRevision(); + final ContentRevision br2 = otherChange.getBeforeRevision(); + final ContentRevision ar1 = getAfterRevision(); + final ContentRevision ar2 = otherChange.getAfterRevision(); + + FilePath fbr1 = br1 != null ? br1.getFile() : null; + FilePath fbr2 = br2 != null ? br2.getFile() : null; + + FilePath far1 = ar1 != null ? ar1.getFile() : null; + FilePath far2 = ar2 != null ? ar2.getFile() : null; + + return Comparing.equal(fbr1, fbr2) && Comparing.equal(far1, far2); + } + + public int hashCode() { + if (myHash == -1) { + myHash = calculateHash(); + } + return myHash; + } + + private int calculateHash() { + return revisionHashCode(getBeforeRevision()) * 27 + revisionHashCode(getAfterRevision()); + } + + private static int revisionHashCode(ContentRevision rev) { + if (rev == null) return 0; + return rev.getFile().getIOFile().getPath().hashCode(); + } + + public boolean affectsFile(File ioFile) { + if (myBeforeRevision != null && myBeforeRevision.getFile().getIOFile().equals(ioFile)) return true; + if (myAfterRevision != null && myAfterRevision.getFile().getIOFile().equals(ioFile)) return true; + return false; + } + + public boolean isRenamed() { + cacheRenameOrMove(null); + return myRenamed; + } + + public boolean isMoved() { + cacheRenameOrMove(null); + return myMoved; + } + + public String getMoveRelativePath(Project project) { + cacheRenameOrMove(project); + return myMoveRelativePath; + } + + private void cacheRenameOrMove(final Project project) { + if (myBeforeRevision != null && myAfterRevision != null && (! revisionPathsSame())) { + if (!myRenameOrMoveCached) { + myRenameOrMoveCached = true; + if (Comparing.equal(myBeforeRevision.getFile().getParentPath(), myAfterRevision.getFile().getParentPath())) { + myRenamed = true; + } + else { + myMoved = true; + } + } + if (myMoved && myMoveRelativePath == null && project != null) { + myMoveRelativePath = VcsPathPresenter.getInstance(project).getPresentableRelativePath(myBeforeRevision, myAfterRevision); + } + } + } + + private boolean revisionPathsSame() { + final String path1 = myBeforeRevision.getFile().getIOFile().getAbsolutePath(); + final String path2 = myAfterRevision.getFile().getIOFile().getAbsolutePath(); + return path1.equals(path2); + } + + @NonNls + public String toString() { + final Type type = getType(); + //noinspection EnumSwitchStatementWhichMissesCases + switch (type) { + case NEW: return "A: " + myAfterRevision; + case DELETED: return "D: " + myBeforeRevision; + case MOVED: return "M: " + myBeforeRevision + " -> " + myAfterRevision; + default: return "M: " + myAfterRevision; + } + } + + @Nullable + public String getOriginText(final Project project) { + cacheRenameOrMove(project); + if (isMoved()) { + return getMovedText(project); + } else if (isRenamed()) { + return getRenamedText(); + } + return myIsReplaced ? VcsBundle.message("change.file.replaced.text") : null; + } + + @Nullable + protected String getRenamedText() { + return VcsBundle.message("change.file.renamed.from.text", myBeforeRevision.getFile().getName()); + } + + @Nullable + protected String getMovedText(final Project project) { + return VcsBundle.message("change.file.moved.from.text", getMoveRelativePath(project)); + } + + public boolean isIsReplaced() { + return myIsReplaced; + } + + public void setIsReplaced(final boolean isReplaced) { + myIsReplaced = isReplaced; + } + + @Nullable + public Icon getAdditionalIcon() { + return null; + } + + @Nullable + public String getDescription() { + return null; + } +} |