summaryrefslogtreecommitdiffstatsabout
diff options
context:
space:
mode:
authorilya_ivanov2011-02-03 13:32:39 (EST)
committer Dariusz Luksza2011-02-03 15:39:52 (EST)
commit390b6b146aa218a9c985e6ce9df2845eb575be48 (patch)
treeaafcdfd0b31cb51e5a976ea3adb8976a1bbb9225
parentd5ad12d2ea644c4800c64c284a626183f3497e68 (diff)
downloadegit-390b6b146aa218a9c985e6ce9df2845eb575be48.zip
egit-390b6b146aa218a9c985e6ce9df2845eb575be48.tar.gz
egit-390b6b146aa218a9c985e6ce9df2845eb575be48.tar.bz2
Branches and Tags links in commit message viewerrefs/changes/07/2407/6
Some analog of 'gitk' utility links. Added following info to commit message viewer: Branches - links to branch refs Tags - list of tags pointing to this commit Follows - link to previous tag in history Precedes - link to next tag in history Bug: 336223 Change-Id: I1c61d2c7eca14ba534302eec6e38bdbe85e0107f Signed-off-by: ilya.ivanov <ilya.ivanov@intland.com> Signed-off-by: Dariusz Luksza <dariusz@luksza.org>
-rw-r--r--org.eclipse.egit.ui/src/org/eclipse/egit/ui/UIText.java12
-rw-r--r--org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/history/CommitGraphTable.java27
-rw-r--r--org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/history/CommitMessageViewer.java188
-rw-r--r--org.eclipse.egit.ui/src/org/eclipse/egit/ui/uitext.properties4
4 files changed, 223 insertions, 8 deletions
diff --git a/org.eclipse.egit.ui/src/org/eclipse/egit/ui/UIText.java b/org.eclipse.egit.ui/src/org/eclipse/egit/ui/UIText.java
index acd4e04..d03560d 100644
--- a/org.eclipse.egit.ui/src/org/eclipse/egit/ui/UIText.java
+++ b/org.eclipse.egit.ui/src/org/eclipse/egit/ui/UIText.java
@@ -1684,6 +1684,18 @@ public class UIText extends NLS {
public static String CommitMessageViewer_child;
/** */
+ public static String CommitMessageViewer_branches;
+
+ /** */
+ public static String CommitMessageViewer_tags;
+
+ /** */
+ public static String CommitMessageViewer_follows;
+
+ /** */
+ public static String CommitMessageViewer_precedes;
+
+ /** */
public static String CommitMessageViewer_commit;
/** */
diff --git a/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/history/CommitGraphTable.java b/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/history/CommitGraphTable.java
index 0f21ab5..ccc9c69 100644
--- a/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/history/CommitGraphTable.java
+++ b/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/history/CommitGraphTable.java
@@ -109,6 +109,9 @@ class CommitGraphTable {
private SWTCommitList allCommits;
+ // used for resolving PlotCommit objects by ids
+ private HashMap<String, PlotCommit> commitsMap = null;
+
private RevFlag highlight;
private HistoryPageInput input;
@@ -164,8 +167,8 @@ class CommitGraphTable {
CommitGraphTable(final Composite parent, final IPageSite site,
final MenuManager menuMgr) {
- this(parent);
- final IAction selectAll = createStandardAction(ActionFactory.SELECT_ALL);
+ this(parent);
+ final IAction selectAll = createStandardAction(ActionFactory.SELECT_ALL);
getControl().addFocusListener(new FocusListener() {
public void focusLost(FocusEvent e) {
site.getActionBars().setGlobalActionHandler(
@@ -231,8 +234,14 @@ class CommitGraphTable {
}
void selectCommit(final RevCommit c) {
- table.setSelection(new StructuredSelection(c));
- table.reveal(c);
+ if (c instanceof PlotCommit) {
+ table.setSelection(new StructuredSelection(c));
+ table.reveal(c);
+ } else {
+ PlotCommit swtCommit = commitsMap.get(c.getId().name());
+ table.setSelection(new StructuredSelection(swtCommit));
+ table.reveal(swtCommit);
+ }
}
void addSelectionChangedListener(final ISelectionChangedListener l) {
@@ -276,13 +285,21 @@ class CommitGraphTable {
allCommits = list;
table.setInput(asArray);
if (asArray != null && asArray.length > 0) {
- if (oldList != list)
+ if (oldList != list) {
selectCommit(asArray[0]);
+ initCommitsMap();
+ }
} else {
table.getTable().deselectAll();
}
}
+ private void initCommitsMap() {
+ commitsMap = new HashMap<String, PlotCommit>();
+ for (PlotCommit commit : allCommits)
+ commitsMap.put(commit.getId().name(), commit);
+ }
+
private void createColumns(final Table rawTable, final TableLayout layout) {
final TableColumn graph = new TableColumn(rawTable, SWT.NONE);
graph.setResizable(true);
diff --git a/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/history/CommitMessageViewer.java b/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/history/CommitMessageViewer.java
index 049cef0..ab234b6 100644
--- a/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/history/CommitMessageViewer.java
+++ b/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/history/CommitMessageViewer.java
@@ -18,6 +18,10 @@ import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Comparator;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
@@ -42,10 +46,16 @@ import org.eclipse.jface.viewers.IStructuredSelection;
import org.eclipse.jface.viewers.SelectionChangedEvent;
import org.eclipse.jgit.diff.DiffFormatter;
import org.eclipse.jgit.diff.RawText;
+import org.eclipse.jgit.errors.IncorrectObjectTypeException;
+import org.eclipse.jgit.errors.MissingObjectException;
+import org.eclipse.jgit.lib.Constants;
+import org.eclipse.jgit.lib.ObjectId;
import org.eclipse.jgit.lib.PersonIdent;
+import org.eclipse.jgit.lib.Ref;
import org.eclipse.jgit.lib.Repository;
import org.eclipse.jgit.revplot.PlotCommit;
import org.eclipse.jgit.revwalk.RevCommit;
+import org.eclipse.jgit.revwalk.RevWalk;
import org.eclipse.jgit.treewalk.TreeWalk;
import org.eclipse.osgi.util.NLS;
import org.eclipse.swt.SWT;
@@ -305,7 +315,7 @@ class CommitMessageViewer extends TextViewer implements
for (int i = 0; i < commit.getChildCount(); i++) {
final RevCommit p = commit.getChild(i);
d.append(UIText.CommitMessageViewer_child);
- d.append(": "); //$NON-NLS-1$
+ d.append(": "); //$NON-NLS-1$
addLink(d, styles, p);
d.append(" ("); //$NON-NLS-1$
d.append(p.getShortMessage());
@@ -313,6 +323,63 @@ class CommitMessageViewer extends TextViewer implements
d.append(LF);
}
+ List<Ref> branches = getBranches();
+ if (!branches.isEmpty()) {
+ d.append(UIText.CommitMessageViewer_branches);
+ d.append(": "); //$NON-NLS-1$
+ for (Iterator<Ref> i = branches.iterator(); i.hasNext(); ) {
+ Ref head = i.next();
+ RevCommit p;
+ try {
+ p = new RevWalk(db).parseCommit(head.getObjectId());
+ addLink(d, formatHeadRef(head), styles, p);
+ if (i.hasNext())
+ d.append(", "); //$NON-NLS-1$
+ } catch (MissingObjectException e) {
+ Activator.logError(e.getMessage(), e);
+ } catch (IncorrectObjectTypeException e) {
+ Activator.logError(e.getMessage(), e);
+ } catch (IOException e) {
+ Activator.logError(e.getMessage(), e);
+ }
+ }
+ d.append(LF);
+ }
+
+ String tagsString = getTagsString();
+ if (tagsString.length() > 0) {
+ d.append(UIText.CommitMessageViewer_tags);
+ d.append(": "); //$NON-NLS-1$
+ d.append(tagsString);
+ d.append(LF);
+ }
+
+ try {
+ Ref followingTag = getNextTag(false);
+ if (followingTag != null) {
+ d.append(UIText.CommitMessageViewer_follows);
+ d.append(": "); //$NON-NLS-1$
+ RevCommit p = new RevWalk(db).parseCommit(followingTag.getObjectId());
+ addLink(d, formatTagRef(followingTag), styles, p);
+ d.append(LF);
+ }
+ } catch (IOException e) {
+ Activator.logError(e.getMessage(), e);
+ }
+
+ try {
+ Ref precedingTag = getNextTag(true);
+ if (precedingTag != null) {
+ d.append(UIText.CommitMessageViewer_precedes);
+ d.append(": "); //$NON-NLS-1$
+ RevCommit p = new RevWalk(db).parseCommit(precedingTag.getObjectId());
+ addLink(d, formatTagRef(precedingTag), styles, p);
+ d.append(LF);
+ }
+ } catch (IOException e) {
+ Activator.logError(e.getMessage(), e);
+ }
+
makeGrayText(d, styles);
d.append(LF);
String msg = commit.getFullMessage();
@@ -349,6 +416,37 @@ class CommitMessageViewer extends TextViewer implements
getTextWidget().setStyleRanges(arr);
}
+ private String getTagsString() {
+ StringBuilder sb = new StringBuilder();
+ Map<String, Ref> tagsMap = db.getTags();
+ for (String tagName : tagsMap.keySet()) {
+ ObjectId peeledId = tagsMap.get(tagName).getPeeledObjectId();
+ if (peeledId != null && peeledId.equals(commit)) {
+ if (sb.length() > 0)
+ sb.append(", "); //$NON-NLS-1$
+ sb.append(tagName);
+ }
+ }
+
+ return sb.toString();
+ }
+
+ private String formatHeadRef(Ref ref) {
+ final String name = ref.getName();
+ if (name.startsWith(Constants.R_HEADS))
+ return name.substring(Constants.R_HEADS.length());
+ else if (name.startsWith(Constants.R_REMOTES))
+ return name.substring(Constants.R_REMOTES.length());
+ return name;
+ }
+
+ private String formatTagRef(Ref ref) {
+ final String name = ref.getName();
+ if (name.startsWith(Constants.R_TAGS))
+ return name.substring(Constants.R_TAGS.length());
+ return name;
+ }
+
private void makeGrayText(StringBuilder d, ArrayList<StyleRange> styles) {
int p0 = 0;
for (int i = 0; i < styles.size(); ++i) {
@@ -371,18 +469,23 @@ class CommitMessageViewer extends TextViewer implements
}
}
- private void addLink(final StringBuilder d,
+ private void addLink(final StringBuilder d, String linkLabel,
final ArrayList<StyleRange> styles, final RevCommit to) {
final ObjectLink sr = new ObjectLink();
sr.targetCommit = to;
sr.foreground = sys_linkColor;
sr.underline = true;
sr.start = d.length();
- d.append(to.getId().name());
+ d.append(linkLabel);
sr.length = d.length() - sr.start;
styles.add(sr);
}
+ private void addLink(final StringBuilder d,
+ final ArrayList<StyleRange> styles, final RevCommit to) {
+ addLink(d, to.getId().name(), styles, to);
+ }
+
private void addDiff(final StringBuilder d,
final ArrayList<StyleRange> styles) {
final DiffFormatter diffFmt = new DiffFormatter(
@@ -527,4 +630,83 @@ class CommitMessageViewer extends TextViewer implements
}
+ /**
+ * Finds nextdoor tagged revition. Searches forwards (in descendants) or backwards (in ancestors)
+ * @param searchDescendant if <code>false</code>, will search for tagged revision in ancestors
+ * @return {@link Ref} or <code>null</code> if no tag found
+ * @throws IOException
+ */
+ private Ref getNextTag(boolean searchDescendant) throws IOException {
+ RevWalk revWalk = new RevWalk(db);
+
+ Map<String, Ref> tagsMap = db.getTags();
+ Ref tagRef = null;
+
+ for (String tagName : tagsMap.keySet()) {
+ // both RevCommits must be allocated using same RevWalk instance,
+ // otherwise isMergedInto returns wrong result!
+ RevCommit current = revWalk.parseCommit(commit);
+ RevCommit newTag = revWalk.parseCommit(tagsMap.get(tagName).getObjectId());
+
+ if (newTag.getId().equals(commit))
+ continue;
+
+ // check if newTag matches our criteria
+ if (isMergedInto(revWalk, newTag, current, searchDescendant)) {
+ if (tagRef != null) {
+ RevCommit oldTag = revWalk.parseCommit(tagRef.getObjectId());
+
+ // both oldTag and newTag satisfy search criteria, so taking the closest one
+ if (isMergedInto(revWalk, oldTag, newTag, searchDescendant))
+ tagRef = tagsMap.get(tagName);
+ } else
+ tagRef = tagsMap.get(tagName);
+ }
+ }
+
+ return tagRef;
+ }
+
+ /**
+ * @param rw
+ * @param base
+ * @param tip
+ * @param swap if <code>true</code>, base and tip arguments are swapped
+ * @return <code>true</code> if there is a path directly from tip to base (and thus base is fully merged into tip); <code>false</code> otherwise.
+ * @throws IOException
+ */
+ private boolean isMergedInto(final RevWalk rw, final RevCommit base, final RevCommit tip, boolean swap)
+ throws IOException {
+ return !swap ? rw.isMergedInto(base, tip) : rw.isMergedInto(tip, base);
+ }
+
+ /**
+ * @return List of heads from those current commit is reachable
+ */
+ private List<Ref> getBranches() {
+ RevWalk revWalk = new RevWalk(db);
+ List<Ref> result = new ArrayList<Ref>();
+
+ try {
+ Map<String, Ref> refsMap = new HashMap<String, Ref>();
+ refsMap.putAll(db.getRefDatabase().getRefs(Constants.R_HEADS));
+ // add remote heads to search
+ refsMap.putAll(db.getRefDatabase().getRefs(Constants.R_REMOTES));
+
+ for (String headName : refsMap.keySet()) {
+ RevCommit headCommit = revWalk.parseCommit(refsMap.get(headName).getObjectId());
+ // the base RevCommit also must be allocated using same RevWalk instance,
+ // otherwise isMergedInto returns wrong result!
+ RevCommit base = revWalk.parseCommit(commit);
+
+ if (revWalk.isMergedInto(base, headCommit))
+ result.add(refsMap.get(headName)); // commit is reachable from this head
+ }
+ } catch (IOException e) {
+ // skip exception
+ }
+
+ return result;
+ }
+
}
diff --git a/org.eclipse.egit.ui/src/org/eclipse/egit/ui/uitext.properties b/org.eclipse.egit.ui/src/org/eclipse/egit/ui/uitext.properties
index 9a5181c..cc1c233 100644
--- a/org.eclipse.egit.ui/src/org/eclipse/egit/ui/uitext.properties
+++ b/org.eclipse.egit.ui/src/org/eclipse/egit/ui/uitext.properties
@@ -552,6 +552,10 @@ SpellCheckingMessageArea_paste=&Paste
SpellCheckingMessageArea_selectAll=Select &All
CommitMessageViewer_author=Author
CommitMessageViewer_child=Child
+CommitMessageViewer_branches=Branches
+CommitMessageViewer_tags=Tags
+CommitMessageViewer_follows=Follows
+CommitMessageViewer_precedes=Precedes
CommitMessageViewer_commit=commit
CommitMessageViewer_committer=Committer
CommitMessageViewer_errorGettingFileDifference=Can't get file difference of {0}.