/*
* Zed Attack Proxy (ZAP) and its related class files.
*
* ZAP is an HTTP/HTTPS proxy for assessing web application security.
*
* Copyright 2013 The Zed Attack Proxy Team
*
* 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 org.zaproxy.zap.utils;
import java.text.AttributedCharacterIterator;
import java.text.FieldPosition;
import java.text.Format;
import java.text.NumberFormat;
import java.text.ParseException;
import java.text.ParsePosition;
import javax.swing.JSpinner;
import javax.swing.SpinnerNumberModel;
import javax.swing.text.DefaultFormatterFactory;
import javax.swing.text.NumberFormatter;
public class ZapNumberSpinner extends JSpinner {
private static final long serialVersionUID = -3475273563365395482L;
private int minValue;
private int maxValue;
private int defaultValue;
public ZapNumberSpinner() {
this (0, 0, Integer.MAX_VALUE);
}
public ZapNumberSpinner(int minValue, int defaultValue, int maxValue) {
this.minValue = minValue;
this.maxValue = maxValue;
if (!isValidValue(defaultValue)) {
this.defaultValue = minValue;
} else {
this.defaultValue = defaultValue;
}
setModel(new SpinnerNumberModel(this.defaultValue, minValue, maxValue, 1));
((NumberEditor)getEditor()).getTextField().setFormatterFactory(
new DefaultFormatterFactory(new ZapNumberFormatter(minValue, maxValue)));
}
private boolean isValidValue(int value) {
if (value < minValue || value > maxValue) {
return false;
}
return true;
}
public void changeToDefaultValue() {
super.setValue(Integer.valueOf(defaultValue));
}
@Override
public void setValue(Object value) {
if ((value == null) || !(value instanceof Number)) {
return;
}
setValue(((Number) value).intValue());
}
public void setValue(int value) {
if (!isValidValue(value)) {
return;
}
super.setValue(Integer.valueOf(value));
}
@Override
public Integer getValue() {
return (Integer)super.getValue();
}
public void setEditable(boolean enabled) {
super.setEnabled(enabled);
((NumberEditor)getEditor()).getTextField().setEnabled(true);
((NumberEditor)getEditor()).getTextField().setEditable(enabled);
}
private static class ZapNumberFormatter extends NumberFormatter {
private static final long serialVersionUID = 4888079030453662194L;
private int minValue;
private int maxValue;
public ZapNumberFormatter(int minValue, int maxValue) {
this.minValue = minValue;
this.maxValue = maxValue;
setValueClass(Integer.class);
setMinimum(Integer.valueOf(minValue));
setMaximum(Integer.valueOf(maxValue));
setAllowsInvalid(false);
setFormat(new ZapNumberFormat(minValue));
}
@Override
public Object stringToValue(String text) throws ParseException {
Object o = null;
try {
o = super.stringToValue(text);
} catch (ParseException e) {
boolean throwException = true;
if (e.getMessage().equals("Value not within min/max range")) {
final int value = ((Number)getFormat().parseObject(text)).intValue();
if (value < minValue) {
o = Integer.valueOf(minValue);
throwException = false;
} else if (value > maxValue) {
o = Integer.valueOf(maxValue);
throwException = false;
}
}
if (throwException) {
throw e;
}
}
return o;
}
}
private static class ZapNumberFormat extends Format {
private static final long serialVersionUID = 7864449797301371031L;
private final NumberFormat numberFormat;
private int minValue;
public ZapNumberFormat(int minValue) {
this.minValue = minValue;
this.numberFormat = NumberFormat.getIntegerInstance();
this.numberFormat.setGroupingUsed(false);
}
@Override
public AttributedCharacterIterator formatToCharacterIterator(Object obj) {
return numberFormat.formatToCharacterIterator(obj);
}
@Override
public StringBuffer format(Object obj, StringBuffer toAppendTo, FieldPosition pos) {
return numberFormat.format(obj, toAppendTo, pos);
}
@Override
public Object parseObject(String source, ParsePosition pos) {
if (source.isEmpty()) {
pos.setIndex(1);
return Integer.valueOf(minValue);
}
Object val = numberFormat.parseObject(source, pos);
if (pos.getIndex() != source.length()) {
pos.setErrorIndex(pos.getIndex());
pos.setIndex(0);
}
return val;
}
}
}