From a502d96a860456ec5e8c96761db70f7cabb74751 Mon Sep 17 00:00:00 2001 From: Paul Martin <paul@paulsputer.com> Date: Sat, 30 Apr 2016 04:19:14 -0400 Subject: [PATCH] Merge pull request #1073 from gitblit/1062-DocEditorUpdates --- src/main/java/com/gitblit/wicket/pages/BlamePage.java | 201 +++++++++++++++++++++++++++++++++++++++++--------- 1 files changed, 165 insertions(+), 36 deletions(-) diff --git a/src/main/java/com/gitblit/wicket/pages/BlamePage.java b/src/main/java/com/gitblit/wicket/pages/BlamePage.java index 9f00d21..2fcca0a 100644 --- a/src/main/java/com/gitblit/wicket/pages/BlamePage.java +++ b/src/main/java/com/gitblit/wicket/pages/BlamePage.java @@ -15,25 +15,34 @@ */ package com.gitblit.wicket.pages; +import java.awt.Color; import java.text.DateFormat; import java.text.MessageFormat; import java.text.SimpleDateFormat; +import java.util.Comparator; +import java.util.Date; +import java.util.HashSet; import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.TreeSet; +import org.apache.wicket.Component; import org.apache.wicket.PageParameters; +import org.apache.wicket.behavior.SimpleAttributeModifier; import org.apache.wicket.markup.html.basic.Label; import org.apache.wicket.markup.html.link.BookmarkablePageLink; +import org.apache.wicket.markup.html.link.ExternalLink; import org.apache.wicket.markup.repeater.Item; import org.apache.wicket.markup.repeater.data.DataView; import org.apache.wicket.markup.repeater.data.ListDataProvider; -import org.eclipse.jgit.lib.Constants; import org.eclipse.jgit.lib.ObjectId; import org.eclipse.jgit.revwalk.RevCommit; -import com.gitblit.GitBlit; import com.gitblit.Keys; import com.gitblit.models.AnnotatedLine; import com.gitblit.models.PathModel; +import com.gitblit.utils.ColorFactory; import com.gitblit.utils.DiffUtils; import com.gitblit.utils.JGitUtils; import com.gitblit.utils.StringUtils; @@ -47,36 +56,47 @@ @CacheControl(LastModified.BOOT) public class BlamePage extends RepositoryPage { + /** + * The different types of Blame visualizations. + */ + private enum BlameType { + COMMIT, + + AUTHOR, + + AGE; + + private BlameType() { + } + + public static BlameType get(String name) { + for (BlameType blameType : BlameType.values()) { + if (blameType.name().equalsIgnoreCase(name)) { + return blameType; + } + } + throw new IllegalArgumentException("Unknown Blame Type [" + name + + "]"); + } + + @Override + public String toString() { + return name().toLowerCase(); + } + } + public BlamePage(PageParameters params) { super(params); final String blobPath = WicketUtils.getPath(params); + final String blameTypeParam = params.getString("blametype", BlameType.COMMIT.toString()); + final BlameType activeBlameType = BlameType.get(blameTypeParam); + RevCommit commit = getCommit(); - - add(new BookmarkablePageLink<Void>("blobLink", BlobPage.class, - WicketUtils.newPathParameter(repositoryName, objectId, blobPath))); - add(new BookmarkablePageLink<Void>("commitLink", CommitPage.class, - WicketUtils.newObjectParameter(repositoryName, objectId))); - add(new BookmarkablePageLink<Void>("commitDiffLink", CommitDiffPage.class, - WicketUtils.newObjectParameter(repositoryName, objectId))); - - // blame page links - add(new BookmarkablePageLink<Void>("headLink", BlamePage.class, - WicketUtils.newPathParameter(repositoryName, Constants.HEAD, blobPath))); - add(new BookmarkablePageLink<Void>("historyLink", HistoryPage.class, - WicketUtils.newPathParameter(repositoryName, objectId, blobPath))); - - add(new CommitHeaderPanel("commitHeader", repositoryName, commit)); - - add(new PathBreadcrumbsPanel("breadcrumbs", repositoryName, blobPath, objectId)); - - String format = GitBlit.getString(Keys.web.datetimestampLongFormat, - "EEEE, MMMM d, yyyy HH:mm Z"); - final DateFormat df = new SimpleDateFormat(format); - df.setTimeZone(getTimeZone()); - + PathModel pathModel = null; + List<PathModel> paths = JGitUtils.getFilesInPath(getRepository(), StringUtils.getRootPath(blobPath), commit); for (PathModel path : paths) { if (path.path.equals(blobPath)) { @@ -84,33 +104,85 @@ break; } } - + if (pathModel == null) { + final String notFound = MessageFormat.format("Blame page failed to find {0} in {1} @ {2}", + blobPath, repositoryName, objectId); + logger.error(notFound); add(new Label("annotation").setVisible(false)); add(new Label("missingBlob", missingBlob(blobPath, commit)).setEscapeModelStrings(false)); return; } + + if (pathModel.isFilestoreItem()) { + String rawUrl = JGitUtils.getLfsRepositoryUrl(getContextUrl(), repositoryName, pathModel.getFilestoreOid()); + add(new ExternalLink("blobLink", rawUrl)); + } else { + add(new BookmarkablePageLink<Void>("blobLink", BlobPage.class, + WicketUtils.newPathParameter(repositoryName, objectId, blobPath))); + } + + add(new BookmarkablePageLink<Void>("commitLink", CommitPage.class, + WicketUtils.newObjectParameter(repositoryName, objectId))); + add(new BookmarkablePageLink<Void>("commitDiffLink", CommitDiffPage.class, + WicketUtils.newObjectParameter(repositoryName, objectId))); + + // blame page links + add(new BookmarkablePageLink<Void>("historyLink", HistoryPage.class, + WicketUtils.newPathParameter(repositoryName, objectId, blobPath))); + + // "Blame by" links + for (BlameType type : BlameType.values()) { + String typeString = type.toString(); + PageParameters blameTypePageParam = + WicketUtils.newBlameTypeParameter(repositoryName, commit.getName(), + WicketUtils.getPath(params), typeString); + + String blameByLinkText = "blameBy" + + Character.toUpperCase(typeString.charAt(0)) + typeString.substring(1) + + "Link"; + BookmarkablePageLink<Void> blameByPageLink = + new BookmarkablePageLink<Void>(blameByLinkText, BlamePage.class, blameTypePageParam); + + if (activeBlameType == type) { + blameByPageLink.add(new SimpleAttributeModifier("style", "font-weight:bold;")); + } + + add(blameByPageLink); + } + + add(new CommitHeaderPanel("commitHeader", repositoryName, commit)); + + add(new PathBreadcrumbsPanel("breadcrumbs", repositoryName, blobPath, objectId)); + + String format = app().settings().getString(Keys.web.datetimestampLongFormat, + "EEEE, MMMM d, yyyy HH:mm Z"); + final DateFormat df = new SimpleDateFormat(format); + df.setTimeZone(getTimeZone()); + + + + add(new Label("missingBlob").setVisible(false)); + final int tabLength = app().settings().getInteger(Keys.web.tabLength, 4); List<AnnotatedLine> lines = DiffUtils.blame(getRepository(), blobPath, objectId); + final Map<?, String> colorMap = initializeColors(activeBlameType, lines); ListDataProvider<AnnotatedLine> blameDp = new ListDataProvider<AnnotatedLine>(lines); DataView<AnnotatedLine> blameView = new DataView<AnnotatedLine>("annotation", blameDp) { private static final long serialVersionUID = 1L; - private int count; private String lastCommitId = ""; private boolean showInitials = true; private String zeroId = ObjectId.zeroId().getName(); @Override public void populateItem(final Item<AnnotatedLine> item) { - AnnotatedLine entry = item.getModelObject(); - item.add(new Label("line", "" + entry.lineNumber)); - item.add(new Label("data", StringUtils.escapeForHtml(entry.data, true)) - .setEscapeModelStrings(false)); + final AnnotatedLine entry = item.getModelObject(); + + // commit id and author if (!lastCommitId.equals(entry.commitId)) { lastCommitId = entry.commitId; - count++; if (zeroId.equals(entry.commitId)) { // unknown commit item.add(new Label("commit", "<?>")); @@ -123,6 +195,7 @@ WicketUtils.setHtmlTooltip(commitLink, MessageFormat.format("{0}, {1}", entry.author, df.format(entry.when))); item.add(commitLink); + WicketUtils.setCssStyle(item, "border-top: 1px solid #ddd;"); showInitials = true; } } else { @@ -135,11 +208,26 @@ item.add(new Label("commit").setVisible(false)); } } - if (count % 2 == 0) { - WicketUtils.setCssClass(item, "even"); - } else { - WicketUtils.setCssClass(item, "odd"); + + // line number + item.add(new Label("line", "" + entry.lineNumber)); + + // line content + String color; + switch (activeBlameType) { + case AGE: + color = colorMap.get(entry.when); + break; + case AUTHOR: + color = colorMap.get(entry.author); + break; + default: + color = colorMap.get(entry.commitId); + break; } + Component data = new Label("data", StringUtils.escapeForHtml(entry.data, true, tabLength)).setEscapeModelStrings(false); + data.add(new SimpleAttributeModifier("style", "background-color: " + color + ";")); + item.add(data); } }; add(blameView); @@ -160,6 +248,11 @@ } @Override + protected boolean isCommitPage() { + return true; + } + + @Override protected Class<? extends BasePage> getRepoNavPageClass() { return TreePage.class; } @@ -172,4 +265,40 @@ sb.append("</div>"); return sb.toString(); } + + private Map<?, String> initializeColors(BlameType blameType, List<AnnotatedLine> lines) { + ColorFactory colorFactory = new ColorFactory(); + Map<?, String> colorMap; + + if (BlameType.AGE == blameType) { + Set<Date> keys = new TreeSet<Date>(new Comparator<Date>() { + @Override + public int compare(Date o1, Date o2) { + // younger code has a brighter, older code lightens to white + return o1.compareTo(o2); + } + }); + + for (AnnotatedLine line : lines) { + keys.add(line.when); + } + + // TODO consider making this a setting + colorMap = colorFactory.getGraduatedColorMap(keys, Color.decode("#FFA63A")); + } else { + Set<String> keys = new HashSet<String>(); + + for (AnnotatedLine line : lines) { + if (blameType == BlameType.AUTHOR) { + keys.add(line.author); + } else { + keys.add(line.commitId); + } + } + + colorMap = colorFactory.getRandomColorMap(keys); + } + + return colorMap; + } } -- Gitblit v1.9.1