blob: cb595c0c8d1b041fedea447847e051491acf2719 [file] [log] [blame]
// Copyright (C) 2009 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.Link;
import com.google.gerrit.client.data.ApprovalType;
import com.google.gerrit.client.patches.LineCommentPanel;
import com.google.gerrit.client.patches.PatchUtil;
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.reviewdb.Patch;
import com.google.gerrit.client.reviewdb.PatchLineComment;
import com.google.gerrit.client.reviewdb.PatchSet;
import com.google.gerrit.client.rpc.Common;
import com.google.gerrit.client.rpc.GerritCallback;
import com.google.gerrit.client.ui.AccountScreen;
import com.google.gerrit.client.ui.PatchLink;
import com.google.gerrit.client.ui.SmallHeading;
import com.google.gwt.user.client.DOM;
import com.google.gwt.user.client.Event;
import com.google.gwt.user.client.History;
import com.google.gwt.user.client.ui.Button;
import com.google.gwt.user.client.ui.ClickListener;
import com.google.gwt.user.client.ui.FlowPanel;
import com.google.gwt.user.client.ui.FormHandler;
import com.google.gwt.user.client.ui.FormPanel;
import com.google.gwt.user.client.ui.FormSubmitCompleteEvent;
import com.google.gwt.user.client.ui.FormSubmitEvent;
import com.google.gwt.user.client.ui.Label;
import com.google.gwt.user.client.ui.Panel;
import com.google.gwt.user.client.ui.RadioButton;
import com.google.gwt.user.client.ui.TextArea;
import com.google.gwt.user.client.ui.VerticalPanel;
import com.google.gwt.user.client.ui.Widget;
import com.google.gwtexpui.safehtml.client.SafeHtml;
import com.google.gwtjsonrpc.client.VoidResult;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
public class PublishCommentScreen extends AccountScreen implements
ClickListener {
private final PatchSet.Id patchSetId;
private Collection<ValueRadioButton> approvalButtons;
private ChangeDescriptionBlock descBlock;
private Panel approvalPanel;
private TextArea message;
private Panel draftsPanel;
private Button send;
private Button cancel;
private boolean displayedOnce;
public PublishCommentScreen(final PatchSet.Id psi) {
super(Util.M.publishComments(psi.getParentKey().get(), psi.get()));
addStyleName("gerrit-PublishCommentsScreen");
patchSetId = psi;
}
@Override
public Object getScreenCacheToken() {
return new ScreenCacheToken(patchSetId);
}
@Override
public void onLoad() {
if (message == null) {
approvalButtons = new ArrayList<ValueRadioButton>();
descBlock = new ChangeDescriptionBlock();
add(descBlock);
final FormPanel form = new FormPanel();
final FlowPanel body = new FlowPanel();
form.setWidget(body);
form.addFormHandler(new FormHandler() {
public void onSubmit(FormSubmitEvent event) {
event.setCancelled(true);
}
public void onSubmitComplete(FormSubmitCompleteEvent event) {
}
});
add(form);
approvalPanel = new FlowPanel();
body.add(approvalPanel);
initMessage(body);
draftsPanel = new FlowPanel();
body.add(draftsPanel);
final FlowPanel buttonRow = new FlowPanel();
buttonRow.setStyleName("gerrit-CommentEditor-Buttons");
body.add(buttonRow);
send = new Button(Util.C.buttonPublishCommentsSend());
send.addClickListener(this);
buttonRow.add(send);
cancel = new Button(Util.C.buttonPublishCommentsCancel());
cancel.addClickListener(this);
buttonRow.add(cancel);
}
super.onLoad();
message.setFocus(true);
send.setEnabled(false);
Util.DETAIL_SVC.patchSetPublishDetail(patchSetId,
new GerritCallback<PatchSetPublishDetail>() {
public void onSuccess(final PatchSetPublishDetail result) {
send.setEnabled(true);
display(result);
}
});
}
public void onClick(final Widget sender) {
if (send == sender) {
onSend();
} else if (cancel == sender) {
Gerrit.uncache(this);
goChange();
}
}
private void initMessage(final Panel body) {
body.add(new SmallHeading(Util.C.headingCoverMessage()));
final VerticalPanel mwrap = new VerticalPanel();
mwrap.setStyleName("gerrit-CoverMessage");
body.add(mwrap);
message = new TextArea();
message.setCharacterWidth(60);
message.setVisibleLines(10);
DOM.setElementPropertyBoolean(message.getElement(), "spellcheck", true);
mwrap.add(message);
}
private void initApprovals(final PatchSetPublishDetail r, final Panel body) {
for (final ApprovalType ct : Common.getGerritConfig().getApprovalTypes()) {
if (r.isAllowed(ct.getCategory().getId())) {
initApprovalType(r, body, ct);
}
}
}
private void initApprovalType(final PatchSetPublishDetail r,
final Panel body, final ApprovalType ct) {
body.add(new SmallHeading(ct.getCategory().getName() + ":"));
final VerticalPanel vp = new VerticalPanel();
vp.setStyleName("gerrit-ApprovalCategoryList");
final List<ApprovalCategoryValue> lst =
new ArrayList<ApprovalCategoryValue>(ct.getValues());
Collections.reverse(lst);
final ApprovalCategory.Id catId = ct.getCategory().getId();
final Set<ApprovalCategoryValue.Id> allowed = r.getAllowed(catId);
final ChangeApproval prior = r.getChangeApproval(catId);
for (final ApprovalCategoryValue buttonValue : lst) {
if (!allowed.contains(buttonValue.getId())) {
continue;
}
final ValueRadioButton b =
new ValueRadioButton(buttonValue, ct.getCategory().getName());
final StringBuilder m = new StringBuilder();
if (buttonValue.getValue() == 0) {
m.append(' ');
} else if (buttonValue.getValue() > 0) {
m.append('+');
}
m.append(buttonValue.getValue());
m.append(' ');
m.append(buttonValue.getName());
b.setText(m.toString());
b.setChecked(prior != null ? buttonValue.getValue() == prior.getValue()
: buttonValue.getValue() == 0);
approvalButtons.add(b);
vp.add(b);
}
body.add(vp);
}
private void display(final PatchSetPublishDetail r) {
descBlock.display(r.getChange(), r.getPatchSetInfo(), r.getAccounts());
if (!displayedOnce) {
if (r.getChange().getStatus().isOpen()) {
initApprovals(r, approvalPanel);
}
}
draftsPanel.clear();
if (!r.getDrafts().isEmpty()) {
draftsPanel.add(new SmallHeading(Util.C.headingPatchComments()));
Panel panel = null;
String priorFile = "";
for (final PatchLineComment c : r.getDrafts()) {
final Patch.Key patchKey = c.getKey().getParentKey();
final String fn = patchKey.get();
if (!fn.equals(priorFile)) {
panel = new FlowPanel();
panel.addStyleName("gerrit-PatchComments");
draftsPanel.add(panel);
panel.add(new PatchLink.SideBySide(fn, patchKey));
priorFile = fn;
}
Label m;
m = new DoubleClickLinkLabel(patchKey);
m.setText(Util.M.lineHeader(c.getLine()));
m.setStyleName("gerrit-LineHeader");
panel.add(m);
m = new DoubleClickLinkLabel(patchKey);
SafeHtml.set(m.getElement(), LineCommentPanel.toSafeHtml(c));
m.setStyleName("gerrit-PatchLineComment");
panel.add(m);
}
}
displayedOnce = true;
}
private void onSend() {
final Map<ApprovalCategory.Id, ApprovalCategoryValue.Id> values =
new HashMap<ApprovalCategory.Id, ApprovalCategoryValue.Id>();
for (final ValueRadioButton b : approvalButtons) {
if (b.isChecked()) {
values.put(b.value.getCategoryId(), b.value.getId());
}
}
PatchUtil.DETAIL_SVC.publishComments(patchSetId, message.getText().trim(),
new HashSet<ApprovalCategoryValue.Id>(values.values()),
new GerritCallback<VoidResult>() {
public void onSuccess(final VoidResult result) {
goChange();
}
});
}
private void goChange() {
final Change.Id ck = patchSetId.getParentKey();
Gerrit.display(Link.toChange(ck), new ChangeScreen(ck));
}
private static class ValueRadioButton extends RadioButton {
final ApprovalCategoryValue value;
ValueRadioButton(final ApprovalCategoryValue v, final String label) {
super(label);
value = v;
}
}
private static class DoubleClickLinkLabel extends Label {
private final Patch.Key patchKey;
DoubleClickLinkLabel(final Patch.Key p) {
patchKey = p;
sinkEvents(Event.ONDBLCLICK);
}
@Override
public void onBrowserEvent(final Event event) {
switch (DOM.eventGetType(event)) {
case Event.ONDBLCLICK:
History.newItem(Link.toPatchSideBySide(patchKey), true);
break;
}
super.onBrowserEvent(event);
}
}
private static final class ScreenCacheToken {
private final PatchSet.Id patchSetId;
ScreenCacheToken(final PatchSet.Id psi) {
patchSetId = psi;
}
@Override
public boolean equals(Object obj) {
if (obj instanceof ScreenCacheToken) {
final ScreenCacheToken c = (ScreenCacheToken) obj;
return patchSetId.equals(c.patchSetId);
}
return false;
}
@Override
public int hashCode() {
return patchSetId.hashCode();
}
}
}