Index: trunk/src/org/openstreetmap/josm/actions/WireframeToggleAction.java
===================================================================
--- trunk/src/org/openstreetmap/josm/actions/WireframeToggleAction.java	(revision 4086)
+++ trunk/src/org/openstreetmap/josm/actions/WireframeToggleAction.java	(revision 4087)
@@ -6,17 +6,12 @@
 import java.awt.event.ActionEvent;
 import java.awt.event.KeyEvent;
-import java.util.ArrayList;
-import java.util.List;
-
-import javax.swing.ButtonModel;
 
 import org.openstreetmap.josm.Main;
+import org.openstreetmap.josm.data.osm.visitor.paint.MapRendererFactory;
+import org.openstreetmap.josm.data.osm.visitor.paint.StyledMapRenderer;
+import org.openstreetmap.josm.data.osm.visitor.paint.WireframeMapRenderer;
 import org.openstreetmap.josm.tools.Shortcut;
 
 public class WireframeToggleAction extends JosmAction {
-    private final List<ButtonModel> buttonModels = new ArrayList<ButtonModel>();
-    //FIXME: replace with property Action.SELECTED_KEY when migrating to
-    // Java 6
-    private boolean selected;
     public WireframeToggleAction() {
         super(
@@ -27,37 +22,20 @@
                 true /* register shortcut */
         );
-        selected = Main.pref.getBoolean("draw.wireframe", false);
-        notifySelectedState();
+        putValue(SELECTED_KEY, MapRendererFactory.getInstance().isWireframeMapRendererActive());
     }
 
-    public void addButtonModel(ButtonModel model) {
-        if (model != null && !buttonModels.contains(model)) {
-            buttonModels.add(model);
-            model.setSelected(selected);
+    public void toggleSelectedState() {
+        boolean selected = (Boolean)getValue(SELECTED_KEY);
+
+        if (selected){
+            MapRendererFactory.getInstance().activate(WireframeMapRenderer.class);
+        } else {
+            MapRendererFactory.getInstance().activate(StyledMapRenderer.class);
         }
-    }
-
-    public void removeButtonModel(ButtonModel model) {
-        if (model != null && buttonModels.contains(model)) {
-            buttonModels.remove(model);
-        }
-    }
-
-    protected void notifySelectedState() {
-        for (ButtonModel model: buttonModels) {
-            if (model.isSelected() != selected) {
-                model.setSelected(selected);
-            }
-        }
-    }
-
-    protected void toggleSelectedState() {
-        selected = !selected;
-        Main.pref.put("draw.wireframe", selected);
-        notifySelectedState();
         if (Main.map != null) {
             Main.map.mapView.repaint();
         }
     }
+
     public void actionPerformed(ActionEvent e) {
         toggleSelectedState();
@@ -66,9 +44,5 @@
     @Override
     protected void updateEnabledState() {
-        setEnabled(Main.map != null && Main.main.getEditLayer() != null);
-    }
-
-    public boolean isSelected() {
-        return selected;
+        setEnabled(Main.main.getEditLayer() != null);
     }
 }
Index: trunk/src/org/openstreetmap/josm/actions/mapmode/SelectAction.java
===================================================================
--- trunk/src/org/openstreetmap/josm/actions/mapmode/SelectAction.java	(revision 4086)
+++ trunk/src/org/openstreetmap/josm/actions/mapmode/SelectAction.java	(revision 4087)
@@ -37,5 +37,5 @@
 import org.openstreetmap.josm.data.osm.WaySegment;
 import org.openstreetmap.josm.data.osm.visitor.AllNodesVisitor;
-import org.openstreetmap.josm.data.osm.visitor.paint.SimplePaintVisitor;
+import org.openstreetmap.josm.data.osm.visitor.paint.WireframeMapRenderer;
 import org.openstreetmap.josm.gui.ExtendedDialog;
 import org.openstreetmap.josm.gui.MapFrame;
@@ -298,5 +298,5 @@
                 Point2D p1 = mv.getPoint2D(wnp.a = w.getNode(ws.lowerIndex));
                 Point2D p2 = mv.getPoint2D(wnp.b = w.getNode(ws.lowerIndex + 1));
-                if (SimplePaintVisitor.isLargeSegment(p1, p2, virtualSpace)) {
+                if (WireframeMapRenderer.isLargeSegment(p1, p2, virtualSpace)) {
                     Point2D pc = new Point2D.Double((p1.getX() + p2.getX()) / 2, (p1.getY() + p2.getY()) / 2);
                     if (p.distanceSq(pc) < virtualSnapDistSq) {
Index: trunk/src/org/openstreetmap/josm/data/Bounds.java
===================================================================
--- trunk/src/org/openstreetmap/josm/data/Bounds.java	(revision 4086)
+++ trunk/src/org/openstreetmap/josm/data/Bounds.java	(revision 4087)
@@ -205,4 +205,14 @@
     }
 
+    /**
+     * <p>Replies true, if this bounds are <em>collapsed</em>, i.e. if the min
+     * and the max corner are equal.</p>
+     * 
+     * @return true, if this bounds are <em>collapsed</em>
+     */
+    public boolean isCollapsed() {
+        return getMin().equals(getMax());
+    }
+
     @Override
     public int hashCode() {
Index: trunk/src/org/openstreetmap/josm/data/osm/DataSet.java
===================================================================
--- trunk/src/org/openstreetmap/josm/data/osm/DataSet.java	(revision 4086)
+++ trunk/src/org/openstreetmap/josm/data/osm/DataSet.java	(revision 4087)
@@ -20,4 +20,5 @@
 import java.util.concurrent.locks.ReentrantReadWriteLock;
 
+import org.openstreetmap.josm.data.Bounds;
 import org.openstreetmap.josm.data.SelectionChangedListener;
 import org.openstreetmap.josm.data.coor.EastNorth;
@@ -145,5 +146,5 @@
     public LinkedList<Collection<? extends OsmPrimitive>> getSelectionHistory() {
         return selectionHistory;
-    } 
+    }
 
     /**
@@ -151,6 +152,6 @@
      */
     public void clearSelectionHistory() {
-            selectionHistory.clear();
-        }
+        selectionHistory.clear();
+    }
 
     /**
@@ -1041,3 +1042,25 @@
         }
     }
+
+    /**
+     * <p>Replies the list of data source bounds.</p>
+     * 
+     * <p>Dataset maintains a list of data sources which have been merged into the
+     * data set. Each of these sources can optionally declare a bounding box of the
+     * data it supplied to the dataset.</p>
+     * 
+     * <p>This method replies the list of defined (non {@code null}) bounding boxes.</p>
+     * 
+     * @return the list of data source bounds. An empty list, if no non-null data source
+     * bounds are defined.
+     */
+    public List<Bounds> getDataSourceBounds() {
+        List<Bounds> ret = new ArrayList<Bounds>(dataSources.size());
+        for (DataSource ds : dataSources) {
+            if (ds.bounds != null) {
+                ret.add(ds.bounds);
+            }
+        }
+        return ret;
+    }
 }
Index: trunk/src/org/openstreetmap/josm/data/osm/visitor/paint/AbstractMapRenderer.java
===================================================================
--- trunk/src/org/openstreetmap/josm/data/osm/visitor/paint/AbstractMapRenderer.java	(revision 4087)
+++ trunk/src/org/openstreetmap/josm/data/osm/visitor/paint/AbstractMapRenderer.java	(revision 4087)
@@ -0,0 +1,41 @@
+// License: GPL. For details, see LICENSE file.
+package org.openstreetmap.josm.data.osm.visitor.paint;
+
+import java.awt.Graphics2D;
+
+import org.openstreetmap.josm.gui.NavigatableComponent;
+import org.openstreetmap.josm.tools.CheckParameterUtil;
+
+/**
+ * <p>Abstract common superclass for {@link Rendering} implementations.</p>
+ *
+ */
+public abstract class AbstractMapRenderer implements Rendering {
+
+    /** the graphics context to which the visitor renders OSM objects */
+    protected Graphics2D g;
+    /** the map viewport - provides projection and hit detection functionality */
+    protected NavigatableComponent nc;
+    /** if true, the paint visitor shall render OSM objects such that they
+     * look inactive. Example: rendering of data in an inactive layer using light gray as color only.
+     */
+    protected boolean isInactiveMode;
+
+    /**
+     * <p>Creates an abstract paint visitor</p>
+     * 
+     * @param g the graphics context. Must not be null.
+     * @param nc the map viewport. Must not be null.
+     * @param isInactiveMode if true, the paint visitor shall render OSM objects such that they
+     * look inactive. Example: rendering of data in an inactive layer using light gray as color only.
+     * @throws IllegalArgumentException thrown if {@code g} is null
+     * @throws IllegalArgumentException thrown if {@code nc} is null
+     */
+    public AbstractMapRenderer(Graphics2D g, NavigatableComponent nc, boolean isInactiveMode) throws IllegalArgumentException{
+        CheckParameterUtil.ensureParameterNotNull(g);
+        CheckParameterUtil.ensureParameterNotNull(nc);
+        this.g = g;
+        this.nc = nc;
+        this.isInactiveMode = isInactiveMode;
+    }
+}
Index: trunk/src/org/openstreetmap/josm/data/osm/visitor/paint/MapPaintVisitor.java
===================================================================
--- trunk/src/org/openstreetmap/josm/data/osm/visitor/paint/MapPaintVisitor.java	(revision 4086)
+++ 	(revision )
@@ -1,232 +1,0 @@
-// License: GPL. Copyright 2007 by Immanuel Scholz and others
-package org.openstreetmap.josm.data.osm.visitor.paint;
-
-import java.awt.Graphics2D;
-import java.awt.RenderingHints;
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.List;
-
-import org.openstreetmap.josm.Main;
-import org.openstreetmap.josm.data.Bounds;
-import org.openstreetmap.josm.data.osm.BBox;
-import org.openstreetmap.josm.data.osm.DataSet;
-import org.openstreetmap.josm.data.osm.Node;
-import org.openstreetmap.josm.data.osm.OsmPrimitive;
-import org.openstreetmap.josm.data.osm.Relation;
-import org.openstreetmap.josm.data.osm.Way;
-import org.openstreetmap.josm.gui.NavigatableComponent;
-import org.openstreetmap.josm.gui.mappaint.AreaElemStyle;
-import org.openstreetmap.josm.gui.mappaint.ElemStyle;
-import org.openstreetmap.josm.gui.mappaint.ElemStyles;
-import org.openstreetmap.josm.gui.mappaint.MapPaintStyles;
-import org.openstreetmap.josm.gui.mappaint.NodeElemStyle;
-import org.openstreetmap.josm.gui.mappaint.StyleCache.StyleList;
-
-public class MapPaintVisitor implements PaintVisitor {
-
-    private Graphics2D g;
-    private boolean inactive;
-    private NavigatableComponent nc;
-
-    private ElemStyles styles;
-    private double circum;
-    private MapPainter painter;
-    private MapPaintSettings paintSettings;
-
-    private static int FLAG_NORMAL = 0;
-    private static int FLAG_DISABLED = 1;
-    private static int FLAG_SELECTED = 2;
-    private static int FLAG_MEMBER_OF_SELECTED = 4;
-
-    private static class StyleRecord implements Comparable<StyleRecord> {
-        final ElemStyle style;
-        final OsmPrimitive osm;
-        final int flags;
-
-        public StyleRecord(ElemStyle style, OsmPrimitive osm, int flags) {
-            this.style = style;
-            this.osm = osm;
-            this.flags = flags;
-        }
-
-        @Override
-        public int compareTo(StyleRecord other) {
-            if ((this.flags & FLAG_DISABLED) != 0 && (other.flags & FLAG_DISABLED) == 0)
-                return -1;
-            if ((this.flags & FLAG_DISABLED) == 0 && (other.flags & FLAG_DISABLED) != 0)
-                return 1;
-            float z_index1 = this.style.z_index;
-            if ((this.flags & FLAG_SELECTED) != 0) {
-                z_index1 += 700f;
-            } else if ((this.flags & FLAG_MEMBER_OF_SELECTED) != 0) {
-                z_index1 += 600f;
-            }
-            float z_index2 = other.style.z_index;
-            if ((other.flags & FLAG_SELECTED) != 0) {
-                z_index2 += 700f;
-            } else if ((other.flags & FLAG_MEMBER_OF_SELECTED) != 0) {
-                z_index2 += 600f;
-            }
-            
-            int d1 = Float.compare(z_index1, z_index2);
-            if (d1 != 0)
-                return d1;
-            
-            // simple node on top of icons and shapes
-            if (this.style == NodeElemStyle.SIMPLE_NODE_ELEMSTYLE && other.style != NodeElemStyle.SIMPLE_NODE_ELEMSTYLE)
-                return 1;
-            if (this.style != NodeElemStyle.SIMPLE_NODE_ELEMSTYLE && other.style == NodeElemStyle.SIMPLE_NODE_ELEMSTYLE)
-                return -1;
-            
-            // newer primitives to the front
-            long id = this.osm.getUniqueId() - other.osm.getUniqueId();
-            if (id > 0)
-                return 1;
-            if (id < 0)
-                return -1;
-            
-            return Float.compare(this.style.object_z_index, other.style.object_z_index);
-        }
-    }
-    
-    private class StyleCollector {
-        private final boolean drawArea;
-        private final boolean drawMultipolygon;
-        private final boolean drawRestriction;
-
-        private final List<StyleRecord> styleElems;
-
-        public StyleCollector(boolean drawArea, boolean drawMultipolygon, boolean drawRestriction) {
-            this.drawArea = drawArea;
-            this.drawMultipolygon = drawMultipolygon;
-            this.drawRestriction = drawRestriction;
-            styleElems = new ArrayList<StyleRecord>();
-        }
-
-        public void add(Node osm, int flags) {
-            StyleList sl = styles.get(osm, circum, nc);
-            for (ElemStyle s : sl) {
-                styleElems.add(new StyleRecord(s, osm, flags));
-            }
-        }
-
-        public void add(Way osm, int flags) {
-            StyleList sl = styles.get(osm, circum, nc);
-            for (ElemStyle s : sl) {
-                if (!(drawArea && (flags & FLAG_DISABLED) == 0) && s instanceof AreaElemStyle) {
-                    continue;
-                }
-                styleElems.add(new StyleRecord(s, osm, flags));
-            }
-        }
-
-        public void add(Relation osm, int flags) {
-            StyleList sl = styles.get(osm, circum, nc);
-            for (ElemStyle s : sl) {
-                if (drawMultipolygon && drawArea && s instanceof AreaElemStyle && (flags & FLAG_DISABLED) == 0) {
-                    styleElems.add(new StyleRecord(s, osm, flags));
-                } else if (drawRestriction && s instanceof NodeElemStyle) {
-                    styleElems.add(new StyleRecord(s, osm, flags));
-                }
-            }
-        }
-
-        public void drawAll() {
-            Collections.sort(styleElems);
-            for (StyleRecord r : styleElems) {
-                r.style.paintPrimitive(
-                        r.osm, 
-                        paintSettings, 
-                        painter, 
-                        (r.flags & FLAG_SELECTED) != 0, 
-                        (r.flags & FLAG_MEMBER_OF_SELECTED) != 0
-                );
-            }
-        }
-    }
-
-    public void visitAll(final DataSet data, boolean virtual, Bounds bounds) {
-        //long start = System.currentTimeMillis();
-        BBox bbox = new BBox(bounds);
-
-        styles = MapPaintStyles.getStyles();
-
-        this.paintSettings = MapPaintSettings.INSTANCE;
-
-        circum = nc.getDist100Pixel();
-        boolean drawArea = circum <= Main.pref.getInteger("mappaint.fillareas", 10000000);
-        boolean drawMultipolygon = drawArea && Main.pref.getBoolean("mappaint.multipolygon", true);
-        styles.setDrawMultipolygon(drawMultipolygon);
-        boolean drawRestriction = Main.pref.getBoolean("mappaint.restriction", true);
-        boolean leftHandTraffic = Main.pref.getBoolean("mappaint.lefthandtraffic", false);
-
-        g.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
-                Main.pref.getBoolean("mappaint.use-antialiasing", true) ?
-                        RenderingHints.VALUE_ANTIALIAS_ON : RenderingHints.VALUE_ANTIALIAS_OFF);
-
-        this.painter = new MapPainter(paintSettings, g, inactive, nc, virtual, circum, leftHandTraffic);
-
-        StyleCollector sc = new StyleCollector(drawArea, drawMultipolygon, drawRestriction);
-
-        for (final Node n: data.searchNodes(bbox)) {
-            if (n.isDrawable()) {
-                if (n.isDisabled()) {
-                    sc.add(n, FLAG_DISABLED);
-                } else if (data.isSelected(n)) {
-                    sc.add(n, FLAG_SELECTED);
-                } else if (n.isMemberOfSelected()) {
-                    sc.add(n, FLAG_MEMBER_OF_SELECTED);
-                } else {
-                    sc.add(n, FLAG_NORMAL);
-                }
-            }
-        }
-        for (final Way w : data.searchWays(bbox)) {
-            if (w.isDrawable()) {
-                if (w.isDisabled()) {
-                    sc.add(w, FLAG_DISABLED);
-                } else if (data.isSelected(w)) {
-                    sc.add(w, FLAG_SELECTED);
-                } else if (w.isMemberOfSelected()) {
-                    sc.add(w, FLAG_MEMBER_OF_SELECTED);
-                } else {
-                    sc.add(w, FLAG_NORMAL);
-                }
-            }
-        }
-        for (Relation r: data.searchRelations(bbox)) {
-            if (r.isDrawable()) {
-                if (r.isDisabled()) {
-                    sc.add(r, FLAG_DISABLED);
-                } else if (data.isSelected(r)) {
-                    sc.add(r, FLAG_SELECTED);
-                } else {
-                    sc.add(r, FLAG_NORMAL);
-                }
-            }
-        }
-
-        //long phase1 = System.currentTimeMillis();
-
-        sc.drawAll();
-        sc = null;
-
-        painter.drawVirtualNodes(data.searchWays(bbox));
-        
-        //long now = System.currentTimeMillis();
-        //System.err.println(String.format("PAINTING TOOK %d [PHASE1 took %d] (at scale %s)", now - start, phase1 - start, circum));
-    }
-
-    public void setGraphics(Graphics2D g) {
-        this.g = g;
-    }
-
-    public void setInactive(boolean inactive) {
-        this.inactive = inactive;
-    }
-
-    public void setNavigatableComponent(NavigatableComponent nc) {
-        this.nc = nc;
-    }
-}
Index: trunk/src/org/openstreetmap/josm/data/osm/visitor/paint/MapPainter.java
===================================================================
--- trunk/src/org/openstreetmap/josm/data/osm/visitor/paint/MapPainter.java	(revision 4086)
+++ trunk/src/org/openstreetmap/josm/data/osm/visitor/paint/MapPainter.java	(revision 4087)
@@ -80,6 +80,5 @@
     public MapPainter(MapPaintSettings settings, Graphics2D g,
             boolean inactive, NavigatableComponent nc, boolean virtual,
-            double circum, boolean leftHandTraffic)
-    {
+            double circum, boolean leftHandTraffic){
         this.settings = settings;
         this.g = g;
@@ -163,5 +162,4 @@
                             final double sy = l * (p1.y - p2.y);
 
-                            double tmp = p2.x + cosPHI * sx - sinPHI * sy;
                             orientationArrows.moveTo (p2.x + cosPHI * sx - sinPHI * sy, p2.y + sinPHI * sx + cosPHI * sy);
                             orientationArrows.lineTo(p2.x, p2.y);
@@ -699,7 +697,7 @@
                     continue;
                 }
-                drawArea(r, p, 
+                drawArea(r, p,
                         pd.selected ? settings.getRelationSelectedColor(color.getAlpha()) : color,
-                        fillImage, fillImageAlpha, text);
+                                fillImage, fillImageAlpha, text);
             }
         }
