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 31397)
+++ /applications/editors/josm/plugins/mapillary/src/org/openstreetmap/josm/plugins/mapillary/MapillaryData.java	(revision 31398)
@@ -2,8 +2,5 @@
 
 import org.openstreetmap.josm.Main;
-import org.openstreetmap.josm.data.cache.CacheEntry;
-import org.openstreetmap.josm.data.cache.CacheEntryAttributes;
-import org.openstreetmap.josm.data.cache.ICachedLoaderListener;
-import org.openstreetmap.josm.plugins.mapillary.cache.MapillaryCache;
+import org.openstreetmap.josm.plugins.mapillary.cache.Utils;
 
 import java.util.ArrayList;
@@ -19,5 +16,5 @@
  *
  */
-public class MapillaryData implements ICachedLoaderListener {
+public class MapillaryData {
 
   /** Unique instance of the class */
@@ -41,5 +38,5 @@
     multiSelectedImages = new ArrayList<>();
     selectedImage = null;
-    
+
     addListener(MapillaryPlugin.walkAction);
   }
@@ -249,16 +246,12 @@
         // Downloading thumbnails of surrounding pictures.
         if (mapillaryImage.next() != null) {
-          new MapillaryCache(((MapillaryImage) mapillaryImage.next()).getKey(), MapillaryCache.Type.THUMBNAIL).submit(
-              this, false);
+          Utils.downloadPicture(mapillaryImage.next());
           if (mapillaryImage.next().next() != null)
-            new MapillaryCache(((MapillaryImage) mapillaryImage.next().next()).getKey(), MapillaryCache.Type.THUMBNAIL)
-                .submit(this, false);
+            Utils.downloadPicture(mapillaryImage.next().next());
         }
         if (mapillaryImage.previous() != null) {
-          new MapillaryCache(((MapillaryImage) mapillaryImage.previous()).getKey(), MapillaryCache.Type.THUMBNAIL)
-              .submit(this, false);
+          Utils.downloadPicture(mapillaryImage.previous());
           if (mapillaryImage.previous().previous() != null)
-            new MapillaryCache(((MapillaryImage) mapillaryImage.previous().previous()).getKey(),
-                MapillaryCache.Type.THUMBNAIL).submit(this, false);
+            Utils.downloadPicture(mapillaryImage.previous().previous());
         }
       }
