blob: 4fdd06722e70d18c70aa4b88639671d2b1adbb0d [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.account;
import com.google.gerrit.client.ConfirmationCallback;
import com.google.gerrit.client.ConfirmationDialog;
import com.google.gerrit.client.ErrorDialog;
import com.google.gerrit.client.Gerrit;
import com.google.gerrit.client.rpc.GerritCallback;
import com.google.gerrit.client.rpc.NativeString;
import com.google.gerrit.client.rpc.RestApi;
import com.google.gerrit.client.ui.OnEditEnabler;
import com.google.gerrit.extensions.client.AccountFieldName;
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.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.TextBox;
import com.google.gwtexpui.clippy.client.CopyableLabel;
import com.google.gwtexpui.globalkey.client.NpTextBox;
import com.google.gwtexpui.safehtml.client.SafeHtmlBuilder;
class UsernameField extends Composite {
// If these regular expressions are modified the same modifications should be done to the
// corresponding regular expressions in the
// com.google.gerrit.server.account.externalids.ExternalId class.
private static final String USER_NAME_PATTERN_FIRST_REGEX = "[a-zA-Z0-9]";
private static final String USER_NAME_PATTERN_REST_REGEX = "[a-zA-Z0-9.!#$%&’*+=?^_`\\{|\\}~@-]";
private CopyableLabel userNameLbl;
private NpTextBox userNameTxt;
private Button setUserName;
UsernameField() {
String user = Gerrit.getUserAccount().username();
userNameLbl = new CopyableLabel(user != null ? user : "");
userNameLbl.setStyleName(Gerrit.RESOURCES.css().accountUsername());
if (user != null || !canEditUserName()) {
initWidget(userNameLbl);
} else {
final FlowPanel body = new FlowPanel();
initWidget(body);
setStyleName(Gerrit.RESOURCES.css().usernameField());
userNameTxt = new NpTextBox();
userNameTxt.addKeyPressHandler(new UserNameValidator());
userNameTxt.addStyleName(Gerrit.RESOURCES.css().accountUsername());
userNameTxt.setVisibleLength(16);
userNameTxt.addKeyPressHandler(
new KeyPressHandler() {
@Override
public void onKeyPress(KeyPressEvent event) {
if (event.getNativeEvent().getKeyCode() == KeyCodes.KEY_ENTER) {
confirmSetUserName();
}
}
});
setUserName = new Button(Util.C.buttonSetUserName());
setUserName.setVisible(canEditUserName());
setUserName.setEnabled(false);
setUserName.addClickHandler(
new ClickHandler() {
@Override
public void onClick(ClickEvent event) {
confirmSetUserName();
}
});
new OnEditEnabler(setUserName, userNameTxt);
userNameLbl.setVisible(false);
body.add(userNameLbl);
body.add(userNameTxt);
body.add(setUserName);
}
}
private boolean canEditUserName() {
return Gerrit.info().auth().canEdit(AccountFieldName.USER_NAME);
}
private void confirmSetUserName() {
new ConfirmationDialog(
Util.C.confirmSetUserNameTitle(),
new SafeHtmlBuilder().append(Util.C.confirmSetUserName()),
new ConfirmationCallback() {
@Override
public void onOk() {
doSetUserName();
}
})
.center();
}
private void doSetUserName() {
if (!canEditUserName()) {
return;
}
enableUI(false);
String newName = userNameTxt.getText();
if ("".equals(newName)) {
newName = null;
}
final String newUserName = newName;
AccountApi.setUsername(
"self",
newUserName,
new GerritCallback<NativeString>() {
@Override
public void onSuccess(NativeString result) {
Gerrit.getUserAccount().username(newUserName);
userNameLbl.setText(newUserName);
userNameLbl.setVisible(true);
userNameTxt.setVisible(false);
setUserName.setVisible(false);
}
@Override
public void onFailure(Throwable caught) {
enableUI(true);
if (RestApi.isExpected(422 /* Unprocessable Entity */)) {
new ErrorDialog(Util.C.invalidUserName()).center();
} else {
super.onFailure(caught);
}
}
});
}
private void enableUI(boolean on) {
userNameTxt.setEnabled(on);
setUserName.setEnabled(on);
}
private static final class UserNameValidator implements KeyPressHandler {
@Override
public void onKeyPress(KeyPressEvent event) {
final char code = event.getCharCode();
final int nativeCode = event.getNativeEvent().getKeyCode();
switch (nativeCode) {
case KeyCodes.KEY_ALT:
case KeyCodes.KEY_BACKSPACE:
case KeyCodes.KEY_CTRL:
case KeyCodes.KEY_DELETE:
case KeyCodes.KEY_DOWN:
case KeyCodes.KEY_END:
case KeyCodes.KEY_ENTER:
case KeyCodes.KEY_ESCAPE:
case KeyCodes.KEY_HOME:
case KeyCodes.KEY_LEFT:
case KeyCodes.KEY_PAGEDOWN:
case KeyCodes.KEY_PAGEUP:
case KeyCodes.KEY_RIGHT:
case KeyCodes.KEY_SHIFT:
case KeyCodes.KEY_TAB:
case KeyCodes.KEY_UP:
// Allow these, even if one of their assigned codes is
// identical to an ASCII character we do not want to
// allow in the box.
//
// We still want to let the user move around the input box
// with their arrow keys, or to move between fields using tab.
// Invalid characters introduced will be caught through the
// server's own validation of the input data.
//
break;
default:
final TextBox box = (TextBox) event.getSource();
final String re;
if (box.getCursorPos() == 0) {
re = USER_NAME_PATTERN_FIRST_REGEX;
} else {
re = USER_NAME_PATTERN_REST_REGEX;
}
if (!String.valueOf(code).matches("^" + re + "$")) {
event.preventDefault();
event.stopPropagation();
}
}
}
}
}