Index: trunk/src/org/openstreetmap/josm/actions/AboutAction.java
===================================================================
--- trunk/src/org/openstreetmap/josm/actions/AboutAction.java	(revision 10374)
+++ trunk/src/org/openstreetmap/josm/actions/AboutAction.java	(revision 10375)
@@ -7,5 +7,4 @@
 import java.awt.Dimension;
 import java.awt.GridBagLayout;
-import java.awt.Image;
 import java.awt.event.ActionEvent;
 import java.awt.event.KeyEvent;
@@ -16,5 +15,4 @@
 
 import javax.swing.BorderFactory;
-import javax.swing.ImageIcon;
 import javax.swing.JLabel;
 import javax.swing.JPanel;
Index: trunk/src/org/openstreetmap/josm/gui/MapStatus.java
===================================================================
--- trunk/src/org/openstreetmap/josm/gui/MapStatus.java	(revision 10374)
+++ trunk/src/org/openstreetmap/josm/gui/MapStatus.java	(revision 10375)
@@ -387,5 +387,5 @@
 
                         // Do nothing, if required data is missing
-                        if (ms.mousePos == null || mv.center == null) {
+                        if (ms.mousePos == null || mv.getCenter() == null) {
                             continue;
                         }
@@ -868,5 +868,5 @@
             @Override
             public void mouseMoved(MouseEvent e) {
-                if (mv.center == null)
+                if (mv.getCenter() == null)
                     return;
                 // Do not update the view if ctrl is pressed.
Index: trunk/src/org/openstreetmap/josm/gui/MapView.java
===================================================================
--- trunk/src/org/openstreetmap/josm/gui/MapView.java	(revision 10374)
+++ trunk/src/org/openstreetmap/josm/gui/MapView.java	(revision 10375)
@@ -936,4 +936,5 @@
      */
     public boolean prepareToDraw() {
+        updateLocationState();
         if (initialViewport != null) {
             zoomTo(initialViewport);
Index: trunk/src/org/openstreetmap/josm/gui/MapViewState.java
===================================================================
--- trunk/src/org/openstreetmap/josm/gui/MapViewState.java	(revision 10374)
+++ trunk/src/org/openstreetmap/josm/gui/MapViewState.java	(revision 10375)
@@ -2,9 +2,11 @@
 package org.openstreetmap.josm.gui;
 
+import java.awt.Container;
 import java.awt.Point;
+import java.awt.geom.AffineTransform;
 import java.awt.geom.Point2D;
 import java.awt.geom.Point2D.Double;
 
-import javax.swing.SwingUtilities;
+import javax.swing.JComponent;
 
 import org.openstreetmap.josm.Main;
@@ -14,4 +16,5 @@
 import org.openstreetmap.josm.data.coor.LatLon;
 import org.openstreetmap.josm.data.projection.Projection;
+import org.openstreetmap.josm.gui.download.DownloadDialog;
 
 /**
@@ -20,7 +23,7 @@
  * @since 10343
  */
-public class MapViewState {
-
-    private final Projection projection = Main.getProjection();
+public final class MapViewState {
+
+    private final Projection projection;
 
     private final int viewWidth;
@@ -34,18 +37,72 @@
     private final EastNorth topLeft;
 
-    private final NavigatableComponent navigatableComponent;
-
-    /**
-     * Create a new {@link MapViewState} object for the given map view.
-     * @param navigatableComponent The view.
-     */
-    public MapViewState(NavigatableComponent navigatableComponent) {
-        this.navigatableComponent = navigatableComponent;
-        viewWidth = navigatableComponent.getWidth();
-        viewHeight = navigatableComponent.getHeight();
-
-        scale = navigatableComponent.getScale();
-        EastNorth center = navigatableComponent.getCenter();
-        topLeft = new EastNorth(center.east() - viewWidth / 2.0 * scale, center.north() + viewHeight / 2.0 * scale);
+    private final Point topLeftOnScreen;
+    private final Point topLeftInWindow;
+
+    /**
+     * Create a new {@link MapViewState}
+     * @param projection The projection to use.
+     * @param viewWidth The view width
+     * @param viewHeight The view height
+     * @param scale The scale to use
+     * @param topLeft The top left corner in east/north space.
+     */
+    private MapViewState(Projection projection, int viewWidth, int viewHeight, double scale, EastNorth topLeft) {
+        this.projection = projection;
+        this.scale = scale;
+        this.topLeft = topLeft;
+
+        this.viewWidth = viewWidth;
+        this.viewHeight = viewHeight;
+        topLeftInWindow = new Point(0, 0);
+        topLeftOnScreen = new Point(0, 0);
+    }
+
+    private MapViewState(EastNorth topLeft, MapViewState mapViewState) {
+        this.projection = mapViewState.projection;
+        this.scale = mapViewState.scale;
+        this.topLeft = topLeft;
+
+        viewWidth = mapViewState.viewWidth;
+        viewHeight = mapViewState.viewHeight;
+        topLeftInWindow = mapViewState.topLeftInWindow;
+        topLeftOnScreen = mapViewState.topLeftOnScreen;
+    }
+
+    private MapViewState(double scale, MapViewState mapViewState) {
+        this.projection = mapViewState.projection;
+        this.scale = scale;
+        this.topLeft = mapViewState.topLeft;
+
+        viewWidth = mapViewState.viewWidth;
+        viewHeight = mapViewState.viewHeight;
+        topLeftInWindow = mapViewState.topLeftInWindow;
+        topLeftOnScreen = mapViewState.topLeftOnScreen;
+    }
+
+    private MapViewState(JComponent position, MapViewState mapViewState) {
+        this.projection = mapViewState.projection;
+        this.scale = mapViewState.scale;
+        this.topLeft = mapViewState.topLeft;
+
+        viewWidth = position.getWidth();
+        viewHeight = position.getHeight();
+        topLeftInWindow = new Point();
+        // better than using swing utils, since this allows us to use the mehtod if no screen is present.
+        Container component = position;
+        while (component != null) {
+            topLeftInWindow.x += component.getX();
+            topLeftInWindow.y += component.getY();
+            component = component.getParent();
+        }
+        topLeftOnScreen = position.getLocationOnScreen();
+    }
+
+    /**
+     * The scale in east/north units per pixel.
+     * @return The scale.
+     */
+    public double getScale() {
+        return scale;
     }
 
@@ -110,4 +167,86 @@
 
     /**
+     * Creates an affine transform that is used to convert the east/north coordinates to view coordinates.
+     * @return The affine transform. It should not be changed.
+     * @since xxx
+     */
+    public AffineTransform getAffineTransform() {
+        return new AffineTransform(1.0 / scale, 0.0, 0.0, -1.0 / scale, topLeft.east() / scale,
+                topLeft.north() / scale);
+    }
+
+    /**
+     * Creates a new state that is the same as the current state except for that it is using a new center.
+     * @param newCenter The new center coordinate.
+     * @return The new state.
+     * @since xxx
+     */
+    public MapViewState usingCenter(EastNorth newCenter) {
+        return movedTo(getCenter(), newCenter);
+    }
+
+    /**
+     * @param mapViewPoint The reference point.
+     * @param newEastNorthThere The east/north coordinate that should be there.
+     * @return The new state.
+     * @since xxx
+     */
+    public MapViewState movedTo(MapViewPoint mapViewPoint, EastNorth newEastNorthThere) {
+        EastNorth delta = newEastNorthThere.subtract(mapViewPoint.getEastNorth());
+        if (delta.distanceSq(0, 0) < .000001) {
+            return this;
+        } else {
+            return new MapViewState(topLeft.add(delta), this);
+        }
+    }
+
+    /**
+     * Creates a new state that is the same as the current state except for that it is using a new scale.
+     * @param newScale The new scale to use.
+     * @return The new state.
+     * @since xxx
+     */
+    public MapViewState usingScale(double newScale) {
+        return new MapViewState(newScale, this);
+    }
+
+    /**
+     * Creates a new state that is the same as the current state except for that it is using the location of the given component.
+     * <p>
+     * The view is moved so that the center is the same as the old center.
+     * @param positon The new location to use.
+     * @return The new state.
+     * @since xxx
+     */
+    public MapViewState usingLocation(JComponent positon) {
+        EastNorth center = this.getCenter().getEastNorth();
+        return new MapViewState(positon, this).usingCenter(center);
+    }
+
+    /**
+     * Create the default {@link MapViewState} object for the given map view. The screen position won't be set so that this method can be used
+     * before the view was added to the hirarchy.
+     * @param width The view width
+     * @param height The view height
+     * @return The state
+     * @since xxx
+     */
+    public static MapViewState createDefaultState(int width, int height) {
+        Projection projection = Main.getProjection();
+        double scale = projection.getDefaultZoomInPPD();
+        MapViewState state = new MapViewState(projection, width, height, scale, new EastNorth(0, 0));
+        EastNorth center = calculateDefaultCenter();
+        return state.movedTo(state.getCenter(), center);
+    }
+
+    private static EastNorth calculateDefaultCenter() {
+        Bounds b = DownloadDialog.getSavedDownloadBounds();
+        if (b == null) {
+            b = Main.getProjection().getWorldBoundsLatLon();
+        }
+        return Main.getProjection().latlon2eastNorth(b.getCenter());
+    }
+
+    /**
      * A class representing a point in the map view. It allows to convert between the different coordinate systems.
      * @author Michael Zangl
@@ -132,6 +271,5 @@
          */
         public Point2D getInWindow() {
-            Point corner = SwingUtilities.convertPoint(navigatableComponent, new Point(0, 0), null);
-            return getUsingCorner(corner);
+            return getUsingCorner(topLeftInWindow);
         }
 
@@ -141,7 +279,5 @@
          */
         public Point2D getOnScreen() {
-            Point corner = new Point(0, 0);
-            SwingUtilities.convertPointToScreen(corner, navigatableComponent);
-            return getUsingCorner(corner);
+            return getUsingCorner(topLeftOnScreen);
         }
 
@@ -268,3 +404,4 @@
         }
     }
+
 }
Index: trunk/src/org/openstreetmap/josm/gui/NavigatableComponent.java
===================================================================
--- trunk/src/org/openstreetmap/josm/gui/NavigatableComponent.java	(revision 10374)
+++ trunk/src/org/openstreetmap/josm/gui/NavigatableComponent.java	(revision 10375)
@@ -5,4 +5,8 @@
 import java.awt.Point;
 import java.awt.Rectangle;
+import java.awt.event.ComponentAdapter;
+import java.awt.event.ComponentEvent;
+import java.awt.event.HierarchyEvent;
+import java.awt.event.HierarchyListener;
 import java.awt.geom.AffineTransform;
 import java.awt.geom.Point2D;
@@ -25,4 +29,5 @@
 
 import javax.swing.JComponent;
+import javax.swing.SwingUtilities;
 
 import org.openstreetmap.josm.Main;
@@ -48,5 +53,4 @@
 import org.openstreetmap.josm.data.projection.Projections;
 import org.openstreetmap.josm.gui.MapViewState.MapViewPoint;
-import org.openstreetmap.josm.gui.download.DownloadDialog;
 import org.openstreetmap.josm.gui.help.Helpful;
 import org.openstreetmap.josm.gui.layer.NativeScaleLayer;
@@ -135,13 +139,36 @@
     }
 
-    private double scale = Main.getProjection().getDefaultZoomInPPD();
-    /**
-     * Center n/e coordinate of the desired screen center.
-     */
-    protected EastNorth center = calculateDefaultCenter();
+    // The only events that may move/resize this map view are window movements or changes to the map view size.
+    // We can clean this up more by only recalculating the state on repaint.
+    private final HierarchyListener hierarchyListener = new HierarchyListener() {
+        @Override
+        public void hierarchyChanged(HierarchyEvent e) {
+            long interestingFlags = HierarchyEvent.ANCESTOR_MOVED | HierarchyEvent.SHOWING_CHANGED;
+            if ((e.getChangeFlags() & interestingFlags) != 0) {
+                updateLocationState();
+            }
+        }
+    };
+
+    private final ComponentAdapter componentListener = new ComponentAdapter() {
+        @Override
+        public void componentShown(ComponentEvent e) {
+            updateLocationState();
+        }
+
+        @Override
+        public void componentResized(ComponentEvent e) {
+            updateLocationState();
+        }
+    };
 
     protected transient ViewportData initialViewport;
 
     protected final transient CursorManager cursorManager = new CursorManager(this);
+
+    /**
+     * The current state (scale, center, ...) of this map view.
+     */
+    private MapViewState state;
 
     /**
@@ -150,4 +177,20 @@
     public NavigatableComponent() {
         setLayout(null);
+        state = MapViewState.createDefaultState(getWidth(), getHeight());
+    }
+
+    @Override
+    public void addNotify() {
+        updateLocationState();
+        addHierarchyListener(hierarchyListener);
+        addComponentListener(componentListener);
+        super.addNotify();
+    }
+
+    @Override
+    public void removeNotify() {
+        removeHierarchyListener(hierarchyListener);
+        removeComponentListener(componentListener);
+        super.removeNotify();
     }
 
@@ -158,5 +201,5 @@
     public void setNativeScaleLayer(NativeScaleLayer nativeScaleLayer) {
         this.nativeScaleLayer = nativeScaleLayer;
-        zoomTo(center, scaleRound(scale));
+        zoomTo(getCenter(), scaleRound(getScale()));
         repaint();
     }
@@ -251,5 +294,5 @@
      */
     public void zoomIn() {
-        zoomTo(center, scaleZoomIn());
+        zoomTo(getCenter(), scaleZoomIn());
     }
 
@@ -258,5 +301,5 @@
      */
     public void zoomOut() {
-        zoomTo(center, scaleZoomOut());
+        zoomTo(getCenter(), scaleZoomOut());
     }
 
@@ -265,10 +308,16 @@
     }
 
-    private static EastNorth calculateDefaultCenter() {
-        Bounds b = DownloadDialog.getSavedDownloadBounds();
-        if (b == null) {
-            b = Main.getProjection().getWorldBoundsLatLon();
-        }
-        return Main.getProjection().latlon2eastNorth(b.getCenter());
+    protected void updateLocationState() {
+        if (SwingUtilities.getWindowAncestor(this) != null && isShowing()) {
+            state = state.usingLocation(this);
+        }
+    }
+
+    /**
+     * Gets the current view state. This includes the scale, the current view area and the position.
+     * @return The current state.
+     */
+    public MapViewState getState() {
+        return state;
     }
 
@@ -339,5 +388,5 @@
      */
     public EastNorth getCenter() {
-        return center;
+        return state.getCenter().getEastNorth();
     }
 
@@ -350,5 +399,5 @@
      */
     public double getScale() {
-        return scale;
+        return state.getScale();
     }
 
@@ -360,11 +409,9 @@
      */
     public EastNorth getEastNorth(int x, int y) {
-        return new EastNorth(
-                center.east() + (x - getWidth()/2.0)*scale,
-                center.north() - (y - getHeight()/2.0)*scale);
+        return state.getForView(x, y).getEastNorth();
     }
 
     public ProjectionBounds getProjectionBounds() {
-        return new MapViewState(this).getViewArea().getProjectionBounds();
+        return getState().getViewArea().getProjectionBounds();
     }
 
@@ -378,5 +425,5 @@
     /* FIXME: replace with better method - used by Main to reset Bounds when projection changes, don't use otherwise */
     public Bounds getRealBounds() {
-        return new MapViewState(this).getViewArea().getCornerBounds();
+        return getState().getViewArea().getCornerBounds();
     }
 
@@ -397,5 +444,5 @@
 
     public ProjectionBounds getProjectionBounds(Rectangle r) {
-        MapViewState state = new MapViewState(this);
+        MapViewState state = getState();
         MapViewPoint p1 = state.getForView(r.getMinX(), r.getMinY());
         MapViewPoint p2 = state.getForView(r.getMaxX(), r.getMaxY());
@@ -412,6 +459,5 @@
 
     public AffineTransform getAffineTransform() {
-        return new AffineTransform(
-                1.0/scale, 0.0, 0.0, -1.0/scale, getWidth()/2.0 - center.east()/scale, getHeight()/2.0 + center.north()/scale);
+        return getState().getAffineTransform();
     }
 
@@ -425,7 +471,5 @@
         if (null == p)
             return new Point();
-        double x = (p.east()-center.east())/scale + getWidth()/2d;
-        double y = (center.north()-p.north())/scale + getHeight()/2d;
-        return new Point2D.Double(x, y);
+        return getState().getPointFor(p).getInView();
     }
 
@@ -513,5 +557,5 @@
         if (ll1.isValid() && ll2.isValid() && b.contains(ll1) && b.contains(ll2)) {
             double dm = ll1.greatCircleDistance(ll2);
-            double den = 100 * scale;
+            double den = 100 * getScale();
             double scaleMin = 0.01 * den / dm / 100;
             if (!Double.isInfinite(scaleMin) && newScale < scaleMin) {
@@ -521,9 +565,9 @@
 
         // snap scale to imagery if needed
-        scale = scaleRound(scale);
-
-        if (!newCenter.equals(center) || !Utils.equalsEpsilon(scale, newScale)) {
+        newScale = scaleRound(newScale);
+
+        if (!newCenter.equals(getCenter()) || !Utils.equalsEpsilon(getScale(), newScale)) {
             if (!initial) {
-                pushZoomUndo(center, scale);
+                pushZoomUndo(getCenter(), getScale());
             }
             zoomNoUndoTo(newCenter, newScale, initial);
@@ -539,14 +583,16 @@
      */
     private void zoomNoUndoTo(EastNorth newCenter, double newScale, boolean initial) {
-        if (!newCenter.equals(center)) {
-            EastNorth oldCenter = center;
-            center = newCenter;
+        if (!newCenter.equals(getCenter())) {
+            EastNorth oldCenter = getCenter();
+            state = state.usingCenter(newCenter);
             if (!initial) {
                 firePropertyChange(PROPNAME_CENTER, oldCenter, newCenter);
             }
         }
-        if (!Utils.equalsEpsilon(scale, newScale)) {
-            double oldScale = scale;
-            scale = newScale;
+        if (!Utils.equalsEpsilon(getScale(), newScale)) {
+            double oldScale = getScale();
+            state = state.usingScale(newScale);
+            // temporary. Zoom logic needs to be moved.
+            state = state.movedTo(state.getCenter(), newCenter);
             if (!initial) {
                 firePropertyChange(PROPNAME_SCALE, oldScale, newScale);
@@ -561,5 +607,5 @@
 
     public void zoomTo(EastNorth newCenter) {
-        zoomTo(newCenter, scale);
+        zoomTo(newCenter, getScale());
     }
 
@@ -576,7 +622,7 @@
         final int fps = 20;     // animation frames per second
         final int speed = 1500; // milliseconds for full-screen-width pan
-        if (!newCenter.equals(center)) {
-            final EastNorth oldCenter = center;
-            final double distance = newCenter.distance(oldCenter) / scale;
+        if (!newCenter.equals(getCenter())) {
+            final EastNorth oldCenter = getCenter();
+            final double distance = newCenter.distance(oldCenter) / getScale();
             final double milliseconds = distance / getWidth() * speed;
             final double frames = milliseconds * fps / 1000;
@@ -601,5 +647,5 @@
 
     public void zoomManyTimes(double x, double y, int times) {
-        double oldScale = scale;
+        double oldScale = getScale();
         double newScale = scaleZoomManyTimes(times);
         zoomToFactor(x, y, newScale / oldScale);
@@ -607,19 +653,17 @@
 
     public void zoomToFactor(double x, double y, double factor) {
-        double newScale = scale*factor;
-        // New center position so that point under the mouse pointer stays the same place as it was before zooming
-        // You will get the formula by simplifying this expression: newCenter = oldCenter + mouseCoordinatesInNewZoom - mouseCoordinatesInOldZoom
-        zoomTo(new EastNorth(
-                center.east() - (x - getWidth()/2.0) * (newScale - scale),
-                center.north() + (y - getHeight()/2.0) * (newScale - scale)),
-                newScale);
+        double newScale = getScale()*factor;
+        EastNorth oldUnderMouse = getState().getForView(x, y).getEastNorth();
+        MapViewState newState = getState().usingScale(newScale);
+        newState = newState.movedTo(newState.getForView(x, y), oldUnderMouse);
+        zoomTo(newState.getCenter().getEastNorth(), newScale);
     }
 
     public void zoomToFactor(EastNorth newCenter, double factor) {
-        zoomTo(newCenter, scale*factor);
+        zoomTo(newCenter, getScale()*factor);
     }
 
     public void zoomToFactor(double factor) {
-        zoomTo(center, scale*factor);
+        zoomTo(getCenter(), getScale()*factor);
     }
 
@@ -714,5 +758,5 @@
         if (!zoomUndoBuffer.isEmpty()) {
             ZoomData zoom = zoomUndoBuffer.pop();
-            zoomRedoBuffer.push(new ZoomData(center, scale));
+            zoomRedoBuffer.push(new ZoomData(getCenter(), getScale()));
             zoomNoUndoTo(zoom.getCenterEastNorth(), zoom.getScale(), false);
         }
@@ -722,5 +766,5 @@
         if (!zoomRedoBuffer.isEmpty()) {
             ZoomData zoom = zoomRedoBuffer.pop();
-            zoomUndoBuffer.push(new ZoomData(center, scale));
+            zoomUndoBuffer.push(new ZoomData(getCenter(), getScale()));
             zoomNoUndoTo(zoom.getCenterEastNorth(), zoom.getScale(), false);
         }
@@ -1443,5 +1487,5 @@
      */
     public Projection getProjection() {
-        return Main.getProjection();
+        return state.getProjection();
     }
 
@@ -1457,5 +1501,5 @@
      */
     public int getViewID() {
-        String x = center.east() + '_' + center.north() + '_' + scale + '_' +
+        String x = getCenter().east() + '_' + getCenter().north() + '_' + getScale() + '_' +
                 getWidth() + '_' + getHeight() + '_' + getProjection().toString();
         CRC32 id = new CRC32();
Index: trunk/src/org/openstreetmap/josm/gui/mappaint/styleelement/BoxTextElement.java
===================================================================
--- trunk/src/org/openstreetmap/josm/gui/mappaint/styleelement/BoxTextElement.java	(revision 10374)
+++ trunk/src/org/openstreetmap/josm/gui/mappaint/styleelement/BoxTextElement.java	(revision 10375)
@@ -261,5 +261,4 @@
     }
 
-
     private static void initDefaultParameters() {
         if (defaultTextColorCache != null) return;
Index: trunk/src/org/openstreetmap/josm/tools/bugreport/BugReport.java
===================================================================
--- trunk/src/org/openstreetmap/josm/tools/bugreport/BugReport.java	(revision 10374)
+++ trunk/src/org/openstreetmap/josm/tools/bugreport/BugReport.java	(revision 10375)
@@ -31,10 +31,10 @@
  * @since 10285
  */
-public class BugReport {
+public final class BugReport {
     /**
      * Create a new bug report
      * @param e The {@link ReportedException} to use. No more data should be added after creating the report.
      */
-    public BugReport(ReportedException e) {
+    private BugReport(ReportedException e) {
         // TODO: Use this class to create the bug report.
     }