@@ -985,8 +983,4 @@
     }
 
-    public boolean isInactive() {
-        return inactive;
-    }
-
     public boolean isShowNames() {
         return showNames;
@@ -1001,3 +995,6 @@
     }
 
+    public boolean isInactiveMode() {
+        return inactive;
+    }
 }
Index: trunk/src/org/openstreetmap/josm/data/osm/visitor/paint/MapRendererFactory.java
===================================================================
--- trunk/src/org/openstreetmap/josm/data/osm/visitor/paint/MapRendererFactory.java	(revision 4087)
+++ trunk/src/org/openstreetmap/josm/data/osm/visitor/paint/MapRendererFactory.java	(revision 4087)
@@ -0,0 +1,323 @@
+// License: GPL. For details, see LICENSE file.
+package org.openstreetmap.josm.data.osm.visitor.paint;
+
+import static org.openstreetmap.josm.tools.I18n.tr;
+
+import java.awt.Graphics2D;
+import java.lang.reflect.Constructor;
+import java.lang.reflect.InvocationTargetException;
+import java.text.MessageFormat;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Iterator;
+import java.util.List;
+
+import org.openstreetmap.josm.Main;
+import org.openstreetmap.josm.gui.NavigatableComponent;
+import org.openstreetmap.josm.plugins.PluginHandler;
+import org.openstreetmap.josm.tools.CheckParameterUtil;
+
+/**
+ * <p>MapRendererFactory manages a list of map renderer classes and associated
+ * meta data (display name, description).</p>
+ * 
+ * <p>Plugins can implement and supply their own map renderers.</p>
+ * <strong>Sample code in a plugin</strong>
+ * <pre>
+ * public class MyMapRenderer extends AbstractMapRenderer {
+ *    // ....
+ * }
+ * 
+ * // to be called when the plugin is created
+ * MapRendererFactory factory = MapRendererFactory.getInstance();
+ * factory.register(MyMapRenderer.class, "My map renderer", "This is is a fast map renderer");
+ * factory.activate(MyMapRenderer.class);
+ * 
+ * </pre>
+ *
+ */
+public class MapRendererFactory {
+
+    /** preference key for the the renderer class name. Default: class name for {@link StyledMapRenderer}
+     * 
+     */
+    static public final String PREF_KEY_RENDERER_CLASS_NAME = "mappaint.renderer-class-name";
+
+    static public class MapRendererFactoryException extends RuntimeException {
+        public MapRendererFactoryException() {
+        }
+
+        public MapRendererFactoryException(String message, Throwable cause) {
+            super(message, cause);
+        }
+
+        public MapRendererFactoryException(String message) {
+            super(message);
+        }
+
+        public MapRendererFactoryException(Throwable cause) {
+            super(cause);
+        }
+    }
+
+    static public class Descriptor {
+        private Class<? extends AbstractMapRenderer> renderer;
+        private String displayName;
+        private String description;
+
+        public Descriptor(Class<? extends AbstractMapRenderer> renderer, String displayName, String description) {
+            this.renderer = renderer;
+            this.displayName  = displayName;
+            this.description = description;
+        }
+
+        public Class<? extends AbstractMapRenderer> getRenderer() {
+            return renderer;
+        }
+
+        public String getDisplayName() {
+            return displayName;
+        }
+
+        public String getDescription() {
+            return description;
+        }
+    }
+
+    static private MapRendererFactory instance;
+
+    /**
+     * Replies the unique instance
+     * @return
+     */
+    public static MapRendererFactory getInstance() {
+        if (instance == null) {
+            instance = new MapRendererFactory();
+        }
+        return instance;
+    }
+
+    private static Class<?> loadRendererClass(String className) {
+        for (ClassLoader cl : PluginHandler.getResourceClassLoaders()) {
+            try {
+                return Class.forName(className, true, cl);
+            } catch (final ClassNotFoundException e) {
+                // ignore
+            }
+        }
+        System.err.println(tr("Error: failed to load map renderer class ''{0}''. The class wasn''t found.", className));
+        return null;
+    }
+
+    private final List<Descriptor> descriptors = new ArrayList<Descriptor>();
+    private Class<? extends AbstractMapRenderer> activeRenderer = null;
+
+    private MapRendererFactory() {
+        registerDefaultRenderers();
+        activateDefault();
+        boolean drawWireframe = false;
+        if (Main.pref.hasKey("draw.wireframe")) {
+            drawWireframe = Main.pref.getBoolean("draw.wireframe",false);
+            /*
+             * transition 05/2011 - 'draw.wireframe' isn't supported anymore. Remove
+             * it from the preferences.
+             * Can be removed after ~ 01/2012
+             */
+            Main.pref.put("draw.wireframe", null);
+        }
+        if (drawWireframe){
+            activate(WireframeMapRenderer.class);
+            return;
+        }
+
+        String rendererClassName = Main.pref.get(PREF_KEY_RENDERER_CLASS_NAME);
+        if (rendererClassName != null) {
+            activateMapRenderer(rendererClassName);
+        } else {
+            activateDefault();
+        }
+    }
+
+    private void activateMapRenderer(String rendererClassName){
+        Class<?> c = loadRendererClass(rendererClassName);
+        if (c == null){
+            System.err.println(tr("Can''t activate map renderer class ''{0}'', because the class wasn''t found.", rendererClassName));
+            System.err.println(tr("Activating the standard map renderer instead."));
+            activateDefault();
+        } else if (! AbstractMapRenderer.class.isAssignableFrom(c)) {
+            System.err.println(tr("Can''t activate map renderer class ''{0}'', because it isn''t a subclass of ''{1}''.", rendererClassName, AbstractMapRenderer.class.getName()));
+            System.err.println(tr("Activating the standard map renderer instead."));
+            activateDefault();
+        } else {
+            Class<? extends AbstractMapRenderer> renderer = c.asSubclass(AbstractMapRenderer.class);
+            if (! isRegistered(renderer)) {
+                System.err.println(tr("Can''t activate map renderer class ''{0}'', because it isn''t registered as map renderer.", rendererClassName));
+                System.err.println(tr("Activating the standard map renderer instead."));
+                activateDefault();
+            } else {
+                activate(renderer);
+            }
+        }
+    }
+
+    private void registerDefaultRenderers() {
+        register(
+                WireframeMapRenderer.class,
+                tr("Wireframe Map Renderer"),
+                tr("Renders the map as simple wire frame.")
+        );
+        register(
+                StyledMapRenderer.class,
+                tr("Styled Map Renderer"),
+                tr("Renders the map using style rules in a set of style sheets.")
+        );
+    }
+
+    /**
+     * <p>Replies true, if {@code Renderer} is already a registered map renderer
+     * class.</p>
+     * 
+     * @param renderer the map renderer class. Must not be null.
+     * @return true, if {@code Renderer} is already a registered map renderer
+     * class
+     * @throws IllegalArgumentException thrown if {@code renderer} is null
+     */
+    public boolean isRegistered(Class<? extends AbstractMapRenderer> renderer) throws IllegalArgumentException {
+        CheckParameterUtil.ensureParameterNotNull(renderer);
+        for (Descriptor d: descriptors) {
+            if (d.getRenderer().getName().equals(renderer.getName())) return true;
+        }
+        return false;
+    }
+
+    /**
+     * <p>Registers a map renderer class.</p>
+     * 
+     * @param renderer the map renderer class. Must not be null.
+     * @param displayName the display name to be displayed in UIs (i.e. in the preference dialog)
+     * @param description the description
+     * @throws IllegalArgumentException thrown if {@code renderer} is null
+     * @throws IllegalStateException thrown if {@code renderer} is already registered
+     */
+    public void register(Class<? extends AbstractMapRenderer> renderer, String displayName, String description) throws IllegalArgumentException, IllegalStateException{
+        CheckParameterUtil.ensureParameterNotNull(renderer);
+        if (isRegistered(renderer))
+            throw new IllegalStateException(
+                    // no I18n - this is a technical message
+                    MessageFormat.format("Class ''{0}'' already registered a renderer", renderer.getName())
+            );
+        Descriptor d = new Descriptor(renderer, displayName, description);
+        descriptors.add(d);
+    }
+
+
+    /**
+     * <p>Unregisters a map renderer class.</p>
+     *
+     * <p>If the respective class is also the active renderer, the renderer is reset
+     * to the default renderer.</p>
+     * 
+     * @param renderer the map renderer class. Must not be null.
+     * 
+     */
+    public void unregister(Class<? extends AbstractMapRenderer> renderer) {
+        if (renderer == null) return;
+        if (!isRegistered(renderer)) return;
+        Iterator<Descriptor> it = descriptors.iterator();
+        while(it.hasNext()) {
+            Descriptor d = it.next();
+            if (d.getRenderer().getName().equals(renderer.getName())) {
+                it.remove();
+                break;
+            }
+        }
+        if (activeRenderer != null && activeRenderer.getName().equals(renderer.getName())) {
+            activateDefault();
+        }
+    }
+
+    /**
+     * <p>Activates a map renderer class.</p>
+     *
+     * <p>The renderer class must already be registered.</p>
+     * 
+     * @param renderer the map renderer class. Must not be null.
+     * @throws IllegalArgumentException thrown if {@code renderer} is null
+     * @throws IllegalStateException thrown if {@code renderer} isn't registered yet
+     * 
+     */
+    public void activate(Class<? extends AbstractMapRenderer> renderer) throws IllegalArgumentException, IllegalStateException{
+        CheckParameterUtil.ensureParameterNotNull(renderer);
+        if (!isRegistered(renderer))
+            throw new IllegalStateException(
+                    // no I18n required
+                    MessageFormat.format("Class ''{0}'' not registered as renderer. Can''t activate it.", renderer.getName())
+            );
+        this.activeRenderer = renderer;
+        Main.pref.put(PREF_KEY_RENDERER_CLASS_NAME, activeRenderer.getName());
+
+    }
+
+    /**
+     * <p>Activates the default map renderer.</p>
+     *
+     * @throws IllegalStateException thrown if the default renderer {@link StyledMapRenderer} isn't registered
+     * 
+     */
+    public void activateDefault() throws IllegalStateException{
+        Class<? extends AbstractMapRenderer> defaultRenderer = StyledMapRenderer.class;
+        if (!isRegistered(defaultRenderer))
+            throw new IllegalStateException(
+                    MessageFormat.format("Class ''{0}'' not registered as renderer. Can''t activate default renderer.", defaultRenderer.getName())
+            );
+        activate(defaultRenderer);
+    }
+
+    /**
+     * <p>Creates an instance of the currently active renderer.</p>
+     *
+     * @throws MapRendererFactoryException thrown if creating an instance fails
+     * @see AbstractMapRenderer#AbstractMapRenderer(Graphics2D, NavigatableComponent, boolean)
+     */
+    public AbstractMapRenderer createActiveRenderer(Graphics2D g, NavigatableComponent viewport, boolean isInactiveMode) throws MapRendererFactoryException{
+        try {
+            Constructor<?> c = activeRenderer.getConstructor(new Class<?>[]{Graphics2D.class, NavigatableComponent.class, boolean.class});
+            return AbstractMapRenderer.class.cast(c.newInstance(g, viewport, isInactiveMode));
+        } catch(NoSuchMethodException e){
+            throw new MapRendererFactoryException(e);
+        } catch (IllegalArgumentException e) {
+            throw new MapRendererFactoryException(e);
+        } catch (InstantiationException e) {
+            throw new MapRendererFactoryException(e);
+        } catch (IllegalAccessException e) {
+            throw new MapRendererFactoryException(e);
+        } catch (InvocationTargetException e) {
+            throw new MapRendererFactoryException(e.getCause());
+        }
+    }
+
+    /**
+     * <p>Replies the (unmodifiable) list of map renderer descriptors.</p>
+     * 
+     * @return the descriptors
+     */
+    public List<Descriptor> getMapRendererDescriptors() {
+        return Collections.unmodifiableList(descriptors);
+    }
+
+    /**
+     * <p>Replies true, if currently the wireframe map renderer is active. Otherwise,
+     * false.</p>
+     * 
+     * <p>There is a specific method for {@link WireframeMapRenderer} for legacy support.
+     * Until 03/2011 there were only two possible map renderers in JOSM: the wireframe
+     * renderer and the styled renderer. For the time being there are still UI elements
+     * (menu entries, etc.) which toggle between these two renderers only.</p>
+     * 
+     * @return true, if currently the wireframe map renderer is active. Otherwise,
+     * false
+     */
+    public boolean isWireframeMapRendererActive() {
+        return activeRenderer != null && activeRenderer.getName().equals(WireframeMapRenderer.class.getName());
+    }
+}
Index: trunk/src/org/openstreetmap/josm/data/osm/visitor/paint/PaintVisitor.java
===================================================================
--- trunk/src/org/openstreetmap/josm/data/osm/visitor/paint/PaintVisitor.java	(revision 4086)
+++ 	(revision )
@@ -1,15 +1,0 @@
-// License: GPL. For details, see LICENSE file.
-package org.openstreetmap.josm.data.osm.visitor.paint;
-
-import java.awt.Graphics2D;
-
-import org.openstreetmap.josm.data.Bounds;
-import org.openstreetmap.josm.data.osm.DataSet;
-import org.openstreetmap.josm.gui.NavigatableComponent;
-
-public interface PaintVisitor {
-    void setGraphics(Graphics2D g);
-    void setNavigatableComponent(NavigatableComponent nc);
-    void setInactive(boolean inactive);
-    void visitAll(DataSet data, boolean virtual, Bounds box);
-}
Index: trunk/src/org/openstreetmap/josm/data/osm/visitor/paint/Rendering.java
===================================================================
--- trunk/src/org/openstreetmap/josm/data/osm/visitor/paint/Rendering.java	(revision 4087)
+++ trunk/src/org/openstreetmap/josm/data/osm/visitor/paint/Rendering.java	(revision 4087)
@@ -0,0 +1,20 @@
+// License: GPL. For details, see LICENSE file.
+package org.openstreetmap.josm.data.osm.visitor.paint;
+
+import org.openstreetmap.josm.data.Bounds;
+import org.openstreetmap.josm.data.osm.DataSet;
+
+/**
+ * <p>An object which can render data provided by a {@link DataSet}.</p>
+ */
+public interface Rendering {
+    /**
+     * <p>Renders the OSM data in {@code data}</p>
+     * 
+     * @param data the data set to be rendered
+     * @param renderVirtualNodes if true, renders virtual nodes. Otherwise, ignores them.
+     * @param bbox the bounding box for the data to be rendered. Only objects within or intersecting
+     * with {@code bbox} are rendered
+     */
+    void render(DataSet data, boolean renderVirtualNodes, Bounds bbox);
+}
Index: trunk/src/org/openstreetmap/josm/data/osm/visitor/paint/SimplePaintVisitor.java
===================================================================
--- trunk/src/org/openstreetmap/josm/data/osm/visitor/paint/SimplePaintVisitor.java	(revision 4086)
+++ 	(revision )
@@ -1,544 +1,0 @@
-/* License: GPL. Copyright 2007 by Immanuel Scholz and others */
-package org.openstreetmap.josm.data.osm.visitor.paint;
-
-/* To enable debugging or profiling remove the double / signs */
-
-import java.awt.BasicStroke;
-import java.awt.Color;
-import java.awt.Graphics2D;
-import java.awt.Point;
-import java.awt.Polygon;
-import java.awt.Rectangle;
-import java.awt.RenderingHints;
-import java.awt.Stroke;
-import java.awt.geom.GeneralPath;
-import java.awt.geom.Point2D;
-import java.util.Collection;
-import java.util.Iterator;
-
-import org.openstreetmap.josm.Main;
-import org.openstreetmap.josm.data.Bounds;
-import org.openstreetmap.josm.data.osm.BBox;
-import org.openstreetmap.josm.data.osm.DataSet;
-import org.openstreetmap.josm.data.osm.Node;
-import org.openstreetmap.josm.data.osm.OsmPrimitive;
-import org.openstreetmap.josm.data.osm.Relation;
-import org.openstreetmap.josm.data.osm.RelationMember;
-import org.openstreetmap.josm.data.osm.Way;
-import org.openstreetmap.josm.data.osm.visitor.AbstractVisitor;
-import org.openstreetmap.josm.gui.NavigatableComponent;
-
-/**
- * A visitor that paints a simple scheme of every primitive it visits to a
- * previous set graphic environment.
- *
- * @author imi
- */
-public class SimplePaintVisitor extends AbstractVisitor implements PaintVisitor {
-    /**
-     * The environment to paint to.
-     */
-    protected Graphics2D g;
-    /**
-     * MapView to get screen coordinates.
-     */
-    protected NavigatableComponent nc;
-
-    public boolean inactive;
-
-    /**
-     * Preferences
-     */
-    protected Color inactiveColor;
-    protected Color selectedColor;
-    protected Color nodeColor;
-    protected Color dfltWayColor;
-    protected Color relationColor;
-    protected Color untaggedWayColor;
-    protected Color incompleteColor;
-    protected Color backgroundColor;
-    protected Color highlightColor;
-    protected Color taggedColor;
-    protected Color connectionColor;
-    protected Color taggedConnectionColor;
-    protected boolean showDirectionArrow;
-    protected boolean showOnewayArrow;
-    protected boolean showHeadArrowOnly;
-    protected boolean showOrderNumber;
-    protected boolean fillSelectedNode;
-    protected boolean fillUnselectedNode;
-    protected boolean fillTaggedNode;
-    protected boolean fillConnectionNode;
-    protected int selectedNodeSize;
-    protected int unselectedNodeSize;
-    protected int connectionNodeSize;
-    protected int taggedNodeSize;
-    protected int defaultSegmentWidth;
-    protected int virtualNodeSize;
-    protected int virtualNodeSpace;
-    protected int segmentNumberSpace;
-
-    /**
-     * Draw subsequent segments of same color as one Path
-     */
-    protected Color currentColor = null;
-    protected GeneralPath currentPath = new GeneralPath();
-
-    public void getColors()
-    {
-        inactiveColor = PaintColors.INACTIVE.get();
-        selectedColor = PaintColors.SELECTED.get();
-        nodeColor = PaintColors.NODE.get();
-        dfltWayColor = PaintColors.DEFAULT_WAY.get();
-        relationColor = PaintColors.RELATION.get();
-        untaggedWayColor = PaintColors.UNTAGGED_WAY.get();
-        incompleteColor = PaintColors.INCOMPLETE_WAY.get();
-        backgroundColor = PaintColors.BACKGROUND.get();
-        highlightColor = PaintColors.HIGHLIGHT.get();
-        taggedColor = PaintColors.TAGGED.get();
-        connectionColor = PaintColors.CONNECTION.get();
-
-        if (taggedColor != nodeColor) {
-            taggedConnectionColor = taggedColor;
-        } else {
-            taggedConnectionColor = connectionColor;
-        }
-    }
-
-    protected void getSettings(boolean virtual) {
-        MapPaintSettings settings = MapPaintSettings.INSTANCE;
-        showDirectionArrow = settings.isShowDirectionArrow();
-        showOnewayArrow = settings.isShowOnewayArrow();
-        showHeadArrowOnly = settings.isShowHeadArrowOnly();
-        showOrderNumber = settings.isShowOrderNumber();
-        selectedNodeSize = settings.getSelectedNodeSize();
-        unselectedNodeSize = settings.getUnselectedNodeSize();
-        connectionNodeSize = settings.getConnectionNodeSize();
-        taggedNodeSize = settings.getTaggedNodeSize();
-        defaultSegmentWidth = settings.getDefaultSegmentWidth();
-        fillSelectedNode = settings.isFillSelectedNode();
-        fillUnselectedNode = settings.isFillUnselectedNode();
-        fillConnectionNode = settings.isFillConnectionNode();
-        fillTaggedNode = settings.isFillTaggedNode();
-        virtualNodeSize = virtual ? Main.pref.getInteger("mappaint.node.virtual-size", 8) / 2 : 0;
-        virtualNodeSpace = Main.pref.getInteger("mappaint.node.virtual-space", 70);
-        segmentNumberSpace = Main.pref.getInteger("mappaint.segmentnumber.space", 40);
-        getColors();
-
-        g.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
-                Main.pref.getBoolean("mappaint.wireframe.use-antialiasing", false) ?
-                        RenderingHints.VALUE_ANTIALIAS_ON : RenderingHints.VALUE_ANTIALIAS_OFF);
-    }
-
-    DataSet ds;
-    public void visitAll(DataSet data, boolean virtual, Bounds bounds) {
-        BBox bbox = new BBox(bounds);
-        this.ds = data;
-        //boolean profiler = Main.pref.getBoolean("simplepaint.profiler",false);
-        //long profilerStart = java.lang.System.currentTimeMillis();
-        //long profilerLast = profilerStart;
-        //int profilerN = 0;
-        //if(profiler)
-        //    System.out.println("Simplepaint Profiler");
-
-        getSettings(virtual);
-
-        //if(profiler)
-        //{
-        //    System.out.format("Prepare  : %4dms\n", (java.lang.System.currentTimeMillis()-profilerLast));
-        //    profilerLast = java.lang.System.currentTimeMillis();
-        //}
-
-        /* draw tagged ways first, then untagged ways. takes
-           time to iterate through list twice, OTOH does not
-           require changing the colour while painting... */
-        //profilerN = 0;
-        for (final OsmPrimitive osm: data.searchRelations(bbox)) {
-            if (!osm.isDeleted() && !ds.isSelected(osm) && !osm.isDisabledAndHidden()) {
-                osm.visit(this);
-                //        profilerN++;
-            }
-        }
-
-        //if(profiler)
-        //{
-        //    System.out.format("Relations: %4dms, n=%5d\n", (java.lang.System.currentTimeMillis()-profilerLast), profilerN);
-        //    profilerLast = java.lang.System.currentTimeMillis();
-        //}
-
-        //profilerN = 0;
-        for (final OsmPrimitive osm:data.searchWays(bbox)){
-            if (!osm.isDeleted() && !ds.isSelected(osm) && !osm.isDisabledAndHidden() && osm.isTagged()) {
-                osm.visit(this);
-                //        profilerN++;
-            }
-        }
-        displaySegments();
-
-        for (final OsmPrimitive osm:data.searchWays(bbox)){
-            if (!osm.isDeleted() && !ds.isSelected(osm) && !osm.isDisabledAndHidden() && !osm.isTagged()) {
-                osm.visit(this);
-                //        profilerN++;
-            }
-        }
-        displaySegments();
-
-        //if(profiler)
-        //{
-        //    System.out.format("Ways     : %4dms, n=%5d\n",
-        //        (java.lang.System.currentTimeMillis()-profilerLast), profilerN);
-        //    profilerLast = java.lang.System.currentTimeMillis();
-        //}
-
-        //profilerN = 0;
-        for (final OsmPrimitive osm : data.getSelected()) {
-            if (!osm.isDeleted()) {
-                osm.visit(this);
-                //        profilerN++;
-            }
-        }
-        displaySegments();
-
-        //if(profiler)
-        //{
-        //    System.out.format("Selected : %4dms, n=%5d\n", (java.lang.System.currentTimeMillis()-profilerLast), profilerN);
-        //    profilerLast = java.lang.System.currentTimeMillis();
-        //}
-
-        //profilerN = 0;
-        for (final OsmPrimitive osm: data.searchNodes(bbox)) {
-            if (!osm.isDeleted() && !ds.isSelected(osm) && !osm.isDisabledAndHidden())
-            {
-                osm.visit(this);
-                //        profilerN++;
-            }
-        }
-
-        //if(profiler)
-        //{
-        //    System.out.format("Nodes    : %4dms, n=%5d\n",
-        //        (java.lang.System.currentTimeMillis()-profilerLast), profilerN);
-        //    profilerLast = java.lang.System.currentTimeMillis();
-        //}
-
-        drawVirtualNodes(data.searchWays(bbox));
-
-        //if(profiler)
-        //{
-        //    System.out.format("All      : %4dms\n", (profilerLast-profilerStart));
-        //}
-    }
-
-    private static final int max(int a, int b, int c, int d) {
-        return Math.max(Math.max(a, b), Math.max(c, d));
-    }
-
-    /**
-     * Draw a small rectangle.
-     * White if selected (as always) or red otherwise.
-     *
-     * @param n The node to draw.
-     */
-    public void visit(Node n) {
-        if (n.isIncomplete()) return;
-
-        if (n.isHighlighted()) {
-            drawNode(n, highlightColor, selectedNodeSize, fillSelectedNode);
-        } else {
-            Color color;
-
-            if (inactive || n.isDisabled()) {
-                color = inactiveColor;
-            } else if (ds.isSelected(n)) {
-                color = selectedColor;
-            } else if (n.isConnectionNode()) {
-                if (n.isTagged()) {
-                    color = taggedConnectionColor;
-                } else {
-                    color = connectionColor;
-                }
-            } else {
-                if (n.isTagged()) {
-                    color = taggedColor;
-                } else {
-                    color = nodeColor;
-                }
-            }
-
-            final int size = max((ds.isSelected(n) ? selectedNodeSize : 0),
-                    (n.isTagged() ? taggedNodeSize : 0),
-                    (n.isConnectionNode() ? connectionNodeSize : 0),
-                    unselectedNodeSize);
-
-            final boolean fill = (ds.isSelected(n) && fillSelectedNode) ||
-            (n.isTagged() && fillTaggedNode) ||
-            (n.isConnectionNode() && fillConnectionNode) ||
-            fillUnselectedNode;
-
-            drawNode(n, color, size, fill);
-        }
-    }
-
-    public static boolean isLargeSegment(Point2D p1, Point2D p2, int space)
-    {
-        double xd = Math.abs(p1.getX()-p2.getX());
-        double yd = Math.abs(p1.getY()-p2.getY());
-        return (xd+yd > space);
-    }
-
-    public void drawVirtualNodes(Collection<Way> ways) {
-
-        if (virtualNodeSize != 0) {
-            GeneralPath path = new GeneralPath();
-            for (Way osm: ways){
-                if (osm.isUsable() && !osm.isDisabledAndHidden() && !osm.isDisabled()) {
-                    visitVirtual(path, osm);
-                }
-            }
-            g.setColor(nodeColor);
-            g.draw(path);
-        }
-    }
-
-    public void visitVirtual(GeneralPath path, Way w) {
-        Iterator<Node> it = w.getNodes().iterator();
-        if (it.hasNext()) {
-            Point lastP = nc.getPoint(it.next());
-            while(it.hasNext())
-            {
-                Point p = nc.getPoint(it.next());
-                if(isSegmentVisible(lastP, p) && isLargeSegment(lastP, p, virtualNodeSpace))
-                {
-                    int x = (p.x+lastP.x)/2;
-                    int y = (p.y+lastP.y)/2;
-                    path.moveTo(x-virtualNodeSize, y);
-                    path.lineTo(x+virtualNodeSize, y);
-                    path.moveTo(x, y-virtualNodeSize);
-                    path.lineTo(x, y+virtualNodeSize);
-                }
-                lastP = p;
-            }
-        }
-    }
-
-    /**
-     * Draw a darkblue line for all segments.
-     * @param w The way to draw.
-     */
-    public void visit(Way w) {
-        if (w.isIncomplete() || w.getNodesCount() < 2)
-            return;
-
-        /* show direction arrows, if draw.segment.relevant_directions_only is not set, the way is tagged with a direction key
-           (even if the tag is negated as in oneway=false) or the way is selected */
-
-        boolean showThisDirectionArrow = ds.isSelected(w) || showDirectionArrow;
-        /* head only takes over control if the option is true,
-           the direction should be shown at all and not only because it's selected */
-        boolean showOnlyHeadArrowOnly = showThisDirectionArrow && !ds.isSelected(w) && showHeadArrowOnly;
-        Color wayColor;
-
-        if (inactive || w.isDisabled()) {
-            wayColor = inactiveColor;
-        } else if(w.isHighlighted()) {
-            wayColor = highlightColor;
-        } else if(ds.isSelected(w)) {
-            wayColor = selectedColor;
-        } else if (!w.isTagged()) {
-            wayColor = untaggedWayColor;
-        } else {
-            wayColor = dfltWayColor;
-        }
-
-        Iterator<Node> it = w.getNodes().iterator();
-        if (it.hasNext()) {
-            Point lastP = nc.getPoint(it.next());
-            for (int orderNumber = 1; it.hasNext(); orderNumber++) {
-                Point p = nc.getPoint(it.next());
-                drawSegment(lastP, p, wayColor,
-                        showOnlyHeadArrowOnly ? !it.hasNext() : showThisDirectionArrow);
-                if (showOrderNumber) {
-                    drawOrderNumber(lastP, p, orderNumber);
-                }
-                lastP = p;
-            }
-        }
-    }
-
-    private Stroke relatedWayStroke = new BasicStroke(
-            4, BasicStroke.CAP_SQUARE, BasicStroke.JOIN_BEVEL);
-    public void visit(Relation r) {
-        if (r.isIncomplete()) return;
-
-        Color col;
-        if (inactive || r.isDisabled()) {
-            col = inactiveColor;
-        } else if (ds.isSelected(r)) {
-            col = selectedColor;
-        } else {
-            col = relationColor;
-        }
-        g.setColor(col);
-
-        for (RelationMember m : r.getMembers()) {
-            if (m.getMember().isIncomplete() || m.getMember().isDeleted()) {
-                continue;
-            }
-
-            if (m.isNode()) {
-                Point p = nc.getPoint(m.getNode());
-                if (p.x < 0 || p.y < 0
-                        || p.x > nc.getWidth() || p.y > nc.getHeight()) {
-                    continue;
-                }
-
-                g.drawOval(p.x-3, p.y-3, 6, 6);
-            } else if (m.isWay()) {
-                GeneralPath path = new GeneralPath();
-
-                boolean first = true;
-                for (Node n : m.getWay().getNodes()) {
-                    if (n.isIncomplete() || n.isDeleted()) {
-                        continue;
-                    }
-                    Point p = nc.getPoint(n);
-                    if (first) {
-                        path.moveTo(p.x, p.y);
-                        first = false;
-                    } else {
-                        path.lineTo(p.x, p.y);
-                    }
-                }
-
-                g.draw(relatedWayStroke.createStrokedShape(path));
-            }
-        }
-    }
-
-    /**
-     * Draw an number of the order of the two consecutive nodes within the
-     * parents way
-     */
-    protected void drawOrderNumber(Point p1, Point p2, int orderNumber) {
-        if (isSegmentVisible(p1, p2) && isLargeSegment(p1, p2, segmentNumberSpace)) {
-            String on = Integer.toString(orderNumber);
-            int strlen = on.length();
-            int x = (p1.x+p2.x)/2 - 4*strlen;
-            int y = (p1.y+p2.y)/2 + 4;
-
-            if(virtualNodeSize != 0 && isLargeSegment(p1, p2, virtualNodeSpace))
-            {
-                y = (p1.y+p2.y)/2 - virtualNodeSize - 3;
-            }
-
-            displaySegments(); /* draw nodes on top! */
-            Color c = g.getColor();
-            g.setColor(backgroundColor);
-            g.fillRect(x-1, y-12, 8*strlen+1, 14);
-            g.setColor(c);
-            g.drawString(on, x, y);
-        }
-    }
-
-    /**
-     * Draw the node as small rectangle with the given color.
-     *
-     * @param n     The node to draw.
-     * @param color The color of the node.
-     */
-    public void drawNode(Node n, Color color, int size, boolean fill) {
-        if (size > 1) {
-            int radius = size / 2;
-            Point p = nc.getPoint(n);
-            if ((p.x < 0) || (p.y < 0) || (p.x > nc.getWidth())
-                    || (p.y > nc.getHeight()))
-                return;
-            g.setColor(color);
-            if (fill) {
-                g.fillRect(p.x - radius, p.y - radius, size, size);
-                g.drawRect(p.x - radius, p.y - radius, size, size);
-            } else {
-                g.drawRect(p.x - radius, p.y - radius, size, size);
-            }
-        }
-    }
-
-    private static final double PHI = Math.toRadians(20);
-    private static final double cosPHI = Math.cos(PHI);
-    private static final double sinPHI = Math.sin(PHI);
-
-    protected void drawSegment(GeneralPath path, Point p1, Point p2, boolean showDirection) {
-        Rectangle bounds = g.getClipBounds();
-        bounds.grow(100, 100);                  // avoid arrow heads at the border
-        LineClip clip = new LineClip(p1, p2, bounds);
-        if (clip.execute()) {
-            p1 = clip.getP1();
-            p2 = clip.getP2();
-            path.moveTo(p1.x, p1.y);
-            path.lineTo(p2.x, p2.y);
-
-            if (showDirection) {
-                final double l =  10. / p1.distance(p2);
-
-                final double sx = l * (p1.x - p2.x);
-                final double sy = l * (p1.y - p2.y);
-
-                path.lineTo (p2.x + (int) Math.round(cosPHI * sx - sinPHI * sy), p2.y + (int) Math.round(sinPHI * sx + cosPHI * sy));
-                path.moveTo (p2.x + (int) Math.round(cosPHI * sx + sinPHI * sy), p2.y + (int) Math.round(- sinPHI * sx + cosPHI * sy));
-                path.lineTo(p2.x, p2.y);
-            }
-        }
-    }
-
-    /**
-     * Draw a line with the given color.
-     */
-    protected void drawSegment(Point p1, Point p2, Color col, boolean showDirection) {
-        if (col != currentColor) {
-            displaySegments(col);
-        }
-        drawSegment(currentPath, p1, p2, showDirection);
-    }
-
-    protected boolean isSegmentVisible(Point p1, Point p2) {
-        if ((p1.x < 0) && (p2.x < 0)) return false;
-        if ((p1.y < 0) && (p2.y < 0)) return false;
-        if ((p1.x > nc.getWidth()) && (p2.x > nc.getWidth())) return false;
-        if ((p1.y > nc.getHeight()) && (p2.y > nc.getHeight())) return false;
-        return true;
-    }
-
-    protected boolean isPolygonVisible(Polygon polygon) {
-        Rectangle bounds = polygon.getBounds();
-        if (bounds.width == 0 && bounds.height == 0) return false;
-        if (bounds.x > nc.getWidth()) return false;
-        if (bounds.y > nc.getHeight()) return false;
-        if (bounds.x + bounds.width < 0) return false;
-        if (bounds.y + bounds.height < 0) return false;
-        return true;
-    }
-
-    public void setGraphics(Graphics2D g) {
-        this.g = g;
-    }
-
-    public void setNavigatableComponent(NavigatableComponent nc) {
-        this.nc = nc;
-    }
-
-    protected void displaySegments() {
-        displaySegments(null);
-    }
-    protected void displaySegments(Color newColor) {
-        if (currentPath != null) {
-            g.setColor(currentColor);
-            g.draw(currentPath);
-            currentPath = new GeneralPath();
-            currentColor = newColor;
-        }
-    }
-
-    public void setInactive(boolean inactive) {
-        this.inactive = inactive;
-    }
-}
Index: trunk/src/org/openstreetmap/josm/data/osm/visitor/paint/StyledMapRenderer.java
===================================================================
--- trunk/src/org/openstreetmap/josm/data/osm/visitor/paint/StyledMapRenderer.java	(revision 4087)
+++ trunk/src/org/openstreetmap/josm/data/osm/visitor/paint/StyledMapRenderer.java	(revision 4087)
@@ -0,0 +1,236 @@
+// License: GPL. Copyright 2007 by Immanuel Scholz and others
+package org.openstreetmap.josm.data.osm.visitor.paint;
+
+import java.awt.Graphics2D;
+import java.awt.RenderingHints;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+import org.openstreetmap.josm.Main;
+import org.openstreetmap.josm.data.Bounds;
+import org.openstreetmap.josm.data.osm.BBox;
+import org.openstreetmap.josm.data.osm.DataSet;
+import org.openstreetmap.josm.data.osm.Node;
+import org.openstreetmap.josm.data.osm.OsmPrimitive;
+import org.openstreetmap.josm.data.osm.Relation;
+import org.openstreetmap.josm.data.osm.Way;
+import org.openstreetmap.josm.gui.NavigatableComponent;
+import org.openstreetmap.josm.gui.mappaint.AreaElemStyle;
+import org.openstreetmap.josm.gui.mappaint.ElemStyle;
+import org.openstreetmap.josm.gui.mappaint.ElemStyles;
+import org.openstreetmap.josm.gui.mappaint.MapPaintStyles;
+import org.openstreetmap.josm.gui.mappaint.NodeElemStyle;
+import org.openstreetmap.josm.gui.mappaint.StyleCache.StyleList;
+
+/**
+ * <p>A map renderer which renders a map according to style rules in a set of style sheets.</p>
+ * 
+ */
+public class StyledMapRenderer extends AbstractMapRenderer{
+
+    private ElemStyles styles;
+    private double circum;
+    private MapPainter painter;
+    private MapPaintSettings paintSettings;
+
+    private static int FLAG_NORMAL = 0;
+    private static int FLAG_DISABLED = 1;
+    private static int FLAG_SELECTED = 2;
+    private static int FLAG_MEMBER_OF_SELECTED = 4;
+
+    private static class StyleRecord implements Comparable<StyleRecord> {
+        final ElemStyle style;
+        final OsmPrimitive osm;
+        final int flags;
+
+        public StyleRecord(ElemStyle style, OsmPrimitive osm, int flags) {
+            this.style = style;
+            this.osm = osm;
+            this.flags = flags;
+        }
+
+        @Override
+        public int compareTo(StyleRecord other) {
+            if ((this.flags & FLAG_DISABLED) != 0 && (other.flags & FLAG_DISABLED) == 0)
+                return -1;
+            if ((this.flags & FLAG_DISABLED) == 0 && (other.flags & FLAG_DISABLED) != 0)
+                return 1;
+            float z_index1 = this.style.z_index;
+            if ((this.flags & FLAG_SELECTED) != 0) {
+                z_index1 += 700f;
+            } else if ((this.flags & FLAG_MEMBER_OF_SELECTED) != 0) {
+                z_index1 += 600f;
+            }
+            float z_index2 = other.style.z_index;
+            if ((other.flags & FLAG_SELECTED) != 0) {
+                z_index2 += 700f;
+            } else if ((other.flags & FLAG_MEMBER_OF_SELECTED) != 0) {
+                z_index2 += 600f;
+            }
+
+            int d1 = Float.compare(z_index1, z_index2);
+            if (d1 != 0)
+                return d1;
+
+            // simple node on top of icons and shapes
+            if (this.style == NodeElemStyle.SIMPLE_NODE_ELEMSTYLE && other.style != NodeElemStyle.SIMPLE_NODE_ELEMSTYLE)
+                return 1;
+            if (this.style != NodeElemStyle.SIMPLE_NODE_ELEMSTYLE && other.style == NodeElemStyle.SIMPLE_NODE_ELEMSTYLE)
+                return -1;
+
+            // newer primitives to the front
+            long id = this.osm.getUniqueId() - other.osm.getUniqueId();
+            if (id > 0)
+                return 1;
+            if (id < 0)
+                return -1;
+
+            return Float.compare(this.style.object_z_index, other.style.object_z_index);
+        }
+    }
+
+    private class StyleCollector {
+        private final boolean drawArea;
+        private final boolean drawMultipolygon;
+        private final boolean drawRestriction;
+
+        private final List<StyleRecord> styleElems;
+
+        public StyleCollector(boolean drawArea, boolean drawMultipolygon, boolean drawRestriction) {
+            this.drawArea = drawArea;
+            this.drawMultipolygon = drawMultipolygon;
+            this.drawRestriction = drawRestriction;
+            styleElems = new ArrayList<StyleRecord>();
+        }
+
+        public void add(Node osm, int flags) {
+            StyleList sl = styles.get(osm, circum, nc);
+            for (ElemStyle s : sl) {
+                styleElems.add(new StyleRecord(s, osm, flags));
+            }
+        }
+
+        public void add(Way osm, int flags) {
+            StyleList sl = styles.get(osm, circum, nc);
+            for (ElemStyle s : sl) {
+                if (!(drawArea && (flags & FLAG_DISABLED) == 0) && s instanceof AreaElemStyle) {
+                    continue;
+                }
+                styleElems.add(new StyleRecord(s, osm, flags));
+            }
+        }
+
+        public void add(Relation osm, int flags) {
+            StyleList sl = styles.get(osm, circum, nc);
+            for (ElemStyle s : sl) {
+                if (drawMultipolygon && drawArea && s instanceof AreaElemStyle && (flags & FLAG_DISABLED) == 0) {
+                    styleElems.add(new StyleRecord(s, osm, flags));
+                } else if (drawRestriction && s instanceof NodeElemStyle) {
+                    styleElems.add(new StyleRecord(s, osm, flags));
+                }
+            }
+        }
+
+        public void drawAll() {
+            Collections.sort(styleElems);
+            for (StyleRecord r : styleElems) {
+                r.style.paintPrimitive(
+                        r.osm,
+                        paintSettings,
+                        painter,
+                        (r.flags & FLAG_SELECTED) != 0,
+                        (r.flags & FLAG_MEMBER_OF_SELECTED) != 0
+                );
+            }
+        }
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public StyledMapRenderer(Graphics2D g, NavigatableComponent nc, boolean isInactiveMode) {
+        super(g, nc, isInactiveMode);
+    }
+
+    private void collectNodeStyles(DataSet data, StyleCollector sc, BBox bbox) {
+        for (final Node n: data.searchNodes(bbox)) {
+            if (n.isDrawable()) {
+                if (n.isDisabled()) {
+                    sc.add(n, FLAG_DISABLED);
+                } else if (data.isSelected(n)) {
+                    sc.add(n, FLAG_SELECTED);
+                } else if (n.isMemberOfSelected()) {
+                    sc.add(n, FLAG_MEMBER_OF_SELECTED);
+                } else {
+                    sc.add(n, FLAG_NORMAL);
+                }
+            }
+        }
+    }
+
+    private void collectWayStyles(DataSet data, StyleCollector sc, BBox bbox) {
+        for (final Way w : data.searchWays(bbox)) {
+            if (w.isDrawable()) {
+                if (w.isDisabled()) {
+                    sc.add(w, FLAG_DISABLED);
+                } else if (data.isSelected(w)) {
+                    sc.add(w, FLAG_SELECTED);
+                } else if (w.isMemberOfSelected()) {
+                    sc.add(w, FLAG_MEMBER_OF_SELECTED);
+                } else {
+                    sc.add(w, FLAG_NORMAL);
+                }
+            }
+        }
+    }
+
+    private void collectRelationStyles(DataSet data, StyleCollector sc, BBox bbox) {
+        for (Relation r: data.searchRelations(bbox)) {
+            if (r.isDrawable()) {
+                if (r.isDisabled()) {
+                    sc.add(r, FLAG_DISABLED);
+                } else if (data.isSelected(r)) {
+                    sc.add(r, FLAG_SELECTED);
+                } else {
+                    sc.add(r, FLAG_NORMAL);
+                }
+            }
+        }
+    }
+
+    @Override
+    public void render(final DataSet data, boolean renderVirtualNodes, Bounds bounds) {
+        //long start = System.currentTimeMillis();
+        BBox bbox = new BBox(bounds);
+
+        styles = MapPaintStyles.getStyles();
+
+        this.paintSettings = MapPaintSettings.INSTANCE;
+
+        circum = nc.getDist100Pixel();
+        boolean drawArea = circum <= Main.pref.getInteger("mappaint.fillareas", 10000000);
+        boolean drawMultipolygon = drawArea && Main.pref.getBoolean("mappaint.multipolygon", true);
+        styles.setDrawMultipolygon(drawMultipolygon);
+        boolean drawRestriction = Main.pref.getBoolean("mappaint.restriction", true);
+        boolean leftHandTraffic = Main.pref.getBoolean("mappaint.lefthandtraffic", false);
+
+        g.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
+                Main.pref.getBoolean("mappaint.use-antialiasing", true) ?
+                        RenderingHints.VALUE_ANTIALIAS_ON : RenderingHints.VALUE_ANTIALIAS_OFF);
+
+        this.painter = new MapPainter(paintSettings, g, isInactiveMode, nc, renderVirtualNodes, circum, leftHandTraffic);
+
+        StyleCollector sc = new StyleCollector(drawArea, drawMultipolygon, drawRestriction);
+        collectNodeStyles(data, sc, bbox);
+        collectWayStyles(data, sc, bbox);
+        collectRelationStyles(data, sc, bbox);
+        //long phase1 = System.currentTimeMillis();
+        sc.drawAll();
+        sc = null;
+        painter.drawVirtualNodes(data.searchWays(bbox));
+
+        //long now = System.currentTimeMillis();
+        //System.err.println(String.format("PAINTING TOOK %d [PHASE1 took %d] (at scale %s)", now - start, phase1 - start, circum));
+    }
+}
Index: trunk/src/org/openstreetmap/josm/data/osm/visitor/paint/WireframeMapRenderer.java
===================================================================
--- trunk/src/org/openstreetmap/josm/data/osm/visitor/paint/WireframeMapRenderer.java	(revision 4087)
+++ trunk/src/org/openstreetmap/josm/data/osm/visitor/paint/WireframeMapRenderer.java	(revision 4087)
@@ -0,0 +1,476 @@
+/* License: GPL. Copyright 2007 by Immanuel Scholz and others */
+package org.openstreetmap.josm.data.osm.visitor.paint;
+
+import java.awt.BasicStroke;
+import java.awt.Color;
+import java.awt.Graphics2D;
+import java.awt.Point;
+import java.awt.Polygon;
+import java.awt.Rectangle;
+import java.awt.RenderingHints;
+import java.awt.Stroke;
+import java.awt.geom.GeneralPath;
+import java.awt.geom.Point2D;
+import java.util.Collection;
+import java.util.Iterator;
+
+import org.openstreetmap.josm.Main;
+import org.openstreetmap.josm.data.Bounds;
+import org.openstreetmap.josm.data.osm.BBox;
+import org.openstreetmap.josm.data.osm.Changeset;
+import org.openstreetmap.josm.data.osm.DataSet;
+import org.openstreetmap.josm.data.osm.Node;
+import org.openstreetmap.josm.data.osm.OsmPrimitive;
+import org.openstreetmap.josm.data.osm.Relation;
+import org.openstreetmap.josm.data.osm.RelationMember;
+import org.openstreetmap.josm.data.osm.Way;
+import org.openstreetmap.josm.data.osm.visitor.Visitor;
+import org.openstreetmap.josm.gui.NavigatableComponent;
+
+/**
+ * A map renderer that paints a simple scheme of every primitive it visits to a
+ * previous set graphic environment.
+ *
+ * @author imi
+ */
+public class WireframeMapRenderer extends AbstractMapRenderer implements Visitor {
+
+    /**
+     * Preferences
+     */
+    protected Color inactiveColor;
+    protected Color selectedColor;
+    protected Color nodeColor;
+    protected Color dfltWayColor;
+    protected Color relationColor;
+    protected Color untaggedWayColor;
+    protected Color incompleteColor;
+    protected Color backgroundColor;
+    protected Color highlightColor;
+    protected Color taggedColor;
+    protected Color connectionColor;
+    protected Color taggedConnectionColor;
+    protected boolean showDirectionArrow;
+    protected boolean showOnewayArrow;
+    protected boolean showHeadArrowOnly;
+    protected boolean showOrderNumber;
+    protected boolean fillSelectedNode;
+    protected boolean fillUnselectedNode;
+    protected boolean fillTaggedNode;
+    protected boolean fillConnectionNode;
+    protected int selectedNodeSize;
+    protected int unselectedNodeSize;
+    protected int connectionNodeSize;
+    protected int taggedNodeSize;
+    protected int defaultSegmentWidth;
+    protected int virtualNodeSize;
+    protected int virtualNodeSpace;
+    protected int segmentNumberSpace;
+
+    /**
+     * Draw subsequent segments of same color as one Path
+     */
+    protected Color currentColor = null;
+    protected GeneralPath currentPath = new GeneralPath();
+
+    /**
+     * {@inheritDoc}
+     */
+    public WireframeMapRenderer(Graphics2D g, NavigatableComponent nc, boolean isInactiveMode) {
+        super(g, nc, isInactiveMode);
+    }
+
+    public void getColors()
+    {
+        inactiveColor = PaintColors.INACTIVE.get();
+        selectedColor = PaintColors.SELECTED.get();
+        nodeColor = PaintColors.NODE.get();
+        dfltWayColor = PaintColors.DEFAULT_WAY.get();
+        relationColor = PaintColors.RELATION.get();
+        untaggedWayColor = PaintColors.UNTAGGED_WAY.get();
+        incompleteColor = PaintColors.INCOMPLETE_WAY.get();
+        backgroundColor = PaintColors.BACKGROUND.get();
+        highlightColor = PaintColors.HIGHLIGHT.get();
+        taggedColor = PaintColors.TAGGED.get();
+        connectionColor = PaintColors.CONNECTION.get();
+
+        if (taggedColor != nodeColor) {
+            taggedConnectionColor = taggedColor;
+        } else {
+            taggedConnectionColor = connectionColor;
+        }
+    }
+
+    protected void getSettings(boolean virtual) {
+        MapPaintSettings settings = MapPaintSettings.INSTANCE;
+        showDirectionArrow = settings.isShowDirectionArrow();
+        showOnewayArrow = settings.isShowOnewayArrow();
+        showHeadArrowOnly = settings.isShowHeadArrowOnly();
+        showOrderNumber = settings.isShowOrderNumber();
+        selectedNodeSize = settings.getSelectedNodeSize();
+        unselectedNodeSize = settings.getUnselectedNodeSize();
+        connectionNodeSize = settings.getConnectionNodeSize();
+        taggedNodeSize = settings.getTaggedNodeSize();
+        defaultSegmentWidth = settings.getDefaultSegmentWidth();
+        fillSelectedNode = settings.isFillSelectedNode();
+        fillUnselectedNode = settings.isFillUnselectedNode();
+        fillConnectionNode = settings.isFillConnectionNode();
+        fillTaggedNode = settings.isFillTaggedNode();
+        virtualNodeSize = virtual ? Main.pref.getInteger("mappaint.node.virtual-size", 8) / 2 : 0;
+        virtualNodeSpace = Main.pref.getInteger("mappaint.node.virtual-space", 70);
+        segmentNumberSpace = Main.pref.getInteger("mappaint.segmentnumber.space", 40);
+        getColors();
+
+        g.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
+                Main.pref.getBoolean("mappaint.wireframe.use-antialiasing", false) ?
+                        RenderingHints.VALUE_ANTIALIAS_ON : RenderingHints.VALUE_ANTIALIAS_OFF);
+    }
+
+    DataSet ds;
+    public void render(DataSet data, boolean virtual, Bounds bounds) {
+        BBox bbox = new BBox(bounds);
+        this.ds = data;
+        getSettings(virtual);
+
+        /* draw tagged ways first, then untagged ways. takes
+           time to iterate through list twice, OTOH does not
+           require changing the colour while painting... */
+        for (final OsmPrimitive osm: data.searchRelations(bbox)) {
+            if (!osm.isDeleted() && !ds.isSelected(osm) && !osm.isDisabledAndHidden()) {
+                osm.visit(this);
+            }
+        }
+
+        for (final OsmPrimitive osm:data.searchWays(bbox)){
+            if (!osm.isDeleted() && !ds.isSelected(osm) && !osm.isDisabledAndHidden() && osm.isTagged()) {
+                osm.visit(this);
+            }
+        }
+        displaySegments();
+
+        for (final OsmPrimitive osm:data.searchWays(bbox)){
+            if (!osm.isDeleted() && !ds.isSelected(osm) && !osm.isDisabledAndHidden() && !osm.isTagged()) {
+                osm.visit(this);
+            }
+        }
+        displaySegments();
+        for (final OsmPrimitive osm : data.getSelected()) {
+            if (!osm.isDeleted()) {
+                osm.visit(this);
+            }
+        }
+        displaySegments();
+
+        for (final OsmPrimitive osm: data.searchNodes(bbox)) {
+            if (!osm.isDeleted() && !ds.isSelected(osm) && !osm.isDisabledAndHidden())
+            {
+                osm.visit(this);
+            }
+        }
+        drawVirtualNodes(data.searchWays(bbox));
+    }
+
+    private static final int max(int a, int b, int c, int d) {
+        return Math.max(Math.max(a, b), Math.max(c, d));
+    }
+
+    /**
+     * Draw a small rectangle.
+     * White if selected (as always) or red otherwise.
+     *
+     * @param n The node to draw.
+     */
+    public void visit(Node n) {
+        if (n.isIncomplete()) return;
+
+        if (n.isHighlighted()) {
+            drawNode(n, highlightColor, selectedNodeSize, fillSelectedNode);
+        } else {
+            Color color;
+
+            if (isInactiveMode || n.isDisabled()) {
+                color = inactiveColor;
+            } else if (ds.isSelected(n)) {
+                color = selectedColor;
+            } else if (n.isConnectionNode()) {
+                if (n.isTagged()) {
+                    color = taggedConnectionColor;
+                } else {
+                    color = connectionColor;
+                }
+            } else {
+                if (n.isTagged()) {
+                    color = taggedColor;
+                } else {
+                    color = nodeColor;
+                }
+            }
+
+            final int size = max((ds.isSelected(n) ? selectedNodeSize : 0),
+                    (n.isTagged() ? taggedNodeSize : 0),
+                    (n.isConnectionNode() ? connectionNodeSize : 0),
+                    unselectedNodeSize);
+
+            final boolean fill = (ds.isSelected(n) && fillSelectedNode) ||
+            (n.isTagged() && fillTaggedNode) ||
+            (n.isConnectionNode() && fillConnectionNode) ||
+            fillUnselectedNode;
+
+            drawNode(n, color, size, fill);
+        }
+    }
+
+    public static boolean isLargeSegment(Point2D p1, Point2D p2, int space)
+    {
+        double xd = Math.abs(p1.getX()-p2.getX());
+        double yd = Math.abs(p1.getY()-p2.getY());
+        return (xd+yd > space);
+    }
+
+    public void drawVirtualNodes(Collection<Way> ways) {
+
+        if (virtualNodeSize != 0) {
+            GeneralPath path = new GeneralPath();
+            for (Way osm: ways){
+                if (osm.isUsable() && !osm.isDisabledAndHidden() && !osm.isDisabled()) {
+                    visitVirtual(path, osm);
+                }
+            }
+            g.setColor(nodeColor);
+            g.draw(path);
+        }
+    }
+
+    public void visitVirtual(GeneralPath path, Way w) {
+        Iterator<Node> it = w.getNodes().iterator();
+        if (it.hasNext()) {
+            Point lastP = nc.getPoint(it.next());
+            while(it.hasNext())
+            {
+                Point p = nc.getPoint(it.next());
+                if(isSegmentVisible(lastP, p) && isLargeSegment(lastP, p, virtualNodeSpace))
+                {
+                    int x = (p.x+lastP.x)/2;
+                    int y = (p.y+lastP.y)/2;
+                    path.moveTo(x-virtualNodeSize, y);
+                    path.lineTo(x+virtualNodeSize, y);
+                    path.moveTo(x, y-virtualNodeSize);
+                    path.lineTo(x, y+virtualNodeSize);
+                }
+                lastP = p;
+            }
+        }
+    }
+
+    /**
+     * Draw a darkblue line for all segments.
+     * @param w The way to draw.
+     */
+    public void visit(Way w) {
+        if (w.isIncomplete() || w.getNodesCount() < 2)
+            return;
+
+        /* show direction arrows, if draw.segment.relevant_directions_only is not set, the way is tagged with a direction key
+           (even if the tag is negated as in oneway=false) or the way is selected */
+
+        boolean showThisDirectionArrow = ds.isSelected(w) || showDirectionArrow;
+        /* head only takes over control if the option is true,
+           the direction should be shown at all and not only because it's selected */
+        boolean showOnlyHeadArrowOnly = showThisDirectionArrow && !ds.isSelected(w) && showHeadArrowOnly;
+        Color wayColor;
+
+        if (isInactiveMode || w.isDisabled()) {
+            wayColor = inactiveColor;
+        } else if(w.isHighlighted()) {
+            wayColor = highlightColor;
+        } else if(ds.isSelected(w)) {
+            wayColor = selectedColor;
+        } else if (!w.isTagged()) {
+            wayColor = untaggedWayColor;
+        } else {
+            wayColor = dfltWayColor;
+        }
+
+        Iterator<Node> it = w.getNodes().iterator();
+        if (it.hasNext()) {
+            Point lastP = nc.getPoint(it.next());
+            for (int orderNumber = 1; it.hasNext(); orderNumber++) {
+                Point p = nc.getPoint(it.next());
+                drawSegment(lastP, p, wayColor,
+                        showOnlyHeadArrowOnly ? !it.hasNext() : showThisDirectionArrow);
+                if (showOrderNumber) {
+                    drawOrderNumber(lastP, p, orderNumber);
+                }
+                lastP = p;
+            }
+        }
+    }
+
+    private Stroke relatedWayStroke = new BasicStroke(
+            4, BasicStroke.CAP_SQUARE, BasicStroke.JOIN_BEVEL);
+    public void visit(Relation r) {
+        if (r.isIncomplete()) return;
+
+        Color col;
+        if (isInactiveMode || r.isDisabled()) {
+            col = inactiveColor;
+        } else if (ds.isSelected(r)) {
+            col = selectedColor;
+        } else {
+            col = relationColor;
+        }
+        g.setColor(col);
+
+        for (RelationMember m : r.getMembers()) {
+            if (m.getMember().isIncomplete() || m.getMember().isDeleted()) {
+                continue;
+            }
+
+            if (m.isNode()) {
+                Point p = nc.getPoint(m.getNode());
+                if (p.x < 0 || p.y < 0
+                        || p.x > nc.getWidth() || p.y > nc.getHeight()) {
+                    continue;
+                }
+
+                g.drawOval(p.x-3, p.y-3, 6, 6);
+            } else if (m.isWay()) {
+                GeneralPath path = new GeneralPath();
+
+                boolean first = true;
+                for (Node n : m.getWay().getNodes()) {
+                    if (n.isIncomplete() || n.isDeleted()) {
+                        continue;
+                    }
+                    Point p = nc.getPoint(n);
+                    if (first) {
+                        path.moveTo(p.x, p.y);
+                        first = false;
+                    } else {
+                        path.lineTo(p.x, p.y);
+                    }
+                }
+
+                g.draw(relatedWayStroke.createStrokedShape(path));
+            }
+        }
+    }
+
+    @Override
+    public void visit(Changeset cs) {/* ignore */}
+
+    /**
+     * Draw an number of the order of the two consecutive nodes within the
+     * parents way
+     */
+    protected void drawOrderNumber(Point p1, Point p2, int orderNumber) {
+        if (isSegmentVisible(p1, p2) && isLargeSegment(p1, p2, segmentNumberSpace)) {
+            String on = Integer.toString(orderNumber);
+            int strlen = on.length();
+            int x = (p1.x+p2.x)/2 - 4*strlen;
+            int y = (p1.y+p2.y)/2 + 4;
+
+            if(virtualNodeSize != 0 && isLargeSegment(p1, p2, virtualNodeSpace))
+            {
+                y = (p1.y+p2.y)/2 - virtualNodeSize - 3;
+            }
+
+            displaySegments(); /* draw nodes on top! */
+            Color c = g.getColor();
+            g.setColor(backgroundColor);
+            g.fillRect(x-1, y-12, 8*strlen+1, 14);
+            g.setColor(c);
+            g.drawString(on, x, y);
+        }
+    }
+
+    /**
+     * Draw the node as small rectangle with the given color.
+     *
+     * @param n     The node to draw.
+     * @param color The color of the node.
+     */
+    public void drawNode(Node n, Color color, int size, boolean fill) {
+        if (size > 1) {
+            int radius = size / 2;
+            Point p = nc.getPoint(n);
+            if ((p.x < 0) || (p.y < 0) || (p.x > nc.getWidth())
+                    || (p.y > nc.getHeight()))
+                return;
+            g.setColor(color);
+            if (fill) {
+                g.fillRect(p.x - radius, p.y - radius, size, size);
+                g.drawRect(p.x - radius, p.y - radius, size, size);
+            } else {
+                g.drawRect(p.x - radius, p.y - radius, size, size);
+            }
+        }
+    }
+
+    private static final double PHI = Math.toRadians(20);
+    private static final double cosPHI = Math.cos(PHI);
+    private static final double sinPHI = Math.sin(PHI);
+
+    protected void drawSegment(GeneralPath path, Point p1, Point p2, boolean showDirection) {
+        Rectangle bounds = g.getClipBounds();
+        bounds.grow(100, 100);                  // avoid arrow heads at the border
+        LineClip clip = new LineClip(p1, p2, bounds);
+        if (clip.execute()) {
+            p1 = clip.getP1();
+            p2 = clip.getP2();
+            path.moveTo(p1.x, p1.y);
+            path.lineTo(p2.x, p2.y);
+
+            if (showDirection) {
+                final double l =  10. / p1.distance(p2);
+
+                final double sx = l * (p1.x - p2.x);
+                final double sy = l * (p1.y - p2.y);
+
+                path.lineTo (p2.x + (int) Math.round(cosPHI * sx - sinPHI * sy), p2.y + (int) Math.round(sinPHI * sx + cosPHI * sy));
+                path.moveTo (p2.x + (int) Math.round(cosPHI * sx + sinPHI * sy), p2.y + (int) Math.round(- sinPHI * sx + cosPHI * sy));
+                path.lineTo(p2.x, p2.y);
+            }
+        }
+    }
+
+    /**
+     * Draw a line with the given color.
+     */
+    protected void drawSegment(Point p1, Point p2, Color col, boolean showDirection) {
+        if (col != currentColor) {
+            displaySegments(col);
+        }
+        drawSegment(currentPath, p1, p2, showDirection);
+    }
+
+    protected boolean isSegmentVisible(Point p1, Point p2) {
+        if ((p1.x < 0) && (p2.x < 0)) return false;
+        if ((p1.y < 0) && (p2.y < 0)) return false;
+        if ((p1.x > nc.getWidth()) && (p2.x > nc.getWidth())) return false;
+        if ((p1.y > nc.getHeight()) && (p2.y > nc.getHeight())) return false;
+        return true;
+    }
+
+    protected boolean isPolygonVisible(Polygon polygon) {
+        Rectangle bounds = polygon.getBounds();
+        if (bounds.width == 0 && bounds.height == 0) return false;
+        if (bounds.x > nc.getWidth()) return false;
+        if (bounds.y > nc.getHeight()) return false;
+        if (bounds.x + bounds.width < 0) return false;
+        if (bounds.y + bounds.height < 0) return false;
+        return true;
+    }
+
+    protected void displaySegments() {
+        displaySegments(null);
+    }
+    protected void displaySegments(Color newColor) {
+        if (currentPath != null) {
+            g.setColor(currentColor);
+            g.draw(currentPath);
+            currentPath = new GeneralPath();
+            currentColor = newColor;
+        }
+    }
+}
Index: trunk/src/org/openstreetmap/josm/gui/MainMenu.java
===================================================================
--- trunk/src/org/openstreetmap/josm/gui/MainMenu.java	(revision 4086)
+++ trunk/src/org/openstreetmap/josm/gui/MainMenu.java	(revision 4087)
@@ -277,5 +277,4 @@
         viewMenu.add(wireframe);
         wireframe.setAccelerator(wireFrameToggleAction.getShortcut().getKeyStroke());
