Java tutorial
// Copyright (C) 2015 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.googlesource.gerrit.plugins.labelui.client; import com.google.gerrit.client.GerritUiExtensionPoint; import com.google.gerrit.client.info.AccountInfo; import com.google.gerrit.client.info.AccountInfo.AvatarInfo; import com.google.gerrit.client.info.ChangeInfo; import com.google.gerrit.client.info.ChangeInfo.ApprovalInfo; import com.google.gerrit.client.info.ChangeInfo.LabelInfo; import com.google.gerrit.client.rpc.Natives; import com.google.gerrit.plugin.client.Plugin; import com.google.gerrit.plugin.client.extension.Panel; import com.google.gerrit.plugin.client.rpc.RestApi; import com.google.gwt.core.client.GWT; import com.google.gwt.dom.client.Style; import com.google.gwt.dom.client.Style.Cursor; import com.google.gwt.dom.client.Style.Display; import com.google.gwt.dom.client.Style.TextAlign; import com.google.gwt.dom.client.Style.Unit; import com.google.gwt.resources.client.ImageResource; import com.google.gwt.user.client.rpc.AsyncCallback; import com.google.gwt.user.client.ui.Grid; import com.google.gwt.user.client.ui.HTMLTable.CellFormatter; import com.google.gwt.user.client.ui.HorizontalPanel; import com.google.gwt.user.client.ui.Image; import com.google.gwt.user.client.ui.Label; import com.google.gwt.user.client.ui.VerticalPanel; import com.google.gwt.user.client.ui.Widget; import java.util.HashMap; import java.util.HashSet; import java.util.Map; import java.util.Set; import java.util.TreeMap; import java.util.TreeSet; public class LabelPanel extends VerticalPanel { static class Factory implements Panel.EntryPoint { @Override public void onLoad(Panel panel) { panel.setWidget(new LabelPanel(panel)); } } private final static String COLOR_GREEN = "#060"; private final static String COLOR_RED = "#F00"; LabelPanel(final Panel panel) { new RestApi("accounts").id("self").view(Plugin.get().getPluginName(), "preferences") .get(new AsyncCallback<PreferencesInfo>() { @Override public void onSuccess(PreferencesInfo result) { LabelUIPlugin.refreshDefaultLabelUi(result.ui()); ChangeInfo change = panel.getObject(GerritUiExtensionPoint.Key.CHANGE_INFO).cast(); switch (result.ui()) { case LABEL_USER_TABLE: displayLabelUserTable(change); break; case USER_LABEL_TABLE: displayUserLabelTable(change); break; case DEFAULT: default: return; } } @Override public void onFailure(Throwable caught) { // never invoked } }); } private void displayLabelUserTable(ChangeInfo change) { Set<String> labelNames = getLabelNames(change); Map<String, AccountInfo> users = getUserMap(labelNames, change); Map<Integer, VotableInfo> votable = votable(change); Grid g = createGrid(labelNames.size() + 1, users.size() + 1); int i = 1; for (AccountInfo account : users.values()) { g.setWidget(0, i, createUserWidget(account)); i++; } i = 1; for (String labelName : labelNames) { g.setWidget(i, 0, createLabelLabel(change.label(labelName))); int j = 1; for (AccountInfo account : users.values()) { LabelInfo label = change.label(labelName); ApprovalInfo ai = label.forUser(account._accountId()); g.setWidget(i, j, createLabelValueWidget(label, ai)); if (!votable.get(account._accountId()).isVotable(labelName)) { formatNonVotable(g, i, j); } j++; } i++; } add(g); } private void displayUserLabelTable(ChangeInfo change) { Set<String> labelNames = getLabelNames(change); Map<String, AccountInfo> users = getUserMap(labelNames, change); Map<Integer, VotableInfo> votable = votable(change); Grid g = createGrid(users.size() + 1, labelNames.size() + 1); int i = 1; for (String labelName : labelNames) { g.setWidget(0, i, createLabelLabel(change.label(labelName))); i++; } i = 1; for (AccountInfo account : users.values()) { g.setWidget(i, 0, createUserWidget(account)); int j = 1; for (String labelName : labelNames) { LabelInfo label = change.label(labelName); ApprovalInfo ai = label.forUser(account._accountId()); g.setWidget(i, j, createLabelValueWidget(label, ai)); if (!votable.get(account._accountId()).isVotable(labelName)) { formatNonVotable(g, i, j); } j++; } i++; } add(g); } private static Grid createGrid(int rows, int columns) { Grid g = new Grid(rows, columns); g.addStyleName("infoBlock"); g.addStyleName("changeTable"); CellFormatter fmt = g.getCellFormatter(); fmt.addStyleName(0, 0, "leftMostCell"); fmt.addStyleName(0, 0, "topmost"); for (int c = 1; c < columns; c++) { fmt.addStyleName(0, c, "header"); fmt.addStyleName(0, c, "topmost"); } for (int r = 1; r < rows; r++) { fmt.addStyleName(r, 0, "leftMostCell"); fmt.addStyleName(r, 0, "header"); for (int c = 1; c < columns; c++) { fmt.addStyleName(r, c, "dataCell"); } } for (int c = 0; c < columns; c++) { fmt.addStyleName(rows - 1, c, "bottomheader"); } return g; } private static Set<String> getLabelNames(ChangeInfo change) { return new TreeSet<String>(change.labels()); } private static Map<String, AccountInfo> getUserMap(Set<String> labelNames, ChangeInfo change) { Map<String, AccountInfo> users = new TreeMap<>(); for (String labelName : labelNames) { LabelInfo label = change.label(labelName); for (ApprovalInfo ai : Natives.asList(label.all())) { users.put(ai.name(), ai); } } return users; } private static Widget createLabelValueWidget(LabelInfo label, ApprovalInfo ai) { int accountId = ai._accountId(); String formattedValue = formatValue(ai.value()); String valueText = label.valueText(formattedValue); if (label.approved() != null && label.approved()._accountId() == accountId) { return createImage(LabelUIPlugin.RESOURCES.greenCheck(), valueText); } else if (label.rejected() != null && label.rejected()._accountId() == accountId) { return createImage(LabelUIPlugin.RESOURCES.redNot(), valueText); } else { return createValueLabel(formattedValue, valueText, ai.value()); } } private static Label createLabelLabel(LabelInfo label) { Label l = new Label(label.name()); Style s = l.getElement().getStyle(); s.setCursor(Cursor.DEFAULT); if (label.rejected() != null) { s.setColor(COLOR_RED); l.setTitle("Rejected by " + label.rejected().name()); } else if (label.approved() != null) { s.setColor(COLOR_GREEN); l.setTitle("Approved by " + label.approved().name()); } return l; } private static Widget createUserWidget(AccountInfo account) { HorizontalPanel p = new HorizontalPanel(); Label l = new Label(account.name()); if (account.hasAvatarInfo()) { p.add(createAvatar(account)); l.getElement().getStyle().setMarginTop(3, Unit.PX); } l.getElement().getStyle().setCursor(Cursor.DEFAULT); l.setTitle(formatToolTip(account)); p.add(l); return p; } private static Image createAvatar(AccountInfo account) { int size = 16; AvatarInfo avatar = account.avatar(size); if (avatar == null) { avatar = account.avatar(AvatarInfo.DEFAULT_SIZE); } String url; if (avatar == null) { RestApi api = new RestApi("/accounts/").id(account._accountId()).view("avatar").addParameter("s", size); url = GWT.getHostPageBaseURL() + api.path().substring(1); } else { url = avatar.url(); } Image avatarImage = new Image(url); avatarImage.setSize("", size + "px"); return avatarImage; } private static String formatToolTip(AccountInfo ai) { StringBuilder b = new StringBuilder(); b.append(ai.name()); if (ai.email() != null) { b.append(" <"); b.append(ai.email()); b.append(">"); } return b.toString(); } private static Image createImage(ImageResource imageResource, String valueText) { Image image = new Image(imageResource); if (valueText != null) { image.setTitle(valueText); } center(image); return image; } private static void center(Image image) { Style s = image.getElement().getStyle(); s.setProperty("margin-left", "auto"); s.setProperty("margin-right", "auto"); s.setDisplay(Display.BLOCK); } public static Label createValueLabel(String formattedValue, String valueText, short value) { Label l = new Label(formattedValue); if (valueText != null) { l.setTitle(valueText); } Style s = l.getElement().getStyle(); s.setTextAlign(TextAlign.CENTER); s.setCursor(Cursor.DEFAULT); if (value > 0) { s.setColor(COLOR_GREEN); } else if (value < 0) { s.setColor(COLOR_RED); } else { // make label invisible, we cannot omit it since we need the label to show // a tooltip s.setColor("transparent"); } return l; } private static String formatValue(short value) { if (value < 0) { return Short.toString(value); } else if (value == 0) { return " 0"; } else { return "+" + Short.toString(value); } } private static void formatNonVotable(Grid g, int row, int column) { Widget w = g.getWidget(row, column); g.getCellFormatter().addStyleName(row, column, "header"); w.setTitle("cannot vote on this label"); } private static Map<Integer, VotableInfo> votable(ChangeInfo change) { Map<Integer, VotableInfo> d = new HashMap<>(); for (String name : change.labels()) { LabelInfo label = change.label(name); if (label.all() != null) { for (ApprovalInfo ai : Natives.asList(label.all())) { int id = ai._accountId(); VotableInfo ad = d.get(id); if (ad == null) { ad = new VotableInfo(); d.put(id, ad); } if (ai.hasValue()) { ad.votable(name); } } } } return d; } private static class VotableInfo { private Set<String> votable; void votable(String label) { if (votable == null) { votable = new HashSet<>(); } votable.add(label); } Set<String> votableLabels() { Set<String> s = new HashSet<>(); if (votable != null) { s.addAll(votable); } return s; } boolean isVotable(String label) { return votableLabels().contains(label); } } }