| // Copyright (C) 2013 The Android Open Source Project |
| // |
| // 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.google.gerrit.client.change; |
| |
| import com.google.gerrit.client.AvatarImage; |
| import com.google.gerrit.client.FormatUtil; |
| import com.google.gerrit.client.info.AccountInfo; |
| import com.google.gerrit.client.info.ChangeInfo; |
| import com.google.gerrit.client.info.ChangeInfo.CommitInfo; |
| import com.google.gerrit.client.info.ChangeInfo.GitPerson; |
| import com.google.gerrit.client.info.ChangeInfo.RevisionInfo; |
| import com.google.gerrit.client.info.WebLinkInfo; |
| import com.google.gerrit.client.rpc.Natives; |
| import com.google.gerrit.client.ui.CommentLinkProcessor; |
| import com.google.gerrit.client.ui.InlineHyperlink; |
| import com.google.gerrit.common.Nullable; |
| import com.google.gerrit.common.PageLinks; |
| import com.google.gwt.core.client.GWT; |
| import com.google.gwt.core.client.JsArray; |
| import com.google.gwt.dom.client.Element; |
| import com.google.gwt.dom.client.TableRowElement; |
| import com.google.gwt.event.dom.client.ClickEvent; |
| import com.google.gwt.resources.client.CssResource; |
| import com.google.gwt.uibinder.client.UiBinder; |
| import com.google.gwt.uibinder.client.UiField; |
| import com.google.gwt.uibinder.client.UiHandler; |
| import com.google.gwt.user.client.DOM; |
| import com.google.gwt.user.client.ui.Button; |
| import com.google.gwt.user.client.ui.Composite; |
| import com.google.gwt.user.client.ui.FlowPanel; |
| import com.google.gwt.user.client.ui.HTML; |
| import com.google.gwt.user.client.ui.HTMLPanel; |
| import com.google.gwt.user.client.ui.Image; |
| import com.google.gwt.user.client.ui.ScrollPanel; |
| import com.google.gwt.user.client.ui.UIObject; |
| import com.google.gwtexpui.clippy.client.CopyableLabel; |
| import com.google.gwtexpui.safehtml.client.SafeHtmlBuilder; |
| |
| class CommitBox extends Composite { |
| interface Binder extends UiBinder<HTMLPanel, CommitBox> {} |
| |
| private static final Binder uiBinder = GWT.create(Binder.class); |
| |
| interface Style extends CssResource { |
| String collapsed(); |
| |
| String expanded(); |
| |
| String clippy(); |
| |
| String parentWebLink(); |
| } |
| |
| @UiField Style style; |
| @UiField FlowPanel authorPanel; |
| @UiField FlowPanel committerPanel; |
| @UiField Image mergeCommit; |
| @UiField CopyableLabel commitName; |
| @UiField FlowPanel webLinkPanel; |
| @UiField TableRowElement firstParent; |
| @UiField FlowPanel parentCommits; |
| @UiField FlowPanel parentWebLinks; |
| @UiField InlineHyperlink authorNameEmail; |
| @UiField Element authorDate; |
| @UiField InlineHyperlink committerNameEmail; |
| @UiField Element committerDate; |
| @UiField CopyableLabel idText; |
| @UiField HTML text; |
| @UiField ScrollPanel scroll; |
| @UiField Button more; |
| @UiField Element parentNotCurrentText; |
| private boolean expanded; |
| |
| CommitBox() { |
| initWidget(uiBinder.createAndBindUi(this)); |
| addStyleName(style.collapsed()); |
| } |
| |
| void onShowView() { |
| more.setVisible(scroll.getMaximumVerticalScrollPosition() > 0); |
| } |
| |
| @UiHandler("more") |
| void onMore(@SuppressWarnings("unused") ClickEvent e) { |
| if (expanded) { |
| removeStyleName(style.expanded()); |
| addStyleName(style.collapsed()); |
| } else { |
| removeStyleName(style.collapsed()); |
| addStyleName(style.expanded()); |
| } |
| expanded = !expanded; |
| } |
| |
| void set(CommentLinkProcessor commentLinkProcessor, ChangeInfo change, String revision) { |
| RevisionInfo revInfo = change.revision(revision); |
| CommitInfo commit = revInfo.commit(); |
| |
| commitName.setText(revision); |
| idText.setText("Change-Id: " + change.changeId()); |
| idText.setPreviewText(change.changeId()); |
| |
| formatLink(commit.author(), authorPanel, authorNameEmail, authorDate, change); |
| formatLink(commit.committer(), committerPanel, committerNameEmail, committerDate, change); |
| text.setHTML( |
| commentLinkProcessor.apply(new SafeHtmlBuilder().append(commit.message()).linkify())); |
| setWebLinks(webLinkPanel, revInfo.commit()); |
| |
| if (revInfo.commit().parents().length() > 1) { |
| mergeCommit.setVisible(true); |
| } |
| |
| setParents(revInfo.commit().parents()); |
| } |
| |
| void setParentNotCurrent(boolean parentNotCurrent) { |
| // display the orange ball if parent has moved on (not current) |
| UIObject.setVisible(parentNotCurrentText, parentNotCurrent); |
| parentNotCurrentText.setInnerText(parentNotCurrent ? "\u25CF" : ""); |
| } |
| |
| private void setWebLinks(FlowPanel panel, CommitInfo commit) { |
| JsArray<WebLinkInfo> links = commit.webLinks(); |
| if (links != null) { |
| for (WebLinkInfo link : Natives.asList(links)) { |
| panel.add(link.toAnchor()); |
| } |
| } |
| } |
| |
| private void setParents(JsArray<CommitInfo> commits) { |
| setVisible(firstParent, true); |
| TableRowElement next = firstParent; |
| TableRowElement previous = null; |
| for (CommitInfo c : Natives.asList(commits)) { |
| if (next == firstParent) { |
| CopyableLabel copyLabel = getCommitLabel(c); |
| parentCommits.add(copyLabel); |
| setWebLinks(parentWebLinks, c); |
| } else { |
| next.appendChild(DOM.createTD()); |
| Element td1 = DOM.createTD(); |
| td1.appendChild(getCommitLabel(c).getElement()); |
| next.appendChild(td1); |
| FlowPanel linksPanel = new FlowPanel(); |
| linksPanel.addStyleName(style.parentWebLink()); |
| setWebLinks(linksPanel, c); |
| Element td2 = DOM.createTD(); |
| td2.appendChild(linksPanel.getElement()); |
| next.appendChild(td2); |
| previous.getParentElement().insertAfter(next, previous); |
| } |
| previous = next; |
| next = DOM.createTR().cast(); |
| } |
| } |
| |
| private CopyableLabel getCommitLabel(CommitInfo c) { |
| CopyableLabel copyLabel; |
| copyLabel = new CopyableLabel(c.commit()); |
| copyLabel.setTitle(c.subject()); |
| copyLabel.setStyleName(style.clippy()); |
| return copyLabel; |
| } |
| |
| private static void formatLink( |
| GitPerson person, FlowPanel p, InlineHyperlink name, Element date, ChangeInfo change) { |
| // only try to fetch the avatar image for author and committer if an avatar |
| // plugin is installed, if the change owner has no avatar info assume that |
| // no avatar plugin is installed |
| if (change.owner().hasAvatarInfo()) { |
| AvatarImage avatar; |
| if (sameEmail(change.owner(), person)) { |
| avatar = new AvatarImage(change.owner()); |
| } else { |
| avatar = new AvatarImage(AccountInfo.create(0, person.name(), person.email(), null)); |
| } |
| p.insert(avatar, 0); |
| } |
| |
| name.setText(renderName(person)); |
| name.setTargetHistoryToken(PageLinks.toAccountQuery(owner(person), change.status())); |
| date.setInnerText(FormatUtil.mediumFormat(person.date())); |
| } |
| |
| private static String renderName(GitPerson person) { |
| return person.name() + " <" + person.email() + ">"; |
| } |
| |
| private static String owner(GitPerson person) { |
| if (person.email() != null) { |
| return person.email(); |
| } else if (person.name() != null) { |
| return person.name(); |
| } else { |
| return ""; |
| } |
| } |
| |
| private static boolean sameEmail(@Nullable AccountInfo p1, @Nullable GitPerson p2) { |
| return p1 != null |
| && p2 != null |
| && p1.email() != null |
| && p2.email() != null |
| && p1.email().equals(p2.email()); |
| } |
| } |