package com.revolsys.swing.map.component;
import java.awt.Dimension;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.ItemEvent;
import java.awt.event.ItemListener;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.lang.ref.Reference;
import java.lang.ref.WeakReference;
import java.util.Arrays;
import java.util.Vector;
import javax.measure.quantity.Quantity;
import javax.measure.unit.Unit;
import javax.swing.ComboBoxModel;
import javax.swing.DefaultComboBoxModel;
import javax.swing.JComboBox;
import javax.swing.SwingConstants;
import com.revolsys.datatype.DataTypes;
import com.revolsys.geometry.cs.CoordinateSystem;
import com.revolsys.geometry.cs.GeographicCoordinateSystem;
import com.revolsys.geometry.model.BoundingBox;
import com.revolsys.geometry.model.GeometryFactory;
import com.revolsys.swing.field.FunctionStringConverter;
import com.revolsys.swing.map.MapPanel;
import com.revolsys.swing.parallel.Invoke;
import com.revolsys.util.Property;
import com.revolsys.util.number.Doubles;
public class SelectMapUnitsPerPixel extends JComboBox
implements ItemListener, PropertyChangeListener, ActionListener {
private static ComboBoxModel GEOGRAPHIC_MODEL = new DefaultComboBoxModel(
new Vector<>(Arrays.asList(2.0, 1.0, 0.5, 0.2, 0.1, 0.05, 0.02, 0.01, 0.005, 0.002, 0.001,
0.0005, 0.0002, 0.0001, 0.00005, 0.00002, 0.00001, 0.000005, 0.000002, 0.000001, 0.0000005,
0.0000002, 0.0000001)));
private static ComboBoxModel PROJECTED_MODEL = new DefaultComboBoxModel(
new Vector<>(Arrays.asList(500000.0, 200000.0, 100000.0, 50000.0, 20000.0, 10000.0, 5000.0,
2000.0, 1000.0, 500.0, 200.0, 100.0, 50.0, 20.0, 10.0, 5.0, 2.0, 1.0, 0.5, 0.2, 0.1, 0.05,
0.02, 0.01, 0.005, 0.002, 0.001)));
private static final long serialVersionUID = 1L;
private final Reference<MapPanel> map;
private String unitString = "m";
public SelectMapUnitsPerPixel(final MapPanel map) {
super(PROJECTED_MODEL);
this.map = new WeakReference<>(map);
setEditable(true);
final FunctionStringConverter renderer = new FunctionStringConverter(this::format);
renderer.setHorizontalAlignment(SwingConstants.RIGHT);
final SelectMapScaleEditor editor = new SelectMapScaleEditor(getEditor(), renderer);
setEditor(editor);
setRenderer(renderer);
addItemListener(this);
addActionListener(this);
Property.addListener(map, this);
final Dimension size = new Dimension(120, 22);
setPreferredSize(size);
setMaximumSize(size);
setToolTipText("Resolution (m/pixel)");
}
@Override
public void actionPerformed(final ActionEvent e) {
try {
final Object item = getSelectedItem();
String string = DataTypes.toString(item);
string = string.replaceAll("([^0-9\\.])+", "");
final double unitsPerPixel = Double.parseDouble(string);
final MapPanel map = getMap();
if (map != null) {
map.setUnitsPerPixel(unitsPerPixel);
}
} catch (final Throwable t) {
}
}
public String format(final Object value) {
if (value instanceof Number) {
final Number number = (Number)value;
double doubleValue = number.doubleValue();
final ComboBoxModel<?> model = getModel();
if (model == PROJECTED_MODEL) {
doubleValue = Doubles.makePrecise(1000, doubleValue);
} else {
doubleValue = Doubles.makePrecise(10000000, doubleValue);
}
return Doubles.toString(doubleValue) + this.unitString;
} else {
return "Unknown";
}
}
public MapPanel getMap() {
return this.map.get();
}
@Override
public void itemStateChanged(final ItemEvent e) {
final MapPanel map = getMap();
if (map != null) {
if (e.getStateChange() == ItemEvent.SELECTED) {
double unitsPerPixel = map.getUnitsPerPixel();
final Object value = e.getItem();
if (value instanceof Double) {
unitsPerPixel = (Double)value;
}
map.setUnitsPerPixel(unitsPerPixel);
}
}
}
@Override
public void propertyChange(final PropertyChangeEvent event) {
final MapPanel map = getMap();
if (map != null) {
final String propertyName = event.getPropertyName();
if ("scale".equals(propertyName) || "unitsPerPixel".equals(propertyName)) {
final double unitsPerPixel = map.getUnitsPerPixel();
if (unitsPerPixel > 0 && !Double.isInfinite(unitsPerPixel)
&& !Double.isNaN(unitsPerPixel)) {
Invoke.later(() -> setSelectedItem(unitsPerPixel));
}
} else if ("boundingBox".equals(propertyName)) {
String toolTip;
final BoundingBox boundingBox = map.getBoundingBox();
ComboBoxModel model;
if (boundingBox == null) {
toolTip = "Map Resolution (m/pixel)";
model = PROJECTED_MODEL;
} else {
final GeometryFactory geometryFactory = boundingBox.getGeometryFactory();
final CoordinateSystem coordinateSystem = geometryFactory.getCoordinateSystem();
if (coordinateSystem instanceof GeographicCoordinateSystem) {
model = GEOGRAPHIC_MODEL;
} else {
model = PROJECTED_MODEL;
}
final Unit<Quantity> unit = coordinateSystem.getUnit();
this.unitString = unit.toString();
toolTip = "Map Resolution (" + unit + "/pixel)";
}
} else if ("geometryFactory".equals(propertyName)) {
String toolTip;
final GeometryFactory geometryFactory = map.getGeometryFactory();
ComboBoxModel model;
if (geometryFactory == null) {
toolTip = "Map Resolution (m/pixel)";
model = PROJECTED_MODEL;
} else {
final CoordinateSystem coordinateSystem = geometryFactory.getCoordinateSystem();
if (geometryFactory.isGeographics()) {
model = GEOGRAPHIC_MODEL;
} else {
model = PROJECTED_MODEL;
}
final Unit<Quantity> unit = coordinateSystem.getUnit();
this.unitString = unit.toString();
toolTip = "Map Resolution (" + unit + "/pixel)";
}
Invoke.later(() -> {
setToolTipText(toolTip);
if (model != getModel()) {
setModel(model);
}
});
}
}
}
}