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.event.ActionListener;
007import java.io.Serializable;
008import java.util.Collection;
009import java.util.Collections;
010import java.util.Comparator;
011import java.util.regex.Matcher;
012import java.util.regex.Pattern;
013
014import javax.swing.JPanel;
015
016import org.openstreetmap.josm.data.projection.Projection;
017import org.openstreetmap.josm.data.projection.Projections;
018
019/**
020 * Projection choice that lists all known projects by code.
021 * @since 5634
022 */
023public class CodeProjectionChoice extends AbstractProjectionChoice implements SubPrefsOptions {
024
025    private String code;
026
027    /**
028     * Constructs a new {@code CodeProjectionChoice}.
029     */
030    public CodeProjectionChoice() {
031        super(tr("By Code (EPSG)"), /* NO-ICON */ "core:code");
032    }
033
034    /**
035     * Comparator that compares the number part of the code numerically.
036     */
037    public static class CodeComparator implements Comparator<String>, Serializable {
038        private static final long serialVersionUID = 1L;
039        private final Pattern codePattern = Pattern.compile("([a-zA-Z]+):(\\d+)");
040
041        @Override
042        public int compare(String c1, String c2) {
043            Matcher matcher1 = codePattern.matcher(c1);
044            Matcher matcher2 = codePattern.matcher(c2);
045            if (matcher1.matches()) {
046                if (matcher2.matches()) {
047                    int cmp1 = matcher1.group(1).compareTo(matcher2.group(1));
048                    if (cmp1 != 0)
049                        return cmp1;
050                    int num1 = Integer.parseInt(matcher1.group(2));
051                    int num2 = Integer.parseInt(matcher2.group(2));
052                    return Integer.compare(num1, num2);
053                } else
054                    return -1;
055            } else if (matcher2.matches())
056                return 1;
057            return c1.compareTo(c2);
058        }
059    }
060
061    @Override
062    public Projection getProjection() {
063        return Projections.getProjectionByCode(code);
064    }
065
066    @Override
067    public String getCurrentCode() {
068        // not needed - getProjection() is overridden
069        throw new UnsupportedOperationException();
070    }
071
072    @Override
073    public String getProjectionName() {
074        // not needed - getProjection() is overridden
075        throw new UnsupportedOperationException();
076    }
077
078    @Override
079    public void setPreferences(Collection<String> args) {
080        if (args != null && !args.isEmpty()) {
081            code = args.iterator().next();
082        }
083    }
084
085    @Override
086    public JPanel getPreferencePanel(ActionListener listener) {
087        return new CodeSelectionPanel(code, listener);
088    }
089
090    @Override
091    public Collection<String> getPreferences(JPanel panel) {
092        if (!(panel instanceof CodeSelectionPanel)) {
093            throw new IllegalArgumentException("Unsupported panel: "+panel);
094        }
095        CodeSelectionPanel csPanel = (CodeSelectionPanel) panel;
096        return Collections.singleton(csPanel.getCode());
097    }
098
099    /* don't return all possible codes - this projection choice it too generic */
100    @Override
101    public String[] allCodes() {
102        return new String[0];
103    }
104
105    /* not needed since allCodes() returns empty array */
106    @Override
107    public Collection<String> getPreferencesFromCode(String code) {
108        return null;
109    }
110
111    @Override
112    public boolean showProjectionCode() {
113        return true;
114    }
115
116    @Override
117    public boolean showProjectionName() {
118        return true;
119    }
120
121}