Index: applications/editors/josm/plugins/mapillary/src/org/openstreetmap/josm/plugins/mapillary/MapillaryAbstractImage.java
===================================================================
--- applications/editors/josm/plugins/mapillary/src/org/openstreetmap/josm/plugins/mapillary/MapillaryAbstractImage.java	(revision 32039)
+++ applications/editors/josm/plugins/mapillary/src/org/openstreetmap/josm/plugins/mapillary/MapillaryAbstractImage.java	(revision 32064)
@@ -28,7 +28,7 @@
   private MapillarySequence sequence;
   /** Position of the picture. */
-  public final LatLon latLon;
+  protected LatLon latLon;
   /** Direction of the picture. */
-  public final double ca;
+  protected double ca;
   /** Temporal position of the picture until it is uploaded. */
   public LatLon tempLatLon;
@@ -218,4 +218,8 @@
   }
 
+  public void setCa(final double ca) {
+    this.ca = ca;
+  }
+
   /**
    * Sets the Epoch time when the picture was captured.
@@ -225,4 +229,10 @@
   public void setCapturedAt(final long capturedAt) {
     this.capturedAt = capturedAt;
+  }
+
+  public void setLatLon(final LatLon latLon) {
+    if (latLon != null) {
+      this.latLon = latLon;
+    }
   }
 
Index: applications/editors/josm/plugins/mapillary/src/org/openstreetmap/josm/plugins/mapillary/MapillaryData.java
===================================================================
--- applications/editors/josm/plugins/mapillary/src/org/openstreetmap/josm/plugins/mapillary/MapillaryData.java	(revision 32039)
+++ applications/editors/josm/plugins/mapillary/src/org/openstreetmap/josm/plugins/mapillary/MapillaryData.java	(revision 32064)
@@ -11,6 +11,8 @@
 import org.openstreetmap.josm.Main;
 import org.openstreetmap.josm.data.Bounds;
+import org.openstreetmap.josm.data.coor.LatLon;
 import org.openstreetmap.josm.plugins.mapillary.cache.CacheUtils;
 import org.openstreetmap.josm.plugins.mapillary.gui.MapillaryMainDialog;
+import org.openstreetmap.josm.plugins.mapillary.utils.MapillaryUtils;
 
 /**
@@ -22,5 +24,4 @@
  */
 public class MapillaryData {
-
   private final Set<MapillaryAbstractImage> images;
   /**
@@ -39,9 +40,9 @@
    * Listeners of the class.
    */
-  private final CopyOnWriteArrayList<MapillaryDataListener> listeners = new CopyOnWriteArrayList<>();
+  private final List<MapillaryDataListener> listeners = new CopyOnWriteArrayList<>();
   /**
    * The bounds of the areas for which the pictures have been downloaded.
    */
-  public List<Bounds> bounds;
+  private final List<Bounds> bounds;
 
   /**
@@ -52,4 +53,5 @@
     this.multiSelectedImages = Collections.newSetFromMap(new ConcurrentHashMap<MapillaryAbstractImage, Boolean>());
     this.selectedImage = null;
+    this.bounds = new CopyOnWriteArrayList<>();
 
     // Adds the basic set of listeners.
@@ -82,6 +84,7 @@
       this.images.add(image);
     }
-    if (update)
+    if (update) {
       dataUpdated();
+    }
     fireImagesAdded();
   }
@@ -151,4 +154,8 @@
     }
     Main.map.mapView.repaint();
+  }
+
+  public List<Bounds> getBounds() {
+    return bounds;
   }
 
Index: applications/editors/josm/plugins/mapillary/src/org/openstreetmap/josm/plugins/mapillary/MapillaryImage.java
===================================================================
--- applications/editors/josm/plugins/mapillary/src/org/openstreetmap/josm/plugins/mapillary/MapillaryImage.java	(revision 32039)
+++ applications/editors/josm/plugins/mapillary/src/org/openstreetmap/josm/plugins/mapillary/MapillaryImage.java	(revision 32064)
@@ -6,4 +6,6 @@
 
 import org.openstreetmap.josm.data.coor.LatLon;
+import org.openstreetmap.josm.plugins.mapillary.utils.MapillaryUtils;
+import org.openstreetmap.josm.plugins.mapillary.utils.ValidationUtil;
 
 /**
@@ -33,4 +35,5 @@
   public MapillaryImage(final String key, final LatLon latLon, final double ca) {
     super(latLon, ca);
+    ValidationUtil.throwExceptionForInvalidImgKey(key, true);
     this.key = key;
   }
@@ -105,6 +108,8 @@
   @Override
   public String toString() {
-    return "Image[key=" + this.key + ";lat=" + this.latLon.lat() + ";lon="
-        + this.latLon.lon() + ";ca=" + this.ca + ']';
+    return String.format(
+      "Image[key=%s,lat=%f,lon=%f,ca=%f,location=%s,user=%s,capturedAt=%d]",
+      key, latLon.lat(), latLon.lon(), ca, location, user, capturedAt
+    );
   }
 
Index: applications/editors/josm/plugins/mapillary/src/org/openstreetmap/josm/plugins/mapillary/MapillaryLayer.java
===================================================================
--- applications/editors/josm/plugins/mapillary/src/org/openstreetmap/josm/plugins/mapillary/MapillaryLayer.java	(revision 32039)
+++ applications/editors/josm/plugins/mapillary/src/org/openstreetmap/josm/plugins/mapillary/MapillaryLayer.java	(revision 32064)
@@ -20,5 +20,4 @@
 import java.awt.image.AffineTransformOp;
 import java.awt.image.BufferedImage;
-import java.util.concurrent.CopyOnWriteArrayList;
 
 import javax.swing.AbstractAction;
@@ -101,5 +100,4 @@
     super(tr("Mapillary Images"));
     this.data = new MapillaryData();
-    this.data.bounds = new CopyOnWriteArrayList<>();
   }
 
@@ -291,5 +289,5 @@
       // paint remainder
       g.setPaint(this.hatched);
-      g.fill(MapViewGeometryUtil.getNonDownloadedArea(mv, this.data.bounds));
+      g.fill(MapViewGeometryUtil.getNonDownloadedArea(mv, this.data.getBounds()));
     }
 
Index: applications/editors/josm/plugins/mapillary/src/org/openstreetmap/josm/plugins/mapillary/MapillarySequence.java
===================================================================
--- applications/editors/josm/plugins/mapillary/src/org/openstreetmap/josm/plugins/mapillary/MapillarySequence.java	(revision 32039)
+++ applications/editors/josm/plugins/mapillary/src/org/openstreetmap/josm/plugins/mapillary/MapillarySequence.java	(revision 32064)
@@ -2,7 +2,8 @@
 package org.openstreetmap.josm.plugins.mapillary;
 
-import java.util.ArrayList;
 import java.util.List;
 import java.util.concurrent.CopyOnWriteArrayList;
+
+import org.openstreetmap.josm.plugins.mapillary.utils.ValidationUtil;
 
 /**
@@ -39,6 +40,10 @@
    * @param key       The unique identifier of the sequence.
    * @param createdAt The date the sequence was created.
+   * @throws IllegalArgumentException if the key is invalid
+   *           according to {@link ValidationUtil#validateSequenceKey(String)}
    */
   public MapillarySequence(String key, long createdAt) {
+    ValidationUtil.throwExceptionForInvalidSeqKey(key, true);
+
     this.images = new CopyOnWriteArrayList<>();
     this.key = key;
Index: applications/editors/josm/plugins/mapillary/src/org/openstreetmap/josm/plugins/mapillary/gui/MapillaryFilterDialog.java
===================================================================
--- applications/editors/josm/plugins/mapillary/src/org/openstreetmap/josm/plugins/mapillary/gui/MapillaryFilterDialog.java	(revision 32039)
+++ applications/editors/josm/plugins/mapillary/src/org/openstreetmap/josm/plugins/mapillary/gui/MapillaryFilterDialog.java	(revision 32064)
@@ -4,5 +4,7 @@
 import static org.openstreetmap.josm.tools.I18n.tr;
 
-import java.awt.*;
+import java.awt.FlowLayout;
+import java.awt.GridBagConstraints;
+import java.awt.GridBagLayout;
 import java.awt.event.ActionEvent;
 import java.awt.event.KeyEvent;
Index: applications/editors/josm/plugins/mapillary/src/org/openstreetmap/josm/plugins/mapillary/io/download/MapillaryDownloader.java
===================================================================
--- applications/editors/josm/plugins/mapillary/src/org/openstreetmap/josm/plugins/mapillary/io/download/MapillaryDownloader.java	(revision 32039)
+++ applications/editors/josm/plugins/mapillary/src/org/openstreetmap/josm/plugins/mapillary/io/download/MapillaryDownloader.java	(revision 32064)
@@ -104,5 +104,5 @@
     if (isViewDownloaded(view))
       return;
-    MapillaryLayer.getInstance().getData().bounds.add(view);
+    MapillaryLayer.getInstance().getData().getBounds().add(view);
     getImages(view);
   }
@@ -139,5 +139,5 @@
    */
   private static boolean isInBounds(LatLon latlon) {
-    for (Bounds bounds : MapillaryLayer.getInstance().getData().bounds) {
+    for (Bounds bounds : MapillaryLayer.getInstance().getData().getBounds()) {
       if (bounds.contains(latlon))
         return true;
@@ -162,6 +162,6 @@
     for (Bounds bounds : Main.map.mapView.getEditLayer().data
         .getDataSourceBounds()) {
-      if (!layer.getData().bounds.contains(bounds)) {
-        layer.getData().bounds.add(bounds);
+      if (!layer.getData().getBounds().contains(bounds)) {
+        layer.getData().getBounds().add(bounds);
         MapillaryDownloader.getImages(bounds.getMin(), bounds.getMax());
       }
Index: applications/editors/josm/plugins/mapillary/src/org/openstreetmap/josm/plugins/mapillary/io/download/MapillarySequenceDownloadThread.java
===================================================================
--- applications/editors/josm/plugins/mapillary/src/org/openstreetmap/josm/plugins/mapillary/io/download/MapillarySequenceDownloadThread.java	(revision 32039)
+++ applications/editors/josm/plugins/mapillary/src/org/openstreetmap/josm/plugins/mapillary/io/download/MapillarySequenceDownloadThread.java	(revision 32064)
@@ -127,5 +127,5 @@
 
   private static boolean isInside(MapillaryAbstractImage image) {
-    for (Bounds b : MapillaryLayer.getInstance().getData().bounds) {
+    for (Bounds b : MapillaryLayer.getInstance().getData().getBounds()) {
       if (b.contains(image.getLatLon())) {
         return true;
Index: applications/editors/josm/plugins/mapillary/src/org/openstreetmap/josm/plugins/mapillary/utils/MapillaryURL.java
===================================================================
--- applications/editors/josm/plugins/mapillary/src/org/openstreetmap/josm/plugins/mapillary/utils/MapillaryURL.java	(revision 32039)
+++ applications/editors/josm/plugins/mapillary/src/org/openstreetmap/josm/plugins/mapillary/utils/MapillaryURL.java	(revision 32064)
@@ -26,12 +26,12 @@
   /**
    * Gives you the URL for the online editor of a specific mapillary image.
-   * @param key the key of the image to which you want to link
+   * @param imgKey the key of the image to which you want to link
    * @return the URL of the online editor for the image with the given image key
+   * @throws IllegalArgumentException if the image key is <code>null</code> or invalid according
+   *           to {@link ValidationUtil#validateImageKey(String)}
    */
-  public static URL browseEditURL(String key) {
-    if (key == null || !key.matches("[a-zA-Z0-9\\-_]{22}")) {
-      throw new IllegalArgumentException("Invalid image key");
-    }
-    return string2URL(BASE_WEBSITE_URL + "map/e/" + key);
+  public static URL browseEditURL(String imgKey) {
+    ValidationUtil.throwExceptionForInvalidImgKey(imgKey, false);
+    return string2URL(BASE_WEBSITE_URL + "map/e/" + imgKey);
   }
 
@@ -40,9 +40,9 @@
    * @param key the key of the image to which you want to link
    * @return the URL of the online viewer for the image with the given image key
+   * @throws IllegalArgumentException if the image key is <code>null</code> or invalid according
+   *           to {@link ValidationUtil#validateImageKey(String)}
    */
   public static URL browseImageURL(String key) {
-    if (key == null || !key.matches("[a-zA-Z0-9\\-_]{22}")) {
-      throw new IllegalArgumentException("Invalid image key");
-    }
+    ValidationUtil.throwExceptionForInvalidImgKey(key, false);
     return string2URL(BASE_WEBSITE_URL + "map/im/" + key);
   }
Index: applications/editors/josm/plugins/mapillary/src/org/openstreetmap/josm/plugins/mapillary/utils/ValidationUtil.java
===================================================================
--- applications/editors/josm/plugins/mapillary/src/org/openstreetmap/josm/plugins/mapillary/utils/ValidationUtil.java	(revision 32064)
+++ applications/editors/josm/plugins/mapillary/src/org/openstreetmap/josm/plugins/mapillary/utils/ValidationUtil.java	(revision 32064)
@@ -0,0 +1,67 @@
+package org.openstreetmap.josm.plugins.mapillary.utils;
+
+import org.openstreetmap.josm.tools.I18n;
+
+public final class ValidationUtil {
+  private static final String KEY_REGEX = "[a-zA-Z0-9\\-_]{22}";
+
+  private ValidationUtil() {
+    // Empty private constructor to avoid instantiation
+  }
+
+  /**
+   * Checks if the given image key matches the expected format (22 characters, that can be alphanumeric,
+   * <code>-</code> or <code>_</code>).
+   * @param imgKey the image key that should be validated
+   * @return <code>true</code> iff the image key matches the expected format or if it is <code>null</code>,
+   *           otherwise <code>false</code>.
+   */
+  public static boolean validateImageKey(String imgKey) {
+    return imgKey != null && imgKey.matches(KEY_REGEX);
+  }
+
+  /**
+   * Checks if the given sequence key matches the expected format (same as in {@link #validateImageKey(String)}).
+   * This method is completely the same as {@link #validateImageKey(String)}, but I wanted to separate the validation
+   * of image and sequence keys.
+   * @param seqKey the sequence key that should be validated
+   * @return <code>true</code> iff the sequence key matches the expected format or if it is <code>null</code>,
+   *           otherwise <code>false</code>.
+   * @see {@link #validateImageKey(String)}
+   */
+  public static boolean validateSequenceKey(String seqKey) {
+    return validateImageKey(seqKey);
+  }
+
+  /**
+   * Validates the image key and throws an {@link IllegalArgumentException} when it is not valid.
+   * @param imgKey the image key to validate
+   * @param nullAllowed this controls the behaviour when the key is <code>null</code>. If this variable is
+   *          <code>false</code>, an {@link IllegalArgumentException} is then thrown, otherwise nothing is done.
+   * @see {@link #validateImageKey(String)}
+   */
+  public static void throwExceptionForInvalidImgKey(String imgKey, boolean nullAllowed) {
+    if (!validateSequenceKey(imgKey)) {
+      throw new IllegalArgumentException(I18n.tr("The image key ''{{0}}'' is invalid!", imgKey));
+    }
+    if (!nullAllowed && imgKey == null) {
+      throw new IllegalArgumentException(I18n.tr("The image key must not be null here!"));
+    }
+  }
+
+  /**
+   * Validates the sequence key and throws an {@link IllegalArgumentException} when it is not valid.
+   * @param seqKey the sequence key to validate
+   * @param nullAllowed this controls the behaviour when the key is <code>null</code>. If this variable is
+   *          <code>false</code>, an {@link IllegalArgumentException} is then thrown, otherwise nothing is done.
+   * @see {@link #validateSequenceKey(String)}
+   */
+  public static void throwExceptionForInvalidSeqKey(String seqKey, boolean nullAllowed) {
+    if (!validateSequenceKey(seqKey)) {
+      throw new IllegalArgumentException(I18n.tr("The sequence key ''{{0}}'' is invalid!", seqKey));
+    }
+    if (!nullAllowed && seqKey == null) {
+      throw new IllegalArgumentException(I18n.tr("The sequence key must not be null here!"));
+    }
+  }
+}