@@ -324,13 +317,4 @@
 
   /**
-   * This is empty because it is used just to make sure that certain images have
-   * already been downloaded.
-   */
-  @Override
-  public void loadingFinished(CacheEntry data, CacheEntryAttributes attributes, LoadResult result) {
-    // DO NOTHING
-  }
-
-  /**
    * Returns the amount of images contained by this object.
    *
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 31397)
+++ /applications/editors/josm/plugins/mapillary/src/org/openstreetmap/josm/plugins/mapillary/MapillaryLayer.java	(revision 31398)
@@ -5,5 +5,5 @@
 
 import org.openstreetmap.josm.plugins.mapillary.actions.MapillaryDownloadViewAction;
-import org.openstreetmap.josm.plugins.mapillary.cache.MapillaryCache;
+import org.openstreetmap.josm.plugins.mapillary.cache.Utils;
 import org.openstreetmap.josm.plugins.mapillary.downloads.MapillaryDownloader;
 import org.openstreetmap.josm.plugins.mapillary.gui.MapillaryFilterDialog;
@@ -221,5 +221,5 @@
     super.destroy();
   }
-  
+
   /**
    * Zooms to fit all the {@link MapillaryAbstractImage} icons into the map view.
@@ -505,9 +505,7 @@
     // Predownloads the thumbnails
     if (ret[0] != null)
-      new MapillaryCache(ret[0].getKey(), MapillaryCache.Type.THUMBNAIL)
-          .submit(data, false);
+      Utils.downloadPicture(ret[0]);
     if (ret[1] != null)
-      new MapillaryCache(ret[1].getKey(), MapillaryCache.Type.THUMBNAIL)
-          .submit(data, false);
+      Utils.downloadPicture(ret[1]);
     return ret;
   }
Index: /applications/editors/josm/plugins/mapillary/src/org/openstreetmap/josm/plugins/mapillary/actions/MapillaryWalkAction.java
===================================================================
--- /applications/editors/josm/plugins/mapillary/src/org/openstreetmap/josm/plugins/mapillary/actions/MapillaryWalkAction.java	(revision 31397)
+++ /applications/editors/josm/plugins/mapillary/src/org/openstreetmap/josm/plugins/mapillary/actions/MapillaryWalkAction.java	(revision 31398)
@@ -6,7 +6,5 @@
 import java.awt.event.ActionEvent;
 import java.awt.event.KeyEvent;
-import java.awt.image.BufferedImage;
-import java.util.concurrent.locks.Lock;
-import java.util.concurrent.locks.ReentrantLock;
+import java.util.ArrayList;
 
 import javax.swing.JDialog;
@@ -16,7 +14,5 @@
 import org.openstreetmap.josm.actions.JosmAction;
 import org.openstreetmap.josm.plugins.mapillary.MapillaryAbstractImage;
-import org.openstreetmap.josm.plugins.mapillary.MapillaryData;
 import org.openstreetmap.josm.plugins.mapillary.MapillaryDataListener;
-import org.openstreetmap.josm.plugins.mapillary.MapillaryLayer;
 import org.openstreetmap.josm.plugins.mapillary.MapillaryPlugin;
 import org.openstreetmap.josm.plugins.mapillary.gui.MapillaryMainDialog;
@@ -27,5 +23,5 @@
 /**
  * Walks forward at a given interval.
- * 
+ *
  * @author nokutu
  *
@@ -36,6 +32,9 @@
   private static final long serialVersionUID = 3454223919402245818L;
 
+  private WalkThread thread = null;
+  private ArrayList<WalkListener> listeners = new ArrayList<>();
+
   /**
-   * 
+   *
    */
   public MapillaryWalkAction() {
@@ -57,6 +56,9 @@
     if (pane.getValue() != null
         && (int) pane.getValue() == JOptionPane.OK_OPTION) {
-      new WalkThread((int) dialog.spin.getValue(),
-          dialog.waitForPicture.isSelected()).start();
+      thread = new WalkThread((int) dialog.spin.getValue(),
+          dialog.waitForPicture.isSelected());
+      fireWalkStarted();
+      thread.start();
+      MapillaryMainDialog.getInstance().setMode(MapillaryMainDialog.Mode.WALK);
     }
   }
@@ -65,4 +67,29 @@
   public void imagesAdded() {
     // Nothing
+  }
+
+  /**
+   * Adds a listener.
+   *
+   * @param lis
+   */
+  public void addListener(WalkListener lis) {
+    listeners.add(lis);
+  }
+
+  /**
+   * Removes a listener.
+   *
+   * @param lis
+   */
+  public void removeListener(WalkListener lis) {
+    listeners.remove(lis);
+  }
+
+  private void fireWalkStarted() {
+    if (listeners.isEmpty())
+      return;
+    for (WalkListener lis : listeners)
+      lis.walkStarted(thread);
   }
 
@@ -76,71 +103,4 @@
   }
 
