blob: 0c1df6a50a5b67e7b61976b0c2c6fb1937e46a76 [file] [log] [blame]
/*
* Copyright 2000-2009 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 git4idea.annotate;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.vcs.VcsException;
import com.intellij.openapi.vcs.VcsKey;
import com.intellij.openapi.vcs.annotate.*;
import com.intellij.openapi.vcs.history.VcsFileRevision;
import com.intellij.openapi.vcs.history.VcsRevisionNumber;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.util.ObjectUtils;
import com.intellij.util.text.DateFormatUtil;
import git4idea.GitRevisionNumber;
import git4idea.GitVcs;
import git4idea.i18n.GitBundle;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.*;
public class GitFileAnnotation extends FileAnnotation {
private final StringBuffer myContentBuffer = new StringBuffer(); // annotated content
private final ArrayList<LineInfo> myLines = new ArrayList<LineInfo>(); // The currently annotated lines
private final Project myProject;
private final VcsRevisionNumber myBaseRevision;
@NotNull private final Map<VcsRevisionNumber, VcsFileRevision> myRevisionMap = new HashMap<VcsRevisionNumber, VcsFileRevision>();
@NotNull private final VirtualFile myFile;
@NotNull private final GitVcs myVcs;
private final LineAnnotationAspect DATE_ASPECT = new GitAnnotationAspect(LineAnnotationAspect.DATE, true) {
@Override
public String doGetValue(LineInfo info) {
final Date date = info.getDate();
return date == null ? "" : DateFormatUtil.formatPrettyDate(date);
}
};
private final LineAnnotationAspect REVISION_ASPECT = new GitAnnotationAspect(LineAnnotationAspect.REVISION, false) {
@Override
protected String doGetValue(LineInfo lineInfo) {
final GitRevisionNumber revision = lineInfo.getRevision();
return revision == null ? "" : String.valueOf(revision.getShortRev());
}
};
private final LineAnnotationAspect AUTHOR_ASPECT = new GitAnnotationAspect(LineAnnotationAspect.AUTHOR, true) {
@Override
protected String doGetValue(LineInfo lineInfo) {
final String author = lineInfo.getAuthor();
return author == null ? "" : author;
}
};
public GitFileAnnotation(@NotNull final Project project,
@NotNull VirtualFile file,
final VcsRevisionNumber revision) {
super(project);
myProject = project;
myVcs = ObjectUtils.assertNotNull(GitVcs.getInstance(myProject));
myFile = file;
myBaseRevision = revision == null ? (myVcs.getDiffProvider().getCurrentRevision(file)) : revision;
}
public void addLogEntries(List<VcsFileRevision> revisions) {
for (VcsFileRevision vcsFileRevision : revisions) {
myRevisionMap.put(vcsFileRevision.getRevisionNumber(), vcsFileRevision);
}
}
@Override
public void dispose() {
}
@Override
public LineAnnotationAspect[] getAspects() {
return new LineAnnotationAspect[]{REVISION_ASPECT, DATE_ASPECT, AUTHOR_ASPECT};
}
@Override
public String getToolTip(final int lineNumber) {
if (myLines.size() <= lineNumber || lineNumber < 0) {
return "";
}
final LineInfo info = myLines.get(lineNumber);
VcsFileRevision fileRevision = myRevisionMap.get(info.getRevision());
if (fileRevision != null) {
return GitBundle.message("annotation.tool.tip", info.getRevision().asString(), info.getAuthor(), info.getDate(),
fileRevision.getCommitMessage());
}
else {
return "";
}
}
@Override
public String getAnnotatedContent() {
return myContentBuffer.toString();
}
@Override
public List<VcsFileRevision> getRevisions() {
final List<VcsFileRevision> result = new ArrayList<VcsFileRevision>(myRevisionMap.values());
Collections.sort(result, new Comparator<VcsFileRevision>() {
@Override
public int compare(@NotNull VcsFileRevision o1, @NotNull VcsFileRevision o2) {
return -1 * o1.getRevisionNumber().compareTo(o2.getRevisionNumber());
}
});
return result;
}
@Override
public boolean revisionsNotEmpty() {
return ! myRevisionMap.isEmpty();
}
@Override
public AnnotationSourceSwitcher getAnnotationSourceSwitcher() {
return null;
}
@Override
public int getLineCount() {
return myLines.size();
}
@Override
public VcsRevisionNumber getLineRevisionNumber(final int lineNumber) {
if (lineNumberCheck(lineNumber)) {
return null;
}
return myLines.get(lineNumber).getRevision();
}
private boolean lineNumberCheck(int lineNumber) {
return myLines.size() <= lineNumber || lineNumber < 0;
}
@Override
public Date getLineDate(int lineNumber) {
if (lineNumberCheck(lineNumber)) {
return null;
}
return myLines.get(lineNumber).getDate();
}
/**
* Get revision number for the line.
*/
@Override
public VcsRevisionNumber originalRevision(int lineNumber) {
return getLineRevisionNumber(lineNumber);
}
/**
* Append line info
*
* @param date the revision date
* @param revision the revision number
* @param author the author
* @param line the line content
* @param lineNumber the line number for revision
* @throws VcsException in case when line could not be processed
*/
public void appendLineInfo(final Date date,
final GitRevisionNumber revision,
final String author,
final String line,
final long lineNumber) throws VcsException {
int expectedLineNo = myLines.size() + 1;
if (lineNumber != expectedLineNo) {
throw new VcsException("Adding for info for line " + lineNumber + " but we are expecting it to be for " + expectedLineNo);
}
myLines.add(new LineInfo(date, revision, author));
myContentBuffer.append(line);
}
public int getNumLines() {
return myLines.size();
}
/**
* Revision annotation aspect implementation
*/
private abstract class GitAnnotationAspect extends LineAnnotationAspectAdapter {
public GitAnnotationAspect(String id, boolean showByDefault) {
super(id, showByDefault);
}
@Override
public String getValue(int lineNumber) {
if (lineNumberCheck(lineNumber)) {
return "";
}
else {
return doGetValue(myLines.get(lineNumber));
}
}
protected abstract String doGetValue(LineInfo lineInfo);
@Override
protected void showAffectedPaths(int lineNum) {
if (lineNum >= 0 && lineNum < myLines.size()) {
LineInfo info = myLines.get(lineNum);
ShowAllAffectedGenericAction.showSubmittedFiles(myProject, info.getRevision(), myFile, GitVcs.getKey());
}
}
}
/**
* Line information
*/
static class LineInfo {
private final Date myDate;
private final GitRevisionNumber myRevision;
private final String myAuthor;
public LineInfo(Date date, GitRevisionNumber revision, String author) {
myDate = date;
myRevision = revision;
myAuthor = author;
}
public Date getDate() {
return myDate;
}
public GitRevisionNumber getRevision() {
return myRevision;
}
public String getAuthor() {
return myAuthor;
}
}
@NotNull
@Override
public VirtualFile getFile() {
return myFile;
}
@Nullable
@Override
public VcsRevisionNumber getCurrentRevision() {
return myBaseRevision;
}
@Override
public VcsKey getVcsKey() {
return GitVcs.getKey();
}
@Override
public boolean isBaseRevisionChanged(VcsRevisionNumber number) {
final VcsRevisionNumber currentCurrentRevision = myVcs.getDiffProvider().getCurrentRevision(myFile);
return myBaseRevision != null && ! myBaseRevision.equals(currentCurrentRevision);
}
}