| // Copyright (C) 2008 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.changes; |
| |
| import com.google.gerrit.client.ErrorDialog; |
| import com.google.gerrit.client.Gerrit; |
| import com.google.gerrit.client.data.AccountInfoCache; |
| import com.google.gerrit.client.data.ApprovalDetail; |
| import com.google.gerrit.client.data.ApprovalType; |
| import com.google.gerrit.client.data.ChangeDetail; |
| import com.google.gerrit.client.patches.AddReviewerResult; |
| import com.google.gerrit.client.patches.PatchUtil; |
| import com.google.gerrit.client.reviewdb.Account; |
| import com.google.gerrit.client.reviewdb.ApprovalCategory; |
| import com.google.gerrit.client.reviewdb.ApprovalCategoryValue; |
| import com.google.gerrit.client.reviewdb.Change; |
| import com.google.gerrit.client.reviewdb.PatchSetApproval; |
| import com.google.gerrit.client.rpc.GerritCallback; |
| import com.google.gerrit.client.ui.AccountDashboardLink; |
| import com.google.gerrit.client.ui.AddMemberBox; |
| import com.google.gwt.event.dom.client.ClickEvent; |
| import com.google.gwt.event.dom.client.ClickHandler; |
| import com.google.gwt.user.client.DOM; |
| import com.google.gwt.user.client.Element; |
| import com.google.gwt.user.client.ui.Composite; |
| import com.google.gwt.user.client.ui.FlowPanel; |
| import com.google.gwt.user.client.ui.Grid; |
| import com.google.gwt.user.client.ui.Panel; |
| import com.google.gwt.user.client.ui.Widget; |
| import com.google.gwt.user.client.ui.HTMLTable.CellFormatter; |
| import com.google.gwtexpui.safehtml.client.SafeHtmlBuilder; |
| |
| import java.util.ArrayList; |
| import java.util.List; |
| import java.util.Map; |
| import java.util.Set; |
| |
| /** Displays a table of {@link ApprovalDetail} objects for a change record. */ |
| public class ApprovalTable extends Composite { |
| private final List<ApprovalType> types; |
| private final Grid table; |
| private final Widget missing; |
| private final Panel addReviewer; |
| private final AddMemberBox addMemberBox; |
| private Change.Id changeId; |
| private boolean changeIsOpen; |
| private AccountInfoCache accountCache = AccountInfoCache.empty(); |
| |
| public ApprovalTable() { |
| types = Gerrit.getConfig().getApprovalTypes().getApprovalTypes(); |
| table = new Grid(1, 3 + types.size()); |
| table.addStyleName("gerrit-InfoTable"); |
| displayHeader(); |
| |
| missing = new Widget() { |
| { |
| setElement(DOM.createElement("ul")); |
| } |
| }; |
| missing.setStyleName("gerrit-MissingApprovalList"); |
| |
| addReviewer = new FlowPanel(); |
| addReviewer.setStyleName("gerrit-AddReviewer"); |
| addMemberBox = new AddMemberBox(); |
| addMemberBox.setAddButtonText(Util.C.approvalTableAddReviewer()); |
| addMemberBox.addClickHandler(new ClickHandler() { |
| @Override |
| public void onClick(final ClickEvent event) { |
| doAddReviewer(); |
| } |
| }); |
| addReviewer.add(addMemberBox); |
| addReviewer.setVisible(false); |
| |
| final FlowPanel fp = new FlowPanel(); |
| fp.add(table); |
| fp.add(missing); |
| fp.add(addReviewer); |
| initWidget(fp); |
| |
| setStyleName("gerrit-ApprovalTable"); |
| } |
| |
| private void displayHeader() { |
| int col = 0; |
| header(col++, Util.C.approvalTableReviewer()); |
| header(col++, ""); |
| |
| for (final ApprovalType t : types) { |
| header(col++, t.getCategory().getName()); |
| } |
| applyEdgeStyles(0); |
| } |
| |
| private void header(final int col, final String title) { |
| table.setText(0, col, title); |
| table.getCellFormatter().addStyleName(0, col, "header"); |
| } |
| |
| private void applyEdgeStyles(final int row) { |
| final CellFormatter fmt = table.getCellFormatter(); |
| fmt.addStyleName(row, 0, "leftmost"); |
| fmt.addStyleName(row, 0, "reviewer"); |
| fmt.addStyleName(row, 1, "approvalrole"); |
| fmt.addStyleName(row, 1 + types.size(), "rightmost"); |
| fmt.addStyleName(row, 2 + types.size(), "approvalhint"); |
| } |
| |
| private void applyScoreStyles(final int row) { |
| final CellFormatter fmt = table.getCellFormatter(); |
| for (int col = 0; col < types.size(); col++) { |
| fmt.addStyleName(row, 2 + col, "approvalscore"); |
| } |
| } |
| |
| public void setAccountInfoCache(final AccountInfoCache aic) { |
| assert aic != null; |
| accountCache = aic; |
| } |
| |
| private AccountDashboardLink link(final Account.Id id) { |
| return AccountDashboardLink.link(accountCache, id); |
| } |
| |
| public void display(final Change change, final Set<ApprovalCategory.Id> need, |
| final List<ApprovalDetail> rows) { |
| changeId = change.getId(); |
| |
| final int oldcnt = table.getRowCount(); |
| table.resizeRows(1 + rows.size()); |
| if (oldcnt < 1 + rows.size()) { |
| for (int row = oldcnt; row < 1 + rows.size(); row++) { |
| applyEdgeStyles(row); |
| applyScoreStyles(row); |
| } |
| } |
| |
| if (rows.isEmpty()) { |
| table.setVisible(false); |
| } else { |
| table.setVisible(true); |
| for (int i = 0; i < rows.size(); i++) { |
| displayRow(i + 1, rows.get(i)); |
| } |
| } |
| |
| final Element missingList = missing.getElement(); |
| while (DOM.getChildCount(missingList) > 0) { |
| DOM.removeChild(missingList, DOM.getChild(missingList, 0)); |
| } |
| |
| missing.setVisible(false); |
| if (need != null) { |
| for (final ApprovalType at : types) { |
| if (need.contains(at.getCategory().getId())) { |
| final Element li = DOM.createElement("li"); |
| li.setClassName("gerrit-MissingApproval"); |
| DOM.setInnerText(li, Util.M.needApproval(at.getCategory().getName(), |
| at.getMax().formatValue(), at.getMax().getName())); |
| DOM.appendChild(missingList, li); |
| missing.setVisible(true); |
| } |
| } |
| } |
| |
| changeIsOpen = change.getStatus().isOpen(); |
| addReviewer.setVisible(Gerrit.isSignedIn() && changeIsOpen); |
| } |
| |
| private void doAddReviewer() { |
| final String nameEmail = addMemberBox.getText(); |
| if (nameEmail.length() == 0) { |
| return; |
| } |
| |
| addMemberBox.setEnabled(false); |
| final List<String> reviewers = new ArrayList<String>(); |
| reviewers.add(nameEmail); |
| |
| PatchUtil.DETAIL_SVC.addReviewers(changeId, reviewers, |
| new GerritCallback<AddReviewerResult>() { |
| public void onSuccess(final AddReviewerResult result) { |
| addMemberBox.setEnabled(true); |
| addMemberBox.setText(""); |
| |
| if (!result.getErrors().isEmpty()) { |
| final SafeHtmlBuilder r = new SafeHtmlBuilder(); |
| for (final AddReviewerResult.Error e : result.getErrors()) { |
| switch (e.getType()) { |
| case ACCOUNT_NOT_FOUND: |
| r.append(Util.M.accountNotFound(e.getName())); |
| break; |
| |
| case CHANGE_NOT_VISIBLE: |
| r.append(Util.M.changeNotVisibleTo(e.getName())); |
| break; |
| |
| default: |
| r.append(e.getName()); |
| r.append(" - "); |
| r.append(e.getType()); |
| r.br(); |
| break; |
| } |
| } |
| new ErrorDialog(r).center(); |
| } |
| |
| final ChangeDetail r = result.getChange(); |
| if (r != null) { |
| setAccountInfoCache(r.getAccounts()); |
| display(r.getChange(), r.getMissingApprovals(), r.getApprovals()); |
| } |
| } |
| |
| @Override |
| public void onFailure(final Throwable caught) { |
| addMemberBox.setEnabled(true); |
| super.onFailure(caught); |
| } |
| }); |
| } |
| |
| private void displayRow(final int row, final ApprovalDetail ad) { |
| final CellFormatter fmt = table.getCellFormatter(); |
| final Map<ApprovalCategory.Id, PatchSetApproval> am = ad.getApprovalMap(); |
| final StringBuilder hint = new StringBuilder(); |
| int col = 0; |
| table.setWidget(row, col++, link(ad.getAccount())); |
| table.clearCell(row, col++); // TODO populate the account role |
| |
| for (final ApprovalType type : types) { |
| final PatchSetApproval ca = am.get(type.getCategory().getId()); |
| if (ca == null || ca.getValue() == 0) { |
| table.clearCell(row, col); |
| col++; |
| continue; |
| } |
| |
| final ApprovalCategoryValue acv = type.getValue(ca); |
| if (acv != null) { |
| if (hint.length() > 0) { |
| hint.append("; "); |
| } |
| hint.append(acv.getName()); |
| } |
| |
| if (type.isMaxNegative(ca)) { |
| table.setWidget(row, col, Gerrit.ICONS.redNot().createImage()); |
| |
| } else if (type.isMaxPositive(ca)) { |
| table.setWidget(row, col, Gerrit.ICONS.greenCheck().createImage()); |
| |
| } else { |
| String vstr = String.valueOf(ca.getValue()); |
| if (ca.getValue() > 0) { |
| vstr = "+" + vstr; |
| fmt.removeStyleName(row, col, "negscore"); |
| fmt.addStyleName(row, col, "posscore"); |
| } else { |
| fmt.addStyleName(row, col, "negscore"); |
| fmt.removeStyleName(row, col, "posscore"); |
| } |
| table.setText(row, col, vstr); |
| } |
| |
| col++; |
| } |
| |
| table.setText(row, col++, hint.toString()); |
| } |
| } |