-  private class WalkThread extends Thread implements MapillaryDataListener {
-    private int interval;
-    private MapillaryData data;
-    private Lock lock = new ReentrantLock();
-    private boolean end = false;
-    private boolean waitForPicture;
-    private BufferedImage lastImage;
 
-    private WalkThread(int interval, boolean waitForPicture) {
-      this.interval = interval;
-      this.waitForPicture = waitForPicture;
-      data = MapillaryLayer.getInstance().getMapillaryData();
-      data.addListener(this);
-    }
-
-    @Override
-    public void run() {
-      try {
-        while (!end && data.getSelectedImage().next() != null) {
-          try {
-            synchronized (this) {
-              if (waitForPicture) {
-                while (MapillaryMainDialog.getInstance().mapillaryImageDisplay
-                    .getImage() == lastImage
-                    || MapillaryMainDialog.getInstance().mapillaryImageDisplay
-                        .getImage() == null
-                    || MapillaryMainDialog.getInstance().mapillaryImageDisplay
-                        .getImage().getWidth() < 2048)
-                  wait(100);
-              }
-              wait(interval);
-            }
-            lastImage = MapillaryMainDialog.getInstance().mapillaryImageDisplay
-                .getImage();
-            synchronized (lock) {
-              data.selectNext();
-            }
-          } catch (InterruptedException e) {
-            return;
-          }
-        }
-      } catch (NullPointerException e) {
-        return;
-      }
-    }
-
-    @Override
-    public void interrupt() {
-      end = true;
-      data.removeListener(this);
-      super.interrupt();
-    }
-
-    @Override
-    public void imagesAdded() {
-      // Nothing
-    }
-
-    @Override
-    public void selectedImageChanged(MapillaryAbstractImage oldImage,
-        MapillaryAbstractImage newImage) {
-      if (newImage != oldImage.next()) {
-        synchronized (lock) {
-          interrupt();
-        }
-      }
-    }
-  }
 }
