Index: /trunk/src/org/openstreetmap/josm/data/projection/Projections.java
===================================================================
--- /trunk/src/org/openstreetmap/josm/data/projection/Projections.java	(revision 5633)
+++ /trunk/src/org/openstreetmap/josm/data/projection/Projections.java	(revision 5634)
@@ -7,6 +7,9 @@
 import java.io.InputStreamReader;
 import java.util.Collection;
+import java.util.Collections;
 import java.util.HashMap;
+import java.util.HashSet;
 import java.util.Map;
+import java.util.Set;
 import java.util.regex.Matcher;
 import java.util.regex.Pattern;
@@ -113,5 +116,5 @@
 
     public static String getInit(String id) {
-        return inits.get(id.toLowerCase()).b;
+        return inits.get(id.toUpperCase()).b;
     }
 
@@ -132,5 +135,5 @@
                     Matcher m = epsgPattern.matcher(line);
                     if (m.matches()) {
-                        inits.put("epsg:" + m.group(1), Pair.create(name, m.group(2).trim()));
+                        inits.put("EPSG:" + m.group(1), Pair.create(name, m.group(2).trim()));
                     } else {
                         System.err.println("Warning: failed to parse line from the epsg projection definition: "+line);
@@ -144,27 +147,39 @@
     }
 
-    private final static Map<String, ProjectionChoice> allCodesPC = new HashMap<String, ProjectionChoice>();
-    private final static Map<String, Projection> allCodes = new HashMap<String, Projection>();
+    private final static Set<String> allCodes = new HashSet<String>();
+    private final static Map<String, ProjectionChoice> allProjectionChoicesByCode = new HashMap<String, ProjectionChoice>();
+    private final static Map<String, Projection> projectionsByCode_cache = new HashMap<String, Projection>();
 
     static {
-        // FIXME: use {@link #inits}, because it may contain more codes in future
-        // than exposed by the ProjectionChoices
         for (ProjectionChoice pc : ProjectionPreference.getProjectionChoices()) {
             for (String code : pc.allCodes()) {
-                allCodesPC.put(code, pc);
+                allProjectionChoicesByCode.put(code, pc);
             }
         }
+        allCodes.addAll(inits.keySet());
+        allCodes.addAll(allProjectionChoicesByCode.keySet());
     }
 
     public static Projection getProjectionByCode(String code) {
-        Projection p = allCodes.get(code);
-        if (p != null) return p;
-        ProjectionChoice pc = allCodesPC.get(code);
-        if (pc == null) return null;
-        Collection<String> pref = pc.getPreferencesFromCode(code);
-        pc.setPreferences(pref);
-        p = pc.getProjection();
-        allCodes.put(code, p);
-        return p;
+        Projection proj = projectionsByCode_cache.get(code);
+        if (proj != null) return proj;
+        ProjectionChoice pc = allProjectionChoicesByCode.get(code);
+        if (pc != null) {
+            Pair<String, String> pair = inits.get(code);
+            if (pair == null) return null;
+            String name = pair.a;
+            String init = pair.b;
+            proj = new CustomProjection(name, code, init, null);
+        } else {
+            Collection<String> pref = pc.getPreferencesFromCode(code);
+            pc.setPreferences(pref);
+            proj = pc.getProjection();
+        }
+        projectionsByCode_cache.put(code, proj);
+        return proj;
+    }
+
+    public static Collection<String> getAllProjectionCodes() {
+        return Collections.unmodifiableCollection(allCodes);
     }
 