-        wireFrameToggleAction.addButtonModel(wireframe.getModel());
 
         viewMenu.addSeparator();
Index: trunk/src/org/openstreetmap/josm/gui/dialogs/MapPaintDialog.java
===================================================================
--- trunk/src/org/openstreetmap/josm/gui/dialogs/MapPaintDialog.java	(revision 4086)
+++ trunk/src/org/openstreetmap/josm/gui/dialogs/MapPaintDialog.java	(revision 4087)
@@ -13,5 +13,4 @@
 import java.awt.Rectangle;
 import java.awt.event.ActionEvent;
-import java.awt.event.ActionListener;
 import java.awt.event.KeyEvent;
 import java.awt.event.MouseEvent;
@@ -28,5 +27,4 @@
 
 import javax.swing.AbstractAction;
-import javax.swing.DefaultButtonModel;
 import javax.swing.DefaultListSelectionModel;
 import javax.swing.JCheckBox;
@@ -99,22 +97,8 @@
         JLabel wfLabel = new JLabel(tr("Wireframe View"), ImageProvider.get("dialogs/mappaint", "wireframe_small"), JLabel.HORIZONTAL);
         wfLabel.setFont(wfLabel.getFont().deriveFont(Font.PLAIN));
-
-        cbWireframe.setModel(new DefaultButtonModel() {
-            @Override
-            public void setSelected(boolean b) {
-                super.setSelected(b);
-                tblStyles.setEnabled(!b);
-                onoffAction.updateEnabledState();
-                upAction.updateEnabledState();
-                downAction.updateEnabledState();
-            }
-        });
-        cbWireframe.addActionListener(new ActionListener() {
-            public void actionPerformed(ActionEvent e) {
-                Main.main.menu.wireFrameToggleAction.actionPerformed(null);
-            }
-        });
+        cbWireframe.setFont(cbWireframe.getFont().deriveFont(Font.PLAIN));
+        cbWireframe.setAction(Main.main.menu.wireFrameToggleAction);
         cbWireframe.setBorder(new EmptyBorder(new Insets(1,1,1,1)));