Index: /applications/editors/josm/plugins/mapillary/src/org/openstreetmap/josm/plugins/mapillary/actions/WalkListener.java
===================================================================
--- /applications/editors/josm/plugins/mapillary/src/org/openstreetmap/josm/plugins/mapillary/actions/WalkListener.java	(revision 31398)
+++ /applications/editors/josm/plugins/mapillary/src/org/openstreetmap/josm/plugins/mapillary/actions/WalkListener.java	(revision 31398)
@@ -0,0 +1,19 @@
+package org.openstreetmap.josm.plugins.mapillary.actions;
+
+
+/**
+ * Implemented by those classes that need to listen to the creation of the walk
+ * threads.
+ *
+ * @author nokutu
+ *
+ */
+public interface WalkListener {
+
+  /**
+   * Called when a new walk thread is started.
+   *
+   * @param thread
+   */
+  public void walkStarted(WalkThread thread);
+}
Index: /applications/editors/josm/plugins/mapillary/src/org/openstreetmap/josm/plugins/mapillary/actions/WalkThread.java
===================================================================
--- /applications/editors/josm/plugins/mapillary/src/org/openstreetmap/josm/plugins/mapillary/actions/WalkThread.java	(revision 31398)
+++ /applications/editors/josm/plugins/mapillary/src/org/openstreetmap/josm/plugins/mapillary/actions/WalkThread.java	(revision 31398)
@@ -0,0 +1,140 @@
+package org.openstreetmap.josm.plugins.mapillary.actions;
+
+import java.awt.image.BufferedImage;
+import java.util.concurrent.locks.Lock;
+import java.util.concurrent.locks.ReentrantLock;
+
+import org.openstreetmap.josm.plugins.mapillary.MapillaryAbstractImage;
+import org.openstreetmap.josm.plugins.mapillary.MapillaryData;
+import org.openstreetmap.josm.plugins.mapillary.MapillaryDataListener;
+import org.openstreetmap.josm.plugins.mapillary.MapillaryImage;
+import org.openstreetmap.josm.plugins.mapillary.MapillaryLayer;
+import org.openstreetmap.josm.plugins.mapillary.cache.Utils;
+import org.openstreetmap.josm.plugins.mapillary.gui.MapillaryMainDialog;
+
+/**
+ * Thread containing the walk process.
+ *
+ * @author nokutu
+ *
+ */
+public class WalkThread extends Thread implements MapillaryDataListener {
+  private int interval;
+  private MapillaryData data;
+  private Lock lock = new ReentrantLock();
+  private boolean end = false;
+  private boolean waitForPicture;
+  private BufferedImage lastImage;
+  private volatile boolean paused = false;
+
+  /**
+   * Main constructor.
+   *
+   * @param interval
+   * @param waitForPicture
+   */
+  public WalkThread(int interval, boolean waitForPicture) {
+    this.interval = interval;
+    this.waitForPicture = waitForPicture;
+    data = MapillaryLayer.getInstance().getMapillaryData();
+    data.addListener(this);
+  }
+
+  @Override
+  public void run() {
+    try {
+      while (!end && data.getSelectedImage().next() != null) {
+        MapillaryAbstractImage image = data.getSelectedImage();
+        for (int i = 0; i < 5; i++) {
+          if (image.next() == null)
+            break;
+          image = image.next();
+          Utils.downloadPicture(image);
+        }
+        try {
+          synchronized (this) {
+            if (waitForPicture
+                && data.getSelectedImage() instanceof MapillaryImage) {
+              while (MapillaryMainDialog.getInstance().mapillaryImageDisplay
+                  .getImage() == lastImage
+                  || MapillaryMainDialog.getInstance().mapillaryImageDisplay
+                      .getImage() == null
+                  || MapillaryMainDialog.getInstance().mapillaryImageDisplay
+                      .getImage().getWidth() < 2048)
+                wait(100);
+            } else {
+              while (MapillaryMainDialog.getInstance().mapillaryImageDisplay
+                  .getImage() == lastImage
+                  || MapillaryMainDialog.getInstance().mapillaryImageDisplay
+                      .getImage() == null
+                  || MapillaryMainDialog.getInstance().mapillaryImageDisplay
+                      .getImage().getWidth() < 320)
+                wait(100);
+            }
+            while (paused)
+              wait(100);
+            wait(interval);
+            while (paused)
+              wait(100);
+          }
+          lastImage = MapillaryMainDialog.getInstance().mapillaryImageDisplay
+              .getImage();
+          synchronized (lock) {
+            data.selectNext();
+          }
+        } catch (InterruptedException e) {
+          return;
+        }
+      }
+    } catch (NullPointerException e) {
+      return;
+    }
+    end = true;
+    data.removeListener(this);
+    MapillaryMainDialog.getInstance().setMode(MapillaryMainDialog.Mode.NORMAL);
+  }
+
+  @Override
+  public void interrupt() {
+    end = true;
+    data.removeListener(this);
+    MapillaryMainDialog.getInstance().setMode(MapillaryMainDialog.Mode.NORMAL);
+    super.interrupt();
+  }
+
+  @Override
+  public void imagesAdded() {
+    // Nothing
+  }
+
+  @Override
+  public void selectedImageChanged(MapillaryAbstractImage oldImage,
+      MapillaryAbstractImage newImage) {
+    if (newImage != oldImage.next()) {
+      synchronized (lock) {
+        interrupt();
+      }
+    }
+  }
+
+  /**
+   * Continues with the execution if paused.
+   */
+  public void play() {
+    paused = false;
+  }
+
+  /**
+   * Pauses the execution.
+   */
+  public void pause() {
+    paused = true;
+  }
+
+  /**
+   * Stops the execution.
+   */
+  public void stopWalk() {
+    this.interrupt();
+  }
+}
Index: /applications/editors/josm/plugins/mapillary/src/org/openstreetmap/josm/plugins/mapillary/cache/Utils.java
===================================================================
--- /applications/editors/josm/plugins/mapillary/src/org/openstreetmap/josm/plugins/mapillary/cache/Utils.java	(revision 31398)
+++ /applications/editors/josm/plugins/mapillary/src/org/openstreetmap/josm/plugins/mapillary/cache/Utils.java	(revision 31398)
@@ -0,0 +1,40 @@
+package org.openstreetmap.josm.plugins.mapillary.cache;
+
+import org.openstreetmap.josm.data.cache.CacheEntry;
+import org.openstreetmap.josm.data.cache.CacheEntryAttributes;
+import org.openstreetmap.josm.data.cache.ICachedLoaderListener;
+import org.openstreetmap.josm.plugins.mapillary.MapillaryAbstractImage;
+import org.openstreetmap.josm.plugins.mapillary.MapillaryImage;
+
+/**
+ * Downloads and stores pictures in cache.
+ *
+ * @author nokutu
+ *
+ */
+public class Utils implements ICachedLoaderListener {
+
+  static Utils INSTANCE = new Utils();
+
+
+  /**
+   * Downloads the picture of the given image.
+   *
+   * @param img
+   */
+  public static void downloadPicture(MapillaryAbstractImage img) {
+    if (!(img instanceof MapillaryImage))
+      throw new IllegalArgumentException();
+    new MapillaryCache(((MapillaryImage) img).getKey(), MapillaryCache.Type.THUMBNAIL).submit(
+        INSTANCE, false);
+    new MapillaryCache(((MapillaryImage) img).getKey(), MapillaryCache.Type.FULL_IMAGE).submit(
+        INSTANCE, false);
+  }
+
+  @Override
+  public void loadingFinished(CacheEntry arg0, CacheEntryAttributes arg1,
+      LoadResult arg2) {
+    // Nothing
+  }
+
+}
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 31397)
+++ /applications/editors/josm/plugins/mapillary/src/org/openstreetmap/josm/plugins/mapillary/gui/MapillaryFilterDialog.java	(revision 31398)
@@ -20,7 +20,5 @@
 import javax.swing.JSpinner;
 import javax.swing.JTextField;
