Index: trunk/src/org/openstreetmap/josm/Main.java
===================================================================
--- trunk/src/org/openstreetmap/josm/Main.java	(revision 11641)
+++ trunk/src/org/openstreetmap/josm/Main.java	(revision 11642)
@@ -113,4 +113,5 @@
 import org.openstreetmap.josm.tools.Territories;
 import org.openstreetmap.josm.tools.Utils;
+import org.openstreetmap.josm.tools.bugreport.BugReport;
 
 /**
@@ -523,5 +524,11 @@
 
         // This needs to be done before RightAndLefthandTraffic::initialize is called
-        new InitializationTask(tr("Initializing internal boundaries data"), Territories::initialize).call();
+        try {
+            new InitializationTask(tr("Initializing internal boundaries data"), Territories::initialize).call();
+        } catch (JosmRuntimeException e) {
+            // Can happen if the current projection needs NTV2 grid which is not available
+            // In this case we want the user be able to change his projection
+            BugReport.intercept(e).warn();
+        }
 
         // contains several initialization tasks to be executed (in parallel) by a ExecutorService
Index: trunk/src/org/openstreetmap/josm/data/projection/Projections.java
===================================================================
--- trunk/src/org/openstreetmap/josm/data/projection/Projections.java	(revision 11641)
+++ trunk/src/org/openstreetmap/josm/data/projection/Projections.java	(revision 11642)
@@ -50,6 +50,5 @@
  * Class to manage projections.
  *
- * Use this class to query available projection or register new projections
- * from a plugin.
+ * Use this class to query available projection or register new projections from a plugin.
  */
 public final class Projections {
@@ -59,8 +58,14 @@
      */
     public static class ProjectionDefinition {
-        public String code;
-        public String name;
-        public String definition;
-
+        public final String code;
+        public final String name;
+        public final String definition;
+
+        /**
+         * Constructs a new {@code ProjectionDefinition}.
+         * @param code EPSG code
+         * @param name projection name
+         * @param definition projection definition (EPSG format)
+         */
         public ProjectionDefinition(String code, String name, String definition) {
             this.code = code;
@@ -141,16 +146,12 @@
                 Ellipsoid.Bessel1841, 598.1, 73.7, 418.2, 0.202, 0.045, -2.455, 6.7));
 
-        nadgrids.put("BETA2007.gsb", NTV2GridShiftFileWrapper.BETA2007);
-        nadgrids.put("ntf_r93_b.gsb", NTV2GridShiftFileWrapper.ntf_rgf93);
-
-        List<ProjectionDefinition> pds;
         try {
-            pds = loadProjectionDefinitions("resource://data/projection/custom-epsg");
+            inits = new LinkedHashMap<>();
+            for (ProjectionDefinition pd : loadProjectionDefinitions("resource://data/projection/custom-epsg")) {
+                inits.put(pd.code, pd);
+                loadNadgrids(pd.definition);
+            }
         } catch (IOException ex) {
             throw new JosmRuntimeException(ex);
-        }
-        inits = new LinkedHashMap<>();
-        for (ProjectionDefinition pd : pds) {
-            inits.put(pd.code, pd);
         }
 
@@ -166,4 +167,21 @@
     private Projections() {
         // Hide default constructor for utils classes
+    }
+
+    private static void loadNadgrids(String definition) {
+        final String key = CustomProjection.Param.nadgrids.key;
+        if (definition.contains(key)) {
+            try {
+                String nadgridsId = CustomProjection.parseParameterList(definition, true).get(key);
+                if (nadgridsId.startsWith("@")) {
+                    nadgridsId = nadgridsId.substring(1);
+                }
+                if (!"null".equals(nadgridsId) && !nadgrids.containsKey(nadgridsId)) {
+                    nadgrids.put(nadgridsId, new NTV2GridShiftFileWrapper(nadgridsId));
+                }
+            } catch (ProjectionConfigurationException e) {
+                Main.trace(e);
+            }
+        }
     }
 
Index: trunk/src/org/openstreetmap/josm/data/projection/datum/NTV2Datum.java
===================================================================
--- trunk/src/org/openstreetmap/josm/data/projection/datum/NTV2Datum.java	(revision 11641)
+++ trunk/src/org/openstreetmap/josm/data/projection/datum/NTV2Datum.java	(revision 11642)
@@ -2,6 +2,9 @@
 package org.openstreetmap.josm.data.projection.datum;
 
+import java.io.IOException;
+
 import org.openstreetmap.josm.data.coor.LatLon;
 import org.openstreetmap.josm.data.projection.Ellipsoid;
+import org.openstreetmap.josm.tools.JosmRuntimeException;
 
 /**
@@ -10,6 +13,13 @@
 public class NTV2Datum extends AbstractDatum {
 
-    protected NTV2GridShiftFileWrapper nadgrids;
+    private final NTV2GridShiftFileWrapper nadgrids;
 
+    /**
+     * Constructs a new {@code NTV2Datum}.
+     * @param name datum name
+     * @param proj4Id PROJ.4 id
+     * @param ellps ellipsoid
+     * @param nadgrids NTV2 grid shift file wrapper
+     */
     public NTV2Datum(String name, String proj4Id, Ellipsoid ellps, NTV2GridShiftFileWrapper nadgrids) {
         super(name, proj4Id, ellps);
@@ -20,6 +30,10 @@
     public LatLon toWGS84(LatLon ll) {
         NTV2GridShift gs = new NTV2GridShift(ll);
-        nadgrids.getShiftFile().gridShiftForward(gs);
-        return new LatLon(ll.lat() + gs.getLatShiftDegrees(), ll.lon() + gs.getLonShiftPositiveEastDegrees());
+        try {
+            nadgrids.getShiftFile().gridShiftForward(gs);
+            return new LatLon(ll.lat() + gs.getLatShiftDegrees(), ll.lon() + gs.getLonShiftPositiveEastDegrees());
+        } catch (IOException e) {
+            throw new JosmRuntimeException(e);
+        }
     }
 
@@ -27,6 +41,10 @@
     public LatLon fromWGS84(LatLon ll) {
         NTV2GridShift gs = new NTV2GridShift(ll);
-        nadgrids.getShiftFile().gridShiftReverse(gs);
-        return new LatLon(ll.lat() + gs.getLatShiftDegrees(), ll.lon() + gs.getLonShiftPositiveEastDegrees());
+        try {
+            nadgrids.getShiftFile().gridShiftReverse(gs);
+            return new LatLon(ll.lat() + gs.getLatShiftDegrees(), ll.lon() + gs.getLonShiftPositiveEastDegrees());
+        } catch (IOException e) {
+            throw new JosmRuntimeException(e);
+        }
     }
 }
Index: trunk/src/org/openstreetmap/josm/data/projection/datum/NTV2GridShiftFileWrapper.java
===================================================================
--- trunk/src/org/openstreetmap/josm/data/projection/datum/NTV2GridShiftFileWrapper.java	(revision 11641)
+++ trunk/src/org/openstreetmap/josm/data/projection/datum/NTV2GridShiftFileWrapper.java	(revision 11642)
@@ -2,9 +2,10 @@
 package org.openstreetmap.josm.data.projection.datum;
 
+import java.io.File;
 import java.io.IOException;
 import java.io.InputStream;
 
+import org.openstreetmap.josm.Main;
 import org.openstreetmap.josm.io.CachedFile;
-import org.openstreetmap.josm.tools.JosmRuntimeException;
 
 /**
@@ -15,24 +16,4 @@
  */
 public class NTV2GridShiftFileWrapper {
-
-    // CHECKSTYLE.OFF: LineLength
-
-    /**
-     * Used in Germany to convert coordinates between the DHDN (<i>Deutsches Hauptdreiecksnetz</i>)
-     * and ETRS89 (<i>European Terrestrial Reference System 1989</i>) datums.
-     * @see <a href="http://crs.bkg.bund.de/crseu/crs/descrtrans/eu-descrtrans.php?crs_id=REVfREhETiAvIEdLXzM=&op_id=REVfREhETiAoQmVUQSwgMjAwNykgdG8gRVRSUzg5">
-     * Description of Transformation - DE_DHDN (BeTA, 2007) to ETRS89</a>
-     */
-    public static final NTV2GridShiftFileWrapper BETA2007 = new NTV2GridShiftFileWrapper("resource://data/projection/BETA2007.gsb");
-
-    /**
-     * Used in France to convert coordinates between the NTF (<i>Nouvelle triangulation de la France</i>)
-     * and RGF93 (<i>Réseau géodésique français 1993</i>) datums.
-     * @see <a href="http://geodesie.ign.fr/contenu/fichiers/documentation/algorithmes/notice/NT111_V1_HARMEL_TransfoNTF-RGF93_FormatGrilleNTV2.pdf">
-     * [French] Transformation de coordonnées NTF – RGF93 / Format de grille NTv2</a>
-     */
-    public static final NTV2GridShiftFileWrapper ntf_rgf93 = new NTV2GridShiftFileWrapper("resource://data/projection/ntf_r93_b.gsb");
-
-    // CHECKSTYLE.ON: LineLength
 
     private NTV2GridShiftFile instance;
@@ -51,12 +32,37 @@
      * The grid file is only loaded once, when first accessed.
      * @return The NTv2 grid file
+     * @throws IOException if the grid file cannot be found/loaded
      */
-    public NTV2GridShiftFile getShiftFile() {
+    public synchronized NTV2GridShiftFile getShiftFile() throws IOException {
         if (instance == null) {
-            try (CachedFile cf = new CachedFile(gridFileName); InputStream is = cf.getInputStream()) {
-                instance = new NTV2GridShiftFile();
-                instance.loadGridShiftFile(is, false);
-            } catch (IOException e) {
-                throw new JosmRuntimeException(e);
+            File grid = null;
+            // Check is the grid is installed in default PROJ.4 directories
+            for (File dir : Main.platform.getDefaultProj4NadshiftDirectories()) {
+                File file = new File(dir, gridFileName);
+                if (file.exists() && file.isFile()) {
+                    grid = file;
+                    break;
+                }
+            }
+            // If not, search into PROJ_LIB directory
+            if (grid == null) {
+                String projLib = System.getProperty("PROJ_LIB");
+                if (projLib != null && !projLib.isEmpty()) {
+                    File dir = new File(projLib);
+                    if (dir.exists() && dir.isDirectory()) {
+                        File file = new File(dir, gridFileName);
+                        if (file.exists() && file.isFile()) {
+                            grid = file;
+                        }
+                    }
+                }
+            }
+            // If not, retrieve it from JOSM website
+            String location = grid != null ? grid.getAbsolutePath() : (Main.getJOSMWebsite() + "/proj/" + gridFileName);
+            // Try to load grid file
+            try (CachedFile cf = new CachedFile(location); InputStream is = cf.getInputStream()) {
+                NTV2GridShiftFile ntv2 = new NTV2GridShiftFile();
+                ntv2.loadGridShiftFile(is, false);
+                instance = ntv2;
             }
         }
Index: trunk/src/org/openstreetmap/josm/tools/PlatformHook.java
===================================================================
--- trunk/src/org/openstreetmap/josm/tools/PlatformHook.java	(revision 11641)
+++ trunk/src/org/openstreetmap/josm/tools/PlatformHook.java	(revision 11642)
@@ -9,4 +9,5 @@
 import java.security.NoSuchAlgorithmException;
 import java.security.cert.CertificateException;
+import java.util.List;
 
 /**
@@ -172,3 +173,10 @@
      */
     File getDefaultUserDataDirectory();
+
+    /**
+     * Returns the list of platform-dependent default datum shifting directories for the PROJ.4 library.
+     * @return the list of platform-dependent default datum shifting directories for the PROJ.4 library
+     * @since 11642
+     */
+    List<File> getDefaultProj4NadshiftDirectories();
 }
Index: trunk/src/org/openstreetmap/josm/tools/PlatformHookOsx.java
===================================================================
--- trunk/src/org/openstreetmap/josm/tools/PlatformHookOsx.java	(revision 11641)
+++ trunk/src/org/openstreetmap/josm/tools/PlatformHookOsx.java	(revision 11642)
@@ -15,4 +15,5 @@
 import java.lang.reflect.Proxy;
 import java.util.Arrays;
+import java.util.Collections;
 import java.util.List;
 
@@ -382,3 +383,8 @@
                 Main.pref.getJOSMDirectoryBaseName());
     }
+
+    @Override
+    public List<File> getDefaultProj4NadshiftDirectories() {
+        return Collections.emptyList();
+    }
 }
Index: trunk/src/org/openstreetmap/josm/tools/PlatformHookUnixoid.java
===================================================================
--- trunk/src/org/openstreetmap/josm/tools/PlatformHookUnixoid.java	(revision 11641)
+++ trunk/src/org/openstreetmap/josm/tools/PlatformHookUnixoid.java	(revision 11642)
@@ -18,4 +18,5 @@
 import java.nio.file.Paths;
 import java.util.Arrays;
+import java.util.List;
 import java.util.Locale;
 
@@ -433,3 +434,7 @@
     }
 
+    @Override
+    public List<File> getDefaultProj4NadshiftDirectories() {
+        return Arrays.asList(new File("/usr/local/share/proj"), new File("/usr/share/proj"));
+    }
 }
Index: trunk/src/org/openstreetmap/josm/tools/PlatformHookWindows.java
===================================================================
--- trunk/src/org/openstreetmap/josm/tools/PlatformHookWindows.java	(revision 11641)
+++ trunk/src/org/openstreetmap/josm/tools/PlatformHookWindows.java	(revision 11642)
@@ -53,4 +53,5 @@
 import java.security.spec.X509EncodedKeySpec;
 import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.Collection;
 import java.util.Enumeration;
@@ -572,3 +573,8 @@
         return def;
     }
+
+    @Override
+    public List<File> getDefaultProj4NadshiftDirectories() {
+        return Arrays.asList(new File("C:\\PROJ\\NAD"));
+    }
 }