-
+        cbWireframe.setText("");
         tblStyles = new StylesTable(model);
         tblStyles.setSelectionModel(selectionModel= new DefaultListSelectionModel());
@@ -130,4 +114,5 @@
         tblStyles.setShowGrid(false);
         tblStyles.setIntercellSpacing(new Dimension(0, 0));
+        cbWireframe.addChangeListener(tblStyles);
 
         JPanel p = new JPanel(new GridBagLayout());
@@ -137,11 +122,9 @@
 
         pnl.add(new JScrollPane(p), BorderLayout.CENTER);
-
         pnl.add(buildButtonRow(), BorderLayout.SOUTH);
-
         add(pnl, BorderLayout.CENTER);
     }
 
-    protected static class StylesTable extends JTable {
+    protected class StylesTable extends JTable implements ChangeListener{
 
         public StylesTable(TableModel dm) {
@@ -157,4 +140,9 @@
             rect.setLocation(rect.x - pt.x, rect.y - pt.y);
             viewport.scrollRectToVisible(rect);
+        }
+
+        @Override
+        public void stateChanged(ChangeEvent e) {
+            setEnabled(!cbWireframe.isSelected());
         }
     }
@@ -170,4 +158,8 @@
         selectionModel.addListSelectionListener(upAction);
         selectionModel.addListSelectionListener(downAction);
+        cbWireframe.addChangeListener(onoffAction);
+        cbWireframe.addChangeListener(upAction);
+        cbWireframe.addChangeListener(downAction);
+
         p.add(new SideButton(onoffAction));
         p.add(new SideButton(upAction));
@@ -180,11 +172,11 @@
     @Override
     public void showNotify() {
+        cbWireframe.setAction(Main.main.menu.wireFrameToggleAction);
         MapPaintStyles.addMapPaintSylesUpdateListener(model);
-        Main.main.menu.wireFrameToggleAction.addButtonModel(cbWireframe.getModel());
     }
 
     @Override
     public void hideNotify() {
-        Main.main.menu.wireFrameToggleAction.removeButtonModel(cbWireframe.getModel());
+        cbWireframe.setAction(null);
         MapPaintStyles.removeMapPaintSylesUpdateListener(model);
     }
@@ -304,5 +296,20 @@
     }
 
