blob: 728824600fe7f320874b1f262605774d41794410 [file] [log] [blame]
// 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.Gerrit;
import com.google.gerrit.client.SignedInListener;
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.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.ChangeApproval;
import com.google.gerrit.client.rpc.Common;
import com.google.gerrit.client.rpc.GerritCallback;
import com.google.gerrit.client.rpc.ScreenLoadCallback;
import com.google.gerrit.client.ui.AccountDashboardLink;
import com.google.gerrit.client.ui.AddMemberBox;
import com.google.gwt.user.client.ui.ClickListener;
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.Label;
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.gwtjsonrpc.client.VoidResult;
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 Panel missing;
private final Panel addReviewer;
private final AddMemberBox addMemberBox;
private final SignedInListener signedInListener;
private Change.Id changeId;
private boolean changeIsOpen;
private AccountInfoCache accountCache = AccountInfoCache.empty();
public ApprovalTable() {
types = Common.getGerritConfig().getApprovalTypes();
table = new Grid(1, 3 + types.size());
table.addStyleName("gerrit-InfoTable");
displayHeader();
missing = new FlowPanel();
missing.setStyleName("gerrit-Change-MissingApprovalList");
addReviewer = new FlowPanel();
addReviewer.setStyleName("gerrit-Change-AddReviewer");
addMemberBox = new AddMemberBox();
addMemberBox.setAddButtonText(Util.C.approvalTableAddReviewer());
addMemberBox.addClickListener(new ClickListener() {
public void onClick(final Widget sender) {
doAddReviewer();
}
});
addReviewer.add(addMemberBox);
addReviewer.setVisible(false);
final FlowPanel fp = new FlowPanel();
fp.add(table);
fp.add(missing);
fp.add(addReviewer);
initWidget(fp);
signedInListener = new SignedInListener() {
public void onSignIn() {
addReviewer.setVisible(changeIsOpen);
}
public void onSignOut() {
addReviewer.setVisible(false);
}
};
}
@Override
protected void onLoad() {
Gerrit.addSignedInListener(signedInListener);
super.onLoad();
}
@Override
protected void onUnload() {
Gerrit.removeSignedInListener(signedInListener);
super.onUnload();
}
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));
}
}
missing.clear();
missing.setVisible(false);
if (need != null) {
for (final ApprovalType at : types) {
if (need.contains(at.getCategory().getId())) {
final Label l =
new Label(Util.M.needApproval(at.getCategory().getName()));
l.setStyleName("gerrit-Change-MissingApproval");
missing.add(l);
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<VoidResult>() {
public void onSuccess(final VoidResult result) {
addMemberBox.setEnabled(true);
addMemberBox.setText("");
Util.DETAIL_SVC.changeDetail(changeId,
new ScreenLoadCallback<ChangeDetail>() {
public void onSuccess(final ChangeDetail r) {
if (isAttached()) {
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, ChangeApproval> 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 ChangeApproval 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());
}
}