package org.activityinfo.ui.client.component.form.field;
import com.google.gwt.cell.client.ValueUpdater;
import com.google.gwt.dom.client.InputElement;
import com.google.gwt.event.dom.client.KeyUpEvent;
import com.google.gwt.event.dom.client.KeyUpHandler;
import com.google.gwt.event.logical.shared.ValueChangeEvent;
import com.google.gwt.event.logical.shared.ValueChangeHandler;
import com.google.gwt.event.shared.EventBus;
import com.google.gwt.user.client.DOM;
import com.google.gwt.user.client.ui.FlowPanel;
import com.google.gwt.user.client.ui.InlineLabel;
import com.google.gwt.user.client.ui.Widget;
import org.activityinfo.i18n.shared.I18N;
import org.activityinfo.model.resource.ResourceId;
import org.activityinfo.model.type.FieldType;
import org.activityinfo.model.type.number.Quantity;
import org.activityinfo.model.type.number.QuantityType;
import org.activityinfo.promise.Promise;
import org.activityinfo.ui.client.component.form.event.FieldMessageEvent;
import org.activityinfo.ui.client.widget.DoubleBox;
import javax.annotation.Nullable;
import java.text.ParseException;
public class QuantityFieldWidget implements FormFieldWidget<Quantity> {
@Nullable
private final EventBus eventBus;
private final ResourceId fieldId;
private final FlowPanel panel;
private final DoubleBox box;
private final InlineLabel unitsLabel;
public QuantityFieldWidget(final QuantityType type, final ValueUpdater<Quantity> valueUpdater,
@Nullable EventBus eventBus, ResourceId fieldId) {
this.eventBus = eventBus;
this.fieldId = fieldId;
box = new DoubleBox();
box.addValueChangeHandler(new ValueChangeHandler<Double>() {
@Override
public void onValueChange(ValueChangeEvent<Double> event) {
valueUpdater.update(new Quantity(event.getValue(), type.getUnits()));
}
});
box.addKeyUpHandler(new KeyUpHandler() {
@Override
public void onKeyUp(KeyUpEvent event) {
validate(true);
}
});
unitsLabel = new InlineLabel(type.getUnits());
unitsLabel.setStyleName("input-group-addon");
panel = new FlowPanel();
panel.setStyleName("input-group");
panel.add(box);
panel.add(unitsLabel);
}
@Override
public void setReadOnly(boolean readOnly) {
box.setReadOnly(readOnly);
}
@Override
public Promise<Void> setValue(Quantity value) {
box.setValue(value != null ? value.getValue() : null);
return Promise.done();
}
@Override
public void clearValue() {
box.setValue(null);
}
@Override
public void setType(FieldType type) {
unitsLabel.setText(((QuantityType) type).getUnits());
}
@Override
public Widget asWidget() {
return panel;
}
private void validate(boolean onKeyUp) {
if (eventBus == null) {
return;
}
eventBus.fireEvent(new FieldMessageEvent(fieldId, "").setClearMessage(true));
try {
// The value sanitization algorithm is as follows: If the value of the element is not a valid floating-point number,
// then set it to the empty string instead.
// http://stackoverflow.com/questions/18852244/how-to-get-the-raw-value-an-input-type-number-field
// SOLUTION : if we know that user typed something and value is null then browser sanitized it for us -> input invalid
if (onKeyUp && box.getValue() == null) {
eventBus.fireEvent(new FieldMessageEvent(fieldId, invalidErrorMessage()));
}
box.getValueOrThrow();
} catch (ParseException e) {
eventBus.fireEvent(new FieldMessageEvent(fieldId, invalidErrorMessage()));
}
}
private String invalidErrorMessage() {
return I18N.MESSAGES.quantityFieldInvalidValue(15, 2000, 1.5);
}
}