-    protected class OnOffAction extends AbstractAction implements ListSelectionListener {
+    protected abstract class EventListeningAction extends AbstractAction implements ListSelectionListener, ChangeListener {
+
+        protected abstract void updateEnabledState();
+
+        @Override
+        public void valueChanged(ListSelectionEvent e) {
+            updateEnabledState();
+        }
+
+        @Override
+        public void stateChanged(ChangeEvent e) {
+            updateEnabledState();
+        }
+    }
+
+    protected class OnOffAction extends EventListeningAction {
         public OnOffAction() {
             putValue(SHORT_DESCRIPTION, tr("Turn selected styles on or off"));
@@ -311,11 +318,7 @@
         }
 
+        @Override
         protected void updateEnabledState() {
             setEnabled(!cbWireframe.isSelected() && tblStyles.getSelectedRowCount() > 0);
-        }
-
-        @Override
-        public void valueChanged(ListSelectionEvent e) {
-            updateEnabledState();
         }
 
@@ -334,5 +337,5 @@
      * The action to move down the currently selected entries in the list.
      */
-    protected class MoveUpDownAction extends AbstractAction implements ListSelectionListener {
+    protected class MoveUpDownAction extends EventListeningAction {
 
         final int increment;
@@ -345,4 +348,5 @@
         }
 
+        @Override
         public void updateEnabledState() {
             int[] sel = tblStyles.getSelectedRows();
@@ -360,8 +364,4 @@
             }
             model.ensureSelectedIsVisible();
-        }
-
-        public void valueChanged(ListSelectionEvent e) {
-            updateEnabledState();
         }
     }
@@ -503,18 +503,6 @@
                     error = true;
                 } finally {
-                    if (bis != null) {
-                        try {
-                            bis.close();
-                        } catch (IOException e) {
-                            e.printStackTrace();
-                        }
-                    }
-                    if (bos != null) {
-                        try {
-                            bos.close();
-                        } catch (IOException e) {
-                            e.printStackTrace();
-                        }
-                    }
+                    Utils.close(bis);
+                    Utils.close(bos);
                 }
             }
