<html><head><meta name="color-scheme" content="light dark"></head><body><pre style="word-wrap: break-word; white-space: pre-wrap;">/*
 * Used by Choice and occasionally NRCS mode
 * (ChoiceHandler.java)
 * (NRCSHandler.java)
 */
package usda.weru.weps.location.chooser;

import java.awt.Color;
import java.awt.Component;
import java.awt.EventQueue;
import java.awt.event.ItemEvent;
import java.awt.event.ItemListener;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.text.DecimalFormat;
import java.text.NumberFormat;
import javax.measure.Quantity;
import javax.measure.quantity.Length;
import javax.measure.Unit;
import javax.swing.DefaultComboBoxModel;
import javax.swing.JLabel;
import javax.swing.JList;
import javax.swing.JPanel;
import javax.swing.ListCellRenderer;
import usda.weru.gis.latlong.LatLong;
import usda.weru.gis.GISUtil;
import usda.weru.weps.location.Station;

/**
 *
 * @author Joseph Levin &lt;joelevin@weru.ksu.edu&gt;
 */
public class StationChoiceView extends JPanel implements StationViewInterface,
        ListCellRenderer&lt;Object&gt;, ItemListener, PropertyChangeListener {

    private static final long serialVersionUID = 1L;

    private StationChooser c_chooser;
    private final InternalComboBoxModel c_model;
    private final NumberFormat c_format = new DecimalFormat("0.0");

    /** Creates new form StationNearestView */
    public StationChoiceView() {
        initComponents();
        combo.setRenderer(this);
        c_model = new InternalComboBoxModel();
        combo.setModel(c_model);

    }

    /** This method is called from within the constructor to
     * initialize the form.
     * WARNING: Do NOT modify this code. The content of this method is
     * always regenerated by the Form Editor.
     */
    @SuppressWarnings("unchecked")
    // &lt;editor-fold defaultstate="collapsed" desc="Generated Code"&gt;//GEN-BEGIN:initComponents
    private void initComponents() {

        renderer = new javax.swing.JPanel();
        stationName = new javax.swing.JLabel();
        stationDistance = new javax.swing.JLabel();
        combo = new javax.swing.JComboBox&lt;Station&gt;();

        stationName.setFont(stationName.getFont().deriveFont(stationName.getFont().getStyle() &amp; ~java.awt.Font.BOLD));
        stationName.setText("displayName");
        stationName.setPreferredSize(null);

        stationDistance.setFont(stationDistance.getFont().deriveFont(stationDistance.getFont().getStyle() &amp; ~java.awt.Font.BOLD));
        stationDistance.setText("100");

        javax.swing.GroupLayout rendererLayout = new javax.swing.GroupLayout(renderer);
        renderer.setLayout(rendererLayout);
        rendererLayout.setHorizontalGroup(
            rendererLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, rendererLayout.createSequentialGroup()
                .addComponent(stationName, javax.swing.GroupLayout.DEFAULT_SIZE, 161, Short.MAX_VALUE)
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                .addComponent(stationDistance)
                .addContainerGap())
        );
        rendererLayout.setVerticalGroup(
            rendererLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addComponent(stationDistance, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
            .addComponent(stationName, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
        );

        javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this);
        this.setLayout(layout);
        layout.setHorizontalGroup(
            layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addComponent(combo, 0, 165, Short.MAX_VALUE)
        );
        layout.setVerticalGroup(
            layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addComponent(combo, javax.swing.GroupLayout.PREFERRED_SIZE, 20, javax.swing.GroupLayout.PREFERRED_SIZE)
        );
    }// &lt;/editor-fold&gt;//GEN-END:initComponents

    @Override
    public Component install(StationChooser chooser) {
        c_chooser = chooser;
        enqueueUpdate();
        updateDistance();
        c_chooser.addPropertyChangeListener(this);
        return this;
    }

    @Override
    public void uninstall(StationChooser chooser) {
        JLabel subLabel = c_chooser.getSubLabel();
        if (subLabel != null) {
            subLabel.setText("");
        }
        c_chooser.removePropertyChangeListener(this);
        c_chooser = null;
    }

    @Override
    public void propertyChange(PropertyChangeEvent evt) {
        switch (evt.getPropertyName()) {
            case StationChooser.PROP_DISTANCE_UNITS:
                //only need to repaint because the cell renderer will calculate the distance on each paint
                repaint();
                updateDistance();
                break;
            case StationChooser.PROP_LATLONG:
                //only need to repaint because the cell renderer will calculate the distance on each paint
                repaint();
                break;
            case StationChooser.PROP_STATION_CHOICES:
                //the choices changed, upate the model
                enqueueUpdate();
                break;
            case StationChooser.PROP_SELECTED_STATION:
                //the selected station changed'
                setStation(c_chooser.getSelectedStation());
                break;
            case StationChooser.PROP_DISTANCE:
                updateDistance();
                break;
        }

    }

    private void updateDistance() {
        JLabel subLabel = c_chooser.getSubLabel();
        if (subLabel != null) {
            Quantity&lt;Length&gt; distance = c_chooser.getDistance();
            Unit&lt;Length&gt; unit = c_chooser.getDistanceUnits();
            if (distance != null &amp;&amp; unit != null) {
                Double distanceNum = distance.to(unit).getValue().doubleValue();
                subLabel.setText("&lt; " + c_format.format(distanceNum) + " " + unit.toString());
            } else {
                subLabel.setText("");
            }
        }

    }

    public void setStation(Station station) {
        assert EventQueue.isDispatchThread();
        setItemListenerActive(false);
        if (station != null) {
            combo.setSelectedItem(station);
        } else {
            combo.setSelectedIndex(-1);
        }
        setItemListenerActive(true);
    }

   @Override
    public void setEnabled(boolean enabled) {
        super.setEnabled(enabled);
        combo.setEnabled(enabled);
    }

    private void setItemListenerActive(boolean active) {
        if (active) {
            combo.addItemListener(this);
        } else {
            combo.removeItemListener(this);
        }
    }

    @Override
    public void itemStateChanged(ItemEvent e) {
        if (ItemEvent.SELECTED == e.getStateChange()) {
            c_chooser.setSelectedStation((Station) combo.getSelectedItem());
        }
    }

    private synchronized void enqueueUpdate() {
        c_model.update();
    }
    // Variables declaration - do not modify//GEN-BEGIN:variables
    private javax.swing.JComboBox&lt;Station&gt; combo;
    private javax.swing.JPanel renderer;
    private javax.swing.JLabel stationDistance;
    private javax.swing.JLabel stationName;
    // End of variables declaration//GEN-END:variables

    @Override
    @SuppressWarnings("rawtypes")
    public Component getListCellRendererComponent(JList list, Object value, int index,
            boolean isSelected, boolean cellHasFocus) {
        if (value != null &amp;&amp; value instanceof Station) {
            Station station = (Station) value;

            if (isSelected) {
                renderer.setBackground(list.getSelectionBackground());
            } else {
                // list is coming up gray, so use the combo
                renderer.setBackground(Color.WHITE);
            }

            stationName.setText(station.getDisplayName());

            double distanceMeters = 0;
            //TODO: can the chooser actually ever be null?
            if (c_chooser != null &amp;&amp; c_chooser.getLatLong() != null) {
                //TODO: perhaps cache the distances?  Is this a costly calculation?
                LatLong latlong1 = c_chooser.getLatLong();
                LatLong latlong2 = station.getLatLong();

                Quantity&lt;Length&gt; distance = GISUtil.distanceBetweenCoordinates(latlong1, latlong2);

                if (distance != null &amp;&amp; c_chooser.getDistanceUnits() != null) {
                    distanceMeters = distance.to(c_chooser.getDistanceUnits()).getValue().doubleValue();
                    stationDistance.setText(c_format.format(distanceMeters));
                } else {
                    stationDistance.setText("");
                }
            } else {
                stationDistance.setText("");
            }
        } else {
            stationName.setText("");
            stationDistance.setText("");
        }

        if (index == -1) {
            Unit units = c_chooser.getDistanceUnits();
            stationDistance.setText(stationDistance.getText() + " " + (units != null ? units.toString() : ""));
        }
        return renderer;
    }

    private class InternalComboBoxModel extends DefaultComboBoxModel&lt;Station&gt; {

        private static final long serialVersionUID = 1L;

        public InternalComboBoxModel() {
        }

        public void update() {
            setItemListenerActive(false);
            try {
                combo.setEnabled(false);
                removeAllElements();
                for (Station station : c_chooser.getStationChoices()) {
                    addElement(station);
                }

                // The station model always dictates what is selected.
                setSelectedItem(c_chooser.getSelectedStation());

            } finally {
                combo.setEnabled(true);
                setItemListenerActive(true);
            }

        }
    }
}
</pre></body></html>