/*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
* Copyright (c) 2013, MPL CodeInside http://codeinside.ru
*/
package ru.codeinside.gses.vaadin;
import com.vaadin.data.Property;
import com.vaadin.data.Validator;
import com.vaadin.terminal.PaintException;
import com.vaadin.terminal.PaintTarget;
import com.vaadin.ui.ClientWidget;
import com.vaadin.ui.TextField;
import ru.codeinside.gses.vaadin.client.VMaskedTextField;
/**
* Значения null разрешены, на клиентской стороне представлены как "".
* В этом случае предполагается, что данные по маске не заполнены.
*/
@ClientWidget(VMaskedTextField.class)
public class MaskedTextField extends TextField {
private static final long serialVersionUID = -5168618178262041249L;
private String mask;
private MaskValidator maskValidator;
private void init() {
setNullSettingAllowed(true);
setNullRepresentation("");
}
public MaskedTextField() {
init();
}
public MaskedTextField(String caption) {
setCaption(caption);
init();
}
public MaskedTextField(String caption, String mask) {
setCaption(caption);
setMask(mask);
init();
}
public MaskedTextField(Property dataSource) {
super(dataSource);
init();
}
public MaskedTextField(String caption, Property dataSource) {
super(caption, dataSource);
init();
}
public String getMask() {
return mask;
}
/**
* Пустая строка считается не заполненным значением.
*/
@Override
public void setValue(Object newValue) throws ReadOnlyException, ConversionException {
//Logger.getAnonymousLogger().info("update: " + (newValue == null ? "NULL" : newValue.toString()));
String str = newValue == null ? null : newValue.toString();
if (str != null && str.isEmpty()) {
str = null;
}
super.setValue(str);
}
public void setMask(String mask) {
this.mask = mask;
if (maskValidator != null) {
removeValidator(maskValidator);
maskValidator = null;
}
if (mask != null) {
maskValidator = new MaskValidator(mask);
addValidator(maskValidator);
setMaxLength(maskValidator.getLength());
}
requestRepaint();
}
@Override
public void paintContent(PaintTarget target) throws PaintException {
target.addAttribute("mask", mask);
super.paintContent(target);
}
final static class MaskValidator implements Validator {
final static String CFG = "#UL?A*~H";
final String maskCfg;
final String maskSym;
MaskValidator(final String mask) {
final StringBuilder cfgBuilder = new StringBuilder();
final StringBuilder symBuilder = new StringBuilder();
if (mask != null) {
final int length = mask.length();
final int last = length - 1;
for (int i = 0; i < length; i++) {
final char c = mask.charAt(i);
if (CFG.indexOf(c) >= 0) {
cfgBuilder.append(c);
symBuilder.append('_');
} else {
cfgBuilder.append(' ');
if (c != '\'' || i == last) {
symBuilder.append(c);
} else {
i++;
symBuilder.append(mask.charAt(i));
}
}
}
}
this.maskCfg = cfgBuilder.toString();
this.maskSym = symBuilder.toString();
}
public int getLength() {
return maskCfg.length();
}
@Override
public void validate(Object value) throws InvalidValueException {
if (!isValid(value)) {
throw new InvalidValueException("Заполните данные по маске!");
}
}
@Override
public boolean isValid(final Object value) {
return value instanceof String && maskIsValid((String) value);
}
private boolean maskIsValid(final String value) {
if (maskCfg.length() != value.length()) {
return false;
}
final int length = value.length();
for (int i = 0; i < length; i++) {
final char c = value.charAt(i);
switch (maskCfg.charAt(i)) {
case ' ':
if (c != maskSym.charAt(i)) {
return false;
}
break;
case '#':
if (!Character.isDigit(c)) {
return false;
}
break;
case 'U':
if (!Character.isUpperCase(c)) {
return false;
}
break;
case 'L':
if (!Character.isLowerCase(c)) {
return false;
}
break;
case '?':
if (!Character.isLetter(c)) {
return false;
}
break;
case 'A':
if (!Character.isLetterOrDigit(c)) {
return false;
}
break;
case '*':
break;
case '~':
if (c != '-' && c != '+') {
return false;
}
break;
case 'H':
if (!Character.isDigit(c) && !('A' <= c && c <= 'F')) {
return false;
}
break;
default:
return false;
}
}
return true;
}
}
}