@@ -648,8 +636,5 @@
                 txtSource.append("<ERROR: failed to read file!>");
             } finally {
-                try {
-                    is.close();
-                } catch (IOException ex) {
-                }
+                Utils.close(is);
             }
         }
Index: trunk/src/org/openstreetmap/josm/gui/layer/OsmDataLayer.java
===================================================================
--- trunk/src/org/openstreetmap/josm/gui/layer/OsmDataLayer.java	(revision 4086)
+++ trunk/src/org/openstreetmap/josm/gui/layer/OsmDataLayer.java	(revision 4087)
@@ -42,5 +42,4 @@
 import org.openstreetmap.josm.data.conflict.Conflict;
 import org.openstreetmap.josm.data.conflict.ConflictCollection;
-import org.openstreetmap.josm.data.coor.EastNorth;
 import org.openstreetmap.josm.data.coor.LatLon;
 import org.openstreetmap.josm.data.gpx.GpxData;
@@ -61,7 +60,6 @@
 import org.openstreetmap.josm.data.osm.visitor.AbstractVisitor;
 import org.openstreetmap.josm.data.osm.visitor.BoundingXYVisitor;
-import org.openstreetmap.josm.data.osm.visitor.paint.MapPaintVisitor;
-import org.openstreetmap.josm.data.osm.visitor.paint.PaintVisitor;
-import org.openstreetmap.josm.data.osm.visitor.paint.SimplePaintVisitor;
+import org.openstreetmap.josm.data.osm.visitor.paint.MapRendererFactory;
+import org.openstreetmap.josm.data.osm.visitor.paint.Rendering;
 import org.openstreetmap.josm.data.validation.TestError;
 import org.openstreetmap.josm.gui.HelpAwareOptionPane;