-import javax.swing.SpinnerModel;
 import javax.swing.SpinnerNumberModel;
-import javax.swing.SwingUtilities;
 
 import org.openstreetmap.josm.Main;
Index: /applications/editors/josm/plugins/mapillary/src/org/openstreetmap/josm/plugins/mapillary/gui/MapillaryMainDialog.java
===================================================================
--- /applications/editors/josm/plugins/mapillary/src/org/openstreetmap/josm/plugins/mapillary/gui/MapillaryMainDialog.java	(revision 31397)
+++ /applications/editors/josm/plugins/mapillary/src/org/openstreetmap/josm/plugins/mapillary/gui/MapillaryMainDialog.java	(revision 31398)
@@ -28,5 +28,9 @@
 import org.openstreetmap.josm.plugins.mapillary.MapillaryImportedImage;
 import org.openstreetmap.josm.plugins.mapillary.MapillaryLayer;
+import org.openstreetmap.josm.plugins.mapillary.MapillaryPlugin;
+import org.openstreetmap.josm.plugins.mapillary.actions.WalkListener;
+import org.openstreetmap.josm.plugins.mapillary.actions.WalkThread;
 import org.openstreetmap.josm.plugins.mapillary.cache.MapillaryCache;
+import org.openstreetmap.josm.tools.ImageProvider;
 import org.openstreetmap.josm.tools.Shortcut;
 
@@ -62,4 +66,21 @@
   /** Button used to jump to the image following the blue line */
   public final SideButton blueButton = new SideButton(new blueAction());
+
+  private final SideButton playButton = new SideButton(new playAction());
+  private final SideButton pauseButton = new SideButton(new pauseAction());
+  private final SideButton stopButton = new SideButton(new stopAction());
+
+  /**
+   * Buttons mode.
+   *
+   * @author nokutu
+   *
+   */
+  public static enum Mode {
+    /** Standard mode to view pictures. */
+    NORMAL,
+    /** Mode when in walk. */
+    WALK;
+  }
 
   private JPanel buttonsPanel;
@@ -119,4 +140,28 @@
       INSTANCE = new MapillaryMainDialog();
     return INSTANCE;
