Index: applications/editors/josm/plugins/print/src/org/openstreetmap/josm/plugins/print/PrintAction.java
===================================================================
--- applications/editors/josm/plugins/print/src/org/openstreetmap/josm/plugins/print/PrintAction.java	(revision 27251)
+++ applications/editors/josm/plugins/print/src/org/openstreetmap/josm/plugins/print/PrintAction.java	(revision 27252)
@@ -28,7 +28,6 @@
 import java.awt.event.ActionEvent;
 import java.awt.event.KeyEvent;
-import java.awt.print.*;
 
-import javax.swing.JOptionPane;
+import javax.swing.SwingUtilities;
 
 import org.openstreetmap.josm.Main;
@@ -40,5 +39,5 @@
  * and takes care of reasonable temporary adjustments to the preferences.
  */
-public class PrintAction extends JosmAction {
+public class PrintAction extends JosmAction implements Runnable {
     
     /**
@@ -56,39 +55,23 @@
 
     /**
-     * Trigger the printing process.
+     * Trigger the printing dialog.
      * 
      * @param e not used.
      */
     public void actionPerformed(ActionEvent e) {
-        PrinterJob job = PrinterJob.getPrinterJob();
-        job.setPrintable(new PrintableMapView());
-        if (job.printDialog()) {
-            try {
-                PrintPlugin.adjustPrefs();
-                job.print();
-            }
-            catch (PrinterAbortException ex) {
-                String msg = ex.getLocalizedMessage();
-                if (msg.length() == 0) {
-                    msg = tr("Printing has been cancelled.");
-                }
-                JOptionPane.showMessageDialog(Main.main.parent, msg,
-                  tr("Printing stopped"),
-                  JOptionPane.WARNING_MESSAGE);
-            }
-            catch (PrinterException ex) {
-                String msg = ex.getLocalizedMessage();
-                if (msg.length() == 0) {
-                    msg = tr("Printing has failed.");
-                }
-                JOptionPane.showMessageDialog(Main.main.parent, msg,
-                  tr("Printing stopped"),
-                  JOptionPane.ERROR_MESSAGE);
-            }
-            finally {
-                PrintPlugin.restorePrefs();
-            }
-        }
+        // Allow the JOSM GUI to be redrawn before modifying preferences
+        SwingUtilities.invokeLater(this);
     }
     
+    /**
+     * Open the printing dialog
+     * 
+     * This will temporarily modify the mappaint preferences.
+     */
+    public void run () {
+        PrintPlugin.adjustPrefs();
+        PrintDialog window = new PrintDialog(Main.main.parent);
+        window.setVisible(true);
+        PrintPlugin.restorePrefs();
+    }
 }
Index: applications/editors/josm/plugins/print/src/org/openstreetmap/josm/plugins/print/PrintDialog.java
===================================================================
--- applications/editors/josm/plugins/print/src/org/openstreetmap/josm/plugins/print/PrintDialog.java	(revision 27252)
+++ applications/editors/josm/plugins/print/src/org/openstreetmap/josm/plugins/print/PrintDialog.java	(revision 27252)
@@ -0,0 +1,406 @@
+/*
+ *      PrintDialog.java
+ *      
+ *      Copyright 2011 Kai Pastor
+ *      
+ *      This program is free software; you can redistribute it and/or modify
+ *      it under the terms of the GNU General Public License as published by
+ *      the Free Software Foundation; either version 2 of the License, or
+ *      (at your option) any later version.
+ *      
+ *      This program is distributed in the hope that it will be useful,
+ *      but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *      GNU General Public License for more details.
+ *      
+ *      You should have received a copy of the GNU General Public License
+ *      along with this program; if not, write to the Free Software
+ *      Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+ *      MA 02110-1301, USA.
+ *      
+ *      
+ */
+
+package org.openstreetmap.josm.plugins.print;
+
+import static org.openstreetmap.josm.tools.I18n.tr;
+
+import java.awt.Component;
+import java.awt.Dimension;
+import java.awt.GridBagConstraints;
+import java.awt.GridBagLayout;
+import java.awt.Insets;
+import java.awt.Toolkit;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import java.awt.print.*;
+
+import java.text.ParseException;
+
+import javax.print.*;
+import javax.print.attribute.*;
+import javax.print.attribute.standard.*;
+import javax.swing.JButton;
+import javax.swing.JCheckBox;
+import javax.swing.JDialog;
+import javax.swing.JLabel;
+import javax.swing.JOptionPane;
+import javax.swing.JPanel;
+import javax.swing.JScrollPane;
+import javax.swing.JSpinner;
+import javax.swing.JTextField;
+import javax.swing.SpinnerNumberModel;
+import javax.swing.SwingUtilities;
+import javax.swing.event.ChangeEvent;
+import javax.swing.event.ChangeListener;
+import javax.swing.event.DocumentEvent;
+import javax.swing.event.DocumentListener;
+
+import org.openstreetmap.josm.Main;
+import org.openstreetmap.josm.tools.GBC;
+import org.openstreetmap.josm.tools.WindowGeometry;
+
+/**
+ * A print dialog with preview
+ */
+public class PrintDialog extends JDialog implements ActionListener {
+
+    /**
+     * The printer name
+     */
+    protected JTextField printerField;
+    
+    /**
+     * The media format name
+     */
+    protected JTextField paperField;
+    
+    /**
+     * The media orientation
+     */
+    protected JTextField orientationField;
+
+    /**
+     * The preview toggle checkbox
+     */
+    protected JCheckBox previewCheckBox;
+    
+    /**
+     * The resolution in dpi for printing/preview
+     */
+    protected SpinnerNumberModel resolutionModel;
+    
+    /**
+     * The page preview
+     */
+    protected PrintPreview printPreview;
+    
+    /**
+     * The printer job
+     */
+    protected PrinterJob job;
+    
+    /**
+     * The custom printer job attributes
+     */
+    PrintRequestAttributeSet attrs = new HashPrintRequestAttributeSet();
+    
+    /** 
+     * Create a new print dialog
+     * 
+     * @param parent the parent component
+     */
+    public PrintDialog(Component parent) {
+        super(JOptionPane.getFrameForComponent(parent), tr("Print the Map"), ModalityType.DOCUMENT_MODAL);
+        job = PrinterJob.getPrinterJob();
+        job.setJobName("JOSM Map");
+        build();
+        updateFields();
+        pack();
+        //setMinimumSize(getPreferredSize());
+        setMaximumSize(Toolkit.getDefaultToolkit().getScreenSize());
+    }
+    
+    /**
+     * Show or hide the dialog
+     * 
+     * Set the dialog size to reasonable values.
+     * 
+     * @param visible a flag indication the visibility of the dialog
+     */
+    @Override
+    public void setVisible(boolean visible) {
+        if (visible) {
+            // Make the dialog at most as large as the parent JOSM window
+            // Have to take window decorations into account or the windows will
+            // be too large
+            Insets i = this.getParent().getInsets();
+            Dimension p = this.getParent().getSize();
+            p = new Dimension(Math.min(p.width-i.left-i.right, 1000),
+                    Math.min(p.height-i.top-i.bottom, 700));
+            new WindowGeometry(
+                    getClass().getName() + ".geometry",
+                    WindowGeometry.centerInWindow(
+                            getParent(),
+                            p
+                    )
+            ).applySafe(this);
+        } else if (!visible && isShowing()){
+            new WindowGeometry(this).remember(getClass().getName() + ".geometry");
+            Main.pref.put("print.preview.enabled",previewCheckBox.isSelected());
+        }
+        super.setVisible(visible);
+    }
+
+    /**
+     * Construct the dialog from components
+     */
+    public void build() {
+        setLayout(new GridBagLayout());
+        final GBC std = GBC.std().insets(0,5,5,0);
+        std.fill = GBC.HORIZONTAL;
+        final GBC twocolumns  = GBC.std().insets(0,5,5,0).span(2).fill(GBC.HORIZONTAL);
+        
+        JLabel caption;
+        
+        int row = 0;
+        caption = new JLabel(tr("Printer:"));
+        add(caption, std.grid(2, row));
+        printerField = new JTextField();
+        printerField.setEditable(false);
+        add(printerField, std.grid(3, row));
+
+        row++;
+        caption = new JLabel(tr("Paper:"));
+        add(caption, std.grid(2, row));
+        paperField = new JTextField();
+        paperField.setEditable(false);
+        add(paperField, std.grid(3, row));
+
+        row++;
+        caption = new JLabel(tr("Orientation:"));
+        add(caption, std.grid(2, row));
+        orientationField = new JTextField();
+        orientationField.setEditable(false);
+        add(orientationField, std.grid(3, row));
+
+        row++;
+        JButton printerButton = new JButton(tr("Printer settings..."));
+        printerButton.setActionCommand("printer-dialog");
+        printerButton.addActionListener(this);
+        add(printerButton, twocolumns.grid(2, row));
+
+        row++;
+        add(GBC.glue(5,10), GBC.std(1,row).fill(GBC.VERTICAL));
+        
+        row++;
+        caption = new JLabel(tr("Resolution (dpi):"));
+        add(caption, std.grid(2, row));
+        resolutionModel = new SpinnerNumberModel(
+          (int)Main.pref.getInteger("print.resolution.dpi", PrintPlugin.DEF_RESOLUTION_DPI),
+          30, 1200, 10 );
+        final JSpinner resolutionField = new JSpinner(resolutionModel);
+        resolutionField.addChangeListener(new ChangeListener() {
+            public void stateChanged(ChangeEvent evt) {
+                SwingUtilities.invokeLater(new Runnable() {
+                    public void run() {
+                        try {
+                            resolutionField.commitEdit();
+                            Main.pref.put("print.resolution.dpi",resolutionModel.getNumber().toString());
+                            printPreview.repaint();
+                        }
+                        catch (ParseException pe) {
+                            ; // NOP
+                        }
+                    }
+                });
+            }
+        });
+        add(resolutionField, std.grid(3, row));
+
+        row++;
+        caption = new JLabel(tr("Attribution:"));
+        add(caption, std.grid(2, row));
+
+        row++;
+        final JTextField attributionField = new JTextField();
+        attributionField.setText(Main.pref.get("print.attribution", PrintPlugin.DEF_ATTRIBUTION));
+        attributionField.getDocument().addDocumentListener(new DocumentListener() {
+            public void insertUpdate(DocumentEvent evt) {
+                SwingUtilities.invokeLater(new Runnable() {
+                    public void run() {
+                        Main.pref.put("print.attribution", attributionField.getText());
+                        printPreview.repaint();
+                    }
+                });
+            }
+            public void removeUpdate(DocumentEvent evt) {
+                this.insertUpdate(evt);
+            }
+            public void changedUpdate(DocumentEvent evt) {
+                ; // NOP
+            }
+        });
+        add(attributionField, twocolumns.grid(2, row));
+
+        row++;
+        add(GBC.glue(5,10), GBC.std(1,row).fill(GBC.VERTICAL));
+        
+        row++;
+        previewCheckBox = new JCheckBox(tr("Map Preview"));
+        previewCheckBox.setSelected(Main.pref.getBoolean("print.preview.enabled",false));
+        previewCheckBox.setActionCommand("toggle-preview");
+        previewCheckBox.addActionListener(this);
+        add(previewCheckBox, twocolumns.grid(2, row));
+
+        row++;
+        JButton zoomInButton = new JButton(tr("Zoom In"));
+        zoomInButton.setActionCommand("zoom-in");
+        zoomInButton.addActionListener(this);
+        add(zoomInButton, twocolumns.grid(2, row));
+
+        row++;
+        JButton zoomOutButton = new JButton(tr("Zoom Out"));
+        zoomOutButton.setActionCommand("zoom-out");
+        zoomOutButton.addActionListener(this);
+        add(zoomOutButton, twocolumns.grid(2, row));
+        
+        row++;
+        JButton zoomToPageButton = new JButton(tr("Zoom To Page"));
+        zoomToPageButton.setActionCommand("zoom-to-page");
+        zoomToPageButton.addActionListener(this);
+        add(zoomToPageButton, twocolumns.grid(2, row));
+        
+        row++;
+        JButton zoomToActualSize = new JButton(tr("Zoom To Actual Size"));
+        zoomToActualSize.setActionCommand("zoom-to-actual-size");
+        zoomToActualSize.addActionListener(this);
+        add(zoomToActualSize, twocolumns.grid(2, row));
+        
+        printPreview = new PrintPreview();
+        if (previewCheckBox.isSelected()) {
+            printPreview.setPrintable(new PrintableMapView());
+        }
+        JScrollPane previewPane = new JScrollPane(printPreview, JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED, JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED);
+        previewPane.setPreferredSize(Main.main != null ? Main.main.map.mapView.getSize() : new Dimension(210,297));
+        add(previewPane, GBC.std(0,0).span(1, GBC.RELATIVE).fill().weight(5.0,5.0));
+
+        row++;
+        JPanel actionPanel = new JPanel();
+        JButton printButton = new JButton(tr("Print"));
+        printButton.setActionCommand("print");
+        printButton.addActionListener(this);
+        actionPanel.add(printButton);
+        JButton cancelButton = new JButton(tr("Cancel"));
+        cancelButton.setActionCommand("cancel");
+        cancelButton.addActionListener(this);
+        actionPanel.add(cancelButton);
+        add(actionPanel, GBC.std(0,row).insets(5,5,5,5).span(GBC.REMAINDER).fill(GBC.HORIZONTAL));
+    }
+    
+    /**
+     * Update the dialog fields from the underlying model
+     */
+    protected void updateFields() {
+        PrintService service = job.getPrintService();
+        if (service == null) {
+            printerField.setText("-");
+            paperField.setText("-");
+            orientationField.setText("-");
+        }
+        else {
+            printerField.setText(service.getName());
+            if (! attrs.containsKey(Media.class)) {
+                attrs.add((Attribute) service.getDefaultAttributeValue(Media.class));
+            } 
+            if (attrs.containsKey(Media.class)) {
+                paperField.setText(attrs.get(Media.class).toString());
+            }
+
+            if (! attrs.containsKey(OrientationRequested.class)) {
+                attrs.add((Attribute) service.getDefaultAttributeValue(OrientationRequested.class));
+            }
+            if (attrs.containsKey(OrientationRequested.class)) {
+                orientationField.setText(attrs.get(OrientationRequested.class).toString());
+            }
+
+            if (! attrs.containsKey(MediaPrintableArea.class)) {
+                PageFormat pf = job.defaultPage();
+                attrs.add(new MediaPrintableArea(
+                  (float)pf.getImageableX()/72,(float)pf.getImageableY()/72,
+                  (float)pf.getImageableWidth()/72,(float)pf.getImageableHeight()/72,
+                  MediaPrintableArea.INCH) );
+            }
+            
+            PageFormat pf = job.getPageFormat(attrs);
+            printPreview.setPageFormat(pf);
+        }
+    }
+    
+    /**
+     * Handle user input
+     * 
+     * @param e an ActionEvent with one of the known commands
+     */
+    public void actionPerformed(ActionEvent e) {
+        String cmd = e.getActionCommand();
+        if (cmd.equals("printer-dialog")) {
+            PrintService[] services = PrintServiceLookup.lookupPrintServices(null, null);
+            PrintService svc = PrintServiceLookup.lookupDefaultPrintService();
+            if (job.printDialog(attrs)) {
+                updateFields();
+            }
+        }
+        else if (cmd.equals("toggle-preview")) {
+            Main.pref.put("print.preview.enabled", previewCheckBox.isSelected());
+            if (previewCheckBox.isSelected() == true) {
+                printPreview.setPrintable(new PrintableMapView());
+            }
+            else {
+                printPreview.setPrintable(null);
+            }
+        }
+        else if (cmd.equals("zoom-in")) {
+            printPreview.zoomIn();
+        }
+        else if (cmd.equals("zoom-out")) {
+            printPreview.zoomOut();
+        }
+        else if (cmd.equals("zoom-to-page")) {
+            printPreview.zoomToPage();
+        }
+        else if (cmd.equals("zoom-to-actual-size")) {
+            printPreview.setZoom(1.0);
+        }
+        else if (cmd.equals("print")) {
+            try {
+                job.setPrintable(new PrintableMapView());
+                job.print(attrs);
+            }
+            catch (PrinterAbortException ex) {
+                String msg = ex.getLocalizedMessage();
+                if (msg.length() == 0) {
+                    msg = tr("Printing has been cancelled.");
+                }
+                JOptionPane.showMessageDialog(Main.main.parent, msg,
+                  tr("Printing stopped"),
+                  JOptionPane.WARNING_MESSAGE);
+            }
+            catch (PrinterException ex) {
+                String msg = ex.getLocalizedMessage();
+                if (msg.length() == 0) {
+                    msg = tr("Printing has failed.");
+                }
+                JOptionPane.showMessageDialog(Main.main.parent, msg,
+                  tr("Printing stopped"),
+                  JOptionPane.ERROR_MESSAGE);
+            }
+            dispose();
+        }
+        else if (cmd.equals("cancel")) {
+            dispose();
+        }
+    }
+    
+}
+
Index: applications/editors/josm/plugins/print/src/org/openstreetmap/josm/plugins/print/PrintPlugin.java
===================================================================
--- applications/editors/josm/plugins/print/src/org/openstreetmap/josm/plugins/print/PrintPlugin.java	(revision 27251)
+++ applications/editors/josm/plugins/print/src/org/openstreetmap/josm/plugins/print/PrintPlugin.java	(revision 27252)
@@ -23,4 +23,6 @@
 
 package org.openstreetmap.josm.plugins.print;
+
+import java.awt.Toolkit;
 
 import javax.swing.JMenu;
@@ -47,5 +49,5 @@
      * The default resolution
      */
-    public static final int DEF_RESOLUTION_DPI = 200;
+    public static final int DEF_RESOLUTION_DPI = 100;
 
     /**
@@ -86,4 +88,6 @@
         Main.pref.putDefault(
           "print.attribution", DEF_ATTRIBUTION);
+        Main.pref.putDefault(
+          "print.preview.enabled", new Boolean(false).toString());
 
         restorePrefs(); // Recover after crash if neccesseary
@@ -183,4 +187,5 @@
             restorePref("mappaint.node.virtual-size");
             Main.pref.put("print.saved-prefs", false);
+            //Main.main.map.mapView.repaint();
         }
     }
Index: applications/editors/josm/plugins/print/src/org/openstreetmap/josm/plugins/print/PrintPreview.java
===================================================================
--- applications/editors/josm/plugins/print/src/org/openstreetmap/josm/plugins/print/PrintPreview.java	(revision 27252)
+++ applications/editors/josm/plugins/print/src/org/openstreetmap/josm/plugins/print/PrintPreview.java	(revision 27252)
@@ -0,0 +1,308 @@
+/*
+ *      PrintPreview.java
+ *      
+ *      Copyright 2011 Kai Pastor
+ *      
+ *      This program is free software; you can redistribute it and/or modify
+ *      it under the terms of the GNU General Public License as published by
+ *      the Free Software Foundation; either version 2 of the License, or
+ *      (at your option) any later version.
+ *      
+ *      This program is distributed in the hope that it will be useful,
+ *      but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *      GNU General Public License for more details.
+ *      
+ *      You should have received a copy of the GNU General Public License
+ *      along with this program; if not, write to the Free Software
+ *      Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+ *      MA 02110-1301, USA.
+ *      
+ *      
+ */
+
+package org.openstreetmap.josm.plugins.print;
+
+import java.awt.Color;
+import java.awt.Container;
+import java.awt.Dimension;
+import java.awt.Graphics;
+import java.awt.Graphics2D;
+import java.awt.Rectangle;
+import java.awt.Toolkit;
+import java.awt.geom.AffineTransform;
+import java.awt.geom.Rectangle2D;
+import java.awt.print.PageFormat;
+import java.awt.print.Printable;
+import java.awt.print.PrinterException;
+
+import javax.swing.JViewport;
+import javax.swing.JPanel;
+import javax.swing.RepaintManager;
+
+/**
+ * A generic print preview component
+ * 
+ * Given a Printable, a PageFormat and a zoom factor, this component 
+ * will render a scrollable and zoomable print preview. If no Printable 
+ * is defined, it will fill the printable area of the page format in 
+ * plain gray.
+ * 
+ * There is a special zoom-to-page condition where the component will
+ * automatically adjust the zoom level such that the whole page preview
+ * will just fit into the size of the component.
+ */
+class PrintPreview extends JPanel {
+    
+    /**
+     * The PageFormat chosen for printing (and preview)
+     */
+    protected PageFormat format = null;
+    
+    /**
+     * The current zoom factor for the preview
+     */
+    protected double zoom = 1.0;
+    
+    /**
+     * If true, the preview is always zoomed such that 
+     * the whole page fits into the preview area.
+     */
+    protected boolean zoomToPage = true;
+    
+    /**
+     * When this flag is true, no painting operations will be performed.
+     */
+    protected boolean paintingDisabled = false;
+    
+    /**
+     * the printable object for rendering preview contents
+     */
+    protected Printable printable = null;
+    
+    /**
+     * Constructs a new preview component 
+     */
+    public PrintPreview() {
+        super();
+    }
+
+    /**
+     * Constructs a new preview component for a printable
+     * 
+     * @param p the printable object for rendering preview contents, or null
+     */
+    public PrintPreview(Printable p) {
+        super();
+        printable = p;
+    }
+
+    /**
+     * Sets (and unsets) the printable object
+     * 
+     * @param p a printable object, or null
+     */
+    public void setPrintable(Printable p) {
+        printable = p;
+        repaint();
+    }
+    
+    /**
+     * Sets the page format
+     * 
+     * @param format the PageFormat chosen for printing (and preview)
+     */
+    public void setPageFormat(PageFormat format) {
+        this.format = format;
+        revalidate();
+        repaint();
+    }
+    
+    /**
+     * Sets the preview zoom relativ to the actual size
+     *
+     * @param zoom the zoom factor 
+     */
+    public void setZoom(double zoom) {
+        setZoom(zoom, false);
+    }
+    
+    /**
+     * Zoom into the preview
+     * 
+     * Doubles the current zoom factor, if smaller than 5.0.
+     */
+    public void zoomIn() {
+        double zoom = getZoom();
+        if (zoom < 5.0) {
+            setZoom(2.0 * zoom);
+        }
+    }
+ 
+    /**
+     * Zoom out of the preview
+     * 
+     * Set the zoom factor to half its current value, if bigger than 0.1.
+     */
+    public void zoomOut() {
+        double zoom = getZoom();
+        if (zoom > 0.1) {
+            setZoom(0.5 * zoom);
+        }
+    }
+
+    /**
+     * Zoom to fit the page size
+     * 
+     * Set the zoom factor such that the whole page fits into the 
+     * preview area.
+     */
+    public void zoomToPage() {
+        Container parent = getParent();
+        Dimension dim;
+        if (parent instanceof JViewport) {
+            dim = getParent().getSize(); // could get rid of scrollbars
+        }
+        else {
+            dim = getVisibleRect().getSize();
+        }
+        int resolution = Toolkit.getDefaultToolkit().getScreenResolution();
+        double widthZoom = 72.0 * dim.getWidth() / resolution / format.getWidth();
+        double heightZoom = 72.0 * dim.getHeight() / resolution / format.getHeight();
+        setZoom(Math.min(widthZoom, heightZoom), true);
+    }
+
+    /**
+     * Sets the preview zoom relativ to the actual size
+     *
+     * @param zoom the zoom factor 
+     * @param zoomToPage when set to true, the zoom factor will be 
+     *   adjusted on resize operations such that the whole page always
+     *   fits to the preview area.
+     */
+    protected void setZoom(double zoom, boolean zoomToPage) {
+        if (format == null || zoom == this.zoom) {
+            return;
+        }
+
+        Dimension oldDim = getZoomedPageDimension();
+        Rectangle oldView = getVisibleRect();
+
+        paintingDisabled = true; // avoid flickering during zooming
+
+        this.zoom = zoom;
+        this.zoomToPage = zoomToPage;
+        revalidate(); // Make JScrollPane aware of the change in size
+        RepaintManager.currentManager(this).validateInvalidComponents(); 
+
+        Dimension dim = getZoomedPageDimension();
+        Rectangle view = getVisibleRect();
+
+        view.x = (int)((0.5*oldView.width+oldView.x)/Math.max(oldView.width,oldDim.width)*Math.max(view.width,dim.width)-0.5*view.width);
+        view.y = (int)((0.5*oldView.height+oldView.y)/Math.max(oldView.height,oldDim.height)*Math.max(view.height,dim.height)-0.5*view.height);
+
+        scrollRectToVisible(view);
+        paintingDisabled = false;
+        repaint(view); // repaint now when zooming is completed
+    }
+
+    /**
+     * Returns the actual current zoom
+     * 
+     * This factor might be different from the last explicitly set factor
+     * when zoomToPage is true.
+     * 
+     * @return the zoom factor 
+     */
+    public double getZoom() {
+        if (zoomToPage || zoom < 0.01) {
+            // actually this is zoom-to-page 
+            Dimension dim = getParent().getSize();
+            int resolution = Toolkit.getDefaultToolkit().getScreenResolution();
+            double widthZoom = 72.0 * dim.getWidth() / resolution / format.getWidth();
+            double heightZoom = 72.0 * dim.getHeight() / resolution / format.getHeight();
+            return Math.min(widthZoom, heightZoom);
+        }
+        return zoom;
+    }
+        
+    /**
+     * Get the current dimension of the page preview
+     * 
+     * @return dimension in pixels
+     */
+    public Dimension getZoomedPageDimension() {
+        int resolution = Toolkit.getDefaultToolkit().getScreenResolution();
+        double zoom = getZoom();
+        int width = (int)(zoom * resolution * format.getWidth() / 72.0);
+        int height = (int)(zoom * resolution * format.getHeight() / 72.0);
+        return new Dimension(width, height);
+    }
+
+    /**
+     * Get the current preferred size of the component
+     * 
+     * @return indicates a zero size when zoomToPage is active, 
+     *   the zoomed page dimension otherwise
+     */
+    @Override
+    public Dimension getPreferredSize() {
+        if (format == null || zoomToPage == true || zoom < 0.01) {
+            return new Dimension(0,0);
+        }
+        return getZoomedPageDimension();
+    }
+
+    /**
+     * Paints the component
+     * 
+     * This will do nothing, not even call super.paintComponent(g), if 
+     * painting is disabled in this component.
+     * 
+     * @param g a Graphics to draw to
+     */
+    @Override
+    public void paintComponent(Graphics g) {
+        if (paintingDisabled) {
+            return;
+        }
+        super.paintComponent(g);
+        if (format == null) {
+            return;
+        }
+
+        Graphics2D g2d = (Graphics2D) g;
+        AffineTransform at = g2d.getTransform();
+
+        Dimension out = getZoomedPageDimension();
+        double scale = Math.min(
+          out.getHeight()/format.getHeight() , out.getWidth()/format.getWidth() );
+        double left = 0.5 * ((double)getWidth() - scale * format.getWidth());
+        double top  = 0.5 * ((double)getHeight() - scale * format.getHeight());
+        
+        g2d.translate(left, top);
+        g2d.setColor(Color.black);
+        g2d.drawRect(-1, -1, out.width+1, out.height+1);
+        g2d.setColor(Color.white);
+        g2d.fillRect(0, 0, out.width, out.height);
+
+        g2d.scale(scale, scale);
+        g2d.clip(new Rectangle2D.Double(format.getImageableX(), format.getImageableY(), format.getImageableWidth(), format.getImageableHeight()));
+        if (printable != null) {
+            try {
+                printable.print(g2d, format, 0);
+            }
+            catch (PrinterException e) {
+                // should never happen since we are not printing
+            }
+        }
+        else {
+            g2d.setColor(Color.gray);
+            g2d.fillRect(0, 0, (int)format.getWidth(), (int)format.getHeight());
+        }
+
+
+        g2d.setTransform(at);
+    }
+
+}
Index: applications/editors/josm/plugins/print/src/org/openstreetmap/josm/plugins/print/PrintableMapView.java
===================================================================
--- applications/editors/josm/plugins/print/src/org/openstreetmap/josm/plugins/print/PrintableMapView.java	(revision 27251)
+++ applications/editors/josm/plugins/print/src/org/openstreetmap/josm/plugins/print/PrintableMapView.java	(revision 27252)
@@ -27,4 +27,5 @@
 
 import java.awt.Color;
+import java.awt.Dimension;
 import java.awt.Font;
 import java.awt.Graphics;
@@ -57,9 +58,4 @@
 public class PrintableMapView extends MapView implements Printable {
     
-    /** 
-     * Indicates that the instance has been initialized 
-     */
-    protected boolean initialized;
-    
     /**
      * The factor for scaling the printing graphics to the desired
@@ -93,5 +89,4 @@
         
         mapView = Main.main.map.mapView;
-        initialized = false;
     }
 
@@ -108,6 +103,30 @@
         double heightZoomFactor = g2dFactor * mapView.getHeight() / pageFormat.getImageableHeight();
         setSize((int)(pageFormat.getImageableWidth()/g2dFactor),(int)(pageFormat.getImageableHeight()/g2dFactor));
-        zoomTo(mapView.getRealBounds());
-    }
+    }
+    
+    /**
+     * Resizes this component. 
+     */
+    @Override
+    public void setSize(int width, int height) {
+        Dimension dim = getSize();
+        if (dim.width != width || dim.height != height) {
+            super.setSize(width, height);
+            zoomTo(mapView.getRealBounds());
+        }
+    }
+            
+    /**
+     * Resizes this component. 
+     */
+    @Override
+    public void setSize(Dimension newSize) {
+        Dimension dim = getSize();
+        if (dim.width != newSize.width || dim.height != newSize.height) {
+            super.setSize(newSize);
+            zoomTo(mapView.getRealBounds());
+        }
+    }
+            
 
     /**
@@ -129,11 +148,8 @@
                                                     PrinterException {
         if (page > 0) { /* stop after first page */
-            initialized = false;
             return NO_SUCH_PAGE;
         }
-        else if (! initialized) {
-            initialize(pageFormat);
-            initialized = true;
-        }
+
+        initialize(pageFormat);
 
         Graphics2D g2d = (Graphics2D)g;
@@ -324,4 +340,5 @@
             layers,
             new Comparator<Layer>() {
+                @Override
                 public int compare(Layer l2, Layer l1) { // l1 and l2 swapped!
                     if (l1 instanceof OsmDataLayer && l2 instanceof OsmDataLayer) {