@@ -241,14 +239,13 @@
             Area a = new Area(b);
 
-            // now succesively subtract downloaded areas
-            for (DataSource src : data.dataSources) {
-                if (src.bounds != null && !src.bounds.getMin().equals(src.bounds.getMax())) {
-                    EastNorth en1 = mv.getProjection().latlon2eastNorth(src.bounds.getMin());
-                    EastNorth en2 = mv.getProjection().latlon2eastNorth(src.bounds.getMax());
-                    Point p1 = mv.getPoint(en1);
-                    Point p2 = mv.getPoint(en2);
-                    Rectangle r = new Rectangle(Math.min(p1.x, p2.x),Math.min(p1.y, p2.y),Math.abs(p2.x-p1.x),Math.abs(p2.y-p1.y));
-                    a.subtract(new Area(r));
+            // now successively subtract downloaded areas
+            for (Bounds bounds : data.getDataSourceBounds()) {
+                if (bounds.isCollapsed()) {
+                    continue;
                 }
+                Point p1 = mv.getPoint(bounds.getMin());
+                Point p2 = mv.getPoint(bounds.getMax());
+                Rectangle r = new Rectangle(Math.min(p1.x, p2.x),Math.min(p1.y, p2.y),Math.abs(p2.x-p1.x),Math.abs(p2.y-p1.y));
+                a.subtract(new Area(r));
             }
 
@@ -258,14 +255,6 @@
         }
 
-        PaintVisitor painter;
-        if (Main.pref.getBoolean("draw.wireframe")) {
-            painter = new SimplePaintVisitor();
-        } else {
-            painter = new MapPaintVisitor();
-        }
-        painter.setGraphics(g);
-        painter.setNavigatableComponent(mv);
-        painter.setInactive(inactive);
-        painter.visitAll(data, virtual, box);
+        Rendering painter = MapRendererFactory.getInstance().createActiveRenderer(g, mv, inactive);
+        painter.render(data, virtual, box);
         Main.map.conflictDialog.paintConflicts(g, mv);
     }