Index: /trunk/src/org/openstreetmap/josm/gui/preferences/projection/CodeProjectionChoice.java
===================================================================
--- /trunk/src/org/openstreetmap/josm/gui/preferences/projection/CodeProjectionChoice.java	(revision 5634)
+++ /trunk/src/org/openstreetmap/josm/gui/preferences/projection/CodeProjectionChoice.java	(revision 5634)
@@ -0,0 +1,239 @@
+// License: GPL. For details, see LICENSE file.
+package org.openstreetmap.josm.gui.preferences.projection;
+
+import static org.openstreetmap.josm.tools.I18n.tr;
+
+import java.awt.Dimension;
+import java.awt.GridBagLayout;
+import java.awt.event.ActionListener;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.List;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+import javax.swing.AbstractListModel;
+import javax.swing.JList;
+import javax.swing.JPanel;
+import javax.swing.JScrollPane;
+import javax.swing.JTextField;
+import javax.swing.event.DocumentEvent;
+import javax.swing.event.DocumentListener;
+import javax.swing.event.ListSelectionEvent;
+import javax.swing.event.ListSelectionListener;
+
+import org.openstreetmap.josm.data.projection.Projection;
+import org.openstreetmap.josm.data.projection.Projections;
+import org.openstreetmap.josm.tools.GBC;
+
+/**
+ * Projection choice that lists all known projects by code.
+ */
+public class CodeProjectionChoice extends AbstractProjectionChoice implements SubPrefsOptions {
+
+    String code;
+
+    public CodeProjectionChoice() {
+        super(tr("By Code (EPSG)"), "core:code");
+    }
+
+    private class CodeSelectionPanel extends JPanel implements ListSelectionListener, DocumentListener {
+
+        public JTextField filter;
+        private ProjectionCodeListModel model;
+        public JList selectionList;
+        List<String> data;
+        List<String> filteredData;
+        final String DEFAULT_CODE = "EPSG:3857";
+        String lastCode = DEFAULT_CODE;
+        ActionListener listener;
+
+        public CodeSelectionPanel(String initialCode, ActionListener listener) {
+            this.listener = listener;
+            data = new ArrayList<String>(Projections.getAllProjectionCodes());
+            Collections.sort(data, new CodeComparator());
+            filteredData = new ArrayList<String>(data);
+            build();
+            setCode(initialCode != null ? initialCode : DEFAULT_CODE);
+            selectionList.addListSelectionListener(this);
+        }
+
+        /**
+         * Comparator that compares the number part of the code numerically.
+         */
+        private class CodeComparator implements Comparator<String> {
+            final Pattern codePattern = Pattern.compile("([a-zA-Z]+):(\\d+)");
+            @Override
+            public int compare(String c1, String c2) {
+                Matcher matcher1 = codePattern.matcher(c1);
+                Matcher matcher2 = codePattern.matcher(c2);
+                if (matcher1.matches()) {
+                    if (matcher2.matches()) {
+                        int cmp1 = matcher1.group(1).compareTo(matcher2.group(1));
+                        if (cmp1 != 0) return cmp1;
+                        int num1 = Integer.parseInt(matcher1.group(2));
+                        int num2 = Integer.parseInt(matcher2.group(2));
+                        return new Integer(num1).compareTo(num2);
+                    } else
+                        return -1;
+                } else if (matcher2.matches())
+                    return 1;
+                return c1.compareTo(c2);
+            }
+        }
+
+        /**
+         * List model for the filtered view on the list of all codes.
+         */
+        private class ProjectionCodeListModel extends AbstractListModel {
+            @Override
+            public int getSize() {
+                return filteredData.size();
+            }
+
+            @Override
+            public Object getElementAt(int index) {
+                if (index >= 0 && index < filteredData.size())
+                    return filteredData.get(index);
+                else
+                    return null;
+            }
+
+            public void fireContentsChanged() {
+                fireContentsChanged(this, 0, this.getSize()-1);
+            }
+        }
+
+        private void build() {
+            filter = new JTextField(30);
+            filter.setColumns(10);
+            filter.getDocument().addDocumentListener(this);
+
+            selectionList = new JList(data.toArray());
+            selectionList.setModel(model = new ProjectionCodeListModel());
+            JScrollPane scroll = new JScrollPane(selectionList);
+            scroll.setPreferredSize(new Dimension(200, 214));
+
+            this.setLayout(new GridBagLayout());
+            this.add(filter, GBC.eol().weight(1.0, 0.0));
+            this.add(scroll, GBC.eol());
+        }
+
+        public String getCode() {
+            int idx = selectionList.getSelectedIndex();
+            if (idx == -1) return lastCode;
+            return filteredData.get(selectionList.getSelectedIndex());
+        }
+
+        public void setCode(String code) {
+            int idx = filteredData.indexOf(code);
+            if (idx != -1) {
+                selectionList.setSelectedIndex(idx);
+                selectionList.ensureIndexIsVisible(idx);
+            }
+        }
+
+        @Override
+        public void valueChanged(ListSelectionEvent e) {
+            listener.actionPerformed(null);
+            lastCode = getCode();
+        }
+
+        @Override
+        public void insertUpdate(DocumentEvent e) {
+            updateFilter();
+        }
+
+        @Override
+        public void removeUpdate(DocumentEvent e) {
+            updateFilter();
+        }
+
+        @Override
+        public void changedUpdate(DocumentEvent e) {
+            updateFilter();
+        }
+
+        private void updateFilter() {
+            filteredData.clear();
+            String filterTxt = filter.getText().trim().toLowerCase();
+            for (String code : data) {
+                if (code.toLowerCase().contains(filterTxt)) {
+                    filteredData.add(code);
+                }
+            }
+            model.fireContentsChanged();
+            int idx =  filteredData.indexOf(lastCode);
+            if (idx == -1) {
+                selectionList.clearSelection();
+                if (selectionList.getModel().getSize() > 0) {
+                    selectionList.ensureIndexIsVisible(0);
+                }
+            } else {
+                selectionList.setSelectedIndex(idx);
+                selectionList.ensureIndexIsVisible(idx);
+            }
+        }
+    }
+
+    @Override
+    public Projection getProjection() {
+        return Projections.getProjectionByCode(code);
+    }
+
+
+    @Override
+    public String getCurrentCode() {
+        // not needed - getProjection() is overridden
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public String getProjectionName() {
+        // not needed - getProjection() is overridden
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public void setPreferences(Collection<String> args) {
+        if (args != null && !args.isEmpty()) {
+            code = args.iterator().next();
+        }
+    }
+
+    @Override
+    public JPanel getPreferencePanel(ActionListener listener) {
+        return new CodeSelectionPanel(code, listener);
+    }
+
+    @Override
+    public Collection<String> getPreferences(JPanel pnl) {
+        CodeSelectionPanel csPanel = (CodeSelectionPanel) pnl;
+        return Collections.singleton(csPanel.getCode());
+    }
+
+    /* don't return all possible codes - this projection choice it too generic */
+    @Override
+    public String[] allCodes() {
+        return new String[0];
+    }
+
+    /* not needed since allCodes() returns empty array */
+    @Override
+    public Collection<String> getPreferencesFromCode(String code) {
+        return null;
+    }
+
+    @Override
+    public boolean showProjectionCode() {
+        return true;
+    }
+
+    @Override
+    public boolean showProjectionName() {
+        return true;
+    }
+
+}
Index: /trunk/src/org/openstreetmap/josm/gui/preferences/projection/CustomProjectionChoice.java
===================================================================
--- /trunk/src/org/openstreetmap/josm/gui/preferences/projection/CustomProjectionChoice.java	(revision 5633)
+++ /trunk/src/org/openstreetmap/josm/gui/preferences/projection/CustomProjectionChoice.java	(revision 5634)
@@ -245,3 +245,8 @@
         return false;
     }
+
+    @Override
+    public boolean showProjectionName() {
+        return false;
+    }
 }
