package com.revolsys.swing.field;
import java.awt.Dimension;
import java.awt.event.ItemEvent;
import java.awt.event.ItemListener;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Set;
import javax.measure.Measure;
import javax.measure.quantity.Length;
import javax.measure.unit.NonSI;
import javax.measure.unit.SI;
import javax.measure.unit.Unit;
import com.revolsys.datatype.DataType;
import com.revolsys.datatype.DataTypes;
import com.revolsys.swing.EventQueue;
import com.revolsys.swing.component.ValueField;
import com.revolsys.swing.layout.GroupLayouts;
import com.revolsys.swing.listener.EventQueueRunnableListener;
import com.revolsys.swing.listener.WeakFocusListener;
public class LengthMeasureTextField extends ValueField implements ItemListener {
private static final long serialVersionUID = 6402788548005557723L;
private static final Map<Unit<Length>, String> UNITS = new LinkedHashMap<>();
static {
UNITS.put(NonSI.PIXEL, "Pixel");
UNITS.put(SI.METRE, "Metre");
UNITS.put(SI.KILOMETRE, "Kilometre");
UNITS.put(NonSI.FOOT, "Foot");
UNITS.put(NonSI.MILE, "Mile");
}
private Number number;
private Unit<Length> unit;
private final ComboBox<Unit<Length>> unitField;
private final NumberTextField valueField;
public LengthMeasureTextField(final Measure<Length> value, final Unit<Length> unit) {
this(null, value, unit);
}
public LengthMeasureTextField(final String fieldName, final Measure<Length> value) {
this(fieldName, value, value.getUnit());
}
public LengthMeasureTextField(final String fieldName, final Measure<Length> value,
final Unit<Length> unit) {
super(fieldName, value);
setOpaque(false);
this.valueField = new NumberTextField(fieldName, DataTypes.DOUBLE, 6, 2);
if (value == null) {
this.number = 0;
if (unit == null) {
this.unit = NonSI.PIXEL;
} else {
this.unit = unit;
}
} else {
this.number = value.getValue();
this.unit = value.getUnit();
}
this.valueField.setFieldValue(this.number);
final EventQueueRunnableListener updateNumberListener = EventQueue.addAction(this.valueField,
() -> updateNumber());
this.valueField.addFocusListener(new WeakFocusListener(updateNumberListener));
add(this.valueField);
this.valueField.addActionListener(updateNumberListener);
final Set<Unit<Length>> units = UNITS.keySet();
this.unitField = ComboBox.newComboBox("unit", units, UNITS::get);
this.unitField.setMinimumSize(new Dimension(100, 20));
this.unitField.addItemListener(this);
this.unitField.setSelectedItem(this.unit);
add(this.unitField);
GroupLayouts.makeColumns(this, 2, true);
}
public Measure<Length> getLength() {
return Measure.valueOf(this.number.doubleValue(), this.unit);
}
public Number getNumber() {
final String text = this.valueField.getText();
if (text == null) {
return 0.0;
} else {
return Double.parseDouble(text);
}
}
public Unit<Length> getUnit() {
return this.unit;
}
@SuppressWarnings("unchecked")
@Override
public void itemStateChanged(final ItemEvent e) {
if (e.getSource() == this.unitField && e.getStateChange() == ItemEvent.SELECTED) {
final Object selectedItem = this.unitField.getSelectedItem();
if (selectedItem instanceof Unit<?>) {
setUnit((Unit<Length>)selectedItem);
}
}
}
@Override
public void save() {
final Unit<Length> selectedItem = this.unitField.getSelectedItem();
setUnit(selectedItem);
updateNumber();
}
@Override
public void setEditable(final boolean enabled) {
this.valueField.setEditable(enabled);
this.unitField.setEditable(enabled);
}
@Override
public boolean setFieldValue(final Object value) {
final boolean updated = super.setFieldValue(value);
final Measure<Length> fieldValue = getFieldValue();
setNumber(fieldValue.getValue());
setUnit(fieldValue.getUnit());
return updated;
}
public void setNumber(final Number value) {
final Object oldValue = this.number;
this.number = value.doubleValue();
this.valueField.setFieldValue(value);
if (!DataType.equal(oldValue, this.number)) {
firePropertyChange("number", oldValue, this.number);
setFieldValue(Measure.valueOf(this.number.doubleValue(), this.unit));
}
}
public void setText(final CharSequence text) {
if (text == null) {
this.valueField.setText(null);
} else {
this.valueField.setText(text.toString());
}
}
public void setUnit(final Unit<Length> unit) {
final Object oldValue = this.unit;
this.unit = unit;
this.unitField.setSelectedItem(this.unit);
if (!DataType.equal(oldValue, this.unit)) {
firePropertyChange("unit", oldValue, this.unit);
setFieldValue(Measure.valueOf(this.number.doubleValue(), unit));
}
}
@Override
public void updateFieldValue() {
final Unit<Length> selectedItem = this.unitField.getSelectedItem();
setUnit(selectedItem);
updateNumber();
}
public void updateNumber() {
this.valueField.updateFieldValue();
final Object value = this.valueField.getFieldValue();
if (value instanceof Number) {
final Number number = (Number)value;
setNumber(number);
} else {
setNumber(0);
}
}
}