@@ -528,6 +517,7 @@
             }
             String name = n.get("name");
-            if (name == null)
-		continue;
+            if (name == null) {
+                continue;
+            }
             WayPoint wpt = new WayPoint(n.getCoor());
             wpt.attr.put("name", name);
@@ -538,6 +528,6 @@
             String desc = n.get("description");
             if (desc != null) {
-               wpt.attr.put("desc", desc);
-	    }
+                wpt.attr.put("desc", desc);
+            }
 
             gpxData.waypoints.add(wpt);
Index: trunk/src/org/openstreetmap/josm/gui/mappaint/NodeElemStyle.java
===================================================================
--- trunk/src/org/openstreetmap/josm/gui/mappaint/NodeElemStyle.java	(revision 4086)
+++ trunk/src/org/openstreetmap/josm/gui/mappaint/NodeElemStyle.java	(revision 4087)
@@ -127,4 +127,5 @@
         }
 
+        @Override
         protected String toStringImpl() {
             return super.toStringImpl() + " hAlign=" + hAlign + " vAlign=" + vAlign;
@@ -207,5 +208,5 @@
         }
 
-        return new NodeElemStyle(c, 
+        return new NodeElemStyle(c,
                 icon == null ? null : icon.a,
                 icon == null ? null : icon.b,
@@ -342,5 +343,5 @@
             Node n = (Node) primitive;
             if (icon != null && painter.isShowIcons()) {
-                painter.drawNodeIcon(n, (painter.isInactive() || n.isDisabled()) ? getDisabledIcon() : icon,
+                painter.drawNodeIcon(n, (painter.isInactiveMode() || n.isDisabled()) ? getDisabledIcon() : icon,
                         Utils.color_int2float(iconAlpha), selected, member, text);
             } else if (symbol != null) {
@@ -350,5 +351,5 @@
                         fillColor = settings.getHighlightColor();
                     } else {
-                        if (painter.isInactive() || n.isDisabled()) {
+                        if (painter.isInactiveMode() || n.isDisabled()) {
                             fillColor = settings.getInactiveColor();
                         } else if (selected) {
@@ -364,5 +365,5 @@
                         strokeColor = settings.getHighlightColor();
                     } else {
-                        if (painter.isInactive() || n.isDisabled()) {
+                        if (painter.isInactiveMode() || n.isDisabled()) {
                             strokeColor = settings.getInactiveColor();
                         } else if (selected) {
@@ -381,5 +382,5 @@
                     boolean isConnection = n.isConnectionNode();
 
-                    if (painter.isInactive() || n.isDisabled()) {
+                    if (painter.isInactiveMode() || n.isDisabled()) {
                         color = settings.getInactiveColor();
                     } else if (selected) {
@@ -402,12 +403,12 @@
 
                     final int size = Utils.max((selected ? settings.getSelectedNodeSize() : 0),
-                                            (n.isTagged() ? settings.getTaggedNodeSize() : 0),
-                                            (isConnection ? settings.getConnectionNodeSize() : 0),
-                                            settings.getUnselectedNodeSize());
+                            (n.isTagged() ? settings.getTaggedNodeSize() : 0),
+                            (isConnection ? settings.getConnectionNodeSize() : 0),
+                            settings.getUnselectedNodeSize());
 
                     final boolean fill = (selected && settings.isFillSelectedNode()) ||
-                                            (n.isTagged() && settings.isFillTaggedNode()) ||
-                                            (isConnection && settings.isFillConnectionNode()) ||
-                                            settings.isFillUnselectedNode();
+                            (n.isTagged() && settings.isFillTaggedNode()) ||
+                            (isConnection && settings.isFillConnectionNode()) ||
+                            settings.isFillUnselectedNode();
 
                     painter.drawNode(n, color, size, fill, text);
@@ -474,4 +475,3 @@
         return s.toString();
     }
-
 }
Index: trunk/src/org/openstreetmap/josm/plugins/PluginDownloadTask.java
===================================================================
--- trunk/src/org/openstreetmap/josm/plugins/PluginDownloadTask.java	(revision 4086)
+++ trunk/src/org/openstreetmap/josm/plugins/PluginDownloadTask.java	(revision 4087)
@@ -24,4 +24,5 @@
 import org.openstreetmap.josm.gui.progress.ProgressMonitor;
 import org.openstreetmap.josm.tools.CheckParameterUtil;
+import org.openstreetmap.josm.tools.Utils;
 import org.xml.sax.SAXException;
 
@@ -145,17 +146,9 @@
             throw new PluginDownloadException(e);
         } finally {
-            if (in != null) {
-                try {
-                    in.close();
-                } catch(IOException e) { /* ignore */}
-            }
+            Utils.close(in);
             synchronized(this) {
                 downloadConnection = null;
             }
-            if (out != null) {
-                try {
-                    out.close();
-                } catch(IOException e) { /* ignore */}
-            }
+            Utils.close(out);
         }
     }
Index: trunk/src/org/openstreetmap/josm/plugins/ReadLocalPluginInformationTask.java
===================================================================
--- trunk/src/org/openstreetmap/josm/plugins/ReadLocalPluginInformationTask.java	(revision 4086)
+++ trunk/src/org/openstreetmap/josm/plugins/ReadLocalPluginInformationTask.java	(revision 4087)
@@ -18,4 +18,5 @@
 import org.openstreetmap.josm.io.OsmTransferException;
 import org.openstreetmap.josm.tools.ImageProvider;
+import org.openstreetmap.josm.tools.Utils;
 import org.xml.sax.SAXException;
 
@@ -186,9 +187,5 @@
             throw new PluginListParseException(e);
         } finally {
-            if (fin != null) {
-                try {
-                    fin.close();
-                } catch(IOException e){ /* ignore */}
-            }
+            Utils.close(fin);
         }
     }
Index: trunk/src/org/openstreetmap/josm/plugins/ReadRemotePluginInformationTask.java
===================================================================
--- trunk/src/org/openstreetmap/josm/plugins/ReadRemotePluginInformationTask.java	(revision 4086)
+++ trunk/src/org/openstreetmap/josm/plugins/ReadRemotePluginInformationTask.java	(revision 4087)
@@ -34,4 +34,5 @@
 import org.openstreetmap.josm.io.OsmTransferException;
 import org.openstreetmap.josm.tools.ImageProvider;
+import org.openstreetmap.josm.tools.Utils;
 import org.xml.sax.SAXException;
 
@@ -188,9 +189,5 @@
                 connection = null;
             }
-            if (in != null) {
-                try {
-                    in.close();
-                } catch(IOException e){/* ignore */}
-            }
+            Utils.close(in);
             monitor.finishTask();
         }
@@ -242,9 +239,5 @@
                 connection = null;
             }
-            if (in != null) {
-                try {
-                    in.close();
-                } catch(IOException e){/* ignore */}
-            }
+            Utils.close(in);
             monitor.finishTask();
         }
Index: trunk/src/org/openstreetmap/josm/tools/Utils.java
===================================================================
--- trunk/src/org/openstreetmap/josm/tools/Utils.java	(revision 4086)
+++ trunk/src/org/openstreetmap/josm/tools/Utils.java	(revision 4087)
@@ -7,4 +7,5 @@
 import java.io.InputStream;
 import java.io.OutputStream;
+import java.io.Reader;
 import java.text.MessageFormat;
 import java.util.Collection;
@@ -202,3 +203,45 @@
         return( path.delete() );
     }
+
+    /**
+     * <p>Utility method for closing an input stream.</p>
+     * 
+     * @param is the input stream. May be null.
+     */
+    public static void close(InputStream is){
+        if (is == null) return;
+        try {
+            is.close();
+        } catch(IOException e){
+            // ignore
+        }
+    }
+
+    /**
+     * <p>Utility method for closing an output stream.</p>
+     * 
+     * @param os the output stream. May be null.
+     */
+    public static void close(OutputStream os){
+        if (os == null) return;
+        try {
+            os.close();
+        } catch(IOException e){
+            // ignore
+        }
+    }
+
+    /**
+     * <p>Utility method for closing a reader.</p>
+     * 
+     * @param reader the reader. May be null.
+     */
+    public static void close(Reader reader){
+        if (reader == null) return;
+        try {
+            reader.close();
+        } catch(IOException e){
+            // ignore
+        }
+    }
 }
Index: trunk/test/functional/mapcss/performance/PerformanceTest.groovy
===================================================================
--- trunk/test/functional/mapcss/performance/PerformanceTest.groovy	(revision 4086)
+++ trunk/test/functional/mapcss/performance/PerformanceTest.groovy	(revision 4087)
@@ -12,5 +12,5 @@
 import org.openstreetmap.josm.data.Bounds
 import org.openstreetmap.josm.data.osm.DataSet
-import org.openstreetmap.josm.data.osm.visitor.paint.MapPaintVisitor
+import org.openstreetmap.josm.data.osm.visitor.paint.StyledMapRenderer
 import org.openstreetmap.josm.gui.MainApplication
 import org.openstreetmap.josm.gui.layer.OsmDataLayer
@@ -116,5 +116,5 @@
         Graphics2D g = img.createGraphics()
         g.setClip(0,0, mv.getWidth(), mv.getHeight())
-        def visitor = new MapPaintVisitor()
+        def visitor = new StyledMapRenderer()
         visitor.setNavigatableComponent(Main.map.mapView)
         visitor.setGraphics(g)
@@ -122,5 +122,5 @@
         print "Rendering ..."
         long time = timed {
-            visitor.visitAll(ds, false, new Bounds(-90,-180,90,180))
+            visitor.render(ds, false, new Bounds(-90,-180,90,180))
         }
         println "DONE"
Index: trunk/test/performance/org/openstreetmap/josm/data/osm/MapPaintVisitorPerformanceTest.java
===================================================================
--- trunk/test/performance/org/openstreetmap/josm/data/osm/MapPaintVisitorPerformanceTest.java	(revision 4086)
+++ trunk/test/performance/org/openstreetmap/josm/data/osm/MapPaintVisitorPerformanceTest.java	(revision 4087)
@@ -10,6 +10,6 @@
 import org.openstreetmap.josm.Main;
 import org.openstreetmap.josm.data.Bounds;
-import org.openstreetmap.josm.data.osm.visitor.paint.MapPaintVisitor;
-import org.openstreetmap.josm.data.osm.visitor.paint.PaintVisitor;
+import org.openstreetmap.josm.data.osm.visitor.paint.Rendering;
+import org.openstreetmap.josm.data.osm.visitor.paint.StyledMapRenderer;
 import org.openstreetmap.josm.data.projection.Mercator;
 import org.openstreetmap.josm.gui.NavigatableComponent;
@@ -52,11 +52,8 @@
 
     private static void test(int iterations, DataSet ds, Bounds bounds) throws Exception {
-        PaintVisitor visitor = new MapPaintVisitor();
+        Rendering visitor = new StyledMapRenderer(g,nc,false);
         nc.zoomTo(bounds);
-        visitor.setGraphics(g);
-        visitor.setNavigatableComponent(nc);
-        visitor.setInactive(false);
         for (int i=0; i<iterations; i++) {
-            visitor.visitAll(ds, true, bounds);
+            visitor.render(ds, true, bounds);
         }
     }
