// Copyright (C) 2010 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.admin; import com.google.gerrit.client.Gerrit; import com.google.gerrit.client.rpc.GerritCallback; import com.google.gerrit.client.ui.AccountGroupSuggestOracle; import com.google.gerrit.client.ui.HintTextBox; import com.google.gerrit.client.ui.RPCSuggestOracle; import com.google.gerrit.common.data.ApprovalType; import com.google.gerrit.common.data.ProjectDetail; import com.google.gerrit.reviewdb.AccountGroup; import com.google.gerrit.reviewdb.ApprovalCategory; import com.google.gerrit.reviewdb.ApprovalCategoryValue; import com.google.gerrit.reviewdb.Project; import com.google.gerrit.reviewdb.RefRight; import com.google.gwt.event.dom.client.ChangeEvent; import com.google.gwt.event.dom.client.ChangeHandler; import com.google.gwt.event.dom.client.ClickEvent; import com.google.gwt.event.dom.client.ClickHandler; import com.google.gwt.event.dom.client.KeyCodes; import com.google.gwt.event.dom.client.KeyPressEvent; import com.google.gwt.event.dom.client.KeyPressHandler; import com.google.gwt.event.logical.shared.HasValueChangeHandlers; import com.google.gwt.event.logical.shared.ValueChangeEvent; import com.google.gwt.event.logical.shared.ValueChangeHandler; import com.google.gwt.event.shared.HandlerRegistration; 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.Grid; import com.google.gwt.user.client.ui.ListBox; import com.google.gwt.user.client.ui.SuggestBox; public class AccessRightEditor extends Composite implements HasValueChangeHandlers<ProjectDetail> { private Project.NameKey projectKey; private ListBox catBox; private HintTextBox nameTxt; private SuggestBox nameSug; private HintTextBox referenceTxt; private ListBox topBox; private ListBox botBox; private Button addBut; private Button clearBut; public AccessRightEditor(final Project.NameKey key) { projectKey = key; initWidgets(); initCategories(); final Grid grid = new Grid(5, 2); grid.setText(0, 0, Util.C.columnApprovalCategory() + ":"); grid.setWidget(0, 1, catBox); grid.setText(1, 0, Util.C.columnGroupName() + ":"); grid.setWidget(1, 1, nameSug); grid.setText(2, 0, Util.C.columnRefName() + ":"); grid.setWidget(2, 1, referenceTxt); grid.setText(3, 0, Util.C.columnRightRange() + ":"); grid.setWidget(3, 1, topBox); grid.setText(4, 0, ""); grid.setWidget(4, 1, botBox); FlowPanel fp = new FlowPanel(); fp.setStyleName(Gerrit.RESOURCES.css().addSshKeyPanel()); fp.add(grid); fp.add(addBut); fp.add(clearBut); initWidget(fp); } protected void initWidgets() { catBox = new ListBox(); catBox.addChangeHandler(new ChangeHandler() { @Override public void onChange(final ChangeEvent event) { updateCategorySelection(); } }); nameTxt = new HintTextBox(); nameSug = new SuggestBox(new RPCSuggestOracle( new AccountGroupSuggestOracle()), nameTxt); nameTxt.setVisibleLength(50); nameTxt.setHintText(Util.C.defaultAccountGroupName()); referenceTxt = new HintTextBox(); referenceTxt.setVisibleLength(50); referenceTxt.setText(""); referenceTxt.addKeyPressHandler(new KeyPressHandler() { @Override public void onKeyPress(KeyPressEvent event) { if (event.getCharCode() == KeyCodes.KEY_ENTER) { doAddNewRight(); } } }); topBox = new ListBox(); botBox = new ListBox(); addBut = new Button(Util.C.buttonAddProjectRight()); addBut.addClickHandler(new ClickHandler() { @Override public void onClick(final ClickEvent event) { doAddNewRight(); } }); clearBut = new Button(Util.C.buttonClearProjectRight()); clearBut.addClickHandler(new ClickHandler() { @Override public void onClick(final ClickEvent event) { clear(); } }); } protected void initCategories() { for (final ApprovalType at : Gerrit.getConfig().getApprovalTypes() .getApprovalTypes()) { final ApprovalCategory c = at.getCategory(); catBox.addItem(c.getName(), c.getId().get()); } for (final ApprovalType at : Gerrit.getConfig().getApprovalTypes() .getActionTypes()) { final ApprovalCategory c = at.getCategory(); if (Gerrit.getConfig().getWildProject().equals(projectKey) && !c.getId().canBeOnWildProject()) { // Giving out control of the WILD_PROJECT to other groups beyond // Administrators is dangerous. Having control over WILD_PROJECT // is about the same as having Administrator access as users are // able to affect grants in all projects on the system. // continue; } catBox.addItem(c.getName(), c.getId().get()); } if (catBox.getItemCount() > 0) { catBox.setSelectedIndex(0); updateCategorySelection(); } } public void enableForm(final boolean on) { final boolean canAdd = on && catBox.getItemCount() > 0; addBut.setEnabled(canAdd); clearBut.setEnabled(canAdd); nameTxt.setEnabled(canAdd); referenceTxt.setEnabled(canAdd); catBox.setEnabled(canAdd); topBox.setEnabled(canAdd); botBox.setEnabled(canAdd); } public void clear() { setCat(null); setName(""); setReference(""); } public void load(final RefRight right, final AccountGroup group) { final ApprovalType atype = Gerrit.getConfig().getApprovalTypes().getApprovalType( right.getApprovalCategoryId()); setCat(atype != null ? atype.getCategory().getName() : right.getApprovalCategoryId().get() ); setName(group.getName()); setReference(right.getRefPatternForDisplay()); setRange(atype.getCategory().isRange() ? atype.getValue(right.getMinValue()) : null, atype.getValue(right.getMaxValue()) ); } protected void doAddNewRight() { final ApprovalType at = getApprovalType(); ApprovalCategoryValue min = getMin(at); ApprovalCategoryValue max = getMax(at); if (at == null || min == null || max == null) { return; } final String groupName = nameSug.getText(); if ("".equals(groupName) || Util.C.defaultAccountGroupName().equals(groupName)) { return; } final String refPattern = referenceTxt.getText(); addBut.setEnabled(false); Util.PROJECT_SVC.addRight(projectKey, at.getCategory().getId(), groupName, refPattern, min.getValue(), max.getValue(), new GerritCallback<ProjectDetail>() { public void onSuccess(final ProjectDetail result) { addBut.setEnabled(true); nameSug.setText(""); referenceTxt.setText(""); ValueChangeEvent.fire(AccessRightEditor.this, result); } @Override public void onFailure(final Throwable caught) { addBut.setEnabled(true); super.onFailure(caught); } }); } protected void updateCategorySelection() { final ApprovalType at = getApprovalType(); if (at == null || at.getValues().isEmpty()) { topBox.setEnabled(false); botBox.setEnabled(false); referenceTxt.setEnabled(false); addBut.setEnabled(false); clearBut.setEnabled(false); return; } updateRanges(at); } protected void updateRanges(final ApprovalType at) { ApprovalCategoryValue min = null, max = null, last = null; topBox.clear(); botBox.clear(); for(final ApprovalCategoryValue v : at.getValues()) { final int nval = v.getValue(); final String vStr = String.valueOf(nval); String nStr = vStr + ": " + v.getName(); if (nval > 0) { nStr = "+" + nStr; } topBox.addItem(nStr, vStr); botBox.addItem(nStr, vStr); if (min == null || nval < 0) { min = v; } else if (max == null && nval > 0) { max = v; } last = v; } if (max == null) { max = last; } if (ApprovalCategory.READ.equals(at.getCategory().getId())) { // Special case; for READ the most logical range is just // +1 READ, so assume that as the default for both. min = max; } if (! at.getCategory().isRange()) { max = null; } setRange(min, max); } protected void setCat(final String cat) { if (cat == null) { catBox.setSelectedIndex(0); } else { setSelectedText(catBox, cat); } updateCategorySelection(); } protected void setName(final String name) { nameTxt.setText(name); } protected void setReference(final String ref) { referenceTxt.setText(ref); } protected void setRange(final ApprovalCategoryValue min, final ApprovalCategoryValue max) { if (min == null || max == null) { botBox.setVisible(false); if (max != null) { setSelectedValue(topBox, "" + max.getValue()); return; } } else { botBox.setVisible(true); setSelectedValue(botBox, "" + max.getValue()); } setSelectedValue(topBox, "" + min.getValue()); } private ApprovalType getApprovalType() { int idx = catBox.getSelectedIndex(); if (idx < 0) { return null; } return Gerrit.getConfig().getApprovalTypes().getApprovalType( new ApprovalCategory.Id(catBox.getValue(idx))); } public ApprovalCategoryValue getMin(ApprovalType at) { final ApprovalCategoryValue top = getTop(at); final ApprovalCategoryValue bot = getBot(at); if (bot == null) { for (final ApprovalCategoryValue v : at.getValues()) { if (0 <= v.getValue() && v.getValue() <= top.getValue()) { return v; } } return at.getMin(); } if (top.getValue() > bot.getValue()) { return bot; } return top; } public ApprovalCategoryValue getMax(ApprovalType at) { final ApprovalCategoryValue top = getTop(at); final ApprovalCategoryValue bot = getBot(at); if (bot == null || bot.getValue() < top.getValue()) { return top; } return bot; } protected ApprovalCategoryValue getTop(ApprovalType at) { int idx = topBox.getSelectedIndex(); if (idx < 0) { return null; } return at.getValue(Short.parseShort(topBox.getValue(idx))); } protected ApprovalCategoryValue getBot(ApprovalType at) { int idx = botBox.getSelectedIndex(); if (idx < 0 || ! botBox.isVisible()) { return null; } return at.getValue(Short.parseShort(botBox.getValue(idx))); } public HandlerRegistration addValueChangeHandler( final ValueChangeHandler<ProjectDetail> handler) { return addHandler(handler, ValueChangeEvent.getType()); } public static boolean setSelectedText(ListBox box, String text) { if (text == null) { return false; } for (int i =0 ; i < box.getItemCount(); i++) { if (text.equals(box.getItemText(i))) { box.setSelectedIndex(i); return true; } } return false; } public static boolean setSelectedValue(ListBox box, String value) { if (value == null) { return false; } for (int i =0 ; i < box.getItemCount(); i++) { if (value.equals(box.getValue(i))) { box.setSelectedIndex(i); return true; } } return false; } }