001// License: GPL. For details, see LICENSE file.
002package org.openstreetmap.josm.gui.preferences.projection;
003
004import static org.openstreetmap.josm.tools.I18n.tr;
005
006import java.awt.GridBagLayout;
007import java.awt.event.ActionListener;
008import java.util.ArrayList;
009import java.util.Arrays;
010import java.util.Collection;
011import java.util.List;
012
013import javax.swing.ButtonGroup;
014import javax.swing.JLabel;
015import javax.swing.JPanel;
016import javax.swing.JRadioButton;
017
018import org.openstreetmap.josm.data.projection.proj.TransverseMercator.Hemisphere;
019import org.openstreetmap.josm.tools.GBC;
020import org.openstreetmap.josm.tools.Logging;
021
022/**
023 * ProjectionChoice for UTM.
024 * <p>
025 * @see <a href="https://en.wikipedia.org/wiki/Universal_Transverse_Mercator_coordinate_system">UTM</a>
026 */
027public class UTMProjectionChoice extends ListProjectionChoice {
028
029    private static final Hemisphere DEFAULT_HEMISPHERE = Hemisphere.North;
030
031    private Hemisphere hemisphere;
032
033    private static final List<String> cbEntries = new ArrayList<>();
034    static {
035        for (int i = 1; i <= 60; i++) {
036            cbEntries.add(Integer.toString(i));
037        }
038    }
039
040    /**
041     * Constructs a new {@code UTMProjectionChoice}.
042     */
043    public UTMProjectionChoice() {
044        super(tr("UTM"), /* NO-ICON */ "core:utm", cbEntries.toArray(new String[0]), tr("UTM Zone"));
045    }
046
047    private class UTMPanel extends CBPanel {
048
049        public JRadioButton north, south;
050
051        UTMPanel(String[] entries, int initialIndex, String label, ActionListener listener) {
052            super(entries, initialIndex, label, listener);
053
054            north = new JRadioButton();
055            north.setSelected(hemisphere == Hemisphere.North);
056            south = new JRadioButton();
057            south.setSelected(hemisphere == Hemisphere.South);
058
059            ButtonGroup group = new ButtonGroup();
060            group.add(north);
061            group.add(south);
062
063            JPanel bPanel = new JPanel(new GridBagLayout());
064
065            bPanel.add(new JLabel(tr("North")), GBC.std().insets(5, 5, 0, 5));
066            bPanel.add(north, GBC.std().fill(GBC.HORIZONTAL));
067            bPanel.add(GBC.glue(1, 0), GBC.std().fill(GBC.HORIZONTAL));
068            bPanel.add(new JLabel(tr("South")), GBC.std().insets(5, 5, 0, 5));
069            bPanel.add(south, GBC.std().fill(GBC.HORIZONTAL));
070            bPanel.add(GBC.glue(1, 1), GBC.eol().fill(GBC.BOTH));
071
072            this.add(new JLabel(tr("Hemisphere")), GBC.std().insets(5, 5, 0, 5));
073            this.add(GBC.glue(1, 0), GBC.std().fill(GBC.HORIZONTAL));
074            this.add(bPanel, GBC.eop().fill(GBC.HORIZONTAL));
075            this.add(GBC.glue(1, 1), GBC.eol().fill(GBC.BOTH));
076
077            if (listener != null) {
078                north.addActionListener(listener);
079                south.addActionListener(listener);
080            }
081        }
082    }
083
084    @Override
085    public JPanel getPreferencePanel(ActionListener listener) {
086        return new UTMPanel(entries, index, label, listener);
087    }
088
089    @Override
090    public String getCurrentCode() {
091        int zone = index + 1;
092        int code = 32600 + zone + (hemisphere == Hemisphere.South ? 100 : 0);
093        return "EPSG:" + Integer.toString(code);
094    }
095
096    @Override
097    public String getProjectionName() {
098        return tr("UTM");
099    }
100
101    @Override
102    public Collection<String> getPreferences(JPanel panel) {
103        if (!(panel instanceof UTMPanel)) {
104            throw new IllegalArgumentException("Unsupported panel: "+panel);
105        }
106        UTMPanel p = (UTMPanel) panel;
107        int idx = p.prefcb.getSelectedIndex();
108        Hemisphere hem = p.south.isSelected() ? Hemisphere.South : Hemisphere.North;
109        return Arrays.asList(indexToZone(idx), hem.toString());
110    }
111
112    @Override
113    public String[] allCodes() {
114        List<String> projections = new ArrayList<>(60*4);
115        for (int zone = 1; zone <= 60; zone++) {
116            for (Hemisphere hem : Hemisphere.values()) {
117                projections.add("EPSG:" + (32600 + zone + (hem == Hemisphere.South ? 100 : 0)));
118            }
119        }
120        return projections.toArray(new String[0]);
121    }
122
123    @Override
124    public Collection<String> getPreferencesFromCode(String code) {
125
126        if (code.startsWith("EPSG:326") || code.startsWith("EPSG:327")) {
127            try {
128                Hemisphere hem = code.charAt(7) == '6' ? Hemisphere.North : Hemisphere.South;
129                String zonestring = code.substring(8);
130                int zoneval = Integer.parseInt(zonestring);
131                if (zoneval > 0 && zoneval <= 60)
132                    return Arrays.asList(zonestring, hem.toString());
133            } catch (NumberFormatException e) {
134                Logging.warn(e);
135            }
136        }
137        return null;
138    }
139
140    @Override
141    public void setPreferences(Collection<String> args) {
142        super.setPreferences(args);
143        Hemisphere hem = DEFAULT_HEMISPHERE;
144
145        if (args != null) {
146            String[] array = args.toArray(new String[0]);
147
148            if (array.length > 1) {
149                hem = Hemisphere.valueOf(array[1]);
150            }
151        }
152        this.hemisphere = hem;
153    }
154
155    @Override
156    protected String indexToZone(int idx) {
157        return Integer.toString(idx + 1);
158    }
159
160    @Override
161    protected int zoneToIndex(String zone) {
162        try {
163            return Integer.parseInt(zone) - 1;
164        } catch (NumberFormatException e) {
165            Logging.warn(e);
166        }
167        return defaultIndex;
168    }
169}