+  }
+
+  /**
+   * @param mode
+   */
+  public void setMode(Mode mode) {
+    switch (mode) {
+      case NORMAL:
+        createLayout(
+            mapillaryImageDisplay,
+            Arrays.asList(new SideButton[] { blueButton, previousButton,
+                nextButton, redButton }),
+            Main.pref.getBoolean("mapillary.reverse-buttons"));
+        break;
+      case WALK:
+        createLayout(
+            mapillaryImageDisplay,
+            Arrays.asList(new SideButton[] { playButton, pauseButton,
+                stopButton }),
+            Main.pref.getBoolean("mapillary.reverse-buttons"));
+        break;
+    }
+    disableAllButtons();
+
   }
 
@@ -284,5 +329,5 @@
    *
    */
-  class nextPictureAction extends AbstractAction {
+  private class nextPictureAction extends AbstractAction {
 
     private static final long serialVersionUID = 3023827221453154340L;
@@ -305,5 +350,5 @@
    *
    */
-  class previousPictureAction extends AbstractAction {
+  private class previousPictureAction extends AbstractAction {
 
     private static final long serialVersionUID = -6420511632957956012L;
@@ -327,5 +372,5 @@
    *
    */
-  class redAction extends AbstractAction {
+  private class redAction extends AbstractAction {
 
     private static final long serialVersionUID = -6480229431481386376L;
@@ -351,5 +396,5 @@
    *
    */
-  class blueAction extends AbstractAction {
+  private class blueAction extends AbstractAction {
 
     private static final long serialVersionUID = 6250690644594703314L;
@@ -366,4 +411,78 @@
         MapillaryData.getInstance().setSelectedImage(MapillaryLayer.BLUE, true);
       }
+    }
+  }
+
+  private class stopAction extends AbstractAction implements WalkListener {
+
+    private static final long serialVersionUID = -6561451575815789198L;
+
+    private WalkThread thread;
+
+    public stopAction() {
+      putValue(NAME, tr("Stop"));
+      putValue(SHORT_DESCRIPTION, tr("Stops the walk."));
+      putValue(SMALL_ICON, ImageProvider.get("dialogs/mapillaryStop.png"));
+      MapillaryPlugin.walkAction.addListener(this);
+    }
+
+    @Override
+    public void actionPerformed(ActionEvent e) {
+      if (thread != null)
+        thread.stopWalk();
+    }
+
+    @Override
+    public void walkStarted(WalkThread thread) {
+      this.thread = thread;
+    }
+  }
+
+  private class playAction extends AbstractAction implements WalkListener {
+
+    private static final long serialVersionUID = -17943404752082788L;
+    private WalkThread thread;
+
+    public playAction() {
+      putValue(NAME, tr("Play"));
+      putValue(SHORT_DESCRIPTION, tr("Continues with the paused walk."));
+      putValue(SMALL_ICON, ImageProvider.get("dialogs/mapillaryPlay.png"));
+      MapillaryPlugin.walkAction.addListener(this);
+    }
+
+    @Override
+    public void actionPerformed(ActionEvent e) {
+      if (thread != null)
+        thread.play();
+    }
+
+    @Override
+    public void walkStarted(WalkThread thread) {
+      if (thread != null)
+        this.thread = thread;
+    }
+  }
+
+  private class pauseAction extends AbstractAction implements WalkListener {
+
+    private static final long serialVersionUID = 4400240686337741192L;
+
+    private WalkThread thread;
+
+    public pauseAction() {
+      putValue(NAME, tr("Pause"));
+      putValue(SHORT_DESCRIPTION, tr("Pauses the walk."));
+      putValue(SMALL_ICON, ImageProvider.get("dialogs/mapillaryPause.png"));
+      MapillaryPlugin.walkAction.addListener(this);
+    }
+
+    @Override
+    public void actionPerformed(ActionEvent e) {
+      thread.pause();
+    }
+
+    @Override
+    public void walkStarted(WalkThread thread) {
+      this.thread = thread;
     }
   }