Index: /trunk/src/org/openstreetmap/josm/gui/preferences/projection/ProjectionPreference.java
===================================================================
--- /trunk/src/org/openstreetmap/josm/gui/preferences/projection/ProjectionPreference.java	(revision 5633)
+++ /trunk/src/org/openstreetmap/josm/gui/preferences/projection/ProjectionPreference.java	(revision 5634)
@@ -204,4 +204,9 @@
 
         /************************
+         * Projection by Code.
+         */
+        registerProjectionChoice(new CodeProjectionChoice());
+
+        /************************
          * Custom projection.
          */
@@ -265,4 +270,7 @@
     private Component projectionCodeGlue;
     private JLabel projectionCode = new JLabel();
+    private JLabel projectionNameLabel;
+    private Component projectionNameGlue;
+    private JLabel projectionName = new JLabel();
     private JLabel bounds = new JLabel();
 
@@ -304,4 +312,7 @@
         projPanel.add(projectionCodeGlue = GBC.glue(5,0), GBC.std().fill(GBC.HORIZONTAL));
         projPanel.add(projectionCode, GBC.eop().fill(GBC.HORIZONTAL).insets(0,5,5,5));
+        projPanel.add(projectionNameLabel = new JLabel(tr("Projection name")), GBC.std().insets(25,5,0,5));
+        projPanel.add(projectionNameGlue = GBC.glue(5,0), GBC.std().fill(GBC.HORIZONTAL));
+        projPanel.add(projectionName, GBC.eop().fill(GBC.HORIZONTAL).insets(0,5,5,5));
         projPanel.add(new JLabel(tr("Bounds")), GBC.std().insets(25,5,0,5));
         projPanel.add(GBC.glue(5,0), GBC.std().fill(GBC.HORIZONTAL));
@@ -328,14 +339,20 @@
         Projection proj = pc.getProjection();
         projectionCode.setText(proj.toCode());
+        projectionName.setText(proj.toString());
         Bounds b = proj.getWorldBoundsLatLon();
         CoordinateFormat cf = CoordinateFormat.getDefaultFormat();
         bounds.setText(b.getMin().lonToString(cf)+", "+b.getMin().latToString(cf)+" : "+b.getMax().lonToString(cf)+", "+b.getMax().latToString(cf));
         boolean showCode = true;
+        boolean showName = false;
         if (pc instanceof SubPrefsOptions) {
             showCode = ((SubPrefsOptions) pc).showProjectionCode();
+            showName = ((SubPrefsOptions) pc).showProjectionName();
         }
         projectionCodeLabel.setVisible(showCode);
         projectionCodeGlue.setVisible(showCode);
         projectionCode.setVisible(showCode);
+        projectionNameLabel.setVisible(showName);
+        projectionNameGlue.setVisible(showName);
+        projectionName.setVisible(showName);
     }
 
Index: /trunk/src/org/openstreetmap/josm/gui/preferences/projection/SubPrefsOptions.java
===================================================================
--- /trunk/src/org/openstreetmap/josm/gui/preferences/projection/SubPrefsOptions.java	(revision 5633)
+++ /trunk/src/org/openstreetmap/josm/gui/preferences/projection/SubPrefsOptions.java	(revision 5634)
@@ -11,3 +11,8 @@
      */
     boolean showProjectionCode();
+
+    /**
+     * @return true, if the projection name should be displayed in the top panel
+     */
+    boolean showProjectionName();
 }
